文件
開啟 Studio

API 參考

finlab.analysis

本頁內容11

finlab.analysis 從流動性、波動、時期穩定性、超額報酬與回撤幾個角度檢查一份回測,幫你判斷策略能不能真的拿去交易。所有分析都用 report.run_analysis() 執行,想要的檢查沒有內建時,也可以繼承 Analysis 自己寫。

選哪個分析

你想知道的事用這個關鍵輸出
大資金會不會買不到、賣不掉(只限台股)LiquidityAnalysis漲跌停、低成交量、處置股比例
停損停利該設在哪MaeMfeAnalysis12 個子圖(MAE/MFE/勝率/Edge Ratio)
各年度、月度與近期的表現穩不穩PeriodStatsAnalysis年度、月度、近期表現
有沒有超越大盤、跟大盤有多連動AlphaBetaAnalysis超額報酬、市場敏感度
回撤有多深、持續多久DrawdownAnalysis回撤事件、持續時間
加上某個因子門檻後,報酬會怎麼變InequalityAnalysis因子門檻以上與以下的平均交易報酬差
做一個專屬的分析繼承 Analysis由你決定

對回測執行分析

先跑完回測,再把分析模組的名稱交給 report.run_analysis(),其餘參數會交給該模組:

from finlab import data
from finlab.backtest import sim

# 完成回測
close = data.get('price:收盤價')
position = close > close.average(20)
report = sim(position, resample='M')

# 1. 流動性檢測
report.run_analysis('LiquidityAnalysis', required_volume=100000)

# 2. 波動分析(MAE/MFE)
report.display_mae_mfe_analysis()

# 3. 時期穩定性分析
report.run_analysis('PeriodStatsAnalysis')

# 4. Alpha/Beta 分析
report.run_analysis('AlphaBetaAnalysis')

傳字串是簡寫,也可以先建立模組物件再傳入,兩種寫法結果相同:

# 簡寫
report.run_analysis('LiquidityAnalysis', required_volume=100000)

# 等價寫法
from finlab.analysis.liquidityAnalysis import LiquidityAnalysis

report.run_analysis(LiquidityAnalysis(required_volume=100000))

report.run_analysis(analysis) 會先呼叫 calculate_trade_info(),把回傳的欄位加進交易紀錄,再呼叫 analyze();除非傳入 display=False,最後回傳 display() 的結果。

檢查成交風險

LiquidityAnalysis

檢查策略的交易在進場日與出場日遇到流動性問題的比例。只支援台股:is_market_supported() 只有台股市場回傳 True,因為它檢查的是台股的漲跌幅限制,以及警示股、處置股、全額交割股的規則。

類別

finlab.analysis.LiquidityAnalysis

LiquidityAnalysis(required_volume, required_turnover)

分析台股策略流動性風險項目的機率

Note

參考VIP限定文章更了解流動性檢測內容細節。

參數

required_volume int 預設 200000

要求進出場時的單日成交股數至少要多少?

required_turnover int 預設 1000000

要求進出場時的單日成交金額至少要多少元?避免成交股數夠,但因低價股因素,造成胃納量仍無法符合資金需求。

範例


# better syntax
report.run_analysis('LiquidityAnalysis', required_volume=100000)

# original syntax
from finlab.analysis.liquidityAnalysis import LiquidityAnalysis
report.run_analysis(LiquidityAnalysis(required_volume=100000))

方法與屬性

is_market_supported
函式

is_market_supported

is_market_supported(market) -> bool

Check if the market is supported for liquidity analysis.

Currently only Taiwan stock market is supported, as it has unique features like disposal stocks, warning stocks, full delivery stocks, and price limit regulations.

參數

market Market

結果是一張表,entry 與 exit 各一列,每一欄是交易中符合下列情況的比例:

  • buy_high:在距離漲跌停 5% 以內買進(多單進場、空單出場)
  • sell_low:在距離漲跌停 5% 以內賣出(多單出場、空單進場)
  • low_volume_stocks:成交股數少於 required_volume
  • low_turnover_stocks:成交金額少於 required_turnover
  • 以及訊號日為警示股、處置股、全額交割股的比例
回測報告・可互動 開新視窗

想更了解流動性檢測的細節,可以看流動性檢測文章。

找出停損停利點

MaeMfeAnalysis

分析每筆交易持有期間最多虧多少(MAE)、最多賺多少(MFE),畫成 12 個子圖。最常用的入口是 report.display_mae_mfe_analysis(),等同 report.run_analysis('MaeMfeAnalysis'):

