Chapter 2
Backtesting Engine
Our backtesting engine is built in-house using an event-driven architecture. It simulates trading decisions exactly as they would occur in reality — one bar at a time, never using information from the future.
1. Event-Driven Architecture
The core design principle of our engine is that the strategy can only ever see data from the current bar and earlier — never from future bars. This is enforced architecturally, not as a policy. It is physically impossible for the strategy code to access forward data.
Processing Loop (per bar)
Data Feed
OHLCV bar arrives
Indicator Engine
Recalculate indicators
Strategy Logic
Evaluate entry/exit rules
Order Generator
Create pending orders
Order Execution
Fill on next-bar open
Portfolio Update
P&L, equity curve
Sequential Processing
Each bar is processed one at a time, in chronological order. The engine maintains a strict cursor — it can read bar T and all prior bars, but bar T+1 does not exist yet.
Deterministic Output
Given the same data file and the same strategy parameters, the engine produces identical results every time. No randomness, no floating-point variance between runs.
Multi-Asset Support
The engine can run strategies simultaneously across multiple instruments, respecting portfolio-level capital constraints and cross-asset correlation.
2. Signal Generation
Trading signals are generated by applying indicator functions to the price series. All indicator values at bar T are computed using only data available at bar T — i.e., prices from bar 0 through bar T inclusive. The signal is then acted on at bar T+1's open price.
Supported Indicator Types
- ▸ Moving averages (SMA, EMA, WMA, DEMA, TEMA, KAMA)
- ▸ Momentum (RSI, MACD, Stochastic, CCI, ROC)
- ▸ Volatility (ATR, Bollinger Bands, Keltner Channels, HV)
- ▸ Volume (OBV, CMF, VWAP, Volume Profile)
- ▸ Trend (ADX, Parabolic SAR, Ichimoku Cloud)
- ▸ Oscillators (Williams %R, Ultimate Oscillator, MFI)
- ▸ Statistical (Z-score, linear regression slope, correlation)
- ▸ Custom composite indicators (strategy-specific)
Signal Types
- ▸ Entry long / Entry short
- ▸ Exit long / Exit short (explicit)
- ▸ Stop-loss trigger (price-based or ATR multiple)
- ▸ Take-profit trigger (fixed target or trailing)
- ▸ Scale-in / Scale-out (pyramid entries)
- ▸ Time-based exit (fixed holding period)
- ▸ Regime filter (market condition gate)
- ▸ Risk-based exit (portfolio drawdown threshold)
3. Execution Model
The execution model determines how orders are filled. We use conservative assumptions that slightly underestimate real-world performance — intentionally. It is better to be pleasantly surprised than disappointed.
Execution Parameters
Why Next-Bar Open?
Most retail backtesting tools allow filling orders on the same bar that generated the signal — which is impossible in practice. If a crossover occurs at the close of bar T, you cannot trade at bar T's close because the signal was not known until the bar closed.
4. Position Sizing Models
Position sizing determines how much capital is allocated to each trade. The sizing model used in a report is always disclosed in the report header. Different strategies use different models depending on their risk characteristics.
Fixed Fractional (% of Equity)
Most commonThe most widely used model. A fixed percentage of the current account equity is risked on each trade. As the account grows, position sizes grow proportionally; as it shrinks, they shrink.
Position size = Account equity × risk% ÷ (entry price – stop price)
Account: HK$100,000 | Risk: 2% | Entry: HK$10 | Stop: HK$9 → Size = HK$2,000 ÷ HK$1 = 2,000 shares
Fixed Dollar Amount
Simple strategiesA constant dollar amount is allocated to each trade, regardless of account size. Straightforward to understand but does not adapt to account growth.
Position size = Fixed dollar amount ÷ entry price
Fixed: HK$10,000 | Entry: HK$10 → Size = 1,000 shares
Volatility-Adjusted (ATR-Based)
Trend strategiesPosition size is adjusted inversely to the instrument's recent volatility, measured by Average True Range (ATR). High-volatility instruments get smaller positions; low-volatility get larger.
Position size = (Account equity × risk%) ÷ (ATR(14) × ATR multiplier)
Account: HK$100,000 | Risk: 2% | ATR: HK$0.50 | Mult: 2 → Size = HK$2,000 ÷ HK$1 = 2,000 shares
Kelly Criterion (Half-Kelly)
Advanced useThe Kelly formula optimizes long-run growth based on the strategy's historical win rate and reward-to-risk ratio. We use half-Kelly (50% of the formula output) to reduce variance.
f* = (W × R – (1–W)) ÷ R → half-Kelly = f* ÷ 2
Win rate: 55% | R:R ratio: 2:1 → f* = (0.55×2 – 0.45)/2 = 32.5% → Half-Kelly = 16.25% of equity
5. Portfolio-Level Simulation
When a strategy trades multiple instruments simultaneously, the engine enforces portfolio-level constraints. This prevents the unrealistic scenario where an unlimited number of trades can be open at once.
Capital Allocation
Each open position consumes capital. The engine tracks total deployed capital and refuses new entries if remaining cash falls below the minimum position size. No leverage unless explicitly specified in the strategy.
Maximum Open Positions
Each strategy defines a maximum number of concurrent open positions. When the limit is reached, new entry signals are queued and filled as existing positions close. This prevents over-diversification.
Portfolio Drawdown Stop
If the overall portfolio drawdown exceeds a configurable threshold (default: 25%), all positions are closed and new entries are halted for a cooldown period. This simulates risk management discipline.
Rebalancing & Drift
For multi-asset strategies, the engine periodically rebalances position weights back to target allocations. Rebalancing frequency and tolerance bands are configurable per strategy.
6. Supported Timeframes
The engine supports multiple data resolutions. The appropriate timeframe for a strategy depends on its holding period and signal frequency.
| Timeframe | Typical Holding Period | Strategy Type | Availability |
|---|---|---|---|
| Daily (EOD) | 5 days – 12 months | Swing trading, position trading | All markets |
| Weekly | 1–6 months | Trend following, long-term | All markets |
| Monthly | 3–24 months | Macro strategies, factor models | All markets |
| 4-Hour | 1–5 days | Short-term swing | HK, US (via aggregation) |
| 1-Hour | 4–48 hours | Intraday swing | HK, US only |
| 15-Minute | 1–8 hours | Day trading | HK, US only |
| 5-Minute | 30 min – 4 hours | Scalping strategies | US only (limited history) |