private static void SetOptimalMiningConfigWithThreshold(Profit profit, IProfitSwitchingStrategy profitSwitchingStrategy, DeviceConfig algorithmDeviceConfig, Pool algorithmPool, Dictionary <string, MiningConfig> optimalMiningConfigs)
        {
            MiningConfig newMiningConfig = new MiningConfig(algorithmDeviceConfig, algorithmPool);

            if (_currentMininigConfigs.ContainsKey(algorithmDeviceConfig.FullDeviceId))
            {
                MiningConfig currentMiningConfig = _currentMininigConfigs[algorithmDeviceConfig.FullDeviceId];
                Profit?      currentProfit       = GetAdjustedProfit(currentMiningConfig.Pool, currentMiningConfig.DeviceConfig.ExpectedHashrate, true);
                if (!currentProfit.HasValue || profitSwitchingStrategy.IsProfitABetterThanB(profit, algorithmPool.ProfitTimeframe, currentProfit.Value, currentMiningConfig.Pool.ProfitTimeframe, Config.ProfitSwitchThreshold))
                {
                    newMiningConfig = new MiningConfig(currentMiningConfig.DeviceConfig, currentMiningConfig.Pool);
                }
            }
            optimalMiningConfigs[newMiningConfig.DeviceConfig.FullDeviceId] = newMiningConfig;
        }
        private static void CheckSwitching()
        {
            try
            {
                WriteInfo(" Check switching..");
                IProfitSwitchingStrategy profitSwitchingStrategy = ProfitSwitchingStrategyFactory.GetProfitSwitchingStrategy(_profitSwitchingStrategy ?? ProfitSwitchingStrategy.MaximizeFiat);
                // Find optimal configs
                Dictionary <string, MiningConfig> optimalMiningConfigs = new Dictionary <string, MiningConfig>();
                if (_manualMode)
                {
                    foreach (var manualMininigConfig in _manualMininigConfigs)
                    {
                        MiningConfig miningConfig = new MiningConfig(manualMininigConfig.Value.DeviceConfig, manualMininigConfig.Value.Pool);
                        optimalMiningConfigs.Add(manualMininigConfig.Key, miningConfig);
                    }
                }
                else
                {
                    foreach (Algorithm algorithm in Config.Algorithms)
                    {
                        if (algorithm.Enabled)
                        {
                            foreach (DeviceConfig algorithmDeviceConfig in algorithm.DeviceConfigs)
                            {
                                if (algorithmDeviceConfig.Enabled)
                                {
                                    foreach (Pool algorithmPool in algorithm.Pools.Where(p => p.Enabled))
                                    {
                                        Profit?profit = GetAdjustedProfit(algorithmPool, algorithmDeviceConfig.ExpectedHashrate, true);
                                        if (profit.HasValue)
                                        {
                                            if (!optimalMiningConfigs.ContainsKey(algorithmDeviceConfig.FullDeviceId))
                                            {
                                                SetOptimalMiningConfigWithThreshold(profit.Value, profitSwitchingStrategy, algorithmDeviceConfig, algorithmPool, optimalMiningConfigs);
                                            }
                                            else
                                            {
                                                MiningConfig bestMiningConfig = optimalMiningConfigs[algorithmDeviceConfig.FullDeviceId];
                                                Profit?      bestProfit       = GetAdjustedProfit(bestMiningConfig.Pool, bestMiningConfig.DeviceConfig.ExpectedHashrate, true);
                                                if (!bestProfit.HasValue || profitSwitchingStrategy.IsProfitABetterThanB(profit.Value, algorithmPool.ProfitTimeframe, bestProfit.Value, bestMiningConfig.Pool.ProfitTimeframe, 0))
                                                {
                                                    SetOptimalMiningConfigWithThreshold(profit.Value, profitSwitchingStrategy, algorithmDeviceConfig, algorithmPool, optimalMiningConfigs);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                // Merge miners and get list of optimal miners
                List <IMiner> optimalMiners = new List <IMiner>();
                foreach (var optimalMiningConfigKeyValue in optimalMiningConfigs)
                {
                    MiningConfig miningConfig = optimalMiningConfigKeyValue.Value;
                    IMiner       miner        = MinerFactory.GetMiner(new HashSet <DeviceConfig>()
                    {
                        miningConfig.DeviceConfig
                    }, miningConfig.Pool);
                    IMiner existingMiner = optimalMiners.FirstOrDefault(m => m.Name == miner.Name && m.Pool.Equals(miner.Pool));
                    if (existingMiner != null)
                    {
                        existingMiner.DeviceConfigs.Add(miningConfig.DeviceConfig);
                        miningConfig.Miner = existingMiner;
                    }
                    else
                    {
                        miningConfig.Miner = miner;
                        optimalMiners.Add(miner);
                    }
                }

                bool displayNeedsUpdate = false;
                // Get list of current miners
                List <IMiner> currentMiners = GetCurrentMiners();

                //Check if existing miner will be kept
                foreach (IMiner currentMiner in currentMiners)
                {
                    if (optimalMiners.Any(om => om.Pool.Equals(currentMiner.Pool) && om.DeviceConfigs.SetEquals(currentMiner.DeviceConfigs)))
                    {
                        foreach (DeviceConfig currentMinerDeviceConfig in currentMiner.DeviceConfigs)
                        {
                            optimalMiningConfigs[currentMinerDeviceConfig.FullDeviceId].Miner = currentMiner;
                        }
                    }
                }

                //Check if existing miner has to be closed
                foreach (IMiner currentMiner in currentMiners.ToArray())
                {
                    if (!optimalMiners.Any(om => om.Pool.Equals(currentMiner.Pool) && om.DeviceConfigs.SetEquals(currentMiner.DeviceConfigs)))
                    {
                        displayNeedsUpdate = true;
                        currentMiner.StopMiner();
                        currentMiners.Remove(currentMiner);
                    }
                }

                //Check if new miner has to start
                foreach (IMiner optimalMiner in optimalMiners)
                {
                    if (!currentMiners.Any(cm => cm.Pool.Equals(optimalMiner.Pool) && cm.DeviceConfigs.SetEquals(optimalMiner.DeviceConfigs)))
                    {
                        displayNeedsUpdate = true;
                        foreach (DeviceConfig deviceConfig in optimalMiner.DeviceConfigs)
                        {
                            if (!string.IsNullOrEmpty(deviceConfig.PrepareScript))
                            {
                                Helpers.ExecuteScript(deviceConfig.MinerPath, AppFolderPath);
                            }
                        }
                        Task.Delay(TimeSpan.FromSeconds(Config.MinerStartDelay)).Wait();
                        optimalMiner.StartMiner(Config.StartMinerMinimized);
                    }
                }

                _currentMininigConfigs = optimalMiningConfigs;

                if (displayNeedsUpdate)
                {
                    _displayUpdaterCts?.Cancel();
                }
            }
            catch (Exception e)
            {
                Log.Debug("Check switching failed: " + e);
            }
        }