Quantitative finance · 2026
Simple Stock Trader
The same strategy object runs live and in the backtest.
Most retail trading systems fail at the seam between research and execution: the backtest runs one implementation and the live engine runs another, and the two quietly diverge. This platform has one implementation. The identical strategy and risk-manager objects are instantiated by the live loop and by the event-driven backtester, so a result that reproduces in research reproduces in production or the bug is in the data, not the code.
- Status
- Production
- Domain
- Algorithmic trading · Risk systems
- Role
- Architecture, strategy design, risk engine
- Year
- 2026
Stack
- Python
- C++ · pybind11
- R
- Tauri
- FastAPI
- SQLite
- asyncio
An algorithmic foreign-exchange platform with two mechanical strategies, conviction-scaled position sizing, drawdown circuit breakers, an event-driven backtester, and crash-safe auto-flatten.
Two strategies that hedge each other
A range-breakout scalper trades session breakouts gated by volatility-regime percentile, compression, trend agreement, relative volume and a spread cap.
Its paired counterpart fades exactly the breakouts those gates reject — the false moves the scalper is designed to avoid. A third, slower trend-continuation system runs on the hourly frame across crosses and metals. The pairing means the filter that costs the first strategy an entry is the signal that gives the second one.
Risk as layers, not a stop-loss
Position size is a function of a multi-layer conviction score rather than a fixed fraction, and it sits underneath drawdown circuit breakers and per-strategy cooldowns.
Above all of it are the operational safeties that matter more than any edge: a kill switch, a heartbeat watchdog, and crash-safe auto-flatten so an engine that dies does not leave a position open behind it.
One implementation, and what that costs
Sharing strategy and risk objects between the live loop and the backtester removes an entire class of silent divergence, but it constrains the design: every strategy must be written against an event interface that a historical replay can satisfy, which rules out convenient shortcuts like reaching for the current wall-clock time or querying a broker mid-decision.
The discipline is the point. Anything a strategy cannot get from the event stream is something the backtest could not have known either.
C++ where it earns its keep
Indicator hot paths — rolling volatility, channel extremes — are compiled C++ bound in-process through pybind11.
Everything else stays in Python, where it can be read and changed. The boundary is drawn at measured cost, not at preference.
The adapter is the seam
Live broker, an optional second platform, and the backtest all sit behind one adapter interface.
That is what makes the shared-implementation claim enforceable rather than aspirational: the engine cannot tell which one it is talking to, so there is nowhere for live-only behaviour to hide. Adding a venue is implementing an interface; it is not touching a strategy.
Safety before edge
The features that took the most care are the ones that produce no return: a watchdog that flattens on heartbeat loss, notifications tiered by severity so a critical event is not buried among informational ones, and state persisted such that an engine restarting mid-session recovers its own positions rather than discovering them.
An edge that survives one bad disconnection is worth more than a better edge that does not.
Pipeline
One implementation, two drivers
Stage Can reject
-
01
Adapter
Event stream
Live or replay — engine cannot tell
-
02
Strategy
Signal
-
03
Gates
Filtered signal
Regime · volume · spread
-
04
Conviction
Position size
-
05
Risk
Approved order
Drawdown breaker · cooldown
-
06
Execution
Fill + state
The mathematics
What the model
actually computes.
Equations and every symbol defined. Fitted parameters — shares, tapers, elasticities, reconciliation bands — stay in the configuration they belong to.
Conviction-scaled position size
Size is a function of how many independent conditions agree, floored at zero and capped by the risk layer above it — never a fixed fraction.
- κ
- Conviction score from the weighted gates
- 1[g]
- Indicator that gate g passed
- R
- Risk fraction per trade
- E
- Account equity
- ATR
- Average true range — the volatility unit
- λ
- Stop distance in ATR units
- θdd
- Drawdown throttle, 0 when a breaker has tripped
Sizing in volatility units rather than price units is what keeps risk per trade constant across instruments and regimes. The drawdown throttle multiplies rather than subtracts, so a tripped breaker takes size to zero instead of to something small.
Skills exercised
What the build
actually demanded.
Against the corpus · 15 systems
This system Corpus median
Strategy
- Session-breakout and mean-reversion system design
- Volatility-regime classification and signal gating
- Paired strategies that monetise each other’s rejections
- Multi-timeframe trend continuation across FX and metals
Risk
- Multi-layer conviction scoring driving position size
- Drawdown circuit breakers and per-strategy cooldowns
- Spread and slippage modelling shared with the backtester
- Kill switch, heartbeat watchdog and crash-safe flatten
Engineering
- Event-driven backtesting that reuses live code paths
- C++ indicator kernels bound in-process via pybind11
- Async broker adapters behind one interface
- Native desktop packaging from a web UI
What it establishes
-
One implementation
Live and backtest share strategy and risk objects
-
Layered conviction sizing
Under drawdown breakers and cooldowns
-
Crash-safe
Kill switch · heartbeat watchdog · auto-flatten
-
Native desktop
Rust shell, one binary per platform
-
Venue-agnostic
Live, alternate platform and replay behind one interface