static int GetTimerInterval(BarSize barSize) { DateTime now = DateTime.Now; switch (barSize) { case BarSize.OneSecond: return 1000 - now.Millisecond; case BarSize.OneMinute: return (60 - now.Second) * 1000 - now.Millisecond; case BarSize.OneHour: return (60 - now.Minute) * 60 * 1000 - (60 - now.Second) * 1000 - now.Millisecond; case BarSize.OneDay: return (24 - now.Hour) * 24 * 60 * 1000 - (60 - now.Minute) * 60 * 1000 - (60 - now.Second) * 1000 - now.Millisecond; default: throw new NotImplementedException($"BarSize {barSize} is currently not supported by the ForexFeed data source"); } }
public RealTimeDataRequest(Instrument instrument, BarSize frequency, bool rthOnly = true, bool savetoLocalStorage = false) { Instrument = instrument; Frequency = frequency; RTHOnly = rthOnly; SaveToLocalStorage = savetoLocalStorage; }
public DataAdditionRequest(BarSize frequency, Instrument instrument, List<OHLCBar> data, bool overwrite = true) { Data = data; Frequency = frequency; Instrument = instrument; Overwrite = overwrite; }
public RealTimeStreamInfo(Instrument instrument, int requestID, string datasource, BarSize frequency, bool rthOnly) : this() { Instrument = instrument; RequestID = requestID; Datasource = datasource; Frequency = frequency; RTHOnly = rthOnly; }
public HistoricalDataRequest(Instrument instrument, BarSize frequency, DateTime startingDate, DateTime endingDate, bool forceFreshData = false, bool localStorageOnly = false, bool saveToLocalStorage = true, bool rthOnly = false) { Frequency = frequency; Instrument = instrument; StartingDate = startingDate; EndingDate = endingDate; ForceFreshData = forceFreshData; LocalStorageOnly = localStorageOnly; SaveDataToStorage = saveToLocalStorage; RTHOnly = rthOnly; }
public List<OHLCBar> GetData(Instrument inst, DateTime startTime, DateTime endTime, BarSize frequency = BarSize.OneDay) { _logger.Log(LogLevel.Info, string.Format("Data request for {0} from {1} to {2} @ {3}", inst, startTime, endTime, frequency)); //Check the cache lock (_dataCacheLock) { if (_dataCache.ContainsKey(inst.ID) && _dataCache[inst.ID].First().DT <= startTime && _dataCache[inst.ID].Last().DT >= endTime) { _logger.Log(LogLevel.Info, "Found data in cache"); return _dataCache[inst.ID].Where(x => x.DT >= startTime && x.DT <= endTime).ToList(); } } //if external data is not allowed, just grab the prior positions data if (!_useExternalDataSource) { return GetLocalData(inst, startTime, endTime); } //If the cache is not enough, go to the external datasource var data = ExternalDataSource.GetData(inst, startTime, endTime); //External datasource didn't have anything, get data from prior positions if (data == null || data.Count == 0) { _logger.Log(LogLevel.Info, "Data was not available externally, getting it form prior positions"); return GetLocalData(inst, startTime, endTime); } //QDMS data does NOT cover the entire period requested. //Try to supplement the data with the prices from prior positions if(frequency == BarSize.OneDay && (data.First().DT.Date > startTime.Date || data.Last().DT.Date < endTime)) { SupplementWithLocalData(inst, startTime, endTime, ref data); } AddToCache(data, inst.ID); return data; }
/// <summary> /// Delets data of a specific frequency for a specific instrument. /// </summary> /// <param name="instrument"></param> /// <param name="frequency"></param> public void DeleteData(Instrument instrument, BarSize frequency) { bool isConnected; MySqlConnection connection = TryConnect(out isConnected); if (!isConnected) { throw new Exception("Could not connect to database"); } using (var cmd = new MySqlCommand("", connection)) { cmd.CommandText = string.Format("DELETE FROM data WHERE InstrumentID = {0} AND Frequency = {1}", instrument.ID, (int)frequency); cmd.ExecuteNonQuery(); cmd.CommandText = string.Format("DELETE FROM instrumentinfo WHERE InstrumentID = {0} AND Frequency = {1}", instrument.ID, (int)frequency); cmd.ExecuteNonQuery(); } Log(LogLevel.Info, string.Format("Deleted all {0} data for instrument {1}", frequency, instrument)); connection.Close(); }
private void LoadDataBtn_Click(object sender, RoutedEventArgs e) { Data.Clear(); //grab the data using (var localStorage = DataStorageFactory.Get()) { var bars = localStorage.GetData(TheInstrument, StartTime, EndTime, (BarSize)ResolutionComboBox.SelectedItem); //find largest significant decimal by sampling the prices at the start and end of the series var decPlaces = new List <int>(); for (int i = 0; i < Math.Min(bars.Count, 20); i++) { decPlaces.Add(bars[i].Open.CountDecimalPlaces()); decPlaces.Add(bars[bars.Count - 1 - i].Close.CountDecimalPlaces()); } //set the column format to use that number so we don't get any useless trailing 0s SetPriceColumnFormat(decPlaces.Max()); foreach (OHLCBar b in bars) { //do any required time zone coversions if (TimezoneComboBox.Text == "UTC") { b.DT = TimeZoneInfo.ConvertTimeToUtc(b.DT, _tzInfo); } else if (TimezoneComboBox.Text == "Local") { b.DT = TimeZoneInfo.ConvertTime(b.DT, _tzInfo, TimeZoneInfo.Local); } Data.Add(b); } _loadedFrequency = (BarSize)ResolutionComboBox.SelectedItem; _loadedTimeZone = TimezoneComboBox.Text; } StatusLabel.Content = string.Format("Loaded {0} Bars", Data.Count); }
private bool RequestNewData(BarSize barSize, List <string> symbols, out Dictionary <string, Hashtable> data) { StringBuilder sb = new StringBuilder(); foreach (var symbol in symbols) { if (sb.Length > 0) { sb.Append(","); } sb.Append(symbol); } _api.setTimeout(30); _api.setSymbol(sb.ToString()); _api.setInterval(_intervalCache[barSize]); _api.setPeriods(1); ArrayList quotes = _api.getData(); if (_api.getStatus().Equals("OK")) { Dictionary <string, Hashtable> locData = new Dictionary <string, Hashtable>(); foreach (var quoteTmp in quotes) { Hashtable quote = (Hashtable)quoteTmp; locData.Add((string)quote["symbol"], quote); } data = locData; return(true); } LogError("getData"); data = null; return(false); }
private int GetInterval(BarSize frequency) { switch (frequency) { case BarSize.TwoMinutes: return(2); case BarSize.FiveMinutes: return(5); case BarSize.FifteenMinutes: return(15); case BarSize.ThirtyMinutes: return(30); case BarSize.OneHour: return(60); default: return(1); } }
public static string FrequencyToRequestString(BarSize frequency) { switch (frequency) { case BarSize.OneDay: return("d"); case BarSize.OneWeek: return("w"); case BarSize.OneMonth: return("m"); case BarSize.OneQuarter: return("q"); case BarSize.OneYear: return("a"); default: return("d"); } }
public static string FrequencyToRequestString(BarSize frequency) { switch (frequency) { case BarSize.OneDay: return "d"; case BarSize.OneWeek: return "w"; case BarSize.OneMonth: return "m"; case BarSize.OneQuarter: return "q"; case BarSize.OneYear: return "a"; default: return "d"; } }
private void UpdateHistoricalData(BarSize barSize) { var frequency = barSize; //(BarSize) ((MenuItem) sender).Tag; int requestCount = 0; using (var localStorage = DataStorageFactory.Get()) { foreach (var instrument in selectedInstruments) { var storageInfo = localStorage.GetStoredDataInfo(instrument.ID); if (storageInfo.Any(x => x.Frequency == frequency)) { var relevantStorageInfo = storageInfo.First(x => x.Frequency == frequency); Client.RequestHistoricalData(new HistoricalDataRequest( instrument, frequency, relevantStorageInfo.LatestDate + frequency.ToTimeSpan(), DateTime.Now, DataLocation.ExternalOnly, true)); requestCount++; } } } if (ProgressBarValue >= ProgressBarMaximum) { ProgressBarMaximum = requestCount; ProgressBarValue = 0; } else { ProgressBarMaximum += requestCount; } }
/// <summary> /// Gets the range of dates for which data is available for the specified instrument, at the specified frequency. /// </summary> /// <returns>Null if no match was found. A SotredDataInfo otherwise.</returns> public StoredDataInfo GetStorageInfo(int instrumentID, BarSize frequency) { bool isConnected; MySqlConnection connection = TryConnect(out isConnected); if (!isConnected) { throw new Exception("Could not connect to database"); } var instrumentInfo = new StoredDataInfo(); using (var cmd = new MySqlCommand("", connection)) { cmd.CommandText = string.Format("SELECT * FROM instrumentinfo WHERE InstrumentID = {0} AND Frequency = {1}", instrumentID, (int)frequency); using (var reader = cmd.ExecuteReader()) { if (reader.Read()) { instrumentInfo.InstrumentID = instrumentID; instrumentInfo.Frequency = (BarSize)reader.GetInt32("Frequency"); instrumentInfo.EarliestDate = reader.GetDateTime("EarliestDate"); instrumentInfo.LatestDate = reader.GetDateTime("LatestDate"); } else { return(null); //return null if nothing is found that matches these criteria } } } connection.Close(); return(instrumentInfo); }
public void UpdateData(List<OHLCBar> data, Instrument instrument, BarSize frequency) { throw new NotImplementedException(); }
public List<OHLCBar> GetData(Instrument instrument, DateTime startDate, DateTime endDate, BarSize barSize = BarSize.OneDay) { throw new NotImplementedException(); }
private static int[] BarSizeRange(BarSize barSize, TimeUnit timeUnit) { return(BarSizeRanges[barSize][timeUnit]); }
public HistoricalDataRequest(Instrument instrument, BarSize frequency, DateTime startingDate, DateTime endingDate, DataLocation dataLocation = DataLocation.Both, bool saveToLocalStorage = true, bool rthOnly = true, int requestID = 0) { Frequency = frequency; Instrument = instrument; StartingDate = startingDate; EndingDate = endingDate; DataLocation = dataLocation; SaveDataToStorage = saveToLocalStorage; RTHOnly = rthOnly; RequestID = requestID; }
public List <OHLCBar> GetData(Instrument inst, DateTime startTime, DateTime endTime, BarSize frequency = BarSize.OneDay) { _logger.Log(LogLevel.Info, string.Format("Data request for {0} from {1} to {2} @ {3}", inst, startTime, endTime, frequency)); //Check the cache lock (_dataCacheLock) { if (_dataCache.ContainsKey(inst.ID) && _dataCache[inst.ID].First().DT <= startTime && _dataCache[inst.ID].Last().DT >= endTime) { _logger.Log(LogLevel.Info, "Found data in cache"); return(_dataCache[inst.ID].Where(x => x.DT >= startTime && x.DT <= endTime).ToList()); } } //if external data is not allowed, just grab the prior positions data if (!_useExternalDataSource) { return(GetLocalData(inst, startTime, endTime)); } //If the cache is not enough, go to the external datasource var data = ExternalDataSource.GetData(inst, startTime, endTime); //External datasource didn't have anything, get data from prior positions if (data == null || data.Count == 0) { _logger.Log(LogLevel.Info, "Data was not available externally, getting it form prior positions"); return(GetLocalData(inst, startTime, endTime)); } //QDMS data does NOT cover the entire period requested. //Try to supplement the data with the prices from prior positions if (frequency == BarSize.OneDay && (data.First().DT.Date > startTime.Date || data.Last().DT.Date < endTime)) { SupplementWithLocalData(inst, startTime, endTime, ref data); } AddToCache(data, inst.ID); return(data); }
private List <OHLCBar> RequestData(Instrument instrument, DateTime startTime, DateTime endTime, BarSize frequency = BarSize.OneDay) { if (!instrument.ID.HasValue) { return(null); } //the data doesn't exist locally, request it var req = new HistoricalDataRequest { Instrument = instrument, StartingDate = startTime.Date, EndingDate = endTime.Date, Frequency = frequency, DataLocation = _allowFreshData ? DataLocation.Both : DataLocation.LocalOnly, RTHOnly = true, SaveDataToStorage = true }; int requestID = _client.RequestHistoricalData(req); _requestIDs.Add(requestID, false); //Wait until the data arrives int i = 0; while (i < 100) { Thread.Sleep(20); lock (_arrivedDataLock) { if (_requestIDs[requestID]) { var data = _arrivedData[instrument.ID.Value]; _arrivedData.Remove(instrument.ID.Value); return(data); } } i++; } return(new List <OHLCBar>()); }
public List<OHLCBar> GetData(int externalInstrumentID, DateTime from, DateTime to, BarSize frequency = BarSize.OneDay) { if (!_client.Connected) return null; RefreshInstrumentsList(); var instrument = _instrumentsList.FirstOrDefault(x => x.ID == externalInstrumentID); if (instrument == null) return null; return RequestData(instrument, from, to); }
public async System.Threading.Tasks.Task <List <DataBar> > GetHistoricalDataAsync(SecurityType securityType, string ticker, BarSize barSize, DateTime?endDate = null) { var client = new AlphaVantageStocksClient(Constants.AlphaVantageApiKey); var HistoricalBarCollection = new List <DataBar>(); StockTimeSeries timeSeries; switch (barSize) { case BarSize.DAY: timeSeries = await client.RequestDailyTimeSeriesAsync(ticker, TimeSeriesSize.Full, adjusted : false); break; case BarSize.WEEK: timeSeries = await client.RequestWeeklyTimeSeriesAsync(ticker, adjusted : false); break; case BarSize.MONTH: timeSeries = await client.RequestMonthlyTimeSeriesAsync(ticker, adjusted : false); break; default: timeSeries = await client.RequestIntradayTimeSeriesAsync(ticker, (IntradayInterval)barSize, TimeSeriesSize.Full); break; } ((List <StockDataPoint>)timeSeries.DataPoints).ForEach(bar => HistoricalBarCollection.Add(new DataBar(bar))); return(HistoricalBarCollection); }
private void CheckForAbnormalRanges(List <OHLCBar> data, int toSkip, double abnormalStDevRange, Instrument inst, BarSize freq) { //Check for abnormally large ranges var highs = data.Select(x => x.AdjHigh.HasValue ? x.AdjHigh.Value : x.High); var lows = data.Select(x => x.AdjLow.HasValue ? x.AdjLow.Value : x.Low); var ranges = highs.Zip(lows, (h, l) => (double)(h - l)); double stDev = ranges.QDMSStandardDeviation(); double mean = ranges.Average(); if (ranges.Skip(toSkip).Any(x => x > mean + stDev * abnormalStDevRange)) { _errors.Add(string.Format( "Possible dirty data detected, abnormally large range in instrument {0} at frequency {1}.", inst, freq)); } }
public FeedTimer(BarSize barSize) { BarSize = barSize; loopHandler = TimerLoop; }
public List<OHLCBar> GetData(EntityModel.Instrument instrument, DateTime from, DateTime to, BarSize frequency = BarSize.OneDay) { if (!_client.Connected) return null; RefreshInstrumentsList(); var qdmsInst = instrument.GetQDMSInstrument(_instrumentsList); if (qdmsInst == null) //nothing like this in QDMS, just grab local data { return null; } StoredDataInfo dataInfo = TryGetStorageInfo(qdmsInst); //Here we check if there's is absolutely no if ((dataInfo == null || dataInfo.LatestDate < from || dataInfo.EarliestDate > to) && !_allowFreshData) { return null; } //grab the data return RequestData(qdmsInst, from, to, frequency); }
private void TimerElapsed(object sender, BarSize e) { if (!Connected) { return; } foreach (KeyValuePair <BarSize, ConcurrentDictionary <int, RealTimeDataRequest> > pair in _connectedRequests) { if (_connectedRequests.Count == 0) { continue; } List <string> symbols = new List <string>(); List <RealTimeDataRequest> requestList = pair.Value.Select(p => p.Value).ToList(); { List <RealTimeDataRequest> requestsToIgnore = new List <RealTimeDataRequest>(); foreach (var request in requestList) { //if needed, we filter out the data outside of regular trading hours if (request.RTHOnly && request.Frequency < BarSize.OneDay && request.Instrument.Sessions != null) { if (!DateTime.UtcNow.InSession(request.Instrument.Sessions)) { requestsToIgnore.Add(request); } } } requestList.RemoveAll(x => requestsToIgnore.Contains(x)); } // @ToDo: Feacture: Diese Abfrage könnte gecachet werden, um Performance zu spaaren foreach (RealTimeDataRequest request in requestList) { string symbol = request.Instrument.DatasourceSymbol; if (string.IsNullOrEmpty(symbol)) { symbol = request.Instrument.Symbol; } if (!symbols.Contains(symbol)) { symbols.Add(symbol); } } if (symbols.Count > 0) { Dictionary <string, Hashtable> data; if (RequestNewData(pair.Key, symbols, out data)) { foreach (var request in requestList) { string symbol = request.Instrument.DatasourceSymbol; if (string.IsNullOrEmpty(symbol)) { symbol = request.Instrument.Symbol; } RaiseEvent(DataReceived, this, new RealTimeDataEventArgs( request.Instrument.ID.Value, long.Parse((string)data[symbol]["time"], CultureInfo.InvariantCulture), decimal.Parse((string)data[symbol]["open"], CultureInfo.InvariantCulture), decimal.Parse((string)data[symbol]["high"], CultureInfo.InvariantCulture), decimal.Parse((string)data[symbol]["low"], CultureInfo.InvariantCulture), decimal.Parse((string)data[symbol]["close"], CultureInfo.InvariantCulture), 0, 0, 0, request.AssignedID )); } } } } }
public List<OHLCBar> GetAllData(EntityModel.Instrument instrument, BarSize frequency = BarSize.OneDay) { if (!_client.Connected) return new List<OHLCBar>(); RefreshInstrumentsList(); //find instrument var qdmsInst = instrument.GetQDMSInstrument(_instrumentsList); if (qdmsInst == null) //nothing like this in QDMS, just grab local data { return new List<OHLCBar>(); } StoredDataInfo dataInfo = TryGetStorageInfo(qdmsInst); if (dataInfo == null) { return new List<OHLCBar>(); } return GetData( instrument, dataInfo.EarliestDate, dataInfo.LatestDate, frequency); }
public void AddData(List <OHLCBar> data, Instrument instrument, BarSize frequency, bool overwrite = false, bool adjust = true) { if (ParameterChecks(data)) { return; } if (!TryConnect(out SqlConnection connection)) { throw new Exception("Could not connect to database"); } using (connection) { using (var cmd = new SqlCommand("", connection)) { cmd.CommandTimeout = 0; var sb = new StringBuilder(); sb.Append("BEGIN TRAN T1;"); //We create a temporary table which will then be used to merge the data into the data table var r = new Random(); var tableName = "tmpdata" + r.Next(); sb.AppendFormat("SELECT * INTO {0} from data where 1=2;", tableName); //start the insert for (var i = 0; i < data.Count; i++) { var bar = data[i]; if (frequency >= BarSize.OneDay) { //we don't save the time when saving this stuff to allow flexibility with changing sessions bar.DateTimeClose = bar.DateTimeClose.Date; bar.DateTimeOpen = null; } if (i == 0 || (i - 1) % 500 == 0) { sb.AppendFormat("INSERT INTO {0} " + "(DateTimeClose, InstrumentID, Frequency, [Open], High, Low, [Close], " + "Volume, DateTimeOpen) VALUES ", tableName); } AppendBar(instrument, frequency, sb, bar); sb.Append(i % 500 != 0 && i < data.Count - 1 ? ", " : ";"); } //Merge the temporary table with the data table sb.AppendFormat(@"MERGE INTO dbo.data T USING (SELECT * FROM {0}) AS S (InstrumentID, Frequency,DateTimeClose, [Open], High, Low, [Close], DateTimeOpen,Volume ) ON T.InstrumentID = S.InstrumentID AND T.Frequency = S.Frequency AND T.DateTimeClose = S.DateTimeClose WHEN NOT MATCHED THEN INSERT (InstrumentID, Frequency,DateTimeClose, [Open], High, Low, [Close], DateTimeOpen,Volume) VALUES (InstrumentID, Frequency,DateTimeClose, [Open], High, Low, [Close], DateTimeOpen,Volume)", tableName); if (overwrite) { sb.Append(@" WHEN MATCHED THEN UPDATE SET T.InstrumentID = S.InstrumentID, T.Frequency = S.Frequency, T.DateTimeClose = S.DateTimeClose, T.[Open] = S.[Open], T.High = S.High, T.Low = S.Low, T.[Close] = S.[Close], T.Volume = S.Volume, T.DateTimeOpen = S.DateTimeOpen;"); } else { sb.Append(";"); } sb.AppendFormat("DROP TABLE {0};", tableName); sb.Append("COMMIT TRAN T1;"); cmd.CommandText = sb.ToString(); ExecuteQuery(cmd); cmd.CommandText = $@" MERGE INTO instrumentinfo T USING (SELECT * FROM (VALUES ({instrument.ID}, {(int)frequency}, '{data [0].DateTimeClose:yyyy-MM-dd HH:mm:ss.fff}', '{data[data.Count - 1].DateTimeClose:yyyy-MM-dd HH:mm:ss.fff}')) Dummy(InstrumentID, Frequency, EarliestDate, LatestDate)) S ON T.InstrumentID = S.InstrumentID AND T.Frequency = S.Frequency WHEN NOT MATCHED THEN INSERT (InstrumentID, Frequency, EarliestDate, LatestDate) VALUES (InstrumentID, Frequency, EarliestDate, LatestDate) WHEN MATCHED THEN UPDATE SET T.EarliestDate = (SELECT MIN(mydate) FROM (VALUES (T.EarliestDate), (S.EarliestDate)) AS AllDates(mydate)), T.LatestDate = (SELECT MAX(mydate) FROM (VALUES (T.LatestDate), (S.LatestDate)) AS AllDates(mydate));"; ExecuteQuery(cmd); Log(LogLevel.Info, $"Saved {data.Count} data points of {instrument.Symbol} @ {Enum.GetName(typeof(BarSize), frequency)} " + $"to local storage. {(overwrite ? "Overwrite" : "NoOverwrite")} {(adjust ? "Adjust" : "NoAdjust")}"); } } }
public void DeleteData(Instrument instrument, BarSize frequency) { throw new NotImplementedException(); }
public List <OHLCBar> GetData(EntityModel.Instrument instrument, DateTime from, DateTime to, BarSize frequency = BarSize.OneDay) { if (!_client.Connected) { return(null); } RefreshInstrumentsList(); var qdmsInst = instrument.GetQDMSInstrument(_instrumentsList); if (qdmsInst == null) //nothing like this in QDMS, just grab local data { return(null); } StoredDataInfo dataInfo = TryGetStorageInfo(qdmsInst); //Here we check if there's is absolutely no if ((dataInfo == null || dataInfo.LatestDate < from || dataInfo.EarliestDate > to) && !_allowFreshData) { return(null); } //grab the data return(RequestData(qdmsInst, from, to, frequency)); }
private List<OHLCBar> RequestData(Instrument instrument, DateTime startTime, DateTime endTime, BarSize frequency = BarSize.OneDay) { if (!instrument.ID.HasValue) return null; //the data doesn't exist locally, request it var req = new HistoricalDataRequest { Instrument = instrument, StartingDate = startTime.Date, EndingDate = endTime.Date, Frequency = frequency, DataLocation = _allowFreshData ? DataLocation.Both : DataLocation.LocalOnly, RTHOnly = true, SaveDataToStorage = true }; int requestID = _client.RequestHistoricalData(req); _requestIDs.Add(requestID, false); //Wait until the data arrives int i = 0; while (i < 100) { Thread.Sleep(20); lock (_arrivedDataLock) { if (_requestIDs[requestID]) { var data = _arrivedData[instrument.ID.Value]; _arrivedData.Remove(instrument.ID.Value); return data; } } i++; } return new List<OHLCBar>(); }
private void CheckForAbnormalReturns(List <OHLCBar> data, int toSkip, double abnormalLimit, Instrument inst, BarSize freq) { var closePrices = data .Select(x => x.AdjClose.HasValue ? (double)x.AdjClose.Value : (double)x.Close); if (closePrices.Any(x => x == 0)) { //avoid div by 0 return; } var absRets = closePrices.Zip(closePrices.Skip(1), (x, y) => Math.Abs(y / x - 1)); if (absRets.Skip(Math.Max(0, toSkip - 1)).Max() >= abnormalLimit) { _errors.Add(string.Format( "Possible dirty data detected, abnormally large returns in instrument {0} at frequency {1}.", inst, freq)); } }
/// <summary> /// Returns data from local storage. /// </summary> /// <param name="instrument">The instrument whose data you want.</param> /// <param name="startDate">Starting datetime.</param> /// <param name="endDate">Ending datetime.</param> /// <param name="frequency">Frequency.</param> /// <returns></returns> public List <OHLCBar> GetData(Instrument instrument, DateTime startDate, DateTime endDate, BarSize frequency = BarSize.OneDay) { bool isConnected; MySqlConnection connection = TryConnect(out isConnected); if (!isConnected) { throw new Exception("Could not connect to database"); } using (var cmd = new MySqlCommand("", connection)) { cmd.CommandText = "SELECT * FROM data WHERE " + "InstrumentID = ?ID AND Frequency = ?Freq AND DT >= ?Start AND DT <= ?End ORDER BY DT ASC"; cmd.Parameters.AddWithValue("ID", instrument.ID); cmd.Parameters.AddWithValue("Freq", (int)frequency); cmd.Parameters.AddWithValue("Start", frequency >= BarSize.OneDay ? startDate.Date : startDate); cmd.Parameters.AddWithValue("End", frequency >= BarSize.OneDay ? endDate.Date : endDate); var data = new List <OHLCBar>(); using (var reader = cmd.ExecuteReader(System.Data.CommandBehavior.SequentialAccess)) { while (reader.Read()) { var bar = new OHLCBar { DT = reader.GetDateTime(0), Open = (decimal)reader[3], High = (decimal)reader[4], Low = (decimal)reader[5], Close = (decimal)reader[6], AdjOpen = reader[7] as decimal?, AdjHigh = reader[8] as decimal?, AdjLow = reader[9] as decimal?, AdjClose = reader[10] as decimal?, Volume = reader[11] as long?, OpenInterest = reader[12] as int?, Dividend = reader[13] as decimal?, Split = reader[14] as decimal?, DTOpen = reader.IsDBNull(15) ? null : (DateTime?)reader.GetDateTime(15) }; data.Add(bar); } } connection.Close(); return(data); } }
//Add new data to local storage public void AddData(List <OHLCBar> data, Instrument instrument, BarSize frequency, bool overwrite = false, bool adjust = true) { if (!instrument.ID.HasValue) { throw new Exception("Instrument must have an ID assigned to it."); } if (data.Count == 0) { Log(LogLevel.Error, "Local storage: asked to add data of 0 length"); return; } bool isConnected; MySqlConnection connection = TryConnect(out isConnected); if (!isConnected) { throw new Exception("Could not connect to database"); } bool needsAdjustment = false; using (var cmd = new MySqlCommand("", connection)) { var sb = new StringBuilder(); sb.Append("START TRANSACTION;"); int tmpCounter = 0; for (int i = 0; i < data.Count; i++) { var bar = data[i]; if (frequency >= BarSize.OneDay) { //we don't save the time when saving this stuff to allow flexibility with changing sessions bar.DT = bar.DT.Date; bar.DTOpen = null; } sb.AppendFormat(CultureInfo.InvariantCulture, "{16} INTO data " + "(DT, InstrumentID, Frequency, Open, High, Low, Close, AdjOpen, AdjHigh, AdjLow, AdjClose, " + "Volume, OpenInterest, Dividend, Split, DTOpen) VALUES (" + "'{0}', {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, {12}, {13}, {14}, {15});", bar.DT.ToString("yyyy-MM-dd HH:mm:ss.fff"), instrument.ID, (int)frequency, bar.Open.ToString(CultureInfo.InvariantCulture), bar.High.ToString(CultureInfo.InvariantCulture), bar.Low.ToString(CultureInfo.InvariantCulture), bar.Close.ToString(CultureInfo.InvariantCulture), bar.AdjOpen.HasValue ? bar.AdjOpen.Value.ToString(CultureInfo.InvariantCulture) : "NULL", bar.AdjHigh.HasValue ? bar.AdjHigh.Value.ToString(CultureInfo.InvariantCulture) : "NULL", bar.AdjLow.HasValue ? bar.AdjLow.Value.ToString(CultureInfo.InvariantCulture) : "NULL", bar.AdjClose.HasValue ? bar.AdjClose.Value.ToString(CultureInfo.InvariantCulture) : "NULL", bar.Volume.HasValue ? bar.Volume.Value.ToString(CultureInfo.InvariantCulture) : "NULL", bar.OpenInterest.HasValue ? bar.OpenInterest.Value.ToString(CultureInfo.InvariantCulture) : "NULL", bar.Dividend.HasValue ? bar.Dividend.Value.ToString(CultureInfo.InvariantCulture) : "NULL", bar.Split.HasValue ? bar.Split.Value.ToString(CultureInfo.InvariantCulture) : "NULL", bar.DTOpen.HasValue ? String.Format("'{0:yyyy-MM-dd HH:mm:ss.fff}'", bar.DTOpen.Value) : "NULL", overwrite ? "REPLACE" : "INSERT IGNORE" ); if (!needsAdjustment && (data[i].Dividend.HasValue || data[i].Split.HasValue)) { needsAdjustment = true; } tmpCounter++; //periodically insert...not sure what the optimal number of rows is if (tmpCounter > 1000) { sb.Append("COMMIT;"); cmd.CommandText = sb.ToString(); try { cmd.ExecuteNonQuery(); } catch (Exception ex) { Log(LogLevel.Error, "MySql query error: " + ex.Message); } sb.Clear(); sb.Append("START TRANSACTION;"); tmpCounter = 0; } } sb.Append("COMMIT;"); cmd.CommandText = sb.ToString(); try { cmd.ExecuteNonQuery(); } catch (Exception ex) { //no need to log duplicate key errors if we're not overwriting, it's by design. if (!ex.Message.Contains("Duplicate")) { Log(LogLevel.Error, "MySql query error: " + ex.Message); } } //finally update the instrument info cmd.CommandText = string.Format( "INSERT INTO instrumentinfo (InstrumentID, Frequency, EarliestDate, LatestDate) VALUES " + "({0}, {1}, '{2}', '{3}') " + "ON DUPLICATE KEY UPDATE EarliestDate = LEAST(EarliestDate, '{2}'), " + "LatestDate = GREATEST(LatestDate, '{3}')", instrument.ID.Value, (int)frequency, data[0].DT.ToString("yyyy-MM-dd HH:mm:ss.fff"), data[data.Count - 1].DT.ToString("yyyy-MM-dd HH:mm:ss.fff")); try { cmd.ExecuteNonQuery(); } catch (Exception ex) { Log(LogLevel.Error, "MySql query error: " + ex.Message); } Log(LogLevel.Info, string.Format( "Saved {0} data points of {1} @ {2} to local storage. {3} {4}", data.Count, instrument.Symbol, Enum.GetName(typeof(BarSize), frequency), overwrite ? "Overwrite" : "NoOverwrite", adjust ? "Adjust" : "NoAdjust")); } connection.Close(); //if there were dividends or splits in the data we added, //we need to generate adjusted prices if (adjust && needsAdjustment && frequency == BarSize.OneDay) //adjustments are nonsensical on any other frequency { AdjustData(instrument, frequency); } }
public List <OHLCBar> GetData(int externalInstrumentID, DateTime from, DateTime to, BarSize frequency = BarSize.OneDay) { if (!_client.Connected) { return(null); } RefreshInstrumentsList(); var instrument = _instrumentsList.FirstOrDefault(x => x.ID == externalInstrumentID); if (instrument == null) { return(null); } return(RequestData(instrument, from, to)); }
private void LoadDataBtn_Click(object sender, RoutedEventArgs e) { Data.Clear(); //grab the data using (var localStorage = new MySQLStorage()) { var tzInfo = TimeZoneInfo.FindSystemTimeZoneById(TheInstrument.Exchange.Timezone); var bars = localStorage.GetData(TheInstrument, StartTime, EndTime, (BarSize)ResolutionComboBox.SelectedItem); foreach (OHLCBar b in bars) { //do any required time zone coversions if (TimezoneComboBox.Text == "UTC") { b.DT = TimeZoneInfo.ConvertTimeToUtc(b.DT, tzInfo); } else if (TimezoneComboBox.Text == "Local") { b.DT = TimeZoneInfo.ConvertTime(b.DT, TimeZoneInfo.Local, tzInfo); } Data.Add(b); } _loadedFrequency = (BarSize)ResolutionComboBox.SelectedItem; } StatusLabel.Content = string.Format("Loaded {0} Bars", Data.Count); }
private void LoadDataBtn_Click(object sender, RoutedEventArgs e) { Data.Clear(); //grab the data using (var localStorage = DataStorageFactory.Get()) { var bars = localStorage.GetData(TheInstrument, StartTime, EndTime, (BarSize)ResolutionComboBox.SelectedItem); //find largest significant decimal by sampling the prices at the start and end of the series var decPlaces = new List<int>(); for (int i = 0; i < Math.Min(bars.Count, 20); i++) { decPlaces.Add(bars[i].Open.CountDecimalPlaces()); decPlaces.Add(bars[bars.Count - 1 - i].Close.CountDecimalPlaces()); } //set the column format to use that number so we don't get any useless trailing 0s SetPriceColumnFormat(decPlaces.Max()); foreach (OHLCBar b in bars) { //do any required time zone coversions if (TimezoneComboBox.Text == "UTC") { b.DT = TimeZoneInfo.ConvertTimeToUtc(b.DT, _tzInfo); } else if (TimezoneComboBox.Text == "Local") { b.DT = TimeZoneInfo.ConvertTime(b.DT, _tzInfo, TimeZoneInfo.Local); } Data.Add(b); } _loadedFrequency = (BarSize)ResolutionComboBox.SelectedItem; _loadedTimeZone = TimezoneComboBox.Text; } StatusLabel.Content = string.Format("Loaded {0} Bars", Data.Count); }
public async Task <List <ChartData> > GetChartData(CurrencyPair currencyPair, BarSize period) { return(await GetChartData(currencyPair, period, Helper.DateTimeUnixEpochStart, DateTime.UtcNow)); }
private void DrawBar(long originSeconds, Location location, LocalDateTime start, LocalDateTime end, BarSize barHeight, string label, int top) { if (start >= end) { end = end.PlusDays(1); } if (start >= end) { return; } int x1 = DateToPixels(originSeconds, start.InZoneLeniently(location.TimeZone)); int x2 = DateToPixels(originSeconds, end.InZoneLeniently(location.TimeZone)); if (x1 <= 0) { x1 = 0; } else if (x1 >= width) { return; } if (x2 >= width) { x2 = width - 1; } if (x2 < 0) { return; } var tb = new TextBlock { Foreground = MyBrushes.Gray224, Background = location.Brush, Opacity = .95, TextAlignment = TextAlignment.Center, LineHeight = 11, LineStackingStrategy = LineStackingStrategy.BlockLineHeight, Width = x2 - x1 + 1 }; var y1 = top; switch (barHeight) { case BarSize.Holiday: case BarSize.Weekend: tb.Background = location.Brush.Clone(); tb.Background.Opacity = .5; tb.Foreground = MyBrushes.Gray224; tb.Height = 11; tb.Text = label; tb.FitText(); break; case BarSize.L: tb.Height = 11; if (zoomFormats.SecondsPerPixel < 1800) { tb.Text = label; tb.FitText(); } break; case BarSize.M: tb.Height = 5; y1 += 3; break; case BarSize.S: tb.Height = 1; y1 += 5; break; } Canvas.SetTop(tb, y1); Canvas.SetLeft(tb, x1); canvas.Children.Add(tb); }
public void AddData(List <OHLCBar> data, Instrument instrument, BarSize frequency, bool overwrite = false, bool adjust = true) { if (!instrument.ID.HasValue) { throw new Exception("Instrument must have an ID assigned to it."); } if (data.Count == 0) { Log(LogLevel.Error, "Local storage: asked to add data of 0 length"); return; } SqlConnection connection; if (!TryConnect(out connection)) { throw new Exception("Could not connect to database"); } bool needsAdjustment = false; using (var cmd = new SqlCommand("", connection)) { cmd.CommandTimeout = 0; var sb = new StringBuilder(); sb.Append("BEGIN TRAN T1;"); //We create a temporary table which will then be used to merge the data into the data table var r = new Random(); string tableName = "tmpdata" + r.Next(); sb.AppendFormat("SELECT * INTO {0} from data where 1=2;", tableName); //start the insert for (int i = 0; i < data.Count; i++) { var bar = data[i]; if (frequency >= BarSize.OneDay) { //we don't save the time when saving this stuff to allow flexibility with changing sessions bar.DT = bar.DT.Date; bar.DTOpen = null; } if (i == 0 || (i - 1) % 500 == 0) { sb.AppendFormat("INSERT INTO {0} " + "(DT, InstrumentID, Frequency, [Open], High, Low, [Close], AdjOpen, AdjHigh, AdjLow, AdjClose, " + "Volume, OpenInterest, Dividend, Split, DTOpen) VALUES ", tableName); } sb.AppendFormat("('{0}', {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, {12}, {13}, {14}, {15})", bar.DT.ToString("yyyy-MM-ddTHH:mm:ss.fff"), instrument.ID, (int)frequency, bar.Open.ToString(CultureInfo.InvariantCulture), bar.High.ToString(CultureInfo.InvariantCulture), bar.Low.ToString(CultureInfo.InvariantCulture), bar.Close.ToString(CultureInfo.InvariantCulture), bar.AdjOpen.HasValue ? bar.AdjOpen.Value.ToString(CultureInfo.InvariantCulture) : "NULL", bar.AdjHigh.HasValue ? bar.AdjHigh.Value.ToString(CultureInfo.InvariantCulture) : "NULL", bar.AdjLow.HasValue ? bar.AdjLow.Value.ToString(CultureInfo.InvariantCulture) : "NULL", bar.AdjClose.HasValue ? bar.AdjClose.Value.ToString(CultureInfo.InvariantCulture) : "NULL", bar.Volume.HasValue ? bar.Volume.Value.ToString(CultureInfo.InvariantCulture) : "NULL", bar.OpenInterest.HasValue ? bar.OpenInterest.Value.ToString(CultureInfo.InvariantCulture) : "NULL", bar.Dividend.HasValue ? bar.Dividend.Value.ToString(CultureInfo.InvariantCulture) : "NULL", bar.Split.HasValue ? bar.Split.Value.ToString(CultureInfo.InvariantCulture) : "NULL", bar.DTOpen.HasValue ? String.Format("'{0:yyyy-MM-ddTHH:mm:ss.fff}'", bar.DTOpen.Value) : "NULL" ); sb.Append((i % 500 != 0 && i < data.Count - 1) ? ", " : ";"); if (!needsAdjustment && (data[i].Dividend.HasValue || data[i].Split.HasValue)) { needsAdjustment = true; } } //Merge the temporary table with the data table sb.AppendFormat(@"MERGE INTO dbo.data T USING (SELECT * FROM {0}) AS S (DT, InstrumentID, Frequency, [Open], High, Low, [Close], AdjOpen, AdjHigh, AdjLow, AdjClose, Volume, OpenInterest, Dividend, Split, DTOpen) ON T.InstrumentID = S.InstrumentID AND T.Frequency = S.Frequency AND T.DT = S.DT WHEN NOT MATCHED THEN INSERT (DT, InstrumentID, Frequency, [Open], High, Low, [Close], AdjOpen, AdjHigh, AdjLow, AdjClose, Volume, OpenInterest, Dividend, Split, DTOpen) VALUES (DT, InstrumentID, Frequency, [Open], High, Low, [Close], AdjOpen, AdjHigh, AdjLow, AdjClose, Volume, OpenInterest, Dividend, Split, DTOpen)", tableName); if (overwrite) { sb.Append(@" WHEN MATCHED THEN UPDATE SET T.DT = S.DT, T.InstrumentID = S.InstrumentID, T.Frequency = S.Frequency, T.[Open] = S.[Open], T.High = S.High, T.Low = S.Low, T.[Close] = S.[Close], T.AdjOpen = S.AdjOpen, T.AdjHigh = S.AdjHigh, T.AdjLow = S.AdjLow, T.AdjClose = S.AdjClose, T.Volume = S.Volume, T.OpenInterest = S.OpenInterest, T.Dividend = S.Dividend, T.Split = S.Split, T.DTOpen = S.DTOpen;"); } else { sb.Append(";"); } sb.AppendFormat("DROP TABLE {0};", tableName); sb.Append("COMMIT TRAN T1;"); cmd.CommandText = sb.ToString(); try { cmd.ExecuteNonQuery(); } catch (Exception ex) { Log(LogLevel.Error, "SQL Server query error: " + ex.Message); } //finally update the instrument info cmd.CommandText = string.Format(@" MERGE INTO instrumentinfo T USING (SELECT * FROM (VALUES ({0}, {1}, '{2}', '{3}')) Dummy(InstrumentID, Frequency, EarliestDate, LatestDate)) S ON T.InstrumentID = S.InstrumentID AND T.Frequency = S.Frequency WHEN NOT MATCHED THEN INSERT (InstrumentID, Frequency, EarliestDate, LatestDate) VALUES (InstrumentID, Frequency, EarliestDate, LatestDate) WHEN MATCHED THEN UPDATE SET T.EarliestDate = (SELECT MIN(mydate) FROM (VALUES (T.EarliestDate), (S.EarliestDate)) AS AllDates(mydate)), T.LatestDate = (SELECT MAX(mydate) FROM (VALUES (T.LatestDate), (S.LatestDate)) AS AllDates(mydate));", instrument.ID.Value, (int)frequency, data[0].DT.ToString("yyyy-MM-dd HH:mm:ss.fff"), data[data.Count - 1].DT.ToString("yyyy-MM-dd HH:mm:ss.fff")); try { cmd.ExecuteNonQuery(); } catch (Exception ex) { Log(LogLevel.Error, "SQL Server query error: " + ex.Message); } Log(LogLevel.Info, string.Format( "Saved {0} data points of {1} @ {2} to local storage. {3} {4}", data.Count, instrument.Symbol, Enum.GetName(typeof(BarSize), frequency), overwrite ? "Overwrite" : "NoOverwrite", adjust ? "Adjust" : "NoAdjust")); } connection.Close(); //if there were dividends or splits in the data we added, //we need to generate adjusted prices if (adjust && needsAdjustment && frequency == BarSize.OneDay) //adjustments are nonsensical on any other frequency { AdjustData(instrument, frequency); } }
public void AddDataAsync(OHLCBar data, Instrument instrument, BarSize frequency, bool overwrite = false) { AddData(new List <OHLCBar> { data }, instrument, frequency, overwrite); }
public void DeleteData(Instrument instrument, BarSize frequency, List<OHLCBar> bars) { throw new NotImplementedException(); }
public void UpdateData(List <OHLCBar> data, Instrument instrument, BarSize frequency, bool adjust = false) { AddData(data, instrument, frequency, true, adjust); }
public StoredDataInfo GetStorageInfo(int instrumentID, BarSize barSize) { throw new NotImplementedException(); }
public void DeleteData(Instrument instrument, BarSize frequency, List <OHLCBar> bars) { SqlConnection connection; if (!TryConnect(out connection)) { throw new Exception("Could not connect to database"); } using (var cmd = new SqlCommand("", connection)) { var sb = new StringBuilder(); sb.Append("BEGIN TRAN T1;"); for (int i = 0; i < bars.Count; i++) { sb.AppendFormat("DELETE FROM data WHERE InstrumentID = {0} AND Frequency = {1} AND DT = '{2}';", instrument.ID, (int)frequency, frequency < BarSize.OneDay ? bars[i].DT.ToString("yyyy-MM-dd HH:mm:ss.fff") : bars[i].DT.ToString("yyyy-MM-dd")); //for frequencies greater than a day, we don't care about time } sb.Append("COMMIT TRAN T1;"); cmd.CommandText = sb.ToString(); cmd.ExecuteNonQuery(); //check if there's any data left cmd.CommandText = string.Format("SELECT COUNT(*) FROM data WHERE InstrumentID = {0} AND Frequency = {1}", instrument.ID, (int)frequency); using (var reader = cmd.ExecuteReader()) { reader.Read(); int count = reader.GetInt32(0); reader.Close(); if (count == 0) { //remove from the instrumentinfo table cmd.CommandText = string.Format("DELETE FROM instrumentinfo WHERE InstrumentID = {0} AND Frequency = {1}", instrument.ID, (int)frequency); cmd.ExecuteNonQuery(); } else { //update the instrumentinfo table cmd.CommandText = string.Format( @"UPDATE instrumentinfo SET EarliestDate = (SELECT MIN(DT) FROM data WHERE InstrumentID = {0} AND Frequency = {1}), LatestDate = (SELECT MAX(DT) FROM data WHERE InstrumentID = {0} AND Frequency = {1}) WHERE InstrumentID = {0} AND Frequency = {1}" , instrument.ID, (int)frequency); cmd.ExecuteNonQuery(); } } } Log(LogLevel.Info, string.Format("Deleted {0} {1} bars for instrument {2}", bars.Count, frequency, instrument)); connection.Close(); }
/// <summary> /// This method allows adding data, but allowing the actual saving of the data to be delayed. /// Useful when you want to allow the data source the ability to make batch inserts/save to file/whatever on its own discretion. /// </summary> /// <param name="data"></param> /// <param name="instrument"></param> /// <param name="frequency"></param> /// <param name="overwrite"></param> public void AddDataAsync(List<OHLCBar> data, Instrument instrument, BarSize frequency, bool overwrite = false) { throw new NotImplementedException(); }
void SendData(BarSize barSize) { foreach (KeyValuePair <RequestGrouping, ConcurrentDictionary <int, RealTimeDataRequest> > pair in _connectedRequests) { // @ToDo: Performance: if many entries exists in this list, this could be an performance issue. if (pair.Key.Frequency != barSize) { continue; } if (_connectedRequests.Count == 0) { continue; } int historicalRequestId; if (!_historicalRequests.TryGetValue(pair.Key, out historicalRequestId)) { continue; // the historical request is not made yet. } List <OHLCBar> historicalData; if (!_historicalData.TryGetValue(historicalRequestId, out historicalData)) { continue; // the historical data did not arrived yet. } List <int> requestsToDelete = new List <int>(); foreach (var pair2 in pair.Value) { // get the current position int indexPosition = 0; if (_requestPosition.TryGetValue(pair2.Key, out indexPosition)) { indexPosition++; } if (historicalData.Count <= indexPosition) { // end of historical data _logger.Log(LogLevel.Info, $"End of historical data for real time simulation - request ID: {pair2.Key}"); requestsToDelete.Add(pair2.Key); } else { var currentBar = historicalData[indexPosition]; RaiseEvent(DataReceived, this, new RealTimeDataEventArgs( pair2.Value.Instrument.ID.Value, barSize, MyUtils.ConvertToTimestamp(currentBar.DT), currentBar.Open, currentBar.High, currentBar.Low, currentBar.Close, currentBar.Volume ?? 0, 0, 0, pair2.Value.AssignedID )); if (indexPosition == 0) { _requestPosition.TryAdd(pair2.Key, indexPosition); } else { _requestPosition[pair2.Key] = indexPosition; } } } RealTimeDataRequest dummy; foreach (var i in requestsToDelete) { pair.Value.TryRemove(i, out dummy); } } }
/// <summary> /// Returns data from local storage. /// </summary> /// <param name="instrument">The instrument whose data you want.</param> /// <param name="startDate">Starting datetime.</param> /// <param name="endDate">Ending datetime.</param> /// <param name="frequency">Frequency.</param> /// <returns></returns> public List <OHLCBar> GetData(Instrument instrument, DateTime startDate, DateTime endDate, BarSize frequency = BarSize.OneDay) { SqlConnection connection; if (!TryConnect(out connection)) { throw new Exception("Could not connect to database"); } using (var cmd = new SqlCommand("", connection)) { cmd.CommandText = "SELECT * FROM data WHERE " + "InstrumentID = @ID AND Frequency = @Freq AND DT >= @Start AND DT <= @End ORDER BY DT ASC"; cmd.Parameters.AddWithValue("ID", instrument.ID); cmd.Parameters.AddWithValue("Freq", (int)frequency); cmd.Parameters.AddWithValue("Start", frequency >= BarSize.OneDay ? startDate.Date : startDate); cmd.Parameters.AddWithValue("End", frequency >= BarSize.OneDay ? endDate.Date : endDate); var data = new List <OHLCBar>(); using (var reader = cmd.ExecuteReader()) { while (reader.Read()) { var bar = new OHLCBar { DT = reader.GetDateTime(0), DTOpen = reader.IsDBNull(15) ? null : (DateTime?)reader.GetDateTime(15), Open = reader.GetDecimal(3), High = reader.GetDecimal(4), Low = reader.GetDecimal(5), Close = reader.GetDecimal(6), AdjOpen = reader.IsDBNull(7) ? null : (decimal?)reader.GetDecimal(7), AdjHigh = reader.IsDBNull(8) ? null : (decimal?)reader.GetDecimal(8), AdjLow = reader.IsDBNull(9) ? null : (decimal?)reader.GetDecimal(9), AdjClose = reader.IsDBNull(10) ? null : (decimal?)reader.GetDecimal(10), Volume = reader.IsDBNull(11) ? null : (long?)reader.GetInt64(11), OpenInterest = reader.IsDBNull(12) ? null : (int?)reader.GetInt32(12), Dividend = reader.IsDBNull(13) ? null : (decimal?)reader.GetDecimal(13), Split = reader.IsDBNull(14) ? null : (decimal?)reader.GetDecimal(14) }; data.Add(bar); } } connection.Close(); return(data); } }
public MarketDataRequest(Contract contract, DateTime endDateTime, Duration duration, BarSize barSize, WhatToShow whatToShow) { Contract = contract ?? throw new ArgumentNullException(nameof(contract)); EndDateTime = endDateTime; Duration = duration; BarSize = barSize; WhatToShow = whatToShow; }