private IEnumerable <Order> GetQuote(ThreadSafeAsk ask, out long orderQuantity, int maxLegDepth = 5, bool doLock = false, bool isMarketQuote = false) { IEnumerable <Order> orders = null; orderQuantity = 0; ask.SetLockExecuteQuantity(); if (ask.LockExecuteQuantity > 0) { ConcurrentBag <IEnumerable <ProposedOrderLeg> > orderLegs = new ConcurrentBag <IEnumerable <ProposedOrderLeg> >(); foreach (var sellID in ask.CommoditySellID) { BuildOrderLegs(sellID, ask.CommodityBuyID, orderLegs, maxLegDepth: maxLegDepth, doLock: doLock); } if (orderLegs.Count > 0) { orders = BuildOrder(ask, orderLegs.Select(orderLeg => BuildProposedOrder(ask, ask.LockExecuteQuantity, orderLeg, isMarketOrder: isMarketQuote)).ToArray(), out orderQuantity, isMarketQuote, doLock); if (orders.Count() == 0) { orders = null; } } IEnumerable <ProposedOrderLeg> leg; while (orderLegs.TryTake(out leg)) { leg = null; } orderLegs = null; GC.Collect(); } return(orders); }
public Task Start() { return(Task.Factory.StartNew(() => { if (Token == null) { Token = new CancellationTokenSource(); } AskRepositoryTask = AskRepository.Start(Token); OpenAsksByBuyerCommdoity.Clear(); OpenAsks.Clear(); var commodities = CommodityRepository.GetCommodities(); Parallel.ForEach(commodities, c => OpenAsksByBuyerCommdoity.AddOrUpdate(c.CommodityID, new ConcurrentDictionary <int, ConcurrentDictionary <long, ThreadSafeAsk> >(), (k, o) => o)); Parallel.ForEach(OpenAsksByBuyerCommdoity, buyCommodityDictionary => { foreach (var commodity in commodities) { buyCommodityDictionary.Value.AddOrUpdate(commodity.CommodityID, new ConcurrentDictionary <long, ThreadSafeAsk>(), (k, o) => o); } }); Parallel.ForEach(AskRepository.GetAsks(), ask => { ThreadSafeAsk tAsk = CreateAsk(new ThreadSafeAsk(ask)); foreach (var commodityBuyID in tAsk.CommodityBuyID) { foreach (var commoditySellID in tAsk.CommoditySellID) { OpenAsksByBuyerCommdoity[commodityBuyID][commoditySellID].AddOrUpdate(tAsk.AskID, tAsk, (k, o) => o); } } OpenAsks.AddOrUpdate(tAsk.AskID, tAsk, (k, o) => o); }); })); }
public ProposedOrderLeg(ThreadSafeAsk ask, int legLevel, bool doLock = false, ThreadSafeAskLeg leg = null) { Ask = ask; LegLevel = legLevel; DoLock = doLock; Leg = leg; }
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 void BuildProposedOrderForSell(ThreadSafeAsk ask, long askQuantity, IEnumerable <ProposedOrderLeg> orderLegs, ProposedOrder propOrder, bool useLock = false) { bool isFirst = true; int maxLegLevel = orderLegs.Max(l => l.LegLevel); foreach (var legs in orderLegs.GroupBy(o => o.LegLevel).OrderBy(o => o.Key)) { long buyCap = long.MaxValue; if (ask.Legs.Count > 0 && legs.Key == maxLegLevel) { int commodityBuyID = orderLegs.Where(l => l.LegLevel == maxLegLevel).First().CommodityBuyID; var askLeg = ask.Legs.Where(l => l.CommodityID == commodityBuyID).First(); if (askLeg.AvailableQuantityWithoutLockExecute != null) { buyCap = askLeg.AvailableQuantityWithoutLockExecute.Value; } } var propOrderLegs = FillProposedOrderLegsForSell(ask, askQuantity, legs, useLock: useLock, buyCap: buyCap); if (propOrderLegs.Count == 0) { break; } propOrder.SetOrderLegs(propOrderLegs); long sellQuantity = propOrderLegs.Sum(p => p.ProposedSellQuantity); if (askQuantity > sellQuantity && sellQuantity > 0 && !isFirst) { RebalanceOrderLegsForSell(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.ProposedBuyQuantity); propOrderLegs = FillProposedOrderLegsForSell(ask, askQuantity, legs, useLock: useLock); if (propOrderLegs.Count == 0 || askQuantity <= 0) { break; } propOrder.SetOrderLegs(propOrderLegs); } } askQuantity = propOrderLegs.Sum(p => p.ProposedBuyQuantity); if (askQuantity <= 0 || sellQuantity <= 0) { break; } isFirst = false; } }
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 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 ICollection <ProposedOrderLeg> FillProposedOrderLegsForSell(ThreadSafeAsk ask, long askQuantity, IEnumerable <ProposedOrderLeg> orderLegs, bool useLock = false, long buyCap = long.MaxValue) { List <ProposedOrderLeg> propOrderLegs = new List <ProposedOrderLeg>(); foreach (var leg in orderLegs.OrderBy(l => l.RealBuyRatio).ThenBy(l => l.Ask.AskDate)) { leg.SetSellQuantity(askQuantity, useLock, buyCap); if (leg.ProposedBuyQuantity > 0 || leg.ProposedSellQuantity > 0) { propOrderLegs.Add(leg); } askQuantity -= leg.ProposedSellQuantity; buyCap -= leg.ProposedBuyQuantity; if (askQuantity <= 0) { break; } } return(propOrderLegs); }
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); }
public ThreadSafeAskLeg(AskLeg leg, ThreadSafeAsk ask, object sync) { this.Leg = leg; this.sync = sync; this.Ask = ask; }
public ProposedOrder(ThreadSafeAsk ask) { this.Ask = ask; this.orderLegs = new SortedDictionary <int, ICollection <ProposedOrderLeg> >(); }
private ICollection <ProposedOrderLeg> FillProposedOrderLegsForRebalanceForSell(ThreadSafeAsk ask, long buyQuantity, IEnumerable <ProposedOrderLeg> orderLegs, bool useLock = false) { List <ProposedOrderLeg> propOrderLegs = new List <ProposedOrderLeg>(); foreach (var leg in orderLegs.OrderBy(l => l.RealBuyRatio).ThenBy(l => l.Ask.AskDate)) { leg.SetBuyQuantity(buyQuantity, useLock); if (leg.ProposedBuyQuantity > 0 && leg.ProposedSellQuantity > 0) { propOrderLegs.Add(leg); } buyQuantity -= leg.ProposedBuyQuantity; if (buyQuantity <= 0) { break; } } return(propOrderLegs); }
private ThreadSafeAsk CreateAsk(ThreadSafeAsk ask) { ask.PropertyChanged += ThreadSafeAsk_PropertyChanged; return(ask); }
private void DisposeAsk(ThreadSafeAsk ask) { ask.PropertyChanged -= ThreadSafeAsk_PropertyChanged; }
private void ThreadSafeAsk_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { ThreadSafeAsk ask = (ThreadSafeAsk)sender; AsksToProcess.AddOrUpdate(ask.AskID, ask, (k, a) => a); }
private IEnumerable <Order> ExecuteAsk(ThreadSafeAsk ask, int maxLegDepth = 5) { long orderQuantity; var orders = GetQuote(ask, out orderQuantity, maxLegDepth, true); ThreadSafeAsk tAsk; if (ask.AskID == 0 || !OpenAsks.TryGetValue(ask.AskID, out tAsk)) { this.AskRepository.AddAsk(ask.Ask); tAsk = CreateAsk(ask); this.OpenAsks[ask.AskID] = tAsk; foreach (var buyID in tAsk.CommodityBuyID) { foreach (var sellID in tAsk.CommoditySellID) { this.OpenAsksByBuyerCommdoity[buyID][sellID][ask.AskID] = tAsk; } } } List <Ask> orderLegAsks = new List <Ask>(); List <AskLeg> legs = new List <AskLeg>(); if (orders != null) { if (!tAsk.FillOrder(orderQuantity)) { orders = null; } tAsk.RealizeLockExecuteQuantiy(); if (tAsk.AskQuantity <= 0) { if (this.OpenAsks.TryRemove(tAsk.AskID, out tAsk)) { foreach (var buyID in tAsk.CommodityBuyID) { foreach (var sellID in tAsk.CommoditySellID) { this.OpenAsksByBuyerCommdoity[buyID][sellID].TryRemove(tAsk.AskID, out tAsk); } } } } if (orders != null) { foreach (var order in orders) { order.AskID = tAsk.AskID; order.OrderID = Guid.NewGuid(); foreach (var orderLeg in order.OrderLegs) { orderLeg.OrderID = order.OrderID; orderLeg.OrderLegID = Guid.NewGuid(); ThreadSafeAsk orderAsk; if (OpenAsks.TryGetValue(orderLeg.AskID, out orderAsk)) { orderAsk.RealizeLock(orderAsk.IsBuy ? orderLeg.SellQuantity : orderLeg.BuyQuantity); if (orderAsk.Legs.Count > 0) { var leg = orderAsk.Legs.Where(l => orderAsk.IsBuy ? l.CommodityID == orderLeg.CommodityBuyID : l.CommodityID == orderLeg.CommoditySellID).Single(); leg.RealizeLock(orderAsk.IsBuy ? orderLeg.BuyQuantity : orderLeg.SellQuantity); legs.Add(leg.Leg); } if (orderAsk.AskQuantity <= 0) { if (this.OpenAsks.TryRemove(orderAsk.AskID, out orderAsk)) { foreach (var buyID in tAsk.CommodityBuyID) { foreach (var sellID in tAsk.CommoditySellID) { this.OpenAsksByBuyerCommdoity[buyID][sellID].TryRemove(tAsk.AskID, out orderAsk); } } } if (orderAsk != null) { DisposeAsk(orderAsk); } } if (orderAsk != null) { orderLegAsks.Add(orderAsk.Ask); } } } } } } else { tAsk.RealizeLockExecuteQuantiy(); } AskRepository.ExecuteAsk(ask.Ask, orders, orderLegAsks, legs); return(orders); }