예제 #1
0
        public async Task BuildDepthCache(string symbol)
        {
            // Code example of building out a Dictionary local cache for a symbol using deltas from the WebSocket
            var localDepthCache = new Dictionary <string, DepthCacheObject> {
                { symbol, new DepthCacheObject()
                  {
                      Asks = new Dictionary <decimal, decimal>(),
                      Bids = new Dictionary <decimal, decimal>(),
                  } }
            };
            var marketDepthCache = localDepthCache[symbol];

            // Get Order Book, and use Cache
            var depthResults = await BinaREST.GetOrderBook(symbol, 100);

            // Populate our depth cache
            depthResults.Asks.ForEach(a =>
            {
                if (a.Quantity != 0.00000000M)
                {
                    marketDepthCache.Asks.Add(a.Price, a.Quantity);
                }
            });
            depthResults.Bids.ForEach(a =>
            {
                if (a.Quantity != 0.00000000M)
                {
                    marketDepthCache.Bids.Add(a.Price, a.Quantity);
                }
            });

            UpdateIDs[symbol]  = depthResults.LastUpdateId;
            OrderBooks[symbol] = localDepthCache[symbol];
        }
예제 #2
0
        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);
                }
            }
        }
예제 #3
0
        public static async Task Main(string[] args)
        {
            Console.WriteLine("--------------------------");
            Console.WriteLine("        BinaTrader");
            Console.WriteLine("--------------------------");

            // Provide your configuration and keys here, this allows the client to function as expected.
            string apiKey    = ConfigurationManager.AppSettings["API_KEY"];
            string secretKey = ConfigurationManager.AppSettings["SECRET_KEY"];

            // Initialize logging:
            var Log = LogManager.GetLogger(typeof(Program));

            Log.Debug("\n\nRUN START - " + DateTime.Now);

            // Initialise the general client client with config
            var client = new BinanceClient(new ClientConfiguration()
            {
                ApiKey    = apiKey,
                SecretKey = secretKey,
                Logger    = Log,
                //EnableRateLimiting = true
            });

            BinaREST.SetClient(client);



            // Initialze strategy markets, then execute strategy:
            strategy = new Strategy_Phase1();
            await strategy.Initialize();

            PrintOrderBook(Strategy_Phase1.SETTINGS.SubSpecificSymbols[0], 35);
            await strategy.Execute();


            Console.WriteLine("\n\n\n\n\t*** END OF PROGRAM ***\n\n\t  Press enter 3 times to exit.");
            Console.ReadKey();
            Console.ReadKey();
            Console.ReadKey();
        }
예제 #4
0
        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;
        }
