Example #1
0
        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);
        }
Example #3
0
        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)));
        }
Example #4
0
        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);
        }
Example #5
0
        public void OrderBooks_PrepareForEnumeration_0_0_Test()
        {
            var orderBooks = GetOrderBooks(_btceur, _eurusd);

            var result = SynthOrderBook.PrepareForEnumeration(orderBooks, _btcusd);

            AssertChained2(result);
        }
Example #6
0
        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);
        }
Example #7
0
        public SynthOrderBookLine(SynthOrderBook synthOrderBook, VolumePrice volumePrice)
        {
            Debug.Assert(synthOrderBook != null);

            Price          = volumePrice.Price;
            Volume         = volumePrice.Volume;
            SynthOrderBook = synthOrderBook;
        }
Example #8
0
        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);
        }
Example #9
0
        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);
        }
Example #10
0
        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);
        }
Example #11
0
        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);
        }
Example #12
0
        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));
        }
Example #13
0
        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));
        }
Example #14
0
        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);
        }
Example #15
0
        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);
        }
Example #16
0
        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);
        }
Example #17
0
        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);
        }
Example #18
0
        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);
        }
Example #19
0
        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);
        }
Example #21
0
        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>));
        }