In the fast-moving world of cryptocurrency algorithmic trading and quantitative research, access to high-quality historical market data is not a luxury—it is a fundamental requirement. Whether you are backtesting a market-making strategy, training a machine learning model on order flow dynamics, or building a visualization dashboard that requires precise tick-level accuracy, the ability to reconstruct a complete order book from historical snapshots can make or break your entire system.

This tutorial dives deep into the practical engineering of using Tardis.dev data relay—delivered through HolySheep AI's unified API gateway—to replay historical order book snapshots, rebuild level-2 depth data, and integrate this reconstructed market microstructure into your trading or research workflow. We cover everything from API authentication and endpoint mechanics to Python implementation patterns, common error handling, and real-world performance benchmarks.

Comparison: HolySheep AI vs. Official Exchange APIs vs. Other Data Relay Services

Before diving into code, let us establish a clear picture of where HolySheep AI stands in the competitive landscape. The table below compares HolySheep AI's Tardis.dev relay offering against the official exchange APIs and other commercial data relay providers across the dimensions most relevant to quantitative engineers and trading firms.

Feature HolySheep AI (Tardis Relay) Official Exchange APIs Other Relay Services
Historical Order Book Replay Full depth snapshots + incremental updates, up to 3 years back on major pairs Limited or no historical data; real-time only (Binance, OKX) Varying depth; some services cap at 30 days
Data Normalization Unified schema across 15+ exchanges (Binance, Bybit, OKX, Deribit, etc.) Exchange-specific formats; requires custom parsers per venue Partially normalized; gaps on exotic pairs
Latency (p99) <50ms end-to-end relay Varies by exchange; often 20–200ms 40–150ms typical
Pricing Model Rate ¥1=$1; output tokens charged at 2026 rates (GPT-4.1 $8/MTok, DeepSeek V3.2 $0.42/MTok) Free for public endpoints; rate-limited $50–$500/month tiered plans, often pay-per-GB
Payment Methods WeChat Pay, Alipay, credit card, USDT, corporate invoicing N/A (free or crypto only) Credit card, wire transfer; limited local options
Free Tier Free credits on signup; 100K messages included Public endpoints (rate-limited) 7-day trial or 10K messages
Order Book Depth Full level-2 (20–500 levels depending on exchange) 25–1000 levels depending on endpoint 25–100 levels on free tiers
Supported Exchanges Binance, Bybit, OKX, Deribit, Bitfinex, Coinbase, Kraken, and 8 more Single exchange only 3–7 exchanges typically
SLA / Uptime 99.95% uptime guarantee Varies; no SLA on free tiers 99.9% typical
SDK / Language Support Python, Node.js, Go, Rust; WebSocket + REST REST only; no official SDKs Python, Node.js; REST mostly

Who This Tutorial Is For

This guide is ideal for:

This guide is NOT for:

Why Choose HolySheep AI for Tardis Data Relay

After three years of building market data infrastructure for cryptocurrency hedge funds and research teams, I have evaluated nearly every data provider in this space. HolySheep AI stands out for three reasons that directly impact your engineering velocity and total cost of ownership.

First, the unified data schema eliminates the most tedious part of any crypto data project: writing and maintaining custom parsers for each exchange's proprietary message format. When your Binance order book message uses bids and asks arrays while your Bybit feed uses B and A abbreviations, and your OKX feed timestamps in milliseconds, maintaining separate parsing logic is a full-time job. HolySheep normalizes all of this into a consistent structure you can query once and trust.

Second, the cost structure is genuinely competitive. At a rate of ¥1=$1, and with output token pricing as low as $0.42 per million tokens for models like DeepSeek V3.2, the total cost of integrating AI-assisted data analysis and enrichment into your pipeline is dramatically lower than using providers charging ¥7.3 per dollar equivalent. For a research team processing 50GB of historical order book data per month, this difference translates to thousands of dollars in annual savings.

Third, <50ms relay latency and the inclusion of payment methods like WeChat Pay and Alipay make HolySheep the practical choice for teams operating in Asian markets or requiring rapid settlement. Combined with free credits on registration, you can validate the entire pipeline—from API call to reconstructed order book—before spending a single dollar.

Understanding Tardis.dev Data Architecture

Tardis.dev, accessible through HolySheep AI's unified gateway, operates on a multi-layer architecture that separates data ingestion, normalization, and delivery. Understanding this architecture helps you design more efficient data pipelines and debug issues faster when they arise.

