"""LEAN Engine backtesting tools for Sigma.

Generate QuantConnect LEAN-compatible Python algorithms for backtesting trading strategies.
"""

import os
import json
from datetime import datetime, timedelta
from typing import Any, Optional


# LEAN Algorithm Templates
LEAN_BASE_TEMPLATE = '''# LEAN Algorithm - Generated by Sigma
# Strategy: {strategy_name}
# Generated: {timestamp}
# Symbol: {symbol}

from AlgorithmImports import *


class {class_name}(QCAlgorithm):
    """
    {strategy_description}
    
    Generated by Sigma Financial Research Agent
    """
    
    def Initialize(self):
        """Initialize algorithm parameters and data."""
        # Backtest period
        self.SetStartDate({start_year}, {start_month}, {start_day})
        self.SetEndDate({end_year}, {end_month}, {end_day})
        
        # Starting capital
        self.SetCash({initial_capital})
        
        # Add securities
        self.symbol = self.AddEquity("{symbol}", Resolution.Daily).Symbol
        
        # Strategy parameters
{strategy_params}
        
        # Indicators
{indicators}
        
        # Tracking variables
        self.previous_price = 0
        self.trade_count = 0
        
    def OnData(self, data: Slice):
        """Handle incoming data and execute strategy logic."""
        if not data.Bars.ContainsKey(self.symbol):
            return
        
        bar = data.Bars[self.symbol]
        price = bar.Close
        
{strategy_logic}
        
        self.previous_price = price
    
    def OnOrderEvent(self, orderEvent):
        """Handle order events."""
        if orderEvent.Status == OrderStatus.Filled:
            self.trade_count += 1
            self.Debug(f"Order filled: {{orderEvent.Symbol}} {{orderEvent.FillQuantity}} @ {{orderEvent.FillPrice}}")
    
    def OnEndOfAlgorithm(self):
        """Called at end of backtest."""
        self.Debug(f"Total trades executed: {{self.trade_count}}")
'''

# Strategy-specific templates
STRATEGY_TEMPLATES = {
    "sma_crossover": {
        "name": "SMA Crossover",
        "description": "Classic moving average crossover strategy. Goes long when fast SMA crosses above slow SMA, exits when it crosses below.",
        "params": '''        self.fast_period = {fast_period}
        self.slow_period = {slow_period}
        self.position_size = {position_size}  # Fraction of portfolio''',
        "indicators": '''        self.fast_sma = self.SMA(self.symbol, self.fast_period, Resolution.Daily)
        self.slow_sma = self.SMA(self.symbol, self.slow_period, Resolution.Daily)
        
        # Warm up indicators
        self.SetWarmUp(self.slow_period)''',
        "logic": '''        # Wait for indicators to warm up
        if self.IsWarmingUp:
            return
        
        if not self.fast_sma.IsReady or not self.slow_sma.IsReady:
            return
        
        holdings = self.Portfolio[self.symbol].Quantity
        
        # Buy signal: fast SMA crosses above slow SMA
        if self.fast_sma.Current.Value > self.slow_sma.Current.Value:
            if holdings <= 0:
                self.SetHoldings(self.symbol, self.position_size)
                self.Debug(f"BUY: Fast SMA ({self.fast_sma.Current.Value:.2f}) > Slow SMA ({self.slow_sma.Current.Value:.2f})")
        
        # Sell signal: fast SMA crosses below slow SMA
        elif self.fast_sma.Current.Value < self.slow_sma.Current.Value:
            if holdings > 0:
                self.Liquidate(self.symbol)
                self.Debug(f"SELL: Fast SMA ({self.fast_sma.Current.Value:.2f}) < Slow SMA ({self.slow_sma.Current.Value:.2f})")''',
        "default_params": {"fast_period": 10, "slow_period": 30, "position_size": 0.95}
    },
    
    "rsi_mean_reversion": {
        "name": "RSI Mean Reversion",
        "description": "Mean reversion strategy using RSI. Buys when RSI is oversold and sells when overbought.",
        "params": '''        self.rsi_period = {rsi_period}
        self.oversold = {oversold}
        self.overbought = {overbought}
        self.position_size = {position_size}''',
        "indicators": '''        self.rsi = self.RSI(self.symbol, self.rsi_period, MovingAverageType.Wilders, Resolution.Daily)
        
        # Warm up
        self.SetWarmUp(self.rsi_period * 2)''',
        "logic": '''        if self.IsWarmingUp or not self.rsi.IsReady:
            return
        
        holdings = self.Portfolio[self.symbol].Quantity
        rsi_value = self.rsi.Current.Value
        
        # Buy when oversold
        if rsi_value < self.oversold:
            if holdings <= 0:
                self.SetHoldings(self.symbol, self.position_size)
                self.Debug(f"BUY: RSI oversold at {rsi_value:.2f}")
        
        # Sell when overbought
        elif rsi_value > self.overbought:
            if holdings > 0:
                self.Liquidate(self.symbol)
                self.Debug(f"SELL: RSI overbought at {rsi_value:.2f}")''',
        "default_params": {"rsi_period": 14, "oversold": 30, "overbought": 70, "position_size": 0.95}
    },
    
    "macd_momentum": {
        "name": "MACD Momentum",
        "description": "Momentum strategy using MACD histogram. Enters on positive histogram, exits on negative.",
        "params": '''        self.fast_period = {fast_period}
        self.slow_period = {slow_period}
        self.signal_period = {signal_period}
        self.position_size = {position_size}''',
        "indicators": '''        self.macd = self.MACD(self.symbol, self.fast_period, self.slow_period, self.signal_period, 
                               MovingAverageType.Exponential, Resolution.Daily)
        
        # Warm up
        self.SetWarmUp(self.slow_period + self.signal_period)''',
        "logic": '''        if self.IsWarmingUp or not self.macd.IsReady:
            return
        
        holdings = self.Portfolio[self.symbol].Quantity
        histogram = self.macd.Histogram.Current.Value
        
        # Buy when histogram turns positive
        if histogram > 0:
            if holdings <= 0:
                self.SetHoldings(self.symbol, self.position_size)
                self.Debug(f"BUY: MACD histogram positive at {histogram:.4f}")
        
        # Sell when histogram turns negative
        elif histogram < 0:
            if holdings > 0:
                self.Liquidate(self.symbol)
                self.Debug(f"SELL: MACD histogram negative at {histogram:.4f}")''',
        "default_params": {"fast_period": 12, "slow_period": 26, "signal_period": 9, "position_size": 0.95}
    },
    
    "bollinger_bands": {
        "name": "Bollinger Bands",
        "description": "Mean reversion strategy using Bollinger Bands. Buys at lower band, sells at upper band.",
        "params": '''        self.bb_period = {bb_period}
        self.std_dev = {std_dev}
        self.position_size = {position_size}''',
        "indicators": '''        self.bb = self.BB(self.symbol, self.bb_period, self.std_dev, Resolution.Daily)
        
        # Warm up
        self.SetWarmUp(self.bb_period)''',
        "logic": '''        if self.IsWarmingUp or not self.bb.IsReady:
            return
        
        holdings = self.Portfolio[self.symbol].Quantity
        upper = self.bb.UpperBand.Current.Value
        lower = self.bb.LowerBand.Current.Value
        middle = self.bb.MiddleBand.Current.Value
        
        # Buy at lower band
        if price <= lower:
            if holdings <= 0:
                self.SetHoldings(self.symbol, self.position_size)
                self.Debug(f"BUY: Price ({price:.2f}) at lower band ({lower:.2f})")
        
        # Sell at upper band
        elif price >= upper:
            if holdings > 0:
                self.Liquidate(self.symbol)
                self.Debug(f"SELL: Price ({price:.2f}) at upper band ({upper:.2f})")''',
        "default_params": {"bb_period": 20, "std_dev": 2, "position_size": 0.95}
    },
    
    "dual_momentum": {
        "name": "Dual Momentum",
        "description": "Trend-following strategy using both absolute and relative momentum.",
        "params": '''        self.lookback = {lookback}
        self.position_size = {position_size}
        self.benchmark = self.AddEquity("SPY", Resolution.Daily).Symbol''',
        "indicators": '''        self.mom = self.MOM(self.symbol, self.lookback, Resolution.Daily)
        self.benchmark_mom = self.MOM(self.benchmark, self.lookback, Resolution.Daily)
        
        # Risk-free rate proxy
        self.bond = self.AddEquity("TLT", Resolution.Daily).Symbol
        
        # Warm up
        self.SetWarmUp(self.lookback)''',
        "logic": '''        if self.IsWarmingUp or not self.mom.IsReady:
            return
        
        holdings = self.Portfolio[self.symbol].Quantity
        stock_mom = self.mom.Current.Value
        bench_mom = self.benchmark_mom.Current.Value
        
        # Absolute momentum: only invest if positive
        # Relative momentum: invest in stock if beats benchmark
        if stock_mom > 0 and stock_mom > bench_mom:
            if holdings <= 0:
                self.SetHoldings(self.symbol, self.position_size)
                self.Debug(f"BUY: Dual momentum positive (Stock: {stock_mom:.2f}, Bench: {bench_mom:.2f})")
        else:
            if holdings > 0:
                self.Liquidate(self.symbol)
                self.Debug(f"SELL: Dual momentum negative")''',
        "default_params": {"lookback": 252, "position_size": 0.95}
    },
    
    "breakout": {
        "name": "Breakout Strategy",
        "description": "Donchian channel breakout strategy. Enters on new highs, exits on new lows.",
        "params": '''        self.entry_period = {entry_period}
        self.exit_period = {exit_period}
        self.position_size = {position_size}''',
        "indicators": '''        self.entry_high = self.MAX(self.symbol, self.entry_period, Resolution.Daily)
        self.exit_low = self.MIN(self.symbol, self.exit_period, Resolution.Daily)
        
        # Warm up
        self.SetWarmUp(max(self.entry_period, self.exit_period))''',
        "logic": '''        if self.IsWarmingUp or not self.entry_high.IsReady:
            return
        
        holdings = self.Portfolio[self.symbol].Quantity
        highest = self.entry_high.Current.Value
        lowest = self.exit_low.Current.Value
        
        # Buy on breakout above highest high
        if price >= highest:
            if holdings <= 0:
                self.SetHoldings(self.symbol, self.position_size)
                self.Debug(f"BUY: Breakout above {highest:.2f}")
        
        # Sell on breakdown below lowest low
        elif price <= lowest:
            if holdings > 0:
                self.Liquidate(self.symbol)
                self.Debug(f"SELL: Breakdown below {lowest:.2f}")''',
        "default_params": {"entry_period": 20, "exit_period": 10, "position_size": 0.95}
    }
}


