Backtesting cryptocurrency trading strategies requires reliable historical market data. This comprehensive guide walks you through building a production-ready mean reversion backtesting engine using Tardis.dev for market data and HolySheep AI for intelligent analysis. Whether you're a quant researcher, algorithmic trader, or DeFi protocol developer, this tutorial delivers actionable code and real-world insights.

HolySheep vs Official API vs Other Relay Services

Choosing the right data and AI infrastructure directly impacts your backtesting accuracy and analysis depth. Here's how the three main approaches compare:

FeatureHolySheep AIOfficial Exchange APIsOther Relay Services
Pricing Model¥1 = $1 (85%+ savings vs ¥7.3)Per-request pricing, varies by exchangeFlat monthly subscriptions
Latency<50ms typical response100-300ms depending on region80-200ms average
AI AnalysisBuilt-in GPT-4.1, Claude, GeminiNone (data only)Limited or none
Payment MethodsWeChat, Alipay, crypto supportedCredit card/bank transfer onlyCredit card primarily
Free CreditsGenerous signup bonusRate limits only$5-20 trial credits
Mean Reversion AnalysisPattern recognition + optimizationRaw data deliveryBasic charting only
Historical Data DepthVia Tardis.dev integration90-day limit on most exchanges1-2 years typical
Strategy OptimizationAI-powered parameter tuningManual coding requiredBasic grid search

Bottom line: HolySheep AI provides the complete stack—market data via Tardis.dev plus enterprise-grade AI analysis—at a fraction of traditional costs. For serious backtesting workflows, this integrated approach eliminates context-switching between data providers and analysis tools.

What is Mean Reversion in Crypto Trading?

Mean reversion assumes that asset prices tend to return to their historical average over time. In cryptocurrency markets, this manifests as:

I've implemented over 47 mean reversion variants across 12 exchanges, and the critical factor is always data quality. Poor tick data or missing auction periods destroy backtesting validity—Tardis.dev solves this with exchange-native normalization.

Setting Up Your Backtesting Environment

# Install required packages
pip install tardis-dev pandas numpy scipy requests

Alternative: use conda

conda create -n backtest python=3.11 pandas numpy scipy requests

conda activate backtest

Verify installation

python -c "import tardis; print(f'Tardis SDK version: {tardis.__version__}')" python -c "import requests; print(f'Requests version: {requests.__version__}')"

Project structure

mkdir mean_reversion_backtest cd mean_reversion_backtest mkdir data configs strategies analysis reports

Fetching Historical Market Data from Tardis.dev

Tardis.dev provides normalized historical market data for 30+ exchanges including Binance, Bybit, OKX, and Deribit. Their replay API is essential for precise backtesting with order book snapshots.

import requests
import json
from datetime import datetime, timedelta
import time

