private static void GetBidsAndAsks(Core.Model.OrderBook orderBook, int pricePrecision, int quantityPrecision, int listDisplayCount, int chartDisplayCount, out List <OrderBookPriceLevel> topAsks, out List <OrderBookPriceLevel> topBids, out List <OrderBookPriceLevel> chartAsks, out List <OrderBookPriceLevel> chartBids, out List <OrderBookPriceLevel> aggregatedAsks, out List <OrderBookPriceLevel> aggregatedBids, out decimal bidAskSpread) { var orderBookCount = chartDisplayCount > listDisplayCount ? chartDisplayCount : listDisplayCount; // Order by price: bids (DESC) and asks (ASC) var orderedAsks = orderBook.Asks.OrderBy(a => a.Price).ToList(); var orderedBids = orderBook.Bids.OrderByDescending(b => b.Price).ToList(); // The OrderBookCount is the greater of the OrderBookDisplayCount OrderBookChartDisplayCount. // Take the asks and bids for the OrderBookCount as new instances of type OrderBookPriceLevel // i.e. discard those that we are not interested in displaying on the screen. var asks = orderedAsks.Take(orderBookCount).Select(ask => new OrderBookPriceLevel { Price = ask.Price.Trim(pricePrecision), Quantity = ask.Quantity.Trim(quantityPrecision) }).ToList(); var bids = orderedBids.Take(orderBookCount).Select(bid => new OrderBookPriceLevel { Price = bid.Price.Trim(pricePrecision), Quantity = bid.Quantity.Trim(quantityPrecision) }).ToList(); var topAsk = asks.First(); var topBid = bids.First(); if (topAsk.Price != 0) { bidAskSpread = Math.Round(((topAsk.Price - topBid.Price) / topAsk.Price) * 100, 2, MidpointRounding.AwayFromZero); } else { bidAskSpread = 0.00m; } // Take the top bids and asks for the order book bid and ask lists and order descending. topAsks = asks.Take(listDisplayCount).Reverse().ToList(); topBids = bids.Take(listDisplayCount).ToList(); // Take the bid and aks to display in the the order book chart. chartAsks = asks.Take(chartDisplayCount).ToList(); var tempbids = bids.Take(chartDisplayCount).ToList(); chartBids = tempbids.Reverse <OrderBookPriceLevel>().ToList(); // Create the aggregated bids and asks for the aggregated bid and ask chart. aggregatedAsks = GetAggregatedList(asks); var aggBids = GetAggregatedList(bids); aggregatedBids = aggBids.Reverse <OrderBookPriceLevel>().ToList(); }
public Task <OrderBook> CreateLocalOrderBook(Symbol symbol, Core.Model.OrderBook orderBook, int listDisplayCount, int chartDisplayCount) { if (symbol == null) { throw new ArgumentNullException(nameof(symbol)); } if (orderBook == null) { throw new ArgumentNullException(nameof(orderBook)); } var tcs = new TaskCompletionSource <OrderBook>(); try { List <OrderBookPriceLevel> topAsks; List <OrderBookPriceLevel> topBids; List <OrderBookPriceLevel> chartAsks; List <OrderBookPriceLevel> chartBids; List <OrderBookPriceLevel> aggregatedAsks; List <OrderBookPriceLevel> aggregatedBids; decimal bidAskSpread; GetBidsAndAsks(orderBook, symbol.PricePrecision, symbol.QuantityPrecision, listDisplayCount, chartDisplayCount, out topAsks, out topBids, out chartAsks, out chartBids, out aggregatedAsks, out aggregatedBids, out bidAskSpread); var newOrderBook = new OrderBook { LastUpdateId = orderBook.LastUpdateId, Symbol = orderBook.Symbol, BaseSymbol = symbol.BaseAsset.Symbol, QuoteSymbol = symbol.QuoteAsset.Symbol, BidAskSpread = bidAskSpread }; newOrderBook.TopAsks.AddRange(topAsks); newOrderBook.TopBids.AddRange(topBids); newOrderBook.ChartAsks.AddRange(new ChartValues <OrderBookPriceLevel>(chartAsks)); newOrderBook.ChartBids.AddRange(new ChartValues <OrderBookPriceLevel>(chartBids)); newOrderBook.ChartAggregatedAsks.AddRange(new ChartValues <OrderBookPriceLevel>(aggregatedAsks)); newOrderBook.ChartAggregatedBids.AddRange(new ChartValues <OrderBookPriceLevel>(aggregatedBids)); tcs.SetResult(newOrderBook); } catch (Exception ex) { tcs.SetException(ex); } return(tcs.Task); }
private static Core.Model.OrderBook NewOrderBook(OrderBook ob) { var orderBook = new Core.Model.OrderBook { Symbol = ob.Symbol, Exchange = Exchange.Binance, LastUpdateId = ob.LastUpdateId }; orderBook.Asks = (from ask in ob.Asks select new Core.Model.OrderBookPriceLevel { Price = ask.Price, Quantity = ask.Quantity }).ToList(); orderBook.Bids = (from bid in ob.Bids select new Core.Model.OrderBookPriceLevel { Price = bid.Price, Quantity = bid.Quantity }).ToList(); return(orderBook); }
public void UpdateLocalOrderBook(OrderBook orderBook, Core.Model.OrderBook updateOrderBook, int pricePrecision, int quantityPrecision, int listDisplayCount, int chartDisplayCount) { if (updateOrderBook == null) { throw new ArgumentNullException(nameof(updateOrderBook)); } if (orderBook == null) { throw new ArgumentNullException(nameof(orderBook)); } orderBook.LastUpdateId = updateOrderBook.LastUpdateId; List <OrderBookPriceLevel> topAsks; List <OrderBookPriceLevel> topBids; List <OrderBookPriceLevel> chartAsks; List <OrderBookPriceLevel> chartBids; List <OrderBookPriceLevel> aggregatedAsks; List <OrderBookPriceLevel> aggregatedBids; decimal bidAskSpread; GetBidsAndAsks(updateOrderBook, pricePrecision, quantityPrecision, listDisplayCount, chartDisplayCount, out topAsks, out topBids, out chartAsks, out chartBids, out aggregatedAsks, out aggregatedBids, out bidAskSpread); // Create new instances of the top // bids and asks, reversing the asks orderBook.TopAsks.Clear(); orderBook.TopBids.Clear(); orderBook.TopAsks.AddRange(topAsks); orderBook.TopBids.AddRange(topBids); orderBook.BidAskSpread = bidAskSpread; // Update the existing orderbook chart // bids and asks, reversing the bids. UpdateChartValues(orderBook.ChartAsks, chartAsks); UpdateChartValues(orderBook.ChartBids, chartBids); UpdateChartValues(orderBook.ChartAggregatedAsks, aggregatedAsks); UpdateChartValues(orderBook.ChartAggregatedBids, aggregatedBids); }
internal async void UpdateOrderBook(Core.Model.OrderBook exchangeOrderBook) { if (symbolCancellationTokenSource.IsCancellationRequested) { return; } await orderBookSemaphoreSlim.WaitAsync(symbolCancellationTokenSource.Token); try { if (OrderBook == null) { OrderBook = await orderBookHelper.CreateLocalOrderBook(Symbol, exchangeOrderBook, OrderBookDisplayCount, OrderBookChartDisplayCount); if (IsLoadingOrderBook) { IsLoadingOrderBook = false; } } else if (OrderBook.LastUpdateId >= exchangeOrderBook.LastUpdateId) { // If the incoming order book is older than the local one ignore it. return; } else { orderBookHelper.UpdateLocalOrderBook(OrderBook, exchangeOrderBook, symbol.PricePrecision, symbol.QuantityPrecision, OrderBookDisplayCount, OrderBookChartDisplayCount); } } finally { orderBookSemaphoreSlim.Release(); } }
public async Task <OrderBook> CreateLocalOrderBook(Symbol symbol, Core.Model.OrderBook orderBook, int listDisplayCount, int chartDisplayCount) { if (symbol == null) { throw new ArgumentNullException(nameof(symbol)); } if (orderBook == null) { throw new ArgumentNullException(nameof(orderBook)); } Core.Model.OrderBook snapShot; using (var cancellationTokenSource = new CancellationTokenSource()) { snapShot = await kucoinExchangeApi.GetOrderBookAsync(symbol.ExchangeSymbol, 100, cancellationTokenSource.Token).ConfigureAwait(false); } // Order by price: bids (ASC) and asks (ASC) // Discard those that we are not interested in displaying on the screen. var snapShotAsks = new List <Core.Model.OrderBookPriceLevel>(snapShot.Asks.OrderBy(a => a.Price).ToList()); var snapShotBids = new List <Core.Model.OrderBookPriceLevel>(snapShot.Bids.OrderBy(b => b.Price).ToList()); long latestSquence = snapShot.LastUpdateId; ReplayPriceLevels(snapShotAsks, orderBook.Asks, snapShot.LastUpdateId, ref latestSquence); ReplayPriceLevels(snapShotBids, orderBook.Bids, snapShot.LastUpdateId, ref latestSquence); var pricePrecision = symbol.PricePrecision; var quantityPrecision = symbol.QuantityPrecision; var asks = snapShotAsks.Select(ask => new OrderBookPriceLevel { Price = ask.Price.Trim(pricePrecision), Quantity = ask.Quantity.Trim(quantityPrecision) }).ToList(); var bids = snapShotBids.Select(bid => new OrderBookPriceLevel { Price = bid.Price.Trim(pricePrecision), Quantity = bid.Quantity.Trim(quantityPrecision) }).ToList(); var topAsk = asks.First(); var topBid = bids.First(); decimal bidAskSpread; if (topAsk.Price != 0) { bidAskSpread = Math.Round(((topAsk.Price - topBid.Price) / topAsk.Price) * 100, 2, MidpointRounding.AwayFromZero); } else { bidAskSpread = 0.00m; } // Take the top bids and asks for the order book bid and ask lists and order descending. var topAsks = asks.Take(listDisplayCount).OrderByDescending(a => a.Price).ToList(); var topBids = bids.OrderByDescending(b => b.Price).Take(listDisplayCount).ToList(); var skipExcessBids = 0; if (bids.Count > chartDisplayCount) { skipExcessBids = bids.Count - chartDisplayCount; } // Take the bid and aks to display in the the order book chart. var chartAsks = asks.Take(chartDisplayCount).ToList(); var chartBids = bids.Skip(skipExcessBids).ToList(); // Create the aggregated bids and asks for the aggregated bid and ask chart. var aggregatedAsks = GetAggregatedAsks(chartAsks); var aggregatedBids = GetAggregatedBids(chartBids); var newOrderBook = new OrderBook { LastUpdateId = latestSquence, Symbol = orderBook.Symbol, BaseSymbol = symbol.BaseAsset.Symbol, QuoteSymbol = symbol.QuoteAsset.Symbol, BidAskSpread = bidAskSpread }; newOrderBook.Asks.AddRange(snapShotAsks); newOrderBook.Bids.AddRange(snapShotBids); newOrderBook.TopAsks.AddRange(topAsks); newOrderBook.TopBids.AddRange(topBids); newOrderBook.ChartAsks.AddRange(new ChartValues <OrderBookPriceLevel>(chartAsks)); newOrderBook.ChartBids.AddRange(new ChartValues <OrderBookPriceLevel>(chartBids)); newOrderBook.ChartAggregatedAsks.AddRange(new ChartValues <OrderBookPriceLevel>(aggregatedAsks)); newOrderBook.ChartAggregatedBids.AddRange(new ChartValues <OrderBookPriceLevel>(aggregatedBids)); return(newOrderBook); }
public void UpdateLocalOrderBook(OrderBook orderBook, Core.Model.OrderBook updateOrderBook, int pricePrecision, int quantityPrecision, int listDisplayCount, int chartDisplayCount) { if (orderBook == null) { throw new ArgumentNullException(nameof(orderBook)); } if (updateOrderBook == null) { throw new ArgumentNullException(nameof(updateOrderBook)); } long latestSquence = orderBook.LastUpdateId; ReplayPriceLevels(orderBook.Asks, updateOrderBook.Asks, orderBook.LastUpdateId, ref latestSquence); ReplayPriceLevels(orderBook.Bids, updateOrderBook.Bids, orderBook.LastUpdateId, ref latestSquence); orderBook.LastUpdateId = latestSquence; var asks = orderBook.Asks.Select(ask => new OrderBookPriceLevel { Price = ask.Price.Trim(pricePrecision), Quantity = ask.Quantity.Trim(quantityPrecision) }).ToList(); var bids = orderBook.Bids.Select(bid => new OrderBookPriceLevel { Price = bid.Price.Trim(pricePrecision), Quantity = bid.Quantity.Trim(quantityPrecision) }).ToList(); var topAsk = asks.First(); var topBid = bids.First(); if (topAsk.Price != 0) { orderBook.BidAskSpread = Math.Round(((topAsk.Price - topBid.Price) / topAsk.Price), 2, MidpointRounding.AwayFromZero); } else { orderBook.BidAskSpread = 0.00m; } // Take the top bids and asks for the order book bid and ask lists and order descending. orderBook.TopAsks.Clear(); orderBook.TopBids.Clear(); orderBook.TopAsks.AddRange(asks.Take(listDisplayCount).OrderByDescending(a => a.Price).ToList()); orderBook.TopBids.AddRange(bids.OrderByDescending(b => b.Price).Take(listDisplayCount).ToList()); var skipExcessBids = 0; if (bids.Count > chartDisplayCount) { skipExcessBids = bids.Count - chartDisplayCount; } // Take the bid and aks to display in the the order book chart. var chartAsks = asks.Take(chartDisplayCount).ToList(); var chartBids = bids.Skip(skipExcessBids).ToList(); // Create the aggregated bids and asks for the aggregated bid and ask chart. var aggregatedAsks = GetAggregatedAsks(chartAsks); var aggregatedBids = GetAggregatedBids(chartBids); UpdateChartValues(orderBook.ChartAsks, chartAsks); UpdateChartValues(orderBook.ChartBids, chartBids); UpdateChartValues(orderBook.ChartAggregatedAsks, aggregatedAsks); UpdateChartValues(orderBook.ChartAggregatedBids, aggregatedBids); }