private void RebalanceOrder(ProposedOrder propOrder, bool useLock = false) { foreach (var legs in propOrder.OrderLegs.GroupBy(o => o.LegLevel).OrderByDescending(o => o.Key).Skip(1)) { var sellQuantity = legs.Sum(l => l.ProposedSellQuantity); var nextLevelOrderLegs = propOrder.GetOrderLegs(legs.Key + 1); if (nextLevelOrderLegs == null) { break; } var buyQuantity = nextLevelOrderLegs.Sum(o => o.ProposedBuyQuantity); if (buyQuantity == sellQuantity) { continue; } if (sellQuantity <= 0 || buyQuantity <= 0) { break; } if (sellQuantity < buyQuantity) { long newBuyQuantity = sellQuantity; foreach (var orderLeg in nextLevelOrderLegs.OrderBy(o => (double)o.ProposedBuyQuantity / (double)o.ProposedSellQuantity)) { var adj = RebalanceOrderLegForBuy(propOrder, orderLeg, newBuyQuantity, useLock); buyQuantity += adj; newBuyQuantity -= orderLeg.ProposedBuyQuantity; if (buyQuantity <= sellQuantity) { break; } } } else { long newSellQuantity = buyQuantity; foreach (var orderLeg in legs.OrderBy(o => (double)o.ProposedBuyQuantity / (double)o.ProposedSellQuantity)) { var adj = RebalanceOrderLegForSell(propOrder, orderLeg, newSellQuantity, useLock); sellQuantity += adj; newSellQuantity -= orderLeg.ProposedSellQuantity; if (sellQuantity <= buyQuantity) { break; } } } if (!propOrder.OrderQuantitiesInSync && sellQuantity > 0 && buyQuantity > 0) { RebalanceOrder(propOrder); break; } else if (sellQuantity <= 0 || buyQuantity <= 0) { break; } } }
private void RemoveWorstOrderLeg(ThreadSafeAsk ask, ProposedOrder propOrder, bool useLock = false) { while (propOrder.IsValidOrder && propOrder.BuyRatio < ask.GetBuyRatio(propOrder.SellCommodityID, propOrder.BuyCommodityID) && propOrder.ProposedQuanityBuy > 0) { var worstPerfomingOrderLeg = propOrder.RemoveWorstPerforming(useLock); if (worstPerfomingOrderLeg == null) { break; } RebalanceOrder(propOrder, useLock); propOrder.CleanUpOrder(); } }
private long RebalanceOrderLegForSell(ProposedOrder propOrder, ProposedOrderLeg orderLeg, long buyQuantity, bool useLock = false) { long sellQuantityAdj = 0; if (!orderLeg.Ask.AllowPartialFill || orderLeg.ProposedSellQuantity < buyQuantity) { sellQuantityAdj = -1 * orderLeg.ProposedSellQuantity; } else { sellQuantityAdj = -1 * (orderLeg.ProposedSellQuantity - buyQuantity); } sellQuantityAdj = orderLeg.SetSellQuantity(sellQuantityAdj, useLock: useLock); return(sellQuantityAdj); }
private IEnumerable <OrderLeg> BuildOrderLegs(ThreadSafeAsk ask, ProposedOrder order, Dictionary <long, Tuple <ThreadSafeAsk, long> > asksInOrder, ref long orderQuanity, bool doLock = false, bool isMarketQuote = false) { bool hasBrokenLeg = false; List <OrderLeg> legs = new List <OrderLeg>(); IEnumerable <ProposedOrderLeg> orderLegs = null; if ((ask.IsBuy ? order.ProposedQuanityBuy : order.ProposedQuantitySell) + orderQuanity <= ask.LockExecuteQuantity) { orderLegs = ProcessOrderLegs(order.OrderLegs, legs, asksInOrder, out hasBrokenLeg); } else if (orderQuanity < ask.LockExecuteQuantity) { ClearProposedOrderLegs(order.OrderLegs, useLock: doLock); var newOrder = BuildProposedOrder(ask, ask.LockExecuteQuantity - orderQuanity, order.OrderLegs, useLock: doLock); if (newOrder.IsValidOrder && (isMarketQuote || newOrder.BuyRatio >= ask.GetBuyRatio(newOrder.SellCommodityID, newOrder.BuyCommodityID))) { orderLegs = ProcessOrderLegs(newOrder.OrderLegs, legs, asksInOrder, out hasBrokenLeg); } else { ClearProposedOrderLegs(newOrder.OrderLegs, useLock: doLock); return(new OrderLeg[] { }); } order = newOrder; } if (hasBrokenLeg) { ClearProposedOrderLegs(order.OrderLegs, asksInOrder, useLock: doLock); var newOrder = BuildProposedOrder(ask, ask.LockExecuteQuantity - orderQuanity, orderLegs, useLock: doLock); legs.Clear(); if (newOrder.IsValidOrder && (isMarketQuote || newOrder.BuyRatio >= ask.GetBuyRatio(newOrder.SellCommodityID, newOrder.BuyCommodityID))) { ProcessOrderLegs(order.OrderLegs, legs, asksInOrder, out hasBrokenLeg); if (hasBrokenLeg) { ClearProposedOrderLegs(newOrder.OrderLegs, asksInOrder, useLock: doLock); return(new OrderLeg[] { }); } } else { ClearProposedOrderLegs(newOrder.OrderLegs, asksInOrder, useLock: doLock); return(new OrderLeg[] { }); } } orderQuanity += ask.IsBuy ? legs.Where(l => l.CommodityBuyID == order.BuyCommodityID).Sum(l => l.BuyQuantity) : legs.Where(l => l.CommoditySellID == order.SellCommodityID).Sum(l => l.SellQuantity); return(legs); }
private IEnumerable <Order> BuildOrder(ThreadSafeAsk ask, IEnumerable <ProposedOrder> orders, out long orderQuanity, bool isMarketQuote = false, bool doLock = false) { orderQuanity = 0; Dictionary <Tuple <int, int>, Order> finalOrders = new Dictionary <Tuple <int, int>, Order>(); Dictionary <long, Tuple <ThreadSafeAsk, long> > asksInOrder = new Dictionary <long, Tuple <ThreadSafeAsk, long> >(); var orderBuyRatios = orders.GroupBy(o => new Tuple <int, int>(o.SellCommodityID, o.BuyCommodityID)).Select(g => new { SellBuyCommodities = g.Key, AskBuyRatio = ask.GetBuyRatio(g.Key.Item1, g.Key.Item2), AverageBuyRatio = g.Average(o => o.BuyRatio) }).ToDictionary(g => g.SellBuyCommodities); foreach (var propOrder in orders.Where( o => o.IsValidOrder && (isMarketQuote || o.BuyRatio >= orderBuyRatios[new Tuple <int, int>(o.SellCommodityID, o.BuyCommodityID)].AskBuyRatio)).OrderByDescending(o => isMarketQuote ? (o.BuyRatio - orderBuyRatios[new Tuple <int, int>(o.SellCommodityID, o.BuyCommodityID)].AverageBuyRatio) / orderBuyRatios[new Tuple <int, int>(o.SellCommodityID, o.BuyCommodityID)].AverageBuyRatio : (o.BuyRatio - orderBuyRatios[new Tuple <int, int>(o.SellCommodityID, o.BuyCommodityID)].AskBuyRatio) / orderBuyRatios[new Tuple <int, int>(o.SellCommodityID, o.BuyCommodityID)].AskBuyRatio)) { ClearProposedOrderLegs(propOrder.OrderLegs); ProposedOrder newOrder = BuildProposedOrder(ask, ask.LockExecuteQuantity - orderQuanity, propOrder.OrderLegs, useLock: doLock); if (newOrder.IsValidOrder && (isMarketQuote || newOrder.BuyRatio >= ask.GetBuyRatio(newOrder.SellCommodityID, newOrder.BuyCommodityID))) { foreach (var leg in BuildOrderLegs(ask, newOrder, asksInOrder, ref orderQuanity, doLock, isMarketQuote)) { Order order = null; if (!finalOrders.ContainsKey(new Tuple <int, int>(newOrder.SellCommodityID, newOrder.BuyCommodityID))) { order = new Order(); order.CommodityBuyID = newOrder.BuyCommodityID; order.CommoditySellID = newOrder.SellCommodityID; order.CommissionCommodityID = newOrder.Ask.GetApplyCommissionToBuy(newOrder.SellCommodityID, newOrder.BuyCommodityID) ? newOrder.BuyCommodityID : newOrder.SellCommodityID; finalOrders[new Tuple <int, int>(newOrder.SellCommodityID, newOrder.BuyCommodityID)] = order; } else { order = finalOrders[new Tuple <int, int>(newOrder.SellCommodityID, newOrder.BuyCommodityID)]; } order.OrderLegs.Add(leg); } } if (orderQuanity >= ask.LockExecuteQuantity) { break; } } orders = null; foreach (var order in finalOrders) { ApplyCommission(order.Value, ask.GetApplyCommissionToBuy(order.Key.Item1, order.Key.Item2)); } return(finalOrders.Values); }
private ProposedOrder BuildProposedOrder(ThreadSafeAsk ask, long askQuantity, IEnumerable <ProposedOrderLeg> orderLegs, bool useLock = false, bool isMarketOrder = false) { ProposedOrder propOrder = new ProposedOrder(ask); if (ask.IsBuy) { BuildProposedOrderForBuy(ask, askQuantity, orderLegs, propOrder, useLock); } else { BuildProposedOrderForSell(ask, askQuantity, orderLegs, propOrder, useLock); } propOrder.CleanUpOrder(); if (!isMarketOrder && ask.AllowPartialFill && propOrder.IsValidOrder) { RemoveWorstOrderLeg(ask, propOrder, useLock); } orderLegs = null; return(propOrder); }
private void RebalanceOrderLegsForSell(ThreadSafeAsk ask, IEnumerable <ProposedOrderLeg> orderLegs, int legLevel, long sellQuantity, ProposedOrder propOrder, bool useLock = false) { var previousOrderLegs = propOrder.GetOrderLegs(legLevel); while (previousOrderLegs != null) { ClearProposedOrderLegs(previousOrderLegs, useLock: useLock); var newLegs = FillProposedOrderLegsForRebalanceForSell(ask, sellQuantity, orderLegs.Where(o => o.LegLevel == legLevel), useLock); sellQuantity = newLegs.Sum(p => p.ProposedSellQuantity); if (sellQuantity > 0) { propOrder.SetOrderLegs(newLegs); } legLevel--; previousOrderLegs = propOrder.GetOrderLegs(legLevel); } }
private void BuildProposedOrderForBuy(ThreadSafeAsk ask, long askQuantity, IEnumerable <ProposedOrderLeg> orderLegs, ProposedOrder propOrder, bool useLock = false) { bool isFirst = true; foreach (var legs in orderLegs.GroupBy(o => o.LegLevel).OrderByDescending(o => o.Key)) { long sellCap = long.MaxValue; if (ask.Legs.Count > 0 && legs.Key == 1) { int commoditySellID = orderLegs.Where(l => l.LegLevel == 1).First().CommoditySellID; var askLeg = ask.Legs.Where(l => l.CommodityID == commoditySellID).First(); if (askLeg.AvailableQuantityWithoutLockExecute != null) { sellCap = askLeg.AvailableQuantityWithoutLockExecute.Value; } } var propOrderLegs = FillProposedOrderLegsForBuy(ask, askQuantity, legs, useLock: useLock, sellCap: sellCap); if (propOrderLegs.Count == 0) { break; } propOrder.SetOrderLegs(propOrderLegs); long sellQuantity = propOrderLegs.Sum(p => p.ProposedBuyQuantity); if (askQuantity > sellQuantity && sellQuantity > 0 && !isFirst) { RebalanceOrderLegsForBuy(ask, orderLegs, legs.Key + 1, sellQuantity, propOrder, useLock); var previousOrderLegs = propOrder.GetOrderLegs(legs.Key + 1); if (previousOrderLegs != null) { ClearProposedOrderLegs(propOrderLegs, useLock: useLock); askQuantity = previousOrderLegs.Sum(p => p.ProposedSellQuantity); propOrderLegs = FillProposedOrderLegsForBuy(ask, askQuantity, legs, useLock: useLock); if (propOrderLegs.Count == 0 || askQuantity <= 0) { break; } propOrder.SetOrderLegs(propOrderLegs); } } askQuantity = propOrderLegs.Sum(p => p.ProposedSellQuantity); if (askQuantity <= 0 || sellQuantity <= 0) { break; } isFirst = false; } }