public async Task Execute() { var spreadMiddle = 0M; var lastUpdate = new DateTime(); // BEGIN EXECUTION LOOP: while (true) { // Place new/Replace tiered orders, then pause if (DateTime.Now - lastUpdate > SETTINGS.OrderExecDelay) { spreadMiddle = await ReplaceSpreadOrders("XLMUSDT", spreadMiddle); lastUpdate = DateTime.Now; } else if (userDATA.UserUpdateQueue.IsEmpty) { Thread.Sleep(100); } // PROCESS ORDER UPDATES, MAKE DECISIONS BASED ON ExecutionType: while (!userDATA.UserUpdateQueue.IsEmpty) { // DeQueue next order update: bool tryDQ = false; var userMsg = new UserDataUpdate(); do { tryDQ = userDATA.UserUpdateQueue.TryDequeue(out userMsg); } while (!tryDQ); if (userMsg.TradeOrderData != null) // (!= balance update msg) { var clientID = userMsg.TradeOrderData.NewClientOrderId.Split('_'); if (clientID[0] == "bin2") { await StrategyP2.HandleTradeMsg(userMsg.TradeOrderData, clientID); continue; } else if (clientID[0] != "bina") { continue; } switch (userMsg.TradeOrderData.ExecutionType) { case ExecutionType.New: // UPDATE UNCONFIRMED BUY/SELL OrderInfo in openOrders LIST: var orderInfo = new OrderInfo(userMsg.TradeOrderData); if (clientID[1] == "Buy") { OpenBUYorders[OpenBUYorders.IndexOf(OpenBUYorders.First(o => o.ClientID == userMsg.TradeOrderData.NewClientOrderId))] = orderInfo; } else if (clientID[1] == "Sell") { OpenSELLorders[OpenSELLorders.IndexOf(OpenSELLorders.First(o => o.ClientID == userMsg.TradeOrderData.NewClientOrderId))] = orderInfo; } break; case ExecutionType.Trade: if (userMsg.TradeOrderData.OrderStatus == OrderStatus.Filled) { // UPDATE ORDERS StratStatus in OpenDATAorders: var order = new OrderInfo(userMsg.TradeOrderData); if (clientID[1] == "Buy") { // HANDLE RAPID TP-ORDER HERE if (order.StratState == StrategyState.OPEN_FILLED) { // place TP order, update to TP_ENTERED var tpPrice = Math.Round(order.Price * (1 + SETTINGS.TakeProfitMargin), PriceRoundDigits); var tpQty = order.Qty; var ord = new CreateOrderRequest() { Side = OrderSide.Sell, Symbol = order.Symbol, Price = tpPrice, Quantity = tpQty, NewClientOrderId = order.ClientID }; var resp = await BinaREST.CreateLimitOrder(ord); if (resp != null) { Log.Debug($">>> [BUY] Take-Profit submitted"); } // update order info order = new OrderInfo(ord, StrategyState.TP_UNCONFIRMED); } OpenBUYorders[OpenBUYorders.IndexOf(OpenBUYorders.First(o => o.ClientID == userMsg.TradeOrderData.NewClientOrderId))] = order; } else if (clientID[1] == "Sell") { // HANDLE RAPID TP-ORDER HERE if (order.StratState == StrategyState.OPEN_FILLED) { // place TP order, update to TP_ENTERED var tpPrice = Math.Round(order.Price * (1 - SETTINGS.TakeProfitMargin), PriceRoundDigits); var tpQty = Math.Round(Convert.ToDecimal(order.BaseCurrReturn) / (tpPrice * (1 + SETTINGS.FeePercentage)), QtyRoundDigits); var ord = new CreateOrderRequest() { Side = OrderSide.Buy, Symbol = order.Symbol, Price = tpPrice, Quantity = tpQty, NewClientOrderId = order.ClientID }; var resp = await BinaREST.CreateLimitOrder(ord); if (resp != null) { Log.Debug($">>> [SELL] Take-Profit submitted"); } // update order info order = new OrderInfo(ord, StrategyState.TP_UNCONFIRMED); } OpenSELLorders[OpenSELLorders.IndexOf(OpenSELLorders.First(o => o.ClientID == userMsg.TradeOrderData.NewClientOrderId))] = order; } } else if (userMsg.TradeOrderData.OrderStatus == OrderStatus.PartiallyFilled) { // HANDLE PARTIAL FILLS (ANCHOR UNTIL FILLED) var order = new OrderInfo(userMsg.TradeOrderData); if (order.StratState == StrategyState.PARTIAL_FILL) { if (clientID[1] == "Buy") { OpenBUYorders[OpenBUYorders.IndexOf(OpenBUYorders.First(o => o.ClientID == userMsg.TradeOrderData.NewClientOrderId))] = order; } else if (clientID[1] == "Sell") { OpenSELLorders[OpenSELLorders.IndexOf(OpenSELLorders.First(o => o.ClientID == userMsg.TradeOrderData.NewClientOrderId))] = order; } } } break; case ExecutionType.Cancelled: break; case ExecutionType.Rejected: LogOrderMessage(userMsg.TradeOrderData); break; default: LogOrderMessage(userMsg.TradeOrderData); break; } } } if (OpenBUYorders.Where(o => o.StratState == StrategyState.TP_ENTERED).Count() == SETTINGS.Tiers && OpenSELLorders.Where(o => o.StratState == StrategyState.TP_ENTERED).Count() == SETTINGS.Tiers && !SETTINGS.MutePhase2) { var window_top = OpenBUYorders.Min(tp => tp.Price); var window_bottom = OpenSELLorders.Max(tp => tp.Price); await StrategyP2.Activate(depthDATA.GetSpreadMiddle(SETTINGS.SubSpecificSymbols[0]), window_top, window_bottom); } else { await StrategyP2.Deactivate(); } } }