public async Task BestPathConversion()
        {
            var marketProfile = new Core.Domain.MarketProfile();
            var btcUsdBid     = 8600;
            var slrUsdAsk     = 0.4508;
            // USD wights are lower than CHF, so best par from BTC to SLR is through USD.
            var feedData = new List <FeedData>
            {
                new FeedData {
                    Asset = "BTCUSD", Ask = 9000, Bid = btcUsdBid, DateTime = DateTime.UtcNow
                },
                new FeedData {
                    Asset = "SLRUSD", Ask = slrUsdAsk, Bid = 0.0003, DateTime = DateTime.UtcNow
                },
                new FeedData {
                    Asset = "BTCCHF", Ask = 0.98599, Bid = 0.97925, DateTime = DateTime.UtcNow
                },
                new FeedData {
                    Asset = "SLRCHF", Ask = 0.4466, Bid = 0.0005, DateTime = DateTime.UtcNow
                },
            };

            marketProfile.Profile = feedData;

            var amountInBase = await _service.GetAmountInBaseWithProfile("BTC", 1, "SLR", marketProfile);

            Assert.Equal((btcUsdBid / slrUsdAsk).TruncateDecimalPlaces(TestsUtils.CryptoAccuracy), amountInBase);
        }
Ejemplo n.º 2
0
        public async Task <double> GetAmountInBaseWithProfile(
            string assetFrom,
            double amount,
            string assetTo,
            Core.Domain.MarketProfile marketProfile)
        {
            if (assetFrom == assetTo)
            {
                return(amount);
            }

            if (Math.Abs(amount) < double.Epsilon)
            {
                return(0);
            }

            var marketProfileData = marketProfile ?? await GetMarketProfileRemoteAsync();

            var pricesData = _crossPairsCalculator.PrepareForConversion(marketProfileData);

            return(GetCrossPairsAmountInBase(
                       assetFrom,
                       amount,
                       assetTo,
                       pricesData));
        }
Ejemplo n.º 3
0
        internal Dictionary <string, NodeInfo> PrepareForConversion(Core.Domain.MarketProfile marketProfile)
        {
            var result          = new Dictionary <string, NodeInfo>();
            var assetIdsToBuild = new HashSet <string>();

            foreach (var feedData in marketProfile.Profile)
            {
                var pair = _assetPairsReadModelRepository.TryGet(feedData.Asset);
                if (pair == null)
                {
                    continue;
                }

                result[$"{pair.BaseAssetId}_{pair.QuotingAssetId}"] = new NodeInfo
                {
                    Straight = true,
                    Bid      = feedData.Bid,
                    Ask      = feedData.Ask,
                };
                result[$"{pair.QuotingAssetId}_{pair.BaseAssetId}"] = new NodeInfo
                {
                    Straight = false,
                    Bid      = feedData.Bid,
                    Ask      = feedData.Ask,
                };

                if (!_links.ContainsKey(pair.BaseAssetId))
                {
                    _links.TryAdd(pair.BaseAssetId, new ConcurrentDictionary <string, byte>());
                }
                if (!_links.ContainsKey(pair.QuotingAssetId))
                {
                    _links.TryAdd(pair.QuotingAssetId, new ConcurrentDictionary <string, byte>());
                }
                bool added = _links[pair.BaseAssetId].TryAdd(pair.QuotingAssetId, 0);
                if (added)
                {
                    assetIdsToBuild.Add(pair.BaseAssetId);
                }
                added = _links[pair.QuotingAssetId].TryAdd(pair.BaseAssetId, 0);
                if (added)
                {
                    assetIdsToBuild.Add(pair.QuotingAssetId);
                }
            }

            foreach (var assetId in assetIdsToBuild)
            {
                BuildBestAssetIdLinks(assetId);
            }

            return(result);
        }
Ejemplo n.º 4
0
        public async Task Is_GetAmountInBase_Inverted_Correct()
        {
            var marketProfile = new Core.Domain.MarketProfile();
            var feedData      = new List <FeedData>
            {
                new FeedData {
                    Asset = "USDCHF", Ask = 0.98599, Bid = 0.97925, DateTime = DateTime.UtcNow
                }
            };

            marketProfile.Profile = feedData;

            var amountInBase = await _service.GetAmountInBaseWithProfile("CHF", 1, "USD", marketProfile);

            Assert.Equal(1.01, amountInBase);
        }