def get_available_strategies() -> dict[str, dict]:
    """Get list of available backtesting strategies."""
    return {
        name: {
            "name": s["name"],
            "description": s["description"],
            "default_params": s["default_params"]
        }
        for name, s in STRATEGY_TEMPLATES.items()
    }


def generate_lean_algorithm(
    symbol: str,
    strategy: str,
    start_date: Optional[str] = None,
    end_date: Optional[str] = None,
    initial_capital: float = 100000,
    params: Optional[dict] = None,
    output_dir: Optional[str] = None,
) -> dict[str, Any]:
    """Generate a LEAN-compatible Python algorithm file.
    
    Args:
        symbol: Stock ticker symbol
        strategy: Strategy type (sma_crossover, rsi_mean_reversion, etc.)
        start_date: Backtest start date (YYYY-MM-DD)
        end_date: Backtest end date (YYYY-MM-DD)
        initial_capital: Starting capital
        params: Strategy-specific parameters (optional)
        output_dir: Directory to save the file (optional)
        
    Returns:
        Dict with file path and algorithm details
    """
    if strategy not in STRATEGY_TEMPLATES:
        available = list(STRATEGY_TEMPLATES.keys())
        return {"error": f"Unknown strategy '{strategy}'. Available: {available}"}
    
    template = STRATEGY_TEMPLATES[strategy]
    
    # Parse dates
    if start_date:
        start = datetime.strptime(start_date, "%Y-%m-%d")
    else:
        start = datetime.now() - timedelta(days=365 * 2)  # 2 years back
    
    if end_date:
        end = datetime.strptime(end_date, "%Y-%m-%d")
    else:
        end = datetime.now()
    
    # Merge default params with custom params
    strategy_params = template["default_params"].copy()
    if params:
        strategy_params.update(params)
    
    # Create class name
    class_name = f"Sigma{strategy.title().replace('_', '')}Algorithm"
    
    # Format params
    params_code = template["params"].format(**strategy_params)
    indicators_code = template["indicators"]
    logic_code = template["logic"]
    
    # Generate the algorithm
    algorithm_code = LEAN_BASE_TEMPLATE.format(
        strategy_name=template["name"],
        timestamp=datetime.now().isoformat(),
        symbol=symbol.upper(),
        class_name=class_name,
        strategy_description=template["description"],
        start_year=start.year,
        start_month=start.month,
        start_day=start.day,
        end_year=end.year,
        end_month=end.month,
        end_day=end.day,
        initial_capital=int(initial_capital),
        strategy_params=params_code,
        indicators=indicators_code,
        strategy_logic=logic_code,
    )
    
    # Create output directory
    if output_dir is None:
        output_dir = os.path.expanduser("~/sigma_backtests")
    
    os.makedirs(output_dir, exist_ok=True)
    
    # Save algorithm file
    filename = f"{symbol.lower()}_{strategy}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.py"
    filepath = os.path.join(output_dir, filename)
    
    with open(filepath, 'w') as f:
        f.write(algorithm_code)
    
    # Also save config
    config = {
        "algorithm-type-name": class_name,
        "algorithm-language": "Python",
        "parameters": strategy_params,
        "symbol": symbol.upper(),
        "strategy": strategy,
        "start_date": start.strftime("%Y-%m-%d"),
        "end_date": end.strftime("%Y-%m-%d"),
        "initial_capital": initial_capital,
    }
    
    config_path = filepath.replace('.py', '_config.json')
    with open(config_path, 'w') as f:
        json.dump(config, f, indent=2)
    
    return {
        "success": True,
        "algorithm_file": filepath,
        "config_file": config_path,
        "class_name": class_name,
        "strategy": template["name"],
        "description": template["description"],
        "symbol": symbol.upper(),
        "period": f"{start.strftime('%Y-%m-%d')} to {end.strftime('%Y-%m-%d')}",
        "initial_capital": f"${initial_capital:,.0f}",
        "parameters": strategy_params,
        "instructions": [
            "1. Install LEAN: pip install lean",
            "2. Initialize workspace: lean init",
            f"3. Copy {filename} to your LEAN project",
            "4. Run backtest: lean backtest <project-name>",
            "Or upload to QuantConnect.com for cloud backtesting"
        ]
    }


