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 Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace KLHZ.Trader.Service.Controllers { [ApiController] [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) { _dbContextFactory = dbContextFactory; _dataBus = dataBus; _traderDataProvider = traderDataProvider; } [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, 4, 14, 0, 0, DateTimeKind.Utc); //var time2 = DateTime.UtcNow.AddMinutes(18); using var context1 = await _dbContextFactory.CreateDbContextAsync(); context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; var data = await context1.PriceChanges .Where(c => (c.Figi == figi1 || c.Figi == figi2) && c.Time >= time1) .OrderBy(c => c.Time) .Select(c => new NewPriceMessage() { Figi = c.Figi, Ticker = c.Ticker, Time = c.Time, Value = c.Value, IsHistoricalData = true, Direction = c.Direction, Count = c.Count, }) .ToArrayAsync(); foreach (var mess in data) { await _dataBus.Broadcast(mess); } } catch (Exception ex) { } } [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) // { // } //} } }