# violin 圖模式:'group' 或 'overlay';MFE 散點圖的 X 軸:'mae' 或 'return'
report.display_mae_mfe_analysis(violinmode='overlay', mfe_scatter_x='return')
類別

finlab.analysis.MaeMfeAnalysis

MaeMfeAnalysis(violinmode, mfe_scatter_x, **kwargs)

參數

violinmode str 預設 'group'
mfe_scatter_x str 預設 'mae'
kwargs object 預設 {}
回測報告・可互動 開新視窗

更多解讀方式請看 MAE/MFE 分析文章。

檢查不同時期的穩定性

PeriodStatsAnalysis

把策略和對標指數放在不同時期比較:整段期間的日、月、年報酬,各個年度,以及最近一個月、一季、半年、一年、三年。

類別

finlab.analysis.PeriodStatsAnalysis

PeriodStatsAnalysis()

分析台股策略的不同時期與大盤指標作比較

範例

可以執行以下程式碼來產生分析結果:

report.run_analysis('PeriodStatsAnalysis')

產生的結果:

benchmarkstrategy
('overall_daily', 'calmar_ratio')0.1491920.0655645
('overall_daily', 'sortino_ratio')0.6779860.447837
('overall_daily', 'sharpe_ratio')0.5320140.306351
('overall_daily', 'profit_factor')1.200221.07741
('overall_daily', 'tail_ratio')0.9148810.987751
('overall_daily', 'return')0.08358010.0478957
('overall_daily', 'volatility')0.1821670.312543
('overall_monthly', 'calmar_ratio')0.1553210.0731378
('overall_monthly', 'sortino_ratio')0.6973820.439003
('overall_monthly', 'sharpe_ratio')0.5249430.307292
('overall_monthly', 'profit_factor')1.757141.27059
('overall_monthly', 'tail_ratio')1.033220.903335
('overall_monthly', 'return')0.08365450.0479377
('overall_monthly', 'volatility')0.1869890.316178
('overall_yearly', 'calmar_ratio')0.4360750.127784
('overall_yearly', 'sortino_ratio')0.7383270.694786
('overall_yearly', 'sharpe_ratio')0.4073240.350986
('overall_yearly', 'profit_factor')2.21.66667
('overall_yearly', 'tail_ratio')1.716471.359
('overall_yearly', 'return')0.08144690.0663674
('overall_yearly', 'volatility')0.2847420.419087

評估標準:

  • 策略 sharpe_ratio < benchmark:策略需改進
  • 某些年度表現特別差:檢查是否遇到特定市場環境
  • 近期表現大幅衰退:策略可能失效

衡量超額報酬與回撤

AlphaBetaAnalysis

計算策略相對對標指數的 Alpha(年化超額報酬)與 Beta(市場敏感度)。

report.run_analysis('AlphaBetaAnalysis')
類別

finlab.analysis.AlphaBetaAnalysis

AlphaBetaAnalysis()

理想指標:

  • Alpha > 0:策略有超額報酬
  • Beta 0.5-1.5:市場相關性適中
  • Beta < 0:策略與市場負相關(適合避險)

DrawdownAnalysis

列出策略與對標指數的回撤事件與持續時間。

report.run_analysis('DrawdownAnalysis')
類別

finlab.analysis.DrawdownAnalysis

DrawdownAnalysis()

方法與屬性

display
函式

display

display() -> dict[str, dict[str, object]]

Display drawdown analysis result.

風險控制:

  • 最大回撤 > -50%:風險過高
  • 回撤持續時間 > 1 年:策略可能長期失效

看因子門檻對報酬的影響

InequalityAnalysis

對每個門檻 x,分析加上 factor < x 或 factor > x 的條件後,交易報酬會怎麼變。交易依 date_type 當天的因子值排序;上方的圖是每個門檻保留下來的交易平均 target 減去全部交易的平均(標題為 <name> < x 與 <name> > x),下方的圖是每個切點的因子值,橫軸是交易筆數。target 超過 3 個標準差的極端值會被截斷,保留交易太少的前 50 個切點不畫出來。

from finlab import data
from finlab.analysis.inequalityAnalysis import InequalityAnalysis
from finlab.backtest import sim

close = data.get('price:收盤價')
pb = data.get('price_earning_ratio:股價淨值比')

position = close > close.average(20)
report = sim(position, resample='M')
report.run_analysis(InequalityAnalysis(name='股價淨值比', df=pb))

