public LongTaskLaunchResult Filtrate(ICandlesFiltrationRequest request, bool analyzeOnly)
        {
            // We should not run filtration multiple times before the first attempt ends.
            if (Health != null && Health.State == CandlesFiltrationState.InProgress)
            {
                return(LongTaskLaunchResult.AlreadyInProgress);
            }

            // And also we should check if the specified asset pair is enabled.
            var storedAssetPair = _assetPairsManager.TryGetEnabledPairAsync(request.AssetPairId).GetAwaiter().GetResult();

            if (storedAssetPair == null || !_candlesHistoryRepository.CanStoreAssetPair(request.AssetPairId))
            {
                return(LongTaskLaunchResult.AssetPairNotSupported);
            }

            var epsilon = Math.Pow(10, -storedAssetPair.Accuracy);

            _log.Info(nameof(Filtrate), $"Starting candles with extreme price filtration for {request.AssetPairId}...");

            Health = new CandlesFiltrationHealthReport(request.AssetPairId, request.LimitLow, request.LimitHigh, analyzeOnly);

            var priceTypeTasks = new List <Task>();

            if (request.PriceType.HasValue)
            {
                priceTypeTasks.Add(
                    DoFiltrateAsync(request.AssetPairId, request.LimitLow, request.LimitHigh, request.PriceType.Value, epsilon,
                                    analyzeOnly));
            }
            else
            {
                foreach (var priceType in Constants.StoredPriceTypes)
                {
                    priceTypeTasks.Add(
                        DoFiltrateAsync(request.AssetPairId, request.LimitLow, request.LimitHigh, priceType, epsilon,
                                        analyzeOnly));
                }
            }

            Task.WhenAll(priceTypeTasks.ToArray()).ContinueWith(t =>
            {
                Health.State = CandlesFiltrationState.Finished;

                if (analyzeOnly)
                {
                    _log.Info(nameof(Filtrate),
                              $"Filtration for {request.AssetPairId} finished: analyze only. Total amount of candles to delete: {Health.DeletedCandlesCount.Values.Sum()}, " +
                              $"total amount of candles to replace: {Health.ReplacedCandlesCount.Values.Sum()}. Errors count: {Health.Errors.Count}.");
                }
                else
                {
                    _log.Info(nameof(Filtrate),
                              $"Filtration for {request.AssetPairId} finished. Total amount of deleted Sec candles: {Health.DeletedCandlesCount.Values.Sum()}, " +
                              $"total amount of replaced bigger candles: {Health.ReplacedCandlesCount.Values.Sum()}. Errors count: {Health.Errors.Count}.");
                }
            });

            return(LongTaskLaunchResult.Started);
        }
 /// <summary>
 /// Throws an <see cref="InvalidOperationException"/> if the specified asset pair is not supported.
 /// </summary>
 /// <param name="assetPairId">Asset pair ID.</param>
 private void CheckupAssetPairOrFail(string assetPairId)
 {
     if (!_candlesHistoryRepository.CanStoreAssetPair(assetPairId))
     {
         throw new InvalidOperationException($"Connection string for asset pair {assetPairId} not configured");
     }
 }
예제 #3
0
        public async Task InitializeCacheAsync()
        {
            // Depending on cache invalidation period and on asset pairs amount, there may be a case when
            // the invalidation timer fires before the cache loading has stopped. This will be a signal
            // to skip timer-based invalidation.
            // Below we combine two approaches:
            // - we're exporting a fast signal for any timer-based routine that we have already been initializing the cache;
            // - and we additionally block all the cache-related operations for other parts of code.
            // The first is needed to avoid queueing of timer events. If we simply use blocks, we will finally face a problem
            // when cache initialization may become infinitly repeated. The second is important for avoidining a multi-threaded
            // write operations to the cache: if we've got a candle update set, we need to await for cache fill completion and
            // then proceed.
            lock (_initializationStateLocker)
            {
                if (InitializationState == CacheInitializationState.InProgress)
                {
                    return;
                }

                InitializationState = CacheInitializationState.InProgress;
            }

            await _cacheSem.WaitAsync();

            try
            {
                _log.Info(nameof(InitializeCacheAsync), "Caching candles history...");

                SlotType activeSlot = await _candlesCacheService.GetActiveSlotAsync(_marketType);

                //initialize cache to inactive slot
                SlotType initSlot = activeSlot == SlotType.Slot0
                    ? SlotType.Slot1
                    : SlotType.Slot0;

                var assetPairs = await _assetPairsManager.GetAllAsync();

                var now = _clock.UtcNow;

                foreach (var pairs in assetPairs.Where(a => _candlesHistoryRepository.CanStoreAssetPair(a.Id)).Batch(6))
                {
                    var tasks = pairs.Select(p => CacheAssetPairCandlesAsync(p, now, initSlot));
                    await Task.WhenAll(tasks);
                }

                await _candlesCacheService.InjectCacheValidityToken();                // Initial validation token set.

                await _candlesCacheService.SetActiveSlotAsync(_marketType, initSlot); //switch slots

                _log.Info(nameof(InitializeCacheAsync), "All candles history is cached");
            }
            finally
            {
                InitializationState = CacheInitializationState.Idle;
                _cacheSem.Release();
            }
        }
