public virtual void Append(IQuoteCapture q) { if (q == null || q.Count <= 0 || this.Symbol != q.Symbol) { return; } var sindex = q.Count - 1; while (sindex >= 0 && q.Time[sindex] > this.LastTime) { --sindex; } if (sindex == -1) { this.Time.AddRange(q.Time); this.Price.AddRange(q.Price); this.Volume.AddRange(q.Volume); } else if (sindex < q.Count - 1) { ++sindex; this.Time.AddRange(q.Time.GetRange(sindex, q.Count - sindex)); this.Price.AddRange(q.Price.GetRange(sindex, q.Count - sindex)); this.Volume.AddRange(q.Volume.GetRange(sindex, q.Count - sindex)); } }
private void Create(IQuoteCapture q) { if (q != null) { this.Create(q.Symbol, q.PipFactor, q.Time, q.Price, q.Volume); } }
static public IQuoteCapture Uncompress(IQuoteCapture qc) { if (qc == null) { throw new ArgumentNullException(); } IQuoteCapture result = new QuoteCapture(qc.Symbol); if (qc.Count == 0) { return(result); } //qc中至少有1个数据 bool isSegment = false; result.Add(qc.FirstTime, qc.Price[0]); //true则认为此时在处理分段 每处理完一次分段时置为false isSegment = true; for (var i = 1; i < qc.Count; ++i) {// //通常NO_USED_PRICE不会被使用 if (qc.Price[i] == NO_USED_PRICE && isSegment) {//这是重复数据 要展开 var endTime = qc.Time[i]; var endPrice = qc.Price[i]; var startTime = qc.Time[i - 1]; var startPrice = qc.Price[i - 1]; var j = startTime + MIN_INTERVAL; //用startPrice生成start到end之间的数据 while (j < endTime) { result.Add(j, startPrice); j += MIN_INTERVAL; } //生成end数据(endtime 大则代表是正确的分段 小则意味不正确的分段 插入原来的数据 result.Add(endTime, endTime > startTime ? startPrice : endPrice); //分段解压缩结束 isSegment = false; } else//非重复数据或者数据起始点 直接插入 { result.Add(qc.Time[i], qc.Price[i]); isSegment = true; } } return(result); }
static public IQuoteCapture Compress(IQuoteCapture qc) { if (qc == null) { throw new ArgumentNullException(); } IQuoteCapture result = new QuoteCapture(qc.Symbol); if (qc.Count == 0) { return(result); } //此时qc有值 先插入一个数据 result.Add(qc.Time[0], qc.Price[0]); bool tail = false; for (int i = 1; i < qc.Count; i++) { var time = qc.Time[i]; var price = qc.Price[i]; var lastTime = qc.Time[i - 1]; var lastPrice = qc.Price[i - 1]; if (time - lastTime == MIN_INTERVAL && price == lastPrice) {//价格重复且时间递增那么该数据可以压缩 tail = true; } else {//本次数据不能被压缩那么把该数据当作分段新的起始点 //添加上一个分段的末尾如果分段数据只有1个那么不需要添加结尾 //[start: price, start+1:price,..., end:price]=>[start : price, end:-1] if (tail) { result.Add(lastTime, NO_USED_PRICE); } //分段新的起始点 result.Add(time, price); tail = false; } } //可能qc末尾是个分段但是此时还没能添加分段尾 if (tail) { result.Add(qc.Time.Last(), NO_USED_PRICE); } return(result); }
private int AddItemByQuoteCapture(IQuoteCapture q, int sindex, int eindex) { var len = eindex - sindex + 1; var price = q.Price.GetRange(sindex, len); var volumnList = q.Volume.GetRange(sindex, len); var time = q.Time[sindex] / this.Interval * this.Interval; var open = this.Count > 0 ? this.Close.Last() : q.Price[sindex]; var close = q.Price[eindex]; var high = price.Max(); var low = price.Min(); var volumn = volumnList.Sum(); return(this.AddUpdate(time, open, high, low, close, volumn)); //add the data }
public void AddQuoteCapture(IQuoteCapture qc, bool isTriggerEvent) { lock (this) { var interval = this.Intervals[0]; var quoteId = this.CreateQuote(qc.Symbol, interval); var num = Quotes[quoteId].Append(qc, false); if (num >= 0) { var d = this.AddToOtherQuotes(Quotes[quoteId], 1, isTriggerEvent); //QuoteStore_OnDataAddedOrUpdated(this, this.Quotes[quoteId], num); //foreach (var id in d.Keys) QuoteStore_OnDataAddedOrUpdated(this, this.Quotes[id], d[id]); } } }
public void TestAppend() { IQuoteCapture qc = null; // 测试null _quoteCapture.Append(qc); Assert.AreEqual(0, _quoteCapture.Count); // 测试空 qc = new QuoteCapture(); _quoteCapture.Append(qc); Assert.AreEqual(0, _quoteCapture.Count); // 测试不同的symbol qc = new QuoteCapture("symbol1"); qc.Add(10, 20, 30); _quoteCapture.Append(qc); Assert.AreEqual(0, _quoteCapture.Count); // 测试_quoteCapter.LastTime < qc.LastTime qc = new QuoteCapture("symbol0"); _quoteCapture.Add(10, 20, 15); qc.Add(5, 20); _quoteCapture.Append(qc); Assert.AreEqual(1, _quoteCapture.Count); Assert.AreEqual(10, _quoteCapture.Time[0]); Assert.AreEqual(20, _quoteCapture.Price[0]); Assert.AreEqual(15, _quoteCapture.Volume[0]); // 测试不添加小于LastTime的数据 qc.Add(10, 18, 18); qc.Add(20, 30, 17); _quoteCapture.Append(qc); Assert.AreEqual(2, _quoteCapture.Count); Assert.AreEqual(10, _quoteCapture.Time[0]); Assert.AreEqual(20, _quoteCapture.Time[1]); Assert.AreEqual(20, _quoteCapture.Price[0]); Assert.AreEqual(30, _quoteCapture.Price[1]); Assert.AreEqual(15, _quoteCapture.Volume[0]); Assert.AreEqual(17, _quoteCapture.Volume[1]); }
public void TestExtract_LongLong() { _quoteCapture.Add(100, 10, 21); _quoteCapture.Add(200, 20, 22); _quoteCapture.Add(300, 30, 23); _quoteCapture.Add(400, 40, 24); _quoteCapture.Add(500, 50, 26); IQuoteCapture qc = _quoteCapture.Extract(150L, 350L); Assert.AreEqual(2, qc.Count); Assert.AreEqual(200, qc.Time[0]); Assert.AreEqual(300, qc.Time[1]); Assert.AreEqual(20, qc.Price[0]); Assert.AreEqual(30, qc.Price[1]); Assert.AreEqual(30, qc.Price[1]); Assert.AreEqual(22, qc.Volume[0]); Assert.AreEqual(23, qc.Volume[1]); qc = _quoteCapture.Extract(10L, 110L); Assert.AreEqual(1, qc.Count); Assert.AreEqual(100, qc.Time[0]); qc = _quoteCapture.Extract(10L, 20L); Assert.AreEqual(0, qc.Count); qc = _quoteCapture.Extract(600L, 900L); Assert.AreEqual(0, qc.Count); qc = _quoteCapture.Extract(0L, 900L); Assert.AreEqual(5, qc.Count); _quoteCapture.Clear(); _quoteCapture.Add(100, 10); qc = _quoteCapture.Extract(80L, 110L); Assert.AreEqual(1, qc.Count); }
public void TestExtract_IntInt() { IQuoteCapture qc = null; // 测试sindex > eindex TestHelper.AssertException(() => _quoteCapture.Extract(1, 0), typeof(ArgumentException)); // 测试sindex < 0 TestHelper.AssertException(() => _quoteCapture.Extract(-1, 0), typeof(ArgumentException)); // 测试eindex < 0 TestHelper.AssertException(() => _quoteCapture.Extract(0, -1), typeof(ArgumentException)); // 测试eindex > _quoteCapture.Count - 1; _quoteCapture.Add(10, 12); TestHelper.AssertException(() => _quoteCapture.Extract(0, 5), typeof(ArgumentException)); _quoteCapture = new QuoteCapture("xyz"); _quoteCapture.Add(100, 10, 23); _quoteCapture.Add(200, 20, 24); _quoteCapture.Add(300, 30, 26); _quoteCapture.Add(400, 40, 27); _quoteCapture.Add(500, 50, 28); qc = _quoteCapture.Extract(1, 3); Assert.AreEqual(3, qc.Count); Assert.AreEqual(200, qc.Time[0]); Assert.AreEqual(300, qc.Time[1]); Assert.AreEqual(400, qc.Time[2]); Assert.AreEqual(20, qc.Price[0]); Assert.AreEqual(30, qc.Price[1]); Assert.AreEqual(40, qc.Price[2]); Assert.AreEqual(24, qc.Volume[0]); Assert.AreEqual(26, qc.Volume[1]); Assert.AreEqual(27, qc.Volume[2]); }
public void Assign(IQuoteCapture q) { this.Create(q); }
public QuoteCapture(IQuoteCapture q) { Create(q); }
private async void _qcStore_OnQuoteCaptureDataAdded(object sender, string exchange, IQuoteCapture quote, int numAppended) { try { var symbol = quote.Symbol; if (_symbolsInitialized.Contains(symbol)) { _qbStore.AddQuoteCapture(quote, true); } else //initialize IQuoteBasicBase { this.InitQuoteBasic(symbol); } } catch (Exception ex) { OnExceptionOccured?.Invoke(this, this.Exchange, ex); } }
public int Append(IQuoteCapture q, bool isTriggerDataUpdated = false) { if (q == null || q.Count <= 0 || q.LastTime <= this.LastTime || this.Symbol != q.Symbol) { return(0); } //search backward for the quotes. the found time should be >= lastTime int indexStartSearch = -1; for (int i = q.Count - 1; i >= 0; i--) { if (q.Time[i] < this.LastTime) //for basic quote we include price at previous interval for calculation { break; } indexStartSearch = i; } if (indexStartSearch == -1) { return(0); } //////////////////////////////////////////////////////////////////////////// var isDataChanged = false; var numAddedElement = 0; int sindex = indexStartSearch; // interval区间的开始索引 var eindex = -1; var endTime = q.Time[sindex] / this.Interval * this.Interval + this.Interval; //use the first time as the data bar time for (int i = indexStartSearch; i <= q.Count - 1; i++) { if (q.Time[i] >= endTime) { eindex = i - 1; // interval区间的结束索引 var num = this.AddItemByQuoteCapture(q, sindex, eindex); if (num >= 0) { numAddedElement += num; isDataChanged = true; } sindex = i; endTime = q.Time[sindex] / this.Interval * this.Interval + this.Interval; } } //add last element if (sindex > eindex) { var num = this.AddItemByQuoteCapture(q, sindex, q.Count - 1); if (num >= 0) { numAddedElement += num; isDataChanged = true; } } if (isTriggerDataUpdated && isDataChanged) { OnDataAddedOrUpdated?.Invoke(this, this, numAddedElement); } return(isDataChanged ? numAddedElement : -1); //-1 means nothing changed, 0 means updated, >=1 means added }