diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..90c7b22c Binary files /dev/null and b/.DS_Store differ diff --git a/.github/codeql/extensions/quantalib-csharp/codeql-pack.yml b/.github/codeql/extensions/quantalib-csharp/codeql-pack.yml new file mode 100644 index 00000000..feaae3df --- /dev/null +++ b/.github/codeql/extensions/quantalib-csharp/codeql-pack.yml @@ -0,0 +1,7 @@ +name: mihakralj/quantalib-csharp +version: 0.0.0 +library: true +extensionTargets: + codeql/csharp-all: '*' +dataExtensions: + - models/**/*.yml diff --git a/.sonarlint/CSharp/SonarLint.xml b/.sonarlint/CSharp/SonarLint.xml new file mode 100644 index 00000000..99dacdae --- /dev/null +++ b/.sonarlint/CSharp/SonarLint.xml @@ -0,0 +1,13 @@ + + + + + + + + csharpsquid:S3776 + + + + + diff --git a/.sonarlint/csharp.ruleset b/.sonarlint/csharp.ruleset new file mode 100644 index 00000000..5dff3f86 --- /dev/null +++ b/.sonarlint/csharp.ruleset @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 5b4a7dfb..00000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - - { - "name": "Build lib/quantalib.csproj (Debug net10.0)", - "type": "coreclr", - "request": "launch", - "program": "dotnet", - "args": [ - "build", - "${workspaceFolder}/lib/quantalib.csproj", - "--configuration", - "Debug", - "--framework", - "net10.0" - ], - "cwd": "${workspaceFolder}", - "stopAtEntry": false, - "console": "integratedTerminal", - "logging": { - "moduleLoad": false - } - }, - { - "name": "Debug Tests", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build-sln-debug", - "program": "dotnet", - "args": [ - "test", - "${workspaceFolder}/QuanTAlib.sln", - "--no-build" - ], - "cwd": "${workspaceFolder}", - "stopAtEntry": false, - "console": "internalConsole", - "logging": { - "moduleLoad": false - } - }, - { - "name": "Debug Library", - "type": "coreclr", - "request": "attach", - "processId": "${command:pickProcess}", - "justMyCode": true, - "logging": { - "moduleLoad": false - } - }, - { - "name": "Build solution (Debug)", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build-sln-debug", - "program": "dotnet", - "args": [ - "build", - "${workspaceFolder}/QuanTAlib.sln", - "--configuration", - "Debug" - ], - "cwd": "${workspaceFolder}", - "stopAtEntry": false, - "console": "integratedTerminal", - "logging": { - "moduleLoad": false - } - } - ] -} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 8fa0c170..42ecf80c 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,23 +2,8 @@ "version": "2.0.0", "tasks": [ { - "label": "Build & Audit (Roslyn + JetBrains)", - "dependsOrder": "sequence", - "dependsOn": ["Create .sarif Dir", "Build: QuanTAlib", "JetBrains: Inspect"], - "group": { "kind": "build", "isDefault": true } - }, - { - "label": "Create .sarif Dir", - "type": "shell", - "command": "mkdir -p .sarif", - "windows": { - "command": "powershell", - "args": ["-Command", "if (!(Test-Path .sarif)) { New-Item -Path .sarif -ItemType Directory }"] - }, - "presentation": { "reveal": "silent" } - }, - { - "label": "Build: QuanTAlib", + "label": "Build", + "detail": "dotnet build QuanTAlib.sln", "type": "process", "command": "dotnet", "args": [ @@ -27,63 +12,36 @@ "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], - "problemMatcher": "$msCompile" - }, - { - "label": "JetBrains: Inspect", - "type": "shell", - "command": "jb inspectcode QuanTAlib.sln --output=.sarif/jetbrains.sarif --format=Sarif", - "presentation": { "reveal": "always" }, - "problemMatcher": [], - "postLines": ["Analysis complete. Open .sarif/jetbrains.sarif to view results."] - }, - { - "label": "JetBrains: Cleanup", - "type": "shell", - "command": "jb cleanupcode QuanTAlib.sln", - "problemMatcher": [] - }, - { - "label": "test-net10", - "command": "dotnet", - "type": "process", - "args": [ - "test", - "${workspaceFolder}/lib/QuanTAlib.Tests.csproj", - "--framework", - "net10.0" - ], "problemMatcher": "$msCompile", - "group": { "kind": "test", "isDefault": true }, - "presentation": { "reveal": "always", "panel": "new" } + "group": { "kind": "build", "isDefault": true } }, { - "label": "build-lib-net10-debug", + "label": "Build Library", + "detail": "dotnet build lib/quantalib.csproj (Debug, net10.0)", "type": "process", "command": "dotnet", "args": [ "build", "${workspaceFolder}/lib/quantalib.csproj", - "--configuration", - "Debug", - "--framework", - "net10.0" + "--configuration", "Debug", + "--framework", "net10.0" ], "problemMatcher": "$msCompile", - "group": { "kind": "build", "isDefault": false } + "group": "build" }, { - "label": "build-sln-debug", + "label": "Test", + "detail": "dotnet test lib/QuanTAlib.Tests.csproj (net10.0)", "type": "process", "command": "dotnet", "args": [ - "build", - "${workspaceFolder}/QuanTAlib.sln", - "--configuration", - "Debug" + "test", + "${workspaceFolder}/lib/QuanTAlib.Tests.csproj", + "--framework", "net10.0" ], "problemMatcher": "$msCompile", - "group": { "kind": "build", "isDefault": false } + "group": { "kind": "test", "isDefault": true }, + "presentation": { "reveal": "always", "panel": "new" } } ] } diff --git a/Directory.Build.props b/Directory.Build.props index f5979f3a..62afc10c 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -19,7 +19,7 @@ true snupkg true - + true true @@ -33,12 +33,15 @@ - $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), 'QuanTAlib.sln'))\.sarif - $(SarifOutputDir)\$(MSBuildProjectName).sarif,version=2.1 + + $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), 'QuanTAlib.sln'))/.sarif + $(SarifOutputDir)/$(MSBuildProjectName).sarif,version=2.1 - + + + @@ -46,15 +49,15 @@ portable true true - + link - + false false true - + false @@ -62,7 +65,8 @@ - $(NoWarn);S107;S1144;S1944;S2053;S2245;S2259;S2583;S2589;S3329;S3604;S3655;S3776;S3949;S3966;S4158;S4347;S5773;S6781;MA0048;MA0051;MA0076;RCS1123;RCS1159;IDE0007 + + $(NoWarn);S107;S1144;S1944;S2053;S2245;S2259;S2583;S2589;S3329;S3604;S3655;S3776;S3949;S3966;S4158;S4347;S5773;S6781;MA0007;MA0048;MA0051;MA0076;RCS1123;RCS1159;IDE0007 @@ -74,6 +78,16 @@ [xunit.*]*,[*.Tests]* + + + $(MSBuildThisFileDirectory).sonarlint\csharp.ruleset + + + + Properties\SonarLint.xml + + + diff --git a/lib/channels/maenv/Maenv.cs b/lib/channels/maenv/Maenv.cs index 82a60b31..ba0ac540 100644 --- a/lib/channels/maenv/Maenv.cs +++ b/lib/channels/maenv/Maenv.cs @@ -289,7 +289,7 @@ public sealed class Maenv : ITValuePublisher private double CalculateEMA(double value, bool isNew) { // Use EmaWeight==0 to detect first value for correct isNew=false behavior - if (_state.EmaWeight == 0) + if (Math.Abs(_state.EmaWeight) < double.Epsilon) { // First value - persist only for isNew=true if (isNew) diff --git a/lib/channels/sdchannel/Sdchannel.cs b/lib/channels/sdchannel/Sdchannel.cs index 166d9430..a94454cb 100644 --- a/lib/channels/sdchannel/Sdchannel.cs +++ b/lib/channels/sdchannel/Sdchannel.cs @@ -75,6 +75,9 @@ public sealed class Sdchannel : ITValuePublisher public event TValuePublishedHandler? Pub; + /// + /// Initializes a new Standard Deviation Channel indicator with specified period and multiplier. + /// /// Lookback period for regression (default 20, must be > 1) /// Standard deviation multiplier for bands (default 2.0, must be > 0) public Sdchannel(int period = 20, double multiplier = 2.0) diff --git a/lib/cycles/stc/Stc.cs b/lib/cycles/stc/Stc.cs index cbbebd67..8f76832f 100644 --- a/lib/cycles/stc/Stc.cs +++ b/lib/cycles/stc/Stc.cs @@ -1,6 +1,5 @@ using System; using System.Buffers; -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -121,7 +120,6 @@ public sealed class Stc : AbstractBase } [MethodImpl(MethodImplOptions.AggressiveInlining)] - [SuppressMessage("SonarQube", "S3776:Cognitive Complexity", Justification = "High-performance SIMD code with intentionally optimized control flow")] private static void UpdateMinMax(double added, double removed, bool hasRemoved, RingBuffer buf, ref double min, ref double max) { if (double.IsNaN(added)) return; @@ -559,4 +557,4 @@ public sealed class Stc : AbstractBase ArrayPool.Shared.Return(rentedStoch1); } } -} \ No newline at end of file +} diff --git a/lib/momentum/roc/Roc.cs b/lib/momentum/roc/Roc.cs index eaf50931..b13371cd 100644 --- a/lib/momentum/roc/Roc.cs +++ b/lib/momentum/roc/Roc.cs @@ -27,6 +27,9 @@ public sealed class Roc : AbstractBase public override bool IsHot => _buffer.Count > _period; + /// + /// Initializes a new Rate of Change indicator with specified lookback period. + /// /// Lookback period (must be >= 1) public Roc(int period = 9) { @@ -39,6 +42,9 @@ public sealed class Roc : AbstractBase WarmupPeriod = period + 1; } + /// + /// Initializes a new Rate of Change indicator with source for event-based chaining. + /// /// Source indicator for chaining /// Lookback period public Roc(ITValuePublisher source, int period = 9) : this(period) diff --git a/lib/numerics/change/Change.cs b/lib/numerics/change/Change.cs index 6ad5f3d7..59c2785b 100644 --- a/lib/numerics/change/Change.cs +++ b/lib/numerics/change/Change.cs @@ -27,6 +27,9 @@ public sealed class Change : AbstractBase public override bool IsHot => _buffer.Count > _period; + /// + /// + /// /// Lookback period (must be >= 1) public Change(int period = 1) { @@ -39,6 +42,9 @@ public sealed class Change : AbstractBase WarmupPeriod = period + 1; } + /// + /// + /// /// Source indicator for chaining /// Lookback period public Change(ITValuePublisher source, int period = 1) : this(period) @@ -99,7 +105,7 @@ public sealed class Change : AbstractBase for (int i = 0; i < source.Length; i++) { - Update(new TValue(time, source[i]), true); + Update(new TValue(time, value: source[i]), isNew: true); time += interval; } } @@ -189,4 +195,4 @@ public sealed class Change : AbstractBase _p_state = default; Last = default; } -} \ No newline at end of file +} diff --git a/lib/numerics/exptrans/Exptrans.cs b/lib/numerics/exptrans/Exptrans.cs index a95232a1..a2810b3a 100644 --- a/lib/numerics/exptrans/Exptrans.cs +++ b/lib/numerics/exptrans/Exptrans.cs @@ -30,6 +30,9 @@ public sealed class Exptrans : AbstractBase WarmupPeriod = 0; } + /// + /// Creates Exptrans with source for event-based chaining. + /// /// Source indicator for chaining public Exptrans(ITValuePublisher source) : this() { @@ -146,4 +149,4 @@ public sealed class Exptrans : AbstractBase _p_state = new(1.0); Last = default; } -} \ No newline at end of file +} diff --git a/lib/numerics/highest/Highest.cs b/lib/numerics/highest/Highest.cs index 824940e7..414b1abe 100644 --- a/lib/numerics/highest/Highest.cs +++ b/lib/numerics/highest/Highest.cs @@ -26,6 +26,9 @@ public sealed class Highest : AbstractBase public override bool IsHot => _buffer.Count >= _period; + /// + /// Initializes a new Highest indicator with specified lookback period. + /// /// Lookback window size (must be >= 1) public Highest(int period) { @@ -38,6 +41,9 @@ public sealed class Highest : AbstractBase WarmupPeriod = period; } + /// + /// Initializes a new Highest indicator with source for event-based chaining. + /// /// Source indicator for chaining /// Lookback window size public Highest(ITValuePublisher source, int period) : this(period) @@ -89,7 +95,7 @@ public sealed class Highest : AbstractBase for (int i = 0; i < source.Length; i++) { - Update(new TValue(time, source[i]), true); + Update(input: new TValue(time, source[i]), isNew: true); time += interval; } } diff --git a/lib/numerics/lineartrans/Lineartrans.cs b/lib/numerics/lineartrans/Lineartrans.cs index 0a6fc988..f7744da4 100644 --- a/lib/numerics/lineartrans/Lineartrans.cs +++ b/lib/numerics/lineartrans/Lineartrans.cs @@ -48,6 +48,9 @@ public sealed class Lineartrans : AbstractBase WarmupPeriod = 0; } + /// + /// Creates a Linear transformer with source for event-based chaining. + /// /// Source indicator for chaining /// Multiplicative factor (default: 1.0) /// Additive constant (default: 0.0) diff --git a/lib/numerics/logtrans/Logtrans.cs b/lib/numerics/logtrans/Logtrans.cs index e280b53f..2aff50e0 100644 --- a/lib/numerics/logtrans/Logtrans.cs +++ b/lib/numerics/logtrans/Logtrans.cs @@ -30,6 +30,9 @@ public sealed class Logtrans : AbstractBase WarmupPeriod = 0; } + /// + /// Creates Logtrans with source for event-based chaining. + /// /// Source indicator for chaining public Logtrans(ITValuePublisher source) : this() { @@ -132,4 +135,4 @@ public sealed class Logtrans : AbstractBase _p_state = default; Last = default; } -} \ No newline at end of file +} diff --git a/lib/numerics/lowest/Lowest.cs b/lib/numerics/lowest/Lowest.cs index 6f08914b..11bf164d 100644 --- a/lib/numerics/lowest/Lowest.cs +++ b/lib/numerics/lowest/Lowest.cs @@ -26,6 +26,9 @@ public sealed class Lowest : AbstractBase public override bool IsHot => _buffer.Count >= _period; + /// + /// Initializes a new Lowest indicator with specified lookback period. + /// /// Lookback window size (must be >= 1) public Lowest(int period) { @@ -38,6 +41,9 @@ public sealed class Lowest : AbstractBase WarmupPeriod = period; } + /// + /// Initializes a new Lowest indicator with source for event-based chaining. + /// /// Source indicator for chaining /// Lookback window size public Lowest(ITValuePublisher source, int period) : this(period) @@ -192,4 +198,4 @@ public sealed class Lowest : AbstractBase _p_state = default; Last = default; } -} \ No newline at end of file +} diff --git a/lib/numerics/midpoint/Midpoint.cs b/lib/numerics/midpoint/Midpoint.cs index b02680bf..16f3b047 100644 --- a/lib/numerics/midpoint/Midpoint.cs +++ b/lib/numerics/midpoint/Midpoint.cs @@ -26,6 +26,9 @@ public sealed class Midpoint : AbstractBase public override bool IsHot => _highest.IsHot && _lowest.IsHot; + /// + /// Initializes a new Midpoint indicator with specified lookback period. + /// /// Lookback window size (must be >= 1) public Midpoint(int period) { @@ -38,6 +41,9 @@ public sealed class Midpoint : AbstractBase WarmupPeriod = period; } + /// + /// Initializes a new Midpoint indicator with source for event-based chaining. + /// /// Source indicator for chaining /// Lookback window size public Midpoint(ITValuePublisher source, int period) : this(period) @@ -157,4 +163,4 @@ public sealed class Midpoint : AbstractBase _lowest.Reset(); Last = default; } -} \ No newline at end of file +} diff --git a/lib/numerics/normalize/Normalize.cs b/lib/numerics/normalize/Normalize.cs index 65a5d4aa..81b505b0 100644 --- a/lib/numerics/normalize/Normalize.cs +++ b/lib/numerics/normalize/Normalize.cs @@ -30,6 +30,9 @@ public sealed class Normalize : AbstractBase public override bool IsHot => _buffer.Count >= _period; + /// + /// Initializes a new Normalize indicator with specified lookback period. + /// /// Lookback period for min/max calculation (default 14) public Normalize(int period = 14) { @@ -44,6 +47,9 @@ public sealed class Normalize : AbstractBase _p_state = _state; } + /// + /// Initializes a new Normalize indicator with source for event-based chaining. + /// /// Source indicator for chaining /// Lookback period (default 14) public Normalize(ITValuePublisher source, int period = 14) : this(period) diff --git a/lib/numerics/relu/Relu.cs b/lib/numerics/relu/Relu.cs index 2f585fd1..3d3f3755 100644 --- a/lib/numerics/relu/Relu.cs +++ b/lib/numerics/relu/Relu.cs @@ -34,6 +34,9 @@ public sealed class Relu : AbstractBase WarmupPeriod = 0; } + /// + /// + /// /// Source indicator for chaining public Relu(ITValuePublisher source) : this() { diff --git a/lib/numerics/sigmoid/Sigmoid.cs b/lib/numerics/sigmoid/Sigmoid.cs index dbfde68a..f9b70307 100644 --- a/lib/numerics/sigmoid/Sigmoid.cs +++ b/lib/numerics/sigmoid/Sigmoid.cs @@ -30,6 +30,9 @@ public sealed class Sigmoid : AbstractBase public override bool IsHot => true; // No warmup needed + /// + /// Initializes a new Sigmoid indicator with specified steepness and midpoint. + /// /// Steepness factor (default 1.0). Higher values create steeper transitions. /// Midpoint value where output equals 0.5 (default 0.0). public Sigmoid(double k = 1.0, double x0 = 0.0) @@ -43,6 +46,9 @@ public sealed class Sigmoid : AbstractBase WarmupPeriod = 0; } + /// + /// Initializes a new Sigmoid indicator with source for event-based chaining. + /// /// Source indicator for chaining /// Steepness factor (default 1.0) /// Midpoint value (default 0.0) diff --git a/lib/numerics/sqrttrans/Sqrttrans.cs b/lib/numerics/sqrttrans/Sqrttrans.cs index e5d71460..4939f2eb 100644 --- a/lib/numerics/sqrttrans/Sqrttrans.cs +++ b/lib/numerics/sqrttrans/Sqrttrans.cs @@ -30,6 +30,9 @@ public sealed class Sqrttrans : AbstractBase WarmupPeriod = 0; } + /// + /// Creates a Square Root transformer with source for event-based chaining. + /// /// Source indicator for chaining public Sqrttrans(ITValuePublisher source) : this() { @@ -131,4 +134,4 @@ public sealed class Sqrttrans : AbstractBase _p_state = default; Last = default; } -} \ No newline at end of file +} diff --git a/lib/trends_FIR/hamma/Hamma.cs b/lib/trends_FIR/hamma/Hamma.cs index 675e81a8..d627c045 100644 --- a/lib/trends_FIR/hamma/Hamma.cs +++ b/lib/trends_FIR/hamma/Hamma.cs @@ -75,6 +75,9 @@ public sealed class Hamma : AbstractBase _state.LastValidValue = double.NaN; } + /// + /// Creates HAMMA with source for event-based chaining. + /// /// Data source for event-based updates /// Lookback period for the Hamming window (default: 10) [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -391,4 +394,4 @@ public sealed class Hamma : AbstractBase _p_state = _state; Last = default; } -} \ No newline at end of file +} diff --git a/lib/trends_FIR/hanma/Hanma.cs b/lib/trends_FIR/hanma/Hanma.cs index f144391b..868310bf 100644 --- a/lib/trends_FIR/hanma/Hanma.cs +++ b/lib/trends_FIR/hanma/Hanma.cs @@ -70,6 +70,9 @@ public sealed class Hanma : AbstractBase _state = new State(double.NaN, IsInitialized: false); } + /// + /// + /// /// Data source for event-based updates /// Lookback period for the Hanning window (default: 10) [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/lib/trends_FIR/hwma/Hwma.cs b/lib/trends_FIR/hwma/Hwma.cs index 2ff79ec8..83f1cee6 100644 --- a/lib/trends_FIR/hwma/Hwma.cs +++ b/lib/trends_FIR/hwma/Hwma.cs @@ -109,6 +109,9 @@ public sealed class Hwma : AbstractBase _state = new State(double.NaN, 0, 0, double.NaN, IsInitialized: false); } + /// + /// Creates HWMA with source for event-based chaining. + /// /// Data source for event-based updates /// Period for smoothing factor calculation (default: 10) [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -339,4 +342,4 @@ public sealed class Hwma : AbstractBase _p_state = _state; Last = default; } -} \ No newline at end of file +} diff --git a/lib/trends_FIR/sgma/Sgma.cs b/lib/trends_FIR/sgma/Sgma.cs index ac0aaecc..812b1cf9 100644 --- a/lib/trends_FIR/sgma/Sgma.cs +++ b/lib/trends_FIR/sgma/Sgma.cs @@ -101,7 +101,7 @@ public sealed class Sgma : AbstractBase weights[3] = 0.3429; weights[4] = -0.0857; double sum5 = weights[0] + weights[1] + weights[2] + weights[3] + weights[4]; - invWeightSum = sum5 != 0.0 ? 1.0 / sum5 : 0.0; + invWeightSum = Math.Abs(sum5) > double.Epsilon ? 1.0 / sum5 : 0.0; return; } @@ -116,7 +116,7 @@ public sealed class Sgma : AbstractBase weights[6] = -0.0476; double sum7 = 0.0; for (int i = 0; i < 7; i++) sum7 += weights[i]; - invWeightSum = sum7 != 0.0 ? 1.0 / sum7 : 0.0; + invWeightSum = Math.Abs(sum7) > double.Epsilon ? 1.0 / sum7 : 0.0; return; } @@ -133,7 +133,7 @@ public sealed class Sgma : AbstractBase weights[8] = -0.0281; double sum9 = 0.0; for (int i = 0; i < 9; i++) sum9 += weights[i]; - invWeightSum = sum9 != 0.0 ? 1.0 / sum9 : 0.0; + invWeightSum = Math.Abs(sum9) > double.Epsilon ? 1.0 / sum9 : 0.0; return; } } @@ -376,7 +376,7 @@ public sealed class Sgma : AbstractBase continue; } - if (invWeightSum == 0.0) + if (Math.Abs(invWeightSum) < double.Epsilon) { output[i] = val; continue; @@ -399,7 +399,7 @@ public sealed class Sgma : AbstractBase [MethodImpl(MethodImplOptions.AggressiveInlining)] private static double CalculateWeightedSumFull(RingBuffer buffer, double[] weights, double invWeightSum, double fallbackValue) { - if (invWeightSum == 0.0) + if (Math.Abs(invWeightSum) < double.Epsilon) return fallbackValue; ReadOnlySpan internalBuf = buffer.InternalBuffer; @@ -435,7 +435,7 @@ public sealed class Sgma : AbstractBase Math.FusedMultiplyAdd(window[3], w3, window[4] * w4)))); double weightSum = w0 + w1 + w2 + w3 + w4; - return weightSum != 0.0 ? sum / weightSum : fallbackValue; + return Math.Abs(weightSum) > double.Epsilon ? sum / weightSum : fallbackValue; } if (p == 7) @@ -458,7 +458,7 @@ public sealed class Sgma : AbstractBase sum = Math.FusedMultiplyAdd(window[6], w6, sum); double weightSum = w0 + w1 + w2 + w3 + w4 + w5 + w6; - return weightSum != 0.0 ? sum / weightSum : fallbackValue; + return Math.Abs(weightSum) > double.Epsilon ? sum / weightSum : fallbackValue; } if (p == 9) @@ -485,7 +485,7 @@ public sealed class Sgma : AbstractBase sum = Math.FusedMultiplyAdd(window[8], w8, sum); double weightSum = w0 + w1 + w2 + w3 + w4 + w5 + w6 + w7 + w8; - return weightSum != 0.0 ? sum / weightSum : fallbackValue; + return Math.Abs(weightSum) > double.Epsilon ? sum / weightSum : fallbackValue; } } @@ -522,4 +522,4 @@ public sealed class Sgma : AbstractBase _p_lastValidValue = double.NaN; Last = default; } -} \ No newline at end of file +} diff --git a/lib/trends_FIR/sma/Sma.cs b/lib/trends_FIR/sma/Sma.cs index 6bd55199..9b6659f4 100644 --- a/lib/trends_FIR/sma/Sma.cs +++ b/lib/trends_FIR/sma/Sma.cs @@ -189,7 +189,6 @@ public sealed class Sma : AbstractBase double val = GetValidValue(input.Value); UpdateState(val); - } else { diff --git a/lib/trends_IIR/vama/Vama.cs b/lib/trends_IIR/vama/Vama.cs index 8799cfa1..d5c5a7a0 100644 --- a/lib/trends_IIR/vama/Vama.cs +++ b/lib/trends_IIR/vama/Vama.cs @@ -39,8 +39,8 @@ public sealed class Vama : AbstractBase { public static VamaState New() => new() { - ShortAtr = new RmaState(0, 1.0, false), - LongAtr = new RmaState(0, 1.0, false), + ShortAtr = new RmaState(Ema: 0, E: 1.0, IsCompensated: false), + LongAtr = new RmaState(Ema: 0, E: 1.0, IsCompensated: false), PrevClose = double.NaN, BufferHead = 0, BufferSum = 0, @@ -244,7 +244,7 @@ public sealed class Vama : AbstractBase newHead, bufferSum, validCount, - true); + IsInitialized: true); Last = new TValue(input.Time, result); PubEvent(Last, isNew); @@ -285,7 +285,7 @@ public sealed class Vama : AbstractBase for (int i = 0; i < len; i++) { var bar = source[i]; - var result = Update(bar, true); + var result = Update(bar, isNew: true); tSpan[i] = bar.Time; vSpan[i] = result.Value; } @@ -314,7 +314,7 @@ public sealed class Vama : AbstractBase for (int i = 0; i < len; i++) { - var result = Update(new TValue(sourceTimes[i], sourceValues[i]), true); + var result = Update(new TValue(sourceTimes[i], sourceValues[i]), isNew: true); tSpan[i] = sourceTimes[i]; vSpan[i] = result.Value; } @@ -330,7 +330,7 @@ public sealed class Vama : AbstractBase Reset(); foreach (double val in source) { - Update(new TValue(DateTime.MinValue, val), true); + Update(new TValue(DateTime.MinValue, val), isNew: true); } } diff --git a/lib/trends_IIR/yzvama/Yzvama.cs b/lib/trends_IIR/yzvama/Yzvama.cs index 99aa0267..0a314a07 100644 --- a/lib/trends_IIR/yzvama/Yzvama.cs +++ b/lib/trends_IIR/yzvama/Yzvama.cs @@ -37,8 +37,8 @@ public sealed class Yzvama : AbstractBase { public static YzvamaState New() => new() { - ShortVar = new RmaState(0, 1.0, false), - LongVar = new RmaState(0, 1.0, false), + ShortVar = new RmaState(Ema: 0, E: 1.0, IsCompensated: false), + LongVar = new RmaState(Ema: 0, E: 1.0, IsCompensated: false), PrevClose = double.NaN, SourceHead = 0, SourceSum = 0, @@ -390,7 +390,7 @@ public sealed class Yzvama : AbstractBase validCount, yzvHead, yzvCount, - true); + IsInitialized: true); Last = new TValue(input.Time, result); PubEvent(Last, isNew); @@ -428,7 +428,7 @@ public sealed class Yzvama : AbstractBase for (int i = 0; i < len; i++) { var bar = source[i]; - var result = Update(bar, true); + var result = Update(bar, isNew: true); tSpan[i] = bar.Time; vSpan[i] = result.Value; } @@ -457,7 +457,7 @@ public sealed class Yzvama : AbstractBase for (int i = 0; i < len; i++) { - var result = Update(new TValue(sourceTimes[i], sourceValues[i]), true); + var result = Update(new TValue(sourceTimes[i], sourceValues[i]), isNew: true); tSpan[i] = sourceTimes[i]; vSpan[i] = result.Value; } @@ -473,7 +473,7 @@ public sealed class Yzvama : AbstractBase { Reset(); foreach (double val in source) - Update(new TValue(DateTime.MinValue, val), true); + Update(new TValue(DateTime.MinValue, val), isNew: true); } /// @@ -484,7 +484,7 @@ public sealed class Yzvama : AbstractBase { Reset(); foreach (TValue tv in source) - Update(tv, true); + Update(tv, isNew: true); } /// diff --git a/lib/trends_IIR/zlema/Zlema.Validation.Tests.cs b/lib/trends_IIR/zlema/Zlema.Validation.Tests.cs index 805ee2ef..c5fd6b57 100644 --- a/lib/trends_IIR/zlema/Zlema.Validation.Tests.cs +++ b/lib/trends_IIR/zlema/Zlema.Validation.Tests.cs @@ -7,7 +7,7 @@ public class ZlemaValidationTests [Fact] public void Zlema_Streaming_MatchesReference() { - int period = 20; + const int period = 20; TSeries series = BuildSeries(300, seed: 5); double[] reference = new double[series.Count]; @@ -24,7 +24,7 @@ public class ZlemaValidationTests [Fact] public void Zlema_Batch_MatchesReference() { - int period = 14; + const int period = 14; TSeries series = BuildSeries(250, seed: 9); double[] reference = new double[series.Count]; @@ -40,7 +40,7 @@ public class ZlemaValidationTests [Fact] public void Zlema_Span_MatchesReference() { - int period = 30; + const int period = 30; TSeries series = BuildSeries(200, seed: 12); double[] values = series.Values.ToArray(); var output = new double[values.Length]; diff --git a/lib/volatility/atrn/Atrn.Tests.cs b/lib/volatility/atrn/Atrn.Tests.cs index b1f8eb05..bcdb1906 100644 --- a/lib/volatility/atrn/Atrn.Tests.cs +++ b/lib/volatility/atrn/Atrn.Tests.cs @@ -54,7 +54,7 @@ public class AtrnTests public void Update_ReturnsValidTValue() { var atrn = new Atrn(DefaultPeriod); - var result = atrn.Update(_bars[0], true); + var result = atrn.Update(_bars[0], isNew: true); Assert.IsType(result); Assert.Equal(_bars[0].Time, result.Time); @@ -67,7 +67,7 @@ public class AtrnTests for (int i = 0; i < _bars.Count; i++) { - var result = atrn.Update(_bars[i], true); + var result = atrn.Update(_bars[i], isNew: true); Assert.True(result.Value >= 0 && result.Value <= 1, $"Value {result.Value} at index {i} is outside [0,1] range"); } @@ -447,4 +447,4 @@ public class AtrnTests } #endregion -} \ No newline at end of file +} diff --git a/lib/volatility/atrn/Atrn.cs b/lib/volatility/atrn/Atrn.cs index 24620f70..ee9509a7 100644 --- a/lib/volatility/atrn/Atrn.cs +++ b/lib/volatility/atrn/Atrn.cs @@ -51,7 +51,7 @@ public sealed class Atrn : AbstractBase Name = $"Atrn({period})"; WarmupPeriod = _rma.WarmupPeriod + _lookbackWindow; - _state = new State(default, false, 0.0, 0.0); + _state = new State(PrevBar: default, IsInitialized: false, LastValidTr: 0.0, LastValidAtr: 0.0); _p_state = _state; } @@ -95,7 +95,7 @@ public sealed class Atrn : AbstractBase for (int i = 0; i < source.Length; i++) { double tr = source[i]; - TValue atr = _rma.Update(new TValue(DateTime.UtcNow.AddMinutes(i), tr), true); + TValue atr = _rma.Update(new TValue(DateTime.UtcNow.AddMinutes(i), tr), isNew: true); _atrBuffer.Add(atr.Value); } @@ -117,7 +117,7 @@ public sealed class Atrn : AbstractBase { _rma.Reset(); _atrBuffer.Clear(); - _state = new State(default, false, 0.0, 0.0); + _state = new State(PrevBar: default, IsInitialized: false, LastValidTr: 0.0, LastValidAtr: 0.0); _p_state = _state; Last = default; } @@ -180,7 +180,7 @@ public sealed class Atrn : AbstractBase // Update state _state = isNew - ? new State(input, true, tr, currentAtr) + ? new State(PrevBar: input, IsInitialized: true, LastValidTr: tr, LastValidAtr: currentAtr) : _state with { LastValidTr = tr, LastValidAtr = currentAtr }; TValue result = new(input.Time, normalized); @@ -246,7 +246,7 @@ public sealed class Atrn : AbstractBase for (int i = 0; i < source.Count; i++) { - TValue result = Update(source[i], true); + TValue result = Update(source[i], isNew: true); t.Add(result.Time); v.Add(result.Value); } @@ -266,7 +266,7 @@ public sealed class Atrn : AbstractBase for (int i = 0; i < source.Count; i++) { - TValue result = Update(source[i], true); + TValue result = Update(source[i], isNew: true); t.Add(source[i].Time); v.Add(result.Value); }