예제 #4
0
        public async Task InitializeCacheAsync()
        {
            await _log.WriteInfoAsync(nameof(CandlesCacheInitalizationService), nameof(InitializeCacheAsync), null, "Caching candles history...");

            var assetPairs = await _assetPairsManager.GetAllEnabledAsync();

            var now = _clock.UtcNow;
            var cacheAssetPairTasks = assetPairs
                                      .Where(a => _candlesHistoryRepository.CanStoreAssetPair(a.Id))
                                      .Select(assetPair => CacheAssetPairCandlesAsync(assetPair, now));

            await Task.WhenAll(cacheAssetPairTasks);

            await _log.WriteInfoAsync(nameof(CandlesCacheInitalizationService), nameof(InitializeCacheAsync), null, "All candles history is cached");
        }
        public async Task <string> MigrateAsync(string assetPairId, IHistoryProvider historyProvider)
        {
            if (!MigrationEnabled)
            {
                return(string.Empty);
            }

            if (!_candlesHistoryRepository.CanStoreAssetPair(assetPairId))
            {
                return($"Connection string for the asset pair '{assetPairId}' not configuer");
            }

            var assetPair = await _assetPairsManager.TryGetAssetPairAsync(assetPairId);

            if (assetPair == null)
            {
                return($"Asset pair '{assetPairId}' not found");
            }

            lock (_assetManagers)
            {
                if (_assetManagers.ContainsKey(assetPairId))
                {
                    return($"{assetPairId} already being processed");
                }

                var telemetryService = new AssetPairMigrationTelemetryService(_logFactory, assetPairId);
                var assetManager     = new AssetPairMigrationManager(
                    _healthService,
                    _candlesPersistenceQueue,
                    _candlesGenerator,
                    telemetryService,
                    assetPair,
                    _logFactory,
                    new BidAskHCacheService(),
                    historyProvider,
                    _candlesHistoryMigrationService,
                    OnMigrationStopped,
                    _settings);

                assetManager.Start();

                _assetHealthServices.Add(assetPairId, telemetryService);
                _assetManagers.Add(assetPairId, assetManager);

                return($"{assetPairId} processing is started");
            }
        }
        public async Task <LongTaskLaunchResult> RunFixMidPricesAsync(string assetPairId, bool analyzeOnly)
        {
            // We should not run filtration multiple times before the first attempt ends.
            if (Health != null && Health.State == CandlesFiltrationState.InProgress)
            {
                return(LongTaskLaunchResult.AlreadyInProgress);
            }

            // And also we should check if the specified asset pair is enabled.
            var storedAssetPair = await _assetPairsManager.TryGetEnabledPairAsync(assetPairId);

            if (storedAssetPair == null || !_candlesHistoryRepository.CanStoreAssetPair(assetPairId))
            {
                return(LongTaskLaunchResult.AssetPairNotSupported);
            }

            _log.Info($"Starting mid candles price fix for {assetPairId}...");

            Health = new MidPricesFixHealthReport(assetPairId, analyzeOnly);

#pragma warning disable 4014
            Task.Run(async() =>
#pragma warning restore 4014
            {
                await FixMidPricesAsync(assetPairId, storedAssetPair.Accuracy, analyzeOnly);

                Health.State = CandlesFiltrationState.Finished;

                if (analyzeOnly)
                {
                    _log.Info($"Mid candle prices fix for {assetPairId} finished: analyze only. Total amount of corrupted candles: {Health.CorruptedCandlesCount}, " +
                              $" errors count: {Health.Errors.Count}.");
                }
                else
                {
                    _log.Info($"Mid candle prices fix for {assetPairId} finished. Total amount of corrupted candles: {Health.CorruptedCandlesCount}, " +
                              $"errors count: {Health.Errors.Count}.");
                }
            });

            return(LongTaskLaunchResult.Started);
        }
 /// <summary>
 /// Checks if we can handle/store the given asset pair.
 /// </summary>
 /// <param name="assetPairId">Asset pair ID.</param>
 /// <returns>True if repository is able to store such a pair, and false otherwise.</returns>
 public virtual bool CanHandleAssetPair(string assetPairId) => _candlesHistoryRepository.CanStoreAssetPair(assetPairId);