From 64c702ebf18fb796fbe40e57a5cafc856acd144d Mon Sep 17 00:00:00 2001 From: vlad zverzhkhovskiy Date: Tue, 7 Oct 2025 13:05:38 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A7=D0=B8=D1=81=D1=82=D0=BA=D0=B0=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Declisions/Dtos/CachedValue.cs | 10 +- .../Declisions/Interfaces/ICachedValue.cs | 10 + .../Messaging/Dtos/Interfaces/INewPrice.cs | 14 +- .../Messaging/Dtos/NewPriceMessage.cs | 2 +- .../Services/Cache/PriceHistoryCacheUnit2.cs | 2 +- .../Declisions/Utils/Statistics.cs | 6 +- .../HistoryCacheUnit2Tests.cs | 32 +- .../DataLayer/Entities/Prices/PriceChange.cs | 2 +- .../Entities/Prices/ProcessedPrice.cs | 2 +- .../Exchange/Models/Configs/ExchangeConfig.cs | 2 - .../Exchange/Services/ExchangeDataReader.cs | 2 +- KLHZ.Trader.Core/Exchange/Services/Trader.cs | 428 ++++-------------- .../Exchange/Services/TraderDataProvider.cs | 12 +- .../Exchange/Utils/TraderUtils.cs | 2 +- .../Controllers/PlayController.cs | 337 +------------- KLHZ.Trader.Service/Models/TimeSeriesData.cs | 2 +- KLHZ.Trader.Service/appsettings.json | 2 - 17 files changed, 135 insertions(+), 732 deletions(-) create mode 100644 KLHZ.Trader.Core.Contracts/Declisions/Interfaces/ICachedValue.cs diff --git a/KLHZ.Trader.Core.Contracts/Declisions/Dtos/CachedValue.cs b/KLHZ.Trader.Core.Contracts/Declisions/Dtos/CachedValue.cs index 52d6872..510916a 100644 --- a/KLHZ.Trader.Core.Contracts/Declisions/Dtos/CachedValue.cs +++ b/KLHZ.Trader.Core.Contracts/Declisions/Dtos/CachedValue.cs @@ -1,9 +1,15 @@ namespace KLHZ.Trader.Core.Contracts.Declisions.Dtos { - public class CachedValue + public class CachedValue //: ICachedValue { public DateTime Time { get; init; } - public decimal Count { get; init; } + public long Count { get; init; } public decimal Price { get; init; } + public decimal Value { get; init; } + public decimal Value2 { get; init; } + //public bool IsHistoricalData { get; init; } + //public required string Figi { get; init; } = string.Empty; + //public required string Ticker { get; init; } = string.Empty; + //public int Direction { get; init; } } } diff --git a/KLHZ.Trader.Core.Contracts/Declisions/Interfaces/ICachedValue.cs b/KLHZ.Trader.Core.Contracts/Declisions/Interfaces/ICachedValue.cs new file mode 100644 index 0000000..c25f851 --- /dev/null +++ b/KLHZ.Trader.Core.Contracts/Declisions/Interfaces/ICachedValue.cs @@ -0,0 +1,10 @@ +using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces; + +namespace KLHZ.Trader.Core.Contracts.Declisions.Interfaces +{ + internal interface ICachedValue : INewPrice + { + public decimal Value { get; } + public decimal Value2 { get; } + } +} diff --git a/KLHZ.Trader.Core.Contracts/Messaging/Dtos/Interfaces/INewPrice.cs b/KLHZ.Trader.Core.Contracts/Messaging/Dtos/Interfaces/INewPrice.cs index 9ad2df7..36c905d 100644 --- a/KLHZ.Trader.Core.Contracts/Messaging/Dtos/Interfaces/INewPrice.cs +++ b/KLHZ.Trader.Core.Contracts/Messaging/Dtos/Interfaces/INewPrice.cs @@ -2,12 +2,12 @@ { public interface INewPrice { - public bool IsHistoricalData { get; set; } - public decimal Value { get; set; } - public string Figi { get; set; } - public string Ticker { get; set; } - public DateTime Time { get; set; } - public long Count { get; set; } - public int Direction { get; set; } + public bool IsHistoricalData { get; } + public decimal Price { get; } + public string Figi { get; } + public string Ticker { get; } + public DateTime Time { get; } + public long Count { get; } + public int Direction { get; } } } diff --git a/KLHZ.Trader.Core.Contracts/Messaging/Dtos/NewPriceMessage.cs b/KLHZ.Trader.Core.Contracts/Messaging/Dtos/NewPriceMessage.cs index 4da2112..ea5b145 100644 --- a/KLHZ.Trader.Core.Contracts/Messaging/Dtos/NewPriceMessage.cs +++ b/KLHZ.Trader.Core.Contracts/Messaging/Dtos/NewPriceMessage.cs @@ -4,7 +4,7 @@ namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos { public class NewPriceMessage : INewPrice { - public decimal Value { get; set; } + public decimal Price { get; set; } public required string Figi { get; set; } public required string Ticker { get; set; } public DateTime Time { get; set; } diff --git a/KLHZ.Trader.Core.Math/Declisions/Services/Cache/PriceHistoryCacheUnit2.cs b/KLHZ.Trader.Core.Math/Declisions/Services/Cache/PriceHistoryCacheUnit2.cs index b81fe9b..6c64191 100644 --- a/KLHZ.Trader.Core.Math/Declisions/Services/Cache/PriceHistoryCacheUnit2.cs +++ b/KLHZ.Trader.Core.Math/Declisions/Services/Cache/PriceHistoryCacheUnit2.cs @@ -111,7 +111,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Services.Cache lock (_locker) { _pointer++; - Prices[_pointer] = priceChange.Value; + Prices[_pointer] = priceChange.Price; Timestamps[_pointer] = priceChange.Time; if (_length < CacheMaxLength) { diff --git a/KLHZ.Trader.Core.Math/Declisions/Utils/Statistics.cs b/KLHZ.Trader.Core.Math/Declisions/Utils/Statistics.cs index 850002c..a2a92a2 100644 --- a/KLHZ.Trader.Core.Math/Declisions/Utils/Statistics.cs +++ b/KLHZ.Trader.Core.Math/Declisions/Utils/Statistics.cs @@ -94,9 +94,9 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils { var tradevolume_diffMean = values.Mean(); var dprice_diffMean = values.Mean2(); - var sum1 = (double)values.Sum(d => (d.Count - tradevolume_diffMean) * (d.Price - dprice_diffMean)); - var sum2 = values.Sum(d => (d.Count - tradevolume_diffMean) * (d.Count - tradevolume_diffMean)); - var sum3 = values.Sum(d => (d.Price - dprice_diffMean) * (d.Price - dprice_diffMean)); + var sum1 = (double)values.Sum(d => (d.Value2 - tradevolume_diffMean) * (d.Value - dprice_diffMean)); + var sum2 = values.Sum(d => (d.Value2 - tradevolume_diffMean) * (d.Value2 - tradevolume_diffMean)); + var sum3 = values.Sum(d => (d.Value - dprice_diffMean) * (d.Value - dprice_diffMean)); if (sum2 != 0 && sum3 != 0) { result = (decimal)(sum1 / System.Math.Sqrt((double)(sum2 * sum3))); diff --git a/KLHZ.Trader.Core.Tests/HistoryCacheUnit2Tests.cs b/KLHZ.Trader.Core.Tests/HistoryCacheUnit2Tests.cs index 99c8019..fd06664 100644 --- a/KLHZ.Trader.Core.Tests/HistoryCacheUnit2Tests.cs +++ b/KLHZ.Trader.Core.Tests/HistoryCacheUnit2Tests.cs @@ -20,7 +20,7 @@ namespace KLHZ.Trader.Core.Tests Ticker = figi + "_ticker", Id = i, Time = startDt, - Value = (decimal)(i + 0.5) + Price = (decimal)(i + 0.5) }; } } @@ -53,7 +53,7 @@ namespace KLHZ.Trader.Core.Tests Assert.That(data.timestamps.Length == count); for (var i = 0; i < count; i++) { - Assert.That((float)hist[i].Value, Is.EqualTo(data.prices[i])); + Assert.That((float)hist[i].Price, Is.EqualTo(data.prices[i])); Assert.That(hist[i].Time, Is.EqualTo(data.timestamps[i])); } } @@ -72,7 +72,7 @@ namespace KLHZ.Trader.Core.Tests for (var i = 0; i < count; i++) { - Assert.That((float)hist[i].Value, Is.EqualTo(data.prices[i])); + Assert.That((float)hist[i].Price, Is.EqualTo(data.prices[i])); Assert.That(hist[i].Time, Is.EqualTo(data.timestamps[i])); } } @@ -91,7 +91,7 @@ namespace KLHZ.Trader.Core.Tests for (var i = 0; i < count; i++) { - Assert.That((float)hist[i].Value, Is.EqualTo(data.prices[i])); + Assert.That((float)hist[i].Price, Is.EqualTo(data.prices[i])); Assert.That(hist[i].Time, Is.EqualTo(data.timestamps[i])); } } @@ -114,7 +114,7 @@ namespace KLHZ.Trader.Core.Tests var k = i + shift; if (k < hist.Length) { - Assert.That((float)hist[k].Value, Is.EqualTo(data.prices[i])); + Assert.That((float)hist[k].Price, Is.EqualTo(data.prices[i])); Assert.That(hist[k].Time, Is.EqualTo(data.timestamps[i])); } } @@ -138,7 +138,7 @@ namespace KLHZ.Trader.Core.Tests var k = i + shift; if (k < hist.Length) { - Assert.That((float)hist[k].Value, Is.EqualTo(data.prices[i])); + Assert.That((float)hist[k].Price, Is.EqualTo(data.prices[i])); Assert.That(hist[k].Time, Is.EqualTo(data.timestamps[i])); } } @@ -162,7 +162,7 @@ namespace KLHZ.Trader.Core.Tests var k = i + shift; if (k < hist.Length) { - Assert.That((float)hist[k].Value, Is.EqualTo(data.prices[i])); + Assert.That((float)hist[k].Price, Is.EqualTo(data.prices[i])); Assert.That(hist[k].Time, Is.EqualTo(data.timestamps[i])); } } @@ -183,24 +183,24 @@ namespace KLHZ.Trader.Core.Tests for (var i = 0; i < count; i++) { - Assert.That((float)hist[i].Value, Is.EqualTo(data.prices[i])); + Assert.That((float)hist[i].Price, Is.EqualTo(data.prices[i])); Assert.That(hist[i].Time, Is.EqualTo(data.timestamps[i])); } - var newData1 = new PriceChange() { Figi = figi, Ticker = figi, Value = 100500, Time = DateTime.UtcNow }; + var newData1 = new PriceChange() { Figi = figi, Ticker = figi, Price = 100500, Time = DateTime.UtcNow }; cacheUnit.AddData(newData1); var data2 = cacheUnit.GetData().Result; - Assert.IsTrue(data2.prices[data2.prices.Length - 1] == newData1.Value); + Assert.IsTrue(data2.prices[data2.prices.Length - 1] == newData1.Price); Assert.IsTrue(data2.timestamps[data2.timestamps.Length - 1] == newData1.Time); - var newData2 = new PriceChange() { Figi = figi, Ticker = figi, Value = 100501, Time = DateTime.UtcNow }; + var newData2 = new PriceChange() { Figi = figi, Ticker = figi, Price = 100501, Time = DateTime.UtcNow }; cacheUnit.AddData(newData2); var data3 = cacheUnit.GetData().Result; - Assert.IsTrue(data3.prices[data3.prices.Length - 1] == newData2.Value); + Assert.IsTrue(data3.prices[data3.prices.Length - 1] == newData2.Price); Assert.IsTrue(data3.timestamps[data3.timestamps.Length - 1] == newData2.Time); } @@ -210,7 +210,7 @@ namespace KLHZ.Trader.Core.Tests var cacheUnit = new PriceHistoryCacheUnit2(""); for (int i = 0; i < 5 * PriceHistoryCacheUnit2.CacheMaxLength; i++) { - cacheUnit.AddData(new PriceChange() { Figi = "", Ticker = "", Value = i, Time = DateTime.UtcNow }); + cacheUnit.AddData(new PriceChange() { Figi = "", Ticker = "", Price = i, Time = DateTime.UtcNow }); if (i >= PriceHistoryCacheUnit2.CacheMaxLength) { var data = cacheUnit.GetData().Result; @@ -237,11 +237,11 @@ namespace KLHZ.Trader.Core.Tests Assert.That(data.prices.Length == length); Assert.That(data.timestamps.Length == length); - Assert.That(data.prices.Last() == hist.Last().Value); + Assert.That(data.prices.Last() == hist.Last().Price); Assert.That(data.timestamps.Last() == hist.Last().Time); for (var i = 1; i <= length; i++) { - Assert.That(hist[hist.Length - i].Value, Is.EqualTo(data.prices[data.prices.Length - i])); + Assert.That(hist[hist.Length - i].Price, Is.EqualTo(data.prices[data.prices.Length - i])); Assert.That(hist[hist.Length - i].Time, Is.EqualTo(data.timestamps[data.prices.Length - i])); } } @@ -267,7 +267,7 @@ namespace KLHZ.Trader.Core.Tests Assert.That(data.prices.Length == length); Assert.That(data.timestamps.Length == length); - Assert.That(data.prices.Last() == hist.Last().Value); + Assert.That(data.prices.Last() == hist.Last().Price); Assert.That(data.timestamps.Last() == hist.Last().Time); } diff --git a/KLHZ.Trader.Core/DataLayer/Entities/Prices/PriceChange.cs b/KLHZ.Trader.Core/DataLayer/Entities/Prices/PriceChange.cs index 3ecade0..eaeb7bf 100644 --- a/KLHZ.Trader.Core/DataLayer/Entities/Prices/PriceChange.cs +++ b/KLHZ.Trader.Core/DataLayer/Entities/Prices/PriceChange.cs @@ -13,7 +13,7 @@ namespace KLHZ.Trader.Core.DataLayer.Entities.Prices public DateTime Time { get; set; } [Column("value")] - public decimal Value { get; set; } + public decimal Price { get; set; } [Column("figi")] public required string Figi { get; set; } diff --git a/KLHZ.Trader.Core/DataLayer/Entities/Prices/ProcessedPrice.cs b/KLHZ.Trader.Core/DataLayer/Entities/Prices/ProcessedPrice.cs index 0b28df1..cbe43fa 100644 --- a/KLHZ.Trader.Core/DataLayer/Entities/Prices/ProcessedPrice.cs +++ b/KLHZ.Trader.Core/DataLayer/Entities/Prices/ProcessedPrice.cs @@ -13,7 +13,7 @@ namespace KLHZ.Trader.Core.DataLayer.Entities.Prices public DateTime Time { get; set; } [Column("value")] - public decimal Value { get; set; } + public decimal Price { get; set; } [Column("figi")] public required string Figi { get; set; } diff --git a/KLHZ.Trader.Core/Exchange/Models/Configs/ExchangeConfig.cs b/KLHZ.Trader.Core/Exchange/Models/Configs/ExchangeConfig.cs index c467f43..5b54692 100644 --- a/KLHZ.Trader.Core/Exchange/Models/Configs/ExchangeConfig.cs +++ b/KLHZ.Trader.Core/Exchange/Models/Configs/ExchangeConfig.cs @@ -3,12 +3,10 @@ public class ExchangeConfig { public bool ExchangeDataRecievingEnabled { get; init; } - public decimal StopBuyLengthMinuts { get; init; } public decimal FutureComission { get; init; } public decimal ShareComission { get; init; } public decimal AccountCashPart { get; init; } public decimal AccountCashPartFutures { get; init; } - public decimal DefaultBuyPartOfAccount { get; init; } public string[] DataRecievingInstrumentsFigis { get; init; } = []; public string[] TradingInstrumentsFigis { get; init; } = []; public string[] ManagingAccountNamePatterns { get; init; } = []; diff --git a/KLHZ.Trader.Core/Exchange/Services/ExchangeDataReader.cs b/KLHZ.Trader.Core/Exchange/Services/ExchangeDataReader.cs index dddfb8a..ca0dda8 100644 --- a/KLHZ.Trader.Core/Exchange/Services/ExchangeDataReader.cs +++ b/KLHZ.Trader.Core/Exchange/Services/ExchangeDataReader.cs @@ -149,7 +149,7 @@ namespace KLHZ.Trader.Core.Exchange.Services Figi = response.Trade.Figi, Ticker = _tradeDataProvider.GetTickerByFigi(response.Trade.Figi), Time = response.Trade.Time.ToDateTime().ToUniversalTime(), - Value = response.Trade.Price, + Price = response.Trade.Price, IsHistoricalData = false, Direction = (int)response.Trade.Direction, Count = response.Trade.Quantity, diff --git a/KLHZ.Trader.Core/Exchange/Services/Trader.cs b/KLHZ.Trader.Core/Exchange/Services/Trader.cs index 5b397cb..ec5ff17 100644 --- a/KLHZ.Trader.Core/Exchange/Services/Trader.cs +++ b/KLHZ.Trader.Core/Exchange/Services/Trader.cs @@ -39,11 +39,6 @@ namespace KLHZ.Trader.Core.Exchange.Services private readonly ConcurrentDictionary DPirsonValues = new(); - private readonly ConcurrentDictionary LongOpeningStops = new(); - private readonly ConcurrentDictionary ShortOpeningStops = new(); - private readonly ConcurrentDictionary LongClosingStops = new(); - private readonly ConcurrentDictionary ShortClosingStops = new(); - private readonly Channel _pricesChannel = Channel.CreateUnbounded(); private readonly Channel _commands = Channel.CreateUnbounded(); private readonly Channel _orderbooks = Channel.CreateUnbounded(); @@ -87,7 +82,7 @@ namespace KLHZ.Trader.Core.Exchange.Services if (command.CommandType == Contracts.Messaging.Dtos.Enums.TradeCommandType.OpenLong || command.CommandType == Contracts.Messaging.Dtos.Enums.TradeCommandType.OpenShort) { - var fakeMessage = new NewPriceMessage() { Figi = command.Figi, Ticker = "", Count = command.Count, Direction = 1, IsHistoricalData = false, Time = DateTime.UtcNow, Value = command.RecomendPrice ?? 0m }; + var fakeMessage = new NewPriceMessage() { Figi = command.Figi, Ticker = "", Count = command.Count, Direction = 1, IsHistoricalData = false, Time = DateTime.UtcNow, Price = command.RecomendPrice ?? 0m }; var positionType = command.CommandType == TradeCommandType.OpenLong ? PositionType.Long : PositionType.Short; var stops = GetStops(fakeMessage, positionType); var accounts = _portfolioWrapper.Accounts @@ -99,7 +94,7 @@ namespace KLHZ.Trader.Core.Exchange.Services } else { - var fakeMessage = new NewPriceMessage() { Figi = command.Figi, Ticker = "", Count = command.Count, Direction = 1, IsHistoricalData = false, Time = DateTime.UtcNow, Value = command.RecomendPrice ?? 0m }; + var fakeMessage = new NewPriceMessage() { Figi = command.Figi, Ticker = "", Count = command.Count, Direction = 1, IsHistoricalData = false, Time = DateTime.UtcNow, Price = command.RecomendPrice ?? 0m }; var assetsForClose = _portfolioWrapper.Accounts .SelectMany(a => a.Value.Assets.Values) .Where(a => a.Figi == fakeMessage.Figi) @@ -109,7 +104,7 @@ namespace KLHZ.Trader.Core.Exchange.Services } catch (Exception ex) { - + _logger.LogError(ex, "Ошибка при выполнении команды."); } } } @@ -123,7 +118,6 @@ namespace KLHZ.Trader.Core.Exchange.Services } } - private async Task ProcessPrices() { var pricesCache1 = new Dictionary>(); @@ -150,27 +144,27 @@ namespace KLHZ.Trader.Core.Exchange.Services { Time = message.Time, Count = message.Count, - Price = message.Value, + Price = message.Price, }); await _tradeDataProvider.AddDataTo5MinuteWindowCache(message.Figi, Constants._5minBuyCacheKey, new Contracts.Declisions.Dtos.CachedValue() { Time = message.Time, - Count = (decimal)message.Count, - Price = message.Value, + Count = message.Count, + Price = message.Price, }); await _tradeDataProvider.AddDataTo15MinuteWindowCache(message.Figi, Constants._15minBuyCacheKey, new Contracts.Declisions.Dtos.CachedValue() { Time = message.Time, - Count = (decimal)message.Count, - Price = message.Value, + Count = message.Count, + Price = message.Price, }); await _tradeDataProvider.AddDataTo1MinuteWindowCache(message.Figi, Constants._1minBuyCacheKey, new Contracts.Declisions.Dtos.CachedValue() { Time = message.Time, - Count = (decimal)message.Count, - Price = message.Value, + Count = message.Count, + Price = message.Price, }); } if (message.Direction == 2) @@ -178,201 +172,101 @@ namespace KLHZ.Trader.Core.Exchange.Services await _tradeDataProvider.AddDataTo5MinuteWindowCache(message.Figi, Constants._5minSellCacheKey, new Contracts.Declisions.Dtos.CachedValue() { Time = message.Time, - Count = (decimal)message.Count, - Price = message.Value, + Count = message.Count, + Price = message.Price, }); await _tradeDataProvider.AddDataTo15MinuteWindowCache(message.Figi, Constants._15minSellCacheKey, new Contracts.Declisions.Dtos.CachedValue() { Time = message.Time, - Count = (decimal)message.Count, - Price = message.Value, + Count = message.Count, + Price = message.Price, }); await _tradeDataProvider.AddDataTo1MinuteWindowCache(message.Figi, Constants._1minSellCacheKey, new Contracts.Declisions.Dtos.CachedValue() { Time = message.Time, - Count = (decimal)message.Count, - Price = message.Value, + Count = message.Count, + Price = message.Price, }); await _tradeDataProvider.AddDataTo20SecondsWindowCache(message.Figi, "2", new Contracts.Declisions.Dtos.CachedValue() { Time = message.Time, Count = message.Count, - Price = message.Value, + Price = message.Price, }); } } #endregion - if (_exchangeConfig.TradingInstrumentsFigis.Contains(message.Figi) && (message.Figi == "FUTIMOEXF000" || message.Figi == "BBG004730N88") && message.Direction == 1) + if (_exchangeConfig.TradingInstrumentsFigis.Contains(message.Figi) && message.Direction == 1) { var smallWindow = TimeSpan.FromSeconds(120); var bigWindow = TimeSpan.FromSeconds(240); var meanWindow = TimeSpan.FromSeconds(240); var currentTime = message.IsHistoricalData ? message.Time : DateTime.UtcNow; - try - { - var buys = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, Constants._15minBuyCacheKey); - var sells = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, Constants._15minSellCacheKey); - var trades = buys.ToList(); - trades.AddRange(sells); - var trades2 = trades.OrderBy(t => t.Time).ToArray(); - if (trades2.TryCalcTimeWindowsDiff(bigWindow, smallWindow, v => v.Count, false, out var tradesDiff) - && buys.TryCalcTimeWindowsDiff(bigWindow, smallWindow, v => v.Price, true, out var pricesDiff)) - { - await LogPrice(message, "privcesDiff", pricesDiff); - await LogPrice(message, "tradevolume_diff", tradesDiff); - await _tradeDataProvider.AddDataTo15MinuteWindowCache(message.Figi, "5min_diff", new Contracts.Declisions.Dtos.CachedValue() - { - Time = message.Time, - Count = tradesDiff, - Price = pricesDiff, - }); - var diffs = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, "5min_diff"); - if (diffs.TryCalcTimeWindowsDiff(bigWindow, smallWindow, (c) => c.Price, true, out var resdp) - && diffs.TryCalcTimeWindowsDiff(bigWindow, smallWindow, (c) => c.Count, true, out var resv)) + var buys = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, Constants._15minBuyCacheKey); + var sells = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, Constants._15minSellCacheKey); + var trades = buys.ToList(); + trades.AddRange(sells); + var trades2 = trades.OrderBy(t => t.Time).ToArray(); + if (trades2.TryCalcTimeWindowsDiff(bigWindow, smallWindow, v => v.Count, false, out var tradesDiff) + && buys.TryCalcTimeWindowsDiff(bigWindow, smallWindow, v => v.Price, true, out var pricesDiff)) + { + await LogPrice(message, "privcesDiff", pricesDiff); + await LogPrice(message, "tradevolume_diff", tradesDiff); + await _tradeDataProvider.AddDataTo15MinuteWindowCache(message.Figi, "5min_diff", new Contracts.Declisions.Dtos.CachedValue() + { + Time = message.Time, + Value2 = tradesDiff, + Value = pricesDiff, + }); + + var diffs = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, "5min_diff"); + if (diffs.TryCalcTimeWindowsDiff(bigWindow, smallWindow, (c) => c.Value, true, out var resdp) + && diffs.TryCalcTimeWindowsDiff(bigWindow, smallWindow, (c) => c.Value2, true, out var resv)) + { + await LogPrice(message, "privcesDiffDiff", (decimal)resdp); + await LogPrice(message, "tradevolume_diff_diff", (decimal)resv); + + if (diffs.TryCalcPirsonCorrelation(meanWindow, out var pirson)) { - await LogPrice(message, "privcesDiffDiff", (decimal)resdp); - await LogPrice(message, "tradevolume_diff_diff", (decimal)resv); - await _tradeDataProvider.AddDataTo15MinuteWindowCache(message.Figi, "5min_diff_diff", new Contracts.Declisions.Dtos.CachedValue() + await LogPrice(message, "diffs_pirson", (decimal)pirson); + await _tradeDataProvider.AddDataTo15MinuteWindowCache(message.Figi, "diffs_pirson", new Contracts.Declisions.Dtos.CachedValue() { Time = message.Time, - Count = resv, - Price = resdp, + Value = (decimal)pirson, }); - if (diffs.TryCalcPirsonCorrelation(meanWindow, out var pirson)) + var diffs_pirson = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, "diffs_pirson"); + if (diffs_pirson.TryCalcTimeWindowsDiff(bigWindow, smallWindow, (c) => c.Value, true, out var res)) { - await LogPrice(message, "diffs_pirson", (decimal)pirson); - await _tradeDataProvider.AddDataTo15MinuteWindowCache(message.Figi, "diffs_pirson", new Contracts.Declisions.Dtos.CachedValue() + if (DPirsonValues.TryGetValue(message.Figi, out var olddpirs)) { - Time = message.Time, - Count = (decimal)pirson, - }); - var diffs_pirson = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, "diffs_pirson"); - if (diffs_pirson.TryCalcTimeWindowsDiff(bigWindow, smallWindow, (c) => c.Count, true, out var res)) - { - await LogPrice(message, "diffs_pirson_diff", (decimal)res); - if (DPirsonValues.TryGetValue(message.Figi, out var olddpirs)) + if (olddpirs < 0.5m && res > 0.5m) { - if (olddpirs < 0 && res > 0) - { - await LogPrice(message, "diffs_pirson_diff_point0", message.Value); - } - if (olddpirs < 0.25m && res > 0.25m) - { - await LogPrice(message, "diffs_pirson_diff_point0.25", message.Value); - } - if (olddpirs < 0.5m && res > 0.5m) - { - await LogPrice(message, "diffs_pirson_diff_point0.5", message.Value); - } + await LogPrice(message, "diffs_pirson_diff_point0.5", message.Price); } - DPirsonValues[message.Figi] = res; } + DPirsonValues[message.Figi] = res; } } } - - if (timesCache.TryGetValue(message.Figi, out var dt)) - { - if ((message.Time - dt).TotalSeconds > 10) - { - timesCache[message.Figi] = message.Time; - var newMod = await CalcTradingMode2(message); - if (TradingModes.TryGetValue(message.Figi, out var oldMod)) - { - if ((oldMod == TradingMode.Growing || oldMod == TradingMode.Stable) - && oldMod != newMod) - { - changeMods[TradingEvent.UptrendEnd] = Constants.PowerUppingCoefficient; - } - if ((oldMod == TradingMode.Dropping || oldMod == TradingMode.SlowDropping) - && oldMod != newMod) - { - changeMods[TradingEvent.DowntrendEnd] = Constants.PowerUppingCoefficient; - } - if (newMod == TradingMode.Growing && newMod != oldMod && !LongOpeningStops.ContainsKey(message.Figi)) - { - //changeMods[TradingEvent.UptrendStart] = Constants.PowerUppingCoefficient; - } - if (newMod == TradingMode.Dropping && newMod != oldMod && !ShortOpeningStops.ContainsKey(message.Figi)) - { - //changeMods[TradingEvent.DowntrendStart] = Constants.PowerUppingCoefficient; - } - TradingModes[message.Figi] = newMod; - if (oldMod != newMod) - { - var accountForStopsChanging = _portfolioWrapper.Accounts - .Where(a => a.Value.Assets.ContainsKey(message.Figi)) - .ToArray(); - - foreach (var account in accountForStopsChanging) - { - if (account.Value.Assets.TryGetValue(message.Figi, out var asset)) - { - var stops = GetStops(message, asset.Count > 0 ? PositionType.Long : PositionType.Short); - if (!message.IsHistoricalData) - { - await account.Value.ResetStops(message.Figi, stops.stopLoss, stops.takeProfit); - if (asset.Count < 0) - { - await LogDeclision(DeclisionTradeAction.ResetStopsShort, asset.BoughtPrice - stops.takeProfit, message.Time.AddMilliseconds(-100), message); - await LogDeclision(DeclisionTradeAction.ResetStopsShort, asset.BoughtPrice + stops.stopLoss, message.Time.AddMilliseconds(100), message); - } - else - { - await LogDeclision(DeclisionTradeAction.ResetStopsLong, asset.BoughtPrice + stops.takeProfit, message.Time.AddMilliseconds(-100), message); - await LogDeclision(DeclisionTradeAction.ResetStopsLong, asset.BoughtPrice - stops.stopLoss, message.Time.AddMilliseconds(100), message); - } - } - } - } - } - } - } - } - else - { - timesCache[message.Figi] = message.Time; - } - } - catch (Exception ex) - { - - } - if (TradingModes.TryGetValue(message.Figi, out var mode)) - { - await LogPrice(message, "trading_mode", (decimal)mode); - } - try - { - if (message.Direction != 1) continue; - await _tradeDataProvider.AddData(message); - //ProcessStops(message, currentTime); - var windowMaxSize = 2000; - //var data = await _tradeDataProvider.GetData(message.Figi, windowMaxSize); - //var state = ExchangeScheduler.GetCurrentState(message.Time); - // await ProcessNewPriceIMOEXF3(data, state, message, windowMaxSize, changeMods.ToImmutableDictionary()); - } - catch (Exception ex) - { - _logger.LogError(ex, "Ошибка при боработке новой цены IMOEXF"); } } } - catch (Exception e) + catch (Exception ex) { - + _logger.LogError(ex, "Ошибка при боработке новой цены."); } } } + private async Task ClosePositions(Asset[] assets, INewPrice message, bool withProfitOnly = true) { var loggedDeclisions = 0; var assetType = _tradeDataProvider.GetAssetTypeByFigi(message.Figi); var assetsForClose = new List(); - var price = message.Value; + var price = message.Price; if (price == 0) { price = await _tradeDataProvider.GetLastPrice(message.Figi); @@ -381,6 +275,8 @@ namespace KLHZ.Trader.Core.Exchange.Services var messages = new List(); foreach (var asset in assets) { + Asset? assetForClose = null; + string? mess = null; if (withProfitOnly) { var profit = 0m; @@ -405,8 +301,8 @@ namespace KLHZ.Trader.Core.Exchange.Services if (profit > 0) { profit = System.Math.Round(profit, 2); - assetsForClose.Add(asset); - messages.Add($"Закрываю позицию {asset.Figi} ({(asset.Count > 0 ? "лонг" : "шорт")}) на счёте {_portfolioWrapper.Accounts[asset.AccountId].AccountName}. Количество {(long)asset.Count}, цена ~{price}, профит {profit}"); + assetForClose = asset; + mess = $"Закрываю позицию {asset.Figi} ({(asset.Count > 0 ? "лонг" : "шорт")}) на счёте {_portfolioWrapper.Accounts[asset.AccountId].AccountName}. Количество {(long)asset.Count}, цена ~{price}, профит {profit}"; if (loggedDeclisions == 0) { loggedDeclisions++; @@ -416,16 +312,15 @@ namespace KLHZ.Trader.Core.Exchange.Services } else { - messages.Add($"Закрываю позицию {asset.Figi} ({(asset.Count > 0 ? "лонг" : "шорт")}) на счёте {_portfolioWrapper.Accounts[asset.AccountId].AccountName}. Количество {(long)asset.Count}, цена ~{price}"); - assetsForClose.Add(asset); + mess = $"Закрываю позицию {asset.Figi} ({(asset.Count > 0 ? "лонг" : "шорт")}) на счёте {_portfolioWrapper.Accounts[asset.AccountId].AccountName}. Количество {(long)asset.Count}, цена ~{price}"; + assetForClose = asset; } - } - for (int i = 0; i < assetsForClose.Count; i++) - { - var asset = assetsForClose[i]; - await _portfolioWrapper.Accounts[asset.AccountId].ClosePosition(message.Figi); - await _dataBus.Broadcast(new MessageForAdmin() { Text = messages[i] }); + if (assetForClose != null && mess != null) + { + await _portfolioWrapper.Accounts[asset.AccountId].ClosePosition(message.Figi); + await _dataBus.Broadcast(new MessageForAdmin() { Text = mess }); + } } } @@ -435,14 +330,14 @@ namespace KLHZ.Trader.Core.Exchange.Services var sign = positionType == PositionType.Long ? 1 : 1; foreach (var acc in accounts) { - if (TraderUtils.IsOperationAllowed(acc, message.Value, 1, _exchangeConfig.AccountCashPartFutures, _exchangeConfig.AccountCashPart)) + if (TraderUtils.IsOperationAllowed(acc, message.Price, 1, _exchangeConfig.AccountCashPartFutures, _exchangeConfig.AccountCashPart)) { await acc.OpenPosition(message.Figi, positionType, stopLossShift, takeProfitShift, count); await _dataBus.Broadcast(new MessageForAdmin() { Text = $"Открываю позицию {message.Figi} ({(positionType == PositionType.Long ? "лонг" : "шорт")}) " + $"на счёте {acc.AccountName}. Количество {(positionType == PositionType.Long ? "" : "-")}{count}, " + - $"цена ~{System.Math.Round(message.Value, 2)}. Стоп лосс: {(positionType == PositionType.Long ? "-" : "+")}{stopLossShift}. " + + $"цена ~{System.Math.Round(message.Price, 2)}. Стоп лосс: {(positionType == PositionType.Long ? "-" : "+")}{stopLossShift}. " + $"Тейк профит: {(positionType == PositionType.Long ? "+" : "-")}{takeProfitShift}" }); } @@ -450,7 +345,6 @@ namespace KLHZ.Trader.Core.Exchange.Services if (loggedDeclisions == 0) { await LogDeclision(DeclisionTradeAction.OpenLongReal, message); - LongOpeningStops[message.Figi] = message.Time.AddMinutes(1); loggedDeclisions++; } } @@ -460,7 +354,6 @@ namespace KLHZ.Trader.Core.Exchange.Services { var state = ExchangeScheduler.GetCurrentState(); if (result[TradingEvent.UptrendStart] >= Constants.UppingCoefficient - && !LongOpeningStops.ContainsKey(message.Figi) && state == ExchangeState.Open ) { @@ -473,16 +366,14 @@ namespace KLHZ.Trader.Core.Exchange.Services .Select(a => a.Value) .ToArray(); await OpenPositions(accounts, message, PositionType.Long, stops.stopLoss, stops.takeProfit, 1); - LongOpeningStops[message.Figi] = DateTime.UtcNow.AddMinutes(1); } - await LogDeclision(DeclisionTradeAction.OpenLong, message.Value, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message); - await LogDeclision(DeclisionTradeAction.ResetStopsLong, message.Value + stops.takeProfit, message.Time.AddMilliseconds(-RandomNumberGenerator.GetInt32(300, 1000)), message); - await LogDeclision(DeclisionTradeAction.ResetStopsLong, message.Value - stops.stopLoss, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(300, 1000)), message); + await LogDeclision(DeclisionTradeAction.OpenLong, message.Price, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message); + await LogDeclision(DeclisionTradeAction.ResetStopsLong, message.Price + stops.takeProfit, message.Time.AddMilliseconds(-RandomNumberGenerator.GetInt32(300, 1000)), message); + await LogDeclision(DeclisionTradeAction.ResetStopsLong, message.Price - stops.stopLoss, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(300, 1000)), message); } if (result[TradingEvent.DowntrendStart] >= Constants.UppingCoefficient - && !ShortOpeningStops.ContainsKey(message.Figi) && state == ExchangeState.Open - ) + ) { var stops = GetStops(message, PositionType.Short); if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase()) @@ -493,12 +384,11 @@ namespace KLHZ.Trader.Core.Exchange.Services .Select(a => a.Value) .ToArray(); await OpenPositions(accounts, message, PositionType.Short, stops.stopLoss, stops.takeProfit, 1); - ShortOpeningStops[message.Figi] = DateTime.UtcNow.AddMinutes(1); } - await LogDeclision(DeclisionTradeAction.OpenShort, message.Value, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message); - await LogDeclision(DeclisionTradeAction.ResetStopsShort, message.Value - stops.takeProfit, message.Time.AddMilliseconds(-RandomNumberGenerator.GetInt32(300, 1000)), message); - await LogDeclision(DeclisionTradeAction.ResetStopsShort, message.Value + stops.stopLoss, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(300, 1000)), message); + await LogDeclision(DeclisionTradeAction.OpenShort, message.Price, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message); + await LogDeclision(DeclisionTradeAction.ResetStopsShort, message.Price - stops.takeProfit, message.Time.AddMilliseconds(-RandomNumberGenerator.GetInt32(300, 1000)), message); + await LogDeclision(DeclisionTradeAction.ResetStopsShort, message.Price + stops.stopLoss, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(300, 1000)), message); } if (result[TradingEvent.UptrendEnd] >= Constants.UppingCoefficient * 10) { @@ -510,7 +400,7 @@ namespace KLHZ.Trader.Core.Exchange.Services .ToArray(); await ClosePositions(assetsForClose, message); } - await LogDeclision(DeclisionTradeAction.CloseLong, message.Value, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message); + await LogDeclision(DeclisionTradeAction.CloseLong, message.Price, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message); } @@ -524,43 +414,11 @@ namespace KLHZ.Trader.Core.Exchange.Services .ToArray(); await ClosePositions(assetsForClose, message); } - await LogDeclision(DeclisionTradeAction.CloseShort, message.Value, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message); + await LogDeclision(DeclisionTradeAction.CloseShort, message.Price, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message); } } - private void ProcessStops(INewPrice message, DateTime currentTime) - { - if (LongOpeningStops.TryGetValue(message.Figi, out var dt)) - { - if (dt < currentTime) - { - LongOpeningStops.TryRemove(message.Figi, out _); - } - } - if (ShortClosingStops.TryGetValue(message.Figi, out var dt2)) - { - if (dt2 < currentTime) - { - ShortClosingStops.TryRemove(message.Figi, out _); - } - } - if (LongClosingStops.TryGetValue(message.Figi, out var dt3)) - { - if (dt3 < currentTime) - { - LongClosingStops.TryRemove(message.Figi, out _); - } - } - if (ShortOpeningStops.TryGetValue(message.Figi, out var dt4)) - { - if (dt4 < currentTime) - { - ShortOpeningStops.TryRemove(message.Figi, out _); - } - } - } - private async Task LogPrice(INewPrice message, string processor, decimal value) { await _tradeDataProvider.LogPrice(new ProcessedPrice() @@ -569,7 +427,7 @@ namespace KLHZ.Trader.Core.Exchange.Services Ticker = message.Ticker, Processor = processor, Time = message.Time, - Value = value, + Price = value, }, false); } @@ -581,7 +439,7 @@ namespace KLHZ.Trader.Core.Exchange.Services Ticker = ticker, Processor = processor, Time = time, - Value = value, + Price = value, }, false); } @@ -593,7 +451,7 @@ namespace KLHZ.Trader.Core.Exchange.Services Figi = message.Figi, Ticker = message.Ticker, Value = profit, - Price = message.Value, + Price = message.Price, Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow, Action = action, }, false); @@ -645,135 +503,11 @@ namespace KLHZ.Trader.Core.Exchange.Services return res; } - private async ValueTask CalcTradingMode2(INewPrice message) - { - var res = TradingMode.None; - var data = await _tradeDataProvider.GetData(message.Figi, TimeSpan.FromMinutes(20)); - - if (data.isFullIntervalExists) - { - if (LocalTrends.TryCalcTrendDiff(data.timestamps, data.prices, out var diff)) - { - if (diff >= -2 && diff <= 2) - { - res = TradingMode.Stable; - } - else if (diff < -6) - { - res = TradingMode.Dropping; - } - else if (diff > 6) - { - res = TradingMode.Growing; - } - else if (diff < -2) - { - res = TradingMode.SlowDropping; - } - else if (diff > 2) - { - res = TradingMode.SlowGrowing; - } - } - } - return res; - } - private (decimal stopLoss, decimal takeProfit) GetStops(INewPrice message, PositionType type) { - var mode = TradingModes[message.Figi]; decimal stopLossShift = 2m; decimal takeProfitShift = 6; - if (mode == TradingMode.Growing && type == PositionType.Long) - { - takeProfitShift = 15; - //stopLossShift = 2; - } - if (mode == TradingMode.Growing && type == PositionType.Short) - { - //stopLossShift = 2; - takeProfitShift = 3m; - } - if (mode == TradingMode.Stable && type == PositionType.Long) - { - takeProfitShift = 3m; - } - if (mode == TradingMode.Stable && type == PositionType.Short) - { - takeProfitShift = 3m; - //stopLossShift = 10; - } - if (mode == TradingMode.SlowDropping && type == PositionType.Short) - { - - } - if (mode == TradingMode.SlowDropping && type == PositionType.Long) - { - takeProfitShift = 1.5m; - //stopLossShift = 10; - } - if (mode == TradingMode.SlowGrowing && type == PositionType.Short) - { - //takeProfitShift = 2.5m; - //stopLossShift = 10; - } - if (mode == TradingMode.SlowGrowing && type == PositionType.Long) - { - } - if (mode == TradingMode.Dropping && type == PositionType.Short) - { - takeProfitShift = 15; - //stopLossShift = 2; - } - if (mode == TradingMode.Dropping && type == PositionType.Long) - { - //stopLossShift = 2; - takeProfitShift = 3m; - } return (stopLossShift, takeProfitShift); } - - private Task> GetTradingModeMods(INewPrice message) - { - var res = TraderUtils.GetInitDict(1); - var mode = TradingModes[message.Figi]; - if (mode == TradingMode.None) - { - //res[TradingEvent.UptrendEnd] = Constants.UppingCoefficient; - //res[TradingEvent.UptrendStart] = 1; - res[TradingEvent.DowntrendStart] = Constants.LowingCoefficient; - //res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient; - } - if (mode == TradingMode.Growing) - { - //res[TradingEvent.UptrendEnd] = Constants.LowingCoefficient; - res[TradingEvent.UptrendStart] = Constants.UppingCoefficient; - res[TradingEvent.DowntrendStart] = Constants.BlockingCoefficient; - res[TradingEvent.DowntrendEnd] = Constants.PowerUppingCoefficient; - } - if (mode == TradingMode.Stable) - { - //res[TradingEvent.UptrendEnd] = 1; - res[TradingEvent.UptrendStart] = Constants.LowingCoefficient; - //res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient; - res[TradingEvent.DowntrendStart] = Constants.LowingCoefficient; - } - if (mode == TradingMode.SlowDropping) - { - //res[TradingEvent.UptrendEnd] = Constants.PowerUppingCoefficient; - //res[TradingEvent.UptrendStart] = Constants.LowingCoefficient; - res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient; - //res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient; - } - if (mode == TradingMode.Dropping) - { - res[TradingEvent.UptrendEnd] = Constants.PowerUppingCoefficient; - res[TradingEvent.UptrendStart] = Constants.BlockingCoefficient; - res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient; - //res[TradingEvent.DowntrendEnd] = Constants.LowingCoefficient; - } - return Task.FromResult(res.ToImmutableDictionary()); - } - } } diff --git a/KLHZ.Trader.Core/Exchange/Services/TraderDataProvider.cs b/KLHZ.Trader.Core/Exchange/Services/TraderDataProvider.cs index cdd5658..00b03b2 100644 --- a/KLHZ.Trader.Core/Exchange/Services/TraderDataProvider.cs +++ b/KLHZ.Trader.Core/Exchange/Services/TraderDataProvider.cs @@ -9,7 +9,6 @@ using KLHZ.Trader.Core.DataLayer.Entities.Prices; using KLHZ.Trader.Core.Exchange.Models.Configs; using KLHZ.Trader.Core.Math.Declisions.Dtos.FFT; using KLHZ.Trader.Core.Math.Declisions.Services.Cache; -using KLHZ.Trader.Core.Math.Declisions.Utils; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -241,7 +240,7 @@ namespace KLHZ.Trader.Core.Exchange.Services Figi = c.Figi, Ticker = c.Ticker, Time = c.Time, - Value = c.Value, + Price = c.Price, IsHistoricalData = true, Direction = c.Direction, Count = c.Count, @@ -251,15 +250,6 @@ namespace KLHZ.Trader.Core.Exchange.Services foreach (var price in data) { await AddData(price); - - var cachedData = await GetData(price.Figi); - if ((DateTime.UtcNow - price.Time).TotalMinutes < 5) - { - if (ShapeAreaCalculator.TryGetAreasRelation(cachedData.timestamps, cachedData.prices, price.Value, Constants.AreasRelationWindow, out var rel)) - { - await AddDataTo1MinuteWindowCache(price.Figi, Constants._1minCacheKey, new CachedValue() { Time = price.Time, Count = (decimal)rel }); - } - } } } diff --git a/KLHZ.Trader.Core/Exchange/Utils/TraderUtils.cs b/KLHZ.Trader.Core/Exchange/Utils/TraderUtils.cs index 4c4920c..0c2ce9c 100644 --- a/KLHZ.Trader.Core/Exchange/Utils/TraderUtils.cs +++ b/KLHZ.Trader.Core/Exchange/Utils/TraderUtils.cs @@ -82,7 +82,7 @@ namespace KLHZ.Trader.Core.Exchange.Utils Direction = message.Direction, IsHistoricalData = message.IsHistoricalData, Time = message.Time, - Value = list.Sum(l => l.Value) / list.Count + Price = list.Sum(l => l.Price) / list.Count }; list.Clear(); return message; diff --git a/KLHZ.Trader.Service/Controllers/PlayController.cs b/KLHZ.Trader.Service/Controllers/PlayController.cs index 92ba368..a99c348 100644 --- a/KLHZ.Trader.Service/Controllers/PlayController.cs +++ b/KLHZ.Trader.Service/Controllers/PlayController.cs @@ -2,9 +2,6 @@ using KLHZ.Trader.Core.Contracts.Messaging.Dtos; using KLHZ.Trader.Core.Contracts.Messaging.Interfaces; using KLHZ.Trader.Core.DataLayer; using KLHZ.Trader.Core.DataLayer.Entities.Orders; -using KLHZ.Trader.Core.DataLayer.Entities.Prices; -using KLHZ.Trader.Core.Exchange.Services; -using KLHZ.Trader.Core.Math.Declisions.Utils; using KLHZ.Trader.Service.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -15,15 +12,13 @@ namespace KLHZ.Trader.Service.Controllers [Route("[controller]/[action]")] public class PlayController : ControllerBase { - private readonly TraderDataProvider _traderDataProvider; private readonly IDataBus _dataBus; private readonly IDbContextFactory _dbContextFactory; - public PlayController(IDataBus dataBus, IDbContextFactory dbContextFactory, TraderDataProvider traderDataProvider) + public PlayController(IDataBus dataBus, IDbContextFactory dbContextFactory) { _dbContextFactory = dbContextFactory; _dataBus = dataBus; - _traderDataProvider = traderDataProvider; } [HttpGet] @@ -59,7 +54,7 @@ namespace KLHZ.Trader.Service.Controllers Figi = c.Figi, Ticker = c.Ticker, Time = c.Time, - Value = c.Value, + Price = c.Price, IsHistoricalData = true, Direction = c.Direction, Count = c.Count, @@ -239,334 +234,6 @@ namespace KLHZ.Trader.Service.Controllers } } - [HttpGet] - public async Task CalcOrderbookMeanav(string figi) - { - try - { - var t = DateTime.UtcNow.AddHours(-4); - using var context1 = await _dbContextFactory.CreateDbContextAsync(); - context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; - var data = await context1.OrderbookItems - .Where(i => i.Time > t && i.Figi == figi && (i.ItemType == Core.DataLayer.Entities.Orders.Enums.OrderbookItemType.BidsSummary4 || i.ItemType == Core.DataLayer.Entities.Orders.Enums.OrderbookItemType.AsksSummary4)) - .OrderBy(i => i.Time) - .ToArrayAsync(); - var bids = new LinkedList(); - var asks = new LinkedList(); - var buffer = new List(); - var dt = TimeSpan.FromMinutes(1); - var q = data.ToLookup(d => d.Time); - foreach (var d in q) - { - var pair = d.DistinctBy(www => www.ItemType).OrderBy(www => www.ItemType).ToArray(); - if (pair.Length == 2) - { - bids.AddLast(pair[1]); - if (bids.Last().Time - bids.First().Time > dt) - { - bids.RemoveFirst(); - } - if (pair[0].Count != 0) - { - pair[1].Price = ((decimal)pair[1].Count) / ((decimal)pair[0].Count); - buffer.Add(new OrderbookItem() - { - Figi = pair[1].Figi, - Ticker = pair[1].Ticker, - Count = 1, - ItemType = Core.DataLayer.Entities.Orders.Enums.OrderbookItemType.BidsAsksSummary4_2min, - Price = bids.Sum(b => b.Price) / bids.Count, - Time = pair[1].Time, - }); - } - if (buffer.Count > 10000) - { - await context1.OrderbookItems.AddRangeAsync(buffer); - await context1.SaveChangesAsync(); - buffer.Clear(); - } - } - else - { - } - } - if (buffer.Count > 0) - { - await context1.OrderbookItems.AddRangeAsync(buffer); - await context1.SaveChangesAsync(); - buffer.Clear(); - } - } - catch (Exception ex) - { - - } - } - - [HttpGet] - public async Task CalcTradesMeanav(string figi) - { - try - { - var t = DateTime.UtcNow.AddHours(-4); - using var context1 = await _dbContextFactory.CreateDbContextAsync(); - context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; - var data = await context1.PriceChanges - .Where(i => i.Time > t && i.Figi == figi) - .OrderBy(i => i.Time) - .ToArrayAsync(); - var sells = new LinkedList(); - var buys = new LinkedList(); - var buffer = new List(); - var dt = TimeSpan.FromMinutes(1); - foreach (var d in data) - { - if (d.Direction == 1) - { - if (buys.Last().Time - buys.First().Time > dt) - { - buys.RemoveFirst(); - } - buys.AddLast(d); - } - if (d.Direction == 2) - { - sells.AddLast(d); - if (sells.Last().Time - sells.First().Time > dt) - { - sells.RemoveFirst(); - } - sells.AddLast(d); - } - - if (sells.Count > 0 && buys.Count > 0) - { - var meanS = ((decimal)sells.Sum(s => s.Count)) / sells.Count; - var meanB = ((decimal)buys.Sum(s => s.Count)) / buys.Count; - if (meanS != 0) - { - buffer.Add(new ProcessedPrice() - { - Figi = d.Figi, - Processor = "tradesbalance", - Ticker = d.Ticker, - Count = 1, - Direction = 0, - Time = d.Time, - Value = meanB / meanS - }); - } - } - - if (buffer.Count > 10000) - { - await context1.ProcessedPrices.AddRangeAsync(buffer); - await context1.SaveChangesAsync(); - buffer.Clear(); - } - } - if (buffer.Count > 0) - { - await context1.ProcessedPrices.AddRangeAsync(buffer); - await context1.SaveChangesAsync(); - buffer.Clear(); - } - } - catch (Exception ex) - { - - } - } - - - [HttpGet] - public async Task TestInmterpolate(string figi) - { - try - { - var t1 = DateTime.UtcNow.AddHours(-4); - var t2 = DateTime.UtcNow.AddHours(1); - - //t1 = new DateTime(2025, 9, 15, 10, 1, 0, DateTimeKind.Utc); - //t2 = new DateTime(2025, 9, 15, 10, 1, 50, DateTimeKind.Utc); - using var context1 = await _dbContextFactory.CreateDbContextAsync(); - context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; - var data = await context1.PriceChanges - .Where(i => i.Time >= t1 && i.Time <= t2 && i.Figi == figi) - .OrderBy(i => i.Time) - .ToArrayAsync(); - - var buffer = new List(); - var res = SignalProcessing.InterpolateData(data.Select(d => d.Time).ToArray(), data.Select(d => d.Value).ToArray(), - TimeSpan.FromSeconds(1)); - - - for (int i = 0; i < res.Item1.Length; i++) - { - buffer.Add(new ProcessedPrice() - { - Figi = figi, - Processor = "1secinterpol", - Ticker = data[0].Ticker, - Count = 1, - Direction = 0, - Time = res.Item1[i], - Value = (decimal)res.Item2[i] - }); - } - await context1.ProcessedPrices.AddRangeAsync(buffer); - await context1.SaveChangesAsync(); - } - catch (Exception ex) - { - - } - } - - [HttpGet] - public async Task TestFFT(string figi) - { - try - { - var t1 = new DateTime(2025, 9, 15, 6, 30, 0, DateTimeKind.Utc); - var t2 = new DateTime(2025, 9, 15, 7, 50, 50, DateTimeKind.Utc); - - using var context1 = await _dbContextFactory.CreateDbContextAsync(); - context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; - var data = await context1.PriceChanges - .Where(i => i.Time >= t1 && i.Time <= t2 && i.Figi == figi) - .OrderBy(i => i.Time) - .ToArrayAsync(); - - var buffer = new List(); - var values = data.Select(d => d.Value).ToArray(); - var times = data.Select(d => d.Time).ToArray(); - var res = SignalProcessing.InterpolateData(times, values, - TimeSpan.FromSeconds(10)); - - //FFT.GetMainHarmonictPeriod(res.Item2, res.Item1.Last() - res.Item1.First()); - - } - catch (Exception ex) - { - - } - } - //[HttpGet] - //public async Task GetBalance(string figi) - //{ - // try - // { - // var time1 = DateTime.UtcNow.AddDays(-7); - // using var context1 = await _dbContextFactory.CreateDbContextAsync(); - // context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; - // var data = await context1.PriceChanges - // .Where(c => c.Figi == figi && c.Time >= time1) - // .OrderBy(c => c.Time) - // .Select(c => new NewPriceMessage() - // { - // Figi = figi, - // Ticker = c.Ticker, - // Time = c.Time, - // Value = c.Value, - // IsHistoricalData = true - // }) - // .ToArrayAsync(); - // var buffer = new List(); - // var list = new LinkedList<(DateTime time, double value)>(); - // var previous = -1000d; - // foreach (var mess in data) - // { - // await _traderDataProvider.AddData(mess, TimeSpan.FromHours(6)); - // var dataFromCache = await _traderDataProvider.GetData(figi, TimeSpan.FromMinutes(15)); - // if (dataFromCache.isFullIntervalExists) - // { - // if (ShapeAreaCalculator.TryGetAreasRelation(dataFromCache.timestamps, dataFromCache.prices,mess.Value,out var res)) - // { - // if (list.Count > 0 && mess.Time - list.Last().time > TimeSpan.FromMinutes(5)) - // { - // list.Clear(); - // } - // list.AddLast((mess.Time, res)); - // if (list.Last().time - list.First().time > TimeSpan.FromMinutes(1)) - // { - // list.RemoveFirst(); - // } - // var newRes = (decimal)(list.Sum(i => i.value) / list.Count); - // if (list.Count > 0) - // { - // try - // { - // buffer.Add(new ProcessedPrice() - // { - // Figi = figi, - // Processor = "balancescalc30min", - // Ticker = mess.Ticker, - // Time = mess.Time, - // Value = newRes, - // //Value = (decimal)res, - // }); - // } - // catch(Exception ex) - // { - - // } - - // } - // } - // } - // else - // { - // previous = -1d; - // } - // if (buffer.Count > 10000) - // { - // await context1.ProcessedPrices.AddRangeAsync(buffer); - // await context1.SaveChangesAsync(); - // buffer.Clear(); - // } - // } - // if (buffer.Count > 0) - // { - // await context1.ProcessedPrices.AddRangeAsync(buffer); - // await context1.SaveChangesAsync(); - // buffer.Clear(); - // } - // } - // catch (Exception ex) - // { - - // } - //} - - ////[HttpGet] - //public async Task LoadTradesToHistory(string figi) - //{ - // try - // { - // using var context1 = await _dbContextFactory.CreateDbContextAsync(); - // context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; - // var data = await context1.InstrumentTrades - // .Where(c => c.Figi == figi) - // .OrderBy(c => c.BoughtAt) - // .Select(c => new PriceChange() - // { - // Figi = figi, - // Ticker = c.Ticker, - // Time = c.BoughtAt, - // Value = c.Price, - // IsHistoricalData = true - // }) - // .ToArrayAsync(); - // await context1.PriceChanges.Where(p => p.Figi == figi).ExecuteDeleteAsync(); - // await context1.PriceChanges.AddRangeAsync(data); - // await context1.SaveChangesAsync(); - // } - // catch (Exception ex) - // { - - // } - //} } } diff --git a/KLHZ.Trader.Service/Models/TimeSeriesData.cs b/KLHZ.Trader.Service/Models/TimeSeriesData.cs index db044a4..663b880 100644 --- a/KLHZ.Trader.Service/Models/TimeSeriesData.cs +++ b/KLHZ.Trader.Service/Models/TimeSeriesData.cs @@ -2,7 +2,7 @@ namespace KLHZ.Trader.Service.Models { - public class TimeSeriesData + internal class TimeSeriesData { public required string Figi { get; set; } public DateTime Time { get; set; } diff --git a/KLHZ.Trader.Service/appsettings.json b/KLHZ.Trader.Service/appsettings.json index 9fd42ca..89e4b01 100644 --- a/KLHZ.Trader.Service/appsettings.json +++ b/KLHZ.Trader.Service/appsettings.json @@ -8,7 +8,6 @@ }, "LokiUrl": "", "ExchangeConfig": { - "StopBuyLengthMinuts": 15, "ExchangeDataRecievingEnabled": true, "Token": "", "ManagingAccountNamePatterns": [ "автотрейд" ], @@ -18,7 +17,6 @@ "ShareComission": 0.0004, "AccountCashPart": 0.05, "AccountCashPartFutures": 0.5, - "DefaultBuyPartOfAccount": 0.3333, "InstrumentsSettings": [ { "Figi": "FUTIMOEXF000",