Compare commits
3 Commits
9114dda27f
...
83e1b0fe43
Author | SHA1 | Date |
---|---|---|
|
83e1b0fe43 | |
|
f95a34e5a1 | |
|
81d772fea9 |
|
@ -21,7 +21,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
||||||
internal static TradingEvent CheckUptrendStart(DateTime[] times, decimal[] prices, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff, int boundIndex)
|
internal static TradingEvent CheckUptrendStart(DateTime[] times, decimal[] prices, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff, int boundIndex)
|
||||||
{
|
{
|
||||||
var periodStat = GetTwoPeriodsProcessingData(times, prices, firstPeriod, secondPeriod, boundIndex, meanfullDiff);
|
var periodStat = GetTwoPeriodsProcessingData(times, prices, firstPeriod, secondPeriod, boundIndex, meanfullDiff);
|
||||||
var isStartOk = periodStat.Success && periodStat.DiffStart < -meanfullDiff;
|
var isStartOk = periodStat.Success && periodStat.DiffStart < 0.5m * meanfullDiff;
|
||||||
var isEndOk = periodStat.Success && periodStat.DiffEnd >= meanfullDiff;
|
var isEndOk = periodStat.Success && periodStat.DiffEnd >= meanfullDiff;
|
||||||
return isStartOk && isEndOk && prices[periodStat.Start] - prices[periodStat.End] >= meanfullDiff ? TradingEvent.UptrendStart : TradingEvent.None;
|
return isStartOk && isEndOk && prices[periodStat.Start] - prices[periodStat.End] >= meanfullDiff ? TradingEvent.UptrendStart : TradingEvent.None;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||||
|
<PackageReference Include="NSubstitute" Version="5.3.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.14.0" />
|
<PackageReference Include="NUnit" Version="3.14.0" />
|
||||||
<PackageReference Include="NUnit.Analyzers" Version="3.9.0" />
|
<PackageReference Include="NUnit.Analyzers" Version="3.9.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
using KLHZ.Trader.Core.Exchange.Models.AssetsAccounting;
|
||||||
|
|
||||||
|
namespace KLHZ.Trader.Core.Tests
|
||||||
|
{
|
||||||
|
public class TraderTests
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void IsBuyAllowedTest1()
|
||||||
|
{
|
||||||
|
|
||||||
|
var account = new ManagedAccount("111");
|
||||||
|
account.Total = 10000;
|
||||||
|
account.Balance = 9000;
|
||||||
|
account.Assets["123"] = new Asset()
|
||||||
|
{
|
||||||
|
AccountId = account.AccountId,
|
||||||
|
Figi = "123",
|
||||||
|
Ticker = "123",
|
||||||
|
Type = AssetType.Futures,
|
||||||
|
};
|
||||||
|
Assert.IsTrue(KLHZ.Trader.Core.Exchange.Services.Trader.IsBuyAllowed(account, 3000, 1, 0.5m, 0.3m));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void IsBuyAllowedTest2()
|
||||||
|
{
|
||||||
|
|
||||||
|
var account = new ManagedAccount("111");
|
||||||
|
account.Total = 10000;
|
||||||
|
account.Balance = 5000;
|
||||||
|
account.Assets["123"] = new Asset()
|
||||||
|
{
|
||||||
|
AccountId = account.AccountId,
|
||||||
|
Figi = "123",
|
||||||
|
Ticker = "123",
|
||||||
|
Type = AssetType.Futures,
|
||||||
|
};
|
||||||
|
Assert.IsFalse(KLHZ.Trader.Core.Exchange.Services.Trader.IsBuyAllowed(account, 3000, 1, 0.5m, 0.3m));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void IsBuyAllowedTest3()
|
||||||
|
{
|
||||||
|
|
||||||
|
var account = new ManagedAccount("111");
|
||||||
|
account.Total = 10000;
|
||||||
|
account.Balance = 5000;
|
||||||
|
account.Assets["123"] = new Asset()
|
||||||
|
{
|
||||||
|
AccountId = account.AccountId,
|
||||||
|
Figi = "123",
|
||||||
|
Ticker = "123",
|
||||||
|
Type = AssetType.Futures,
|
||||||
|
};
|
||||||
|
Assert.IsFalse(KLHZ.Trader.Core.Exchange.Services.Trader.IsBuyAllowed(account, 1500, 2, 0.5m, 0.3m));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void IsBuyAllowedTest4()
|
||||||
|
{
|
||||||
|
|
||||||
|
var account = new ManagedAccount("111");
|
||||||
|
account.Total = 10000;
|
||||||
|
account.Balance = 3000;
|
||||||
|
account.Assets["123"] = new Asset()
|
||||||
|
{
|
||||||
|
AccountId = account.AccountId,
|
||||||
|
Figi = "123",
|
||||||
|
Ticker = "123",
|
||||||
|
Type = AssetType.Futures,
|
||||||
|
};
|
||||||
|
Assert.IsFalse(KLHZ.Trader.Core.Exchange.Services.Trader.IsBuyAllowed(account, 1500, 1, 0.5m, 0.3m));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void IsBuyAllowedTest5()
|
||||||
|
{
|
||||||
|
|
||||||
|
var account = new ManagedAccount("111");
|
||||||
|
account.Total = 10000;
|
||||||
|
account.Balance = 5000;
|
||||||
|
account.Assets["123"] = new Asset()
|
||||||
|
{
|
||||||
|
AccountId = account.AccountId,
|
||||||
|
Figi = "123",
|
||||||
|
Ticker = "123",
|
||||||
|
Type = AssetType.Common,
|
||||||
|
};
|
||||||
|
Assert.IsTrue(KLHZ.Trader.Core.Exchange.Services.Trader.IsBuyAllowed(account, 3000, 1, 0.5m, 0.1m));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,42 +1,42 @@
|
||||||
namespace KLHZ.Trader.Core.Common
|
namespace KLHZ.Trader.Core.Common
|
||||||
{
|
{
|
||||||
public class BotModeSwitcher
|
public static class BotModeSwitcher
|
||||||
{
|
{
|
||||||
private readonly object _locker = new();
|
private readonly static object _locker = new();
|
||||||
private bool _canSell = true;
|
private static bool _canSell = false;
|
||||||
private bool _canPurchase = true;
|
private static bool _canPurchase = false;
|
||||||
|
|
||||||
public bool CanSell()
|
public static bool CanSell()
|
||||||
{
|
{
|
||||||
lock (_locker)
|
lock (_locker)
|
||||||
return _canSell;
|
return _canSell;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanPurchase()
|
public static bool CanPurchase()
|
||||||
{
|
{
|
||||||
lock (_locker)
|
lock (_locker)
|
||||||
return _canPurchase;
|
return _canPurchase;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopSelling()
|
public static void StopSelling()
|
||||||
{
|
{
|
||||||
lock (_locker)
|
lock (_locker)
|
||||||
_canSell = false;
|
_canSell = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopPurchase()
|
public static void StopPurchase()
|
||||||
{
|
{
|
||||||
lock (_locker)
|
lock (_locker)
|
||||||
_canPurchase = false;
|
_canPurchase = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartSelling()
|
public static void StartSelling()
|
||||||
{
|
{
|
||||||
lock (_locker)
|
lock (_locker)
|
||||||
_canSell = true;
|
_canSell = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartPurchase()
|
public static void StartPurchase()
|
||||||
{
|
{
|
||||||
lock (_locker)
|
lock (_locker)
|
||||||
_canPurchase = true;
|
_canPurchase = true;
|
||||||
|
|
|
@ -61,7 +61,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
if (_instrumentsFigis.Contains(future.Figi))
|
if (_instrumentsFigis.Contains(future.Figi))
|
||||||
{
|
{
|
||||||
_tickersCache.TryAdd(future.Figi, future.Ticker);
|
_tickersCache.TryAdd(future.Figi, future.Ticker);
|
||||||
_assetTypesCache.TryAdd(future.Figi, AssetType.Common);
|
_assetTypesCache.TryAdd(future.Figi, AssetType.Futures);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using KLHZ.Trader.Core.Common;
|
using KLHZ.Trader.Core.Common;
|
||||||
using KLHZ.Trader.Core.Contracts.Declisions.Dtos.Enums;
|
using KLHZ.Trader.Core.Contracts.Declisions.Dtos.Enums;
|
||||||
using KLHZ.Trader.Core.Contracts.Declisions.Interfaces;
|
using KLHZ.Trader.Core.Contracts.Declisions.Interfaces;
|
||||||
|
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.Contracts.Messaging.Interfaces;
|
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
|
||||||
using KLHZ.Trader.Core.DataLayer;
|
using KLHZ.Trader.Core.DataLayer;
|
||||||
|
@ -27,12 +28,11 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
public class Trader : IHostedService
|
public class Trader : IHostedService
|
||||||
{
|
{
|
||||||
private readonly IDataBus _dataBus;
|
private readonly IDataBus _dataBus;
|
||||||
private readonly BotModeSwitcher _botModeSwitcher;
|
|
||||||
private readonly IDbContextFactory<TraderDbContext> _dbContextFactory;
|
private readonly IDbContextFactory<TraderDbContext> _dbContextFactory;
|
||||||
private readonly TradeDataProvider _tradeDataProvider;
|
private readonly TradeDataProvider _tradeDataProvider;
|
||||||
private readonly ILogger<Trader> _logger;
|
private readonly ILogger<Trader> _logger;
|
||||||
private readonly ConcurrentDictionary<string, DeferredTrade> DeferredLongOpens = new();
|
internal readonly ConcurrentDictionary<string, DeferredTrade> DeferredLongOpens = new();
|
||||||
private readonly ConcurrentDictionary<string, DeferredTrade> DeferredLongCloses = new();
|
internal 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();
|
||||||
private readonly ConcurrentDictionary<string, IPriceHistoryCacheUnit> _historyCash = new();
|
private readonly ConcurrentDictionary<string, IPriceHistoryCacheUnit> _historyCash = new();
|
||||||
|
@ -43,7 +43,6 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
private readonly decimal _shareComission;
|
private readonly decimal _shareComission;
|
||||||
private readonly decimal _accountCashPart;
|
private readonly decimal _accountCashPart;
|
||||||
private readonly decimal _accountCashPartFutures;
|
private readonly decimal _accountCashPartFutures;
|
||||||
private readonly decimal _defaultBuyPartOfAccount;
|
|
||||||
private readonly string[] _tradingInstrumentsFigis = [];
|
private readonly string[] _tradingInstrumentsFigis = [];
|
||||||
|
|
||||||
private readonly Channel<INewPrice> _pricesChannel = Channel.CreateUnbounded<INewPrice>();
|
private readonly Channel<INewPrice> _pricesChannel = Channel.CreateUnbounded<INewPrice>();
|
||||||
|
@ -51,8 +50,6 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
private readonly CancellationTokenSource _cts = new();
|
private readonly CancellationTokenSource _cts = new();
|
||||||
public Trader(
|
public Trader(
|
||||||
ILogger<Trader> logger,
|
ILogger<Trader> logger,
|
||||||
BotModeSwitcher botModeSwitcher,
|
|
||||||
IServiceProvider provider,
|
|
||||||
IOptions<ExchangeConfig> options,
|
IOptions<ExchangeConfig> options,
|
||||||
IDataBus dataBus,
|
IDataBus dataBus,
|
||||||
IDbContextFactory<TraderDbContext> dbContextFactory,
|
IDbContextFactory<TraderDbContext> dbContextFactory,
|
||||||
|
@ -61,14 +58,12 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
{
|
{
|
||||||
_tradeDataProvider = tradeDataProvider;
|
_tradeDataProvider = tradeDataProvider;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_botModeSwitcher = botModeSwitcher;
|
|
||||||
_dataBus = dataBus;
|
_dataBus = dataBus;
|
||||||
_dbContextFactory = dbContextFactory;
|
_dbContextFactory = dbContextFactory;
|
||||||
_futureComission = options.Value.FutureComission;
|
_futureComission = options.Value.FutureComission;
|
||||||
_shareComission = options.Value.ShareComission;
|
_shareComission = options.Value.ShareComission;
|
||||||
_accountCashPart = options.Value.AccountCashPart;
|
_accountCashPart = options.Value.AccountCashPart;
|
||||||
_accountCashPartFutures = options.Value.AccountCashPartFutures;
|
_accountCashPartFutures = options.Value.AccountCashPartFutures;
|
||||||
_defaultBuyPartOfAccount = options.Value.DefaultBuyPartOfAccount;
|
|
||||||
_tradingInstrumentsFigis = options.Value.TradingInstrumentsFigis;
|
_tradingInstrumentsFigis = options.Value.TradingInstrumentsFigis;
|
||||||
_buyStopLength = (double)options.Value.StopBuyLengthMinuts;
|
_buyStopLength = (double)options.Value.StopBuyLengthMinuts;
|
||||||
|
|
||||||
|
@ -125,10 +120,34 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
DeferredLongOpens.TryRemove(message.Figi, out _);
|
DeferredLongOpens.TryRemove(message.Figi, out _);
|
||||||
if (message.Value - longOpen.Price < 1)
|
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))
|
||||||
|
{
|
||||||
|
await _dataBus.Broadcast(new TradeCommand()
|
||||||
|
{
|
||||||
|
AccountId = acc.Value.AccountId,
|
||||||
|
Figi = message.Figi,
|
||||||
|
CommandType = Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketBuy,
|
||||||
|
Count = 1,
|
||||||
|
RecomendPrice = null,
|
||||||
|
});
|
||||||
LogDeclision(declisionsForSave, DeclisionTradeAction.OpenLong, message);
|
LogDeclision(declisionsForSave, DeclisionTradeAction.OpenLong, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogDeclision(declisionsForSave, DeclisionTradeAction.OpenLong, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DeferredTrade? longClose;
|
DeferredTrade? longClose;
|
||||||
DeferredLongCloses.TryGetValue(message.Figi, out longClose);
|
DeferredLongCloses.TryGetValue(message.Figi, out longClose);
|
||||||
|
@ -139,16 +158,55 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
DeferredLongCloses.TryRemove(message.Figi, out _);
|
DeferredLongCloses.TryRemove(message.Figi, out _);
|
||||||
if (longClose.Price - message.Value < 1)
|
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,
|
||||||
|
});
|
||||||
LogDeclision(declisionsForSave, DeclisionTradeAction.CloseLong, message);
|
LogDeclision(declisionsForSave, DeclisionTradeAction.CloseLong, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogDeclision(declisionsForSave, DeclisionTradeAction.CloseLong, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var windowMaxSize = 100;
|
var windowMaxSize = 100;
|
||||||
var data = await unit.GetData(windowMaxSize);
|
var data = await unit.GetData(windowMaxSize);
|
||||||
var state = ExchangeScheduler.GetCurrentState(message.Time);
|
var state = ExchangeScheduler.GetCurrentState(message.Time);
|
||||||
|
|
||||||
if (state == ExchangeState.ClearingTime
|
if (state == ExchangeState.ClearingTime
|
||||||
|
&& !message.IsHistoricalData
|
||||||
&& data.timestamps.Length > 1
|
&& data.timestamps.Length > 1
|
||||||
&& (data.timestamps[data.timestamps.Length - 1] - data.timestamps[data.timestamps.Length - 2]) > TimeSpan.FromMinutes(3))
|
&& (data.timestamps[data.timestamps.Length - 1] - data.timestamps[data.timestamps.Length - 2]) > TimeSpan.FromMinutes(3))
|
||||||
{
|
{
|
||||||
|
@ -174,15 +232,27 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
var resultMoveAvFull = MovingAverage.CheckByWindowAverageMean(data.timestamps, data.prices, windowMaxSize, 45, 180, 2.5m);
|
var resultMoveAvFull = MovingAverage.CheckByWindowAverageMean(data.timestamps, data.prices, windowMaxSize, 45, 180, 2.5m);
|
||||||
var resultLongClose = MovingAverage.CheckByWindowAverageMean(data.timestamps, data.prices, windowMaxSize, 15, 120, 2.5m).events;
|
var resultLongClose = MovingAverage.CheckByWindowAverageMean(data.timestamps, data.prices, windowMaxSize, 15, 120, 2.5m).events;
|
||||||
|
|
||||||
var uptrendStarts = LocalTrends.CheckByLocalTrends(data.timestamps, data.prices, TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(15), 2m, 10);
|
var uptrendStarts = LocalTrends.CheckByLocalTrends(data.timestamps, data.prices, TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(20), 1.5m, 15);
|
||||||
//var uptrendStarts2 = LocalTrends.CheckByLocalTrends(data.timestamps, data.prices, TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(3), 1.5m, 2);
|
//var uptrendStarts2 = LocalTrends.CheckByLocalTrends(data.timestamps, data.prices, TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(3), 1.5m, 2);
|
||||||
|
|
||||||
|
|
||||||
res |= (uptrendStarts & TradingEvent.UptrendStart);
|
res |= (uptrendStarts & TradingEvent.UptrendStart);
|
||||||
//res |= (uptrendStarts2 & TradingEvent.UptrendStart);
|
|
||||||
//res |= downtrendEnds;
|
|
||||||
res |= resultLongClose;
|
res |= resultLongClose;
|
||||||
res |= resultMoveAvFull.events;
|
res |= resultMoveAvFull.events;
|
||||||
|
|
||||||
|
//res = TradingEvent.None;
|
||||||
|
|
||||||
|
//if (!stopBuy &&RandomNumberGenerator.GetInt32(100) < 20)
|
||||||
|
//{
|
||||||
|
// res |= TradingEvent.UptrendStart;
|
||||||
|
//}
|
||||||
|
//else if (!stopSell && (RandomNumberGenerator.GetInt32(100) < 20))
|
||||||
|
//{
|
||||||
|
// res |= TradingEvent.UptrendEnd;
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (resultMoveAvFull.bigWindowAv != 0)
|
if (resultMoveAvFull.bigWindowAv != 0)
|
||||||
{
|
{
|
||||||
LogPrice(processedPrices, message, bigWindowProcessor, resultMoveAvFull.bigWindowAv);
|
LogPrice(processedPrices, message, bigWindowProcessor, resultMoveAvFull.bigWindowAv);
|
||||||
|
@ -190,7 +260,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
}
|
}
|
||||||
if ((resultLongClose & TradingEvent.StopBuy) == TradingEvent.StopBuy)
|
if ((resultLongClose & TradingEvent.StopBuy) == TradingEvent.StopBuy)
|
||||||
{
|
{
|
||||||
var stopTo = (message.IsHistoricalData ? message.Time : DateTime.UtcNow).AddMinutes(_buyStopLength);
|
var stopTo = (message.IsHistoricalData ? message.Time : DateTime.UtcNow).AddMinutes(_buyStopLength / 2);
|
||||||
OpeningStops.AddOrUpdate(message.Figi, stopTo, (k, v) => stopTo);
|
OpeningStops.AddOrUpdate(message.Figi, stopTo, (k, v) => stopTo);
|
||||||
//LogDeclision(declisionsForSave, DeclisionTradeAction.StopBuy, message);
|
//LogDeclision(declisionsForSave, DeclisionTradeAction.StopBuy, message);
|
||||||
}
|
}
|
||||||
|
@ -333,52 +403,32 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private decimal CalcProfit(string accountId, string figi, decimal closePrice)
|
private decimal GetLeverage(string figi, bool isShort)
|
||||||
{
|
{
|
||||||
if (_tradeDataProvider.Accounts.TryGetValue(accountId, out var account))
|
var res = 1m;
|
||||||
{
|
|
||||||
if (account.Assets.TryGetValue(figi, out var asset))
|
|
||||||
{
|
|
||||||
var leverageValue = 1m;
|
|
||||||
var isShort = asset.Position == PositionType.Short;
|
|
||||||
if (Leverages.TryGetValue(figi, out var leverage))
|
if (Leverages.TryGetValue(figi, out var leverage))
|
||||||
{
|
{
|
||||||
if (asset.Type == AssetType.Futures && !isShort)
|
res = isShort ? leverage.ShortLeverage : leverage.LongLeverage;
|
||||||
{
|
|
||||||
leverageValue = leverage.LongLeverage;
|
|
||||||
}
|
}
|
||||||
else if (isShort)
|
return res;
|
||||||
{
|
|
||||||
leverageValue = leverage.ShortLeverage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TradingCalculator.CaclProfit(asset.BoughtPrice, closePrice, GetComission(asset.Type), leverageValue, isShort);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private decimal GetCount(string accountId, decimal boutPrice)
|
internal static bool IsBuyAllowed(ManagedAccount account, decimal boutPrice, decimal count,
|
||||||
|
decimal accountCashPartFutures, decimal accountCashPart)
|
||||||
{
|
{
|
||||||
var balance = _tradeDataProvider.Accounts[accountId].Balance;
|
if (!BotModeSwitcher.CanPurchase()) return false;
|
||||||
return System.Math.Floor(balance * _defaultBuyPartOfAccount / boutPrice);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsBuyAllowed(string accountId, decimal boutPrice, decimal count, bool needBigCash)
|
var balance = account.Balance;
|
||||||
|
var total = account.Total;
|
||||||
|
|
||||||
|
var futures = account.Assets.Values.FirstOrDefault(v => v.Type == AssetType.Futures);
|
||||||
|
if (futures != null)
|
||||||
{
|
{
|
||||||
if (!_botModeSwitcher.CanPurchase()) return false;
|
if ((balance - boutPrice * count) / total < accountCashPartFutures) return false;
|
||||||
|
|
||||||
var balance = _tradeDataProvider.Accounts[accountId].Balance;
|
|
||||||
var total = _tradeDataProvider.Accounts[accountId].Total;
|
|
||||||
|
|
||||||
var futures = _tradeDataProvider.Accounts[accountId].Assets.Values.FirstOrDefault(v => v.Type == AssetType.Futures);
|
|
||||||
if (futures != null || needBigCash)
|
|
||||||
{
|
|
||||||
if ((balance - boutPrice * count) / total < _accountCashPartFutures) return false;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((balance - boutPrice * count) / total < _accountCashPart) return false;
|
if ((balance - boutPrice * count) / total < accountCashPart) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -10,11 +10,11 @@ namespace KLHZ.Trader.Core.Exchange.Utils
|
||||||
private readonly static TimeOnly _openTimeHoliday = new(7, 10);
|
private readonly static TimeOnly _openTimeHoliday = new(7, 10);
|
||||||
private readonly static TimeOnly _closeTimeHoliday = new(17, 45);
|
private readonly static TimeOnly _closeTimeHoliday = new(17, 45);
|
||||||
|
|
||||||
private readonly static TimeOnly _firstClearingStart = new(10, 55);
|
private readonly static TimeOnly _firstClearingStart = new(10, 45);
|
||||||
private readonly static TimeOnly _firstClearingEnd = new(11, 10);
|
private readonly static TimeOnly _firstClearingEnd = new(11, 10);
|
||||||
|
|
||||||
private readonly static TimeOnly _mainClearingStart = new(15, 50);
|
private readonly static TimeOnly _mainClearingStart = new(15, 45);
|
||||||
private readonly static TimeOnly _mainClearingEnd = new(16, 5);
|
private readonly static TimeOnly _mainClearingEnd = new(16, 10);
|
||||||
|
|
||||||
internal static ExchangeState GetCurrentState(DateTime? currentDt = null)
|
internal static ExchangeState GetCurrentState(DateTime? currentDt = null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,13 +15,11 @@ namespace KLHZ.Trader.Core.TG.Services
|
||||||
public class BotMessagesHandler : IUpdateHandler
|
public class BotMessagesHandler : IUpdateHandler
|
||||||
{
|
{
|
||||||
private readonly ImmutableArray<long> _admins = [];
|
private readonly ImmutableArray<long> _admins = [];
|
||||||
private readonly BotModeSwitcher _botModeSwitcher;
|
|
||||||
private readonly IDataBus _eventBus;
|
private readonly IDataBus _eventBus;
|
||||||
private readonly ILogger<BotMessagesHandler> _logger;
|
private readonly ILogger<BotMessagesHandler> _logger;
|
||||||
public BotMessagesHandler(BotModeSwitcher botModeSwitcher, IDataBus eventBus, IOptions<TgBotConfig> options, ILogger<BotMessagesHandler> logger)
|
public BotMessagesHandler(IDataBus eventBus, IOptions<TgBotConfig> options, ILogger<BotMessagesHandler> logger)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_botModeSwitcher = botModeSwitcher;
|
|
||||||
_eventBus = eventBus;
|
_eventBus = eventBus;
|
||||||
_admins = ImmutableArray.CreateRange(options.Value.Admins);
|
_admins = ImmutableArray.CreateRange(options.Value.Admins);
|
||||||
}
|
}
|
||||||
|
@ -52,25 +50,25 @@ namespace KLHZ.Trader.Core.TG.Services
|
||||||
}
|
}
|
||||||
case Constants.BotCommandsButtons.EnableSelling:
|
case Constants.BotCommandsButtons.EnableSelling:
|
||||||
{
|
{
|
||||||
_botModeSwitcher.StartSelling();
|
BotModeSwitcher.StartSelling();
|
||||||
await botClient.SendMessage(update.Message.Chat, "Продажи начаты!");
|
await botClient.SendMessage(update.Message.Chat, "Продажи начаты!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Constants.BotCommandsButtons.DisableSelling:
|
case Constants.BotCommandsButtons.DisableSelling:
|
||||||
{
|
{
|
||||||
_botModeSwitcher.StopSelling();
|
BotModeSwitcher.StopSelling();
|
||||||
await botClient.SendMessage(update.Message.Chat, "Продажи остановлены!");
|
await botClient.SendMessage(update.Message.Chat, "Продажи остановлены!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Constants.BotCommandsButtons.EnablePurchases:
|
case Constants.BotCommandsButtons.EnablePurchases:
|
||||||
{
|
{
|
||||||
_botModeSwitcher.StartPurchase();
|
BotModeSwitcher.StartPurchase();
|
||||||
await botClient.SendMessage(update.Message.Chat, "Покупки начаты!");
|
await botClient.SendMessage(update.Message.Chat, "Покупки начаты!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Constants.BotCommandsButtons.DisablePurchases:
|
case Constants.BotCommandsButtons.DisablePurchases:
|
||||||
{
|
{
|
||||||
_botModeSwitcher.StopPurchase();
|
BotModeSwitcher.StopPurchase();
|
||||||
await botClient.SendMessage(update.Message.Chat, "Покупки остановлены!");
|
await botClient.SendMessage(update.Message.Chat, "Покупки остановлены!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using KLHZ.Trader.Core.Common;
|
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Services;
|
using KLHZ.Trader.Core.Common.Messaging.Services;
|
||||||
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
|
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
|
||||||
using KLHZ.Trader.Core.DataLayer;
|
using KLHZ.Trader.Core.DataLayer;
|
||||||
|
@ -53,7 +52,6 @@ builder.Services.AddHostedService<TradingCommandsExecutor>();
|
||||||
builder.Services.AddSingleton<IUpdateHandler, BotMessagesHandler>();
|
builder.Services.AddSingleton<IUpdateHandler, BotMessagesHandler>();
|
||||||
|
|
||||||
builder.Services.AddSingleton<TradeDataProvider>();
|
builder.Services.AddSingleton<TradeDataProvider>();
|
||||||
builder.Services.AddSingleton<BotModeSwitcher>();
|
|
||||||
builder.Services.AddSingleton<IDataBus, DataBus>();
|
builder.Services.AddSingleton<IDataBus, DataBus>();
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
|
|
Loading…
Reference in New Issue