private static void SwichMostProfitableGroupUpMethod(object sender, SmaUpdateEventArgs e)
 {
     _ = NormalizedProfitsUpdate(e.NormalizedProfits);
 }
 private static async void SwichMostProfitableGroupUpMethod(object sender, SmaUpdateEventArgs e)
 {
     await SwichMostProfitableGroupUpMethodTask(sender, e);
 }
        private static async Task SwichMostProfitableGroupUpMethodTask(object sender, SmaUpdateEventArgs e)
        {
            CalculateAndUpdateMiningDevicesProfits(e.NormalizedProfits);
            var(currentProfit, prevStateProfit) = GetCurrentAndPreviousProfits();

            // log profits scope
            {
                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 PluginAlgorithm dualAlg && dualAlg.IsDual)
                        {
                            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());
                }
                Logger.Info(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();
                }
                await PauseAllMiners();

                return;
            }

            // check profit threshold
            Logger.Info(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
                    Logger.Info(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;
                }
                Logger.Info(Tag, $"Will SWITCH profit diff is {percDiff}, current threshold {ConfigManager.GeneralConfig.SwitchProfitabilityThreshold}");
            }

            await _semaphore.WaitAsync();

            var hasChanged = false;

            try
            {
                // group new miners
                var newGroupedMiningPairs = GroupingUtils.GetGroupedMiningPairs(GetProfitableMiningPairs());
                // check newGroupedMiningPairs and running Groups to figure out what to start/stop and keep running
                var currentRunningGroups = _runningMiners.Keys.ToArray();
                // check which groupMiners should be stopped and which ones should be started and which to keep running
                var noChangeGroupMinersKeys = newGroupedMiningPairs.Where(pair => currentRunningGroups.Contains(pair.Key)).Select(pair => pair.Key).OrderBy(uuid => uuid).ToArray();
                var toStartMinerGroupKeys   = newGroupedMiningPairs.Where(pair => !currentRunningGroups.Contains(pair.Key)).Select(pair => pair.Key).OrderBy(uuid => uuid).ToArray();
                var toStopMinerGroupKeys    = currentRunningGroups.Where(runningKey => !newGroupedMiningPairs.Keys.Contains(runningKey)).OrderBy(uuid => uuid).ToArray();
                // first stop currently running
                foreach (var stopKey in toStopMinerGroupKeys)
                {
                    var stopGroup = _runningMiners[stopKey];
                    _runningMiners.Remove(stopKey);
                    await stopGroup.StopTask();

                    stopGroup.End();
                }
                // start new
                var miningLocation = StratumService.SelectedServiceLocation;
                foreach (var startKey in toStartMinerGroupKeys)
                {
                    var miningPairs = newGroupedMiningPairs[startKey];
                    var toStart     = MinerFactory.CreateMinerForMining(miningPairs, startKey);
                    if (toStart == null)
                    {
                        Logger.Error(Tag, $"CreateMinerForMining for key='{startKey}' returned <null>");
                        continue;
                    }
                    _runningMiners[startKey] = toStart;
                    await toStart.StartTask(miningLocation, _username);
                }
                // log scope
                {
                    var stopLog = toStopMinerGroupKeys.Length > 0 ? string.Join(",", toStopMinerGroupKeys) : "EMTPY";
                    Logger.Info(Tag, $"Stop Old Mining: ({stopLog})");
                    var startLog = toStartMinerGroupKeys.Length > 0 ? string.Join(",", toStartMinerGroupKeys) : "EMTPY";
                    Logger.Info(Tag, $"Start New Mining : ({startLog})");
                    var sameLog = noChangeGroupMinersKeys.Length > 0 ? string.Join(",", noChangeGroupMinersKeys) : "EMTPY";
                    Logger.Info(Tag, $"No change : ({sameLog})");
                }
                hasChanged = toStartMinerGroupKeys.Length > 0 || toStopMinerGroupKeys.Length > 0;
            }
            finally
            {
                _semaphore.Release();
            }


            // There is a change in groups, change GUI
            if (hasChanged)
            {
                ApplicationStateManager.ClearRatesAll();
                await MinerStatsCheck();
            }
        }
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();
        }