台灣股市有揭露三大法人當日買進賣出的金額,在市場上會有流派依照這些進出的資訊,調整手上的資金部位。因為有一種說法是,當法人決定對某檔個股買進,或是對台灣股市執行某向策略,在某個時期內,方向不會變。
不過...現在台股有當日沖銷這樣的機制,而且政府為了推行這個制度,在當沖稅率上還有優惠,這個優惠政策目前看起來會持續到 2024 年。因為稅率有優惠,而且現在台股的波動大,觀察新聞可以看到很多「少年股神」的新聞。這些少年股神們的進出,是足以影響當日的波動。另外,也不是所有的法人進出大量都是長期佈局的,也是有特定的外資法人交易的頻率就是在當天敲大單買進,然後隔天倒出的。因為文章不想提及特定券商法人,建議可以蒐尋「隔日沖」、「券商」等關鍵字,你就會看到別人整理的隔日沖券商和特定分點資料。這邊比較要注意的是特定分點的資料,就只是某帳戶在該分點進出的量而,並不是那個分點自己下單,即使今天你看到特定分點下巨量的單,也不代表明天就會賣出。
資料下載頁面
https://www.twse.com.tw/zh/page/trading/fund/BFI82U.html
如果要拿當前最新資料(英文版)
https://www.twse.com.tw/en/fund/BFI82U?response=csv&dayDate=&weekDate=&monthDate=&type=day
如果要拿某月某日的資料(英文版)
因為這隻 api 拿取資料的方式是一次一天,沒辦法像前面的 K 線資料,可以一次拿取多天的資料,所以使用一次 API 的 query,沒辦法把計算後的三大法人百分比,用 line chart 表示。
如果考慮目前拿到資料的方式,已經有目前大盤當日成交量,那就能算出[三大法人] / [非三大法人] 的比例。而呈現比例最方便的 chart 就是 pie chart,接下來,我們就用 pie chart 呈現三大法人佔當日成交量的百分比。
需要的欄位是 [Total Buy] [Total Sell] [Difference]
如果不確定 item 中每一行代表的意義,可以下載一下中文的資料做對照。
DataModel 設計如下
struct MajorInvestor {
let typeString: String
let date: Date
let totalBuyString: String
let totalSellString: String
let diffString: String
private var numberFormatter: NumberFormatter {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
return formatter
}
var totalBuy: Double {
return numberFormatter.number(from: totalBuyString)?.doubleValue ?? 0
}
var totalSell: Double {
return numberFormatter.number(from: totalSellString)?.doubleValue ?? 0
}
var difference: Double {
return numberFormatter.number(from: diffString)?.doubleValue ?? 0
}
}
而日期的資訊,在第一行的第一個空白之前
所以我們需要把 yyyy/MM/dd 這一段 String 拿出來,再給 DateUtility 轉成 Date 型別
private func getFirstLine(_ string: String) -> String {
return CSVAdapter.getFirstLine(string).replacingOccurrences(of: "\"", with: "")
}
private func getDateString(from firstLine: String) -> String {
let separatedString = firstLine.components(separatedBy: " ")
return separatedString.first ?? ""
}
整個拉取資料的類別設計如下
import Foundation
//三大法人
//https://www.twse.com.tw/zh/page/trading/fund/BFI82U.html
//https://www.twse.com.tw/en/fund/BFI82U?response=csv&dayDate=&weekDate=&monthDate=&type=day
// 如果要 query 某個日期
//https://www.twse.com.tw/en/fund/BFI82U?response=csv&dayDate=20210914&weekDate=20210913&monthDate=20210915&type=day
class ThreeMajorInvestorsManager {
private lazy var alamofireAdapter: AlamofireAdapter = {
return AlamofireAdapter()
}()
func requestInvestorsInfo(completion: @escaping (([MajorInvestor], Error?) -> Void)) {
let urlString = "https://www.twse.com.tw/en/fund/BFI82U?response=csv&dayDate=&weekDate=&monthDate=&type=day"
alamofireAdapter.requestForString(urlString, method: .get) { [weak self] result in
guard let self = self else { return }
switch result {
case .success(let string):
let firstLine = self.getFirstLine(string)
let dateString = self.getDateString(from: firstLine)
let majorInvestors = self.convert(from: string, dateString: dateString)
completion(majorInvestors, nil)
case .failure(let error):
completion([], error)
}
}
}
private func trimmedFirstLine(_ string: String) -> String {
return CSVAdapter.removeLine(string, at: 1)
}
private func getFirstLine(_ string: String) -> String {
return CSVAdapter.getFirstLine(string).replacingOccurrences(of: "\"", with: "")
}
private func getDateString(from firstLine: String) -> String {
let separatedString = firstLine.components(separatedBy: " ")
return separatedString.first ?? ""
}
private func convert(from string: String, dateString: String) -> [MajorInvestor] {
var majorInvestors = [MajorInvestor]()
let trimmedString = self.trimmedFirstLine(string)
let dateUtility = DateUtility()
if let csv = CSVAdapter(rawString: trimmedString),
let date = dateUtility.getDate(from: dateString, format: "yyyy/MM/dd") {
for each in csv.namedRows {
let item = each["Item"] ?? ""
let totalBuy = each["Total Buy"] ?? ""
let totalSell = each["Total Sell"] ?? ""
let difference = each["Difference"] ?? ""
// 這一份 csv 檔有 footer,如果 difference 沒有字,就是 footer
if !difference.isEmpty {
let majorInvestor = MajorInvestor(typeString: item, date: date, totalBuyString: totalBuy, totalSellString: totalSell, diffString: difference)
majorInvestors.append(majorInvestor)
}
}
}
return majorInvestors
}
}
台股申購日曆
IT鐵人賽Demo App
下方是這次 D1 ~ D12 的完成品,可以下載來試
App Store - 台股申購日曆