df 不給時會自動執行 data.get(name),這時 name 要是資料集的 key,例如 report.run_analysis('InequalityAnalysis', name='price_earning_ratio:股價淨值比')。因子值會以 <name>@<date_type> 為欄名加進交易紀錄。

類別

finlab.analysis.InequalityAnalysis

InequalityAnalysis(name, df, date_type, target)

Analyze return of trades with condition inequality

參數

name str

name of the condition

df pd.DataFrame or None

value used in condition. If df is None, data.get(name) will be automatically perform to fetch the values.

date_type str 預設 'entry_sig_date'

can be either entry_date, entry_sig_date, exit_date, exit_sig_date.

target str 預設 'return'

the target to optimize. Any column name in report.get_trades()

範例

report.run_analysis('InequalityAnalysis', name='price_earning_ratio:股價淨值比')
回測報告・可互動 開新視窗

怎麼讀這張圖:

  • 門檻移動時曲線穩定上升,代表這個因子能分出好交易和壞交易
  • 曲線平貼在 0 附近,代表用這個因子篩選不會改變報酬
  • 只留下少數幾筆交易的門檻雜訊很大,請對照下方圖的交易筆數

自訂分析模組

想做內建沒有的分析,繼承 finlab.analysis.Analysis,實作 analyze() 與 display()。需要額外的交易資訊時,再覆寫 calculate_trade_info()。

from finlab.analysis import Analysis

class IndustryAnalysis(Analysis):
    """各產業的平均交易報酬"""

    def analyze(self, report):
        trades = report.get_trades()
        self.result = (
            trades.groupby('industry')['return']
            .agg(['count', 'mean'])
            .sort_values('mean', ascending=False)
        )
        return self.result.to_dict()

    def display(self):
        return self.result

# 使用
report.run_analysis(IndustryAnalysis())
類別

finlab.analysis.Analysis

Analysis()

方法與屬性

is_market_supported
函式

is_market_supported

is_market_supported(market) -> bool

Check if market info is supported

參數

market Market

回傳

bool

True, support. False not support.

calculate_trade_info
函式

calculate_trade_info

calculate_trade_info(report) -> list[list[object]]

Additional trade info can be calculated easily.

User could override this function if additional trade info is required for later anlaysis.

Examples

from finlab.analysis import Analysis

class SomeAnalysis(Analysis):
  def calculate_trade_info(self, report):
    return [
      ['股價淨值比', data.get('price_earning_ratio:股價淨值比'), 'entry_sig_date']
    ]

report.run_analysis(SomeAnalysis())
trades = report.get_trades()

assert '股價淨值比@entry_sig_date' in trades.columns

print(trades)

參數

report Report
analyze
函式

analyze

analyze(report) -> object

Analyze trading report.

One could assume self.caluclate_trade_info will be executed before self.analyze, so the report.get_trades() will contain the required trade info.

參數

report Report
display
函式

display

display() -> object

Display result

When implement this function, returning Plotly figure instance is recommended.

建議的分析順序

# Step 1: 基本績效檢視
report.display()

# Step 2: 流動性風險(大資金必檢)
if capital > 1000000:
    report.run_analysis('LiquidityAnalysis', required_volume=100000)

# Step 3: 波動分析(必做)
report.display_mae_mfe_analysis()

# Step 4: 時期穩定性
report.run_analysis('PeriodStatsAnalysis')

# Step 5: Alpha/Beta
report.run_analysis('AlphaBetaAnalysis')

不同類型的策略,重點看的模組不同:

策略類型重點分析模組
短線交易(日內、週線)MaeMfeAnalysis
長線投資(月線、季線)PeriodStatsAnalysis
大資金策略(> 1000 萬)LiquidityAnalysis
市場中性策略AlphaBetaAnalysis
高頻交易DrawdownAnalysis

常見問題

LiquidityAnalysis 可以用在美股嗎?

不行。它檢查的漲跌幅限制與警示股、處置股、全額交割股都是台股的規則,is_market_supported() 只有台股市場回傳 True。美股策略可以用 MaeMfeAnalysis、PeriodStatsAnalysis 與 AlphaBetaAnalysis。

只想拿到數據、不要畫圖怎麼辦?

傳入 display=False,run_analysis() 會回傳 analyze() 的結果,而不是 display() 的圖表:

result = report.run_analysis('PeriodStatsAnalysis', display=False)

下一步

原始碼在 GitHub。

↑↓ 選擇 Enter 開啟 Esc 關閉