예제 #1
0
        public async void CanGetAssetPairRateFromUrlGeneric()
        {
            var container = CreateContainer();
            var bus       = container.GetInstance <IBus>();

            var date = new LocalDateTime(2020, 12, 1, 12, 30).InUtc().ToInstant();

            var gbp = new Currency("GBP");
            var usd = new Currency("USD");
            var btc = new Asset("Bitcoin", "BTC", Asset.Type.Coin);

            await bus.Command(new RetroactiveCommand <RegisterAssetPair>(new RegisterAssetPair(AssetPair.Fordom(btc, usd), btc, usd), date));

            await bus.Command(new RetroactiveCommand <AddQuoteUrl>(new AddQuoteUrl(AssetPair.Fordom(btc, usd), Api.Coin.Url(btc, usd)), date));

            await bus.Command(new RetroactiveCommand <RegisterAssetPair>(new RegisterAssetPair(AssetPair.Fordom(gbp, usd), gbp, usd), date));

            await bus.Command(new RetroactiveCommand <AddQuoteUrl>(new AddQuoteUrl(AssetPair.Fordom(gbp, usd), Api.Fx.Url(gbp, usd)), date));

            await bus.Command(new RetroactiveCommand <UpdateQuote>(new UpdateQuote(AssetPair.Fordom(gbp, usd)), date));

            await bus.Equal(new HistoricalQuery <SingleAssetPriceQuery, SingleAssetPrice>(new SingleAssetPriceQuery(AssetPair.Fordom(gbp, usd)), date), s => s.Price, 1.342652);

            await bus.Command(new RetroactiveCommand <UpdateQuote>(new UpdateQuote(AssetPair.Fordom(btc, usd)), date));

            await bus.Equal(new HistoricalQuery <AssetPriceQuery, AssetPrice>(new AssetPriceQuery(btc, gbp), date), s => Math.Round(s.Price, 6), Math.Round(19609.52143957559 / 1.342652, 6));
        }
예제 #2
0
        public async void CanDepositAsset()
        {
            var container  = CreateContainer();
            var bus        = container.GetInstance <IBus>();
            var repository = container.GetInstance <IEsRepository <IAggregate> >();
            var timeline   = container.GetInstance <ITimeline>();

            var ccy   = new Currency("USD");
            var asset = new Asset("Bitcoin", "BTC", Asset.Type.Coin);
            await await bus.CommandAsync(new RegisterAssetPair(AssetPair.Fordom(asset, ccy), asset, ccy));

            await await bus.CommandAsync(new AddQuote(AssetPair.Fordom(asset, ccy), timeline.Now, 23000));

            await await bus.CommandAsync(new CreateAccount("Account", AccountType.Trading));

            await await bus.CommandAsync(new DepositAsset("Account", new Quantity(1.0, asset)));

            var account = await repository.Find <Account>("Account");

            Assert.Equal("Bitcoin", account.Assets[0]);

            await bus.Equal(new AccountStatsQuery("Account", asset), s => s.Balance, new Quantity(1.0, asset));

            await bus.Equal(new AccountStatsQuery("Account", ccy), s => s.Balance, new Quantity(23000, ccy));
        }
