using Managing.Application.Abstractions; using Managing.Application.Abstractions.Repositories; using Managing.Application.Abstractions.Services; using Managing.Application.Workers.Abstractions; using Managing.Domain.Accounts; using Managing.Domain.Candles; using Managing.Domain.MoneyManagements; using Managing.Domain.Scenarios; using Managing.Domain.Shared.Helpers; using Managing.Domain.Statistics; using Managing.Domain.Strategies; using Managing.Domain.Trades; using Microsoft.Extensions.Logging; using static Managing.Common.Enums; namespace Managing.Application.Workers; public class StatisticService : IStatisticService { private readonly IStatisticRepository _statisticRepository; private readonly IExchangeService _exchangeService; private readonly IAccountService _accountService; private readonly IEvmManager _evmManager; private readonly ITradingService _tradingService; private readonly IBacktester _backtester; private readonly ITradaoService _tradaoService; private readonly IMessengerService _messengerService; private readonly ILogger _logger; public StatisticService( IExchangeService exchangeService, IAccountService accountService, ILogger logger, IStatisticRepository statisticRepository, IEvmManager evmManager, ITradingService tradingService, IBacktester backtester, ITradaoService tradaoService, IMessengerService messengerService) { _exchangeService = exchangeService; _accountService = accountService; _logger = logger; _statisticRepository = statisticRepository; _evmManager = evmManager; _tradingService = tradingService; _backtester = backtester; _tradaoService = tradaoService; _messengerService = messengerService; } public async Task UpdateTopVolumeTicker(TradingExchanges exchange, int top) { var account = _accountService.GetAccounts(false, false).FirstOrDefault(a => a.Exchange == exchange); var date = DateTime.UtcNow; if (account == null) throw new Exception($"Enable to found account for exchange {exchange}"); var lastTop = GetLastTopVolumeTicker(); if (lastTop != null && lastTop.Count > 0) { _logger.LogInformation($"A top of {lastTop.Count} already exist for the current rage"); return; } var volumeTickers = new Dictionary(); foreach (var ticker in (Ticker[])Enum.GetValues(typeof(Ticker))) { var volume = _exchangeService.GetVolume(account, ticker); var price = _exchangeService.GetPrice(account, ticker, date); volumeTickers.Add(ticker, volume * price); } var currentTop = volumeTickers.OrderByDescending(v => v.Value).Take(top).ToList(); for (int rank = 0; rank < currentTop.Count; rank++) { var dto = new TopVolumeTicker() { Date = date, Rank = rank + 1, Ticker = currentTop[rank].Key, Volume = currentTop[rank].Value, Exchange = exchange }; await _statisticRepository.InsertTopVolumeTicker(dto); } } public IList GetLastTopVolumeTicker() { var from = DateTime.UtcNow.AddDays(-1); return _statisticRepository.GetTopVolumeTickers(from); } public IList GetTickers() { return _evmManager.GetAvailableTicker().Result; } public async Task UpdateSpotlight() { var scenarios = _tradingService.GetScenarios(); var account = _accountService.GetAccounts(false, false).FirstOrDefault(a => a.Exchange == TradingExchanges.Evm); if (account == null) throw new Exception($"Enable to found default account"); var overview = GetLastSpotlight(DateTime.Now.AddMinutes(-20)); if (overview != null) { if(overview.Spotlights.Count < overview.ScenarioCount) { _logger.LogInformation($"Spotlights not up to date. {overview.Spotlights.Count}/{overview.ScenarioCount}"); } else { _logger.LogInformation("No need to update spotlights"); return; } } else { overview = new SpotlightOverview { Spotlights = new List(), DateTime = DateTime.Now, Identifier = Guid.NewGuid(), ScenarioCount = scenarios.Count(), }; await _statisticRepository.SaveSpotligthtOverview(overview); } var tickers = GetTickers(); foreach (var scenario in scenarios) { if (overview.Spotlights.Any(s => s.Scenario.Name == scenario.Name)) continue; var spotlight = new Spotlight { TickerSignals = new List(), Scenario = scenario }; var options = new ParallelOptions() { MaxDegreeOfParallelism = 2 }; _ = Parallel.ForEach(tickers, options, ticker => { spotlight.TickerSignals.Add(new TickerSignal { Ticker = ticker, FiveMinutes = GetSignals(account, scenario, ticker, Timeframe.FiveMinutes), FifteenMinutes = GetSignals(account, scenario, ticker, Timeframe.FifteenMinutes), OneHour = GetSignals(account, scenario, ticker, Timeframe.OneHour), FourHour = GetSignals(account, scenario, ticker, Timeframe.FourHour), OneDay = GetSignals(account, scenario, ticker, Timeframe.OneDay) }); }); overview.Spotlights.Add(spotlight); _statisticRepository.UpdateSpotlightOverview(overview); } overview.DateTime = DateTime.Now; _statisticRepository.UpdateSpotlightOverview(overview); } private List GetSignals(Account account, Scenario scenario, Ticker ticker, Timeframe timeframe) { try { var moneyManagement = new MoneyManagement() { BalanceAtRisk = 0.05m, Leverage = 1, Timeframe = timeframe, StopLoss = 0.008m, TakeProfit = 0.02m }; var backtest = _backtester.RunScalpingBotBacktest( account, moneyManagement, ticker, scenario, timeframe, CandleExtensions.GetMinimalDays(timeframe), 1000, isForWatchingOnly: true); return backtest.Signals; } catch (Exception ex) { _logger.LogError("Backtest cannot be run", ex); } return null; } public SpotlightOverview GetLastSpotlight(DateTime dateTime) { var overviews = _statisticRepository.GetSpotlightOverviews(dateTime); if (overviews.Any()) { return overviews.OrderBy(o => o.DateTime).Last(); } return null; } public List GetBestTraders() { return _statisticRepository.GetBestTraders(); } public List GetBadTraders() { return _statisticRepository.GetBadTraders(); } public async Task> GetLeadboardPositons() { var customWatchAccount = _tradingService.GetTradersWatch(); var trades = new List(); foreach (var trader in customWatchAccount) { trades.AddRange(await _tradaoService.GetTrades(trader.Address)); } return trades; } public async Task UpdateLeaderboard() { var previousBestTraders = _statisticRepository.GetBestTraders(); var lastBestTrader = (await _tradaoService.GetBestTrader()).FindGoodTrader(); // Update / Insert best trader foreach (var trader in lastBestTrader) { if (previousBestTraders.Exists((p) => p.Address == trader.Address)) { _statisticRepository.UpdateBestTrader(trader); } else { await _statisticRepository.InsertBestTrader(trader); } } // Remove trader that wasnt good enough foreach (var trader in previousBestTraders) { if (!lastBestTrader.Exists((t) => t.Address == trader.Address)) { await _statisticRepository.RemoveBestTrader(trader); } } await _messengerService.SendBestTraders(lastBestTrader); } public async Task UpdateNoobiesboard() { var previousBadTraders = _statisticRepository.GetBadTraders(); var lastBadTrader = (await _tradaoService.GetBadTrader()).FindBadTrader(); // Update / Insert best trader foreach (var trader in lastBadTrader) { if (previousBadTraders.Exists((p) => p.Address == trader.Address)) { _statisticRepository.UpdateBadTrader(trader); } else { await _statisticRepository.InsertBadTrader(trader); } } // Remove trader that wasnt good enough foreach (var trader in previousBadTraders) { if (!lastBadTrader.Exists((t) => t.Address == trader.Address)) { await _statisticRepository.RemoveBadTrader(trader); } } await _messengerService.SendBadTraders(lastBadTrader); } }