We replaced fixed 5% position sizing with calibrated half-Kelly plus drawdown scaling, improving Sharpe from 0.79 to 1.34 and cutting maximum drawdown from 18.3% to 9.7%.
1.34
Sharpe ratio, 4-week (was 0.79)
9.7%
Max drawdown, 4-week (was 18.3%)
5.9%
Return, 4-week (was 4.1%)
72.2%
Top-decile signal win rate
CHAPTER 01
Apex's early position sizing used a fixed 5% of capital per trade regardless of signal confidence, historical win rate, or current drawdown. The result was symmetric exposure across wildly asymmetric opportunities. A signal with 72% win rate and 1.8:1 reward-to-risk received the same allocation as a signal with 48% win rate and 0.9:1 reward-to-risk. Capital was poorly distributed, and drawdown episodes were uncontrolled because the system continued full allocation through losing streaks.
The position sizing problem had three distinct subproblems. Optimal fraction given signal quality: given a win probability estimate and an expected payoff ratio, what fraction of capital maximizes long-run growth without risking ruin? Signal quality estimation: the win probability input to Kelly could not be assumed known and had to be estimated from signal score and calibrated against backtest outcomes. Dynamic scaling under drawdown: full Kelly allocations during adverse market regimes amplified losses.
CHAPTER 02
The full Kelly formula for a binary outcome is f* = (p * b - q) / b where p is win probability, q is loss probability, and b is the net payoff ratio. Full Kelly was capped at 0.25 as an absolute ceiling, because full Kelly at high win rates can produce allocations above 40%, which is ruin-adjacent in practice due to execution slippage and estimation error.
The implementation used 50% Kelly as the default scaling factor. Half Kelly reduces growth rate by approximately 25% relative to full Kelly but reduces variance and maximum drawdown by approximately 50%. For a system with estimation error in p, half Kelly is generally superior to full Kelly on a risk-adjusted basis.
Calibration mapping was built using isotonic regression of observed win rate against score decile across 10,486 historical trades. The result was a monotone mapping from score to calibrated win probability: P(win | score = 0.82) = 0.712, P(win | score = 0.61) = 0.438.
ARCHITECTURE OVERVIEW
INGEST
Rust 1.84 (position sizer module)
FEATURES
ClickHouse 26.3 (calibration table)
TRAIN
Python 3.12 (isotonic regression)
v1 / v2 / v3
SERVE
OKX API
Production predictions feed back into training set. Continuous retraining cadence
CHAPTER 03
Drawdown scaling: current equity drawdown was computed continuously as dd = 1 - (current_equity / hwm) where hwm is the rolling high-water mark. Below 5% drawdown, full half-Kelly was used. Between 5 and 25% drawdown, sizing scaled down linearly to 20% of half-Kelly. At or beyond 25% drawdown, position size was capped at 20% of half-Kelly regardless of signal quality until the portfolio recovered above the 5% drawdown threshold. The 25% hard floor was set rather than zero to prevent complete inactivity during drawdown.
The position sizer was implemented as a Rust module. The calibration table was loaded at startup from a ClickHouse query into a sorted Vec, then binary-searched at runtime for each sizing call. The market hours enforcement blocked new entries within 30 minutes of the relevant market's close. US equities blocked new entries after 15:30 ET. Crypto used a 4-hour maximum hold time as a proxy.
One postmortem issue: early implementation computed drawdown using mark-to-market equity including open position unrealized PnL. This caused drawdown scaling to fire mid-trend when unrealized losses were temporarily large but would recover. The fix changed the high-water mark computation to use only realized equity.
TECH STACK
CHAPTER 04
The shift from fixed sizing to Kelly-based sizing improved Sharpe from 0.79 to 1.34 on the same signal set over the same 4-week period. Maximum drawdown dropped from 18.3% to 9.7%. The drawdown scaling mechanism activated 9 times over the 4-week period, each time reducing exposure automatically without human intervention. In 7 of 9 activations, the drawdown was temporary and the portfolio recovered within 3 to 5 trading days.
1.34
Sharpe ratio, 4-week (was 0.79)
9.7%
Max drawdown, 4-week (was 18.3%)
5.9%
Return, 4-week (was 4.1%)
72.2%
Top-decile signal win rate
CHAPTER 05
DECISION · 01
Calibrate p before using Kelly. Uncalibrated model scores fed directly into the Kelly formula produced systematic errors. The isotonic regression calibration step was non-optional, not an enhancement.
DECISION · 02
Half-Kelly, not full. Full Kelly at estimated probabilities in the 0.68 to 0.78 range produced allocations between 18 and 35% of capital per trade, excessive given execution slippage and estimation noise.
DECISION · 03
Drawdown scaling on realized equity. Using unrealized PnL in the drawdown calculation caused false triggers mid-trend. Scaling on realized equity only made the mechanism stable without losing its protective effect during genuine losing streaks.
START A PROJECT
We build fast. Most projects ship in under two weeks. Start with a free 30-minute discovery call.
Start a ProjectWe rebuilt the signal scoring pipeline from scratch, fixing look-ahead contamination and adding a top-decile filter that produced 72.2% win rate on selected signals.
72.2% Win rate (top-decile signals)
Read case study →
AI / Machine LearningWe found a 50-percentage-point win rate spread between market regimes, fixed a regime classifier that was routing by symbol name instead of market structure, and built a live suppression system for anti-patterns.
62.1% Win rate in choppy regime
Read case study →
AI / Machine LearningWe built a Rust correlation engine processing 1,200 symbols with incremental sliding window updates at 340ms p95 per cycle, 14x faster than full recompute.
1,200 Symbols in correlation matrix
Read case study →