private void Initialize() { _log.Info("Initializing last state from history if needed..."); lock (_syncLastReset) _lastReset = _firstStateAfterResetTimeRepository.GetAsync().GetAwaiter().GetResult(); // Initialize _allMarketCaps RefreshCoinMarketCapDataAsync().GetAwaiter().GetResult(); // Restore top assets from DB var lastIndexHistory = _indexHistoryRepository.TakeLastAsync(1).GetAwaiter().GetResult().SingleOrDefault(); // if found then restore _topAssets (constituents) if (lastIndexHistory != null) { lock (_syncLastIndexHistory) _lastIndexHistory = lastIndexHistory; lock (_sync) _topAssets.AddRange(lastIndexHistory.Weights.Keys); _log.Info("Initialized previous weights and market caps from history."); } }
public async Task <IndexHistory> GetAsync(DateTime dateTime) { var model = await _storage.GetDataAsync(GetPartitionKey(dateTime), GetRowKey(dateTime)); if (model == null) { return(null); } var blob = await _blobRepository.GetAsync(dateTime); if (blob == null) { return(null); } var tickPrices = Mapper.Map <IReadOnlyCollection <TickPrice> >(blob.TickPrices); var assetPrices = Mapper.Map <IReadOnlyCollection <AssetPrice> >(blob.GetAssetPrices()); var domain = new IndexHistory( model.Value, Mapper.Map <AssetMarketCap[]>(model.MarketCaps), model.Weights, tickPrices, assetPrices, model.MiddlePrices, model.Time, Mapper.Map <AssetSettings[]>(model.AssetsSettings)); return(domain); }
private async Task SaveAsync(IndexState indexState, IndexHistory indexHistory) { // Save index state for the next execution await _indexStateRepository.SetAsync(indexState); // Save index history await _indexHistoryRepository.InsertAsync(indexHistory); }
public async Task InsertAsync(IndexHistory domain) { // Table var entity = Mapper.Map <IndexHistoryEntity>(domain); entity.PartitionKey = GetPartitionKey(domain.Time); entity.RowKey = GetRowKey(domain.Time); await _storage.InsertOrReplaceAsync(entity); // Blob var blob = Mapper.Map <IndexHistoryBlob>(domain); await _blobRepository.SaveAsync(blob); }
private void Publish(IndexHistory indexHistory) { var assetsInfo = new List <Contract.AssetInfo>(); var frozenAssets = indexHistory.AssetsSettings.Where(x => x.IsDisabled).Select(x => x.AssetId).ToList(); foreach (var asset in indexHistory.Weights.Keys.ToList()) { var isFrozen = frozenAssets.Contains(asset); assetsInfo.Add(new Contract.AssetInfo(asset, indexHistory.Weights[asset], indexHistory.MiddlePrices[asset], isFrozen)); } // Publish index to RabbitMq var tickPrice = new Contract.IndexTickPrice(RabbitMqSource, _indexName.ToUpper(), indexHistory.Value, indexHistory.Value, indexHistory.Time, assetsInfo); _tickPricePublisher.Publish(tickPrice); }
private async Task CalculateThenSaveAndPublishAsync() { _log.Info("Started calculating index..."); var settings = Settings; var whiteListAssets = settings.Assets; if (!whiteListAssets.Any()) { _log.Info("There are no assets in the white list, skipped index calculation."); return; } IReadOnlyCollection <string> topAssets; IReadOnlyCollection <AssetMarketCap> allMarketCaps; lock (_sync) { allMarketCaps = _allMarketCaps.ToList(); topAssets = _topAssets; // Must be obtained from _topAssets (daily rebuild changes it) } if (!topAssets.Any()) { _log.Info("There are no top assets yet, skipped index calculation."); return; } var lastIndex = await _indexStateRepository.GetAsync(); var sources = settings.Sources.ToList(); var tickPrices = _tickPricesService.GetTickPrices(sources); var assetPrices = _tickPricesService.GetAssetPrices(sources); var assetsSettings = settings.AssetsSettings; var topUsingPrices = GetAssetsUsingPrices(topAssets, assetPrices, assetsSettings); // If just started and prices are not present yet, then skip. // If started more then {_waitForTopAssetsPricesFromStart} ago then write warning to DB and log. var areAllPricesPresent = await ArePricesPresentForAllAssets(topAssets, topUsingPrices); if (!areAllPricesPresent) { return; } // Auto freeze await AutoFreezeIfNeeded(topAssets, topUsingPrices, lastIndex, settings); assetsSettings = Settings.AssetsSettings; // Recalculate top weights var topSupplies = new Dictionary <string, decimal>(); var topMarketCaps = allMarketCaps.Where(x => topAssets.Contains(x.Asset)).ToList(); foreach (var mc in topMarketCaps) { topSupplies.Add(mc.Asset, mc.CirculatingSupply); } var calculatedTopMarketCaps = CalculateMarketCaps(topAssets, topSupplies, topUsingPrices); lock (_sync) { _lastTopAssetMarketCaps.Clear(); foreach (var mc in calculatedTopMarketCaps) { _lastTopAssetMarketCaps[mc.Asset] = mc.MarketCap.Value; } } var calculatedTopWeights = CalculateWeightsOrderedByDesc(calculatedTopMarketCaps); // Calculate current index state var indexState = CalculateIndex(lastIndex, calculatedTopWeights, topUsingPrices); // Calculate current index history element var indexHistory = new IndexHistory( indexState.Value, calculatedTopMarketCaps, calculatedTopWeights, tickPrices.SelectMany(x => x.Value).ToList(), assetPrices.SelectMany(x => x.Value).ToList(), topUsingPrices, DateTime.UtcNow, assetsSettings); // if there was a reset then skip until next iteration which will have initial state if (State == null) { if (indexState.Value != InitialIndexValue) { _log.Info($"Skipped saving and publishing index because of reset - previous state is null and current index not equals {InitialIndexValue}."); return; } await _firstStateAfterResetTimeRepository.SetAsync(indexHistory.Time); lock (_syncLastReset) _lastReset = indexHistory.Time; _log.Info($"Reset at: {indexHistory.Time.ToIsoDateTime()}."); } // Skip if changed to 'disabled' if (!Settings.Enabled) { _log.Info($"Skipped saving and publishing index because {nameof(Settings)}.{nameof(Settings.Enabled)} = {Settings.Enabled}."); return; } lock (_syncLastIndexHistory) _lastIndexHistory = indexHistory; await SaveAsync(indexState, indexHistory); Publish(indexHistory); await _indexHandler.HandleAsync(indexHistory); _log.Info($"Finished calculating index for {calculatedTopMarketCaps.Count} assets, value: {indexState.Value}."); }
public Task HandleAsync(IndexHistory indexHistory) { try { lock (_sync24H) { if (!_initialized) { Initialize(); _initialized = true; } _currentValue = indexHistory.Value; _history24H[indexHistory.Time] = indexHistory.Value; // remove old foreach (var time in _history24H.Keys.ToList()) { if (time < DateTime.UtcNow.AddDays(-1)) { _history24H.Remove(time); } } CalculateKeyNumbers24H(); } lock (_sync5D) { var newest = _history5D.Keys.LastOrDefault(); if (newest == default(DateTime) || // empty indexHistory.Time - newest > TimeSpan.FromMinutes(5)) { _chartHistory5DRepository.InsertOrReplaceAsync(indexHistory.Time, indexHistory.Value).GetAwaiter().GetResult(); _history5D[indexHistory.Time] = indexHistory.Value; // remove old foreach (var time in _history5D.Keys.ToList()) { if (time < DateTime.UtcNow.AddDays(-5)) { _history5D.Remove(time); } } CalculateKeyNumbers5D(); } } lock (_sync30D) { var newest = _history30D.Keys.LastOrDefault(); if (newest == default(DateTime) || // empty indexHistory.Time - newest > TimeSpan.FromMinutes(30)) { _chartHistory30DRepository.InsertOrReplaceAsync(indexHistory.Time, indexHistory.Value).GetAwaiter().GetResult(); _history30D[indexHistory.Time] = indexHistory.Value; // remove old foreach (var time in _history30D.Keys.ToList()) { if (time < DateTime.UtcNow.AddDays(-30)) { _history30D.Remove(time); } } CalculateKeyNumbers30D(); } } } catch (Exception ex) { _log.Warning("Something went wrong in StatisticsService.", ex); } return(Task.CompletedTask); }