很多人在策略上線後會擔心策略失效,這樣的擔心是沒有意義的,因為很多事你無法控制,可能一個漲跌幅再放寬,就一堆策略波動規律改變。
真正重要的是你有沒有能力研發與調整策略,有能力的話,你就不會害怕局勢變化,腦袋終有應變方法,這個能力容不容易培養?
老實說,從 0 到 1 很難,不是很吃交易經驗,就是很吃資料科學的能力,兩者都很難速成。要速成就要站在巨人的研究基礎上,再加上一點點資料分析的能力,就有機會有小成。
本篇將教你從「菲式思考」最後一個章節「嘉實XQ內建策略回測之探討」取範例,照著「反思菲式思考 Part.2|策略回測探討」的SOP,來實作策略優化與分析的邏輯,結合 FinLab 量化平台的分析工具,打造出屬於自己的策略。
可能恢復信用交易的個股
參考自「菲式思考」p.299 策略 617。這個策略帶有基本面、籌碼面、事件面的因素,當股票的每股淨值翻到 10 元以上,就能擁有信用交易的資格,資金調度變靈活,有機會吸引投機買盤進場,讓股價往上衝,同時這也代表基本面可能有復甦跡象,一般來說「每股淨值」在 10 元以下的公司都有成長性或財務狀況不穩的狀況,若每股淨值在之後翻到 10 元以上,可能代表營運趨勢改變,會吸引看好轉機的買盤。
不論是恢復或是停止信用交易,都會在每季財報公告截止日後五個工作天進行審核是否恢復信用交易,若是在事前押寶成功,標地真的恢復信用交易,可能買盤力道強,反之押寶失敗,未如情況恢復信用交易,可能基本面仍不夠好,會引發失望賣壓。
書中選股條件
- 每股淨值介於 9~10元之間。
- 近一季營業利益率 > 0。
- 月營收月增率 > 5%。
- 近 3 個月月營收月增率平均 > 5%。
- 使用30天交易日回測。
FinLab 回測驗證
程式碼
from finlab import data
from finlab.backtest import sim
收盤價 = data.get('price:收盤價')
股價淨值比 = data.get('price_earning_ratio:股價淨值比')
每股淨值 = 收盤價/股價淨值比
營業利益率 = data.get('fundamental_features:營業利益率').deadline()
月營收月增率 = data.get('monthly_revenue:上月比較增減(%)')
c1 = (9 <= 每股淨值) & (每股淨值 < 10)
c2 = 營業利益率 > 0
c3 = 月營收月增率 > 5
c4 = 月營收月增率.average(3) > 5
position = c1 & c2 & c3 & c4
report = sim(position, resample='M', upload=False)
report.display()
回測結果
報酬率與波動
流動性風險
回測交叉比對
由於 FinLab 財報資料庫因要統一 IFRS 會計欄位,資料從 2013 開始,和 XQ 會有差異。
跑出來的數據發現平均年化報酬率、MDD(最大回撤)、勝率 都要比 XQ 回測的結果要差,這可能和書中部分條件定義不清或資料差異所導致。
FinLab 回測結果和 XQ 回測結果近似的地方在該策略的交易次數不多,只有 200多次 ,是比較少見的事件,策略報酬曲線類似,主要報酬都是靠近3年拉起來,2021年前的績效較不穩定。
優化設定方向
- 交易次數過少:需回測單因子條件,看能否用最少的條件得到最多的次數與回測報酬。由於交易次數少,可能某些月份會有 1~2檔 重壓的情況,讓波動風險難以控制,因此應要設定單檔持股比例上限。
- 波動過大:回檔太大,夏普率不夠高,由於該策略是低每股淨值,低每股淨值很可能也是低價股,因此加入之前研究的低價股策略來降波動,參考「給小資族的禮物|低價股量化策略的實戰訣竅」、「膽小貓策略」。
- 太容易選到流動性很差的標地,有多達 38% 的股票在進出當日的交易張數低於100張,成交金額有 33% 低於 100 萬,大資金難進出。資金較大者,最好多設定成交量或成交金額條件,降低流動性風險。
策略優化
使用策略優化器,找出最佳條件組合,回測統一加上單檔最大持股上限(position_limit)為 20%的設定,避免重壓的運氣成份。多加一個「低價股策略」的「低波動條件」來看看能否降低波動。
from finlab import data
from finlab.backtest import sim
from finlab.optimize.combinations import sim_conditions
收盤價 = data.get('price:收盤價')
股價淨值比 = data.get('price_earning_ratio:股價淨值比')
每股淨值 = 收盤價/股價淨值比
營業利益率 = data.get('fundamental_features:營業利益率').deadline()
月營收月增率 = data.get('monthly_revenue:上月比較增減(%)')
最高價 = data.get("price:最高價")
最低價 = data.get("price:最低價")
成交股數 = data.get("price:成交股數")
c1 = (9 <= 每股淨值) & (每股淨值 < 10)
c2 = 營業利益率 > 0
c3 = 月營收月增率 > 5
c4 = 月營收月增率.average(3) > 5
# 低波動條件
c5 = (1 - 最低價.rolling(60).min()/最高價.rolling(60).max()) < 0.3
conditions = {'c1':c1, 'c2':c2, 'c3':c3, 'c4':c4, 'c5':c5}
report_collection = sim_conditions(conditions=conditions, resample='M', position_limit=0.2, upload=False)
分析結果
優化出的結果「c1 & c2 & c3」這組結果最優,相較書中原本的策略,少加條件 c4 (近 3 個月月營收月增率平均 > 5%)。
原本「c1 & c2 & c3 & c4」的組合再加上單檔最大持股上限後,報酬率巨幅下降到 14.7%! 可見書中原策略的報酬率很可能是重押押對的結果,不可不慎!
持股組合只有「c1 & c2 & c3、 c1 & c2」這兩組報酬率超過 20%,與其他組別拉開差距,比對這兩組合的指標數值。「c1 & c2 & c3」優點是 MDD、avg_mdd (交易對 MDD 平均值),向下波動風險較小,若願意犧牲一點報酬率換取回檔波動的穩定性,可以考慮調整。
你可能會納悶「c1 & c2 & c3」的交易次數比「c1 & c2」多?不是多一個條件嗎?原因在使用營收資料會增加換股的次數,「c1 & c2」的組合持有天期會比較長,持股組合較少異動。
波動分析 & 停損設定
我們取「c1 & c2 & c3」這組策略來做分析,MAE Distribution 建議了兩種停損設定,分別是勝手MAE Q3 的位置 3.68%、敗手MFE Q3 的位置 13.95%。
使用前者通常可以降低 MDD,並有機會提升報酬率,但因為停損較緊,勝率通常也會降低,可能把原本會大賺的標地也移除。若跑出的報酬率、勝率降幅太大則不適用。
使用後者則通常可維持勝率及報酬率,並止血虧損異常大的交易,但由於停損較鬆,MDD改善的機會比前者小。
未設定停損
停損設定4%
年化報酬率、夏普率、MDD、勝率皆下降,整體波動下調,勝率掉特別多。
停損設定14%
年化報酬率、夏普率、勝率皆下降,MDD 微幅上升。
小結
設定停損的會降低策略指標?年化報酬率還下降些了,為什麼會這樣呢?那是因為有些獲利的藍點也有很大的 MAE ,在停損的過程被犧牲掉了。
既然結果變差,可以不設定停損嗎?答案是「還是要設停損」,因為你不知道策略未來失效時會發生什麼事,雖然停損設定讓回測績效變差,但能在未來交易出現不利情況時,有防火牆止掉大幅虧損,避免大賠是交易的第一要務。
最終策略代碼
from finlab import data
from finlab.backtest import sim
收盤價 = data.get('price:收盤價')
股價淨值比 = data.get('price_earning_ratio:股價淨值比')
每股淨值 = 收盤價/股價淨值比
營業利益率 = data.get('fundamental_features:營業利益率').deadline()
月營收月增率 = data.get('monthly_revenue:上月比較增減(%)')
c1 = (9 <= 每股淨值) & (每股淨值 < 10)
c2 = 營業利益率 > 0
c3 = 月營收月增率 > 5
position = c1 & c2 & c3
report = sim(position, resample='M', upload=False, position_limit=0.2, mae_mfe_window=40, stop_loss=0.14)
結論
經過以上的策略優化與檢測邏輯,將「菲式策略」的策略 617「可能恢復信用交易的個股」優化為較穩定的版本,站在巨人的肩膀上開發策略,是不是沒有你想像中的難呢?完整的策略優或過程的程式碼從這裡下載,也可以到量化平台定期追蹤此策略的表現。