private void runSellStrategy(IWebSocketClientConnection webSocketConnection, string symbol) { OrderBook.IOrder bestBid = _tradeclient.GetOrderBook(symbol).BestBid; OrderBook.IOrder bestOffer = _tradeclient.GetOrderBook(symbol).BestOffer; if (_priceType == PriceType.MARKET_AS_MAKER) { ulong sellPrice = 0; if (bestBid != null) { sellPrice = bestBid.Price + (ulong)(0.01 * 1e8); } else if (bestOffer != null) { sellPrice = bestOffer.Price; } if (sellPrice > 0 || _sell_floor_price > 0) { if (sellPrice >= _sell_floor_price) { replaceOrder(webSocketConnection, symbol, OrderSide.SELL, sellPrice); return; } _sellTargetPrice = _sell_floor_price; // find the best position as maker for the sell floor price } else { // empty book scenario without a user defined sell floor price _tradeclient.CancelOrderByClOrdID(webSocketConnection, _strategySellOrderClorid); return; } } // available funds with a target price should execute ASAP even as liquidity takers whenever possible if (_sellTargetPrice > 0 && bestBid != null && bestBid.Price >= _sellTargetPrice && bestBid.UserId != _tradeclient.UserId) { ulong availableQty = calculateOrderQty(symbol, OrderSide.SELL, bestBid.Price, ulong.MaxValue); if (availableQty > _minOrderSize) { ulong sell_qty = Math.Min(availableQty, bestBid.Qty); // execute the order as taker and emulate IOC instruction sendOrder(webSocketConnection, symbol, OrderSide.SELL, sell_qty, bestBid.Price, OrdType.LIMIT, 0, ExecInst.DEFAULT, TimeInForce.IMMEDIATE_OR_CANCEL); return; } else { // cancel current order to free balance to be used as taker MiniOMS.IOrder own_sell_order = _tradeclient.miniOMS.GetOrderByClOrdID(_strategySellOrderClorid); if (own_sell_order != null && (own_sell_order.OrdStatus == OrdStatus.NEW || own_sell_order.OrdStatus == OrdStatus.PARTIALLY_FILLED)) { if (own_sell_order.LeavesQty > _minOrderSize) { ulong sell_qty = Math.Min(own_sell_order.LeavesQty, bestBid.Qty); _tradeclient.CancelOrderByClOrdID(webSocketConnection, own_sell_order.ClOrdID); sendOrder(webSocketConnection, symbol, OrderSide.SELL, sell_qty, bestBid.Price, OrdType.LIMIT, 0, ExecInst.DEFAULT, TimeInForce.IMMEDIATE_OR_CANCEL); return; } } } } // post the order in the order book if (bestOffer != null) { if (bestOffer.UserId != _tradeclient.UserId) { // sell @ 1 cent bellow the best price (TODO: parameter for price increment) ulong sellPrice = bestOffer.Price - (ulong)(0.01 * 1e8); if (sellPrice >= _sellTargetPrice) { // TODO: Become a Taker when the spread is "small" (i.e for stop trailing converted to pegged or for any pegged) if (sellPrice > bestBid.Price) { replaceOrder(webSocketConnection, symbol, OrderSide.SELL, sellPrice); } else { // avoid being a taker or receiving a reject when using ExecInst=6 but stay in the book with max price ulong max_sell_price = bestBid.Price + (ulong)(0.01 * 1e8); var own_order = _tradeclient.miniOMS.GetOrderByClOrdID(_strategySellOrderClorid); ulong availableQty = calculateOrderQty(symbol, OrderSide.SELL); if (own_order == null || own_order.Price != max_sell_price || availableQty > own_order.OrderQty) { replaceOrder(webSocketConnection, symbol, OrderSide.SELL, max_sell_price); } } } else { // cannot fight for the first position thus try to find a visible position in the book OrderBook orderBook = _tradeclient.GetOrderBook(symbol); List <OrderBook.Order> sellside = orderBook.GetOfferOrders(); int i = sellside.BinarySearch( new OrderBook.Order(OrderBook.OrdSide.SELL, _sellTargetPrice + (ulong)(0.01 * 1e8)), new OrderBook.OrderPriceComparer() ); int position = (i < 0 ? ~i : i); Debug.Assert(position > 0); // verificar se a profundidade vale a pena: (TODO: parameters for max_pos_depth and max_amount_depth) if (position > 15 + 1 && orderBook.DoesAmountExceedsLimit( OrderBook.OrdSide.SELL, position - 1, (ulong)(20 * 1e8))) { _tradeclient.CancelOrderByClOrdID(webSocketConnection, _strategySellOrderClorid); return; } var pivotOrder = sellside[position]; if (pivotOrder.UserId == _tradeclient.UserId) { // make sure the order is the same or from another client instance MiniOMS.IOrder own_sell_order = _tradeclient.miniOMS.GetOrderByClOrdID(_strategySellOrderClorid); if (sellside[position].OrderId == own_sell_order.OrderID) { // ordem ja e minha : pega + recursos disponiveis e cola no preco do vizinho se já nao estiver ulong price_delta = sellside.Count > position + 1 ? sellside[position + 1].Price - pivotOrder.Price : 0; ulong newSellPrice = (price_delta > (ulong)(0.01 * 1e8) ? pivotOrder.Price + price_delta - (ulong)(0.01 * 1e8) : pivotOrder.Price); ulong availableQty = calculateOrderQty(symbol, OrderSide.SELL); if (newSellPrice > pivotOrder.Price || availableQty > pivotOrder.Qty) { replaceOrder(webSocketConnection, symbol, OrderSide.SELL, newSellPrice, availableQty); } } } else { // estabelece preco de venda 1 centavo menor do que nesta posicao ulong newSellPrice = pivotOrder.Price - (ulong)(0.01 * 1e8); replaceOrder(webSocketConnection, symbol, OrderSide.SELL, newSellPrice); } } } else { // check and replace the order on the top to get closer to the order in the second position and gather more available funds MiniOMS.IOrder own_sell_order = _tradeclient.miniOMS.GetOrderByClOrdID(_strategySellOrderClorid); List <OrderBook.Order> sellside = _tradeclient.GetOrderBook(symbol).GetOfferOrders(); if (sellside[0].OrderId == own_sell_order.OrderID) { ulong price_delta = sellside.Count > 1 ? sellside[1].Price - sellside[0].Price : 0; ulong newSellPrice = (price_delta > (ulong)(0.01 * 1e8) ? bestOffer.Price + price_delta - (ulong)(0.01 * 1e8) : bestOffer.Price); ulong availableQty = calculateOrderQty(symbol, OrderSide.SELL); if (newSellPrice > bestOffer.Price || availableQty > bestOffer.Qty) { replaceOrder(webSocketConnection, symbol, OrderSide.SELL, newSellPrice, availableQty); } } } } else { // empty book scenario ulong availableQty = calculateOrderQty(symbol, OrderSide.SELL); Debug.Assert(_sellTargetPrice > 0); ulong sell_price = Math.Max(_sellTargetPrice, bestBid != null ? bestBid.Price + (ulong)(0.01 * 1e8) : 0); sendOrder(webSocketConnection, symbol, OrderSide.SELL, availableQty, sell_price); } }
private void runSellStrategy(IWebSocketClientConnection webSocketConnection, string symbol) { OrderBook.IOrder bestOffer = _tradeclient.GetOrderBook(symbol).BestOffer; if (bestOffer != null) { if (bestOffer.UserId != _tradeclient.UserId) { // sell @ 1 cent bellow the best price (TODO: parameter for price increment) ulong sellPrice = bestOffer.Price - (ulong)(0.01 * 1e8); if (sellPrice >= _sellTargetPrice) { replaceOrder(webSocketConnection, symbol, OrderSide.SELL, sellPrice); } else { // cannot fight for the first position thus try to find a visible position in the book OrderBook orderBook = _tradeclient.GetOrderBook(symbol); List <OrderBook.Order> sellside = orderBook.GetOfferOrders(); int i = sellside.BinarySearch( new OrderBook.Order(OrderBook.OrdSide.SELL, _sellTargetPrice + (ulong)(0.01 * 1e8)), new OrderBook.OrderPriceComparer() ); int position = (i < 0 ? ~i : i); Debug.Assert(position > 0); // verificar se a profundidade vale a pena: (TODO: parameters for max_pos_depth and max_amount_depth) if (position > 5 + 1 && orderBook.DoesAmountExceedsLimit( OrderBook.OrdSide.SELL, position - 1, (ulong)(10 * 1e8))) { _tradeclient.CancelOrderByClOrdID(webSocketConnection, _strategySellOrderClorid); return; } var pivotOrder = sellside[position]; if (pivotOrder.UserId == _tradeclient.UserId) { // ordem ja e minha : pega + recursos disponiveis e cola no preco no vizinho se já nao estiver ulong price_delta = sellside[position + 1].Price - pivotOrder.Price; ulong newSellPrice = (price_delta > (ulong)(0.01 * 1e8) ? pivotOrder.Price + price_delta - (ulong)(0.01 * 1e8) : pivotOrder.Price); ulong availableQty = calculateOrderQty(symbol, OrderSide.SELL); if (newSellPrice > pivotOrder.Price || availableQty > pivotOrder.Qty) { replaceOrder(webSocketConnection, symbol, OrderSide.SELL, newSellPrice, availableQty); } } else { // estabelece preco de venda 1 centavo menor do que nesta posicao ulong newSellPrice = pivotOrder.Price - (ulong)(0.01 * 1e8); replaceOrder(webSocketConnection, symbol, OrderSide.SELL, newSellPrice); } } } else { // check and replace the order to get closer to the order in the second position and gather more available funds List <OrderBook.Order> sellside = _tradeclient.GetOrderBook(symbol).GetOfferOrders(); ulong price_delta = sellside.Count > 1 ? sellside[1].Price - sellside[0].Price : 0; ulong newSellPrice = (price_delta > (ulong)(0.01 * 1e8) ? bestOffer.Price + price_delta - (ulong)(0.01 * 1e8) : bestOffer.Price); ulong availableQty = calculateOrderQty(symbol, OrderSide.SELL); if (newSellPrice > bestOffer.Price || availableQty > bestOffer.Qty) { replaceOrder(webSocketConnection, symbol, OrderSide.SELL, newSellPrice, availableQty); } } } else { // TODO: empty book scenario } }