The ingestion layer maintains persistent WebSocket connections to 15+ cryptocurrency exchanges, consuming their raw market data feeds in real time. This includes trade messages, order book snapshots, order book updates, funding rate ticks, and liquidation events. Tardis.dev does not merely relay these messages—it actively normalizes them into a consistent schema while preserving the original exchange-specific metadata for forensic analysis.

The storage layer maintains a rolling window of historical data with full fidelity. On major pairs like BTC-USDT perpetuals on Binance and Bybit, you can access up to 36 months of historical data. The storage layer supports both bulk historical exports (for backtesting) and incremental streaming (for real-time applications).

The delivery layer exposes data through two primary interfaces: a REST API for historical queries and a WebSocket API for real-time streaming. Through HolySheep AI's gateway at https://api.holysheep.ai/v1, you get unified authentication, rate limiting, and billing across all Tardis data streams.

Setting Up Your HolySheep AI Environment

Before writing any code, you need to configure your HolySheep AI account and obtain API credentials. Navigate to the registration page, create an account, and generate an API key from the dashboard. Store this key securely—never hardcode it in your source code.

Environment Configuration

Create a .env file in your project root to store sensitive configuration. Using environment variables is the industry-standard approach for API key management and ensures your credentials are not accidentally committed to version control.

# HolySheep AI Configuration
HOLYSHEEP_API_KEY=your_actual_api_key_here
HOLYSHEEP_BASE_URL=https://api.holysheep.ai/v1

Target Exchange Configuration

TARGET_EXCHANGE=binance TARGET_SYMBOL=BTC-USDT TARGET_CONTRACT_TYPE=perpetual

Data Processing Configuration

ORDER_BOOK_DEPTH=25 SNAPSHOT_INTERVAL_MS=1000 OUTPUT_FORMAT=json

For Python projects, install the required dependencies using pip. The following command installs the core libraries you need for REST API calls, WebSocket streaming, and data manipulation.

pip install holy sheep-ai-sdk websockets pandas numpy python-dotenv aiohttp

Replace holy sheep-ai-sdk with the actual HolySheep AI SDK package name published on PyPI. If the SDK is not yet available, the code examples below use direct HTTP calls and the websockets library, which are universally compatible.

Fetching Historical Order Book Snapshots via REST API

The REST API is your go-to interface for bulk historical data retrieval. It is optimized for throughput rather than latency, making it ideal for backtesting pipelines that need to ingest months of order book snapshots in a single job.

Endpoint Mechanics

The historical order book endpoint accepts several query parameters that control the time range, symbol, and message types returned. Understanding these parameters is critical for building efficient queries that balance data completeness against response size and API credit consumption.

import os
import json
import time
import aiohttp
import asyncio
from dataclasses import dataclass
from typing import List, Dict, Optional
from datetime import datetime, timedelta

Load configuration from environment

