void UpdateGroupedDevices()
        {
            foreach (DestinationOSDeviceInfo driver in allDrivers.DownloadedDestinationOSDrivers)
            {
                DestinationOSDevicesGroup destinationOSDevicesGroup = GroupedDevices.Where(g => g.DeviceClass == driver.DeviceClass).FirstOrDefault();
                if (destinationOSDevicesGroup == null)
                {
                    GroupedDevices.Add(new DestinationOSDevicesGroup(driver.DeviceClass, driver.DeviceClassName, driver.DeviceClassImageSmall, new List <DestinationOSDeviceInfo> {
                        driver
                    }));
                }
                else
                {
                    destinationOSDevicesGroup.Drivers.Add(driver);
                }
            }

            OrderedDeviceGroups = CollectionViewSource.GetDefaultView(GroupedDevices);
            OrderedDeviceGroups.SortDescriptions.Clear();
            OrderedDeviceGroups.SortDescriptions.Add(new SortDescription("Order", ListSortDirection.Ascending));
            OrderedDeviceGroups.Refresh();
        }
Example #2
0
        public async Task SwichMostProfitableGroupUpMethod(Dictionary <AlgorithmType, NiceHashSMA> NiceHashData, bool log = true)
        {
#if (SWITCH_TESTING)
            MiningDevice.SetNextTest();
#endif
            List <MiningPair> profitableDevices = new List <MiningPair>();
            double            CurrentProfit     = 0.0d;
            double            PrevStateProfit   = 0.0d;
            foreach (var device in _miningDevices)
            {
                // calculate profits
                device.CalculateProfits(NiceHashData);
                // check if device has profitable algo
                if (device.HasProfitableAlgo())
                {
                    profitableDevices.Add(device.GetMostProfitablePair());
                    CurrentProfit   += device.GetCurrentMostProfitValue;
                    PrevStateProfit += device.GetPrevMostProfitValue;
                }
            }

            // 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.GetFullName()));
                    foreach (var algo in device.Algorithms)
                    {
                        stringBuilderDevice.AppendLine(String.Format("\t\tPROFIT = {0}\t(SPEED = {1}\t\t| NHSMA = {2})\t[{3}]",
                                                                     algo.CurrentProfit.ToString(DOUBLE_FORMAT),                                          // Profit
                                                                     algo.AvaragedSpeed + (algo.IsDual() ? "/" + algo.SecondaryAveragedSpeed : ""),       // Speed
                                                                     algo.CurNhmSMADataVal + (algo.IsDual() ? "/" + algo.SecondaryCurNhmSMADataVal : ""), // NiceHashData
                                                                     algo.AlgorithmStringID                                                               // Name
                                                                     ));
                    }
                    // most profitable
                    stringBuilderDevice.AppendLine(String.Format("\t\tMOST PROFITABLE ALGO: {0}, PROFIT: {1}",
                                                                 device.GetMostProfitableString(),
                                                                 device.GetCurrentMostProfitValue.ToString(DOUBLE_FORMAT)));
                    stringBuilderFull.AppendLine(stringBuilderDevice.ToString());
                }
                Helpers.ConsolePrint(TAG, stringBuilderFull.ToString());
            }

            // check if should mine
            // Only check if profitable inside this method when getting SMA data, cheching during mining is not reliable
            if (CheckIfShouldMine(CurrentProfit, log) == false)
            {
                foreach (var device in _miningDevices)
                {
                    device.SetNotMining();
                }
                return;
            }

            // check profit threshold
            Helpers.ConsolePrint(TAG, String.Format("PrevStateProfit {0}, CurrentProfit {1}", PrevStateProfit, CurrentProfit));
            if (PrevStateProfit > 0 && CurrentProfit > 0)
            {
                double a = Math.Max(PrevStateProfit, CurrentProfit);
                double b = Math.Min(PrevStateProfit, CurrentProfit);
                //double percDiff = Math.Abs((PrevStateProfit / CurrentProfit) - 1);
                double percDiff = ((a - b)) / b;
                if (percDiff < ConfigManager.GeneralConfig.SwitchProfitabilityThreshold)
                {
                    // don't switch
                    Helpers.ConsolePrint(TAG, String.Format("Will NOT switch profit diff is {0}, current threshold {1}", percDiff, ConfigManager.GeneralConfig.SwitchProfitabilityThreshold));
                    // RESTORE OLD PROFITS STATE
                    foreach (var device in _miningDevices)
                    {
                        device.RestoreOldProfitsState();
                    }
                    if (!Miner.SHOULD_START_DONATING)
                    {
                        return;
                    }
                }
                else
                {
                    Helpers.ConsolePrint(TAG, String.Format("Will SWITCH profit diff is {0}, current threshold {1}", percDiff, ConfigManager.GeneralConfig.SwitchProfitabilityThreshold));
                }
            }

            // group new miners
            Dictionary <string, List <MiningPair> > newGroupedMiningPairs = new Dictionary <string, List <MiningPair> >();
            // group devices with same supported algorithms
            {
                var currentGroupedDevices = new List <GroupedDevices>();
                for (int first = 0; first < profitableDevices.Count; ++first)
                {
                    var firstDev = profitableDevices[first].Device;
                    // check if is in group
                    bool isInGroup = false;
                    foreach (var groupedDevices in currentGroupedDevices)
                    {
                        if (groupedDevices.Contains(firstDev.UUID))
                        {
                            isInGroup = true;
                            break;
                        }
                    }
                    // if device is not in any group create new group and check if other device should group
                    if (isInGroup == false)
                    {
                        var newGroup    = new GroupedDevices();
                        var miningPairs = new List <MiningPair>()
                        {
                            profitableDevices[first]
                        };
                        newGroup.Add(firstDev.UUID);
                        for (int second = first + 1; second < profitableDevices.Count; ++second)
                        {
                            // check if we should group
                            var firstPair  = profitableDevices[first];
                            var secondPair = profitableDevices[second];
                            if (GroupingLogic.ShouldGroup(firstPair, secondPair))
                            {
                                var secondDev = profitableDevices[second].Device;
                                newGroup.Add(secondDev.UUID);
                                miningPairs.Add(profitableDevices[second]);
                            }
                        }
                        currentGroupedDevices.Add(newGroup);
                        newGroupedMiningPairs[CalcGroupedDevicesKey(newGroup)] = miningPairs;
                    }
                }
            }
            //bool IsMinerStatsCheckUpdate = false;
            {
                // check which groupMiners should be stopped and which ones should be started and which to keep running
                Dictionary <string, GroupMiner> toStopGroupMiners   = new Dictionary <string, GroupMiner>();
                Dictionary <string, GroupMiner> toRunNewGroupMiners = new Dictionary <string, GroupMiner>();
                Dictionary <string, GroupMiner> noChangeGroupMiners = new Dictionary <string, GroupMiner>();
                // check what to stop/update
                foreach (string runningGroupKey in _runningGroupMiners.Keys)
                {
                    if (newGroupedMiningPairs.ContainsKey(runningGroupKey) == false)
                    {
                        // runningGroupKey not in new group definately needs to be stopped and removed from curently running
                        toStopGroupMiners[runningGroupKey] = _runningGroupMiners[runningGroupKey];
                    }
                    // If we need to start donating, stop everything
                    else if (!Miner.IS_DONATING && Miner.SHOULD_START_DONATING)
                    {
                        toStopGroupMiners[runningGroupKey] = _runningGroupMiners[runningGroupKey];

                        var        miningPairs   = newGroupedMiningPairs[runningGroupKey];
                        var        newAlgoType   = GetMinerPairAlgorithmType(miningPairs);
                        GroupMiner newGroupMiner = null;
                        if (newAlgoType == AlgorithmType.DaggerHashimoto)
                        {
                            if (_ethminerNVIDIAPaused != null && _ethminerNVIDIAPaused.Key == runningGroupKey)
                            {
                                newGroupMiner = _ethminerNVIDIAPaused;
                            }
                            if (_ethminerAMDPaused != null && _ethminerAMDPaused.Key == runningGroupKey)
                            {
                                newGroupMiner = _ethminerAMDPaused;
                            }
                        }
                        if (newGroupMiner == null)
                        {
                            newGroupMiner = new GroupMiner(miningPairs, runningGroupKey);
                        }
                        toRunNewGroupMiners[runningGroupKey] = newGroupMiner;
                        Miner.IS_DONATING = true;
                    }
                    else if (Miner.IS_DONATING && Miner.SHOULD_STOP_DONATING)
                    {
                        toStopGroupMiners[runningGroupKey] = _runningGroupMiners[runningGroupKey];

                        var        miningPairs   = newGroupedMiningPairs[runningGroupKey];
                        var        newAlgoType   = GetMinerPairAlgorithmType(miningPairs);
                        GroupMiner newGroupMiner = null;
                        if (newAlgoType == AlgorithmType.DaggerHashimoto)
                        {
                            if (_ethminerNVIDIAPaused != null && _ethminerNVIDIAPaused.Key == runningGroupKey)
                            {
                                newGroupMiner = _ethminerNVIDIAPaused;
                            }
                            if (_ethminerAMDPaused != null && _ethminerAMDPaused.Key == runningGroupKey)
                            {
                                newGroupMiner = _ethminerAMDPaused;
                            }
                        }
                        if (newGroupMiner == null)
                        {
                            newGroupMiner = new GroupMiner(miningPairs, runningGroupKey);
                        }
                        toRunNewGroupMiners[runningGroupKey] = newGroupMiner;

                        Miner.DonationStart = Miner.DonationStart.Add(Miner.DonateEvery);
                        Miner.IS_DONATING   = false;
                    }
                    else
                    {
                        // runningGroupKey is contained but needs to check if mining algorithm is changed
                        var miningPairs = newGroupedMiningPairs[runningGroupKey];
                        var newAlgoType = GetMinerPairAlgorithmType(miningPairs);
                        if (newAlgoType != AlgorithmType.NONE && newAlgoType != AlgorithmType.INVALID)
                        {
                            // if algoType valid and different from currently running update
                            if (newAlgoType != _runningGroupMiners[runningGroupKey].DualAlgorithmType)
                            {
                                // remove current one and schedule to stop mining
                                toStopGroupMiners[runningGroupKey] = _runningGroupMiners[runningGroupKey];
                                // create new one TODO check if DaggerHashimoto
                                GroupMiner newGroupMiner = null;
                                if (newAlgoType == AlgorithmType.DaggerHashimoto)
                                {
                                    if (_ethminerNVIDIAPaused != null && _ethminerNVIDIAPaused.Key == runningGroupKey)
                                    {
                                        newGroupMiner = _ethminerNVIDIAPaused;
                                    }
                                    if (_ethminerAMDPaused != null && _ethminerAMDPaused.Key == runningGroupKey)
                                    {
                                        newGroupMiner = _ethminerAMDPaused;
                                    }
                                }
                                if (newGroupMiner == null)
                                {
                                    newGroupMiner = new GroupMiner(miningPairs, runningGroupKey);
                                }
                                toRunNewGroupMiners[runningGroupKey] = newGroupMiner;
                            }
                            else
                            {
                                noChangeGroupMiners[runningGroupKey] = _runningGroupMiners[runningGroupKey];
                            }
                        }
                    }
                }
                // check brand new
                foreach (var kvp in newGroupedMiningPairs)
                {
                    var key         = kvp.Key;
                    var miningPairs = kvp.Value;
                    if (_runningGroupMiners.ContainsKey(key) == false)
                    {
                        GroupMiner newGroupMiner = new GroupMiner(miningPairs, key);
                        toRunNewGroupMiners[key] = newGroupMiner;
                    }
                }

                if ((toStopGroupMiners.Values.Count > 0) || (toRunNewGroupMiners.Values.Count > 0))
                {
                    StringBuilder stringBuilderPreviousAlgo = new StringBuilder();
                    StringBuilder stringBuilderCurrentAlgo  = new StringBuilder();
                    StringBuilder stringBuilderNoChangeAlgo = new StringBuilder();

                    // stop old miners
                    foreach (var toStop in toStopGroupMiners.Values)
                    {
                        stringBuilderPreviousAlgo.Append(String.Format("{0}: {1}, ", toStop.DevicesInfoString, toStop.AlgorithmType));

                        toStop.Stop();
                        _runningGroupMiners.Remove(toStop.Key);
                        // TODO check if daggerHashimoto and save
                        if (toStop.AlgorithmType == AlgorithmType.DaggerHashimoto)
                        {
                            if (toStop.DeviceType == DeviceType.NVIDIA)
                            {
                                _ethminerNVIDIAPaused = toStop;
                            }
                            else if (toStop.DeviceType == DeviceType.AMD)
                            {
                                _ethminerAMDPaused = toStop;
                            }
                        }
                    }

                    // start new miners
                    foreach (var toStart in toRunNewGroupMiners.Values)
                    {
                        stringBuilderCurrentAlgo.Append(String.Format("{0}: {1}, ", toStart.DevicesInfoString, toStart.AlgorithmType));

                        toStart.Start(_miningLocation, _btcAdress, _worker);
                        _runningGroupMiners[toStart.Key] = toStart;
                    }

                    // which miners dosen't change
                    foreach (var noChange in noChangeGroupMiners.Values)
                    {
                        stringBuilderNoChangeAlgo.Append(String.Format("{0}: {1}, ", noChange.DevicesInfoString, noChange.AlgorithmType));
                    }

                    if (stringBuilderPreviousAlgo.Length > 0)
                    {
                        Helpers.ConsolePrint(TAG, String.Format("Stop Mining: {0}", stringBuilderPreviousAlgo.ToString()));
                    }

                    if (stringBuilderCurrentAlgo.Length > 0)
                    {
                        Helpers.ConsolePrint(TAG, String.Format("Now Mining : {0}", stringBuilderCurrentAlgo.ToString()));
                    }

                    if (stringBuilderNoChangeAlgo.Length > 0)
                    {
                        Helpers.ConsolePrint(TAG, String.Format("No change  : {0}", stringBuilderNoChangeAlgo.ToString()));
                    }
                }
            }

            // stats quick fix code
            //if (_currentAllGroupedDevices.Count != _previousAllGroupedDevices.Count) {
            await MinerStatsCheck(NiceHashData);

            //}
        }