예제 #3
0
        public async void CanGetHistoricalPairQuote()
        {
            var container = CreateContainer();
            var bus       = container.GetInstance <IBus>();

            var date = new LocalDateTime(2020, 12, 1, 12, 30).InUtc().ToInstant();

            var gbp = new Currency("GBP");
            var usd = new Currency("USD");
            var btc = new Asset("Bitcoin", "BTC", Asset.Type.Coin);

            await bus.Command(new RetroactiveCommand <RegisterAssetPair>(new RegisterAssetPair(AssetPair.Fordom(btc, usd), btc, usd), date));

            await bus.Command(new RetroactiveCommand <RegisterAssetPair>(new RegisterAssetPair(AssetPair.Fordom(gbp, usd), gbp, usd), date));

            var midDate  = new LocalDateTime(2020, 12, 10, 12, 30).InUtc().ToInstant();
            var lastdate = new LocalDateTime(2020, 12, 15, 12, 30).InUtc().ToInstant();
            await bus.Command(new RetroactiveCommand <UpdateQuote>(new UpdateQuote(AssetPair.Fordom(gbp, usd)), midDate));

            await bus.Command(new RetroactiveCommand <UpdateQuote>(new UpdateQuote(AssetPair.Fordom(gbp, usd)), lastdate));

            await bus.Command(new RetroactiveCommand <UpdateQuote>(new UpdateQuote(AssetPair.Fordom(btc, usd)), midDate));

            await bus.Equal(new AssetPriceQuery(btc, gbp) { Timestamp = midDate }, a => a.Timestamp, midDate);

            var quote = await bus.QueryAsync(new AssetPriceQuery(btc, gbp) { Timestamp = midDate });

            var historicalQuote = await bus.QueryAsync(new HistoricalQuery <AssetPriceQuery, AssetPrice>(new AssetPriceQuery(btc, gbp), midDate));

            Assert.Equal(quote.Price, historicalQuote.Price);
            Assert.Equal(quote.Timestamp, historicalQuote.Timestamp);
        }
예제 #4
0
        private void Handle(CoinCreated e)
        {
            var forAsset = new Asset(e.Name, e.Ticker, Asset.Type.Coin);
            var domAsset = new Currency("USD");
            var command  = new RegisterAssetPair(AssetPair.Fordom(forAsset, domAsset), forAsset, domAsset)
            {
                Timestamp    = new LocalDate(2000, 1, 1).AtMidnight().InUtc().ToInstant(),
                UseTimestamp = true,
            };

            SendCommand(command);
        }
예제 #5
0
        public async void CanRollbackQuote()
        {
            var container   = CreateContainer();
            var bus         = container.GetInstance <IBus>();
            var retroactive = container.GetInstance <IRetroactive>();

            var forAsset = new Currency("GBP");
            var domAsset = new Currency("USD");

            var command = new UpdateQuote(AssetPair.Fordom(forAsset, domAsset));

            await bus.Command(new RegisterAssetPair("GBPUSD", forAsset, domAsset));

            await bus.Command(command);

            await retroactive.RollbackCommands(new[] { command });
        }
예제 #6
0
        public async void CanProcessHashflare()
        {
            var container = CreateContainer();
            var bus       = container.GetInstance <IBus>();
            var timeline  = container.GetInstance <ITimeline>();
            var manager   = container.GetInstance <IBranchManager>();

            var asset = new Asset("Bitcoin", "BTC", Asset.Type.Coin);
            var usd   = new Currency("USD");
            await bus.Command(new RegisterAssetPair(AssetPair.Fordom(asset, usd), asset, usd));

            await bus.Command(new AddQuote(AssetPair.Fordom(asset, usd), timeline.Now, 23000));

            await bus.Command(new RegisterHashflare("*****@*****.**"));

            await manager.Ready;
            await bus.Command(new CreateContract("0", asset.Ticker, 100, 1000));

            await bus.Command(new AddMinedCoinToHashflare(asset.Ticker, 0.1));

            await bus.Equal(new AccountStatsQuery("Hashflare", usd), a => a.Balance, new Quantity(23000 * 0.1, usd));
        }
예제 #7
0
        public async void CanGetLatestPairQuote()
        {
            var container = CreateContainer();
            var bus       = container.GetInstance <IBus>();
            var log       = container.GetInstance <ILog>();

            var forAsset = new Currency("GBP");
            var domAsset = new Currency("USD");

            await bus.Command(new RegisterAssetPair("GBPUSD", forAsset, domAsset));

            await bus.Command(new UpdateQuote(AssetPair.Fordom(forAsset, domAsset)));

            await bus.Command(new UpdateQuote(AssetPair.Fordom(forAsset, domAsset)));

            await log.Errors.Observable.FirstAsync(e => e.Message.Contains("Quote already added"));

            await bus.IsTrue(new AssetPriceQuery(forAsset, domAsset), q => q.Price > 1);

            var res = await bus.QueryAsync(new AssetPriceQuery(forAsset, domAsset));

            log.Info($"{AssetPair.Fordom(forAsset, domAsset)} is {res.Price} for {res.Timestamp}");
        }
