public static StrategyVariant[] BruteForceGeneration(OptimiseParameter[] ops)
        {
            List <StrategyVariant> variants = new List <StrategyVariant>();

            List <List <object> > values = new List <List <object> >();

            foreach (OptimiseParameter op in ops)
            {
                values.Add(new List <object>(op.GetValues()));
            }

            int[] indexArray = new int[ops.Length];

            int floater = indexArray.Length - 1;

            bool exitLoop = false;

            while (indexArray[floater] < values[floater].Count && !exitLoop)
            {
                StrategyVariant variant = new StrategyVariant();
                variants.Add(variant);
                for (int i = 0; i < indexArray.Length; i++)
                {
                    variant.Parameters.Add(values[i][indexArray[i]]);
                }


                if (indexArray[floater] >= values[floater].Count - 1)
                {
                    indexArray[floater] = 0;

                    int carry = floater - 1;
                    while (carry >= 0)
                    {
                        if (indexArray[carry] >= values[carry].Count - 1)
                        {
                            indexArray[carry] = 0;
                            carry--;
                            if (carry < 0)
                            {
                                exitLoop = true;
                            }
                        }
                        else
                        {
                            indexArray[carry]++;
                            break;
                        }
                    }
                }
                else
                {
                    indexArray[floater]++;
                }
            }

            return(variants.ToArray());
        }
        public static StrategyVariant Default(StrategyParameter[] strateyParameters)
        {
            StrategyVariant svar = new StrategyVariant();

            foreach (StrategyParameter sp in strateyParameters)
            {
                svar.Parameters.Add(sp.Value);
            }

            return(svar);
        }
        public void Run(string strategyName, string strategiesDLL, bool optimise = false)
        {
            start = DateTime.Now;

            TestSummary = new TestSummary();

            Optimise = optimise;

            //Get the strategy
            Strategy strategy = Strategy.Load(strategyName, strategiesDLL);

            //Copy across the strategy back test setup
            if (strategy.StartDate != null)
            {
                TestSummary.StartDate = strategy.StartDate;
            }
            if (strategy.EndDate != null)
            {
                TestSummary.EndDate = strategy.EndDate;
            }
            TestSummary.ReduceCorrelatedParams = strategy.ReduceCorrelatedParams;
            TestSummary.ReduceByRankParams     = strategy.ReduceByRankParams;
            TestSummary.TradeDataLabels        = strategy.TradeDataLabels;

            //Get all the possible variants from this strategies parameters
            StrategyVariant[] variants;
            if (optimise)
            {
                variants = StrategyVariant.BruteForceGeneration(strategy.OptimiseParameters.ToArray());
            }
            else
            {
                variants = new StrategyVariant[] { StrategyVariant.Default(strategy.Parameters.ToArray()) }
            };

            threadTasks = new Queue <BackTestTask> [strategy.Cpus];

            //Load in the asset details and add these to the strategy if selected in TradeAssetList
            Dictionary <string, Asset> assetDetails = Asset.LoadAssetFile(strategy.AssetDetailsFile);

            foreach (string assetName in strategy.TradeAssetList)
            {
                Asset asset = assetDetails[assetName];

                MessageDelegate?.Invoke("Loading in data " + assetName);

                //load in the data before we start
                foreach (ExternalFeatureData externalFeature in strategy.ExternalFeatures)
                {
                    if (!asset.Data.ContainsKey(externalFeature.Timeframe))
                    {
                        DataBuilder.LoadExternalFeatureBinary(asset, externalFeature, MessageDelegate);
                    }
                }

                //Read all the bytes from the datapath from the 1 min timeframe if the data is not already loaded
                //this is very fast about 0.9 seconds for 10 years of minute data
                if (asset.Dataset == null)
                {
                    asset.Dataset = DataBuilder.LoadBinary(asset.DataPath);
                }
            }

            tasksRequired = 0;

            int threadIndex = 0;

            foreach (string assetName in strategy.TradeAssetList)
            {
                foreach (StrategyVariant currentVariant in variants)
                {
                    Strategy localStrategy = Strategy.Load(strategyName, strategiesDLL);
                    Asset    asset         = assetDetails[assetName];
                    localStrategy.Assets.Add(assetName, asset);

                    //set the strategy parameters
                    for (int pIndex = 0; pIndex < localStrategy.Parameters.Count; pIndex++)
                    {
                        localStrategy.SetParameter(localStrategy.Parameters[pIndex].Name, currentVariant.Parameters[pIndex]);
                    }

                    localStrategy.Description = asset.Name + " " + currentVariant.ToString();

                    if (threadIndex >= threadTasks.Length)
                    {
                        threadIndex = 0;
                    }

                    BackTestTask btt = new BackTestTask(asset, localStrategy);

                    if (threadTasks[threadIndex] == null)
                    {
                        threadTasks[threadIndex] = new Queue <BackTestTask>();
                    }
                    threadTasks[threadIndex].Enqueue(btt);

                    tasksRequired++;

                    threadIndex++;
                }
            }

            MessageDelegate?.Invoke("Starting " + tasksRequired + " tests ...");

            foreach (Queue <BackTestTask> threadQueue in threadTasks)
            {
                if (threadQueue != null)
                {
                    if (threadQueue.Count > 0)
                    {
                        Thread thread = new Thread(() => Test(threadQueue, OnCompleteTest));
                        thread.Start();
                    }
                }
            }
        }