private void OptionsClick(object sender, RoutedEventArgs e) { var security = SelectedSecurity; var id = _optionSecurities.TryGetValue2(security); if (id == null) { var wnd = new OptionWindow(); if (!wnd.ShowModal(this)) { return; } Trader.SubscribeOptionCalc(security, wnd.Volatility, wnd.OptionPrice, wnd.AssetPrice); Options.IsChecked = true; } else { Trader.UnSubscribeOptionCalc(id.Value); _optionSecurities.Remove(security); Options.IsChecked = false; } }
public int this[IMessageAdapter adapter] { get { lock (SyncRoot) return(_enables.TryGetValue2(adapter) ?? -1); } set { if (value < -1) { throw new ArgumentOutOfRangeException(); } lock (SyncRoot) { if (!Contains(adapter)) { Add(adapter); } _enables[adapter] = value; //_portfolioTraders.Clear(); } } }
private IEnumerable <QuoteChange> Filter(IEnumerable <QuoteChange> quotes) { return(quotes .Select(quote => { var res = quote.Clone(); var key = Tuple.Create(res.Side, res.Price); var own = _ownVolumes.TryGetValue2(key); if (own != null) { res.Volume -= own.Value; } return res.Volume <= 0 ? null : res; }) .Where(q => q != null)); }
/// <inheritdoc /> protected override void Export(IEnumerable <PositionChangeMessage> messages) { Do(worker => { var columns = new Dictionary <PositionChangeTypes, int>(); worker .SetCell(0, 0, LocalizedStrings.Time).SetStyle(0, "yyyy-MM-dd HH:mm:ss.fff"); var row = 1; foreach (var message in messages) { worker.SetCell(0, row, message.LocalTime); foreach (var pair in message.Changes) { var type = pair.Key; var columnIndex = columns.TryGetValue2(type); if (columnIndex == null) { columnIndex = columns.Count; columns.Add(type, columnIndex.Value); worker.SetCell(columnIndex.Value, 0, type.GetDisplayName()); ApplyCellStyle(worker, type, columnIndex.Value); } worker.SetCell(columns[type], row, pair.Value); } if (!Check(++row)) { break; } } }); }
private void OptionsClick(object sender, RoutedEventArgs e) { foreach (var security in SecurityPicker.SelectedSecurities) { if (security.Type == SecurityTypes.Option) { var id = _optionSecurities.TryGetValue2(security); if (id == null) { var wnd = new OptionWindow(); if (!wnd.ShowModal(this)) { return; } id = Trader.SubscribeOptionCalc(security, wnd.Volatility, wnd.OptionPrice, wnd.AssetPrice); _optionSecurities.Add(security, id.Value); Options.IsChecked = true; } else { Trader.UnSubscribeOptionCalc(id.Value); _optionSecurities.Remove(security); Options.IsChecked = false; } } else { if (!_optionsInitialized) { Trader.NewOptionParameters += TraderOnNewOptionParameters; _optionsInitialized = true; } Trader.RequestOptionParameters(security); } } }
/// <inheritdoc /> protected override void Export(IEnumerable <Level1ChangeMessage> messages) { Do(worker => { var columns = new Dictionary <Level1Fields, int>(); //{ // { Level1Fields.LastTradeId, 1 }, // { Level1Fields.LastTradePrice, 2 }, // { Level1Fields.LastTradeVolume, 3 }, // { Level1Fields.LastTradeOrigin, 4 }, // { Level1Fields.BestBidPrice, 5 }, // { Level1Fields.BestBidVolume, 6 }, // { Level1Fields.BestAskPrice, 7 }, // { Level1Fields.BestAskVolume, 8 }, // { Level1Fields.StepPrice, 9 }, // { Level1Fields.OpenInterest, 10 }, // { Level1Fields.TheorPrice, 11 }, // { Level1Fields.ImpliedVolatility, 12 }, // { Level1Fields.OpenPrice, 13 }, // { Level1Fields.HighPrice, 14 }, // { Level1Fields.LowPrice, 15 }, // { Level1Fields.ClosePrice, 16 }, // { Level1Fields.Volume, 17 }, //}; worker .SetCell(0, 0, LocalizedStrings.Time).SetStyle(0, "yyyy-MM-dd HH:mm:ss.fff"); //foreach (var pair in columns) //{ // var field = pair.Key; // var columnIndex = pair.Value; // worker.SetCell(columnIndex, 0, field.GetDisplayName()); // ApplyCellStyle(worker, field, columnIndex); //} var row = 1; foreach (var message in messages) { worker.SetCell(0, row, message.LocalTime); foreach (var pair in message.Changes) { var field = pair.Key; var columnIndex = columns.TryGetValue2(field); if (columnIndex == null) { columnIndex = columns.Count; columns.Add(field, columnIndex.Value); worker.SetCell(columnIndex.Value, 0, field.GetDisplayName()); ApplyCellStyle(worker, field, columnIndex.Value); } worker.SetCell(columns[field], row, pair.Value); } if (!Check(++row)) { break; } } }); }
/// <summary> /// Обработать сообщение. /// </summary> /// <param name="message">Сообщение.</param> public void Process(Message message) { if (message == null) { throw new ArgumentNullException("message"); } LogReceiver.AddDebugLog("Out. {0}", message); switch (message.Type) { case MessageTypes.Level1Change: { var l1Msg = (Level1ChangeMessage)message; lock (_prevLevel1.SyncRoot) { var prevLevel1 = _prevLevel1.TryGetValue(l1Msg.SecurityId); if (prevLevel1 == null) { _prevLevel1.Add(l1Msg.SecurityId, (Level1ChangeMessage)l1Msg.Clone()); } else { l1Msg.Changes.RemoveWhere(p => { var prevValue = prevLevel1.Changes.TryGetValue(p.Key); if (prevValue != null && prevValue.Equals(p.Value)) { return(true); } prevLevel1.Changes[p.Key] = p.Value; return(false); }); if (l1Msg.Changes.Count == 0) { return; } } } _sessionHolder.ReplaceSecurityId(l1Msg.SecurityId, id => l1Msg.SecurityId = id); break; } case MessageTypes.Security: { var secMsg = (SecurityMessage)message; var classCode = secMsg.SecurityId.BoardCode; var classInfo = _sessionHolder.GetSecurityClassInfo(classCode); // из квика не транслируется поле тип инструмента, если тип инструмента не найден по классу, то берем по умолчанию. secMsg.SecurityType = secMsg.Multiplier == 0 ? SecurityTypes.Index : (classInfo.Item1 ?? SecurityTypes.Stock); _sessionHolder.ReplaceSecurityId(secMsg.SecurityId, id => secMsg.SecurityId = id); break; } case MessageTypes.QuoteChange: { var quoteMsg = (QuoteChangeMessage)message; _sessionHolder.ReplaceSecurityId(quoteMsg.SecurityId, id => quoteMsg.SecurityId = id); quoteMsg.ServerTime = _sessionHolder.CurrentTime.Convert(TimeHelper.Moscow); break; } case MessageTypes.Execution: { var execMsg = (ExecutionMessage)message; var isTransaction = false; switch (execMsg.ExecutionType) { case ExecutionTypes.Order: { isTransaction = true; if (execMsg.OrderId != null && execMsg.OriginalTransactionId != 0) { _transactionsByOrderId.SafeAdd(execMsg.OrderId.Value, i => execMsg.OriginalTransactionId); var trades = _tradesByOrderId.TryGetValue(execMsg.OrderId.Value); if (trades != null) { trades.ForEach(_fixServer.SendInMessage); _tradesByOrderId.Remove(execMsg.OrderId.Value); } } break; } case ExecutionTypes.Trade: { isTransaction = true; if (execMsg.OriginalTransactionId != 0) { break; } var orderId = execMsg.OrderId; if (orderId != null) { var origTransactionId = _transactionsByOrderId.TryGetValue2(orderId.Value); if (origTransactionId == null) { _tradesByOrderId.SafeAdd(orderId.Value).Add(execMsg); return; } execMsg.OriginalTransactionId = origTransactionId.Value; } break; } } if (isTransaction) { // запоминаем номер исходной транзакции, который будет исопльзоваться в FixServer execMsg.UserOrderId = execMsg.OriginalTransactionId.To <string>(); var transaction = _transactions.TryGetValue(execMsg.OriginalTransactionId); if (transaction != null && execMsg.Error != null) { switch (transaction.TransactionType) { case TransactionTypes.ReRegister: { var replaceMsg = (OrderReplaceMessage)transaction.Message; // дополнительно отправляем сообщение ошибки снятия заявки var cancelErrMsg = (ExecutionMessage)execMsg.Clone(); cancelErrMsg.OrderId = replaceMsg.OldOrderId; cancelErrMsg.IsCancelled = true; break; } case TransactionTypes.Cancel: { var cancelMsg = (OrderCancelMessage)transaction.Message; // заполняем номер заявки execMsg.OrderId = cancelMsg.OrderId; execMsg.IsCancelled = true; break; } } } } _sessionHolder.ReplaceSecurityId(execMsg.SecurityId, id => execMsg.SecurityId = id); break; } case MessageTypes.Portfolio: { var pfMsg = (PortfolioMessage)message; _sessionHolder.ReplaceBoardCode(pfMsg.BoardCode, board => pfMsg.BoardCode = board); break; } case MessageTypes.PortfolioChange: { var pfMsg = (PortfolioChangeMessage)message; _sessionHolder.ReplaceBoardCode(pfMsg.BoardCode, board => pfMsg.BoardCode = board); var depoName = (string)pfMsg.Changes.TryGetValue(PositionChangeTypes.DepoName); if (!depoName.IsEmpty()) { _depoNames[pfMsg.PortfolioName] = depoName; } break; } case MessageTypes.Position: { var pfMsg = (PositionMessage)message; _sessionHolder.ReplaceSecurityId(pfMsg.SecurityId, id => pfMsg.SecurityId = id); break; } case MessageTypes.PositionChange: { var pfMsg = (PositionChangeMessage)message; _sessionHolder.ReplaceSecurityId(pfMsg.SecurityId, id => pfMsg.SecurityId = id); break; } } _fixServer.SendInMessage(message); }
/// <summary> /// Экспортировать <see cref="Level1ChangeMessage"/>. /// </summary> /// <param name="messages">Сообщения.</param> protected override void Export(IEnumerable <Level1ChangeMessage> messages) { Do(worker => { var columns = new Dictionary <Level1Fields, int> { { Level1Fields.LastTradeId, 1 }, { Level1Fields.LastTradePrice, 2 }, { Level1Fields.LastTradeVolume, 3 }, { Level1Fields.LastTradeOrigin, 4 }, { Level1Fields.BestBidPrice, 5 }, { Level1Fields.BestBidVolume, 6 }, { Level1Fields.BestAskPrice, 7 }, { Level1Fields.BestAskVolume, 8 }, { Level1Fields.StepPrice, 9 }, { Level1Fields.OpenInterest, 10 }, { Level1Fields.TheorPrice, 11 }, { Level1Fields.ImpliedVolatility, 12 }, { Level1Fields.OpenPrice, 13 }, { Level1Fields.HighPrice, 14 }, { Level1Fields.LowPrice, 15 }, { Level1Fields.ClosePrice, 16 }, { Level1Fields.Volume, 17 }, }; worker .SetCell(0, 0, LocalizedStrings.Str219).SetStyle(0, "yyyy-MM-dd HH:mm:ss.fff"); foreach (var field in Enumerator.GetValues <Level1Fields>()) { var columnIndex = columns.TryGetValue2(field); if (columnIndex == null) { columnIndex = columns.Count; columns.Add(field, columnIndex.Value); } var cell = worker.SetCell(columns[field], 0, field.GetDisplayName()); switch (field) { case Level1Fields.LastTrade: case Level1Fields.BestAsk: case Level1Fields.BestBid: continue; case Level1Fields.LastTradeId: case Level1Fields.BidsCount: case Level1Fields.AsksCount: case Level1Fields.TradesCount: cell.SetStyle(columns[field], typeof(long)); break; case Level1Fields.LastTradeTime: case Level1Fields.BestAskTime: case Level1Fields.BestBidTime: cell.SetStyle(columns[field], typeof(DateTimeOffset)); break; default: cell.SetStyle(columns[field], typeof(decimal)); break; } } var row = 1; foreach (var message in messages) { worker.SetCell(0, row, message.LocalTime); foreach (var pair in message.Changes) { worker.SetCell(columns[pair.Key], row, pair.Value); } if (!Check(++row)) { break; } } }); }
/// <summary> /// To export <see cref="Level1ChangeMessage"/>. /// </summary> /// <param name="messages">Messages.</param> protected override void Export(IEnumerable<Level1ChangeMessage> messages) { Do(worker => { var columns = new Dictionary<Level1Fields, int>(); //{ // { Level1Fields.LastTradeId, 1 }, // { Level1Fields.LastTradePrice, 2 }, // { Level1Fields.LastTradeVolume, 3 }, // { Level1Fields.LastTradeOrigin, 4 }, // { Level1Fields.BestBidPrice, 5 }, // { Level1Fields.BestBidVolume, 6 }, // { Level1Fields.BestAskPrice, 7 }, // { Level1Fields.BestAskVolume, 8 }, // { Level1Fields.StepPrice, 9 }, // { Level1Fields.OpenInterest, 10 }, // { Level1Fields.TheorPrice, 11 }, // { Level1Fields.ImpliedVolatility, 12 }, // { Level1Fields.OpenPrice, 13 }, // { Level1Fields.HighPrice, 14 }, // { Level1Fields.LowPrice, 15 }, // { Level1Fields.ClosePrice, 16 }, // { Level1Fields.Volume, 17 }, //}; worker .SetCell(0, 0, LocalizedStrings.Time).SetStyle(0, "yyyy-MM-dd HH:mm:ss.fff"); //foreach (var pair in columns) //{ // var field = pair.Key; // var columnIndex = pair.Value; // worker.SetCell(columnIndex, 0, field.GetDisplayName()); // ApplyCellStyle(worker, field, columnIndex); //} var row = 1; foreach (var message in messages) { worker.SetCell(0, row, message.LocalTime); foreach (var pair in message.Changes) { var field = pair.Key; var columnIndex = columns.TryGetValue2(field); if (columnIndex == null) { columnIndex = columns.Count; columns.Add(field, columnIndex.Value); worker.SetCell(columnIndex.Value, 0, field.GetDisplayName()); ApplyCellStyle(worker, field, columnIndex.Value); } worker.SetCell(columns[field], row, pair.Value); } if (!Check(++row)) break; } }); }
/// <summary> /// To process the trade message. /// </summary> /// <param name="message">The trade message.</param> /// <returns><see langword="true" />, if the rule is activated, otherwise, <see langword="false" />.</returns> public override bool ProcessMessage(Message message) { switch (message.Type) { case MessageTypes.PositionChange: { var posMsg = (PositionChangeMessage)message; var currValue = (decimal?)posMsg.Changes.TryGetValue(PositionChangeTypes.CurrentValue); if (currValue == null) { return(false); } var key = Tuple.Create(posMsg.SecurityId, posMsg.PortfolioName); if (currValue == 0) { _posOpenTime.Remove(key); return(false); } var openTime = _posOpenTime.TryGetValue2(key); if (openTime == null) { _posOpenTime.Add(key, posMsg.LocalTime); return(false); } var diff = posMsg.LocalTime - openTime; if (diff < Time) { return(false); } _posOpenTime.Remove(key); return(true); } case MessageTypes.Time: { List <Tuple <SecurityId, string> > removingPos = null; foreach (var pair in _posOpenTime) { var diff = message.LocalTime - pair.Value; if (diff < Time) { continue; } if (removingPos == null) { removingPos = new List <Tuple <SecurityId, string> >(); } removingPos.Add(pair.Key); } if (removingPos != null) { removingPos.ForEach(t => _posOpenTime.Remove(t)); } return(removingPos != null); } } return(false); }
/// <summary> /// Экспортировать <see cref="Level1ChangeMessage"/>. /// </summary> /// <param name="messages">Сообщения.</param> protected override void Export(IEnumerable<Level1ChangeMessage> messages) { Do(worker => { var columns = new Dictionary<Level1Fields, int> { { Level1Fields.LastTradeId, 1 }, { Level1Fields.LastTradePrice, 2 }, { Level1Fields.LastTradeVolume, 3 }, { Level1Fields.LastTradeOrigin, 4 }, { Level1Fields.BestBidPrice, 5 }, { Level1Fields.BestBidVolume, 6 }, { Level1Fields.BestAskPrice, 7 }, { Level1Fields.BestAskVolume, 8 }, { Level1Fields.StepPrice, 9 }, { Level1Fields.OpenInterest, 10 }, { Level1Fields.TheorPrice, 11 }, { Level1Fields.ImpliedVolatility, 12 }, { Level1Fields.OpenPrice, 13 }, { Level1Fields.HighPrice, 14 }, { Level1Fields.LowPrice, 15 }, { Level1Fields.ClosePrice, 16 }, { Level1Fields.Volume, 17 }, }; worker .SetCell(0, 0, LocalizedStrings.Str219).SetStyle(0, "yyyy-MM-dd HH:mm:ss.fff"); foreach (var field in Enumerator.GetValues<Level1Fields>()) { var columnIndex = columns.TryGetValue2(field); if (columnIndex == null) { columnIndex = columns.Count; columns.Add(field, columnIndex.Value); } var cell = worker.SetCell(columns[field], 0, field.GetDisplayName()); switch (field) { case Level1Fields.LastTrade: case Level1Fields.BestAsk: case Level1Fields.BestBid: continue; case Level1Fields.LastTradeId: case Level1Fields.BidsCount: case Level1Fields.AsksCount: case Level1Fields.TradesCount: cell.SetStyle(columns[field], typeof(long)); break; case Level1Fields.LastTradeTime: case Level1Fields.BestAskTime: case Level1Fields.BestBidTime: cell.SetStyle(columns[field], typeof(DateTimeOffset)); break; default: cell.SetStyle(columns[field], typeof(decimal)); break; } } var row = 1; foreach (var message in messages) { worker.SetCell(0, row, message.LocalTime); foreach (var pair in message.Changes) worker.SetCell(columns[pair.Key], row, pair.Value); if (!Check(++row)) break; } }); }
private void ProcessMessage <TMessage>(SecurityId securityId, TMessage message, Func <TMessage, TMessage, TMessage> processSuspend) where TMessage : Message { if (securityId.Native != null) { SecurityId?fullSecurityId; lock (_syncRoot) fullSecurityId = _securityIds.TryGetValue2(securityId); if (fullSecurityId == null) { lock (_syncRoot) { var tuple = _suspendedMessages.SafeAdd(securityId, key => RefTuple.Create((List <Message>)null, (Dictionary <MessageTypes, Message>)null)); var clone = message.Clone(); if (processSuspend == null) { if (tuple.First == null) { tuple.First = new List <Message>(); } tuple.First.Add(clone); } else { if (tuple.Second == null) { tuple.Second = new Dictionary <MessageTypes, Message>(); } var prev = tuple.Second.TryGetValue(clone.Type); tuple.Second[clone.Type] = prev == null ? clone : processSuspend((TMessage)prev, (TMessage)clone); } } return; } ReplaceSecurityId(message, fullSecurityId.Value); } else { var securityCode = securityId.SecurityCode; var boardCode = securityId.BoardCode; var isSecCodeEmpty = securityCode.IsEmpty(); if (isSecCodeEmpty && message.Type != MessageTypes.Execution) { throw new InvalidOperationException(); } if (!isSecCodeEmpty && boardCode.IsEmpty()) { SecurityId?foundedId = null; lock (_syncRoot) { foreach (var id in _securityIds.Keys) { if (!id.SecurityCode.CompareIgnoreCase(securityCode)) { continue; } if (securityId.SecurityType != null && securityId.SecurityType != id.SecurityType) { continue; } foundedId = id; } if (foundedId == null) { var tuple = _suspendedMessages.SafeAdd(securityId, key => RefTuple.Create(new List <Message>(), (Dictionary <MessageTypes, Message>)null)); tuple.First.Add(message.Clone()); return; } } ReplaceSecurityId(message, foundedId.Value); //// если указан код и тип инструмента, то пытаемся найти инструмент по ним //if (securityId.SecurityType != null) //{ //} //else // throw new ArgumentException(nameof(securityId), LocalizedStrings.Str682Params.Put(securityCode, securityId.SecurityType)); } } base.OnInnerAdapterNewOutMessage(message); }
/// <summary> /// To process the message for transaction delay calculation. Messages of types <see cref="OrderRegisterMessage"/>, <see cref="OrderReplaceMessage"/>, <see cref="OrderPairReplaceMessage"/>, <see cref="OrderCancelMessage"/> and <see cref="ExecutionMessage"/> are accepted. /// </summary> /// <param name="message">Message.</param> /// <returns>Transaction delay.</returns> public TimeSpan?ProcessMessage(Message message) { switch (message.Type) { case MessageTypes.OrderRegister: { var regMsg = (OrderRegisterMessage)message; lock (_syncObject) { AddRegister(regMsg.TransactionId, regMsg.LocalTime); } break; } case MessageTypes.OrderReplace: { var replaceMsg = (OrderReplaceMessage)message; lock (_syncObject) { AddCancel(replaceMsg.TransactionId, replaceMsg.LocalTime); AddRegister(replaceMsg.TransactionId, replaceMsg.LocalTime); } break; } case MessageTypes.OrderPairReplace: { var replaceMsg = (OrderPairReplaceMessage)message; lock (_syncObject) { AddCancel(replaceMsg.Message1.TransactionId, replaceMsg.LocalTime); AddRegister(replaceMsg.Message1.TransactionId, replaceMsg.LocalTime); AddCancel(replaceMsg.Message2.TransactionId, replaceMsg.LocalTime); AddRegister(replaceMsg.Message2.TransactionId, replaceMsg.LocalTime); } break; } case MessageTypes.OrderCancel: { var cancelMsg = (OrderCancelMessage)message; lock (_syncObject) AddCancel(cancelMsg.TransactionId, cancelMsg.LocalTime); break; } case MessageTypes.Execution: { var execMsg = (ExecutionMessage)message; if (execMsg.ExecutionType == ExecutionTypes.Order) { if (execMsg.OrderState == OrderStates.Pending) { return(null); } lock (_syncObject) { var time = _register.TryGetValue2(execMsg.OriginalTransactionId); if (time == null) { time = _cancel.TryGetValue2(execMsg.OriginalTransactionId); if (time != null) { _cancel.Remove(execMsg.OriginalTransactionId); if (execMsg.OrderState == OrderStates.Failed) { return(null); } return(execMsg.LocalTime - time); } } else { _register.Remove(execMsg.OriginalTransactionId); if (execMsg.OrderState == OrderStates.Failed) { return(null); } return(execMsg.LocalTime - time); } } } break; } } return(null); }
private static string Escape(string text, bool useSecurityIds, out IEnumerable <string> identifiers) { if (text.IsEmptyOrWhiteSpace()) { throw new ArgumentNullException(nameof(text)); } if (useSecurityIds) { text = Decode(text.ToUpperInvariant()); identifiers = GetSecurityIds(text).Distinct().ToArray(); var i = 0; foreach (var id in identifiers) { text = text.ReplaceIgnoreCase(id, $"values[{i}]"); i++; } if (i == 0) { throw new InvalidOperationException(LocalizedStrings.NoSecIdsFound.Put(text)); } return(ReplaceFuncs(text)); } else { //var textWithoutFunctions = _funcReplaces // .CachedPairs // .Aggregate(text, (current, pair) => current.ReplaceIgnoreCase(pair.Key, string.Empty)); const string dotSep = "__DOT__"; text = text.Replace(".", dotSep); var groups = GetVariableNames(text) .Where(g => !g.Value.ContainsIgnoreCase(dotSep) && !long.TryParse(g.Value, out _) && !_funcReplaces.ContainsKey(g.Value)) .ToArray(); var dict = new Dictionary <string, int>(StringComparer.InvariantCultureIgnoreCase); foreach (var g in groups.OrderByDescending(g => g.Index)) { var i = dict.TryGetValue2(g.Value); if (i == null) { i = dict.Count; dict.Add(g.Value, i.Value); } text = text.Remove(g.Index, g.Length).Insert(g.Index, $"values[{i}]"); } identifiers = dict.Keys.ToArray(); text = text.Replace(dotSep, "."); return(ReplaceFuncs(text)); } }
/// <inheritdoc /> protected override void OnInnerAdapterNewOutMessage(Message message) { long TryReplaceOriginId(long id) { if (id == 0) { return(0); } lock (_sync) return(_replaceId.TryGetValue(id, out var prevId) ? prevId : id); } var prevOriginId = 0L; var newOriginId = 0L; if (message is IOriginalTransactionIdMessage originIdMsg1) { newOriginId = originIdMsg1.OriginalTransactionId; prevOriginId = originIdMsg1.OriginalTransactionId = TryReplaceOriginId(newOriginId); } switch (message.Type) { case MessageTypes.SubscriptionResponse: { lock (_sync) { if (((SubscriptionResponseMessage)message).IsOk()) { if (_subscriptionsById.TryGetValue(prevOriginId, out var info)) { // no need send response after re-subscribe cause response was handled prev time if (_replaceId.ContainsKey(newOriginId)) { if (info.State != SubscriptionStates.Stopped) { return; } } else { ChangeState(info, SubscriptionStates.Active); } } } else { if (!_historicalRequests.Remove(prevOriginId)) { if (_subscriptionsById.TryGetAndRemove(prevOriginId, out var info)) { ChangeState(info, SubscriptionStates.Error); _replaceId.Remove(newOriginId); } } } } break; } case MessageTypes.SubscriptionOnline: { lock (_sync) { if (!_subscriptionsById.TryGetValue(prevOriginId, out var info)) { break; } if (_replaceId.ContainsKey(newOriginId)) { // no need send response after re-subscribe cause response was handled prev time if (info.State == SubscriptionStates.Online) { return; } } else { ChangeState(info, SubscriptionStates.Online); } } break; } case MessageTypes.SubscriptionFinished: { lock (_sync) { if (_replaceId.ContainsKey(newOriginId)) { return; } _historicalRequests.Remove(prevOriginId); } break; } default: { if (message is ISubscriptionIdMessage subscrMsg) { lock (_sync) { if (subscrMsg.GetSubscriptionIds().Length == 0) { if (subscrMsg.OriginalTransactionId != 0 && _historicalRequests.ContainsKey(subscrMsg.OriginalTransactionId)) { subscrMsg.SetSubscriptionIds(subscriptionId: subscrMsg.OriginalTransactionId); } } else { lock (_sync) { if (_replaceId.Count > 0) { subscrMsg.SetSubscriptionIds(subscrMsg.GetSubscriptionIds().Select(id => _replaceId.TryGetValue2(id) ?? id).ToArray()); } } } } } break; } } base.OnInnerAdapterNewOutMessage(message); switch (message.Type) { case ExtendedMessageTypes.ReconnectingFinished: { Message[] subscriptions; lock (_sync) { _replaceId.Clear(); subscriptions = _subscriptionsById.Values.Distinct().Select(i => { var subscription = i.Subscription.TypedClone(); subscription.TransactionId = TransactionIdGenerator.GetNextId(); _replaceId.Add(subscription.TransactionId, i.Subscription.TransactionId); this.AddInfoLog("Re-map subscription: {0}->{1} for '{2}'.", i.Subscription.TransactionId, subscription.TransactionId, i.Subscription); return(((Message)subscription).LoopBack(this)); }).ToArray(); } foreach (var subscription in subscriptions) { base.OnInnerAdapterNewOutMessage(subscription); } break; } } }
public override void SendOutMessage(Message message) { switch (message.Type) { case MessageTypes.Portfolio: { var pfMsg = (PortfolioMessage)message; SessionHolder.ReplaceBoardCode(pfMsg.BoardCode, board => pfMsg.BoardCode = board); break; } case MessageTypes.PortfolioChange: { var pfMsg = (PortfolioChangeMessage)message; SessionHolder.ReplaceBoardCode(pfMsg.BoardCode, board => pfMsg.BoardCode = board); var depoName = (string)pfMsg.Changes.TryGetValue(PositionChangeTypes.DepoName); if (!depoName.IsEmpty()) { _depoNames[pfMsg.PortfolioName] = depoName; } break; } case MessageTypes.Position: { var pfMsg = (PositionMessage)message; SessionHolder.ReplaceSecurityId(pfMsg.SecurityId, id => pfMsg.SecurityId = id); break; } case MessageTypes.PositionChange: { var pfMsg = (PositionChangeMessage)message; SessionHolder.ReplaceSecurityId(pfMsg.SecurityId, id => pfMsg.SecurityId = id); break; } case MessageTypes.Execution: { var execMsg = (ExecutionMessage)message; switch (execMsg.ExecutionType) { case ExecutionTypes.Order: { if (execMsg.OrderId != null && execMsg.OriginalTransactionId != 0) { _transactionsByOrderId.SafeAdd(execMsg.OrderId.Value, i => execMsg.OriginalTransactionId); var trades = _tradesByOrderId.TryGetValue(execMsg.OrderId.Value); if (trades != null) { trades.ForEach(SendOutMessage); _tradesByOrderId.Remove(execMsg.OrderId.Value); } } break; } case ExecutionTypes.Trade: { if (execMsg.OriginalTransactionId != 0) { break; } var orderId = execMsg.OrderId; if (orderId != null) { var origTransactionId = _transactionsByOrderId.TryGetValue2(orderId.Value); if (origTransactionId == null) { _tradesByOrderId.SafeAdd(orderId.Value).Add(execMsg); return; } execMsg.OriginalTransactionId = origTransactionId.Value; } break; } } SessionHolder.ReplaceSecurityId(execMsg.SecurityId, id => execMsg.SecurityId = id); // запоминаем номер исходной транзакции, который будет исопльзоваться в FixServer execMsg.UserOrderId = execMsg.OriginalTransactionId.To <string>(); var transaction = _transactions.TryGetValue(execMsg.OriginalTransactionId); if (transaction != null && execMsg.Error != null) { switch (transaction.TransactionType) { case TransactionTypes.ReRegister: { var replaceMsg = (OrderReplaceMessage)transaction.Message; // дополнительно отправляем сообщение ошибки снятия заявки var cancelErrMsg = (ExecutionMessage)execMsg.Clone(); cancelErrMsg.OrderId = replaceMsg.OldOrderId; cancelErrMsg.IsCancelled = true; base.SendOutMessage(cancelErrMsg); break; } case TransactionTypes.Cancel: { var cancelMsg = (OrderCancelMessage)transaction.Message; // заполняем номер заявки execMsg.OrderId = cancelMsg.OrderId; execMsg.IsCancelled = true; break; } } } break; } } base.SendOutMessage(message); }