策略開發 10 分鐘上手
想快速了解 FinLab 策略開發工具的精華功能嗎?看這份範例就對了。
1. 安裝套件
2. 取得資料
2-1. 時間序列
使用 data.get() 可以取得各種時間序列資料,回傳的 DataFrame 以日期為索引、股票代號為欄位。
from finlab import data
pb = data.get('price_earning_ratio:股價淨值比')
close = data.get('price:收盤價')
close.iloc[:5, :5]
2-2. 非時間序列
部分資料(如公司基本資訊)不是時間序列格式,而是以每間公司為一列的靜態資料表。
3. 撰寫策略
3-1. 策略條件
價格 > 20 日均線入場,價格 < 60 日均線出場,最多持有 10 檔,超過 10 個進場訊號,則以股價淨值比小的股票優先選入。
3-2. hold_until function
這大概是所有策略撰寫中,最重要的語法糖。上述語法中 entries 為進場訊號,而 exits 是出場訊號。所以 entries.hold_until(exits) ,就是進場訊號為 True 時,買入並持有該檔股票,直到出場訊號為 True 則賣出。
此函式有很多細部設定,可以讓你最多選擇 N 檔股票做輪動。另外,當超過 N 檔進場訊號發生,也可以按照客制化的排序,選擇優先選入的股票。最後,可以額外設定停損停利,來增加出場的時機點。以下是 hold_until 的參數說明:
| 參數 | 型別 | 說明 |
|---|---|---|
exit |
pd.DataFrame |
出場訊號 |
nstocks_limit |
int |
持有檔數上限 |
stop_loss |
float |
停損基準。範例:0.1,代表成本價下跌 10% 時出場 |
take_profit |
float |
停利基準。範例:0.1,代表成本價上漲 10% 時出場 |
trade_at |
str |
停損停利參考價。可選 close 或 open |
rank |
pd.DataFrame |
當天進場訊號超過 nstocks_limit 時,以 rank 數字越大的股票優先進場 |
from finlab import data
from finlab.backtest import sim
close = data.get('price:收盤價')
pb = data.get('price_earning_ratio:股價淨值比')
sma20 = close.average(20)
sma60 = close.average(60)
entries = close > sma20
exits = close < sma60
position = entries.hold_until(exits, nstocks_limit=10, rank=-pb, take_profit=0.4)
backtest_report = sim(position, upload=False)
4. 回測
4-1. 顯示策略回測結果
from finlab.backtest import sim
backtest_report = sim(position, upload=False)
# 新增對標的指數,你的策略能贏大盤嗎?
backtest_report.benchmark = data.get('benchmark_return:發行量加權股價報酬指數').squeeze()
backtest_report.display()
4-2. 取得報酬率序列
4-3. 取得近期持有部位與預期換股資訊
4-4. 取得交易紀錄
get_trades() 回傳一個 DataFrame,包含每一筆交易的進出場資訊。以下是重點欄位說明:
| 欄位 | 說明 |
|---|---|
entry_sig_date |
進場訊號產生日 |
exit_sig_date |
出場訊號產生日 |
entry_date |
進場日 |
exit_date |
出場日 |
period |
持有天數 |
position |
持有佔比 |
return |
報酬率 |
mdd |
持有期間最大回撤 |
mae |
持有期間最大不利幅度 |
gmfe |
持有期間最大有利幅度 |
bmfe |
mae 發生前的最大有利幅度 |
4-5. 交易紀錄應用 - 繪製報酬率分佈
利用交易紀錄,可以繪製報酬率分佈圖,了解策略的獲利與虧損分佈狀況。
import plotly.express as px
trade_record['profit_loss'] = trade_record['return'].apply(lambda s: 'profit' if s > 0 else 'loss')
win_ratio = round(sum(trade_record['profit_loss'] == 'profit') / len(trade_record['profit_loss']) * 100, 2)
return_mean = round(trade_record['return'].mean(), 2)
fig = px.histogram(trade_record, x="return", color="profit_loss", title=f'profit_loss_hist - win_ratio: {win_ratio} %')
fig.add_vline(x=return_mean, line_width=3, line_dash="dash", line_color="green",
annotation_position="top left",
annotation_text=f'avg_return:{return_mean}', row=1, col=1)
4-6. 策略流動性風險檢測
使用 LiquidityAnalysis 可以檢測策略的流動性風險,包含交易紀錄進出場成交張數大於指定門檻的比例,以及成交金額大於指定門檻的比例,用來檢測資金部位胃納量。
from finlab.analysis.liquidityAnalysis import LiquidityAnalysis
backtest_report.run_analysis(LiquidityAnalysis(required_volume=100000, required_turnover=1000000))
4-7. 取得策略統計指標
取得數據如夏普率、索提諾比率、最大回檔、近期報酬率統計等。
策略指標解析:
夏普值 (Sharpe):小於零代表賠錢。以一個簡易的選股策略來說,一般人波段實單操作可能是 0.7;以 ETF 來說,0.9 就已經很不錯了;而以網路上付費選股策略,1.3 可能會是比較理想的數值。當然也有真的很厲害的選股策略,Sharpe 可以到 2 或 3。
獲利峰態 (kurt):跟一般的高斯分佈做比較,比高斯分佈更尖則 kurt 越高,通常代表策略績效越穩定。一般股票而言大盤的 kurt 大約在 1~2 左右,大於 2 基本上算是勉強堪用,5 以上就算還不錯。偏態的話也是跟高斯分佈比較,越偏向右邊越小,通常 -0.5 以下算是勉強堪用,-1 左右算是還不錯。
5. 上傳 strategy
sim 中的參數 upload 預設為 True,執行完回測後會在平台網頁上顯示選股清單。
複製下列程式碼,貼到 FinLab 量化平台,即可設定每日自動更新策略清單。
from finlab import data
from finlab.backtest import sim
close = data.get('price:收盤價')
pb = data.get('price_earning_ratio:股價淨值比')
sma20 = close.average(20)
sma60 = close.average(60)
entries = close > sma20
exits = close < sma60
position = entries.hold_until(exits, nstocks_limit=10, rank=-pb, take_profit=0.4)
sim(position, name='策略教學範例:pb_ma')