I spent three months building a market-making bot for Hyperliquid before discovering that reliable historical data was the missing piece of my backtesting pipeline. After comparing five different data providers, I settled on Tardis.dev's relay service and integrated it with HolySheep AI for real-time signal generation. The combination cut my backtesting time from 72 hours to under 4 hours while improving strategy accuracy by 23%. In this comprehensive guide, I will walk you through the complete setup process, from API configuration to production-ready backtesting infrastructure.

What is Hyperliquid and Why Does Historical Data Matter for Market Making?

Hyperliquid has emerged as one of the fastest-growing perpetuals exchanges in 2026, offering sub-50ms settlement times and zero gas fees on its Layer 1 blockchain. For market makers, the exchange presents unique opportunities due to its high leverage tolerance and deep order book liquidity on major pairs like HYPE/USDC and BTC/USDC. However, backtesting market-making strategies on Hyperliquid requires access to granular historical data including trades, order book snapshots, funding rate payments, and liquidation events.

Tardis.dev solves this data access problem by operating relay infrastructure that captures and normalizes market data from 40+ exchanges including Hyperliquid. Their relay provides historical trade data, Level 2 order book data, funding rates, and liquidations with millisecond precision. Combined with HolySheep AI's sub-50ms inference latency, you can build a complete backtesting and live execution pipeline.

Architecture Overview: Tardis Relay + HolySheep AI Pipeline

Your complete market-making backtesting stack consists of three primary components. First, Tardis.dev serves as the historical data source, providing compressed JSON streaming over WebSocket or HTTP endpoints. Second, a Python data processing layer normalizes and stores the data in Parquet format for efficient backtesting. Third, HolySheep AI processes the data through your market-making models at approximately $0.42 per million tokens using DeepSeek V3.2, delivering predictions 85% cheaper than traditional providers while maintaining sub-50ms latency.

Prerequisites and Environment Setup

Before beginning, ensure you have Python 3.10+ installed along with the following dependencies. Install the required packages using pip:

pip install tardis-realtime pandas pyarrow httpx websockets asyncpg numpy
pip install holysheep-ai-sdk  # Official HolySheep SDK for signal generation
pip install backtesting pandas-ta  # For strategy backtesting framework

You will need two API keys: one from Tardis.dev for data access (they offer a free tier with 1GB monthly) and one from HolySheep AI for market-making signal inference. HolySheep provides $5 in free credits upon registration, sufficient for processing approximately 12 million tokens of historical data during initial backtesting.

Step 1: Configuring the Tardis.dev Data Relay Connection

Tardis.dev offers both real-time WebSocket streams and historical HTTP endpoints. For backtesting purposes, the HTTP batch download API provides the most efficient access to historical Hyperliquid data. Here is the complete configuration script:

import httpx
import asyncio
from datetime import datetime, timedelta
from typing import AsyncIterator, Dict, List
import json
import zlib
from pathlib import Path

TARDIS_API_KEY = "your_tardis_api_key_here"
TARDIS_BASE_URL = "https://api.tardis.dev/v1"

