private void RemoveSubscription(long id) { if (_subscriptionIds.TryGetAndRemove(id, out var tuple)) { this.AddInfoLog("OL->{0} unsubscribed {1}/{2}.", tuple.Second ? "MD" : "TICK", tuple.First, id); } }
/// <summary> /// Remove series tracking. /// </summary> /// <param name="transactionId">Request identifier.</param> /// <returns>Candles series.</returns> public CandleSeries RemoveCandleSeries(long transactionId) { CandlesSeriesHolder info; lock (_holders.SyncRoot) info = _holders.TryGetAndRemove(transactionId); return(info?.Series); }
private bool TryRemoveSubscription(long id, out SubscriptionInfo info) { if (!_subscriptionIds.TryGetAndRemove(id, out info)) { return(false); } this.AddInfoLog("OL->{0} unsubscribed {1}/{2}.", info.IsTicks ? "MD" : "TICK", info.Origin.SecurityId, info.Origin.TransactionId); return(true); }
/// <summary> /// Start storage auto-save thread. /// </summary> private void StartStorageTimer() { if (_timer != null || !Buffer.Enabled || Buffer.DisableStorageTimer) { return; } var isProcessing = false; var sync = new SyncObject(); _timer = ThreadingHelper.Timer(() => { lock (sync) { if (isProcessing) { return; } isProcessing = true; } try { var incremental = Settings.IsMode(StorageModes.Incremental); var snapshot = Settings.IsMode(StorageModes.Snapshot); foreach (var pair in Buffer.GetTicks()) { if (incremental) { Settings.GetStorage <ExecutionMessage>(pair.Key, ExecutionTypes.Tick).Save(pair.Value); } } foreach (var pair in Buffer.GetOrderLog()) { if (incremental) { Settings.GetStorage <ExecutionMessage>(pair.Key, ExecutionTypes.OrderLog).Save(pair.Value); } } foreach (var pair in Buffer.GetTransactions()) { var secId = pair.Key; if (incremental) { Settings.GetStorage <ExecutionMessage>(secId, ExecutionTypes.Transaction).Save(pair.Value); } if (snapshot) { var snapshotStorage = GetSnapshotStorage(DataType.Transactions); foreach (var message in pair.Value) { // do not store cancellation commands into snapshot if (message.IsCancellation) { this.AddWarningLog("Cancellation transaction: {0}", message); continue; } var originTransId = message.OriginalTransactionId; if (originTransId == 0) { continue; } if (_cancellationTransactions.TryGetValue(originTransId, out var cancelledId)) { // do not store cancellation errors if (message.Error != null) { continue; } // override cancel trans id by original order's registration trans id originTransId = cancelledId; } else if (_orderStatusIds.Contains(originTransId)) { // override status request trans id by original order's registration trans id originTransId = message.TransactionId; } else if (_replaceTransactions.TryGetAndRemove(originTransId, out var replacedId)) { if (message.Error == null) { var replaced = (ExecutionMessage)snapshotStorage.Get(replacedId); if (replaced == null) { this.AddWarningLog("Replaced order {0} not found.", replacedId); } else { if (replaced.OrderState != OrderStates.Done) { replaced.OrderState = OrderStates.Done; } } } } message.SecurityId = secId; if (message.TransactionId == 0) { message.TransactionId = originTransId; } message.OriginalTransactionId = 0; SaveTransaction(snapshotStorage, message); } } } foreach (var pair in Buffer.GetOrderBooks()) { if (incremental) { Settings.GetStorage <QuoteChangeMessage>(pair.Key, null).Save(pair.Value); } if (snapshot) { var snapshotStorage = GetSnapshotStorage(DataType.MarketDepth); foreach (var message in pair.Value) { snapshotStorage.Update(message); } } } foreach (var pair in Buffer.GetLevel1()) { var messages = pair.Value.Where(m => m.Changes.Count > 0).ToArray(); if (incremental) { Settings.GetStorage <Level1ChangeMessage>(pair.Key, null).Save(messages); } if (Settings.IsMode(StorageModes.Snapshot)) { var snapshotStorage = GetSnapshotStorage(DataType.Level1); foreach (var message in messages) { snapshotStorage.Update(message); } } } foreach (var pair in Buffer.GetCandles()) { Settings.GetStorage(pair.Key.Item1, pair.Key.Item2, pair.Key.Item3).Save(pair.Value); } foreach (var pair in Buffer.GetPositionChanges()) { var messages = pair.Value.Where(m => m.Changes.Count > 0).ToArray(); if (incremental) { Settings.GetStorage <PositionChangeMessage>(pair.Key, null).Save(messages); } if (snapshot) { var snapshotStorage = GetSnapshotStorage(DataType.PositionChanges); foreach (var message in messages) { snapshotStorage.Update(message); } } } var news = Buffer.GetNews().ToArray(); if (news.Length > 0) { Settings.GetStorage <NewsMessage>(default, null).Save(news);
private MarketDataMessage ProcessMarketDataRequest(MarketDataMessage message) { if (message.IsSubscribe) { if (!InnerAdapter.IsMarketDataTypeSupported(MarketDataTypes.OrderLog)) { return(message); } var isBuild = message.BuildMode == MarketDataBuildModes.Build && message.BuildFrom == MarketDataTypes.OrderLog; switch (message.DataType) { case MarketDataTypes.MarketDepth: { if (isBuild || !InnerAdapter.IsMarketDataTypeSupported(message.DataType)) { var secId = GetSecurityId(message.SecurityId); IOrderLogMarketDepthBuilder builder = null; if (InnerAdapter.IsSecurityRequired(DataType.OrderLog)) { builder = InnerAdapter.CreateOrderLogMarketDepthBuilder(secId); } _subscriptionIds.Add(message.TransactionId, RefTuple.Create(secId, true, builder)); message = (MarketDataMessage)message.Clone(); message.DataType = MarketDataTypes.OrderLog; this.AddInfoLog("OL->MD subscribed {0}/{1}.", secId, message.TransactionId); } break; } case MarketDataTypes.Trades: { if (isBuild || !InnerAdapter.IsMarketDataTypeSupported(message.DataType)) { var secId = GetSecurityId(message.SecurityId); _subscriptionIds.Add(message.TransactionId, RefTuple.Create(secId, false, (IOrderLogMarketDepthBuilder)null)); message = (MarketDataMessage)message.Clone(); message.DataType = MarketDataTypes.OrderLog; this.AddInfoLog("OL->TICK subscribed {0}/{1}.", secId, message.TransactionId); } break; } } } else { var tuple = _subscriptionIds.TryGetAndRemove(message.OriginalTransactionId); if (tuple != null) { this.AddInfoLog("OL->{0} unsubscribed {1}/{2}.", tuple.Second ? "MD" : "TICK", tuple.First, message.OriginalTransactionId); } } return(message); }
/// <inheritdoc /> protected override void OnInnerAdapterNewOutMessage(Message message) { var processSuspended = false; switch (message.Type) { case MessageTypes.SubscriptionResponse: { var responseMsg = (SubscriptionResponseMessage)message; if (responseMsg.Error != null) { _transactionLogSubscriptions.Remove(responseMsg.OriginalTransactionId); } break; } case MessageTypes.SubscriptionFinished: case MessageTypes.SubscriptionOnline: { var originMsg = (IOriginalTransactionIdMessage)message; if (!_transactionLogSubscriptions.TryGetAndRemove(originMsg.OriginalTransactionId, out var subscription)) { break; } Tuple <ExecutionMessage, List <ExecutionMessage> >[] tuples; lock (subscription.Sync) tuples = subscription.Transactions.Values.ToArray(); var canProcessFailed = subscription.Original.States.Contains(OrderStates.Failed); foreach (var tuple in tuples) { var order = tuple.Item1; if (order.OrderState == OrderStates.Failed && !canProcessFailed) { if (tuple.Item2.Count > 0) { this.AddWarningLog("Order {0} has failed state but contains {1} trades.", order.TransactionId, tuple.Item2.Count); } continue; } base.OnInnerAdapterNewOutMessage(order); ProcessSuspended(order); foreach (var trade in tuple.Item2) { base.OnInnerAdapterNewOutMessage(trade); } } break; } case MessageTypes.Execution: { var execMsg = (ExecutionMessage)message; if (execMsg.IsMarketData()) { break; } // skip cancellation cause they are reply on action and no have transaction state if (execMsg.IsCancellation) { break; } var transId = execMsg.TransactionId; if (transId != 0) { _secIds.TryAdd(transId, execMsg.SecurityId); } else { if (execMsg.SecurityId == default && _secIds.TryGetValue(execMsg.OriginalTransactionId, out var secId)) { execMsg.SecurityId = secId; } } if (transId != 0 || execMsg.OriginalTransactionId != 0) { if (transId == 0) { transId = execMsg.OriginalTransactionId; } if (execMsg.OrderId != null) { _orderIds.TryAdd(execMsg.OrderId.Value, transId); } else if (!execMsg.OrderStringId.IsEmpty()) { _orderStringIds.TryAdd(execMsg.OrderStringId, transId); } } if (execMsg.TransactionId == 0 && execMsg.HasTradeInfo && _orderStatusIds.Contains(execMsg.OriginalTransactionId)) { // below the code will try find order's transaction execMsg.OriginalTransactionId = 0; } if (/*execMsg.TransactionId == 0 && */ execMsg.OriginalTransactionId == 0) { if (!execMsg.HasTradeInfo) { this.AddWarningLog("Order doesn't have origin trans id: {0}", execMsg); break; } if (execMsg.OrderId != null) { if (_orderIds.TryGetValue(execMsg.OrderId.Value, out var originId)) { execMsg.OriginalTransactionId = originId; } else { this.AddWarningLog("Trade doesn't have origin trans id: {0}", execMsg); break; } } else if (!execMsg.OrderStringId.IsEmpty()) { if (_orderStringIds.TryGetValue(execMsg.OrderStringId, out var originId)) { execMsg.OriginalTransactionId = originId; } else { this.AddWarningLog("Trade doesn't have origin trans id: {0}", execMsg); break; } } } if (execMsg.HasTradeInfo && !execMsg.HasOrderInfo) { if (execMsg.OrderId != null && !_orderIds.ContainsKey(execMsg.OrderId.Value) && (execMsg.OriginalTransactionId == 0 || !_secIds.ContainsKey(execMsg.OriginalTransactionId))) { this.AddInfoLog("{0} suspended.", execMsg); lock (_nonAssociatedLock) _nonAssociatedOrderIds.SafeAdd(execMsg.OrderId.Value).Add(execMsg.TypedClone()); return; } else if (!execMsg.OrderStringId.IsEmpty() && !_orderStringIds.ContainsKey(execMsg.OrderStringId) && (execMsg.OriginalTransactionId == 0 || !_secIds.ContainsKey(execMsg.OriginalTransactionId))) { this.AddInfoLog("{0} suspended.", execMsg); lock (_nonAssociatedLock) _nonAssociatedStringOrderIds.SafeAdd(execMsg.OrderStringId).Add(execMsg.TypedClone()); return; } } if (_transactionLogSubscriptions.Count == 0) { processSuspended = true; break; } if (!_transactionLogSubscriptions.TryGetValue(execMsg.OriginalTransactionId, out var subscription)) { if (!_orders.TryGetValue(execMsg.OriginalTransactionId, out var orderTransId)) { break; } if (!_transactionLogSubscriptions.TryGetValue(orderTransId, out subscription)) { break; } } if (transId == 0) { if (execMsg.HasTradeInfo) { transId = execMsg.OriginalTransactionId; } if (transId == 0) { this.AddWarningLog("Message {0} do not contains transaction id.", execMsg); break; } } lock (subscription.Sync) { if (subscription.Transactions.TryGetValue(transId, out var tuple)) { var snapshot = tuple.Item1; if (execMsg.HasOrderInfo) { if (execMsg.Balance != null) { snapshot.Balance = snapshot.Balance.ApplyNewBalance(execMsg.Balance.Value, transId, this); } if (execMsg.OrderState != null) { snapshot.OrderState = snapshot.OrderState.ApplyNewState(execMsg.OrderState.Value, transId, this); } if (execMsg.OrderStatus != null) { snapshot.OrderStatus = execMsg.OrderStatus; } if (execMsg.OrderId != null) { snapshot.OrderId = execMsg.OrderId; } if (!execMsg.OrderStringId.IsEmpty()) { snapshot.OrderStringId = execMsg.OrderStringId; } if (execMsg.OrderBoardId != null) { snapshot.OrderBoardId = execMsg.OrderBoardId; } if (execMsg.PnL != null) { snapshot.PnL = execMsg.PnL; } if (execMsg.Position != null) { snapshot.Position = execMsg.Position; } if (execMsg.Commission != null) { snapshot.Commission = execMsg.Commission; } if (execMsg.CommissionCurrency != null) { snapshot.CommissionCurrency = execMsg.CommissionCurrency; } if (execMsg.AveragePrice != null) { snapshot.AveragePrice = execMsg.AveragePrice; } if (execMsg.Latency != null) { snapshot.Latency = execMsg.Latency; } } if (execMsg.HasTradeInfo) { var clone = execMsg.TypedClone(); // all order's info in snapshot execMsg.HasTradeInfo = false; clone.HasOrderInfo = false; tuple.Item2.Add(clone); } } else { _orders.Add(transId, execMsg.OriginalTransactionId); subscription.Transactions.Add(transId, Tuple.Create(execMsg.TypedClone(), new List <ExecutionMessage>())); } } return; } } base.OnInnerAdapterNewOutMessage(message); if (processSuspended) { ProcessSuspended((ExecutionMessage)message); } }
/// <inheritdoc /> protected override void OnInnerAdapterNewOutMessage(Message message) { switch (message.Type) { case MessageTypes.SubscriptionResponse: { var responseMsg = (SubscriptionResponseMessage)message; if (responseMsg.Error != null) { _transactionLogSubscriptions.Remove(responseMsg.OriginalTransactionId); } break; } case MessageTypes.SubscriptionFinished: case MessageTypes.SubscriptionOnline: { var originMsg = (IOriginalTransactionIdMessage)message; if (!_transactionLogSubscriptions.TryGetAndRemove(originMsg.OriginalTransactionId, out var subscription)) { break; } foreach (var pair in subscription.Transactions) { base.OnInnerAdapterNewOutMessage(pair.Value.Item1); foreach (var trade in pair.Value.Item2) { base.OnInnerAdapterNewOutMessage(trade); } } break; } case MessageTypes.Execution: { var execMsg = (ExecutionMessage)message; if (execMsg.IsMarketData()) { break; } // skip cancellation cause they are reply on action and no have transaction state if (execMsg.IsCancellation) { break; } var transId = execMsg.TransactionId; if (transId != 0) { _secIds.TryAdd(transId, execMsg.SecurityId); } else { if (execMsg.SecurityId == default && _secIds.TryGetValue(execMsg.OriginalTransactionId, out var secId)) { execMsg.SecurityId = secId; } } if (transId != 0 || execMsg.OriginalTransactionId != 0) { if (transId == 0) { transId = execMsg.OriginalTransactionId; } if (execMsg.OrderId != null) { _orderIds.TryAdd(execMsg.OrderId.Value, transId); } else if (!execMsg.OrderStringId.IsEmpty()) { _orderStringIds.TryAdd(execMsg.OrderStringId, transId); } } if (execMsg.TransactionId == 0 && execMsg.HasTradeInfo && _orderStatusIds.Contains(execMsg.OriginalTransactionId)) { // below the code will try find order's transaction execMsg.OriginalTransactionId = 0; } if (/*execMsg.TransactionId == 0 && */ execMsg.OriginalTransactionId == 0) { if (!execMsg.HasTradeInfo) { this.AddWarningLog("Order doesn't have origin trans id: {0}", execMsg); break; } if (execMsg.OrderId != null) { if (_orderIds.TryGetValue(execMsg.OrderId.Value, out var originId)) { execMsg.OriginalTransactionId = originId; } else { this.AddWarningLog("Trade doesn't have origin trans id: {0}", execMsg); break; } } else if (!execMsg.OrderStringId.IsEmpty()) { if (_orderStringIds.TryGetValue(execMsg.OrderStringId, out var originId)) { execMsg.OriginalTransactionId = originId; } else { this.AddWarningLog("Trade doesn't have origin trans id: {0}", execMsg); break; } } } if (_transactionLogSubscriptions.Count == 0) { break; } if (!_transactionLogSubscriptions.TryGetValue(execMsg.OriginalTransactionId, out var subscription)) { if (!_orders.TryGetValue(execMsg.OriginalTransactionId, out var orderTransId)) { break; } if (!_transactionLogSubscriptions.TryGetValue(orderTransId, out subscription)) { break; } } if (transId == 0) { if (execMsg.HasTradeInfo) { transId = execMsg.OriginalTransactionId; } if (transId == 0) { this.AddWarningLog("Message {0} do not contains transaction id.", execMsg); break; } } lock (subscription.Sync) { if (subscription.Transactions.TryGetValue(transId, out var tuple)) { var snapshot = tuple.Item1; if (execMsg.HasOrderInfo) { if (execMsg.Balance != null) { snapshot.Balance = snapshot.Balance.ApplyNewBalance(execMsg.Balance.Value, transId, this); } if (execMsg.OrderState != null) { snapshot.OrderState = snapshot.OrderState.ApplyNewState(execMsg.OrderState.Value, transId, this); } if (execMsg.OrderStatus != null) { snapshot.OrderStatus = execMsg.OrderStatus; } if (execMsg.OrderId != null) { snapshot.OrderId = execMsg.OrderId; } if (execMsg.OrderStringId != null) { snapshot.OrderStringId = execMsg.OrderStringId; } if (execMsg.OrderBoardId != null) { snapshot.OrderBoardId = execMsg.OrderBoardId; } if (execMsg.PnL != null) { snapshot.PnL = execMsg.PnL; } if (execMsg.Position != null) { snapshot.Position = execMsg.Position; } if (execMsg.Commission != null) { snapshot.Commission = execMsg.Commission; } if (execMsg.CommissionCurrency != null) { snapshot.CommissionCurrency = execMsg.CommissionCurrency; } if (execMsg.AveragePrice != null) { snapshot.AveragePrice = execMsg.AveragePrice; } if (execMsg.Latency != null) { snapshot.Latency = execMsg.Latency; } } if (execMsg.HasTradeInfo) { var clone = execMsg.TypedClone(); // all order's info in snapshot execMsg.HasTradeInfo = false; clone.HasOrderInfo = false; tuple.Item2.Add(clone); } } else { _orders.Add(transId, execMsg.OriginalTransactionId); subscription.Transactions.Add(transId, Tuple.Create(execMsg.TypedClone(), new List <ExecutionMessage>())); } } return; } } base.OnInnerAdapterNewOutMessage(message); }
/// <inheritdoc /> protected override bool OnSendInMessage(Message message) { switch (message.Type) { case MessageTypes.Reset: { _subscriptions.Clear(); _strategyIdMap.Clear(); _strategySubscriptions.Clear(); lock (_sync) _positionManager.ProcessMessage(message); break; } case MessageTypes.PortfolioLookup: { var lookupMsg = (PortfolioLookupMessage)message; if (lookupMsg.IsSubscribe) { if (!lookupMsg.StrategyId.IsEmpty()) { this.AddDebugLog("Subscription (strategy='{1}') {0} added.", lookupMsg.TransactionId, lookupMsg.StrategyId); _strategyIdMap.Add(lookupMsg.TransactionId, lookupMsg.StrategyId); _strategySubscriptions.SafeAdd(lookupMsg.StrategyId).Add(lookupMsg.TransactionId); RaiseNewOutMessage(lookupMsg.CreateResult()); return(true); } if (lookupMsg.To == null) { this.AddDebugLog("Subscription {0} added.", lookupMsg.TransactionId); _subscriptions.Add(lookupMsg.TransactionId); lock (_sync) _positionManager.ProcessMessage(message); } if (IsEmulate) { RaiseNewOutMessage(lookupMsg.CreateResult()); return(true); } } else { if (_subscriptions.Remove(lookupMsg.OriginalTransactionId)) { this.AddDebugLog("Subscription {0} removed.", lookupMsg.OriginalTransactionId); lock (_sync) _positionManager.ProcessMessage(message); } else if (_strategyIdMap.TryGetAndRemove(lookupMsg.OriginalTransactionId, out var strategyId)) { _strategySubscriptions.TryGetValue(strategyId)?.Remove(lookupMsg.OriginalTransactionId); this.AddDebugLog("Subscription (strategy='{1}') {0} removed.", lookupMsg.OriginalTransactionId, strategyId); return(true); } if (IsEmulate) { //RaiseNewOutMessage(lookupMsg.CreateResponse()); return(true); } } break; } default: { lock (_sync) _positionManager.ProcessMessage(message); break; } } return(base.OnSendInMessage(message)); }
/// <inheritdoc /> protected override void OnInnerAdapterNewOutMessage(Message message) { base.OnInnerAdapterNewOutMessage(message); switch (message.Type) { case MessageTypes.SubscriptionResponse: { var response = (SubscriptionResponseMessage)message; if (!response.IsOk()) { lock (_sync) _pending.Remove(response.OriginalTransactionId); } break; } case MessageTypes.SubscriptionFinished: { var finished = (SubscriptionFinishedMessage)message; lock (_sync) _pending.Remove(finished.OriginalTransactionId); break; } case MessageTypes.SubscriptionOnline: { var online = (SubscriptionOnlineMessage)message; ISubscriptionMessage subscrMsg; lock (_sync) { if (!_pending.TryGetAndRemove(online.OriginalTransactionId, out subscrMsg)) { break; } } foreach (var snapshot in _holder.GetSnapshot(subscrMsg)) { if (snapshot is ISubscriptionIdMessage subscrIdMsg) { subscrIdMsg.OriginalTransactionId = online.OriginalTransactionId; subscrIdMsg.SetSubscriptionIds(subscriptionId: online.OriginalTransactionId); } base.OnInnerAdapterNewOutMessage(snapshot); } break; } default: { lock (_sync) { if (_pending.Count > 0 && message is ISubscriptionIdMessage subscrMsg) { foreach (var id in subscrMsg.GetSubscriptionIds()) { _pending.Remove(id); } } } break; } } }
/// <inheritdoc /> protected override bool OnSendInMessage(Message message) { switch (message.Type) { case MessageTypes.Reset: { _infos.Clear(); _infosBySecId.Clear(); break; } case MessageTypes.MarketData: { var mdMsg = (MarketDataMessage)message; if (mdMsg.IsSubscribe) { if (!(mdMsg is FilteredMarketDepthMessage filteredMsg)) { break; } if (mdMsg.SecurityId == default) { break; } var transId = mdMsg.TransactionId; var data = mdMsg.GetArg <Tuple <QuoteChangeMessage, ExecutionMessage[]> >(); var info = new FilteredMarketDepthInfo(filteredMsg.TypedClone(), data.Item2); _infos.Add(transId, info); _infosBySecId.SafeAdd(mdMsg.SecurityId).Add(transId); mdMsg = new MarketDataMessage(); filteredMsg.CopyTo(mdMsg); mdMsg.DataType2 = DataType.MarketDepth; message = mdMsg; RaiseNewOutMessage(info.Process(data.Item1)); } else { if (_infos.TryGetAndRemove(mdMsg.OriginalTransactionId, out var info)) { info.State = SubscriptionStates.Stopped; _infosBySecId.TryGetValue(info.Origin.SecurityId)?.Remove(mdMsg.OriginalTransactionId); var clone = new MarketDataMessage(); mdMsg.CopyTo(clone); message = clone; } } break; } } return(base.OnSendInMessage(message)); }