def generate_custom_algorithm(
    symbol: str,
    entry_conditions: list[str],
    exit_conditions: list[str],
    indicators: list[str],
    start_date: Optional[str] = None,
    end_date: Optional[str] = None,
    initial_capital: float = 100000,
    output_dir: Optional[str] = None,
) -> dict[str, Any]:
    """Generate a custom LEAN algorithm with user-specified conditions.
    
    Args:
        symbol: Stock ticker
        entry_conditions: List of entry condition descriptions
        exit_conditions: List of exit condition descriptions
        indicators: List of indicators to use
        
    Returns:
        Dict with file path and details
    """
    # Map indicator names to LEAN code
    indicator_map = {
        "sma": ("SMA", "sma_{period}", "self.SMA(self.symbol, {period}, Resolution.Daily)"),
        "ema": ("EMA", "ema_{period}", "self.EMA(self.symbol, {period}, Resolution.Daily)"),
        "rsi": ("RSI", "rsi", "self.RSI(self.symbol, 14, MovingAverageType.Wilders, Resolution.Daily)"),
        "macd": ("MACD", "macd", "self.MACD(self.symbol, 12, 26, 9, MovingAverageType.Exponential, Resolution.Daily)"),
        "bb": ("Bollinger Bands", "bb", "self.BB(self.symbol, 20, 2, Resolution.Daily)"),
        "atr": ("ATR", "atr", "self.ATR(self.symbol, 14, Resolution.Daily)"),
        "adx": ("ADX", "adx", "self.ADX(self.symbol, 14, Resolution.Daily)"),
    }
    
    # Build indicator code
    indicator_code_lines = []
    for ind in indicators:
        ind_lower = ind.lower()
        for key, (name, var, code) in indicator_map.items():
            if key in ind_lower:
                indicator_code_lines.append(f"        self.{var} = {code}")
                break
    
    indicator_code = "\n".join(indicator_code_lines) if indicator_code_lines else "        pass  # No indicators"
    
    # Build entry/exit logic (basic template)
    entry_comment = "\n".join([f"        # Entry: {c}" for c in entry_conditions])
    exit_comment = "\n".join([f"        # Exit: {c}" for c in exit_conditions])
    
    logic_code = f'''        {entry_comment}
        # TODO: Implement entry logic based on conditions above
        
        {exit_comment}
        # TODO: Implement exit logic based on conditions above
        
        holdings = self.Portfolio[self.symbol].Quantity
        
        # Example entry (customize based on your conditions)
        if not self.Portfolio[self.symbol].Invested:
            self.SetHoldings(self.symbol, 0.95)
            self.Debug(f"BUY at {{price}}")'''
    
    # Parse dates
    if start_date:
        start = datetime.strptime(start_date, "%Y-%m-%d")
    else:
        start = datetime.now() - timedelta(days=365 * 2)
    
    if end_date:
        end = datetime.strptime(end_date, "%Y-%m-%d")
    else:
        end = datetime.now()
    
    # Generate algorithm
    algorithm_code = LEAN_BASE_TEMPLATE.format(
        strategy_name="Custom Strategy",
        timestamp=datetime.now().isoformat(),
        symbol=symbol.upper(),
        class_name="SigmaCustomAlgorithm",
        strategy_description=f"Custom strategy for {symbol.upper()}\nEntry: {', '.join(entry_conditions)}\nExit: {', '.join(exit_conditions)}",
        start_year=start.year,
        start_month=start.month,
        start_day=start.day,
        end_year=end.year,
        end_month=end.month,
        end_day=end.day,
        initial_capital=int(initial_capital),
        strategy_params="        self.position_size = 0.95",
        indicators=indicator_code,
        strategy_logic=logic_code,
    )
    
    # Save
    if output_dir is None:
        output_dir = os.path.expanduser("~/sigma_backtests")
    
    os.makedirs(output_dir, exist_ok=True)
    filename = f"{symbol.lower()}_custom_{datetime.now().strftime('%Y%m%d_%H%M%S')}.py"
    filepath = os.path.join(output_dir, filename)
    
    with open(filepath, 'w') as f:
        f.write(algorithm_code)
    
    return {
        "success": True,
        "algorithm_file": filepath,
        "symbol": symbol.upper(),
        "strategy": "Custom",
        "entry_conditions": entry_conditions,
        "exit_conditions": exit_conditions,
        "indicators": indicators,
        "note": "This is a template. Please review and customize the entry/exit logic before running."
    }


