API 參考
finlab.analysis
本頁內容11
finlab.analysis 從流動性、波動、時期穩定性、超額報酬與回撤幾個角度檢查一份回測,幫你判斷策略能不能真的拿去交易。所有分析都用 report.run_analysis() 執行,想要的檢查沒有內建時,也可以繼承 Analysis 自己寫。
選哪個分析
| 你想知道的事 | 用這個 | 關鍵輸出 |
|---|---|---|
| 大資金會不會買不到、賣不掉(只限台股) | LiquidityAnalysis | 漲跌停、低成交量、處置股比例 |
| 停損停利該設在哪 | MaeMfeAnalysis | 12 個子圖(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_volumeint預設200000要求進出場時的單日成交股數至少要多少?
required_turnoverint預設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) -> boolCheck 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.
參數
marketMarket
結果是一張表,entry 與 exit 各一列,每一欄是交易中符合下列情況的比例:
buy_high:在距離漲跌停 5% 以內買進(多單進場、空單出場)sell_low:在距離漲跌停 5% 以內賣出(多單出場、空單進場)low_volume_stocks:成交股數少於required_volumelow_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)參數
violinmodestr預設'group'mfe_scatter_xstr預設'mae'kwargsobject預設{}
更多解讀方式請看 MAE/MFE 分析文章。
檢查不同時期的穩定性
PeriodStatsAnalysis
把策略和對標指數放在不同時期比較:整段期間的日、月、年報酬,各個年度,以及最近一個月、一季、半年、一年、三年。
finlab.analysis.PeriodStatsAnalysis
PeriodStatsAnalysis()分析台股策略的不同時期與大盤指標作比較
範例
可以執行以下程式碼來產生分析結果:
report.run_analysis('PeriodStatsAnalysis')產生的結果:
| benchmark | strategy | |
|---|---|---|
| ('overall_daily', 'calmar_ratio') | 0.149192 | 0.0655645 |
| ('overall_daily', 'sortino_ratio') | 0.677986 | 0.447837 |
| ('overall_daily', 'sharpe_ratio') | 0.532014 | 0.306351 |
| ('overall_daily', 'profit_factor') | 1.20022 | 1.07741 |
| ('overall_daily', 'tail_ratio') | 0.914881 | 0.987751 |
| ('overall_daily', 'return') | 0.0835801 | 0.0478957 |
| ('overall_daily', 'volatility') | 0.182167 | 0.312543 |
| ('overall_monthly', 'calmar_ratio') | 0.155321 | 0.0731378 |
| ('overall_monthly', 'sortino_ratio') | 0.697382 | 0.439003 |
| ('overall_monthly', 'sharpe_ratio') | 0.524943 | 0.307292 |
| ('overall_monthly', 'profit_factor') | 1.75714 | 1.27059 |
| ('overall_monthly', 'tail_ratio') | 1.03322 | 0.903335 |
| ('overall_monthly', 'return') | 0.0836545 | 0.0479377 |
| ('overall_monthly', 'volatility') | 0.186989 | 0.316178 |
| ('overall_yearly', 'calmar_ratio') | 0.436075 | 0.127784 |
| ('overall_yearly', 'sortino_ratio') | 0.738327 | 0.694786 |
| ('overall_yearly', 'sharpe_ratio') | 0.407324 | 0.350986 |
| ('overall_yearly', 'profit_factor') | 2.2 | 1.66667 |
| ('overall_yearly', 'tail_ratio') | 1.71647 | 1.359 |
| ('overall_yearly', 'return') | 0.0814469 | 0.0663674 |
| ('overall_yearly', 'volatility') | 0.284742 | 0.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
參數
namestrname of the condition
dfpd.DataFrame or Nonevalue used in condition. If df is None,
data.get(name)will be automatically perform to fetch the values.date_typestr預設'entry_sig_date'can be either
entry_date,entry_sig_date,exit_date,exit_sig_date.targetstr預設'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) -> boolCheck if market info is supported
參數
marketMarket
回傳
boolTrue, 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)參數
reportReport
analyze
analyze
analyze(report) -> objectAnalyze 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.
參數
reportReport
display
display
display() -> objectDisplay 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。
這一頁有幫到你嗎?