Live demo

Botlance

How I built a quantitative trading platform that survives the real world: zero look-ahead bias, redundant data pipelines, and LLMs as risk gatekeepers.

Visual preview of Botlance

01

Why Algorithmic Trading Fails: The Two Fatal Flaws

Every retail trading system fails for the same reason. There's no surprised gasp when it collapses. Just silence. The money simply disappears.

Flaw #1: Backtest Divergence

You run a backtest. Your strategy crosses two moving averages. Price dips, goes oversold, bounces. You make money in the backtest. You're excited.

But when you run it live, execution prices are completely different from what the simulator assumed. Slippage is worse. Liquidity evaporates right when you want to sell. Your historical performance is a mirage.

Flaw #2: Data Fragility

You rely on a single API for all your trading decisions. It works for 6 months. Then one day the API goes down for 2 hours. Your bot can't make decisions. The losses you accumulate in those 2 hours erase 3 months of gains.

Or worse: the API silently returns corrupted data. Your bot makes decisions based on wrong information. Nobody knows until it's too late.

BotLance was designed to solve both problems.

02

Data Ingestion: Market Context, Not Just Prices

A common mistake when designing backtesting engines is obsessing solely over OHLCV (Open, High, Low, Close, Volume) data. But price action in a vacuum is blind.

To give BotLance true intelligence, I designed an exhaustive data ingestion layer. The system consolidates information from six different providers:

  • Polygon.io: High-frequency bars and market news
  • Financial Modeling Prep: Economic calendars, earnings, insider trades (Form 4)
  • Federal Reserve FRED: Macro data (VIX, yield curves, CPI)
  • Yahoo Finance: Historical data, stock splits
  • Binance: Crypto 24/7

But ingesting this quickly became a technical nightmare. APIs fail constantly. Return sparse arrays. Silently change their JSON schemas.

The solution was designing the pipeline around three distinct execution modes:

BotLance economic calendar and market-context ingestion

03

The Zero-Divergence Engine: Eliminating Look-Ahead Bias

As the system grew, I faced the final boss of quantitative trading: look-ahead bias. It's terrifyingly easy to introduce variables into a backtest that your live bot could never have known at that exact millisecond.

If an earnings report is released "After Market Close" (AMC), your backtester can't legally use that data during that day's trading session. But it's trivially easy to make that mistake.

The architectural solution in BotLance was radical: completely isolate the strategy engine. The core file, strategy/core.py, acts as a pure function. It has no idea if it's operating in a 2021 backtest or trading live today.

Both the historical simulator and the live orchestrator inject data using the exact same struct (DailyContext). The backtester iterates bar-by-bar, strictly slicing the data arrays up to index i before passing them to the evaluator.

Fills occur on the open of index i+1. If strategy logic changes, it changes for both environments simultaneously. By design, divergence is mathematically impossible.

BotLance backtest results with zero look-ahead bias

04

The Cycle Context Pattern: Frictionless Orchestration

When you scale from testing a single strategy to running fifty different bots evaluating dozens of assets every hour, you hit a massive scalability wall.

Every bot tries to download the macroeconomic context, today's earnings, recent prices. The rate limits for Polygon and FMP were exhausted within seconds.

The solution was introducing the Cycle Context Pattern in the orchestration layer (built on APScheduler).

Before the execution cycle begins for a specific hour, the system builds an in-memory cache—the CycleContext. It fetches the current market regime, today's economic events, the latest VIX, global market sentiment—exactly once.

When the fifty bots wake up to make their decisions, they all read from this shared state. This drastically reduced network I/O and guaranteed that all agents making decisions in a specific minute share a perfectly synchronized worldview.

05

Taming the LLM: From Generator to Risk Gatekeeper

The ultimate goal of BotLance was to integrate AI (specifically Gemini) into the decision-making flow. The initial instinct of most developers is to ask the LLM to write trading code on the fly or make the trading decision directly from raw data. This is a disaster in production.

LLMs are non-deterministic. They hallucinate numerical thresholds. They're notoriously bad at generating arbitrary continuous scores ("Score this setup 85/100").

In BotLance, the flow is inverted.

Phase 1: The Builder

The LLM acts as a compiler. It translates the user's natural language intent ("Buy tech stocks on oversold pullbacks if the market is bullish") into a strict, validated JSON configuration that defines rigid mathematical thresholds.

Phase 2: The Live Gatekeeper

During live execution, the deterministic mathematical engine does the heavy lifting. Only when technical and macroeconomic indicators align perfectly to generate a "BUY" signal is the LLM invoked.

Instead of asking for a subjective score, the LLM is injected with a dense Markdown prompt containing exact indicator values, recent news sentiment, and insider trading data. It acts as an institutional risk manager. It's forced into a binary constraint: generate chain-of-thought analysis and return strict True or False to approve or veto the trade.

By forcing AI into boolean constraints based on hard data, I eliminate hallucinated variance.

BotLance LLM risk-gatekeeper decision output

06

What's Next: Mathematical Edge Metrics and Walk-Forward Validation

Building BotLance taught me that a robust trading platform is fundamentally a data engineering problem, not just a financial one. The current MVP has a rock-solid foundation, but markets are constantly evolving.

The next architectural challenges involve implementing a rigorous scoring engine that ranks bots based on their mathematical Expectancy:

E = (WinRate × AvgWin) - (LossRate × AvgLoss)

By combining this with max-drawdown penalties and building an automated Walk-Forward Validator for out-of-sample testing, BotLance will move from a highly resilient execution engine to a platform capable of validating true mathematical edge.

The problem shaped the architecture. The product needed to turn a large, noisy dataset into searchable evidence, predictions, and actionable strategies. None of those capabilities worked in isolation, so the architecture had to connect retrieval, analytics, and an agent without hiding their uncertainty.

What I built

Architecture of Botlance
Four layers separate durable data, asynchronous computation, model orchestration and the interactive client.

Related writing

The part of the work worth explaining.

Published articles and prepared topics documenting decisions, problems and lessons.

Article in preparation

Hybrid search over 20 million rows

Combining BM25 and pgvector without turning ranking into a black box.

Article in preparation

One interface for several LLM providers

Capability negotiation, retries and consistent tool contracts.

Article in preparation

What I learned building a SaaS alone in six months

Architecture choices, scope cuts and the operational cost of ownership.