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 Task ProfitSwitcherTaskAsync(string appFolderPath, DirectoryInfo appRootFolder, Settings settings, List <Coin> coins, List <NicehashAlgorithm> nicehashAlgorithms, CancellationToken token) { return(Task.Run(() => { //Get pool profit data while (!token.IsCancellationRequested) { var statusCts = new CancellationTokenSource(); var watchdogCts = new CancellationTokenSource(); try { ResetConsole(); // Get pool mined coins profitability var timeoutCts = new CancellationTokenSource(60000); var childCts = CancellationTokenSource.CreateLinkedTokenSource(token, timeoutCts.Token); var profitProviders = Helpers.GetPoolProfitProviders(settings, null); foreach (var coin in coins.Where(c => !String.IsNullOrEmpty(c.OverridePoolProfitProviders))) { foreach (var profitProviderString in coin.OverridePoolProfitProviders.Split(",")) { ProfitProvider profitProvider; if (Enum.TryParse(profitProviderString, out profitProvider)) { if (!profitProviders.Contains(profitProvider)) { profitProviders.Add(profitProvider); } } } } var poolProfitsDictionaryUnordered = new Dictionary <ProfitProvider, Dictionary <string, Profit> >(); var profitProviderTasks = new List <Task>(); foreach (var profitProvider in profitProviders) { if (!poolProfitsDictionaryUnordered.ContainsKey(profitProvider)) { profitProviderTasks.Add(Task.Run(() => { IPoolProfitProvider profitProviderClass = PoolProfitProviderFactory.GetPoolProfitProvider(profitProvider); poolProfitsDictionaryUnordered[profitProvider] = profitProviderClass.GetProfits(appRootFolder, settings, coins, childCts.Token); }, childCts.Token)); } } #if DEBUG Stopwatch sw = new Stopwatch(); sw.Start(); #endif Task.WhenAll(profitProviderTasks).Wait(childCts.Token); #if DEBUG sw.Stop(); Console.WriteLine($"Fetching profit data took {(int)sw.Elapsed.TotalSeconds} seconds."); #endif //Reorder because of async var poolProfitsDictionary = new Dictionary <ProfitProvider, Dictionary <string, Profit> >(); foreach (var profitProvider in profitProviders) { if (poolProfitsDictionaryUnordered.ContainsKey(profitProvider)) { poolProfitsDictionary[profitProvider] = poolProfitsDictionaryUnordered[profitProvider]; } } IProfitSwitchingStrategy profitSwitchingStrategy = ProfitSwitchingStrategyFactory.GetProfitSwitchingStrategy(settings.ProfitSwitchingStrategy); MineableReward currentReward = null; // Get best pool mined coin MineableReward bestPoolminedCoin = null; if (!token.IsCancellationRequested) { var result = profitSwitchingStrategy.GetBestPoolminedCoin(coins, _currentMineable, poolProfitsDictionary, settings); bestPoolminedCoin = result?.Result; if (currentReward == null) { currentReward = result?.Current; } if (bestPoolminedCoin?.Mineable != null) { Console.WriteLine("Got best pool mined coin: " + bestPoolminedCoin.Mineable.DisplayName); } else { Console.WriteLine("Couldn't determine best pool mined coin."); } } //Get Nicehash Profit Dictionary <int, Profit> nicehashProfitsDictionary = null; if (!token.IsCancellationRequested) { nicehashProfitsDictionary = NicehashApi.GetProfits(appRootFolder, settings, nicehashAlgorithms, childCts.Token); } //Get best nicehash algorithm MineableReward bestNicehashAlgorithm = null; if (!token.IsCancellationRequested && nicehashProfitsDictionary != null) { var result = profitSwitchingStrategy.GetBestNicehashAlgorithm(nicehashAlgorithms, _currentMineable, nicehashProfitsDictionary, settings); bestNicehashAlgorithm = result?.Result; if (currentReward == null) { currentReward = result?.Current; } if (bestNicehashAlgorithm?.Mineable != null) { Console.WriteLine("Got best nicehash algorithm: " + bestNicehashAlgorithm.Mineable.DisplayName); } else { Console.WriteLine("Couldn't determine best nicehash algorithm."); } } //Sort profit table if (settings.ProfitSorting != SortingMode.None) { var coinProfitComparer = new CoinProfitComparer(settings.ProfitSorting, poolProfitsDictionary); coins.Sort(coinProfitComparer); var nicehashProfitComparer = new NicehashProfitComparer(settings.ProfitSorting, nicehashProfitsDictionary); nicehashAlgorithms.Sort(nicehashProfitComparer); } //Print table if (!token.IsCancellationRequested && nicehashProfitsDictionary != null) { PrintProfitTable(coins, poolProfitsDictionary, nicehashAlgorithms, nicehashProfitsDictionary, settings); } //Mine using best algorithm/coin if (!token.IsCancellationRequested) { Console.WriteLine(); Mineable bestOverallMineable = null; if (_manualSelection && _manualSelectedMineable != null) { bestOverallMineable = _manualSelectedMineable; } else { bestOverallMineable = profitSwitchingStrategy.GetBestMineable(bestPoolminedCoin, bestNicehashAlgorithm, currentReward, settings)?.Mineable; } if (bestOverallMineable != null) { Console.WriteLine($"Determined best mining method: {bestOverallMineable.DisplayName}"); if (_currentMineable == null || _currentMineable.Id != bestOverallMineable.Id) { StartMiner(bestOverallMineable, settings, appFolderPath, appRootFolder); } } else { Log.Information("Couldn't determine best mining method."); } } var statusUpdaterTask = StatusUpdaterTaskAsync(DateTimeOffset.Now.AddSeconds(settings.ProfitCheckInterval), settings, appRootFolder, coins, poolProfitsDictionary, nicehashAlgorithms, nicehashProfitsDictionary, statusCts.Token); if (!token.IsCancellationRequested) { if (settings.ProfitCheckInterval > 0) { Task.Delay(TimeSpan.FromSeconds(settings.ProfitCheckInterval), token).Wait(token); } else { token.WaitHandle.WaitOne(); } } statusCts.Cancel(); } catch (TaskCanceledException) { Log.Information("Cancelled profit task."); statusCts.Cancel(); } catch (AggregateException) { Log.Information("Cancelled profit task 2."); statusCts.Cancel(); } catch (OperationCanceledException) { Log.Information("Cancelled profit task 3."); statusCts.Cancel(); } catch (Exception ex) { Log.Error("Profit switcher task failed: " + ex); statusCts.Cancel(); } } }, token)); }
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); } }