mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-01 19:27:44 +00:00
d7dbd7078a
- Updated event handler signatures to use TValueEventArgs for consistency in Mama, Mgdi, Pwma, Rma, Sma, Ssf, Super, T3, Tema, Trima, Usf, Vidya, Wma, and Atr classes. - Enhanced argument validation by specifying parameter names in exceptions for clarity. - Adjusted tests to align with new event handler signatures. - Improved code readability and maintainability by using structured records and lambda expressions.
147 lines
4.0 KiB
C#
147 lines
4.0 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace QuanTAlib;
|
|
|
|
/// <summary>
|
|
/// A high-performance time series implementation using Structure of Arrays (SoA) layout.
|
|
/// Stores Time (long) and Value (double) in separate contiguous arrays for SIMD efficiency.
|
|
/// Supports "New Bar" vs "Update Last" streaming semantics.
|
|
/// </summary>
|
|
public class TSeries : IReadOnlyList<TValue>, ITValuePublisher
|
|
{
|
|
#pragma warning disable MA0016 // Prefer using collection abstraction instead of implementation
|
|
protected readonly List<long> _t;
|
|
protected readonly List<double> _v;
|
|
#pragma warning restore MA0016
|
|
|
|
public string Name { get; set; } = "Data";
|
|
|
|
public event TValuePublishedHandler? Pub;
|
|
|
|
public TSeries() : this(0)
|
|
{
|
|
}
|
|
|
|
public TSeries(int capacity)
|
|
{
|
|
_t = new List<long>(capacity);
|
|
_v = new List<double>(capacity);
|
|
}
|
|
|
|
public TSeries(IReadOnlyList<long> time, IReadOnlyList<double> values)
|
|
{
|
|
if (time is List<long> timeList && values is List<double> valueList)
|
|
{
|
|
_t = timeList;
|
|
_v = valueList;
|
|
}
|
|
else
|
|
{
|
|
_t = new List<long>(time);
|
|
_v = new List<double>(values);
|
|
}
|
|
}
|
|
|
|
public int Count
|
|
{
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
get => _v.Count;
|
|
}
|
|
|
|
public TValue this[int index]
|
|
{
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
get => new(_t[index], _v[index]);
|
|
}
|
|
|
|
public TValue Last
|
|
{
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
get => _v.Count > 0 ? new(_t[^1], _v[^1]) : default;
|
|
}
|
|
|
|
public double LastValue
|
|
{
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
get => _v.Count > 0 ? _v[^1] : double.NaN;
|
|
}
|
|
|
|
public long LastTime
|
|
{
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
get => _t.Count > 0 ? _t[^1] : 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Direct access to the underlying Value array as a Span for SIMD operations.
|
|
/// </summary>
|
|
public ReadOnlySpan<double> Values
|
|
{
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
get => CollectionsMarshal.AsSpan(_v);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Direct access to the underlying Time array as a Span.
|
|
/// </summary>
|
|
public ReadOnlySpan<long> Times
|
|
{
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
get => CollectionsMarshal.AsSpan(_t);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public virtual void Add(TValue value, bool isNew)
|
|
{
|
|
if (isNew || _v.Count == 0)
|
|
{
|
|
_t.Add(value.Time);
|
|
_v.Add(value.Value);
|
|
}
|
|
else
|
|
{
|
|
int lastIdx = _v.Count - 1;
|
|
_t[lastIdx] = value.Time;
|
|
_v[lastIdx] = value.Value;
|
|
}
|
|
|
|
var args = new TValueEventArgs { Value = value, IsNew = isNew };
|
|
Pub?.Invoke(this, args);
|
|
}
|
|
|
|
// Overload for backward compatibility (assumes isNew=true)
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public virtual void Add(TValue value) => Add(value, true);
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void Add(long time, double value, bool isNew = true) => Add(new TValue(time, value), isNew);
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void Add(DateTime time, double value, bool isNew = true) => Add(new TValue(time, value), isNew);
|
|
|
|
public void Add(IEnumerable<double> values)
|
|
{
|
|
long t = DateTime.UtcNow.Ticks;
|
|
foreach (var v in values)
|
|
{
|
|
Add(new TValue(t, v), isNew: true);
|
|
t += TimeSpan.TicksPerMinute;
|
|
}
|
|
}
|
|
|
|
// IEnumerable implementation
|
|
public IEnumerator<TValue> GetEnumerator()
|
|
{
|
|
for (int i = 0; i < _v.Count; i++)
|
|
{
|
|
yield return new TValue(_t[i], _v[i]);
|
|
}
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
}
|