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.Math.Declisions.Utils; using KLHZ.Trader.Service.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace KLHZ.Trader.Service.Controllers { [ApiController] [Route("[controller]/[action]")] public class PlayController : ControllerBase { private readonly IDataBus _dataBus; private readonly IDbContextFactory _dbContextFactory; public PlayController(IDataBus dataBus, IDbContextFactory dbContextFactory) { _dbContextFactory = dbContextFactory; _dataBus = dataBus; } [HttpGet] public async Task Run(double? shift = null) { try { var figi1 = "FUTIMOEXF000"; //var figi1 = "BBG004730N88"; var figi2 = "BBG004730N88"; //var figi2 = "FUTIMOEXF000"; var time1 = DateTime.UtcNow.AddDays(-shift ?? -7).Date; //var time1 = new DateTime(2025, 9, 24, 11, 00, 0, DateTimeKind.Utc); //var time2 = DateTime.UtcNow.AddMinutes(18); using var context1 = await _dbContextFactory.CreateDbContextAsync(); context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; while (time1 < DateTime.UtcNow) { var data = new List(); var data2 = new List(); var time2 = time1.AddHours(1); var orderbooks = await context1.OrderbookItems .Where(oi => (oi.Figi == figi1 || oi.Figi == figi2) && oi.Time >= time1 && oi.Time < time2) .OrderBy(c => c.Time) .ToArrayAsync(); var prices = await context1.PriceChanges .Where(c => (c.Figi == figi1 || c.Figi == figi2) && c.Time >= time1 && c.Time < time2) .OrderBy(c => c.Time) .Select(c => new TradeDataItem() { Figi = c.Figi, Ticker = c.Ticker, Time = c.Time, Price = c.Price, IsHistoricalData = true, Direction = c.Direction, Count = c.Count, }) .ToArrayAsync(); var lookupImoexf = orderbooks.Where(o => o.Figi == "FUTIMOEXF000").ToLookup(o => o.Time); var lookupSber = orderbooks.Where(o => o.Figi == "BBG004730N88").ToLookup(o => o.Time); foreach (var item in lookupImoexf) { var asks = item .Where(i => i.ItemType == Core.DataLayer.Entities.Orders.Enums.OrderbookItemType.Ask) .OrderBy(o => o.Price) .ToList(); var bids = item .Where(i => i.ItemType == Core.DataLayer.Entities.Orders.Enums.OrderbookItemType.Bid) .OrderByDescending(o => o.Price) .ToList(); var forRemove = new List(); if (asks.Count > 4 || bids.Count > 4) { } foreach (var bid in bids) { var bids2 = bids.Where(b => b.Price == bid.Price).ToList(); var summCount = bids2.Sum(b => b.Count); var b = bids2.First(); b.Count = summCount; bids2.Remove(b); forRemove.AddRange(bids2); } foreach (var ask in asks) { var asks2 = asks.Where(b => b.Price == ask.Price).ToList(); var summCount = asks2.Sum(b => b.Count); var b = asks2.First(); b.Count = summCount; asks2.Remove(b); forRemove.AddRange(asks2); } asks.RemoveAll(a => forRemove.Contains(a)); bids.RemoveAll(a => forRemove.Contains(a)); var orderbook = new NewOrderbookMessage() { Figi = "FUTIMOEXF000", Ticker = "IMOEXF", Asks = asks.ToArray(), Bids = bids.ToArray(), AsksCount = asks.Sum(a => a.Count), BidsCount = bids.Sum(a => a.Count), Time = item.Key }; var wrapper = new TimeSeriesData() { Figi = orderbook.Figi, Orderbook = orderbook, Time = item.Key, }; data.Add(wrapper); } foreach (var item in lookupSber) { var asks = item .Where(i => i.ItemType == Core.DataLayer.Entities.Orders.Enums.OrderbookItemType.Ask) .OrderBy(o => o.Price) .ToList(); var bids = item .Where(i => i.ItemType == Core.DataLayer.Entities.Orders.Enums.OrderbookItemType.Bid) .OrderByDescending(o => o.Price) .ToList(); var forRemove = new List(); if (asks.Count > 4 || bids.Count > 4) { } foreach (var bid in bids) { var bids2 = bids.Where(b => b.Price == bid.Price).ToList(); var summCount = bids2.Sum(b => b.Count); var b = bids2.First(); b.Count = summCount; bids2.Remove(b); forRemove.AddRange(bids2); } foreach (var ask in asks) { var asks2 = asks.Where(b => b.Price == ask.Price).ToList(); var summCount = asks2.Sum(b => b.Count); var b = asks2.First(); b.Count = summCount; asks2.Remove(b); forRemove.AddRange(asks2); } asks.RemoveAll(a => forRemove.Contains(a)); bids.RemoveAll(a => forRemove.Contains(a)); var orderbook = new NewOrderbookMessage() { Figi = "BBG004730N88", Ticker = "SBER", Asks = asks.ToArray(), Bids = bids.ToArray(), AsksCount = asks.Sum(a => a.Count), BidsCount = bids.Sum(a => a.Count), Time = item.Key }; var wrapper = new TimeSeriesData() { Figi = orderbook.Figi, Orderbook = orderbook, Time = item.Key, }; data.Add(wrapper); } time1 = time2; foreach (var price in prices) { var wrapper = new TimeSeriesData() { Figi = price.Figi, NewPrice = price, Time = price.Time, }; data.Add(wrapper); } data = data.OrderBy(d => d.Time).ToList(); for (int i = 0; i < data.Count; i++) { if (data[i].NewPrice != null && i > 0) { for (int i1 = i - 1; i1 >= 0; i1--) { var ob = data[i1].Orderbook; if (data[i1].Figi == data[i].Figi && ob != null) { var d = new TimeSeriesData() { Figi = ob.Figi, Orderbook = ob, Time = data[i].Time, NewPrice = data[i].NewPrice, }; data2.Add(d); break; } } } else { var ob = data[i].Orderbook; if (ob != null) { var d = new TimeSeriesData() { Figi = ob.Figi, Orderbook = ob, Time = ob.Time, }; data2.Add(d); } } } foreach (var mess in data2) { if (mess.Orderbook != null) { await _dataBus.Broadcast(mess.Orderbook); } if (mess.NewPrice != null) { //await _traderDataProvider.AddData(mess.NewPrice, TimeSpan.FromHours(6)); await _dataBus.Broadcast(mess.NewPrice); } } data.Clear(); data2.Clear(); } } catch (Exception ex) { } } [HttpGet] public async Task RunConvolution(double? shift = null) { var timeStep = 30; var time = DateTime.UtcNow.AddDays(-shift ?? -7).Date; while (time < DateTime.UtcNow) { var forSave = new List(); time = time.AddMinutes(timeStep); var figi1 = "FUTIMOEXF000"; //var figi1 = "BBG004730N88"; var figi2 = "FUTIMOEXF000"; //var figi2 = "FUTIMOEXF000"; var time2 = time; //var time1 = new DateTime(2025, 9, 24, 11, 00, 0, DateTimeKind.Utc); //var time2 = DateTime.UtcNow.AddMinutes(18); using var context1 = await _dbContextFactory.CreateDbContextAsync(); context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; var time1 = time2.AddHours(-3); var prices = await context1.PriceChanges .Where(c => (c.Figi == figi1 || c.Figi == figi2) && c.Time >= time1 && c.Time < time2 && c.Direction == 1) .OrderBy(c => c.Time) .Select(c => new TradeDataItem() { Figi = c.Figi, Ticker = c.Ticker, Time = c.Time, Price = c.Price, IsHistoricalData = true, Direction = c.Direction, Count = c.Count, }) .ToArrayAsync(); var pricesToSave = prices.Where(p => p.Time < time && p.Time >= time.AddMinutes(-timeStep)).ToArray(); if (pricesToSave.Any()) { var p1 = pricesToSave.Last(); forSave.Add(new Core.DataLayer.Entities.Prices.ProcessedPrice() { Figi = p1.Figi, Processor = "support_level_calc", Ticker = p1.Ticker, Count = p1.Count, Direction = p1.Direction, Time = p1.Time, Price = p1.Price, }); var leverage = 3; var hist = Statistics.CalcHistogram(prices); var convs = Statistics.CalcConvolution(hist, leverage).ToList(); var orderedConvs = convs.OrderByDescending(c => c.Sum).Take(5).ToList(); orderedConvs = orderedConvs.OrderBy(c => c.Value).ToList(); var values = new List(); foreach (var c in orderedConvs) { var left = c.Value - 0.5m * (leverage - 1); var right = c.Value + 0.5m * (leverage + 1); if (values.Count > 0) { var last = values.Last(); if (last < left) { values.Add(left); values.Add(right); } else if (last >= left && last < right) { values.Remove(last); values.Add(right); } else if (last >= right) { } } else { values.Add(left); values.Add(right); } } var pairs = new List<(decimal left, decimal right)>(); for (int i = 0; i < values.Count - 1; i += 2) { pairs.Add((values[i], values[i + 1])); } foreach (var price in pricesToSave) { foreach (var p in pairs) { if (price.Price >= p.left && price.Price <= p.right) { forSave.Add(new Core.DataLayer.Entities.Prices.ProcessedPrice() { Figi = price.Figi, Processor = "support_level", Ticker = price.Ticker, Count = price.Count, Direction = price.Direction, Time = price.Time, Price = price.Price, }); } } } await context1.ProcessedPrices.AddRangeAsync(forSave); await context1.SaveChangesAsync(); } } } } }