|
|
|
|
@@ -2,6 +2,7 @@
|
|
|
|
|
using Managing.Application.Abstractions.Services;
|
|
|
|
|
using Managing.Application.Trading;
|
|
|
|
|
using Managing.Application.Trading.Commands;
|
|
|
|
|
using Managing.Core.FixedSizedQueue;
|
|
|
|
|
using Managing.Domain.Accounts;
|
|
|
|
|
using Managing.Domain.Bots;
|
|
|
|
|
using Managing.Domain.Candles;
|
|
|
|
|
@@ -27,6 +28,7 @@ public class TradingBot : Bot, ITradingBot
|
|
|
|
|
|
|
|
|
|
public Account Account { get; set; }
|
|
|
|
|
public HashSet<IStrategy> Strategies { get; set; }
|
|
|
|
|
public FixedSizeQueue<Candle> OptimizedCandles { get; set; }
|
|
|
|
|
public HashSet<Candle> Candles { get; set; }
|
|
|
|
|
public HashSet<Signal> Signals { get; set; }
|
|
|
|
|
public List<Position> Positions { get; set; }
|
|
|
|
|
@@ -80,6 +82,7 @@ public class TradingBot : Bot, ITradingBot
|
|
|
|
|
|
|
|
|
|
Strategies = new HashSet<IStrategy>();
|
|
|
|
|
Signals = new HashSet<Signal>();
|
|
|
|
|
OptimizedCandles = new FixedSizeQueue<Candle>(600);
|
|
|
|
|
Candles = new HashSet<Candle>();
|
|
|
|
|
Positions = new List<Position>();
|
|
|
|
|
WalletBalances = new Dictionary<DateTime, decimal>();
|
|
|
|
|
@@ -160,13 +163,13 @@ public class TradingBot : Bot, ITradingBot
|
|
|
|
|
Logger.LogInformation(
|
|
|
|
|
$"Time : {DateTime.Now} - Server time {DateTime.Now.ToUniversalTime()} - Bot : {Name} - Type {BotType} - Ticker : {Ticker}");
|
|
|
|
|
|
|
|
|
|
var previousCandleCount = Candles.Count;
|
|
|
|
|
var previousCandleCount = OptimizedCandles.Count;
|
|
|
|
|
|
|
|
|
|
if (!IsForBacktest)
|
|
|
|
|
await UpdateCandles();
|
|
|
|
|
|
|
|
|
|
if (Candles.Count > previousCandleCount || IsForBacktest)
|
|
|
|
|
await UpdateSignals(Candles);
|
|
|
|
|
if (OptimizedCandles.Count > previousCandleCount || IsForBacktest)
|
|
|
|
|
await UpdateSignals(OptimizedCandles);
|
|
|
|
|
else
|
|
|
|
|
Logger.LogInformation($"No need to update signals for {Ticker}");
|
|
|
|
|
|
|
|
|
|
@@ -177,35 +180,38 @@ public class TradingBot : Bot, ITradingBot
|
|
|
|
|
SaveBackup();
|
|
|
|
|
|
|
|
|
|
await UpdateWalletBalances();
|
|
|
|
|
Logger.LogInformation($"Candles : {Candles.Count}");
|
|
|
|
|
Logger.LogInformation($"Signals : {Signals.Count}");
|
|
|
|
|
Logger.LogInformation($"ExecutionCount : {ExecutionCount}");
|
|
|
|
|
Logger.LogInformation($"Positions : {Positions.Count}");
|
|
|
|
|
Logger.LogInformation("__________________________________________________");
|
|
|
|
|
if (OptimizedCandles.Count % 100 == 0) // Log every 10th execution
|
|
|
|
|
{
|
|
|
|
|
Logger.LogInformation($"Candle date : {OptimizedCandles.Last().Date:u}");
|
|
|
|
|
Logger.LogInformation($"Signals : {Signals.Count}");
|
|
|
|
|
Logger.LogInformation($"ExecutionCount : {ExecutionCount}");
|
|
|
|
|
Logger.LogInformation($"Positions : {Positions.Count}");
|
|
|
|
|
Logger.LogInformation("__________________________________________________");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task PreloadCandles()
|
|
|
|
|
{
|
|
|
|
|
if (Candles.Any())
|
|
|
|
|
if (OptimizedCandles.Any())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var candles = await ExchangeService.GetCandlesInflux(Account.Exchange, Ticker, PreloadSince, Timeframe);
|
|
|
|
|
|
|
|
|
|
foreach (var candle in candles.Where(c => c.Date < DateTime.Now.ToUniversalTime()))
|
|
|
|
|
{
|
|
|
|
|
if (!Candles.Any(c => c.Date == candle.Date))
|
|
|
|
|
if (!OptimizedCandles.Any(c => c.Date == candle.Date))
|
|
|
|
|
{
|
|
|
|
|
Candles.Add(candle);
|
|
|
|
|
await UpdateSignals(Candles);
|
|
|
|
|
OptimizedCandles.Enqueue(candle);
|
|
|
|
|
await UpdateSignals(OptimizedCandles);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PreloadedCandlesCount = Candles.Count();
|
|
|
|
|
PreloadedCandlesCount = OptimizedCandles.Count();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task UpdateSignals(HashSet<Candle> candles)
|
|
|
|
|
private async Task UpdateSignals(FixedSizeQueue<Candle> candles)
|
|
|
|
|
{
|
|
|
|
|
var signal = TradingBox.GetSignal(candles, Strategies, Signals);
|
|
|
|
|
var signal = TradingBox.GetSignal(candles.ToHashSet(), Strategies, Signals);
|
|
|
|
|
|
|
|
|
|
if (signal == null) return;
|
|
|
|
|
|
|
|
|
|
@@ -236,15 +242,15 @@ public class TradingBot : Bot, ITradingBot
|
|
|
|
|
|
|
|
|
|
protected async Task UpdateCandles()
|
|
|
|
|
{
|
|
|
|
|
if (Candles.Count == 0 || ExecutionCount == 0)
|
|
|
|
|
if (OptimizedCandles.Count == 0 || ExecutionCount == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var lastCandle = Candles.Last();
|
|
|
|
|
var lastCandle = OptimizedCandles.Last();
|
|
|
|
|
var newCandle = await ExchangeService.GetCandlesInflux(Account.Exchange, Ticker, lastCandle.Date, Timeframe);
|
|
|
|
|
|
|
|
|
|
foreach (var candle in newCandle.Where(c => c.Date < DateTime.Now.ToUniversalTime()))
|
|
|
|
|
{
|
|
|
|
|
Candles.Add(candle);
|
|
|
|
|
OptimizedCandles.Enqueue(candle);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -269,17 +275,25 @@ public class TradingBot : Bot, ITradingBot
|
|
|
|
|
|
|
|
|
|
private async Task UpdateWalletBalances()
|
|
|
|
|
{
|
|
|
|
|
var lastCandle = OptimizedCandles.LastOrDefault();
|
|
|
|
|
if (lastCandle == null) return;
|
|
|
|
|
|
|
|
|
|
var date = lastCandle.Date;
|
|
|
|
|
|
|
|
|
|
if (WalletBalances.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
WalletBalances.Add(Candles.LastOrDefault().Date, await ExchangeService.GetBalance(Account, IsForBacktest));
|
|
|
|
|
WalletBalances[date] = await ExchangeService.GetBalance(Account, IsForBacktest);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if (!WalletBalances.Any(w => w.Key == Candles.LastOrDefault().Date))
|
|
|
|
|
|
|
|
|
|
if (!WalletBalances.ContainsKey(date))
|
|
|
|
|
{
|
|
|
|
|
var walletBalance = WalletBalances.FirstOrDefault().Value + GetProfitAndLoss();
|
|
|
|
|
WalletBalances.Add(Candles.LastOrDefault().Date, walletBalance);
|
|
|
|
|
var previousBalance = WalletBalances.First().Value;
|
|
|
|
|
WalletBalances[date] = previousBalance + GetProfitAndLoss();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private async Task UpdatePosition(Signal signal, Position positionForSignal)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
@@ -293,7 +307,6 @@ public class TradingBot : Bot, ITradingBot
|
|
|
|
|
if (position.Status == (PositionStatus.Finished | PositionStatus.Flipped))
|
|
|
|
|
{
|
|
|
|
|
await HandleClosedPosition(positionForSignal);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if (position.Status == PositionStatus.Filled)
|
|
|
|
|
{
|
|
|
|
|
@@ -301,7 +314,7 @@ public class TradingBot : Bot, ITradingBot
|
|
|
|
|
// check if position is still open
|
|
|
|
|
// Check status, if still open update the status of the position
|
|
|
|
|
var lastCandle = IsForBacktest
|
|
|
|
|
? Candles.Last()
|
|
|
|
|
? OptimizedCandles.Last()
|
|
|
|
|
: ExchangeService.GetCandle(Account, Ticker, DateTime.UtcNow);
|
|
|
|
|
|
|
|
|
|
if (positionForSignal.OriginDirection == TradeDirection.Long)
|
|
|
|
|
@@ -401,7 +414,7 @@ public class TradingBot : Bot, ITradingBot
|
|
|
|
|
&& p.SignalIdentifier != signal.Identifier);
|
|
|
|
|
|
|
|
|
|
var lastPrice = IsForBacktest
|
|
|
|
|
? Candles.Last().Close
|
|
|
|
|
? OptimizedCandles.Last().Close
|
|
|
|
|
: ExchangeService.GetPrice(Account, Ticker, DateTime.UtcNow);
|
|
|
|
|
|
|
|
|
|
// If position open
|
|
|
|
|
@@ -511,7 +524,7 @@ public class TradingBot : Bot, ITradingBot
|
|
|
|
|
if (lastPosition == null)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
var tenCandleAgo = Candles.TakeLast(10).First();
|
|
|
|
|
var tenCandleAgo = OptimizedCandles.TakeLast(10).First();
|
|
|
|
|
var positionSignal = Signals.FirstOrDefault(s => s.Identifier == lastPosition.SignalIdentifier);
|
|
|
|
|
|
|
|
|
|
return positionSignal.Date < tenCandleAgo.Date;
|
|
|
|
|
@@ -543,8 +556,8 @@ public class TradingBot : Bot, ITradingBot
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var closedPosition =
|
|
|
|
|
await (new ClosePositionCommandHandler(ExchangeService, AccountService, TradingService))
|
|
|
|
|
.Handle(command);
|
|
|
|
|
(new ClosePositionCommandHandler(ExchangeService, AccountService, TradingService)
|
|
|
|
|
.Handle(command)).Result;
|
|
|
|
|
|
|
|
|
|
if (closedPosition.Status == (PositionStatus.Finished | PositionStatus.Flipped))
|
|
|
|
|
{
|
|
|
|
|
|