public void SwichMostProfitableGroupUpMethod(Dictionary <AlgorithmType, NiceHashSMA> NiceHashData, bool log = true) { List <MiningDevice> profitableDevices = new List <MiningDevice>(); double CurrentProfit = 0.0d; foreach (var device in _miningDevices) { // calculate profits device.CalculateProfits(NiceHashData); // check if device has profitable algo if (device.MostProfitableKey != AlgorithmType.NONE) { profitableDevices.Add(device); CurrentProfit += device.GetCurrentMostProfitValue; device.Device.MostProfitableAlgorithm = device.Algorithms[device.MostProfitableKey].algoRef; } } // print profit statuses if (log) { StringBuilder stringBuilderFull = new StringBuilder(); stringBuilderFull.AppendLine("Current device profits:"); foreach (var device in _miningDevices) { StringBuilder stringBuilderDevice = new StringBuilder(); stringBuilderDevice.AppendLine(String.Format("\tProfits for {0} ({1}):", device.Device.UUID, device.Device.Name)); foreach (var algo in device.Algorithms) { stringBuilderDevice.AppendLine(String.Format("\t\tPROFIT = {0}\t(SPEED = {1}\t\t| NHSMA = {2})\t[{3}]", algo.Value.CurrentProfit.ToString(DOUBLE_FORMAT), // Profit algo.Value.AvaragedSpeed, // Speed algo.Value.CurNhmSMADataVal, // NiceHashData AlgorithmNiceHashNames.GetName(algo.Key) // Name )); } // most profitable stringBuilderDevice.AppendLine(String.Format("\t\tMOST PROFITABLE ALGO: {0}, PROFIT: {1}", AlgorithmNiceHashNames.GetName(device.MostProfitableKey), device.GetCurrentMostProfitValue.ToString(DOUBLE_FORMAT))); stringBuilderFull.AppendLine(stringBuilderDevice.ToString()); } Helpers.ConsolePrint(TAG, stringBuilderFull.ToString()); } // check if should mine if (CheckIfShouldMine(CurrentProfit, log) == false) { return; } // group devices with same supported algorithms _previousAllGroupedDevices = _currentAllGroupedDevices; _currentAllGroupedDevices = new List <SortedSet <string> >(); Dictionary <GroupedDevices, Algorithm> newGroupAndAlgorithm = new Dictionary <GroupedDevices, Algorithm>(); for (int first = 0; first < profitableDevices.Count; ++first) { var firstDev = profitableDevices[first].Device; // skip if no algorithm is profitable if (firstDev.MostProfitableAlgorithm == null) { if (log) { Helpers.ConsolePrint("SwichMostProfitableGroupUpMethod", String.Format("Device {0}, MostProfitableAlgorithm == null", firstDev.Name)); } continue; } // check if is in group bool isInGroup = false; foreach (var groupedDevices in _currentAllGroupedDevices) { if (groupedDevices.Contains(firstDev.UUID)) { isInGroup = true; break; } } if (isInGroup) { continue; } var newGroup = new GroupedDevices(); newGroup.Add(firstDev.UUID); for (int second = first + 1; second < profitableDevices.Count; ++second) { var secondDev = profitableDevices[second].Device; // first check if second device has profitable algorithm if (secondDev.MostProfitableAlgorithm != null) { // check if we should group if (GroupingLogic.IsEquihashGroupLogic(firstDev, secondDev) || GroupingLogic.IsDaggerAndSameComputePlatform(firstDev, secondDev) || GroupingLogic.IsGroupBinaryAndAlgorithmSame(firstDev, secondDev)) { newGroup.Add(secondDev.UUID); } } } _currentAllGroupedDevices.Add(newGroup); newGroupAndAlgorithm.Add(newGroup, firstDev.MostProfitableAlgorithm); } // stop groupes that aren't in current group devices foreach (var curPrevGroup in _previousAllGroupedDevices) { var curPrevGroupKey = CalcGroupedDevicesKey(curPrevGroup); bool contains = false; foreach (var curCheckGroup in _currentAllGroupedDevices) { var curCheckGroupKey = CalcGroupedDevicesKey(curCheckGroup); if (curPrevGroupKey == curCheckGroupKey) { contains = true; break; } } if (!contains) { _groupedDevicesMiners[curPrevGroupKey].Stop(); } } // switch to newGroupAndAlgorithm most profitable algorithm foreach (var kvpGroupAlgorithm in newGroupAndAlgorithm) { var group = kvpGroupAlgorithm.Key; var algorithm = kvpGroupAlgorithm.Value; GroupMiners currentGroupMiners; // try find if it doesn't exist create new string groupStringKey = CalcGroupedDevicesKey(group); if (!_groupedDevicesMiners.TryGetValue(groupStringKey, out currentGroupMiners)) { currentGroupMiners = new GroupMiners(group); _groupedDevicesMiners.Add(groupStringKey, currentGroupMiners); } currentGroupMiners.StartAlgorihtm(algorithm, _miningLocation, _workerBtcStringWorker); } // stats quick fix code if (_currentAllGroupedDevices.Count != _previousAllGroupedDevices.Count) { MinerStatsCheck(NiceHashData); } }
/// <summary> /// SwichMostProfitable should check the best combination for most profit. /// Calculate profit for each supported algorithm per device group. /// Build from ground up compatible devices and algorithms. /// See #region Groupping logic /// Device groups are CPU, AMD_OpenCL and NVIDIA CUDA SM.x.x. /// NVIDIA SMx.x should be paired separately except for daggerhashimoto. /// </summary> /// <param name="NiceHashData"></param> public void SwichMostProfitableGroupUpMethod(Dictionary <AlgorithmType, NiceHashSMA> NiceHashData) { var devProfits = GetEnabledDeviceProifitDictionary(_perDeviceSpeedDictionary, NiceHashData); #if (SWITCH_TESTING) SwitchTesting.Instance.SetNext(ref devProfits, _enabledDevices); #endif double CurrentProfit = 0.0d; // calculate most profitable algorithm per enabled device foreach (var cdev in _enabledDevices) { var curDevProfits = devProfits[cdev.UUID]; double maxProfit = double.MinValue; AlgorithmType maxAlgorithmTypeKey = AlgorithmType.NONE; var algorithmSettings = cdev.DeviceBenchmarkConfig.AlgorithmSettings; foreach (var kvpTypeProfit in curDevProfits) { if (algorithmSettings.ContainsKey(kvpTypeProfit.Key) && !algorithmSettings[kvpTypeProfit.Key].Skip && kvpTypeProfit.Value > 0.0d && maxProfit < kvpTypeProfit.Value) { // extra check if current device can't handle dagger if (AlgorithmType.DaggerHashimoto == kvpTypeProfit.Key && !cdev.IsEtherumCapale) { continue; } maxProfit = kvpTypeProfit.Value; maxAlgorithmTypeKey = kvpTypeProfit.Key; } } if (maxAlgorithmTypeKey == AlgorithmType.NONE) { cdev.MostProfitableAlgorithm = null; } else { cdev.MostProfitableAlgorithm = algorithmSettings[maxAlgorithmTypeKey]; // add most profitable to cumulative profit CurrentProfit += maxProfit; } } // now if profitable check // TODO FOR NOW USD ONLY var currentProfitUSD = (CurrentProfit * Globals.BitcoinRate); Helpers.ConsolePrint(TAG, "Current Global profit: " + currentProfitUSD.ToString("F8") + " USD/Day"); if (ConfigManager.Instance.GeneralConfig.MinimumProfit > 0 && currentProfitUSD < ConfigManager.Instance.GeneralConfig.MinimumProfit) { IsProfitable = false; IsCurrentlyIdle = true; _mainFormRatesComunication.ShowNotProfitable(); // return don't group StopAllMinersNonProfitable(); Helpers.ConsolePrint(TAG, "Current Global profit: NOT PROFITABLE MinProfit " + ConfigManager.Instance.GeneralConfig.MinimumProfit.ToString("F8") + " USD/Day"); return; } else { IsProfitable = true; IsCurrentlyIdle = false; _mainFormRatesComunication.HideNotProfitable(); string profitabilityInfo = ConfigManager.Instance.GeneralConfig.MinimumProfit == 0 ? "mine always regardless of profit" : ConfigManager.Instance.GeneralConfig.MinimumProfit.ToString("F8") + " USD/Day"; Helpers.ConsolePrint(TAG, "Current Global profit: IS PROFITABLE MinProfit " + profitabilityInfo); } // group devices with same supported algorithms _previousAllGroupedDevices = _currentAllGroupedDevices; _currentAllGroupedDevices = new AllGroupedDevices(); Dictionary <GroupedDevices, Algorithm> newGroupAndAlgorithm = new Dictionary <GroupedDevices, Algorithm>(); for (int first = 0; first < _enabledDevices.Count; ++first) { var firstDev = _enabledDevices[first]; // skip if no algorithm is profitable if (firstDev.MostProfitableAlgorithm == null) { Helpers.ConsolePrint("SwichMostProfitableGroupUpMethod", String.Format("Device {0}, MostProfitableAlgorithm == null", firstDev.Name)); continue; } // check if is in group bool isInGroup = false; foreach (var groupedDevices in _currentAllGroupedDevices) { if (groupedDevices.Contains(firstDev.UUID)) { isInGroup = true; break; } } if (isInGroup) { continue; } var newGroup = new GroupedDevices(); newGroup.Add(firstDev.UUID); for (int second = first + 1; second < _enabledDevices.Count; ++second) { var secondDev = _enabledDevices[second]; // first check if second device has profitable algorithm if (secondDev.MostProfitableAlgorithm != null) { // check if we should group if (IsDaggerAndSameComputePlatform(firstDev, secondDev) || IsGroupBinaryAndAlgorithmSame(firstDev, secondDev)) { newGroup.Add(secondDev.UUID); } } } _currentAllGroupedDevices.Add(newGroup); newGroupAndAlgorithm.Add(newGroup, firstDev.MostProfitableAlgorithm); } // stop groupes that aren't in current group devices foreach (var curPrevGroup in _previousAllGroupedDevices) { var curPrevGroupKey = CalcGroupedDevicesKey(curPrevGroup); bool contains = false; foreach (var curCheckGroup in _currentAllGroupedDevices) { var curCheckGroupKey = CalcGroupedDevicesKey(curCheckGroup); if (curPrevGroupKey == curCheckGroupKey) { contains = true; break; } } if (!contains) { _groupedDevicesMiners[curPrevGroupKey].Stop(); } } // switch to newGroupAndAlgorithm most profitable algorithm foreach (var kvpGroupAlgorithm in newGroupAndAlgorithm) { var group = kvpGroupAlgorithm.Key; var algorithm = kvpGroupAlgorithm.Value; GroupMiners currentGroupMiners; // try find if it doesn't exist create new string groupStringKey = CalcGroupedDevicesKey(group); if (!_groupedDevicesMiners.TryGetValue(groupStringKey, out currentGroupMiners)) { currentGroupMiners = new GroupMiners(group); _groupedDevicesMiners.Add(groupStringKey, currentGroupMiners); } currentGroupMiners.StartAlgorihtm(algorithm, _miningLocation, _workerBtcStringWorker); } // stats quick fix code if (_currentAllGroupedDevices.Count != _previousAllGroupedDevices.Count) { MinerStatsCheck(NiceHashData); } }