private static void calculateKDValue(List <StockChartData> result, int idx, StockChartData chartDataToday)
        {
            if (idx >= 9)
            {
                List <StockChartData> charts = GetNDaysChart(result, idx, 9).ToList();
                decimal max = charts.Select(x => x.PriceToday.High).Max();
                decimal min = charts.Select(x => x.PriceToday.Low).Min();
                if (max == min)
                {
                    chartDataToday.RSV = 50;
                }
                else
                {
                    chartDataToday.RSV = ((chartDataToday.PriceToday.Close - min) / (max - min)) * 100;
                }

                chartDataToday.KValue = (result.Where(x => x.ChartIdx == idx - 1).Single().KValue * 2 / 3) + (chartDataToday.RSV / 3);
                chartDataToday.DValue = (result.Where(x => x.ChartIdx == idx - 1).Single().DValue * 2 / 3) + (chartDataToday.KValue / 3);
            }
            else
            {
                chartDataToday.RSV    = 50;
                chartDataToday.KValue = 50;
                chartDataToday.DValue = 50;
            }
        }
        /// <summary>
        /// 取得基本分析指標資料
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static List <StockChartData> StockPriceDataToChart(List <StockPrice> source)
        {
            List <StockChartData> result = new List <StockChartData>();
            int        idx            = 0;
            StockPrice priceYesterday = new StockPrice();

            foreach (StockPrice priceData in source.OrderBy(s => s.Date))
            {
                ++idx;
                StockChartData chartDataToday = new StockChartData();
                chartDataToday.PriceToday = priceData;
                if (idx > 1)
                {
                    chartDataToday.PriceYesterday = priceYesterday;
                }
                chartDataToday.ChartIdx = idx;

                result.Add(chartDataToday);

                processTechnicalAnalysisIndicators(result, idx, chartDataToday);

                priceYesterday = chartDataToday.PriceToday;
            }

            return(result);
        }
 private static void calculateBBand(List <StockChartData> result, int idx, StockChartData chartDataToday)
 {
     if (idx >= 20)
     {
         decimal stdavg = MathHelper.CaculateStdAvg(GetNDaysChart(result, idx, 20).Select(x => x.PriceToday.Close).ToArray());
         chartDataToday.BBUB = chartDataToday.MA20 + stdavg * 2;
         chartDataToday.BBLB = chartDataToday.MA20 - stdavg * 2;
     }
 }
 private static void calculateMovingAverage(List <StockChartData> result, int idx, StockChartData chartDataToday)
 {
     if (idx >= 5)
     {
         chartDataToday.MA5  = GetNDaysChart(result, idx, 5).Select(x => x.PriceToday.Close).Average();
         chartDataToday.VMA5 = GetNDaysChart(result, idx, 5).Select(x => Convert.ToDecimal(x.PriceToday.Amount)).Average();
     }
     if (idx >= 10)
     {
         chartDataToday.MA10  = GetNDaysChart(result, idx, 10).Select(x => x.PriceToday.Close).Average();
         chartDataToday.VMA10 = GetNDaysChart(result, idx, 10).Select(x => Convert.ToDecimal(x.PriceToday.Amount)).Average();
     }
     if (idx >= 20)
     {
         chartDataToday.MA20  = GetNDaysChart(result, idx, 20).Select(x => x.PriceToday.Close).Average();
         chartDataToday.VMA20 = GetNDaysChart(result, idx, 20).Select(x => Convert.ToDecimal(x.PriceToday.Amount)).Average();
     }
     if (idx >= 60)
     {
         chartDataToday.MA60 = GetNDaysChart(result, idx, 60).Select(x => x.PriceToday.Close).Average();
     }
     if (idx >= 120)
     {
         chartDataToday.MA120 = GetNDaysChart(result, idx, 120).Select(x => x.PriceToday.Close).Average();
     }
 }
        private static void processTechnicalAnalysisIndicators(List <StockChartData> result, int idx, StockChartData chartDataToday)
        {
            calculateMovingAverage(result, idx, chartDataToday);

            calculateKDValue(result, idx, chartDataToday);

            calculateBBand(result, idx, chartDataToday);
        }
        public async Task <Response <StockChartData> > GetStockChartDataAsync(string id)
        {
            var fnResult = new Response <StockChartData>
            {
                StatusCode = (int)HttpStatusCode.BadRequest
            };

            try
            {
                var uri = _yahooFinanceApiSettings.BaseClient + string.Format(_yahooFinanceApiSettings.GetStockChartUri, id);

                var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, uri));

                if (response.StatusCode != HttpStatusCode.OK)
                {
                    return(fnResult);
                }

                var content = await response.Content.ReadAsStringAsync();

                var requestBody = JObject.Parse(content);

                var timestampList = requestBody.SelectToken($"chart.result[0].timestamp").Values <long>().ToList();
                var priceJToken   = requestBody.SelectToken($"chart.result[0].indicators.quote[0].close");
                var priceList     = new List <double>();

                foreach (var price in priceJToken)
                {
                    var priceString = price.ToString();
                    if (string.IsNullOrWhiteSpace(priceString))
                    {
                        priceList.Add(0);
                    }
                    else
                    {
                        priceList.Add((double)price);
                    }
                }

                var stockChartData = new StockChartData();

                for (int i = 0; i < timestampList.Count; i++)
                {
                    var start = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
                    start = start.AddSeconds(timestampList[i]).ToLocalTime();

                    stockChartData.ChartDataList.Add(new ChartData
                    {
                        price         = priceList[i],
                        timestampLong = timestampList[i],
                        time          = start.ToString("g")
                    });
                }

                fnResult.StatusCode = (int)HttpStatusCode.OK;
                fnResult.Data       = stockChartData;

                return(fnResult);
            }
            catch (Exception e)
            {
                fnResult.StatusCode = (int)HttpStatusCode.InternalServerError;
                fnResult.Message    = e.Message;
                return(fnResult);
            }
        }
        public List <StockSelectionResult> GetSelectionResult(List <StockChartData> stockPriceList, DateTime checkBgn, DateTime checkEnd)
        {
            List <StockSelectionResult> result = new List <StockSelectionResult>();

            for (DateTime date = checkBgn; date <= checkEnd; date = date.AddDays(1))
            {
                // 該日期沒股價資訊則跳過
                if (stockPriceList.Where(x => x.PriceToday.Date == date.Date).Count() == 0)
                {
                    continue;
                }

                StockChartData currentDatePrice = stockPriceList.Where(x => x.PriceToday.Date == date).First();

                if (currentDatePrice.ChartIdx < 30)
                {
                    continue;
                }

                // 量必須為5日均量的1.5倍以上為爆量
                if (currentDatePrice.PriceToday.Amount < currentDatePrice.VMA5 * 1.5m)
                {
                    continue;
                }

                // 漲幅必須大於3%
                if ((currentDatePrice.PriceToday.Close - currentDatePrice.PriceYesterday.Close) / currentDatePrice.PriceYesterday.Close <= 0.03m)
                {
                    continue;
                }

                // 漲停買不到,跳過
                if (currentDatePrice.IsLimitUp)
                {
                    continue;
                }

                List <StockChartData> stock10Days = StockAnalysisHelper.GetNDaysChart(stockPriceList, currentDatePrice.ChartIdx - 1, 10).ToList();

                // 10日內最高點
                if (currentDatePrice.PriceToday.Close > stock10Days.Select(x => x.PriceToday.Close).Max())
                {
                    // 10日內布林上下緣在7%以內
                    bool chk = true;
                    foreach (StockChartData data in stock10Days)
                    {
                        if (((data.BBUB - data.BBLB) / data.BBLB) > 0.07m)
                        {
                            chk = false;
                        }
                    }

                    if (chk)
                    {
                        StockChartData nextDayData = StockAnalysisHelper.GetNextNDaysChart(stockPriceList, currentDatePrice.ChartIdx, 1);
                        result.Add(new StockSelectionResult()
                        {
                            Date = currentDatePrice.PriceToday.Date,
                            Memo = String.Format("布林拳; 布林平均: {0}%;漲幅: {1}%;爆量: {2}倍; 今日收盤: {3}; 明日開盤: {4}",
                                                 (stock10Days.Select(x => (x.BBUB - x.BBLB) / x.BBLB).Average() * 100m).ToString("0.00"),
                                                 (((currentDatePrice.PriceToday.Close - currentDatePrice.PriceYesterday.Close) / currentDatePrice.PriceYesterday.Close) * 100m).ToString("0.00"),
                                                 (currentDatePrice.PriceToday.Amount / currentDatePrice.VMA5).ToString("0.00"),
                                                 currentDatePrice.PriceToday.Close.ToString("0.00"),
                                                 nextDayData == null ? "0.00": nextDayData.PriceToday.Open.ToString("0.00")
                                                 )
                        });
                    }
                }
            }



            return(result);
        }