private void OnAccountTradeUpdate(AccountTradeUpdateEventArgs e) { var symbol = e.Trade.Symbol; var immutableAccountTrades = _cache.GetAccountTrades(symbol); if (immutableAccountTrades != null) { _log.LogDebug($"new account trade recieved {e.Trade?.Id}", e); var mutableTrades = immutableAccountTrades.ToBuilder(); var previousTrade = mutableTrades.FirstOrDefault(p => p.Id == e.Trade.Id); if (previousTrade != null) { _log.LogDebug($"previous account trade removed {e.Trade?.Id}", e); mutableTrades.Remove(previousTrade); } mutableTrades.Add(e.Trade); _cache.SetAccountTrades(symbol, mutableTrades.ToImmutable()); UpdateOrders(e.Order, symbol); _log.LogDebug($"new account trade added {e.Trade?.Id}", e); } }
private static void OnTradeUpdateEvent(object sender, AccountTradeUpdateEventArgs e) { lock (Program.ConsoleSync) { Console.WriteLine(); Console.WriteLine($"Order [{e.Order.Id}] update: {e.OrderExecutionType}"); Program.Display(e.Order); Console.WriteLine(); Program.Display(e.Trade); Console.WriteLine(); } }
public void Properties() { var time = DateTimeOffset.FromUnixTimeMilliseconds(DateTime.UtcNow.ToTimestamp()).UtcDateTime; var user = new BinanceApiUser("api-key"); var symbol = Symbol.BTC_USDT; const int id = 123456; const string clientOrderId = "test-order"; const decimal price = 4999; const decimal originalQuantity = 1; const decimal executedQuantity = 0.5m; const OrderStatus status = OrderStatus.PartiallyFilled; const TimeInForce timeInForce = TimeInForce.IOC; const OrderType orderType = OrderType.Market; const OrderSide orderSide = OrderSide.Sell; const decimal stopPrice = 5000; const decimal icebergQuantity = 0.1m; const bool isWorking = true; var order = new Order(user, symbol, id, clientOrderId, price, originalQuantity, executedQuantity, status, timeInForce, orderType, orderSide, stopPrice, icebergQuantity, time, isWorking); const OrderRejectedReason orderRejectedReason = OrderRejectedReason.None; const string newClientOrderId = "new-test-order"; const long tradeId = 12345; const long orderId = 54321; const decimal quantity = 1; const decimal commission = 10; const string commissionAsset = "BNB"; const bool isBuyer = true; const bool isMaker = true; const bool isBestPriceMatch = true; var trade = new AccountTrade(symbol, tradeId, orderId, price, quantity, commission, commissionAsset, time, isBuyer, isMaker, isBestPriceMatch); const decimal quantityOfLastFilledTrade = 1; using (var cts = new CancellationTokenSource()) { var args = new AccountTradeUpdateEventArgs(time, cts.Token, order, orderRejectedReason, newClientOrderId, trade, quantityOfLastFilledTrade); Assert.Equal(time, args.Time); Assert.Equal(order, args.Order); Assert.Equal(OrderExecutionType.Trade, args.OrderExecutionType); Assert.Equal(orderRejectedReason, args.OrderRejectedReason); Assert.Equal(newClientOrderId, args.NewClientOrderId); Assert.Equal(trade, args.Trade); Assert.Equal(quantityOfLastFilledTrade, args.QuantityOfLastFilledTrade); } }
private void OnAccountTradeUpdate(AccountTradeUpdateEventArgs e) { var symbol = e.Trade.Symbol; var immutableAccountTrades = _cache.GetAccountTrades(symbol); if (immutableAccountTrades != null) { var mutableTrades = immutableAccountTrades.ToBuilder(); var previousTrade = mutableTrades.FirstOrDefault(p => p.Id == e.Trade.Id); if (previousTrade != null) { mutableTrades.Remove(previousTrade); } mutableTrades.Add(e.Trade); _cache.SetAccountTrades(symbol, mutableTrades.ToImmutable()); UpdateOrders(e.Order, symbol); } }
/// <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 OnWebSocketEvent(WebSocketStreamEventArgs args, IEnumerable <Action <UserDataEventArgs> > callbacks) { if (!ListenKeys.ContainsKey(args.StreamName)) { Logger?.LogError($"{nameof(UserDataWebSocketClient)}.{nameof(OnWebSocketEvent)}: Unknown listen key (\"{args.StreamName}\"). [thread: {Thread.CurrentThread.ManagedThreadId}]"); return; // ignore. } var user = ListenKeys[args.StreamName]; Logger?.LogDebug($"{nameof(UserDataWebSocketClient)}: \"{args.Json}\""); try { var jObject = JObject.Parse(args.Json); var eventType = jObject["e"].Value <string>(); var eventTime = jObject["E"].Value <long>().ToDateTimeK(); // 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, args.Token, new AccountInfo(user, commissions, status, jObject["u"].Value <long>().ToDateTimeK(), balances)); try { if (callbacks != null) { foreach (var callback in callbacks) { callback(eventArgs); } } AccountUpdate?.Invoke(this, eventArgs); } catch (OperationCanceledException) { } catch (Exception e) { if (!args.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>() .ToDateTimeK(), // 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, args.Token, order, rejectedReason, newClientOrderId, trade, quantityOfLastFilledTrade); try { if (callbacks != null) { foreach (var callback in callbacks) { callback(eventArgs); } } TradeUpdate?.Invoke(this, eventArgs); } catch (OperationCanceledException) { } catch (Exception e) { if (!args.Token.IsCancellationRequested) { Logger?.LogError(e, $"{nameof(UserDataWebSocketClient)}: Unhandled trade update event handler exception."); } } } else // order update event. { var eventArgs = new OrderUpdateEventArgs(eventTime, args.Token, order, executionType, rejectedReason, newClientOrderId); try { if (callbacks != null) { foreach (var callback in callbacks) { callback(eventArgs); } } OrderUpdate?.Invoke(this, eventArgs); } catch (OperationCanceledException) { } catch (Exception e) { if (!args.Token.IsCancellationRequested) { Logger?.LogError(e, $"{nameof(UserDataWebSocketClient)}: Unhandled order update event handler exception."); } } } } else { Logger?.LogWarning($"{nameof(UserDataWebSocketClient)}.{nameof(OnWebSocketEvent)}: Unexpected event type ({eventType}) - \"{args.Json}\""); } } catch (OperationCanceledException) { } catch (Exception e) { if (!args.Token.IsCancellationRequested) { Logger?.LogError(e, $"{nameof(UserDataWebSocketClient)}.{nameof(OnWebSocketEvent)}"); } } }
private void OnAccountTradeUpdate(object sender, AccountTradeUpdateEventArgs args) { _onAccountTradeUpdate?.Invoke(args); }