Example #3
0
        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);
            }
        }
Example #4
0
        private void SwichMostProfitableGroupUpMethod(object sender, SmaUpdateEventArgs e)
        {
#if (SWITCH_TESTING)
            MiningDevice.SetNextTest();
#endif
            var profitableDevices = new List <MiningPair>();
            var currentProfit     = 0.0d;
            var prevStateProfit   = 0.0d;
            foreach (var device in _miningDevices)
            {
                // calculate profits
                device.CalculateProfits(e.NormalizedProfits);
                // check if device has profitable algo
                if (device.HasProfitableAlgo())
                {
                    profitableDevices.Add(device.GetMostProfitablePair());
                    currentProfit   += device.GetCurrentMostProfitValue;
                    prevStateProfit += device.GetPrevMostProfitValue;
                }
            }
            var stringBuilderFull = new StringBuilder();
            stringBuilderFull.AppendLine("Current device profits:");
            foreach (var device in _miningDevices)
            {
                var stringBuilderDevice = new StringBuilder();
                stringBuilderDevice.AppendLine($"\tProfits for {device.Device.Uuid} ({device.Device.GetFullName()}):");
                foreach (var algo in device.Algorithms)
                {
                    stringBuilderDevice.AppendLine(
                        $"\t\tPROFIT = {algo.CurrentProfit.ToString(DoubleFormat)}" +
                        $"\t(SPEED = {algo.AvaragedSpeed:e5}" +
                        $"\t\t| NHSMA = {algo.CurNhmSmaDataVal:e5})" +
                        $"\t[{algo.AlgorithmStringID}]"
                        );
                    if (algo is DualAlgorithm dualAlg)
                    {
                        stringBuilderDevice.AppendLine(
                            $"\t\t\t\t\t  Secondary:\t\t {dualAlg.SecondaryAveragedSpeed:e5}" +
                            $"\t\t\t\t  {dualAlg.SecondaryCurNhmSmaDataVal:e5}"
                            );
                    }
                }
                // most profitable
                stringBuilderDevice.AppendLine(
                    $"\t\tMOST PROFITABLE ALGO: {device.GetMostProfitableString()}, PROFIT: {device.GetCurrentMostProfitValue.ToString(DoubleFormat)}");
                stringBuilderFull.AppendLine(stringBuilderDevice.ToString());
            }
            Helpers.ConsolePrint(Tag, stringBuilderFull.ToString());

            // check if should mine
            // Only check if profitable inside this method when getting SMA data, cheching during mining is not reliable
            if (CheckIfShouldMine(currentProfit) == false)
            {
                foreach (var device in _miningDevices)
                {
                    device.SetNotMining();
                }

                return;
            }

            // check profit threshold
            Helpers.ConsolePrint(Tag, $"PrevStateProfit {prevStateProfit}, CurrentProfit {currentProfit}");
            if (prevStateProfit > 0 && currentProfit > 0)
            {
                var a = Math.Max(prevStateProfit, currentProfit);
                var b = Math.Min(prevStateProfit, currentProfit);
                //double percDiff = Math.Abs((PrevStateProfit / CurrentProfit) - 1);
                var percDiff = ((a - b)) / b;
                if (percDiff < ConfigManager.GeneralConfig.SwitchProfitabilityThreshold)
                {
                    // don't switch
                    Helpers.ConsolePrint(Tag,
                                         $"Will NOT switch profit diff is {percDiff}, current threshold {ConfigManager.GeneralConfig.SwitchProfitabilityThreshold}");
                    // RESTORE OLD PROFITS STATE
                    foreach (var device in _miningDevices)
                    {
                        device.RestoreOldProfitsState();
                    }

                    return;
                }

                Helpers.ConsolePrint(Tag,
                                     $"Will SWITCH profit diff is {percDiff}, current threshold {ConfigManager.GeneralConfig.SwitchProfitabilityThreshold}");
            }

            // group new miners
            var newGroupedMiningPairs = new Dictionary <string, List <MiningPair> >();
            // group devices with same supported algorithms
            {
                var currentGroupedDevices = new List <GroupedDevices>();
                for (var first = 0; first < profitableDevices.Count; ++first)
                {
                    var firstDev = profitableDevices[first].Device;
                    // check if is in group
                    var isInGroup = currentGroupedDevices.Any(groupedDevices => groupedDevices.Contains(firstDev.Uuid));
                    // if device is not in any group create new group and check if other device should group
                    if (isInGroup == false)
                    {
                        var newGroup    = new GroupedDevices();
                        var miningPairs = new List <MiningPair>()
                        {
                            profitableDevices[first]
                        };
                        newGroup.Add(firstDev.Uuid);
                        for (var second = first + 1; second < profitableDevices.Count; ++second)
                        {
                            // check if we should group
                            var firstPair  = profitableDevices[first];
                            var secondPair = profitableDevices[second];
                            if (GroupingLogic.ShouldGroup(firstPair, secondPair))
                            {
                                var secondDev = profitableDevices[second].Device;
                                newGroup.Add(secondDev.Uuid);
                                miningPairs.Add(profitableDevices[second]);
                            }
                        }

                        currentGroupedDevices.Add(newGroup);
                        newGroupedMiningPairs[CalcGroupedDevicesKey(newGroup)] = miningPairs;
                    }
                }
            }
            //bool IsMinerStatsCheckUpdate = false;
            {
                // check which groupMiners should be stopped and which ones should be started and which to keep running
                var toStopGroupMiners   = new Dictionary <string, GroupMiner>();
                var toRunNewGroupMiners = new Dictionary <string, GroupMiner>();
                var noChangeGroupMiners = new Dictionary <string, GroupMiner>();
                // check what to stop/update
                foreach (var runningGroupKey in _runningGroupMiners.Keys)
                {
                    if (newGroupedMiningPairs.ContainsKey(runningGroupKey) == false)
                    {
                        // runningGroupKey not in new group definately needs to be stopped and removed from curently running
                        toStopGroupMiners[runningGroupKey] = _runningGroupMiners[runningGroupKey];
                    }
                    else
                    {
                        // runningGroupKey is contained but needs to check if mining algorithm is changed
                        var miningPairs = newGroupedMiningPairs[runningGroupKey];
                        var newAlgoType = GetMinerPairAlgorithmType(miningPairs);
                        if (newAlgoType != AlgorithmType.NONE && newAlgoType != AlgorithmType.INVALID)
                        {
                            // Check if dcri optimal value has changed
                            var dcriChanged = false;
                            foreach (var mPair in _runningGroupMiners[runningGroupKey].Miner.MiningSetup.MiningPairs)
                            {
                                if (mPair.Algorithm is DualAlgorithm algo &&
                                    algo.TuningEnabled &&
                                    algo.MostProfitableIntensity != algo.CurrentIntensity)
                                {
                                    dcriChanged = true;
                                    break;
                                }
                            }

                            // if algoType valid and different from currently running update
                            if (newAlgoType != _runningGroupMiners[runningGroupKey].DualAlgorithmType || dcriChanged)
                            {
                                // remove current one and schedule to stop mining
                                toStopGroupMiners[runningGroupKey] = _runningGroupMiners[runningGroupKey];
                                // create new one TODO check if DaggerHashimoto
                                GroupMiner newGroupMiner = null;
                                if (newAlgoType == AlgorithmType.DaggerHashimoto)
                                {
                                    if (_ethminerNvidiaPaused != null && _ethminerNvidiaPaused.Key == runningGroupKey)
                                    {
                                        newGroupMiner = _ethminerNvidiaPaused;
                                    }

                                    if (_ethminerAmdPaused != null && _ethminerAmdPaused.Key == runningGroupKey)
                                    {
                                        newGroupMiner = _ethminerAmdPaused;
                                    }
                                }

                                if (newGroupMiner == null)
                                {
                                    newGroupMiner = new GroupMiner(miningPairs, runningGroupKey);
                                }

                                toRunNewGroupMiners[runningGroupKey] = newGroupMiner;
                            }
                            else
                            {
                                noChangeGroupMiners[runningGroupKey] = _runningGroupMiners[runningGroupKey];
                            }
                        }
                    }
                }

                // check brand new
                foreach (var kvp in newGroupedMiningPairs)
                {
                    var key         = kvp.Key;
                    var miningPairs = kvp.Value;
                    if (_runningGroupMiners.ContainsKey(key) == false)
                    {
                        var newGroupMiner = new GroupMiner(miningPairs, key);
                        toRunNewGroupMiners[key] = newGroupMiner;
                    }
                }

                if ((toStopGroupMiners.Values.Count > 0) || (toRunNewGroupMiners.Values.Count > 0))
                {
                    var stringBuilderPreviousAlgo = new StringBuilder();
                    var stringBuilderCurrentAlgo  = new StringBuilder();
                    var stringBuilderNoChangeAlgo = new StringBuilder();

                    // stop old miners
                    foreach (var toStop in toStopGroupMiners.Values)
                    {
                        stringBuilderPreviousAlgo.Append($"{toStop.DevicesInfoString}: {toStop.AlgorithmType}, ");

                        toStop.Stop();
                        _runningGroupMiners.Remove(toStop.Key);
                        // TODO check if daggerHashimoto and save
                        if (toStop.AlgorithmType == AlgorithmType.DaggerHashimoto)
                        {
                            if (toStop.DeviceType == DeviceType.NVIDIA)
                            {
                                _ethminerNvidiaPaused = toStop;
                            }
                            else if (toStop.DeviceType == DeviceType.AMD)
                            {
                                _ethminerAmdPaused = toStop;
                            }
                        }
                    }

                    // start new miners
                    foreach (var toStart in toRunNewGroupMiners.Values)
                    {
                        stringBuilderCurrentAlgo.Append($"{toStart.DevicesInfoString}: {toStart.AlgorithmType}, ");

                        toStart.Start(_miningLocation, _btcAdress, _worker);
                        _runningGroupMiners[toStart.Key] = toStart;
                    }

                    // which miners dosen't change
                    foreach (var noChange in noChangeGroupMiners.Values)
                    {
                        stringBuilderNoChangeAlgo.Append($"{noChange.DevicesInfoString}: {noChange.AlgorithmType}, ");
                    }

                    if (stringBuilderPreviousAlgo.Length > 0)
                    {
                        Helpers.ConsolePrint(Tag, $"Stop Mining: {stringBuilderPreviousAlgo}");
                    }

                    if (stringBuilderCurrentAlgo.Length > 0)
                    {
                        Helpers.ConsolePrint(Tag, $"Now Mining : {stringBuilderCurrentAlgo}");
                    }

                    if (stringBuilderNoChangeAlgo.Length > 0)
                    {
                        Helpers.ConsolePrint(Tag, $"No change  : {stringBuilderNoChangeAlgo}");
                    }
                }
            }

            // stats quick fix code
            //if (_currentAllGroupedDevices.Count != _previousAllGroupedDevices.Count) {
            //await MinerStatsCheck();
            //}

            _mainFormRatesComunication?.ForceMinerStatsUpdate();
        }
