/// <summary>
        /// Get historical stock quotes from Yahoo Finance
        /// </summary>
        /// <param name="country"></param>
        /// <param name="stockId"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <param name="writeToErrorLogAction"></param>
        /// <returns></returns>
        public override async Task <IReadOnlyList <IStockQuoteFromDataSource> > GetHistoricalQuotesAsync(Country country, string stockId, DateTime start, DateTime end, Action <Exception> writeToErrorLogAction)
        {
            string stockFullId         = country == Country.USA ? stockId : $"{stockId}.{country.GetShortName()}";
            string yahooSingleQuoteUrl = string.Format(Configuration["YahooFinanceURL"], stockFullId);

            (string HtmlContent, IReadOnlyList <Cookie> Cookies)response = await GetHttpContentAsync(yahooSingleQuoteUrl).ConfigureAwait(false);

            IStockQuoteFromDataSource yahooQuote = _parser.ParseSingleQuote(country, stockId, response.HtmlContent, writeToErrorLogAction);
            IReadOnlyList <Cookie>    cookies    = response.Cookies;

            if (!(yahooQuote is YahooFinanceDataResult yahooResult) || string.IsNullOrEmpty(yahooResult.Crumb))
            {
                return(null);
            }

            string startTimestamp     = new DateTime(start.Year, start.Month, start.Day, 0, 0, 0).ToUnixTimestamp();
            string endTimestamp       = new DateTime(end.Year, end.Month, end.Day, 23, 59, 59).ToUnixTimestamp();
            string yahooHistoricalUrl = string.Format(Configuration["YahooHistoricalDataUrl"], stockFullId, startTimestamp, endTimestamp, yahooResult.Crumb);

            (string HtmlContent, IReadOnlyList <Cookie> Cookies)response2 = await GetHttpContentAsync(yahooHistoricalUrl, cookies).ConfigureAwait(false);

            IReadOnlyList <IStockQuoteFromDataSource> quotes = _parser.ParseMultiQuotes(country, stockId, response2.HtmlContent, writeToErrorLogAction);

            return(quotes.Where(a => a.TradeDateTime >= start && a.TradeDateTime <= end).ToList());
        }
示例#2
0
        private void RemoveStockQuote(List <IStock> stocks, IStockQuoteFromDataSource stockQuote)
        {
            IStock stock = stocks.Find(x => string.Equals(x.StockId, stockQuote.StockId, StringComparison.OrdinalIgnoreCase));

            if (stock != null)
            {
                stocks.Remove(stock);
            }
        }
示例#3
0
        public void DataSourceRealTimeWithInternetPriceTest(Country country, string stockId)
        {
            IConfiguration config = TestServiceProvider.GetTestConfiguration();
            IStockQuoteDataSourceOperations operations = new StockQuoteDataSourceOperations();
            IStockQuoteParser      parser = new AlphaVantageParser();
            AlphaVantageDataSource source = new AlphaVantageDataSource(config, operations, parser);

            IStockQuoteFromDataSource quote = source.GetMostRecentQuoteAsync(country, stockId, WriteToErrorLogAction).Result;

            Assert.NotNull(quote);
            Assert.True(quote.IsValid);
        }
        public void GetMostRecentQuoteTest(Country country, string stockId)
        {
            IConfiguration        config      = TestServiceProvider.GetTestConfiguration();
            IStockQuoteProvider   provider    = new StockQuoteSourceProvider(config, country);
            IStockQuoteDataSource yahooSource = provider.GetStockDataSources().FirstOrDefault(a => a.Source == Contracts.StockQuoteSource.Yahoo);

            Assert.NotNull(yahooSource);

            IStockQuoteFromDataSource result = yahooSource.GetMostRecentQuoteAsync(country, stockId, WriteToErrorLogAction).Result;

            Assert.NotNull(result);
            Assert.True(result.IsValid);
        }
示例#5
0
        public void ParseSingleQuoteTest()
        {
            Country country = Country.USA;
            string  stockId = "HDV";

            AlphaVantageParser parser = new AlphaVantageParser();

            string jsonContent = TestUtilities.ReadTestFile(Av5MinsJsonFile);
            IStockQuoteFromDataSource quote = parser.ParseSingleQuote(country, stockId, jsonContent, WriteToErrorLogAction);

            Assert.NotNull(quote);
            Assert.True(quote.IsValid);
        }
示例#6
0
        public void ParseSingleQuoteEmptyInputTest()
        {
            Country country = Country.USA;
            string  stockId = "HDV";

            AlphaVantageParser parser = new AlphaVantageParser();

            _isWriteToErrorLogActionRan = false;

            IStockQuoteFromDataSource quote = parser.ParseSingleQuote(country, stockId, null, WriteToErrorLogAction);

            Assert.Null(quote);
            Assert.True(_isWriteToErrorLogActionRan);
        }
