GMX v2 - Trading (#7)
* Move PrivateKeys.cs * Update gitignore * Update gitignore * updt * Extract GmxServiceTests.cs * Refact * update todo * Update code * Fix hashdata * Replace static token hashed datas * Set allowance * Add get orders * Add get orders tests * Add ignore * add close orders * revert * Add get gas limit * Start increasePosition. Todo: Finish GetExecutionFee and estimateGas * little refact * Update gitignore * Fix namespaces and clean repo * Add tests samples * Add execution fee * Add increase position * Handle backtest on the frontend * Add tests * Update increase * Test increase * fix increase * Fix size * Start get position * Update get positions * Fix get position * Update rpc and trade mappers * Finish close position * Fix leverage
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using Managing.Application.Abstractions;
|
||||
using Managing.Application.Abstractions.Repositories;
|
||||
using Managing.Application.Abstractions.Services;
|
||||
using Managing.Core;
|
||||
using Managing.Domain.Accounts;
|
||||
@@ -40,11 +41,11 @@ namespace Managing.Application.Backtesting
|
||||
{
|
||||
_backtestRepository.InsertBacktest(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Backtest RunScalpingBotBacktest(
|
||||
Account account,
|
||||
public Backtest RunScalpingBotBacktest(Account account,
|
||||
MoneyManagement moneyManagement,
|
||||
Ticker ticker,
|
||||
Scenario scenario,
|
||||
@@ -52,22 +53,27 @@ namespace Managing.Application.Backtesting
|
||||
double days,
|
||||
decimal balance,
|
||||
bool isForWatchingOnly = false,
|
||||
bool save = false)
|
||||
bool save = false,
|
||||
List<Candle> initialCandles = null)
|
||||
{
|
||||
var scalpingBot = _botFactory.CreateBacktestScalpingBot(account.Name, moneyManagement, ticker, "scenario", timeframe, isForWatchingOnly);
|
||||
var scalpingBot = _botFactory.CreateBacktestScalpingBot(account.Name, moneyManagement, ticker, "scenario",
|
||||
timeframe, isForWatchingOnly);
|
||||
scalpingBot.LoadStrategies(ScenarioHelpers.GetStrategiesFromScenario(scenario));
|
||||
var candles = GetCandles(account, ticker, timeframe, days);
|
||||
var result = GetBacktestingResult(ticker, scenario, timeframe, scalpingBot, candles, balance, account, moneyManagement);
|
||||
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;
|
||||
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}");
|
||||
@@ -75,35 +81,46 @@ namespace Managing.Application.Backtesting
|
||||
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)
|
||||
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);
|
||||
var flippingBot = _botFactory.CreateBacktestFlippingBot(account.Name, moneyManagement, ticker, "scenario",
|
||||
timeframe, false);
|
||||
var strategy = ScenarioHelpers.GetStrategiesFromScenario(scenario);
|
||||
flippingBot.LoadStrategies(ScenarioHelpers.GetStrategiesFromScenario(scenario));
|
||||
var candles = GetCandles(account, ticker, timeframe, days);
|
||||
var result = GetBacktestingResult(ticker, scenario, timeframe, flippingBot, candles, balance, account, moneyManagement);
|
||||
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)
|
||||
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);
|
||||
var bot = _botFactory.CreateBacktestScalpingBot(account.Name, moneyManagement, ticker, "scenario",
|
||||
timeframe, false);
|
||||
bot.LoadStrategies(ScenarioHelpers.GetStrategiesFromScenario(scenario));
|
||||
var result = GetBacktestingResult(ticker, scenario, timeframe, bot, candles, balance, account, moneyManagement);
|
||||
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)
|
||||
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);
|
||||
var result = GetBacktestingResult(ticker, scenario, timeframe, bot, candles, balance, account, moneyManagement);
|
||||
var bot = _botFactory.CreateBacktestFlippingBot(account.Name, moneyManagement, ticker, "scenario",
|
||||
timeframe, false);
|
||||
var result = GetBacktestingResult(ticker, scenario, timeframe, bot, candles, balance, account,
|
||||
moneyManagement);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -137,7 +154,8 @@ namespace Managing.Application.Backtesting
|
||||
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)
|
||||
var result = new Backtest(ticker, scenario.Name, bot.Positions, bot.Signals.ToList(), timeframe, candles,
|
||||
bot.BotType, account.Name)
|
||||
{
|
||||
FinalPnl = finalPnl,
|
||||
WinRate = winRate,
|
||||
@@ -154,7 +172,6 @@ namespace Managing.Application.Backtesting
|
||||
}
|
||||
|
||||
|
||||
|
||||
public IEnumerable<Backtest> GetBacktests()
|
||||
{
|
||||
return _backtestRepository.GetBacktests();
|
||||
@@ -189,4 +206,4 @@ namespace Managing.Application.Backtesting
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Concurrent;
|
||||
using Managing.Application.Abstractions;
|
||||
using Managing.Application.Abstractions.Repositories;
|
||||
using Managing.Application.Abstractions.Services;
|
||||
using Managing.Application.Bots;
|
||||
using Managing.Common;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Managing.Application.Abstractions;
|
||||
using Managing.Application.Abstractions.Services;
|
||||
using Managing.Domain.MoneyManagements;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using static Managing.Common.Enums;
|
||||
@@ -13,9 +14,9 @@ public class SettingsService : ISettingsService
|
||||
private readonly ILogger<SettingsService> _logger;
|
||||
|
||||
public SettingsService(IMoneyManagementService moneyManagementService,
|
||||
IScenarioService scenarioService,
|
||||
IBacktester backtester,
|
||||
ILogger<SettingsService> logger)
|
||||
IScenarioService scenarioService,
|
||||
IBacktester backtester,
|
||||
ILogger<SettingsService> logger)
|
||||
{
|
||||
_moneyManagementService = moneyManagementService;
|
||||
_scenarioService = scenarioService;
|
||||
@@ -68,6 +69,7 @@ public class SettingsService : ISettingsService
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -94,7 +96,7 @@ public class SettingsService : ISettingsService
|
||||
SetupSuperTrend(timeframe);
|
||||
SetupChandelierExit(timeframe);
|
||||
SetupStochRsiTrend(timeframe);
|
||||
SetupStochSTCTrend(timeframe);
|
||||
SetupStochSTCTrend(timeframe);
|
||||
SetupEmaTrend(timeframe);
|
||||
SetupEmaCross(timeframe);
|
||||
}
|
||||
@@ -103,11 +105,11 @@ public class SettingsService : ISettingsService
|
||||
{
|
||||
var name = "STCTrend";
|
||||
var strategy = _scenarioService.CreateStrategy(StrategyType.Stc,
|
||||
timeframe,
|
||||
name,
|
||||
fastPeriods: 23,
|
||||
slowPeriods: 50,
|
||||
cyclePeriods: 10);
|
||||
timeframe,
|
||||
name,
|
||||
fastPeriods: 23,
|
||||
slowPeriods: 50,
|
||||
cyclePeriods: 10);
|
||||
_scenarioService.CreateScenario(name, new List<string> { strategy.Name });
|
||||
}
|
||||
|
||||
@@ -115,11 +117,11 @@ public class SettingsService : ISettingsService
|
||||
{
|
||||
var name = "MacdCross";
|
||||
var strategy = _scenarioService.CreateStrategy(StrategyType.MacdCross,
|
||||
timeframe,
|
||||
name,
|
||||
fastPeriods: 12,
|
||||
slowPeriods: 26,
|
||||
signalPeriods: 9);
|
||||
timeframe,
|
||||
name,
|
||||
fastPeriods: 12,
|
||||
slowPeriods: 26,
|
||||
signalPeriods: 9);
|
||||
_scenarioService.CreateScenario(name, new List<string> { strategy.Name });
|
||||
}
|
||||
|
||||
@@ -127,9 +129,9 @@ public class SettingsService : ISettingsService
|
||||
{
|
||||
var name = "RsiDiv6";
|
||||
var strategy = _scenarioService.CreateStrategy(StrategyType.RsiDivergence,
|
||||
timeframe,
|
||||
name,
|
||||
period: 6);
|
||||
timeframe,
|
||||
name,
|
||||
period: 6);
|
||||
_scenarioService.CreateScenario(name, new List<string> { strategy.Name });
|
||||
}
|
||||
|
||||
@@ -137,9 +139,9 @@ public class SettingsService : ISettingsService
|
||||
{
|
||||
var name = "RsiDivConfirm6";
|
||||
var strategy = _scenarioService.CreateStrategy(StrategyType.RsiDivergenceConfirm,
|
||||
timeframe,
|
||||
name,
|
||||
period: 6);
|
||||
timeframe,
|
||||
name,
|
||||
period: 6);
|
||||
_scenarioService.CreateScenario(name, new List<string> { strategy.Name });
|
||||
}
|
||||
|
||||
@@ -147,10 +149,10 @@ public class SettingsService : ISettingsService
|
||||
{
|
||||
var name = "SuperTrend";
|
||||
var strategy = _scenarioService.CreateStrategy(StrategyType.SuperTrend,
|
||||
timeframe,
|
||||
name,
|
||||
period: 10,
|
||||
multiplier: 3);
|
||||
timeframe,
|
||||
name,
|
||||
period: 10,
|
||||
multiplier: 3);
|
||||
_scenarioService.CreateScenario(name, new List<string> { strategy.Name });
|
||||
}
|
||||
|
||||
@@ -158,22 +160,23 @@ public class SettingsService : ISettingsService
|
||||
{
|
||||
var name = "ChandelierExit";
|
||||
var strategy = _scenarioService.CreateStrategy(StrategyType.ChandelierExit,
|
||||
timeframe,
|
||||
name,
|
||||
period: 22,
|
||||
multiplier: 3);
|
||||
timeframe,
|
||||
name,
|
||||
period: 22,
|
||||
multiplier: 3);
|
||||
_scenarioService.CreateScenario(name, new List<string> { strategy.Name });
|
||||
}
|
||||
|
||||
private void SetupStochRsiTrend(Timeframe timeframe)
|
||||
{
|
||||
var name = "StochRsiTrend";
|
||||
var strategy = _scenarioService.CreateStrategy(StrategyType.StochRsiTrend,
|
||||
timeframe,
|
||||
name,
|
||||
period: 14,
|
||||
stochPeriods: 14,
|
||||
signalPeriods: 3,
|
||||
smoothPeriods: 1);
|
||||
timeframe,
|
||||
name,
|
||||
period: 14,
|
||||
stochPeriods: 14,
|
||||
signalPeriods: 3,
|
||||
smoothPeriods: 1);
|
||||
_scenarioService.CreateScenario(name, new List<string> { strategy.Name });
|
||||
}
|
||||
|
||||
@@ -181,9 +184,9 @@ public class SettingsService : ISettingsService
|
||||
{
|
||||
var name = "Ema200Trend";
|
||||
var strategy = _scenarioService.CreateStrategy(StrategyType.EmaTrend,
|
||||
timeframe,
|
||||
name,
|
||||
period: 200);
|
||||
timeframe,
|
||||
name,
|
||||
period: 200);
|
||||
_scenarioService.CreateScenario(name, new List<string> { strategy.Name });
|
||||
}
|
||||
|
||||
@@ -191,9 +194,9 @@ public class SettingsService : ISettingsService
|
||||
{
|
||||
var name = "Ema200Cross";
|
||||
var strategy = _scenarioService.CreateStrategy(StrategyType.EmaCross,
|
||||
timeframe,
|
||||
name,
|
||||
period: 200);
|
||||
timeframe,
|
||||
name,
|
||||
period: 200);
|
||||
_scenarioService.CreateScenario(name, new List<string> { strategy.Name });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,49 +7,43 @@ using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Application.Trading;
|
||||
|
||||
public class ClosePositionCommandHandler : ICommandHandler<ClosePositionCommand, Position>
|
||||
public class ClosePositionCommandHandler(
|
||||
IExchangeService exchangeService,
|
||||
IAccountService accountService,
|
||||
ITradingService tradingService)
|
||||
: ICommandHandler<ClosePositionCommand, Position>
|
||||
{
|
||||
private readonly IExchangeService _exchangeService;
|
||||
private readonly IAccountService _accountService;
|
||||
private readonly ITradingService _tradingService;
|
||||
|
||||
public ClosePositionCommandHandler(
|
||||
IExchangeService exchangeService,
|
||||
IAccountService accountService,
|
||||
ITradingService tradingService)
|
||||
{
|
||||
_exchangeService = exchangeService;
|
||||
_accountService = accountService;
|
||||
_tradingService = tradingService;
|
||||
}
|
||||
|
||||
public async Task<Position> Handle(ClosePositionCommand request)
|
||||
{
|
||||
// Get Trade
|
||||
var account = await _accountService.GetAccount(request.Position.AccountName, false, false);
|
||||
var account = await accountService.GetAccount(request.Position.AccountName, false, false);
|
||||
if (request.Position == null)
|
||||
{
|
||||
_ = _exchangeService.CancelOrder(account, request.Position.Ticker).Result;
|
||||
_ = exchangeService.CancelOrder(account, request.Position.Ticker).Result;
|
||||
return request.Position;
|
||||
}
|
||||
|
||||
var isForPaperTrading = request.Position.Initiator == PositionInitiator.PaperTrading;
|
||||
|
||||
var lastPrice = request.Position.Initiator == PositionInitiator.PaperTrading ?
|
||||
request.ExecutionPrice.GetValueOrDefault() :
|
||||
_exchangeService.GetPrice(account, request.Position.Ticker, DateTime.UtcNow);
|
||||
var lastPrice = request.Position.Initiator == PositionInitiator.PaperTrading
|
||||
? request.ExecutionPrice.GetValueOrDefault()
|
||||
: exchangeService.GetPrice(account, request.Position.Ticker, DateTime.UtcNow);
|
||||
|
||||
// Close market
|
||||
var closedPosition = _exchangeService.ClosePosition(account, request.Position, lastPrice, isForPaperTrading).Result;
|
||||
var closeRequestedOrders = isForPaperTrading ? true : _exchangeService.CancelOrder(account, request.Position.Ticker).Result;
|
||||
var closedPosition =
|
||||
await exchangeService.ClosePosition(account, request.Position, lastPrice, isForPaperTrading);
|
||||
var closeRequestedOrders =
|
||||
isForPaperTrading || (await exchangeService.CancelOrder(account, request.Position.Ticker));
|
||||
|
||||
if (closeRequestedOrders || closedPosition.Status == (TradeStatus.PendingOpen | TradeStatus.Filled))
|
||||
{
|
||||
request.Position.Status = PositionStatus.Finished;
|
||||
request.Position.ProfitAndLoss = TradingBox.GetProfitAndLoss(request.Position, closedPosition.Quantity, lastPrice);
|
||||
_tradingService.UpdatePosition(request.Position);
|
||||
request.Position.ProfitAndLoss =
|
||||
TradingBox.GetProfitAndLoss(request.Position, closedPosition.Quantity, lastPrice,
|
||||
request.Position.Open.Leverage);
|
||||
tradingService.UpdatePosition(request.Position);
|
||||
}
|
||||
|
||||
return request.Position;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,33 +7,30 @@ using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Application.Trading
|
||||
{
|
||||
public class OpenPositionCommandHandler : ICommandHandler<OpenPositionRequest, Position>
|
||||
public class OpenPositionCommandHandler(
|
||||
IExchangeService exchangeService,
|
||||
IAccountService accountService,
|
||||
ITradingService tradingService)
|
||||
: ICommandHandler<OpenPositionRequest, Position>
|
||||
{
|
||||
private readonly IExchangeService _exchangeService;
|
||||
private readonly IAccountService _accountService;
|
||||
private readonly ITradingService _tradingService;
|
||||
|
||||
public OpenPositionCommandHandler(
|
||||
IExchangeService exchangeService,
|
||||
IAccountService accountService,
|
||||
ITradingService tradingService)
|
||||
public async Task<Position> Handle(OpenPositionRequest request)
|
||||
{
|
||||
_exchangeService = exchangeService;
|
||||
_accountService = accountService;
|
||||
_tradingService = tradingService;
|
||||
}
|
||||
|
||||
public Task<Position> Handle(OpenPositionRequest request)
|
||||
{
|
||||
var account = _accountService.GetAccount(request.AccountName, hideSecrets: false, getBalance: false).Result;
|
||||
if (!request.IsForPaperTrading && !_exchangeService.CancelOrder(account, request.Ticker).Result)
|
||||
var account = await accountService.GetAccount(request.AccountName, hideSecrets: false, getBalance: false);
|
||||
if (!request.IsForPaperTrading)
|
||||
{
|
||||
throw new Exception($"Not able to close all orders for {request.Ticker}");
|
||||
var cancelOrderResult = await exchangeService.CancelOrder(account, request.Ticker);
|
||||
if (!cancelOrderResult)
|
||||
{
|
||||
throw new Exception($"Not able to close all orders for {request.Ticker}");
|
||||
}
|
||||
}
|
||||
|
||||
var initiator = request.IsForPaperTrading ? PositionInitiator.PaperTrading : request.Initiator;
|
||||
var position = new Position(request.AccountName, request.Direction, request.Ticker, request.MoneyManagement, initiator, request.Date);
|
||||
var balance = request.IsForPaperTrading ? request.Balance.GetValueOrDefault() : _exchangeService.GetBalance(account, request.IsForPaperTrading).Result;
|
||||
var position = new Position(request.AccountName, request.Direction, request.Ticker, request.MoneyManagement,
|
||||
initiator, request.Date);
|
||||
var balance = request.IsForPaperTrading
|
||||
? request.Balance.GetValueOrDefault()
|
||||
: exchangeService.GetBalance(account, request.IsForPaperTrading).Result;
|
||||
var balanceAtRisk = RiskHelpers.GetBalanceAtRisk(balance, request.MoneyManagement);
|
||||
|
||||
if (balanceAtRisk < 13)
|
||||
@@ -41,11 +38,13 @@ namespace Managing.Application.Trading
|
||||
throw new Exception($"Try to risk {balanceAtRisk} $ but inferior to minimum to trade");
|
||||
}
|
||||
|
||||
var price = request.IsForPaperTrading && request.Price.HasValue ?
|
||||
request.Price.Value :
|
||||
_exchangeService.GetPrice(account, request.Ticker, DateTime.Now);
|
||||
var price = request.IsForPaperTrading && request.Price.HasValue
|
||||
? request.Price.Value
|
||||
: exchangeService.GetPrice(account, request.Ticker, DateTime.Now);
|
||||
var quantity = balanceAtRisk / price;
|
||||
var fee = request.IsForPaperTrading ? request.Fee.GetValueOrDefault() : _tradingService.GetFee(account, request.IsForPaperTrading);
|
||||
var fee = request.IsForPaperTrading
|
||||
? request.Fee.GetValueOrDefault()
|
||||
: tradingService.GetFee(account, request.IsForPaperTrading);
|
||||
|
||||
var expectedStatus = GetExpectedStatus(request);
|
||||
position.Open = TradingPolicies.OpenPosition(expectedStatus).Execute(
|
||||
@@ -53,18 +52,18 @@ namespace Managing.Application.Trading
|
||||
{
|
||||
var openPrice = request.IsForPaperTrading || request.Price.HasValue
|
||||
? request.Price.Value
|
||||
: _exchangeService.GetBestPrice(account, request.Ticker, price, quantity, request.Direction);
|
||||
: exchangeService.GetBestPrice(account, request.Ticker, price, quantity, request.Direction);
|
||||
|
||||
var trade = _exchangeService.OpenTrade(
|
||||
account,
|
||||
request.Ticker,
|
||||
request.Direction,
|
||||
openPrice,
|
||||
quantity,
|
||||
request.MoneyManagement.Leverage,
|
||||
TradeType.Limit,
|
||||
isForPaperTrading: request.IsForPaperTrading,
|
||||
currentDate: request.Date).Result;
|
||||
var trade = exchangeService.OpenTrade(
|
||||
account,
|
||||
request.Ticker,
|
||||
request.Direction,
|
||||
openPrice,
|
||||
quantity,
|
||||
request.MoneyManagement.Leverage,
|
||||
TradeType.Limit,
|
||||
isForPaperTrading: request.IsForPaperTrading,
|
||||
currentDate: request.Date).Result;
|
||||
|
||||
trade.Fee = TradingHelpers.GetFeeAmount(fee, openPrice * quantity, account.Exchange);
|
||||
return trade;
|
||||
@@ -73,11 +72,12 @@ namespace Managing.Application.Trading
|
||||
|
||||
if (IsOpenTradeHandled(position.Open.Status, account.Exchange) && !request.IgnoreSLTP.GetValueOrDefault())
|
||||
{
|
||||
|
||||
var closeDirection = request.Direction == TradeDirection.Long ? TradeDirection.Short : TradeDirection.Long;
|
||||
var closeDirection = request.Direction == TradeDirection.Long
|
||||
? TradeDirection.Short
|
||||
: TradeDirection.Long;
|
||||
|
||||
// Stop loss
|
||||
position.StopLoss = _exchangeService.BuildEmptyTrade(
|
||||
position.StopLoss = exchangeService.BuildEmptyTrade(
|
||||
request.Ticker,
|
||||
RiskHelpers.GetStopLossPrice(request.Direction, position.Open.Price, request.MoneyManagement),
|
||||
position.Open.Quantity,
|
||||
@@ -87,10 +87,11 @@ namespace Managing.Application.Trading
|
||||
request.Date,
|
||||
TradeStatus.PendingOpen);
|
||||
|
||||
position.StopLoss.Fee = TradingHelpers.GetFeeAmount(fee, position.StopLoss.Price * position.StopLoss.Quantity, account.Exchange);
|
||||
position.StopLoss.Fee = TradingHelpers.GetFeeAmount(fee,
|
||||
position.StopLoss.Price * position.StopLoss.Quantity, account.Exchange);
|
||||
|
||||
// Take profit
|
||||
position.TakeProfit1 = _exchangeService.BuildEmptyTrade(
|
||||
position.TakeProfit1 = exchangeService.BuildEmptyTrade(
|
||||
request.Ticker,
|
||||
RiskHelpers.GetTakeProfitPrice(request.Direction, position.Open.Price, request.MoneyManagement),
|
||||
quantity,
|
||||
@@ -100,13 +101,16 @@ namespace Managing.Application.Trading
|
||||
request.Date,
|
||||
TradeStatus.PendingOpen);
|
||||
|
||||
position.TakeProfit1.Fee = TradingHelpers.GetFeeAmount(fee, position.TakeProfit1.Price * position.TakeProfit1.Quantity, account.Exchange);
|
||||
position.TakeProfit1.Fee = TradingHelpers.GetFeeAmount(fee,
|
||||
position.TakeProfit1.Price * position.TakeProfit1.Quantity, account.Exchange);
|
||||
}
|
||||
|
||||
position.Status = IsOpenTradeHandled(position.Open.Status, account.Exchange) ? position.Status : PositionStatus.Rejected;
|
||||
_tradingService.InsertPosition(position);
|
||||
position.Status = IsOpenTradeHandled(position.Open.Status, account.Exchange)
|
||||
? position.Status
|
||||
: PositionStatus.Rejected;
|
||||
tradingService.InsertPosition(position);
|
||||
|
||||
return Task.FromResult(position);
|
||||
return position;
|
||||
}
|
||||
|
||||
private static TradeStatus GetExpectedStatus(OpenPositionRequest request)
|
||||
@@ -122,7 +126,7 @@ namespace Managing.Application.Trading
|
||||
private static bool IsOpenTradeHandled(TradeStatus tradeStatus, TradingExchanges exchange)
|
||||
{
|
||||
return tradeStatus == TradeStatus.Filled
|
||||
|| (exchange == TradingExchanges.Evm && tradeStatus == TradeStatus.Requested);
|
||||
|| (exchange == TradingExchanges.Evm && tradeStatus == TradeStatus.Requested);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,6 @@ public class TradingService : ITradingService
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Scenario GetScenarioByName(string scenario)
|
||||
{
|
||||
return _tradingRepository.GetScenarioByName(scenario);
|
||||
@@ -126,7 +125,8 @@ public class TradingService : ITradingService
|
||||
if (quantityInPosition > 0)
|
||||
{
|
||||
// Position still open
|
||||
position.ProfitAndLoss = TradingBox.GetProfitAndLoss(position, position.Open.Quantity, lastPrice);
|
||||
position.ProfitAndLoss =
|
||||
TradingBox.GetProfitAndLoss(position, position.Open.Quantity, lastPrice, position.Open.Leverage);
|
||||
_logger.LogInformation($"Position is still open - PNL : {position.ProfitAndLoss.Realized} $");
|
||||
_logger.LogInformation($"Requested trades : {orders.Count}");
|
||||
}
|
||||
@@ -138,7 +138,8 @@ public class TradingService : ITradingService
|
||||
// SL hit
|
||||
_logger.LogInformation($"Stop loss is filled on exchange.");
|
||||
position.StopLoss.SetStatus(TradeStatus.Filled);
|
||||
position.ProfitAndLoss = TradingBox.GetProfitAndLoss(position, position.StopLoss.Quantity, position.StopLoss.Price);
|
||||
position.ProfitAndLoss = TradingBox.GetProfitAndLoss(position, position.StopLoss.Quantity,
|
||||
position.StopLoss.Price, position.Open.Leverage);
|
||||
_ = _exchangeService.CancelOrder(account, position.Ticker);
|
||||
}
|
||||
else if (orders.All(o => o.TradeType != TradeType.TakeProfit))
|
||||
@@ -147,19 +148,22 @@ public class TradingService : ITradingService
|
||||
if (position.TakeProfit1.Status == TradeStatus.Filled && position.TakeProfit2 != null)
|
||||
{
|
||||
position.TakeProfit2.SetStatus(TradeStatus.Filled);
|
||||
position.ProfitAndLoss = TradingBox.GetProfitAndLoss(position, position.TakeProfit2.Quantity, position.TakeProfit2.Price);
|
||||
position.ProfitAndLoss = TradingBox.GetProfitAndLoss(position, position.TakeProfit2.Quantity,
|
||||
position.TakeProfit2.Price, 1);
|
||||
_logger.LogInformation($"TakeProfit 2 is filled on exchange.");
|
||||
}
|
||||
else
|
||||
{
|
||||
position.TakeProfit1.SetStatus(TradeStatus.Filled);
|
||||
position.ProfitAndLoss = TradingBox.GetProfitAndLoss(position, position.TakeProfit1.Quantity, position.TakeProfit1.Price);
|
||||
position.ProfitAndLoss = TradingBox.GetProfitAndLoss(position, position.TakeProfit1.Quantity,
|
||||
position.TakeProfit1.Price, 1);
|
||||
_logger.LogInformation($"TakeProfit 1 is filled on exchange.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation($"Position closed manually or forced close by exchange because quantity in position is below 0.");
|
||||
_logger.LogInformation(
|
||||
$"Position closed manually or forced close by exchange because quantity in position is below 0.");
|
||||
position.Status = PositionStatus.Finished;
|
||||
|
||||
if (orders.Any()) await _exchangeService.CancelOrder(account, position.Ticker);
|
||||
@@ -202,10 +206,8 @@ public class TradingService : ITradingService
|
||||
return 0.000665M;
|
||||
}
|
||||
|
||||
return _cacheService.GetOrSave($"Fee-{account.Exchange}", () =>
|
||||
{
|
||||
return _tradingRepository.GetFee(TradingExchanges.Evm)?.Cost ?? 0m;
|
||||
}, TimeSpan.FromHours(2));
|
||||
return _cacheService.GetOrSave($"Fee-{account.Exchange}",
|
||||
() => { return _tradingRepository.GetFee(TradingExchanges.Evm)?.Cost ?? 0m; }, TimeSpan.FromHours(2));
|
||||
}
|
||||
|
||||
public void UpdatePosition(Position position)
|
||||
@@ -246,7 +248,6 @@ public class TradingService : ITradingService
|
||||
{
|
||||
await ManageTrader(a, availableTickers);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_cacheService.SaveValue(key, aqip, TimeSpan.FromMinutes(10));
|
||||
@@ -255,8 +256,10 @@ public class TradingService : ITradingService
|
||||
public IEnumerable<Trader> GetTradersWatch()
|
||||
{
|
||||
var watchAccount = _statisticRepository.GetBestTraders();
|
||||
var customWatchAccount = _accountService.GetAccounts(true, false).Where(a => a.Type == AccountType.Watch).ToList().MapToTraders();
|
||||
watchAccount.AddRange(customWatchAccount.Where(a => !watchAccount.Any(w => w.Address.Equals(a.Address, StringComparison.InvariantCultureIgnoreCase))));
|
||||
var customWatchAccount = _accountService.GetAccounts(true, false).Where(a => a.Type == AccountType.Watch)
|
||||
.ToList().MapToTraders();
|
||||
watchAccount.AddRange(customWatchAccount.Where(a =>
|
||||
!watchAccount.Any(w => w.Address.Equals(a.Address, StringComparison.InvariantCultureIgnoreCase))));
|
||||
return watchAccount;
|
||||
}
|
||||
|
||||
@@ -279,14 +282,16 @@ public class TradingService : ITradingService
|
||||
{
|
||||
if (oldTrade != null)
|
||||
{
|
||||
_logger.LogInformation($"[{shortAddress}][{ticker}] Trader previously got a position open but the position was close by trader");
|
||||
_logger.LogInformation(
|
||||
$"[{shortAddress}][{ticker}] Trader previously got a position open but the position was close by trader");
|
||||
await _messengerService.SendClosedPosition(a.Account.Address, oldTrade);
|
||||
a.Trades.Remove(oldTrade);
|
||||
}
|
||||
}
|
||||
else if ((newTrade != null && oldTrade == null) || (newTrade.Quantity > oldTrade.Quantity))
|
||||
{
|
||||
_logger.LogInformation($"[{shortAddress}][{ticker}] Trader increase {newTrade.Direction} by {newTrade.Quantity - (oldTrade?.Quantity ?? 0)} with leverage {newTrade.Leverage} at {newTrade.Price} leverage.");
|
||||
_logger.LogInformation(
|
||||
$"[{shortAddress}][{ticker}] Trader increase {newTrade.Direction} by {newTrade.Quantity - (oldTrade?.Quantity ?? 0)} with leverage {newTrade.Leverage} at {newTrade.Price} leverage.");
|
||||
|
||||
var index = a.Trades.IndexOf(oldTrade);
|
||||
if (index != -1)
|
||||
@@ -307,12 +312,14 @@ public class TradingService : ITradingService
|
||||
var decreaseAmount = oldTrade.Quantity - newTrade.Quantity;
|
||||
var index = a.Trades.IndexOf(oldTrade);
|
||||
a.Trades[index] = newTrade;
|
||||
_logger.LogInformation($"[{a.Account.Address.Substring(0, 6)}][{ticker}] Trader decrease position but didnt close it {decreaseAmount}");
|
||||
_logger.LogInformation(
|
||||
$"[{a.Account.Address.Substring(0, 6)}][{ticker}] Trader decrease position but didnt close it {decreaseAmount}");
|
||||
await _messengerService.SendDecreasePosition(a.Account.Address, newTrade, decreaseAmount);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation($"[{shortAddress}][{ticker}] No change - Quantity still {newTrade.Quantity}");
|
||||
_logger.LogInformation(
|
||||
$"[{shortAddress}][{ticker}] No change - Quantity still {newTrade.Quantity}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -324,7 +331,7 @@ public class TradingService : ITradingService
|
||||
|
||||
private List<TraderFollowup> GetAccountsQuantityInPosition(IEnumerable<Trader> watchAccount)
|
||||
{
|
||||
var result = new List<TraderFollowup> ();
|
||||
var result = new List<TraderFollowup>();
|
||||
foreach (var account in watchAccount)
|
||||
{
|
||||
var trader = SetupFollowUp(account);
|
||||
@@ -352,4 +359,4 @@ public class TradingService : ITradingService
|
||||
public List<Trade> Trades { get; set; }
|
||||
public List<string> PositionIdentifiers { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using Managing.Application.Abstractions;
|
||||
using Managing.Application.Abstractions.Services;
|
||||
using Managing.Application.Workflows.Flows.Feeds;
|
||||
using Managing.Application.Workflows.Flows.Strategies;
|
||||
using Managing.Application.Workflows.Flows.Trading;
|
||||
using Managing.Domain.Workflows;
|
||||
using Managing.Domain.Workflows.Synthetics;
|
||||
@@ -15,7 +16,8 @@ public class FlowFactory : IFlowFactory
|
||||
private readonly ITradingService _tradingService;
|
||||
private readonly IAccountService _accountService;
|
||||
|
||||
public FlowFactory(IExchangeService exchangeService, ICacheService cacheService, ITradingService tradingService, IAccountService accountService)
|
||||
public FlowFactory(IExchangeService exchangeService, ICacheService cacheService, ITradingService tradingService,
|
||||
IAccountService accountService)
|
||||
{
|
||||
_exchangeService = exchangeService;
|
||||
_cacheService = cacheService;
|
||||
@@ -29,16 +31,18 @@ public class FlowFactory : IFlowFactory
|
||||
{
|
||||
FlowType.FeedTicker => new FeedTicker(_exchangeService),
|
||||
FlowType.RsiDivergence => new RsiDiv(),
|
||||
FlowType.OpenPosition => new OpenPosition(_exchangeService, _cacheService, _accountService, _tradingService),
|
||||
FlowType.OpenPosition => new OpenPosition(_exchangeService, _cacheService, _accountService,
|
||||
_tradingService),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
|
||||
flow.Children = new List<IFlow>();
|
||||
flow.Parameters = new List<FlowParameter>();
|
||||
|
||||
foreach (var parameter in request.Parameters)
|
||||
foreach (var parameter in request.Parameters)
|
||||
{
|
||||
if (!flow.Parameters.Any(p => p.Name == parameter.Name)) {
|
||||
if (!flow.Parameters.Any(p => p.Name == parameter.Name))
|
||||
{
|
||||
flow.Parameters.Add(new FlowParameter
|
||||
{
|
||||
Name = parameter.Name,
|
||||
@@ -46,6 +50,7 @@ public class FlowFactory : IFlowFactory
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return flow;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using Managing.Domain.Workflows;
|
||||
using Newtonsoft.Json;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Application.Workflows.Flows.Feeds;
|
||||
namespace Managing.Application.Workflows.Flows.Strategies;
|
||||
|
||||
public class RsiDiv : FlowBase
|
||||
{
|
||||
@@ -36,7 +36,7 @@ public class RsiDiv : FlowBase
|
||||
|
||||
Output = JsonConvert.SerializeObject(strategy.Signals);
|
||||
|
||||
if(Children != null && Children.Count > 0)
|
||||
if (Children != null && Children.Count > 0)
|
||||
{
|
||||
foreach (var child in Children)
|
||||
{
|
||||
@@ -62,4 +62,4 @@ public class RsiDivParameters
|
||||
{
|
||||
public int Period { get; set; }
|
||||
public Timeframe Timeframe { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using Managing.Application.Abstractions.Repositories;
|
||||
using Managing.Application.Abstractions.Services;
|
||||
using Managing.Application.Workflows.Flows.Feeds;
|
||||
using Managing.Application.Workflows.Flows.Strategies;
|
||||
using Managing.Application.Workflows.Flows.Trading;
|
||||
using Managing.Domain.Workflows;
|
||||
using Managing.Domain.Workflows.Synthetics;
|
||||
@@ -14,7 +15,7 @@ public class WorkflowService : IWorkflowService
|
||||
private readonly IExchangeService _exchangeService;
|
||||
private readonly IFlowFactory _flowFactory;
|
||||
private readonly ICacheService _cacheService;
|
||||
private readonly ITradingService _tradingService;
|
||||
private readonly ITradingService _tradingService;
|
||||
private readonly IAccountService _accountService;
|
||||
|
||||
public WorkflowService(
|
||||
@@ -50,10 +51,9 @@ public class WorkflowService : IWorkflowService
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
return Map(workflowRequest);
|
||||
}
|
||||
|
||||
@@ -122,5 +122,4 @@ public class WorkflowService : IWorkflowService
|
||||
|
||||
return Task.FromResult(availableFlows.AsEnumerable());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user