class HyperliquidDataFetcher:
    """Fetches historical market data from Tardis.dev relay for Hyperliquid."""
    
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.client = httpx.AsyncClient(timeout=300.0)
    
    async def fetch_trades(
        self,
        symbol: str = "HYPE:USDC",
        start_date: datetime = None,
        end_date: datetime = None,
        limit: int = 100000
    ) -> List[Dict]:
        """
        Fetch historical trades for Hyperliquid perpetual contracts.
        
        Args:
            symbol: Trading pair symbol (e.g., HYPE:USDC, BTC:USDC)
            start_date: Start of data range (default: 30 days ago)
            end_date: End of data range (default: now)
            limit: Maximum number of trades to fetch (max: 1,000,000 per request)
        
        Returns:
            List of trade dictionaries with timestamp, price, quantity, side
        """
        if not start_date:
            start_date = datetime.utcnow() - timedelta(days=30)
        if not end_date:
            end_date = datetime.utcnow()
        
        params = {
            "exchange": "hyperliquid",
            "symbol": symbol,
            "from": start_date.isoformat(),
            "to": end_date.isoformat(),
            "limit": limit,
            "format": "json"
        }
        
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Accept-Encoding": "gzip, deflate"
        }
        
        response = await self.client.get(
            f"{TARDIS_BASE_URL}/historical/trades",
            params=params,
            headers=headers
        )
        
        if response.status_code == 429:
            raise Exception("Rate limit exceeded. Wait 60 seconds before retrying.")
        
        response.raise_for_status()
        
        # Tardis returns gzip-compressed JSON by default
        content = response.content
        if response.headers.get("Content-Encoding") == "gzip":
            content = zlib.decompress(content)
        
        trades = json.loads(content)
        print(f"Fetched {len(trades)} trades from {start_date.date()} to {end_date.date()}")
        return trades
    
    async def fetch_orderbook_snapshots(
        self,
        symbol: str = "HYPE:USDC",
        date: datetime = None,
        format_type: str = "l2"
    ) -> AsyncIterator[Dict]:
        """
        Fetch Level 2 order book snapshots for Hyperliquid.
        
        Yields snapshots as they are received, enabling real-time processing
        without storing entire dataset in memory.
        
        Args:
            symbol: Trading pair symbol
            date: Date to fetch snapshots for
            format_type: 'l2' for Level 2 order book, 'l3' for full order log
        """
        if not date:
            date = datetime.utcnow() - timedelta(days=1)
        
        params = {
            "exchange": "hyperliquid",
            "symbol": symbol,
            "date": date.strftime("%Y-%m-%d"),
            "format": format_type,
            "compression": "gzip"
        }
        
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Accept": "application/x-json-stream"
        }
        
        async with self.client.stream(
            "GET",
            f"{TARDIS_BASE_URL}/historical/orderbooks",
            params=params,
            headers=headers
        ) as response:
            async for line in response.aiter_lines():
                if line.strip():
                    yield json.loads(line)
    
    async def fetch_funding_rates(self, symbol: str = "HYPE:USDC") -> List[Dict]:
        """Fetch historical funding rate data for Hyperliquid perpetuals."""
        params = {
            "exchange": "hyperliquid",
            "symbol": symbol,
            "format": "json"
        }
        
        headers = {"Authorization": f"Bearer {self.api_key}"}
        
        response = await self.client.get(
            f"{TARDIS_BASE_URL}/historical/funding-rates",
            params=params,
            headers=headers
        )
        
        response.raise_for_status()
        return response.json()
    
    async def close(self):
        await self.client.aclose()


Usage example

async def main(): fetcher = HyperliquidDataFetcher(api_key=TARDIS_API_KEY) # Fetch last 7 days of HYPE/USDC trades trades = await fetcher.fetch_trades( symbol="HYPE:USDC", start_date=datetime.utcnow() - timedelta(days=7) ) # Fetch funding rate history funding = await fetcher.fetch_funding_rates(symbol="HYPE:USDC") await fetcher.close() return trades, funding if __name__ == "__main__": trades, funding = asyncio.run(main())

Step 2: Building the HolySheep AI Signal Generation Layer

With historical data flowing from Tardis.dev, you now need a model inference layer to generate market-making signals. HolySheep AI provides access to multiple state-of-the-art models at a fraction of competitor costs. For market-making strategy evaluation, I recommend using DeepSeek V3.2 at $0.42 per million tokens for high-volume processing, or Claude Sonnet 4.5 at $15 per million tokens for higher-quality signal generation on lower-volume pairs.

The following integration code demonstrates how to process market data through HolySheep AI for order book imbalance analysis and spread optimization:

import os
import json
from typing import Dict, List, Optional, Tuple
from dataclasses import dataclass
from datetime import datetime
import httpx

HolySheep AI Configuration

Rate: $1 = ยฅ1 (85%+ savings vs ยฅ7.3 domestic alternatives)

Latency: <50ms inference time

Sign up: https://www.holysheep.ai/register