예제 #5
0
        public async Task HandleTradeMsg(BinanceTradeOrderData TradeMsg, string[] ID)
        {
            // EXECUTION SWITCH
            switch (TradeMsg.ExecutionType)
            {
            case ExecutionType.New:
                // UPDATE UNCONFIRMED BUY/SELL OrderInfo in openOrders LIST:
                var orderInfo = new OrderInfo(TradeMsg);

                if (ID[1] == "Buy")
                {
                    P2_BuyOrders[P2_BuyOrders.IndexOf(P2_BuyOrders.First(o => o.ClientID == TradeMsg.NewClientOrderId))] = orderInfo;
                }
                else if (ID[1] == "Sell")
                {
                    P2_SellOrders[P2_SellOrders.IndexOf(P2_SellOrders.First(o => o.ClientID == TradeMsg.NewClientOrderId))] = orderInfo;
                }

                break;

            case ExecutionType.Trade:
                if (TradeMsg.OrderStatus == OrderStatus.Filled)
                {
                    // UPDATE ORDERS StratStatus in OpenDATAorders:
                    var order = new OrderInfo(TradeMsg);

                    if (ID[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 tpOrd   = new CreateOrderRequest()
                            {
                                Side             = OrderSide.Sell,
                                Symbol           = order.Symbol,
                                Price            = tpPrice,
                                Quantity         = tpQty,
                                NewClientOrderId = order.ClientID
                            };
                            var resp = await BinaREST.CreateLimitOrder(tpOrd);

                            if (resp != null)
                            {
                                Log.Debug($">>> [BUY] Take-Profit submitted");
                            }

                            // update order info
                            var initPrice = order.Price;
                            order = new OrderInfo(tpOrd, StrategyState.TP_UNCONFIRMED);
                            order.InitialPrice = initPrice;
                        }
                        else if (order.StratState == StrategyState.TP_FILLED)
                        {
                            BUYProfitCyclesP2++;
                        }

                        P2_BuyOrders[P2_BuyOrders.IndexOf(P2_BuyOrders.First(o => o.ClientID == TradeMsg.NewClientOrderId))] = order;
                    }
                    else if (ID[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
                            var initPrice = order.Price;
                            order = new OrderInfo(ord, StrategyState.TP_UNCONFIRMED);
                            order.InitialPrice = initPrice;
                        }
                        else if (order.StratState == StrategyState.TP_FILLED)
                        {
                            SELLProfitCyclesP2++;
                        }

                        P2_SellOrders[P2_SellOrders.IndexOf(P2_SellOrders.First(o => o.ClientID == TradeMsg.NewClientOrderId))] = order;
                    }
                }
                else if (TradeMsg.OrderStatus == OrderStatus.PartiallyFilled)
                {
                    // HANDLE PARTIAL FILLS (ANCHOR UNTIL FILLED)
                    var order = new OrderInfo(TradeMsg);
                    if (order.StratState == StrategyState.PARTIAL_FILL)
                    {
                        if (ID[1] == "Buy")
                        {
                            P2_BuyOrders[P2_BuyOrders.IndexOf(P2_BuyOrders.First(o => o.ClientID == TradeMsg.NewClientOrderId))] = order;
                        }
                        else if (ID[1] == "Sell")
                        {
                            P2_SellOrders[P2_SellOrders.IndexOf(P2_SellOrders.First(o => o.ClientID == TradeMsg.NewClientOrderId))] = order;
                        }
                    }
                }

                break;

            case ExecutionType.Cancelled:
                break;

            case ExecutionType.Rejected:
                LogOrderMessage(TradeMsg);
                break;

            default:
                LogOrderMessage(TradeMsg);
                break;
            }
        }
예제 #6
0
        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;
        }
예제 #7
0
        private async Task LoadOpenOrders()
        {
            // CALL ALL ORDERS FOR MARKET, SORT THROUGH ALREADY PLACED ORDERS
            var orders = await BinaREST.GetOpenOrders(SETTINGS.SubSpecificSymbols[0]);

            foreach (var ord in orders)
            {
                var clientID = ord.ClientOrderId.Split('_');
                if (clientID[0] == "bin2")
                {
                    await StrategyP2.LoadOpenP2Order(ord, clientID);

                    continue;
                }
                else if (clientID[0] != "bina")
                {
                    continue;
                }

                var ordInfo = new OrderInfo(ord);

                if (ordInfo.Status == OrderStatus.New)
                {
                    if (clientID[1] == "Buy")
                    {
                        OpenBUYorders.Add(ordInfo);
                    }
                    else if (clientID[1] == "Sell")
                    {
                        OpenSELLorders.Add(ordInfo);
                    }
                    continue;
                }
                else if (ordInfo.Status == OrderStatus.PartiallyFilled)
                {
                    if (clientID[1] == "Buy")
                    {
                        if (ordInfo.Side == OrderSide.Buy)
                        {
                            ordInfo.StratState = StrategyState.PARTIAL_FILL;
                            OpenBUYorders.Add(ordInfo);
                        }
                        else
                        {
                            OpenBUYorders.Add(ordInfo);
                        }
                    }
                    else if (clientID[1] == "Sell")
                    {
                        if (ordInfo.Side == OrderSide.Sell)
                        {
                            {
                                ordInfo.StratState = StrategyState.PARTIAL_FILL;
                                OpenSELLorders.Add(ordInfo);
                            }
                        }
                        else
                        {
                            OpenSELLorders.Add(ordInfo);
                        }
                    }
                    continue;
                }
            }
        }
예제 #8
0
        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);
            }
        }
예제 #9
0
        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();
                }
            }
        }