using System.Collections;
using System.Diagnostics;
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Repositories;
using Managing.Application.Abstractions.Services;
using Managing.Application.Backtests;
using Managing.Application.Hubs;
using Managing.Core;
using Managing.Domain.Bots;
using Managing.Domain.Candles;
using Managing.Domain.MoneyManagements;
using Managing.Domain.Scenarios;
using Managing.Domain.Strategies;
using Managing.Domain.Strategies.Signals;
using Microsoft.AspNetCore.SignalR;
using Moq;
using Newtonsoft.Json;
using Xunit;
using static Managing.Common.Enums;

namespace Managing.Application.Tests
{
    public class BotsTests : BaseTests
    {
        private readonly IBacktester _backtester;
        private readonly string _reportPath;
        private string _analysePath;
        private readonly string _errorsPath;
        private readonly string _s = "|";
        private List<double> _elapsedTimes { get; set; }

        public BotsTests() : base()
        {
            var backtestRepository = new Mock<IBacktestRepository>().Object;
            var discordService = new Mock<IMessengerService>().Object;
            var scenarioService = new Mock<IScenarioService>().Object;
            var messengerService = new Mock<IMessengerService>().Object;
            var kaigenService = new Mock<IKaigenService>().Object;
            var hubContext = new Mock<IHubContext<BacktestHub>>().Object;
            var tradingBotLogger = TradingBaseTests.CreateTradingBotLogger();
            var backtestLogger = TradingBaseTests.CreateBacktesterLogger();
            var botService = new Mock<IBotService>().Object;
            _backtester = new Backtester(_exchangeService, backtestRepository, backtestLogger,
                scenarioService, _accountService.Object, messengerService, kaigenService, hubContext, null);
            _elapsedTimes = new List<double>();

            // Initialize cross-platform file paths
            var reportsDirectory = GetBacktestReportsDirectory();
            _reportPath = Path.Combine(reportsDirectory, "backtesting.csv");
            _analysePath = Path.Combine(reportsDirectory, "analyse");
            _errorsPath = Path.Combine(reportsDirectory, "errorsAnalyse.csv");
        }

        [Theory]
        [InlineData(Ticker.BTC, Timeframe.FifteenMinutes, -10)]
        public async Task SwingBot_Should_Return_Positiv_Profit_For_Every_Position(Ticker ticker, Timeframe timeframe,
            int days)
        {
            // Arrange 
            var scenario = new Scenario("FlippingScenario");
            var strategy = ScenarioHelpers.BuildIndicator(IndicatorType.RsiDivergence, "RsiDiv", period: 14);
            var localCandles =
                FileHelpers.ReadJson<List<Candle>>($"{ticker.ToString()}-{timeframe.ToString()}-candles.json");

            var config = new TradingBotConfig
            {
                AccountName = _account.Name,
                MoneyManagement = MoneyManagement,
                Ticker = ticker,
                Scenario = LightScenario.FromScenario(scenario),
                Timeframe = timeframe,
                IsForWatchingOnly = false,
                BotTradingBalance = 1000,
                IsForBacktest = true,
                CooldownPeriod = 1,
                MaxLossStreak = 0,
                FlipPosition = true,
                Name = "Test",
                FlipOnlyWhenInProfit = true,
                MaxPositionTimeHours = null,
                CloseEarlyWhenProfitable = false
            };

            // Act
            var backtestResult =
                await _backtester.RunTradingBotBacktest(config, DateTime.UtcNow.AddDays(-6),
                    DateTime.UtcNow, null, false, false);

            var json = JsonConvert.SerializeObject(backtestResult, Formatting.None);
            File.WriteAllText($"{ticker}-{timeframe}-{Guid.NewGuid()}.json", json);
            // WriteCsvReport(backtestResult.GetStringReport());

            // Assert
            Assert.True(backtestResult.FinalPnl > 0);
            Assert.True(backtestResult.WinRate >= 30);
            Assert.True(backtestResult.GrowthPercentage > backtestResult.HodlPercentage);
        }

        [Theory]
        //[InlineData(Enums.Exchanges.Binance, "ADAUSDT", Timeframe.ThirtyMinutes, -5)]
        //[InlineData(Enums.Exchanges.Binance, "ADAUSDT", Timeframe.FifteenMinutes, -5)]
        //[InlineData(Enums.Exchanges.Binance, "SOLUSDT", Timeframe.ThirtyMinutes, -4)]
        //[InlineData(Enums.Exchanges.Binance, "SOLUSDT", Timeframe.FifteenMinutes, -4)]
        //[InlineData(Enums.Exchanges.Binance, "BTCUSDT", Timeframe.ThirtyMinutes, -4)]
        //[InlineData(Enums.Exchanges.Binance, "BTCUSDT", Timeframe.FifteenMinutes, -4)]
        [InlineData(Ticker.BTC, Timeframe.FifteenMinutes, -14)]
        public async Task ScalpingBot_Should_Return_Positiv_Profit_For_Every_Position(Ticker ticker,
            Timeframe timeframe,
            int days)
        {
            // Arrange 
            var scenario = new Scenario("ScalpingScenario");

            var config = new TradingBotConfig
            {
                AccountName = _account.Name,
                MoneyManagement = MoneyManagement,
                Ticker = ticker,
                Scenario = LightScenario.FromScenario(scenario),
                Timeframe = timeframe,
                IsForWatchingOnly = false,
                BotTradingBalance = 1000,
                IsForBacktest = true,
                CooldownPeriod = 1,
                MaxLossStreak = 0,
                FlipPosition = false,
                Name = "Test",
                FlipOnlyWhenInProfit = true,
                MaxPositionTimeHours = null,
                CloseEarlyWhenProfitable = false
            };

            // Act
            var backtestResult = await _backtester.RunTradingBotBacktest(config, DateTime.UtcNow.AddDays(-6),
                DateTime.UtcNow, null, false, false);
            //WriteCsvReport(backtestResult.GetStringReport());

            // Assert
            Assert.True(backtestResult.FinalPnl > 0);
            Assert.True(backtestResult.WinRate >= 30);
            Assert.True(backtestResult.GrowthPercentage > backtestResult.HodlPercentage);
        }

        [Theory]
        [InlineData(Ticker.BTC, Timeframe.FifteenMinutes, -8)]
        public async Task MacdCross_Should_Return_Positiv_Profit_For_Every_Position(Ticker ticker, Timeframe timeframe,
            int days)
        {
            // Arrange 
            var scenario = new Scenario("ScalpingScenario")
            {
                Indicators = new List<IndicatorBase>
                {
                    new MacdCrossIndicatorBase("MacdCross", 12, 26, 9)
                }
            };

            var moneyManagement = new MoneyManagement()
            {
                Leverage = 1,
                Timeframe = timeframe,
                StopLoss = 0.01m,
                TakeProfit = 0.02m
            };

            var config = new TradingBotConfig
            {
                AccountName = _account.Name,
                MoneyManagement = moneyManagement,
                Ticker = ticker,
                Scenario = LightScenario.FromScenario(scenario),
                Timeframe = timeframe,
                IsForWatchingOnly = false,
                BotTradingBalance = 1000,
                IsForBacktest = true,
                CooldownPeriod = 1,
                MaxLossStreak = 0,
                FlipPosition = false,
                Name = "Test",
                FlipOnlyWhenInProfit = true,
                MaxPositionTimeHours = null,
                CloseEarlyWhenProfitable = false
            };

            // Act
            var backtestResult = await _backtester.RunTradingBotBacktest(config, DateTime.UtcNow.AddDays(-6),
                DateTime.UtcNow, null, false, false);
            // WriteCsvReport(backtestResult.GetStringReport());

            // Assert
            Assert.True(backtestResult.FinalPnl > 0);
            Assert.True(backtestResult.WinRate >= 30);
            Assert.True(backtestResult.GrowthPercentage > backtestResult.HodlPercentage);
        }

