Mubin Attar

Production

TradePulse

An honest quant backtesting platform — a look-ahead-free event-driven engine, costs modeled by default, and a grounded NL→strategy AI copilot.

  • Designed and built (solo)
  • 2025 – present
Silent tour of the live product — an honest backtesting terminal, “no cherry-picked numbers.” Visit the live app →

Context

A backtest's only job is to tell you the truth about a strategy, and most retail backtesters lie in subtle ways: they let a strategy act on the same bar's close it used to decide, ignore trading costs, drift on float money, and let an AI narrate figures it invented. TradePulse's entire thesis is honesty over flattering numbers— those lies are engineered to be structurally impossible, not merely discouraged.

Constraints

Free market data and a $0 stack, so no paid real-time feed. And a hard product constraint: a strategy you can't actually trade must be un-authorable — no acting on the signal bar, no zero-cost fills, no entry-only strategies with no exit or risk control.

System architecture

A modular monolith: a FastAPI API and an ARQ worker, TimescaleDB for bars, Redis for queues, and a Next.js builder. The keystone is the StrategySpec DSL — one canonical, declarative, non-Turing-complete spec shared by the builder, engine, paper trading, and the AI. Operands read only closed bars, so look-ahead is unrepresentable; exit, sizing, and risk limits are mandatory fields.

System map

Tap to inspect

  1. 01
  2. 02
  3. 03
  4. 04

Use the arrow keys, Home, or End to move between nodes. Press Enter or Space to pin a node's decision, and Escape to release it.

TradePulse — one StrategySpec feeds the backtest engine, the paper engine, and the AI.

Data flow

A spec is validated (Pydantic v2), then replayed bar by bar: the engine decides on a closed bar i, applies risk limits, and fills at bar i+1's open with commission and slippage. The result carries its metrics, trades, risk events, and a reproducibility triple. The paper engine replays the same engine live with a single flag.

Key decisions

The engine contract, verbatim: decisions are made on a closed bar i; market orders fill on the next bar's open — no peeking at the signal bar's close.

Look-ahead-free by construction, not convention

Instead of: fill at the signal bar's close, warn against look-ahead in docs

Indicators read only closed bars and warm up with min_periods (MACD even double-warms its signal EMA), so a strategy can't peek even if the author wants to.

Trade-off accepted A bar of latency between signal and fill, and no 'just fill at close' mode outside tests.

Decimal money and costs-on by default

Instead of: float accounting, frictionless unless enabled

All accounting is Decimal; every fill pays commission (2 bps/side) and slippage (1 bps, adverse), and returns are shown net. A cash-conservation test asserts initial + Σ P&L equals final equity.

Trade-off accepted More arithmetic discipline; frictionless mode exists only for tests.

Risk limits enforced at entry, not reported after

Instead of: compute risk stats post-hoc, no built-in limits

A position clamp, a daily-loss kill-switch, and a consecutive-loss halt fire before a position is taken and are recorded as risk events.

Trade-off accepted Strategies can be halted mid-run and 'look worse' — which is the point.

Reproducibility as a first-class output

Instead of: store only the metrics

Every result carries a spec hash (canonical JSON), the engine version, and a data fingerprint, so any run can be audited and re-derived.

Trade-off accepted A little bookkeeping per run.

A grounded AI copilot over a chatty one

Instead of: an LLM that narrates results freely

NL→strategy uses a validate-and-repair loop and returns a validated spec it never auto-executes; narration is instructed to use only the numbers present and never extrapolate.

Trade-off accepted The copilot sometimes refuses rather than guesses — exactly what a financial tool should do.

What failed

The first indicators emitted finite values from bar zero — a subtle look-ahead, because an indicator that needs N bars shouldn't report a number before it has them. The fix was to warm them up with min_periods so they emit honest null gaps; MACD warms twice, because its signal line sits on the already-gapped MACD line.

v1leakyindicator warm-up

Causeindicators emitted finite values from bar 0 — a quiet look-ahead

v2honestindicator warm-up

Fixwarm up with min_periods (null gaps); MACD double-warms its signal EMA

Performance & cost

MetricValueMethod
correctness suitecanary + paritytest_lookahead_canary perturbs future bars 3× and proves equity through the cut bar is byte-identical; a parity test proves the paper engine reuses the backtest engine.
Sharpe risk-free rate0 (stated)Annualized from per-bar returns; shown wherever Sharpe/Sortino appear. Max drawdown always shown.
default costs2 / 1 bps2 bps/side commission + 1 bps adverse slippage on every fill; frictionless mode exists only in tests.
data provenanceDELAYEDPrices polled ~30s and labeled DELAYED; every result carries a hypothetical-performance notice.

Operations

Live ingestion and paper trading run on an ARQ worker; the paper engine is the backtest engine with close_at_end=False, guaranteed to agree by a parity test. The AI copilot runs on Gemini (free tier) or local Ollama behind one provider contract, with per-user (200K/day) and global (5M/day) token budgets.

What I'd do differently

Several things are deliberately notclaimed yet, and stating that is part of the honesty contract: a real-time consolidated feed, point-in-time survivorship-free fundamentals, an automatic in-sample/out-of-sample split, a Deflated-Sharpe / multiple-testing correction, and a buy-and-hold benchmark overlay. Those are the next things I'd build.

Evidence

The app is live and the engine, DSL, and test suite are in the repository linked above.

Changelog

  1. Public per-ticker pages, a position-sizing calculator, and real paper-trading email alerts.

  2. A public methodology page and a reality pass — cut anything the engine couldn't back.

  3. Credible backtest report: an underwater drawdown curve and full trade CSV export.

  4. Free-tier cloud deploy (Docker on Hugging Face Spaces + Neon) running on real live market data.

  5. First build — a look-ahead-safe, cost-aware backtest engine with a grounded NL→strategy copilot.