klhztrader/KLHZ.Trader.Core.Math/Declisions/Services/Cache/PriceHistoryCacheUnit3.cs

161 lines
5.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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;
}
}