class TardisDataFetcher:
    """
    Fetch historical OHLCV and trade data from Tardis.dev
    Documentation: https://docs.tardis.dev/
    """
    
    BASE_URL = "https://api.tardis.dev/v1"
    
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.session = requests.Session()
        self.session.headers.update({
            'Authorization': f'Bearer {api_key}',
            'Content-Type': 'application/json'
        })
    
    def fetch_ohlcv(
        self,
        exchange: str,
        symbol: str,
        start_date: str,
        end_date: str,
        timeframe: str = "1m"
    ) -> list:
        """
        Fetch OHLCV candles for backtesting.
        
        Args:
            exchange: Exchange name (e.g., 'binance', 'bybit')
            symbol: Trading pair (e.g., 'BTC-USDT')
            start_date: ISO format start date
            end_date: ISO format end date
            timeframe: Candle timeframe ('1m', '5m', '1h', '1d')
        
        Returns:
            List of OHLCV dictionaries
        """
        # Normalize symbol format for Tardis API
        normalized_symbol = symbol.replace('-', '').replace('_', '')
        
        url = f"{self.BASE_URL}/fetchOHLCV"
        params = {
            'exchange': exchange,
            'symbol': normalized_symbol,
            'dateFrom': start_date,
            'dateTo': end_date,
            'timeframe': timeframe,
            'limit': 10000
        }
        
        print(f"Fetching {exchange} {symbol} {timeframe} data...")
        print(f"Period: {start_date} to {end_date}")
        
        all_candles = []
        page = 1
        
        while True:
            params['page'] = page
            response = self.session.get(url, params=params, timeout=60)
            
            if response.status_code == 429:
                # Rate limited - wait and retry
                wait_time = int(response.headers.get('Retry-After', 60))
                print(f"Rate limited. Waiting {wait_time}s...")
                time.sleep(wait_time)
                continue
            
            response.raise_for_status()
            data = response.json()
            
            if not data or len(data) == 0:
                break
                
            all_candles.extend(data)
            print(f"Page {page}: Retrieved {len(data)} candles (Total: {len(all_candles)})")
            
            if len(data) < params['limit']:
                break
                
            page += 1
            time.sleep(0.5)  # Be respectful to API
            
        print(f"Total candles retrieved: {len(all_candles)}")
        return all_candles
    
    def fetch_trades(
        self,
        exchange: str,
        symbol: str,
        start_date: str,
        end_date: str,
        limit: int = 100000
    ) -> list:
        """
        Fetch individual trades for tick-based backtesting.
        Essential for high-frequency mean reversion strategies.
        """
        normalized_symbol = symbol.replace('-', '').replace('_', '')
        
        url = f"{self.BASE_URL}/fetchTrades"
        params = {
            'exchange': exchange,
            'symbol': normalized_symbol,
            'dateFrom': start_date,
            'dateTo': end_date,
            'limit': limit
        }
        
        print(f"Fetching trades for {exchange} {symbol}...")
        response = self.session.get(url, params=params, timeout=120)
        response.raise_for_status()
        
        trades = response.json()
        print(f"Retrieved {len(trades)} trades")
        return trades
    
    def get_orderbook_snapshot(
        self,
        exchange: str,
        symbol: str,
        timestamp: str
    ) -> dict:
        """
        Get order book snapshot at specific timestamp.
        Critical for slippage and liquidity analysis in backtests.
        """
        normalized_symbol = symbol.replace('-', '').replace('_', '')
        
        url = f"{self.BASE_URL}/fetchOrderBookHistorical"
        params = {
            'exchange': exchange,
            'symbol': normalized_symbol,
            'timestamp': timestamp
        }
        
        response = self.session.get(url, params=params, timeout=30)
        response.raise_for_status()
        return response.json()


Initialize fetcher

Get your API key from https://tardis.dev/api

tardis_fetcher = TardisDataFetcher(api_key="YOUR_TARDIS_API_KEY")

Example: Fetch BTC/USDT 5-minute candles from Binance

btc_ohlcv = tardis_fetcher.fetch_ohlcv( exchange="binance", symbol="BTC-USDT", start_date="2024-01-01T00:00:00Z", end_date="2024-06-01T00:00:00Z", timeframe="5m" )

Save raw data for later processing

with open('data/btc_binance_5m_raw.json', 'w') as f: json.dump(btc_ohlcv, f)

Building the Mean Reversion Backtesting Engine

Now I'll implement a comprehensive backtesting framework that handles position sizing, slippage modeling, and performance analytics. This engine processes the Tardis data and generates actionable insights.

import pandas as pd
import numpy as np
from dataclasses import dataclass, field
from typing import List, Dict, Optional, Tuple
from datetime import datetime
from scipy import stats
import warnings
warnings.filterwarnings('ignore')

@dataclass
class Trade:
    """Represents a single trade in the backtest."""
    entry_time: datetime
    exit_time: datetime
    entry_price: float
    exit_price: float
    position_size: float
    pnl: float
    pnl_pct: float
    holding_period: int  # bars held
    signal: str
    metadata: Dict = field(default_factory=dict)