        [Theory]
        [InlineData(Timeframe.FifteenMinutes, -6, IndicatorType.Stc, BotType.ScalpingBot)]
        //[InlineData(Timeframe.FifteenMinutes, -6, Enums.StrategyType.RsiDivergenceConfirm, Enums.BotType.FlippingBot)]
        public void GetBestPeriodRsiForDivergenceFlippingBot(Timeframe timeframe, int days, IndicatorType indicatorType,
            BotType botType)
        {
            var result = new List<Tuple<string, int, decimal, decimal, decimal, decimal>>();
            var errors = new List<string>();
            var options = new ParallelOptions()
            {
                MaxDegreeOfParallelism = 4
            };

            var periodRange = new List<int>() { 2, 7 };
            var stopLossRange = new List<decimal>() { 0.005m, 0.05m, 0.005m };
            var takeProfitRange = new List<decimal>() { 0.01m, 0.1m, 0.02m };
            var fileIdentifier = $"{indicatorType}-{timeframe}";
            var completedTest = 0;
            var totalTests = GetTotalTrades(periodRange, stopLossRange, takeProfitRange) *
                             Enum.GetNames(typeof(Ticker)).Length;

            CleanAnalyseFile(fileIdentifier);
            UpdateProgression(totalTests, completedTest);

            Parallel.ForEach((Ticker[])Enum.GetValues(typeof(Ticker)), options, ticker =>
            {
                var candles = _exchangeService
                    .GetCandles(_account, ticker, DateTime.Now.AddDays(Convert.ToDouble(days)), timeframe, true).Result;

                if (candles == null || candles.Count == 0)
                    return;

                Parallel.For((long)periodRange[0], periodRange[1], options, i =>
                {
                    var scenario = new Scenario("ScalpingScenario");
                    scenario.Indicators = new List<IndicatorBase>
                    {
                        new RsiDivergenceIndicatorBase("RsiDiv", (int)i)
                    };

                    // -0.5 to -5
                    for (decimal s = stopLossRange[0]; s < stopLossRange[1]; s += stopLossRange[2])
                    {
                        // +1% to +10% in 1%
                        for (decimal t = takeProfitRange[0]; t < takeProfitRange[1]; t += takeProfitRange[2])
                        {
                            var moneyManagement = new MoneyManagement()
                            {
                                Leverage = 1,
                                Timeframe = timeframe,
                                StopLoss = s,
                                TakeProfit = t
                            };

                            try
                            {
                                var timer = new Stopwatch();
                                timer.Start();

                                var backtestResult = botType switch
                                {
                                    BotType.SimpleBot => throw new NotImplementedException(),
                                    BotType.ScalpingBot => _backtester.RunTradingBotBacktest(new TradingBotConfig
                                        {
                                            AccountName = _account.Name,
                                            MoneyManagement = moneyManagement,
                                            Ticker = ticker,
                                            Scenario = LightScenario.FromScenario(scenario),
                                            Timeframe = timeframe,
                                            IsForWatchingOnly = false,
                                            BotTradingBalance = 1000,
                                            IsForBacktest = true,
                                            CooldownPeriod = 1,
                                            MaxLossStreak = 0,
                                            FlipPosition = false,
                                            Name = "Test",
                                            FlipOnlyWhenInProfit = true,
                                            MaxPositionTimeHours = null,
                                            CloseEarlyWhenProfitable = false
                                        }, DateTime.UtcNow.AddDays(-6),
                                        DateTime.UtcNow, null, false, false).Result,
                                    BotType.FlippingBot => _backtester.RunTradingBotBacktest(new TradingBotConfig
                                        {
                                            AccountName = _account.Name,
                                            MoneyManagement = moneyManagement,
                                            Ticker = ticker,
                                            Scenario = LightScenario.FromScenario(scenario),
                                            Timeframe = timeframe,
                                            IsForWatchingOnly = false,
                                            BotTradingBalance = 1000,
                                            IsForBacktest = true,
                                            CooldownPeriod = 1,
                                            MaxLossStreak = 0,
                                            FlipPosition = true,
                                            Name = "Test",
                                            FlipOnlyWhenInProfit = true,
                                            MaxPositionTimeHours = null,
                                            CloseEarlyWhenProfitable = false
                                        }, DateTime.UtcNow.AddDays(-6),
                                        DateTime.UtcNow, null, false, false).Result,
                                    _ => throw new NotImplementedException(),
                                };
                                timer.Stop();

                                if (backtestResult.FinalPnl > 0
                                    && (backtestResult.GrowthPercentage - backtestResult.HodlPercentage) > 30
                                    && backtestResult.Score < 3)
                                {
                                    var currentResult = new Tuple<string, int, decimal, decimal, decimal, decimal>(
                                        ticker.ToString(), (int)i,
                                        backtestResult.FinalPnl, s, t,
                                        backtestResult.GrowthPercentage - backtestResult.HodlPercentage);
                                    result.Add(currentResult);
                                }

                                completedTest++;
                                UpdateProgression(totalTests, completedTest, timer.Elapsed.TotalSeconds);
                            }
                            catch (Exception ex)
                            {
                                completedTest++;
                                errors.Add($"{ticker}{_s}{i}{_s}{s}{_s}{t}{_s}{ex.Message}");
                            }
                        }
                    }
                });
            });

            foreach (var r in result)
            {
                WriteCsvAnalyse(
                    $"{r.Item1}{_s}{r.Item2}{_s}{r.Item3.ToString("0.000")}{_s}{r.Item4 * 100}{_s}{r.Item5 * 100}{_s}{r.Item6}");
            }

            foreach (var e in errors)
            {
                WriteCsvErrors(e);
            }

            var bestResult = result.OrderByDescending(b => b.Item3).FirstOrDefault();
            WriteCsvAnalyse(
                $"Best result : {bestResult.Item1} - Rsi Period : {bestResult.Item2} - {bestResult.Item3} - SL : {bestResult.Item4}% - TP : {bestResult.Item5}%");

            Assert.True(result.Any());
        }