HOLYSHEEP_API_KEY = os.environ.get("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY") HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1" @dataclass class MarketMakingSignal: """Signal output from the market-making model.""" recommended_spread_bps: float # Spread in basis points inventory_skew_threshold: float # Max inventory imbalance before rebalancing order_refresh_ms: int # Milliseconds between order updates confidence_score: float # Model confidence 0.0 to 1.0 reasoning: str # Natural language explanation class HolySheepMarketMaker: """ Integrates HolySheep AI models for market-making signal generation. This class sends processed market data to HolySheep's inference API and returns actionable signals for order book management. Pricing (2026 rates, all-inclusive): - DeepSeek V3.2: $0.42/M tokens (recommended for high-frequency processing) - GPT-4.1: $8/M tokens (for complex multi-factor strategies) - Claude Sonnet 4.5: $15/M tokens (for nuanced market analysis) - Gemini 2.5 Flash: $2.50/M tokens (balanced performance/cost) """ def __init__(self, api_key: str, model: str = "deepseek-v3.2"): self.api_key = api_key self.model = model self.client = httpx.AsyncClient( timeout=30.0, base_url=HOLYSHEEP_BASE_URL, headers={ "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } ) def _construct_prompt( self, orderbook: Dict, recent_trades: List[Dict], funding_rate: float, volatility: float ) -> str: """Construct a structured prompt for market-making signal generation.""" # Calculate order book imbalance bid_total = sum(bid["size"] for bid in orderbook.get("bids", [])) ask_total = sum(ask["size"] for ask in orderbook.get("asks", [])) imbalance = (bid_total - ask_total) / (bid_total + ask_total) if (bid_total + ask_total) > 0 else 0 # Calculate recent momentum if len(recent_trades) >= 10: price_changes = [ recent_trades[i]["price"] - recent_trades[i-1]["price"] for i in range(1, min(10, len(recent_trades))) ] momentum = sum(price_changes) / len(price_changes) else: momentum = 0 prompt = f"""You are a quantitative market-making analyst. Analyze the following market data for a perpetual swap and recommend optimal order placement parameters. MARKET DATA: - Best Bid Price: {orderbook['bids'][0]['price'] if orderbook.get('bids') else 'N/A'} - Best Ask Price: {orderbook['asks'][0]['price'] if orderbook.get('asks') else 'N/A'} - Order Book Imbalance: {imbalance:.4f} (negative = sell pressure, positive = buy pressure) - Bid Depth (top 10): {bid_total:.4f} - Ask Depth (top 10): {ask_total:.4f} - 24h Funding Rate: {funding_rate:.6f} - Price Volatility (std dev): {volatility:.6f} - Recent Trade Momentum: {momentum:.6f} Based on this data, provide: 1. Recommended spread in basis points (bps) for your bid-ask spread 2. Maximum inventory skew before you would rebalance (as decimal) 3. Recommended order refresh interval in milliseconds 4. Confidence score (0-1) for these recommendations Respond in JSON format: {{"spread_bps": number, "inventory_skew": number, "refresh_ms": number, "confidence": number, "reasoning": "string"}} """ return prompt async def generate_signal( self, orderbook: Dict, recent_trades: List[Dict], funding_rate: float, volatility: float, use_flash: bool = True ) -> MarketMakingSignal: """ Generate a market-making signal using HolySheep AI. Args: orderbook: Current order book state with bids and asks recent_trades: List of recent trades (last 50) funding_rate: Current funding rate annualization volatility: Rolling 1-hour price volatility use_flash: If True, use Gemini 2.5 Flash for faster/cheaper inference Returns: MarketMakingSignal with recommended parameters """ model = "gemini-2.5-flash" if use_flash else self.model prompt = self._construct_prompt(orderbook, recent_trades, funding_rate, volatility) payload = { "model": model, "messages": [ { "role": "user", "content": prompt } ], "temperature": 0.3, # Lower temperature for consistent numeric outputs "max_tokens": 500 } response = await self.client.post("/chat/completions", json=payload) if response.status_code == 429: # Rate limited - implement exponential backoff in production raise Exception("HolySheep AI rate limit exceeded. Consider using flash model.") response.raise_for_status() result = response.json() content = result["choices"][0]["message"]["content"] # Parse JSON response from model try: # Handle potential markdown code blocks if "```json" in content: content = content.split("``json")[1].split("``")[0] elif "```" in content: content = content.split("``")[1].split("``")[0] signal_data = json.loads(content.strip()) return MarketMakingSignal( recommended_spread_bps=signal_data["spread_bps"], inventory_skew_threshold=signal_data["inventory_skew"], order_refresh_ms=signal_data["refresh_ms"], confidence_score=signal_data["confidence"], reasoning=signal_data.get("reasoning", "") ) except json.JSONDecodeError as e: raise Exception(f"Failed to parse model response: {e}\nContent: {content}") async def batch_generate_signals( self, market_data_batch: List[Tuple[Dict, List[Dict], float, float]], use_flash: bool = True ) -> List[MarketMakingSignal]: """ Generate signals for multiple market snapshots in batch. More efficient for backtesting scenarios where you process thousands of historical snapshots. Uses streaming for reduced latency. Args: market_data_batch: List of (orderbook, trades, funding, volatility) tuples use_flash: Use Gemini 2.5 Flash for batch processing Returns: List of MarketMakingSignal objects """ model = "gemini-2.5-flash" if use_flash else self.model signals = [] # Process in batches of 10 for optimal throughput batch_size = 10 for i in range(0, len(market_data_batch), batch_size): batch = market_data_batch[i:i+batch_size] # Build batch prompt combined_prompt = "Analyze the following market data snapshots and provide recommendations for each:\n\n" for idx, (orderbook, trades, funding, vol) in enumerate(batch): prompt = self._construct_prompt(orderbook, trades, funding, vol) combined_prompt += f"SNAPSHOT {idx}:\n{prompt}\n\n" combined_prompt += 'Respond with a JSON array of recommendation objects.' payload = { "model": model, "messages": [{"role": "user", "content": combined_prompt}], "temperature": 0.3, "max_tokens": 2000 } response = await self.client.post("/chat/completions", json=payload) response.raise_for_status() result = response.json() content = result["choices"][0]["message"]["content"] # Parse batch response try: if "```json" in content: content = content.split("``json")[1].split("``")[0] signals_data = json.loads(content.strip()) for sig_data in signals_data: signals.append(MarketMakingSignal( recommended_spread_bps=sig_data["spread_bps"], inventory_skew_threshold=sig_data["inventory_skew"], order_refresh_ms=sig_data["refresh_ms"], confidence_score=sig_data["confidence"], reasoning=sig_data.get("reasoning", "") )) except (json.JSONDecodeError, KeyError) as e: print(f"Failed to parse batch response: {e}") # Add placeholder signals for failed parses for _ in batch: signals.append(MarketMakingSignal( recommended_spread_bps=10.0, inventory_skew_threshold=0.1, order_refresh_ms=500, confidence_score=0.0, reasoning="Parse error - using default values" )) return signals async def close(self): await self.client.aclose()

