Files
managing-apps/src/Managing.Application/Backtesting/Backtester.cs
Oda c715da8a17 Add indicators to backtest and bot (#14)
* Add indicators to backtest and bot

* Remove
2025-02-28 00:53:25 +07:00

246 lines
9.2 KiB
C#

using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Repositories;
using Managing.Application.Abstractions.Services;
using Managing.Core;
using Managing.Core.FixedSizedQueue;
using Managing.Domain.Accounts;
using Managing.Domain.Backtests;
using Managing.Domain.Candles;
using Managing.Domain.MoneyManagements;
using Managing.Domain.Scenarios;
using Managing.Domain.Shared.Helpers;
using Managing.Domain.Strategies;
using Managing.Domain.Strategies.Base;
using Managing.Domain.Workflows;
using Microsoft.Extensions.Logging;
using static Managing.Common.Enums;
namespace Managing.Application.Backtesting
{
public class Backtester : IBacktester
{
private readonly IBacktestRepository _backtestRepository;
private readonly ILogger<Backtester> _logger;
private readonly IExchangeService _exchangeService;
private readonly IBotFactory _botFactory;
private readonly IScenarioService _scenarioService;
public Backtester(
IExchangeService exchangeService,
IBotFactory botFactory,
IBacktestRepository backtestRepository,
ILogger<Backtester> logger, IScenarioService scenarioService)
{
_exchangeService = exchangeService;
_botFactory = botFactory;
_backtestRepository = backtestRepository;
_logger = logger;
_scenarioService = scenarioService;
}
public Backtest RunSimpleBotBacktest(Workflow workflow, bool save = false)
{
var simplebot = _botFactory.CreateSimpleBot("scenario", workflow);
Backtest result = null;
if (save)
{
_backtestRepository.InsertBacktest(result);
}
return result;
}
public Backtest RunScalpingBotBacktest(Account account,
MoneyManagement moneyManagement,
Ticker ticker,
Scenario scenario,
Timeframe timeframe,
double days,
decimal balance,
bool isForWatchingOnly = false,
bool save = false,
List<Candle> initialCandles = null)
{
var scalpingBot = _botFactory.CreateBacktestScalpingBot(account.Name, moneyManagement, ticker, "scenario",
timeframe, isForWatchingOnly);
scalpingBot.LoadScenario(scenario.Name);
var candles = initialCandles ?? GetCandles(account, ticker, timeframe, days);
var result = GetBacktestingResult(ticker, scenario, timeframe, scalpingBot, candles, balance, account,
moneyManagement);
if (save)
{
_backtestRepository.InsertBacktest(result);
}
return result;
}
private List<Candle> GetCandles(Account account, Ticker ticker, Timeframe timeframe, double days)
{
var candles = _exchangeService.GetCandlesInflux(account.Exchange, ticker,
DateTime.Now.AddDays(Convert.ToDouble(days)), timeframe).Result;
if (candles == null || candles.Count == 0)
throw new Exception($"No candles for {ticker} on {account.Exchange}");
return candles;
}
public Backtest RunFlippingBotBacktest(Account account, MoneyManagement moneyManagement, Ticker ticker,
Scenario scenario, Timeframe timeframe,
double days, decimal balance, bool isForWatchingOnly = false, bool save = false,
List<Candle> initialCandles = null)
{
var flippingBot = _botFactory.CreateBacktestFlippingBot(account.Name, moneyManagement, ticker, "scenario",
timeframe, false);
flippingBot.LoadScenario(scenario.Name);
var candles = initialCandles ?? GetCandles(account, ticker, timeframe, days);
var result = GetBacktestingResult(ticker, scenario, timeframe, flippingBot, candles, balance, account,
moneyManagement);
if (save)
{
_backtestRepository.InsertBacktest(result);
}
return result;
}
public Backtest RunScalpingBotBacktest(Account account, MoneyManagement moneyManagement, Scenario scenario,
Timeframe timeframe, List<Candle> candles, decimal balance)
{
var ticker = MiscExtensions.ParseEnum<Ticker>(candles.FirstOrDefault().Ticker);
var bot = _botFactory.CreateBacktestScalpingBot(account.Name, moneyManagement, ticker, "scenario",
timeframe, false);
bot.LoadScenario(scenario.Name);
var result = GetBacktestingResult(ticker, scenario, timeframe, bot, candles, balance, account,
moneyManagement);
return result;
}
public Backtest RunFlippingBotBacktest(Account account, MoneyManagement moneyManagement, Scenario scenario,
Timeframe timeframe, List<Candle> candles, decimal balance)
{
var ticker = MiscExtensions.ParseEnum<Ticker>(candles.FirstOrDefault().Ticker);
var bot = _botFactory.CreateBacktestFlippingBot(account.Name, moneyManagement, ticker, "scenario",
timeframe, false);
bot.LoadScenario(scenario.Name);
var result = GetBacktestingResult(ticker, scenario, timeframe, bot, candles, balance, account,
moneyManagement);
return result;
}
private Backtest GetBacktestingResult(
Ticker ticker,
Scenario scenario,
Timeframe timeframe,
ITradingBot bot,
List<Candle> candles,
decimal balance,
Account account,
MoneyManagement moneyManagement)
{
if (candles == null || candles.Count == 0)
{
throw new Exception("No candle to backtest");
}
bot.WalletBalances.Add(candles.FirstOrDefault().Date, balance);
foreach (var candle in candles)
{
bot.OptimizedCandles.Enqueue(candle);
bot.Candles.Add(candle);
bot.Run();
}
bot.Candles = new HashSet<Candle>(candles);
// bot.UpdateStrategiesValues();
var strategies = _scenarioService.GetStrategies();
var strategiesValues = GetStrategiesValues(strategies, candles);
var finalPnl = bot.GetProfitAndLoss();
var winRate = bot.GetWinRate();
var optimizedMoneyManagement = TradingBox.GetBestMoneyManagement(candles, bot.Positions, moneyManagement);
var stats = TradingHelpers.GetStatistics(bot.WalletBalances);
var growthPercentage = TradingHelpers.GetGrowthFromInitalBalance(balance, finalPnl);
var hodlPercentage = TradingHelpers.GetHodlPercentage(candles[0], candles.Last());
var result = new Backtest(ticker, scenario.Name, bot.Positions, bot.Signals.ToList(), timeframe, candles,
bot.BotType, account.Name)
{
FinalPnl = finalPnl,
WinRate = winRate,
GrowthPercentage = growthPercentage,
HodlPercentage = hodlPercentage,
Fees = bot.GetTotalFees(),
WalletBalances = bot.WalletBalances.ToList(),
Statistics = stats,
OptimizedMoneyManagement = optimizedMoneyManagement,
MoneyManagement = moneyManagement,
StrategiesValues = strategiesValues
};
return result;
}
private Dictionary<StrategyType, StrategiesResultBase> GetStrategiesValues(IEnumerable<Strategy> strategies,
List<Candle> candles)
{
var strategiesValues = new Dictionary<StrategyType, StrategiesResultBase>();
var fixedCandles = new FixedSizeQueue<Candle>(10000);
foreach (var candle in candles)
{
fixedCandles.Enqueue(candle);
}
foreach (var strategy in strategies)
{
try
{
var s = ScenarioHelpers.BuildStrategy(strategy, 10000);
s.Candles = fixedCandles;
strategiesValues[strategy.Type] = s.GetStrategyValues();
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
return strategiesValues;
}
public IEnumerable<Backtest> GetBacktests()
{
return _backtestRepository.GetBacktests();
}
public bool DeleteBacktest(string id)
{
try
{
_backtestRepository.DeleteBacktestById(id);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool DeleteBacktests()
{
try
{
_backtestRepository.DeleteAllBacktests();
//_backtestRepository.DropCollection();
return true;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
}
}