Files
managing-apps/src/Managing.Application/Trading/OpenPositionCommandHandler.cs
Oda 422fecea7b Postgres (#30)
* Add postgres

* Migrate users

* Migrate geneticRequest

* Try to fix Concurrent call

* Fix asyncawait

* Fix async and concurrent

* Migrate backtests

* Add cache for user by address

* Fix backtest migration

* Fix not open connection

* Fix backtest command error

* Fix concurrent

* Fix all concurrency

* Migrate TradingRepo

* Fix scenarios

* Migrate statistic repo

* Save botbackup

* Add settings et moneymanagement

* Add bot postgres

* fix a bit more backups

* Fix bot model

* Fix loading backup

* Remove cache market for read positions

* Add workers to postgre

* Fix workers api

* Reduce get Accounts for workers

* Migrate synth to postgre

* Fix backtest saved

* Remove mongodb

* botservice decorrelation

* Fix tradingbot scope call

* fix tradingbot

* fix concurrent

* Fix scope for genetics

* Fix account over requesting

* Fix bundle backtest worker

* fix a lot of things

* fix tab backtest

* Remove optimized moneymanagement

* Add light signal to not use User and too much property

* Make money management lighter

* insert indicators to awaitable

* Migrate add strategies to await

* Refactor scenario and indicator retrieval to use asynchronous methods throughout the application

* add more async await

* Add services

* Fix and clean

* Fix bot a bit

* Fix bot and add message for cooldown

* Remove fees

* Add script to deploy db

* Update dfeeploy script

* fix script

* Add idempotent script and backup

* finish script migration

* Fix did user and agent name on start bot
2025-07-27 20:42:17 +07:00

122 lines
4.8 KiB
C#

using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Services;
using Managing.Application.Trading.Commands;
using Managing.Common;
using Managing.Domain.Shared.Helpers;
using Managing.Domain.Trades;
using static Managing.Common.Enums;
namespace Managing.Application.Trading
{
public class OpenPositionCommandHandler(
IExchangeService exchangeService,
IAccountService accountService,
ITradingService tradingService)
: ICommandHandler<OpenPositionRequest, Position>
{
public async Task<Position> Handle(OpenPositionRequest request)
{
var account = await accountService.GetAccount(request.AccountName, hideSecrets: false, getBalance: false);
if (!request.IsForPaperTrading)
{
// 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(Guid.NewGuid().ToString(), request.AccountName, request.Direction,
request.Ticker,
request.MoneyManagement,
initiator, request.Date, request.User);
if (!string.IsNullOrEmpty(request.SignalIdentifier))
{
position.SignalIdentifier = request.SignalIdentifier;
}
// Always use BotTradingBalance directly as the balance to risk
decimal balanceToRisk = request.AmountToTrade;
// Minimum check
if (balanceToRisk < Constants.GMX.Config.MinimumPositionAmount)
{
throw new Exception(
$"Bot trading balance of {balanceToRisk} USD is less than the minimum {Constants.GMX.Config.MinimumPositionAmount} USD required to trade");
}
var price = request.IsForPaperTrading && request.Price.HasValue
? request.Price.Value
: await exchangeService.GetPrice(account, request.Ticker, DateTime.Now);
var quantity = balanceToRisk / price;
var openPrice = request.IsForPaperTrading || request.Price.HasValue
? request.Price.Value
: await exchangeService.GetBestPrice(account, request.Ticker, price, quantity, request.Direction);
// Determine SL/TP Prices
var stopLossPrice = RiskHelpers.GetStopLossPrice(request.Direction, openPrice, request.MoneyManagement);
var takeProfitPrice = RiskHelpers.GetTakeProfitPrice(request.Direction, openPrice, request.MoneyManagement);
var trade = await exchangeService.OpenTrade(
account,
request.Ticker,
request.Direction,
openPrice,
quantity,
request.MoneyManagement.Leverage,
TradeType.Limit,
isForPaperTrading: request.IsForPaperTrading,
currentDate: request.Date,
stopLossPrice: stopLossPrice,
takeProfitPrice: takeProfitPrice);
position.Open = trade;
var closeDirection = request.Direction == TradeDirection.Long
? TradeDirection.Short
: TradeDirection.Long;
// Stop loss
position.StopLoss = exchangeService.BuildEmptyTrade(
request.Ticker,
stopLossPrice,
position.Open.Quantity,
closeDirection,
request.MoneyManagement.Leverage,
TradeType.StopLoss,
request.Date,
TradeStatus.Requested);
// Take profit
position.TakeProfit1 = exchangeService.BuildEmptyTrade(
request.Ticker,
takeProfitPrice,
quantity,
closeDirection,
request.MoneyManagement.Leverage,
TradeType.TakeProfit,
request.Date,
TradeStatus.Requested);
position.Status = IsOpenTradeHandled(position.Open.Status, account.Exchange)
? position.Status
: PositionStatus.Rejected;
if (!request.IsForPaperTrading)
{
await tradingService.InsertPositionAsync(position);
}
return position;
}
private static bool IsOpenTradeHandled(TradeStatus tradeStatus, TradingExchanges exchange)
{
return tradeStatus == TradeStatus.Filled
|| (exchange == TradingExchanges.Evm && tradeStatus == TradeStatus.Requested);
}
}
}