        [Theory]
        [InlineData(Timeframe.OneHour, -30, IndicatorType.MacdCross, BotType.FlippingBot)]
        [InlineData(Timeframe.OneHour, -30, IndicatorType.MacdCross, BotType.ScalpingBot)]
        public void GetBestMMForMacdFlippingBot(Timeframe timeframe, int days, IndicatorType indicatorType,
            BotType botType)
        {
            var result = new List<Tuple<string, decimal, decimal, decimal, decimal>>();
            var errors = new List<string>();
            var options = new ParallelOptions()
            {
                MaxDegreeOfParallelism = 4
            };

            var stopLossRange = new List<decimal>() { 0.005m, 0.05m, 0.005m };
            var takeProfitRange = new List<decimal>() { 0.01m, 0.1m, 0.02m };
            var fileIdentifier = $"{indicatorType}-{timeframe}-{botType}";
            var completedTest = 0;
            var totalTests = GetTotalTradeForStopLossTakeProfit(stopLossRange, takeProfitRange) *
                             Enum.GetNames(typeof(Ticker)).Length;

            CleanAnalyseFile(fileIdentifier);
            UpdateProgression(totalTests, completedTest);

            Parallel.ForEach((Ticker[])Enum.GetValues(typeof(Ticker)), options, ticker =>
            {
                var candles = _exchangeService
                    .GetCandles(_account, ticker, DateTime.Now.AddDays(Convert.ToDouble(days)), timeframe, true).Result;

                if (candles == null || candles.Count == 0)
                    return;

                var scenario = new Scenario("ScalpingScenario");
                scenario.Indicators = new List<IndicatorBase>
                {
                    new MacdCrossIndicatorBase("MacdCross", 12, 26, 9)
                };

                // -0.5 to -5
                for (decimal s = stopLossRange[0]; s < stopLossRange[1]; s += stopLossRange[2])
                {
                    // +1% to +10% in 1%
                    for (decimal t = takeProfitRange[0]; t < takeProfitRange[1]; t += takeProfitRange[2])
                    {
                        var timer = new Stopwatch();
                        timer.Start();
                        try
                        {
                            var moneyManagement = new MoneyManagement()
                            {
                                Leverage = 1,
                                Timeframe = timeframe,
                                StopLoss = s,
                                TakeProfit = t
                            };

                            var backtestResult = botType switch
                            {
                                BotType.SimpleBot => throw new NotImplementedException(),
                                BotType.ScalpingBot => _backtester.RunTradingBotBacktest(new TradingBotConfig
                                    {
                                        AccountName = _account.Name,
                                        MoneyManagement = moneyManagement,
                                        Ticker = ticker,
                                        Scenario = LightScenario.FromScenario(scenario),
                                        Timeframe = timeframe,
                                        IsForWatchingOnly = false,
                                        BotTradingBalance = 1000,
                                        IsForBacktest = true,
                                        CooldownPeriod = 1,
                                        MaxLossStreak = 0,
                                        FlipPosition = false,
                                        Name = "Test",
                                        FlipOnlyWhenInProfit = true,
                                        MaxPositionTimeHours = null,
                                        CloseEarlyWhenProfitable = false
                                    }, DateTime.UtcNow.AddDays(-6),
                                    DateTime.UtcNow, null, false, false).Result,
                                BotType.FlippingBot => _backtester.RunTradingBotBacktest(new TradingBotConfig
                                    {
                                        AccountName = _account.Name,
                                        MoneyManagement = moneyManagement,
                                        Ticker = ticker,
                                        Scenario = LightScenario.FromScenario(scenario),
                                        Timeframe = timeframe,
                                        IsForWatchingOnly = false,
                                        BotTradingBalance = 1000,
                                        IsForBacktest = true,
                                        CooldownPeriod = 1,
                                        MaxLossStreak = 0,
                                        FlipPosition = true,
                                        Name = "Test",
                                        FlipOnlyWhenInProfit = true,
                                        MaxPositionTimeHours = null,
                                        CloseEarlyWhenProfitable = false
                                    }, DateTime.UtcNow.AddDays(-6),
                                    DateTime.UtcNow, null, false, false).Result,
                                _ => throw new NotImplementedException(),
                            };

                            if (backtestResult.FinalPnl > 0
                                && (backtestResult.GrowthPercentage - backtestResult.HodlPercentage) > 30)
                            {
                                var currentResult = new Tuple<string, decimal, decimal, decimal, decimal>(
                                    ticker.ToString(),
                                    backtestResult.FinalPnl, s, t,
                                    backtestResult.GrowthPercentage - backtestResult.HodlPercentage);
                                result.Add(currentResult);
                            }

                            completedTest++;
                            UpdateProgression(totalTests, completedTest, timer.Elapsed.TotalSeconds);
                        }
                        catch (Exception ex)
                        {
                            completedTest++;
                            errors.Add($"{ticker}{_s}{s}{_s}{t}{_s}{ex.Message}");
                        }

                        timer.Stop();
                    }
                }
            });

            foreach (var r in result)
            {
                WriteCsvAnalyse(
                    $"{r.Item1}{_s}{r.Item2.ToString("0.000")}{_s}{r.Item3 * 100}{_s}{r.Item4 * 100}{_s}{r.Item5}");
            }

            foreach (var e in errors)
            {
                WriteCsvErrors(e);
            }

            var bestResult = result.OrderByDescending(b => b.Item3).FirstOrDefault();
            WriteCsvAnalyse(
                $"Best result : {bestResult.Item1} - Rsi Period : {bestResult.Item2} - {bestResult.Item3} - SL : {bestResult.Item4}% - TP : {bestResult.Item5}%");

            Assert.True(result.Any());
        }


        private void WriteCsvReport(string line)
        {
            File.AppendAllLines(_reportPath, new[] { line });
        }

        private void WriteCsvAnalyse(string line, string fileIdentifier = null)
        {
            if (!string.IsNullOrEmpty(fileIdentifier))
                _analysePath += $"-{fileIdentifier}-{DateTime.Now.ToString("dd-MM-HH-mm")}.csv";

            File.AppendAllLines(_analysePath, new[] { line });
        }

        private void WriteCsvErrors(string line)
        {
            File.AppendAllLines(_errorsPath, new[] { line });
        }

        private void CleanAnalyseFile(string fileIdentifier)
        {
            WriteCsvAnalyse("", fileIdentifier);
        }

        private decimal GetTotalTrades(List<int> periodRange, List<decimal> stopLossRange,
            List<decimal> takeProfitRange)
        {
            var stopLossRangeTotalTest = stopLossRange[1] / stopLossRange[2];
            var takeProfitRangeTotalTest = takeProfitRange[1] / takeProfitRange[2];

            var totalTrades = GetTotalTradeForStopLossTakeProfit(stopLossRange, takeProfitRange) *
                              stopLossRangeTotalTest * takeProfitRangeTotalTest;
            return totalTrades;
        }

        private decimal GetTotalTradeForStopLossTakeProfit(List<decimal> stopLossRange, List<decimal> takeProfitRange)
        {
            var stopLossRangeTotalTest = stopLossRange[1] / stopLossRange[2];
            var takeProfitRangeTotalTest = takeProfitRange[1] / takeProfitRange[2];

            var totalTrades = stopLossRangeTotalTest * takeProfitRangeTotalTest;
            return totalTrades;
        }


