From ecd9a70e2e84b2ec21eca84fdcde791fc25e7499 Mon Sep 17 00:00:00 2001 From: vlad zverzhkhovskiy Date: Wed, 15 Oct 2025 16:19:58 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=81=D1=82=D1=80=D0=B0=D1=82=D0=B5=D0=B3?= =?UTF-8?q?=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Messaging/Dtos/TradeDataItem.cs | 23 ++ .../Declisions/Utils/LocalTrends.cs | 30 ++ .../ExchangeSchedulerTests.cs | 2 +- .../DataLayer/Entities/Prices/PriceChange.cs | 3 +- KLHZ.Trader.Core/Exchange/Constants.cs | 16 +- .../Trading/{ => Enums}/ExchangeState.cs | 2 +- .../Models/Trading/Enums/TradingMode.cs | 14 + KLHZ.Trader.Core/Exchange/Services/Trader.cs | 281 +++++++++++++++--- .../Exchange/Services/TraderDataProvider.cs | 17 -- .../Exchange/Utils/ExchangeScheduler.cs | 2 +- 10 files changed, 310 insertions(+), 80 deletions(-) rename KLHZ.Trader.Core/Exchange/Models/Trading/{ => Enums}/ExchangeState.cs (61%) create mode 100644 KLHZ.Trader.Core/Exchange/Models/Trading/Enums/TradingMode.cs diff --git a/KLHZ.Trader.Core.Contracts/Messaging/Dtos/TradeDataItem.cs b/KLHZ.Trader.Core.Contracts/Messaging/Dtos/TradeDataItem.cs index 3692642..a780745 100644 --- a/KLHZ.Trader.Core.Contracts/Messaging/Dtos/TradeDataItem.cs +++ b/KLHZ.Trader.Core.Contracts/Messaging/Dtos/TradeDataItem.cs @@ -1,4 +1,5 @@ using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces; +using System.ComponentModel.DataAnnotations.Schema; namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos { @@ -13,5 +14,27 @@ namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos public int Direction { get; set; } public decimal Value { get; init; } public decimal Value2 { get; init; } + [NotMapped] + public AttachedInfo? AttachedInfo + { + get + { + lock (_locker) + { + return _attachedInfo; + } + } + } + + public void SetAttachedInfo(AttachedInfo? attachedInfo) + { + lock (_locker) + { + _attachedInfo = attachedInfo; + } + } + + private AttachedInfo? _attachedInfo; + private readonly object _locker = new(); } } diff --git a/KLHZ.Trader.Core.Math/Declisions/Utils/LocalTrends.cs b/KLHZ.Trader.Core.Math/Declisions/Utils/LocalTrends.cs index 61b4aae..8025888 100644 --- a/KLHZ.Trader.Core.Math/Declisions/Utils/LocalTrends.cs +++ b/KLHZ.Trader.Core.Math/Declisions/Utils/LocalTrends.cs @@ -1,4 +1,5 @@ using KLHZ.Trader.Core.Contracts.Declisions.Dtos.Enums; +using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces; using MathNet.Numerics; namespace KLHZ.Trader.Core.Math.Declisions.Utils @@ -116,5 +117,34 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils return true; } } + + public static bool TryCalcTrendDiff(ITradeDataItem[] data, out decimal diff) + { + diff = 0; + if (data.Length <= 1) + { + return false; + } + else + { + var startTime = data[0].Time; + var x = new double[data.Length]; + for (int i = 0; i < data.Length; i++) + { + x[i] = (data[i].Time - startTime).TotalSeconds; + } + if (x.Min() == x.Max()) + { + return false; + } + var line = Fit.Line(x.ToArray(), data.Select(d => (double)d.Price).ToArray()); + + var p1 = line.A + line.B * 0; + var p2 = line.A + line.B * (data[data.Length - 1].Time - data[0].Time).TotalSeconds; + + diff = (decimal)(p2 - p1); + return true; + } + } } } diff --git a/KLHZ.Trader.Core.Tests/ExchangeSchedulerTests.cs b/KLHZ.Trader.Core.Tests/ExchangeSchedulerTests.cs index 6b15063..615c2cd 100644 --- a/KLHZ.Trader.Core.Tests/ExchangeSchedulerTests.cs +++ b/KLHZ.Trader.Core.Tests/ExchangeSchedulerTests.cs @@ -1,4 +1,4 @@ -using KLHZ.Trader.Core.Exchange.Models.Trading; +using KLHZ.Trader.Core.Exchange.Models.Trading.Enums; using KLHZ.Trader.Core.Exchange.Utils; namespace KLHZ.Trader.Core.Tests diff --git a/KLHZ.Trader.Core/DataLayer/Entities/Prices/PriceChange.cs b/KLHZ.Trader.Core/DataLayer/Entities/Prices/PriceChange.cs index 5f7497d..50ea37d 100644 --- a/KLHZ.Trader.Core/DataLayer/Entities/Prices/PriceChange.cs +++ b/KLHZ.Trader.Core/DataLayer/Entities/Prices/PriceChange.cs @@ -7,8 +7,6 @@ namespace KLHZ.Trader.Core.DataLayer.Entities.Prices [Table("price_changes")] public class PriceChange : ITradeDataItem { - private readonly object _locker = new(); - [Column("id")] public long Id { get; set; } @@ -59,5 +57,6 @@ namespace KLHZ.Trader.Core.DataLayer.Entities.Prices } private AttachedInfo? _attachedInfo; + private readonly object _locker = new(); } } diff --git a/KLHZ.Trader.Core/Exchange/Constants.cs b/KLHZ.Trader.Core/Exchange/Constants.cs index d98f92b..b76c5b3 100644 --- a/KLHZ.Trader.Core/Exchange/Constants.cs +++ b/KLHZ.Trader.Core/Exchange/Constants.cs @@ -2,24 +2,14 @@ { internal static class Constants { - internal const string _1minCacheKey = "1min"; - internal const string _15minSellCacheKey = "5min_sell"; - internal const string _5minSellCacheKey = "5min_sell"; - internal const string _5minBuyCacheKey = "5min_buy"; - internal const string _15minBuyCacheKey = "5min_buy"; - internal const string _1minSellCacheKey = "1min_sell"; - internal const string _1minBuyCacheKey = "1min_buy"; - - internal const string BigWindowCrossingAverageProcessor = "Trader_big"; - internal const string SmallWindowCrossingAverageProcessor = "Trader_small"; - internal const string AreasRelationProcessor = "balancescalc30min"; - internal readonly static TimeSpan AreasRelationWindow = TimeSpan.FromMinutes(15); - internal const decimal ForceExecuteCoefficient = 500000m; internal const decimal PowerUppingCoefficient = 1.69m; internal const decimal UppingCoefficient = 1.3m; internal const decimal LowingCoefficient = .76m; internal const decimal PowerLowingCoefficient = .59m; internal const decimal BlockingCoefficient = 0.01m; + + internal const string PriceIsInSupportLevel = "PriceIsInSupportLevel"; + internal const string PriceIsNotInSupportLevel = "PriceIsNotInSupportLevel"; } } diff --git a/KLHZ.Trader.Core/Exchange/Models/Trading/ExchangeState.cs b/KLHZ.Trader.Core/Exchange/Models/Trading/Enums/ExchangeState.cs similarity index 61% rename from KLHZ.Trader.Core/Exchange/Models/Trading/ExchangeState.cs rename to KLHZ.Trader.Core/Exchange/Models/Trading/Enums/ExchangeState.cs index 1afd49f..71f15f5 100644 --- a/KLHZ.Trader.Core/Exchange/Models/Trading/ExchangeState.cs +++ b/KLHZ.Trader.Core/Exchange/Models/Trading/Enums/ExchangeState.cs @@ -1,4 +1,4 @@ -namespace KLHZ.Trader.Core.Exchange.Models.Trading +namespace KLHZ.Trader.Core.Exchange.Models.Trading.Enums { internal enum ExchangeState { diff --git a/KLHZ.Trader.Core/Exchange/Models/Trading/Enums/TradingMode.cs b/KLHZ.Trader.Core/Exchange/Models/Trading/Enums/TradingMode.cs new file mode 100644 index 0000000..fb4ab32 --- /dev/null +++ b/KLHZ.Trader.Core/Exchange/Models/Trading/Enums/TradingMode.cs @@ -0,0 +1,14 @@ +namespace KLHZ.Trader.Core.Exchange.Models.Trading.Enums +{ + [Flags] + internal enum TradingMode + { + None = 0, + Growing = 1, + Falling = 2, + InSupportLevel = 4, + TryingGrowFromSupportLevel = 8, + TryingFallFromSupportLevel = 16, + Bezpont = 32, + } +} diff --git a/KLHZ.Trader.Core/Exchange/Services/Trader.cs b/KLHZ.Trader.Core/Exchange/Services/Trader.cs index 1939c0b..697a92e 100644 --- a/KLHZ.Trader.Core/Exchange/Services/Trader.cs +++ b/KLHZ.Trader.Core/Exchange/Services/Trader.cs @@ -10,6 +10,7 @@ using KLHZ.Trader.Core.Exchange.Interfaces; using KLHZ.Trader.Core.Exchange.Models.AssetsAccounting; using KLHZ.Trader.Core.Exchange.Models.Configs; using KLHZ.Trader.Core.Exchange.Models.Trading; +using KLHZ.Trader.Core.Exchange.Models.Trading.Enums; using KLHZ.Trader.Core.Exchange.Utils; using KLHZ.Trader.Core.Math.Declisions.Utils; using Microsoft.EntityFrameworkCore; @@ -37,6 +38,7 @@ namespace KLHZ.Trader.Core.Exchange.Services private readonly ConcurrentDictionary> SupportLevelsHistory = new(); private readonly ConcurrentDictionary _supportLevelsCalculationTimes = new(); + private readonly ConcurrentDictionary _marginCloses = new(); private readonly ConcurrentDictionary _usedSupportLevels = new(); private readonly ConcurrentDictionary _usedSupportLevelsForClosing = new(); private readonly ConcurrentDictionary _oldItems = new(); @@ -169,52 +171,173 @@ namespace KLHZ.Trader.Core.Exchange.Services { if (message.Figi == "FUTIMOEXF000") { - await CalcSupportLevels(message, 2, 3); + await CalcSupportLevels(message, 3, 3); + var processSupportLevelsRes = await ProcessSupportLevels(message); + var mode = await CalcTradingMode(message); var stops = GetStops(message); + if ((mode & TradingMode.InSupportLevel) == TradingMode.InSupportLevel) + { + if ((mode & TradingMode.Bezpont) == TradingMode.Bezpont) + { - var declisionsSupportLevels = await ProcessSupportLevels(message); - //var pirson = await CalcPirson(message); - //var mavRes = await CalcTimeWindowAverageValue(message); + } + else + { + var mavRes = await CalcTimeWindowAverageValue(message, true); + await ExecuteDeclisions(mavRes, message, stops, 1); + } + } + else + { + var mavRes = await CalcTimeWindowAverageValue(message); + var pirson = await CalcPirson(message); + var declisionPirson = ProcessPirson(pirson, message); + var declisionsStops = ProcessStops(stops, 2m); + var tradingModeResult = ProcessTradingMode(mode); - //var declisionPirson = ProcessPirson(pirson, message); - //var declisionsStops = ProcessStops(stops, 2m); + var res = TraderUtils.MergeResultsMult(declisionPirson, processSupportLevelsRes); + res = TraderUtils.MergeResultsMult(res, declisionsStops); + res = TraderUtils.MergeResultsMult(res, tradingModeResult); + res = TraderUtils.MergeResultsMax(res, mavRes); - - //var res = TraderUtils.MergeResultsMult(declisionPirson, declisionsSupportLevels); - //res = TraderUtils.MergeResultsMult(res, declisionsStops); - //res = TraderUtils.MergeResultsMax(res, mavRes); - - //await ExecuteDeclisions(res.ToImmutableDictionary(), message, stops, 1); + await ExecuteDeclisions(res.ToImmutableDictionary(), message, stops, 1); + } _oldItems[message.Figi] = message; } } - private async Task CheckTradingMode() + private async Task CalcTradingMode(ITradeDataItem message) { + var res = TradingMode.None; + //var res1hour = await CalcTradingMode(message, TimeSpan.FromMinutes(60),8); + //var res30min = await CalcTradingMode(message, TimeSpan.FromMinutes(30),6); + + var res20min = await CalcTradingMode(message, TimeSpan.FromMinutes(20), 3); + var res10min = await CalcTradingMode(message, TimeSpan.FromMinutes(10), 3); + //res |= res1hour; + //res|=res30min; + res |= res20min; + res &= res10min; + + if ((res & TradingMode.TryingGrowFromSupportLevel) == TradingMode.TryingGrowFromSupportLevel) + { + await _tradeDataProvider.LogPrice(message, "TryingGrowFromSupportLevel", message.Price); + } + if ((res & TradingMode.TryingFallFromSupportLevel) == TradingMode.TryingFallFromSupportLevel) + { + await _tradeDataProvider.LogPrice(message, "TryingFallFromSupportLevel", message.Price); + } + + if ((res & TradingMode.InSupportLevel) == TradingMode.InSupportLevel) + { + await _tradeDataProvider.LogPrice(message, "InSupportLevel", message.Price); + } + if ((res & TradingMode.Growing) == TradingMode.Growing) + { + await _tradeDataProvider.LogPrice(message, "InSupportLevelGrowing", message.Price); + } + if ((res & TradingMode.Falling) == TradingMode.Falling) + { + await _tradeDataProvider.LogPrice(message, "InSupportLevelGrowingFalling", message.Price); + } + if ((res & TradingMode.Bezpont) == TradingMode.Bezpont) + { + var data = await _tradeDataProvider.GetDataForTimeWindow(message.Figi, TimeSpan.FromMinutes(30), selector: (i) => i.Direction == 1); + + if (data.Any() && (data.Max(d => d.Price) - data.Min(d => d.Price)) < 4) + { + await _tradeDataProvider.LogPrice(message, "Bezpont", message.Price); + } + else + { + res |= ~TradingMode.Bezpont; + } + } + + return res; } - private async Task> CalcTimeWindowAverageValue(ITradeDataItem message) + private async Task CalcTradingMode(ITradeDataItem message, TimeSpan period, decimal meanfullValue) + { + var res = TradingMode.None; + + var data = await _tradeDataProvider.GetDataForTimeWindow(message.Figi, period); + if (LocalTrends.TryCalcTrendDiff(data, out var diff)) + { + var items = data.Where(d => d.AttachedInfo != null).ToArray(); + var itemsInSupportLevels = (decimal)items.Count(i => i.AttachedInfo?.Key == Constants.PriceIsInSupportLevel); + var itemsHigherThenSupportLevel = (decimal)items.Count(i => i.AttachedInfo?.Key == Constants.PriceIsNotInSupportLevel + && (i.AttachedInfo?.Value2 < i.Price)); + var itemsLowerThenSupportLevel = (decimal)items.Count(i => i.AttachedInfo?.Key == Constants.PriceIsNotInSupportLevel + && (i.AttachedInfo?.Value1 > i.Price)); + + if (items.Length > 0) + { + var itemsInSupportLevelsRel = itemsInSupportLevels / items.Length; + var itemsHigherThenSupportLevelRel = itemsHigherThenSupportLevel / items.Length; + var itemsLowerThenSupportLevelRel = itemsLowerThenSupportLevel / items.Length; + + if (itemsInSupportLevelsRel > 0.7m && message?.AttachedInfo?.Key == Constants.PriceIsInSupportLevel) + { + res |= TradingMode.InSupportLevel; + if (itemsHigherThenSupportLevelRel > 0.05m && (itemsLowerThenSupportLevelRel == 0 || itemsHigherThenSupportLevelRel / itemsLowerThenSupportLevelRel > 2)) + { + res |= TradingMode.TryingGrowFromSupportLevel; + } + if (itemsLowerThenSupportLevelRel > 0.05m && (itemsHigherThenSupportLevelRel == 0 || itemsLowerThenSupportLevelRel / itemsHigherThenSupportLevelRel > 2)) + { + res |= TradingMode.TryingGrowFromSupportLevel; + } + } + + + if (diff > meanfullValue) + { + res |= TradingMode.Growing; + } + if (diff < -meanfullValue) + { + res |= TradingMode.Falling; + } + if (itemsInSupportLevelsRel > 0.8m && message?.AttachedInfo?.Key == Constants.PriceIsInSupportLevel && + System.Math.Abs(diff) < 1.5m * meanfullValue) + { + res |= TradingMode.Bezpont; + } + } + } + + return res; + } + + private async Task> CalcTimeWindowAverageValue(ITradeDataItem message, bool calcOpens = false) { var res = TraderUtils.GetInitDict(Constants.BlockingCoefficient); var cacheSize = TimeSpan.FromSeconds(60 * 60); var data = await _tradeDataProvider.GetDataForTimeWindow(message.Figi, cacheSize, selector: (i) => i.Direction == 1); + + if (calcOpens) + { + var re = MovingAverage.CheckByWindowAverageMean2(data, 100, 15, 300, -2m, 2m); + + if ((re.events & TradingEvent.OpenShort) == TradingEvent.OpenShort) + { + res[TradingEvent.OpenShort] = Constants.PowerUppingCoefficient; + } + if ((re.events & TradingEvent.OpenLong) == TradingEvent.OpenLong) + { + res[TradingEvent.OpenLong] = Constants.PowerUppingCoefficient; + } + } + var closings = MovingAverage.CheckByWindowAverageMean2(data, data.Length, 15, 300, -5m, 5m); - //var re = MovingAverage.CheckByWindowAverageMean2(data, 100, 15, 300, -4m, 4m); if (closings.smallWindowAv != 0) { await _tradeDataProvider.LogPrice(message, "maw_small", closings.smallWindowAv); await _tradeDataProvider.LogPrice(message, "maw_big", closings.bigWindowAv); } - //if ((re.events & TradingEvent.OpenShort) == TradingEvent.OpenShort) - //{ - // res[TradingEvent.OpenShort] = Constants.PowerUppingCoefficient; - //} - //if ((re.events & TradingEvent.OpenLong) == TradingEvent.OpenLong) - //{ - // res[TradingEvent.OpenLong] = Constants.PowerUppingCoefficient; - //} if ((closings.events & TradingEvent.CloseShort) == TradingEvent.CloseShort) { res[TradingEvent.CloseShort] = Constants.PowerUppingCoefficient; @@ -227,6 +350,23 @@ namespace KLHZ.Trader.Core.Exchange.Services return res.ToImmutableDictionary(); } + private ImmutableDictionary ProcessTradingMode(TradingMode mode) + { + var res = TraderUtils.GetInitDict(1); + if ((mode & TradingMode.Growing) == TradingMode.Growing) + { + res[TradingEvent.OpenShort] = Constants.BlockingCoefficient; + res[TradingEvent.OpenLong] = Constants.UppingCoefficient; + } + if ((mode & TradingMode.Falling) == TradingMode.Growing) + { + res[TradingEvent.OpenLong] = Constants.BlockingCoefficient; + res[TradingEvent.OpenShort] = Constants.UppingCoefficient; + } + + return res.ToImmutableDictionary(); + } + private ImmutableDictionary ProcessPirson(PirsonCalculatingResult pirson, ITradeDataItem message) { var res = TraderUtils.GetInitDict(Constants.BlockingCoefficient); @@ -244,6 +384,28 @@ namespace KLHZ.Trader.Core.Exchange.Services } + if (pirson.Pirson > 0.5m && pirson.Pirson < 0.8m && (pirson.Pirson - olddpirs > 0.05m) && pirson.PriceDiff > 0 && (pirson.TradesDiffRelative > 0.25m)) + { + res[TradingEvent.OpenLong] = Constants.PowerUppingCoefficient; + } + + if (pirson.Pirson < -0.5m && pirson.Pirson > -0.8m && (pirson.Pirson - olddpirs < -0.05m) && pirson.PriceDiff < 0 && (pirson.TradesDiffRelative > 0.25m)) + { + res[TradingEvent.OpenShort] = Constants.PowerUppingCoefficient; + } + + //if (pirson.Pirson > 0.7m && (pirson.Pirson > olddpirs) && pirson.PriceDiff > 0 && (pirson.TradesDiffRelative > 0.25m)) + //{ + // res[TradingEvent.OpenLong] = Constants.UppingCoefficient; + //} + + //if (pirson.Pirson < -0.7m && (pirson.Pirson < olddpirs) && pirson.PriceDiff < 0 && (pirson.TradesDiffRelative > 0.25m)) + //{ + // res[TradingEvent.OpenShort] = Constants.UppingCoefficient; + //} + + + if (olddpirs > 0.9m && pirson.Pirson <= 0.9m && pirson.TradesDiffRelative < -0.1m && pirson.TradesDiff <= 0) { res[TradingEvent.CloseLong] = Constants.PowerUppingCoefficient; @@ -318,8 +480,16 @@ namespace KLHZ.Trader.Core.Exchange.Services var state = ExchangeScheduler.GetCurrentState(message.Time); if (!message.IsHistoricalData && state == ExchangeState.ClearingTime) { + if (_marginCloses.TryGetValue(string.Empty, out var time)) + { + if (message.Time - time < TimeSpan.FromHours(2)) + { + return; + } + } var futuresFigis = _portfolioWrapper.Accounts.Values.SelectMany(v => v.Assets.Values.Where(a => a.Type == AssetType.Futures)).ToArray(); await ClosePositions(futuresFigis, message, false); + _marginCloses[string.Empty] = message.Time; } } @@ -492,7 +662,7 @@ namespace KLHZ.Trader.Core.Exchange.Services var closingResult = await _portfolioWrapper.Accounts[asset.AccountId].ClosePosition(message.Figi); if (closingResult.Success) { - var profitText = profit == 0 ? string.Empty : ", профит {profit}"; + var profitText = profit == 0 ? string.Empty : $", профит {profit}"; mess = $"Закрываю позицию {asset.Figi} ({(asset.Count > 0 ? "лонг" : "шорт")}) на счёте {_portfolioWrapper.Accounts[asset.AccountId].AccountName}. Количество {(long)asset.Count}, цена ~{closingResult.ExecutedPrice / (settings?.PointPriceRub ?? 1)}, комиссия {closingResult.Comission}" + profitText; } else @@ -543,7 +713,7 @@ namespace KLHZ.Trader.Core.Exchange.Services private async Task ExecuteDeclisions(ImmutableDictionary result, ITradeDataItem message, Stops st, int accountsForOpening = 1) { var state = ExchangeScheduler.GetCurrentState(message.Time); - if (result[TradingEvent.OpenLong] >= Constants.UppingCoefficient + if (result[TradingEvent.OpenLong] > Constants.UppingCoefficient && state == ExchangeState.Open ) { @@ -565,7 +735,7 @@ namespace KLHZ.Trader.Core.Exchange.Services //await _tradeDataProvider.LogDeclision(DeclisionTradeAction.ResetStopsLong, valHigh, message.Time.AddMilliseconds(-RandomNumberGenerator.GetInt32(300, 1000)), message); await _tradeDataProvider.LogDeclision(DeclisionTradeAction.ResetStopsLong, valLow, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(300, 1000)), message); } - if (result[TradingEvent.OpenShort] >= Constants.UppingCoefficient + if (result[TradingEvent.OpenShort] > Constants.UppingCoefficient && state == ExchangeState.Open ) { @@ -680,12 +850,15 @@ namespace KLHZ.Trader.Core.Exchange.Services if (message.Price > nearestLevel.HighValue) { longStopLossShift = message.Price - nearestLevel.HighValue + additionalShift; + shortStopLossShift = message.Price - nearestLevel.HighValue + additionalShift; } nearestLevel = levelsByDiffForShort[0]; if (message.Price < nearestLevel.LowValue) { shortStopLossShift = nearestLevel.LowValue - message.Price + additionalShift; + longStopLossShift = nearestLevel.LowValue - message.Price + additionalShift; + } } } @@ -729,6 +902,13 @@ namespace KLHZ.Trader.Core.Exchange.Services var levelByTime = levelsByTime[0]; if (message.Price >= levelByTime.LowValue && message.Price < levelByTime.HighValue) { + var info = new AttachedInfo() + { + Key = Constants.PriceIsInSupportLevel, + Value1 = levelByTime.LowValue, + Value2 = levelByTime.HighValue, + }; + message.SetAttachedInfo(info); if (message.Price > levelByTime.Value) { res[TradingEvent.OpenLong] = Constants.BlockingCoefficient; @@ -763,35 +943,46 @@ namespace KLHZ.Trader.Core.Exchange.Services } } - else if (_oldItems.TryGetValue(message.Figi, out var old)) + else { - if (old.Price >= levelByTime.LowValue && old.Price < levelByTime.HighValue) + var info = new AttachedInfo() { - var islevelUsed = false; - if (_usedSupportLevels.TryGetValue(message.Figi, out var time)) + Key = Constants.PriceIsNotInSupportLevel, + Value1 = levelByTime.LowValue, + Value2 = levelByTime.HighValue, + }; + message.SetAttachedInfo(info); + if (_oldItems.TryGetValue(message.Figi, out var old)) + { + if (old.Price >= levelByTime.LowValue && old.Price < levelByTime.HighValue) { - if (time == levelByTime.CalculatedAt) + var islevelUsed = false; + if (_usedSupportLevels.TryGetValue(message.Figi, out var time)) { - islevelUsed = true; + if (time == levelByTime.CalculatedAt) + { + islevelUsed = true; + } } - } - if (!islevelUsed) - { - if (message.Price < levelByTime.LowValue) + if (!islevelUsed) { - res[TradingEvent.OpenShort] = Constants.ForceExecuteCoefficient; - res[TradingEvent.OpenLong] = Constants.ForceExecuteCoefficient; - _usedSupportLevels[message.Figi] = levelByTime.CalculatedAt; - } - else if (message.Price > levelByTime.HighValue) - { - res[TradingEvent.OpenShort] = Constants.ForceExecuteCoefficient; - res[TradingEvent.OpenLong] = Constants.ForceExecuteCoefficient; - _usedSupportLevels[message.Figi] = levelByTime.CalculatedAt; + if (message.Price < levelByTime.LowValue) + { + res[TradingEvent.OpenShort] = Constants.UppingCoefficient; + res[TradingEvent.OpenLong] = Constants.UppingCoefficient; + _usedSupportLevels[message.Figi] = levelByTime.CalculatedAt; + } + else if (message.Price > levelByTime.HighValue) + { + res[TradingEvent.OpenShort] = Constants.UppingCoefficient; + res[TradingEvent.OpenLong] = Constants.UppingCoefficient; + _usedSupportLevels[message.Figi] = levelByTime.CalculatedAt; + } } } } } + } } return res.ToImmutableDictionary(); diff --git a/KLHZ.Trader.Core/Exchange/Services/TraderDataProvider.cs b/KLHZ.Trader.Core/Exchange/Services/TraderDataProvider.cs index d3f8f2b..c74fa4c 100644 --- a/KLHZ.Trader.Core/Exchange/Services/TraderDataProvider.cs +++ b/KLHZ.Trader.Core/Exchange/Services/TraderDataProvider.cs @@ -89,23 +89,6 @@ namespace KLHZ.Trader.Core.Exchange.Services return ValueTask.FromResult(Array.Empty()); } - public ValueTask GetDataFrom20SecondsWindowCache2(string figi, string key) - { - return GetDataForTimeWindow(figi, TimeSpan.FromSeconds(20), key); - } - - public ValueTask GetDataFrom1MinuteWindowCache2(string figi, string key) - { - return GetDataForTimeWindow(figi, TimeSpan.FromSeconds(60), key); - } - public ValueTask GetDataFrom5MinuteWindowCache2(string figi, string key) - { - return GetDataForTimeWindow(figi, TimeSpan.FromMinutes(5), key); - } - public ValueTask GetDataFrom15MinuteWindowCache2(string figi, string key) - { - return GetDataForTimeWindow(figi, TimeSpan.FromMinutes(15), key); - } public async ValueTask AddOrderbook(IOrderbook orderbook) { if (!_historyCash3.TryGetValue(orderbook.Figi, out var unit)) diff --git a/KLHZ.Trader.Core/Exchange/Utils/ExchangeScheduler.cs b/KLHZ.Trader.Core/Exchange/Utils/ExchangeScheduler.cs index 311bbfa..c27651e 100644 --- a/KLHZ.Trader.Core/Exchange/Utils/ExchangeScheduler.cs +++ b/KLHZ.Trader.Core/Exchange/Utils/ExchangeScheduler.cs @@ -1,4 +1,4 @@ -using KLHZ.Trader.Core.Exchange.Models.Trading; +using KLHZ.Trader.Core.Exchange.Models.Trading.Enums; namespace KLHZ.Trader.Core.Exchange.Utils {