Example #5
0
        /// <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);
            }
        }
Example #6
0
        public bool StartInitialize(IMainFormRatesComunication mainFormRatesComunication,
                                    string miningLocation, string worker, string btcAdress)
        {
            _mainFormRatesComunication = mainFormRatesComunication;
            _miningLocation            = miningLocation;
            _worker    = worker;
            _btcAdress = btcAdress;

            if (_worker.Length > 0)
            {
                _workerBtcStringWorker = _btcAdress + "." + _worker;
            }
            else
            {
                _workerBtcStringWorker = _btcAdress;
            }

            _perDeviceSpeedDictionary = GetEnabledDeviceTypeSpeeds();
            //_groupedDevicesMiners = new Dictionary<GroupedDevices, GroupMiners>();
            _groupedDevicesMiners     = new Dictionary <string, GroupMiners>();
            _enabledDevices           = new List <ComputeDevice>();
            _currentAllGroupedDevices = new AllGroupedDevices();

            // assume profitable
            IsProfitable = true;


            // this checks if there are enabled devices and enabled algorithms
            bool isMiningEnabled = false;

            foreach (var cdev in ComputeDevice.AllAvaliableDevices)
            {
                if (cdev.Enabled)
                {
                    _enabledDevices.Add(cdev);
                    // check if in CPU group and add the saved CPU miners
                    if (cdev.DeviceGroupType == DeviceGroupType.CPU)
                    {
                        GroupedDevices gdevs = new GroupedDevices();
                        gdevs.Add(cdev.UUID);
                        cpuminer      miner         = _cpuMiners[cdev.Group];
                        CpuGroupMiner cpuGroupMiner = new CpuGroupMiner(gdevs, miner);
                        _groupedDevicesMiners.Add(CalcGroupedDevicesKey(gdevs), cpuGroupMiner);
                    }
                    // check if any algorithm enabled
                    if (!isMiningEnabled)
                    {
                        foreach (var algorithm in cdev.DeviceBenchmarkConfig.AlgorithmSettings)
                        {
                            if (!algorithm.Value.Skip)
                            {
                                isMiningEnabled = true;
                                break;
                            }
                        }
                    }
                }
            }

            if (isMiningEnabled)
            {
                _preventSleepTimer.Start();
            }

            IsCurrentlyIdle = !isMiningEnabled;

            return(isMiningEnabled);
        }
