using KLHZ.Trader.Core.Contracts.Declisions.Interfaces; using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces; namespace KLHZ.Trader.Core.Math.Declisions.Services.Cache { public class PriceHistoryCacheUnit2 : IPriceHistoryCacheUnit { public const int CacheMaxLength = 500; private const int _arrayMaxLength = 1500; public string Figi { get; init; } public int Length { get { lock (_locker) { return _length; } } } public long AsksCount { get { lock (_locker) { return _asksCount; } } } public long BidsCount { get { lock (_locker) { return _bidsCount; } } } private readonly object _locker = new(); private readonly float[] Prices = new float[_arrayMaxLength]; private readonly DateTime[] Timestamps = new DateTime[_arrayMaxLength]; private int _length = 0; private int _pointer = -1; private long _asksCount = 1; private long _bidsCount = 1; public ValueTask AddData(INewPrice priceChange) { if (priceChange.Figi != Figi) return ValueTask.CompletedTask; lock (_locker) { _pointer++; Prices[_pointer] = (float)priceChange.Value; Timestamps[_pointer] = priceChange.Time; if (_length < CacheMaxLength) { _length++; } if (_pointer == _arrayMaxLength - 1) { Array.Copy(Prices, Prices.Length - CacheMaxLength, Prices, 0, CacheMaxLength); Array.Copy(Timestamps, Timestamps.Length - CacheMaxLength, Timestamps, 0, CacheMaxLength); _pointer = CacheMaxLength - 1; } } return ValueTask.CompletedTask; } public ValueTask<(DateTime[] timestamps, float[] prices)> GetData() { lock (_locker) { if (_pointer < 0) { return ValueTask.FromResult((Array.Empty(), Array.Empty())); } else { var prices = new float[_length]; var timestamps = new DateTime[_length]; Array.Copy(Prices, 1 + _pointer - _length, prices, 0, prices.Length); Array.Copy(Timestamps, 1 + _pointer - _length, timestamps, 0, timestamps.Length); return ValueTask.FromResult((timestamps, prices)); } } } public ValueTask AddOrderbook(IOrderbook orderbook) { if (orderbook.Figi != Figi) return ValueTask.CompletedTask; lock (_locker) { _asksCount = orderbook.AsksCount; _bidsCount = orderbook.BidsCount; } return ValueTask.CompletedTask; } public PriceHistoryCacheUnit2(string figi, params INewPrice[] priceChanges) { Figi = figi; if (priceChanges.Length == 0) { return; } var selectedPriceChanges = priceChanges .OrderBy(pc => pc.Time) .Skip(priceChanges.Length - CacheMaxLength) .ToArray(); foreach (var pc in selectedPriceChanges) { AddData(pc); } } } }