public void AdjustsForSplitsCorrectly() { _data[1].Split = 10; PriceAdjuster.AdjustData(ref _data); Assert.AreEqual(10, _data[0].AdjClose); Assert.AreEqual(100, _data[1].AdjClose); }
/// <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); }
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); }
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); }
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); } }
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); }
public void DoesNotCrashOnNullInput() { _data = null; PriceAdjuster.AdjustData(ref _data); }
//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); }