klhztrader/KLHZ.Trader.Service/Controllers/PlayController.cs

573 lines
24 KiB
C#

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;
namespace KLHZ.Trader.Service.Controllers
{
[ApiController]
[Route("[controller]/[action]")]
public class PlayController : ControllerBase
{
private readonly TraderDataProvider _traderDataProvider;
private readonly IDataBus _dataBus;
private readonly IDbContextFactory<TraderDbContext> _dbContextFactory;
public PlayController(IDataBus dataBus, IDbContextFactory<TraderDbContext> 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, 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<TimeSeriesData>();
var data2 = new List<TimeSeriesData>();
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 NewPriceMessage()
{
Figi = c.Figi,
Ticker = c.Ticker,
Time = c.Time,
Value = c.Value,
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<OrderbookItem>();
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<OrderbookItem>();
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 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<OrderbookItem>();
var asks = new LinkedList<OrderbookItem>();
var buffer = new List<OrderbookItem>();
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<PriceChange>();
var buys = new LinkedList<PriceChange>();
var buffer = new List<ProcessedPrice>();
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<ProcessedPrice>();
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<ProcessedPrice>();
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<ProcessedPrice>();
// 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)
// {
// }
//}
}
}