public virtual bool TurnOver(DataRowCollection rows, int index)
        {
            if (!AnalysisCommon.CheckTrendPeriod(index, rows.Count, TrendPeriod))
            {
                return(false);
            }

            AnalysisCommon.TrendDirection before = AnalysisCommon.TrendDirection.None;
            AnalysisCommon.TrendDirection after  = AnalysisCommon.TrendDirection.None;

            try
            {
                before = AnalysisCommon.CheckBeforeTrendDirection(rows, index, TrendPeriod);
                after  = AnalysisCommon.CheckAfterTrendDirection(rows, index, TrendPeriod);
            }
            catch (Exception ex)
            {
                if (ex is SMANULLException)
                {
                    return(false);
                }
            }

            if ((before == AnalysisCommon.TrendDirection.Down && after == AnalysisCommon.TrendDirection.Up) ||
                (before == AnalysisCommon.TrendDirection.Up && after == AnalysisCommon.TrendDirection.Down))
            {
                return(true);
            }

            return(false);
        }
        public override bool Valid(DataRowCollection rows, int index)
        {
            if (AnalysisCommon.CheckAfterTrendDirection(rows, index, AnalysisCommon.TrendPeriod.Short) != AnalysisCommon.TrendDirection.Up)
            {
                return(false);
            }

            return(true);
        }
        public virtual async Task <bool> Analyze(DataTable dtPrices, DataTable rootTable)
        {
            var rows = dtPrices.Rows;

            if (rows.Count == 0)
            {
                return(false);
            }

            string symbolId = rows[0][Common.SymbolIdColumn].ToString();
            var    table    = AnalysisCommon.MakeAnalysisResultsTable();

            Console.WriteLine(string.Format("Analyzing Symbol {0} with method {1}", symbolId, Name));
            for (int i = 0; i < rows.Count; i++)
            {
                bool isQualified = false;
                bool isValid     = false;

                StockData currentPrice = TryGetPriceValues(rows, i);
                StockData beforePrice  = TryGetPriceValues(rows, i - 1);
                StockData afterPrice   = TryGetPriceValues(rows, i + 1);

                //if current date has no volume then skip it
                if (currentPrice != null && currentPrice.volume != null && currentPrice.volume == 0)
                {
                    continue;
                }

                if (Qualified(rows, i, currentPrice, beforePrice, afterPrice))
                {
                    isQualified = true;
                    isValid     = Valid(rows, i);
                    var newRow = table.NewRow();
                    newRow[Common.SymbolIdColumn]   = symbolId;
                    newRow[Common.MethodNameColumn] = Name;
                    newRow[Common.DateColumn]       = rows[i][Common.DateColumn].ToString();
                    newRow[Common.QualifiedColumn]  = Convert.ToInt32(isQualified).ToString();
                    newRow[Common.ValidColumn]      = Convert.ToInt32(isValid).ToString();
                    table.Rows.Add(newRow);
                }
            }

            if (table.Rows.Count > 0)
            {
                Console.WriteLine(string.Format("Write {0} rows to DB for symbol {1} and method {2}", table.Rows.Count, symbolId, Name));
                var ret = await SqlExecutor.BulkCopy(table);
            }

            //AnalysisCommon.MergeAnalysisResultTable(rootTable, table);
            return(true);
        }
        public virtual bool BeforeHasTrend(DataRowCollection rows, int index)
        {
            if (!AnalysisCommon.CheckTrendPeriod(index, rows.Count, TrendPeriod))
            {
                return(false);
            }

            var trendDirect = AnalysisCommon.CheckBeforeTrendDirection(rows, index, TrendPeriod);

            if (trendDirect == AnalysisCommon.TrendDirection.None)
            {
                return(false);
            }

            return(true);
        }
        public override bool Qualified(DataRowCollection rows, int index, StockData currentPrice, StockData beforePrice, StockData afterPrice)
        {
            if (currentPrice == null || beforePrice == null)
            {
                return(false);
            }

            if (!BeforeHasTrend(rows, index))
            {
                return(false);
            }

            //Before trend must be Down
            if (AnalysisCommon.CheckBeforeTrendDirection(rows, index, _trendPeriod) != AnalysisCommon.TrendDirection.Down)
            {
                return(false);
            }

            //Previous day must be down
            if (beforePrice.open < beforePrice.close)
            {
                return(false);
            }
            //Current day must be up
            if (currentPrice.open > currentPrice.close)
            {
                return(false);
            }

            //Current Open must be less than previous close
            if (currentPrice.open > beforePrice.close)
            {
                return(false);
            }

            //Current close must be greater than previous close
            if (currentPrice.close < beforePrice.close)
            {
                return(false);
            }

            //Shadow line must be very short for previous
            if ((beforePrice.high - beforePrice.close) > (beforePrice.high - beforePrice.low) * multiplier)
            {
                return(false);
            }

            if ((beforePrice.open - beforePrice.low) > (beforePrice.high - beforePrice.low) * multiplier)
            {
                return(false);
            }

            //Shadow line must be very short for current
            if ((currentPrice.high - currentPrice.open) > (currentPrice.high - currentPrice.low) * multiplier)
            {
                return(false);
            }

            if ((currentPrice.close - currentPrice.low) > (currentPrice.high - currentPrice.low) * multiplier)
            {
                return(false);
            }

            //current close must be in body of previous bar for more than 60%
            if ((currentPrice.close - beforePrice.close) < (beforePrice.open - beforePrice.close) * multiplier2)
            {
                return(false);
            }

            return(true);
        }