In this hands-on engineering tutorial, I walk through building a complete orderbook reconstruction pipeline using Tardis.dev historical market data and implementing a simulation matching engine in Python. Whether you are backtesting algorithmic trading strategies, building market microstructure models, or training machine learning systems on historical liquidity patterns, this guide delivers production-ready code you can deploy today.

What You Will Build

Why Tardis.dev + HolySheep AI

Tardis.dev provides tick-level historical market data from major crypto exchanges including Binance, Bybit, OKX, and Deribit. Their normalized API structure simplifies multi-exchange backtesting. HolySheep AI relay adds a critical cost layer: their 2026 pricing (DeepSeek V3.2 at $0.42/MTok output) enables massive-scale analysis workloads at a fraction of OpenAI/Anthropic costs.

2026 AI Provider Pricing Comparison

Before diving into code, here is the pricing landscape that directly impacts your backtesting infrastructure costs:

Provider / ModelOutput Price ($/MTok)10M Tokens/Month Costvs DeepSeek V3.2
GPT-4.1 (OpenAI)$8.00$80.0019× more expensive
Claude Sonnet 4.5 (Anthropic)$15.00$150.0035.7× more expensive
Gemini 2.5 Flash (Google)$2.50$25.005.9× more expensive
DeepSeek V3.2 (via HolySheep)$0.42$4.20Baseline

For a typical quant team running 10 million tokens monthly through AI-assisted strategy analysis, switching from GPT-4.1 to DeepSeek V3.2 via HolySheep relay saves $75.80/month — a 94.75% cost reduction. At scale (100M tokens), the savings reach $758/month.

Prerequisites

Step 1: Fetching Historical Orderbook Data from Tardis.dev

The following async Python client fetches historical orderbook snapshots. Tardis.dev uses a WebSocket-first API for live data and REST endpoints for historical replay.

# tardis_client.py
import aiohttp
import asyncio
import json
from datetime import datetime, timedelta
from typing import AsyncIterator, Dict, List, Optional

class TardisOrderbookClient:
    """
    Async client for fetching historical orderbook snapshots from Tardis.dev.
    Supports Binance, Bybit, OKX, and Deribit normalized data format.
    """
    
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = "https://api.tardis.dev/v1"
    
    async def fetch_orderbook_snapshots(
        self,
        exchange: str,
        symbol: str,
        start_date: datetime,
        end_date: datetime
    ) -> AsyncIterator[Dict]:
        """
        Fetch historical orderbook snapshots for a given exchange/symbol pair.
        
        Args:
            exchange: 'binance', 'bybit', 'okx', 'deribit'
            symbol: Trading pair, e.g., 'BTCUSDT'
            start_date: Start of historical window
            end_date: End of historical window
        """
        # Convert dates to Unix timestamps (milliseconds)
        start_ts = int(start_date.timestamp() * 1000)
        end_ts = int(end_date.timestamp() * 1000)
        
        url = f"{self.base_url}/historical/orderbooks/{exchange}/{symbol}"
        params = {
            "from": start_ts,
            "to": end_ts,
            "format": "json"
        }
        headers = {"Authorization": f"Bearer {self.api_key}"}
        
        async with aiohttp.ClientSession() as session:
            page = 1
            while True:
                params["page"] = page
                async with session.get(
                    url, 
                    params=params, 
                    headers=headers,
                    timeout=aiohttp.ClientTimeout(total=60)
                ) as response:
                    if response.status == 429:
                        retry_after = int(response.headers.get("Retry-After", 5))
                        await asyncio.sleep(retry_after)
                        continue
                    
                    response.raise_for_status()
                    data = await response.json()
                    
                    if not data or len(data.get("data", [])) == 0:
                        break
                    
                    for item in data["data"]:
                        # Normalize to internal format
                        yield self._normalize_orderbook(item, exchange, symbol)
                    
                    if not data.get("hasMore", False):
                        break
                    
                    page += 1
                    await asyncio.sleep(0.1)  # Rate limiting
    
    def _normalize_orderbook(
        self, 
        raw: Dict, 
        exchange: str, 
        symbol: str
    ) -> Dict:
        """Convert exchange-specific format to normalized internal schema."""
        return {
            "exchange": exchange,
            "symbol": symbol,
            "timestamp": raw["timestamp"],
            "localTimestamp": raw.get("localTimestamp"),
            "bids": [[float(p), float(q)] for p, q in raw.get("bids", [])],
            "asks": [[float(p), float(q)] for p, q in raw.get("asks", [])],
            "type": raw.get("type", "snapshot")  # 'snapshot' or 'update'
        }

