mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-19 11:08:05 +00:00
chore: Update documentation links and improve code readability in averages and tests
This commit is contained in:
@@ -51,7 +51,7 @@
|
|||||||
| SINEMA | Sine-weighted MA |
|
| SINEMA | Sine-weighted MA |
|
||||||
| [SMA](sma/Sma.cs) | Simple MA |
|
| [SMA](sma/Sma.cs) | Simple MA |
|
||||||
| SSF | Ehlers Super Smooth Filter |
|
| SSF | Ehlers Super Smooth Filter |
|
||||||
| T3 | Tillson T3 MA |
|
| [T3](t3/T3.cs) | Tillson T3 MA |
|
||||||
| [TEMA](tema/Tema.cs) | Triple Exponential MA |
|
| [TEMA](tema/Tema.cs) | Triple Exponential MA |
|
||||||
| [TRIMA](trima/Trima.cs) | Triangular MA |
|
| [TRIMA](trima/Trima.cs) | Triangular MA |
|
||||||
| USF | Ehlers Ultrasmooth Filter |
|
| USF | Ehlers Ultrasmooth Filter |
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ public sealed class Hma : ITValuePublisher
|
|||||||
|
|
||||||
public TSeries Update(TSeries source)
|
public TSeries Update(TSeries source)
|
||||||
{
|
{
|
||||||
if (source.Count == 0) return new TSeries(new List<long>(), new List<double>());
|
if (source.Count == 0) return new TSeries([], new List<double>());
|
||||||
|
|
||||||
int len = source.Count;
|
int len = source.Count;
|
||||||
var t = new List<long>(len);
|
var t = new List<long>(len);
|
||||||
|
|||||||
@@ -35,10 +35,12 @@ public sealed class T3 : ITValuePublisher
|
|||||||
|
|
||||||
public override bool Equals(object? obj) => obj is State other && Equals(other);
|
public override bool Equals(object? obj) => obj is State other && Equals(other);
|
||||||
|
|
||||||
|
#pragma warning disable S1244 // Do not check floating point equality with exact values
|
||||||
public bool Equals(State other) =>
|
public bool Equals(State other) =>
|
||||||
E1 == other.E1 && E2 == other.E2 && E3 == other.E3 &&
|
E1 == other.E1 && E2 == other.E2 && E3 == other.E3 &&
|
||||||
E4 == other.E4 && E5 == other.E5 && E6 == other.E6 &&
|
E4 == other.E4 && E5 == other.E5 && E6 == other.E6 &&
|
||||||
IsInitialized == other.IsInitialized;
|
IsInitialized == other.IsInitialized;
|
||||||
|
#pragma warning restore S1244 // Do not check floating point equality with exact values
|
||||||
|
|
||||||
public override int GetHashCode() => HashCode.Combine(E1, E2, E3, E4, E5, E6, IsInitialized);
|
public override int GetHashCode() => HashCode.Combine(E1, E2, E3, E4, E5, E6, IsInitialized);
|
||||||
|
|
||||||
@@ -63,10 +65,12 @@ public sealed class T3 : ITValuePublisher
|
|||||||
|
|
||||||
public override bool Equals(object? obj) => obj is Parameters other && Equals(other);
|
public override bool Equals(object? obj) => obj is Parameters other && Equals(other);
|
||||||
|
|
||||||
|
#pragma warning disable S1244 // Do not check floating point equality with exact values
|
||||||
public bool Equals(Parameters other) =>
|
public bool Equals(Parameters other) =>
|
||||||
Alpha == other.Alpha &&
|
Alpha == other.Alpha &&
|
||||||
C1 == other.C1 && C2 == other.C2 &&
|
C1 == other.C1 && C2 == other.C2 &&
|
||||||
C3 == other.C3 && C4 == other.C4;
|
C3 == other.C3 && C4 == other.C4;
|
||||||
|
#pragma warning restore S1244 // Do not check floating point equality with exact values
|
||||||
|
|
||||||
public override int GetHashCode() => HashCode.Combine(Alpha, C1, C2, C3, C4);
|
public override int GetHashCode() => HashCode.Combine(Alpha, C1, C2, C3, C4);
|
||||||
|
|
||||||
|
|||||||
@@ -111,9 +111,11 @@ public class IndicatorExtensionsTests
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void LogicMethods_CalculateCorrectly()
|
public void LogicMethods_CalculateCorrectly()
|
||||||
{
|
{
|
||||||
var indicator = new TestIndicator();
|
var indicator = new TestIndicator
|
||||||
indicator.CurrentChart = new MockChart();
|
{
|
||||||
|
CurrentChart = new MockChart()
|
||||||
|
};
|
||||||
|
|
||||||
// Add some data
|
// Add some data
|
||||||
var now = new DateTime(2024, 1, 1, 12, 0, 0, DateTimeKind.Utc);
|
var now = new DateTime(2024, 1, 1, 12, 0, 0, DateTimeKind.Utc);
|
||||||
for (int i = 0; i < 20; i++)
|
for (int i = 0; i < 20; i++)
|
||||||
@@ -134,8 +136,8 @@ public class IndicatorExtensionsTests
|
|||||||
|
|
||||||
// 2. Test GetSmoothCurvePoints
|
// 2. Test GetSmoothCurvePoints
|
||||||
var series = new LineSeries("Test", Color.Blue, 1, LineStyle.Solid);
|
var series = new LineSeries("Test", Color.Blue, 1, LineStyle.Solid);
|
||||||
for (int i = 0; i < 20; i++) series.AddValue();
|
for (int i = 0; i < 20; i++) series.AddValue();
|
||||||
for (int i = 0; i < 20; i++) series.SetValue(100 + i, i);
|
for (int i = 0; i < 20; i++) series.SetValue(100 + i, i);
|
||||||
|
|
||||||
var points = IndicatorExtensions.GetSmoothCurvePoints(indicator, converter, clientRect, series);
|
var points = IndicatorExtensions.GetSmoothCurvePoints(indicator, converter, clientRect, series);
|
||||||
Assert.NotEmpty(points);
|
Assert.NotEmpty(points);
|
||||||
@@ -143,11 +145,11 @@ public class IndicatorExtensionsTests
|
|||||||
// MockChart.BarsWidth defaults to something? Let's assume 0 or check logic.
|
// MockChart.BarsWidth defaults to something? Let's assume 0 or check logic.
|
||||||
// In GetSmoothCurvePoints: barX + halfBarWidth.
|
// In GetSmoothCurvePoints: barX + halfBarWidth.
|
||||||
// Our mock GetChartX returns 10.
|
// Our mock GetChartX returns 10.
|
||||||
|
|
||||||
// 3. Test GetHistogramRectangles
|
// 3. Test GetHistogramRectangles
|
||||||
var histSeries = new LineSeries("Hist", Color.Blue, 1, LineStyle.Solid);
|
var histSeries = new LineSeries("Hist", Color.Blue, 1, LineStyle.Solid);
|
||||||
for (int i = 0; i < 20; i++) histSeries.AddValue();
|
for (int i = 0; i < 20; i++) histSeries.AddValue();
|
||||||
for (int i = 0; i < 20; i++)
|
for (int i = 0; i < 20; i++)
|
||||||
{
|
{
|
||||||
double val = (i % 2 == 0) ? 10.0 : -10.0;
|
double val = (i % 2 == 0) ? 10.0 : -10.0;
|
||||||
histSeries.SetValue(val, i);
|
histSeries.SetValue(val, i);
|
||||||
@@ -155,20 +157,20 @@ public class IndicatorExtensionsTests
|
|||||||
|
|
||||||
var rects = IndicatorExtensions.GetHistogramRectangles(indicator, converter, clientRect, histSeries);
|
var rects = IndicatorExtensions.GetHistogramRectangles(indicator, converter, clientRect, histSeries);
|
||||||
Assert.NotEmpty(rects);
|
Assert.NotEmpty(rects);
|
||||||
|
|
||||||
// Check value at offset 9 (i=9 in setup loop)
|
// Check value at offset 9 (i=9 in setup loop)
|
||||||
// i=9 is odd -> -10.0 (Negative)
|
// i=9 is odd -> -10.0 (Negative)
|
||||||
// Color should be Red (150, 255, 0, 0)
|
// Color should be Red (150, 255, 0, 0)
|
||||||
var first = rects.First();
|
var first = rects[0];
|
||||||
Assert.Equal(Color.FromArgb(150, 255, 0, 0), first.Color);
|
Assert.Equal(Color.FromArgb(150, 255, 0, 0), first.Color);
|
||||||
|
|
||||||
// Verify geometry
|
// Verify geometry
|
||||||
// Value is -10. GetChartY(-10) -> -10.
|
// Value is -10. GetChartY(-10) -> -10.
|
||||||
// GetChartY(0) -> 0.
|
// GetChartY(0) -> 0.
|
||||||
// Height = Abs(0 - (-10)) = 10.
|
// Height = Abs(0 - (-10)) = 10.
|
||||||
// Y = 0 (since negative bars start at 0 and go down? No, GDI+ coords usually go down.
|
// Y = 0 (since negative bars start at 0 and go down? No, GDI+ coords usually go down.
|
||||||
// But here we are testing the logic in GetHistogramRectangles:
|
// But here we are testing the logic in GetHistogramRectangles:
|
||||||
// else { new Rectangle(barX, barY0, ...) } -> Y = barY0 = 0.
|
// else new Rectangle(barX, barY0, ...) -> Y = barY0 = 0.
|
||||||
Assert.Equal(0, first.Rect.Y);
|
Assert.Equal(0, first.Rect.Y);
|
||||||
Assert.Equal(10, first.Rect.Height);
|
Assert.Equal(10, first.Rect.Height);
|
||||||
}
|
}
|
||||||
@@ -179,27 +181,38 @@ public class IndicatorExtensionsTests
|
|||||||
{
|
{
|
||||||
// This test attempts to verify that paint methods don't crash.
|
// This test attempts to verify that paint methods don't crash.
|
||||||
// It requires System.Drawing.Common to be functional.
|
// It requires System.Drawing.Common to be functional.
|
||||||
|
|
||||||
// On non-Windows, this might fail if libgdiplus is not installed.
|
// On non-Windows, this might fail if libgdiplus is not installed.
|
||||||
// We'll try-catch the PlatformNotSupportedException to allow the test to pass (but not cover) on those systems.
|
// We'll try-catch the PlatformNotSupportedException to allow the test to pass (but not cover) on those systems.
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var bitmap = new Bitmap(100, 100);
|
using var bitmap = new Bitmap(100, 100);
|
||||||
using var graphics = Graphics.FromImage(bitmap);
|
using var graphics = Graphics.FromImage(bitmap);
|
||||||
RunPaintTests(graphics);
|
RunPaintTests(graphics);
|
||||||
Assert.True(true); // Assertion to satisfy SonarCloud RSPEC-2699
|
Assert.True(true); // Assertion to satisfy SonarCloud RSPEC-2699
|
||||||
}
|
}
|
||||||
catch (TypeInitializationException) { return; } // System.Drawing.Common not supported
|
catch (TypeInitializationException)
|
||||||
catch (PlatformNotSupportedException) { return; } // GDI+ not available
|
{
|
||||||
catch (DllNotFoundException) { return; } // libgdiplus not found
|
// System.Drawing.Common not supported on this platform
|
||||||
|
}
|
||||||
|
catch (PlatformNotSupportedException)
|
||||||
|
{
|
||||||
|
// GDI+ not available on this platform
|
||||||
|
}
|
||||||
|
catch (DllNotFoundException)
|
||||||
|
{
|
||||||
|
// libgdiplus not found on this platform
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
|
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
|
||||||
private void RunPaintTests(Graphics graphics)
|
private void RunPaintTests(Graphics graphics)
|
||||||
{
|
{
|
||||||
var indicator = new TestIndicator();
|
var indicator = new TestIndicator
|
||||||
indicator.CurrentChart = new MockChart();
|
{
|
||||||
|
CurrentChart = new MockChart()
|
||||||
|
};
|
||||||
|
|
||||||
// Add some data
|
// Add some data
|
||||||
var now = new DateTime(2024, 1, 1, 12, 0, 0, DateTimeKind.Utc);
|
var now = new DateTime(2024, 1, 1, 12, 0, 0, DateTimeKind.Utc);
|
||||||
for (int i = 0; i < 20; i++)
|
for (int i = 0; i < 20; i++)
|
||||||
@@ -213,7 +226,7 @@ public class IndicatorExtensionsTests
|
|||||||
|
|
||||||
var args = new PaintChartEventArgs(graphics, new Rectangle(0, 0, 100, 100));
|
var args = new PaintChartEventArgs(graphics, new Rectangle(0, 0, 100, 100));
|
||||||
using var pen = new Pen(Color.Red);
|
using var pen = new Pen(Color.Red);
|
||||||
|
|
||||||
// Test PaintHLine
|
// Test PaintHLine
|
||||||
IndicatorExtensions.PaintHLine(indicator, args, 100, pen);
|
IndicatorExtensions.PaintHLine(indicator, args, 100, pen);
|
||||||
|
|
||||||
@@ -221,12 +234,12 @@ public class IndicatorExtensionsTests
|
|||||||
foreach (LineStyle style in Enum.GetValues(typeof(LineStyle)))
|
foreach (LineStyle style in Enum.GetValues(typeof(LineStyle)))
|
||||||
{
|
{
|
||||||
var series = new LineSeries("Test", Color.Blue, 1, style);
|
var series = new LineSeries("Test", Color.Blue, 1, style);
|
||||||
for (int i = 0; i < 20; i++) series.AddValue();
|
for (int i = 0; i < 20; i++) series.AddValue();
|
||||||
for (int i = 0; i < 20; i++) series.SetValue(100 + i, i);
|
for (int i = 0; i < 20; i++) series.SetValue(100 + i, i);
|
||||||
|
|
||||||
// Test with warmup and cold values
|
// Test with warmup and cold values
|
||||||
IndicatorExtensions.PaintSmoothCurve(indicator, args, series, warmupPeriod: 5, showColdValues: true);
|
IndicatorExtensions.PaintSmoothCurve(indicator, args, series, warmupPeriod: 5, showColdValues: true);
|
||||||
|
|
||||||
// Test without cold values
|
// Test without cold values
|
||||||
IndicatorExtensions.PaintSmoothCurve(indicator, args, series, warmupPeriod: 5, showColdValues: false);
|
IndicatorExtensions.PaintSmoothCurve(indicator, args, series, warmupPeriod: 5, showColdValues: false);
|
||||||
}
|
}
|
||||||
@@ -234,7 +247,7 @@ public class IndicatorExtensionsTests
|
|||||||
// Test PaintHistogram with Positive and Negative values
|
// Test PaintHistogram with Positive and Negative values
|
||||||
var histSeries = new LineSeries("Hist", Color.Blue, 1, LineStyle.Solid);
|
var histSeries = new LineSeries("Hist", Color.Blue, 1, LineStyle.Solid);
|
||||||
for (int i = 0; i < 20; i++) histSeries.AddValue();
|
for (int i = 0; i < 20; i++) histSeries.AddValue();
|
||||||
for (int i = 0; i < 20; i++)
|
for (int i = 0; i < 20; i++)
|
||||||
{
|
{
|
||||||
// Alternate positive and negative
|
// Alternate positive and negative
|
||||||
double val = (i % 2 == 0) ? 10.0 : -10.0;
|
double val = (i % 2 == 0) ? 10.0 : -10.0;
|
||||||
@@ -256,9 +269,9 @@ public class IndicatorExtensionsTests
|
|||||||
|
|
||||||
// Cast to an invalid SourceType to trigger default case
|
// Cast to an invalid SourceType to trigger default case
|
||||||
SourceType invalidType = (SourceType)999;
|
SourceType invalidType = (SourceType)999;
|
||||||
|
|
||||||
var result = IndicatorExtensions.GetInputValue(indicator, args, invalidType);
|
var result = IndicatorExtensions.GetInputValue(indicator, args, invalidType);
|
||||||
|
|
||||||
Assert.Equal(105, result.Value); // Should default to Close (105)
|
Assert.Equal(105, result.Value); // Should default to Close (105)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -170,24 +170,23 @@ public static class IndicatorExtensions
|
|||||||
DateTime rightTime = new[] { converter.GetTime(clientRect.Right), indicator.HistoricalData.Time(0) }.Min();
|
DateTime rightTime = new[] { converter.GetTime(clientRect.Right), indicator.HistoricalData.Time(0) }.Min();
|
||||||
int rightIndex = (int)indicator.HistoricalData.GetIndexByTime(rightTime.Ticks);
|
int rightIndex = (int)indicator.HistoricalData.GetIndexByTime(rightTime.Ticks);
|
||||||
|
|
||||||
using (Pen defaultPen = new(series.Color, series.Width) { DashStyle = ConvertLineStyleToDashStyle(series.Style) })
|
using Pen defaultPen = new(series.Color, series.Width) { DashStyle = ConvertLineStyleToDashStyle(series.Style) };
|
||||||
using (Pen coldPen = new(series.Color, series.Width) { DashStyle = DashStyle.Dot })
|
using Pen coldPen = new(series.Color, series.Width) { DashStyle = DashStyle.Dot };
|
||||||
|
|
||||||
|
int hotCount = indicator.Count - warmupPeriod - rightIndex;
|
||||||
|
|
||||||
|
// Draw the hot part
|
||||||
|
if (hotCount > 0)
|
||||||
{
|
{
|
||||||
int hotCount = indicator.Count - warmupPeriod - rightIndex;
|
var hotPoints = allPoints.Take(Math.Min(hotCount + 1, allPoints.Count)).ToArray();
|
||||||
|
gr.DrawCurve(defaultPen, hotPoints, 0, hotPoints.Length - 1, (float)tension);
|
||||||
|
}
|
||||||
|
|
||||||
// Draw the hot part
|
// Draw the cold part
|
||||||
if (hotCount > 0)
|
if (showColdValues && hotCount < allPoints.Count)
|
||||||
{
|
{
|
||||||
var hotPoints = allPoints.Take(Math.Min(hotCount + 1, allPoints.Count)).ToArray();
|
var coldPoints = allPoints.Skip(Math.Max(0, hotCount)).ToArray();
|
||||||
gr.DrawCurve(defaultPen, hotPoints, 0, hotPoints.Length - 1, (float)tension);
|
gr.DrawCurve(coldPen, coldPoints, 0, coldPoints.Length - 1, (float)tension);
|
||||||
}
|
|
||||||
|
|
||||||
// Draw the cold part
|
|
||||||
if (showColdValues && hotCount < allPoints.Count)
|
|
||||||
{
|
|
||||||
var coldPoints = allPoints.Skip(Math.Max(0, hotCount)).ToArray();
|
|
||||||
gr.DrawCurve(coldPen, coldPoints, 0, coldPoints.Length - 1, (float)tension);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user