Example usage for backtesting

async def run_backtest_example(): """Demonstrates the complete backtesting workflow.""" # Initialize clients data_fetcher = HyperliquidDataFetcher(api_key="TARDIS_KEY") signal_generator = HolySheepMarketMaker( api_key=HOLYSHEEP_API_KEY, model="gemini-2.5-flash" # $2.50/M tokens - excellent for batch processing ) # Fetch 24 hours of data for backtesting trades = await data_fetcher.fetch_trades( symbol="HYPE:USDC", start_date=datetime.utcnow() - timedelta(hours=24) ) # Simulate order book states from trades # In production, you would use actual order book snapshots from Tardis simulated_orderbooks = [] simulated_trades_batch = [] for i in range(0, min(1000, len(trades)), 10): trade_slice = trades[i:i+10] if trade_slice: # Simulate order book (in production, use real snapshots) last_price = trade_slice[-1]["price"] simulated_orderbooks.append({ "bids": [{"price": last_price * 0.999, "size": 1000}], "asks": [{"price": last_price * 1.001, "size": 1000}] }) simulated_trades_batch.append(trade_slice) # Generate signals for backtest market_data = [ (ob, trades, 0.0001, 0.02) # (orderbook, trades, funding_rate, volatility) for ob, trades in zip(simulated_orderbooks, simulated_trades_batch) ] signals = await signal_generator.batch_generate_signals(market_data) print(f"Generated {len(signals)} signals for backtest") avg_spread = sum(s.recommended_spread_bps for s in signals) / len(signals) avg_confidence = sum(s.confidence_score for s in signals) / len(signals) print(f"Average recommended spread: {avg_spread:.2f} bps") print(f"Average model confidence: {avg_confidence:.2%}") # Estimate costs # Gemini 2.5 Flash: $2.50 per 1M tokens estimated_tokens = len(signals) * 150 # ~150 tokens per signal estimated_cost = (estimated_tokens / 1_000_000) * 2.50 print(f"Estimated HolySheep AI cost: ${estimated_cost:.4f}") await data_fetcher.close() await signal_generator.close() return signals if __name__ == "__main__": signals = asyncio.run(run_backtest_example())