        private void UpdateProgression(decimal totalTest, int completedTest, double? elapsed = null)
        {
            var timeRemaining = "";
            if (elapsed.HasValue && completedTest > 0)
            {
                //_elapsedTimes.Add((elapsed.Value / completedTest) * ((double)totalTest - completedTest));
                _elapsedTimes.Add(elapsed.Value);
                //var t = (_elapsedTimes.Average() / completedTest) * ((double)totalTest - completedTest);
                var t = (_elapsedTimes.Average() * (double)(totalTest - completedTest));
                timeRemaining = $"   Remaining time: {t} seconds - Estimated end date: {DateTime.Now.AddSeconds(t)}";
            }

            ModifyFirstRow(_analysePath, $"{completedTest}/{totalTest}{timeRemaining}");
        }

        private void ModifyFirstRow(string filepath, string newValue)
        {
            ArrayList rows = new ArrayList();

            using (StreamReader reader = new StreamReader(filepath))
            {
                string row = null;

                while ((row = reader.ReadLine()) != null)
                {
                    rows.Add(row);
                }
            }

            // Determ if the file even contains rows.
            if (rows.Count > 0)
            {
                // Replace the first row.
                rows[0] = newValue;
            }
            else
            {
                // Add the new value because there
                // where no rows found in the file.
                rows.Add(newValue);
            }

            // Write the modified content to the file.
            using (StreamWriter writer = new StreamWriter(filepath, false))
            {
                foreach (String row in rows)
                {
                    writer.WriteLine(row);
                }
            }
        }

        [Theory]
        [InlineData(Ticker.BTC, Timeframe.FifteenMinutes, -10)]
        public async Task ListScenarios(Ticker ticker, Timeframe timeframe, int days)
        {
            // Arrange 
            var scenarios = GenerateScenarioCombinations();
            Console.WriteLine($"Total scenarios generated: {scenarios.Count}");

            // Display breakdown by strategy count
            var breakdown = CalculateScenarioBreakdown();
            Console.WriteLine("\n=== SCENARIO BREAKDOWN ===");
            Console.WriteLine($"Single strategy scenarios: {breakdown.SingleStrategy}");
            Console.WriteLine($"Two strategy scenarios: {breakdown.TwoStrategy}");
            Console.WriteLine($"Three strategy scenarios: {breakdown.ThreeStrategy}");
            Console.WriteLine($"Four strategy scenarios: {breakdown.FourStrategy}");
            Console.WriteLine($"Total estimated scenarios: {breakdown.Total}");

            // Display some example scenarios
            Console.WriteLine("\n=== EXAMPLE SCENARIOS ===");
            foreach (var scenario in scenarios.Take(3))
            {
                Console.WriteLine($"Scenario: {scenario.Name} ({scenario.Indicators.Count} strategies)");
                foreach (var strategy in scenario.Indicators)
                {
                    Console.WriteLine($"  - {strategy.Name} (Type: {strategy.Type})");
                }

                Console.WriteLine();
            }
        }

        [Theory]
        [InlineData(Ticker.BTC, Timeframe.FifteenMinutes, -10, BotType.ScalpingBot)]
        // [InlineData(Ticker.BTC, Timeframe.FifteenMinutes, -10, BotType.FlippingBot)]
        public async Task ComprehensiveScenarioBacktest(Ticker ticker, Timeframe timeframe, int days, BotType botType)
        {
            // Arrange
            var scenarios = GenerateScenarioCombinations();
            var results = new List<ScenarioBacktestResult>();
            var errors = new List<string>();
            var options = new ParallelOptions { MaxDegreeOfParallelism = 4 };

            // Standard money management for filtering best strategies
            var standardMoneyManagement = CreateStandardMoneyManagement(timeframe);

            var fileIdentifier = $"ScenarioBacktest_{ticker}_{timeframe}_{botType}_{DateTime.Now:yyyyMMdd_HHmmss}";
            var completedTests = 0;
            var totalTests = scenarios.Count;

            // Initialize CSV with headers
            InitializeScenarioBacktestCsv(fileIdentifier);
            UpdateScenarioProgression(totalTests, completedTests, fileIdentifier);

            Console.WriteLine($"Starting comprehensive backtest of {totalTests} scenarios...");
            Console.WriteLine($"Ticker: {ticker} | Timeframe: {timeframe} | Days: {days} | BotType: {botType}");

            // Get candles for backtesting
            var candles =
                await _exchangeService.GetCandles(_account, ticker, DateTime.Now.AddDays(days), timeframe, true);
            if (candles == null || candles.Count == 0)
            {
                Console.WriteLine("No candles available for backtesting");
                return;
            }

            Console.WriteLine($"Loaded {candles.Count} candles for backtesting");

            // Process scenarios in parallel
            Parallel.ForEach(scenarios, options, scenario =>
            {
                try
                {
                    var timer = new Stopwatch();
                    timer.Start();

                    var config = new TradingBotConfig
                    {
                        AccountName = _account.Name,
                        MoneyManagement = standardMoneyManagement,
                        Ticker = ticker,
                        Scenario = LightScenario.FromScenario(scenario),
                        Timeframe = timeframe,
                        IsForWatchingOnly = false,
                        BotTradingBalance = 1000,
                        IsForBacktest = true,
                        CooldownPeriod = 1,
                        MaxLossStreak = 0,
                        FlipPosition = botType == BotType.FlippingBot,
                        Name = $"Test_{scenario.Name}",
                        FlipOnlyWhenInProfit = true,
                        MaxPositionTimeHours = null,
                        CloseEarlyWhenProfitable = false
                    };

                    var backtestResult = _backtester.RunTradingBotBacktest(config, DateTime.UtcNow.AddDays(-6),
                        DateTime.UtcNow, null, false, false).Result;

                    timer.Stop();

                    var scenarioResult = new ScenarioBacktestResult
                    {
                        ScenarioName = scenario.Name,
                        StrategyCount = scenario.Indicators.Count,
                        Ticker = ticker.ToString(),
                        BotType = botType.ToString(),
                        FinalPnl = backtestResult.FinalPnl,
                        WinRate = backtestResult.WinRate,
                        GrowthPercentage = backtestResult.GrowthPercentage,
                        HodlPercentage = backtestResult.HodlPercentage,
                        OutperformanceVsHodl = backtestResult.GrowthPercentage - backtestResult.HodlPercentage,
                        MaxDrawdown = (double)(backtestResult.MaxDrawdown ?? 0),
                        SharpeRatio = (double)(backtestResult.SharpeRatio ?? 0),
                        ExecutionTime = timer.Elapsed.TotalSeconds,
                        StopLoss = standardMoneyManagement.StopLoss,
                        TakeProfit = standardMoneyManagement.TakeProfit,
                        Leverage = standardMoneyManagement.Leverage,
                        Score = backtestResult.Score,
                    };

                    results.Add(scenarioResult);
                    WriteScenarioBacktestResult(scenarioResult, fileIdentifier);

                    Interlocked.Increment(ref completedTests);
                    UpdateScenarioProgression(totalTests, completedTests, fileIdentifier, timer.Elapsed.TotalSeconds);
                }
                catch (Exception ex)
                {
                    Interlocked.Increment(ref completedTests);
                    var error = $"{scenario.Name}{_s}{ticker}{_s}{ex.Message}";
                    errors.Add(error);
                    WriteScenarioError(error, fileIdentifier);
                    UpdateScenarioProgression(totalTests, completedTests, fileIdentifier);
                }
            });

            // Write summary and analysis
            WriteSummaryAnalysis(results, fileIdentifier);
            WriteTopPerformingScenarios(results, fileIdentifier);

            Console.WriteLine($"\nBacktest completed! Results written to: {fileIdentifier}");
            Console.WriteLine($"Total scenarios tested: {results.Count}");
            Console.WriteLine($"Errors encountered: {errors.Count}");

            // Display top 5 performing scenarios
            var topScenarios = results
                .Where(r => r.FinalPnl > 0 && r.OutperformanceVsHodl > 10)
                .OrderByDescending(r => r.Score)
                .Take(5);

            Console.WriteLine("\n=== TOP 5 PERFORMING SCENARIOS ===");
            foreach (var scenario in topScenarios)
            {
                Console.WriteLine($"Scenario: {scenario.ScenarioName}");
                Console.WriteLine(
                    $"  Score: {scenario.Score:F2} | PnL: ${scenario.FinalPnl:F2} | WinRate: {scenario.WinRate}% | Outperformance: {scenario.OutperformanceVsHodl:F2}%");
                Console.WriteLine($"  Strategies: {scenario.StrategyCount}");
                Console.WriteLine();
            }

            Assert.True(results.Any(r => r.FinalPnl > 0), "At least one scenario should be profitable");
        }

