台湾股市有揭露三大法人当日买进卖出的金额,在市场上会有流派依照这些进出的资讯,调整手上的资金部位。因为有一种说法是,当法人决定对某档个股买进,或是对台湾股市执行某向策略,在某个时期内,方向不会变。
不过...现在台股有当日冲销这样的机制,而且政府为了推行这个制度,在当冲税率上还有优惠,这个优惠政策目前看起来会持续到 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
如果要拿某月某日的资料(英文版)
https://www.twse.com.tw/en/fund/BFI82U?response=csv&dayDate=20210914&weekDate=20210913&monthDate=20210915&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 - 台股申购日历
<<: Day20 NiFi - 与 GCP Cloud Storage 对接设定
placeholder ...
Day1 的时候有提到我们公司使用的云端方案是GCP (Google Cloud Platform)...
提完了那麽多有关 APCS 的事,这次想要分析考 APCS 能够有怎样的好处。 权威性: APCS ...
最後,还是到了这最後一天,这第 30 天不完美的完赛,有时候时常都会想,上班就很忙了,开的 Tick...
今天主要介绍VSCode开发Flutter时装哪些扩充插件, 还有一些开发时会用到的小眉角,写起来稍...