Commit before refact factory into service

This commit is contained in:
2024-07-12 19:58:19 +07:00
parent 13e70cbf63
commit 0544749a69
11 changed files with 243 additions and 169 deletions

View File

@@ -32,7 +32,6 @@ namespace Managing.Application.Tests
_botFactory = new BotFactory( _botFactory = new BotFactory(
_exchangeService, _exchangeService,
tradingBotLogger, tradingBotLogger,
_moneyManagementService.Object,
discordService, discordService,
_accountService.Object, _accountService.Object,
_tradingService.Object, _tradingService.Object,

View File

@@ -1,8 +1,31 @@
using Managing.Application.Bots;
using Managing.Common; using Managing.Common;
using Managing.Domain.Bots;
using Managing.Domain.MoneyManagements;
using Managing.Domain.Workflows;
namespace Managing.Application.Abstractions;
public interface IBotService public interface IBotService
{ {
void SaveBotBackup(BotBackup botBackup); void SaveBotBackup(BotBackup botBackup);
void SaveBotBackup(string name, Enums.BotType botType, string data); void SaveBotBackup(string name, Enums.BotType botType, string data);
void AddSimpleBotToCache(IBot bot);
void AddTradingBotToCache(ITradingBot bot);
List<ITradingBot> GetActiveBots();
IEnumerable<BotBackup> GetSavedBots();
void StartBot(BotBackup backupBot);
ITradingBot CreateScalpingBot(string accountName, MoneyManagement moneyManagement, string name, Enums.Ticker ticker,
string scenario, Enums.Timeframe interval, bool isForWatchingOnly);
ITradingBot CreateBacktestScalpingBot(string accountName, MoneyManagement moneyManagement, Enums.Ticker ticker,
string scenario, Enums.Timeframe interval, bool isForWatchingOnly);
ITradingBot CreateFlippingBot(string accountName, MoneyManagement moneyManagement, string name, Enums.Ticker ticker,
string scenario, Enums.Timeframe interval, bool isForWatchingOnly);
ITradingBot CreateBacktestFlippingBot(string accountName, MoneyManagement moneyManagement, Enums.Ticker ticker,
string scenario, Enums.Timeframe interval, bool isForWatchingOnly);
IBot CreateSimpleBot(string botName, Workflow workflow);
} }

View File

@@ -10,7 +10,6 @@ namespace Managing.Application.Bots.Base
{ {
public class BotFactory : IBotFactory public class BotFactory : IBotFactory
{ {
private readonly IMoneyManagementService _moneyManagementService;
private readonly IExchangeService _exchangeService; private readonly IExchangeService _exchangeService;
private readonly IMessengerService _messengerService; private readonly IMessengerService _messengerService;
private readonly IAccountService _accountService; private readonly IAccountService _accountService;
@@ -21,7 +20,6 @@ namespace Managing.Application.Bots.Base
public BotFactory( public BotFactory(
IExchangeService exchangeService, IExchangeService exchangeService,
ILogger<TradingBot> tradingBotLogger, ILogger<TradingBot> tradingBotLogger,
IMoneyManagementService moneyManagementService,
IMessengerService messengerService, IMessengerService messengerService,
IAccountService accountService, IAccountService accountService,
ITradingService tradingService, ITradingService tradingService,
@@ -29,7 +27,6 @@ namespace Managing.Application.Bots.Base
{ {
_tradingBotLogger = tradingBotLogger; _tradingBotLogger = tradingBotLogger;
_exchangeService = exchangeService; _exchangeService = exchangeService;
_moneyManagementService = moneyManagementService;
_messengerService = messengerService; _messengerService = messengerService;
_accountService = accountService; _accountService = accountService;
_tradingService = tradingService; _tradingService = tradingService;

View File

@@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging; using Managing.Application.Abstractions;
using Microsoft.Extensions.Logging;
using static Managing.Common.Enums; using static Managing.Common.Enums;
using Managing.Application.Abstractions.Services; using Managing.Application.Abstractions.Services;
using Managing.Domain.MoneyManagements; using Managing.Domain.MoneyManagements;
@@ -22,20 +23,20 @@ namespace Managing.Application.Bots
bool isForBacktest = false, bool isForBacktest = false,
bool isForWatchingOnly = false) bool isForWatchingOnly = false)
: base(accountName, : base(accountName,
moneyManagement, moneyManagement,
name, name,
ticker, ticker,
scenario, scenario,
exchangeService, exchangeService,
logger, logger,
tradingService, tradingService,
timeframe, timeframe,
accountService, accountService,
messengerService, messengerService,
botService, botService,
isForBacktest, isForBacktest,
isForWatchingOnly, isForWatchingOnly,
flipPosition: true) flipPosition: true)
{ {
BotType = BotType.FlippingBot; BotType = BotType.FlippingBot;
} }
@@ -47,4 +48,4 @@ namespace Managing.Application.Bots
Logger.LogInformation($"Starting {Name} bot - Status : {Status}"); Logger.LogInformation($"Starting {Name} bot - Status : {Status}");
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging; using Managing.Application.Abstractions;
using Microsoft.Extensions.Logging;
using static Managing.Common.Enums; using static Managing.Common.Enums;
using Managing.Application.Abstractions.Services; using Managing.Application.Abstractions.Services;
using Managing.Domain.MoneyManagements; using Managing.Domain.MoneyManagements;

View File

@@ -1,4 +1,5 @@
using Managing.Domain.Bots; using Managing.Application.Abstractions;
using Managing.Domain.Bots;
using Managing.Domain.Workflows; using Managing.Domain.Workflows;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Newtonsoft.Json; using Newtonsoft.Json;
@@ -12,7 +13,8 @@ namespace Managing.Application.Bots
private readonly IBotService _botService; private readonly IBotService _botService;
private Workflow _workflow; private Workflow _workflow;
public SimpleBot(string name, ILogger<TradingBot> logger, Workflow workflow, IBotService botService) : base(name) public SimpleBot(string name, ILogger<TradingBot> logger, Workflow workflow, IBotService botService) :
base(name)
{ {
Logger = logger; Logger = logger;
_botService = botService; _botService = botService;
@@ -51,4 +53,4 @@ namespace Managing.Application.Bots
_workflow = JsonConvert.DeserializeObject<Workflow>(backup.Data); _workflow = JsonConvert.DeserializeObject<Workflow>(backup.Data);
} }
} }
} }

View File

@@ -103,13 +103,15 @@ public class TradingBot : Bot, ITradingBot
await CancelAllOrders(); await CancelAllOrders();
try try
{ {
await MessengerService.SendMessage($"Hi everyone, I'm going to run {Name}. \nI will send a message here everytime a signal is triggered by the {string.Join(",", Strategies.Select(s => s.Name))} strategies."); await MessengerService.SendMessage(
$"Hi everyone, I'm going to run {Name}. \nI will send a message here everytime a signal is triggered by the {string.Join(",", Strategies.Select(s => s.Name))} strategies.");
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.LogError(ex, ex.Message); Logger.LogError(ex, ex.Message);
} }
await InitWorker(Run); await InitWorker(Run);
} }
@@ -155,7 +157,8 @@ public class TradingBot : Bot, ITradingBot
public async Task Run() public async Task Run()
{ {
Logger.LogInformation($"____________________{Name}____________________"); Logger.LogInformation($"____________________{Name}____________________");
Logger.LogInformation($"Time : {DateTime.Now} - Server time {DateTime.Now.ToUniversalTime()} - Bot : {Name} - Type {BotType} - Ticker : {Ticker}"); Logger.LogInformation(
$"Time : {DateTime.Now} - Server time {DateTime.Now.ToUniversalTime()} - Bot : {Name} - Type {BotType} - Ticker : {Ticker}");
var previousCandleCount = Candles.Count; var previousCandleCount = Candles.Count;
@@ -183,6 +186,9 @@ public class TradingBot : Bot, ITradingBot
private async Task PreloadCandles() private async Task PreloadCandles()
{ {
if (Candles.Any())
return;
var candles = await ExchangeService.GetCandlesInflux(Account.Exchange, Ticker, PreloadSince, Timeframe); var candles = await ExchangeService.GetCandlesInflux(Account.Exchange, Ticker, PreloadSince, Timeframe);
foreach (var candle in candles.Where(c => c.Date < DateTime.Now.ToUniversalTime())) foreach (var candle in candles.Where(c => c.Date < DateTime.Now.ToUniversalTime()))
@@ -218,7 +224,7 @@ public class TradingBot : Bot, ITradingBot
signal.Status = SignalStatus.Expired; signal.Status = SignalStatus.Expired;
var signalText = $"{Scenario} trigger a signal. Signal told you " + var signalText = $"{Scenario} trigger a signal. Signal told you " +
$"to {signal.Direction} {Ticker} on {Timeframe}. The confidence in this signal is {signal.Confidence}. Identifier : {signal.Identifier}"; $"to {signal.Direction} {Ticker} on {Timeframe}. The confidence in this signal is {signal.Confidence}. Identifier : {signal.Identifier}";
Logger.LogInformation(signalText); Logger.LogInformation(signalText);
@@ -280,7 +286,9 @@ public class TradingBot : Bot, ITradingBot
{ {
Logger.LogInformation($"Updating position {positionForSignal.SignalIdentifier}"); Logger.LogInformation($"Updating position {positionForSignal.SignalIdentifier}");
var position = IsForBacktest ? positionForSignal : TradingService.GetPositionByIdentifier(positionForSignal.Identifier); var position = IsForBacktest
? positionForSignal
: TradingService.GetPositionByIdentifier(positionForSignal.Identifier);
if (position.Status == (PositionStatus.Finished | PositionStatus.Flipped)) if (position.Status == (PositionStatus.Finished | PositionStatus.Flipped))
{ {
@@ -292,32 +300,41 @@ public class TradingBot : Bot, ITradingBot
// For backtesting or force close if not executed on exchange : // For backtesting or force close if not executed on exchange :
// check if position is still open // check if position is still open
// Check status, if still open update the status of the position // Check status, if still open update the status of the position
var lastCandle = IsForBacktest ? Candles.Last() : ExchangeService.GetCandle(Account, Ticker, DateTime.UtcNow); var lastCandle = IsForBacktest
? Candles.Last()
: ExchangeService.GetCandle(Account, Ticker, DateTime.UtcNow);
if (positionForSignal.OriginDirection == TradeDirection.Long) if (positionForSignal.OriginDirection == TradeDirection.Long)
{ {
if (positionForSignal.StopLoss.Price >= lastCandle.Low) if (positionForSignal.StopLoss.Price >= lastCandle.Low)
{ {
await LogInformation($"Closing position - SL {positionForSignal.StopLoss.Price} >= Price {lastCandle.Low}"); await LogInformation(
await CloseTrade(signal, positionForSignal, positionForSignal.StopLoss, positionForSignal.StopLoss.Price, true); $"Closing position - SL {positionForSignal.StopLoss.Price} >= Price {lastCandle.Low}");
await CloseTrade(signal, positionForSignal, positionForSignal.StopLoss,
positionForSignal.StopLoss.Price, true);
positionForSignal.StopLoss.SetStatus(TradeStatus.Filled); positionForSignal.StopLoss.SetStatus(TradeStatus.Filled);
} }
else if (positionForSignal.TakeProfit1.Price <= lastCandle.High else if (positionForSignal.TakeProfit1.Price <= lastCandle.High
&& positionForSignal.TakeProfit1.Status != TradeStatus.Filled) && positionForSignal.TakeProfit1.Status != TradeStatus.Filled)
{ {
await LogInformation($"Closing position - TP1 {positionForSignal.TakeProfit1.Price} <= Price {lastCandle.High}"); await LogInformation(
await CloseTrade(signal, positionForSignal, positionForSignal.TakeProfit1, positionForSignal.TakeProfit1.Price, positionForSignal.TakeProfit2 == null); $"Closing position - TP1 {positionForSignal.TakeProfit1.Price} <= Price {lastCandle.High}");
await CloseTrade(signal, positionForSignal, positionForSignal.TakeProfit1,
positionForSignal.TakeProfit1.Price, positionForSignal.TakeProfit2 == null);
positionForSignal.TakeProfit1.SetStatus(TradeStatus.Filled); positionForSignal.TakeProfit1.SetStatus(TradeStatus.Filled);
} }
else if (positionForSignal.TakeProfit2?.Price <= lastCandle.High) else if (positionForSignal.TakeProfit2?.Price <= lastCandle.High)
{ {
await LogInformation($"Closing position - TP2 {positionForSignal.TakeProfit2.Price} <= Price {lastCandle.High}"); await LogInformation(
await CloseTrade(signal, positionForSignal, positionForSignal.TakeProfit2, positionForSignal.TakeProfit2.Price, true); $"Closing position - TP2 {positionForSignal.TakeProfit2.Price} <= Price {lastCandle.High}");
await CloseTrade(signal, positionForSignal, positionForSignal.TakeProfit2,
positionForSignal.TakeProfit2.Price, true);
positionForSignal.TakeProfit2.SetStatus(TradeStatus.Filled); positionForSignal.TakeProfit2.SetStatus(TradeStatus.Filled);
} }
else else
{ {
Logger.LogInformation($"Position {signal.Identifier} don't need to be update. Position still opened"); Logger.LogInformation(
$"Position {signal.Identifier} don't need to be update. Position still opened");
} }
} }
@@ -325,26 +342,33 @@ public class TradingBot : Bot, ITradingBot
{ {
if (positionForSignal.StopLoss.Price <= lastCandle.High) if (positionForSignal.StopLoss.Price <= lastCandle.High)
{ {
await LogInformation($"Closing position - SL {positionForSignal.StopLoss.Price} <= Price {lastCandle.High}"); await LogInformation(
await CloseTrade(signal, positionForSignal, positionForSignal.StopLoss, positionForSignal.StopLoss.Price, true); $"Closing position - SL {positionForSignal.StopLoss.Price} <= Price {lastCandle.High}");
await CloseTrade(signal, positionForSignal, positionForSignal.StopLoss,
positionForSignal.StopLoss.Price, true);
positionForSignal.StopLoss.SetStatus(TradeStatus.Filled); positionForSignal.StopLoss.SetStatus(TradeStatus.Filled);
} }
else if (positionForSignal.TakeProfit1.Price >= lastCandle.Low else if (positionForSignal.TakeProfit1.Price >= lastCandle.Low
&& positionForSignal.TakeProfit1.Status != TradeStatus.Filled) && positionForSignal.TakeProfit1.Status != TradeStatus.Filled)
{ {
await LogInformation($"Closing position - TP1 {positionForSignal.TakeProfit1.Price} >= Price {lastCandle.Low}"); await LogInformation(
await CloseTrade(signal, positionForSignal, positionForSignal.TakeProfit1, positionForSignal.TakeProfit1.Price, positionForSignal.TakeProfit2 == null); $"Closing position - TP1 {positionForSignal.TakeProfit1.Price} >= Price {lastCandle.Low}");
await CloseTrade(signal, positionForSignal, positionForSignal.TakeProfit1,
positionForSignal.TakeProfit1.Price, positionForSignal.TakeProfit2 == null);
positionForSignal.TakeProfit1.SetStatus(TradeStatus.Filled); positionForSignal.TakeProfit1.SetStatus(TradeStatus.Filled);
} }
else if (positionForSignal.TakeProfit2?.Price >= lastCandle.Low) else if (positionForSignal.TakeProfit2?.Price >= lastCandle.Low)
{ {
await LogInformation($"Closing position - TP2 {positionForSignal.TakeProfit2.Price} >= Price {lastCandle.Low}"); await LogInformation(
await CloseTrade(signal, positionForSignal, positionForSignal.TakeProfit2, positionForSignal.TakeProfit2.Price, true); $"Closing position - TP2 {positionForSignal.TakeProfit2.Price} >= Price {lastCandle.Low}");
await CloseTrade(signal, positionForSignal, positionForSignal.TakeProfit2,
positionForSignal.TakeProfit2.Price, true);
positionForSignal.TakeProfit2.SetStatus(TradeStatus.Filled); positionForSignal.TakeProfit2.SetStatus(TradeStatus.Filled);
} }
else else
{ {
Logger.LogInformation($"Position {signal.Identifier} don't need to be update. Position still opened"); Logger.LogInformation(
$"Position {signal.Identifier} don't need to be update. Position still opened");
} }
} }
} }
@@ -368,16 +392,17 @@ public class TradingBot : Bot, ITradingBot
} }
private async Task OpenPosition(Signal signal) private async Task OpenPosition(Signal signal)
{ {
// Check if a position is already open // Check if a position is already open
Logger.LogInformation($"Opening position for {signal.Identifier}"); Logger.LogInformation($"Opening position for {signal.Identifier}");
var openedPosition = Positions.FirstOrDefault(p => p.Status == PositionStatus.Filled var openedPosition = Positions.FirstOrDefault(p => p.Status == PositionStatus.Filled
&& p.SignalIdentifier != signal.Identifier); && p.SignalIdentifier != signal.Identifier);
var lastPrice = IsForBacktest ? Candles.Last().Close : ExchangeService.GetPrice(Account, Ticker, DateTime.UtcNow); var lastPrice = IsForBacktest
? Candles.Last().Close
: ExchangeService.GetPrice(Account, Ticker, DateTime.UtcNow);
// If position open // If position open
if (openedPosition != null) if (openedPosition != null)
@@ -388,7 +413,8 @@ public class TradingBot : Bot, ITradingBot
if (openedPosition.OriginDirection == signal.Direction) if (openedPosition.OriginDirection == signal.Direction)
{ {
// An operation is already open for the same direction // An operation is already open for the same direction
await LogInformation($"Signal {signal.Identifier} try to open a position but {previousSignal.Identifier} is already open for the same direction"); await LogInformation(
$"Signal {signal.Identifier} try to open a position but {previousSignal.Identifier} is already open for the same direction");
SetSignalStatus(signal.Identifier, SignalStatus.Expired); SetSignalStatus(signal.Identifier, SignalStatus.Expired);
} }
else else
@@ -401,11 +427,13 @@ public class TradingBot : Bot, ITradingBot
await CloseTrade(previousSignal, openedPosition, openedPosition.Open, lastPrice, true); await CloseTrade(previousSignal, openedPosition, openedPosition.Open, lastPrice, true);
await SetPositionStatus(previousSignal.Identifier, PositionStatus.Flipped); await SetPositionStatus(previousSignal.Identifier, PositionStatus.Flipped);
await OpenPosition(signal); await OpenPosition(signal);
await LogInformation($"Position {previousSignal.Identifier} flipped by {signal.Identifier} at {lastPrice}$"); await LogInformation(
$"Position {previousSignal.Identifier} flipped by {signal.Identifier} at {lastPrice}$");
} }
else else
{ {
await LogWarning($"A position is already open for signal {previousSignal.Identifier}. Position flipping is currently not enable, the position will not be flipped."); await LogWarning(
$"A position is already open for signal {previousSignal.Identifier}. Position flipping is currently not enable, the position will not be flipped.");
SetSignalStatus(signal.Identifier, SignalStatus.Expired); SetSignalStatus(signal.Identifier, SignalStatus.Expired);
} }
} }
@@ -414,12 +442,14 @@ public class TradingBot : Bot, ITradingBot
{ {
if (!CanOpenPosition(signal)) if (!CanOpenPosition(signal))
{ {
await LogInformation("Tried to open position but last position was a loss. Wait for an opposition direction side or wait x candles to open a new position"); await LogInformation(
"Tried to open position but last position was a loss. Wait for an opposition direction side or wait x candles to open a new position");
SetSignalStatus(signal.Identifier, SignalStatus.Expired); SetSignalStatus(signal.Identifier, SignalStatus.Expired);
return; return;
} }
await LogInformation($"Open position - Date: {signal.Date:T} - SignalIdentifier : {signal.Identifier} - Strategie : {signal.StrategyType}"); await LogInformation(
$"Open position - Date: {signal.Date:T} - SignalIdentifier : {signal.Identifier} - Strategie : {signal.StrategyType}");
try try
{ {
@@ -474,9 +504,9 @@ public class TradingBot : Bot, ITradingBot
return true; return true;
var lastPosition = Positions.LastOrDefault(p => p.IsFinished() var lastPosition = Positions.LastOrDefault(p => p.IsFinished()
&& p.SignalIdentifier != signal.Identifier && p.SignalIdentifier != signal.Identifier
&& p.ProfitAndLoss.Realized < 0 && p.ProfitAndLoss.Realized < 0
&& p.OriginDirection == signal.Direction); && p.OriginDirection == signal.Direction);
if (lastPosition == null) if (lastPosition == null)
return true; return true;
@@ -487,15 +517,18 @@ public class TradingBot : Bot, ITradingBot
return positionSignal.Date < tenCandleAgo.Date; return positionSignal.Date < tenCandleAgo.Date;
} }
private async Task CloseTrade(Signal signal, Position position, Trade tradeToClose, decimal lastPrice, bool tradeClosingPosition = false) private async Task CloseTrade(Signal signal, Position position, Trade tradeToClose, decimal lastPrice,
bool tradeClosingPosition = false)
{ {
if (position.TakeProfit2 != null && position.TakeProfit1.Status == TradeStatus.Filled && tradeToClose.TradeType == TradeType.StopMarket) if (position.TakeProfit2 != null && position.TakeProfit1.Status == TradeStatus.Filled &&
tradeToClose.TradeType == TradeType.StopMarket)
{ {
// If trade is the 2nd Take profit // If trade is the 2nd Take profit
tradeToClose.Quantity = position.TakeProfit2.Quantity; tradeToClose.Quantity = position.TakeProfit2.Quantity;
} }
await LogInformation($"Trying to close trade {Ticker} at {lastPrice} - Type : {tradeToClose.TradeType} - Quantity : {tradeToClose.Quantity} " + await LogInformation(
$"Trying to close trade {Ticker} at {lastPrice} - Type : {tradeToClose.TradeType} - Quantity : {tradeToClose.Quantity} " +
$"- Closing Position : {tradeClosingPosition}"); $"- Closing Position : {tradeClosingPosition}");
// Get status of position before closing it. The position might be already close by the exchange // Get status of position before closing it. The position might be already close by the exchange
@@ -509,8 +542,9 @@ public class TradingBot : Bot, ITradingBot
var command = new ClosePositionCommand(position, lastPrice); var command = new ClosePositionCommand(position, lastPrice);
try try
{ {
var closedPosition = await (new ClosePositionCommandHandler(ExchangeService, AccountService, TradingService)) var closedPosition =
.Handle(command); await (new ClosePositionCommandHandler(ExchangeService, AccountService, TradingService))
.Handle(command);
if (closedPosition.Status == (PositionStatus.Finished | PositionStatus.Flipped)) if (closedPosition.Status == (PositionStatus.Finished | PositionStatus.Flipped))
{ {
@@ -536,7 +570,6 @@ public class TradingBot : Bot, ITradingBot
await SetPositionStatus(signal.Identifier, PositionStatus.Finished); await SetPositionStatus(signal.Identifier, PositionStatus.Finished);
} }
} }
} }
} }
@@ -549,7 +582,8 @@ public class TradingBot : Bot, ITradingBot
position.SignalIdentifier = previousPosition.SignalIdentifier; position.SignalIdentifier = previousPosition.SignalIdentifier;
Positions[positionIndex] = position; Positions[positionIndex] = position;
SetSignalStatus(position.SignalIdentifier, SignalStatus.Expired); SetSignalStatus(position.SignalIdentifier, SignalStatus.Expired);
Logger.LogInformation($"Position {position.SignalIdentifier} type correctly close. Pnl on position : {position.ProfitAndLoss.Realized}"); Logger.LogInformation(
$"Position {position.SignalIdentifier} type correctly close. Pnl on position : {position.ProfitAndLoss.Realized}");
} }
else else
{ {
@@ -689,6 +723,12 @@ public class TradingBot : Bot, ITradingBot
Signals = data.Signals; Signals = data.Signals;
Positions = data.Positions; Positions = data.Positions;
WalletBalances = data.WalletBalances; WalletBalances = data.WalletBalances;
MoneyManagement = data.MoneyManagement;
Timeframe = data.Timeframe;
Ticker = data.Ticker;
Scenario = data.Scenario;
AccountName = data.AccountName;
IsForWatchingOnly = data.IsForWatchingOnly;
} }
} }