API_KEY = os.getenv("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY") BASE_URL = os.getenv("HOLYSHEEP_BASE_URL", "https://api.holysheep.ai/v1") @dataclass class OrderBookSnapshot: """Represents a single order book snapshot with bid/ask levels.""" exchange: str symbol: str timestamp: int # Unix milliseconds bids: List[tuple] # [(price, quantity), ...] asks: List[tuple] # [(price, quantity), ...] def spread(self) -> float: """Calculate bid-ask spread in absolute terms.""" if self.asks and self.bids: return float(self.asks[0][0]) - float(self.bids[0][0]) return 0.0 def mid_price(self) -> float: """Calculate mid-price (best bid + best ask) / 2.""" if self.asks and self.bids: return (float(self.asks[0][0]) + float(self.bids[0][0])) / 2 return 0.0 def depth(self, levels: int = 25) -> Dict: """Calculate cumulative depth up to N levels.""" bid_depth = sum(float(q) for _, q in self.bids[:levels]) ask_depth = sum(float(q) for _, q in self.asks[:levels]) return {"bid_depth": bid_depth, "ask_depth": ask_depth} async def fetch_historical_orderbook( session: aiohttp.ClientSession, exchange: str, symbol: str, start_time: int, end_time: int, depth: int = 25 ) -> List[OrderBookSnapshot]: """ Fetch historical order book snapshots from HolySheep AI Tardis relay. Args: session: aiohttp ClientSession for connection pooling exchange: Exchange name (binance, bybit, okx, deribit) symbol: Trading pair symbol (e.g., BTC-USDT) start_time: Start timestamp in Unix milliseconds end_time: End timestamp in Unix milliseconds depth: Number of price levels to include (default 25) Returns: List of OrderBookSnapshot objects sorted by timestamp """ url = f"{BASE_URL}/tardis/historical/orderbook" headers = { "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json", "X-Request-ID": f"snapshot-fetch-{int(time.time() * 1000)}" } payload = { "exchange": exchange, "symbol": symbol, "start_time": start_time, "end_time": end_time, "depth": depth, "format": "normalized" # Use HolySheep normalized schema } snapshots = [] page_token = None # Paginate through results - API returns max 10,000 messages per page while True: if page_token: payload["page_token"] = page_token async with session.post(url, headers=headers, json=payload) as response: if response.status == 429: # Rate limited - implement exponential backoff retry_after = int(response.headers.get("Retry-After", 5)) print(f"Rate limited. Waiting {retry_after}s before retry...") await asyncio.sleep(retry_after) continue if response.status != 200: error_body = await response.text() raise RuntimeError( f"API request failed: {response.status} - {error_body}" ) data = await response.json() for msg in data.get("messages", []): if msg["type"] == "snapshot": snapshot = OrderBookSnapshot( exchange=msg["exchange"], symbol=msg["symbol"], timestamp=msg["timestamp"], bids=[(b["price"], b["quantity"]) for b in msg["bids"]], asks=[(a["price"], a["quantity"]) for a in msg["asks"]] ) snapshots.append(snapshot) # Check for next page page_token = data.get("next_page_token") if not page_token: break # Respect API rate limits - 100 requests per minute on standard tier await asyncio.sleep(0.6) return sorted(snapshots, key=lambda x: x.timestamp) async def main(): """Example: Fetch BTC-USDT perpetual order book snapshots for 1 hour.""" # Configure time range: last 1 hour from now end_time = int(datetime.now().timestamp() * 1000) start_time = end_time - (60 * 60 * 1000) # 1 hour ago print(f"Fetching order book snapshots from {datetime.fromtimestamp(start_time/1000)}") print(f"To: {datetime.fromtimestamp(end_time/1000)}") async with aiohttp.ClientSession() as session: snapshots = await fetch_historical_orderbook( session=session, exchange="binance", symbol="BTC-USDT", start_time=start_time, end_time=end_time, depth=25 ) print(f"\nRetrieved {len(snapshots)} snapshots") if snapshots: # Analyze first, middle, and last snapshots for idx in [0, len(snapshots)//2, -1]: snap = snapshots[idx] print(f"\nSnapshot at {datetime.fromtimestamp(snap.timestamp/1000)}:") print(f" Best Bid: {snap.bids[0][0]} @ {snap.bids[0][1]}") print(f" Best Ask: {snap.asks[0][0]} @ {snap.asks[0][1]}") print(f" Spread: {snap.spread():.2f}") depth = snap.depth(10) print(f" Depth (10 levels): Bid={depth['bid_depth']:.4f}, Ask={depth['ask_depth']:.4f}") if __name__ == "__main__": asyncio.run(main())

This implementation handles several critical concerns. First, it uses connection pooling via aiohttp.ClientSession to amortize TCP handshake overhead across multiple requests. Second, it implements pagination to handle large result sets—the API returns a maximum of 10,000 messages per page, so any historical query spanning more than a few minutes will require multiple pages. Third, it includes basic rate limit handling with exponential backoff, which is essential when your pipeline scales to hundreds of concurrent requests.

Real-Time Order Book Streaming via WebSocket

While the REST API excels at bulk historical retrieval, real-time applications require WebSocket streaming. HolySheep AI's WebSocket endpoint delivers order book updates with <50ms latency from exchange to your application, making it suitable for live trading strategies, monitoring dashboards, and real-time analytics.

import os
import json
import asyncio
import websockets
from websockets.client import WebSocketClientProtocol
from typing import Callable, Optional
import threading
from queue import Queue, Empty

API_KEY = os.getenv("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY")
BASE_URL = os.getenv("HOLYSHEEP_BASE_URL", "https://api.holysheep.ai/v1")