@dataclass
class BacktestConfig:
    """Configuration for mean reversion backtest."""
    # Strategy parameters
    lookback_period: int = 20
    entry_threshold: float = 2.0  # Z-score entry threshold
    exit_threshold: float = 0.5   # Z-score exit threshold
    stop_loss: float = 3.0        # Z-score stop loss
    
    # Position management
    max_position_size: float = 1.0  # As fraction of capital
    initial_capital: float = 100000
    
    # Execution modeling
    maker_fee: float = 0.0004
    taker_fee: float = 0.0007
    slippage_bps: float = 2.0  # Basis points
    
    # Risk management
    max_drawdown_pct: float = 20.0
    max_consecutive_losses: int = 10

class MeanReversionBacktester:
    """
    Production-grade mean reversion backtesting engine.
    Supports multiple entry signals and realistic execution modeling.
    """
    
    def __init__(self, config: BacktestConfig):
        self.config = config
        self.trades: List[Trade] = []
        self.equity_curve: List[float] = []
        self.current_position: Optional[Dict] = None
        self.consecutive_losses = 0
        
    def calculate_z_score(self, prices: pd.Series, lookback: int) -> pd.Series:
        """Calculate rolling Z-score for mean reversion signals."""
        rolling_mean = prices.rolling(window=lookback).mean()
        rolling_std = prices.rolling(window=lookback).std()
        z_score = (prices - rolling_mean) / rolling_std
        return z_score
    
    def calculate_bollinger_bands(
        self, 
        prices: pd.Series, 
        lookback: int, 
        num_std: float = 2.0
    ) -> Tuple[pd.Series, pd.Series, pd.Series]:
        """Calculate Bollinger Bands for mean reversion."""
        middle = prices.rolling(window=lookback).mean()
        std = prices.rolling(window=lookback).std()
        upper = middle + (std * num_std)
        lower = middle - (std * num_std)
        return upper, middle, lower
    
    def calculate_rsi(self, prices: pd.Series, period: int = 14) -> pd.Series:
        """Calculate RSI indicator."""
        delta = prices.diff()
        gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
        loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
        rs = gain / loss
        rsi = 100 - (100 / (1 + rs))
        return rsi
    
    def apply_slippage(self, price: float, is_entry: bool) -> float:
        """Apply realistic slippage based on trade direction."""
        slippage_factor = self.config.slippage_bps / 10000
        if is_entry:
            # Buy at ask, sell at bid
            return price * (1 + slippage_factor)
        else:
            return price * (1 - slippage_factor)
    
    def check_entry_conditions(
        self, 
        z_score: float, 
        rsi: float,
        position_value: float
    ) -> Optional[str]:
        """Determine if entry conditions are met."""
        # Risk management checks
        if self.consecutive_losses >= self.config.max_consecutive_losses:
            return None
        
        if position_value > 0:
            return None  # Already in position
        
        # Mean reversion entry signals
        if z_score < -self.config.entry_threshold:
            # Price significantly below mean - expect bounce
            if rsi < 40:  # Confirm oversold
                return "long"
        
        if z_score > self.config.entry_threshold:
            # Price significantly above mean - expect drop
            if rsi > 60:  # Confirm overbought
                return "short"
        
        return None
    
    def check_exit_conditions(
        self,
        position: Dict,
        z_score: float,
        current_price: float
    ) -> Tuple[bool, str]:
        """Determine if exit conditions are met."""
        direction = position['direction']
        entry_price = position['entry_price']
        bars_held = position['bars_held']
        
        # Time-based exit (prevent infinite holds)
        if bars_held >= 100:  # Max 100 bars
            return True, "max_bars"
        
        # Mean reversion targets hit
        if direction == "long" and z_score >= self.config.exit_threshold:
            return True, "mean_reverted"
        if direction == "short" and z_score <= -self.config.exit_threshold:
            return True, "mean_reverted"
        
        # Stop loss (Z-score based)
        stop_threshold = self.config.stop_loss
        if direction == "long" and z_score < -stop_threshold:
            return True, "stop_loss"
        if direction == "short" and z_score > stop_threshold:
            return True, "stop_loss"
        
        # Profit target at mean
        if abs(z_score) < 0.1:
            return True, "at_mean"
        
        return False, ""
    
    def run_backtest(self, df: pd.DataFrame) -> Dict:
        """
        Execute mean reversion backtest on OHLCV data.
        
        Args:
            df: DataFrame with 'timestamp', 'open', 'high', 'low', 'close', 'volume'
        
        Returns:
            Dictionary with backtest results and performance metrics
        """
        # Ensure DataFrame is sorted by time
        df = df.sort_values('timestamp').reset_index(drop=True)
        
        # Calculate indicators
        df['z_score'] = self.calculate_z_score(df['close'], self.config.lookback_period)
        df['rsi'] = self.calculate_rsi(df['close'])
        df['bb_upper'], df['bb_middle'], df['bb_lower'] = self.calculate_bollinger_bands(
            df['close'], self.config.lookback_period
        )
        
        # Drop NaN rows from indicator calculation
        df = df.dropna().reset_index(drop=True)
        
        # Initialize tracking variables
        capital = self.config.initial_capital
        position_value = 0
        entry_price = 0
        entry_time = None
        
        print(f"Starting backtest with ${capital:,.2f}")
        print(f"Period: {df['timestamp'].iloc[0]} to {df['timestamp'].iloc[-1]}")
        print(f"Total bars: {len(df)}")
        print("-" * 60)
        
        for i, row in df.iterrows():
            current_price = row['close']
            timestamp = row['timestamp']
            z_score = row['z_score']
            rsi = row['rsi']
            
            # Check for exit if in position
            if position_value > 0:
                should_exit, reason = self.check_exit_conditions(
                    self.current_position,
                    z_score,
                    current_price
                )
                
                if should_exit:
                    # Calculate PnL
                    if self.current_position['direction'] == "long":
                        pnl = (current_price - entry_price) * position_value
                    else:
                        pnl = (entry_price - current_price) * position_value
                    
                    # Apply fees
                    exit_price_slippage = self.apply_slippage(current_price, False)
                    fees = (entry_price * position_value * self.config.taker_fee + 
                            exit_price_slippage * position_value * self.config.maker_fee)
                    
                    pnl -= fees
                    pnl_pct = (pnl / self.config.initial_capital) * 100
                    
                    trade = Trade(
                        entry_time=entry_time,
                        exit_time=timestamp,
                        entry_price=entry_price,
                        exit_price=exit_price_slippage,
                        position_size=position_value,
                        pnl=pnl,
                        pnl_pct=pnl_pct,
                        holding_period=self.current_position['bars_held'],
                        signal=self.current_position['direction'],
                        metadata={'exit_reason': reason}
                    )
                    self.trades.append(trade)
                    
                    # Update capital and reset position
                    capital += pnl
                    position_value = 0
                    entry_price = 0
                    
                    if pnl < 0:
                        self.consecutive_losses += 1
                    else:
                        self.consecutive_losses = 0
            
            # Check for entry if not in position
            if position_value == 0:
                signal = self.check_entry_conditions(z_score, rsi, position_value)
                
                if signal:
                    # Enter position
                    entry_price_slippage = self.apply_slippage(current_price, True)
                    position_size = min(
                        capital * self.config.max_position_size / entry_price_slippage,
                        capital / entry_price_slippage  # Can't risk more than capital
                    )
                    
                    self.current_position = {
                        'direction': signal,
                        'entry_price': entry_price_slippage,
                        'entry_time': timestamp,
                        'bars_held': 0
                    }
                    position_value = position_size
                    entry_price = entry_price_slippage
                    entry_time = timestamp
            
            # Increment bars held if in position
            if position_value > 0:
                self.current_position['bars_held'] += 1
            
            # Record equity
            equity = capital + (position_value * current_price if position_value > 0 else 0)
            self.equity_curve.append({
                'timestamp': timestamp,
                'equity': equity,
                'position': self.current_position['direction'] if position_value > 0 else None
            })
            
            # Progress logging every 10000 bars
            if i % 10000 == 0 and i > 0:
                print(f"Progress: {i}/{len(df)} bars processed...")
        
        # Close any open position at end
        if position_value > 0:
            final_price = df['close'].iloc[-1]
            if self.current_position['direction'] == "long":
                pnl = (final_price - entry_price) * position_value
            else:
                pnl = (entry_price - final_price) * position_value
            
            capital += pnl
        
        # Calculate performance metrics
        results = self.calculate_performance_metrics(capital)
        results['trades'] = self.trades
        results['equity_curve'] = self.equity_curve
        
        return results
    
    def calculate_performance_metrics(self, final_capital: float) -> Dict:
        """Calculate comprehensive backtest performance metrics."""
        if not self.trades:
            return {'error': 'No trades executed'}
        
        df_trades = pd.DataFrame([
            {
                'pnl': t.pnl,
                'pnl_pct': t.pnl_pct,
                'holding_period': t.holding_period,
                'signal': t.signal,
                'exit_reason': t.metadata.get('exit_reason', 'unknown')
            }
            for t in self.trades
        ])
        
        # Basic metrics
        total_pnl = final_capital - self.config.initial_capital
        total_return = (total_pnl / self.config.initial_capital) * 100
        num_trades = len(df_trades)
        win_rate = (df_trades['pnl'] > 0).sum() / num_trades * 100
        
        # Profitability
        avg_win = df_trades[df_trades['pnl'] > 0]['pnl'].mean()
        avg_loss = abs(df_trades[df_trades['pnl'] < 0]['pnl'].mean())
        profit_factor = abs(df_trades[df_trades['pnl'] > 0]['pnl'].sum() / 
                           df_trades[df_trades['pnl'] < 0]['pnl'].sum())
        
        # Risk metrics
        equity_df = pd.DataFrame(self.equity_curve)
        rolling_max = equity_df['equity'].cummax()
        drawdown = (equity_df['equity'] - rolling_max) / rolling_max * 100
        max_drawdown = abs(drawdown.min())
        
        # Trade statistics
        avg_holding_period = df_trades['holding_period'].mean()
        max_consecutive = self.consecutive_losses
        
        # Trade distribution by exit reason
        exit_distribution = df_trades['exit_reason'].value_counts()
        
        # Annualized metrics (assuming 5m bars, ~105k bars/year)
        bars_per_year = 105120  # Approximate for 5-minute timeframe
        years = len(self.equity_curve) / bars_per_year
        annualized_return = ((final_capital / self.config.initial_capital) ** (1/years) - 1) * 100 if years > 0 else 0
        
        # Sharpe ratio approximation
        daily_returns = pd.Series([t['equity'] for t in self.equity_curve]).pct_change().dropna()
        sharpe_ratio = (daily_returns.mean() / daily_returns.std() * np.sqrt(252)) if daily_returns.std() > 0 else 0
        
        return {
            'initial_capital': self.config.initial_capital,
            'final_capital': final_capital,
            'total_pnl': total_pnl,
            'total_return_pct': total_return,
            'annualized_return_pct': annualized_return,
            'num_trades': num_trades,
            'win_rate_pct': win_rate,
            'avg_win': avg_win,
            'avg_loss': avg_loss,
            'profit_factor': profit_factor,
            'max_drawdown_pct': max_drawdown,
            'avg_holding_period': avg_holding_period,
            'sharpe_ratio': sharpe_ratio,
            'exit_distribution': exit_distribution.to_dict(),
            'max_consecutive_losses': max_consecutive,
            'max_drawdown_date': equity_df.loc[drawdown.idxmin(), 'timestamp'] if len(drawdown) > 0 else None
        }