        private MoneyManagement CreateStandardMoneyManagement(Timeframe timeframe)
        {
            // Optimized money management for strategy filtering
            // These values are designed to be balanced - not too aggressive, not too conservative
            return new MoneyManagement
            {
                Name = "StandardForFiltering",
                Timeframe = timeframe,
                Leverage = 2m, // Moderate leverage for meaningful results
                StopLoss = 0.012m, // 1.2% stop loss - tight enough to limit losses, loose enough to avoid noise
                TakeProfit = 0.024m, // 2.4% take profit - 2:1 reward/risk ratio
            };
        }

        private void InitializeScenarioBacktestCsv(string fileIdentifier)
        {
            var csvPath = GetScenarioBacktestCsvPath(fileIdentifier);
            var headers =
                "ScenarioName|StrategyCount|Ticker|BotType|FinalPnl|WinRate|GrowthPercentage|HodlPercentage|OutperformanceVsHodl|MaxDrawdown|TotalTrades|SharpeRatio|StopLoss|TakeProfit|Leverage|Score";
            File.WriteAllText(csvPath, headers + Environment.NewLine);
        }

        private void WriteScenarioBacktestResult(ScenarioBacktestResult result, string fileIdentifier)
        {
            var csvPath = GetScenarioBacktestCsvPath(fileIdentifier);

            // Write data directly with pipe separator - ensure exact field order matching headers
            var line =
                $"{result.ScenarioName}|{result.StrategyCount}|{result.Ticker}|{result.BotType}|{result.FinalPnl:F2}|{result.WinRate}|{result.GrowthPercentage:F2}|{result.HodlPercentage:F2}|{result.OutperformanceVsHodl:F2}|{result.MaxDrawdown:F2}|{result.TotalTrades}|{result.SharpeRatio:F3}|{result.StopLoss:F3}|{result.TakeProfit:F3}|{result.Leverage:F1}|{result.Score:F2}";

            File.AppendAllText(csvPath, line + Environment.NewLine);
        }

        private void WriteScenarioError(string error, string fileIdentifier)
        {
            var errorPath = GetScenarioErrorCsvPath(fileIdentifier);
            // Add CSV header if file doesn't exist
            if (!File.Exists(errorPath))
            {
                File.WriteAllText(errorPath, "ScenarioName|Ticker|ErrorMessage" + Environment.NewLine);
            }

            File.AppendAllText(errorPath, error + Environment.NewLine);
        }

        private void UpdateScenarioProgression(int totalTests, int completedTests, string fileIdentifier,
            double? elapsed = null)
        {
            var timeRemaining = "";
            if (elapsed.HasValue && completedTests > 0)
            {
                _elapsedTimes.Add(elapsed.Value);
                var avgTime = _elapsedTimes.Average();
                var estimatedRemaining = avgTime * (totalTests - completedTests);
                timeRemaining =
                    $" | Remaining: {estimatedRemaining:F0}s | ETA: {DateTime.Now.AddSeconds(estimatedRemaining):HH:mm:ss}";
            }

            var progressText =
                $"{completedTests}/{totalTests} ({(completedTests * 100.0 / totalTests):F1}%){timeRemaining}";

            // Output progress to console only
            Console.WriteLine($"Progress: {progressText}");
        }

        private void WriteSummaryAnalysis(List<ScenarioBacktestResult> results, string fileIdentifier)
        {
            var summaryPath = GetScenarioSummaryCsvPath(fileIdentifier);
            var summary = new List<string>
            {
                "=== COMPREHENSIVE SCENARIO BACKTEST SUMMARY ===",
                $"Total Scenarios Tested: {results.Count}",
                $"Profitable Scenarios: {results.Count(r => r.FinalPnl > 0)} ({results.Count(r => r.FinalPnl > 0) * 100.0 / results.Count:F1}%)",
                $"Scenarios Outperforming HODL: {results.Count(r => r.OutperformanceVsHodl > 0)} ({results.Count(r => r.OutperformanceVsHodl > 0) * 100.0 / results.Count:F1}%)",
                "",
                "=== PERFORMANCE METRICS ===",
                $"Average PnL: ${results.Average(r => r.FinalPnl):F2}",
                $"Best PnL: ${results.Max(r => r.FinalPnl):F2}",
                $"Worst PnL: ${results.Min(r => r.FinalPnl):F2}",
                $"Average Win Rate: {results.Average(r => r.WinRate):F1}%",
                $"Average Outperformance vs HODL: {results.Average(r => r.OutperformanceVsHodl):F2}%",
                $"Average Max Drawdown: {results.Average(r => r.MaxDrawdown):F2}%",
                "",
                "=== STRATEGY ANALYSIS ===",
                $"Single Strategy Scenarios: {results.Count(r => r.StrategyCount == 1)}",
                $"Two Strategy Scenarios: {results.Count(r => r.StrategyCount == 2)}",
                $"Three Strategy Scenarios: {results.Count(r => r.StrategyCount == 3)}",
                $"Four Strategy Scenarios: {results.Count(r => r.StrategyCount == 4)}"
            };

            File.WriteAllLines(summaryPath, summary);
        }

