Example #1
0
 public void AdjustsForSplitsCorrectly()
 {
     _data[1].Split = 10;
     PriceAdjuster.AdjustData(ref _data);
     Assert.AreEqual(10, _data[0].AdjClose);
     Assert.AreEqual(100, _data[1].AdjClose);
 }
Example #2
0
        /// <summary>
        /// Adjusts OHLC data for dividends and splits.
        /// </summary>
        private void AdjustData(Instrument instrument, BarSize frequency)
        {
            var data = GetData(instrument, new DateTime(1900, 1, 1), DateTime.Now, frequency);

            PriceAdjuster.AdjustData(ref data);

            //data has been adjusted, save it to the db
            UpdateData(data, instrument, frequency);
        }
Example #3
0
        public void AdjustsForDividendsCorrectly()
        {
            _data[1].Dividend = 1;
            _data[0].Close    = 101;

            PriceAdjuster.AdjustData(ref _data);
            Assert.AreEqual(100, _data[0].AdjClose);
            Assert.AreEqual(100, _data[1].AdjClose);
        }
Example #4
0
        public void AdjustsForDividendsAndSplitsSimultaneouslyCorrectly()
        {
            _data[1].Dividend = 1;
            _data[0].Close    = 101;
            _data[1].Split    = 10;

            PriceAdjuster.AdjustData(ref _data);

            Assert.AreEqual(10, _data[0].AdjClose);
            Assert.AreEqual(100, _data[1].AdjClose);
        }
Example #5
0
        private void AdjustBtn_OnClick(object sender, RoutedEventArgs e)
        {
            var tmpData = Data.ToList();

            PriceAdjuster.AdjustData(ref tmpData);
            Data.Clear();
            foreach (OHLCBar b in tmpData)
            {
                Data.Add(b);
            }
        }
Example #6
0
        public void LeavesDataUntouchedIfNoDividendsOrSplits()
        {
            PriceAdjuster.AdjustData(ref _data);

            Assert.AreEqual(_data[0].AdjClose, _data[0].Close);
            Assert.AreEqual(_data[1].AdjClose, _data[1].Close);
            Assert.AreEqual(_data[2].AdjClose, _data[2].Close);
            Assert.AreEqual(_data[3].AdjClose, _data[3].Close);

            Assert.AreEqual(100, _data[0].Close);
            Assert.AreEqual(100, _data[1].Close);
            Assert.AreEqual(100, _data[2].Close);
            Assert.AreEqual(100, _data[3].Close);
        }
Example #7
0
 public void DoesNotCrashOnNullInput()
 {
     _data = null;
     PriceAdjuster.AdjustData(ref _data);
 }
