246 lines
9.2 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
} |