161 lines
5.5 KiB
C#
161 lines
5.5 KiB
C#
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
|
||
|
||
namespace KLHZ.Trader.Core.Math.Declisions.Services.Cache
|
||
{
|
||
public class PriceHistoryCacheUnit3
|
||
{
|
||
private readonly Dictionary<string, TimeSpan> _windowSizes = new()
|
||
{
|
||
{string.Empty, TimeSpan.FromDays(3)}
|
||
};
|
||
|
||
public string Figi { get; init; }
|
||
|
||
public IOrderbook? Orderbook
|
||
{
|
||
get
|
||
{
|
||
lock (_locker)
|
||
{
|
||
return _orderbook;
|
||
}
|
||
}
|
||
}
|
||
|
||
private IOrderbook? _orderbook;
|
||
|
||
private readonly object _locker = new();
|
||
private readonly Dictionary<string, LinkedList<ITradeDataItem>> _items = new Dictionary<string, LinkedList<ITradeDataItem>>();
|
||
|
||
public ValueTask AddData(ITradeDataItem item, string? key = null)
|
||
{
|
||
lock (_locker)
|
||
{
|
||
key = key ?? string.Empty;
|
||
if (key == string.Empty)
|
||
{
|
||
if (item.Figi != Figi)
|
||
{
|
||
throw new ArgumentException("Для дефолтного кеша Figi должен совпадать с figi элемента.");
|
||
}
|
||
}
|
||
var windowSize = _windowSizes.TryGetValue(key, out var size) ? size : TimeSpan.FromMinutes(60);
|
||
if (!_items.TryGetValue(key, out var list))
|
||
{
|
||
list = new LinkedList<ITradeDataItem>();
|
||
_items[key] = list;
|
||
}
|
||
list.AddFirst(item);
|
||
while (list.Last != null && list.First != null
|
||
&& list.First.Value.Time - list.Last.Value.Time > windowSize)
|
||
{
|
||
list.RemoveLast();
|
||
}
|
||
}
|
||
return ValueTask.CompletedTask;
|
||
}
|
||
|
||
public ValueTask AddOrderbook(IOrderbook orderbook)
|
||
{
|
||
if (orderbook.Figi != Figi) return ValueTask.CompletedTask;
|
||
lock (_locker)
|
||
{
|
||
_orderbook = orderbook;
|
||
}
|
||
return ValueTask.CompletedTask;
|
||
}
|
||
|
||
public ValueTask<ITradeDataItem[]> GetData(TimeSpan? period = null, string? key = null, Func<ITradeDataItem, bool>? selector = null)
|
||
{
|
||
key = key ?? string.Empty;
|
||
var res = new List<ITradeDataItem>();
|
||
selector = selector ?? defaultSelector;
|
||
lock (_locker)
|
||
{
|
||
if (_items.TryGetValue(key, out var list) && list.First != null && list.Last != null)
|
||
{
|
||
var startTime = list.First.Value.Time;
|
||
if (period.HasValue)
|
||
{
|
||
foreach (var item in list)
|
||
{
|
||
if (startTime - item.Time < period.Value && selector(item))
|
||
{
|
||
res.Add(item);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
return ValueTask.FromResult(list.Where(selector).Reverse().ToArray());
|
||
}
|
||
|
||
}
|
||
}
|
||
res.Reverse();
|
||
return ValueTask.FromResult(res.ToArray());
|
||
}
|
||
|
||
public ValueTask<(DateTime time, decimal price)> GetLastValues(string? key = null)
|
||
{
|
||
key = key ?? string.Empty;
|
||
lock (_locker)
|
||
{
|
||
if (_items.TryGetValue(key, out var list) && list.First != null && list.Last != null)
|
||
{
|
||
return ValueTask.FromResult((list.Last.Value.Time, list.Last.Value.Price));
|
||
}
|
||
}
|
||
return ValueTask.FromResult((DateTime.MinValue, 0m));
|
||
}
|
||
|
||
public ValueTask<ITradeDataItem[]> GetData(TimeSpan shift, TimeSpan period, string? key = null, Func<ITradeDataItem, bool>? selector = null)
|
||
{
|
||
key = key ?? string.Empty;
|
||
var res = new List<ITradeDataItem>();
|
||
var maxPeriod = shift + period;
|
||
selector = selector ?? defaultSelector;
|
||
lock (_locker)
|
||
{
|
||
if (_items.TryGetValue(key, out var list) && list.First != null && list.Last != null)
|
||
{
|
||
var startTime = list.First.Value.Time;
|
||
|
||
foreach (var item in list)
|
||
{
|
||
var dt = startTime - item.Time;
|
||
if (dt > shift && dt < maxPeriod && selector(item))
|
||
{
|
||
res.Add(item);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
res.Reverse();
|
||
return ValueTask.FromResult(res.ToArray());
|
||
}
|
||
|
||
public PriceHistoryCacheUnit3(string figi, params ITradeDataItem[] priceChanges)
|
||
{
|
||
Figi = figi;
|
||
|
||
|
||
if (priceChanges.Length == 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
var selectedPriceChanges = priceChanges
|
||
.OrderBy(pc => pc.Time)
|
||
.ToArray();
|
||
|
||
foreach (var pc in selectedPriceChanges)
|
||
{
|
||
AddData(pc).AsTask().Wait();
|
||
}
|
||
}
|
||
|
||
private static bool defaultSelector(ITradeDataItem item) => true;
|
||
}
|
||
}
|