Usage example

async def main(): client = TardisOrderbookClient(api_key="YOUR_TARDIS_API_KEY") async for orderbook in client.fetch_orderbook_snapshots( exchange="binance", symbol="BTCUSDT", start_date=datetime(2024, 1, 1), end_date=datetime(2024, 1, 2) ): print(f"[{orderbook['timestamp']}] " f"Bids: {len(orderbook['bids'])}, " f"Asks: {len(orderbook['asks'])}") if __name__ == "__main__": asyncio.run(main())

Step 2: Orderbook Reconstruction Engine

The reconstruction engine processes incremental orderbook updates, maintaining a full depth-of-market (DOM) state. This is critical for accurate slippage simulation and liquidity analysis.

# orderbook_engine.py
from dataclasses import dataclass, field
from sortedcontainers import SortedDict
from typing import Dict, List, Tuple, Optional
import heapq
import time

@dataclass
class OrderbookState:
    """
    Reconstructed orderbook state with O(log n) price level operations.
    Uses SortedDict for automatic price ordering.
    """
    bids: SortedDict = field(default_factory=SortedDict)  # price -> quantity
    asks: SortedDict = field(default_factory=SortedDict)  # price -> quantity
    last_update_ts: int = 0
    sequence: int = 0
    
    def get_best_bid(self) -> Optional[Tuple[float, float]]:
        """Returns (price, quantity) of best bid or None."""
        if not self.bids:
            return None
        best_price = self.bids.keys()[-1]  # SortedDict is ascending, bids need descending
        return (best_price, self.bids[best_price])
    
    def get_best_ask(self) -> Optional[Tuple[float, float]]:
        """Returns (price, quantity) of best ask or None."""
        if not self.asks:
            return None
        return (self.asks.keys()[0], self.asks[self.asks.keys()[0]])
    
    def spread(self) -> Optional[float]:
        """Calculate bid-ask spread."""
        best_bid = self.get_best_bid()
        best_ask = self.get_best_ask()
        if best_bid and best_ask:
            return best_ask[0] - best_bid[0]
        return None
    
    def mid_price(self) -> Optional[float]:
        """Calculate mid-market price."""
        best_bid = self.get_best_bid()
        best_ask = self.get_best_ask()
        if best_bid and best_ask:
            return (best_bid[0] + best_ask[0]) / 2
        return None
    
    def depth_at_level(self, levels: int = 10) -> Dict[str, List[Tuple[float, float]]]:
        """Get cumulative depth for top N levels."""
        result = {"bids": [], "asks": []}
        
        # Bids: reverse iterate (highest price first)
        bid_prices = list(self.bids.keys())
        cumsum = 0.0
        for price in reversed(bid_prices[-levels:]):
            cumsum += self.bids[price]
            result["bids"].append((price, cumsum))
        
        # Asks: forward iterate (lowest price first)
        ask_prices = list(self.asks.keys())
        cumsum = 0.0
        for price in ask_prices[:levels]:
            cumsum += self.asks[price]
            result["asks"].append((price, cumsum))
        
        return result