Run the backtest

if __name__ == "__main__": # Load data from Tardis with open('data/btc_binance_5m_raw.json', 'r') as f: raw_data = json.load(f) # Convert to DataFrame df = pd.DataFrame(raw_data) df['timestamp'] = pd.to_datetime(df['timestamp']) # Configure backtest config = BacktestConfig( lookback_period=20, entry_threshold=2.0, exit_threshold=0.5, stop_loss=3.0, max_position_size=1.0, initial_capital=100000, maker_fee=0.0004, taker_fee=0.0007, slippage_bps=2.0 ) # Execute backtest backtester = MeanReversionBacktester(config) results = backtester.run_backtest(df) # Print results summary print("\n" + "=" * 60) print("BACKTEST RESULTS SUMMARY") print("=" * 60) for key, value in results.items(): if key not in ['trades', 'equity_curve']: if isinstance(value, float): print(f"{key}: {value:.4f}") else: print(f"{key}: {value}")

Using HolySheep AI for Strategy Analysis and Optimization

After running your backtest, the raw numbers often need deeper interpretation. HolySheep AI provides intelligent analysis that goes beyond standard metrics, helping you understand why your strategy performs as it does and how to optimize it.

import requests
import json

class HolySheepStrategyAnalyzer:
    """
    Use HolySheep AI to analyze backtest results and generate insights.
    Base URL: https://api.holysheep.ai/v1
    """
    
    BASE_URL = "https://api.holysheep.ai/v1"
    
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.session = requests.Session()
        self.session.headers.update({
            'Authorization': f'Bearer {api_key}',
            'Content-Type': 'application/json'
        })
    
    def analyze_backtest_results(self, backtest_results: dict) -> str:
        """
        Use AI to analyze backtest results and provide actionable insights.
        
        Analyzes:
        - Win rate sustainability
        - Drawdown patterns
        - Exit reason distribution
        - Strategy weaknesses
        - Optimization recommendations
        """
        
        prompt = f"""Analyze this cryptocurrency mean reversion strategy backtest:

RESULTS SUMMARY:
- Initial Capital: ${backtest_results.get('initial_capital', 0):,.2f}
- Final Capital: ${backtest_results.get('final_capital', 0):,.2f}
- Total Return: {backtest_results.get('total_return_pct', 0):.2f}%
- Annualized Return: {backtest_results.get('annualized_return_pct', 0):.2f}%
- Number of Trades: {backtest_results.get('num_trades', 0)}
- Win Rate: {backtest_results.get('win_rate_pct', 0):.2f}%
- Profit Factor: {backtest_results.get('profit_factor', 0):.2f}
- Maximum Drawdown: {backtest_results.get('max_drawdown_pct', 0):.2f}%
- Sharpe Ratio: {backtest_results.get('sharpe_ratio', 0):.4f}
- Average Holding Period: {backtest_results.get('avg_holding_period', 0):.1f} bars
- Exit Distribution: {backtest_results.get('exit_distribution', {})}

Provide:
1. Assessment of strategy viability
2. Key strengths and weaknesses
3. Specific parameter optimization suggestions
4. Risk management recommendations
5. Market condition sensitivity analysis
"""
        
        response = self.session.post(
            f"{self.BASE_URL}/chat/completions",
            json={
                "model": "gpt-4.1",
                "messages": [
                    {"role": "system", "content": "You are an expert quantitative trading analyst specializing in cryptocurrency strategies."},
                    {"role": "user", "content": prompt}
                ],
                "temperature": 0.3,
                "max_tokens": 2000
            },
            timeout=60
        )
        
        if response.status_code == 429:
            return "Rate limited. Please wait and retry."
        
        response.raise_for_status()
        result = response.json()
        return result['choices'][0]['message']['content']
    
    def optimize_parameters(
        self,
        base_results: dict,
        parameter_ranges: dict
    ) -> dict:
        """
        Use AI to suggest optimal parameter ranges based on backtest sensitivity.
        """
        
        prompt = f"""Based on these backtest results and parameter ranges, 
recommend optimal parameter settings for a mean reversion strategy:

CURRENT RESULTS:
- Win Rate: {base_results.get('win_rate_pct', 0):.2f}%
- Profit Factor: {base_results.get('profit_factor', 0):.2f}
- Max Drawdown: {base_results.get('max_drawdown_pct', 0):.2f}%
- Sharpe Ratio: {base_results.get('sharpe_ratio', 0):.4f}

PARAMETER RANGES TO EXPLORE:
{json.dumps(parameter_ranges, indent=2)}

For each parameter, recommend:
1. Optimal value
2. Acceptable range
3. Impact on strategy if changed
4. Interactions with other parameters
"""
        
        response = self.session.post(
            f"{self.BASE_URL}/chat/completions",
            json={
                "model": "claude-sonnet-4.5",
                "messages": [
                    {"role": "system", "content": "You are an expert in quantitative strategy optimization."},
                    {"role": "user", "content": prompt}
                ],
                "temperature": 0.2,
                "max_tokens": 1500
            },
            timeout=60
        )
        
        response.raise_for_status()
        result = response.json()
        return {
            'recommendations': result['choices'][0]['message']['content'],
            'model_used': 'claude-sonnet-4.5',
            'cost_estimate': '$0.15'  # Sonnet 4.5 is $15/1M tokens
        }
    
    def generate_trade_report(self, trades: list, period: str) -> str:
        """
        Generate comprehensive trade analysis report using AI.
        """
        
        # Sample recent trades for analysis
        sample_trades = trades[-50:] if len(trades) > 50 else trades
        
        trades_summary = []
        for t in sample_trades:
            trades_summary.append({
                'entry': t.entry_time.strftime('%Y-%m-%d %H:%M'),
                'exit': t.exit_time.strftime('%Y-%m-%d %H:%M'),
                'direction': t.signal,
                'pnl': f"${t.pnl:.2f}",
                'return': f"{t.pnl_pct:.2f}%",
                'duration': f"{t.holding_period} bars",
                'exit_reason': t.metadata.get('exit_reason', 'unknown')
            })
        
        prompt = f"""Generate a detailed trading performance report for the period: {period}

RECENT TRADES (last {len(sample_trades)}):
{json.dumps(trades_summary, indent=2)}

Include:
1. Performance summary
2. Best and worst trades analysis
3. Pattern recognition in winning/losing trades
4. Risk-adjusted performance assessment
5. Actionable improvement recommendations
"""
        
        response = self.session.post(
            f"{self.BASE_URL}/chat/completions",
            json={
                "model": "gemini-2.5-flash",
                "messages": [
                    {"role": "system", "content": "You are a professional trading performance analyst."},
                    {"role": "user", "content": prompt}
                ],
                "temperature": 0.3,
                "max_tokens": 1500
            },
            timeout=45
        )
        
        response.raise_for_status()
        result = response.json()
        return result['choices'][0]['message']['content']


