private IEnumerable <MessageBuffer <T> > GetFormedBuffers(T msg, DateTimeOffset openTime, SecurityId secId) { var buffers = new List <MessageBuffer <T> >(); lock (_buffers.SyncRoot) { var buffer = _buffers.SafeAdd(openTime, key => new MessageBuffer <T>(openTime, _bufferSize)); buffer.AddMessage(_securityIndecies[secId], msg); if (!buffer.IsFilled) { return(Enumerable.Empty <MessageBuffer <T> >()); } // mika // далее идет обработка 4-рех ситуаций // // 1. первая свеча оказалась заполненой полностью, и мы просто удаляем начальные буфера // так как они уже никогда не заполняться. // // 2. первая свеча оказалось размазанной, тогда так же удаляем хвосты, но при этом формируем // из одной размазанной свечи N (= равное кол-ву инструментов) дозаполненных. // // 3. появилась заполненная полностью свеча, и тогда дозаполняем промежутки с _lastProcessBuffer // // 4. появилась размазанная свеча, и тогда дозаполняем промежутки с _lastProcessBuffer + формируем // из одной размазанной свечи N (= равное кол-ву инструментов) дозаполненных. var firstTimeBuffer = _lastProcessBuffer == null; // последней буфер, до которого (включительно) можно сформировать спред по текущим данным var lastBuffer = buffer; var deleteKeys = new List <DateTimeOffset>(); foreach (var time in _buffers.CachedKeys) { if (time >= lastBuffer.Time) { break; } var curr = _buffers[time]; if (firstTimeBuffer) { if (!buffer.IsFilled) { if (_lastProcessBuffer == null) { _lastProcessBuffer = curr; } else { _lastProcessBuffer.Fill(curr); _lastProcessBuffer = curr; } } } else { curr.Fill(_lastProcessBuffer); _lastProcessBuffer = curr; if (curr.IsFilled) { buffers.Add(curr); } } deleteKeys.Add(time); } if (!buffer.IsFilled) { lastBuffer.Fill(_lastProcessBuffer); } if (lastBuffer.IsFilled) { deleteKeys.Add(lastBuffer.Time); _lastProcessBuffer = lastBuffer; buffers.Add(lastBuffer); } deleteKeys.ForEach(k => _buffers.Remove(k)); } return(buffers); }
private IEnumerable <CandleBuffer> GetFormedBuffers(Candle candle) { var buffers = new List <CandleBuffer>(); lock (_buffers.SyncRoot) { var buffer = _buffers.SafeAdd(candle.OpenTime, key => new CandleBuffer(candle.OpenTime, candle.CloseTime, _bufferSize, false)); buffer.AddCandle(_securityIndecies[candle.Security], candle); if (!buffer.IsFilled) { return(Enumerable.Empty <CandleBuffer>()); // mika // заполняем "размазанные" буфера, чтобы определить, что первее наступит, // заполнится ли полностью одна из свечек, // или мы сможем достроить спред из "размазанных" буферов // TODO пока убрал, нужно больше тестов if (_sparseBuffer1 == null) { _sparseBuffer1 = new CandleBuffer(candle.OpenTime, candle.CloseTime, _bufferSize, true); } if (!_sparseBuffer1.IsFilled) { _sparseBuffer1.AddCandle(_securityIndecies[candle.Security], candle); } else { if (_sparseBuffer2 == null) { _sparseBuffer2 = new CandleBuffer(candle.OpenTime, candle.CloseTime, _bufferSize, true); } _sparseBuffer2.AddCandle(_securityIndecies[candle.Security], candle); // если первая свеча будет построена по размазанному буферу, то разница между временем эти буферов // должна гарантировать, что между ними //if (_lastProcessBuffer == null && _sparseBuffer2.IsFilled && (_sparseBuffer1.CloseTime > _sparseBuffer2.OpenTime)) // return Enumerable.Empty<CandleBuffer>(); } if (_sparseBuffer2 == null || !_sparseBuffer2.IsFilled) { return(Enumerable.Empty <CandleBuffer>()); } } // mika // далее идет обработка 4-рех ситуаций // // 1. первая свеча оказалась заполненой полностью, и мы просто удаляем начальные буфера // так как они уже никогда не заполняться. // // 2. первая свеча оказалось размазанной, тогда так же удаляем хвосты, но при этом формируем // из одной размазанной свечи N (= равное кол-ву инструментов) дозаполненных. // // 3. появилась заполненная полностью свеча, и тогда дозаполняем промежутки с _lastProcessBuffer // // 4. появилась размазанная свеча, и тогда дозаполняем промежутки с _lastProcessBuffer + формируем // из одной размазанной свечи N (= равное кол-ву инструментов) дозаполненных. var firstTimeBuffer = _lastProcessBuffer == null; // последней буфер, до которого (включительно) можно сформировать спред по текущим данным var lastBuffer = buffer.IsFilled ? buffer : _buffers[_sparseBuffer2.OpenTime]; var deleteKeys = new List <DateTimeOffset>(); foreach (var time in _buffers.CachedKeys) { if (time >= lastBuffer.OpenTime) { break; } var curr = _buffers[time]; if (firstTimeBuffer) { if (!buffer.IsFilled) { if (_lastProcessBuffer == null) { _lastProcessBuffer = curr; } else { _lastProcessBuffer.Fill(curr); _lastProcessBuffer = curr; } } } else { curr.Fill(_lastProcessBuffer); if (!curr.IsFilled) { throw new InvalidOperationException(LocalizedStrings.Str655); } _lastProcessBuffer = curr; buffers.Add(curr); } deleteKeys.Add(time); } if (!buffer.IsFilled) { lastBuffer.Fill(_lastProcessBuffer); } if (!lastBuffer.IsFilled) { throw new InvalidOperationException(LocalizedStrings.Str656); } deleteKeys.Add(lastBuffer.OpenTime); _lastProcessBuffer = lastBuffer; buffers.Add(lastBuffer); _sparseBuffer1 = _sparseBuffer2; _sparseBuffer2 = null; deleteKeys.ForEach(k => _buffers.Remove(k)); } return(buffers); }