class OrderbookReconstructor:
    """
    Reconstructs full orderbook state from incremental updates.
    Handles out-of-order messages, gaps, and replay synchronization.
    """
    
    def __init__(self, symbol: str):
        self.symbol = symbol
        self.state = OrderbookState()
        self.message_log: List[Dict] = []
        self._pending_updates: List[Dict] = []
        self._sequence_heap: List[Tuple[int, int]] = []  # (sequence, index)
    
    def apply_snapshot(self, snapshot: Dict) -> None:
        """Apply full orderbook snapshot, replacing current state."""
        self.state.bids.clear()
        self.state.asks.clear()
        
        # Apply bids (price, quantity pairs)
        for price, qty in snapshot["bids"]:
            if qty > 0:
                self.state.bids[price] = qty
            elif price in self.state.bids:
                del self.state.bids[price]
        
        # Apply asks
        for price, qty in snapshot["asks"]:
            if qty > 0:
                self.state.asks[price] = qty
            elif price in self.state.asks:
                del self.state.asks[price]
        
        self.state.last_update_ts = snapshot.get("timestamp", 0)
        self.state.sequence = snapshot.get("sequence", 0)
    
    def apply_update(self, update: Dict) -> None:
        """
        Apply incremental orderbook update.
        Supports both full replacement and delta updates.
        """
        ts = update.get("timestamp", 0)
        seq = update.get("sequence", self.state.sequence + 1)
        
        if seq <= self.state.sequence:
            # Stale or duplicate message
            return
        
        # Process delta updates
        for price, qty in update.get("bids", []):
            if qty <= 0:
                self.state.bids.pop(price, None)
            else:
                self.state.bids[price] = qty
        
        for price, qty in update.get("asks", []):
            if qty <= 0:
                self.state.asks.pop(price, None)
            else:
                self.state.asks[price] = qty
        
        self.state.last_update_ts = ts
        self.state.sequence = seq
        
        self.message_log.append({
            "timestamp": ts,
            "sequence": seq,
            "state_snapshot": self.get_snapshot()
        })
    
    def get_snapshot(self) -> Dict:
        """Export current state as dictionary."""
        return {
            "symbol": self.symbol,
            "timestamp": self.state.last_update_ts,
            "sequence": self.state.sequence,
            "best_bid": self.get_best_bid(),
            "best_ask": self.get_best_ask(),
            "spread": self.spread(),
            "mid_price": self.mid_price(),
            "bid_levels": len(self.state.bids),
            "ask_levels": len(self.state.asks)
        }
    
    # Delegate methods to state
    def get_best_bid(self): return self.state.get_best_bid()
    def get_best_ask(self): return self.state.get_best_ask()
    def spread(self): return self.state.spread()
    def mid_price(self): return self.state.mid_price()
    
    def simulate_execution(
        self, 
        side: str, 
        quantity: float, 
        order_type: str = "market"
    ) -> Dict:
        """
        Simulate executing a trade against current orderbook.
        Returns execution details including average price and slippage.
        """
        if side.lower() == "buy":
            book_side = self.state.asks  # We hit the asks when buying
        else:
            book_side = self.state.bids  # We hit the bids when selling
        
        executed_qty = 0.0
        total_cost = 0.0
        levels_used = []
        
        for price in (list(self.state.asks.keys()) if side.lower() == "buy" 
                      else list(reversed(self.state.bids.keys()))):
            available = book_side.get(price, 0)
            fill_qty = min(available, quantity - executed_qty)
            
            if fill_qty <= 0:
                break
            
            levels_used.append((price, fill_qty))
            total_cost += price * fill_qty
            executed_qty += fill_qty
        
        if executed_qty == 0:
            return {"success": False, "reason": "Insufficient liquidity"}
        
        avg_price = total_cost / executed_qty
        mid = self.mid_price() or avg_price
        slippage_bps = abs(avg_price - mid) / mid * 10000
        
        return {
            "success": True,
            "side": side,
            "requested_quantity": quantity,
            "executed_quantity": executed_qty,
            "fill_percentage": executed_qty / quantity * 100,
            "average_price": avg_price,
            "slippage_bps": round(slippage_bps, 2),
            "levels_used": len(levels_used),
            "execution_details": levels_used
        }


Example usage with reconstructed state

