private void SessionOnStil2Reply(ref Array arrayL2Update) { var asksUpdate = new List <QuoteChange>(); var bidsUpdate = new List <QuoteChange>(); foreach (structSTIL2Update structL2Update in arrayL2Update) { switch (structL2Update.bstrSide.ToSide()) { case Sides.Buy: { bidsUpdate.Add(new QuoteChange(structL2Update.bstrSide.ToSide(), (decimal)structL2Update.fPrice, structL2Update.nQty) { BoardCode = structL2Update.bstrMaker }); break; } case Sides.Sell: { asksUpdate.Add(new QuoteChange(structL2Update.bstrSide.ToSide(), (decimal)structL2Update.fPrice, structL2Update.nQty) { BoardCode = structL2Update.bstrMaker }); break; } } } var quote = (structSTIL2Update)arrayL2Update.GetValue(0); if (_depths.ContainsKey(quote.bstrSymbol)) { _depths.Remove(quote.bstrSymbol); } _depths.Add(quote.bstrSymbol, new Tuple <List <QuoteChange>, List <QuoteChange> >(asksUpdate, bidsUpdate)); var message = new QuoteChangeMessage { SecurityId = new SecurityId { SecurityCode = quote.bstrSymbol, BoardCode = AssociatedBoardCode, }, Asks = asksUpdate, Bids = bidsUpdate, ServerTime = quote.bstrTime.StrToTime(), }; SendOutMessage(message); }
/// <summary> /// Initializes a new instance of the <see cref="DepthCandleBuilderSourceValue"/>. /// </summary> /// <param name="message">Messages containing quotes.</param> /// <param name="type">Type of candle depth based data.</param> public QuoteCandleBuilderSourceValue(QuoteChangeMessage message, DepthCandleSourceTypes type) { QuoteChange = message; Type = type; switch (Type) { case DepthCandleSourceTypes.BestBid: { var bid = message.GetBestBid(); if (bid != null) { _price = bid.Price; _volume = bid.Volume; } break; } case DepthCandleSourceTypes.BestAsk: { var ask = message.GetBestAsk(); if (ask != null) { _price = ask.Price; _volume = ask.Volume; } break; } case DepthCandleSourceTypes.Middle: { var bid = message.GetBestBid(); var ask = message.GetBestAsk(); if (bid != null && ask != null) { _price = (ask.Price + bid.Price) / 2; //_volume = pair.Bid.Volume; } break; } default: throw new ArgumentOutOfRangeException(); } }
/// <summary> /// Initializes a new instance of the <see cref="TimeQuoteChange"/>. /// </summary> /// <param name="side">Direction (buy or sell).</param> /// <param name="quote">The quote, from which changes will be copied.</param> /// <param name="message">The message with quotes.</param> public TimeQuoteChange(Sides side, QuoteChange quote, QuoteChangeMessage message) { if (message is null) { throw new ArgumentNullException(nameof(message)); } SecurityId = message.SecurityId; ServerTime = message.ServerTime; LocalTime = message.LocalTime; Quote = quote; Side = side; }
public NullableTimeQuoteChange(QuoteChange quote, QuoteChangeMessage message) { if (quote == null) { throw new ArgumentNullException(nameof(quote)); } ServerTime = message.ServerTime; LocalTime = message.LocalTime; Price = quote.Price; Volume = quote.Volume; Side = quote.Side; }
private void SessionOnStil2Update(ref structSTIL2Update structL2Update) { var depth = _depths[structL2Update.bstrSymbol]; var quote = new QuoteChange(structL2Update.bstrSide.ToSide(), (decimal)structL2Update.fPrice, structL2Update.nQty); var quotes = quote.Side == Sides.Sell ? depth.Item1 : depth.Item2; switch (structL2Update.bstrAction) { case "A": // add { quotes.Add(quote); break; } case "C": // change { quotes.RemoveWhere(q => q.Price == quote.Price && q.BoardCode == quote.BoardCode); quotes.Add(quote); break; } case "D": // delete { quotes.RemoveWhere(q => q.Price == quote.Price && q.BoardCode == quote.BoardCode); break; } } var board = structL2Update.bstrMaker; if (board.IsEmpty()) { board = AssociatedBoardCode; } var message = new QuoteChangeMessage { SecurityId = new SecurityId { SecurityCode = structL2Update.bstrSymbol, BoardCode = board, }, Asks = depth.Item1.ToArray(), Bids = depth.Item2.ToArray(), ServerTime = structL2Update.bstrTime.StrToTime(), }; SendOutMessage(message); }
/// <summary> /// Создать <see cref="TimeQuoteChange"/>. /// </summary> /// <param name="quote">Котировка, из которой будут скопированы изменения.</param> /// <param name="message">Сообщение с котировками.</param> public TimeQuoteChange(QuoteChange quote, QuoteChangeMessage message) { if (quote == null) { throw new ArgumentNullException("quote"); } SecurityId = message.SecurityId; ServerTime = message.ServerTime; LocalTime = message.LocalTime; Price = quote.Price; Volume = quote.Volume; Side = quote.Side; }
public NullableTimeQuoteChange(Sides side, QuoteChange quote, QuoteChangeMessage message) { if (quote == null) { throw new ArgumentNullException(nameof(quote)); } ServerTime = message.ServerTime; LocalTime = message.LocalTime; Price = quote.Price; Volume = quote.Volume; Side = side; OrdersCount = quote.OrdersCount; Condition = quote.Condition; }
private static string QuotesToString(QuoteChangeMessage quotes) { var sb = new StringBuilder(); foreach (var quote in quotes.Bids) { sb.Append($"Bid:{quote.Price}:{quote.Volume};"); } foreach (var quote in quotes.Asks) { sb.Append($"Ask:{quote.Price}:{quote.Volume};"); } return($"{quotes.ServerTime};{quotes.SecurityId.SecurityCode};{sb}"); }
/// <summary> /// Обновить стакан. /// </summary> /// <param name="message">Стакан.</param> public void UpdateDepth(QuoteChangeMessage message) { if (message == null) { throw new ArgumentNullException("message"); } var clone = new QuoteChangeMessage { Bids = message.Bids, Asks = message.Asks, IsSorted = message.IsSorted, }; lock (_lastDepthSync) _lastQuoteMsg = clone; }
public QuoteChangeMessage Process(QuoteChangeMessage message) { if (message == null) { throw new ArgumentNullException(nameof(message)); } return(new QuoteChangeMessage { SecurityId = message.SecurityId, ServerTime = message.ServerTime, LocalTime = message.LocalTime, IsSorted = message.IsSorted, IsByLevel1 = message.IsByLevel1, IsFiltered = true, Bids = Filter(message.Bids), Asks = Filter(message.Asks), }); }
private void CreateAssociatedSecurityQuotes(QuoteChangeMessage quoteMsg) { if (!CreateAssociatedSecurity) return; if (quoteMsg.SecurityId.IsDefault()) return; if (IsAssociated(quoteMsg.SecurityId.BoardCode)) return; var builder = _quoteChangeDepthBuilders .SafeAdd(quoteMsg.SecurityId.SecurityCode, c => new QuoteChangeDepthBuilder(c, AssociatedBoardCode)); quoteMsg = builder.Process(quoteMsg); var security = LookupSecurity(quoteMsg.SecurityId); ProcessQuotesMessage(security, quoteMsg, false); }
private static string QuotesToString(QuoteChangeMessage quotes) { var sb = new StringBuilder(); foreach (var quote in quotes.Bids) { sb.Append(string.Format("Bid:{0}:{1};", quote.Price, quote.Volume)); } foreach (var quote in quotes.Asks) { sb.Append(string.Format("Ask:{0}:{1};", quote.Price, quote.Volume)); } return(string.Format("{0};{1};{2}", quotes.ServerTime, quotes.SecurityId.SecurityCode, sb )); }
public QuoteChangeMessage Process(QuoteChangeMessage message) { if (message is null) { throw new ArgumentNullException(nameof(message)); } return(new QuoteChangeMessage { SecurityId = message.SecurityId, ServerTime = message.ServerTime, LocalTime = message.LocalTime, IsSorted = message.IsSorted, BuildFrom = message.BuildFrom, Currency = message.Currency, IsFiltered = true, Bids = Filter(Sides.Buy, message.Bids), Asks = Filter(Sides.Sell, message.Asks), }); }
public QuoteChangeMessage Process(QuoteChangeMessage message) { _feeds[message.SecurityId] = message; var bids = _feeds.SelectMany(f => f.Value.Bids).ToArray(); var asks = _feeds.SelectMany(f => f.Value.Asks).ToArray(); return(new QuoteChangeMessage { SecurityId = new SecurityId { SecurityCode = _securityCode, BoardCode = _boardCode }, ServerTime = message.ServerTime, LocalTime = message.LocalTime, Bids = bids, Asks = asks }); }
/// <summary> /// To convert quotes. /// </summary> /// <param name="message">Quotes.</param> /// <returns>Stream <see cref="ExecutionMessage"/>.</returns> public IEnumerable <ExecutionMessage> ToExecutionLog(QuoteChangeMessage message) { if (message == null) { throw new ArgumentNullException(nameof(message)); } if (!_priceStepUpdated || !_volumeStepUpdated) { var quote = message.GetBestBid() ?? message.GetBestAsk(); if (quote != null) { if (!_priceStepUpdated) { _securityDefinition.PriceStep = quote.Price.GetDecimalInfo().EffectiveScale.GetPriceStep(); _priceStepUpdated = true; } if (!_volumeStepUpdated) { _securityDefinition.VolumeStep = quote.Volume.GetDecimalInfo().EffectiveScale.GetPriceStep(); _volumeStepUpdated = true; } } } _lastDepthDate = message.LocalTime.Date; // чтобы склонировать внутренние котировки //message = message.TypedClone(); // TODO для ускорения идет shallow copy котировок var newBids = message.IsSorted ? (IEnumerable <QuoteChange>)message.Bids : message.Bids.OrderByDescending(q => q.Price); var newAsks = message.IsSorted ? (IEnumerable <QuoteChange>)message.Asks : message.Asks.OrderBy(q => q.Price); return(ProcessQuoteChange(message.LocalTime, message.ServerTime, newBids.ToArray(), newAsks.ToArray())); }
/// <inheritdoc /> protected override void OnInnerAdapterNewOutMessage(Message message) { switch (message.Type) { case MessageTypes.SubscriptionResponse: { var responseMsg = (SubscriptionResponseMessage)message; if (!_infos.TryGetValue(responseMsg.OriginalTransactionId, out var info)) { break; } if (responseMsg.Error == null) { info.State = SubscriptionStates.Active; } else { info.State = SubscriptionStates.Error; _infos.Remove(responseMsg.OriginalTransactionId); _infosBySecId.TryGetValue(info.Origin.SecurityId)?.Remove(responseMsg.OriginalTransactionId); } break; } case MessageTypes.SubscriptionFinished: { var finishMsg = (SubscriptionFinishedMessage)message; if (_infos.TryGetAndRemove(finishMsg.OriginalTransactionId, out var info)) { info.State = SubscriptionStates.Finished; _infosBySecId.TryGetValue(info.Origin.SecurityId)?.Remove(finishMsg.OriginalTransactionId); } break; } case MessageTypes.SubscriptionOnline: { var onlineMsg = (SubscriptionOnlineMessage)message; if (_infos.TryGetValue(onlineMsg.OriginalTransactionId, out var info)) { info.State = SubscriptionStates.Online; } break; } case MessageTypes.QuoteChange: { if (_infos.Count == 0) { break; } var quoteMsg = (QuoteChangeMessage)message; var ids = quoteMsg.GetSubscriptionIds(); var set = new HashSet <long>(quoteMsg.GetSubscriptionIds()); QuoteChangeMessage filtered = null; foreach (var id in ids) { if (_infos.TryGetValue(id, out var info) && info.State.IsActive()) { var newIds = _infosBySecId[info.Origin.SecurityId].Cache; filtered = info.Process(quoteMsg); filtered.SetSubscriptionIds(newIds); set.RemoveRange(newIds); break; } } if (set.Count > 0) { quoteMsg.SetSubscriptionIds(set.ToArray()); } else { // subscription for origin book was initialized only by filtered book message = null; } if (filtered != null) { base.OnInnerAdapterNewOutMessage(filtered); } break; } case MessageTypes.Execution: { if (_infosBySecId.Count == 0 || _infos.Count == 0) { break; } var execMsg = (ExecutionMessage)message; if ( execMsg.ExecutionType != ExecutionTypes.Transaction || !execMsg.HasOrderInfo() || execMsg.OrderPrice == 0 || // ignore market orders execMsg.OriginalTransactionId == 0 // ignore unknown orders ) { break; } if (execMsg.OrderState == OrderStates.Active || execMsg.OrderState == OrderStates.Done) { if (!_infosBySecId.TryGetValue(execMsg.SecurityId, out var set)) { break; } foreach (var id in set.Cache) { _infos.TryGetValue(id)?.Process(execMsg); } } break; } } if (message != null) { base.OnInnerAdapterNewOutMessage(message); } }
/// <summary> /// Try create full book. /// </summary> /// <param name="change">Book change.</param> /// <param name="subscriptionId">Subscription.</param> /// <returns>Full book.</returns> public QuoteChangeMessage TryApply(QuoteChangeMessage change, long subscriptionId = default) { if (change is null) { throw new ArgumentNullException(nameof(change)); } if (change.State is null) { throw new ArgumentException(nameof(change)); } var currState = _state; var newState = change.State.Value; void WriteWarning() { var postfix = string.Empty; if (subscriptionId != default) { if (!_invalidSubscriptions.Add(subscriptionId)) { return; } postfix = $" (sub={subscriptionId})"; } this.AddWarningLog($"{currState}->{newState}{postfix}"); } bool CheckSwitch() { switch (currState) { case _none: case QuoteChangeStates.SnapshotStarted: { if (newState != QuoteChangeStates.SnapshotBuilding && newState != QuoteChangeStates.SnapshotComplete) { WriteWarning(); return(false); } break; } case QuoteChangeStates.SnapshotBuilding: { if (newState != QuoteChangeStates.SnapshotBuilding && newState != QuoteChangeStates.SnapshotComplete) { WriteWarning(); return(false); } break; } case QuoteChangeStates.SnapshotComplete: case QuoteChangeStates.Increment: { if (newState == QuoteChangeStates.SnapshotBuilding) { WriteWarning(); return(false); } break; } } return(true); } var resetState = newState == QuoteChangeStates.SnapshotStarted || newState == QuoteChangeStates.SnapshotComplete; if (currState != newState || resetState) { if (!CheckSwitch()) { return(null); } if (currState == _none || resetState) { _bids.Clear(); _asks.Clear(); _bidsByPos.Clear(); _asksByPos.Clear(); } _state = currState = newState; }
private void ProcessQuotesMessage(Security security, QuoteChangeMessage message, bool fromLevel1) { if (MarketDepthChanged != null || MarketDepthsChanged != null) { var marketDepth = GetMarketDepth(security); message.ToMarketDepth(marketDepth, GetSecurity); if (_subscriptionManager.IsFilteredMarketDepthRegistered(security)) GetFilteredMarketDepthInfo(security).Process(message); RaiseMarketDepthChanged(marketDepth); } else { lock (_marketDepths.SyncRoot) { var info = _marketDepths.SafeAdd(security, key => new MarketDepthInfo(EntityFactory.CreateMarketDepth(security))); info.First.LocalTime = message.LocalTime; info.First.LastChangeTime = message.ServerTime; info.Second = message.Bids; info.Third = message.Asks; } } var bestBid = message.GetBestBid(); var bestAsk = message.GetBestAsk(); if (!fromLevel1 && (bestBid != null || bestAsk != null)) { var values = GetSecurityValues(security); var changes = new List<KeyValuePair<Level1Fields, object>>(4); lock (values.SyncRoot) { if (bestBid != null) { values[(int)Level1Fields.BestBidPrice] = bestBid.Price; changes.Add(new KeyValuePair<Level1Fields, object>(Level1Fields.BestBidPrice, bestBid.Price)); if (bestBid.Volume != 0) { values[(int)Level1Fields.BestBidVolume] = bestBid.Volume; changes.Add(new KeyValuePair<Level1Fields, object>(Level1Fields.BestBidVolume, bestBid.Volume)); } } if (bestAsk != null) { values[(int)Level1Fields.BestAskPrice] = bestAsk.Price; changes.Add(new KeyValuePair<Level1Fields, object>(Level1Fields.BestAskPrice, bestAsk.Price)); if (bestAsk.Volume != 0) { values[(int)Level1Fields.BestAskVolume] = bestAsk.Volume; changes.Add(new KeyValuePair<Level1Fields, object>(Level1Fields.BestAskVolume, bestAsk.Volume)); } } } RaiseValuesChanged(security, changes, message.ServerTime, message.LocalTime); } if (UpdateSecurityLastQuotes) { var updated = false; if (!fromLevel1 || bestBid != null) { updated = true; security.BestBid = bestBid == null ? null : new Quote(security, bestBid.Price, bestBid.Volume, Sides.Buy); } if (!fromLevel1 || bestAsk != null) { updated = true; security.BestAsk = bestAsk == null ? null : new Quote(security, bestAsk.Price, bestAsk.Volume, Sides.Sell); } if (updated) { security.LocalTime = message.LocalTime; security.LastChangeTime = message.ServerTime; RaiseSecurityChanged(security); // стаканы по ALL обновляют BestXXX по конкретным инструментам if (security.Board.Code == AssociatedBoardCode) { var changedSecurities = new Dictionary<Security, RefPair<bool, bool>>(); foreach (var bid in message.Bids) { if (bid.BoardCode.IsEmpty()) continue; var innerSecurity = GetSecurity(new SecurityId { SecurityCode = security.Code, BoardCode = bid.BoardCode }); var info = changedSecurities.SafeAdd(innerSecurity); if (info.First) continue; info.First = true; innerSecurity.BestBid = new Quote(innerSecurity, bid.Price, bid.Volume, Sides.Buy); innerSecurity.LocalTime = message.LocalTime; innerSecurity.LastChangeTime = message.ServerTime; } foreach (var ask in message.Asks) { if (ask.BoardCode.IsEmpty()) continue; var innerSecurity = GetSecurity(new SecurityId { SecurityCode = security.Code, BoardCode = ask.BoardCode }); var info = changedSecurities.SafeAdd(innerSecurity); if (info.Second) continue; info.Second = true; innerSecurity.BestAsk = new Quote(innerSecurity, ask.Price, ask.Volume, Sides.Sell); innerSecurity.LocalTime = message.LocalTime; innerSecurity.LastChangeTime = message.ServerTime; } RaiseSecuritiesChanged(changedSecurities.Keys.ToArray()); } } } if (CreateDepthFromLevel1) GetBuilder(message.SecurityId).HasDepth = true; CreateAssociatedSecurityQuotes(message); }
private void ProcessQuotesMessage(QuoteChangeMessage message, bool fromLevel1) { var security = LookupSecurity(message.SecurityId); ProcessQuotesMessage(security, message, fromLevel1); }
private void SessionOnStil2Update(ref structSTIL2Update structL2Update) { var asksUpdate = _depths[structL2Update.bstrSymbol].Item1; var bidsUpdate = _depths[structL2Update.bstrSymbol].Item2; var quote = new QuoteChange(structL2Update.bstrSide.ToSide(), (decimal)structL2Update.fPrice, structL2Update.nQty) { BoardCode = structL2Update.bstrMaker }; switch (structL2Update.bstrSide.ToSide()) { case Sides.Buy: { switch (structL2Update.bstrAction) { case "A": // add { bidsUpdate.Add(quote); break; } case "C": // change { bidsUpdate.RemoveWhere(q => q.Price == quote.Price && q.BoardCode == quote.BoardCode); bidsUpdate.Add(quote); break; } case "D": // delete { bidsUpdate.RemoveWhere(q => q.Price == quote.Price && q.BoardCode == quote.BoardCode); break; } } break; } case Sides.Sell: { switch (structL2Update.bstrAction) { case "A": // add { asksUpdate.Add(quote); break; } case "C": // change { asksUpdate.RemoveWhere(q => q.Price == quote.Price && q.BoardCode == quote.BoardCode); asksUpdate.Add(quote); break; } case "D": // delete { asksUpdate.RemoveWhere(q => q.Price == quote.Price && q.BoardCode == quote.BoardCode); break; } } break; } } var message = new QuoteChangeMessage { SecurityId = new SecurityId { SecurityCode = structL2Update.bstrSymbol, BoardCode = "All", }, Asks = asksUpdate, Bids = bidsUpdate, ServerTime = structL2Update.bstrTime.StrToTime(), }; SendOutMessage(message); }
/// <inheritdoc /> protected override bool OnSendInMessage(Message message) { switch (message.Type) { case MessageTypes.Reset: { lock (_syncObject) _infos.Clear(); break; } case MessageTypes.MarketData: { var mdMsg = (MarketDataMessage)message; if (mdMsg.DataType != MarketDataTypes.MarketDepth) { break; } var isFilteredMsg = mdMsg is FilteredMarketDepthMessage; var transId = mdMsg.TransactionId; if (mdMsg.IsSubscribe) { if (!isFilteredMsg) { break; } var data = (Tuple <QuoteChangeMessage, ExecutionMessage[]>)mdMsg.Arg; QuoteChangeMessage filtered = null; lock (_syncObject) { var info = _infos.SafeAdd(mdMsg.SecurityId, key => new FilteredMarketDepthInfo(transId, data.Item2)); info.Subscriptions.Add(transId); if (info.Subscriptions.Count == 1) { var clone = new MarketDataMessage(); mdMsg.CopyTo(clone); message = clone; filtered = info.Process(data.Item1); } } if (filtered == null) { RaiseNewOutMessage(new SubscriptionResponseMessage { OriginalTransactionId = transId }); return(true); } else { RaiseNewOutMessage(filtered); } } else { SubscriptionResponseMessage reply; lock (_syncObject) { var info = _infos.FirstOrDefault(p => p.Value.Subscriptions.Contains(mdMsg.OriginalTransactionId)).Value; if (info != null) { info.Subscriptions.Remove(mdMsg.OriginalTransactionId); if (info.Subscriptions.Count > 0) { reply = new SubscriptionResponseMessage { OriginalTransactionId = transId, }; } else { message = new MarketDataMessage { IsSubscribe = false, TransactionId = transId, OriginalTransactionId = info.TransactionId, }; break; } } else { if (!isFilteredMsg) { break; } reply = transId.CreateSubscriptionResponse(new InvalidOperationException(LocalizedStrings.SubscriptionNonExist.Put(mdMsg.OriginalTransactionId))); } } RaiseNewOutMessage(reply); return(true); } break; } } return(base.OnSendInMessage(message)); }
private void ConvertFile(string fileName, IStorageRegistry registry, StorageFormats format, ExchangeBoard board, string securityLike, Dictionary <SecurityId, IOrderLogMarketDepthBuilder> orderLog2OrderBookBuilders, int orderBookMaxDepth, TimeZoneInfo tz, TimeZoneInfo mz) { if (!_isStarted) { return; } var fileNameKey = format + "_" + fileName; if (_convertedFiles.Contains(fileNameKey)) { return; } _logManager.Application.AddInfoLog("Начата конвертация файла {0}.", fileName); var securitiesStrings = securityLike.Split(","); var data = new Dictionary <SecurityId, Tuple <List <QuoteChangeMessage>, List <ExecutionMessage>, List <Level1ChangeMessage>, List <ExecutionMessage> > >(); DateTimeOffset ToLocalDto(DateTime dt) => dt.ApplyTimeZone(tz); DateTimeOffset ToServerDto(DateTime dt) => dt.ApplyTimeZone(mz); using (var qr = QshReader.Open(fileName)) { var reader = qr; for (var i = 0; i < qr.StreamCount; i++) { var stream = (ISecurityStream)qr[i]; var securityId = GetSecurityId(stream.Security, board.Code); var priceStep = (decimal)stream.Security.Step; var lastTransactionId = 0L; var builder = orderLog2OrderBookBuilders?.SafeAdd(securityId, key => new PlazaOrderLogMarketDepthBuilder(key)); if (securitiesStrings.Length > 0) { var secCode = securityId.SecurityCode; var streamContainsSecurityFromMask = securitiesStrings.Any(mask => { var isEndMulti = mask.EndsWith("*"); var isStartMulti = mask.StartsWith("*"); if (isStartMulti) { mask = mask.Substring(1); } if (isEndMulti) { mask = mask.Substring(0, mask.Length - 1); } if (isEndMulti) { if (isStartMulti) { return(secCode.ContainsIgnoreCase(mask)); } else { return(secCode.StartsWith(mask, StringComparison.InvariantCultureIgnoreCase)); } } else if (isStartMulti) { return(secCode.EndsWith(mask, StringComparison.InvariantCultureIgnoreCase)); } else { return(secCode.CompareIgnoreCase(mask)); } }); if (!streamContainsSecurityFromMask) { continue; } } var secData = data.SafeAdd(securityId, key => Tuple.Create(new List <QuoteChangeMessage>(), new List <ExecutionMessage>(), new List <Level1ChangeMessage>(), new List <ExecutionMessage>())); switch (stream.Type) { case StreamType.Quotes: { ((IQuotesStream)stream).Handler += quotes => { var bids = new List <QuoteChange>(); var asks = new List <QuoteChange>(); foreach (var q in quotes) { switch (q.Type) { //case QuoteType.Unknown: //case QuoteType.Free: //case QuoteType.Spread: // throw new ArgumentException(q.Type.ToString()); case QuoteType.Ask: case QuoteType.BestAsk: asks.Add(new QuoteChange(priceStep * q.Price, q.Volume)); break; case QuoteType.Bid: case QuoteType.BestBid: bids.Add(new QuoteChange(priceStep * q.Price, q.Volume)); break; default: { continue; //throw new ArgumentException(q.Type.ToString()); } } } var md = new QuoteChangeMessage { LocalTime = ToLocalDto(reader.CurrentDateTime), SecurityId = securityId, ServerTime = ToLocalDto(reader.CurrentDateTime), Bids = bids.ToArray(), Asks = asks.ToArray(), }; //if (md.Verify()) //{ secData.Item1.Add(md); TryFlushData(registry, securityId, format, null, secData.Item1, reader); //} //else // _logManager.Application.AddErrorLog("Стакан для {0} в момент {1} не прошел валидацию. Лучший бид {2}, Лучший офер {3}.", security, qr.CurrentDateTime, md.BestBid, md.BestAsk); }; break; } case StreamType.Deals: { ((IDealsStream)stream).Handler += deal => { secData.Item2.Add(new ExecutionMessage { LocalTime = ToLocalDto(reader.CurrentDateTime), HasTradeInfo = true, ExecutionType = ExecutionTypes.Tick, SecurityId = securityId, OpenInterest = deal.OI == 0 ? (long?)null : deal.OI, ServerTime = ToServerDto(deal.DateTime), TradeVolume = deal.Volume, TradeId = deal.Id == 0 ? (long?)null : deal.Id, TradePrice = deal.Price * priceStep, OriginSide = deal.Type == DealType.Buy ? Sides.Buy : (deal.Type == DealType.Sell ? Sides.Sell : (Sides?)null) }); TryFlushData(registry, securityId, format, ExecutionTypes.Tick, secData.Item2, reader); }; break; } case StreamType.OrdLog: { ((IOrdLogStream)stream).Handler += ol => { var currTransactionId = ol.DateTime.Ticks; if (lastTransactionId < currTransactionId) { lastTransactionId = currTransactionId; } else if (lastTransactionId >= currTransactionId) { lastTransactionId++; } var msg = new ExecutionMessage { LocalTime = ToLocalDto(reader.CurrentDateTime), ExecutionType = ExecutionTypes.OrderLog, SecurityId = securityId, OpenInterest = ol.OI == 0 ? (long?)null : ol.OI, OrderId = ol.OrderId, OrderPrice = priceStep * ol.Price, ServerTime = ToServerDto(ol.DateTime), OrderVolume = ol.Amount, Balance = ol.AmountRest, TradeId = ol.DealId == 0 ? (long?)null : ol.DealId, TradePrice = ol.DealPrice == 0 ? (decimal?)null : priceStep * ol.DealPrice, TransactionId = lastTransactionId }; var status = 0; if (ol.Flags.Contains(OrdLogFlags.Add)) { msg.OrderState = OrderStates.Active; } else if (ol.Flags.Contains(OrdLogFlags.Fill)) { msg.OrderState = OrderStates.Done; } else if (ol.Flags.Contains(OrdLogFlags.Canceled)) { msg.OrderState = OrderStates.Done; status |= 0x200000; } else if (ol.Flags.Contains(OrdLogFlags.CanceledGroup)) { msg.OrderState = OrderStates.Done; status |= 0x400000; } else if (ol.Flags.Contains(OrdLogFlags.Moved)) { status |= 0x100000; } if (ol.Flags.Contains(OrdLogFlags.Buy)) { msg.Side = Sides.Buy; } else if (ol.Flags.Contains(OrdLogFlags.Sell)) { msg.Side = Sides.Sell; } if (ol.Flags.Contains(OrdLogFlags.FillOrKill)) { msg.TimeInForce = TimeInForce.MatchOrCancel; status |= 0x00080000; } if (ol.Flags.Contains(OrdLogFlags.Quote)) { msg.TimeInForce = TimeInForce.PutInQueue; status |= 0x01; } if (ol.Flags.Contains(OrdLogFlags.Counter)) { status |= 0x02; } if (ol.Flags.Contains(OrdLogFlags.CrossTrade)) { status |= 0x20000000; } if (ol.Flags.Contains(OrdLogFlags.NonSystem)) { msg.IsSystem = false; status |= 0x04; } if (ol.Flags.Contains(OrdLogFlags.EndOfTransaction)) { status |= 0x1000; } msg.OrderStatus = status; if (builder == null) { secData.Item4.Add(msg); TryFlushData(registry, securityId, format, ExecutionTypes.OrderLog, secData.Item4, reader); } else { //if (builder.Depth.Bids.Any() || builder.Depth.Asks.Any() || msg.ServerTime.TimeOfDay >= new TimeSpan(0, 18, 45, 00, 1)) { bool updated; try { updated = builder.Update(msg); } catch { updated = false; } if (updated) { secData.Item1.Add(new QuoteChangeMessage { SecurityId = securityId, ServerTime = builder.Depth.ServerTime, Bids = builder.Depth.Bids.Take(orderBookMaxDepth).ToArray(), Asks = builder.Depth.Asks.Take(orderBookMaxDepth).ToArray(), IsSorted = builder.Depth.IsSorted, LocalTime = builder.Depth.LocalTime, }); TryFlushData(registry, securityId, format, null, secData.Item1, reader); } } } }; break; } case StreamType.AuxInfo: { ((IAuxInfoStream)stream).Handler += info => { var l1Msg = new Level1ChangeMessage { LocalTime = ToLocalDto(reader.CurrentDateTime), SecurityId = securityId, ServerTime = ToLocalDto(reader.CurrentDateTime), } .TryAdd(Level1Fields.LastTradePrice, priceStep * info.Price) .TryAdd(Level1Fields.BidsVolume, (decimal)info.BidTotal) .TryAdd(Level1Fields.AsksVolume, (decimal)info.AskTotal) .TryAdd(Level1Fields.HighPrice, priceStep * info.HiLimit) .TryAdd(Level1Fields.LowPrice, priceStep * info.LoLimit) .TryAdd(Level1Fields.StepPrice, (decimal)info.Rate) .TryAdd(Level1Fields.OperatingMargin, (decimal)info.Deposit) .TryAdd(Level1Fields.OpenInterest, (decimal)info.OI); if (l1Msg.Changes.Count == 0) { return; } secData.Item3.Add(l1Msg); TryFlushData(registry, securityId, format, null, secData.Item3, reader); }; break; } case StreamType.OwnOrders: case StreamType.OwnTrades: case StreamType.Messages: case StreamType.None: { continue; } default: throw new ArgumentOutOfRangeException("Неподдерживаемый тип потока {0}.".Put(stream.Type)); } } if (data.Count > 0) { while (qr.CurrentDateTime != DateTime.MaxValue && _isStarted) { qr.Read(true); } } } if (!_isStarted) { return; } foreach (var pair in data) { if (pair.Value.Item1.Any()) { registry.GetQuoteMessageStorage(pair.Key, registry.DefaultDrive, format).Save(pair.Value.Item1); } if (pair.Value.Item2.Any()) { registry.GetTickMessageStorage(pair.Key, registry.DefaultDrive, format).Save(pair.Value.Item2); } if (pair.Value.Item3.Any()) { registry.GetLevel1MessageStorage(pair.Key, registry.DefaultDrive, format).Save(pair.Value.Item3); } if (pair.Value.Item4.Any()) { registry.GetOrderLogMessageStorage(pair.Key, registry.DefaultDrive, format).Save(pair.Value.Item4); } } if (data.Count > 0) { //File.AppendAllLines(_convertedFilesFile, new[] { fileNameKey }); _convertedFiles.Add(fileNameKey); _convertedPerTaskPoolFiles.Add(fileNameKey); } _logManager.Application.AddInfoLog("Завершена конвертация файла {0}.", fileName); }
/// <inheritdoc /> protected override Message OnProcess(Message message) { if (_boardDefinition == null) { if (message.Type == MessageTypes.Board) { _boardDefinition = (BoardMessage)message.Clone(); } return(null); } DateTimeOffset time; switch (message.Type) { case MessageTypes.Level1Change: { var l1Msg = (Level1ChangeMessage)message; var value = l1Msg.TryGetDecimal(Level1Fields.LastTradePrice); if (value != null) { _lastTradePrice = value.Value; } value = l1Msg.TryGetDecimal(Level1Fields.BestBidPrice); if (value != null) { _bestBidPrice = value.Value; } value = l1Msg.TryGetDecimal(Level1Fields.BestAskPrice); if (value != null) { _bestAskPrice = value.Value; } time = l1Msg.ServerTime; break; } case MessageTypes.Execution: { var execMsg = (ExecutionMessage)message; switch (execMsg.ExecutionType) { case ExecutionTypes.Tick: { var tradePrice = execMsg.TradePrice; if (null == _prevTradePrice) { _prevTradePrice = tradePrice; _bestAskPrice = tradePrice; _bestBidPrice = tradePrice; } switch (execMsg.OriginSide) { case null: { if (tradePrice > _prevTradePrice) { _bestAskPrice = tradePrice; //BestBid = PrevTrade; _prevTradePrice = tradePrice; } else if (tradePrice < _prevTradePrice) { _bestBidPrice = tradePrice; //BestAsk = PrevTrade; _prevTradePrice = tradePrice; } break; } case Sides.Buy: _bestAskPrice = tradePrice; break; default: _bestBidPrice = tradePrice; break; } _lastTradePrice = tradePrice; _newTrades = true; break; } default: return(null); } time = execMsg.ServerTime; break; } case MessageTypes.Time: { var timeMsg = (TimeMessage)message; time = timeMsg.ServerTime; break; } default: return(null); } if (_currGenerations == 0 || _bestBidPrice == null || _bestAskPrice == null) { return(null); } var isTradeTime = _boardDefinition.IsTradeTime(time); var canProcess = GenerateDepthOnEachTrade && _newTrades ? isTradeTime : (IsTimeToGenerate(time) && isTradeTime); if (!canProcess) { return(null); } _currGenerations = MaxGenerations; var depth = new QuoteChangeMessage { SecurityId = SecurityId, ServerTime = time, LocalTime = time, }; if (_bestBidPrice == null || _bestAskPrice == null) { if (_lastTradePrice == null) { throw new InvalidOperationException(LocalizedStrings.Str1142); } _bestBidPrice = _bestAskPrice = _lastTradePrice; } if (_currGenerations == 0) { throw new InvalidOperationException(LocalizedStrings.Str1143); } var bidPrice = _bestBidPrice; var askPrice = _bestAskPrice; var minSpred = MinSpreadStepCount * SecurityDefinition.PriceStep; var maxStread = MaxSpreadStepCount * SecurityDefinition.PriceStep; if ((askPrice - bidPrice) < minSpred) { if (_bestBidPrice == _lastTradePrice) // up trend { askPrice = bidPrice + minSpred; } else { bidPrice = askPrice - minSpred; } } else if ((askPrice - bidPrice) > maxStread) { if (_bestBidPrice == _lastTradePrice) // down trend { askPrice = bidPrice + maxStread; } else { bidPrice = askPrice - maxStread; } } var bids = new List <QuoteChange>(); //{ // new QuoteChange(Sides.Buy, bidPrice.Value, Volumes.Next()) //}; var count = MaxBidsDepth /* - bids.Count*/; for (var i = 0; i < count; i++) { var quote = CreateQuote(bidPrice.Value, Sides.Buy); if (quote.Price <= 0) { break; } bids.Add(quote); bidPrice = quote.Price; } var asks = new List <QuoteChange>(); //{ // new QuoteChange(Sides.Sell, askPrice.Value, Volumes.Next()) //}; count = MaxAsksDepth /* - asks.Count*/; for (var i = 0; i < count; i++) { var quote = CreateQuote(askPrice.Value, Sides.Sell); if (quote.Price <= 0) { break; } asks.Add(quote); askPrice = quote.Price; } depth.Bids = bids.ToArray(); depth.Asks = asks.ToArray(); _newTrades = false; _currGenerations--; return(depth); }
private QuoteChangeMessage ApplyNewState(BookInfo info, QuoteChangeMessage quoteMsg, QuoteChangeStates newState) { var currState = info.State; if (currState != newState) { switch (currState) { case _none: case QuoteChangeStates.SnapshotStarted: { if (newState != QuoteChangeStates.SnapshotBuilding && newState != QuoteChangeStates.SnapshotComplete) { this.AddDebugLog($"{currState}->{newState}"); return(null); } info.Bids.Clear(); info.Asks.Clear(); break; } case QuoteChangeStates.SnapshotBuilding: { if (newState != QuoteChangeStates.SnapshotComplete) { this.AddDebugLog($"{currState}->{newState}"); return(null); } break; } case QuoteChangeStates.SnapshotComplete: case QuoteChangeStates.Increment: { if (newState == QuoteChangeStates.SnapshotBuilding) { this.AddDebugLog($"{currState}->{newState}"); return(null); } break; } default: throw new ArgumentOutOfRangeException(currState.ToString()); } info.State = currState = newState; } void Copy(IEnumerable <QuoteChange> from, QuotesDict to) { foreach (var quote in from) { if (quote.Volume == 0) { to.Remove(quote.Price); } else { to[quote.Price] = quote.Volume; } } } Copy(quoteMsg.Bids, info.Bids); Copy(quoteMsg.Asks, info.Asks); if (currState == QuoteChangeStates.SnapshotStarted || currState == QuoteChangeStates.SnapshotBuilding) { return(null); } return(new QuoteChangeMessage { SecurityId = quoteMsg.SecurityId, Bids = info.Bids.Select(p => new QuoteChange(Sides.Buy, p.Key, p.Value)).ToArray(), Asks = info.Asks.Select(p => new QuoteChange(Sides.Sell, p.Key, p.Value)).ToArray(), IsSorted = true, ServerTime = quoteMsg.ServerTime, OriginalTransactionId = quoteMsg.OriginalTransactionId, }); }
/// <inheritdoc /> protected override void OnInnerAdapterNewOutMessage(Message message) { switch (message.Type) { case MessageTypes.SubscriptionResponse: { var responseMsg = (SubscriptionResponseMessage)message; var id = responseMsg.OriginalTransactionId; if (!responseMsg.IsOk()) { if (TryRemoveSubscription(id, out var info)) { lock (info.Lock) info.State = info.State.ChangeSubscriptionState(SubscriptionStates.Error, id, this); } } else { if (_subscriptionIds.TryGetValue(id, out var info)) { lock (info.Lock) info.State = info.State.ChangeSubscriptionState(SubscriptionStates.Active, id, this); } } break; } case MessageTypes.SubscriptionFinished: { var id = ((SubscriptionFinishedMessage)message).OriginalTransactionId; if (TryRemoveSubscription(id, out var info)) { lock (info.Lock) info.State = info.State.ChangeSubscriptionState(SubscriptionStates.Finished, id, this); } break; } case MessageTypes.SubscriptionOnline: { var onlineMsg = (SubscriptionOnlineMessage)message; var id = onlineMsg.OriginalTransactionId; QuoteChangeMessage snapshot = null; if (_subscriptionIds.TryGetValue(id, out var info)) { lock (info.Lock) { info.State = info.State.ChangeSubscriptionState(SubscriptionStates.Online, id, this); if (!info.IsTicks) { snapshot = info.Builder.Snapshot?.TypedClone(); } } } if (snapshot != null) { snapshot.SetSubscriptionIds(subscriptionId: id); base.OnInnerAdapterNewOutMessage(snapshot); } break; } case MessageTypes.Execution: { if (_subscriptionIds.Count == 0) { break; } var execMsg = (ExecutionMessage)message; if (execMsg.ExecutionType == ExecutionTypes.OrderLog && execMsg.IsSystem != false) { message = ProcessBuilders(execMsg); } break; } } if (message != null) { base.OnInnerAdapterNewOutMessage(message); } }
private static string QuotesToString(QuoteChangeMessage quotes) { var sb = new StringBuilder(); foreach (var quote in quotes.Bids) sb.Append($"Bid:{quote.Price}:{quote.Volume};"); foreach (var quote in quotes.Asks) sb.Append($"Ask:{quote.Price}:{quote.Volume};"); return $"{quotes.ServerTime};{quotes.SecurityId.SecurityCode};{sb}"; }
private static string QuotesToString(QuoteChangeMessage quotes) { var sb = new StringBuilder(); foreach (var quote in quotes.Bids) sb.Append(string.Format("Bid:{0}:{1};", quote.Price, quote.Volume)); foreach (var quote in quotes.Asks) sb.Append(string.Format("Ask:{0}:{1};", quote.Price, quote.Volume)); return string.Format("{0};{1};{2}", quotes.ServerTime, quotes.SecurityId.SecurityCode, sb ); }
private void ConvertFile(string fileName, IStorageRegistry registry, StorageFormats format, ExchangeBoard board, string securityLike) { if (!_isStarted) { return; } var fileNameKey = format + "_" + fileName; if (_convertedFiles.Contains(fileNameKey)) { return; } _logManager.Application.AddInfoLog("Конвертация файла {0}.", fileName); var isExact = !securityLike.EndsWith("*"); const int maxBufCount = 1000; var data = new Dictionary <Security, Tuple <List <QuoteChangeMessage>, List <ExecutionMessage>, List <Level1ChangeMessage>, List <ExecutionMessage> > >(); using (var qr = QshReader.Open(fileName)) { var currentDate = qr.CurrentDateTime; for (var i = 0; i < qr.StreamCount; i++) { var stream = (ISecurityStream)qr[i]; var security = GetSecurity(stream.Security, board); var priceStep = security.PriceStep ?? 1; var securityId = security.ToSecurityId(); var lastTransactionId = 0L; if (!securityLike.IsEmpty() && (isExact ? !securityId.SecurityCode.CompareIgnoreCase(securityLike) : !securityId.SecurityCode.ContainsIgnoreCase(securityLike))) { continue; } var secData = data.SafeAdd(security, key => Tuple.Create(new List <QuoteChangeMessage>(), new List <ExecutionMessage>(), new List <Level1ChangeMessage>(), new List <ExecutionMessage>())); switch (stream.Type) { case StreamType.Stock: { ((IStockStream)stream).Handler += (key, quotes, spread) => { var quotes2 = quotes.Select(q => { Sides side; switch (q.Type) { case QuoteType.Unknown: case QuoteType.Free: case QuoteType.Spread: throw new ArgumentException(q.Type.ToString()); case QuoteType.Ask: case QuoteType.BestAsk: side = Sides.Sell; break; case QuoteType.Bid: case QuoteType.BestBid: side = Sides.Buy; break; default: throw new ArgumentOutOfRangeException(); } return(new QuoteChange(side, priceStep * q.Price, q.Volume)); }).ToArray(); var md = new QuoteChangeMessage { SecurityId = securityId, ServerTime = currentDate.ApplyTimeZone(TimeHelper.Moscow), Bids = quotes2.Where(q => q.Side == Sides.Buy), Asks = quotes2.Where(q => q.Side == Sides.Sell), }; //if (md.Verify()) //{ secData.Item1.Add(md); if (secData.Item1.Count > maxBufCount) { registry.GetQuoteMessageStorage(security, format: format).Save(secData.Item1); secData.Item1.Clear(); } //} //else // _logManager.Application.AddErrorLog("Стакан для {0} в момент {1} не прошел валидацию. Лучший бид {2}, Лучший офер {3}.", security, qr.CurrentDateTime, md.BestBid, md.BestAsk); }; break; } case StreamType.Deals: { ((IDealsStream)stream).Handler += deal => { secData.Item2.Add(new ExecutionMessage { ExecutionType = ExecutionTypes.Tick, SecurityId = securityId, OpenInterest = deal.OI == 0 ? (long?)null : deal.OI, ServerTime = deal.DateTime.ApplyTimeZone(TimeHelper.Moscow), Volume = deal.Volume, TradeId = deal.Id == 0 ? (long?)null : deal.Id, TradePrice = (decimal)deal.Price, OriginSide = deal.Type == DealType.Buy ? Sides.Buy : (deal.Type == DealType.Sell ? Sides.Sell : (Sides?)null) }); if (secData.Item2.Count > maxBufCount) { registry.GetTickMessageStorage(security, format: format).Save(secData.Item2); secData.Item2.Clear(); } }; break; } case StreamType.OrdLog: { ((IOrdLogStream)stream).Handler += (key, ol) => { var currTransactionId = ol.DateTime.Ticks; if (lastTransactionId < currTransactionId) { lastTransactionId = currTransactionId; } else if (lastTransactionId >= currTransactionId) { lastTransactionId++; } var msg = new ExecutionMessage { ExecutionType = ExecutionTypes.OrderLog, SecurityId = securityId, OpenInterest = ol.OI == 0 ? (long?)null : ol.OI, OrderId = ol.OrderId, OrderPrice = priceStep * ol.Price, ServerTime = ol.DateTime.ApplyTimeZone(TimeHelper.Moscow), Volume = ol.Amount, Balance = ol.AmountRest, TradeId = ol.DealId == 0 ? (long?)null : ol.DealId, TradePrice = ol.DealPrice == 0 ? (decimal?)null : priceStep * ol.DealPrice, TransactionId = lastTransactionId }; var status = 0; if (ol.Flags.Contains(OrdLogFlags.Add)) { msg.OrderState = OrderStates.Active; } else if (ol.Flags.Contains(OrdLogFlags.Fill)) { msg.OrderState = OrderStates.Done; } else if (ol.Flags.Contains(OrdLogFlags.Canceled)) { msg.OrderState = OrderStates.Done; status |= 0x200000; } else if (ol.Flags.Contains(OrdLogFlags.CanceledGroup)) { msg.OrderState = OrderStates.Done; status |= 0x400000; } else if (ol.Flags.Contains(OrdLogFlags.Moved)) { status |= 0x100000; } if (ol.Flags.Contains(OrdLogFlags.Buy)) { msg.Side = Sides.Buy; } else if (ol.Flags.Contains(OrdLogFlags.Sell)) { msg.Side = Sides.Sell; } if (ol.Flags.Contains(OrdLogFlags.FillOrKill)) { msg.TimeInForce = TimeInForce.MatchOrCancel; status |= 0x00080000; } if (ol.Flags.Contains(OrdLogFlags.Quote)) { msg.TimeInForce = TimeInForce.PutInQueue; status |= 0x01; } if (ol.Flags.Contains(OrdLogFlags.Counter)) { status |= 0x02; } if (ol.Flags.Contains(OrdLogFlags.CrossTrade)) { status |= 0x20000000; } if (ol.Flags.Contains(OrdLogFlags.NonSystem)) { msg.IsSystem = false; status |= 0x04; } if (ol.Flags.Contains(OrdLogFlags.EndOfTransaction)) { status |= 0x1000; } msg.OrderStatus = (OrderStatus)status; secData.Item4.Add(msg); if (secData.Item4.Count > maxBufCount) { registry.GetOrderLogMessageStorage(security, format: format).Save(secData.Item4); secData.Item4.Clear(); } }; break; } case StreamType.AuxInfo: { ((IAuxInfoStream)stream).Handler += (key, info) => { secData.Item3.Add(new Level1ChangeMessage { SecurityId = securityId, ServerTime = info.DateTime.ApplyTimeZone(TimeHelper.Moscow), } .TryAdd(Level1Fields.LastTradePrice, priceStep * info.Price) .TryAdd(Level1Fields.BidsVolume, (decimal)info.BidTotal) .TryAdd(Level1Fields.AsksVolume, (decimal)info.AskTotal) .TryAdd(Level1Fields.HighPrice, priceStep * info.HiLimit) .TryAdd(Level1Fields.LowPrice, priceStep * info.LoLimit) .TryAdd(Level1Fields.OpenInterest, (decimal)info.OI)); if (secData.Item3.Count > maxBufCount) { registry.GetLevel1MessageStorage(security, format: format).Save(secData.Item3); secData.Item3.Clear(); } }; break; } case StreamType.Orders: case StreamType.Trades: case StreamType.Messages: case StreamType.None: { continue; } default: throw new ArgumentOutOfRangeException("Неподдерживаемый тип потока {0}.".Put(stream.Type)); } } if (data.Count > 0) { while (qr.CurrentDateTime != DateTime.MaxValue && _isStarted) { qr.Read(true); } } } if (!_isStarted) { return; } foreach (var pair in data) { if (pair.Value.Item1.Any()) { registry.GetQuoteMessageStorage(pair.Key, format: format).Save(pair.Value.Item1); } if (pair.Value.Item2.Any()) { registry.GetTickMessageStorage(pair.Key, format: format).Save(pair.Value.Item2); } if (pair.Value.Item3.Any()) { registry.GetLevel1MessageStorage(pair.Key, format: format).Save(pair.Value.Item3); } if (pair.Value.Item4.Any()) { registry.GetOrderLogMessageStorage(pair.Key, format: format).Save(pair.Value.Item4); } } if (data.Count > 0) { File.AppendAllLines(_convertedFilesFile, new[] { fileNameKey }); _convertedFiles.Add(fileNameKey); } }
private QuoteChangeMessage ApplyNewState(BookInfo info, QuoteChangeMessage quoteMsg, QuoteChangeStates newState) { var currState = info.State; void CheckSwitch() { switch (currState) { case _none: case QuoteChangeStates.SnapshotStarted: { if (newState != QuoteChangeStates.SnapshotBuilding && newState != QuoteChangeStates.SnapshotComplete) { this.AddDebugLog($"{currState}->{newState}"); } break; } case QuoteChangeStates.SnapshotBuilding: { if (newState != QuoteChangeStates.SnapshotBuilding && newState != QuoteChangeStates.SnapshotComplete) { this.AddDebugLog($"{currState}->{newState}"); } break; } case QuoteChangeStates.SnapshotComplete: case QuoteChangeStates.Increment: { if (newState == QuoteChangeStates.SnapshotBuilding) { this.AddDebugLog($"{currState}->{newState}"); } break; } } } if (currState != newState) { CheckSwitch(); if (newState == QuoteChangeStates.SnapshotStarted) { info.Bids.Clear(); info.Asks.Clear(); } switch (currState) { case _none: { info.Bids.Clear(); info.Asks.Clear(); break; } case QuoteChangeStates.SnapshotStarted: break; case QuoteChangeStates.SnapshotBuilding: break; case QuoteChangeStates.SnapshotComplete: { if (newState == QuoteChangeStates.SnapshotComplete) { info.Bids.Clear(); info.Asks.Clear(); } break; } case QuoteChangeStates.Increment: break; default: throw new ArgumentOutOfRangeException(currState.ToString()); } info.State = currState = newState; } void Apply(IEnumerable <QuoteChange> from, QuotesDict to) { foreach (var quote in from) { if (quote.Volume == 0) { to.Remove(quote.Price); } else { to[quote.Price] = Tuple.Create(quote.Volume, quote.OrdersCount, quote.Condition); } } } void ApplyByPos(IEnumerable <QuoteChange> from, QuotesByPosList to) { foreach (var quote in from) { var startPos = quote.StartPosition.Value; switch (quote.Action) { case QuoteChangeActions.New: { var tuple = Tuple.Create(quote.Price, quote.Volume, quote.OrdersCount, quote.Condition); if (startPos > to.Count) { throw new InvalidOperationException($"Pos={startPos}>Count={to.Count}"); } else if (startPos == to.Count) { to.Add(tuple); } else { to.Insert(startPos, tuple); } break; } case QuoteChangeActions.Update: { to[startPos] = Tuple.Create(quote.Price, quote.Volume, quote.OrdersCount, quote.Condition); break; } case QuoteChangeActions.Delete: { if (quote.EndPosition == null) { to.RemoveAt(startPos); } else { to.RemoveRange(startPos, (quote.EndPosition.Value - startPos) + 1); } break; } default: throw new ArgumentOutOfRangeException(nameof(from), quote.Action, LocalizedStrings.Str1219); } } } if (quoteMsg.HasPositions) { ApplyByPos(quoteMsg.Bids, info.BidsByPos); ApplyByPos(quoteMsg.Asks, info.AsksByPos); } else { Apply(quoteMsg.Bids, info.Bids); Apply(quoteMsg.Asks, info.Asks); } if (currState == QuoteChangeStates.SnapshotStarted || currState == QuoteChangeStates.SnapshotBuilding) { return(null); } IEnumerable <QuoteChange> bids; IEnumerable <QuoteChange> asks; if (quoteMsg.HasPositions) { bids = info.BidsByPos.Select(p => new QuoteChange(p.Item1, p.Item2, p.Item3, p.Item4)); asks = info.AsksByPos.Select(p => new QuoteChange(p.Item1, p.Item2, p.Item3, p.Item4)); } else { bids = info.Bids.Select(p => new QuoteChange(p.Key, p.Value.Item1, p.Value.Item2, p.Value.Item3)); asks = info.Asks.Select(p => new QuoteChange(p.Key, p.Value.Item1, p.Value.Item2, p.Value.Item3)); } return(new QuoteChangeMessage { SecurityId = quoteMsg.SecurityId, Bids = bids.ToArray(), Asks = asks.ToArray(), IsSorted = true, ServerTime = quoteMsg.ServerTime, OriginalTransactionId = quoteMsg.OriginalTransactionId, }); }
/// <summary> /// Try create full book. /// </summary> /// <param name="change">Book change.</param> /// <returns>Full book.</returns> public QuoteChangeMessage TryApply(QuoteChangeMessage change) { if (change is null) { throw new ArgumentNullException(nameof(change)); } if (change.State is null) { throw new ArgumentException(nameof(change)); } var currState = _state; var newState = change.State.Value; bool CheckSwitch() { switch (currState) { case _none: case QuoteChangeStates.SnapshotStarted: { if (newState != QuoteChangeStates.SnapshotBuilding && newState != QuoteChangeStates.SnapshotComplete) { this.AddDebugLog($"{currState}->{newState}"); return(false); } break; } case QuoteChangeStates.SnapshotBuilding: { if (newState != QuoteChangeStates.SnapshotBuilding && newState != QuoteChangeStates.SnapshotComplete) { this.AddDebugLog($"{currState}->{newState}"); return(false); } break; } case QuoteChangeStates.SnapshotComplete: case QuoteChangeStates.Increment: { if (newState == QuoteChangeStates.SnapshotBuilding) { this.AddDebugLog($"{currState}->{newState}"); return(false); } break; } } return(true); } var resetState = newState == QuoteChangeStates.SnapshotStarted || newState == QuoteChangeStates.SnapshotComplete; if (currState != newState || resetState) { if (!CheckSwitch()) { return(null); } if (currState == _none || resetState) { _bids.Clear(); _asks.Clear(); _bidsByPos.Clear(); _asksByPos.Clear(); } _state = currState = newState; }
/// <summary> /// Try create full book. /// </summary> /// <param name="change">Book change.</param> /// <returns>Full book.</returns> public QuoteChangeMessage TryApply(QuoteChangeMessage change) { if (change is null) { throw new ArgumentNullException(nameof(change)); } if (change.State == null) { throw new ArgumentException(nameof(change)); } var currState = _state; var newState = change.State.Value; void CheckSwitch() { switch (currState) { case _none: case QuoteChangeStates.SnapshotStarted: { if (newState != QuoteChangeStates.SnapshotBuilding && newState != QuoteChangeStates.SnapshotComplete) { _logs.AddDebugLog($"{currState}->{newState}"); } break; } case QuoteChangeStates.SnapshotBuilding: { if (newState != QuoteChangeStates.SnapshotBuilding && newState != QuoteChangeStates.SnapshotComplete) { _logs.AddDebugLog($"{currState}->{newState}"); } break; } case QuoteChangeStates.SnapshotComplete: case QuoteChangeStates.Increment: { if (newState == QuoteChangeStates.SnapshotBuilding) { _logs.AddDebugLog($"{currState}->{newState}"); } break; } } } if (currState != newState || newState == QuoteChangeStates.SnapshotComplete) { CheckSwitch(); if (newState == QuoteChangeStates.SnapshotStarted) { _bids.Clear(); _asks.Clear(); } switch (currState) { case _none: { _bids.Clear(); _asks.Clear(); break; } case QuoteChangeStates.SnapshotStarted: break; case QuoteChangeStates.SnapshotBuilding: break; case QuoteChangeStates.SnapshotComplete: { if (newState == QuoteChangeStates.SnapshotComplete) { _bids.Clear(); _asks.Clear(); } break; } case QuoteChangeStates.Increment: break; default: throw new ArgumentOutOfRangeException(currState.ToString()); } _state = currState = newState; } void Apply(IEnumerable <QuoteChange> from, SortedList <decimal, QuoteChange> to) { foreach (var quote in from) { if (quote.Volume == 0) { to.Remove(quote.Price); } else { to[quote.Price] = quote; } } } void ApplyByPos(IEnumerable <QuoteChange> from, List <QuoteChange> to) { foreach (var quote in from) { var startPos = quote.StartPosition.Value; switch (quote.Action) { case QuoteChangeActions.New: { var tuple = new QuoteChange(quote.Price, quote.Volume, quote.OrdersCount, quote.Condition); if (startPos > to.Count) { throw new InvalidOperationException($"Pos={startPos}>Count={to.Count}"); } else if (startPos == to.Count) { to.Add(tuple); } else { to.Insert(startPos, tuple); } break; } case QuoteChangeActions.Update: { to[startPos] = new QuoteChange(quote.Price, quote.Volume, quote.OrdersCount, quote.Condition); break; } case QuoteChangeActions.Delete: { if (quote.EndPosition == null) { to.RemoveAt(startPos); } else { to.RemoveRange(startPos, (quote.EndPosition.Value - startPos) + 1); } break; } default: throw new ArgumentOutOfRangeException(nameof(from), quote.Action, LocalizedStrings.Str1219); } } } if (change.HasPositions) { ApplyByPos(change.Bids, _bidsByPos); ApplyByPos(change.Asks, _asksByPos); } else { Apply(change.Bids, _bids); Apply(change.Asks, _asks); } if (currState == QuoteChangeStates.SnapshotStarted || currState == QuoteChangeStates.SnapshotBuilding) { return(null); } QuoteChange[] bids; QuoteChange[] asks; if (change.HasPositions) { bids = _bidsByPos.ToArray(); asks = _asksByPos.ToArray(); } else { bids = _bids.Values.ToArray(); asks = _asks.Values.ToArray(); } return(new QuoteChangeMessage { SecurityId = SecurityId, Bids = bids, Asks = asks, ServerTime = change.ServerTime, OriginalTransactionId = change.OriginalTransactionId, }); }
public static void WriteMarketDepth(this QuoteChangeMessage quotes) { MemoryToFile(QuotesToString(quotes), Path.Combine(_outputFolder, string.Format("{0}_depth.txt", quotes.SecurityId.SecurityCode))); }