/// <summary>Handle a request to send a range of historic instrument data</summary> private void HandleMsg(OutMsg.RequestInstrumentHistory req) { // Add or select the associated transmitter var trans = AddTransmitter(req.SymbolCode); // Add the time range requests for historic data foreach (var range in req.TimeRanges.InPairs()) { trans.HistoricDataRequests.Add(new HistoricDataRequest( req.TimeFrame.ToCAlgoTimeframe(), new DateTimeOffset(range.Item1, TimeSpan.Zero), new DateTimeOffset(range.Item2, TimeSpan.Zero))); } // Add the index range requests for historic data // Tradee using negative index ranges (i.e. (oldest,newest) = [-Count,0]) but CAlgo uses // inverted positive indices, 0 = now, Count = oldest. foreach (var range in req.IndexRanges.InPairs()) { trans.HistoricDataRequests.Add(new HistoricDataRequest( req.TimeFrame.ToCAlgoTimeframe(), -range.Item1, -range.Item2)); } }
/// <summary>Request historic candle data by index range</summary> public void RequestIndexRange(NegIdx i_oldest, NegIdx i_newest, bool only_if_missing) { Debug.Assert(i_oldest <= i_newest); var msg = new OutMsg.RequestInstrumentHistory(SymbolCode, TimeFrame); // See if we have this range already if (only_if_missing) { var range = IndexRange(i_oldest, i_newest); if (i_oldest < range.Beg) { msg.IndexRanges.Add(i_oldest); msg.IndexRanges.Add(Math.Min(range.Begi, i_newest)); } if (i_newest > range.End) { msg.IndexRanges.Add(Math.Max(range.Endi, i_oldest)); msg.IndexRanges.Add(i_newest); } } else { msg.IndexRanges.Add(i_oldest); msg.IndexRanges.Add(i_newest); } // Request if ranges needed if (msg.IndexRanges.Count != 0) { Model.Post(msg); } }
/// <summary>Handle the hello message</summary> private void HandleMsg(OutMsg.RequestInstrumentHistory msg) { }
/// <summary> /// Request candle data for a time range. /// 'diff_cache' means only request time ranges that appear missing in the local instrument cache db</summary> public void RequestTimeRange(DateTimeOffset t0, DateTimeOffset t1, bool diff_cache) { // The request message var msg = new OutMsg.RequestInstrumentHistory(SymbolCode, TimeFrame); // If the DB is currently empty, request the whole range if (!diff_cache || Count == 0) { msg.TimeRanges.Add(t0.Ticks); msg.TimeRanges.Add(t1.Ticks); } // Otherwise, request time ranges that are missing from the DB else { var time_ranges = new List <Range>(); // One time frame unit var one = Misc.TimeFrameToTicks(1.0, TimeFrame); var ts = "[" + nameof(Candle.Timestamp) + "]"; // If the oldest candle in the DB is newer than 't0', request from t0 to Oldest if (Oldest.TimestampUTC > t0) { Debug.Assert(!Equals(Oldest, Candle.Default)); time_ranges.Add(new Range(t0.Ticks, Oldest.Timestamp)); } // Scan the DB for time ranges of missing data. var sql = Str.Build( // Returns pairs of timestamps that are the ranges of missing data. $"select {ts} from {TimeFrame} where {ts} >= ? and {ts} <= ? and {ts}+? not in (select {ts} from {TimeFrame}) union all ", $"select {ts} from {TimeFrame} where {ts} >= ? and {ts} <= ? and {ts}-? not in (select {ts} from {TimeFrame}) ", $"order by {ts}"); var args = new object[] { t0.Ticks, t1.Ticks, one, t0.Ticks, t1.Ticks, one, }; // Note: ignore the first and last because they are the implicit ranges -inf to first, and last -> +inf foreach (var hole in m_db.EnumRows <long>(sql, 1, args).Skip(1).TakeAllBut(1).InPairs()) { time_ranges.Add(new Range(hole.Item1, hole.Item2)); } // If the newest candle in the DB is older than 't1', request from Latest to t1 if (Latest.TimestampUTC < t1) { Debug.Assert(!Equals(Latest, Candle.Default)); time_ranges.Add(new Range(Latest.Timestamp, t1.Ticks)); } // Exclude the known forex non trading hours foreach (var time_range in time_ranges) { foreach (var hole in Model.Sessions.ClipToTradingHours(time_range)) { Debug.Assert(hole.Size != 0); msg.TimeRanges.Add(hole.Beg); msg.TimeRanges.Add(hole.End); } } } // Post the request Model.Post(msg); }