-
Notifications
You must be signed in to change notification settings - Fork 0
04 Workflows Backtesting
Łukasz Rafał Czarnacki edited this page Mar 9, 2026
·
2 revisions
This page shows the standard workflow using BacktestEngine.
from trade_lab.indicators import EMA
from trade_lab.strategies import StandardStrategy
strategy = StandardStrategy(
indicators=[(EMA(period=20), 1.0), (EMA(period=50), -1.0)],
allow_long=True,
allow_short=True,
entry_threshold=0.2,
exit_threshold=0.05,
)from trade_lab.backtesting import BacktestEngine
from trade_lab.risk_management import FixedSL, FixedTP, SignalStrengthTS
from trade_lab.sizing import RiskBasedPositionSizer
strategy.take_profit = FixedTP(base_points=8.0)
strategy.stop_loss = FixedSL(base_points=5.0)
strategy.trailing_stop = SignalStrengthTS(base_points=6.0, step_points=1.0)
strategy.position_sizer = RiskBasedPositionSizer(max_fraction=0.02, risk_multiplier=2.0)
engine = BacktestEngine(
strategy=strategy,
ticker="SPY",
start="2021-01-01",
end="2026-01-01",
initial_capital=100_000,
leverage=1.0,
commission=0.001,
slippage=0.0005,
)result = engine.run()
print(result.metrics)
print(result.trade_log.tail())result (BacktestResult) contains:
-
df: input data plus generated features andsignal_strength -
equity_curve: equity per bar -
trade_log: closed trades withdirection, entry/exit fields,pnl,commission,bars_held, andexit_reason -
metrics: summary statistics
from trade_lab.backtesting import generate_report
path = generate_report(result, output_path="outputs/backtest_report.html")
print(path)Report includes:
- equity curve chart
- drawdown chart
- price with entry/exit markers
- metrics tables with long/short breakdown
Use run_on(df) when data already exists, for example in optimization or Monte Carlo:
result = engine.run_on(df)Use fetch_data() when you only want the OHLCV DataFrame for another workflow:
df = engine.fetch_data()- TP, SL, and trailing-stop exits are checked before threshold-based signal exits.
-
leverageaffects cash and PnL accounting. - If
position_sizeris set, the engine passessignal_strength, equity, price, and ATR-like volatility into it. - If
position_sizeris not set, the engine falls back to an internal full-equity style size rule.
- No trades: thresholds too strict or strategy never crosses them.
-
NaNvalues at the beginning: normal for rolling indicators and lagged features. - Unrealistic performance: review slippage, commission, leverage, and sizing assumptions.
- Section Home
- Signals
- Signals Module
- Signals Usage Examples
- Indicators
- Indicators: Base API
- Indicators: Moving Averages
- Indicators: Oscillators
- Indicators: Volume
- Indicators: Trend/Volatility
- Indicators: Statistical/Kernels
- Strategies
- Risk Management
- Position Sizing
- Machine Learning