private void InfoClient_OnInfoTrade(InfoTrade trade) { if (trade.acc_id == 0 || !mapAccountIdToAccount.ContainsKey(trade.acc_id)) { return; } var code = trade.security + "|" + trade.board; var instrument = connector.ResolveSymbolAsync(code).Result; if (instrument == null) { Logger.Error().Print($"Unable to resolve instrument for {code}"); return; } var fill = new FillMessage { Account = mapAccountIdToAccount[trade.acc_id].code, Instrument = instrument, ExchangeId = trade.code, Operation = trade.buy_sell == BuySell.BUY ? OrderOperation.Buy : OrderOperation.Sell, Price = PriceHelper.ToPrice(trade.price), Quantity = trade.qty, DateTime = DateTime.FromFileTime((long)trade.trade_time), ExchangeOrderId = trade.order_id }; OnMessageReceived(fill); }
public async Task <List <AssetModel> > HarvestAssetList(string strServiceUri) { var objMessage = new FillMessage(); var lstUris = new List <Uri>(); var lstAssets = new List <AssetModel>(); try { var resultObject = await GetHarvestList(strServiceUri); var bulkUpdates = resultObject.Products.FirstOrDefault()?.BulkUpdates; bulkUpdates.ForEach( bf => bf.BulkFiles.ForEach( harvest => Helpers.ExtractFileInformation(harvest.Location, lstUris, lstAssets) )); return(lstAssets); } catch (Exception ex) { Console.WriteLine(ex.Message); } return(null); }
public override void execDetails(int reqId, Contract contract, Execution execution) { //Сделки с нулевым количеством //Пропускаем BAG, т.к. это контракт для конструкций. Сейчас мы его не используем. //BAG is the security type for COMBO order //https://www.interactivebrokers.com/en/software/api/apiguide/c/placing_a_combination_order.htm //https://www.interactivebrokers.com/en/software/api/apiguide/tables/api_message_codes.htm if (contract.SecType == "BAG") { return; } Log.Debug().PrintFormat("< execDetails {0} {1} {2} {3}", reqId, contract.ConId, execution.ExecId); connector.ContractContainer.GetInstrumentAsync( contract, string.Format("A fill on order \"{0}\", account \"{1}\"", execution.ExecId, execution.AcctNumber), async instrument => { var fill = new FillMessage { Account = execution.AcctNumber, Instrument = instrument, DateTime = ParseExecutionTime(execution.Time), ExchangeId = execution.ExecId, ExchangeOrderId = execution.PermId.ToString(CultureInfo.InvariantCulture), Operation = execution.Side == "BOT" ? OrderOperation.Buy : OrderOperation.Sell, Price = (decimal)execution.Price, Quantity = (uint)execution.CumQty }; // В случае частичного исполнения заявки мы запоминаем прежнее значение CumQty // и в соответствии с ним пересчитываем fill.Quantity using (lastExecCumQtiesLock.Lock()) { var orderKey = new Tuple <Instrument, int>(instrument, execution.PermId); int lastQty; if (lastExecCumQties.TryGetValue(orderKey, out lastQty)) { fill.Quantity = (uint)(execution.CumQty - lastQty); } lastExecCumQties[orderKey] = execution.CumQty; } // Ждём пока в наш адаптер не придут данные по заявке await orderInfoContainer.WaitOrderForFill(execution); // Выплевываем наружу сообщение connector.IBOrderRouter.Transmit(fill); }); }
/// <summary> /// Сгенерировать <see cref="FillMessage"/> /// </summary> private void TryEmitFills(OrderStatus orderStatus, Order order) { if (orderStatus.transaction_status != null) { foreach (var transactionStatus in orderStatus.transaction_status) { switch ((TransactionStatus.Status)transactionStatus.status) { case TransactionStatus.Status.FILL: if (transactionStatus.trade == null) { continue; } foreach (var trade in transactionStatus.trade) { if (trade != null) { using (processedFillsLock.Lock()) { if (!processedFillIds.Add(trade.trade_id)) { // Сделка уже обработана continue; } } var fill = new FillMessage { Instrument = order.Instrument, DateTime = adapter.ResolveDateTime(trade.trade_utc_time), Account = order.Account, Operation = ConvertionHelper.GetOrderOperation((WebAPI.Order.Side)trade.side), Price = instrumentResolver.ConvertPriceBack(trade.contract_id, trade.price), Quantity = trade.qty, ExchangeId = trade.trade_id, ExchangeOrderId = order.OrderExchangeId }; OnMessageReceived(fill); } } break; } } } }
/// <summary> /// Сохраняет свою сделку. /// </summary> /// <param name="fill">Данные своей сделки.</param> protected void AddFill(FillMessage fill) { if (!storeFillsInMemory) { return; } if (!IsPermittedAccount(fill.Account)) { return; } using (SyncRoot.Lock()) { Dictionary <Instrument, List <FillMessage> > accountFills; if (!AvailableAccounts.Contains(fill.Account)) { AvailableAccounts.Add(fill.Account); accountFills = new Dictionary <Instrument, List <FillMessage> >(); Fills.Add(fill.Account, accountFills); } else { accountFills = Fills[fill.Account]; } List <FillMessage> instrumentFills; if (!accountFills.TryGetValue(fill.Instrument, out instrumentFills)) { instrumentFills = new List <FillMessage>(); accountFills.Add(fill.Instrument, instrumentFills); } instrumentFills.Add(fill); } }
/// <summary> /// Выплюнуть из раутера сообщение /// </summary> /// <param name="message"> /// Сообщение /// </param> internal void Transmit(FillMessage message) { OnMessageReceived(message); }
private async void Handle(ExecutionReport msg) { var clOrderId = msg.ClOrdID.Obj; string origClOrderId = null; if (msg.IsSetOrigClOrdID()) { origClOrderId = msg.OrigClOrdID.Obj; } var state = msg.IsSetOrdStatus() ? ConvertOrderState(msg.OrdStatus) : null; var price = msg.IsSetPrice() ? msg.Price.Obj : (decimal?)null; price = price != 0M ? price : null; var qty = msg.IsSetOrderQty() ? (uint)msg.OrderQty.Obj : (uint?)null; var filledQty = msg.IsSetLastQty() ? (uint)msg.LastQty.Obj : (uint?)null; var activeQty = msg.IsSetLeavesQty() ? (uint)msg.LeavesQty.Obj : (uint?)null; var time = msg.IsSetTransactTime() ? ParseTransactTime() : DateTime.Now; var orderExchangeId = msg.IsSetOrderID() ? msg.OrderID.Obj : null; var transactionId = _orders.GetOrCreateOrderTransactionId(origClOrderId ?? clOrderId); var oscm = new OrderStateChangeMessage { TransactionId = transactionId, State = state, Price = price, Quantity = qty, FilledQuantity = filledQty, ActiveQuantity = activeQty, ChangeTime = time, OrderExchangeId = orderExchangeId }; switch (msg.ExecType.Obj) { case ExecType.NEW: _newOrderTransactions.Accept(clOrderId); _orders.SaveOrderExchangeId(transactionId, orderExchangeId); SendMessage(oscm); break; case ExecType.TRADE: _newOrderTransactions.Accept(clOrderId); _orders.SaveOrderExchangeId(transactionId, orderExchangeId); SendMessage(oscm); await EmitFillAsync(); if (oscm.State == OrderState.Filled) { _newOrderTransactions.Forget(transactionId); _killOrderTransactions.Forget(msg.ClOrdID.Obj); _orders.ForgetOrder(transactionId); } break; case ExecType.FILL: _newOrderTransactions.Accept(clOrderId); _orders.SaveOrderExchangeId(transactionId, orderExchangeId); SendMessage(oscm); await EmitFillAsync(); if (oscm.State == OrderState.Filled) { _newOrderTransactions.Forget(transactionId); _killOrderTransactions.Forget(msg.ClOrdID.Obj); _orders.ForgetOrder(transactionId); } break; case ExecType.PARTIAL_FILL: _newOrderTransactions.Accept(clOrderId); _orders.SaveOrderExchangeId(transactionId, orderExchangeId); SendMessage(oscm); await EmitFillAsync(); break; case ExecType.REJECTED: string rejectReason; switch (msg.OrdRejReason.Obj) { case OrdRejReason.UNKNOWN_SYMBOL: rejectReason = "Unknown symbol"; break; case OrdRejReason.EXCHANGE_CLOSED: rejectReason = "Exchange closed"; break; case OrdRejReason.ORDER_EXCEEDS_LIMIT: rejectReason = "Order exceeds limit"; break; case OrdRejReason.DUPLICATE_ORDER: rejectReason = "Duplicate order"; break; default: rejectReason = $"#{msg.OrdRejReason.Obj}"; break; } if (!string.IsNullOrEmpty(msg.Text?.Obj)) { rejectReason = $"{rejectReason}. {msg.Text?.Obj}"; } _newOrderTransactions.Reject(clOrderId, rejectReason); _orders.ForgetOrder(transactionId); break; case ExecType.PENDING_CANCEL: _killOrderTransactions.Accept(msg.ClOrdID.Obj); SendMessage(oscm); break; case ExecType.CANCELED: _killOrderTransactions.Accept(msg.ClOrdID.Obj); _newOrderTransactions.Forget(transactionId); _killOrderTransactions.Forget(msg.ClOrdID.Obj); _orders.ForgetOrder(transactionId); SendMessage(oscm); break; case ExecType.PENDING_REPLACE: _modifyOrderTransactions.Accept(clOrderId); break; case ExecType.REPLACED: _newOrderTransactions.Forget(origClOrderId); _killOrderTransactions.Forget(clOrderId); _orders.UpdateOrderParams( orderExchangeId: orderExchangeId, origClOrderId: origClOrderId, clOrderId: clOrderId, symbol: msg.Symbol.Obj, qty: msg.OrderQty.Obj, side: msg.Side.Obj); SendMessage(oscm); break; default: _Log.Warn().PrintFormat("Unknown ExecType: {0}", msg.ExecType.Obj); break; } OrderState?ConvertOrderState(OrdStatus field) { switch (field.Obj) { case OrdStatus.PENDING_NEW: return(OrderState.New); case OrdStatus.NEW: return(OrderState.Active); case OrdStatus.CANCELED: return(OrderState.Cancelled); case OrdStatus.FILLED: return(OrderState.Filled); case OrdStatus.PARTIALLY_FILLED: return(OrderState.PartiallyFilled); case OrdStatus.REJECTED: return(OrderState.Error); case OrdStatus.PENDING_CANCEL: return(null); case OrdStatus.PENDING_REPLACE: return(null); default: _Log.Warn().PrintFormat("Unknown OrdStatus: {0}", field.Obj); return(null); } } DateTime ParseTransactTime() { var maxLen = "20170912-09:39:57.2761221".Length; var str = msg.GetString(60 /*TransactTime*/); if (str.Length > maxLen) { str = str.Substring(0, maxLen); } var t = DateTime.ParseExact(str, "yyyyMMdd-HH:mm:ss.fffffff", null, DateTimeStyles.AssumeUniversal); return(t); } async Task EmitFillAsync() { if (!msg.IsSetSecondaryExecID()) { return; } var fillExchangeId = msg.SecondaryExecID.Obj; var fillPrice = msg.IsSetLastPx() ? msg.LastPx.Obj : (decimal?)null; price = price != 0M ? price : null; var fillQty = msg.IsSetLastQty() ? (uint)msg.LastQty.Obj : (uint?)null; if (fillPrice == null || fillQty == null) { return; } Instrument instrument; try { instrument = await _settings.InstrumentConverter.ResolveSymbolAsync(this, msg.Symbol.Obj); } catch (Exception e) { _Log.Error().Print(e, $"Failed to resolve instrument {msg.Symbol.Obj}"); return; } var fill = new FillMessage { Price = fillPrice.Value, Quantity = fillQty.Value, DateTime = time, Instrument = instrument, Account = msg.Account.Obj, Operation = msg.Side.Obj == Side.BUY ? OrderOperation.Buy : OrderOperation.Sell, ExchangeId = fillExchangeId, ExchangeOrderId = orderExchangeId }; SendMessage(fill); } }