public async Task <Order> PlaceNewOrder(string oSide, string oProdName, string oSize, string oPrice, bool chaseBestPrice, string orderType = "limit") { OrderPlacer limitOrder = new OrderPlacer(_auth); JObject orderBodyObj = new JObject(); //orderBodyObj.Add(new JProperty("client_oid", "")); orderBodyObj.Add(new JProperty("type", orderType)); orderBodyObj.Add(new JProperty("product_id", oProdName)); orderBodyObj.Add(new JProperty("side", oSide)); orderBodyObj.Add(new JProperty("price", oPrice)); orderBodyObj.Add(new JProperty("size", oSize)); //if post only is set then use this if (AvoidExFees) { if (orderType != "market") { orderBodyObj.Add(new JProperty("post_only", Boolean.TrueString));//"T")); } } if (OrderStartingPrice == 0) //not yet set { OrderStartingPrice = Convert.ToDecimal(oPrice); } Logger.WriteLog(string.Format("placing new {0} {1} order @{2}", orderType, oSide, oPrice)); //changed from await to .Result: neworder should wait for the new order to finish formulating var newOrder = limitOrder.PlaceOrder(orderBodyObj).Result; if (newOrder != null) { var myCurOrder = new MyOrder { OrderId = newOrder.Id, Productname = newOrder.Product_id, OrderType = orderType, Status = "OPEN", UsdPrice = Convert.ToDecimal(newOrder.Price), ProductSize = Convert.ToDecimal(newOrder.Size), Side = newOrder.Side, ChaseBestPrice = chaseBestPrice }; if (newOrder.Status != "rejected") { //if there are no orders in order list then set //already tracking order variables to false if (MyChaseOrderList.Count == 0) { if (fillsClient.BusyCheckingOrder) { fillsClient.BusyCheckingOrder = false; } if (FillsClient.IsBusy_TrackIngOrder) { FillsClient.IsBusy_TrackIngOrder = false; } } AddToOrderList(myCurOrder); //if (chaseBestPrice && MyChaseOrderList.Count == 1) if (chaseBestPrice && MyChaseOrderList.Count > 0) { Logger.WriteLog("Order list contains 1 or more order, starting order tracker"); fillsClient.startTracker(); } } else { //wait before placing a new order //Task.Delay(200); Thread.Sleep(200); Logger.WriteLog("Last order rejected, retrying..."); decimal adjustedPrice = getAdjustedCurrentPrice(myCurOrder); try { var orderAtNewPrice = PlaceNewOrder( oSide: myCurOrder.Side, oProdName: myCurOrder.Productname, oSize: myCurOrder.ProductSize.ToString(), oPrice: adjustedPrice.ToString(), chaseBestPrice: true, orderType: orderType ); } catch (Exception) { Logger.WriteLog("error with recursive new order after last order rejected. Throwing OrderRetryError error (should be cought by CancelAndReorder func)"); throw new Exception("OrderRetryError"); } } } return(newOrder); }
private bool CancelAndReorder() { isBusyCancelAndReorder = true; //Logger.WriteLog("\t\t in cancel and reorder"); //wait until fill status check is done if (fillsClient.BusyCheckingOrder) { Logger.WriteLog("waiting for fill status check to finish"); } int chekingOrderWaitCount = 0; while (fillsClient.BusyCheckingOrder) { Thread.Sleep(50); } //chekingOrderWaitCount += 1; BusyWithWithCancelReorder = true; for (int i = 0; i < MyChaseOrderList.Count; i++) { if (MyChaseOrderList.Count == 0) { break; } MyOrder myCurrentOrder = MyChaseOrderList.FirstOrDefault(); //// skip to the next order if current order is market order, since market orders cant be cancelled //if (myCurrentOrder.OrderType == "market") //{ // Logger.WriteLog(String.Format("market {0} order ({1}) of {2} {3} detected, skipping cancel and reorder", // myCurrentOrder.Side, myCurrentOrder.OrderId, myCurrentOrder.ProductSize, myCurrentOrder.Productname)); // continue; //} //if market order -> will error out when trying to cancel and will be notified filled //if order has been partially filled, move to next order in list if (myCurrentOrder.Status == "PARTIALLY_FILLED") { //change the order size to the remaining of unfilled var UnfilledAmount = myCurrentOrder.ProductSize - myCurrentOrder.FilledSize; if (UnfilledAmount < 0.01m) //smallest size possible to trade { UnfilledAmount = 0.01m; } myCurrentOrder.ProductSize = UnfilledAmount; //myCurrentOrder.ProductSize - myCurrentOrder.FilledSize; //myCurrentOrder.Status = "OPEN"; myCurrentOrder.FilledSize = 0; OrderRetriedCount = 1; //reset the retried count Logger.WriteLog(string.Format( "Modifying partially filled order, retrying to {0} unfilled size of {1} {2} ", myCurrentOrder.Side, UnfilledAmount, myCurrentOrder.Productname)); } //cancell ALL the current orders List <string> cancelledOrder = new List <string>(); try { //pratially filled order already cancelled in FillCLients filled event if (myCurrentOrder.Status == "PARTIALLY_FILLED") { myCurrentOrder.Status = "OPEN"; //remove the partially filled order id from watch list //new id will be added to watch list when a new order is placed RemoveFromOrderList(myCurrentOrder.OrderId); } else { cancelledOrder = CancelSingleOrder(myCurrentOrder.OrderId).Result; //remove the order from the watch list if cancelled //cancelledOrder only indicates if cancelled or not. does not contain any data if (cancelledOrder.Count() > 0) { RemoveFromOrderList(myCurrentOrder.OrderId); //notice how myCurrentOrder.OrderId is used instead of cancelledOrder.first() } } } catch (Exception ex) { Logger.WriteLog(string.Format( "error cancelling order {0}, retrying...", myCurrentOrder.OrderId)); if (ex.InnerException.Message == "OrderNotFound") { Logger.WriteLog("Order not found, removing from watch list and continueing" + myCurrentOrder.OrderId); RemoveFromOrderList(myCurrentOrder.OrderId); NotifyOrderUpdateListener(new OrderUpdateEventArgs { side = "UNKNOWN", filledAtPrice = "0", Message = "ORDER_NOT_FOUND", OrderId = "UNKNOWN", fillFee = "0", fillSize = "0", ProductName = "UNKNOWN" }); } if (ex.InnerException.Message == "OrderAlreadyDone") { Logger.WriteLog("Order already done " + myCurrentOrder.OrderId); //order already done so remove from watch list 2018-02-18 Logger.WriteLog("Order already done, removing from watch list " + myCurrentOrder.OrderId); RemoveFromOrderList(myCurrentOrder.OrderId); NotifyFilledOtherWise(myCurrentOrder.OrderId); } continue; //continue and try again to cancel and reorder //throw; } Logger.WriteLog(string.Format("\tCancelled {0} order ({1}): {2} {3} @{4}", myCurrentOrder.Side, myCurrentOrder.OrderId, myCurrentOrder.ProductSize, myCurrentOrder.Productname, myCurrentOrder.UsdPrice)); decimal adjustedPrice = 0; decimal curPriceDifference = 0; if (OrderStartingPrice > 0) { curPriceDifference = Math.Abs(OrderStartingPrice - PriceTicker.CurrentPrice); } //if (myCurrentOrder == null) // continue; //OrderStartingPrice = adjustedPrice; //var priceChangePercent = PriceTicker.CurrentPrice * 10.00m;//0.0025m; //for testing decimal priceChangePercent = 0.0m; if (AvoidExFees) { priceChangePercent = PriceTicker.CurrentPrice * 0.0020m; // 0.0025m } else { priceChangePercent = PriceTicker.CurrentPrice * 0.0010m; // 0.0025m } //test!! //priceChangePercent = 0.00001m; if (OrderRetriedCount <= 13 && curPriceDifference <= priceChangePercent) // retry a total of 15 times or while less than a "big jump" { adjustedPrice = getAdjustedCurrentPrice(myCurrentOrder); try { //place new order limit order var orderAtNewPrice = PlaceNewOrder( oSide: myCurrentOrder.Side, oProdName: myCurrentOrder.Productname, oSize: myCurrentOrder.ProductSize.ToString(), oPrice: adjustedPrice.ToString(), chaseBestPrice: true, orderType: "limit" ); orderAtNewPrice.Wait(); } catch (Exception) { Logger.WriteLog("error in cancel and reorder occured while placing new limit order, retrying..."); //put the order back in the active order list if there are no //orders since it was cancelled above. this prevents it from //locking up in case the order was cancelled //and an error was encountered while placing a new order if (MyChaseOrderList.Count == 0) { AddToOrderList(myCurrentOrder); } continue; } } else { if (curPriceDifference > priceChangePercent) { Logger.WriteLog("Price changed more than " + curPriceDifference + " Forcing market order"); } adjustedPrice = getAdjustedCurrentPrice(myCurrentOrder, "market"); //place new market order try { var orderAtNewPrice = PlaceNewOrder( oSide: myCurrentOrder.Side, oProdName: myCurrentOrder.Productname, oSize: myCurrentOrder.ProductSize.ToString(), oPrice: adjustedPrice.ToString(), chaseBestPrice: true, orderType: "market" ); orderAtNewPrice.Wait(); } catch (Exception) { Logger.WriteLog("Error in cancel and reorder occured while placing new market order, retrying..."); if (MyChaseOrderList.Count == 0) { AddToOrderList(myCurrentOrder); } continue; } } } BusyWithWithCancelReorder = false; OrderRetriedCount += 1; Logger.WriteLog("Order retried count: " + OrderRetriedCount); Logger.WriteLog("Orders in ActiveOrderList:"); try { MyChaseOrderList.ForEach(x => Logger.WriteLog("\t" + x.OrderId)); } catch (Exception) { Logger.WriteLog("Error enumerating order list, list changed"); } isBusyCancelAndReorder = false; return(true); }