public async Task LoadOpenP2Order(OrderResponse order, string[] ID) { // Place OrderP2 object into dictionary var ordInfo = new OrderInfo(order); if (ordInfo.Status == OrderStatus.New) { if (ordInfo.StratState == StrategyState.OPEN) { var cancelResp = await BinaREST.CancelOrder(ordInfo.Symbol, ordInfo.ClientID); if (cancelResp != null) { Log.Debug($">>> [P2_BUY] CANCELED - Price: {ordInfo.Price}"); } } else if (ID[1] == "Buy") { P2_BuyOrders.Add(ordInfo); } else if (ID[1] == "Sell") { P2_SellOrders.Add(ordInfo); } } else if (ordInfo.Status == OrderStatus.PartiallyFilled) { if (ordInfo.StratState == StrategyState.OPEN) { ordInfo.StratState = StrategyState.PARTIAL_FILL; } if (ID[1] == "Buy") { P2_BuyOrders.Add(ordInfo); } else if (ID[1] == "Sell") { P2_SellOrders.Add(ordInfo); } } }
public async Task Deactivate() { if (!P2_Active) { return; } // Cancel all OPEN orders, leave TakeProfits open var canceledOrds = new List <OrderInfo>(); foreach (var ord in P2_BuyOrders.Where(o => o.StratState == StrategyState.OPEN)) { var cancelResp = await BinaREST.CancelOrder(ord.Symbol, ord.ClientID); if (cancelResp != null) { Log.Debug($">>> [P2_BUY] CANCELED - Price: {ord.Price}"); } canceledOrds.Add(ord); } P2_BuyOrders = P2_BuyOrders.Except(canceledOrds).ToList(); canceledOrds.Clear(); foreach (var ord in P2_SellOrders.Where(o => o.StratState == StrategyState.OPEN)) { var cancelResp = await BinaREST.CancelOrder(ord.Symbol, ord.ClientID); if (cancelResp != null) { Log.Debug($">>> [P2_BUY] CANCELED - Price: {ord.Price}"); } canceledOrds.Add(ord); } P2_SellOrders = P2_SellOrders.Except(canceledOrds).ToList(); P2_Active = false; }
public async Task Activate(decimal middle, decimal top, decimal bottom) { // populate grid values if necessary PopulateGridVals(bottom); // snap existing P2 TakeProfit orders to an initial grid price SetInitialPrices(); // narrow down grid_values to only possible order placements var middleRound = Math.Round(middle, PriceRoundDigits); var possibleBuyVals = grid_values.Where(x => x >= middle * (1 - (SETTINGS.grid_interval * SETTINGS.MaxOrdsPerSide)) && x <middleRound && // Within range, and not impeding the phase1 TP boundary x> bottom && x * (1 + SETTINGS.TakeProfitMargin) < top).ToList(); var possibleSellVals = grid_values.Where(x => x <= middle * (1 + (SETTINGS.grid_interval * SETTINGS.MaxOrdsPerSide)) && x > middleRound && x <top && x * (1 - SETTINGS.TakeProfitMargin)> bottom).ToList(); // further filter possibleVals and cancel any OPEN orders that fall outside: var canceledOrds = new List <OrderInfo>(); foreach (var order in P2_BuyOrders) { // remove already placed orders from possibleVals if (order.StratState == StrategyState.OPEN || order.StratState == StrategyState.OPEN_UNCONFIRMED || order.StratState == StrategyState.OPEN_FILLED || order.StratState == StrategyState.PARTIAL_FILL) { possibleBuyVals.Remove(order.Price); } // cancel any OPEN status orders outside the possibleVals else if (order.StratState == StrategyState.OPEN && !possibleBuyVals.Any(x => x == order.Price)) { var cancelResp = await BinaREST.CancelOrder(order.Symbol, order.ClientID); if (cancelResp != null) { Log.Debug($">>> [P2_BUY] CANCELED - Price: {order.Price}"); } canceledOrds.Add(order); } // and remove possibleVals that already have corresponding TakeProfit.InitPrice open else if (order.StratState == StrategyState.TP_ENTERED || order.StratState == StrategyState.TP_UNCONFIRMED || order.StratState == StrategyState.TP_FILLED) { possibleBuyVals.Remove(order.InitialPrice); } } P2_BuyOrders = P2_BuyOrders.Except(canceledOrds).ToList(); // Same as above for Sell side: canceledOrds.Clear(); foreach (var order in P2_SellOrders) { if (order.StratState == StrategyState.OPEN || order.StratState == StrategyState.OPEN_UNCONFIRMED || order.StratState == StrategyState.OPEN_FILLED || order.StratState == StrategyState.PARTIAL_FILL) { possibleSellVals.Remove(order.Price); } else if (order.StratState == StrategyState.OPEN && !possibleSellVals.Any(x => x == order.Price)) { var cancelResp = await BinaREST.CancelOrder(order.Symbol, order.ClientID); if (cancelResp != null) { Log.Debug($">>> [P2_SELL] CANCELED - Price: {order.Price}"); } canceledOrds.Add(order); } else if (order.StratState == StrategyState.TP_ENTERED || order.StratState == StrategyState.TP_UNCONFIRMED || order.StratState == StrategyState.TP_FILLED) { possibleSellVals.Remove(order.InitialPrice); } } P2_SellOrders = P2_SellOrders.Except(canceledOrds).ToList(); possibleBuyVals = possibleBuyVals.Distinct().ToList(); possibleSellVals = possibleSellVals.Distinct().ToList(); // place orders on remaining values, add to orderInfo Lists possibleBuyVals.OrderByDescending(v => v); foreach (var p in possibleBuyVals) { // FIRST REPLACE ANY 'TP_FILLED' WITH COMPOUNDED GAINS var filledTP = P2_BuyOrders.FirstOrDefault(o => o.StratState == StrategyState.TP_FILLED); if (filledTP != null) { var buyQty = Math.Round(Convert.ToDecimal(filledTP.BaseCurrReturn) / (p * (1 + SETTINGS.FeePercentage)), QtyRoundDigits); var order = new CreateOrderRequest() { Side = OrderSide.Buy, Symbol = MarketSymbol, Price = p, Quantity = buyQty, NewClientOrderId = filledTP.ClientID }; var response = await BinaREST.CreateLimitOrder(order); if (response != null) { Log.Debug($">>> [BUY] (RE)ORDER PLACED - Price: {p}"); } // update order info var newOrd = new OrderInfo(order, StrategyState.OPEN_UNCONFIRMED); newOrd.InitialPrice = p; P2_BuyOrders[P2_BuyOrders.IndexOf(P2_BuyOrders.First(o => o.ClientID == filledTP.ClientID))] = newOrd; } //Place remaining available OPEN order slots else if (P2_BuyOrders.Count() < SETTINGS.MaxOrdsPerSide) { var buyQty = Math.Round(SETTINGS.PrimaryWager / (p * (1 + SETTINGS.FeePercentage)), QtyRoundDigits); var order = new CreateOrderRequest() { Side = OrderSide.Buy, Symbol = MarketSymbol, Price = p, Quantity = buyQty, NewClientOrderId = "bin2_Buy_" + UniqueString() }; var response = await BinaREST.CreateLimitOrder(order); if (response != null) { Log.Debug($">>> [P2_BUY] ORDER PLACED - Price: {p}"); } // add order status to prevent repeat order var newOrd = new OrderInfo(order, StrategyState.OPEN_UNCONFIRMED); newOrd.InitialPrice = p; P2_BuyOrders.Add(newOrd); } // MOVE UP LOWER BUY ORDERS else if (P2_BuyOrders.Any(o => o.StratState == StrategyState.OPEN && o.Price < p)) { // Cancel lowest buy order var minPrice = P2_BuyOrders.Where(o => o.StratState == StrategyState.OPEN).Min(o => o.Price); var oldOrder = P2_BuyOrders.First(o => o.Price == minPrice); var baseReturn = 0M; if (oldOrder.BaseCurrReturn != null) { baseReturn = Convert.ToDecimal(oldOrder.BaseCurrReturn); } var cancelResp = await BinaREST.CancelOrder(oldOrder.Symbol, oldOrder.ClientID); if (cancelResp != null) { Log.Debug($">>> [P2_SELL] CANCELED - Price: {oldOrder.Price}"); } P2_BuyOrders.Remove(oldOrder); // Place order at correct price // If baseCurr != 0, use this to calc QTY, else primary wager var buyQty = Math.Round(SETTINGS.PrimaryWager / (p * (1 + SETTINGS.FeePercentage)), QtyRoundDigits); if (baseReturn != 0) { buyQty = Math.Round(Convert.ToDecimal(baseReturn) / (p * (1 + SETTINGS.FeePercentage)), QtyRoundDigits); } var order = new CreateOrderRequest() { Side = OrderSide.Buy, Symbol = MarketSymbol, Price = p, Quantity = buyQty, NewClientOrderId = "bin2_Buy_" + UniqueString() }; var response = await BinaREST.CreateLimitOrder(order); if (response != null) { Log.Debug($">>> [P2_BUY] ORDER PLACED - Price: {p}"); } // add order status to prevent repeat order var newOrd = new OrderInfo(order, StrategyState.OPEN_UNCONFIRMED); newOrd.InitialPrice = p; P2_BuyOrders.Add(newOrd); } } // Same as above for sell side: possibleSellVals.OrderBy(v => v); foreach (var p in possibleSellVals) { // FIRST REPLACE ANY 'TP_FILLED' WITH COMPOUNDED GAINS var filledTP = P2_SellOrders.FirstOrDefault(o => o.StratState == StrategyState.TP_FILLED); if (filledTP != null) { var sellQty = filledTP.Qty; var order = new CreateOrderRequest() { Side = OrderSide.Sell, Symbol = MarketSymbol, Price = p, Quantity = sellQty, NewClientOrderId = filledTP.ClientID }; var response = await BinaREST.CreateLimitOrder(order); if (response != null) { Log.Debug($">>> [SELL] ORDER (RE)PLACED - Price: {p}"); } // update order info var newOrd = new OrderInfo(order, StrategyState.OPEN_UNCONFIRMED); newOrd.InitialPrice = p; P2_SellOrders[P2_SellOrders.IndexOf(P2_SellOrders.First(o => o.ClientID == filledTP.ClientID))] = newOrd; } //Place remaining available OPEN order slots else if (P2_SellOrders.Count() < SETTINGS.MaxOrdsPerSide) { var sellQty = Math.Round(SETTINGS.PrimaryWager / (p * (1 - SETTINGS.FeePercentage)), QtyRoundDigits); var order = new CreateOrderRequest() { Side = OrderSide.Sell, Symbol = MarketSymbol, Price = p, Quantity = sellQty, NewClientOrderId = "bin2_Sell_" + UniqueString() }; var response = await BinaREST.CreateLimitOrder(order); if (response != null) { Log.Debug($">>> [P2_SELL] ORDER PLACED - Price: {p}"); } // add order status to prevent repeat order var newOrd = new OrderInfo(order, StrategyState.OPEN_UNCONFIRMED); newOrd.InitialPrice = p; P2_SellOrders.Add(newOrd); } // MOVE DOWN ANY HIGHER SELL ORDERS else if (P2_SellOrders.Any(o => o.StratState == StrategyState.OPEN && o.Price > p)) { // Cancel order var maxPrice = P2_SellOrders.Where(o => o.StratState == StrategyState.OPEN).Max(o => o.Price); var oldOrder = P2_SellOrders.First(o => o.Price == maxPrice); var baseCurr = (oldOrder.Price * (1 - SETTINGS.FeePercentage)) * oldOrder.Qty; var cancelResp = await BinaREST.CancelOrder(oldOrder.Symbol, oldOrder.ClientID); if (cancelResp != null) { Log.Debug($">>> [P2_SELL] CANCELED - Price: {oldOrder.Price}"); } P2_SellOrders.Remove(oldOrder); // Place order at correct price // use same BaseCurr wager amount var sellQty = Math.Round(baseCurr / (p * (1 - SETTINGS.FeePercentage)), QtyRoundDigits); var order = new CreateOrderRequest() { Side = OrderSide.Sell, Symbol = MarketSymbol, Price = p, Quantity = sellQty, NewClientOrderId = "bin2_Sell_" + UniqueString() }; var response = await BinaREST.CreateLimitOrder(order); if (response != null) { Log.Debug($">>> [P2_SELL] ORDER PLACED - Price: {p}"); } // add order status to prevent repeat order var newOrd = new OrderInfo(order, StrategyState.OPEN_UNCONFIRMED); newOrd.InitialPrice = p; P2_SellOrders.Add(newOrd); } } P2_Active = true; }
private async Task <decimal> ReplaceSpreadOrders(string symbol, decimal oldMiddle) { // CHECK UserData Websocket STABILITY await CheckUserDataWS(); // SORT LISTS W/ OPEN TAKE-PROFITS AT END if (OpenBUYorders.Any()) { OpenBUYorders = SortOrderList(OpenBUYorders); } if (OpenSELLorders.Any()) { OpenSELLorders = SortOrderList(OpenSELLorders); } //COPY LIST FOR REVISIONS var newBUYorders = new List <OrderInfo>(OpenBUYorders); var newSELLorders = new List <OrderInfo>(OpenSELLorders); var newMiddle = depthDATA.GetSpreadMiddle(symbol); // PLACE/REPLACE ORDERS: for (int t = 0; t < SETTINGS.Tiers; t++) { // BUYS: //if (OpenBUYorders[t] == null) if (OpenBUYorders.ElementAtOrDefault(t) == null) { // no order found on this tier - place order, add new data var buyPrice = Math.Round(newMiddle * (1 - (SETTINGS.PrimaryMargin * SETTINGS.TierMultipliers[t])), PriceRoundDigits); var buyQty = Math.Round(SETTINGS.PrimaryWager / (buyPrice * (1 + SETTINGS.FeePercentage)), QtyRoundDigits); var order = new CreateOrderRequest() { Side = OrderSide.Buy, Symbol = symbol, Price = buyPrice, Quantity = buyQty, NewClientOrderId = "bina_Buy_" + UniqueString() }; var response = await BinaREST.CreateLimitOrder(order); if (response != null) { Log.Debug($">>> [BUY] INITIAL ORDER PLACED: T{t+1}"); } // add order status to prevent repeat order newBUYorders.Add(new OrderInfo(order, StrategyState.OPEN_UNCONFIRMED)); } else { switch (OpenBUYorders[t].StratState) { case StrategyState.OPEN: if (newMiddle > oldMiddle * (1 + SETTINGS.MoveOrderThresh) || newMiddle < oldMiddle * (1 - SETTINGS.MoveOrderThresh)) { // cancel and replace order at new price var cancelResp = await BinaREST.CancelOrder(SETTINGS.SubSpecificSymbols[0], OpenBUYorders[t].ClientID); if (cancelResp != null) { Log.Debug($">>> [BUY] CANCELED: T{t + 1}"); } var newPrice = Math.Round(newMiddle * (1 - (SETTINGS.PrimaryMargin * SETTINGS.TierMultipliers[t])), PriceRoundDigits); var newQty = Math.Round((OpenBUYorders[t].Qty * (OpenBUYorders[t].Price * (1 + SETTINGS.FeePercentage))) / (newPrice * (1 + SETTINGS.FeePercentage)), QtyRoundDigits); var o = new CreateOrderRequest() { Side = OrderSide.Buy, Symbol = symbol, Price = newPrice, Quantity = newQty, NewClientOrderId = OpenBUYorders[t].ClientID }; var r = await BinaREST.CreateLimitOrder(o); if (r != null) { Log.Debug($">>> [BUY] MOVED: T{t + 1}"); } // update order info newBUYorders[t] = new OrderInfo(o, StrategyState.OPEN_UNCONFIRMED); } break; case StrategyState.TP_FILLED: // place new order on starting side, carry over qty for compounding var buyPrice = Math.Round(newMiddle * (1 - (SETTINGS.PrimaryMargin * SETTINGS.TierMultipliers[t])), PriceRoundDigits); var buyQty = Math.Round(Convert.ToDecimal(OpenBUYorders[t].BaseCurrReturn) / (buyPrice * (1 + SETTINGS.FeePercentage)), QtyRoundDigits); var order = new CreateOrderRequest() { Side = OrderSide.Buy, Symbol = symbol, Price = buyPrice, Quantity = buyQty, NewClientOrderId = OpenBUYorders[t].ClientID }; var response = await BinaREST.CreateLimitOrder(order); if (response != null) { Log.Debug($">>> [BUY] ORDER PLACED: T{t + 1}"); } // update order info newBUYorders[t] = new OrderInfo(order, StrategyState.OPEN_UNCONFIRMED); BUYProfitCycles++; break; } } // SELLS: if (OpenSELLorders.ElementAtOrDefault(t) == null) { // no order found on this tier - place order, add new data var sellPrice = Math.Round(newMiddle * (1 + (SETTINGS.PrimaryMargin * SETTINGS.TierMultipliers[t])), PriceRoundDigits); var sellQty = Math.Round(SETTINGS.PrimaryWager / (sellPrice * (1 - SETTINGS.FeePercentage)), QtyRoundDigits); var order = new CreateOrderRequest() { Side = OrderSide.Sell, Symbol = symbol, Price = sellPrice, Quantity = sellQty, NewClientOrderId = "bina_Sell_" + UniqueString() }; var response = await BinaREST.CreateLimitOrder(order); if (response != null) { Log.Debug($">>> [SELL] INITIAL ORDER PLACED: T{t + 1}"); } // add order status to prevent repeat order newSELLorders.Add(new OrderInfo(order, StrategyState.OPEN_UNCONFIRMED)); } else { switch (OpenSELLorders[t].StratState) { case StrategyState.OPEN: if (newMiddle > oldMiddle * (1 + SETTINGS.MoveOrderThresh) || newMiddle < oldMiddle * (1 - SETTINGS.MoveOrderThresh)) { // cancel and replace order at new price var cancelResp = await BinaREST.CancelOrder(SETTINGS.SubSpecificSymbols[0], OpenSELLorders[t].ClientID); if (cancelResp != null) { Log.Debug($">>> [SELL] CANCELED: T{t + 1}"); } var newPrice = Math.Round(newMiddle * (1 + (SETTINGS.PrimaryMargin * SETTINGS.TierMultipliers[t])), PriceRoundDigits); var newQty = Math.Round((OpenSELLorders[t].Qty * (OpenSELLorders[t].Price * (1 - SETTINGS.FeePercentage))) / (newPrice * (1 - SETTINGS.FeePercentage)), QtyRoundDigits); var o = new CreateOrderRequest() { Side = OrderSide.Sell, Symbol = symbol, Price = newPrice, Quantity = newQty, NewClientOrderId = OpenSELLorders[t].ClientID }; var r = await BinaREST.CreateLimitOrder(o); if (r != null) { Log.Debug($">>> [SELL] MOVED: T{t + 1}"); } // update order info newSELLorders[t] = new OrderInfo(o, StrategyState.OPEN_UNCONFIRMED); } break; case StrategyState.TP_FILLED: // place new order on starting side, carry over qty for compounding var sellPrice = Math.Round(newMiddle * (1 + (SETTINGS.PrimaryMargin * SETTINGS.TierMultipliers[t])), PriceRoundDigits); var sellQty = OpenSELLorders[t].Qty; var order = new CreateOrderRequest() { Side = OrderSide.Sell, Symbol = symbol, Price = sellPrice, Quantity = sellQty, NewClientOrderId = OpenSELLorders[t].ClientID }; var response = await BinaREST.CreateLimitOrder(order); if (response != null) { Log.Debug($">>> [SELL] ORDER PLACED: T{t + 1}"); } // update order info newSELLorders[t] = new OrderInfo(order, StrategyState.OPEN_UNCONFIRMED); SELLProfitCycles++; break; } } } // UPDATE ORDER STATUS: OpenBUYorders = new List <OrderInfo>(newBUYorders); OpenSELLorders = new List <OrderInfo>(newSELLorders); if (newMiddle > oldMiddle * (1 + SETTINGS.MoveOrderThresh) || newMiddle < oldMiddle * (1 - SETTINGS.MoveOrderThresh)) { return(newMiddle); } else { return(oldMiddle); } }