示例#7
0
        static void PrintQuote(IStockQuoteFromDataSource quote)
        {
            if (quote == null)
            {
                return;
            }

            Console.WriteLine("Date: " + quote.TradeDateTime);
            Console.WriteLine("Open: " + quote.OpenPrice);
            Console.WriteLine("Close: " + quote.ClosePrice);
            Console.WriteLine("High: " + quote.HighPrice);
            Console.WriteLine("Low: " + quote.LowPrice);
            Console.WriteLine("Volume: " + quote.Volume);
            Console.WriteLine();
        }
示例#8
0
        static async Task RunAlphaVantageSource(string stockId)
        {
            IStockQuoteDataSource alphaVantageDataSource = GetAlphaVantageDataSource(_provider);

            if (alphaVantageDataSource == null)
            {
                Console.WriteLine("Error : Yahoo data source object is null");
                return;
            }

            IStockQuoteFromDataSource quote = await alphaVantageDataSource.GetMostRecentQuoteAsync(_country, stockId, WriteToError).ConfigureAwait(false);

            if (quote != null)
            {
                PrintQuote(quote);
            }
        }
        public void ParseSingleQuoteTest()
        {
            Country           country     = Country.USA;
            string            stockId     = "DRV";
            string            htmlContent = TestUtilities.ReadTestFile(YahooHtmlTestFilename);
            IStockQuoteParser parser      = new YahooFinanceParser();

            IStockQuoteFromDataSource quote = parser.ParseSingleQuote(country, stockId, htmlContent, WriteToErrorLogAction);

            Assert.NotNull(quote);
            Assert.True(quote.IsValid);
            Assert.Equal(14.63m, quote.ClosePrice);
            Assert.Equal(15.0686m, quote.HighPrice);
            Assert.Equal(14.611m, quote.LowPrice);
            Assert.Equal(14.79m, quote.OpenPrice);
            Assert.Equal(67165, quote.Volume);
            Assert.Equal(stockId, quote.StockId);
            Assert.Equal(country, quote.Country);
            Assert.Equal(2018, quote.TradeDateTime.Year);
            Assert.Equal(3, quote.TradeDateTime.Month);
            Assert.Equal(2, quote.TradeDateTime.Day);
            Assert.Equal(15, quote.TradeDateTime.Hour);
            Assert.Equal(59, quote.TradeDateTime.Minute);
        }
        private async Task <IStockQuoteFromDataSource> GetStockPricesFromDataSourceInternalAsync(CountryKind country, string stockId)
        {
            // TODO: 3 moves to constant ?
            for (int retry = 0; retry < 3; retry++)
            {
                foreach (IStockQuoteDataSource source in BaseData.GetStockDataSources())
                {
                    IStockQuoteFromDataSource stockData = null;

                    try
                    {
                        stockData = await source.GetMostRecentQuoteAsync(country.ConvertToTTStockQuoteSourceCountry(),
                                                                         stockId,
                                                                         WriteToErrorLog).ConfigureAwait(false);
                    }
                    catch
                    {
                    }

                    if (TestStatus && (stockData?.IsValid != true))
                    {
                        continue;
                    }

                    if (!TestStatus &&
                        (stockData?.IsValid != true || !BaseData.CurrentTime.IsSameDay(stockData.TradeDateTime)))
                    {
                        continue;
                    }

                    return(stockData);
                }
            }

            return(null);
        }
示例#11
0
        private (decimal?NInSystem, decimal?highestPriceInSystem, decimal?lowestPriceInSystem) DailyPriceCalculationSystem(BuySellStrategyType type, IReadOnlyList <IStockPriceHistory> recentStockPriceHistory, decimal todayATR, IStockQuoteFromDataSource todayPriceDataFromDataSource)
        {
            decimal[]  lowPrices    = null;
            decimal[]  highPrices   = null;
            decimal?[] ATRs         = null;
            decimal?   lowestPrice  = null;
            decimal?   highestPrice = null;
            decimal?   todayN       = null;

            if (recentStockPriceHistory.Count >= type.GetSellIntValue())
            {
                lowPrices = recentStockPriceHistory.Take(type.GetSellIntValue()).Select(a => a.LowPrice).ToArray();
                ATRs      = recentStockPriceHistory.Take(type.GetSellIntValue() - 1).Select(a => a.ATR).ToArray();
            }
            if (recentStockPriceHistory.Count() >= type.GetBuyIntValue())
            {
                highPrices = recentStockPriceHistory.Take(type.GetBuyIntValue()).Select(a => a.HighPrice).ToArray();
                ATRs       = recentStockPriceHistory.Take(type.GetBuyIntValue() - 1).Select(a => a.ATR).ToArray();
            }

            if (lowPrices != null)
            {
                lowestPrice = _baseData.CalculateLowestPrice(lowPrices, todayPriceDataFromDataSource.LowPrice);
            }

            if (highPrices != null)
            {
                highestPrice = _baseData.CalculateHighestPrice(highPrices, todayPriceDataFromDataSource.HighPrice);
            }

            if (ATRs != null)
            {
                List <decimal> validATRList = new List <decimal>();

                foreach (decimal?item in ATRs)
                {
                    if (item.HasValue)
                    {
                        validATRList.Add(item.Value);
                    }
                }

                if (validATRList.Count() == type.GetBuyIntValue() - 1)
                {
                    todayN = _baseData.CalculateTodayN(validATRList.ToArray(), todayATR);
                }
            }

            return(todayN, highestPrice, lowestPrice);
        }