        private void WriteTopPerformingScenarios(List<ScenarioBacktestResult> results, string fileIdentifier)
        {
            var topPath = GetScenarioTopPerformersCsvPath(fileIdentifier);
            var headers =
                "Rank|ScenarioName|Score|FinalPnl|WinRate|OutperformanceVsHodl|MaxDrawdown|StrategyCount";

            var topPerformers = results
                .Where(r => r.FinalPnl > 0 && r.OutperformanceVsHodl > 5) // Filter for meaningful performance
                .OrderByDescending(r => r.Score)
                .Take(50) // Top 50 performers
                .Select((r, index) =>
                    $"{index + 1}|{r.ScenarioName}|{r.Score:F2}|{r.FinalPnl:F2}|{r.WinRate}|{r.OutperformanceVsHodl:F2}|{r.MaxDrawdown:F2}|{r.StrategyCount}")
                .ToList();

            var content = new List<string> { headers };
            content.AddRange(topPerformers);
            File.WriteAllLines(topPath, content);
        }

        private string GetScenarioBacktestCsvPath(string fileIdentifier) =>
            Path.Combine(GetBacktestReportsDirectory(), $"{fileIdentifier}_results.csv");

        private string GetScenarioErrorCsvPath(string fileIdentifier) =>
            Path.Combine(GetBacktestReportsDirectory(), $"{fileIdentifier}_errors.csv");

        private string GetScenarioSummaryCsvPath(string fileIdentifier) =>
            Path.Combine(GetBacktestReportsDirectory(), $"{fileIdentifier}_summary.txt");

        private string GetScenarioTopPerformersCsvPath(string fileIdentifier) =>
            Path.Combine(GetBacktestReportsDirectory(), $"{fileIdentifier}_top_performers.csv");

        private string GetBacktestReportsDirectory()
        {
            // Get the project root directory (where the .sln file should be)
            var currentDirectory = Directory.GetCurrentDirectory();
            var projectRoot = FindProjectRoot(currentDirectory);

            var reportsDirectory = Path.Combine(projectRoot, "BacktestingReports");

            // Create directory if it doesn't exist
            if (!Directory.Exists(reportsDirectory))
            {
                Directory.CreateDirectory(reportsDirectory);
            }

            return reportsDirectory;
        }

        private string FindProjectRoot(string startDirectory)
        {
            var directory = new DirectoryInfo(startDirectory);

            // Look for .sln file or src directory to identify project root
            while (directory != null)
            {
                if (directory.GetFiles("*.sln").Any() ||
                    directory.GetDirectories("src").Any())
                {
                    return directory.FullName;
                }

                directory = directory.Parent;
            }

            // Fallback to current directory if project root not found
            return startDirectory;
        }

        private ScenarioBreakdown CalculateScenarioBreakdown()
        {
            var availableStrategies = GetAllAvailableStrategies();
            var totalStrategies = availableStrategies.Count;

            // Calculate parameter combinations for each strategy
            var avgParametersPerStrategy = availableStrategies.Average(s => s.ParameterSets.Count);

            // Single strategy scenarios (each strategy × its parameter sets)
            var singleStrategy = availableStrategies.Sum(s => s.ParameterSets.Count);

            // Multi-strategy scenarios (combinations × parameter combinations)
            var twoStrategy = CalculateMultiStrategyScenarios(totalStrategies, 2, avgParametersPerStrategy);
            var threeStrategy = CalculateMultiStrategyScenarios(totalStrategies, 3, avgParametersPerStrategy);
            var fourStrategy = CalculateMultiStrategyScenarios(totalStrategies, 4, avgParametersPerStrategy);

            return new ScenarioBreakdown
            {
                SingleStrategy = singleStrategy,
                TwoStrategy = twoStrategy,
                ThreeStrategy = threeStrategy,
                FourStrategy = fourStrategy,
                Total = singleStrategy + twoStrategy + threeStrategy + fourStrategy
            };
        }

        private int CalculateMultiStrategyScenarios(int totalStrategies, int strategyCount, double avgParameters)
        {
            // Calculate combinations: C(n,k) = n! / (k!(n-k)!)
            var combinations = CalculateCombinations(totalStrategies, strategyCount);

            // Each combination has parameter variations (simplified to average)
            var parameterCombinations = Math.Pow(avgParameters, strategyCount);

            return (int)(combinations * parameterCombinations);
        }

        private int CalculateCombinations(int n, int k)
        {
            if (k > n) return 0;
            if (k == 0 || k == n) return 1;

            // Calculate C(n,k) = n! / (k!(n-k)!)
            int result = 1;
            for (int i = 1; i <= k; i++)
            {
                result = result * (n - i + 1) / i;
            }

            return result;
        }

        private List<Scenario> GenerateScenarioCombinations()
        {
            var scenarios = new List<Scenario>();

            // Single strategy scenarios
            scenarios.AddRange(GenerateSingleStrategyScenarios());

            // Two strategy combinations
            scenarios.AddRange(GenerateMultiStrategyScenarios(2));
            //
            // // Three strategy combinations
            // scenarios.AddRange(GenerateMultiStrategyScenarios(3));
            //
            // // Four strategy combinations
            // scenarios.AddRange(GenerateMultiStrategyScenarios(4));

            return scenarios;
        }

        private List<StrategyConfiguration> GetAllAvailableStrategies()
        {
            var strategies = new List<StrategyConfiguration>();

            // Signal strategies
            strategies.Add(new StrategyConfiguration
            {
                Type = IndicatorType.RsiDivergence, Name = "RSI_Divergence",
                ParameterSets = GetRsiDivergenceParameters()
            });
            strategies.Add(new StrategyConfiguration
            {
                Type = IndicatorType.RsiDivergenceConfirm, Name = "RSI_Divergence_Confirm",
                ParameterSets = GetRsiDivergenceConfirmParameters()
            });
            strategies.Add(new StrategyConfiguration
                { Type = IndicatorType.MacdCross, Name = "MACD_Cross", ParameterSets = GetMacdCrossParameters() });
            strategies.Add(new StrategyConfiguration
                { Type = IndicatorType.EmaCross, Name = "EMA_Cross", ParameterSets = GetEmaCrossParameters() });
            strategies.Add(new StrategyConfiguration
            {
                Type = IndicatorType.DualEmaCross, Name = "Dual_EMA_Cross", ParameterSets = GetDualEmaCrossParameters()
            });
            strategies.Add(new StrategyConfiguration
                { Type = IndicatorType.SuperTrend, Name = "SuperTrend", ParameterSets = GetSuperTrendParameters() });
            strategies.Add(new StrategyConfiguration
            {
                Type = IndicatorType.ChandelierExit, Name = "Chandelier_Exit",
                ParameterSets = GetChandelierExitParameters()
            });
            strategies.Add(new StrategyConfiguration
                { Type = IndicatorType.Stc, Name = "STC", ParameterSets = GetStcParameters() });
            strategies.Add(new StrategyConfiguration
                { Type = IndicatorType.LaggingStc, Name = "Lagging_STC", ParameterSets = GetLaggingStcParameters() });
            strategies.Add(new StrategyConfiguration
            {
                Type = IndicatorType.ThreeWhiteSoldiers, Name = "Three_White_Soldiers",
                ParameterSets = GetThreeWhiteSoldiersParameters()
            });
            strategies.Add(new StrategyConfiguration
            {
                Type = IndicatorType.SuperTrendCrossEma, Name = "SuperTrend_Cross_EMA",
                ParameterSets = GetSuperTrendCrossEmaParameters()
            });

            // Trend strategies
            strategies.Add(new StrategyConfiguration
                { Type = IndicatorType.EmaTrend, Name = "EMA_Trend", ParameterSets = GetEmaTrendParameters() });
            strategies.Add(new StrategyConfiguration
            {
                Type = IndicatorType.StochRsiTrend, Name = "StochRSI_Trend",
                ParameterSets = GetStochRsiTrendParameters()
            });

            // Context strategies
            strategies.Add(new StrategyConfiguration
                { Type = IndicatorType.StDev, Name = "Standard_Deviation", ParameterSets = GetStDevParameters() });

            return strategies;
        }

