Algo Trading & Quant
Python automation, backtesting frameworks, execution systems, and quantitative research workflows for systematic trading.
Python Automation
IBKR via ib_insync, Zerodha Kite Connect, yfinance for data, scheduled jobs via cron / GitHub Actions.
Backtesting
Event-driven backtester with stop / target / time-stop simulation, R-multiple tracking, drawdown analysis, and walk-forward validation.
Quant Strategies
Mean reversion, trend following, divergence detection, volatility expansion, pairs trading — all with paper-first deployment.
What "algo trading" actually involves
It's not just "let the computer trade." A complete algo system handles every step a discretionary trader would, but in code:
- Implementing technical indicators — RSI, MACD, ATR, Stochastic, EMA, Supertrend, Bollinger Bands. Either via TA-Lib (C-fast) or pure pandas (portable).
- Detecting candlestick patterns — Doji, Hammer, Engulfing, Morning/Evening Star, Marubozu, Shooting Star. TA-Lib has 60+ patterns built-in.
- Calculating stop-loss dynamically — `stop = entry − N × ATR(14)` is the workhorse. Optional "swing-pivot floor" widens the stop to just past the prior structural level if ATR is tighter.
- Calculating target levels — fixed R-multiple (1.5R, 2R) or technical (mean-reversion to BB middle, prior swing high).
- Position sizing & quantity — `qty = int((NAV × risk_pct%) / (entry − stop))`. Floor first, then divide — small but real bug source.
- Order execution — bracket orders (market entry + stop + target as OCO children) via the broker's API. Always log the parent + child IDs to a CSV for audit.
- Risk management — daily kill switch, max concurrent positions, max loss per trade as % of NAV. Enforce in code, not in the prompt.
- Backtesting before live — replay historical bars, simulate fills at next-bar open, track exits realistically. Watch for lookahead bias.
- Paper-first deployment — never flip to live without 60+ days of paper-account proof that the system behaves as designed under real bid-ask + slippage.
A typical signal-to-order pipeline
# 1. Fetch bars ohlc = fetch_bars(ticker, period="6mo", interval="1d") # 2. Compute indicators ohlc["RSI"] = rsi(ohlc["close"], 14) ohlc["MACD"] = macd(ohlc["close"], 12, 26, 9) ohlc["ATR"] = atr(ohlc, 14) # 3. Detect divergence + candlestick confluence divs = find_divergence(ticker, ohlc) ohlc = detect_candle_patterns(ohlc) # 4. If signal fires, build the trade plan if buy_signal(ohlc): entry = ohlc["close"].iloc[-1] stop = entry - 2.0 * ohlc["ATR"].iloc[-1] target = entry + 3.0 * ohlc["ATR"].iloc[-1] # 1.5R qty = int((NAV * 0.01) / (entry - stop)) # 1% risk # 5. Submit bracket order to broker place_bracket(ticker, "BUY", qty, entry, stop, target) log_to_csv(ticker, qty, entry, stop, target)
Tools we use on the channel
- Python — the only realistic language for retail algo trading in 2026
- pandas + numpy — bar / indicator manipulation
- TA-Lib — fast indicator + candle pattern library (C-backed)
- ib_insync — IBKR API wrapper (much cleaner than native ibapi)
- kiteconnect — Zerodha API for Indian markets
- yfinance — free historical data for backtesting + universe scans
- scipy.signal.argrelextrema — pivot detection for divergence + structure
- matplotlib / lightweight-charts — visualization
The part nobody writes about
Everything above is the strategy. It is maybe a third of the work. The rest is what happens once more than one strategy is running against a real broker account, on a machine that has to stay awake, holding positions your database has to keep agreeing about. These are the pieces that were added because something went wrong without them.
Shared trade registry
Four strategies scanning overlapping universes will eventually both want the same ticker. A shared registry is consulted before any order so no two strategies hold conflicting positions in one symbol, and total concurrent exposure stays under a global cap.
Pre-trade funding checks
A last gate between sizing and submission that asks the broker — not the config file — whether the account can fund the order. Fails closed: a missing or stale account snapshot rejects the trade rather than assuming it is fine.
Config parity gates
Every live config has a backtested twin. A parity check fails the live run when the two drift apart, so you can never quietly trade a configuration you never tested.
Position reconciliation
The broker and your database will disagree. Transient mismatches are suppressed with a snapshot recheck and cross-run debounce; anything that survives is real and gets escalated for a decision rather than auto-corrected.
Timezone-correct scheduling
Trading US markets from Australia means the session runs overnight. Jobs fire on the local clock, compute the exact seconds until the US close, and hold the machine awake for precisely that long — then release so it can sleep.
Local bar cache
Bars are cached in SQLite rather than refetched. This is also a hard constraint on research: IBKR caps 15-minute history at one year, which is why intraday backtests here cover twelve months and daily ones cover five years.
Both live strategies sized every position from a capital figure in a YAML file. One of them tried to read the real account balance instead — but the lookup required a currency match that could never succeed on a non-USD account, so it silently fell back to the hardcoded number. No error, no log line, no way to see it on a chart.
Read the full write-up →Research published here
The strategies described on this page are documented with their actual numbers — including the results that got weaker on a larger sample.
- Divergence on NASDAQ 100 — 5 years of daily bars — the baseline study.
- The same logic on 15-minute bars — where the stop calibration problem first showed up.
- The 1-year refresh on 5,073 trades — a retracted Sharpe ratio and an uncomfortable finding about overnight holds.
- Methodology — data sources, how each metric is defined, and the six costs every backtest here excludes. Read this before trusting any number on the site.
Everything described here runs paper-first. Nothing on this page is a recommendation to trade, and no code shown is intended to be run against a live account without understanding every guard it depends on.