示例#12
0
        public async Task InsertToDatabase(IStockQuoteFromDataSource stockData)
        {
            // get previous close price , if none, it's the first record and then insert to db
            IReadOnlyList <IStockPriceHistory> previousPrices = await _database.GetStockPriceHistoryAsync(stockData.Country.ConvertToTT2Country(), stockData.StockId, stockData.TradeDateTime, 1).ConfigureAwait(false);

            IStockPriceHistory previousStockPriceHistory = previousPrices?.FirstOrDefault();

            if (previousStockPriceHistory == null)
            {
                //string msg = $"The stock data {GetStockFullID(todayPriceFromDataSource.StockId)} from data sourceKind doesn't have the previous closed price, so it will NOT be added to database";
                //WriteToErrorLog(msg);
                IStockPriceHistory priceHist = new StockPriceHistory(stockData.Country.ConvertToTT2Country(), stockData.StockId, stockData.TradeDateTime)
                {
                    OpenPrice  = stockData.OpenPrice,
                    ClosePrice = stockData.ClosePrice,
                    HighPrice  = stockData.HighPrice,
                    LowPrice   = stockData.LowPrice,
                    Volume     = stockData.Volume
                };

                await _database.AddOrUpdateStockPriceHistoryAsync(priceHist).ConfigureAwait(false);

                return;
            }

            // get the max days of SystemN
            IReadOnlyList <IStockPriceHistory> recentStockPriceHistory = await _database.GetStockPriceHistoryAsync(stockData.Country.ConvertToTT2Country(), stockData.StockId, stockData.TradeDateTime, _maxCalculationDay - 1).ConfigureAwait(false);

            // if there exists previous closed price, then calculate today's ATR
            decimal todayATR = _baseData.CalculateTodayATR(stockData.HighPrice, stockData.LowPrice, previousStockPriceHistory.ClosePrice);

            (decimal? N20, decimal? HighIn20, decimal? LowIn10) = DailyPriceCalculationSystem(BuySellStrategyType.N20, recentStockPriceHistory, todayATR, stockData);
            (decimal? N40, decimal? HighIn40, decimal? LowIn15) = DailyPriceCalculationSystem(BuySellStrategyType.N40, recentStockPriceHistory, todayATR, stockData);
            (decimal? N60, decimal? HighIn60, decimal? LowIn20) = DailyPriceCalculationSystem(BuySellStrategyType.N60, recentStockPriceHistory, todayATR, stockData);
            decimal?MA20  = CalculateMovingAverage(20, recentStockPriceHistory, stockData);
            decimal?MA40  = CalculateMovingAverage(40, recentStockPriceHistory, stockData);
            decimal?MA60  = CalculateMovingAverage(60, recentStockPriceHistory, stockData);
            decimal?MA120 = CalculateMovingAverage(120, recentStockPriceHistory, stockData);
            decimal?MA240 = CalculateMovingAverage(240, recentStockPriceHistory, stockData);

            IStockPriceHistory priceHistory = new StockPriceHistory(stockData.Country.ConvertToTT2Country(), stockData.StockId, stockData.TradeDateTime)
            {
                OpenPrice  = stockData.OpenPrice,
                ClosePrice = stockData.ClosePrice,
                HighPrice  = stockData.HighPrice,
                LowPrice   = stockData.LowPrice,
                Volume     = stockData.Volume,
                ATR        = todayATR,
                N20        = N20,
                N40        = N40,
                N60        = N60,
                HighIn20   = HighIn20,
                LowIn10    = LowIn10,
                HighIn40   = HighIn40,
                LowIn15    = LowIn15,
                HighIn60   = HighIn60,
                LowIn20    = LowIn20,
                MA20       = MA20,
                MA40       = MA40,
                MA60       = MA60,
                MA120      = MA120,
                MA240      = MA240
            };

            await _database.AddOrUpdateStockPriceHistoryAsync(priceHistory).ConfigureAwait(false);
        }
示例#13
0
        private decimal?CalculateMovingAverage(int days, IReadOnlyList <IStockPriceHistory> recentStockPriceHistory, IStockQuoteFromDataSource todayPriceDataFromDataSource)
        {
            if (recentStockPriceHistory.Count() >= days - 1)
            {
                decimal[] closePrices = recentStockPriceHistory.Take(days - 1).Select(a => a.ClosePrice).ToArray();
                return((closePrices.Sum() + todayPriceDataFromDataSource.ClosePrice) / (decimal)days);
            }

            return(null);
        }