Example #8
0
        //Downloads data from yahoo. First dividends and splits, then actual price data
        private async Task <List <OHLCBar> > GetData(HistoricalDataRequest request)
        {
            var barSize    = request.Frequency;
            var startDate  = request.StartingDate;
            var endDate    = request.EndingDate;
            var instrument = request.Instrument;
            var symbol     = string.IsNullOrEmpty(instrument.DatasourceSymbol) ? instrument.Symbol : instrument.DatasourceSymbol;

            if (barSize < BarSize.OneDay)
            {
                throw new Exception("Bar size not supporterd");                           //yahoo can't give us anything better than 1 day
            }
            if (startDate > endDate)
            {
                throw new Exception("Start date after end date");                      //obvious
            }
            var data = new List <OHLCBar>();


            //Splits
            string splitURL = string.Format(@"https://query1.finance.yahoo.com/v7/finance/download/{0}?period1={1}&period2={2}&interval=1d&events=split&crumb={3}",
                                            symbol,
                                            ToTimestamp(startDate),
                                            ToTimestamp(endDate),
                                            _crumb);

            HttpResponseMessage response;

            try
            {
                response = await _client.GetAsync(splitURL).ConfigureAwait(false);
            }
            catch (WebException ex)
            {
                _logger.Error(ex, "Yahoo downloader failure, URL: " + splitURL);
                return(new List <OHLCBar>());
            }

            if (!response.IsSuccessStatusCode)
            {
                string errorMessage = string.Format("Error downloading split data from Yahoo, symbol {0}. Status code: {1} Url: ({2})",
                                                    instrument.Symbol,
                                                    response.StatusCode,
                                                    splitURL);
                _logger.Log(LogLevel.Error, errorMessage);

                RaiseEvent(Error, this, new ErrorArgs(0, errorMessage));

                return(new List <OHLCBar>());
            }

            string contents = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

            //stick dividends and splits into their respective dictionaries to be used later
            //the key is the date in yyyy-MM-dd format

            //Split format:
            //Date,Stock Splits
            //2014-06-09,7/1
            var splits = new Dictionary <string, decimal>();

            string[] rows = contents.Split("\n".ToCharArray());
            for (int j = 1; j < rows.Length - 1; j++) //start at 1 because the first line's a header
            {
                string[] items = rows[j].Split(",".ToCharArray());
                decimal  splitNumerator, splitDenominator;
                string   date = items[0];

                string[] splitFactors = items[1].Trim().Split("/".ToCharArray());

                if (decimal.TryParse(splitFactors[0], out splitNumerator) && decimal.TryParse(splitFactors[1], out splitDenominator))
                {
                    splits.Add(date, splitNumerator / splitDenominator);
                }
            }


            //Dividends
            string divURL = string.Format(@"https://query1.finance.yahoo.com/v7/finance/download/{0}?period1={1}&period2={2}&interval=1d&events=div&crumb={3}",
                                          symbol,
                                          ToTimestamp(startDate),
                                          ToTimestamp(endDate),
                                          _crumb);

            try
            {
                response = await _client.GetAsync(divURL).ConfigureAwait(false);
            }
            catch (WebException ex)
            {
                _logger.Error(ex, "Yahoo downloader failure, URL: " + divURL);
                return(new List <OHLCBar>());
            }

            if (!response.IsSuccessStatusCode)
            {
                string errorMessage = string.Format("Error downloading dividend data from Yahoo, symbol {0}. Status code: {1} Url: ({2})",
                                                    instrument.Symbol,
                                                    response.StatusCode,
                                                    divURL);
                _logger.Log(LogLevel.Error, errorMessage);

                RaiseEvent(Error, this, new ErrorArgs(0, errorMessage));

                return(new List <OHLCBar>());
            }

            //Dividend Format
            //Date,Dividends
            //2014-11-06,0.47
            contents = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

            rows = contents.Split("\n".ToCharArray());
            var dividends = new Dictionary <string, decimal>();

            for (int j = 1; j < rows.Length - 1; j++) //start at 1 because the first line's a header
            {
                decimal  dividend;
                string[] items = rows[j].Split(",".ToCharArray());
                string   date  = items[0];

                if (decimal.TryParse(items[1], out dividend))
                {
                    dividends.Add(date, dividend);
                }
            }


            //now download the actual price data
            //csv file comes in the following format:
            //Date,Open,High,Low,Close,Adj Close,Volume
            //2014-06-02,90.565712,90.690002,88.928574,628.650024,89.807144,92337700
            string dataURL = string.Format(@"https://query1.finance.yahoo.com/v7/finance/download/{0}?period1={1}&period2={2}&interval=1d&events=history&crumb={3}",
                                           symbol,
                                           ToTimestamp(startDate),
                                           ToTimestamp(endDate),
                                           _crumb);

            try
            {
                response = await _client.GetAsync(dataURL).ConfigureAwait(false);
            }
            catch (WebException ex)
            {
                _logger.Error(ex, "Yahoo downloader failure, URL: " + dataURL);
                return(new List <OHLCBar>());
            }


            if (!response.IsSuccessStatusCode)
            {
                string errorMessage = string.Format("Error downloading dividend data from Yahoo, symbol {0}. Status code: {1} Url: ({2})",
                                                    instrument.Symbol,
                                                    response.StatusCode,
                                                    dataURL);
                _logger.Log(LogLevel.Error, errorMessage);

                RaiseEvent(Error, this, new ErrorArgs(0, errorMessage));

                return(new List <OHLCBar>());
            }

            contents = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

            //parse the downloaded price data
            rows = contents.Split("\n".ToCharArray());
            for (int j = 1; j < rows.Count(); j++) //start at 1 because the first line's a header
            {
                if (string.IsNullOrEmpty(rows[j]))
                {
                    continue;
                }

                string[] items = rows[j].Split(",".ToCharArray());
                var      bar   = new OHLCBar();

                if (dividends.ContainsKey(items[0]))
                {
                    bar.Dividend = dividends[items[0]];
                }

                if (splits.ContainsKey(items[0]))
                {
                    bar.Split = splits[items[0]];
                }

                //The OHL values are actually split adjusted, we want to turn them back
                if (bar.Split.HasValue)
                {
                    var ratio = bar.Split.Value;
                    for (int i = j - 2; i >= 0; i--)
                    {
                        data[i].Open  = data[i].Open * ratio;
                        data[i].High  = data[i].High * ratio;
                        data[i].Low   = data[i].Low * ratio;
                        data[i].Close = data[i].Close * ratio;
                    }
                }

                try
                {
                    var dt = DateTime.ParseExact(items[0], "yyyy-MM-dd", CultureInfo.InvariantCulture);
                    bar.DT     = dt;
                    bar.Open   = decimal.Parse(items[1]);
                    bar.High   = decimal.Parse(items[2]);
                    bar.Low    = decimal.Parse(items[3]);
                    bar.Close  = decimal.Parse(items[4]);
                    bar.Volume = long.Parse(items[6]);
                    //set adj values so that in case they're not set later (eg if we only get one bar), they're still filled in
                    bar.AdjOpen  = bar.Open;
                    bar.AdjHigh  = bar.High;
                    bar.AdjLow   = bar.Low;
                    bar.AdjClose = bar.Close;

                    //data check, sometimes a bunch of values will be zero - we don't want any of that
                    if (bar.Open == 0 || bar.High == 0 || bar.Low == 0 || bar.Close == 0)
                    {
                        _logger.Error($"Request for {request.Instrument.Symbol} returned faulty data - zeros at {bar.DT}");
                        return(data);
                    }

                    data.Add(bar);
                }
                catch
                {
                    _logger.Error("Failed to parse line: " + rows[j]);
                }
            }

            //For some reason the order of the data is sometimes reversed, make sure it's correct
            data = data.OrderBy(x => x.DT).ToList();

            //Note that due to the latest change, the adjusted close value is incorrect (doesn't include divs)
            //so we need to calc adj values ourselves
            PriceAdjuster.AdjustData(ref data);

            _logger.Log(LogLevel.Info, string.Format("Downloaded {0} bars from Yahoo, symbol {1}.",
                                                     data.Count,
                                                     instrument.Symbol));

            return(data);
        }