def run_backtest(
    symbol: str,
    strategy: str = "sma_crossover",
    period: str = "2y",
    initial_capital: float = 100000,
    **strategy_params
) -> dict[str, Any]:
    """Run a backtest using LEAN CLI.
    
    This will:
    1. Check if LEAN CLI is installed, install if needed
    2. Initialize LEAN workspace if needed
    3. Generate the algorithm
    4. Run the backtest
    5. Return results
    
    Args:
        symbol: Stock ticker symbol
        strategy: Strategy name (sma_crossover, rsi_mean_reversion, macd_momentum, etc.)
        period: Backtest period (1y, 2y, 5y)
        initial_capital: Starting capital
        **strategy_params: Strategy-specific parameters
        
    Returns:
        Backtest results including performance metrics
    """
    import subprocess
    import shutil
    
    results = {
        "symbol": symbol.upper(),
        "strategy": strategy,
        "status": "pending",
        "steps": []
    }
    
    # Step 1: Check if LEAN CLI is installed
    lean_path = shutil.which("lean")
    
    if not lean_path:
        results["steps"].append("LEAN CLI not found - installing...")
        try:
            subprocess.run(
                ["pip", "install", "lean"],
                capture_output=True,
                text=True,
                check=True
            )
            results["steps"].append("LEAN CLI installed successfully")
        except subprocess.CalledProcessError as e:
            results["status"] = "error"
            results["error"] = f"Failed to install LEAN CLI: {e.stderr}"
            results["instructions"] = [
                "Please install LEAN CLI manually:",
                "  pip install lean",
                "Then run this command again."
            ]
            return results
    else:
        results["steps"].append(f"LEAN CLI found at {lean_path}")
    
    # Step 2: Setup LEAN workspace
    lean_workspace = os.path.expanduser("~/sigma_lean")
    config_file = os.path.join(lean_workspace, "lean.json")
    
    if not os.path.exists(config_file):
        results["steps"].append("Initializing LEAN workspace...")
        os.makedirs(lean_workspace, exist_ok=True)
        
        try:
            subprocess.run(
                ["lean", "init"],
                cwd=lean_workspace,
                capture_output=True,
                text=True,
                check=True
            )
            results["steps"].append(f"LEAN workspace initialized at {lean_workspace}")
        except subprocess.CalledProcessError as e:
            # Try creating minimal config
            minimal_config = {
                "data-folder": os.path.join(lean_workspace, "data"),
                "results-destination-folder": os.path.join(lean_workspace, "results")
            }
            os.makedirs(os.path.join(lean_workspace, "data"), exist_ok=True)
            os.makedirs(os.path.join(lean_workspace, "results"), exist_ok=True)
            
            with open(config_file, 'w') as f:
                json.dump(minimal_config, f, indent=2)
            results["steps"].append("Created minimal LEAN config")
    else:
        results["steps"].append(f"Using LEAN workspace at {lean_workspace}")
    
    # Step 3: Generate the algorithm
    results["steps"].append(f"Generating {strategy} algorithm for {symbol.upper()}...")
    
    algo_result = generate_lean_algorithm(
        symbol=symbol,
        strategy=strategy,
        initial_capital=initial_capital,
        output_dir=lean_workspace,
        **strategy_params
    )
    
    if not algo_result.get("success"):
        results["status"] = "error"
        results["error"] = "Failed to generate algorithm"
        return results
    
    algo_file = algo_result["algorithm_file"]
    results["algorithm_file"] = algo_file
    results["steps"].append(f"Algorithm saved to {algo_file}")
    
    # Step 4: Run the backtest
    results["steps"].append("Running LEAN backtest...")
    
    try:
        run_result = subprocess.run(
            ["lean", "backtest", algo_file],
            cwd=lean_workspace,
            capture_output=True,
            text=True,
            timeout=300  # 5 minute timeout
        )
        
        if run_result.returncode == 0:
            results["status"] = "success"
            results["steps"].append("Backtest completed successfully")
            results["output"] = run_result.stdout
            
            # Try to parse results
            results_dir = os.path.join(lean_workspace, "results")
            if os.path.exists(results_dir):
                result_files = os.listdir(results_dir)
                if result_files:
                    latest_result = max(
                        [os.path.join(results_dir, f) for f in result_files],
                        key=os.path.getctime
                    )
                    results["results_file"] = latest_result
        else:
            results["status"] = "error"
            results["error"] = run_result.stderr or run_result.stdout
            results["steps"].append("Backtest failed - see error details")
            
            # Provide helpful instructions
            if "data" in run_result.stderr.lower():
                results["instructions"] = [
                    "LEAN needs market data to run backtests.",
                    "Options:",
                    "1. Use QuantConnect Cloud (free tier available):",
                    "   lean cloud backtest " + algo_file,
                    "",
                    "2. Download free sample data:",
                    "   lean data download --dataset 'US Equities'",
                    "",
                    "3. Use the generated algorithm on QuantConnect.com"
                ]
            
    except subprocess.TimeoutExpired:
        results["status"] = "timeout"
        results["error"] = "Backtest timed out after 5 minutes"
    except FileNotFoundError:
        results["status"] = "error"
        results["error"] = "LEAN CLI not found in PATH after installation"
        results["instructions"] = [
            "Please restart your terminal and try again, or run:",
            "  export PATH=$PATH:~/.local/bin",
            "  lean backtest " + algo_file
        ]
    
    # Always provide manual run instructions
    results["manual_instructions"] = [
        "To run this backtest manually:",
        f"  cd {lean_workspace}",
        f"  lean backtest {os.path.basename(algo_file)}",
        "",
        "Or use QuantConnect Cloud (recommended):",
        f"  lean cloud backtest {os.path.basename(algo_file)}",
        "",
        "Or upload to QuantConnect.com for free cloud backtesting"
    ]
    
    return results


