文件
開啟 Studio

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='我的動能策略')
參數型別預設說明
pathstr必填輸出的 HTML 檔案路徑
titlestr 或 NoneNone瀏覽器分頁標題;不指定時為 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)
參數型別預設說明
heightint12圖表高度
widthint80圖表寬度
show_benchmarkboolTrue是否畫出比較基準
show_drawdownboolTrue是否顯示回撤

需要先安裝 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_ratefloat0.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() 名稱)
cagrannualReturn
daily_sharpesharpeRatio
daily_sortinosortinoRatio
calmarcalmarRatio
daily_volvolatility
max_drawdownmaxDrawdown
avg_drawdownavgDrawdown
avg_drawdown_daysavgDrawdownDays
twelve_month_win_percm12WinRate

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 或 NoneNone回測結果的統計數據;None 時自動計算
riskfree_ratefloat0.02無風險利率

回傳的分類與欄位:

分類欄位說明
backteststartDate, endDate, feeRatio, taxRatio, tradeAt, market, freq回測設定
profitabilityannualReturn, alpha, beta, avgNStock, maxNStock盈利指標
riskmaxDrawdown, avgDrawdown, avgDrawdownDays, valueAtRisk, cvalueAtRisk風險指標
ratiosharpeRatio, sortinoRatio, calmarRatio, volatility, profitFactor, tailRatio比率指標
winratewinRate, m12WinRate, expectancy, mae, mfe勝率指標
liquiditycapacity, 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"))
參數型別預設說明
langstr'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持有期間最大有利報酬率幅度
bmfemae 發生前的最大有利報酬率幅度
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)
參數型別預設說明
analysisstr 或分析物件必填分析模組名稱(結尾的 Analysis 可省略),或分析模組的物件
displayboolTrueTrue 時顯示圖表;False 時只回傳分析結果
**kwargs用名稱傳入時,交給該分析模組的參數

各模組的參數與輸出請見 finlab.analysis。

存檔、分享與上傳

report.to_text()

把回測報告整理成文字,適合 Line 通知、日誌記錄等場景。

text = report.to_text(name='我的策略')
print(text)
參數型別預設說明
namestr 或 NoneNone策略名稱;不指定時為「未命名」

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
參數型別預設說明
namestr 或 NoneNone策略名稱

自訂比較基準

在回測前繼承策略所用的 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()

下一步

↑↓ 選擇 Enter 開啟 Esc 關閉