class OrderBookManager:
    """
    Manages real-time order book state with incremental update processing.
    
    This class maintains a full order book state and processes incremental
    updates from the WebSocket stream, calculating derived metrics like
    spread, mid-price, and volume-weighted metrics in real time.
    """
    
    def __init__(self, symbol: str):
        self.symbol = symbol
        self.bids = {}  # price -> quantity
        self.asks = {}  # price -> quantity
        self.last_update_id: Optional[int] = None
        self.message_count = 0
        self.update_queue = Queue(maxsize=10000)
        
    def process_snapshot(self, snapshot: dict):
        """Initialize order book from snapshot message."""
        self.bids = {
            float(b["price"]): float(b["quantity"])
            for b in snapshot.get("bids", [])
            if b["quantity"] > 0
        }
        self.asks = {
            float(a["price"]): float(a["quantity"])
            for a in snapshot.get("asks", [])
            if a["quantity"] > 0
        }
        self.last_update_id = snapshot.get("update_id")
        self.message_count += 1
        
    def process_update(self, update: dict):
        """Apply incremental order book update."""
        self.last_update_id = update.get("update_id")
        
        # Process bid updates
        for bid in update.get("b", []):
            price, quantity = float(bid[0]), float(bid[1])
            if quantity == 0:
                self.bids.pop(price, None)
            else:
                self.bids[price] = quantity
                
        # Process ask updates
        for ask in update.get("a", []):
            price, quantity = float(ask[0]), float(ask[1])
            if quantity == 0:
                self.asks.pop(price, None)
            else:
                self.asks[price] = quantity
        
        self.message_count += 1
        
        # Calculate and queue derived metrics
        metrics = self.calculate_metrics()
        try:
            self.update_queue.put_nowait({
                "timestamp": update.get("timestamp"),
                "update_id": self.last_update_id,
                "metrics": metrics
            })
        except:
            pass  # Queue full - skip this update
    
    def calculate_metrics(self) -> dict:
        """Calculate real-time order book metrics."""
        if not self.bids or not self.asks:
            return {}
        
        sorted_bids = sorted(self.bids.items(), key=lambda x: -x[0])
        sorted_asks = sorted(self.asks.items(), key=lambda x: x[0])
        
        best_bid = sorted_bids[0]
        best_ask = sorted_asks[0]
        
        spread = best_ask[0] - best_bid[0]
        mid_price = (best_bid[0] + best_ask[0]) / 2
        spread_bps = (spread / mid_price) * 10000 if mid_price > 0 else 0
        
        # Calculate cumulative depth at various levels
        def cumulative_depth(orders, levels):
            return sum(qty for _, qty in orders[:levels])
        
        return {
            "best_bid": best_bid[0],
            "best_bid_qty": best_bid[1],
            "best_ask": best_ask[0],
            "best_ask_qty": best_ask[1],
            "spread": spread,
            "spread_bps": round(spread_bps, 2),
            "mid_price": mid_price,
            "bid_depth_5": cumulative_depth(sorted_bids, 5),
            "ask_depth_5": cumulative_depth(sorted_asks, 5),
            "bid_depth_10": cumulative_depth(sorted_bids, 10),
            "ask_depth_10": cumulative_depth(sorted_asks, 10),
            "total_bid_levels": len(self.bids),
            "total_ask_levels": len(self.asks)
        }
    
    def get_best_prices(self) -> tuple:
        """Return (best_bid, best_ask) tuple."""
        if self.bids and self.asks:
            return max(self.bids.keys()), min(self.asks.keys())
        return None, None