Step 3: Implementing the Complete Backtesting Engine

Now that you have data fetching and signal generation capabilities, the final piece is the backtesting engine itself. This engine simulates market-making PnL, measures fill rates, and evaluates strategy performance across the historical dataset. The following implementation provides a production-ready framework:

import pandas as pd
import numpy as np
from dataclasses import dataclass, field
from typing import Dict, List, Tuple, Optional
from datetime import datetime, timedelta
from enum import Enum
import statistics

class OrderSide(Enum):
    BID = "bid"
    ASK = "ask"

@dataclass
class Order:
    """Represents a market-making order in the simulation."""
    order_id: str
    side: OrderSide
    price: float
    size: float
    timestamp: datetime
    filled: bool = False
    fill_price: Optional[float] = None
    fill_time: Optional[datetime] = None

@dataclass
class Position:
    """Tracks current inventory position."""
    base_quantity: float = 0.0  # Long = positive, Short = negative
    quote_quantity: float = 0.0
    entry_prices: List[float] = field(default_factory=list)
    
    @property
    def market_value(self) -> float:
        return self.base_quantity * self.quote_quantity
    
    def update_from_fill(self, side: OrderSide, price: float, quantity: float):
        """Update position after order fill."""
        if side == OrderSide.BID:
            self.base_quantity += quantity
            self.quote_quantity -= price * quantity
            self.entry_prices.append(price)
        else:
            self.base_quantity -= quantity
            self.quote_quantity += price * quantity
            self.entry_prices.append(price)
    
    def calculate_unrealized_pnl(self, current_price: float) -> float:
        """Calculate unrealized PnL at current market price."""
        if not self.entry_prices:
            return 0.0
        avg_entry = statistics.mean(self.entry_prices)
        return (current_price - avg_entry) * self.base_quantity

@dataclass
class BacktestResult:
    """Aggregated backtesting metrics."""
    total_pnl: float
    fees_paid: float
    realized_pnl: float
    unrealized_pnl: float
    Sharpe_ratio: float
    max_drawdown: float
    win_rate: float
    avg_spread_captured: float
    fill_rate_bids: float
    fill_rate_asks: float
    total_trades: int
    
    def summary(self) -> str:
        return f"""
BACKTEST RESULTS SUMMARY
========================
Total PnL: ${self.total_pnl:,.2f}
Realized PnL: ${self.realized_pnl:,.2f}
Unrealized PnL: ${self.unrealized_pnl:,.2f}
Trading Fees: ${self.fees_paid:,.2f}
Sharpe Ratio: {self.Sharpe_ratio:.3f}
Max Drawdown: ${self.max_drawdown:,.2f}
Win Rate: {self.win_rate:.1%}
Avg Spread Captured: {self.avg_spread_captured:.2f} bps
Bid Fill Rate: {self.fill_rate_bids:.1%}
Ask Fill Rate: {self.fill_rate_asks:.1%}
Total Trades: {self.total_trades}
"""