if __name__ == "__main__": import random reconstructor = OrderbookReconstructor("BTCUSDT") # Simulate receiving a snapshot snapshot = { "timestamp": 1704067200000, "sequence": 1, "bids": [ (42150.0, 2.5), (42148.0, 1.8), (42145.0, 3.2), (42140.0, 5.0), (42135.0, 2.0) ], "asks": [ (42155.0, 1.5), (42158.0, 2.0), (42160.0, 4.5), (42165.0, 3.0), (42170.0, 2.5) ] } reconstructor.apply_snapshot(snapshot) print(f"Initial State: Bid={reconstructor.get_best_bid()}, " f"Ask={reconstructor.get_best_ask()}, " f"Spread={reconstructor.spread()}") # Simulate market buy result = reconstructor.simulate_execution("buy", 5.0) print(f"Market Buy 5 BTC: Avg Price={result['average_price']}, " f"Slippage={result['slippage_bps']} bps")

Step 3: Simulation Matching Engine

The matching engine replays historical trades against reconstructed orderbook states, enabling realistic backtesting with accurate fill simulation.

# matching_engine.py
import asyncio
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import Dict, List, Optional, Tuple
from orderbook_engine import OrderbookReconstructor, OrderbookState

class OrderSide(Enum):
    BUY = "buy"
    SELL = "sell"

class OrderType(Enum):
    MARKET = "market"
    LIMIT = "limit"
    STOP_LOSS = "stop_loss"
    STOP_LIMIT = "stop_limit"

class OrderStatus(Enum):
    PENDING = "pending"
    FILLED = "filled"
    PARTIALLY_FILLED = "partially_filled"
    CANCELLED = "cancelled"
    REJECTED = "rejected"

@dataclass
class Order:
    order_id: str
    symbol: str
    side: OrderSide
    order_type: OrderType
    quantity: float
    price: Optional[float] = None  # For limit orders
    stop_price: Optional[float] = None
    filled_quantity: float = 0.0
    avg_fill_price: float = 0.0
    status: OrderStatus = OrderStatus.PENDING
    created_at: int = 0
    trades: List[Dict] = field(default_factory=list)

@dataclass
class Trade:
    trade_id: str
    order_id: str
    symbol: str
    side: OrderSide
    price: float
    quantity: float
    fee: float = 0.0
    fee_currency: str = "USDT"
    timestamp: int = 0
    liquidity_type: str = "taker"  # 'maker' or 'taker'


