I spent the last year building a backtesting and live trading engine in Python. It started as a personal tool — I was tired of rewriting the same plumbing every time I wanted to test a strategy. Here's how it turned into a real product.
The Problem
Every time I wanted to backtest a trading strategy, I ended up writing the same boilerplate:
- Pull OHLCV data from somewhere
- Wire up indicators
- Write entry/exit logic
- Track positions, P&L, drawdowns
- Build some kind of report
- Hope nothing broke when I changed one thing
I tried the existing tools. Some were abandoned. Some forced you into their API patterns. Some were notebooks-only with no path to live execution. None of them let me go from "I have an idea" to "it's running live" without rewriting half the code.
So I built my own.
What I Built
AlgoDeploy is a Python engine that covers the full loop:
Strategy definition → Backtesting → Risk management → Live execution
The key design decision was making strategies declarative. Most strategies don't need custom Python — they're just indicator conditions, entry rules, exit rules, and position sizing. So I built a YAML config layer:
symbol: SPY
start: 2020-01-01
end: 2025-01-01
capital: 100000
entry:
- close < sma(40)
- rsi(14) < 30
exit:
hard_stop: 2%
trailing: 3%
take_profit: 8%
position_size: 5%
That config is a complete strategy. No Python required. But if you need custom logic, you can drop to Python and use the same engine programmatically.
Architecture
The engine has a few distinct layers, and keeping them separate was the most important decision I made:
Indicators
11 built-in indicators (ATR, EMA, SMA, RSI, MACD, Bollinger, VWAP, Beta, OBV, Stochastic, ADX), all computed as pandas Series from OHLCV data. The indicator layer is stateless — it takes a DataFrame and returns Series. This means you can test indicators independently, swap them out, or add custom ones without touching anything else.
Comparators
Entry conditions are built from composable comparator functions: greater_than, less_than, crosses_above, crosses_below, within_pct_of, between. In YAML, you write close > sma(20). Under the hood, it's parsed into a comparator chain that evaluates on each bar.
Exit Rules
Hard stops, trailing stops, take-profit targets, time-based exits, and scale-outs. Each exit rule is independent — you can stack them, and the first one that triggers wins. This was important because exit logic is where most backtesting frameworks get messy.
Risk Layer
This runs independently from strategy logic. Drawdown limits, daily loss caps, position-level risk caps, exposure constraints, and a "require stop" rule that rejects any order without a stop price. The risk layer can veto any trade the strategy wants to make.
Keeping risk separate from strategy means you can swap strategies without re-implementing risk checks, and you can tighten risk rules without touching strategy code.
Position Sizing
Kelly Criterion, volatility-scaled (target a dollar risk per trade), and fixed fractional (risk X% of equity per trade). Each sizer takes the current portfolio state and returns a position size. Again, independent from everything else.
Testing
The project has 623 automated tests. That's not a vanity metric — it's a survival mechanism.
When you're dealing with financial calculations, a subtle bug in position sizing or exit logic can silently produce wrong results. You won't see it in a stack trace. You'll see it when your backtest returns don't match reality.
So I test aggressively:
- Unit tests for every indicator, comparator, exit rule, position sizer, and risk check
- Integration tests for the backtest engine (known inputs → verified outputs)
- End-to-end tests for the full pipeline: config → data → backtest → report
- Edge cases: zero-volume bars, gaps, splits, single-bar strategies, empty universes
The test suite runs in CI on every commit. If I change how trailing stops calculate, I know within seconds whether anything else broke.
The Dashboard
I built a web UI on top of the engine because not everything needs to be done in code. The dashboard lets you:
- Configure strategies with dropdowns and form fields (no YAML or Python needed)
- Run backtests and see results in real-time via WebSocket updates
- View metrics: total return, CAGR, Sharpe, Sortino, max drawdown, win rate, profit factor
- Compare against benchmarks (SPY, QQQ, etc.)
- Save and load strategy configurations
The dashboard is a local web app — it talks to the same Python engine underneath. Nothing goes to the cloud.
Reports
Backtest results export as self-contained HTML files. One file, no server needed, you can email it or archive it. They include equity curves, drawdown charts, trade logs, and all the summary metrics.
Live Trading
The engine connects to Alpaca for live execution. The same strategy that ran in a backtest can run live with one config change. The live runner follows a state machine: scan universe → evaluate entry rules → risk check → size position → execute. It logs every decision for audit.
There's also a paper trading mode that logs orders without placing them, so you can validate before risking real money.
What I Learned
Declarative first, escape to code. Most users don't want to write Python for a simple moving average crossover. But some users need custom logic. Supporting both from the same engine was the right call.
Risk is not part of strategy. This was the biggest architectural win. When risk checks are independent, you can reason about them separately. "Does my strategy generate good signals?" and "Am I risking too much?" are different questions.
Test financial code like your money depends on it. Because eventually, it does. A 0.1% rounding error in position sizing compounds fast.
Reports need to be portable. Nobody wants to spin up a Jupyter server to share backtest results. Self-contained HTML files solved this completely.
Current Status
The engine is feature-complete and I'm looking for beta testers to stress-test it before public launch. If you're interested in algo trading and want to try it, the site is at algo-deploy.com.
Happy to answer questions about the architecture, the testing approach, or anything else in the comments.
Top comments (0)