Ejemplo n.º 5
0
        public async Task Is_GetAmountInBase_Correct()
        {
            var marketProfile = new Core.Domain.MarketProfile();
            var feedData      = new List <FeedData>
            {
                new FeedData {
                    Asset = "BTCUSD", Ask = 2656.381, Bid = 2652, DateTime = DateTime.UtcNow
                }
            };

            marketProfile.Profile = feedData;

            var amountInBase = await _service.GetAmountInBaseWithProfile("BTC", 1, "USD", marketProfile);

            Assert.Equal(2652, amountInBase);
        }
        public async Task StraightFalseFalseConversion()
        {
            var marketProfile = new Core.Domain.MarketProfile();
            var btcAsk        = 9000;
            var chfAsk        = 0.98599;
            var feedData      = new List <FeedData>
            {
                new FeedData {
                    Asset = "BTCUSD", Ask = btcAsk, Bid = 8600, DateTime = DateTime.UtcNow
                },
                new FeedData {
                    Asset = "USDCHF", Ask = chfAsk, Bid = 0.97925, DateTime = DateTime.UtcNow
                },
            };

            marketProfile.Profile = feedData;

            var amountInBase = await _service.GetAmountInBaseWithProfile("CHF", 1, "BTC", marketProfile);

            Assert.Equal((1 / chfAsk / btcAsk).TruncateDecimalPlaces(TestsUtils.CryptoAccuracy), amountInBase);
        }
        public async Task StraightTrueFalseConversion()
        {
            var marketProfile = new Core.Domain.MarketProfile();
            var btcBid        = 8600;
            var slrAsk        = 0.4508;
            var feedData      = new List <FeedData>
            {
                new FeedData {
                    Asset = "BTCUSD", Ask = 9000, Bid = btcBid, DateTime = DateTime.UtcNow
                },
                new FeedData {
                    Asset = "SLRUSD", Ask = slrAsk, Bid = 0.0003, DateTime = DateTime.UtcNow
                },
            };

            marketProfile.Profile = feedData;

            var amountInBase = await _service.GetAmountInBaseWithProfile("BTC", 1, "SLR", marketProfile);

            Assert.Equal((btcBid / slrAsk).TruncateDecimalPlaces(TestsUtils.CryptoAccuracy), amountInBase);
        }
        public async Task StraightTrueTrueConversion()
        {
            var marketProfile = new Core.Domain.MarketProfile();
            var btcBid        = 8600;
            var chfBid        = 0.97925;
            var feedData      = new List <FeedData>
            {
                new FeedData {
                    Asset = "BTCUSD", Ask = 9000, Bid = btcBid, DateTime = DateTime.UtcNow
                },
                new FeedData {
                    Asset = "USDCHF", Ask = 0.98599, Bid = chfBid, DateTime = DateTime.UtcNow
                },
            };

            marketProfile.Profile = feedData;

            var amountInBase = await _service.GetAmountInBaseWithProfile("BTC", 1, "CHF", marketProfile);

            Assert.Equal((btcBid * chfBid).TruncateDecimalPlaces(TestsUtils.FiatAccuracy), amountInBase);
        }
Ejemplo n.º 9
0
        private ConversionResult GetMarketAmountInBase(
            OrderAction orderAction,
            IEnumerable <IOrderBook> orderBooks,
            AssetWithAmount from,
            string assetTo,
            IReadOnlyDictionary <string, Assets.Client.Models.v3.Asset> assetsDict,
            IEnumerable <Assets.Client.Models.v3.AssetPair> assetPairs,
            Core.Domain.MarketProfile marketProfile)
        {
            var result    = new ConversionResult();
            var assetPair = GetPairWithAssets(assetPairs, from.AssetId, assetTo);

            if (!IsInputValid(from, assetTo, assetsDict) || assetPair == null)
            {
                result.Result = OperationResult.InvalidInputParameters;
                return(result);
            }

            if (from.AssetId == assetTo)
            {
                result.From   = result.To = from;
                result.Price  = result.VolumePrice = 1;
                result.Result = OperationResult.Ok;
                return(result);
            }

            orderAction = IsInverted(assetPair, assetTo) ? orderAction.ViceVersa() : orderAction;
            var isBuy     = orderAction == OrderAction.Buy;
            var orderBook = orderBooks.FirstOrDefault(x => x.AssetPair == assetPair.Id && x.IsBuy == isBuy);

            if (orderBook == null)
            {
                result.Result = OperationResult.NoLiquidity;
                return(result);
            }

            if (IsInverted(assetPair, assetTo))
            {
                orderBook.Invert();
            }

            orderBook.Order();

            double sum      = 0;
            double priceSum = 0;
            int    n        = 0;

            var neededSum = double.MaxValue;

            foreach (var line in orderBook.Prices)
            {
                if (n != 0 && sum >= neededSum)
                {
                    break;
                }

                sum      += Math.Abs(line.Volume);
                priceSum += line.Price;
                n++;
                neededSum = from.Amount * GetRate(assetTo, assetPair, priceSum / n);
            }

            if (n == 0)
            {
                result.Result = OperationResult.NoLiquidity;
                return(result);
            }

            var price = priceSum / n;

            result.From = from;
            var rate        = GetRate(assetTo, assetPair, price);
            var displayRate = GetRate(from.AssetId, assetPair, price);

            result.To = new AssetWithAmount
            {
                AssetId = assetTo,
                Amount  = (rate * from.Amount).TruncateDecimalPlaces(assetsDict[assetTo].Accuracy,
                                                                     orderAction == OrderAction.Buy)
            };
            result.Result = sum < neededSum ? OperationResult.NoLiquidity : OperationResult.Ok;
            result.Price  = GetRate(
                from.AssetId,
                assetPair,
                marketProfile.GetPrice(assetPair.Id, orderAction).GetValueOrDefault());
            result.VolumePrice = displayRate;

            return(result);
        }
 public async Task <double> GetAmountInBaseWithProfile(string assetFrom, string assetTo, double amount, [FromBody] Core.Domain.MarketProfile marketProfile)
 {
     return(await _rateCalculatorService.GetAmountInBaseWithProfile(assetFrom, amount, assetTo, marketProfile));
 }