def setup_lean_engine() -> dict[str, Any]:
    """Setup LEAN Engine for backtesting using Docker.
    
    This is the proper way to run LEAN - using Docker containers.
    
    Returns:
        Setup status and instructions
    """
    import subprocess
    import shutil
    
    result = {
        "success": False,
        "steps_completed": [],
        "errors": [],
        "workspace": os.path.expanduser("~/sigma_lean"),
        "next_steps": []
    }
    
    # Step 1: Check Docker
    docker_path = shutil.which("docker")
    if not docker_path:
        result["errors"].append("Docker is not installed")
        result["next_steps"] = [
            "LEAN requires Docker to run backtests.",
            "",
            "Please install Docker Desktop:",
            "  https://www.docker.com/products/docker-desktop",
            "",
            "After installing, run '/lean setup' again."
        ]
        return result
    
    # Check if Docker is running
    try:
        docker_check = subprocess.run(
            ["docker", "info"],
            capture_output=True,
            text=True,
            timeout=10
        )
        if docker_check.returncode != 0:
            result["errors"].append("Docker is installed but not running")
            result["next_steps"] = [
                "Docker is installed but not running.",
                "",
                "Please start Docker Desktop and run '/lean setup' again."
            ]
            return result
        result["steps_completed"].append("Docker is running")
    except Exception as e:
        result["errors"].append(f"Docker check failed: {e}")
        return result
    
    # Step 2: Create workspace directory
    workspace = result["workspace"]
    os.makedirs(workspace, exist_ok=True)
    os.makedirs(os.path.join(workspace, "data"), exist_ok=True)
    os.makedirs(os.path.join(workspace, "results"), exist_ok=True)
    os.makedirs(os.path.join(workspace, "algorithms"), exist_ok=True)
    result["steps_completed"].append(f"Created workspace at {workspace}")
    
    # Step 3: Pull LEAN Docker image
    result["steps_completed"].append("Pulling LEAN Docker image (this may take a few minutes)...")
    try:
        pull_result = subprocess.run(
            ["docker", "pull", "quantconnect/lean:latest"],
            capture_output=True,
            text=True,
            timeout=600  # 10 minute timeout
        )
        if pull_result.returncode == 0:
            result["steps_completed"].append("LEAN Docker image pulled successfully")
        else:
            result["errors"].append(f"Failed to pull LEAN image: {pull_result.stderr}")
            return result
    except subprocess.TimeoutExpired:
        result["errors"].append("Docker pull timed out - please try again")
        return result
    except Exception as e:
        result["errors"].append(f"Docker pull failed: {e}")
        return result
    
    # Step 4: Create lean.json config
    config = {
        "data-folder": os.path.join(workspace, "data"),
        "results-destination-folder": os.path.join(workspace, "results"),
        "algorithm-location": os.path.join(workspace, "algorithms"),
        "debugging-method": "LocalCmdline",
        "log-handler": "ConsoleLogHandler"
    }
    
    config_path = os.path.join(workspace, "lean.json")
    with open(config_path, 'w') as f:
        json.dump(config, f, indent=2)
    result["steps_completed"].append("Created lean.json config")
    
    # Step 5: Download sample data (optional but helpful)
    result["steps_completed"].append("LEAN Engine setup complete!")
    
    result["success"] = True
    result["next_steps"] = [
        "LEAN Engine is ready!",
        "",
        "To run a backtest:",
        "  /lean run AAPL sma_crossover",
        "",
        "Available strategies:",
        "  sma_crossover, rsi_mean_reversion, macd_momentum,",
        "  bollinger_bands, dual_momentum, breakout",
        "",
        f"Algorithms are saved to: {os.path.join(workspace, 'algorithms')}",
        f"Results are saved to: {os.path.join(workspace, 'results')}"
    ]
    
    return result


def run_lean_backtest(
    symbol: str,
    strategy: str = "sma_crossover",
    initial_capital: float = 100000,
    start_date: Optional[str] = None,
    end_date: Optional[str] = None,
    **strategy_params
) -> dict[str, Any]:
    """Run a comprehensive backtest with detailed metrics and charts.
    
    Args:
        symbol: Stock ticker symbol
        strategy: Strategy name
        initial_capital: Starting capital
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)
        
    Returns:
        Comprehensive backtest results
    """
    result = {
        "symbol": symbol.upper(),
        "strategy": strategy,
        "status": "running",
        "steps": [],
        "metrics": {},
        "charts": {}
    }
    
    workspace = os.path.expanduser("~/sigma_lean")
    algorithms_dir = os.path.join(workspace, "algorithms")
    results_dir = os.path.join(workspace, "results")
    
    # Ensure directories exist
    os.makedirs(algorithms_dir, exist_ok=True)
    os.makedirs(results_dir, exist_ok=True)
    
    # Generate the LEAN algorithm
    result["steps"].append(f"Generating {strategy} algorithm for {symbol.upper()}...")
    
    algo_result = generate_lean_algorithm(
        symbol=symbol,
        strategy=strategy,
        initial_capital=initial_capital,
        start_date=start_date,
        end_date=end_date,
        output_dir=algorithms_dir,
        **strategy_params
    )
    
    if not algo_result.get("success"):
        result["status"] = "error"
        result["error"] = f"Failed to generate algorithm: {algo_result.get('error', 'Unknown error')}"
        return result
    
    algo_file = algo_result["algorithm_file"]
    algo_name = os.path.basename(algo_file)
    result["algorithm_file"] = algo_file
    result["steps"].append(f"Algorithm saved: {algo_name}")
    
    # Run comprehensive Python backtest
    result["steps"].append("Running comprehensive backtest analysis...")
    
    try:
        backtest_results = run_simple_backtest(
            symbol=symbol,
            strategy=strategy,
            initial_capital=initial_capital,
            start_date=start_date,
            end_date=end_date
        )
        
        if backtest_results.get("success"):
            result["status"] = "success"
            result["steps"].append("Backtest completed successfully!")
            result["metrics"] = backtest_results.get("metrics", {})
            result["trades"] = backtest_results.get("trades", [])
            result["monthly_returns"] = backtest_results.get("monthly_returns", [])
            result["charts"] = backtest_results.get("charts", {})
        else:
            result["status"] = "error"
            result["error"] = backtest_results.get("error", "Backtest failed")
            
    except Exception as e:
        result["status"] = "error"
        result["error"] = str(e)
    
    # Provide QuantConnect instructions for institutional-grade backtest
    result["quantconnect_instructions"] = [
        "For INSTITUTIONAL-GRADE backtesting with full market data:",
        "1. Go to https://www.quantconnect.com (FREE account)",
        "2. Click 'Algorithm Lab' -> 'Create New Algorithm'",
        f"3. Paste the code from: {algo_file}",
        "4. Click 'Backtest' for institutional data!"
    ]
    
    result["algorithm_ready"] = True
    
    return result