View File

@@ -1,23 +1,31 @@
using Managing.Application.Abstractions; using Managing.Application.Abstractions;
using Managing.Application.Bots; using Managing.Application.Bots;
using Managing.Common; using Managing.Common;
using Managing.Core;
using Managing.Domain.Bots;
using Newtonsoft.Json;
namespace Managing.Application.ManageBot namespace Managing.Application.ManageBot
{ {
public class BotService : IBotService public class BotService : IBotService
{ {
private readonly IBotRepository _botRepository; private readonly IBotRepository _botRepository;
private readonly ITaskCache _taskCache;
private readonly IBotFactory _botFactory;
public BotService(IBotRepository botRepository) public BotService(IBotRepository botRepository, ITaskCache taskCache, IBotFactory botFactory)
{ {
_botRepository = botRepository; _botRepository = botRepository;
_taskCache = taskCache;
_botFactory = botFactory;
} }
public async void SaveBotBackup(BotBackup botBackup) public async void SaveBotBackup(BotBackup botBackup)
{ {
await _botRepository.InsertBotAsync(botBackup); await _botRepository.InsertBotAsync(botBackup);
} }
public BotBackup GetBotBackup(string name) public BotBackup GetBotBackup(string name)
{ {
return _botRepository.GetBots().FirstOrDefault(b => b.Name == name); return _botRepository.GetBots().FirstOrDefault(b => b.Name == name);
@@ -26,14 +34,14 @@ namespace Managing.Application.ManageBot
public void SaveBotBackup(string name, Enums.BotType botType, string data) public void SaveBotBackup(string name, Enums.BotType botType, string data)
{ {
var backup = GetBotBackup(name); var backup = GetBotBackup(name);
if (backup != null) if (backup != null)
{ {
backup.Data = data; backup.Data = data;
_botRepository.UpdateBackupBot(backup); _botRepository.UpdateBackupBot(backup);
return; return;
} }
var botBackup = new BotBackup var botBackup = new BotBackup
{ {
Name = name, Name = name,
@@ -43,5 +51,70 @@ namespace Managing.Application.ManageBot
_botRepository.InsertBotAsync(botBackup); _botRepository.InsertBotAsync(botBackup);
} }
public void AddSimpleBotToCache(IBot bot)
{
_taskCache.AddOrGetExisting(bot.GetName(), () => Task.FromResult(bot));
}
public void AddTradingBotToCache(ITradingBot bot)
{
_taskCache.AddOrGetExisting(bot.GetName(), () => Task.FromResult(bot));
}
public List<ITradingBot> GetActiveBots()
{
var cachedTask = _taskCache.GetCache<AsyncLazy<ITradingBot>>();
return cachedTask.Select(item => item.Value.Result).ToList();
}
public IEnumerable<BotBackup> GetSavedBots()
{
return _botRepository.GetBots();
}
public void StartBot(BotBackup backupBot)
{
switch (backupBot.BotType)
{
case Enums.BotType.SimpleBot:
Func<Task<IBot>> simpleBot = () =>
Task.FromResult(_botFactory.CreateSimpleBot(backupBot.Name, null));
var bot1 = _taskCache.AddOrGetExisting(backupBot.Name, simpleBot).Result;
bot1.LoadBackup(backupBot);
bot1.Start();
break;
case Enums.BotType.ScalpingBot:
var data = JsonConvert.DeserializeObject<TradingBotBackup>(backupBot.Data);
Func<Task<ITradingBot>> scalpingBot = () => Task.FromResult(_botFactory.CreateScalpingBot(
data.AccountName,
data.MoneyManagement,
data.Name,
data.Ticker,
data.Scenario,
data.Timeframe,
data.IsForWatchingOnly));
var bot2 = _taskCache.AddOrGetExisting(backupBot.Name, scalpingBot).Result;
bot2.LoadBackup(backupBot);
bot2.Start();
break;
case Enums.BotType.FlippingBot:
var dataFlippingBot = JsonConvert.DeserializeObject<TradingBotBackup>(backupBot.Data);
Func<Task<ITradingBot>> flippingBot = () => Task.FromResult(_botFactory.CreateFlippingBot(
dataFlippingBot.AccountName,
dataFlippingBot.MoneyManagement,
dataFlippingBot.Name,
dataFlippingBot.Ticker,
dataFlippingBot.Scenario,
dataFlippingBot.Timeframe,
dataFlippingBot.IsForWatchingOnly));
var bot3 = _taskCache.AddOrGetExisting(backupBot.Name, flippingBot).Result;
bot3.LoadBackup(backupBot);
bot3.Start();
break;
}
;
}
} }
} }

View File

@@ -1,30 +1,15 @@
using Managing.Application.Abstractions; using Managing.Application.Abstractions;
using Managing.Application.ManageBot.Commands; using Managing.Application.ManageBot.Commands;
using Managing.Core;
using MediatR; using MediatR;
namespace Managing.Application.ManageBot namespace Managing.Application.ManageBot
{ {
public class GetActiveBotsCommandHandler : IRequestHandler<GetActiveBotsCommand, List<ITradingBot>> public class GetActiveBotsCommandHandler(IBotService botService)
: IRequestHandler<GetActiveBotsCommand, List<ITradingBot>>
{ {
private readonly ITaskCache taskCache;
public GetActiveBotsCommandHandler(ITaskCache taskCache)
{
this.taskCache = taskCache;
}
public Task<List<ITradingBot>> Handle(GetActiveBotsCommand request, CancellationToken cancellationToken) public Task<List<ITradingBot>> Handle(GetActiveBotsCommand request, CancellationToken cancellationToken)
{ {
var cachedTask = taskCache.GetCache<AsyncLazy<ITradingBot>>(); return Task.FromResult(botService.GetActiveBots());
var result = new List<ITradingBot>();
foreach (var item in cachedTask)
{
result.Add(item.Value.Result);
}
return Task.FromResult(result);
} }
} }
} }

View File

@@ -11,30 +11,21 @@ namespace Managing.Application.ManageBot;
public class LoadBackupBotCommandHandler : IRequestHandler<LoadBackupBotCommand, string> public class LoadBackupBotCommandHandler : IRequestHandler<LoadBackupBotCommand, string>
{ {
private readonly IBotFactory _botFactory; private readonly IBotService _botService;
private readonly ITaskCache _taskCache;
private readonly IMoneyManagementService _moneyManagementService;
private readonly IBotRepository _botRepository;
private readonly ILogger<LoadBackupBotCommandHandler> _logger; private readonly ILogger<LoadBackupBotCommandHandler> _logger;
public LoadBackupBotCommandHandler( public LoadBackupBotCommandHandler(
IBotFactory botFactory, ILogger<LoadBackupBotCommandHandler> logger, IBotService botService)
ITaskCache taskCache,
IMoneyManagementService moneyManagementService,
IBotRepository botRepository,
ILogger<LoadBackupBotCommandHandler> logger)
{ {
_botFactory = botFactory;
_taskCache = taskCache;
_moneyManagementService = moneyManagementService;
_botRepository = botRepository;
_logger = logger; _logger = logger;
_botService = botService;
} }
public Task<string> Handle(LoadBackupBotCommand request, CancellationToken cancellationToken) public Task<string> Handle(LoadBackupBotCommand request, CancellationToken cancellationToken)
{ {
BotStatus botStatus = BotStatus.Down; BotStatus botStatus = BotStatus.Down;
var backupBots = _botRepository.GetBots(); var backupBots = _botService.GetSavedBots();
var activeBots = _botService.GetActiveBots();
var result = new Dictionary<string, BotStatus>(); var result = new Dictionary<string, BotStatus>();
_logger.LogInformation($"Loading {backupBots.Count()} backup bots"); _logger.LogInformation($"Loading {backupBots.Count()} backup bots");
@@ -47,12 +38,11 @@ public class LoadBackupBotCommandHandler : IRequestHandler<LoadBackupBotCommand,
switch (backupBot.BotType) switch (backupBot.BotType)
{ {
case BotType.SimpleBot: case BotType.SimpleBot:
var simpleBot = _taskCache.Get<IBot>(backupBot.Name); var simpleBot = activeBots.FirstOrDefault(b => b.GetName() == backupBot.Name);
if (simpleBot == null) if (simpleBot == null)
{ {
_logger.LogInformation($"Starting backup bot {backupBot.Name}"); _logger.LogInformation($"Starting backup bot {backupBot.Name}");
StartBot(backupBot); _botService.StartBot(backupBot);
simpleBot.LoadBackup(backupBot);
result.Add(simpleBot.GetName(), BotStatus.Backup); result.Add(simpleBot.GetName(), BotStatus.Backup);
} }
else else
@@ -63,19 +53,18 @@ public class LoadBackupBotCommandHandler : IRequestHandler<LoadBackupBotCommand,
break; break;
case BotType.ScalpingBot: case BotType.ScalpingBot:
case BotType.FlippingBot: case BotType.FlippingBot:
var scalpingBot = _taskCache.Get<ITradingBot>(backupBot.Name); var scalpingBot = activeBots.FirstOrDefault(b => b.GetName() == backupBot.Name);
if (scalpingBot == null) if (scalpingBot == null)
{ {
_logger.LogInformation($"Starting backup bot {backupBot.Name}"); _logger.LogInformation($"Starting backup bot {backupBot.Name}");
StartBot(backupBot); _botService.StartBot(backupBot);
scalpingBot = _taskCache.Get<ITradingBot>(backupBot.Name);
scalpingBot.LoadBackup(backupBot);
result.Add(scalpingBot.GetName(), BotStatus.Backup);
} }
else else
{ {
result.Add(scalpingBot.GetName(), MiscExtensions.ParseEnum<BotStatus>(scalpingBot.GetStatus())); result.Add(scalpingBot.GetName(),
MiscExtensions.ParseEnum<BotStatus>(scalpingBot.GetStatus()));
} }
break; break;
default: default:
result.Add(backupBot.Name, BotStatus.Down); result.Add(backupBot.Name, BotStatus.Down);
@@ -91,47 +80,6 @@ public class LoadBackupBotCommandHandler : IRequestHandler<LoadBackupBotCommand,
return Task.FromResult(botStatus.ToString()); return Task.FromResult(botStatus.ToString());
} }
private void StartBot(BotBackup backupBot)
{
switch (backupBot.BotType)
{
case BotType.SimpleBot:
Func<Task<IBot>> simpleBot = () => Task.FromResult(_botFactory.CreateSimpleBot(backupBot.Name, null));
var bot1 = _taskCache.AddOrGetExisting(backupBot.Name, simpleBot).Result;
bot1.LoadBackup(backupBot);
bot1.Start();
break;
case BotType.ScalpingBot:
var data = JsonConvert.DeserializeObject<TradingBotBackup>(backupBot.Data);
Func<Task<ITradingBot>> scalpingBot = () => Task.FromResult(_botFactory.CreateScalpingBot(
data.AccountName,
data.MoneyManagement,
data.Name,
data.Ticker,
data.Scenario,
data.Timeframe,
data.IsForWatchingOnly));
var bot2 = _taskCache.AddOrGetExisting(backupBot.Name, scalpingBot).Result;
bot2.LoadBackup(backupBot);
bot2.Start();
break;
case BotType.FlippingBot:
var dataFlippingBot = JsonConvert.DeserializeObject<TradingBotBackup>(backupBot.Data);
Func<Task<ITradingBot>> flippingBot = () => Task.FromResult(_botFactory.CreateFlippingBot(
dataFlippingBot.AccountName,
dataFlippingBot.MoneyManagement,
dataFlippingBot.Name,
dataFlippingBot.Ticker,
dataFlippingBot.Scenario,
dataFlippingBot.Timeframe,
dataFlippingBot.IsForWatchingOnly));
var bot3 = _taskCache.AddOrGetExisting(backupBot.Name, flippingBot).Result;
bot3.LoadBackup(backupBot);
bot3.Start();
break;
};
}
} }
public class LoadBackupBotCommand : IRequest<string> public class LoadBackupBotCommand : IRequest<string>

View File

@@ -9,13 +9,14 @@ namespace Managing.Application.ManageBot
public class StartBotCommandHandler : IRequestHandler<StartBotCommand, string> public class StartBotCommandHandler : IRequestHandler<StartBotCommand, string>
{ {
private readonly IBotFactory _botFactory; private readonly IBotFactory _botFactory;
private readonly ITaskCache _taskCache; private readonly IBotService _botService;
private readonly IMoneyManagementService _moneyManagementService; private readonly IMoneyManagementService _moneyManagementService;
public StartBotCommandHandler(IBotFactory botFactory, ITaskCache taskCache, IMoneyManagementService moneyManagementService) public StartBotCommandHandler(IBotFactory botFactory, IBotService botService,
IMoneyManagementService moneyManagementService)
{ {
_botFactory = botFactory; _botFactory = botFactory;
_taskCache = taskCache; _botService = botService;
_moneyManagementService = moneyManagementService; _moneyManagementService = moneyManagementService;
} }
@@ -28,21 +29,25 @@ namespace Managing.Application.ManageBot
case BotType.SimpleBot: case BotType.SimpleBot:
var bot = _botFactory.CreateSimpleBot(request.Name, null); var bot = _botFactory.CreateSimpleBot(request.Name, null);
bot.Start(); bot.Start();
Func<Task<IBot>> simpleBot = () => Task.FromResult(bot); _botService.AddSimpleBotToCache(bot);
return Task.FromResult(_taskCache.AddOrGetExisting(request.Name, simpleBot).Result.GetStatus()); return Task.FromResult(bot.GetStatus());
case BotType.ScalpingBot: case BotType.ScalpingBot:
var sBot = _botFactory.CreateScalpingBot(request.AccountName, moneyManagement, request.Name, request.Ticker, request.Scenario, request.Timeframe, request.IsForWatchingOnly); var sBot = _botFactory.CreateScalpingBot(request.AccountName, moneyManagement, request.Name,
request.Ticker, request.Scenario, request.Timeframe, request.IsForWatchingOnly);
sBot.Start(); sBot.Start();
Func<Task<ITradingBot>> scalpingBot = () => Task.FromResult(sBot); _botService.AddTradingBotToCache(sBot);
return Task.FromResult(_taskCache.AddOrGetExisting(request.Name, scalpingBot).Result.GetStatus()); return Task.FromResult(sBot.GetStatus());
case BotType.FlippingBot: case BotType.FlippingBot:
var fBot = _botFactory.CreateFlippingBot(request.AccountName, moneyManagement, request.Name, request.Ticker, request.Scenario, request.Timeframe, request.IsForWatchingOnly); var fBot = _botFactory.CreateFlippingBot(request.AccountName, moneyManagement, request.Name,
request.Ticker, request.Scenario, request.Timeframe, request.IsForWatchingOnly);
fBot.Start(); fBot.Start();
Func<Task<ITradingBot>> flippingBot = () => Task.FromResult(fBot); _botService.AddTradingBotToCache(fBot);
return Task.FromResult(_taskCache.AddOrGetExisting(request.Name, flippingBot).Result.GetStatus()); return Task.FromResult(fBot.GetStatus());
}; }
;
return Task.FromResult(botStatus.ToString()); return Task.FromResult(botStatus.ToString());
} }
} }
} }