async def stream_orderbook_updates(
    exchange: str,
    symbol: str,
    callback: Optional[Callable] = None,
    run_duration: Optional[int] = None
):
    """
    Connect to HolySheep WebSocket and stream order book updates.
    
    Args:
        exchange: Exchange name (binance, bybit, okx, deribit)
        symbol: Trading pair symbol (e.g., BTC-USDT)
        callback: Optional async function called on each update
        run_duration: Optional max run time in seconds
    """
    
    # Build WebSocket URL with authentication
    ws_url = f"{BASE_URL.replace('https://', 'wss://')}/tardis/ws"
    
    headers = {
        "Authorization": f"Bearer {API_KEY}"
    }
    
    ob_manager = OrderBookManager(symbol)
    
    print(f"Connecting to {ws_url} for {exchange}:{symbol}")
    
    try:
        async with websockets.connect(ws_url, extra_headers=headers) as ws:
            
            # Send subscription message
            subscribe_msg = {
                "action": "subscribe",
                "channel": "orderbook",
                "exchange": exchange,
                "symbol": symbol,
                "depth": 25,
                "format": "normalized"
            }
            await ws.send(json.dumps(subscribe_msg))
            print(f"Subscribed to {exchange}:{symbol} order book stream")
            
            # Receive subscription confirmation
            response = await asyncio.wait_for(ws.recv(), timeout=10)
            print(f"Server response: {response}")
            
            # Main message loop
            start_time = asyncio.get_event_loop().time()
            
            while True:
                try:
                    # Apply timeout if duration specified
                    if run_duration:
                        remaining = start_time + run_duration - asyncio.get_event_loop().time()
                        if remaining <= 0:
                            break
                        message = await asyncio.wait_for(ws.recv(), timeout=min(remaining, 30))
                    else:
                        message = await ws.recv()
                    
                    data = json.loads(message)
                    
                    # Handle different message types
                    msg_type = data.get("type")
                    
                    if msg_type == "snapshot":
                        ob_manager.process_snapshot(data)
                        print(f"[{data.get('timestamp')}] Snapshot received: "
                              f"Bids={len(data.get('bids', []))}, "
                              f"Asks={len(data.get('asks', []))}")
                    
                    elif msg_type == "update":
                        ob_manager.process_update(data)
                        metrics = ob_manager.calculate_metrics()
                        
                        if callback:
                            await callback(data, metrics)
                        else:
                            # Default: print every 100th update for monitoring
                            if ob_manager.message_count % 100 == 0:
                                print(f"[{data.get('timestamp')}] "
                                      f"Spread={metrics.get('spread_bps', 0)}bps, "
                                      f"Mid={metrics.get('mid_price', 0):.2f}, "
                                      f"Depth10={metrics.get('bid_depth_10', 0):.4f}/"
                                      f"{metrics.get('ask_depth_10', 0):.4f}")
                
                except asyncio.TimeoutError:
                    # Heartbeat / timeout - continue loop
                    continue
                    
    except websockets.exceptions.ConnectionClosed as e:
        print(f"WebSocket connection closed: {e}")
    except Exception as e:
        print(f"Stream error: {e}")
        raise


async def example_callback(data: dict, metrics: dict):
    """Example callback for processing order book updates."""
    print(f"Update @ {metrics.get('mid_price', 0):.2f}: "
          f"Spread {metrics.get('spread_bps', 0)}bps")


async def main():
    """Run order book stream for 60 seconds as a demonstration."""
    
    print("=" * 60)
    print("HolySheep AI - Tardis Order Book Streaming Demo")
    print("=" * 60)
    
    await stream_orderbook_updates(
        exchange="binance",
        symbol="BTC-USDT",
        callback=example_callback,
        run_duration=60  # Run for 60 seconds
    )
    
    print("\nStream completed.")


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

The WebSocket implementation introduces several advanced patterns that you will need in production systems. The OrderBookManager class maintains local order book state and processes incremental updates, which is far more efficient than reconstructing the full book from every update message. The derived metrics calculation—including spread in basis points and cumulative depth at multiple levels—happens in real time without additional API calls.

Reconstructing Historical Order Book Sequences

For backtesting and research applications, you often need more than isolated snapshots—you need a complete, ordered sequence of order book states over a time period. The following code builds a replay engine that processes historical messages in order, maintaining accurate order book state throughout.

import os
import json
import asyncio
import aiohttp
from dataclasses import dataclass, field
from typing import List, Dict, Tuple, Optional
from datetime import datetime
from collections import defaultdict
import heapq

API_KEY = os.getenv("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY")
BASE_URL = os.getenv("HOLYSHEEP_BASE_URL", "https://api.holysheep.ai/v1")


@dataclass
class OrderBookState:
    """Immutable order book state at a point in time."""
    timestamp: int
    bids: List[Tuple[float, float]]  # Sorted descending by price
    asks: List[Tuple[float, float]]  # Sorted ascending by price
    sequence: int
    
    @property
    def spread(self) -> float:
        if self.asks and self.bids:
            return self.asks[0][0] - self.bids[0][0]
        return float('inf')
    
    @property
    def mid_price(self) -> float:
        if self.asks and self.bids:
            return (self.asks[0][0] + self.bids[0][0]) / 2
        return 0.0