def run_simple_backtest(
    symbol: str,
    strategy: str = "sma_crossover",
    initial_capital: float = 100000,
    start_date: Optional[str] = None,
    end_date: Optional[str] = None
) -> dict[str, Any]:
    """Run a comprehensive Python backtest using yfinance data.
    
    This provides institutional-quality results with detailed metrics,
    charts, and analysis. For even more accurate results, use QuantConnect.
    """
    import yfinance as yf
    import numpy as np
    import plotext as plt
    from datetime import datetime
    
    result = {
        "success": False,
        "symbol": symbol.upper(),
        "strategy": strategy,
        "metrics": {},
        "trades": [],
        "equity_curve": [],
        "monthly_returns": [],
        "charts": {}
    }
    
    # Get historical data
    ticker = yf.Ticker(symbol.upper())
    
    if start_date and end_date:
        hist = ticker.history(start=start_date, end=end_date)
    else:
        hist = ticker.history(period="2y")
    
    if hist.empty or len(hist) < 50:
        result["error"] = f"Insufficient data for {symbol}"
        return result
    
    closes = hist["Close"].values.astype(float)
    opens = hist["Open"].values.astype(float)
    highs = hist["High"].values.astype(float)
    lows = hist["Low"].values.astype(float)
    volumes = hist["Volume"].values.astype(float)
    dates = hist.index
    
    # Initialize tracking
    cash = initial_capital
    shares = 0
    position = None
    trades = []
    equity_curve = []
    daily_returns = []
    
    # Strategy execution
    signals = _generate_signals(closes, strategy)
    
    prev_equity = initial_capital
    for i in range(len(closes)):
        price = closes[i]
        date = dates[i]
        signal = signals[i] if i < len(signals) else 0
        
        # Calculate current equity
        equity = cash + (shares * price if shares > 0 else 0)
        equity_curve.append({
            "date": str(date.date()),
            "equity": equity,
            "price": price
        })
        
        # Track daily returns
        if prev_equity > 0:
            daily_ret = (equity - prev_equity) / prev_equity
            daily_returns.append(daily_ret)
        prev_equity = equity
        
        # Execute signals
        if signal == 1 and position is None and cash > 0:  # BUY
            shares = int(cash * 0.95 / price)
            if shares > 0:
                cost = shares * price
                commission = cost * 0.001  # 0.1% commission
                cash -= (cost + commission)
                position = 'long'
                entry_price = price
                entry_date = date
                trades.append({
                    "date": str(date.date()),
                    "action": "BUY",
                    "price": round(price, 2),
                    "shares": shares,
                    "value": round(cost, 2),
                    "commission": round(commission, 2)
                })
        
        elif signal == -1 and position == 'long' and shares > 0:  # SELL
            proceeds = shares * price
            commission = proceeds * 0.001
            cash += (proceeds - commission)
            
            # Calculate trade P&L
            pnl = (price - entry_price) * shares - (commission * 2)
            pnl_pct = ((price - entry_price) / entry_price) * 100
            holding_days = (date - entry_date).days
            
            trades.append({
                "date": str(date.date()),
                "action": "SELL",
                "price": round(price, 2),
                "shares": shares,
                "value": round(proceeds, 2),
                "commission": round(commission, 2),
                "pnl": round(pnl, 2),
                "pnl_pct": round(pnl_pct, 2),
                "holding_days": holding_days
            })
            shares = 0
            position = None
    
    # Close any open position at end
    if position == 'long' and shares > 0:
        final_price = closes[-1]
        proceeds = shares * final_price
        cash += proceeds
        trades.append({
            "date": str(dates[-1].date()),
            "action": "SELL (Close)",
            "price": round(final_price, 2),
            "shares": shares,
            "value": round(proceeds, 2)
        })
        shares = 0
    
    # Calculate comprehensive metrics
    final_equity = cash
    total_return = ((final_equity - initial_capital) / initial_capital) * 100
    
    # Buy and hold comparison
    bh_shares = int(initial_capital * 0.95 / closes[0])
    bh_final = (initial_capital - bh_shares * closes[0]) + bh_shares * closes[-1]
    bh_return = ((bh_final - initial_capital) / initial_capital) * 100
    
    # Trade statistics
    buy_trades = [t for t in trades if t.get("action") == "BUY"]
    sell_trades = [t for t in trades if "pnl" in t]
    
    wins = [t for t in sell_trades if t.get("pnl", 0) > 0]
    losses = [t for t in sell_trades if t.get("pnl", 0) <= 0]
    
    win_rate = (len(wins) / len(sell_trades) * 100) if sell_trades else 0
    avg_win = np.mean([t["pnl"] for t in wins]) if wins else 0
    avg_loss = np.mean([t["pnl"] for t in losses]) if losses else 0
    
    # Profit factor
    gross_profit = sum(t["pnl"] for t in wins) if wins else 0
    gross_loss = abs(sum(t["pnl"] for t in losses)) if losses else 1
    profit_factor = gross_profit / gross_loss if gross_loss > 0 else 0
    
    # Risk metrics
    daily_returns_arr = np.array(daily_returns)
    
    # Sharpe Ratio (annualized, assuming 252 trading days)
    if len(daily_returns_arr) > 1 and np.std(daily_returns_arr) > 0:
        sharpe = (np.mean(daily_returns_arr) * 252) / (np.std(daily_returns_arr) * np.sqrt(252))
    else:
        sharpe = 0
    
    # Sortino Ratio (downside deviation)
    downside_returns = daily_returns_arr[daily_returns_arr < 0]
    if len(downside_returns) > 1 and np.std(downside_returns) > 0:
        sortino = (np.mean(daily_returns_arr) * 252) / (np.std(downside_returns) * np.sqrt(252))
    else:
        sortino = 0
    
    # Max Drawdown
    peak = initial_capital
    max_dd = 0
    max_dd_duration = 0
    dd_start = None
    current_dd_duration = 0
    
    drawdowns = []
    for i, point in enumerate(equity_curve):
        equity = point["equity"]
        if equity > peak:
            peak = equity
            if dd_start is not None:
                current_dd_duration = i - dd_start
                if current_dd_duration > max_dd_duration:
                    max_dd_duration = current_dd_duration
            dd_start = None
        else:
            if dd_start is None:
                dd_start = i
        
        dd = (peak - equity) / peak * 100
        drawdowns.append(dd)
        if dd > max_dd:
            max_dd = dd
    
    # Calmar Ratio
    annual_return = total_return / (len(closes) / 252)
    calmar = annual_return / max_dd if max_dd > 0 else 0
    
    # Average holding period
    holding_periods = [t.get("holding_days", 0) for t in sell_trades if t.get("holding_days")]
    avg_holding = np.mean(holding_periods) if holding_periods else 0
    
    # Monthly returns
    monthly_returns = {}
    for point in equity_curve:
        date_str = point["date"]
        month_key = date_str[:7]  # YYYY-MM
        if month_key not in monthly_returns:
            monthly_returns[month_key] = {"start": point["equity"], "end": point["equity"]}
        monthly_returns[month_key]["end"] = point["equity"]
    
    monthly_pcts = []
    for month, vals in monthly_returns.items():
        if vals["start"] > 0:
            ret = ((vals["end"] - vals["start"]) / vals["start"]) * 100
            monthly_pcts.append({"month": month, "return": round(ret, 2)})
    
    # Compile metrics
    result["success"] = True
    result["metrics"] = {
        "performance": {
            "initial_capital": f"${initial_capital:,.0f}",
            "final_equity": f"${final_equity:,.2f}",
            "total_return": f"{total_return:+.2f}%",
            "annual_return": f"{annual_return:+.2f}%",
            "buy_hold_return": f"{bh_return:+.2f}%",
            "alpha": f"{total_return - bh_return:+.2f}%"
        },
        "risk": {
            "max_drawdown": f"{max_dd:.2f}%",
            "sharpe_ratio": f"{sharpe:.2f}",
            "sortino_ratio": f"{sortino:.2f}",
            "calmar_ratio": f"{calmar:.2f}",
            "volatility": f"{np.std(daily_returns_arr) * np.sqrt(252) * 100:.2f}%"
        },
        "trades": {
            "total_trades": len(sell_trades),
            "win_rate": f"{win_rate:.1f}%",
            "profit_factor": f"{profit_factor:.2f}",
            "avg_win": f"${avg_win:,.2f}",
            "avg_loss": f"${avg_loss:,.2f}",
            "avg_holding_days": f"{avg_holding:.1f}"
        }
    }
    result["trades"] = trades[-15:]  # Last 15 trades
    result["monthly_returns"] = monthly_pcts[-12:]  # Last 12 months
    
    # Generate charts
    try:
        # 1. Equity Curve Chart
        plt.clear_figure()
        plt.plotsize(120, 25)
        plt.theme("dark")
        plt.canvas_color("black")
        plt.axes_color("black")
        
        equities = [p["equity"] for p in equity_curve]
        plt.plot(equities, color="cyan", marker="hd")
        
        # Add buy/hold line
        bh_equity = []
        bh_val = initial_capital
        for i, price in enumerate(closes):
            if i == 0:
                bh_val = initial_capital
            else:
                bh_val = (initial_capital - bh_shares * closes[0]) + bh_shares * price
            bh_equity.append(bh_val)
        plt.plot(bh_equity, color="gray", marker="hd")
        
        plt.title(f"  Equity Curve: {symbol.upper()} {strategy} (cyan) vs Buy&Hold (gray)")
        plt.ylabel("Equity ($)")
        
        result["charts"]["equity_curve"] = plt.build()
        
        # 2. Drawdown Chart
        plt.clear_figure()
        plt.plotsize(120, 15)
        plt.theme("dark")
        plt.canvas_color("black")
        plt.axes_color("black")
        
        plt.plot([-d for d in drawdowns], color="red", marker="hd", fillx=True)
        plt.title(f"  Drawdown Analysis - Max: {max_dd:.2f}%")
        plt.ylabel("Drawdown (%)")
        
        result["charts"]["drawdown"] = plt.build()
        
        # 3. Trade Distribution
        if sell_trades:
            plt.clear_figure()
            plt.plotsize(80, 12)
            plt.theme("dark")
            plt.canvas_color("black")
            plt.axes_color("black")
            
            pnls = [t.get("pnl", 0) for t in sell_trades]
            colors = ["green" if p > 0 else "red" for p in pnls]
            plt.bar(range(len(pnls)), pnls, color=colors)
            plt.title(f"  Trade P&L Distribution ({len(wins)} wins, {len(losses)} losses)")
            plt.ylabel("P&L ($)")
            
            result["charts"]["trade_pnl"] = plt.build()
        
        # 4. Monthly Returns Bar Chart
        if monthly_pcts:
            plt.clear_figure()
            plt.plotsize(100, 12)
            plt.theme("dark")
            plt.canvas_color("black")
            plt.axes_color("black")
            
            months = [m["month"][-5:] for m in monthly_pcts[-12:]]  # MM format
            returns = [m["return"] for m in monthly_pcts[-12:]]
            colors = ["green" if r > 0 else "red" for r in returns]
            plt.bar(months, returns, color=colors)
            plt.title("  Monthly Returns (%)")
            
            result["charts"]["monthly_returns"] = plt.build()
            
    except Exception as e:
        result["chart_error"] = str(e)
    
    return result


