356 lines
16 KiB
C#
356 lines
16 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.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<TraderDbContext> _dbContextFactory;
|
|
|
|
public PlayController(IDataBus dataBus, IDbContextFactory<TraderDbContext> 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<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 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<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 RunConvolution(double? shift = null)
|
|
{
|
|
var timeStep = 30;
|
|
var time = DateTime.UtcNow.AddDays(-shift ?? -7).Date;
|
|
while (time < DateTime.UtcNow)
|
|
{
|
|
var forSave = new List<Core.DataLayer.Entities.Prices.ProcessedPrice>();
|
|
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<decimal>();
|
|
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|