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)); }
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)); }
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); }
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); }
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 }); }
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)); }
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}"); }
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); }
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)); }