def _generate_signals(closes, strategy: str) -> list:
    """Generate trading signals based on strategy.
    
    Args:
        closes: numpy array of closing prices
        strategy: strategy name
        
    Returns: list of signals (1=buy, -1=sell, 0=hold)
    """
    import numpy as np
    
    signals = [0] * len(closes)
    
    if strategy == "sma_crossover":
        fast_period = 10
        slow_period = 30
        
        if len(closes) < slow_period:
            return signals
        
        fast_sma = np.convolve(closes, np.ones(fast_period)/fast_period, mode='valid')
        slow_sma = np.convolve(closes, np.ones(slow_period)/slow_period, mode='valid')
        
        offset = slow_period - fast_period
        fast_sma = fast_sma[offset:]
        
        for i in range(1, len(slow_sma)):
            idx = i + slow_period - 1
            if idx < len(signals):
                if fast_sma[i] > slow_sma[i] and fast_sma[i-1] <= slow_sma[i-1]:
                    signals[idx] = 1  # Buy
                elif fast_sma[i] < slow_sma[i] and fast_sma[i-1] >= slow_sma[i-1]:
                    signals[idx] = -1  # Sell
    
    elif strategy == "rsi_mean_reversion":
        rsi_period = 14
        oversold = 30
        overbought = 70
        
        rsi = _calculate_rsi(closes, rsi_period)
        
        for i in range(1, len(rsi)):
            if rsi[i] < oversold and rsi[i-1] >= oversold:
                signals[i] = 1  # Buy on oversold
            elif rsi[i] > overbought and rsi[i-1] <= overbought:
                signals[i] = -1  # Sell on overbought
    
    elif strategy == "macd_momentum":
        fast, slow, signal = 12, 26, 9
        
        ema_fast = _ema(closes, fast)
        ema_slow = _ema(closes, slow)
        macd_line = ema_fast - ema_slow
        signal_line = _ema(macd_line, signal)
        histogram = macd_line - signal_line
        
        for i in range(slow + signal + 1, len(histogram)):
            if histogram[i] > 0 and histogram[i-1] <= 0:
                signals[i] = 1  # Buy
            elif histogram[i] < 0 and histogram[i-1] >= 0:
                signals[i] = -1  # Sell
    
    elif strategy == "bollinger_bands":
        period = 20
        std_dev = 2
        
        if len(closes) < period:
            return signals
        
        for i in range(period, len(closes)):
            window = closes[i-period:i]
            middle = np.mean(window)
            std = np.std(window)
            upper = middle + std_dev * std
            lower = middle - std_dev * std
            
            if closes[i] <= lower and closes[i-1] > lower:
                signals[i] = 1  # Buy at lower band
            elif closes[i] >= upper and closes[i-1] < upper:
                signals[i] = -1  # Sell at upper band
    
    elif strategy == "dual_momentum":
        lookback = 60  # 3 months
        
        if len(closes) < lookback:
            return signals
        
        for i in range(lookback, len(closes)):
            momentum = (closes[i] - closes[i-lookback]) / closes[i-lookback]
            prev_momentum = (closes[i-1] - closes[i-lookback-1]) / closes[i-lookback-1] if i > lookback else 0
            
            if momentum > 0 and prev_momentum <= 0:
                signals[i] = 1
            elif momentum < 0 and prev_momentum >= 0:
                signals[i] = -1
    
    elif strategy == "breakout":
        period = 20  # Donchian channel period
        
        if len(closes) < period:
            return signals
        
        for i in range(period, len(closes)):
            high_channel = max(closes[i-period:i])
            low_channel = min(closes[i-period:i])
            
            if closes[i] > high_channel and closes[i-1] <= high_channel:
                signals[i] = 1  # Breakout buy
            elif closes[i] < low_channel and closes[i-1] >= low_channel:
                signals[i] = -1  # Breakdown sell
    
    return signals