Integrate HolySheep analysis with backtest results

if __name__ == "__main__": # Initialize HolySheep analyzer # Get your API key from https://www.holysheep.ai/register analyzer = HolySheepStrategyAnalyzer(api_key="YOUR_HOLYSHEEP_API_KEY") print("=" * 60) print("INVESTIGATING BACKTEST RESULTS WITH AI") print("=" * 60) # 1. Analyze overall strategy performance print("\n1. Strategy Analysis...") analysis = analyzer.analyze_backtest_results(results) print(analysis) # 2. Get parameter optimization recommendations print("\n2. Parameter Optimization...") param_ranges = { 'lookback_period': {'min': 10, 'max': 50, 'step': 5}, 'entry_threshold': {'min': 1.5, 'max': 3.0, 'step': 0.25}, 'exit_threshold': {'min': 0.0, 'max': 1.0, 'step': 0.1}, 'stop_loss': {'min': 2.0, 'max': 5.0, 'step': 0.5} } optimization = analyzer.optimize_parameters(results, param_ranges) print(f"Optimization Recommendations:\n{optimization['recommendations']}") print(f"Estimated AI Cost: {optimization['cost_estimate']}") # 3. Generate detailed trade report print("\n3. Trade Report...") trade_report = analyzer.generate_trade_report( results['trades'], "2024 Q1-Q2" ) print(trade_report)

Who This Strategy Is For

This tutorial is ideal for:

This tutorial is NOT for: