Skip to content

finlab.report

Backtest report module. The Report object is generated by the sim() function and contains complete backtesting performance information.

Use Cases

  • View backtest performance (annualized return, Sharpe ratio, max drawdown)
  • Analyze trade records (entry/exit dates, holding periods, returns)
  • Visualize equity curves and drawdowns
  • Save reports for future reference
  • Upload to FinLab cloud for live tracking
  • Run in-depth analysis (liquidity, stock selection ability, holdings distribution)

Quick Examples

Basic Usage: Generate and View Report

from finlab import data
from finlab.backtest import sim

# Build strategy and backtest
close = data.get('price:收盤價')
position = close > close.average(20)

# Generate backtest report
report = sim(position, resample='M')

# Display report (includes visualizations)
report.display()

Get Performance Metrics

# Get performance statistics (dict)
stats = report.get_stats()
print(f"Annualized return: {stats['daily_mean'] * 100:.2f}%")
print(f"Sharpe ratio: {stats['daily_sharpe']:.2f}")
print(f"Max drawdown: {stats['max_drawdown'] * 100:.2f}%")
print(f"Win rate: {stats['win_ratio'] * 100:.2f}%")

# Get structured performance metrics (nested dict)
metrics = report.get_metrics()
print(f"Annualized return: {metrics['profitability']['annualReturn']:.2%}")
print(f"Sharpe ratio: {metrics['ratio']['sharpeRatio']:.2f}")
print(f"Max drawdown: {metrics['risk']['maxDrawdown']:.2%}")

View Trade Records

# Get all trade records
trades = report.get_trades()
print(f"Total trades: {len(trades)}")
print(trades.head())

# Filter profitable trades
profitable_trades = trades[trades['return'] > 0]
print(f"Profitable trade ratio: {len(profitable_trades) / len(trades):.1%}")

Detailed Guide

See Backtesting Tutorial for: - Complete backtesting workflow - All methods of the Report object - Performance metric interpretation - Trade record analysis


API Reference

Report

The Report object is generated by the sim() function and contains complete backtesting performance information.

from finlab.backtest import sim

report = sim(position)

Key Report Methods:

Method Description Usage Frequency
display() Display full report (with visualizations) Very High
get_stats() Get performance statistics (dict) Very High
get_metrics() Get structured performance metrics (nested dict) Very High
get_trades() Get trade records (DataFrame) Very High
get_mae_mfe() Get Maximum Adverse/Favorable Excursion High
position_info() Get recent holdings and rebalancing info High
upload() Upload to FinLab cloud Medium
run_analysis() Run analysis plugin modules Medium
display_mae_mfe_analysis() Display volatility analysis charts Medium
to_text() Text format backtest summary Low
to_terminal() Terminal ASCII chart display Low
to_html() Export HTML report Low
to_pickle() / from_pickle() Save/load report Low

display()

Display the full backtest report including visualizations and performance metrics.

Usage Examples:

# Basic usage
report.display()

# Return plotly figure object for further customization
fig = report.display(return_fig=True)
fig.update_layout(title='My Strategy Backtest')
fig.show()

Display Contents: - Equity curve (strategy vs benchmark) - Drawdown curve - Performance metrics table (annualized return, Sharpe ratio, max drawdown, etc.)


get_stats()

Get performance statistics.

Signature: get_stats(resample='1d', riskfree_rate=0.02)

Returns: dict

Usage Examples:

stats = report.get_stats()

print(f"Backtest period: {stats['start']} ~ {stats['end']}")
print(f"Annualized return: {stats['daily_mean'] * 100:.2f}%")
print(f"Sharpe ratio: {stats['daily_sharpe']:.2f}")
print(f"Sortino ratio: {stats['daily_sortino']:.2f}")
print(f"Max drawdown: {stats['max_drawdown'] * 100:.2f}%")
print(f"Avg drawdown: {stats['avg_drawdown'] * 100:.2f}%")
print(f"Win rate: {stats['win_ratio'] * 100:.2f}%")

Key Return Fields:

Field Description
start Backtest start date (str)
end Backtest end date (str)
daily_mean Annualized return
daily_sharpe Sharpe ratio
daily_sortino Sortino ratio
max_drawdown Maximum drawdown
avg_drawdown Average drawdown
win_ratio Win rate
return_table Monthly/yearly return table (dict)
drawdown_details Max drawdown details

get_metrics()

Get structured performance metrics (nested dict), suitable for cloud upload or programmatic processing.

Signature: get_metrics(stats_=None, riskfree_rate=0.02)

Returns: dict with the following categories:

Usage Examples:

metrics = report.get_metrics()

# Profitability metrics
print(f"Annual return: {metrics['profitability']['annualReturn']:.2%}")
print(f"Alpha: {metrics['profitability']['alpha']:.4f}")
print(f"Beta: {metrics['profitability']['beta']:.4f}")

# Risk metrics
print(f"Max drawdown: {metrics['risk']['maxDrawdown']:.2%}")
print(f"VaR: {metrics['risk']['valueAtRisk']:.2%}")

# Ratio metrics
print(f"Sharpe ratio: {metrics['ratio']['sharpeRatio']:.2f}")
print(f"Sortino ratio: {metrics['ratio']['sortinoRatio']:.2f}")

# Win rate metrics
print(f"Win rate: {metrics['winrate']['winRate']:.2%}")

Return Structure:

Category Fields Description
backtest startDate, endDate, feeRatio, taxRatio, tradeAt, market, freq Backtest settings
profitability annualReturn, alpha, beta, avgNStock, maxNStock Profitability metrics
risk maxDrawdown, avgDrawdown, avgDrawdownDays, valueAtRisk, cvalueAtRisk Risk metrics
ratio sharpeRatio, sortinoRatio, calmarRatio, volatility, profitFactor, tailRatio Ratio metrics
winrate winRate, m12WinRate, expectancy, mae, mfe Win rate metrics
liquidity capacity, disposalStockRatio, warningStockRatio, fullDeliveryStockRatio Liquidity metrics

get_trades()

Get detailed information for all trade records.

Returns: pd.DataFrame

Usage Examples:

trades = report.get_trades()

# Analyze trade performance
print(f"Total trades: {len(trades)}")
print(f"Average return: {trades['return'].mean():.2%}")
print(f"Win rate: {(trades['return'] > 0).mean():.2%}")

# Filter big wins or big losses
big_wins = trades[trades['return'] > 0.2]
big_losses = trades[trades['return'] < -0.1]

# Statistics by stock
trades_by_stock = trades.groupby('stock_id')['return'].agg(['count', 'mean'])
print(trades_by_stock.sort_values('mean', ascending=False).head())

DataFrame Columns:

Column Description
symbol / stock_id Stock ticker (with name)
entry_sig_date Entry signal date
exit_sig_date Exit signal date
entry_date Entry date
exit_date Exit date
position Holding weight
period Holding days
return Return rate
trade_price@entry_date Entry price
trade_price@exit_date Exit price
mae Maximum adverse excursion during holding
gmfe Maximum favorable excursion during holding
bmfe Maximum favorable excursion before MAE
mdd Maximum drawdown during holding
pdays Number of profitable days
industry Industry sector

get_mae_mfe()

Get Maximum Adverse Excursion (MAE) and Maximum Favorable Excursion (MFE) analysis.

Usage Examples:

# Get MAE/MFE data
mae_mfe = report.get_mae_mfe()

# Visualize MAE/MFE distribution
report.display_mae_mfe_analysis()

Applications: - Setting stop-loss levels: Observe MAE distribution to determine a reasonable stop-loss threshold - Setting take-profit levels: Observe MFE distribution to determine a reasonable take-profit threshold - Optimizing entry/exit: If MFE is large but final return is small, take-profit is too late

MAE/MFE Interpretation

  • MAE (Maximum Adverse Excursion): Maximum unrealized loss during holding period
  • MFE (Maximum Favorable Excursion): Maximum unrealized profit during holding period
  • Ideal scenario: Large MFE, small MAE, indicating good entry timing

upload()

Upload the backtest report to FinLab cloud for live tracking.

Usage Examples:

# Upload report
report.upload(name='My Momentum Strategy')

# View later on FinLab website:
# https://ai.finlab.tw/strategies

Prerequisites

  • Must be logged in to FinLab (finlab.login())
  • Requires VIP membership
  • After upload, can be used for live trading and performance tracking

run_analysis()

Run strategy analysis plugin modules.

Signature: run_analysis(analysis, display=True, **kwargs)

Usage Examples:

# Pass analysis module name (string)
report.run_analysis('Liquidity')
report.run_analysis('MaeMfe')
report.run_analysis('AlphaBeta')
report.run_analysis('PeriodStats')
report.run_analysis('Drawdown')

# Don't display charts, only get results
result = report.run_analysis('Liquidity', display=False)

See Strategy Analysis Modules for detailed documentation.


to_text()

Present the backtest report in text format, suitable for LINE notifications, logging, etc.

Signature: to_text(name=None)

Usage Examples:

text = report.to_text(name='My Strategy')
print(text)

to_terminal()

Display cumulative return ASCII chart and drawdown in the terminal.

Signature: to_terminal(height=12, width=80, show_benchmark=True, show_drawdown=True)

Usage Examples:

report.to_terminal()

# Custom height and width
report.to_terminal(height=8, width=60)

# Hide benchmark and drawdown
report.to_terminal(show_benchmark=False, show_drawdown=False)

Installation

Requires asciichartpy: pip install 'finlab[terminal]'


to_pickle() / from_pickle()

Save and load reports.

Usage Examples:

# Save report
report.to_pickle('my_strategy_report.pkl')

# Load report
from finlab.core.report import Report
loaded_report = Report.from_pickle('my_strategy_report.pkl')
loaded_report.display()

When to Use

  • Backtesting takes a long time and you want to save results
  • Need to compare backtest reports from different periods
  • Share backtest results with others

FAQ

Q: How do I compare performance of multiple strategies?

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({
    'Strategy A': {
        'Annual Return': stats1['daily_mean'],
        'Sharpe Ratio': stats1['daily_sharpe'],
        'Max Drawdown': stats1['max_drawdown'],
    },
    'Strategy B': {
        'Annual Return': stats2['daily_mean'],
        'Sharpe Ratio': stats2['daily_sharpe'],
        'Max Drawdown': stats2['max_drawdown'],
    }
})
print(comparison)

Q: Why can't I see my report?

# Cause 1: Forgot to call .display()
report  # Does not display

report.display()  # Correct

# Cause 2: Jupyter Notebook environment issue
# Add at the beginning of the notebook:
%matplotlib inline

# Cause 3: Data is empty (no trades)
trades = report.get_trades()
if len(trades) == 0:
    print("Strategy has no trade records, please check entry conditions")

Q: How do I customize the report visualization style?

# Get plotly figure object
fig = report.display(return_fig=True)

# Change title
fig.update_layout(title='My Strategy Backtest Report')

# Change colors
fig.update_traces(line_color='blue', selector=dict(name='策略'))

# Adjust chart size
fig.update_layout(width=1200, height=600)

# Display
fig.show()

Resources