Class optimization

This commit is contained in:
Miha
2024-10-27 16:11:08 -07:00
parent b2fcdda785
commit 6c67a0cf31
77 changed files with 2634 additions and 1455 deletions
+44 -22
View File
@@ -1,5 +1,4 @@
using System;
using System.Linq;
using System.Runtime.CompilerServices;
namespace QuanTAlib;
/// <summary>
@@ -36,11 +35,13 @@ namespace QuanTAlib;
/// Note: Second-order derivative providing acceleration insights
/// </remarks>
public class Curvature : AbstractBase
[SkipLocalsInit]
public sealed class Curvature : AbstractBase
{
private readonly int _period;
private readonly Slope _slopeCalculator;
private readonly CircularBuffer _slopeBuffer;
private const double Epsilon = 1e-10;
/// <summary>
/// Gets the y-intercept of the curvature line.
@@ -64,6 +65,7 @@ public class Curvature : AbstractBase
/// <param name="period">The number of points to consider for calculation.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is 2 or less.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Curvature(int period)
{
if (period <= 2)
@@ -82,12 +84,14 @@ public class Curvature : AbstractBase
/// <param name="source">The data source object that publishes updates.</param>
/// <param name="period">The number of points to consider for calculation.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Curvature(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void Init()
{
base.Init();
@@ -98,6 +102,7 @@ public class Curvature : AbstractBase
Line = null;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected override void ManageState(bool isNew)
{
if (isNew)
@@ -107,6 +112,35 @@ public class Curvature : AbstractBase
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static (double sumX, double sumY) CalculateSums(ReadOnlySpan<double> slopes, int count)
{
double sumX = 0, sumY = 0;
for (int i = 0; i < count; i++)
{
sumX += i + 1;
sumY += slopes[i];
}
return (sumX, sumY);
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static (double sumSqX, double sumSqY, double sumSqXY) CalculateSquaredSums(
ReadOnlySpan<double> slopes, int count, double avgX, double avgY)
{
double sumSqX = 0, sumSqY = 0, sumSqXY = 0;
for (int i = 0; i < count; i++)
{
double devX = (i + 1) - avgX;
double devY = slopes[i] - avgY;
sumSqX += devX * devX;
sumSqY += devY * devY;
sumSqXY += devX * devY;
}
return (sumSqX, sumSqY, sumSqXY);
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
protected override double Calculation()
{
ManageState(Input.IsNew);
@@ -122,30 +156,17 @@ public class Curvature : AbstractBase
}
int count = Math.Min(_slopeBuffer.Count, _period);
var slopes = _slopeBuffer.GetSpan().ToArray();
ReadOnlySpan<double> slopes = _slopeBuffer.GetSpan();
// Calculate averages
double sumX = 0, sumY = 0;
for (int i = 0; i < count; i++)
{
sumX += i + 1;
sumY += slopes[i];
}
var (sumX, sumY) = CalculateSums(slopes, count);
double avgX = sumX / count;
double avgY = sumY / count;
// Least squares method
double sumSqX = 0, sumSqY = 0, sumSqXY = 0;
for (int i = 0; i < count; i++)
{
double devX = (i + 1) - avgX;
double devY = slopes[i] - avgY;
sumSqX += devX * devX;
sumSqY += devY * devY;
sumSqXY += devX * devY;
}
var (sumSqX, sumSqY, sumSqXY) = CalculateSquaredSums(slopes, count, avgX, avgY);
if (sumSqX > 0)
if (sumSqX > Epsilon)
{
curvature = sumSqXY / sumSqX;
Intercept = avgY - (curvature * avgX);
@@ -155,9 +176,10 @@ public class Curvature : AbstractBase
double stdDevY = Math.Sqrt(sumSqY / count);
StdDev = stdDevY;
if (stdDevX * stdDevY != 0)
double stdDevProduct = stdDevX * stdDevY;
if (stdDevProduct > Epsilon)
{
double r = sumSqXY / (stdDevX * stdDevY) / count;
double r = sumSqXY / (stdDevProduct) / count;
RSquared = r * r;
}