98 lines
3.7 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|
|
}
|