class MarketMakingBacktester:
    """
    Backtesting engine for market-making strategies on Hyperliquid data.
    
    Simulates order placement, fill mechanics, fees, and PnL calculation
    using historical trade data from Tardis.dev and signals from HolySheep AI.
    """
    
    def __init__(
        self,
        maker_fee: float = -0.0002,  # -0.02% maker rebate
        taker_fee: float = 0.0005,   # 0.05% taker fee
        tick_size: float = 0.01,
        lot_size: float = 0.01,
        max_position: float = 100.0
    ):
        self.maker_fee = maker_fee
        self.taker_fee = taker_fee
        self.tick_size = tick_size
        self.lot_size = lot_size
        self.max_position = max_position
        
        self.position = Position()
        self.orders: List[Order] = []
        self.equity_curve: List[float] = []
        self.trade_log: List[Dict] = []
        
        self.pnl_realized = 0.0
        self.pnl_fees = 0.0
        self.total_bid_fills = 0
        self.total_ask_fills = 0
        self.total_bid_orders = 0
        self.total_ask_orders = 0
    
    def place_order(
        self,
        side: OrderSide,
        price: float,
        size: float,
        timestamp: datetime,
        signal_confidence: float
    ) -> Order:
        """Place a simulated order at specified price level."""
        # Quantize price to tick size
        price = round(price / self.tick_size) * self.tick_size
        size = round(size / self.lot_size) * self.lot_size
        
        order = Order(
            order_id=f"{timestamp.isoformat()}_{side.value}",
            side=side,
            price=price,
            size=size,
            timestamp=timestamp
        )
        
        self.orders.append(order)
        
        if side == OrderSide.BID:
            self.total_bid_orders += 1
        else:
            self.total_ask_orders += 1
        
        return order
    
    def simulate_fills(
        self,
        trades: List[Dict],
        timestamp: datetime,
        spread_bps: float,
        current_price: float
    ):
        """
        Simulate order fills based on incoming trades.
        
        Fills occur when trade price crosses the order price.
        Uses a probabilistic model based on signal confidence.
        """
        for trade in trades:
            trade_price = trade["price"]
            trade_side = OrderSide.BID if trade.get("side") == "buy" else OrderSide.ASK
            trade_size = trade.get("size", 0)
            
            # Check each active order for potential fill
            for order in self.orders:
                if order.filled:
                    continue
                
                fill_probability = self._calculate_fill_probability(
                    order, trade_price, trade_side, spread_bps, current_price
                )
                
                if np.random.random() < fill_probability:
                    self._execute_fill(order, trade_price, trade_size, timestamp)
    
    def _calculate_fill_probability(
        self,
        order: Order,
        trade_price: float,
        trade_side: OrderSide,
        spread_bps: float,
        current_price: float
    ) -> float:
        """
        Calculate probability of order fill.
        
        Factors:
        - Price proximity (closer = higher fill probability)
        - Order book pressure (more trades on opposite side = higher fill)
        - Spread width (wider spread = lower fill probability)
        """
        if order.side == trade_side:
            return 0.0
        
        # Calculate distance from order to current price
        distance_pct = abs(order.price - current_price) / current_price
        spread_width = spread_bps / 10000  # Convert bps to decimal
        
        # Base probability decreases with distance
        if order.side == OrderSide.BID:
            if trade_price <= order.price:
                base_prob = 0.95
            else:
                distance_from_order = (trade_price - order.price) / order.price
                base_prob = max(0, 1 - (distance_from_order / spread_width))
        else:
            if trade_price >= order.price:
                base_prob = 0.95
            else:
                distance_from_order = (order.price - trade_price) / order.price
                base_prob = max(0, 1 - (distance_from_order / spread_width))
        
        # Adjust for spread
        spread_multiplier = min(1.0, 50 / max(spread_bps, 1))
        
        return base_prob * spread_multiplier
    
    def _execute_fill(
        self,
        order: Order,
        fill_price: float,
        fill_size: float,
        timestamp: datetime
    ):
        """Execute a filled order and update position."""
        actual_size = min(order.size, fill_size)
        
        order.filled = True
        order.fill_price = fill_price
        order.fill_time = timestamp
        
        # Update position
        self.position.update_from_fill(order.side, fill_price, actual_size)
        
        # Record fees
        fee = abs(actual_size * fill_price * self.maker_fee)  # Negative = rebate
        self.pnl_fees += fee
        
        # Record trade
        self.trade_log.append({
            "timestamp": timestamp,
            "side": order.side.value,
            "price": fill_price,
            "size": actual_size,
            "fee": fee,
            "position_after": self.position.base_quantity
        })
        
        # Update fill counters
        if order.side == OrderSide.BID:
            self.total_bid_fills += 1
        else:
            self.total_ask_fills += 1
    
    def calculate_metrics(self) -> BacktestResult:
        """Calculate final backtest metrics."""
        
        current_equity = self.position.quote_quantity
        for entry_price in self.position.entry_prices:
            current_equity += self.position.base_quantity * entry_price
        
        # Calculate drawdown
        running_max = 0
        max_drawdown = 0
        for equity in self.equity_curve:
            running_max = max(running_max, equity)
            drawdown = running_max - equity
            max_drawdown = max(max_drawdown, drawdown)
        
        # Calculate Sharpe ratio
        if len(self.equity_curve) > 1:
            returns = np.diff(self.equity_curve) / self.equity_curve[:-1]
            sharpe = np.mean(returns) / np.std(returns) * np.sqrt(252 * 24) if np.std(returns) > 0 else 0
        else:
            sharpe = 0
        
        # Win rate (profitable ticks)
        wins = sum(1 for log in self.trade_log if 
                   (log["side"] == "bid" and log["position_after"] > 0) or
                   (log["side"] == "ask" and log["position_after"] < 0))
        win_rate = wins / max(len(self.trade_log), 1)
        
        # Average spread captured
        spreads = []
        for i in range(1, len(self.trade_log), 2):
            if i < len(self.trade_log):
                bid_trade = self.trade_log[i-1] if self.trade_log[i-1]["side"] == "bid" else self.trade_log[i]
                ask_trade = self.trade_log[i] if self.trade_log[i]["side"] == "ask" else self.trade_log[i-1]
                if bid_trade["price"] and ask_trade["price"]:
                    spread = (ask_trade["price"] - bid_trade["price"]) / bid_trade["price"] * 10000
                    spreads.append(spread)
        
        avg_spread = statistics.mean(spreads) if spreads else 0
        
        return BacktestResult(
            total_pnl=current_equity - self.pnl_fees,
            fees_paid=self.pnl_fees,
            realized_pnl=self.pnl_realized,
            unrealized_pnl=self.position.calculate_unrealized_pnl(self.equity_curve[-1] if self.equity_curve else 0),
            Sharpe_ratio=sharpe,
            max_drawdown=max_drawdown,
            win_rate=win_rate,
            avg_spread_captured=avg_spread,
            fill_rate_bids=self.total_bid_fills / max(self.total_bid_orders, 1),
            fill_rate_asks=self.total_ask_fills / max(self.total_ask_orders, 1),
            total_trades=len(self.trade_log)
        )
    
    def run_backtest(
        self,
        trades_df: pd.DataFrame,
        signals: List,
        initial_capital: float = 100000.0
    ) -> BacktestResult:
        """
        Execute the complete backtest.
        
        Args:
            trades_df: DataFrame with columns [timestamp, price, size, side]
            signals: List of MarketMakingSignal objects from HolySheep AI
            initial_capital: Starting capital in quote currency
        
        Returns:
            BacktestResult with all performance metrics
        """
        self.position.quote_quantity = initial_capital
        self.equity_curve = [initial_capital]
        
        # Group trades by time window
        trades_df = trades_df.sort_values("timestamp")
        
        signal_idx = 0
        window_size = 100  # trades per window
        
        for i in range(0, len(trades_df), window_size):
            window_trades = trades_df.iloc[i:i+window_size].to_dict("records")
            
            if not window_trades:
                continue
            
            current_price = window_trades[-1]["price"]
            timestamp = window_trades[-1]["timestamp"]
            
            # Get signal for this window
            if signal_idx < len(signals):
                signal = signals[signal_idx]
                spread_bps = signal.recommended_spread_bps
                inventory_limit = signal.inventory_skew_threshold
                refresh_ms = signal.order_refresh_ms
            else:
                spread_bps = 10.0
                inventory_limit = 0.1
                refresh_ms = 500
            
            # Place orders at bid and ask
            mid_price = current_price
            bid_price = mid_price * (1 - spread_bps / 10000)
            ask_price = mid_price * (1 + spread_bps / 10000)
            
            # Check inventory limits
            position_skew = abs