public void FromOrderBook_0_Test() { const string source = "FakeExchange"; var timestamp = DateTime.UtcNow; var btcEurOrderBook = new OrderBook(source, _btceur, new List <LimitOrder> // bids { new LimitOrder(8825, 9), new LimitOrder(8823, 5) }, new List <LimitOrder> // asks { new LimitOrder(9000, 10), new LimitOrder(8999.95m, 7), new LimitOrder(8900.12345677m, 3) }, timestamp); var synthOrderBook = SynthOrderBook.FromOrderBook(btcEurOrderBook, _btceur); Assert.Equal(source, synthOrderBook.Source); Assert.Equal(_btceur, synthOrderBook.AssetPair); Assert.Equal("BTCEUR", synthOrderBook.ConversionPath); Assert.Equal(2, synthOrderBook.Bids.Count()); Assert.Equal(3, synthOrderBook.Asks.Count()); Assert.Equal(8825m, synthOrderBook.BestBid.Price); Assert.Equal(9000m, synthOrderBook.Asks.Max(x => x.Price)); Assert.Equal(8823m, synthOrderBook.Bids.Min(x => x.Price)); Assert.Equal(8900.12345677m, synthOrderBook.BestAsk.Price); Assert.Equal(9, synthOrderBook.BestBid.Volume); Assert.Equal(10, synthOrderBook.Asks.Max(x => x.Volume)); Assert.Equal(5, synthOrderBook.Bids.Min(x => x.Volume)); Assert.Equal(3, synthOrderBook.BestAsk.Volume); Assert.Equal(timestamp, synthOrderBook.Timestamp); Assert.Equal(1, synthOrderBook.OriginalOrderBooks.Count); }
public void ArbitrageVolumePnL_Simple2_Test() { var eurgbpOB = new OrderBook("FE", _eurgbp, new List <LimitOrder> (), // bids new List <LimitOrder> // asks { new LimitOrder(0.90477m, 757921.29m) }, DateTime.Now); var eurusdOB = new OrderBook("FE", _eurusd, new List <LimitOrder> // bids { new LimitOrder(1.16211m, 1923.11m), new LimitOrder(0.58117m, 100) }, new List <LimitOrder>(), // asks DateTime.Now); var gbpusdOB = new OrderBook("FE", _gbpusd, new List <LimitOrder>(), // bids new List <LimitOrder> // asks { new LimitOrder(1.28167m, 2909.98m), // 0.78023, 3729.63406 (reciprocal) new LimitOrder(1.29906m, 50000m) // 0.76978, 64953.0 (reciprocal) }, DateTime.Now); var eurgbpSynth = SynthOrderBook.FromOrderBooks(eurusdOB, gbpusdOB, _eurgbp); var volumePnL = Arbitrage.GetArbitrageVolumeAndPnL(eurgbpSynth.Bids, eurgbpOB.Asks); Assert.NotNull(volumePnL?.Volume); Assert.NotNull(volumePnL?.PnL); }
public Task <IEnumerable <SynthOrderBook> > CalculateSynthOrderBooksAsync() { var watch = Stopwatch.StartNew(); var newActualSynthOrderBooks = new List <SynthOrderBook>(); var orderBooks = GetWantedActualOrderBooks().ToList(); var settings = Settings(); foreach (var @base in settings.BaseAssets) { var target = new AssetPair(@base, settings.QuoteAsset, 8, 8); var newActualSynthsFromAll = SynthOrderBook.GetSynthsFromAll(target, orderBooks, orderBooks); newActualSynthOrderBooks.AddRange(newActualSynthsFromAll); } foreach (var newSynthOrderBook in newActualSynthOrderBooks) { _synthOrderBooks[new AssetPairSource(newSynthOrderBook.Source, newSynthOrderBook.AssetPair)] = newSynthOrderBook; } watch.Stop(); if (watch.ElapsedMilliseconds > 500) { _log.Info($"{watch.ElapsedMilliseconds} ms, {_synthOrderBooks.Count} synthetic order books, {orderBooks.Count} order books."); } return(Task.FromResult(_synthOrderBooks.Select(x => x.Value))); }
public void FromOrderBook_1_Test() { const string source = "FakeExchange"; var timestamp = DateTime.UtcNow; var inverted = _btcusd.Invert(); var btcUsdOrderBook = new OrderBook(source, _btcusd, new List <LimitOrder> // bids { new LimitOrder(1 / 8825m, 9), new LimitOrder(1 / 8823m, 5) }, new List <LimitOrder> // asks { new LimitOrder(1 / 9000m, 10), new LimitOrder(1 / 8999.95m, 7), new LimitOrder(1 / 8900.12345677m, 3) }, timestamp); var synthOrderBook = SynthOrderBook.FromOrderBook(btcUsdOrderBook, inverted); Assert.Equal(source, synthOrderBook.Source); Assert.Equal(inverted, synthOrderBook.AssetPair); Assert.Equal("BTCUSD", synthOrderBook.ConversionPath); Assert.Equal(3, synthOrderBook.Bids.Count()); Assert.Equal(2, synthOrderBook.Asks.Count()); Assert.Equal(9000m, synthOrderBook.BestBid.Price, 8); Assert.Equal(8825m, synthOrderBook.Asks.Max(x => x.Price), 8); Assert.Equal(8900.12345677m, synthOrderBook.Bids.Min(x => x.Price), 8); Assert.Equal(8823m, synthOrderBook.BestAsk.Price, 8); Assert.Equal(0.00111111m, synthOrderBook.BestBid.Volume, 8); Assert.Equal(0.00101983m, synthOrderBook.Asks.Max(x => x.Volume), 8); Assert.Equal(0.00033707m, synthOrderBook.Bids.Min(x => x.Volume), 8); Assert.Equal(0.00056670m, synthOrderBook.BestAsk.Volume, 8); Assert.Equal(timestamp, synthOrderBook.Timestamp); Assert.Equal(1, synthOrderBook.OriginalOrderBooks.Count); }
public void OrderBooks_PrepareForEnumeration_0_0_Test() { var orderBooks = GetOrderBooks(_btceur, _eurusd); var result = SynthOrderBook.PrepareForEnumeration(orderBooks, _btcusd); AssertChained2(result); }
public void OrderBooks_PrepareForEnumeration_1_1_1_Test() { var orderBooks = GetOrderBooks(_btceur.Invert(), _eurchf.Invert(), _chfusd.Invert()); var result = SynthOrderBook.PrepareForEnumeration(orderBooks, _btcusd); AssertChained3(result); }
public SynthOrderBookLine(SynthOrderBook synthOrderBook, VolumePrice volumePrice) { Debug.Assert(synthOrderBook != null); Price = volumePrice.Price; Volume = volumePrice.Volume; SynthOrderBook = synthOrderBook; }
public void From3OrderBooks_1_0_1_Test() { const string source1 = "TEST1"; const string source2 = "TEST2"; const string source3 = "TEST3"; var timestamp1 = DateTime.UtcNow.AddSeconds(-2); var timestamp2 = DateTime.UtcNow.AddSeconds(-1); var timestamp3 = DateTime.UtcNow; var btcEurOrderBook = new OrderBook(source1, _eurbtc, new List <VolumePrice> // bids { new VolumePrice(1 / 7310m, 9), new VolumePrice(1 / 7300m, 5) }, new List <VolumePrice> // asks { new VolumePrice(1 / 7320m, 10), new VolumePrice(1 / 7330m, 7), new VolumePrice(1 / 7340m, 3) }, timestamp1); var eurJpyOrderBook = new OrderBook(source2, _eurjpy, new List <VolumePrice> // bids { new VolumePrice(131m, 9), new VolumePrice(130m, 5) }, new List <VolumePrice> // asks { new VolumePrice(132m, 11), new VolumePrice(133m, 7), new VolumePrice(134m, 3) }, timestamp2); var jpyUsdOrderBook = new OrderBook(source3, _usdjpy, new List <VolumePrice> // bids { new VolumePrice(1 / 0.009132m, 9), new VolumePrice(1 / 0.009131m, 5) }, new List <VolumePrice> // asks { new VolumePrice(1 / 0.009133m, 12), new VolumePrice(1 / 0.009134m, 7), new VolumePrice(1 / 0.009135m, 3) }, timestamp3); var synthOrderBook = SynthOrderBook.FromOrderBooks(btcEurOrderBook, eurJpyOrderBook, jpyUsdOrderBook, _btcusd); Assert.Equal("TEST1-TEST2-TEST3", synthOrderBook.Source); Assert.Equal(_btcusd, synthOrderBook.AssetPair); Assert.Equal("TEST1-EURBTC * TEST2-EURJPY * TEST3-USDJPY", synthOrderBook.ConversionPath); Assert.Equal(6, synthOrderBook.Bids.Count()); Assert.Equal(3, synthOrderBook.Asks.Count()); Assert.Equal(8783.6679m, synthOrderBook.BestBid.Value.Price, 8); Assert.Equal(8798.6316m, synthOrderBook.BestAsk.Value.Price, 8); Assert.Equal(0.00034154m, synthOrderBook.BestBid.Value.Volume, 8); Assert.Equal(0.00056827m, synthOrderBook.BestAsk.Value.Volume, 8); Assert.Equal(timestamp1, synthOrderBook.Timestamp); Assert.Equal(3, synthOrderBook.OriginalOrderBooks.Count); }
public void From3OrderBooks_0_1_1_Test() { const string source1 = "TEST1"; const string source2 = "TEST2"; const string source3 = "TEST3"; var timestamp1 = DateTime.UtcNow.AddSeconds(-2); var timestamp2 = DateTime.UtcNow.AddSeconds(-1); var timestamp3 = DateTime.UtcNow; var btcEurOrderBook = new OrderBook(source1, _btceur, new List <VolumePrice> // bids { new VolumePrice(7310m, 9), new VolumePrice(7300m, 5) }, new List <VolumePrice> // asks { new VolumePrice(7320m, 10), new VolumePrice(7330m, 7), new VolumePrice(7340m, 3) }, timestamp1); var jpyEurOrderBook = new OrderBook(source2, _jpyeur, new List <VolumePrice> // bids { new VolumePrice(1 / 132m, 11), new VolumePrice(1 / 133m, 7), new VolumePrice(1 / 134m, 3) }, new List <VolumePrice> // asks { new VolumePrice(1 / 131m, 9), new VolumePrice(1 / 130m, 5) }, timestamp2); var jpyUsdOrderBook = new OrderBook(source3, _usdjpy, new List <VolumePrice> // bids { new VolumePrice(1 / 0.009132m, 9), new VolumePrice(1 / 0.009131m, 5) }, new List <VolumePrice> // asks { new VolumePrice(1 / 0.009133m, 12), new VolumePrice(1 / 0.009134m, 7), new VolumePrice(1 / 0.009135m, 3) }, timestamp3); var synthOrderBook = SynthOrderBook.FromOrderBooks(btcEurOrderBook, jpyEurOrderBook, jpyUsdOrderBook, _btcusd); Assert.Equal("TEST1-TEST2-TEST3", synthOrderBook.Source); Assert.Equal(_btcusd, synthOrderBook.AssetPair); Assert.Equal("TEST1-BTCEUR * TEST2-JPYEUR * TEST3-USDJPY", synthOrderBook.ConversionPath); Assert.Equal(2, synthOrderBook.Bids.Count()); Assert.Equal(3, synthOrderBook.Asks.Count()); Assert.Equal(8747.76735m, synthOrderBook.BestBid.Value.Price, 8); Assert.Equal(8822.73744m, synthOrderBook.BestAsk.Value.Price, 8); Assert.Equal(0.00000940m, synthOrderBook.BestBid.Value.Volume, 8); Assert.Equal(0.00001138m, synthOrderBook.BestAsk.Value.Volume, 8); Assert.Equal(timestamp1, synthOrderBook.Timestamp); Assert.Equal(3, synthOrderBook.OriginalOrderBooks.Count); }
public void From3OrderBooks_0_1_0_Test() { const string source1 = "TEST1"; const string source2 = "TEST2"; const string source3 = "TEST3"; var timestamp1 = DateTime.UtcNow.AddSeconds(-2); var timestamp2 = DateTime.UtcNow.AddSeconds(-1); var timestamp3 = DateTime.UtcNow; var btcEurOrderBook = new OrderBook(source1, _btceur, new List <LimitOrder> // bids { new LimitOrder(7310m, 9), new LimitOrder(7300m, 5) }, new List <LimitOrder> // asks { new LimitOrder(7320m, 10), new LimitOrder(7330m, 7), new LimitOrder(7340m, 3) }, timestamp1); var eurJpyOrderBook = new OrderBook(source2, _eurjpy, new List <LimitOrder> // bids { new LimitOrder(131m, 9), new LimitOrder(130m, 5) }, new List <LimitOrder> // asks { new LimitOrder(132m, 11), new LimitOrder(133m, 7), new LimitOrder(134m, 3) }, timestamp2); var jpyUsdOrderBook = new OrderBook(source3, _jpyusd, new List <LimitOrder> // bids { new LimitOrder(0.009132m, 9), new LimitOrder(0.009131m, 5) }, new List <LimitOrder> // asks { new LimitOrder(0.009133m, 12), new LimitOrder(0.009134m, 7), new LimitOrder(0.009135m, 3) }, timestamp3); var synthOrderBook = SynthOrderBook.FromOrderBooks(btcEurOrderBook, eurJpyOrderBook, jpyUsdOrderBook, _btcusd); Assert.Equal("TEST1 - TEST2 - TEST3", synthOrderBook.Source); Assert.Equal(_btcusd, synthOrderBook.AssetPair); Assert.Equal("BTCEUR & EURJPY & JPYUSD", synthOrderBook.ConversionPath); Assert.Equal(2, synthOrderBook.Bids.Count()); Assert.Equal(3, synthOrderBook.Asks.Count()); Assert.Equal(8744.894520m, synthOrderBook.BestBid.Price); Assert.Equal(8824.669920m, synthOrderBook.BestAsk.Price); Assert.Equal(0.00000940m, synthOrderBook.BestBid.Volume, 8); Assert.Equal(0.00001242m, synthOrderBook.BestAsk.Volume, 8); Assert.Equal(timestamp1, synthOrderBook.Timestamp); Assert.Equal(3, synthOrderBook.OriginalOrderBooks.Count); }
public void From3OrderBooks_1_1_1_Test() { const string source1 = "TEST1"; const string source2 = "TEST2"; const string source3 = "TEST3"; var timestamp1 = DateTime.UtcNow.AddSeconds(-2); var timestamp2 = DateTime.UtcNow.AddSeconds(-1); var timestamp3 = DateTime.UtcNow; var btcEurOrderBook = new OrderBook(source1, _eurbtc, new List <LimitOrder> // bids { new LimitOrder(1 / 7310m, 9), new LimitOrder(1 / 7300m, 5) }, new List <LimitOrder> // asks { new LimitOrder(1 / 7320m, 10), new LimitOrder(1 / 7330m, 7), new LimitOrder(1 / 7340m, 3) }, timestamp1); var eurJpyOrderBook = new OrderBook(source2, _jpyeur, new List <LimitOrder> // bids { new LimitOrder(1 / 131m, 9), new LimitOrder(1 / 130m, 5) }, new List <LimitOrder> // asks { new LimitOrder(1 / 132m, 11), new LimitOrder(1 / 133m, 7), new LimitOrder(1 / 134m, 3) }, timestamp2); var jpyUsdOrderBook = new OrderBook(source3, _usdjpy, new List <LimitOrder> // bids { new LimitOrder(1 / 0.009132m, 9), new LimitOrder(1 / 0.009131m, 5) }, new List <LimitOrder> // asks { new LimitOrder(1 / 0.009133m, 12), new LimitOrder(1 / 0.009134m, 7), new LimitOrder(1 / 0.009135m, 3) }, timestamp3); var synthOrderBook = SynthOrderBook.FromOrderBooks(btcEurOrderBook, eurJpyOrderBook, jpyUsdOrderBook, _btcusd); Assert.Equal("TEST1 - TEST2 - TEST3", synthOrderBook.Source); Assert.Equal(_btcusd, synthOrderBook.AssetPair); Assert.Equal("EURBTC & JPYEUR & USDJPY", synthOrderBook.ConversionPath); Assert.Equal(3, synthOrderBook.Bids.Count()); Assert.Equal(2, synthOrderBook.Asks.Count()); Assert.Equal(8984.8206m, synthOrderBook.BestBid.Price, 8); Assert.Equal(8665.319m, synthOrderBook.BestAsk.Price, 8); Assert.Equal(0.00000305m, synthOrderBook.BestBid.Volume, 8); Assert.Equal(0.00000527m, synthOrderBook.BestAsk.Volume, 8); Assert.Equal(timestamp1, synthOrderBook.Timestamp); Assert.Equal(3, synthOrderBook.OriginalOrderBooks.Count); }
public void OrderBooks_PrepareForEnumeration_0_Test() { var orderBook = new OrderBook("FE", _btcusd, new List <LimitOrder>(), new List <LimitOrder>(), DateTime.UtcNow); var result = SynthOrderBook.PrepareForEnumeration(new List <OrderBook> { orderBook }, _btcusd); Assert.Single(result); Assert.True(result.Single().Key.Equals(_btcusd)); Assert.True(result.Single().Value.AssetPair.EqualOrInverted(_btcusd)); }
public void OrderBooks_PrepareForEnumeration_1_Test() { var usdbtc = _btcusd.Invert(); var orderBook = new OrderBook("FE", usdbtc, new List <VolumePrice>(), new List <VolumePrice>(), DateTime.UtcNow); var result = SynthOrderBook.PrepareForEnumeration(new List <OrderBook> { orderBook }, _btcusd); Assert.Single(result); Assert.True(result.Single().Key.Equals(_btcusd)); Assert.True(result.Single().Value.AssetPair.IsEqualOrInverted(_btcusd)); }
public void From2OrderBooks_0_1_Test() { const string source = "FakeExchange"; var timestamp1 = DateTime.UtcNow.AddSeconds(-1); var timestamp2 = DateTime.UtcNow; var btcEurOrderBook = new OrderBook(source, _btceur, new List <LimitOrder> // bids { new LimitOrder(8825, 9), new LimitOrder(8823, 5) }, new List <LimitOrder> // asks { new LimitOrder(9000, 10), new LimitOrder(8999.95m, 7), new LimitOrder(8900.12345677m, 3) }, timestamp1); var eurUsdOrderBook = new OrderBook(source, _usdeur, new List <LimitOrder> // bids { new LimitOrder(1 / 1.11m, 9), new LimitOrder(1 / 1.10m, 5) }, new List <LimitOrder> // asks { new LimitOrder(1 / 1.12m, 10), new LimitOrder(1 / 1.13m, 7), new LimitOrder(1 / 1.14m, 3) }, timestamp2); var synthOrderBook = SynthOrderBook.FromOrderBooks(btcEurOrderBook, eurUsdOrderBook, _btcusd); Assert.Equal("FakeExchange - FakeExchange", synthOrderBook.Source); Assert.Equal(_btcusd, synthOrderBook.AssetPair); Assert.Equal("BTCEUR & USDEUR", synthOrderBook.ConversionPath); Assert.Equal(3, synthOrderBook.Bids.Count()); Assert.Equal(2, synthOrderBook.Asks.Count()); Assert.Equal(10060.5m, synthOrderBook.BestBid.Price, 8); Assert.Equal(9790.135802447m, synthOrderBook.BestAsk.Price, 8); Assert.Equal(0.00029820m, synthOrderBook.BestBid.Volume, 8); Assert.Equal(0.00051072m, synthOrderBook.BestAsk.Volume, 8); // TODO: Prices must be tested (i.e. GetOrderedLimitOrders methods) Assert.Equal(timestamp1, synthOrderBook.Timestamp); Assert.Equal(2, synthOrderBook.OriginalOrderBooks.Count); }
public void From2OrderBooks_1_0_Test() { const string source = "FakeExchange"; var timestamp1 = DateTime.UtcNow.AddSeconds(-1); var timestamp2 = DateTime.UtcNow; var btcEurOrderBook = new OrderBook(source, _eurbtc, new List <VolumePrice> // bids { new VolumePrice(1 / 8825m, 9), new VolumePrice(1 / 8823m, 5) }, new List <VolumePrice> // asks { new VolumePrice(1 / 9000m, 10), new VolumePrice(1 / 8999.95m, 7), new VolumePrice(1 / 8900.12345677m, 3) }, timestamp1); var eurUsdOrderBook = new OrderBook(source, _eurusd, new List <VolumePrice> // bids { new VolumePrice(1.11m, 9), new VolumePrice(1.10m, 5) }, new List <VolumePrice> // asks { new VolumePrice(1.12m, 10), new VolumePrice(1.13m, 7), new VolumePrice(1.14m, 3) }, timestamp2); var synthOrderBook = SynthOrderBook.FromOrderBooks(btcEurOrderBook, eurUsdOrderBook, _btcusd); Assert.Equal("FakeExchange-FakeExchange", synthOrderBook.Source); Assert.Equal(_btcusd, synthOrderBook.AssetPair); Assert.Equal("FakeExchange-EURBTC * FakeExchange-EURUSD", synthOrderBook.ConversionPath); Assert.Equal(2, synthOrderBook.Bids.Count()); Assert.Equal(2, synthOrderBook.Asks.Count()); Assert.Equal(9990m, synthOrderBook.BestBid.Value.Price, 8); Assert.Equal(9881.76m, synthOrderBook.BestAsk.Value.Price, 8); Assert.Equal(0.001m, synthOrderBook.BestBid.Value.Volume, 8); Assert.Equal(0.00056670m, synthOrderBook.BestAsk.Value.Volume, 8); Assert.Equal(timestamp1, synthOrderBook.Timestamp); Assert.Equal(2, synthOrderBook.OriginalOrderBooks.Count); }
public void From2OrderBooks_1_1_Test() { const string source = "FakeExchange"; var timestamp1 = DateTime.UtcNow.AddSeconds(-1); var timestamp2 = DateTime.UtcNow; var btcEurOrderBook = new OrderBook(source, _eurbtc, new List <LimitOrder> // bids { new LimitOrder(1 / 8825m, 9), new LimitOrder(1 / 8823m, 5) }, new List <LimitOrder> // asks { new LimitOrder(1 / 9000m, 10), new LimitOrder(1 / 8999.95m, 7), new LimitOrder(1 / 8900.12345677m, 3) }, timestamp1); var eurUsdOrderBook = new OrderBook(source, _usdeur, new List <LimitOrder> // bids { new LimitOrder(1 / 1.11m, 9), new LimitOrder(1 / 1.10m, 5) }, new List <LimitOrder> // asks { new LimitOrder(1 / 1.12m, 10), new LimitOrder(1 / 1.13m, 7), new LimitOrder(1 / 1.14m, 3) }, timestamp2); var synthOrderBook = SynthOrderBook.FromOrderBooks(btcEurOrderBook, eurUsdOrderBook, _btcusd); Assert.Equal("FakeExchange - FakeExchange", synthOrderBook.Source); Assert.Equal(_btcusd, synthOrderBook.AssetPair); Assert.Equal("EURBTC & USDEUR", synthOrderBook.ConversionPath); Assert.Equal(3, synthOrderBook.Bids.Count()); Assert.Equal(3, synthOrderBook.Asks.Count()); Assert.Equal(10260m, synthOrderBook.BestBid.Price, 8); Assert.Equal(9705.30m, synthOrderBook.BestAsk.Price, 8); Assert.Equal(0.00029240m, synthOrderBook.BestBid.Volume, 8); Assert.Equal(0.00051518m, synthOrderBook.BestAsk.Volume, 8); Assert.Equal(timestamp1, synthOrderBook.Timestamp); Assert.Equal(2, synthOrderBook.OriginalOrderBooks.Count); }
public void From2OrderBooks_0_0_Test() { const string source = "FakeExchange"; var timestamp1 = DateTime.UtcNow.AddSeconds(-1); var timestamp2 = DateTime.UtcNow; var btcEurOrderBook = new OrderBook(source, _btceur, new List <VolumePrice> // bids { new VolumePrice(8825, 9), new VolumePrice(8823, 5) }, new List <VolumePrice> // asks { new VolumePrice(9000, 10), new VolumePrice(8999.95m, 7), new VolumePrice(8900.12345677m, 3) }, timestamp1); var eurUsdOrderBook = new OrderBook(source, _eurusd, new List <VolumePrice> // bids { new VolumePrice(1.11m, 9), new VolumePrice(1.10m, 5) }, new List <VolumePrice> // asks { new VolumePrice(1.12m, 10), new VolumePrice(1.13m, 7), new VolumePrice(1.14m, 3) }, timestamp2); var synthOrderBook = SynthOrderBook.FromOrderBooks(btcEurOrderBook, eurUsdOrderBook, _btcusd); Assert.Equal("FakeExchange-FakeExchange", synthOrderBook.Source); Assert.Equal(_btcusd, synthOrderBook.AssetPair); Assert.Equal("FakeExchange-BTCEUR * FakeExchange-EURUSD", synthOrderBook.ConversionPath); Assert.Equal(2, synthOrderBook.Bids.Count()); Assert.Equal(3, synthOrderBook.Asks.Count()); Assert.Equal(9795.75m, synthOrderBook.BestBid.Value.Price, 8); Assert.Equal(9968.1382715824m, synthOrderBook.BestAsk.Value.Price, 8); // TODO: Prices must be tested in all From* methods (i.e. GetOrderedVolumePrices methods) Assert.Equal(timestamp1, synthOrderBook.Timestamp); Assert.Equal(2, synthOrderBook.OriginalOrderBooks.Count); }
public void SynthOrderBook_GetAsks_Inverted_Test() { var gbpusdOb = new OrderBook("FE", _gbpusd, new List <LimitOrder> // bids { new LimitOrder(1.28167m, 2909.98m), new LimitOrder(1.29906m, 50000m) }, new List <LimitOrder>(), // asks DateTime.Now); var bids = SynthOrderBook.GetAsks(gbpusdOb, _usdgbp).ToList(); var orderedBids = bids.OrderBy(x => x.Price).ToList(); Assert.Equal(2, bids.Count); Assert.Equal(bids[0].Price, orderedBids[0].Price); Assert.Equal(bids[1].Price, orderedBids[1].Price); }
public void SynthOrderBook_GetAsks_Streight_Test() { var gbpusdOb = new OrderBook("FE", _gbpusd, new List <VolumePrice>(), // bids new List <VolumePrice> // asks { new VolumePrice(1.29906m, 50000m), new VolumePrice(1.28167m, 2909.98m) }, DateTime.Now); var bids = SynthOrderBook.GetAsks(gbpusdOb, _gbpusd).ToList(); var orderedBids = bids.OrderBy(x => x.Price).ToList(); Assert.Equal(2, bids.Count); Assert.Equal(bids[0].Price, orderedBids[0].Price); Assert.Equal(bids[1].Price, orderedBids[1].Price); }
private decimal?Convert(string sourceAsset, string targetAsset, IReadOnlyList <OrderBook> orderBooks) { if (sourceAsset == targetAsset) { return(1); } var target = new AssetPair(sourceAsset, targetAsset, 8, 8); decimal?result = null; var synths1 = SynthOrderBook.GetSynthsFrom1(target, orderBooks, orderBooks); if (synths1.Any()) { result = synths1.First().BestAsk?.Price; } return(result); }
private IEnumerable <Arbitrage> GetArbitrages(IReadOnlyCollection <OrderBook> orderBooks) { orderBooks = orderBooks.Where(x => x.BestBid != null || x.BestAsk != null) .OrderBy(x => x.AssetPair.Name).ToList(); var result = new List <Arbitrage>(); var watch = Stopwatch.StartNew(); var synthsCount = 0; // O( (n^2)/2 ) // TODO: cache should be implemented to avoid iterating over all asset pairs every time for (var i = 0; i < orderBooks.Count; i++) { if (i == orderBooks.Count - 1) { break; } var target = orderBooks.ElementAt(i); for (var j = i + 1; j < orderBooks.Count; j++) { var source = orderBooks.ElementAt(j); if (target.ToString() == source.ToString()) { continue; } // Calculate all synthetic order books between source order book and target order book var synthOrderBooks = SynthOrderBook.GetSynthsFromAll(target.AssetPair, source, orderBooks); synthsCount += synthOrderBooks.Count; // Compare each synthetic with target foreach (var synthOrderBook in synthOrderBooks) { decimal spread = 0; decimal volume = 0; decimal pnL = 0; string targetSide = null; IReadOnlyList <string> marketMakers = new List <string>(); if (target.BestBid?.Price > synthOrderBook.BestAsk?.Price) { spread = Arbitrage.GetSpread(target.BestBid.Price, synthOrderBook.BestAsk.Price); var volumePnL = Arbitrage.GetArbitrageVolumeAndPnL(target.Bids, synthOrderBook.Asks); Debug.Assert(volumePnL?.Volume != null); Debug.Assert(volumePnL?.PnL != null); targetSide = Bid; marketMakers = GetMarketMakers(target.BestBid, synthOrderBook.GetLimitOrdersOfBestAsk()); volume = volumePnL.Value.Volume; pnL = volumePnL.Value.PnL; } if (synthOrderBook.BestBid?.Price > target.BestAsk?.Price) { spread = Arbitrage.GetSpread(synthOrderBook.BestBid.Price, target.BestAsk.Price); var volumePnL = Arbitrage.GetArbitrageVolumeAndPnL(synthOrderBook.Bids, target.Asks); Debug.Assert(volumePnL?.Volume != null); Debug.Assert(volumePnL?.PnL != null); targetSide = Ask; marketMakers = GetMarketMakers(target.BestAsk, synthOrderBook.GetLimitOrdersOfBestBid()); volume = volumePnL.Value.Volume; pnL = volumePnL.Value.PnL; } if (targetSide == null) // no arbitrages { continue; } var volumeInUsd = _orderBooksService.ConvertToUsd(target.AssetPair.Base.Id, volume); var pnLInUsd = _orderBooksService.ConvertToUsd(target.AssetPair.Quote.Id, pnL); var lykkeArbitrage = new Arbitrage( target.AssetPair, source.AssetPair, spread, targetSide, synthOrderBook.ConversionPath, volume, volumeInUsd, pnL, pnLInUsd, target.BestBid?.Price, target.BestAsk?.Price, synthOrderBook.BestBid?.Price, synthOrderBook.BestAsk?.Price, marketMakers, DateTime.UtcNow ); result.Add(lykkeArbitrage); } } } watch.Stop(); if (watch.ElapsedMilliseconds > 1000) { _log.Info($"Performance issue - {watch.ElapsedMilliseconds} ms, {result.Count} arbitrages, {orderBooks.Count} order books," + $"{synthsCount} synthetic order books created."); } return(result.ToList()); }
private Task <IReadOnlyList <LykkeArbitrageRow> > GetArbitragesAsync(IReadOnlyList <OrderBook> orderBooks) { orderBooks = orderBooks.Where(x => x.BestBid.HasValue || x.BestAsk.HasValue).OrderBy(x => x.AssetPair.Name).ToList(); var result = new List <LykkeArbitrageRow>(); var watch = Stopwatch.StartNew(); var synthsCount = 0; // O( (n^2)/2 ) for (var i = 0; i < orderBooks.Count; i++) { if (i == orderBooks.Count - 1) { break; } var target = orderBooks.ElementAt(i); for (var j = i + 1; j < orderBooks.Count; j++) { var source = orderBooks.ElementAt(j); if (target.ToString() == source.ToString()) { continue; } // Calculate all synthetic order books between a source order book and a target order book var synthOrderBooks = SynthOrderBook.GetSynthsFromAll(target.AssetPair, source, orderBooks); synthsCount += synthOrderBooks.Count; // Compare each synthetic with current target asset pair foreach (var synthOrderBook in synthOrderBooks) { decimal spread = 0; decimal volume = 0; decimal pnL = 0; string targetSide = null; // Bid side if (target.BestBid?.Price > synthOrderBook.BestAsk?.Price) { spread = Arbitrage.GetSpread(target.BestBid.Value.Price, synthOrderBook.BestAsk.Value.Price); var volumePnL = Arbitrage.GetArbitrageVolumePnL(target.Bids, synthOrderBook.Asks); Debug.Assert(volumePnL?.Volume != null); Debug.Assert(volumePnL?.PnL != null); targetSide = "Bid"; volume = volumePnL.Value.Volume; pnL = volumePnL.Value.PnL; } // Ask side if (synthOrderBook.BestBid?.Price > target.BestAsk?.Price) { spread = Arbitrage.GetSpread(synthOrderBook.BestBid.Value.Price, target.BestAsk.Value.Price); var volumePnL = Arbitrage.GetArbitrageVolumePnL(synthOrderBook.Bids, target.Asks); Debug.Assert(volumePnL?.Volume != null); Debug.Assert(volumePnL?.PnL != null); targetSide = "Ask"; volume = volumePnL.Value.Volume; pnL = volumePnL.Value.PnL; } if (string.IsNullOrWhiteSpace(targetSide)) // no arbitrage { continue; } var baseToUsdRate = Convert(target.AssetPair.Base, Usd, orderBooks); var quoteToUsdRate = Convert(target.AssetPair.Quote, Usd, orderBooks); var volumeInUsd = volume * baseToUsdRate; volumeInUsd = volumeInUsd.HasValue ? Math.Round(volumeInUsd.Value) : (decimal?)null; var pnLInUsd = pnL * quoteToUsdRate; pnLInUsd = pnLInUsd.HasValue ? Math.Round(pnLInUsd.Value) : (decimal?)null; var lykkeArbitrage = new LykkeArbitrageRow(target.AssetPair, source.AssetPair, spread, targetSide, synthOrderBook.ConversionPath, volume, target.BestBid?.Price, target.BestAsk?.Price, synthOrderBook.BestBid?.Price, synthOrderBook.BestAsk?.Price, volumeInUsd, pnL, pnLInUsd); result.Add(lykkeArbitrage); } } } watch.Stop(); if (watch.ElapsedMilliseconds > 1000) { _log.Info($"{watch.ElapsedMilliseconds} ms, {result.Count} arbitrages, {orderBooks.Count} order books, {synthsCount} synthetic order books."); } return(Task.FromResult(result.OrderBy(x => x.Target).ThenBy(x => x.Source).ToList() as IReadOnlyList <LykkeArbitrageRow>)); }