обновление стратегии + фикс скидывания IMOEXF
test / deploy_trader_prod (push) Successful in 4m24s
Details
test / deploy_trader_prod (push) Successful in 4m24s
Details
parent
a2e58c9a12
commit
7cc13d9ba0
|
@ -9,5 +9,6 @@ namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces
|
||||||
public decimal? RecomendPrice { get; }
|
public decimal? RecomendPrice { get; }
|
||||||
public long Count { get; }
|
public long Count { get; }
|
||||||
public string AccountId { get; }
|
public string AccountId { get; }
|
||||||
|
public bool EnableMargin { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,5 +10,6 @@ namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos
|
||||||
public decimal? RecomendPrice { get; init; }
|
public decimal? RecomendPrice { get; init; }
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,9 +71,44 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
||||||
if (isCrossing.res)
|
if (isCrossing.res)
|
||||||
{
|
{
|
||||||
crossings.Add(i2);
|
crossings.Add(i2);
|
||||||
|
if (crossings.Count == 4 || (shift + 1 == size - 1 || shift + 1 == prices.Length - 1))
|
||||||
|
{
|
||||||
|
if ((shift + 1 == size - 1 || shift + 1 == prices.Length - 1))
|
||||||
|
{
|
||||||
|
crossings.Add(shift);
|
||||||
|
}
|
||||||
|
var diffTotal = pricesForFinalComparison[crossings[0]] - pricesForFinalComparison[crossings[1]];
|
||||||
|
for (int crossingShift = 1; crossingShift < crossings.Count - 2; crossingShift++)
|
||||||
|
{
|
||||||
|
var diff = pricesForFinalComparison[crossings[crossingShift]] - pricesForFinalComparison[crossings[crossingShift + 1]];
|
||||||
|
if (diff >= 0)
|
||||||
|
{
|
||||||
|
diffTotal += diff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// если фильтрация окном 15 наползает на окно 120 сверху, потенциальное время закрытия лонга и возможно открытия шорта
|
||||||
|
if (twavss[size - 1] <= twavbs[size - 1] && twavss[size - 2] > twavbs[size - 2])
|
||||||
|
{
|
||||||
|
if (diffTotal >= meanfullStep
|
||||||
|
&& times[crossings[0]] - times[crossings[1]] >= timeForUptreandStart)
|
||||||
|
{
|
||||||
|
res |= TradingEvent.UptrendEnd;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (crossings.Count == 2 || (shift + 1 == size - 1 || shift + 1 == prices.Length - 1))
|
if (crossings.Count == 2 || (shift + 1 == size - 1 || shift + 1 == prices.Length - 1))
|
||||||
{
|
{
|
||||||
|
if ((shift + 1 == size - 1 || shift + 1 == prices.Length - 1))
|
||||||
|
{
|
||||||
|
crossings.Add(shift);
|
||||||
|
}
|
||||||
// если фильтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга и закрытия шорта
|
// если фильтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга и закрытия шорта
|
||||||
if (twavss[size - 1] >= twavbs[size - 1] && twavss[size - 2] < twavbs[size - 2])
|
if (twavss[size - 1] >= twavbs[size - 1] && twavss[size - 2] < twavbs[size - 2])
|
||||||
{
|
{
|
||||||
|
@ -84,17 +119,6 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// если фильтрация окном 15 наползает на окно 120 сверху, потенциальное время закрытия лонга и возможно открытия шорта
|
|
||||||
if (twavss[size - 1] <= twavbs[size - 1] && twavss[size - 2] > twavbs[size - 2])
|
|
||||||
{
|
|
||||||
if (pricesForFinalComparison[crossings[0]] - pricesForFinalComparison[crossings[1]] >= meanfullStep
|
|
||||||
&& times[crossings[0]] - times[crossings[1]] >= timeForUptreandStart)
|
|
||||||
{
|
|
||||||
res |= TradingEvent.UptrendEnd;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,6 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
private readonly IDataBus _dataBus;
|
private readonly IDataBus _dataBus;
|
||||||
private readonly TraderDataProvider _tradeDataProvider;
|
private readonly TraderDataProvider _tradeDataProvider;
|
||||||
private readonly ILogger<Trader> _logger;
|
private readonly ILogger<Trader> _logger;
|
||||||
private readonly ConcurrentDictionary<string, DeferredTrade> DeferredLongOpens = new();
|
|
||||||
private readonly ConcurrentDictionary<string, DeferredTrade> DeferredLongCloses = new();
|
|
||||||
private readonly ConcurrentDictionary<string, DateTime> OpeningStops = new();
|
private readonly ConcurrentDictionary<string, DateTime> OpeningStops = new();
|
||||||
private readonly ConcurrentDictionary<string, InstrumentSettings> Leverages = new();
|
private readonly ConcurrentDictionary<string, InstrumentSettings> Leverages = new();
|
||||||
|
|
||||||
|
@ -131,7 +129,8 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
{
|
{
|
||||||
AccountId = asset.AccountId,
|
AccountId = asset.AccountId,
|
||||||
Figi = message.Figi,
|
Figi = message.Figi,
|
||||||
CommandType = Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketSell,
|
CommandType = asset.Count < 0? Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketBuy
|
||||||
|
: Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketSell,
|
||||||
Count = (long)asset.Count,
|
Count = (long)asset.Count,
|
||||||
RecomendPrice = null,
|
RecomendPrice = null,
|
||||||
});
|
});
|
||||||
|
@ -146,7 +145,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
INewPrice message, int windowMaxSize)
|
INewPrice message, int windowMaxSize)
|
||||||
{
|
{
|
||||||
var res = TradingEvent.None;
|
var res = TradingEvent.None;
|
||||||
var resultMoveAvFull = MovingAverage.CheckByWindowAverageMean(data.timestamps, data.prices, windowMaxSize, 25, 120, TimeSpan.FromSeconds(20), 1m);
|
var resultMoveAvFull = MovingAverage.CheckByWindowAverageMean(data.timestamps, data.prices, windowMaxSize, 25, 120, TimeSpan.FromSeconds(20), 1.5m);
|
||||||
//var resultLongClose = MovingAverage.CheckByWindowAverageMean(data.timestamps, data.prices, windowMaxSize, 15, 120, 1.5m).events;
|
//var resultLongClose = MovingAverage.CheckByWindowAverageMean(data.timestamps, data.prices, windowMaxSize, 15, 120, 1.5m).events;
|
||||||
|
|
||||||
//ar uptrendStarts = LocalTrends.CheckByLocalTrends(data.timestamps, data.prices, TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(20), 1.5m, 15);
|
//ar uptrendStarts = LocalTrends.CheckByLocalTrends(data.timestamps, data.prices, TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(20), 1.5m, 15);
|
||||||
|
@ -282,114 +281,6 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessDeferredLongOpens(INewPrice message, DateTime currentTime)
|
|
||||||
{
|
|
||||||
if (message.Figi == "FUTIMOEXF000")
|
|
||||||
{
|
|
||||||
DeferredTrade? longOpen;
|
|
||||||
DeferredLongOpens.TryGetValue(message.Figi, out longOpen);
|
|
||||||
if (longOpen != null)
|
|
||||||
{
|
|
||||||
var t = currentTime;
|
|
||||||
if (longOpen.Time <= t
|
|
||||||
&& t - longOpen.Time < TimeSpan.FromMinutes(3))
|
|
||||||
{
|
|
||||||
DeferredLongOpens.TryRemove(message.Figi, out _);
|
|
||||||
if (message.Value - longOpen.Price < 1)
|
|
||||||
{
|
|
||||||
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
|
|
||||||
{
|
|
||||||
var accounts = _tradeDataProvider.Accounts
|
|
||||||
.Where(a => !a.Value.Assets.ContainsKey(message.Figi))
|
|
||||||
.ToArray();
|
|
||||||
foreach (var acc in accounts)
|
|
||||||
{
|
|
||||||
if (IsBuyAllowed(acc.Value, message.Value, 1, _accountCashPartFutures, _accountCashPart))
|
|
||||||
{
|
|
||||||
if (RandomNumberGenerator.GetInt32(100) > 50)
|
|
||||||
{
|
|
||||||
await _dataBus.Broadcast(new TradeCommand()
|
|
||||||
{
|
|
||||||
AccountId = acc.Value.AccountId,
|
|
||||||
Figi = message.Figi,
|
|
||||||
CommandType = Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketBuy,
|
|
||||||
Count = 1,
|
|
||||||
RecomendPrice = null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
await LogDeclision(DeclisionTradeAction.OpenLong, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await LogDeclision(DeclisionTradeAction.OpenLong, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ProcessDeferredLongCloses(INewPrice message, DateTime currentTime)
|
|
||||||
{
|
|
||||||
if (message.Figi == "FUTIMOEXF000")
|
|
||||||
{
|
|
||||||
DeferredTrade? longClose;
|
|
||||||
DeferredLongCloses.TryGetValue(message.Figi, out longClose);
|
|
||||||
if (longClose != null)
|
|
||||||
{
|
|
||||||
if (longClose.Time <= currentTime)
|
|
||||||
{
|
|
||||||
DeferredLongCloses.TryRemove(message.Figi, out _);
|
|
||||||
if (longClose.Price - message.Value < 1)
|
|
||||||
{
|
|
||||||
var assetType = _tradeDataProvider.GetAssetTypeByFigi(message.Figi);
|
|
||||||
if (!message.IsHistoricalData && BotModeSwitcher.CanSell())
|
|
||||||
{
|
|
||||||
var assetsForClose = _tradeDataProvider.Accounts
|
|
||||||
.SelectMany(a => a.Value.Assets.Values)
|
|
||||||
.Where(a => a.Figi == message.Figi && a.Count > 0)
|
|
||||||
.ToArray();
|
|
||||||
foreach (var asset in assetsForClose)
|
|
||||||
{
|
|
||||||
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 (profit > 0)
|
|
||||||
{
|
|
||||||
await _dataBus.Broadcast(new TradeCommand()
|
|
||||||
{
|
|
||||||
AccountId = asset.AccountId,
|
|
||||||
Figi = message.Figi,
|
|
||||||
CommandType = Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketSell,
|
|
||||||
Count = (long)asset.Count,
|
|
||||||
RecomendPrice = null,
|
|
||||||
});
|
|
||||||
await LogDeclision(DeclisionTradeAction.CloseLong, message, profit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await LogDeclision(DeclisionTradeAction.CloseLong, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task LogPrice(INewPrice message, string processor, decimal value)
|
private async Task LogPrice(INewPrice message, string processor, decimal value)
|
||||||
{
|
{
|
||||||
await _tradeDataProvider.LogPrice(new ProcessedPrice()
|
await _tradeDataProvider.LogPrice(new ProcessedPrice()
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using KLHZ.Trader.Core.Contracts.Declisions.Interfaces;
|
using Google.Protobuf.WellKnownTypes;
|
||||||
|
using KLHZ.Trader.Core.Contracts.Declisions.Interfaces;
|
||||||
using KLHZ.Trader.Core.Contracts.Messaging.Dtos;
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos;
|
||||||
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
|
||||||
using KLHZ.Trader.Core.DataLayer;
|
using KLHZ.Trader.Core.DataLayer;
|
||||||
|
@ -416,5 +417,11 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ValueTask<Asset[]> GetAssetsByFigi(string figi)
|
||||||
|
{
|
||||||
|
var assets = Accounts.Values.SelectMany(a => a.Assets.Values.Where(aa => aa.Figi == figi)).ToArray();
|
||||||
|
return ValueTask.FromResult(assets);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
Direction = dir,
|
Direction = dir,
|
||||||
OrderType = OrderType.Market,
|
OrderType = OrderType.Market,
|
||||||
Quantity = tradeCommand.Count,
|
Quantity = tradeCommand.Count,
|
||||||
ConfirmMarginTrade = true,
|
ConfirmMarginTrade = tradeCommand.EnableMargin,
|
||||||
};
|
};
|
||||||
|
|
||||||
var res = await _investApiClient.Orders.PostOrderAsync(req);
|
var res = await _investApiClient.Orders.PostOrderAsync(req);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using KLHZ.Trader.Core.Contracts.Messaging.Dtos;
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos;
|
||||||
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Enums;
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Enums;
|
||||||
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
|
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
|
||||||
|
using KLHZ.Trader.Core.Exchange.Services;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
@ -17,8 +18,10 @@ namespace KLHZ.Trader.Core.TG.Services
|
||||||
private readonly ImmutableArray<long> _admins = [];
|
private readonly ImmutableArray<long> _admins = [];
|
||||||
private readonly IDataBus _eventBus;
|
private readonly IDataBus _eventBus;
|
||||||
private readonly ILogger<BotMessagesHandler> _logger;
|
private readonly ILogger<BotMessagesHandler> _logger;
|
||||||
public BotMessagesHandler(IDataBus eventBus, IOptions<TgBotConfig> options, ILogger<BotMessagesHandler> logger)
|
private readonly TraderDataProvider _traderDataProvider;
|
||||||
|
public BotMessagesHandler(IDataBus eventBus, IOptions<TgBotConfig> options, ILogger<BotMessagesHandler> logger, TraderDataProvider traderDataProvider)
|
||||||
{
|
{
|
||||||
|
_traderDataProvider = traderDataProvider;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_eventBus = eventBus;
|
_eventBus = eventBus;
|
||||||
_admins = ImmutableArray.CreateRange(options.Value.Admins);
|
_admins = ImmutableArray.CreateRange(options.Value.Admins);
|
||||||
|
@ -73,16 +76,25 @@ namespace KLHZ.Trader.Core.TG.Services
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "продать IMOEXF":
|
case "продать IMOEXF":
|
||||||
|
{
|
||||||
|
|
||||||
|
var assets = await _traderDataProvider.GetAssetsByFigi("FUTIMOEXF000");
|
||||||
|
foreach(var asset in assets)
|
||||||
|
{
|
||||||
|
if (asset.Count > 0)
|
||||||
{
|
{
|
||||||
var command = new TradeCommand()
|
var command = new TradeCommand()
|
||||||
{
|
{
|
||||||
AccountId = "2274189208",
|
AccountId = asset.AccountId,
|
||||||
CommandType = TradeCommandType.MarketSell,
|
CommandType = TradeCommandType.MarketSell,
|
||||||
RecomendPrice = null,
|
RecomendPrice = null,
|
||||||
Figi = "FUTIMOEXF000",
|
Figi = asset.Figi,
|
||||||
Count = 1,
|
Count = (long)asset.Count,
|
||||||
};
|
};
|
||||||
await _eventBus.Broadcast(command);
|
await _eventBus.Broadcast(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "купить IMOEXF":
|
case "купить IMOEXF":
|
||||||
|
|
Loading…
Reference in New Issue