using Managing.Application.Abstractions; using Managing.Application.Abstractions.Services; using Managing.Application.Trading.Commands; using Managing.Domain.MoneyManagements; using Managing.Domain.Trades; using Managing.Infrastructure.Evm.Models.Privy; using MediatR; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using static Managing.Common.Enums; namespace Managing.Api.Controllers; /// /// Controller for trading operations such as opening and closing positions, and retrieving trade information. /// Requires authorization for access. /// [ApiController] [Authorize] [Route("[controller]")] public class TradingController : BaseController { private readonly ICommandHandler _openTradeCommandHandler; private readonly ICommandHandler _closeTradeCommandHandler; private readonly ITradingService _tradingService; private readonly IMoneyManagementService _moneyManagementService; private readonly IMediator _mediator; private readonly ILogger _logger; /// /// Initializes a new instance of the class. /// /// Logger for logging information. /// Command handler for opening trades. /// Command handler for closing trades. /// Service for trading operations. /// Mediator for handling commands and requests. public TradingController( ILogger logger, ICommandHandler openTradeCommandHandler, ICommandHandler closeTradeCommandHandler, ITradingService tradingService, IMediator mediator, IMoneyManagementService moneyManagementService, IUserService userService) : base(userService) { _logger = logger; _openTradeCommandHandler = openTradeCommandHandler; _closeTradeCommandHandler = closeTradeCommandHandler; _tradingService = tradingService; _mediator = mediator; _moneyManagementService = moneyManagementService; } /// /// Retrieves a list of positions based on the initiator type. /// /// The initiator of the position (e.g., User, System). /// A list of positions. [HttpGet("GetPositions")] public async Task>> GetPositions(PositionInitiator positionInitiator) { var result = await _mediator.Send(new GetPositionsCommand(positionInitiator)); return Ok(result); } /// /// Retrieves a specific trade by account name, ticker, and exchange order ID. /// /// The name of the account. /// The ticker symbol of the trade. /// The exchange order ID of the trade. /// The requested trade. [HttpGet("GetTrade")] public async Task> GetTrade(string accountName, Ticker ticker, string exchangeOrderId) { var result = await _mediator.Send(new GetTradeCommand(accountName, exchangeOrderId, ticker)); return Ok(result); } /// /// Retrieves a list of trades for a given account and ticker. /// /// The name of the account. /// The ticker symbol of the trades. /// A list of trades. [HttpGet("GetTrades")] public async Task> GetTrades(string accountName, Ticker ticker) { var result = await _mediator.Send(new GetTradesCommand(ticker, accountName)); return Ok(result); } /// /// Closes a position identified by its unique identifier. /// /// The unique identifier of the position to close. /// The closed position. [HttpPost("ClosePosition")] public async Task> ClosePosition(string identifier) { var position = _tradingService.GetPositionByIdentifier(identifier); var result = await _closeTradeCommandHandler.Handle(new ClosePositionCommand(position)); return Ok(result); } /// /// Opens a new position based on the provided parameters. /// /// The name of the account to open the position for. /// The name of the money management strategy to use. /// The direction of the trade (Buy or Sell). /// The ticker symbol for the trade. /// The risk level for the trade. /// Indicates whether the trade is for paper trading. /// The money management strategy details (optional). /// The opening price for the trade (optional). /// The opened position. [HttpPost("OpenPosition")] public async Task> Trade( string accountName, string moneyManagementName, TradeDirection direction, Ticker ticker, RiskLevel riskLevel, bool isForPaperTrading, MoneyManagement? moneyManagement = null, decimal? openPrice = null) { if (string.IsNullOrEmpty(accountName)) { throw new ArgumentException($"'{nameof(accountName)}' cannot be null or empty.", nameof(accountName)); } if (string.IsNullOrEmpty(moneyManagementName) && moneyManagement == null) { throw new ArgumentException($"'{nameof(moneyManagementName)}' cannot be null or empty.", nameof(moneyManagementName)); } var user = await GetUser(); if (moneyManagement != null) { moneyManagement = await _moneyManagementService.GetMoneyMangement(user, moneyManagementName); } var command = new OpenPositionRequest( accountName, moneyManagement, direction, ticker, PositionInitiator.User, DateTime.UtcNow, user, 100m, // Default trading balance for user-initiated trades isForPaperTrading: isForPaperTrading, price: openPrice); var result = await _openTradeCommandHandler.Handle(command); return Ok(result); } /// /// Initializes a Privy wallet address for the user. /// /// The public address of the Privy wallet to initialize. /// The initialization response containing success status and transaction hashes. [HttpPost("InitPrivyWallet")] public async Task> InitPrivyWallet([FromBody] string publicAddress) { if (string.IsNullOrEmpty(publicAddress)) { return BadRequest("Public address cannot be null or empty."); } try { var result = await _tradingService.InitPrivyWallet(publicAddress); return Ok(result); } catch (Exception ex) { _logger.LogError(ex, "Error initializing Privy wallet address: {Address}", publicAddress); return StatusCode(500, new PrivyInitAddressResponse { Success = false, Error = "An error occurred while initializing the Privy wallet address." }); } } }