private async Task <SubscriptionResult> SubscribeAsync(Instrument instrument, SubscriptionFlags flags) { using (LogManager.Scope()) { InstrumentSubscription subscription = null; ContractMetadata metadata = null; var hasSubscriptionLock = false; try { // Получаем параметры подписки на инструмент using (subscriptionsLock.Lock()) { subscriptionsByInstrument.TryGetValue(instrument, out subscription); } if (subscription == null) { // Получаем ID инструмента var contractId = await instrumentResolver.GetContractIdAsync(instrument); if (contractId == uint.MaxValue) { return(SubscriptionResult.Error(instrument, "Symbol is not resolved in tree node for CQG")); } using (subscriptionsLock.Lock()) { if (!subscriptionsByInstrument.TryGetValue(instrument, out subscription)) { if (!subscriptionsByContractId.TryGetValue(contractId, out subscription)) { subscription = new InstrumentSubscription(instrumentResolver, instrument, contractId); // Сразу захватываем блокировку subscription.AcquireFlagsLock(); hasSubscriptionLock = true; subscriptionsByContractId.Add(contractId, subscription); contractMetadatas.TryGetValue(contractId, out metadata); } subscriptionsByInstrument.Add(instrument, subscription); } } } else { // Захватываем блокировку subscription.AcquireFlagsLock(); hasSubscriptionLock = true; } // Подписываемся на инструмент с учетом флагов подписки if ((subscription.Flags & flags) != flags) { // Нужные флаги подписки не проставлены, требуется доподписаться MarketDataSubscription.Level?level = null; switch (subscription.Flags | flags) { case SubscriptionFlags.InstrumentParams: level = MarketDataSubscription.Level.TRADES_BBA_VOLUMES; break; case SubscriptionFlags.OrderBook: level = MarketDataSubscription.Level.TRADES_BBA_DOM; break; case SubscriptionFlags.InstrumentParams | SubscriptionFlags.OrderBook: level = MarketDataSubscription.Level.TRADES_BBA_DOM; break; } if (level != null) { subscription.Flags |= flags; RequestMarketDataSubscription(subscription, level.Value); } } // При необходимости обрабатываем метаданные и выбрасываем события if (metadata != null) { Process(subscription, metadata, (s, data) => s.Handle(data)); } // Готово var result = SubscriptionResult.OK(instrument); return(result); } catch (OperationCanceledException) { _Log.Warn().Print($"Unable to subscribe to {instrument} (operation has been cancelled)"); return(SubscriptionResult.Error(instrument, "Operation has been cancelled")); } catch (Exception e) { _Log.Error().Print(e, $"Unable to subscribe to {instrument}"); return(SubscriptionResult.Error(instrument, e.Message)); } finally { if (subscription != null && hasSubscriptionLock) { subscription.ReleaseFlagsLock(); } } } }
/// <summary> /// Постановка заявки /// </summary> private async void SendTransactionInternal(NewOrderTransaction transaction) { using (LogManager.Scope()) { try { // Получаем счет для транзакции int accountId; var hasAccountId = true; using (accountsLock.ReadLock()) { if (!accountIdsByCode.TryGetValue(transaction.Account, out accountId)) { hasAccountId = false; } } if (!hasAccountId) { OnMessageReceived(TransactionReply.Rejected( transaction, $"Account \"{transaction.Account}\" is unknown")); return; } // Получаем инструмент для транзации uint contractId; try { contractId = await instrumentResolver.GetContractIdAsync(transaction.Instrument); if (contractId == uint.MaxValue) { return; } } catch (OperationCanceledException) { OnMessageReceived(TransactionReply.Rejected( transaction, $"Instrument \"{transaction.Instrument.Code}\" is unknown")); return; } // Пребразовываем цену var price = instrumentResolver.ConvertPrice(contractId, transaction.Price); if (price == null) { OnMessageReceived(TransactionReply.Rejected(transaction, "Unable to convert price")); return; } // Формируем запрос var msg = new OrderRequest { new_order = new NewOrder { order = new WebAPI.Order { cl_order_id = transaction.TransactionId.ToString("N"), account_id = accountId, contract_id = contractId, side = (uint)ConvertionHelper.GetSide(transaction.Operation), order_type = (uint)ConvertionHelper.GetOrderType(transaction.Type), duration = (uint)ConvertionHelper.GetDuration(transaction.ExecutionCondition), limit_price = price.Value, qty = transaction.Quantity, is_manual = transaction.IsManual, user_attribute = { new UserAttribute { name = CommentAttributeName, value = transaction.Comment } } }, suspend = false }, request_id = adapter.GetNextRequestId() }; // Запоминаем заявку using (ordersLock.Lock()) { var order = new Order(transaction); ordersByTransactionId.Add(transaction.TransactionId, order); } // Запоминаем транзакцию StoreTransaction(msg.request_id, transaction); Logger.Debug().PrintFormat("Sending {0}", transaction); adapter.SendMessage(msg); } catch (Exception e) { Logger.Error().Print(e, $"Failed to send {transaction}"); OnMessageReceived(TransactionReply.Rejected(transaction, "Unable to send order")); } } }
private async Task <TimeBarRequest> PrepareTimeBarRequestAsync( Instrument instrument, DateTime begin, DateTime end, HistoryProviderSpan span, TimeBarRequest.RequestType type) { var contractId = await instrumentResolver.GetContractIdAsync(instrument); if (contractId == uint.MaxValue) { return(await Task.FromResult <TimeBarRequest>(null)); } TimeBarParameters.BarUnit barUnit; uint unitsNumber = 0; switch (span) { case HistoryProviderSpan.Minute: barUnit = TimeBarParameters.BarUnit.MIN; unitsNumber = 1; break; case HistoryProviderSpan.Minute5: barUnit = TimeBarParameters.BarUnit.MIN; unitsNumber = 5; break; case HistoryProviderSpan.Minute10: barUnit = TimeBarParameters.BarUnit.MIN; unitsNumber = 10; break; case HistoryProviderSpan.Minute15: barUnit = TimeBarParameters.BarUnit.MIN; unitsNumber = 15; break; case HistoryProviderSpan.Minute30: barUnit = TimeBarParameters.BarUnit.MIN; unitsNumber = 30; break; case HistoryProviderSpan.Hour: barUnit = TimeBarParameters.BarUnit.HOUR; unitsNumber = 1; break; case HistoryProviderSpan.Hour4: barUnit = TimeBarParameters.BarUnit.HOUR; unitsNumber = 4; break; case HistoryProviderSpan.Day: // Для DAY units_number не заполняется barUnit = TimeBarParameters.BarUnit.DAY; break; case HistoryProviderSpan.Week: // Для WEEK units_number не заполняется barUnit = TimeBarParameters.BarUnit.WEEK; break; case HistoryProviderSpan.Month: // Для MONTH units_number не заполняется barUnit = TimeBarParameters.BarUnit.MONTH; break; default: throw new ArgumentOutOfRangeException(nameof(span), span, $"Invalid time span - {span}"); } var message = new TimeBarRequest { request_id = adapter.GetNextRequestId(), request_type = (uint)type, time_bar_parameters = new TimeBarParameters { contract_id = contractId, bar_unit = (uint)barUnit, units_number = unitsNumber, from_utc_time = adapter.ResolveDateTime(begin), to_utc_time = adapter.ResolveDateTime(end) } }; return(message); }