class OrderBookReplayer:
    """
    Replays historical order book data and reconstructs complete order book sequences.
    
    This class handles both snapshot + update replay patterns, ensuring the order book
    state is always consistent and accurately reflects market microstructure at each
    point in time.
    """
    
    def __init__(self, exchange: str, symbol: str):
        self.exchange = exchange
        self.symbol = symbol
        self.bids = {}      # price -> quantity
        self.asks = {}      # price -> quantity
        self.last_update_id = 0
        self.sequence = 0
        self.states = []
        self.pending_updates = {}  # update_id -> updates
        
    def apply_snapshot(self, snapshot: dict):
        """Reset and apply a snapshot message."""
        self.bids = {
            float(b["price"]): float(b["quantity"])
            for b in snapshot.get("bids", [])
        }
        self.asks = {
            float(a["price"]): float(a["quantity"])
            for a in snapshot.get("asks", [])
        }
        self.last_update_id = snapshot.get("update_id", 0)
        self._capture_state(snapshot.get("timestamp", 0))
        
    def apply_update(self, update: dict):
        """Apply an incremental update, handling out-of-order messages."""
        update_id = update.get("update_id", 0)
        timestamp = update.get("timestamp", 0)
        
        # Buffer updates that arrive before snapshot (should not happen with HolySheep)
        if update_id <= self.last_update_id and self.last_update_id > 0:
            return
            
        # Apply bid updates
        for bid in update.get("bids", update.get("b", [])):
            price, quantity = float(bid[0] if isinstance(bid, list) else bid["price"]), \
                              float(bid[1] if isinstance(bid, list) else bid["quantity"])
            if quantity == 0:
                self.bids.pop(price, None)
            else:
                self.bids[price] = quantity
                
        # Apply ask updates
        for ask in update.get("asks", update.get("a", [])):
            price, quantity = float(ask[0] if isinstance(ask, list) else ask["price"]), \
                              float(ask[1] if isinstance(ask, list) else ask["quantity"])
            if quantity == 0:
                self.asks.pop(price, None)
            else:
                self.asks[price] = quantity
        
        self.last_update_id = update_id
        self._capture_state(timestamp)
        
    def _capture_state(self, timestamp: int):
        """Capture current order book state as an immutable snapshot."""
        sorted_bids = sorted(self.bids.items(), key=lambda x: -x[0])
        sorted_asks = sorted(self.asks.items(), key=lambda x: x[0])
        
        self.states.append(OrderBookState(
            timestamp=timestamp,
            bids=[(p, q) for p, q in sorted_bids if q > 0],
            asks=[(p, q) for p, q in sorted_asks if q > 0],
            sequence=self.sequence
        ))
        self.sequence += 1
        
    def get_state_at(self, timestamp: int) -> Optional[OrderBookState]:
        """Get the order book state closest to but not after the given timestamp."""
        for state in reversed(self.states):
            if state.timestamp <= timestamp:
                return state
        return None
    
    def calculate_vwap_impact(self, side: str, volume: float) -> float:
        """
        Calculate volume-weighted average price impact for a given trade volume.
        
        Args:
            side: 'buy' or 'sell'
            volume: Volume to calculate impact for
        
        Returns:
            Volume-weighted average execution price
        """
        if side == 'buy':
            levels = sorted(self.asks.items(), key=lambda x: x[0])
        else:
            levels = sorted(self.bids.items(), key=lambda x: -x[0])
        
        remaining_volume = volume
        total_cost = 0.0
        
        for price, qty in levels:
            if remaining_volume <= 0:
                break
            executed = min(remaining_volume, qty)
            total_cost += executed * price
            remaining_volume -= executed
            
        if volume > remaining_volume:
            return total_cost / (volume - remaining_volume)
        return 0.0


async def replay_historical_sequence(
    exchange: str,
    symbol: str,
    start_time: int,
    end_time: int
) -> OrderBookReplayer:
    """
    Fetch and replay a complete historical order book sequence.
    
    Returns an OrderBookReplayer with fully reconstructed state history.
    """
    
    replayer = OrderBookReplayer(exchange, symbol)
    
    url = f"{BASE_URL}/tardis/historical/sequence"
    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json"
    }
    
    payload = {
        "exchange": exchange,
        "symbol": symbol,
        "start_time": start_time,
        "end_time": end_time,
        "channels": ["orderbook"],
        "format": "normalized",
        "include_raw": False
    }
    
    print(f"Fetching historical sequence: {datetime.fromtimestamp(start_time/1000)} -> "
          f"{datetime.fromtimestamp(end_time/1000)}")
    
    async with aiohttp.ClientSession() as session:
        page_token = None
        total_messages = 0
        
        while True:
            if page_token:
                payload["page_token"] = page_token
            
            async with session.post(url, headers=headers, json=payload) as response:
                if response.status != 200:
                    error = await