此文章為VIP限定
介紹
券商分點理論上是非常有效果的數據,應用得當,可以用來預測股價的走勢,然而,市場上主要將券商分點資料來計算「主力買賣超」、「買賣家數差」,該指標在選股上,效果不好。
本文將提出一種新的方式,來提取券商分點資料,製作更有效的選股指標,其效果非常顯著,搭配回測策略能夠有效獲得卓越的效果。本文將詳細說明這些概念的定義、計算方法及應用,並展示如何將這些知識綜合應用於投資策略的設計與回測。
建議讀者可以自行修改,將策略調整後,有很大的進步空間。
籌碼分點資料(Broker Transactions)
什麼是籌碼分點資料
籌碼分點資料是指某一股票在不同券商之間的買賣交易情況。這些資料包括買入量、賣出量等,反映了不同券商在特定時間段內的交易行為。這些數據能提供市場上資金流動的資訊,有助於投資者理解市場動向。
資料來源與取得方式
在台灣,投資者可以通過一些金融資料平台,如Finlab,來獲取籌碼分點資料。這些平台提供了方便的API接口,使投資者能夠輕鬆下載和分析數據。
from finlab import data
bt = data.get('broker_transactions', force_download=True)
buysell = bt.groupby(['date', 'stock_id']).agg({'buy': 'sum', 'sell': 'sum'})\
.reset_index().pivot(columns='stock_id', index='date', values=['buy', 'sell'])
buysell.head()
籌碼分點資料的深度分析
過往如何通過籌碼分點資料識別主力資金動向
主力資金的動向通常對市場影響巨大。通過分析籌碼分點資料中的大額交易,可以識別出主力資金的買賣行為,從而提前佈局。
過往的券商分點指標
過往有一些券商分點指標,對於選股有一些效果,然而實測上,顯著程度有限。以下列舉最常見的兩種指標:
主力買賣超
定義:
主力買賣超是指某一特定時間段內,主要券商的買入量與賣出量之差。
計算公式:
主力買賣超=∑(主要券商買入量)−∑(主要券商賣出量)
效用:
- 資金動向指標:主力買賣超反映了市場中資金流向的變化,主要券商的大額買入或賣出行為通常代表著市場主力資金的動向,能夠影響股票價格。
- 市場情緒指標:通過觀察主力買賣超,投資者可以了解市場主力的投資情緒,進而做出相應的投資決策。
買賣家數差
定義:
買賣家數差是指買入股票的券商家數與賣出股票的券商家數之差。
計算公式:
買賣家數差=買入券商家數−賣出券商家數
效用:
市場參與度指標:買賣家數差反映了市場中多空雙方的力量對比,當買入券商家數多於賣出券商家數時,表示市場散戶的偏好。
供需平衡指標:買賣家數差能夠幫助投資者判斷市場供需平衡狀況,從而預測未來價格走勢。
上述指標效果平平,接下來,我們將藉由 ChatGPT 發想更優秀的指標。
券商分點資料建構指標
利用 ChatGPT 發想相關想法
為了創建更好的指標,我們可以透過 ChatGPT 來輔助產生不同的 factor 進行運算,這種方法並非標新立異,其實早就在
Cheng, Yuhan, and Ke Tang. “GPT’s idea of stock factors.” Quantitative Finance (2024): 1-26.
被介紹過。
指標種類與計算方式
以下為 ChatGPT 產生的指標,其中有一些是滿有參考性的,我們可以拿來使用看看,下圖中,雖然它誤以為 ICIR 是一種協會(等等介紹這是什麼),然而也提供了一些不錯的指標:
產生程式碼
ChatGPT 除了可以幫忙發想指標外,也可以用來產生出相對應的程式,這樣就不需要親自撰寫程式。
import warnings
warnings.filterwarnings('ignore')
net_volume = buysell['buy'] - buysell['sell']
buy_sell_ratio = buysell['buy'] / buysell['sell']
balance_index = (buysell['buy'] - buysell['sell']) / (buysell['buy'] + buysell['sell'])
feature_dfs = {
'net_volume': net_volume,
'buy_sell_ratio': buy_sell_ratio,
'balance_index': balance_index,
}
有效性
我們當然會希望這些指標是有效的,需要有一個衡量標準,能夠一致性的對於這些不同的指標進行評分,方便我們從中選出最適合選股的指標,通常我們會使用 IC、ICIR 來衡量這些指標是否對於未來的股價有相關性。
Information Coefficient (IC)
介紹
IC,即Information Coefficient,是衡量一個指標在預測資產回報方面的能力的數值。簡單來說,IC代表了預測回報與實際回報之間的相關性。IC的範圍一般在-1到1之間,其中正值表示預測回報與實際回報正相關,負值表示兩者負相關。IC的絕對值越高,表示預測能力越強。
IC的計算方法如下:
IC = Cov(r,x) / σrσx
其中,r 為實際回報,x 為預測回報,Cov(r,x) 為兩者的協方差,σr、σx 分別為實際回報和預測回報的標準差。
IC主要用於衡量單一時點上的預測能力,而ICIR則進一步綜合多個時點上的IC,評估一段時間內的整體預測能力。
ICIR
如何計算ICIR
ICIR的計算主要基於Information Coefficient(IC),其公式如下:
ICIR = Mean(IC) × Std(IC)
在投資中的應用
ICIR能幫助投資者評估不同策略或指標的預測能力,從而選擇具有較穩定的預測能力的策略。高ICIR值通常表示策略具有穩定的預測能力,適合在實際投資中應用。
程式碼
from finlab.tools.factor_analysis import ic
adj_close = data.get('etl:adj_close')
# 每個時間點的IC
ics = ic(feature_dfs, adj_close, days=[10, 20, 60])
# 取平均
ics.mean()
# 取得ICIR
ics.mean() / ics.std()
遞迴優化參數
藉由 ICIR,我們可以疊代不同的公式,產生出更好的指標:
- 產生指標庫:先計算與發想指標
- 計算IC、ICIR
- 更新指標指標庫
- 移除沒有效果的指標
- 有效果的指標進行參數優化,列舉多個變體
- 重複步驟 1
成果
import numpy as np
def std(df, n):
return df.rolling(n).std().replace(0, np.nan)
buy_change = buysell['buy'] - buysell['buy'].shift(1)
sell_change = buysell['sell'] - buysell['sell'].shift(1)
net_volume_change = net_volume - net_volume.shift(1)
feature_dfs = {
'net_volume': net_volume,
'buy_sell_ratio': buy_sell_ratio,
'balance_index': balance_index,
'avg20_net_volume': net_volume / net_volume.rolling(20).mean(),
'avg20_buy_sell_ratio': buy_sell_ratio.rolling(20).mean(),
'avg20_balance_index': balance_index.rolling(20).mean(),
'sharpe5_net_volume': net_volume.rolling(5).mean() / std(net_volume, 5),
'sharpe10_net_volume': net_volume.rolling(10).mean() / std(net_volume, 10),
'sharpe20_net_volume': net_volume.rolling(20).mean() / std(net_volume, 20),
'sharpe60_net_volume': net_volume.rolling(60).mean() / std(net_volume, 60),
'sharpe5_balance_index': balance_index.rolling(5).mean() / std(balance_index, 5),
'sharpe10_balance_index': balance_index.rolling(10).mean() / std(balance_index, 10),
'sharpe20_balance_index': balance_index.rolling(20).mean() / std(balance_index, 20),
'sharpe60_balance_index': balance_index.rolling(60).mean() / std(balance_index, 60),
'sharpe5_buy_sell_ratio': buy_sell_ratio.rolling(5).mean() / std(buy_sell_ratio, 5),
'sharpe10_buy_sell_ratio': buy_sell_ratio.rolling(10).mean() / std(buy_sell_ratio, 10),
'sharpe20_buy_sell_ratio': buy_sell_ratio.rolling(20).mean() / std(buy_sell_ratio, 20),
'sharpe30_buy_sell_ratio': buy_sell_ratio.rolling(30).mean() / std(buy_sell_ratio, 30),
'sharpe60_buy_sell_ratio': buy_sell_ratio.rolling(60).mean() / std(buy_sell_ratio, 60),
}
from finlab.tools.factor_analysis import ic
adj_close = data.get('etl:adj_close')
ics = ic(feature_dfs, adj_close, days=[10, 20, 60])
上圖中可以發現,最終做出來的指標,其 IC 最高,高達 0.04,其中一種指標,雖然表現並不是非常理想,但用選股策略上非常有效果,我把它叫做「主力波動指標」。
主力波動與穩定性
主力常常上攻後又迅速熄火,讓投資者難以捕捉到持續的上漲機會。甚至是隔日沖主力,常常當天買、隔天賣,使得券商分點特別難用。為了克服這一問題,我們需要構建一個更為有效的指標,以更準確地識別市場中的主力動向,特別是穩定買入、持續買入的主力,並提高投資決策的穩定性。
指標的需求
指標必須滿足以下需求:
- 主力買賣比率:滾動平均值(rolling mean)能夠平滑短期波動,使得我們能夠觀察到買賣比率的中期趨勢。通過計算10日滾動平均值,我們可以避免因單日大幅波動而帶來的誤判,更清晰地看到市場主力的買入行為。
- 買入波動性:標準差(std)是衡量數據波動性的重要指標。當買賣比率的標準差較低時,意味著買賣比率在這段時間內波動較小,主力行為相對穩定。低波動性通常表明市場中存在持續且穩定的買入或賣出行為。
- 識別持續買入:該指標將滾動平均值與標準差進行比值計算,即買賣比率的均值除以其標準差。當這個比值較高時,說明在這段時間內,買賣比率不僅處於較高水準,且波動較小,這表明市場中可能存在持續且穩定的買入行為。這些行為通常是由市場主力資金推動的,因為他們在積極且穩定地買入股票,從而推高買賣比率並保持其穩定性。
公式如下
買賣比率 = 前 15 大主力買入 / 前 15 大主力賣出
主力波動 = 買賣比率的10日平均 / 買賣比率的10日標準差
效果
當該指標數值較高時,說明在過去的10日內,主力買入大量且不輕易變化,這表明市場中可能存在持續且穩定的買入行為,這些行為通常由主力資金推動。相反,若該指標數值較低,則表示買賣比率波動較大且不穩定,市場中可能缺乏持續的買入力量、或是有隔日沖的行為。
該指標能夠獲得非常高的 IC,並且利用該指標,可以輕易做出效果顯著的策略。
回測
以下是一個簡單的回測範例,展示如何通過籌碼分點資料來進行策略回測,我們利用「主力波動指標」為主體,月營收YOY為輔助,來尋找短期具有爆發力的股票標的。值得一提的是,這個策略當前並非最佳解,還有很多種方式可以大幅優化此策略的效果,建議讀者可以稍做調整,而非直接使用。
import datetime
from finlab.dataframe import FinlabDataFrame
from finlab.backtest import sim
ind = FinlabDataFrame(feature_dfs['sharpe10_buy_sell_ratio'])
close = data.get('price:收盤價')
volume = data.get('price:成交股數')
rev = data.get('monthly_revenue:當月營收')
# 1. 尋找月營收YOY大於1.5的股票標的
# 2. 成交量來到 300 張,確保流動性
# 3. 以主力波動指標進行排序,選最高的 20 檔
pos = (ind)[(rev / rev.shift(12) > 1.5)
& (volume > 300_000)
].is_largest(20)
r = sim(pos, resample=rev.index)