private void OnHistoryAvailable(object sender, StockQuoteHistory history) { if (HistoryAvailable != null) { HistoryAvailable(this, history); } }
void OnHistoryAvailable(StockQuoteHistory history) { _downloadLog.AddHistory(history); if (HistoryAvailable != null) { HistoryAvailable(this, history); } }
public async Task <bool> UpdateHistory(StockQuoteHistory history) { if (!_downloadError) { _downloadError = true; OnComplete(true, "Download history is not supported by IEXCloud service"); } await Task.Delay(0); return(false); }
internal void Merge(StockQuoteHistory newHistory) { foreach (var item in newHistory.History) { this.AddQuote(item); } // promote any stock quote names to the root (to save space) foreach (var item in this.History) { if (!string.IsNullOrEmpty(item.Name)) { this.Name = item.Name; item.Name = null; } } }
public void AddHistory(StockQuoteHistory history) { this.database[history.Symbol] = history; DownloadInfo info = GetInfo(history.Symbol); if (info == null) { info = new DownloadInfo() { Downloaded = DateTime.Today, Symbol = history.Symbol }; this.Downloaded.Add(info); this._downloaded[info.Symbol] = info; } else { info.Downloaded = DateTime.Today; } DelayedSave(); }
private StockQuoteHistory ParseTimeSeries(JObject o) { StockQuoteHistory history = new StockQuoteHistory(); history.History = new List <StockQuote>(); history.Complete = true; // this is a complete history. Newtonsoft.Json.Linq.JToken value; if (o.TryGetValue("Note", StringComparison.Ordinal, out value)) { string message = (string)value; throw new Exception(message); } if (o.TryGetValue("Error Message", StringComparison.Ordinal, out value)) { string message = (string)value; throw new Exception(message); } if (o.TryGetValue("Meta Data", StringComparison.Ordinal, out value)) { if (value.Type == JTokenType.Object) { JObject child = (JObject)value; if (child.TryGetValue("2. Symbol", StringComparison.Ordinal, out value)) { history.Symbol = (string)value; } } } else { throw new Exception("Time series data schema has changed"); } if (o.TryGetValue("Time Series (Daily)", StringComparison.Ordinal, out value)) { if (value.Type == JTokenType.Object) { JObject series = (JObject)value; foreach (var p in series.Properties().Reverse()) { DateTime date; if (DateTime.TryParse(p.Name, out date)) { value = series.GetValue(p.Name); if (value.Type == JTokenType.Object) { StockQuote quote = new StockQuote() { Date = date, Downloaded = DateTime.Now }; JObject child = (JObject)value; if (child.TryGetValue("1. open", StringComparison.Ordinal, out value)) { quote.Open = (decimal)value; } if (child.TryGetValue("4. close", StringComparison.Ordinal, out value)) { quote.Close = (decimal)value; } if (child.TryGetValue("2. high", StringComparison.Ordinal, out value)) { quote.High = (decimal)value; } if (child.TryGetValue("3. low", StringComparison.Ordinal, out value)) { quote.Low = (decimal)value; } if (child.TryGetValue("5. volume", StringComparison.Ordinal, out value)) { quote.Volume = (decimal)value; } history.History.Add(quote); } } } } } else { throw new Exception("Time series data schema has changed"); } return(history); }
public async Task <bool> UpdateHistory(StockQuoteHistory history) { string outputsize; if (!history.Complete) { outputsize = "full"; } else { outputsize = "compact"; } bool updated = false; const string timeSeriesAddress = "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol={0}&outputsize={1}&apikey={2}"; string symbol = history.Symbol; string uri = string.Format(timeSeriesAddress, symbol, outputsize, this._settings.ApiKey); await Task.Run(new Action(() => { try { // first check if history needs updating! bool historyComplete = history.IsComplete(); if (historyComplete) { OnError(string.Format("History for symbol {0} is already up to date", symbol)); } else { // this service doesn't want too many calls per second. int ms = _throttle.GetSleep(); while (ms > 0) { string message = null; string suffix = (ms > 1000) ? "seconds" : "ms"; int amount = (ms > 1000) ? ms / 1000 : ms; message = string.Format("AlphaVantage history service needs to sleep for {0} {1}", suffix, amount); OnComplete(PendingCount == 0, message); while (!_cancelled && ms > 0) { Thread.Sleep(1000); ms -= 1000; } ms = _throttle.GetSleep(); } if (!_cancelled) { HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri); req.UserAgent = "USER_AGENT=Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;)"; req.Method = "GET"; req.Timeout = 10000; req.UseDefaultCredentials = false; _current = req; OnError("AlphaVantage fetching history for " + symbol); WebResponse resp = req.GetResponse(); _throttle.RecordCall(); using (Stream stm = resp.GetResponseStream()) { using (StreamReader sr = new StreamReader(stm, Encoding.UTF8)) { string json = sr.ReadToEnd(); JObject o = JObject.Parse(json); var newHistory = ParseTimeSeries(o); if (string.Compare(newHistory.Symbol, symbol, StringComparison.OrdinalIgnoreCase) != 0) { OnError(string.Format("History for symbol {0} return different symbol {1}", symbol, newHistory.Symbol)); } else { updated = true; history.Merge(newHistory); history.Complete = true; history.Save(this._logPath); } } } } } } catch (Exception ex) { string message = ex.Message; OnError(message); if (message.Contains("Please visit https://www.alphavantage.co/premium/")) { _throttle.CallsThisMinute += this._settings.ApiRequestsPerMinuteLimit; } } OnComplete(PendingCount == 0, null); })); return(updated); }
public async void BeginFetchHistory(List <string> batch) { string singleton = null; bool busy = false; lock (_downloadSync) { busy = _downloadingHistory; if (busy) { if (batch.Count == 1) { // then we need this individual stock ASAP var item = batch[0]; if (_downloadBatch.Contains(item)) { _downloadBatch.Remove(item); } _downloadBatch.Insert(0, item); singleton = item; } else { // then merge the new batch with existing batch that we are downloading. foreach (var item in batch) { if (!_downloadBatch.Contains(item)) { _downloadBatch.Add(item); } } } } else { // starting a new download batch. _downloadBatch = new List <string>(batch); } } if (busy) { if (!string.IsNullOrEmpty(singleton)) { // in this case we want to load any cached history and make that available to unblock the UI thread ASAP // otherwise UI might be blocks on slow HTTP downloads. var history = await this._downloadLog.GetHistory(singleton); if (history != null && history.History != null && history.History.Count != 0) { // unblock the UI thread with the cached history for now. OnHistoryAvailable(history); } } // only allow one thread do all the downloading. return; } tokenSource = new CancellationTokenSource(); _downloadingHistory = true; while (_downloadingHistory) { string symbol = null; lock (_downloadSync) { if (_downloadBatch != null && _downloadBatch.Count > 0) { symbol = _downloadBatch.First(); _downloadBatch.Remove(symbol); } } if (symbol == null) { break; } else { #if PerformanceBlocks using (PerformanceBlock.Create(ComponentId.Money, CategoryId.View, MeasurementId.DownloadStockQuoteHistory)) { #endif StockQuoteHistory history = null; var info = this._downloadLog.GetInfo(symbol); history = await this._downloadLog.GetHistory(symbol); if (history == null) { history = new StockQuoteHistory() { Symbol = symbol }; } if (info != null && info.Downloaded.Date == DateTime.Today && history != null && history.Complete) { // already up to date } else { try { await _service.UpdateHistory(history); } catch (Exception ex) { OnError("Download history error: " + ex.Message); } } if (history != null && history.History != null && history.History.Count != 0) { OnHistoryAvailable(history); } #if PerformanceBlocks } #endif } } _downloadingHistory = false; while (_downloadingHistory && _downloadBatch.Count > 0) { Thread.Sleep(1000); // wait for download to finish. } _downloadingHistory = false; }
public async Task <StockQuoteHistory> GetHistory(string symbol) { if (database.ContainsKey(symbol)) { return(database[symbol]); } StockQuoteHistory history = null; DownloadInfo info; var changed = false; var changedHistory = false; if (_downloaded.TryGetValue(symbol, out info)) { // read from disk on background thread so we don't block the UI thread loading // all these stock quote histories. await Task.Run(() => { try { history = StockQuoteHistory.Load(this._logFolder, symbol); if (symbol == "GE") { Debug.WriteLine("debug me"); } if (history.RemoveDuplicates()) { changedHistory = true; } } catch (Exception) { // file is bad, so ignore it } }); if (history == null) { this.Downloaded.Remove(info); this._downloaded.Remove(info.Symbol); changed = true; } else { database[symbol] = history; } lock (_downloadedQuotes) { if (_downloadedQuotes.ContainsKey(info.Symbol)) { if (history.AddQuote(_downloadedQuotes[info.Symbol])) { changedHistory = true; } } } } if (changed) { DelayedSave(); } if (changedHistory) { history.Save(_logFolder); } return(history); }