        private List<Scenario> GenerateSingleStrategyScenarios()
        {
            var scenarios = new List<Scenario>();
            var availableStrategies = GetAllAvailableStrategies();

            foreach (var strategyConfig in availableStrategies)
            {
                foreach (var parameterSet in strategyConfig.ParameterSets)
                {
                    var scenario = new Scenario($"{strategyConfig.Name}_{parameterSet.Name}")
                    {
                        Indicators = new List<IndicatorBase>
                        {
                            new RsiDivergenceIndicatorBase("RsiDiv", (int)parameterSet.Period)
                        }
                    };
                    scenarios.Add(scenario);
                }
            }

            return scenarios;
        }

        private List<Scenario> GenerateMultiStrategyScenarios(int strategyCount)
        {
            var scenarios = new List<Scenario>();
            var availableStrategies = GetAllAvailableStrategies();

            // Generate all combinations of strategies with the specified count
            var strategyCombinations = GetCombinations(availableStrategies, strategyCount);

            foreach (var strategyCombination in strategyCombinations)
            {
                // For each strategy combination, generate parameter combinations
                var parameterCombinations = GetParameterCombinations(strategyCombination.ToArray());

                foreach (var paramCombo in parameterCombinations)
                {
                    var scenarioName = string.Join("_",
                        paramCombo.Select(p => $"{p.strategyConfig.Name}_{p.parameterSet.Name}"));
                    var scenario = new Scenario(scenarioName)
                    {
                        Indicators = new List<IndicatorBase>
                        {
                            new RsiDivergenceIndicatorBase("RsiDiv", (int)paramCombo.First().parameterSet.Period)
                        }
                    };
                    scenario.LoopbackPeriod = 15;
                    scenarios.Add(scenario);
                }
            }

            return scenarios;
        }

        private IEnumerable<IEnumerable<T>> GetCombinations<T>(IEnumerable<T> elements, int k)
        {
            return k == 0
                ? new[] { new T[0] }
                : elements.SelectMany((e, i) =>
                    GetCombinations(elements.Skip(i + 1), k - 1).Select(c => (new[] { e }).Concat(c)));
        }

        private List<(StrategyConfiguration strategyConfig, ParameterSet parameterSet)[]> GetParameterCombinations(
            StrategyConfiguration[] strategies)
        {
            var result = new List<(StrategyConfiguration, ParameterSet)[]>();

            // Generate all parameter combinations for each strategy in the combination
            var allParameterSets = strategies.Select(s => s.ParameterSets.ToList()).ToArray();

            // Create cartesian product of all parameter sets
            var combinations = CartesianProduct(allParameterSets);

            foreach (var combination in combinations)
            {
                var parameterCombination =
                    strategies.Zip(combination, (strategy, paramSet) => (strategy, paramSet)).ToArray();
                result.Add(parameterCombination);
            }

            return result;
        }

        private IEnumerable<IEnumerable<T>> CartesianProduct<T>(IEnumerable<IEnumerable<T>> sequences)
        {
            IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
            return sequences.Aggregate(
                emptyProduct,
                (accumulator, sequence) =>
                    from accseq in accumulator
                    from item in sequence
                    select accseq.Concat(new[] { item }));
        }

        // Parameter set definitions for each strategy type - using financially meaningful ranges
        private List<ParameterSet> GetRsiDivergenceParameters()
        {
            var parameters = new List<ParameterSet>();

            // RSI Divergence: Most effective periods for crypto/forex
            var periods = new[] { 10, 14, 18 }; // Avoid too fast (noise) or too slow (lag)

            foreach (var period in periods)
            {
                parameters.Add(new ParameterSet { Name = $"RSI_{period}", Period = period });
            }

            return parameters;
        }

        private List<ParameterSet> GetRsiDivergenceConfirmParameters()
        {
            var parameters = new List<ParameterSet>();

            // RSI Confirmation: Slightly different periods to avoid redundancy
            var periods = new[] { 12, 16, 20 };

            foreach (var period in periods)
            {
                parameters.Add(new ParameterSet { Name = $"RSIConf_{period}", Period = period });
            }

            return parameters;
        }

        private List<ParameterSet> GetMacdCrossParameters()
        {
            var parameters = new List<ParameterSet>();

            // MACD: Proven combinations for different market speeds
            var configs = new[]
            {
                new { Fast = 8, Slow = 21, Signal = 5, Speed = "Fast" }, // Aggressive for scalping
                new { Fast = 12, Slow = 26, Signal = 9, Speed = "Standard" }, // Classic MACD
                new { Fast = 16, Slow = 30, Signal = 12, Speed = "Slow" } // Conservative for trends
            };

            foreach (var config in configs)
            {
                parameters.Add(new ParameterSet
                {
                    Name = $"MACD_{config.Speed}",
                    FastPeriods = config.Fast,
                    SlowPeriods = config.Slow,
                    SignalPeriods = config.Signal
                });
            }

            return parameters;
        }

        private List<ParameterSet> GetEmaCrossParameters()
        {
            var parameters = new List<ParameterSet>();

            // EMA Cross: Standard institutional levels
            var periods = new[] { 20, 50, 100 }; // Skip 200 as it's too slow for most crypto timeframes

            foreach (var period in periods)
            {
                parameters.Add(new ParameterSet { Name = $"EMA_{period}", Period = period });
            }

            return parameters;
        }

        private List<ParameterSet> GetDualEmaCrossParameters()
        {
            var parameters = new List<ParameterSet>();

            // Dual EMA: Non-overlapping combinations to avoid correlation
            var configs = new[]
            {
                new { Fast = 8, Slow = 21, Speed = "Fast" },
                new { Fast = 12, Slow = 26, Speed = "Medium" },
                new { Fast = 20, Slow = 50, Speed = "Slow" }
            };

            foreach (var config in configs)
            {
                parameters.Add(new ParameterSet
                {
                    Name = $"DualEMA_{config.Speed}",
                    FastPeriods = config.Fast,
                    SlowPeriods = config.Slow
                });
            }

            return parameters;
        }