def _calculate_rsi(closes, period: int = 14):
    """Calculate RSI indicator.
    
    Args:
        closes: numpy array of closing prices
        period: RSI period (default 14)
        
    Returns:
        numpy array of RSI values
    """
    import numpy as np
    
    deltas = np.diff(closes)
    gains = np.where(deltas > 0, deltas, 0)
    losses = np.where(deltas < 0, -deltas, 0)
    
    rsi = np.zeros(len(closes))
    rsi[:period] = 50  # Neutral
    
    for i in range(period, len(closes)):
        avg_gain = np.mean(gains[i-period:i])
        avg_loss = np.mean(losses[i-period:i])
        if avg_loss == 0:
            rsi[i] = 100
        else:
            rs = avg_gain / avg_loss
            rsi[i] = 100 - (100 / (1 + rs))
    
    return rsi


def _ema(data, period):
    """Calculate exponential moving average."""
    import numpy as np
    ema = np.zeros_like(data)
    ema[0] = data[0]
    multiplier = 2 / (period + 1)
    for i in range(1, len(data)):
        ema[i] = (data[i] * multiplier) + (ema[i-1] * (1 - multiplier))
    return ema


def check_lean_status() -> dict[str, Any]:
    """Check LEAN Engine status and provide setup instructions.
    
    Returns:
        Status information and setup instructions
    """
    import subprocess
    import shutil
    
    status = {
        "docker_installed": False,
        "docker_running": False,
        "lean_image_pulled": False,
        "workspace_initialized": False,
        "workspace_path": os.path.expanduser("~/sigma_lean"),
        "ready": False,
        "instructions": []
    }
    
    # Check Docker
    docker_path = shutil.which("docker")
    if docker_path:
        status["docker_installed"] = True
        
        # Check if Docker is running
        try:
            docker_check = subprocess.run(
                ["docker", "info"],
                capture_output=True,
                text=True,
                timeout=10
            )
            if docker_check.returncode == 0:
                status["docker_running"] = True
                
                # Check if LEAN image is pulled
                images_check = subprocess.run(
                    ["docker", "images", "quantconnect/lean", "--format", "{{.Repository}}"],
                    capture_output=True,
                    text=True
                )
                if "quantconnect/lean" in images_check.stdout:
                    status["lean_image_pulled"] = True
        except:
            pass
    
    # Check workspace
    workspace = status["workspace_path"]
    if os.path.exists(os.path.join(workspace, "algorithms")):
        status["workspace_initialized"] = True
    
    # Determine readiness
    status["ready"] = status["workspace_initialized"]
    
    # Provide instructions
    if not status["docker_installed"]:
        status["instructions"] = [
            "Docker is required for full LEAN Engine.",
            "",
            "Install Docker Desktop:",
            "  https://www.docker.com/products/docker-desktop",
            "",
            "Then run: /lean setup",
            "",
            "Note: You can still run quick backtests without Docker!"
        ]
    elif not status["docker_running"]:
        status["instructions"] = [
            "Docker is installed but not running.",
            "",
            "Please start Docker Desktop, then run: /lean setup",
            "",
            "Note: You can still run quick backtests without Docker!"
        ]
    elif not status["workspace_initialized"]:
        status["instructions"] = [
            "LEAN needs to be set up.",
            "",
            "Run: /lean setup"
        ]
    else:
        status["instructions"] = [
            "LEAN Engine is ready!",
            "",
            "Run a backtest:",
            "  /lean run AAPL sma_crossover",
            "",
            "Available strategies:",
            "  sma_crossover, rsi_mean_reversion, macd_momentum,",
            "  bollinger_bands, dual_momentum, breakout"
        ]
    
    return status
