Add manual close for bot positions

This commit is contained in:
2025-04-25 17:33:38 +07:00
parent d5dead3d8f
commit 6579bbc06f
8 changed files with 198 additions and 23 deletions

View File

@@ -1,23 +1,13 @@
using Managing.Api.Models.Requests;
using Managing.Api.Models.Responses;
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Services;
using Managing.Application.Hubs;
using Managing.Application.ManageBot.Commands;
using Managing.Common;
using Managing.Domain.Bots;
using Managing.Domain.Users;
using Managing.Domain.Trades;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Managing.Domain.Trades;
using Microsoft.Extensions.DependencyInjection;
using static Managing.Common.Enums;
using ApplicationTradingBot = Managing.Application.Bots.TradingBot;
using ApiTradingBot = Managing.Api.Models.Responses.TradingBot;
@@ -464,4 +454,84 @@ public class BotController : BaseController
return StatusCode(500, $"Error opening position: {ex.Message}");
}
}
/// <summary>
/// Closes a specific position for a trading bot
/// </summary>
/// <param name="request">The request containing the position close parameters</param>
/// <returns>The closed position or an error</returns>
[HttpPost]
[Route("ClosePosition")]
public async Task<ActionResult<Position>> ClosePosition([FromBody] ClosePositionRequest request)
{
try
{
// Check if user owns the account
if (!await UserOwnsBotAccount(request.BotName))
{
return Forbid("You don't have permission to close positions for this bot");
}
var activeBots = _botService.GetActiveBots();
var bot = activeBots.FirstOrDefault(b => b.Name == request.BotName) as ApplicationTradingBot;
if (bot == null)
{
return NotFound($"Bot {request.BotName} not found or is not a trading bot");
}
if (bot.GetStatus() != BotStatus.Up.ToString())
{
return BadRequest($"Bot {request.BotName} is not running");
}
// Find the position to close
var position = bot.Positions.FirstOrDefault(p => p.Identifier == request.PositionId);
if (position == null)
{
return NotFound($"Position with ID {request.PositionId} not found for bot {request.BotName}");
}
// Find the signal associated with this position
var signal = bot.Signals.FirstOrDefault(s => s.Identifier == position.SignalIdentifier);
if (signal == null)
{
return NotFound($"Signal not found for position {request.PositionId}");
}
// Get current price
var lastCandle = bot.OptimizedCandles.LastOrDefault();
if (lastCandle == null)
{
return BadRequest("Cannot get current price to close position");
}
// Close the position at market price
await bot.CloseTrade(signal, position, position.Open, lastCandle.Close, true);
await NotifyBotSubscriberAsync();
return Ok(position);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error closing position");
return StatusCode(500, $"Error closing position: {ex.Message}");
}
}
}
/// <summary>
/// Request model for closing a position
/// </summary>
public class ClosePositionRequest
{
/// <summary>
/// The name of the bot
/// </summary>
public string BotName { get; set; }
/// <summary>
/// The ID of the position to close
/// </summary>
public string PositionId { get; set; }
}