private Tuple <TradeIdea, TradeIdeaLog> GenerateTradeIdeaForLatestDate(List <Signal> signals, HistoricalData historicalData)
        {
            Tuple <TradeIdea, TradeIdeaLog> result;

            DateTime date = historicalData.LatestDate;

            //TODO: should we remove this at all? now delayed
            //SupportAndResistance sr = _algoService.GetSupportAndResistance(historicalData, expandedQuote.Last);
            TradeIdeasGeneratorArgument args = TradeIdeasGeneratorArgument.Create(signals, historicalData /*, sr*/);

            double marketCap = 0;
            //if (quote != null)
            //{
            //    marketCap = quote.MarketCapitalization ?? 0;
            //}

            TradeIdeaLog tradeIdeaLog = new TradeIdeaLog(historicalData.SecurityCode, args, date);
            List <TradeIdeaRuleWrapper> generatedTradeIdeas = GenerateTradeIdeas(args, tradeIdeaLog);

            Signal syrahSentiment = signals
                                    .ForIndicator(TradeIdeasGeneratorArgument.LongTermSentimentForDependencies)
                                    .FirstOrDefault(s => s.Date == date);
            int?syrahSentimentLongTerm = syrahSentiment == null
                ? null
                : (int?)syrahSentiment.Value;

            syrahSentiment = signals
                             .ForIndicator(TradeIdeasGeneratorArgument.ShortTermSentimentForDependencies)
                             .FirstOrDefault(s => s.Date == date);
            int?syrahSentimentShortTerm = syrahSentiment == null
                ? null
                : (int?)syrahSentiment.Value;

            double lastPrice = historicalData.Close.Last();

            string companyName = historicalData.SecurityCode;

            if (generatedTradeIdeas != null && generatedTradeIdeas.Any())
            {
                TradeIdea tradeIdea = new TradeIdea
                {
                    DailyPlay               = false,
                    DateOfScan              = date,
                    MarketCap               = marketCap,
                    Price                   = lastPrice,
                    StockCode               = historicalData.SecurityCode,
                    CompanyName             = companyName,
                    SyrahSentimentValue     = syrahSentimentLongTerm,
                    SyrahSentimentShortTerm = syrahSentimentShortTerm,
                    RuleMatch               = generatedTradeIdeas.Select(item => item.Rule).ToList(),
                    RulesWithLogs           = generatedTradeIdeas
                };

                result = Tuple.Create(tradeIdea, tradeIdeaLog);
            }
            else
            {
                result = Tuple.Create((TradeIdea)null, tradeIdeaLog);
            }

            return(result);
        }
        /// <summary>
        /// Generate trade ideas rules.
        /// </summary>
        public List <TradeIdeaRuleWrapper> GenerateTradeIdeas(TradeIdeasGeneratorArgument arg, TradeIdeaLog tradeIdeaLog)
        {
            const double period         = 14;
            const string cciStudy       = "CCI";
            const string rsiStudy       = "RSI";
            const string mfiStudy       = "MFI";
            const string williamsRStudy = "Williams %R";

            List <TradeIdeaRuleWrapper> returnList = new List <TradeIdeaRuleWrapper>();

            //if (arg.HasOption)
            //{
            //if (NearResistance(arg.LastPrice, arg.NearestResistance, arg.RangeStdDev))
            if (arg.LongTermSentiment != null &&
                arg.LongTermSentiment.Value == Sentiment.Bearish &&
                arg.ShortTermSentiment != null &&
                arg.ShortTermSentiment.Value != Sentiment.Bullish)
            {
                if (ObBearScan(arg.YesterdayRsi14, arg.Rsi14, _rsiObThresh))
                {
                    returnList.Add(new TradeIdeaRuleWrapper
                    {
                        Rule            = TradeIdeaRule.RsiOverboughtBearishCrossover,
                        Study           = rsiStudy,
                        Period          = period,
                        OverBoughtLevel = _rsiObThresh,
                        OverSoldLevel   = _rsiOsThresh
                    });
                }
                if (ObBearScan(arg.YesterdayCci14, arg.Cci14, _cciObThresh))
                {
                    returnList.Add(new TradeIdeaRuleWrapper
                    {
                        Rule            = TradeIdeaRule.CciOverboughtBearishCrossover,
                        Study           = cciStudy,
                        Period          = period,
                        OverBoughtLevel = _cciObThresh,
                        OverSoldLevel   = _cciOsThresh
                    });
                }
                if (ObBearScan(arg.YesterdayWillR14, arg.WillR14, _willrObThresh))
                {
                    returnList.Add(new TradeIdeaRuleWrapper
                    {
                        Rule            = TradeIdeaRule.WilliamsOverboughtBearishCrossover,
                        Study           = williamsRStudy,
                        Period          = period,
                        OverBoughtLevel = _willrObThresh,
                        OverSoldLevel   = _willrOsThresh
                    });
                }
                if (ObBearScan(arg.YesterdayMfi14, arg.Mfi14, _mfiObThresh))
                {
                    returnList.Add(new TradeIdeaRuleWrapper
                    {
                        Rule            = TradeIdeaRule.MfiOverboughtBearishCrossover,
                        Study           = mfiStudy,
                        Period          = period,
                        OverBoughtLevel = _mfiObThresh,
                        OverSoldLevel   = _mfiOsThresh
                    });
                }
            }

            //if (NearSupport(arg.LastPrice, arg.NearestSupport, arg.RangeStdDev))
            if (arg.LongTermSentiment != null &&
                arg.LongTermSentiment.Value == Sentiment.Bullish &&
                arg.ShortTermSentiment != null &&
                arg.ShortTermSentiment.Value != Sentiment.Bearish)
            {
                if (OsBullScan(arg.YesterdayRsi14, arg.Rsi14, _rsiOsThresh))
                {
                    returnList.Add(new TradeIdeaRuleWrapper
                    {
                        Rule            = TradeIdeaRule.RsiOversoldBullishCrossover,
                        Study           = rsiStudy,
                        Period          = period,
                        OverBoughtLevel = _rsiObThresh,
                        OverSoldLevel   = _rsiOsThresh
                    });
                }
                if (OsBullScan(arg.YesterdayCci14, arg.Cci14, _cciOsThresh))
                {
                    returnList.Add(new TradeIdeaRuleWrapper
                    {
                        Rule            = TradeIdeaRule.CciOversoldBullishCrossover,
                        Study           = cciStudy,
                        Period          = period,
                        OverBoughtLevel = _cciObThresh,
                        OverSoldLevel   = _cciOsThresh
                    });
                }
                if (OsBullScan(arg.YesterdayWillR14, arg.WillR14, _willrOsThresh))
                {
                    returnList.Add(new TradeIdeaRuleWrapper
                    {
                        Rule            = TradeIdeaRule.WilliamsROversoldBullishCrossover,
                        Study           = williamsRStudy,
                        Period          = period,
                        OverBoughtLevel = _willrObThresh,
                        OverSoldLevel   = _willrOsThresh
                    });
                }
                if (OsBullScan(arg.YesterdayMfi14, arg.Mfi14, _mfiOsThresh))
                {
                    returnList.Add(new TradeIdeaRuleWrapper
                    {
                        Rule            = TradeIdeaRule.MfiOversoldBullishCrossover,
                        Study           = mfiStudy,
                        Period          = period,
                        OverBoughtLevel = _mfiObThresh,
                        OverSoldLevel   = _mfiOsThresh
                    });
                }
            }

            if (LtStDisagreementFilter(arg.Atr20, arg.YesterdayHigh, arg.YesterdayLow))
            {
                if (arg.LongTermSentiment != null &&
                    arg.LongTermSentiment.Value == Sentiment.Bearish &&
                    arg.ShortTermSentiment != null &&
                    arg.ShortTermSentiment.Value == Sentiment.Bearish)
                {
                    if (StLtBearDisagreementScan(arg.LtRsi50, arg.StRsi5, arg.YesterdayStRsi5, _ltRsiBearThresh, _stRsiBullThresh))
                    {
                        returnList.Add(new TradeIdeaRuleWrapper
                        {
                            Rule            = TradeIdeaRule.RsiRallyInBearishTrend,
                            Study           = rsiStudy,
                            Period          = 5,
                            OverBoughtLevel = _stRsiBullThresh,
                            OverSoldLevel   = _ltRsiBearThresh
                        });
                    }
                    if (StLtBearDisagreementScan(arg.LtCci50, arg.StCci5, arg.YesterdayStCci5, _ltCciBearThresh, _stCciBullThresh))
                    {
                        returnList.Add(new TradeIdeaRuleWrapper
                        {
                            Rule            = TradeIdeaRule.CciRallyInBearishTrend,
                            Study           = cciStudy,
                            Period          = 5,
                            OverBoughtLevel = _stCciBullThresh,
                            OverSoldLevel   = _ltCciBearThresh
                        });
                    }
                }

                if (arg.LongTermSentiment != null &&
                    arg.LongTermSentiment.Value == Sentiment.Bullish &&
                    arg.ShortTermSentiment != null &&
                    arg.ShortTermSentiment.Value == Sentiment.Bullish)
                {
                    if (StLtBullDisagreementScan(arg.LtRsi50, arg.StRsi5, arg.YesterdayStRsi5, _ltRsiBullThresh, _stRsiBearThresh))
                    {
                        returnList.Add(new TradeIdeaRuleWrapper
                        {
                            Rule            = TradeIdeaRule.RsiDipInBullishTrend,
                            Study           = rsiStudy,
                            Period          = 5,
                            OverBoughtLevel = _ltRsiBullThresh,
                            OverSoldLevel   = _stRsiBearThresh
                        });
                    }

                    if (StLtBullDisagreementScan(arg.LtCci50, arg.StCci5, arg.YesterdayStCci5, _ltCciBullThresh, _stCciBearThresh))
                    {
                        returnList.Add(new TradeIdeaRuleWrapper
                        {
                            Rule            = TradeIdeaRule.CciDipInBullishTrend,
                            Study           = cciStudy,
                            Period          = 5,
                            OverBoughtLevel = _ltCciBullThresh,
                            OverSoldLevel   = _stCciBearThresh
                        });
                    }
                }
            }
            //}

            foreach (TradeIdeaRule tradeIdeaRule in returnList.Select(item => item.Rule))
            {
                tradeIdeaLog.Results.Add(tradeIdeaRule);
            }

            return(returnList);
        }