예제 #8
0
            public bool UpdateQuotes(string account, string denominator)
            {
                var assetsList = _bus.QueryAsync(new AssetPairsInfoQuery()).Result;
                var asset      = assetsList.Assets.SingleOrDefault(a => a.AssetId == denominator);

                if (asset == null)
                {
                    throw new InvalidOperationException($"Asset {denominator} not registered");
                }

                var txList = _queries.TransactionInfos(account);

                foreach (var t in txList)
                {
                    var fordom        = AssetPair.Fordom(t.Quantity.Denominator, asset);
                    var assetPairInfo = _coreQueries.AssetPairInfo(fordom);
                    if (!assetPairInfo.QuoteDates.Any(d => d.InUtc().Year == t.Date.InUtc().Year&& d.InUtc().Month == t.Date.InUtc().Month&& d.InUtc().Day == t.Date.InUtc().Day))
                    {
                        _bus.Command(new RetroactiveCommand <UpdateQuote>(new UpdateQuote(fordom), t.Date.InUtc().LocalDateTime.Date.AtMidnight().InUtc().ToInstant())).Wait();
                    }
                }

                return(true);
            }
예제 #9
0
        protected override async Task <AssetPrice> Handle(IProjection <AssetPairsInfo> projection, AssetPriceQuery query)
        {
            var price  = 1.0;
            var fordom = AssetPair.Fordom(query.ForAsset, query.DomAsset);
            var info   = projection.State;

            info.Tree.Log = _log;
            var timestamp = query.Timestamp;

            if (query.Timeline != "")
            {
                timestamp = _branchManager.GetTime(query.Timeline);
            }
            else if (timestamp == default)
            {
                timestamp = _branchManager.GetTime(_branchManager.ActiveBranch);
            }

            if (info.Pairs.ToList().Contains(fordom))
            {
                var result = await _handler.Handle(new SingleAssetPriceQuery(fordom)
                {
                    Timeline  = query.Timeline,
                    Timestamp = query.Timestamp,
                });

                if (result == null || result.Timestamp.Minus(timestamp).Days > 0 || timestamp.Minus(result.Timestamp).Days > 0)
                {
                    throw new InvalidOperationException($"Stale pricing date for {fordom}");
                }
                price = result.Price;
            }
            else
            {
                // try to triangulate the price
                var path = info.Tree.GetPath(query.ForAsset, query.DomAsset);
                if (path == null)
                {
                    throw new InvalidOperationException($"No path found from {query.ForAsset?.Ticker} to {query.DomAsset?.Ticker}");
                }

                foreach (var(forAsset, domAsset) in path)
                {
                    var pathForDom = forAsset + domAsset;
                    var isInverse  = info.Pairs.Contains(domAsset + forAsset);
                    if (isInverse)
                    {
                        pathForDom = domAsset + forAsset;
                    }

                    var pathResult = await _handler.Handle(new SingleAssetPriceQuery(pathForDom)
                    {
                        Timeline  = query.Timeline,
                        Timestamp = query.Timestamp,
                    });

                    if (pathResult == null || pathResult.Timestamp.Minus(timestamp).Days > 0 || timestamp.Minus(pathResult.Timestamp).Days > 0)
                    {
                        throw new InvalidOperationException($"Stale pricing date for {pathForDom}");
                    }

                    if (isInverse)
                    {
                        pathResult.Price = 1.0 / pathResult.Price;
                    }

                    price *= pathResult.Price;
                }
            }

            return(new AssetPrice(price, timestamp));
        }