Добавил блокировку активов
test / deploy_trader_prod (push) Successful in 2m2s
Details
test / deploy_trader_prod (push) Successful in 2m2s
Details
parent
bcc084c49c
commit
0f5284f472
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces
|
||||
{
|
||||
public interface ILockableObject
|
||||
{
|
||||
public Task<bool> Lock(TimeSpan duration);
|
||||
|
||||
public void Unlock();
|
||||
}
|
||||
}
|
|
@ -11,5 +11,6 @@ namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces
|
|||
public long Count { get; }
|
||||
public string AccountId { get; }
|
||||
public bool EnableMargin { get; }
|
||||
public ILockableObject? ExchangeObject { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,5 +12,6 @@ namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos
|
|||
public long Count { get; init; }
|
||||
public required string AccountId { get; init; }
|
||||
public bool EnableMargin { get; init; } = true;
|
||||
public ILockableObject? ExchangeObject { get; init; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
|||
{
|
||||
return ValueAmplitudePosition.UpperThen30Decil;
|
||||
}
|
||||
else if (value < fftData.Mediana && System.Math.Sign(value2)>=0)
|
||||
else if (value < fftData.Mediana && System.Math.Sign(value2) >= 0)
|
||||
{
|
||||
return ValueAmplitudePosition.LowerThenMediana;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
using KLHZ.Trader.Core.Exchange.Models.AssetsAccounting;
|
||||
|
||||
namespace KLHZ.Trader.Core.Tests
|
||||
{
|
||||
public class AssetTests
|
||||
{
|
||||
[Test]
|
||||
public void Test1()
|
||||
{
|
||||
var asset = new Asset() { AccountId = "", Figi = "", Ticker = "" };
|
||||
var dur = TimeSpan.FromSeconds(5);
|
||||
Assert.IsTrue(asset.Lock(dur).Result);
|
||||
Assert.IsFalse(asset.Lock(dur).Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test2()
|
||||
{
|
||||
var asset = new Asset() { AccountId = "", Figi = "", Ticker = "" };
|
||||
var dur = TimeSpan.FromSeconds(5);
|
||||
Assert.IsTrue(asset.Lock(dur).Result);
|
||||
Task.Delay(dur + dur).Wait();
|
||||
Assert.IsTrue(asset.Lock(dur).Result);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
namespace KLHZ.Trader.Core.Exchange.Models.AssetsAccounting
|
||||
{
|
||||
public class Asset
|
||||
public class Asset : LockableExchangeObject
|
||||
{
|
||||
public long? TradeId { get; init; }
|
||||
public decimal BlockedItems { get; init; }
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
|
||||
|
||||
namespace KLHZ.Trader.Core.Exchange.Models.AssetsAccounting
|
||||
{
|
||||
public abstract class LockableExchangeObject : ILockableObject
|
||||
{
|
||||
private readonly SemaphoreSlim _sem = new SemaphoreSlim(1, 1);
|
||||
|
||||
public Task<bool> Lock(TimeSpan duration)
|
||||
{
|
||||
var lockerTask = _sem.WaitAsync(0);
|
||||
_ = lockerTask.ContinueWith(async (t) =>
|
||||
{
|
||||
if (t.Result)
|
||||
{
|
||||
await Task.Delay(duration);
|
||||
_sem.Release();
|
||||
}
|
||||
});
|
||||
return lockerTask;
|
||||
}
|
||||
|
||||
public void Unlock()
|
||||
{
|
||||
try
|
||||
{
|
||||
_sem.Release();
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace KLHZ.Trader.Core.Exchange.Models.AssetsAccounting
|
||||
{
|
||||
public class ManagedAccount
|
||||
public class ManagedAccount : LockableExchangeObject
|
||||
{
|
||||
public readonly string AccountId;
|
||||
private readonly object _locker = new();
|
||||
|
@ -42,217 +42,5 @@ namespace KLHZ.Trader.Core.Exchange.Models.AssetsAccounting
|
|||
{
|
||||
AccountId = accountId;
|
||||
}
|
||||
|
||||
// private async Task ProcessCommands()
|
||||
// {
|
||||
// while (await _channel.Reader.WaitToReadAsync())
|
||||
// {
|
||||
// var command = await _channel.Reader.ReadAsync();
|
||||
// try
|
||||
// {
|
||||
// await ProcessMarketCommand(command);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// _logger.LogError(ex, "Ошибка при обработке команды.");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// internal async Task SyncPortfolio()
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// //await _semaphoreSlim.WaitAsync();
|
||||
// var portfolio = await _investApiClient.Operations.GetPortfolioAsync(new PortfolioRequest()
|
||||
// {
|
||||
// AccountId = AccountId,
|
||||
// });
|
||||
|
||||
// var oldAssets = Assets.Keys.ToHashSet();
|
||||
// using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
// context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
||||
|
||||
// var trades = await context.Trades
|
||||
// .Where(t => t.AccountId == AccountId && t.ArchiveStatus == 0)
|
||||
// .ToListAsync();
|
||||
// foreach (var position in portfolio.Positions)
|
||||
// {
|
||||
// decimal price = 0;
|
||||
// var trade = trades.FirstOrDefault(t => t.Figi == position.Figi);
|
||||
|
||||
// if (trade != null)
|
||||
// {
|
||||
// trades.Remove(trade);
|
||||
// price = trade.Price;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// price = position.AveragePositionPrice;
|
||||
// }
|
||||
|
||||
//#pragma warning disable CS0612 // Тип или член устарел
|
||||
// var asset = new Models.Assets.Asset()
|
||||
// {
|
||||
// TradeId = trade?.Id,
|
||||
// AccountId = AccountId,
|
||||
// Figi = position.Figi,
|
||||
// Ticker = position.Ticker,
|
||||
// BoughtAt = trade?.BoughtAt ?? DateTime.UtcNow,
|
||||
// BoughtPrice = price,
|
||||
// Type = position.InstrumentType.ParseInstrumentType(),
|
||||
// Position = position.Quantity > 0 ? PositionType.Long : PositionType.Short,
|
||||
// BlockedItems = position.BlockedLots,
|
||||
// Count = position.Quantity,
|
||||
// CountLots = position.QuantityLots,
|
||||
// };
|
||||
//#pragma warning restore CS0612 // Тип или член устарел
|
||||
// Assets.AddOrUpdate(asset.Figi, asset, (k, v) => asset);
|
||||
// oldAssets.Remove(asset.Figi);
|
||||
// }
|
||||
|
||||
// Total = portfolio.TotalAmountPortfolio;
|
||||
// Balance = portfolio.TotalAmountCurrencies;
|
||||
|
||||
// foreach (var asset in oldAssets)
|
||||
// {
|
||||
// Assets.TryRemove(asset, out _);
|
||||
// }
|
||||
|
||||
// var ids = trades.Select(t => t.Id).ToArray();
|
||||
// await context.Trades
|
||||
// .Where(t => ids.Contains(t.Id))
|
||||
// .ExecuteUpdateAsync(t => t.SetProperty(tr => tr.ArchiveStatus, 1));
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// _logger.LogError(ex, "Ошибка при синхранизации портфеля счёта {accountId}", AccountId);
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// //_semaphoreSlim.Release();
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
// internal async Task<DealResult> ClosePosition(string figi)
|
||||
// {
|
||||
// if (!string.IsNullOrEmpty(figi) && Assets.TryGetValue(figi, out var asset))
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// var req = new PostOrderRequest()
|
||||
// {
|
||||
// AccountId = AccountId,
|
||||
// InstrumentId = figi,
|
||||
// };
|
||||
// if (asset != null)
|
||||
// {
|
||||
// req.Direction = OrderDirection.Sell;
|
||||
// req.OrderType = OrderType.Market;
|
||||
// req.Quantity = (long)asset.Count;
|
||||
// req.ConfirmMarginTrade = true;
|
||||
// var res = await _investApiClient.Orders.PostOrderAsync(req);
|
||||
// return new DealResult
|
||||
// {
|
||||
// Count = res.LotsExecuted,
|
||||
// Price = res.ExecutedOrderPrice,
|
||||
// Success = true,
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// _logger.LogError(ex, "Ошибка при закрытии позиции по счёту {acc}. figi: {figi}", AccountId, figi);
|
||||
// }
|
||||
// }
|
||||
// return new DealResult
|
||||
// {
|
||||
// Count = 0,
|
||||
// Price = 0,
|
||||
// Success = false,
|
||||
// };
|
||||
// }
|
||||
|
||||
// internal async Task<DealResult> BuyAsset(string figi, decimal count, string? ticker = null, decimal? recommendedPrice = null)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// var req = new PostOrderRequest()
|
||||
// {
|
||||
// AccountId = AccountId,
|
||||
// InstrumentId = figi,
|
||||
// Direction = OrderDirection.Buy,
|
||||
// OrderType = OrderType.Market,
|
||||
// Quantity = (long)count,
|
||||
// };
|
||||
|
||||
// var res = await _investApiClient.Orders.PostOrderAsync(req);
|
||||
|
||||
// using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
// context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
||||
|
||||
// var trade = await context.Trades.FirstOrDefaultAsync(t => t.ArchiveStatus == 0 && t.Figi == figi);
|
||||
// if (trade == null)
|
||||
// {
|
||||
// var newTrade = new DataLayer.Entities.Trades.Trade()
|
||||
// {
|
||||
// AccountId = AccountId,
|
||||
// Figi = figi,
|
||||
// Ticker = ticker ?? string.Empty,
|
||||
// BoughtAt = DateTime.UtcNow,
|
||||
// Count = res.LotsExecuted,
|
||||
// Price = res.ExecutedOrderPrice,
|
||||
// Position = DataLayer.Entities.Trades.Enums.PositionType.Long,
|
||||
// Direction = DataLayer.Entities.Trades.Enums.TradeDirection.Buy,
|
||||
// Asset = DataLayer.Entities.Trades.Enums.AssetType.Common,
|
||||
// };
|
||||
|
||||
// await context.Trades.AddAsync(newTrade);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// var oldAmount = trade.Price * trade.Count;
|
||||
// var newAmount = res.ExecutedOrderPrice * res.LotsExecuted;
|
||||
// trade.Count = res.LotsExecuted + trade.Count;
|
||||
// trade.Price = (oldAmount + newAmount) / trade.Count;
|
||||
// context.Trades.Update(trade);
|
||||
// }
|
||||
|
||||
// await context.SaveChangesAsync();
|
||||
// return new DealResult
|
||||
// {
|
||||
// Count = res.LotsExecuted,
|
||||
// Price = res.ExecutedOrderPrice,
|
||||
// Success = true,
|
||||
// };
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// _logger.LogError(ex, "Ошибка при покупке актива на счёт {acc}. figi: {figi}", AccountId, figi);
|
||||
// }
|
||||
// return new DealResult
|
||||
// {
|
||||
// Count = 0,
|
||||
// Price = 0,
|
||||
// Success = false,
|
||||
// };
|
||||
// }
|
||||
|
||||
// private async Task ProcessMarketCommand(TradeCommand command)
|
||||
// {
|
||||
// if (string.IsNullOrWhiteSpace(command.Figi)) return;
|
||||
// if (command.CommandType == TradeCommandType.MarketBuy)
|
||||
// {
|
||||
// await BuyAsset(command.Figi, command.Count ?? 1, command.Ticker, command.RecomendPrice);
|
||||
// }
|
||||
// else if (command.CommandType == TradeCommandType.ForceClosePosition)
|
||||
// {
|
||||
// await ClosePosition(command.Figi);
|
||||
// }
|
||||
// else return;
|
||||
|
||||
// await SyncPortfolio();
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ using System.Collections.Concurrent;
|
|||
using System.Security.Cryptography;
|
||||
using System.Threading.Channels;
|
||||
using Tinkoff.InvestApi;
|
||||
using Tinkoff.InvestApi.V1;
|
||||
using AssetType = KLHZ.Trader.Core.Exchange.Models.AssetsAccounting.AssetType;
|
||||
|
||||
namespace KLHZ.Trader.Core.Exchange.Services
|
||||
|
@ -190,7 +191,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
|
||||
try
|
||||
{
|
||||
if (message.Figi == "FUTIMOEXF000" && message.Direction==1)
|
||||
if (message.Figi == "FUTIMOEXF000" && message.Direction == 1)
|
||||
{
|
||||
ProcessStops(message, currentTime);
|
||||
var windowMaxSize = 2000;
|
||||
|
@ -224,26 +225,29 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
var assets = acc.Assets.Values.Where(a => a.Figi == message.Figi).ToArray();
|
||||
foreach (var asset in assets)
|
||||
{
|
||||
var profit = TradingCalculator.CaclProfit(asset.BoughtPrice, message.Value,
|
||||
GetComission(assetType), GetLeverage(message.Figi, asset.Count < 0), asset.Count < 0);
|
||||
var stoppingKey = message.Figi + asset.AccountId;
|
||||
if (profit < -66m)
|
||||
if (await asset.Lock(TimeSpan.FromSeconds(60)))
|
||||
{
|
||||
var command = new TradeCommand()
|
||||
var profit = TradingCalculator.CaclProfit(asset.BoughtPrice, message.Value,
|
||||
GetComission(assetType), GetLeverage(message.Figi, asset.Count < 0), asset.Count < 0);
|
||||
var stoppingKey = message.Figi + asset.AccountId;
|
||||
if (profit < -100m)
|
||||
{
|
||||
AccountId = asset.AccountId,
|
||||
Figi = message.Figi,
|
||||
CommandType = asset.Count < 0 ? Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketBuy
|
||||
: Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketSell,
|
||||
Count = System.Math.Abs((long)asset.Count),
|
||||
RecomendPrice = null,
|
||||
EnableMargin = false,
|
||||
};
|
||||
await _dataBus.Broadcast(command);
|
||||
_logger.LogWarning("Сброс актива {figi}! id команды {commandId} Направление сделки: {dir}; Количество активов: {count}; Разрешена ли маржиналка: {margin}",
|
||||
message.Figi, command.CommandId, command.CommandType, command.Count, command.EnableMargin);
|
||||
await LogDeclision(DeclisionTradeAction.CloseLong, message, profit);
|
||||
await LogDeclision(DeclisionTradeAction.CloseLongReal, message, profit);
|
||||
var command = new TradeCommand()
|
||||
{
|
||||
AccountId = acc.AccountId,
|
||||
Figi = message.Figi,
|
||||
CommandType = asset.Count < 0 ? Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketBuy
|
||||
: Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketSell,
|
||||
Count = System.Math.Abs((long)asset.Count),
|
||||
RecomendPrice = null,
|
||||
EnableMargin = false,
|
||||
};
|
||||
await _dataBus.Broadcast(command);
|
||||
_logger.LogWarning("Сброс актива {figi}! id команды {commandId} Направление сделки: {dir}; Количество активов: {count}; Разрешена ли маржиналка: {margin}",
|
||||
message.Figi, command.CommandId, command.CommandType, command.Count, command.EnableMargin);
|
||||
await LogDeclision(DeclisionTradeAction.CloseLong, message, profit);
|
||||
await LogDeclision(DeclisionTradeAction.CloseLongReal, message, profit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -369,7 +373,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
var trendTask = CalcTrendDiff(message);
|
||||
|
||||
var ends = mavTaskEnds.Result & TradingEvent.UptrendEnd;
|
||||
|
||||
|
||||
await Task.WhenAll(mavTask, ltTask, areasTask, positionTask, trendTask, mavTaskShorts, mavTaskEnds);
|
||||
var assetType = _tradeDataProvider.GetAssetTypeByFigi(message.Figi);
|
||||
var res = mavTask.Result | ltTask.Result;
|
||||
|
@ -394,7 +398,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
{
|
||||
if (IsBuyAllowed(acc.Value, message.Value, 1, _accountCashPartFutures, _accountCashPart))
|
||||
{
|
||||
if (RandomNumberGenerator.GetInt32(100) > 50)
|
||||
if (RandomNumberGenerator.GetInt32(100) > 50 && await acc.Value.Lock(TimeSpan.FromSeconds(60)))
|
||||
{
|
||||
var command = new TradeCommand()
|
||||
{
|
||||
|
@ -403,6 +407,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
CommandType = Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketBuy,
|
||||
Count = 1,
|
||||
RecomendPrice = null,
|
||||
ExchangeObject = acc.Value,
|
||||
};
|
||||
await _dataBus.Broadcast(command);
|
||||
_logger.LogWarning("Покупка актива {figi}! id команды {commandId}. Направление сделки: {dir}; Количество активов: {count}; Разрешена ли маржиналка: {margin}",
|
||||
|
@ -431,38 +436,41 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
.ToArray();
|
||||
foreach (var asset in assetsForClose)
|
||||
{
|
||||
var profit = 0m;
|
||||
if (await asset.Lock(TimeSpan.FromSeconds(60)))
|
||||
{
|
||||
var profit = 0m;
|
||||
|
||||
if (assetType == AssetType.Common && asset.Count > 0)
|
||||
{
|
||||
profit = TradingCalculator.CaclProfit(asset.BoughtPrice, message.Value,
|
||||
GetComission(assetType), 1, false);
|
||||
}
|
||||
if (assetType == AssetType.Futures)
|
||||
{
|
||||
profit = TradingCalculator.CaclProfit(asset.BoughtPrice, message.Value,
|
||||
GetComission(assetType), GetLeverage(message.Figi, asset.Count < 0), asset.Count < 0);
|
||||
}
|
||||
if (assetType == AssetType.Common && asset.Count > 0)
|
||||
{
|
||||
profit = TradingCalculator.CaclProfit(asset.BoughtPrice, message.Value,
|
||||
GetComission(assetType), 1, false);
|
||||
}
|
||||
if (assetType == AssetType.Futures)
|
||||
{
|
||||
profit = TradingCalculator.CaclProfit(asset.BoughtPrice, message.Value,
|
||||
GetComission(assetType), GetLeverage(message.Figi, asset.Count < 0), asset.Count < 0);
|
||||
}
|
||||
|
||||
if (profit > 0)
|
||||
{
|
||||
LongClosingStops[message.Figi] = message.Time.AddSeconds(30);
|
||||
var command = new TradeCommand()
|
||||
if (profit > 0)
|
||||
{
|
||||
AccountId = asset.AccountId,
|
||||
Figi = message.Figi,
|
||||
CommandType = Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketSell,
|
||||
Count = (long)asset.Count,
|
||||
RecomendPrice = null,
|
||||
EnableMargin = false,
|
||||
};
|
||||
await _dataBus.Broadcast(command);
|
||||
_logger.LogWarning("Продажа актива {figi}! id команды {commandId}. Направление сделки: {dir}; Количество активов: {count}; Разрешена ли маржиналка: {margin}",
|
||||
message.Figi, command.CommandId, command.CommandType, command.Count, command.EnableMargin);
|
||||
if (loggedDeclisions == 0)
|
||||
{
|
||||
loggedDeclisions++;
|
||||
await LogDeclision(DeclisionTradeAction.CloseLongReal, message, profit);
|
||||
LongClosingStops[message.Figi] = message.Time.AddSeconds(30);
|
||||
var command = new TradeCommand()
|
||||
{
|
||||
AccountId = asset.AccountId,
|
||||
Figi = message.Figi,
|
||||
CommandType = Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketSell,
|
||||
Count = (long)asset.Count,
|
||||
RecomendPrice = null,
|
||||
EnableMargin = false,
|
||||
};
|
||||
await _dataBus.Broadcast(command);
|
||||
_logger.LogWarning("Продажа актива {figi}! id команды {commandId}. Направление сделки: {dir}; Количество активов: {count}; Разрешена ли маржиналка: {margin}",
|
||||
message.Figi, command.CommandId, command.CommandType, command.Count, command.EnableMargin);
|
||||
if (loggedDeclisions == 0)
|
||||
{
|
||||
loggedDeclisions++;
|
||||
await LogDeclision(DeclisionTradeAction.CloseLongReal, message, profit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -482,7 +490,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
var loggedDeclisions = 0;
|
||||
foreach (var acc in accounts)
|
||||
{
|
||||
if (BotModeSwitcher.CanSell())
|
||||
if (BotModeSwitcher.CanSell() && await acc.Value.Lock(TimeSpan.FromSeconds(60)))
|
||||
{
|
||||
if (RandomNumberGenerator.GetInt32(100) > 50)
|
||||
{
|
||||
|
@ -493,7 +501,8 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
CommandType = Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketSell,
|
||||
Count = 1,
|
||||
RecomendPrice = null,
|
||||
EnableMargin = true
|
||||
EnableMargin = true,
|
||||
ExchangeObject = acc.Value,
|
||||
};
|
||||
await _dataBus.Broadcast(command);
|
||||
_logger.LogWarning("Открытие шорта {figi}! id команды {commandId}. Направление сделки: {dir}; Количество активов: {count}; Разрешена ли маржиналка: {margin}",
|
||||
|
@ -524,31 +533,34 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
.ToArray();
|
||||
foreach (var asset in assetsForClose)
|
||||
{
|
||||
var profit = 0m;
|
||||
if (await asset.Lock(TimeSpan.FromSeconds(60)))
|
||||
{
|
||||
var profit = 0m;
|
||||
|
||||
if (assetType == AssetType.Futures)
|
||||
{
|
||||
profit = TradingCalculator.CaclProfit(asset.BoughtPrice, message.Value,
|
||||
GetComission(assetType), GetLeverage(message.Figi, asset.Count < 0), asset.Count < 0);
|
||||
}
|
||||
if (profit > 0)
|
||||
{
|
||||
var command = new TradeCommand()
|
||||
if (assetType == AssetType.Futures)
|
||||
{
|
||||
AccountId = asset.AccountId,
|
||||
Figi = message.Figi,
|
||||
CommandType = Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketBuy,
|
||||
Count = System.Math.Abs((long)asset.Count),
|
||||
RecomendPrice = null,
|
||||
EnableMargin = false,
|
||||
};
|
||||
await _dataBus.Broadcast(command);
|
||||
_logger.LogWarning("Продажа актива {figi}! id команды {commandId}. Направление сделки: {dir}; Количество активов: {count}; Разрешена ли маржиналка: {margin}",
|
||||
message.Figi, command.CommandId, command.CommandType, command.Count, command.EnableMargin);
|
||||
if (loggedDeclisions == 0)
|
||||
profit = TradingCalculator.CaclProfit(asset.BoughtPrice, message.Value,
|
||||
GetComission(assetType), GetLeverage(message.Figi, asset.Count < 0), asset.Count < 0);
|
||||
}
|
||||
if (profit > 0)
|
||||
{
|
||||
loggedDeclisions++;
|
||||
await LogDeclision(DeclisionTradeAction.CloseShortReal, message, profit);
|
||||
var command = new TradeCommand()
|
||||
{
|
||||
AccountId = asset.AccountId,
|
||||
Figi = message.Figi,
|
||||
CommandType = Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketBuy,
|
||||
Count = System.Math.Abs((long)asset.Count),
|
||||
RecomendPrice = null,
|
||||
EnableMargin = false,
|
||||
};
|
||||
await _dataBus.Broadcast(command);
|
||||
_logger.LogWarning("Продажа актива {figi}! id команды {commandId}. Направление сделки: {dir}; Количество активов: {count}; Разрешена ли маржиналка: {margin}",
|
||||
message.Figi, command.CommandId, command.CommandType, command.Count, command.EnableMargin);
|
||||
if (loggedDeclisions == 0)
|
||||
{
|
||||
loggedDeclisions++;
|
||||
await LogDeclision(DeclisionTradeAction.CloseShortReal, message, profit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,6 +91,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
{
|
||||
_logger.LogError(ex, "Ошибка при покупке актива на счёт {acc}. figi: {figi}", tradeCommand.AccountId, tradeCommand.Figi);
|
||||
}
|
||||
tradeCommand.ExchangeObject?.Unlock();
|
||||
}
|
||||
|
||||
private async Task ProcessCommands()
|
||||
|
|
Loading…
Reference in New Issue