klhztrader/KLHZ.Trader.Core/Exchange/Services/TradingCommandsExecutor.cs

98 lines
3.7 KiB
C#

using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
using KLHZ.Trader.Core.Exchange.Models.AssetsAccounting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Threading.Channels;
using Tinkoff.InvestApi;
using Tinkoff.InvestApi.V1;
namespace KLHZ.Trader.Core.Exchange.Services
{
public class TradingCommandsExecutor : IHostedService
{
private readonly TradeDataProvider _tradeDataProvider;
private readonly InvestApiClient _investApiClient;
private readonly IDataBus _dataBus;
private readonly ILogger<TradingCommandsExecutor> _logger;
private readonly Channel<ITradeCommand> _channel = Channel.CreateUnbounded<ITradeCommand>();
public TradingCommandsExecutor(InvestApiClient investApiClient, IDataBus dataBus, ILogger<TradingCommandsExecutor> logger, TradeDataProvider tradeDataProvider)
{
_investApiClient = investApiClient;
_dataBus = dataBus;
_dataBus.AddChannel(nameof(TradingCommandsExecutor), _channel);
_logger = logger;
_tradeDataProvider = tradeDataProvider;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_ = ProcessCommands();
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
internal async Task ExecuteCommand(ITradeCommand tradeCommand)
{
try
{
var dir = OrderDirection.Unspecified;
var dealDirection = DealDirection.Unknown;
var sign = 1;
if (tradeCommand.CommandType == Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketBuy)
{
dir = OrderDirection.Buy;
dealDirection = DealDirection.Buy;
}
else if (tradeCommand.CommandType == Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketSell)
{
sign = -1;
dir = OrderDirection.Sell;
dealDirection = DealDirection.Sell;
}
var req = new PostOrderRequest()
{
AccountId = tradeCommand.AccountId,
InstrumentId = tradeCommand.Figi,
Direction = dir,
OrderType = OrderType.Market,
Quantity = tradeCommand.Count,
ConfirmMarginTrade = true,
};
var res = await _investApiClient.Orders.PostOrderAsync(req);
var result = new DealResult
{
Count = sign * res.LotsExecuted,
Price = res.ExecutedOrderPrice,
Success = true,
Direction = dealDirection,
AccountId = tradeCommand.AccountId,
Figi = tradeCommand.Figi,
};
await _tradeDataProvider.LogDeal(result);
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка при покупке актива на счёт {acc}. figi: {figi}", tradeCommand.AccountId, tradeCommand.Figi);
}
}
private async Task ProcessCommands()
{
while (await _channel.Reader.WaitToReadAsync())
{
var command = await _channel.Reader.ReadAsync();
await ExecuteCommand(command);
}
}
}
}