        private List<ParameterSet> GetSuperTrendParameters()
        {
            var parameters = new List<ParameterSet>();

            // SuperTrend: Balanced between sensitivity and noise reduction
            var configs = new[]
            {
                new { Period = 10, Multiplier = 2.5, Type = "Sensitive" }, // Quick reactions
                new { Period = 14, Multiplier = 3.0, Type = "Balanced" }, // Standard setting
                new { Period = 18, Multiplier = 3.5, Type = "Conservative" } // Reduced noise
            };

            foreach (var config in configs)
            {
                parameters.Add(new ParameterSet
                {
                    Name = $"ST_{config.Type}",
                    Period = config.Period,
                    Multiplier = config.Multiplier
                });
            }

            return parameters;
        }

        private List<ParameterSet> GetChandelierExitParameters()
        {
            var parameters = new List<ParameterSet>();

            // Chandelier Exit: Different lookback periods for volatility
            var configs = new[]
            {
                new { Period = 14, Multiplier = 2.5, Type = "Short" }, // Quick exits
                new { Period = 22, Multiplier = 3.0, Type = "Standard" }, // Classic setting
                new { Period = 30, Multiplier = 3.5, Type = "Long" } // Patient exits
            };

            foreach (var config in configs)
            {
                parameters.Add(new ParameterSet
                {
                    Name = $"Chandelier_{config.Type}",
                    Period = config.Period,
                    Multiplier = config.Multiplier
                });
            }

            return parameters;
        }

        private List<ParameterSet> GetStcParameters()
        {
            var parameters = new List<ParameterSet>();

            // STC: Optimized for different market cycles
            var configs = new[]
            {
                new { Cycle = 8, Fast = 21, Slow = 45, Type = "Fast" }, // Short cycles
                new { Cycle = 10, Fast = 23, Slow = 50, Type = "Standard" }, // Default
                new { Cycle = 12, Fast = 25, Slow = 55, Type = "Smooth" } // Longer cycles
            };

            foreach (var config in configs)
            {
                parameters.Add(new ParameterSet
                {
                    Name = $"STC_{config.Type}",
                    CyclePeriods = config.Cycle,
                    FastPeriods = config.Fast,
                    SlowPeriods = config.Slow
                });
            }

            return parameters;
        }

        private List<ParameterSet> GetLaggingStcParameters()
        {
            var parameters = new List<ParameterSet>();

            // Lagging STC: Slightly different from regular STC to avoid redundancy
            var configs = new[]
            {
                new { Cycle = 9, Fast = 22, Slow = 48, Type = "Fast" },
                new { Cycle = 11, Fast = 24, Slow = 52, Type = "Standard" },
                new { Cycle = 13, Fast = 26, Slow = 56, Type = "Smooth" }
            };

            foreach (var config in configs)
            {
                parameters.Add(new ParameterSet
                {
                    Name = $"LaggingSTC_{config.Type}",
                    CyclePeriods = config.Cycle,
                    FastPeriods = config.Fast,
                    SlowPeriods = config.Slow
                });
            }

            return parameters;
        }

        private List<ParameterSet> GetThreeWhiteSoldiersParameters()
        {
            var parameters = new List<ParameterSet>();

            // Three White Soldiers: Pattern recognition - minimal parameters
            parameters.Add(new ParameterSet { Name = "Standard", Period = 3 });

            return parameters;
        }

        private List<ParameterSet> GetSuperTrendCrossEmaParameters()
        {
            var parameters = new List<ParameterSet>();

            // SuperTrend Cross EMA: Combined indicator parameters
            var configs = new[]
            {
                new { Period = 12, Multiplier = 2.8, Type = "Aggressive" },
                new { Period = 14, Multiplier = 3.0, Type = "Standard" },
                new { Period = 16, Multiplier = 3.2, Type = "Conservative" }
            };

            foreach (var config in configs)
            {
                parameters.Add(new ParameterSet
                {
                    Name = $"STCrossEMA_{config.Type}",
                    Period = config.Period,
                    Multiplier = config.Multiplier
                });
            }

            return parameters;
        }

        private List<ParameterSet> GetEmaTrendParameters()
        {
            var parameters = new List<ParameterSet>();

            // EMA Trend: Long-term trend identification
            var periods = new[] { 50, 100, 200 }; // Institutional levels

            foreach (var period in periods)
            {
                parameters.Add(new ParameterSet { Name = $"EMATrend_{period}", Period = period });
            }

            return parameters;
        }

        private List<ParameterSet> GetStochRsiTrendParameters()
        {
            var parameters = new List<ParameterSet>();

            // StochRSI: Optimized for momentum detection
            var configs = new[]
            {
                new { Period = 12, Stoch = 12, Signal = 3, Smooth = 1, Type = "Fast" },
                new { Period = 14, Stoch = 14, Signal = 3, Smooth = 1, Type = "Standard" },
                new { Period = 16, Stoch = 16, Signal = 5, Smooth = 3, Type = "Smooth" }
            };

            foreach (var config in configs)
            {
                parameters.Add(new ParameterSet
                {
                    Name = $"StochRSI_{config.Type}",
                    Period = config.Period,
                    StochPeriods = config.Stoch,
                    SignalPeriods = config.Signal,
                    SmoothPeriods = config.Smooth
                });
            }

            return parameters;
        }

        private List<ParameterSet> GetStDevParameters()
        {
            var parameters = new List<ParameterSet>();

            // Standard Deviation: Volatility context periods
            var periods = new[] { 14, 20, 26 }; // Short to medium-term volatility

            foreach (var period in periods)
            {
                parameters.Add(new ParameterSet { Name = $"StDev_{period}", Period = period });
            }

            return parameters;
        }
    }

    public class StrategyConfiguration
    {
        public IndicatorType Type { get; set; }
        public string Name { get; set; }
        public List<ParameterSet> ParameterSets { get; set; } = new();
    }

    public class ParameterSet
    {
        public string Name { get; set; }
        public int? Period { get; set; }
        public int? FastPeriods { get; set; }
        public int? SlowPeriods { get; set; }
        public int? SignalPeriods { get; set; }
        public double? Multiplier { get; set; }
        public int? StochPeriods { get; set; }
        public int? SmoothPeriods { get; set; }
        public int? CyclePeriods { get; set; }
    }

    public class ScenarioBreakdown
    {
        public int SingleStrategy { get; set; }
        public int TwoStrategy { get; set; }
        public int ThreeStrategy { get; set; }
        public int FourStrategy { get; set; }
        public int Total { get; set; }
    }

    public class ScenarioBacktestResult
    {
        public string ScenarioName { get; set; }
        public int StrategyCount { get; set; }
        public string Ticker { get; set; }
        public string BotType { get; set; }
        public decimal FinalPnl { get; set; }
        public int WinRate { get; set; }
        public decimal GrowthPercentage { get; set; }
        public decimal HodlPercentage { get; set; }
        public decimal OutperformanceVsHodl { get; set; }
        public double MaxDrawdown { get; set; }
        public int TotalTrades { get; set; }
        public double SharpeRatio { get; set; }
        public double ExecutionTime { get; set; }
        public decimal StopLoss { get; set; }
        public decimal TakeProfit { get; set; }
        public decimal Leverage { get; set; }
        public double Score { get; set; }
    }
}