Добавил блокировку активов
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 long Count { get; }
|
||||||
public string AccountId { get; }
|
public string AccountId { get; }
|
||||||
public bool EnableMargin { 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 long Count { get; init; }
|
||||||
public required string AccountId { get; init; }
|
public required string AccountId { get; init; }
|
||||||
public bool EnableMargin { get; init; } = true;
|
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;
|
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;
|
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
|
namespace KLHZ.Trader.Core.Exchange.Models.AssetsAccounting
|
||||||
{
|
{
|
||||||
public class Asset
|
public class Asset : LockableExchangeObject
|
||||||
{
|
{
|
||||||
public long? TradeId { get; init; }
|
public long? TradeId { get; init; }
|
||||||
public decimal BlockedItems { 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
|
namespace KLHZ.Trader.Core.Exchange.Models.AssetsAccounting
|
||||||
{
|
{
|
||||||
public class ManagedAccount
|
public class ManagedAccount : LockableExchangeObject
|
||||||
{
|
{
|
||||||
public readonly string AccountId;
|
public readonly string AccountId;
|
||||||
private readonly object _locker = new();
|
private readonly object _locker = new();
|
||||||
|
@ -42,217 +42,5 @@ namespace KLHZ.Trader.Core.Exchange.Models.AssetsAccounting
|
||||||
{
|
{
|
||||||
AccountId = accountId;
|
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.Security.Cryptography;
|
||||||
using System.Threading.Channels;
|
using System.Threading.Channels;
|
||||||
using Tinkoff.InvestApi;
|
using Tinkoff.InvestApi;
|
||||||
|
using Tinkoff.InvestApi.V1;
|
||||||
using AssetType = KLHZ.Trader.Core.Exchange.Models.AssetsAccounting.AssetType;
|
using AssetType = KLHZ.Trader.Core.Exchange.Models.AssetsAccounting.AssetType;
|
||||||
|
|
||||||
namespace KLHZ.Trader.Core.Exchange.Services
|
namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
|
@ -190,7 +191,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (message.Figi == "FUTIMOEXF000" && message.Direction==1)
|
if (message.Figi == "FUTIMOEXF000" && message.Direction == 1)
|
||||||
{
|
{
|
||||||
ProcessStops(message, currentTime);
|
ProcessStops(message, currentTime);
|
||||||
var windowMaxSize = 2000;
|
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();
|
var assets = acc.Assets.Values.Where(a => a.Figi == message.Figi).ToArray();
|
||||||
foreach (var asset in assets)
|
foreach (var asset in assets)
|
||||||
{
|
{
|
||||||
var profit = TradingCalculator.CaclProfit(asset.BoughtPrice, message.Value,
|
if (await asset.Lock(TimeSpan.FromSeconds(60)))
|
||||||
GetComission(assetType), GetLeverage(message.Figi, asset.Count < 0), asset.Count < 0);
|
|
||||||
var stoppingKey = message.Figi + asset.AccountId;
|
|
||||||
if (profit < -66m)
|
|
||||||
{
|
{
|
||||||
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,
|
var command = new TradeCommand()
|
||||||
Figi = message.Figi,
|
{
|
||||||
CommandType = asset.Count < 0 ? Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketBuy
|
AccountId = acc.AccountId,
|
||||||
: Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketSell,
|
Figi = message.Figi,
|
||||||
Count = System.Math.Abs((long)asset.Count),
|
CommandType = asset.Count < 0 ? Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketBuy
|
||||||
RecomendPrice = null,
|
: Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketSell,
|
||||||
EnableMargin = false,
|
Count = System.Math.Abs((long)asset.Count),
|
||||||
};
|
RecomendPrice = null,
|
||||||
await _dataBus.Broadcast(command);
|
EnableMargin = false,
|
||||||
_logger.LogWarning("Сброс актива {figi}! id команды {commandId} Направление сделки: {dir}; Количество активов: {count}; Разрешена ли маржиналка: {margin}",
|
};
|
||||||
message.Figi, command.CommandId, command.CommandType, command.Count, command.EnableMargin);
|
await _dataBus.Broadcast(command);
|
||||||
await LogDeclision(DeclisionTradeAction.CloseLong, message, profit);
|
_logger.LogWarning("Сброс актива {figi}! id команды {commandId} Направление сделки: {dir}; Количество активов: {count}; Разрешена ли маржиналка: {margin}",
|
||||||
await LogDeclision(DeclisionTradeAction.CloseLongReal, message, profit);
|
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 trendTask = CalcTrendDiff(message);
|
||||||
|
|
||||||
var ends = mavTaskEnds.Result & TradingEvent.UptrendEnd;
|
var ends = mavTaskEnds.Result & TradingEvent.UptrendEnd;
|
||||||
|
|
||||||
await Task.WhenAll(mavTask, ltTask, areasTask, positionTask, trendTask, mavTaskShorts, mavTaskEnds);
|
await Task.WhenAll(mavTask, ltTask, areasTask, positionTask, trendTask, mavTaskShorts, mavTaskEnds);
|
||||||
var assetType = _tradeDataProvider.GetAssetTypeByFigi(message.Figi);
|
var assetType = _tradeDataProvider.GetAssetTypeByFigi(message.Figi);
|
||||||
var res = mavTask.Result | ltTask.Result;
|
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 (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()
|
var command = new TradeCommand()
|
||||||
{
|
{
|
||||||
|
@ -403,6 +407,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
CommandType = Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketBuy,
|
CommandType = Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketBuy,
|
||||||
Count = 1,
|
Count = 1,
|
||||||
RecomendPrice = null,
|
RecomendPrice = null,
|
||||||
|
ExchangeObject = acc.Value,
|
||||||
};
|
};
|
||||||
await _dataBus.Broadcast(command);
|
await _dataBus.Broadcast(command);
|
||||||
_logger.LogWarning("Покупка актива {figi}! id команды {commandId}. Направление сделки: {dir}; Количество активов: {count}; Разрешена ли маржиналка: {margin}",
|
_logger.LogWarning("Покупка актива {figi}! id команды {commandId}. Направление сделки: {dir}; Количество активов: {count}; Разрешена ли маржиналка: {margin}",
|
||||||
|
@ -431,38 +436,41 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
.ToArray();
|
.ToArray();
|
||||||
foreach (var asset in assetsForClose)
|
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)
|
if (assetType == AssetType.Common && asset.Count > 0)
|
||||||
{
|
{
|
||||||
profit = TradingCalculator.CaclProfit(asset.BoughtPrice, message.Value,
|
profit = TradingCalculator.CaclProfit(asset.BoughtPrice, message.Value,
|
||||||
GetComission(assetType), 1, false);
|
GetComission(assetType), 1, false);
|
||||||
}
|
}
|
||||||
if (assetType == AssetType.Futures)
|
if (assetType == AssetType.Futures)
|
||||||
{
|
{
|
||||||
profit = TradingCalculator.CaclProfit(asset.BoughtPrice, message.Value,
|
profit = TradingCalculator.CaclProfit(asset.BoughtPrice, message.Value,
|
||||||
GetComission(assetType), GetLeverage(message.Figi, asset.Count < 0), asset.Count < 0);
|
GetComission(assetType), GetLeverage(message.Figi, asset.Count < 0), asset.Count < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (profit > 0)
|
if (profit > 0)
|
||||||
{
|
|
||||||
LongClosingStops[message.Figi] = message.Time.AddSeconds(30);
|
|
||||||
var command = new TradeCommand()
|
|
||||||
{
|
{
|
||||||
AccountId = asset.AccountId,
|
LongClosingStops[message.Figi] = message.Time.AddSeconds(30);
|
||||||
Figi = message.Figi,
|
var command = new TradeCommand()
|
||||||
CommandType = Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketSell,
|
{
|
||||||
Count = (long)asset.Count,
|
AccountId = asset.AccountId,
|
||||||
RecomendPrice = null,
|
Figi = message.Figi,
|
||||||
EnableMargin = false,
|
CommandType = Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketSell,
|
||||||
};
|
Count = (long)asset.Count,
|
||||||
await _dataBus.Broadcast(command);
|
RecomendPrice = null,
|
||||||
_logger.LogWarning("Продажа актива {figi}! id команды {commandId}. Направление сделки: {dir}; Количество активов: {count}; Разрешена ли маржиналка: {margin}",
|
EnableMargin = false,
|
||||||
message.Figi, command.CommandId, command.CommandType, command.Count, command.EnableMargin);
|
};
|
||||||
if (loggedDeclisions == 0)
|
await _dataBus.Broadcast(command);
|
||||||
{
|
_logger.LogWarning("Продажа актива {figi}! id команды {commandId}. Направление сделки: {dir}; Количество активов: {count}; Разрешена ли маржиналка: {margin}",
|
||||||
loggedDeclisions++;
|
message.Figi, command.CommandId, command.CommandType, command.Count, command.EnableMargin);
|
||||||
await LogDeclision(DeclisionTradeAction.CloseLongReal, message, profit);
|
if (loggedDeclisions == 0)
|
||||||
|
{
|
||||||
|
loggedDeclisions++;
|
||||||
|
await LogDeclision(DeclisionTradeAction.CloseLongReal, message, profit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -482,7 +490,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
var loggedDeclisions = 0;
|
var loggedDeclisions = 0;
|
||||||
foreach (var acc in accounts)
|
foreach (var acc in accounts)
|
||||||
{
|
{
|
||||||
if (BotModeSwitcher.CanSell())
|
if (BotModeSwitcher.CanSell() && await acc.Value.Lock(TimeSpan.FromSeconds(60)))
|
||||||
{
|
{
|
||||||
if (RandomNumberGenerator.GetInt32(100) > 50)
|
if (RandomNumberGenerator.GetInt32(100) > 50)
|
||||||
{
|
{
|
||||||
|
@ -493,7 +501,8 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
CommandType = Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketSell,
|
CommandType = Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketSell,
|
||||||
Count = 1,
|
Count = 1,
|
||||||
RecomendPrice = null,
|
RecomendPrice = null,
|
||||||
EnableMargin = true
|
EnableMargin = true,
|
||||||
|
ExchangeObject = acc.Value,
|
||||||
};
|
};
|
||||||
await _dataBus.Broadcast(command);
|
await _dataBus.Broadcast(command);
|
||||||
_logger.LogWarning("Открытие шорта {figi}! id команды {commandId}. Направление сделки: {dir}; Количество активов: {count}; Разрешена ли маржиналка: {margin}",
|
_logger.LogWarning("Открытие шорта {figi}! id команды {commandId}. Направление сделки: {dir}; Количество активов: {count}; Разрешена ли маржиналка: {margin}",
|
||||||
|
@ -524,31 +533,34 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
.ToArray();
|
.ToArray();
|
||||||
foreach (var asset in assetsForClose)
|
foreach (var asset in assetsForClose)
|
||||||
{
|
{
|
||||||
var profit = 0m;
|
if (await asset.Lock(TimeSpan.FromSeconds(60)))
|
||||||
|
{
|
||||||
|
var profit = 0m;
|
||||||
|
|
||||||
if (assetType == AssetType.Futures)
|
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()
|
|
||||||
{
|
{
|
||||||
AccountId = asset.AccountId,
|
profit = TradingCalculator.CaclProfit(asset.BoughtPrice, message.Value,
|
||||||
Figi = message.Figi,
|
GetComission(assetType), GetLeverage(message.Figi, asset.Count < 0), asset.Count < 0);
|
||||||
CommandType = Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketBuy,
|
}
|
||||||
Count = System.Math.Abs((long)asset.Count),
|
if (profit > 0)
|
||||||
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++;
|
var command = new TradeCommand()
|
||||||
await LogDeclision(DeclisionTradeAction.CloseShortReal, message, profit);
|
{
|
||||||
|
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);
|
_logger.LogError(ex, "Ошибка при покупке актива на счёт {acc}. figi: {figi}", tradeCommand.AccountId, tradeCommand.Figi);
|
||||||
}
|
}
|
||||||
|
tradeCommand.ExchangeObject?.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessCommands()
|
private async Task ProcessCommands()
|
||||||
|
|
Loading…
Reference in New Issue