開始使用
10 分鐘寫出第一個策略
本頁內容1
這一頁用一個完整的策略,帶你走過 FinLab 策略開發的精華功能:取得資料 → 寫進出場條件 → 回測與分析 → 上傳。照順序執行,後面的程式會用到前面算好的變數。還沒安裝 FinLab 的話,先看快速上手。
- 1 取得資料
data.get('price:收盤價')日期 × 股票的一張表
- 2 寫條件
close > close.average(60)True=那天要持有
- 3 回測
sim(position, resample='M')報酬、回撤、每筆交易
- 4 上線
PortfolioSyncManager每天更新、自動下單
這一頁要寫的策略是:價格 > 20 日均線進場,價格 < 60 日均線出場,最多持有 10 檔;超過 10 個進場訊號時,以股價淨值比小的股票優先選入。
匯入套件
from finlab import data
from finlab.backtest import sim取得資料
data.get() 可以取得各種時間序列資料,回傳的 DataFrame 以日期為索引、股票代號為欄位:
from finlab import data
pb = data.get('price_earning_ratio:股價淨值比')
close = data.get('price:收盤價')
close.iloc[:5, :5]部分資料(如公司基本資訊)不是時間序列,而是每間公司一列的靜態資料表:
company_basic_info = data.get('company_basic_info')
company_basic_info.head(3)寫進出場條件
entries 是進場訊號,exits 是出場訊號。entries.hold_until(exits) 的意思是:進場訊號為 True 時買入並持有該檔股票,直到出場訊號為 True 才賣出。這大概是所有策略撰寫中最重要的語法糖。
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)close > sma20 這種比較會逐格比較兩張表,得到同樣形狀的 True/False 表。下圖以收盤價和 60 日均線為例:
close 收盤價 | 2330 | 2317 | 2454 | |
|---|---|---|---|
| 10/27 | 98 | 51 | 120 |
| 10/28 | 101 | 50 | 118 |
| 10/29 | 104 | 49 | 121 |
| 10/30 | 103 | 52 | 117 |
close.average(60) 60 日均線 | 2330 | 2317 | 2454 | |
|---|---|---|---|
| 10/27 | 100 | 52 | 115 |
| 10/28 | 100 | 51 | 116 |
| 10/29 | 101 | 51 | 117 |
| 10/30 | 101 | 51 | 118 |
position 要持有的股票 | 2330 | 2317 | 2454 | |
|---|---|---|---|
| 10/27 | False | False | True |
| 10/28 | True | False | True |
| 10/29 | True | False | True |
| 10/30 | True | True | False |
hold_until 可以讓你最多選 N 檔股票做輪動;超過 N 檔進場訊號時,按照自訂的排序選擇優先選入的股票;還能另外設定停損停利,增加出場的時機點。上面的程式設了最多 10 檔、用 -pb 排序(rank 數字越大越優先,加負號就是股價淨值比越小越優先),並在上漲 40% 時停利。
| 參數 | 型別 | 說明 |
|---|---|---|
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 數字越大的股票優先進場 |
完整參數請看 FinlabDataFrame API。
回測並顯示報告
from finlab.backtest import sim
backtest_report = sim(position, upload=False)
# 台股 Market 已提供加權報酬指數作為預設比較基準
backtest_report.display()看報酬、持股與交易紀錄
報酬率序列:
backtest_report.creturn近期持有部位與預期換股資訊:
backtest_report.position_info()get_trades() 回傳每一筆交易的進出場資訊:
trade_record = backtest_report.get_trades()
trade_record.head(5)| 欄位 | 說明 |
|---|---|
entry_sig_date | 進場訊號產生日 |
exit_sig_date | 出場訊號產生日 |
entry_date | 進場日 |
exit_date | 出場日 |
period | 持有天數 |
position | 持有佔比 |
return | 報酬率 |
mdd | 持有期間最大回撤 |
mae | 持有期間最大不利幅度 |
gmfe | 持有期間最大有利幅度 |
bmfe | mae 發生前的最大有利幅度 |
用交易紀錄畫出報酬率分佈,可以看出策略的獲利與虧損分佈狀況:
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,
)檢查流動性風險
LiquidityAnalysis 檢查交易紀錄中,進出場成交張數大於指定門檻的比例,以及成交金額大於指定門檻的比例,用來檢測資金部位的胃納量:
from finlab.analysis.liquidityAnalysis import LiquidityAnalysis
backtest_report.run_analysis(
LiquidityAnalysis(required_volume=100000, required_turnover=1000000)
)看統計指標
get_stats() 取得夏普率、索提諾比率、最大回檔、近期報酬率統計等數據:
backtest_report.get_stats()| 指標 | 怎麼看 |
|---|---|
| 夏普值(Sharpe) | 小於零代表賠錢。以簡易的選股策略來說,一般人波段實單操作可能是 0.7;以 ETF 來說,0.9 就已經很不錯;網路上的付費選股策略,1.3 可能是比較理想的數值。也有真的很厲害的選股策略,Sharpe 可以到 2 或 3。 |
| 獲利峰態(kurt) | 跟一般的高斯分佈比較,比高斯分佈更尖則 kurt 越高,通常代表策略績效越穩定。一般股票的大盤 kurt 大約在 1~2,大於 2 算是勉強堪用,5 以上就算還不錯。 |
| 偏態 | 也是跟高斯分佈比較,越偏向右邊越小,通常 -0.5 以下算是勉強堪用,-1 左右算是還不錯。 |
上傳策略,每天自動更新
sim 的參數 upload 預設是 None:只有在雲端排程、或在 Studio 網頁手動執行筆記本時才會上傳;其他地方(自己的電腦、Colab)要在平台上顯示選股清單,請明確設定 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')下一步
- 策略常用的 Pandas 語法 篩選、運算、移動窗格與畫圖,寫條件前先熟悉。
- 寫選股條件 hold_until、is_largest 等選股函式的完整用法。
- 歷史回測 換股頻率、停損停利、交易紀錄與波動分析。
- 每天自動更新策略 讓策略每天重跑,換股日收到通知。
這一頁有幫到你嗎?