class SimulationMatchingEngine:
    """
    High-fidelity simulation matching engine for backtesting.
    Processes orders against reconstructed historical orderbook states.
    """
    
    def __init__(
        self,
        maker_fee: float = 0.0002,  # 0.02% maker fee
        taker_fee: float = 0.0004,  # 0.04% taker fee
        latency_ms: int = 50  # Simulated network latency
    ):
        self.maker_fee = maker_fee
        self.taker_fee = taker_fee
        self.latency_ms = latency_ms
        self.orders: Dict[str, Order] = {}
        self.orderbook: OrderbookReconstructor
        self.trades: List[Trade] = []
        self.position: Dict[str, float] = {}  # symbol -> quantity
        self.cash: float = 1_000_000.0  # Starting cash in USDT
        self.trade_counter: int = 0
    
    def initialize_orderbook(self, symbol: str):
        """Initialize empty orderbook for given symbol."""
        self.orderbook = OrderbookReconstructor(symbol)
    
    def apply_orderbook_state(self, snapshot: Dict):
        """Apply historical orderbook snapshot from replay."""
        self.orderbook.apply_snapshot(snapshot)
    
    def submit_order(self, order: Order) -> Order:
        """
        Submit order for simulation.
        Market orders execute immediately.
        Limit orders are added to the book if they cross the spread.
        """
        self.orders[order.order_id] = order
        order.created_at = self.orderbook.state.last_update_ts
        
        if order.order_type == OrderType.MARKET:
            return self._execute_market_order(order)
        elif order.order_type == OrderType.LIMIT:
            return self._execute_limit_order(order)
        
        return order
    
    def _execute_market_order(self, order: Order) -> Order:
        """Execute market order against current orderbook state."""
        exec_result = self.orderbook.simulate_execution(
            side=order.side.value,
            quantity=order.quantity
        )
        
        if not exec_result["success"]:
            order.status = OrderStatus.REJECTED
            return order
        
        # Calculate costs
        total_cost = exec_result["average_price"] * exec_result["executed_quantity"]
        fees = total_cost * self.taker_fee
        
        # Update cash and position
        if order.side == OrderSide.BUY:
            self.cash -= (total_cost + fees)
            self.position[order.symbol] = (
                self.position.get(order.symbol, 0) + exec_result["executed_quantity"]
            )
        else:
            self.cash += (total_cost - fees)
            self.position[order.symbol] = (
                self.position.get(order.symbol, 0) - exec_result["executed_quantity"]
            )
        
        # Record trade
        trade = Trade(
            trade_id=f"T{self.trade_counter}",
            order_id=order.order_id,
            symbol=order.symbol,
            side=order.side,
            price=exec_result["average_price"],
            quantity=exec_result["executed_quantity"],
            fee=fees,
            timestamp=order.created_at,
            liquidity_type="taker"
        )
        self.trades.append(trade)
        self.trade_counter += 1
        
        order.filled_quantity = exec_result["executed_quantity"]
        order.avg_fill_price = exec_result["average_price"]
        order.status = OrderStatus.FILLED if (
            order.filled_quantity >= order.quantity * 0.999
        ) else OrderStatus.PARTIALLY_FILLED
        order.trades.append({
            "trade_id": trade.trade_id,
            "price": trade.price,
            "quantity": trade.quantity,
            "fee": trade.fee
        })
        
        return order
    
    def _execute_limit_order(self, order: Order) -> Order:
        """Execute limit order with crossing-the-spread logic."""
        best_bid = self.orderbook.get_best_bid()
        best_ask = self.orderbook.get_best_ask()
        
        if not best_bid or not best_ask:
            return order  # No liquidity, order stays pending
        
        should_execute = False
        
        if order.side == OrderSide.BUY and order.price >= best_ask[0]:
            should_execute = True
        elif order.side == OrderSide.SELL and order.price <= best_bid[0]:
            should_execute = True
        
        if should_execute:
            # Cross spread: execute as taker
            order.order_type = OrderType.MARKET
            return self._execute_market_order(order)
        
        # Order rests in book (maker)
        return order
    
    def get_portfolio_value(self, current_price: float) -> float:
        """Calculate total portfolio value."""
        position_value = self.position.get(self.orderbook.symbol, 0) * current_price
        return self.cash + position_value
    
    def generate_execution_report(self) -> Dict:
        """Generate comprehensive execution report for backtesting."""
        if not self.trades:
            return {"error": "No trades to report"}
        
        total_fees = sum(t.fee for t in self.trades)
        buy_trades = [t for t in self.trades if t.side == OrderSide.BUY]
        sell_trades = [t for t in self.trades if t.side == OrderSide.SELL]
        
        return {
            "total_trades": len(self.trades),
            "buy_trades": len(buy_trades),
            "sell_trades": len(sell_trades),
            "total_volume": sum(t.quantity for t in self.trades),
            "total_fees": total_fees,
            "final_cash": self.cash,
            "final_position": self.position,
            "avg_trade_size": sum(t.quantity for t in self.trades) / len(self.trades),
            "avg_slippage_bps": self._calculate_avg_slippage()
        }
    
    def _calculate_avg_slippage(self) -> float:
        """Calculate average slippage across all trades."""
        slippages = []
        for trade in self.trades:
            mid = self.orderbook.mid_price()
            if mid:
                slippage_bps = abs(trade.price - mid) / mid * 10000
                slippages.append(slippage_bps)
        return sum(slippages) / len(slippages) if slippages else 0.0


Backtest runner

