API 參考
finlab.report
本頁內容9
backtest.sim() 回測完會回傳一個 Report 物件,裡面有整段回測的淨值、績效指標和每一筆交易。這一頁列出 Report 的所有方法:看報告、取數字、查交易、深入分析、存檔與上傳。
from finlab import data
from finlab.backtest import sim
# 建立策略並回測
close = data.get('price:收盤價')
position = close > close.average(20)
# 產生回測報告
report = sim(position, resample='M')
# 顯示報告(包含視覺化圖表)
report.display()選哪個函式
| 你想做的事 | 用這個 |
|---|---|
| 看完整的互動報告 | report.display() |
| 拿到年化報酬、夏普率等數字(dict) | report.get_stats() |
| 拿到分好類的績效指標(巢狀 dict) | report.get_metrics() |
| 看每一筆交易(DataFrame) | report.get_trades() |
| 看每筆交易最多賠、最多賺多少(MAE/MFE) | report.get_mae_mfe()、report.display_mae_mfe_analysis() |
| 看近期持股與換股資訊 | report.position_info() |
| 上傳到 FinLab 雲端追蹤實盤 | report.upload() |
| 跑流動性、選股能力、持股分布等深入分析 | report.run_analysis() |
| 用白話讀策略體檢 | report.to_checkup_text()、report.get_checkup() |
| 產生文字摘要,發通知或寫日誌 | report.to_text() |
| 在終端機看報酬曲線 | report.to_terminal() |
| 存成 HTML,用瀏覽器打開 | report.to_html() |
| 存檔,之後再載入 | report.to_pickle()、Report.from_pickle() |
| 換掉比較基準(benchmark) | 自訂 Market 的 get_benchmark() |
看報告
report.display()
顯示完整的回測報告,包含視覺化圖表與績效指標。
report.display()
# 將互動式報告存成 HTML 檔
report.to_html('report.html')報告內容包括:
- 淨值曲線(策略 vs 基準)
- 回撤曲線
- 績效指標表格(年化報酬、夏普率、最大回撤等)
報告是在 notebook 中顯示的互動式儀表板,不是 plotly figure。在 IPython 以外(一般 Python 腳本)執行時,display() 會印出文字摘要;請用 report.to_html('report.html') 存檔後以瀏覽器開啟。
下面是一份範例策略的報告,可以直接在上面操作:
report.to_html()
把互動式報告存成獨立的 HTML 檔,可指定瀏覽器分頁標題。
report.to_html('report.html', title='我的動能策略')| 參數 | 型別 | 預設 | 說明 |
|---|---|---|---|
path | str | 必填 | 輸出的 HTML 檔案路徑 |
title | str 或 None | None | 瀏覽器分頁標題;不指定時為 FinLab Report |
report.to_terminal()
在終端機用 ASCII 圖表顯示累積報酬與回撤。
report.to_terminal()
# 自訂高度與寬度
report.to_terminal(height=8, width=60)
# 不顯示 benchmark 和 drawdown
report.to_terminal(show_benchmark=False, show_drawdown=False)| 參數 | 型別 | 預設 | 說明 |
|---|---|---|---|
height | int | 12 | 圖表高度 |
width | int | 80 | 圖表寬度 |
show_benchmark | bool | True | 是否畫出比較基準 |
show_drawdown | bool | True | 是否顯示回撤 |
需要先安裝 asciichartpy:pip install 'finlab[terminal]'。
取得績效數字
report.get_stats()
取得績效統計,回傳 dict。
stats = report.get_stats()
print(f"回測期間: {stats['start']} ~ {stats['end']}")
print(f"年化報酬: {stats['cagr'] * 100:.2f}%")
print(f"夏普率: {stats['daily_sharpe']:.2f}")
print(f"索提諾比率: {stats['daily_sortino']:.2f}")
print(f"最大回撤: {stats['max_drawdown'] * 100:.2f}%")
print(f"平均回撤: {stats['avg_drawdown'] * 100:.2f}%")
print(f"勝率: {stats['win_ratio'] * 100:.2f}%")| 參數 | 型別 | 預設 | 說明 |
|---|---|---|---|
riskfree_rate | float | 0.02 | 無風險利率 |
resample 參數已棄用:它從未生效,現在傳入會發出 DeprecationWarning。統計一律以日頻報酬計算(daily_*、monthly_*、yearly_* 欄位已涵蓋各頻率)。
主要回傳欄位:
| 欄位 | 說明 |
|---|---|
start | 回測開始日期(str) |
end | 回測結束日期(str) |
cagr | 年化報酬率(CAGR) |
daily_mean | 日報酬算術平均 × 252,不是年化報酬率 |
daily_sharpe | 夏普率 |
daily_sortino | 索提諾比率 |
max_drawdown | 最大回撤 |
avg_drawdown | 平均回撤 |
win_ratio | 勝率 |
return_table | 年月報酬率表(dict) |
drawdown_details | 最大回撤詳情 |
以下欄位也能用 get_metrics() 的名稱取得,兩種寫法結果相同:
get_stats() 欄位 | 別名(get_metrics() 名稱) |
|---|---|
cagr | annualReturn |
daily_sharpe | sharpeRatio |
daily_sortino | sortinoRatio |
calmar | calmarRatio |
daily_vol | volatility |
max_drawdown | maxDrawdown |
avg_drawdown | avgDrawdown |
avg_drawdown_days | avgDrawdownDays |
twelve_month_win_perc | m12WinRate |
win_ratio 沒有別名:它只計算已出場的交易,get_metrics() 的 winRate 則包含持有中的交易。
report.get_metrics()
取得分好類的績效指標(巢狀 dict),適合上傳雲端或在程式裡處理。
metrics = report.get_metrics()
# 盈利指標
print(f"年化報酬: {metrics['profitability']['annualReturn']:.2%}")
print(f"Alpha: {metrics['profitability']['alpha']:.4f}")
print(f"Beta: {metrics['profitability']['beta']:.4f}")
# 風險指標
print(f"最大回撤: {metrics['risk']['maxDrawdown']:.2%}")
print(f"VaR: {metrics['risk']['valueAtRisk']:.2%}")
# 比率指標
print(f"夏普率: {metrics['ratio']['sharpeRatio']:.2f}")
print(f"索提諾比率: {metrics['ratio']['sortinoRatio']:.2f}")
# 勝率指標
print(f"勝率: {metrics['winrate']['winRate']:.2%}")| 參數 | 型別 | 預設 | 說明 |
|---|---|---|---|
stats_ | dict 或 None | None | 回測結果的統計數據;None 時自動計算 |
riskfree_rate | float | 0.02 | 無風險利率 |
回傳的分類與欄位:
| 分類 | 欄位 | 說明 |
|---|---|---|
backtest | startDate, endDate, feeRatio, taxRatio, tradeAt, market, freq | 回測設定 |
profitability | annualReturn, alpha, beta, avgNStock, maxNStock | 盈利指標 |
risk | maxDrawdown, avgDrawdown, avgDrawdownDays, valueAtRisk, cvalueAtRisk | 風險指標 |
ratio | sharpeRatio, sortinoRatio, calmarRatio, volatility, profitFactor, tailRatio | 比率指標 |
winrate | winRate, m12WinRate, expectancy, mae, mfe | 勝率指標 |
liquidity | capacity, disposalStockRatio, warningStockRatio, fullDeliveryStockRatio | 流動性指標(僅台灣市場) |
report.to_checkup_text() / report.get_checkup()
用白話列出策略體檢:五類摘要、各項指標說明與達標判定,不開啟瀏覽器。
print(report.to_checkup_text()) # 五類白話摘要、各項指標說明與達標判定
checkup = report.get_checkup() # 相同內容的 dict,可程式化讀取
print(report.to_checkup_text(lang="en"))| 參數 | 型別 | 預設 | 說明 |
|---|---|---|---|
lang | str | 'zh-tw' | 'zh-tw' 或 'en' |
內容與 HTML 策略體檢共用定義。categories 每類含 question、summary、health_label、passed、total 與 checks;每項檢查含 key、name、explanation、value、formatted、rule、target、passed、status。
- 資料不足時
value為None、status為insufficient_data,不計為通過。 - 未提供的指標不列入檢查;空交易會有明確提示;流動性僅於支援的台灣市場列出。
get_metrics()仍回傳原有數值,不包含這些文字。
查交易紀錄
report.get_trades()
取得所有交易紀錄,回傳 pd.DataFrame,一列是一筆交易。
trades = report.get_trades()
# 分析交易表現
print(f"總交易次數: {len(trades)}")
print(f"平均報酬率: {trades['return'].mean():.2%}")
print(f"勝率: {(trades['return'] > 0).mean():.2%}")
# 篩選大賺或大賠的交易
big_wins = trades[trades['return'] > 0.2]
big_losses = trades[trades['return'] < -0.1]
# 按股票統計
trades_by_stock = trades.groupby('stock_id')['return'].agg(['count', 'mean'])
print(trades_by_stock.sort_values('mean', ascending=False).head())| 欄位 | 說明 |
|---|---|
stock_id | 股票代號(只有代號,例如 2330) |
name | 股票名稱(例如 台積電;查無名稱時為空字串) |
symbol | 代號加名稱(例如 2330 台積電),為相容舊程式保留 |
entry_sig_date | 進場訊號產生日 |
exit_sig_date | 出場訊號產生日 |
entry_date | 進場日 |
exit_date | 出場日 |
position | 持有佔比 |
period | 持有天數 |
return | 報酬率 |
trade_price@entry_date | 進場價 |
trade_price@exit_date | 出場價 |
mae | 持有期間最大不利報酬率幅度 |
gmfe | 持有期間最大有利報酬率幅度 |
bmfe | mae 發生前的最大有利報酬率幅度 |
mdd | 持有期間最大回撤 |
pdays | 處於獲利時的天數 |
industry | 產業別 |
report.get_mae_mfe()
取得每筆交易的最大不利偏移(MAE)與最大有利偏移(MFE)。
mae_mfe = report.get_mae_mfe()MAE/MFE 可以用來:
- 設定停損點:觀察 MAE 分布,決定合理的停損幅度
- 設定停利點:觀察 MFE 分布,決定合理的停利幅度
- 優化進出場:若 MFE 大但最終報酬小,表示停利過晚
report.display_mae_mfe_analysis()
畫出 MAE/MFE 波動分析圖組,等同 report.run_analysis('MaeMfeAnalysis')。
report.display_mae_mfe_analysis()report.position_info()
取得近期持有部位與換股資訊。
info = report.position_info()回傳 dict:每檔股票一筆,含 status、weight、next_weight、entry_date、exit_date、return、entry_price;另有 update_date、next_trading_date、trade_at、freq、market、stop_loss、take_profit 等欄位。
深入分析
report.run_analysis()
執行策略分析外掛模組,例如流動性、Alpha/Beta、各時期績效與回撤。
# 傳入分析模組名稱(字串)
report.run_analysis('Liquidity')
report.run_analysis('MaeMfe')
report.run_analysis('AlphaBeta')
report.run_analysis('PeriodStats')
report.run_analysis('Drawdown')
# 不顯示圖表,只取得結果
result = report.run_analysis('Liquidity', display=False)| 參數 | 型別 | 預設 | 說明 |
|---|---|---|---|
analysis | str 或分析物件 | 必填 | 分析模組名稱(結尾的 Analysis 可省略),或分析模組的物件 |
display | bool | True | True 時顯示圖表;False 時只回傳分析結果 |
**kwargs | 用名稱傳入時,交給該分析模組的參數 |
各模組的參數與輸出請見 finlab.analysis。
存檔、分享與上傳
report.to_text()
把回測報告整理成文字,適合 Line 通知、日誌記錄等場景。
text = report.to_text(name='我的策略')
print(text)| 參數 | 型別 | 預設 | 說明 |
|---|---|---|---|
name | str 或 None | None | 策略名稱;不指定時為「未命名」 |
report.to_pickle() / Report.from_pickle()
把報告存成檔案,之後再載入,不必重跑回測。
# 儲存報告
report.to_pickle('my_strategy_report.pkl')
# 載入報告
from finlab.core.report import Report
loaded_report = Report.from_pickle('my_strategy_report.pkl')
loaded_report.display()適合這些時候:回測要跑很久、想保存結果;要對比不同時期的回測報告;要與他人分享回測結果。
report.upload()
上傳回測報告至 FinLab 雲端,供實盤追蹤使用。
# 上傳報告
report.upload(name='我的動能策略')
# 之後可在 FinLab 網站查看:
# https://ai.finlab.tw/strategies| 參數 | 型別 | 預設 | 說明 |
|---|---|---|---|
name | str 或 None | None | 策略名稱 |
自訂比較基準
在回測前繼承策略所用的 Market(例如 TWMarket),覆寫 get_benchmark() 回傳日期索引的價格或累積淨值 Series,再以 market= 傳入 sim()。以下以還原後的 0050 價格為基準:
from finlab import data
from finlab.backtest import sim
from finlab.markets.tw import TWMarket
class ETFBenchmarkMarket(TWMarket):
@staticmethod
def get_benchmark():
return data.get("etl:adj_close")["0050"]
close = data.get("price:收盤價")
position = close > close.average(20)
report = sim(position, market=ETFBenchmarkMarket(), resample="M", upload=False)
report.display()- 請回傳涵蓋回測期間的價格或累積淨值,不要傳入每日報酬率。
- 更換基準時,請用新的 Market 重跑
sim();回測後直接指定report.benchmark = ...,不會同步更新所有圖表與統計。 - 美股策略可同樣繼承
USMarket或USFundMarket(例如回傳data.get("us_fund_price:adj_close")["SPY"])。
get_benchmark() 的完整規格請見 finlab.market 與自訂市場物件。
常見問題
如何對比多個策略的績效?
把幾份報告的 get_stats() 放進同一張表:
# 兩個策略:站上 20 日均線、站上 60 日均線
position1 = close > close.average(20)
position2 = close > close.average(60)
report1 = sim(position1, resample='M')
report2 = sim(position2, resample='M')
stats1 = report1.get_stats()
stats2 = report2.get_stats()
import pandas as pd
comparison = pd.DataFrame(
{
'策略 A': {
'年化報酬': stats1['cagr'],
'夏普率': stats1['daily_sharpe'],
'最大回撤': stats1['max_drawdown'],
},
'策略 B': {
'年化報酬': stats2['cagr'],
'夏普率': stats2['daily_sharpe'],
'最大回撤': stats2['max_drawdown'],
},
}
)
print(comparison)要一次比較很多份,可以用 finlab.optimize 的 ReportCollection。
為什麼我的報告顯示不出來?
# 原因 1:忘記呼叫 .display()
report # ❌ 不會顯示
report.display() # ✅ 正確
# 原因 2:Jupyter Notebook 環境問題
# 在 notebook 開頭加入:
%matplotlib inline
# 原因 3:資料為空(無任何交易)
trades = report.get_trades()
if len(trades) == 0:
print("策略無任何交易記錄,請檢查進場條件")在一般 Python 腳本裡,display() 只會印出文字摘要,請改用 report.to_html() 存檔後用瀏覽器開啟。
如何調整報告的視覺化樣式?
報告的版面是固定的。要自訂樣式,請用 plotly 自己畫報告的資料:
import plotly.graph_objects as go
fig = go.Figure()
fig.add_scatter(
x=report.daily_creturn.index,
y=report.daily_creturn,
name='策略',
line_color='blue',
)
fig.add_scatter(
x=report.daily_benchmark.index,
y=report.daily_benchmark,
name='基準',
line_color='gray',
)
# 修改標題與圖表大小
fig.update_layout(title='我的策略回測報告', width=1200, height=600)
fig.show()下一步
- 歷史回測 完整回測流程、績效指標解讀與交易紀錄分析。
- finlab.analysis 流動性、MAE/MFE、各時期績效等深入分析工具。
- finlab.portfolio 把多份報告組成一個投資組合。
- 完整策略開發流程 從研究、回測到實盤的端到端步驟。
這一頁有幫到你嗎?