Example #7
0
        public void SwichMostProfitableGroupUpMethod(Dictionary <AlgorithmType, NiceHashSMA> NiceHashData, bool log = true)
        {
#if (SWITCH_TESTING)
            MiningDevice.SetNextTest();
#endif
            List <MiningPair> profitableDevices = new List <MiningPair>();
            double            CurrentProfit     = 0.0d;
            foreach (var device in _miningDevices)
            {
                // calculate profits
                device.CalculateProfits(NiceHashData);
                // check if device has profitable algo
                if (device.HasProfitableAlgo())
                {
                    profitableDevices.Add(device.GetMostProfitablePair());
                    CurrentProfit += device.GetCurrentMostProfitValue;
                }
            }
            // 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;
            }

            Dictionary <string, List <MiningPair> > newGroupedMiningPairs = new Dictionary <string, List <MiningPair> >();
            // group devices with same supported algorithms
            {
                var currentGroupedDevices = new List <GroupedDevices>();
                for (int first = 0; first < profitableDevices.Count; ++first)
                {
                    var firstDev = profitableDevices[first].Device;
                    // check if is in group
                    bool isInGroup = false;
                    foreach (var groupedDevices in currentGroupedDevices)
                    {
                        if (groupedDevices.Contains(firstDev.UUID))
                        {
                            isInGroup = true;
                            break;
                        }
                    }
                    // if device is not in any group create new group and check if other device should group
                    if (isInGroup == false)
                    {
                        var newGroup    = new GroupedDevices();
                        var miningPairs = new List <MiningPair>()
                        {
                            profitableDevices[first]
                        };
                        newGroup.Add(firstDev.UUID);
                        for (int second = first + 1; second < profitableDevices.Count; ++second)
                        {
                            // check if we should group
                            var firstPair  = profitableDevices[first];
                            var secondPair = profitableDevices[second];
                            if (GroupingLogic.ShouldGroup(firstPair, secondPair))
                            {
                                var secondDev = profitableDevices[second].Device;
                                newGroup.Add(secondDev.UUID);
                                miningPairs.Add(profitableDevices[second]);
                            }
                        }
                        currentGroupedDevices.Add(newGroup);
                        newGroupedMiningPairs[CalcGroupedDevicesKey(newGroup)] = miningPairs;
                    }
                }
            }
            //bool IsMinerStatsCheckUpdate = false;
            {
                // check which groupMiners should be stopped and which ones should be started and which to keep running
                Dictionary <string, GroupMiner> toStopGroupMiners   = new Dictionary <string, GroupMiner>();
                Dictionary <string, GroupMiner> toRunNewGroupMiners = new Dictionary <string, GroupMiner>();
                // check what to stop/update
                foreach (string runningGroupKey in _runningGroupMiners.Keys)
                {
                    if (newGroupedMiningPairs.ContainsKey(runningGroupKey) == false)
                    {
                        // runningGroupKey not in new group definately needs to be stopped and removed from curently running
                        toStopGroupMiners[runningGroupKey] = _runningGroupMiners[runningGroupKey];
                    }
                    else
                    {
                        // runningGroupKey is contained but needs to check if mining algorithm is changed
                        var miningPairs = newGroupedMiningPairs[runningGroupKey];
                        var newAlgoType = GetMinerPairAlgorithmType(miningPairs);
                        if (newAlgoType != AlgorithmType.NONE && newAlgoType != AlgorithmType.INVALID)
                        {
                            // if algoType valid and different from currently running update
                            if (newAlgoType != _runningGroupMiners[runningGroupKey].AlgorithmType)
                            {
                                // remove current one and schedule to stop mining
                                toStopGroupMiners[runningGroupKey] = _runningGroupMiners[runningGroupKey];
                                // create new one TODO check if DaggerHashimoto
                                GroupMiner newGroupMiner = null;
                                if (newAlgoType == AlgorithmType.DaggerHashimoto)
                                {
                                    if (_ethminerNVIDIAPaused != null && _ethminerNVIDIAPaused.Key == runningGroupKey)
                                    {
                                        newGroupMiner = _ethminerNVIDIAPaused;
                                    }
                                    if (_ethminerAMDPaused != null && _ethminerAMDPaused.Key == runningGroupKey)
                                    {
                                        newGroupMiner = _ethminerAMDPaused;
                                    }
                                }
                                if (newGroupMiner == null)
                                {
                                    newGroupMiner = new GroupMiner(miningPairs, runningGroupKey);
                                }
                                toRunNewGroupMiners[runningGroupKey] = newGroupMiner;
                            }
                        }
                    }
                }
                // check brand new
                foreach (var kvp in newGroupedMiningPairs)
                {
                    var key         = kvp.Key;
                    var miningPairs = kvp.Value;
                    if (_runningGroupMiners.ContainsKey(key) == false)
                    {
                        GroupMiner newGroupMiner = new GroupMiner(miningPairs, key);
                        toRunNewGroupMiners[key] = newGroupMiner;
                    }
                }
                // stop old miners
                foreach (var toStop in toStopGroupMiners.Values)
                {
                    toStop.Stop();
                    _runningGroupMiners.Remove(toStop.Key);
                    // TODO check if daggerHashimoto and save
                    if (toStop.AlgorithmType == AlgorithmType.DaggerHashimoto)
                    {
                        if (toStop.DeviceType == DeviceType.NVIDIA)
                        {
                            _ethminerNVIDIAPaused = toStop;
                        }
                        else if (toStop.DeviceType == DeviceType.AMD)
                        {
                            _ethminerAMDPaused = toStop;
                        }
                    }
                }
                // start new miners
                foreach (var toStart in toRunNewGroupMiners.Values)
                {
                    toStart.Start(_miningLocation, _btcAdress, _worker);
                    _runningGroupMiners[toStart.Key] = toStart;
                }
            }

            // stats quick fix code
            //if (_currentAllGroupedDevices.Count != _previousAllGroupedDevices.Count) {
            MinerStatsCheck(NiceHashData);
            //}
        }
        public async Task SwichMostProfitableGroupUpMethod(Dictionary <AlgorithmType, CryptoMiner937API> CryptoMiner937Data, bool log = false)
        {
#if (SWITCH_TESTING)
            MiningDevice.SetNextTest();
#endif
            List <MiningPair> profitableDevices = new List <MiningPair>();
            double            CurrentProfit     = 0.0d;
            double            PrevStateProfit   = 0.0d;
            foreach (var device in _miningDevices)
            {
                // calculate profits
                device.CalculateProfits(CryptoMiner937Data);
                // check if device has profitable algo
                if (device.HasProfitableAlgo())
                {
                    profitableDevices.Add(device.GetMostProfitablePair());
                    CurrentProfit   += device.GetCurrentMostProfitValue;
                    PrevStateProfit += device.GetPrevMostProfitValue;
                }
            }

            // 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.GetFullName()));
                    foreach (var algo in device.Algorithms)
                    {
                        stringBuilderDevice.AppendLine(String.Format("\t\tPROFIT = {0}\t(SPEED = {1}\t\t| NHSMA = {2})\t[{3}]",
                                                                     algo.CurrentProfit.ToString(DOUBLE_FORMAT),                                          // Profit
                                                                     algo.AvaragedSpeed + (algo.IsDual() ? "/" + algo.SecondaryAveragedSpeed : ""),       // Speed
                                                                     algo.CurNhmSMADataVal + (algo.IsDual() ? "/" + algo.SecondaryCurNhmSMADataVal : ""), // CryptoMiner937Data
                                                                     algo.AlgorithmStringID                                                               // Name
                                                                     ));
                    }
                    // most profitable
                    stringBuilderDevice.AppendLine(String.Format("\t\tMOST PROFITABLE ALGO: {0}, PROFIT: {1}",
                                                                 device.GetMostProfitableString(),
                                                                 device.GetCurrentMostProfitValue.ToString(DOUBLE_FORMAT)));
                    stringBuilderFull.AppendLine(stringBuilderDevice.ToString());
                }
                Helpers.ConsolePrint(TAG, stringBuilderFull.ToString());
            }

            // check if should mine
            // Only check if profitable inside this method when getting SMA data, cheching during mining is not reliable
            if (CheckIfShouldMine(CurrentProfit, log) == false)
            {
                foreach (var device in _miningDevices)
                {
                    device.SetNotMining();
                }
                return;
            }

            // check profit threshold
            Helpers.ConsolePrint(TAG, String.Format("PrevStateProfit {0}, CurrentProfit {1}", PrevStateProfit, CurrentProfit));
            if (PrevStateProfit > 0 && CurrentProfit > 0)
            {
                double a = Math.Max(PrevStateProfit, CurrentProfit);
                double b = Math.Min(PrevStateProfit, CurrentProfit);
                //double percDiff = Math.Abs((PrevStateProfit / CurrentProfit) - 1);
                double percDiff = ((a - b)) / b;
                if (percDiff < ConfigManager.GeneralConfig.SwitchProfitabilityThreshold)
                {
                    // don't switch
                    //Helpers.ConsolePrint(TAG, String.Format("Will NOT switch profit diff is {0}, current threshold {1}", percDiff, ConfigManager.GeneralConfig.SwitchProfitabilityThreshold));
                    // RESTORE OLD PROFITS STATE
                    foreach (var device in _miningDevices)
                    {
                        device.RestoreOldProfitsState();
                    }
                    if (!SHOULD_START_DONATING)
                    {
                        return;
                    }
                }
                else
                {
                    Helpers.ConsolePrint(TAG, String.Format("Will SWITCH profit diff is {0}, current threshold {1}", percDiff, ConfigManager.GeneralConfig.SwitchProfitabilityThreshold));
                }
            }

            Helpers.ConsolePrint("Monitoring", "If enabled here I would submit Monitoring data to the server");

            if (ConfigManager.GeneralConfig.monitoring == true)
            {                  //Run monitoring command here
                var monversion = "Hash-Kings Miner V" + Application.ProductVersion;
#pragma warning disable CS0219 // The variable 'monstatus' is assigned but its value is never used
                var monstatus = "Running";
#pragma warning restore CS0219 // The variable 'monstatus' is assigned but its value is never used
#pragma warning disable CS0219 // The variable 'monrunningminers' is assigned but its value is never used
                var monrunningminers = "" /*Runningminers go here*/;
#pragma warning restore CS0219 // The variable 'monrunningminers' is assigned but its value is never used
                var monserver = ConfigManager.GeneralConfig.MonServerurl + "/api/report.php";
                var request   = (HttpWebRequest)WebRequest.Create(monserver);
                var postData  = "";

                /* fetch last command line for each miner
                 * Do this for each mining group*/
                foreach (var cdev in ComputeDeviceManager.Avaliable.AllAvaliableDevices)
                {
                    if (cdev.Enabled)
                    {
                        postData += "Name" + Uri.EscapeDataString("Miner Name");
                        postData += "Path" + Uri.EscapeDataString("miner Path goes here");
                        postData += "Type" + Uri.EscapeDataString("Type of card EX. AMD");
                        postData += "Algorithm" + Uri.EscapeDataString("Current mining Algorithm");
                        postData += "Pool" + Uri.EscapeDataString("Pool Goes Here");
                        postData += "CurrentSpeed" + Uri.EscapeDataString("Actual hashrate goes here");
                        postData += "EstimatedSpeed" + Uri.EscapeDataString("Benchmark hashrate Goes Here");
                        postData += "Profit" + Uri.EscapeDataString("group profitability goes here");
                    }
                    ;
                }

                /*
                 *
                 * Convert above data to Json
                 * Fetch Profit to Variable
                 * $Profit = [string]([Math]::Round(($data | Measure-Object Profit -Sum).Sum, 8))
                 * Send the request
                 * $Body = @{user = $Config.MonitoringUser; worker = $Config.WorkerName; version = $Version; status = $Status; profit = $Profit; data = $DataJSON}
                 * Try {
                 * $Response = Invoke-RestMethod -Uri "$($Config.MonitoringServer)/api/report.php" -Method Post -Body $Body -UseBasicParsing -TimeoutSec 10 -ErrorAction Stop
                 * Helpers.ConsolePrint("Monitoring", "Reporting status to server..." + $Server responce here"
                 * }
                 * Catch {
                 * Helpers.ConsolePrint("Monitoring", "Unable to send status to " monserver}*/
                var data = Encoding.ASCII.GetBytes(postData);
                request.Method        = "POST";
                request.ContentType   = "application/x-www-form-urlencoded";
                request.ContentLength = data.Length;

                using (var stream = request.GetRequestStream())
                {
                    stream.Write(data, 0, data.Length);
                }

                var response = (HttpWebResponse)request.GetResponse();

                var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
            }



            // group new miners
            Dictionary <string, List <MiningPair> > newGroupedMiningPairs = new Dictionary <string, List <MiningPair> >();
            // group devices with same supported algorithms
            {
                var currentGroupedDevices = new List <GroupedDevices>();
                for (int first = 0; first < profitableDevices.Count; ++first)
                {
                    var firstDev = profitableDevices[first].Device;
                    // check if is in group
                    bool isInGroup = false;
                    foreach (var groupedDevices in currentGroupedDevices)
                    {
                        if (groupedDevices.Contains(firstDev.UUID))
                        {
                            isInGroup = true;
                            break;
                        }
                    }
                    // if device is not in any group create new group and check if other device should group
                    if (isInGroup == false)
                    {
                        var newGroup    = new GroupedDevices();
                        var miningPairs = new List <MiningPair>()
                        {
                            profitableDevices[first]
                        };
                        newGroup.Add(firstDev.UUID);
                        for (int second = first + 1; second < profitableDevices.Count; ++second)
                        {
                            // check if we should group
                            var firstPair  = profitableDevices[first];
                            var secondPair = profitableDevices[second];
                            if (GroupingLogic.ShouldGroup(firstPair, secondPair))
                            {
                                var secondDev = profitableDevices[second].Device;
                                newGroup.Add(secondDev.UUID);
                                miningPairs.Add(profitableDevices[second]);
                            }
                        }
                        currentGroupedDevices.Add(newGroup);
                        newGroupedMiningPairs[CalcGroupedDevicesKey(newGroup)] = miningPairs;
                    }
                }
            }
            //bool IsMinerStatsCheckUpdate = false;
            {
                // check which groupMiners should be stopped and which ones should be started and which to keep running
                Dictionary <string, GroupMiner> toStopGroupMiners   = new Dictionary <string, GroupMiner>();
                Dictionary <string, GroupMiner> toRunNewGroupMiners = new Dictionary <string, GroupMiner>();
                Dictionary <string, GroupMiner> noChangeGroupMiners = new Dictionary <string, GroupMiner>();
                if (MiningSession.SHOULD_START_DONATING)
                {
                    MiningSession.IS_DONATING = true;
                }

                // check what to stop/update
                int count = _runningGroupMiners.Keys.Count;
                int it    = 0;
                //  + " Mining For : " +(MiningSession.DONATION_SESSION ? "Developer" : "User")
                foreach (string runningGroupKey in _runningGroupMiners.Keys)
                {
                    it++;
                    if (newGroupedMiningPairs.ContainsKey(runningGroupKey) == false)
                    {
                        // runningGroupKey not in new group definately needs to be stopped and removed from curently running
                        toStopGroupMiners[runningGroupKey] = _runningGroupMiners[runningGroupKey];
                    }
                    // If we need to start donating, stop everything
                    else if (MiningSession.IS_DONATING && !MiningSession.DONATION_SESSION)
                    {
                        if (it == count)
                        {
                            MiningSession.DONATION_SESSION = true;
                        }
                        toStopGroupMiners[runningGroupKey] = _runningGroupMiners[runningGroupKey];

                        Helpers.ConsolePrint(TAG, "STARTING - DEV_FEE - Mining Dev-Fee for 24 Minutes.");
                        var        miningPairs   = newGroupedMiningPairs[runningGroupKey];
                        var        newAlgoType   = GetMinerPairAlgorithmType(miningPairs);
                        GroupMiner newGroupMiner = null;
                        if (newAlgoType == AlgorithmType.DaggerHashimoto)
                        {
                            if (_ethminerNVIDIAPaused != null && _ethminerNVIDIAPaused.Key == runningGroupKey)
                            {
                                newGroupMiner = _ethminerNVIDIAPaused;
                            }
                            if (_ethminerAMDPaused != null && _ethminerAMDPaused.Key == runningGroupKey)
                            {
                                newGroupMiner = _ethminerAMDPaused;
                            }
                        }
                        if (newGroupMiner == null)
                        {
                            newGroupMiner = new GroupMiner(miningPairs, runningGroupKey);
                        }
                        toRunNewGroupMiners[runningGroupKey] = newGroupMiner;
                    }
                    else if (MiningSession.IS_DONATING && MiningSession.DONATION_SESSION && MiningSession.SHOULD_STOP_DONATING)
                    {
                        if (it == count)
                        {
                            MiningSession.DONATION_SESSION = false;
                            MiningSession.IS_DONATING      = false;
                            MiningSession.DonationStart    = MiningSession.DonationStart.Add(MiningSession.DonateEvery);
                        }
                        toStopGroupMiners[runningGroupKey] = _runningGroupMiners[runningGroupKey];
                        Helpers.ConsolePrint(TAG, "STOPPING - DEV_FEE - Next Dev-Fee Mining will start in 24 Hours.");
                        var        miningPairs   = newGroupedMiningPairs[runningGroupKey];
                        var        newAlgoType   = GetMinerPairAlgorithmType(miningPairs);
                        GroupMiner newGroupMiner = null;
                        if (newAlgoType == AlgorithmType.DaggerHashimoto)
                        {
                            if (_ethminerNVIDIAPaused != null && _ethminerNVIDIAPaused.Key == runningGroupKey)
                            {
                                newGroupMiner = _ethminerNVIDIAPaused;
                            }
                            if (_ethminerAMDPaused != null && _ethminerAMDPaused.Key == runningGroupKey)
                            {
                                newGroupMiner = _ethminerAMDPaused;
                            }
                        }
                        if (newGroupMiner == null)
                        {
                            newGroupMiner = new GroupMiner(miningPairs, runningGroupKey);
                        }
                        toRunNewGroupMiners[runningGroupKey] = newGroupMiner;
                    }
                    else
                    {
                        MiningSession.DONATION_SESSION = false;
                        MiningSession.IS_DONATING      = false;
                        // runningGroupKey is contained but needs to check if mining algorithm is changed
                        var miningPairs = newGroupedMiningPairs[runningGroupKey];
                        var newAlgoType = GetMinerPairAlgorithmType(miningPairs);
                        if (newAlgoType != AlgorithmType.NONE && newAlgoType != AlgorithmType.INVALID)
                        {
                            // if algoType valid and different from currently running update
                            if (newAlgoType != _runningGroupMiners[runningGroupKey].DualAlgorithmType)
                            {
                                // remove current one and schedule to stop mining
                                toStopGroupMiners[runningGroupKey] = _runningGroupMiners[runningGroupKey];
                                // create new one TODO check if DaggerHashimoto
                                GroupMiner newGroupMiner = null;
                                if (newAlgoType == AlgorithmType.DaggerHashimoto)
                                {
                                    if (_ethminerNVIDIAPaused != null && _ethminerNVIDIAPaused.Key == runningGroupKey)
                                    {
                                        newGroupMiner = _ethminerNVIDIAPaused;
                                    }
                                    if (_ethminerAMDPaused != null && _ethminerAMDPaused.Key == runningGroupKey)
                                    {
                                        newGroupMiner = _ethminerAMDPaused;
                                    }
                                }
                                if (newGroupMiner == null)
                                {
                                    newGroupMiner = new GroupMiner(miningPairs, runningGroupKey);
                                }
                                toRunNewGroupMiners[runningGroupKey] = newGroupMiner;
                            }
                            else
                            {
                                noChangeGroupMiners[runningGroupKey] = _runningGroupMiners[runningGroupKey];
                            }
                        }
                    }
                }
                // check brand new
                foreach (var kvp in newGroupedMiningPairs)
                {
                    var key         = kvp.Key;
                    var miningPairs = kvp.Value;
                    if (_runningGroupMiners.ContainsKey(key) == false)
                    {
                        GroupMiner newGroupMiner = new GroupMiner(miningPairs, key);
                        toRunNewGroupMiners[key] = newGroupMiner;
                    }
                }

                if ((toStopGroupMiners.Values.Count > 0) || (toRunNewGroupMiners.Values.Count > 0))
                {
                    StringBuilder stringBuilderPreviousAlgo = new StringBuilder();
                    StringBuilder stringBuilderCurrentAlgo  = new StringBuilder();
                    StringBuilder stringBuilderNoChangeAlgo = new StringBuilder();
                    // stop old miners
                    foreach (var toStop in toStopGroupMiners.Values)
                    {
                        stringBuilderPreviousAlgo.Append(String.Format("{0}: {1}, ", toStop.DevicesInfoString, toStop.AlgorithmType));

                        toStop.Stop();
                        _runningGroupMiners.Remove(toStop.Key);
                        // TODO check if daggerHashimoto and save
                        if (toStop.AlgorithmType == AlgorithmType.DaggerHashimoto)
                        {
                            if (toStop.DeviceType == DeviceType.NVIDIA)
                            {
                                _ethminerNVIDIAPaused = toStop;
                            }
                            else if (toStop.DeviceType == DeviceType.AMD)
                            {
                                _ethminerAMDPaused = toStop;
                            }
                        }
                    }

                    // start new miners
                    foreach (var toStart in toRunNewGroupMiners.Values)
                    {
                        stringBuilderCurrentAlgo.Append(String.Format("{0}: {1}, ", toStart.DevicesInfoString, toStart.AlgorithmType));

                        toStart.Start(_miningLocation, _btcAddress, _worker);
                        _runningGroupMiners[toStart.Key] = toStart;
                    }

                    // which miners dosen't change
                    foreach (var noChange in noChangeGroupMiners.Values)
                    {
                        stringBuilderNoChangeAlgo.Append(String.Format("{0}: {1}, ", noChange.DevicesInfoString, noChange.AlgorithmType));
                    }

                    if (stringBuilderPreviousAlgo.Length > 0)
                    {
                        Helpers.ConsolePrint(TAG, String.Format("Stop Mining: {0}", stringBuilderPreviousAlgo.ToString()));
                    }

                    if (stringBuilderCurrentAlgo.Length > 0)
                    {
                        Helpers.ConsolePrint(TAG, String.Format("Now Mining : {0}", stringBuilderCurrentAlgo.ToString()));
                    }

                    if (stringBuilderNoChangeAlgo.Length > 0)
                    {
                        Helpers.ConsolePrint(TAG, String.Format("No change  : {0}", stringBuilderNoChangeAlgo.ToString()));
                    }
                }
            }

            // stats quick fix code
            //if (_currentAllGroupedDevices.Count != _previousAllGroupedDevices.Count) {
            await MinerStatsCheck(CryptoMiner937Data);

            //}
        }