async def run_backtest( historical_data: List[Dict], strategy_fn, initial_capital: float = 1_000_000.0 ): """ Run strategy backtest over historical data. Args: historical_data: List of orderbook snapshots and trades strategy_fn: User-defined strategy function(orderbook, portfolio) -> Order initial_capital: Starting capital in quote currency """ engine = SimulationMatchingEngine() engine.cash = initial_capital for tick in historical_data: tick_type = tick.get("type", "snapshot") if tick_type == "snapshot": engine.initialize_orderbook(tick["symbol"]) engine.apply_orderbook_state(tick) elif tick_type == "update": engine.orderbook.apply_update(tick) elif tick_type == "trade": # Generate order signal from strategy order = strategy_fn(engine.orderbook, engine) if order: engine.submit_order(order) # Periodically log portfolio state if tick.get("timestamp", 0) % 3600000 == 0: # Hourly print(f"[{datetime.fromtimestamp(tick['timestamp']/1000)}] " f"Portfolio: ${engine.cash:.2f}") return engine.generate_execution_report()

Example strategy

def simple_momentum_strategy(orderbook, engine) -> Optional[Order]: """Example: Buy on price uptick, sell on downtick.""" # Implementation placeholder return None

Step 4: Integrating HolySheep AI for Strategy Analysis

After running backtests, use HolySheep AI relay to analyze results at scale. Their free tier includes credits for initial testing, and their DeepSeek V3.2 integration costs just $0.42/MTok output — ideal for processing large backtest reports.

# strategy_analysis.py
import aiohttp
import asyncio
import json
from typing import Dict, List, Optional
from dataclasses import dataclass

