private async Task ProcessMessageAsync(ExecutionEvent message) { var trades = new List <TradeEntity>(); foreach (var order in message.Orders) { var orderEntity = _mapper.Map <OrderEntity>(order); if (order.Trades == null) { continue; } foreach (var trade in order.Trades) { var tradeEntity = _mapper.Map <TradeEntity>(trade); tradeEntity.AssetPairId = orderEntity.AssetPairId; tradeEntity.OrderId = orderEntity.Id; tradeEntity.PartitionKey = orderEntity.WalletId; tradeEntity.WalletId = orderEntity.WalletId; trades.Add(tradeEntity); } } var tradesByWallet = trades.GroupBy(x => x.WalletId); var tasks = new List <Task>(); foreach (var walletTrades in tradesByWallet) { var tradeUpdate = new TradeUpdate(); tradeUpdate.Trades.AddRange(_mapper.Map <List <Lykke.HftApi.ApiContract.Trade> >(walletTrades.ToList())); tasks.Add(_tradeStream.WriteToStreamAsync(tradeUpdate, walletTrades.Key)); } await Task.WhenAll(tasks); }
/// <summary> /// Deserialize JSON and raise <see cref="UserDataEventArgs"/> event. /// </summary> /// <param name="json"></param> /// <param name="token"></param> /// <param name="callback"></param> /// <returns></returns> protected override void DeserializeJsonAndRaiseEvent(string json, CancellationToken token, Action <UserDataEventArgs> callback = null) { Throw.IfNullOrWhiteSpace(json, nameof(json)); Logger?.LogDebug($"{nameof(UserDataWebSocketClient)}: \"{json}\""); try { var jObject = JObject.Parse(json); var eventType = jObject["e"].Value <string>(); var eventTime = jObject["E"].Value <long>(); // ReSharper disable once ConvertIfStatementToSwitchStatement if (eventType == "outboundAccountInfo") { var commissions = new AccountCommissions( jObject["m"].Value <int>(), // maker jObject["t"].Value <int>(), // taker jObject["b"].Value <int>(), // buyer jObject["s"].Value <int>()); // seller var status = new AccountStatus( jObject["T"].Value <bool>(), // can trade jObject["W"].Value <bool>(), // can withdraw jObject["D"].Value <bool>()); // can deposit var balances = jObject["B"] .Select(entry => new AccountBalance( entry["a"].Value <string>(), // asset entry["f"].Value <decimal>(), // free amount entry["l"].Value <decimal>())) // locked amount .ToList(); var eventArgs = new AccountUpdateEventArgs(eventTime, token, new AccountInfo(User, commissions, status, jObject["u"].Value <long>(), balances)); try { callback?.Invoke(eventArgs); AccountUpdate?.Invoke(this, eventArgs); } catch (OperationCanceledException) { } catch (Exception e) { if (!token.IsCancellationRequested) { Logger?.LogError(e, $"{nameof(UserDataWebSocketClient)}: Unhandled account update event handler exception."); } } } else if (eventType == "executionReport") { var order = new Order(User); FillOrder(order, jObject); var executionType = ConvertOrderExecutionType(jObject["x"].Value <string>()); var rejectedReason = ConvertOrderRejectedReason(jObject["r"].Value <string>()); var newClientOrderId = jObject["c"].Value <string>(); if (executionType == OrderExecutionType.Trade) // trade update event. { var trade = new AccountTrade( jObject["s"].Value <string>(), // symbol jObject["t"].Value <long>(), // ID jObject["i"].Value <long>(), // order ID jObject["L"].Value <decimal>(), // price (price of last filled trade) jObject["z"].Value <decimal>(), // quantity (accumulated quantity of filled trades) jObject["n"].Value <decimal>(), // commission jObject["N"].Value <string>(), // commission asset jObject["T"].Value <long>(), // timestamp order.Side == OrderSide.Buy, // is buyer jObject["m"].Value <bool>(), // is buyer maker jObject["M"].Value <bool>()); // is best price var quantityOfLastFilledTrade = jObject["l"].Value <decimal>(); var eventArgs = new AccountTradeUpdateEventArgs(eventTime, token, order, rejectedReason, newClientOrderId, trade, quantityOfLastFilledTrade); try { callback?.Invoke(eventArgs); TradeUpdate?.Invoke(this, eventArgs); } catch (OperationCanceledException) { } catch (Exception e) { if (!token.IsCancellationRequested) { Logger?.LogError(e, $"{nameof(UserDataWebSocketClient)}: Unhandled trade update event handler exception."); } } } else // order update event. { var eventArgs = new OrderUpdateEventArgs(eventTime, token, order, executionType, rejectedReason, newClientOrderId); try { callback?.Invoke(eventArgs); OrderUpdate?.Invoke(this, eventArgs); } catch (OperationCanceledException) { } catch (Exception e) { if (!token.IsCancellationRequested) { Logger?.LogError(e, $"{nameof(UserDataWebSocketClient)}: Unhandled order update event handler exception."); } } } } else { Logger?.LogWarning($"{nameof(UserDataWebSocketClient)}.{nameof(DeserializeJsonAndRaiseEvent)}: Unexpected event type ({eventType}) - \"{json}\""); } } catch (OperationCanceledException) { } catch (Exception e) { if (!token.IsCancellationRequested) { Logger?.LogError(e, $"{nameof(UserDataWebSocketClient)}.{nameof(DeserializeJsonAndRaiseEvent)}"); } } }
protected override void HandleMessage(IEnumerable <Action <UserDataEventArgs> > callbacks, string stream, string json) { if (!Users.ContainsKey(stream)) { Logger?.LogError($"{nameof(UserDataClient)}.{nameof(HandleMessage)}: Unknown listen key (\"{stream}\"). [thread: {Thread.CurrentThread.ManagedThreadId}]"); return; // ignore. } var user = Users[stream]; try { var jObject = JObject.Parse(json); var eventType = jObject["e"].Value <string>(); var eventTime = jObject["E"].Value <long>().ToDateTime(); // ReSharper disable once ConvertIfStatementToSwitchStatement if (eventType == "outboundAccountInfo") { var commissions = new AccountCommissions( jObject["m"].Value <int>(), // maker jObject["t"].Value <int>(), // taker jObject["b"].Value <int>(), // buyer jObject["s"].Value <int>()); // seller var status = new AccountStatus( jObject["T"].Value <bool>(), // can trade jObject["W"].Value <bool>(), // can withdraw jObject["D"].Value <bool>()); // can deposit var balances = jObject["B"] .Select(entry => new AccountBalance( entry["a"].Value <string>(), // asset entry["f"].Value <decimal>(), // free amount entry["l"].Value <decimal>())) // locked amount .ToList(); var eventArgs = new AccountUpdateEventArgs(eventTime, new AccountInfo(user, commissions, status, jObject["u"].Value <long>().ToDateTime(), balances)); try { // ReSharper disable once InconsistentlySynchronizedField if (_accountUpdateSubscribers.TryGetValue(stream, out var subscribers)) { foreach (var subcriber in subscribers) { subcriber(eventArgs); } } if (callbacks != null) { foreach (var callback in callbacks) { callback(eventArgs); } } AccountUpdate?.Invoke(this, eventArgs); } catch (OperationCanceledException) { /* ignore */ } catch (Exception e) { Logger?.LogWarning(e, $"{nameof(UserDataClient)}.{nameof(HandleMessage)}: Unhandled account update event handler exception."); } } else if (eventType == "executionReport") { var order = new Order(user); FillOrder(order, jObject); var executionType = ConvertOrderExecutionType(jObject["x"].Value <string>()); var rejectedReason = jObject["r"].Value <string>(); var newClientOrderId = jObject["c"].Value <string>(); if (executionType == OrderExecutionType.Trade) // trade update event. { var trade = new AccountTrade( jObject["s"].Value <string>(), // symbol jObject["t"].Value <long>(), // ID jObject["i"].Value <long>(), // order ID jObject["L"].Value <decimal>(), // price (price of last filled trade) jObject["z"].Value <decimal>(), // quantity (accumulated quantity of filled trades) jObject["n"].Value <decimal>(), // commission jObject["N"].Value <string>(), // commission asset jObject["T"].Value <long>() .ToDateTime(), // time order.Side == OrderSide.Buy, // is buyer jObject["m"].Value <bool>(), // is buyer maker jObject["M"].Value <bool>()); // is best price var quantityOfLastFilledTrade = jObject["l"].Value <decimal>(); var eventArgs = new AccountTradeUpdateEventArgs(eventTime, order, rejectedReason, newClientOrderId, trade, quantityOfLastFilledTrade); try { // ReSharper disable once InconsistentlySynchronizedField if (_accountTradeUpdateSubscribers.TryGetValue(stream, out var subscribers)) { foreach (var subcriber in subscribers) { subcriber(eventArgs); } } if (callbacks != null) { foreach (var callback in callbacks) { callback(eventArgs); } } TradeUpdate?.Invoke(this, eventArgs); } catch (OperationCanceledException) { /* ignore */ } catch (Exception e) { Logger?.LogWarning(e, $"{nameof(UserDataClient)}.{nameof(HandleMessage)}: Unhandled trade update event handler exception."); } } else // order update event. { var eventArgs = new OrderUpdateEventArgs(eventTime, order, executionType, rejectedReason, newClientOrderId); try { // ReSharper disable once InconsistentlySynchronizedField if (_orderUpdateSubscribers.TryGetValue(stream, out var subscribers)) { foreach (var subcriber in subscribers) { subcriber(eventArgs); } } if (callbacks != null) { foreach (var callback in callbacks) { callback(eventArgs); } } OrderUpdate?.Invoke(this, eventArgs); } catch (OperationCanceledException) { /* ignore */ } catch (Exception e) { Logger?.LogWarning(e, $"{nameof(UserDataClient)}.{nameof(HandleMessage)}: Unhandled order update event handler exception."); } } } else { Logger?.LogWarning($"{nameof(UserDataClient)}.{nameof(HandleMessage)}: Unexpected event type ({eventType})."); } } catch (OperationCanceledException) { /* ignore */ } catch (Exception e) { Logger?.LogError(e, $"{nameof(UserDataClient)}.{nameof(HandleMessage)}"); } }
private static void addToUpdatersList( TradeUpdate[] updaters, MamaFieldDescriptor fieldDesc, TradeUpdate updater) { if (fieldDesc == null) return; int fieldId = fieldDesc.getFid(); if (fieldId <= mMaxFid) { updaters[fieldId] = updater; } }
private static TradeUpdate[] createUpdaters() { mMaxFid = MamdaTradeFields.getMaxFid(); TradeUpdate[] updaters = new TradeUpdate[mMaxFid + 1]; addToUpdatersList(updaters, MamdaTradeFields.SYMBOL, new MamdaTradeSymbol()); addToUpdatersList(updaters, MamdaTradeFields.ISSUE_SYMBOL, new MamdaTradeIssueSymbol()); addToUpdatersList(updaters, MamdaTradeFields.PART_ID, new TradeLastPartId()); addToUpdatersList(updaters, MamdaTradeFields.TRADE_ID, new TradeId()); addToUpdatersList(updaters, MamdaTradeFields.ORIG_TRADE_ID, new OrigTradeId()); addToUpdatersList(updaters, MamdaTradeFields.CORR_TRADE_ID, new CorrTradeId()); addToUpdatersList(updaters, MamdaTradeFields.SRC_TIME, new TradeSrcTime()); addToUpdatersList(updaters, MamdaTradeFields.ACTIVITY_TIME, new TradeActivityTime()); addToUpdatersList(updaters, MamdaTradeFields.LINE_TIME, new TradeLineTime()); addToUpdatersList(updaters, MamdaTradeFields.SEND_TIME, new TradeSendTime()); addToUpdatersList(updaters, MamdaTradeFields.PUB_ID, new TradePubId()); addToUpdatersList(updaters, MamdaTradeFields.TRADE_PRICE, new TradeLastPrice()); addToUpdatersList(updaters, MamdaTradeFields.TRADE_SIZE, new TradeLastVolume()); addToUpdatersList(updaters, MamdaTradeFields.TRADE_TIME, new TradeLastTime()); addToUpdatersList(updaters, MamdaTradeFields.TRADE_DATE, new TradeTradeDate()); addToUpdatersList(updaters, MamdaTradeFields.TRADE_DIRECTION, new TradeDirection()); addToUpdatersList(updaters, MamdaTradeFields.AGGRESSOR_SIDE, new AggressorSide()); addToUpdatersList(updaters, MamdaTradeFields.TRADE_SIDE, new TradeSide()); addToUpdatersList(updaters, MamdaTradeFields.NET_CHANGE, new TradeNetChange()); addToUpdatersList(updaters, MamdaTradeFields.PCT_CHANGE, new TradePctChange()); addToUpdatersList(updaters, MamdaTradeFields.TOTAL_VOLUME, new TradeAccVolume()); addToUpdatersList(updaters, MamdaTradeFields.OFF_EXCHANGE_TOTAL_VOLUME, new TradeOffExAccVolume()); addToUpdatersList(updaters, MamdaTradeFields.ON_EXCHANGE_TOTAL_VOLUME, new TradeOnExAccVolume()); addToUpdatersList(updaters, MamdaTradeFields.HIGH_PRICE, new TradeHighPrice()); addToUpdatersList(updaters, MamdaTradeFields.LOW_PRICE, new TradeLowPrice()); addToUpdatersList(updaters, MamdaTradeFields.OPEN_PRICE, new TradeOpenPrice()); addToUpdatersList(updaters, MamdaTradeFields.CLOSE_PRICE, new TradeClosePrice()); addToUpdatersList(updaters, MamdaTradeFields.PREV_CLOSE_PRICE, new TradePrevClosePrice()); addToUpdatersList(updaters, MamdaTradeFields.TRADE_SEQNUM, new TradeEventSeqNum()); addToUpdatersList(updaters, MamdaTradeFields.SHORT_SALE_CIRCUIT_BREAKER, new MamdaShortSaleCircuitBreaker()); addToUpdatersList(updaters, MamdaTradeFields.ORIG_SHORT_SALE_CIRCUIT_BREAKER, new MamdaOrigShortSaleCircuitBreaker()); addToUpdatersList(updaters, MamdaTradeFields.CORR_SHORT_SALE_CIRCUIT_BREAKER, new MamdaCorrShortSaleCircuitBreaker()); addToUpdatersList(updaters, MamdaTradeFields.TRADE_QUALIFIER, new TradeQualStr()); addToUpdatersList(updaters, MamdaTradeFields.SALE_CONDITION, new TradeQualNativeStr()); addToUpdatersList(updaters, MamdaTradeFields.TRADE_PART_ID, new TradeLastPartId()); addToUpdatersList(updaters, MamdaTradeFields.TOTAL_VALUE, new TradeTotalValue()); addToUpdatersList(updaters, MamdaTradeFields.OFF_EXCHANGE_TOTAL_VALUE, new TradeOffExTotalValue()); addToUpdatersList(updaters, MamdaTradeFields.ON_EXCHANGE_TOTAL_VALUE, new TradeOnExTotalValue()); addToUpdatersList(updaters, MamdaTradeFields.VWAP, new TradeVWap()); addToUpdatersList(updaters, MamdaTradeFields.OFF_EXCHANGE_VWAP, new TradeOffExVWap()); addToUpdatersList(updaters, MamdaTradeFields.ON_EXCHANGE_VWAP, new TradeOnExVWap()); addToUpdatersList(updaters, MamdaTradeFields.STD_DEV, new TradeStdDev()); addToUpdatersList(updaters, MamdaTradeFields.STD_DEV_SUM, new TradeStdDevSum()); addToUpdatersList(updaters, MamdaTradeFields.STD_DEV_SUM_SQUARES, new TradeStdDevSumSquares()); addToUpdatersList(updaters, MamdaTradeFields.ORDER_ID, new TradeOrderId()); addToUpdatersList(updaters, MamdaTradeFields.SETTLE_PRICE, new TradeSettlePrice()); addToUpdatersList(updaters, MamdaTradeFields.SETTLE_DATE, new TradeSettleDate()); addToUpdatersList(updaters, MamdaTradeFields.SELLERS_SALE_DAYS, new TradeSellerSalesDays()); addToUpdatersList(updaters, MamdaTradeFields.STOP_STOCK_IND, new TradeStopStockInd()); addToUpdatersList(updaters, MamdaTradeFields.TRADE_EXEC_VENUE, new TradeExecVenue()); addToUpdatersList(updaters, MamdaTradeFields.OFF_EXCHANGE_TRADE_PRICE, new OffExTradePrice()); addToUpdatersList(updaters, MamdaTradeFields.ON_EXCHANGE_TRADE_PRICE, new OnExTradePrice()); addToUpdatersList(updaters, MamdaTradeFields.IS_IRREGULAR, new TradeIsIrregular()); addToUpdatersList(updaters, MamdaTradeFields.ORIG_PART_ID, new TradeOrigPartId()); addToUpdatersList(updaters, MamdaTradeFields.ORIG_PRICE, new TradeOrigPrice()); addToUpdatersList(updaters, MamdaTradeFields.ORIG_SIZE, new TradeOrigVolume()); addToUpdatersList(updaters, MamdaTradeFields.ORIG_SEQNUM, new TradeOrigSeqNum()); addToUpdatersList(updaters, MamdaTradeFields.ORIG_TRADE_QUALIFIER, new TradeOrigQualStr()); addToUpdatersList(updaters, MamdaTradeFields.ORIG_SALE_CONDITION, new TradeOrigQualNativeStr()); addToUpdatersList(updaters, MamdaTradeFields.ORIG_SELLERS_SALE_DAYS, new TradeOrigSellersSaleDays()); addToUpdatersList(updaters, MamdaTradeFields.ORIG_STOP_STOCK_IND, new TradeOrigStopStockInd()); addToUpdatersList(updaters, MamdaTradeFields.CORR_PART_ID, new TradeCorrPartId()); addToUpdatersList(updaters, MamdaTradeFields.CORR_PRICE, new TradeCorrPrice()); addToUpdatersList(updaters, MamdaTradeFields.CORR_SIZE, new TradeCorrVolume()); addToUpdatersList(updaters, MamdaTradeFields.CORR_TRADE_QUALIFIER, new TradeCorrQualStr()); addToUpdatersList(updaters, MamdaTradeFields.CORR_SALE_CONDITION, new TradeCorrQualNativeStr()); addToUpdatersList(updaters, MamdaTradeFields.CORR_SELLERS_SALE_DAYS, new TradeCorrSellersSaleDays()); addToUpdatersList(updaters, MamdaTradeFields.CORR_STOP_STOCK_IND, new TradeCorrStopStockInd()); addToUpdatersList(updaters, MamdaTradeFields.CORR_TIME, new TradeCorrTime()); addToUpdatersList(updaters, MamdaTradeFields.CANCEL_TIME, new TradeCancelTime()); addToUpdatersList(updaters, MamdaTradeFields.TRADE_COUNT, new TradeCount()); addToUpdatersList(updaters, MamdaTradeFields.CONFLATE_COUNT, new TradeConflateCount()); addToUpdatersList(updaters, MamdaTradeFields.TRADE_UNITS, new TradeUnits()); addToUpdatersList(updaters, MamdaTradeFields.HIGH_SEQNUM, new TradeHighSeqNum()); addToUpdatersList(updaters, MamdaTradeFields.LOW_SEQNUM, new TradeLowSeqNum()); addToUpdatersList(updaters, MamdaTradeFields.LAST_SEQNUM, new TradeLastSeqNum()); addToUpdatersList(updaters, MamdaTradeFields.TOTAL_VOLUME_SEQNUM, new TradeTotalVolumeSeqNum()); addToUpdatersList(updaters, MamdaTradeFields.CURRENCY_CODE, new TradeCurrencyCode()); addToUpdatersList(updaters, MamdaTradeFields.BLOCK_COUNT, new TradeBlockCount()); addToUpdatersList(updaters, MamdaTradeFields.BLOCK_VOLUME, new TradeBlockVolume()); addToUpdatersList(updaters, MamdaTradeFields.PREV_CLOSE_DATE, new TradePrevCloseDate()); addToUpdatersList(updaters, MamdaTradeFields.ADJ_PREV_CLOSE, new TradeAdjPrevClose()); addToUpdatersList(updaters, MamdaTradeFields.IRREG_PRICE, new TradeIrregPrice()); addToUpdatersList(updaters, MamdaTradeFields.IRREG_SIZE, new TradeIrregVolume()); addToUpdatersList(updaters, MamdaTradeFields.IRREG_PART_ID, new TradeIrregPartId()); addToUpdatersList(updaters, MamdaTradeFields.IRREG_TIME, new TradeIrregTime()); addToUpdatersList(updaters, MamdaTradeFields.UPDATE_AS_TRADE, new TradeUpdateAsTrade()); return updaters; }
private static void MarketDataSource_TradeUpdateEvent(TradeUpdate tradeUpdate) { Console.WriteLine("Client Id " + tradeUpdate.ClientId + " Product Type " + tradeUpdate.Product + " Order Type " + tradeUpdate.OrderType + " Trade Price " + tradeUpdate.TradePrice + " Traded Qty " + tradeUpdate.TradeQuantity + " Filled Qty " + tradeUpdate.FilledQty); }
public void Start() { _pricesReader.SubscribeToChanges(prices => { foreach (var price in prices) { _priceStraem.WriteToStream(_mapper.Map <PriceUpdate>(price)); } }); _tickerReader.SubscribeToChanges(tickers => { foreach (var ticker in tickers) { _tickerStream.WriteToStream(_mapper.Map <TickerUpdate>(ticker)); } }); _orderbookReader.SubscribeToChanges(orderbooks => { foreach (var orderbook in orderbooks) { var item = _mapper.Map <Orderbook>(orderbook); item.Asks.AddRange(_mapper.Map <List <Orderbook.Types.PriceVolume> >(orderbook.Asks)); item.Bids.AddRange(_mapper.Map <List <Orderbook.Types.PriceVolume> >(orderbook.Bids)); _orderbookStream.WriteToStream(item, orderbook.AssetPairId); } }); _balanceReader.SubscribeToChanges(balances => { var balancesByWallet = balances.GroupBy(x => x.WalletId); foreach (var walletBalanes in balancesByWallet) { var balanceUpdate = new BalanceUpdate(); balanceUpdate.Balances.AddRange(_mapper.Map <List <Balance> >(walletBalanes.ToList())); _balanceStream.WriteToStream(balanceUpdate, walletBalanes.Key); } }); _orderReader.SubscribeToChanges(ordersEntities => { var ordersByWallet = ordersEntities.GroupBy(x => x.WalletId); foreach (var walletOrders in ordersByWallet) { var orderUpdate = new OrderUpdate(); orderUpdate.Orders.AddRange(_mapper.Map <List <Order> >(walletOrders.ToList())); _orderStream.WriteToStream(orderUpdate, walletOrders.Key); } }); _tradeReader.SubscribeToChanges(tradeEntities => { var tradesByWallet = tradeEntities.GroupBy(x => x.WalletId); foreach (var walletTrades in tradesByWallet) { var tradeUpdate = new TradeUpdate(); tradeUpdate.Trades.AddRange(_mapper.Map <List <Trade> >(walletTrades.ToList())); _tradeStream.WriteToStream(tradeUpdate, walletTrades.Key); } }); Console.WriteLine("Stream services started."); }