public async Task StreamLargeAmount_100kIterations_WithBufferAndSlowdown_ShouldBeFast() { var pair = "BTC/USD"; var data = GetOrderBookSnapshotMockData(pair, 500); var snapshot = new OrderBookLevelBulk(OrderBookAction.Insert, data, CryptoOrderBookType.L2); var source = new OrderBookSourceMock(snapshot); var orderBook = new CryptoOrderBookL2(pair, source); var endTime = DateTime.MinValue; orderBook.OrderBookUpdatedStream.Subscribe(x => endTime = DateTime.UtcNow); source.BufferEnabled = true; source.BufferInterval = TimeSpan.FromMilliseconds(1); source.LoadSnapshotEnabled = false; orderBook.SnapshotReloadEnabled = false; orderBook.ValidityCheckEnabled = false; source.StreamSnapshot(); var startTime = DateTime.UtcNow; var elapsedInsertingMs = StreamLevels(pair, source, 100000, 500, 500, true); var msgInserting = $"Elapsed time for inserting was: {elapsedInsertingMs} ms"; _output.WriteLine(msgInserting); await Task.Delay(1000); var elapsedEnd = endTime.Subtract(startTime).TotalMilliseconds; var msg = $"Elapsed time for processing was: {elapsedEnd} ms"; _output.WriteLine(msg); Assert.True(elapsedEnd < 5000, msgInserting); Assert.True(elapsedInsertingMs < 1000, msgInserting); }
public void StreamingSnapshot_DifferentPairs_ShouldHandleCorrectly() { var pair1 = "BTC/USD"; var pair2 = "ETH/BTC"; var data1 = GetOrderBookSnapshotMockData(pair1, 500); var data2 = GetOrderBookSnapshotMockData(pair2, 200); var data = data2.Concat(data1).ToArray(); var now = CryptoDateUtils.ConvertFromUnixSeconds(1577575307.123451); var snapshot = new OrderBookLevelBulk(OrderBookAction.Insert, data, CryptoOrderBookType.L2) { ExchangeName = "test", ServerSequence = 3, ServerTimestamp = now }; var source = new OrderBookSourceMock(snapshot); ICryptoOrderBook orderBook1 = new CryptoOrderBook(pair1, source); ICryptoOrderBook orderBook2 = new CryptoOrderBook(pair2, source); orderBook1.OrderBookUpdatedStream.Subscribe(x => { Assert.Equal("test", x.ExchangeName); Assert.Equal(3, x.ServerSequence); Assert.Equal(now, x.ServerTimestamp); }); orderBook2.OrderBookUpdatedStream.Subscribe(x => { Assert.Equal("test", x.ExchangeName); Assert.Equal(3, x.ServerSequence); Assert.Equal(now, x.ServerTimestamp); }); source.StreamSnapshot(); Assert.Equal(500, orderBook1.BidLevels.Length); Assert.Equal(500, orderBook1.AskLevels.Length); Assert.Equal(200, orderBook2.BidLevels.Length); Assert.Equal(200, orderBook2.AskLevels.Length); Assert.Equal(499, orderBook1.BidLevels.First().Price); Assert.Equal(1499, orderBook1.BidLevels.First().Amount); Assert.Equal(199, orderBook2.BidLevels.First().Price); Assert.Equal(599, orderBook2.BidLevels.First().Amount); Assert.Equal(501, orderBook1.AskLevels.First().Price); Assert.Equal(2501, orderBook1.AskLevels.First().Amount); Assert.Equal(201, orderBook2.AskLevels.First().Price); Assert.Equal(1001, orderBook2.AskLevels.First().Amount); var levels = orderBook1.Levels; foreach (var level in levels) { Assert.Equal(CryptoPairsHelper.Clean(pair1), level.Pair); } }
public void StreamingSnapshot_ShouldHandleCorrectly() { var pair = "BTC/USD"; var data = GetOrderBookSnapshotMockData(pair, 500); var snapshot = new OrderBookLevelBulk(OrderBookAction.Insert, data, CryptoOrderBookType.L2); var source = new OrderBookSourceMock(snapshot); var orderBook = new CryptoOrderBook(pair, source); source.StreamSnapshot(); Assert.Equal(500, orderBook.BidLevels.Length); Assert.Equal(500, orderBook.AskLevels.Length); Assert.Equal(499, orderBook.BidPrice); Assert.Equal(1499, orderBook.BidLevels.First().Amount); Assert.Equal(501, orderBook.AskPrice); Assert.Equal(2501, orderBook.AskLevels.First().Amount); var levels = orderBook.Levels; foreach (var level in levels) { Assert.Equal(CryptoPairsHelper.Clean(pair), level.Pair); } }
public async Task ValidityChecking_Disabling_ShouldWork() { var pair = "BTC/USD"; var data = new [] { CreateLevel(pair, 480, 50, CryptoOrderSide.Bid), CreateLevel(pair, 520, 50, CryptoOrderSide.Ask), }; var snapshot = new OrderBookLevelBulk(OrderBookAction.Insert, data, CryptoOrderBookType.L2); var source = new OrderBookSourceMock(snapshot); var orderBookUpdatedCount = 0; ICryptoOrderBook orderBook = new CryptoOrderBook(pair, source) { ValidityCheckTimeout = TimeSpan.FromMilliseconds(200), ValidityCheckEnabled = false }; orderBook.OrderBookUpdatedStream.Subscribe(x => { orderBookUpdatedCount++; }); source.StreamSnapshot(); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair, 500, 50, CryptoOrderSide.Bid), CreateLevel(pair, 499, 400, CryptoOrderSide.Ask) )); await Task.Delay(TimeSpan.FromMilliseconds(500)); Assert.Null(source.SnapshotLastPair); Assert.Equal(0, source.SnapshotCalledCount); Assert.Equal(2, orderBookUpdatedCount); }
public void NegativePrice_ShouldHandleCorrectly() { var pair = "BTC/USD"; var data = GetOrderBookSnapshotMockData(pair, 500); var snapshot = new OrderBookLevelBulk(OrderBookAction.Insert, data, CryptoOrderBookType.L2); var source = new OrderBookSourceMock(snapshot); source.BufferEnabled = false; ICryptoOrderBook orderBook = new CryptoOrderBook(pair, source) { DebugEnabled = true }; orderBook.IgnoreDiffsBeforeSnapshot = false; source.StreamBulk(GetInsertBulkL2( CreateLevel(pair, -200, -50, CryptoOrderSide.Bid), CreateLevel(pair, 500, -400, CryptoOrderSide.Ask) )); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair, -50, -600, CryptoOrderSide.Bid), CreateLevel(pair, -100, -3350, CryptoOrderSide.Bid) )); Assert.Equal(-50, orderBook.BidPrice); Assert.Equal(600, orderBook.BidAmount); Assert.Equal(500, orderBook.AskPrice); Assert.Equal(400, orderBook.AskAmount); }
public void StreamLargeAmount_20kIterations_ShouldBeFast() { var pair = "BTC/USD"; var data = GetOrderBookSnapshotMockData(pair, 500); var snapshot = new OrderBookLevelBulk(OrderBookAction.Insert, data, CryptoOrderBookType.L2); var source = new OrderBookSourceMock(snapshot); var orderBook = new CryptoOrderBookL2(pair, source); source.BufferEnabled = false; source.LoadSnapshotEnabled = false; orderBook.SnapshotReloadEnabled = false; orderBook.ValidityCheckEnabled = false; source.StreamSnapshot(); var elapsedMs = StreamLevels(pair, source, 20000, 500, 500); var msg = $"Elapsed time was: {elapsedMs} ms"; _output.WriteLine(msg); Assert.Equal(601, orderBook.BidLevels.Length); Assert.Equal(596, orderBook.AskLevels.Length); Assert.Equal(499, orderBook.BidPrice); Assert.Equal(500, orderBook.AskPrice); Assert.Equal(20049, orderBook.BidAmount); Assert.Equal(22999, orderBook.AskAmount); Assert.True(elapsedMs < 2400, msg); }
private static long StreamLevels(string pair, OrderBookSourceMock source, ICryptoOrderBook book, int iterations, int maxBidPrice, int maxAskPrice, bool slowDown = false) { var bid = book.BidLevels[0]; var ask = book.AskLevels[0]; var sw = new Stopwatch(); var iterationsSafe = iterations * 13; for (int i = 0; i < iterationsSafe; i += 13) { var newBidPrice = i % maxBidPrice; var newAskPrice = maxBidPrice + (i % maxAskPrice); // update levels var bulk = GetUpdateBulkL2( CreateLevel(pair, newBidPrice, CryptoOrderSide.Bid, bid.Id), CreateLevel(pair, newAskPrice, CryptoOrderSide.Ask, ask.Id) ); sw.Start(); source.StreamBulk(bulk); sw.Stop(); if (slowDown && i % 1000 == 0) { Thread.Sleep(10); } } return(sw.ElapsedMilliseconds); }
public void UpdateDelete_ShouldConstructCorrectOrderBook() { var pair1 = "BTC/USD"; var source = new OrderBookSourceMock(); source.BufferEnabled = false; ICryptoOrderBook orderBook = new CryptoOrderBook(pair1, source); orderBook.IgnoreDiffsBeforeSnapshot = false; source.StreamBulk( GetInsertBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 100.111, 0.123, CryptoOrderSide.Ask, null, "ASK1")) ); Assert.Equal(0, orderBook.BidPrice); Assert.Equal(0, orderBook.BidAmount); Assert.Equal(100.111, orderBook.AskPrice); Assert.Equal(0.123, orderBook.AskAmount); source.StreamBulk( GetInsertBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 100.111, 0.444, CryptoOrderSide.Ask, null, "ASK2")) ); source.StreamBulk( GetInsertBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 100.111, 0.555, CryptoOrderSide.Ask, null, "ASK3")) ); var asks = orderBook.FindAskLevelsByPrice(100.111); Assert.Equal(3, asks.Length); Assert.Equal(0, orderBook.BidPrice); Assert.Equal(0, orderBook.BidAmount); Assert.Equal(100.111, orderBook.AskPrice); Assert.Equal(0.123, orderBook.AskAmount); source.StreamBulk( GetDeleteBulk(CryptoOrderBookType.L3, CreateLevel(pair1, null, CryptoOrderSide.Ask, "ASK1")) ); asks = orderBook.FindAskLevelsByPrice(100.111); Assert.Equal(2, asks.Length); Assert.Equal(0, orderBook.BidPrice); Assert.Equal(0, orderBook.BidAmount); Assert.Equal(100.111, orderBook.AskPrice); Assert.Equal(0.444, orderBook.AskAmount); source.StreamBulk( GetUpdateBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 100.111, 0.888, CryptoOrderSide.Ask, null, "ASK2")) ); asks = orderBook.FindAskLevelsByPrice(100.111); Assert.Equal(2, asks.Length); Assert.Equal(0, orderBook.BidPrice); Assert.Equal(0, orderBook.BidAmount); Assert.Equal(100.111, orderBook.AskPrice); Assert.Equal(0.555, orderBook.AskAmount); }
public void DifferentPairs_ShouldNotNotifyAboutOtherPair() { var pair1 = "BTC/USD"; var pair2 = "ETH/USD"; var ob1NotifiedCount = 0; var ob2NotifiedCount = 0; var data1 = GetOrderBookSnapshotMockData(pair1, 500); var snapshot = new OrderBookLevelBulk(OrderBookAction.Insert, data1, CryptoOrderBookType.L2); var source = new OrderBookSourceMock(snapshot); source.BufferEnabled = false; ICryptoOrderBook orderBook1 = new CryptoOrderBook(pair1, source) { DebugEnabled = true }; ICryptoOrderBook orderBook2 = new CryptoOrderBook(pair2, source) { DebugEnabled = true }; orderBook1.IgnoreDiffsBeforeSnapshot = false; orderBook2.IgnoreDiffsBeforeSnapshot = false; orderBook1.OrderBookUpdatedStream.Subscribe(x => ob1NotifiedCount++); orderBook1.TopLevelUpdatedStream.Subscribe(x => ob1NotifiedCount++); orderBook1.BidAskUpdatedStream.Subscribe(x => ob1NotifiedCount++); orderBook2.OrderBookUpdatedStream.Subscribe(x => ob2NotifiedCount++); orderBook2.TopLevelUpdatedStream.Subscribe(x => ob2NotifiedCount++); orderBook2.BidAskUpdatedStream.Subscribe(x => ob2NotifiedCount++); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair1, -200, -50, CryptoOrderSide.Bid), CreateLevel(pair1, 500, -400, CryptoOrderSide.Ask) )); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair1, -50, -600, CryptoOrderSide.Bid), CreateLevel(pair1, -100, -3350, CryptoOrderSide.Bid) )); Assert.Equal(-50, orderBook1.BidPrice); Assert.Equal(600, orderBook1.BidAmount); Assert.Equal(500, orderBook1.AskPrice); Assert.Equal(400, orderBook1.AskAmount); Assert.Equal(0, ob2NotifiedCount); Assert.Equal(2 * 3, ob1NotifiedCount); }
public void NegativePrice_ShouldHandleCorrectly() { var pair1 = "BTC/USD"; var source = new OrderBookSourceMock(); source.BufferEnabled = false; var orderBook = new CryptoOrderBook(pair1, source); orderBook.IgnoreDiffsBeforeSnapshot = false; source.StreamBulk( GetInsertBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 100.111, 0.123, CryptoOrderSide.Ask, null, "ASK1")) ); Assert.Equal(0, orderBook.BidPrice); Assert.Equal(0, orderBook.BidAmount); Assert.Equal(100.111, orderBook.AskPrice); Assert.Equal(0.123, orderBook.AskAmount); source.StreamBulk( GetInsertBulk(CryptoOrderBookType.L3, CreateLevel(pair1, -200, 0.444, CryptoOrderSide.Bid, null, "BID1")) ); source.StreamBulk( GetInsertBulk(CryptoOrderBookType.L3, CreateLevel(pair1, -100, 0.555, CryptoOrderSide.Bid, null, "BID2")) ); Assert.Equal(-100, orderBook.BidPrice); Assert.Equal(0.555, orderBook.BidAmount); Assert.Equal(100.111, orderBook.AskPrice); Assert.Equal(0.123, orderBook.AskAmount); source.StreamBulk( GetInsertBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 100, 777, CryptoOrderSide.Bid, null, "BID2")) ); Assert.Equal(100, orderBook.BidPrice); Assert.Equal(777, orderBook.BidAmount); Assert.Equal(100.111, orderBook.AskPrice); Assert.Equal(0.123, orderBook.AskAmount); }
public void InvalidBidAsk_ShouldBePreserved() { var pair1 = "BTC/USD"; var source = new OrderBookSourceMock(); source.BufferEnabled = false; ICryptoOrderBook orderBook = new CryptoOrderBook(pair1, source); orderBook.IgnoreDiffsBeforeSnapshot = false; source.StreamBulk( GetInsertBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 100.111, 0.123, CryptoOrderSide.Ask, null, "ASK1")) ); Assert.Equal(0, orderBook.BidPrice); Assert.Equal(0, orderBook.BidAmount); Assert.Equal(100.111, orderBook.AskPrice); Assert.Equal(0.123, orderBook.AskAmount); source.StreamBulk( GetInsertBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 100, 0.444, CryptoOrderSide.Bid, null, "BID1")) ); source.StreamBulk( GetInsertBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 103, 0.555, CryptoOrderSide.Bid, null, "BID2")) ); Assert.Equal(103, orderBook.BidPrice); Assert.Equal(0.555, orderBook.BidAmount); Assert.Equal(100.111, orderBook.AskPrice); Assert.Equal(0.123, orderBook.AskAmount); source.StreamBulk( GetDeleteBulk(CryptoOrderBookType.L3, CreateLevel(pair1, null, CryptoOrderSide.Bid, "BID2")) ); Assert.Equal(100, orderBook.BidPrice); Assert.Equal(0.444, orderBook.BidAmount); Assert.Equal(100.111, orderBook.AskPrice); Assert.Equal(0.123, orderBook.AskAmount); }
public void FindLevel_ShouldReturnCorrectValue() { var pair1 = "BTC/USD"; var pair2 = "ETH/BTC"; var data1 = GetOrderBookSnapshotMockData(pair1, 500); var data2 = GetOrderBookSnapshotMockData(pair2, 200); var data = data2.Concat(data1).ToArray(); var snapshot = new OrderBookLevelBulk(OrderBookAction.Insert, data, CryptoOrderBookType.L2); var source = new OrderBookSourceMock(snapshot); ICryptoOrderBook orderBook = new CryptoOrderBook(pair1, source); source.StreamSnapshot(); Assert.Equal(1000, orderBook.FindBidLevelByPrice(0)?.Amount); Assert.Equal(1000, orderBook.FindBidLevelById("0-bid")?.Amount); Assert.Equal(3000, orderBook.FindAskLevelByPrice(1000)?.Amount); Assert.Equal(3000, orderBook.FindAskLevelById("1000-ask")?.Amount); }
private static long StreamLevels(string pair, OrderBookSourceMock source, int iterations, int maxBidPrice, int maxAskCount, bool slowDown = false) { var sw = new Stopwatch(); for (int i = 0; i < iterations; i++) { if (i % 10 == 0) { // insert new levels var bulk = GetInsertBulkL2( CreateLevel(pair, (i % maxBidPrice) + 0.4, i + 50, CryptoOrderSide.Bid), CreateLevel(pair, (Math.Max(i - 55, 1) % maxBidPrice) + 0.4, i + 600, CryptoOrderSide.Bid), CreateLevel(pair, (maxBidPrice + (i % maxAskCount) + 0.4), i + 400, CryptoOrderSide.Ask), CreateLevel(pair, (maxBidPrice + (Math.Min(i + 55, maxAskCount) % maxAskCount) + 0.4), i + 3000, CryptoOrderSide.Ask) ); sw.Start(); source.StreamBulk(bulk); sw.Stop(); } else { // update levels var bulk = GetUpdateBulkL2( CreateLevel(pair, (i % maxBidPrice), i + 50, CryptoOrderSide.Bid), CreateLevel(pair, (Math.Max(i - 55, 1) % maxBidPrice), i + 600, CryptoOrderSide.Bid), CreateLevel(pair, (maxBidPrice + (i % maxAskCount)), i + 400, CryptoOrderSide.Ask), CreateLevel(pair, (maxBidPrice + (Math.Min(i + 55, maxAskCount) % maxAskCount)), i + 3000, CryptoOrderSide.Ask) ); sw.Start(); source.StreamBulk(bulk); sw.Stop(); } if (slowDown && i % 1000 == 0) { Thread.Sleep(10); } } return(sw.ElapsedMilliseconds); }
public async Task StreamingDiff_BeforeSnapshot_ShouldDoNothing() { var pair = "BTC/USD"; var source = new OrderBookSourceMock(); var orderBook = new CryptoOrderBook(pair, source); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair, 100, 50, CryptoOrderSide.Bid), CreateLevel(pair, 55, 600, CryptoOrderSide.Bid), CreateLevel(pair, 105, 400, CryptoOrderSide.Ask), CreateLevel(pair, 200, 3000, CryptoOrderSide.Ask) )); await Task.Delay(500); Assert.Empty(orderBook.BidLevels); Assert.Empty(orderBook.AskLevels); Assert.Equal(0, orderBook.BidPrice); Assert.Equal(0, orderBook.AskPrice); }
public void StreamLargeAmount_100kIterations_ShouldBeFast() { var pair = "BTC/USD"; var data = GetOrderBookSnapshotMockData(pair, 500); var snapshot = new OrderBookLevelBulk(OrderBookAction.Insert, data, CryptoOrderBookType.L2); var source = new OrderBookSourceMock(snapshot); var orderBook = new CryptoOrderBook(pair, source); source.BufferEnabled = false; source.LoadSnapshotEnabled = false; orderBook.SnapshotReloadEnabled = false; orderBook.ValidityCheckEnabled = false; source.StreamSnapshot(); var elapsedMs = StreamLevels(pair, source, 100000, 500, 500); var msg = $"Elapsed time was: {elapsedMs} ms"; _output.WriteLine(msg); Assert.True(elapsedMs < 7000, msg); }
public async Task AutoSnapshotReloading_ShouldWorkCorrectly() { var pair = "BTC/USD"; var data = GetOrderBookSnapshotMockData(pair, 500); var snapshot = new OrderBookLevelBulk(OrderBookAction.Insert, data, CryptoOrderBookType.L2); var source = new OrderBookSourceMock(snapshot) { LoadSnapshotEnabled = true, BufferInterval = TimeSpan.FromMilliseconds(100) }; var orderBook = new CryptoOrderBook(pair, source) { SnapshotReloadTimeout = TimeSpan.FromMilliseconds(500), SnapshotReloadEnabled = true }; await Task.Delay(TimeSpan.FromSeconds(6)); Assert.Equal(pair, source.SnapshotLastPair); Assert.True(source.SnapshotCalledCount >= 4); }
public void InvalidBidAsk_ShouldBePreserved() { var pair = "BTC/USD"; var data = GetOrderBookSnapshotMockData(pair, 500); var snapshot = new OrderBookLevelBulk(OrderBookAction.Insert, data, CryptoOrderBookType.L2); var source = new OrderBookSourceMock(snapshot); source.BufferEnabled = false; ICryptoOrderBook orderBook = new CryptoOrderBook(pair, source) { DebugEnabled = true }; orderBook.IgnoreDiffsBeforeSnapshot = false; var changesTopLevel = new List <IOrderBookChangeInfo>(); orderBook.BidAskUpdatedStream.Subscribe(x => changesTopLevel.Add(x)); var changes = new List <IOrderBookChangeInfo>(); orderBook.OrderBookUpdatedStream.Subscribe(x => changes.Add(x)); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair, 100, 50, CryptoOrderSide.Bid), CreateLevel(pair, 200, 400, CryptoOrderSide.Ask), CreateLevel(pair, 300, 600, CryptoOrderSide.Ask) )); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair, 205, 60, CryptoOrderSide.Bid), CreateLevel(pair, 211, 333, CryptoOrderSide.Bid) )); Assert.Equal(211, orderBook.BidPrice); Assert.Equal(333, orderBook.BidAmount); Assert.Equal(200, orderBook.AskPrice); Assert.Equal(400, orderBook.AskAmount); Assert.False(orderBook.IsValid()); source.StreamBulk(GetDeleteBulkL2( CreateLevel(pair, 200, CryptoOrderSide.Ask) )); Assert.Equal(211, orderBook.BidPrice); Assert.Equal(333, orderBook.BidAmount); Assert.Equal(300, orderBook.AskPrice); Assert.Equal(600, orderBook.AskAmount); Assert.True(orderBook.IsValid()); Assert.Equal(3, changesTopLevel.Count); Assert.True(changesTopLevel[0].Quotes.IsValid()); Assert.False(changesTopLevel[1].Quotes.IsValid()); Assert.True(changesTopLevel[2].Quotes.IsValid()); Assert.Equal(3, changes.Count); Assert.True(changes[0].Quotes.IsValid()); Assert.False(changes[1].Quotes.IsValid()); Assert.True(changes[2].Quotes.IsValid()); }
public void UpdateDeleteComplex_ShouldConstructCorrectOrderBook() { var pair1 = "BTC/USD"; var data = GetOrderBookSnapshotMockDataL3(pair1, 200); var snapshot = new OrderBookLevelBulk(OrderBookAction.Insert, data, CryptoOrderBookType.L3); var source = new OrderBookSourceMock(snapshot); source.BufferEnabled = false; var orderBook = new CryptoOrderBook(pair1, source); orderBook.IgnoreDiffsBeforeSnapshot = true; source.StreamBulk( GetInsertBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 100.111, 0.123, CryptoOrderSide.Ask, null, "ASK1")) ); Assert.Equal(0, orderBook.BidPrice); Assert.Equal(0, orderBook.BidAmount); Assert.Equal(0, orderBook.AskPrice); Assert.Equal(0, orderBook.AskAmount); source.StreamSnapshot(); Assert.Equal(19, orderBook.BidPrice); Assert.Equal(590, orderBook.BidAmount); Assert.Equal(20, orderBook.AskPrice); Assert.Equal(1009, orderBook.AskAmount); var asks = orderBook.FindAskLevelsByPrice(20); var levelsToDelete = asks .Select(x => CreateLevel(x.Pair, null, x.Side, x.Id)) .ToArray(); source.StreamBulk( GetDeleteBulk(CryptoOrderBookType.L3, levelsToDelete) ); source.StreamBulk( GetUpdateBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 20, 0.123, CryptoOrderSide.Bid, null, "BID1")) ); Assert.Equal(20, orderBook.BidPrice); Assert.Equal(0.123, orderBook.BidAmount); Assert.Equal(21, orderBook.AskPrice); Assert.Equal(1019, orderBook.AskAmount); var bids = orderBook.BidLevelsPerPrice; foreach (var bidLevel in bids[19]) { source.StreamBulk( GetDeleteBulk(CryptoOrderBookType.L3, CreateLevel(pair1, bidLevel.Price, bidLevel.Amount, bidLevel.Side, null, bidLevel.Id)) ); } source.StreamBulk( GetDeleteBulk(CryptoOrderBookType.L3, CreateLevel(pair1, null, CryptoOrderSide.Bid, "BID1")) ); Assert.Equal(18, orderBook.BidPrice); Assert.Equal(580, orderBook.BidAmount); Assert.Equal(21, orderBook.AskPrice); Assert.Equal(1019, orderBook.AskAmount); }
public void UpdatePrice_ShouldConstructCorrectOrderBook() { var pair1 = "BTC/USD"; var source = new OrderBookSourceMock(); source.BufferEnabled = false; var orderBook = new CryptoOrderBook(pair1, source); orderBook.IgnoreDiffsBeforeSnapshot = false; source.StreamBulk( GetInsertBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 100.111, 0.123, CryptoOrderSide.Ask, null, "ASK1")) ); source.StreamBulk( GetInsertBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 100.111, 0.444, CryptoOrderSide.Ask, null, "ASK2")) ); source.StreamBulk( GetInsertBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 101, 0.555, CryptoOrderSide.Ask, null, "ASK3")) ); source.StreamBulk( GetInsertBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 101, 0.666, CryptoOrderSide.Ask, null, "ASK4")) ); var asks = orderBook.FindAskLevelsByPrice(100.111); Assert.Equal(2, asks.Length); Assert.Equal(0, orderBook.BidPrice); Assert.Equal(0, orderBook.BidAmount); Assert.Equal(100.111, orderBook.AskPrice); Assert.Equal(0.123, orderBook.AskAmount); source.StreamBulk( GetUpdateBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 100, 0.555, CryptoOrderSide.Ask, null, "ASK3")) ); source.StreamBulk( GetUpdateBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 101, 0.123, CryptoOrderSide.Ask, null, "ASK1")) ); source.StreamBulk( GetInsertBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 100.111, 0.111222, CryptoOrderSide.Bid, null, "BID1")) ); source.StreamBulk( GetInsertBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 99, 0.9, CryptoOrderSide.Bid, null, "BID2")) ); var allAsks = orderBook.AskLevelsPerPrice; Assert.Equal(100.111, orderBook.BidPrice); Assert.Equal(0.111222, orderBook.BidAmount); Assert.Equal(100, orderBook.AskPrice); Assert.Equal(0.555, orderBook.AskAmount); Assert.Equal(3, allAsks.Count); Assert.Single(allAsks[100]); Assert.Equal(2, allAsks[101].Length); Assert.Single(allAsks[100.111]); source.StreamBulk( GetUpdateBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 101, 0.123123, CryptoOrderSide.Bid, null, "BID1")) ); source.StreamBulk( GetInsertBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 101, 0.777, CryptoOrderSide.Ask, null, "ASK5")) ); var ask101 = orderBook.FindAskLevelsByPrice(101); Assert.Equal(3, ask101.Length); Assert.Equal("ASK4", ask101[0].Id); Assert.Equal("ASK1", ask101[1].Id); Assert.Equal("ASK5", ask101[2].Id); source.StreamBulk( GetDeleteBulk(CryptoOrderBookType.L3, CreateLevel(pair1, null, CryptoOrderSide.Ask, "ASK4")) ); source.StreamBulk( GetDeleteBulk(CryptoOrderBookType.L3, CreateLevel(pair1, null, CryptoOrderSide.Bid, "BID2")) ); source.StreamBulk( GetDeleteBulk(CryptoOrderBookType.L3, CreateLevel(pair1, null, CryptoOrderSide.Ask, "ASK3")) ); source.StreamBulk( GetUpdateBulk(CryptoOrderBookType.L3, CreateLevel(pair1, 100.111, 0.123, CryptoOrderSide.Ask, null, "ASK1")) ); allAsks = orderBook.AskLevelsPerPrice; Assert.Equal(101, orderBook.BidPrice); Assert.Equal(0.123123, orderBook.BidAmount); Assert.Equal(100.111, orderBook.AskPrice); Assert.Equal(0.444, orderBook.AskAmount); Assert.Equal(2, allAsks.Count); Assert.Equal(2, allAsks[100.111].Length); Assert.Equal("ASK5", allAsks[101][0].Id); }
public async Task StreamingData_ShouldNotifyOneByOne() { var pair = "BTC/USD"; var data = GetOrderBookSnapshotMockData(pair, 500); var snapshot = new OrderBookLevelBulk(OrderBookAction.Insert, data, CryptoOrderBookType.L2); var source = new OrderBookSourceMock(snapshot); source.BufferInterval = TimeSpan.FromMilliseconds(10); var notificationCount = 0; var changes = new List <IOrderBookChangeInfo>(); ICryptoOrderBook orderBook = new CryptoOrderBook(pair, source) { DebugEnabled = true }; orderBook.OrderBookUpdatedStream.Subscribe(x => { notificationCount++; changes.Add(x); Thread.Sleep(2000); }); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair, 499.4, 50, CryptoOrderSide.Bid), CreateLevel(pair, 500.2, 400, CryptoOrderSide.Ask) )); await Task.Delay(50); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair, 499.5, 600, CryptoOrderSide.Bid), CreateLevel(pair, 300.33, 3350, CryptoOrderSide.Bid) )); await Task.Delay(50); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair, 503.1, 3000, CryptoOrderSide.Ask), CreateLevel(pair, 800.123, 1234, CryptoOrderSide.Ask) )); await Task.Delay(50); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair, 504.1, 3000, CryptoOrderSide.Ask), CreateLevel(pair, 800.101, 1234, CryptoOrderSide.Ask) )); await Task.Delay(50); Assert.Equal(1, notificationCount); await Task.Delay(2100); Assert.Equal(2, notificationCount); var firstChange = changes.First(); var secondChange = changes[1]; Assert.Equal(2, firstChange.Levels.Length); Assert.Equal(499.4, firstChange.Levels.First().Price); Assert.Equal(500.2, firstChange.Levels.Last().Price); Assert.Equal(6, secondChange.Levels.Length); }
public async Task StreamingData_ShouldNotifyCorrectly() { var pair = "BTC/USD"; var data = GetOrderBookSnapshotMockData(pair, 500); var snapshot = new OrderBookLevelBulk(OrderBookAction.Insert, data, CryptoOrderBookType.L2); var source = new OrderBookSourceMock(snapshot); var notificationCount = 0; var notificationBidAskCount = 0; var notificationTopLevelCount = 0; var amountDifferenceBid = 0.0; var amountDifferenceAsk = 0.0; var changes = new List <IOrderBookChangeInfo>(); ICryptoOrderBook orderBook = new CryptoOrderBook(pair, source) { DebugEnabled = true }; orderBook.OrderBookUpdatedStream.Subscribe(x => { notificationCount++; changes.Add(x); foreach (var bulk in x.Sources) { amountDifferenceBid += bulk.Levels.Where(x => x.Side == CryptoOrderSide.Bid).Sum(x => x.AmountDifference); amountDifferenceAsk += bulk.Levels.Where(x => x.Side == CryptoOrderSide.Ask).Sum(x => x.AmountDifference); } }); orderBook.BidAskUpdatedStream.Subscribe(_ => notificationBidAskCount++); orderBook.TopLevelUpdatedStream.Subscribe(_ => notificationTopLevelCount++); source.StreamSnapshot(); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair, 499.4, 50, CryptoOrderSide.Bid), CreateLevel(pair, 500.2, 400, CryptoOrderSide.Ask) )); await Task.Delay(50); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair, 499.5, 600, CryptoOrderSide.Bid), CreateLevel(pair, 300.33, 3350, CryptoOrderSide.Bid) )); await Task.Delay(50); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair, 503.1, 3000, CryptoOrderSide.Ask), CreateLevel(pair, 800.123, 1234, CryptoOrderSide.Ask) )); await Task.Delay(50); source.StreamBulk(GetUpdateBulkL2( CreateLevel(pair, 499, 33, CryptoOrderSide.Bid), CreateLevel(pair, 450, 33, CryptoOrderSide.Bid), CreateLevel(pair, 501, 32, CryptoOrderSide.Ask), CreateLevel(pair, 503.1, 32, CryptoOrderSide.Ask), CreateLevel(pair, 100, null, CryptoOrderSide.Bid), CreateLevel(pair, 900, null, CryptoOrderSide.Ask) )); await Task.Delay(50); source.StreamBulk(GetUpdateBulkL2( CreateLevel(pair, 499.5, 100, CryptoOrderSide.Bid) )); await Task.Delay(50); source.StreamBulk(GetUpdateBulkL2( CreateLevel(pair, 499.5, 200, CryptoOrderSide.Bid) )); await Task.Delay(50); source.StreamBulk(GetUpdateBulkL2( CreateLevel(pair, 500.2, 22, CryptoOrderSide.Ask) )); await Task.Delay(50); source.StreamBulk(GetDeleteBulkL2( CreateLevel(pair, 0, CryptoOrderSide.Bid), CreateLevel(pair, 1, CryptoOrderSide.Bid), CreateLevel(pair, 1000, CryptoOrderSide.Ask), CreateLevel(pair, 999, CryptoOrderSide.Ask) )); await Task.Delay(50); Assert.Equal(9, notificationCount); Assert.Equal(3, notificationBidAskCount); Assert.Equal(6, notificationTopLevelCount); var firstChange = changes.First(); var secondChange = changes[1]; Assert.Equal(0, firstChange.Levels.First().Price); Assert.Equal(501, firstChange.Levels.Last().Price); Assert.Equal(499.4, secondChange.Levels.First().Price); Assert.Equal(500.2, secondChange.Levels.Last().Price); Assert.Equal(623466, amountDifferenceBid); Assert.Equal(1368070, amountDifferenceAsk); }
public async Task StreamingDiff_TwoPairs_ShouldHandleCorrectly() { var pair1 = "BTC/USD"; var pair2 = "ETH/USD"; var data1 = GetOrderBookSnapshotMockData(pair1, 500); var data2 = GetOrderBookSnapshotMockData(pair2, 200); var data = data2.Concat(data1).ToArray(); var snapshot = new OrderBookLevelBulk(OrderBookAction.Insert, data, CryptoOrderBookType.L2); var source = new OrderBookSourceMock(snapshot); ICryptoOrderBook orderBook1 = new CryptoOrderBook(pair1, source) { DebugEnabled = true }; ICryptoOrderBook orderBook2 = new CryptoOrderBook(pair2, source) { DebugEnabled = true }; source.StreamSnapshot(); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair2, 199.4, 50, CryptoOrderSide.Bid), CreateLevel(pair2, 198.3, 600, CryptoOrderSide.Bid), CreateLevel(pair2, 50.33, 3350, CryptoOrderSide.Bid), CreateLevel(pair1, 500.2, 400, CryptoOrderSide.Ask), CreateLevel(pair1, 503.1, 3000, CryptoOrderSide.Ask), CreateLevel(pair1, 800.123, 1234, CryptoOrderSide.Ask), CreateLevel(null, 101.1, null, CryptoOrderSide.Bid), CreateLevel(null, 901.1, null, CryptoOrderSide.Ask) )); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair1, 499.4, 50, CryptoOrderSide.Bid), CreateLevel(pair1, 498.3, 600, CryptoOrderSide.Bid), CreateLevel(pair1, 300.33, 3350, CryptoOrderSide.Bid), CreateLevel(pair2, 200.2, 400, CryptoOrderSide.Ask), CreateLevel(pair2, 203.1, 3000, CryptoOrderSide.Ask), CreateLevel(pair2, 250.123, 1234, CryptoOrderSide.Ask) )); source.StreamBulk(GetUpdateBulkL2( CreateLevel(pair1, 499, 33, CryptoOrderSide.Bid), CreateLevel(pair1, 450, 33, CryptoOrderSide.Bid), CreateLevel(pair1, 501, 32, CryptoOrderSide.Ask), CreateLevel(pair1, 503.1, 32, CryptoOrderSide.Ask), CreateLevel(pair1, 100, null, CryptoOrderSide.Bid), CreateLevel(pair1, 900, null, CryptoOrderSide.Ask) )); source.StreamBulk(GetDeleteBulkL2( CreateLevel(pair1, 0, CryptoOrderSide.Bid), CreateLevel(pair1, 1, CryptoOrderSide.Bid), CreateLevel(pair2, 0, CryptoOrderSide.Bid), CreateLevel(pair2, 1, CryptoOrderSide.Bid) )); source.StreamBulk(GetDeleteBulkL2( CreateLevel(pair2, 400, CryptoOrderSide.Ask), CreateLevel(pair2, 399, CryptoOrderSide.Ask), CreateLevel(pair1, 1000, CryptoOrderSide.Ask), CreateLevel(pair1, 999, CryptoOrderSide.Ask) )); await Task.Delay(500); Assert.NotEmpty(orderBook1.BidLevels); Assert.NotEmpty(orderBook1.AskLevels); Assert.Equal(501, orderBook1.BidLevels.Length); Assert.Equal(501, orderBook1.AskLevels.Length); Assert.Equal(201, orderBook2.BidLevels.Length); Assert.Equal(201, orderBook2.AskLevels.Length); Assert.Equal(499.4, orderBook1.BidPrice); Assert.Equal(500.2, orderBook1.AskPrice); Assert.Equal(199.4, orderBook2.BidPrice); Assert.Equal(200.2, orderBook2.AskPrice); Assert.Equal(33, orderBook1.FindBidLevelByPrice(499)?.Amount); Assert.Equal(33, orderBook1.FindBidLevelByPrice(450)?.Amount); Assert.Equal(32, orderBook1.FindAskLevelByPrice(501)?.Amount); Assert.Equal(32, orderBook1.FindAskLevelByPrice(503.1)?.Amount); var notCompleteBid = orderBook1.FindBidLevelByPrice(100); Assert.Equal(CryptoPairsHelper.Clean(pair1), notCompleteBid.Pair); Assert.Equal(1100, notCompleteBid.Amount); Assert.Equal(3, notCompleteBid.Count); var notCompleteAsk = orderBook1.FindAskLevelByPrice(900); Assert.Equal(CryptoPairsHelper.Clean(pair1), notCompleteAsk.Pair); Assert.Equal(2900, notCompleteAsk.Amount); Assert.Equal(3, notCompleteAsk.Count); Assert.Null(orderBook1.FindBidLevelByPrice(0)); Assert.Null(orderBook1.FindBidLevelByPrice(1)); Assert.Null(orderBook1.FindAskLevelByPrice(1000)); Assert.Null(orderBook1.FindAskLevelByPrice(999)); Assert.Null(orderBook1.FindBidLevelByPrice(101.1)); Assert.Null(orderBook1.FindAskLevelByPrice(901.1)); Assert.Null(orderBook2.FindBidLevelByPrice(101.1)); Assert.Null(orderBook2.FindAskLevelByPrice(901.1)); }
public void StreamingData_ShouldComputeDifferenceCorrectly() { var pair = "BTC/USD"; var data = GetOrderBookSnapshotMockData(pair, 500); var snapshot = new OrderBookLevelBulk(OrderBookAction.Insert, data, CryptoOrderBookType.L2); var source = new OrderBookSourceMock(snapshot); source.BufferEnabled = false; var amountDifferenceBid = 0.0; var amountDifferenceAsk = 0.0; ICryptoOrderBook orderBook = new CryptoOrderBook(pair, source) { DebugEnabled = true }; orderBook.SnapshotReloadEnabled = false; orderBook.ValidityCheckEnabled = false; orderBook.IgnoreDiffsBeforeSnapshot = false; orderBook.OrderBookUpdatedStream.Subscribe(x => { foreach (var bulk in x.Sources) { amountDifferenceBid += bulk.Levels.Where(x => x.Side == CryptoOrderSide.Bid).Sum(x => x.AmountDifference); amountDifferenceAsk += bulk.Levels.Where(x => x.Side == CryptoOrderSide.Ask).Sum(x => x.AmountDifference); } }); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair, 100, 50, CryptoOrderSide.Bid), CreateLevel(pair, 101, 500, CryptoOrderSide.Ask) )); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair, 99, 10, CryptoOrderSide.Bid), CreateLevel(pair, 98, 20, CryptoOrderSide.Bid) )); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair, 102, 100, CryptoOrderSide.Ask), CreateLevel(pair, 103, 200, CryptoOrderSide.Ask) )); source.StreamBulk(GetUpdateBulkL2( CreateLevel(pair, 100, 25, CryptoOrderSide.Bid), CreateLevel(pair, 99, 5, CryptoOrderSide.Bid), CreateLevel(pair, 101, 250, CryptoOrderSide.Ask), CreateLevel(pair, 103, 100, CryptoOrderSide.Ask), CreateLevel(pair, 100, null, CryptoOrderSide.Bid), CreateLevel(pair, 102, null, CryptoOrderSide.Ask) )); source.StreamBulk(GetUpdateBulkL2( CreateLevel(pair, 98, 10, CryptoOrderSide.Bid) )); source.StreamBulk(GetUpdateBulkL2( CreateLevel(pair, 99, 10, CryptoOrderSide.Bid) )); source.StreamBulk(GetUpdateBulkL2( CreateLevel(pair, 103, 400, CryptoOrderSide.Ask) )); source.StreamBulk(GetDeleteBulkL2( CreateLevel(pair, 98, CryptoOrderSide.Bid), CreateLevel(pair, 102, CryptoOrderSide.Ask), CreateLevel(pair, 103, CryptoOrderSide.Ask) )); Assert.Equal(35, amountDifferenceBid); Assert.Equal(250, amountDifferenceAsk); }
public void StreamingData_ShouldComputeIndexesCorrectly() { var pair = "BTC/USD"; var data = GetOrderBookSnapshotMockData(pair, 500); var snapshot = new OrderBookLevelBulk(OrderBookAction.Insert, data, CryptoOrderBookType.L2); var source = new OrderBookSourceMock(snapshot); source.BufferEnabled = false; ICryptoOrderBook orderBook = new CryptoOrderBook(pair, source) { DebugEnabled = true }; orderBook.SnapshotReloadEnabled = false; orderBook.ValidityCheckEnabled = false; orderBook.IgnoreDiffsBeforeSnapshot = false; orderBook.IsIndexComputationEnabled = true; var updatedBidLevels = new List <OrderBookLevel>(); var updatedAskLevels = new List <OrderBookLevel>(); orderBook.OrderBookUpdatedStream.Subscribe(x => { foreach (var bulk in x.Sources) { var bidLevels = bulk.Levels.Where(x => x.Side == CryptoOrderSide.Bid).ToArray(); var askLevels = bulk.Levels.Where(x => x.Side == CryptoOrderSide.Ask).ToArray(); updatedBidLevels.AddRange(bidLevels); updatedAskLevels.AddRange(askLevels); } }); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair, 100, 50, CryptoOrderSide.Bid), CreateLevel(pair, 101, 500, CryptoOrderSide.Ask) )); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair, 99, 10, CryptoOrderSide.Bid), CreateLevel(pair, 98, 20, CryptoOrderSide.Bid) )); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair, 102, 100, CryptoOrderSide.Ask), CreateLevel(pair, 103, 200, CryptoOrderSide.Ask) )); source.StreamBulk(GetUpdateBulkL2( CreateLevel(pair, 100, 25, CryptoOrderSide.Bid), CreateLevel(pair, 99, 5, CryptoOrderSide.Bid), CreateLevel(pair, 101, 250, CryptoOrderSide.Ask), CreateLevel(pair, 103, 100, CryptoOrderSide.Ask), CreateLevel(pair, 100, null, CryptoOrderSide.Bid), CreateLevel(pair, 102, null, CryptoOrderSide.Ask) )); source.StreamBulk(GetUpdateBulkL2( CreateLevel(pair, 98, 10, CryptoOrderSide.Bid) )); source.StreamBulk(GetUpdateBulkL2( CreateLevel(pair, 99, 10, CryptoOrderSide.Bid) )); source.StreamBulk(GetUpdateBulkL2( CreateLevel(pair, 103, 400, CryptoOrderSide.Ask) )); source.StreamBulk(GetDeleteBulkL2( CreateLevel(pair, 98, CryptoOrderSide.Bid), CreateLevel(pair, 102, CryptoOrderSide.Ask), CreateLevel(pair, 103, CryptoOrderSide.Ask) )); source.StreamBulk(GetDeleteBulkL2( CreateLevel(pair, 100, CryptoOrderSide.Bid) )); source.StreamBulk(GetDeleteBulkL2( CreateLevel(pair, 99, CryptoOrderSide.Bid) )); Assert.Equal(0, updatedBidLevels[0].Index); Assert.Equal(1, updatedBidLevels[1].Index); Assert.Equal(2, updatedBidLevels[2].Index); Assert.Equal(0, updatedBidLevels[3].Index); Assert.Equal(1, updatedBidLevels[4].Index); Assert.Equal(0, updatedBidLevels[5].Index); Assert.Equal(2, updatedBidLevels[6].Index); Assert.Equal(1, updatedBidLevels[7].Index); Assert.Equal(2, updatedBidLevels[8].Index); Assert.Equal(0, updatedBidLevels[9].Index); Assert.Equal(0, updatedBidLevels[10].Index); Assert.Equal(0, updatedAskLevels[0].Index); Assert.Equal(1, updatedAskLevels[1].Index); Assert.Equal(2, updatedAskLevels[2].Index); Assert.Equal(0, updatedAskLevels[3].Index); Assert.Equal(2, updatedAskLevels[4].Index); Assert.Equal(1, updatedAskLevels[5].Index); Assert.Equal(2, updatedAskLevels[6].Index); Assert.Equal(1, updatedAskLevels[7].Index); Assert.Equal(2, updatedAskLevels[8].Index); }
public async Task StreamingDiff_ShouldHandleCorrectly() { var pair = "BTC/USD"; var data = GetOrderBookSnapshotMockData(pair, 500); var snapshot = new OrderBookLevelBulk(OrderBookAction.Insert, data, CryptoOrderBookType.L2); var source = new OrderBookSourceMock(snapshot); ICryptoOrderBook orderBook = new CryptoOrderBook(pair, source); source.StreamSnapshot(); source.StreamBulk(GetInsertBulkL2( CreateLevel(pair, 499.4, 50, CryptoOrderSide.Bid), CreateLevel(pair, 498.3, 600, CryptoOrderSide.Bid), CreateLevel(pair, 300.33, 3350, CryptoOrderSide.Bid), CreateLevel(pair, 500.2, 400, CryptoOrderSide.Ask), CreateLevel(pair, 503.1, 3000, CryptoOrderSide.Ask), CreateLevel(pair, 800.123, 1234, CryptoOrderSide.Ask), CreateLevel(null, 101.1, null, CryptoOrderSide.Bid), CreateLevel(null, 901.1, null, CryptoOrderSide.Ask) )); source.StreamBulk(GetUpdateBulkL2( CreateLevel(pair, 499, 33, CryptoOrderSide.Bid), CreateLevel(pair, 450, 33, CryptoOrderSide.Bid), CreateLevel(pair, 501, 32, CryptoOrderSide.Ask), CreateLevel(pair, 503.1, 32, CryptoOrderSide.Ask), CreateLevel(pair, 100, null, CryptoOrderSide.Bid), CreateLevel(pair, 900, null, CryptoOrderSide.Ask) )); source.StreamBulk(GetDeleteBulkL2( CreateLevel(pair, 0, CryptoOrderSide.Bid), CreateLevel(pair, 1, CryptoOrderSide.Bid), CreateLevel(pair, 1000, CryptoOrderSide.Ask), CreateLevel(pair, 999, CryptoOrderSide.Ask) )); await Task.Delay(500); Assert.NotEmpty(orderBook.BidLevels); Assert.NotEmpty(orderBook.AskLevels); Assert.Equal(501, orderBook.BidLevels.Length); Assert.Equal(501, orderBook.AskLevels.Length); Assert.Equal(499.4, orderBook.BidPrice); Assert.Equal(500.2, orderBook.AskPrice); Assert.Equal(33, orderBook.FindBidLevelByPrice(499)?.Amount); Assert.Equal(33, orderBook.FindBidLevelByPrice(450)?.Amount); Assert.Equal(32, orderBook.FindAskLevelByPrice(501)?.Amount); Assert.Equal(32, orderBook.FindAskLevelByPrice(503.1)?.Amount); var notCompleteBid = orderBook.FindBidLevelByPrice(100); Assert.Equal(CryptoPairsHelper.Clean(pair), notCompleteBid.Pair); Assert.Equal(1100, notCompleteBid.Amount); Assert.Equal(3, notCompleteBid.Count); var notCompleteAsk = orderBook.FindAskLevelByPrice(900); Assert.Equal(CryptoPairsHelper.Clean(pair), notCompleteAsk.Pair); Assert.Equal(2900, notCompleteAsk.Amount); Assert.Equal(3, notCompleteAsk.Count); Assert.Null(orderBook.FindBidLevelByPrice(0)); Assert.Null(orderBook.FindBidLevelByPrice(1)); Assert.Null(orderBook.FindAskLevelByPrice(1000)); Assert.Null(orderBook.FindAskLevelByPrice(999)); Assert.Null(orderBook.FindBidLevelByPrice(101.1)); Assert.Null(orderBook.FindAskLevelByPrice(901.1)); }
public void StreamingSnapshot_DifferentPairsSeparately_ShouldHandleCorrectly() { var pair1 = "BTC/USD"; var pair2 = "ETH/BTC"; var data1 = GetOrderBookSnapshotMockData(pair1, 500); var data2 = GetOrderBookSnapshotMockData(pair2, 200); var now = CryptoDateUtils.ConvertFromUnixSeconds(1577575307.123451); var snapshot1 = new OrderBookLevelBulk(OrderBookAction.Insert, data1, CryptoOrderBookType.L2) { ExchangeName = "test", ServerSequence = 4, ServerTimestamp = now.AddMilliseconds(1) }; var snapshot2 = new OrderBookLevelBulk(OrderBookAction.Insert, data2, CryptoOrderBookType.L2) { ExchangeName = "test", ServerSequence = 5, ServerTimestamp = now.AddMilliseconds(2) }; var source = new OrderBookSourceMock(); var orderBook1 = new CryptoOrderBookL2(pair1, source); var orderBook2 = new CryptoOrderBookL2(pair2, source); orderBook1.OrderBookUpdatedStream.Subscribe(x => { Assert.Equal("test", x.ExchangeName); Assert.Equal(4, x.ServerSequence); Assert.Equal("1577575307.124451", x.ServerTimestamp.ToUnixSecondsString()); }); orderBook2.OrderBookUpdatedStream.Subscribe(x => { Assert.Equal("test", x.ExchangeName); Assert.Equal(5, x.ServerSequence); Assert.Equal("1577575307.125451", x.ServerTimestamp.ToUnixSecondsString()); }); source.StreamSnapshotRaw(snapshot1); source.StreamSnapshotRaw(snapshot2); Assert.Equal(500, orderBook1.BidLevels.Length); Assert.Equal(500, orderBook1.AskLevels.Length); Assert.Equal(200, orderBook2.BidLevels.Length); Assert.Equal(200, orderBook2.AskLevels.Length); Assert.Equal(499, orderBook1.BidLevels.First().Price); Assert.Equal(1499, orderBook1.BidLevels.First().Amount); Assert.Equal(199, orderBook2.BidLevels.First().Price); Assert.Equal(599, orderBook2.BidLevels.First().Amount); Assert.Equal(501, orderBook1.AskLevels.First().Price); Assert.Equal(2501, orderBook1.AskLevels.First().Amount); Assert.Equal(201, orderBook2.AskLevels.First().Price); Assert.Equal(1001, orderBook2.AskLevels.First().Amount); var levels = orderBook1.Levels; foreach (var level in levels) { Assert.Equal(CryptoPairsHelper.Clean(pair1), level.Pair); } }