private void ProcessTrailingSignals()
        {
            double?globalRating = signalsService.GetGlobalRating();

            foreach (var kvp in trailingSignals)
            {
                string pair = kvp.Key;
                List <SignalTrailingInfo> trailingInfoList = kvp.Value;

                for (int i = trailingInfoList.Count - 1; i >= 0; i--)
                {
                    SignalTrailingInfo trailingInfo = trailingInfoList[i];

                    if (trailingInfo.Rule.Trailing.MaxDuration == 0 || trailingInfo.Duration <= trailingInfo.Rule.Trailing.MaxDuration / Application.Speed)
                    {
                        if (trailingInfo.Duration >= trailingInfo.Rule.Trailing.MinDuration / Application.Speed)
                        {
                            IEnumerable <ISignal> signalsByPair = signalsService.GetSignalsByPair(pair);
                            if (signalsByPair != null)
                            {
                                Dictionary <string, ISignal> signals = signalsByPair.ToDictionary(s => s.Name, s => s);
                                if (rulesService.CheckConditions(trailingInfo.Rule.Conditions, signals, globalRating, pair, null))
                                {
                                    IEnumerable <ISignal> ruleSignals = signals.Where(s => trailingInfo.Rule.Conditions.Any(c => c.Signal == s.Key)).Select(s => s.Value);
                                    InitiateBuy(pair, trailingInfo.Rule, ruleSignals);
                                }
                            }
                        }
                    }
                    else
                    {
                        trailingInfoList.RemoveAt(i);
                        if (trailingInfoList.Count == 0)
                        {
                            trailingSignals.TryRemove(pair, out trailingInfoList);
                        }
                        if (LoggingEnabled)
                        {
                            loggingService.Info($"Cancel trailing signal for {pair}. Rule: {trailingInfo.Rule.Name}, Reason: max duration reached");
                        }
                    }
                }
            }
        }
        public void ProcessAllRules()
        {
            IEnumerable <IRule> enabledRules = tradingService.Rules?.Entries?.Where(r => r.Enabled) ?? new List <IRule>();
            List <string>       allPairs     = tradingService.Exchange.GetMarketPairs(tradingService.Config.Market).ToList();
            double?globalRating = signalsService.GetGlobalRating();

            foreach (string pair in allPairs)
            {
                IEnumerable <ISignal> signalsByPair = signalsService.GetSignalsByPair(pair);
                if (signalsByPair != null)
                {
                    Dictionary <string, ISignal> signals = signalsByPair.ToDictionary(s => s.Name, s => s);
                    ITradingPair  tradingPair            = tradingService.Account.GetTradingPair(pair);
                    TradingConfig modifiedTradingConfig  = tradingService.Config.Clone() as TradingConfig;
                    PairConfig    modifiedPairConfig     = new PairConfig();
                    pairConfigs.TryGetValue(pair, out PairConfig oldPairConfig);
                    var appliedRules = new List <IRule>();

                    foreach (var rule in enabledRules)
                    {
                        if (rulesService.CheckConditions(rule.Conditions, signals, globalRating, pair, tradingPair))
                        {
                            var modifiers = rule.GetModifiers <TradingRuleModifiers>();
                            if (modifiers != null)
                            {
                                // Base Trading Config
                                modifiedTradingConfig.MaxPairs              = modifiers.MaxPairs ?? modifiedTradingConfig.MaxPairs;
                                modifiedTradingConfig.BuyEnabled            = modifiers.BuyEnabled ?? modifiedTradingConfig.BuyEnabled;
                                modifiedTradingConfig.BuyMaxCost            = modifiers.BuyMaxCost ?? modifiedTradingConfig.BuyMaxCost;
                                modifiedTradingConfig.BuyMultiplier         = modifiers.BuyMultiplier ?? modifiedTradingConfig.BuyMultiplier;
                                modifiedTradingConfig.BuyMinBalance         = modifiers.BuyMinBalance ?? modifiedTradingConfig.BuyMinBalance;
                                modifiedTradingConfig.BuySamePairTimeout    = modifiers.BuySamePairTimeout ?? modifiedTradingConfig.BuySamePairTimeout;
                                modifiedTradingConfig.BuyTrailing           = modifiers.BuyTrailing ?? modifiedTradingConfig.BuyTrailing;
                                modifiedTradingConfig.BuyTrailingStopMargin = modifiers.BuyTrailingStopMargin ?? modifiedTradingConfig.BuyTrailingStopMargin;
                                modifiedTradingConfig.BuyTrailingStopAction = modifiers.BuyTrailingStopAction ?? modifiedTradingConfig.BuyTrailingStopAction;

                                modifiedTradingConfig.BuyDCAEnabled            = modifiers.BuyDCAEnabled ?? modifiedTradingConfig.BuyDCAEnabled;
                                modifiedTradingConfig.BuyDCAMultiplier         = modifiers.BuyDCAMultiplier ?? modifiedTradingConfig.BuyDCAMultiplier;
                                modifiedTradingConfig.BuyDCAMinBalance         = modifiers.BuyDCAMinBalance ?? modifiedTradingConfig.BuyDCAMinBalance;
                                modifiedTradingConfig.BuyDCASamePairTimeout    = modifiers.BuyDCASamePairTimeout ?? modifiedTradingConfig.BuyDCASamePairTimeout;
                                modifiedTradingConfig.BuyDCATrailing           = modifiers.BuyDCATrailing ?? modifiedTradingConfig.BuyDCATrailing;
                                modifiedTradingConfig.BuyDCATrailingStopMargin = modifiers.BuyDCATrailingStopMargin ?? modifiedTradingConfig.BuyDCATrailingStopMargin;
                                modifiedTradingConfig.BuyDCATrailingStopAction = modifiers.BuyDCATrailingStopAction ?? modifiedTradingConfig.BuyDCATrailingStopAction;

                                modifiedTradingConfig.SellEnabled            = modifiers.SellEnabled ?? modifiedTradingConfig.SellEnabled;
                                modifiedTradingConfig.SellMargin             = modifiers.SellMargin ?? modifiedTradingConfig.SellMargin;
                                modifiedTradingConfig.SellTrailing           = modifiers.SellTrailing ?? modifiedTradingConfig.SellTrailing;
                                modifiedTradingConfig.SellTrailingStopMargin = modifiers.SellTrailingStopMargin ?? modifiedTradingConfig.SellTrailingStopMargin;
                                modifiedTradingConfig.SellTrailingStopAction = modifiers.SellTrailingStopAction ?? modifiedTradingConfig.SellTrailingStopAction;
                                modifiedTradingConfig.SellStopLossEnabled    = modifiers.SellStopLossEnabled ?? modifiedTradingConfig.SellStopLossEnabled;
                                modifiedTradingConfig.SellStopLossAfterDCA   = modifiers.SellStopLossAfterDCA ?? modifiedTradingConfig.SellStopLossAfterDCA;
                                modifiedTradingConfig.SellStopLossMinAge     = modifiers.SellStopLossMinAge ?? modifiedTradingConfig.SellStopLossMinAge;
                                modifiedTradingConfig.SellStopLossMargin     = modifiers.SellStopLossMargin ?? modifiedTradingConfig.SellStopLossMargin;

                                modifiedTradingConfig.SellDCAMargin             = modifiers.SellDCAMargin ?? modifiedTradingConfig.SellDCAMargin;
                                modifiedTradingConfig.SellDCATrailing           = modifiers.SellDCATrailing ?? modifiedTradingConfig.SellDCATrailing;
                                modifiedTradingConfig.SellDCATrailingStopMargin = modifiers.SellDCATrailingStopMargin ?? modifiedTradingConfig.SellDCATrailingStopMargin;
                                modifiedTradingConfig.SellDCATrailingStopAction = modifiers.SellDCATrailingStopAction ?? modifiedTradingConfig.SellDCATrailingStopAction;

                                modifiedTradingConfig.RepeatLastDCALevel = modifiers.RepeatLastDCALevel ?? modifiedTradingConfig.RepeatLastDCALevel;
                                modifiedTradingConfig.DCALevels          = modifiers.DCALevels ?? modifiedTradingConfig.DCALevels;

                                // Base Pair Config
                                modifiedPairConfig.SwapEnabled     = modifiers.SwapEnabled ?? modifiedPairConfig.SwapEnabled;
                                modifiedPairConfig.SwapSignalRules = modifiers.SwapSignalRules ?? modifiedPairConfig.SwapSignalRules;
                                modifiedPairConfig.SwapTimeout     = modifiers.SwapTimeout ?? modifiedPairConfig.SwapTimeout;

                                modifiedPairConfig.ArbitrageEnabled        = modifiers.ArbitrageEnabled ?? modifiedPairConfig.ArbitrageEnabled;
                                modifiedPairConfig.ArbitrageMarkets        = modifiers.ArbitrageMarkets ?? modifiedPairConfig.ArbitrageMarkets;
                                modifiedPairConfig.ArbitrageType           = modifiers.ArbitrageType ?? modifiedPairConfig.ArbitrageType;
                                modifiedPairConfig.ArbitrageBuyMultiplier  = modifiers.ArbitrageBuyMultiplier ?? modifiedPairConfig.ArbitrageBuyMultiplier;
                                modifiedPairConfig.ArbitrageSellMultiplier = modifiers.ArbitrageSellMultiplier ?? modifiedPairConfig.ArbitrageSellMultiplier;
                                modifiedPairConfig.ArbitrageSignalRules    = modifiers.ArbitrageSignalRules ?? modifiedPairConfig.ArbitrageSignalRules;

                                if (oldPairConfig != null && !oldPairConfig.ArbitrageEnabled && modifiedPairConfig.ArbitrageEnabled)
                                {
                                    signalsService.ProcessPair(pair, signals);
                                }
                            }

                            appliedRules.Add(rule);

                            if (tradingService.RulesConfig.ProcessingMode == RuleProcessingMode.FirstMatch)
                            {
                                break;
                            }
                        }
                    }

                    pairConfigs[pair] = CreatePairConfig(pair, modifiedTradingConfig, modifiedPairConfig, appliedRules);
                }
            }

            healthCheckService.UpdateHealthCheck(Constants.HealthChecks.TradingRulesProcessed, $"Rules: {enabledRules.Count()}, Pairs: {allPairs.Count}");
        }