跳轉到

策略開發 10 分鐘上手

想快速了解 FinLab 策略開發工具的精華功能嗎?看這份範例就對了。

1. 安裝套件

from finlab import data
from finlab.backtest import sim

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. 非時間序列

部分資料(如公司基本資訊)不是時間序列格式,而是以每間公司為一列的靜態資料表。

company_basic_info = data.get('company_basic_info')
company_basic_info.head(3)

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 停損停利參考價。可選 closeopen
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. 取得報酬率序列

backtest_report.creturn

4-3. 取得近期持有部位與預期換股資訊

backtest_report.position_info()

4-4. 取得交易紀錄

get_trades() 回傳一個 DataFrame,包含每一筆交易的進出場資訊。以下是重點欄位說明:

欄位 說明
entry_sig_date 進場訊號產生日
exit_sig_date 出場訊號產生日
entry_date 進場日
exit_date 出場日
period 持有天數
position 持有佔比
return 報酬率
mdd 持有期間最大回撤
mae 持有期間最大不利幅度
gmfe 持有期間最大有利幅度
bmfe mae 發生前的最大有利幅度
trade_record = backtest_report.get_trades()
trade_record.head(5)

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 左右算是還不錯。

backtest_report.get_stats()

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')