@dataclass
class HolySheepClient:
    """
    Async client for HolySheep AI relay API.
    Supports DeepSeek V3.2 at $0.42/MTok output — 95% cheaper than GPT-4.1.
    
    Rate: ¥1 = $1 USD (saves 85%+ vs ¥7.3 domestic pricing)
    Payment: WeChat, Alipay, international cards
    Latency: <50ms p99
    """
    
    base_url: str = "https://api.holysheep.ai/v1"
    api_key: str = "YOUR_HOLYSHEEP_API_KEY"
    model: str = "deepseek-chat-v3.2"
    
    async def analyze_backtest_results(
        self, 
        backtest_report: Dict,
        prompt_override: Optional[str] = None
    ) -> str:
        """
        Analyze backtest results using DeepSeek V3.2.
        
        Generates performance summary, identifies issues, and provides
        optimization suggestions at $0.42/MTok output cost.
        """
        system_prompt = """You are a quantitative trading analyst reviewing 
        backtest results. Provide actionable insights including:
        1. Performance summary (Sharpe, max drawdown, win rate)
        2. Risk analysis
        3. Strategy optimization recommendations
        4. Implementation priorities
        
        Be specific and data-driven in your analysis."""
        
        user_prompt = prompt_override or f"""Analyze this backtest report:
        
        {json.dumps(backtest_report, indent=2)}
        
        Provide a structured analysis with specific recommendations."""
        
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json"
        }
        
        payload = {
            "model": self.model,
            "messages": [
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": user_prompt}
            ],
            "temperature": 0.3,  # Lower for analytical tasks
            "max_tokens": 2048
        }
        
        async with aiohttp.ClientSession() as session:
            async with session.post(
                f"{self.base_url}/chat/completions",
                headers=headers,
                json=payload,
                timeout=aiohttp.ClientTimeout(total=30)
            ) as response:
                if response.status == 429:
                    raise Exception("Rate limit exceeded. Upgrade plan or wait.")
                
                response.raise_for_status()
                result = await response.json()
                
                return result["choices"][0]["message"]["content"]
    
    async def batch_analyze_trades(
        self, 
        trades: List[Dict],
        batch_size: int = 50
    ) -> List[str]:
        """
        Batch analyze trade patterns using HolySheep AI relay.
        Processes trades in batches for cost efficiency.
        
        At $0.42/MTok, analyzing 10,000 trades costs ~$0.50.
        """
        analyses = []
        
        for i in range(0, len(trades), batch_size):
            batch = trades[i:i+batch_size]
            
            prompt = f"""Analyze these {len(batch)} trades for patterns:
            
            - Identify common execution price levels
            - Detect anomalous slippage patterns
            - Flag potential liquidity issues
            
            Trades: {json.dumps(batch[:10], indent=2)}  # First 10 for context"""
            
            result = await self.analyze_backtest_results(
                {"trades": batch, "batch_index": i // batch_size},
                prompt_override=prompt
            )
            analyses.append(result)
            
            # Rate limiting to stay within API limits
            await asyncio.sleep(0.5)
        
        return analyses


async def main():
    client = HolySheepClient(api_key="YOUR_HOLYSHEEP_API_KEY")
    
    # Example backtest report
    sample_report = {
        "total_trades": 1247,
        "total_volume": 456.8,
        "total_fees": 234.56,
        "final_cash": 1245678.90,
        "avg_trade_size": 0.366,
        "sharpe_ratio": 1.45,
        "max_drawdown": -12.3,
        "win_rate": 0.58
    }
    
    analysis = await client.analyze_backtest_results(sample_report)
    print("Strategy Analysis:")
    print(analysis)
    
    # Cost estimate
    output_tokens = len(analysis.split()) * 1.3  # Rough token estimate
    cost = output_tokens / 1_000_000 * 0.42
    print(f"\nEstimated cost: ${cost:.4f} ({output_tokens:.0f} output tokens)")


if __name__ == "__main__":
    asyncio.run(main())

End-to-End Pipeline Integration

Combine all components into a complete backtesting pipeline that fetches historical data, reconstructs orderbooks, runs simulations, and generates AI-powered analysis.

# complete_pipeline.py
import asyncio
import json
from datetime import datetime, timedelta
from tardis_client import TardisOrderbookClient
from orderbook_engine import OrderbookReconstructor
from matching_engine import SimulationMatchingEngine, OrderSide, OrderType, Order
from strategy_analysis import HolySheepClient

class BacktestPipeline:
    """
    Complete backtesting pipeline:
    1. Fetch historical orderbook data from Tardis.dev
    2. Reconstruct orderbook state
    3. Run simulation with order matching
    4. Generate AI-powered analysis via HolySheep
    """
    
    def __init__(
        self,
        tardis_api_key: str,
        holysheep_api_key: str,
        exchange: str = "binance",
        symbol: str = "BTCUSDT"
    ):
        self.tardis_client = TardisOrderbookClient(tardis_api_key)
        self.holysheep = HolySheepClient(api_key=holysheep_api_key)
        self.exchange = exchange
        self.symbol = symbol
        self.engine = SimulationMatchingEngine()
        self.orderbook = OrderbookReconstructor(symbol)
    
    async def run(
        self,
        start_date: datetime,
        end_date: datetime,
        strategy_fn,
        initial_capital: float = 1_000_000.0
    ) -> Dict:
        """
        Execute complete backtest with AI analysis.
        
        Cost breakdown (via HolySheep):
        - Strategy analysis: ~$0.50 per backtest (10K output tokens)
        - Trade pattern analysis: ~$0.20 per 1K trades
        - Total AI cost: <$1.00 per backtest run
        """
        print(f"Starting backtest: {self.exchange}/{self.symbol}")
        print(f"Period: {start_date} to {end_date}")
        print(f"Initial capital: ${initial_capital:,.2f}")
        
        self.engine.cash = initial_capital
        historical_data = []
        
        # Step 1: Fetch historical data
        print("Fetching historical orderbook data...")
        async for orderbook_data in self.tardis_client.fetch_orderbook_snapshots(
            exchange=self.exchange,
            symbol=self.symbol,
            start_date=start_date,
            end_date=end_date
        ):
            historical_data.append(orderbook_data)
            
            # Apply to reconstruction engine
            if orderbook_data.get("type") == "snapshot":
                self.orderbook.apply_snapshot(orderbook_data)
                self.engine.orderbook = self.orderbook
            else:
                self.orderbook.apply_update(orderbook_data)
            
            # Step 2: Generate and execute strategy signals
            order = strategy