mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-27 17:27:43 +00:00
test: setup common stability and robustness properties tracking
This commit is contained in:
@@ -2,20 +2,7 @@
|
||||
name: beast
|
||||
description: Meticulous auto-agent for high-performance .NET library development with full MCP tool integration
|
||||
tools:
|
||||
- execute
|
||||
- read
|
||||
- edit
|
||||
- search
|
||||
- web
|
||||
- codacy-mcp-server/*
|
||||
- gitkraken/*
|
||||
- github/*
|
||||
- qdrant-mcp/*
|
||||
- sequential-thinking-mcp/*
|
||||
- tavily-mcp/*
|
||||
- wolfram-mcp/*
|
||||
- agent
|
||||
- todo
|
||||
[execute/runNotebookCell, execute/testFailure, execute/getTerminalOutput, execute/awaitTerminal, execute/killTerminal, execute/runTask, execute/createAndRunTask, execute/runInTerminal, execute/runTests, read/getNotebookSummary, read/problems, read/readFile, read/readNotebookCellOutput, read/terminalSelection, read/terminalLastCommand, read/getTaskOutput, agent/runSubagent, edit/createDirectory, edit/createFile, edit/createJupyterNotebook, edit/editFiles, edit/editNotebook, search/changes, search/codebase, search/fileSearch, search/listDirectory, search/searchResults, search/textSearch, search/usages, web/fetch, github/add_comment_to_pending_review, github/add_issue_comment, github/assign_copilot_to_issue, github/create_branch, github/create_or_update_file, github/create_pull_request, github/create_repository, github/delete_file, github/fork_repository, github/get_commit, github/get_file_contents, github/get_label, github/get_latest_release, github/get_me, github/get_release_by_tag, github/get_tag, github/get_team_members, github/get_teams, github/issue_read, github/issue_write, github/list_branches, github/list_commits, github/list_issue_types, github/list_issues, github/list_pull_requests, github/list_releases, github/list_tags, github/merge_pull_request, github/pull_request_read, github/pull_request_review_write, github/push_files, github/request_copilot_review, github/search_code, github/search_issues, github/search_pull_requests, github/search_repositories, github/search_users, github/sub_issue_write, github/update_pull_request, github/update_pull_request_branch, codacy-mcp-server/codacy_cli_analyze, codacy-mcp-server/codacy_cli_install, codacy-mcp-server/codacy_get_file_clones, codacy-mcp-server/codacy_get_file_coverage, codacy-mcp-server/codacy_get_file_issues, codacy-mcp-server/codacy_get_file_with_analysis, codacy-mcp-server/codacy_get_issue, codacy-mcp-server/codacy_get_pattern, codacy-mcp-server/codacy_get_pull_request_files_coverage, codacy-mcp-server/codacy_get_pull_request_git_diff, codacy-mcp-server/codacy_get_repository_pull_request, codacy-mcp-server/codacy_get_repository_with_analysis, codacy-mcp-server/codacy_list_files, codacy-mcp-server/codacy_list_organization_repositories, codacy-mcp-server/codacy_list_organizations, codacy-mcp-server/codacy_list_pull_request_issues, codacy-mcp-server/codacy_list_repository_issues, codacy-mcp-server/codacy_list_repository_pull_requests, codacy-mcp-server/codacy_list_repository_tool_patterns, codacy-mcp-server/codacy_list_repository_tools, codacy-mcp-server/codacy_list_tools, codacy-mcp-server/codacy_search_organization_srm_items, codacy-mcp-server/codacy_search_repository_srm_items, codacy-mcp-server/codacy_setup_repository, dotnet-semantic-mcp/ast_diff_unified, dotnet-semantic-mcp/attrs, dotnet-semantic-mcp/code_security, dotnet-semantic-mcp/deps, dotnet-semantic-mcp/diag, dotnet-semantic-mcp/diff, dotnet-semantic-mcp/explore, dotnet-semantic-mcp/hierarchy, dotnet-semantic-mcp/map, dotnet-semantic-mcp/metrics, dotnet-semantic-mcp/nuget_vulnerabilities, dotnet-semantic-mcp/prepare_change, dotnet-semantic-mcp/refs, dotnet-semantic-mcp/scan_cancel, dotnet-semantic-mcp/scan_list, dotnet-semantic-mcp/scan_status, dotnet-semantic-mcp/search, dotnet-semantic-mcp/source, dotnet-semantic-mcp/symbol, dotnet-semantic-mcp/understand, gitkraken/git_add_or_commit, gitkraken/git_blame, gitkraken/git_branch, gitkraken/git_checkout, gitkraken/git_log_or_diff, gitkraken/git_push, gitkraken/git_stash, gitkraken/git_status, gitkraken/git_worktree, gitkraken/gitkraken_workspace_list, gitkraken/issues_add_comment, gitkraken/issues_assigned_to_me, gitkraken/issues_get_detail, gitkraken/pull_request_assigned_to_me, gitkraken/pull_request_create, gitkraken/pull_request_create_review, gitkraken/pull_request_get_comments, gitkraken/pull_request_get_detail, gitkraken/repository_get_file_content, qdrant/qdrant-find, qdrant/qdrant-store, ref/ref_read_url, ref/ref_search_documentation, sequential-thinking/sequentialthinking, tavily/tavily_crawl, tavily/tavily_extract, tavily/tavily_map, tavily/tavily_research, tavily/tavily_search, todo]
|
||||
---
|
||||
|
||||
# Role: Meticulous Auto-Agent
|
||||
|
||||
@@ -41,36 +41,28 @@ jobs:
|
||||
**/*.sln
|
||||
|
||||
- name: Install GitVersion
|
||||
uses: gittools/actions/gitversion/setup@v4.2.0
|
||||
uses: gittools/actions/gitversion/setup@d0139503a9321f76b4a417dfdc8aebcec24decdd # v4.2.0
|
||||
with:
|
||||
versionSpec: "6.x"
|
||||
includePrerelease: true
|
||||
|
||||
- name: Determine Version
|
||||
id: gitversion
|
||||
uses: gittools/actions/gitversion/execute@v4.2.0
|
||||
uses: gittools/actions/gitversion/execute@d0139503a9321f76b4a417dfdc8aebcec24decdd # v4.2.0
|
||||
with:
|
||||
updateAssemblyInfo: false
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
dotnet build ./lib/quantalib.csproj --configuration Release --no-restore --nologo
|
||||
dotnet build ./quantower/Channels.csproj --configuration Release --nologo
|
||||
dotnet build ./quantower/Cycles.csproj --configuration Release --nologo
|
||||
dotnet build ./quantower/Dynamics.csproj --configuration Release --nologo
|
||||
dotnet build ./quantower/Filters.csproj --configuration Release --nologo
|
||||
dotnet build ./quantower/Forecasts.csproj --configuration Release --nologo
|
||||
dotnet build ./quantower/Momentum.csproj --configuration Release --nologo
|
||||
dotnet build ./quantower/Oscillators.csproj --configuration Release --nologo
|
||||
dotnet build ./quantower/Reversals.csproj --configuration Release --nologo
|
||||
dotnet build ./quantower/Statistics.csproj --configuration Release --nologo
|
||||
dotnet build ./quantower/Trends_FIR.csproj --configuration Release --nologo
|
||||
dotnet build ./quantower/Trends_IIR.csproj --configuration Release --nologo
|
||||
dotnet build ./quantower/Volatility.csproj --configuration Release --nologo
|
||||
dotnet build ./quantower/Volume.csproj --configuration Release --nologo
|
||||
- name: Build (warnings as errors)
|
||||
run: dotnet build ./QuanTAlib.slnx --configuration Release --no-restore --nologo /warnaserror
|
||||
|
||||
- name: Test (core)
|
||||
run: dotnet test ./lib/QuanTAlib.Tests.csproj --configuration Release --no-build --nologo
|
||||
|
||||
- name: Test (quantower)
|
||||
run: dotnet test ./quantower/Quantower.Tests.csproj --configuration Release --no-build --nologo
|
||||
|
||||
- name: Pack NuGet
|
||||
run: |
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
||||
<PackageReference Include="FsCheck.Xunit" Version="3.3.2" />
|
||||
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
|
||||
<PackageReference Include="OoplesFinance.StockIndicators" Version="1.1.1" />
|
||||
|
||||
@@ -387,7 +387,7 @@ public sealed class AccBandsValidationTests : IDisposable
|
||||
out var outRange,
|
||||
period);
|
||||
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = Functions.AccbandsLookback(period);
|
||||
|
||||
@@ -432,7 +432,7 @@ public sealed class AccBandsValidationTests : IDisposable
|
||||
out var outRange,
|
||||
period);
|
||||
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = Functions.AccbandsLookback(period);
|
||||
|
||||
@@ -466,7 +466,7 @@ public sealed class AccBandsValidationTests : IDisposable
|
||||
out var outRange,
|
||||
period);
|
||||
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
var (qMiddle, qUpper, qLower) = AccBands.Batch(_testData.Bars, period, 4.0);
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ public sealed class AtrBandsValidationTests : IDisposable
|
||||
out var outRange,
|
||||
period);
|
||||
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = Functions.SmaLookback(period);
|
||||
|
||||
@@ -215,7 +215,7 @@ public sealed class AtrBandsValidationTests : IDisposable
|
||||
out var outRange,
|
||||
period);
|
||||
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = Functions.AtrLookback(period);
|
||||
var (offset, _) = outRange.GetOffsetAndLength(atrOutput.Length);
|
||||
|
||||
@@ -140,9 +140,9 @@ public sealed class BbandsValidationTests : IDisposable
|
||||
period,
|
||||
multiplier,
|
||||
multiplier,
|
||||
Core.MAType.Sma);
|
||||
TALib.Core.MAType.Sma);
|
||||
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = Functions.BbandsLookback(period);
|
||||
|
||||
@@ -185,9 +185,9 @@ public sealed class BbandsValidationTests : IDisposable
|
||||
period,
|
||||
multiplier,
|
||||
multiplier,
|
||||
Core.MAType.Sma);
|
||||
TALib.Core.MAType.Sma);
|
||||
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = Functions.BbandsLookback(period);
|
||||
|
||||
@@ -228,9 +228,9 @@ public sealed class BbandsValidationTests : IDisposable
|
||||
period,
|
||||
multiplier,
|
||||
multiplier,
|
||||
Core.MAType.Sma);
|
||||
TALib.Core.MAType.Sma);
|
||||
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = Functions.BbandsLookback(period);
|
||||
|
||||
|
||||
@@ -347,4 +347,4 @@ public sealed class DchannelValidationTests : IDisposable
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,4 +392,4 @@ public sealed class FcbValidationTests : IDisposable
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -556,4 +556,4 @@ public sealed class KchannelValidationTests : IDisposable
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ public class MaenvIndicatorTests
|
||||
|
||||
Assert.Equal(20, ind.Period);
|
||||
Assert.Equal(1.0, ind.Percentage);
|
||||
Assert.Equal(MaenvType.EMA, ind.MaType);
|
||||
Assert.Equal(MaenvType.EMA, ind.maType);
|
||||
Assert.Equal(PriceType.Close, ind.SourceType);
|
||||
Assert.True(ind.ShowColdValues);
|
||||
Assert.Equal("Maenv - Moving Average Envelope", ind.Name);
|
||||
@@ -30,7 +30,7 @@ public class MaenvIndicatorTests
|
||||
[Fact]
|
||||
public void ShortName_ReflectsParameters()
|
||||
{
|
||||
var ind = new MaenvIndicator { Period = 12, Percentage = 2.5, MaType = MaenvType.SMA };
|
||||
var ind = new MaenvIndicator { Period = 12, Percentage = 2.5, maType = MaenvType.SMA };
|
||||
Assert.Contains("12", ind.ShortName, StringComparison.Ordinal);
|
||||
Assert.Contains("2.5", ind.ShortName, StringComparison.Ordinal);
|
||||
Assert.Contains("SMA", ind.ShortName, StringComparison.Ordinal);
|
||||
@@ -209,11 +209,11 @@ public class MaenvIndicatorTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllMaTypes_ProduceFiniteResults()
|
||||
public void AllmaTypes_ProduceFiniteResults()
|
||||
{
|
||||
foreach (MaenvType maType in Enum.GetValues<MaenvType>())
|
||||
{
|
||||
var ind = new MaenvIndicator { Period = 10, Percentage = 2.0, MaType = maType };
|
||||
var ind = new MaenvIndicator { Period = 10, Percentage = 2.0, maType = maType };
|
||||
ind.Initialize();
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
@@ -347,7 +347,7 @@ public class MaenvTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Maenv_AllMaTypes_ProduceFiniteResults()
|
||||
public void Maenv_AllmaTypes_ProduceFiniteResults()
|
||||
{
|
||||
var gbm = new GBM(startPrice: 100, mu: 0.01, sigma: 0.1, seed: 42);
|
||||
|
||||
|
||||
@@ -440,7 +440,7 @@ public sealed class MaenvValidationTests : IDisposable
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_MaTypesDifferent()
|
||||
public void Validate_maTypesDifferent()
|
||||
{
|
||||
// Different MA types should produce different results (except for first bar)
|
||||
var indSma = new Maenv(10, 2.0, MaenvType.SMA);
|
||||
@@ -595,4 +595,4 @@ public sealed class MaenvValidationTests : IDisposable
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -559,7 +559,7 @@ public sealed class RegchannelValidationTests : IDisposable
|
||||
out var outRange,
|
||||
period);
|
||||
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = Functions.LinearRegLookback(period);
|
||||
|
||||
@@ -593,7 +593,7 @@ public sealed class RegchannelValidationTests : IDisposable
|
||||
out var outRange,
|
||||
period);
|
||||
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = Functions.LinearRegSlopeLookback(period);
|
||||
|
||||
|
||||
@@ -650,4 +650,4 @@ public sealed class SdchannelValidationTests : IDisposable
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -680,4 +680,4 @@ public sealed class StarchannelValidationTests : IDisposable
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -671,7 +671,7 @@ public sealed class TtmLrcValidationTests : IDisposable
|
||||
out var outRange,
|
||||
period);
|
||||
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = Functions.LinearRegLookback(period);
|
||||
|
||||
@@ -704,7 +704,7 @@ public sealed class TtmLrcValidationTests : IDisposable
|
||||
out var outRange,
|
||||
period);
|
||||
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = Functions.LinearRegSlopeLookback(period);
|
||||
var (offset, _) = outRange.GetOffsetAndLength(slopeOutput.Length);
|
||||
|
||||
@@ -19,15 +19,21 @@ public delegate void BiInputBatchDelegate(
|
||||
int period);
|
||||
|
||||
/// <summary>
|
||||
/// Abstract base class for bi-input indicators (indicators that require two inputs like error metrics).
|
||||
/// Abstract base class for error-metric indicators that compare two input series (actual vs predicted).
|
||||
/// Provides common infrastructure for RingBuffer-based sliding window calculations with O(1) updates.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This base class eliminates code duplication across error indicators (MAE, MSE, RMSE, MAPE, etc.)
|
||||
/// by providing:
|
||||
/// - Common state management with bar correction (isNew semantics)
|
||||
/// - RingBuffer-based sliding window with running sum
|
||||
/// - Periodic resync for floating-point drift correction
|
||||
/// This base class is designed specifically for error metrics (MAE, MSE, RMSE, MAPE, SMAPE, etc.)
|
||||
/// where each bar contributes a single scalar error value to a running mean.
|
||||
///
|
||||
/// It is NOT intended for statistical bi-input indicators (Correlation, Cointegration) which
|
||||
/// maintain multiple running sums (Σx, Σy, Σx², Σy², Σxy) and have different state-restoration
|
||||
/// semantics — those indicators manage their own state directly.
|
||||
///
|
||||
/// Infrastructure provided:
|
||||
/// - _p_state / _buffer.Snapshot() / _buffer.Restore() for bar correction (isNew semantics)
|
||||
/// - RingBuffer-based sliding window with a single running sum
|
||||
/// - Periodic resync every 1000 updates for floating-point drift correction
|
||||
/// - NaN/Infinity handling with last-valid-value substitution
|
||||
/// - Template Method pattern: subclasses only implement ComputeError and optionally PostProcess
|
||||
/// </remarks>
|
||||
|
||||
@@ -49,7 +49,7 @@ public sealed class AvgpriceValidationTests : IDisposable
|
||||
var taOut = new double[open.Length];
|
||||
var retCode = Functions.AvgPrice(open.AsSpan(), high.AsSpan(), low.AsSpan(), close.AsSpan(),
|
||||
0..^0, taOut, out var outRange);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
var (offset, length) = outRange.GetOffsetAndLength(taOut.Length);
|
||||
|
||||
// QuanTAlib batch span
|
||||
|
||||
@@ -46,7 +46,7 @@ public sealed class MedpriceValidationTests : IDisposable
|
||||
// TA-Lib MedPrice
|
||||
var taOut = new double[high.Length];
|
||||
var retCode = Functions.MedPrice(high.AsSpan(), low.AsSpan(), 0..^0, taOut, out var outRange);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
var (offset, length) = outRange.GetOffsetAndLength(taOut.Length);
|
||||
|
||||
// QuanTAlib batch via TBarSeries
|
||||
|
||||
@@ -51,7 +51,7 @@ public sealed class MidpointValidationTests : IDisposable
|
||||
|
||||
// Calculate TA-Lib MIDPOINT
|
||||
var retCode = TALib.Functions.MidPoint<double>(tData, 0..^0, output, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.MidPointLookback(period);
|
||||
|
||||
@@ -81,7 +81,7 @@ public sealed class MidpointValidationTests : IDisposable
|
||||
|
||||
// Calculate TA-Lib MIDPOINT
|
||||
var retCode = TALib.Functions.MidPoint<double>(tData, 0..^0, output, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.MidPointLookback(period);
|
||||
|
||||
@@ -107,7 +107,7 @@ public sealed class MidpointValidationTests : IDisposable
|
||||
|
||||
// Calculate TA-Lib MIDPOINT
|
||||
var retCode = TALib.Functions.MidPoint<double>(sourceData, 0..^0, talibOutput, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.MidPointLookback(period);
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ public sealed class MidpriceValidationTests : IDisposable
|
||||
// TA-Lib MidPrice
|
||||
var taOut = new double[high.Length];
|
||||
var retCode = Functions.MidPrice(high.AsSpan(), low.AsSpan(), 0..^0, taOut, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
var (offset, length) = outRange.GetOffsetAndLength(taOut.Length);
|
||||
|
||||
// QuanTAlib batch span
|
||||
@@ -76,7 +76,7 @@ public sealed class MidpriceValidationTests : IDisposable
|
||||
|
||||
var taOut = new double[high.Length];
|
||||
var retCode = Functions.MidPrice(high.AsSpan(), low.AsSpan(), 0..^0, taOut, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
var (offset, length) = outRange.GetOffsetAndLength(taOut.Length);
|
||||
|
||||
var qlOut = new double[high.Length];
|
||||
|
||||
@@ -91,25 +91,51 @@ public sealed class RingBuffer : IEnumerable<double>
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recalculates the sum by iterating over all elements.
|
||||
/// Recalculates the sum by iterating over all elements using SIMD acceleration.
|
||||
/// Useful for correcting floating-point drift after many updates.
|
||||
/// Uses GetSequencedSpans to avoid allocation when buffer wraps.
|
||||
/// </summary>
|
||||
public double RecalculateSum()
|
||||
{
|
||||
double sum = 0;
|
||||
GetSequencedSpans(out var first, out var second);
|
||||
_sum = SumSpanSimd(first) + SumSpanSimd(second);
|
||||
return _sum;
|
||||
}
|
||||
|
||||
for (int i = 0; i < first.Length; i++)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private static double SumSpanSimd(ReadOnlySpan<double> span)
|
||||
{
|
||||
if (span.IsEmpty)
|
||||
{
|
||||
sum += first[i];
|
||||
}
|
||||
for (int i = 0; i < second.Length; i++)
|
||||
{
|
||||
sum += second[i];
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
int vectorSize = Vector<double>.Count;
|
||||
var acc = Vector<double>.Zero;
|
||||
int i = 0;
|
||||
|
||||
if (span.Length >= vectorSize)
|
||||
{
|
||||
ref double spanRef = ref MemoryMarshal.GetReference(span);
|
||||
for (; i <= span.Length - vectorSize; i += vectorSize)
|
||||
{
|
||||
acc += Unsafe.As<double, Vector<double>>(ref Unsafe.Add(ref spanRef, i));
|
||||
}
|
||||
}
|
||||
|
||||
// Horizontal sum of SIMD accumulator
|
||||
double sum = 0.0;
|
||||
for (int j = 0; j < vectorSize; j++)
|
||||
{
|
||||
sum += acc[j];
|
||||
}
|
||||
|
||||
// Scalar tail
|
||||
for (; i < span.Length; i++)
|
||||
{
|
||||
sum += span[i];
|
||||
}
|
||||
|
||||
_sum = sum;
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
using QuanTAlib;
|
||||
|
||||
namespace QuanTAlib.Tests.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Tests verifying the structural stability of indicators across the repository.
|
||||
/// </summary>
|
||||
public class IndicatorPropertiesTests
|
||||
{
|
||||
[Fact]
|
||||
public void Sma_ShouldNotProduceNaN_WithValidInputs()
|
||||
{
|
||||
var sma = new Sma(period: 10);
|
||||
var random = new Random(42);
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
double price = (random.Next(1, 1000000) / 10.0);
|
||||
sma.Update(new TValue(DateTime.Today.AddDays(i), price));
|
||||
|
||||
// Only check for NaN after warmup
|
||||
if (i >= sma.WarmupPeriod && double.IsNaN(sma.Last.Value))
|
||||
{
|
||||
Assert.Fail($"Produced NaN at index {i}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Ema_ShouldNotProduceNaN_WithValidInputs()
|
||||
{
|
||||
var ema = new Ema(period: 10);
|
||||
var random = new Random(42);
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
double price = (random.Next(1, 1000000) / 10.0);
|
||||
ema.Update(new TValue(DateTime.Today.AddDays(i), price));
|
||||
|
||||
// Only check for NaN after warmup
|
||||
if (i >= ema.WarmupPeriod && double.IsNaN(ema.Last.Value))
|
||||
{
|
||||
Assert.Fail($"Produced NaN at index {i}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Indicator_ShouldRecoverFromNaN_WhenReset()
|
||||
{
|
||||
var ema = new Ema(period: 10);
|
||||
|
||||
// Feed valid value
|
||||
ema.Update(new TValue(DateTime.Today.AddDays(1), 100));
|
||||
|
||||
// Feed NaN, which should corrupt state
|
||||
ema.Update(new TValue(DateTime.Today.AddDays(2), double.NaN));
|
||||
|
||||
// Let's actually ensure it is corrupted depending on implementation
|
||||
// Some robust implementations might discard NaN internally, so we don't assert it strictly
|
||||
// We just ensure it recovers properly.
|
||||
|
||||
// Reset should clear the corrupted state
|
||||
ema.Reset();
|
||||
|
||||
// Feed valid value again
|
||||
ema.Update(new TValue(DateTime.Today.AddDays(3), 100));
|
||||
|
||||
// Wait for Warmup
|
||||
for (int i = 4; i < 3 + ema.WarmupPeriod; i++) {
|
||||
ema.Update(new TValue(DateTime.Today.AddDays(i), 100));
|
||||
}
|
||||
|
||||
// Verify recovery after warmup
|
||||
Assert.False(double.IsNaN(ema.Last.Value));
|
||||
Assert.Equal(100, Math.Round(ema.Last.Value, 5));
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ public sealed class TyppriceValidationTests : IDisposable
|
||||
var taOut = new double[high.Length];
|
||||
var retCode = Functions.TypPrice(high.AsSpan(), low.AsSpan(), close.AsSpan(),
|
||||
0..^0, taOut, out var outRange);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
var (offset, length) = outRange.GetOffsetAndLength(taOut.Length);
|
||||
|
||||
// QuanTAlib batch span
|
||||
|
||||
@@ -48,7 +48,7 @@ public sealed class WclpriceValidationTests : IDisposable
|
||||
var taOut = new double[high.Length];
|
||||
var retCode = Functions.WclPrice(high.AsSpan(), low.AsSpan(), close.AsSpan(),
|
||||
0..^0, taOut, out var outRange);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
var (offset, length) = outRange.GetOffsetAndLength(taOut.Length);
|
||||
|
||||
// QuanTAlib batch span
|
||||
|
||||
@@ -380,4 +380,4 @@ public class CcycValidationTests
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,4 +338,4 @@ public class CgIndicatorTests
|
||||
double cgValue = indicator.LinesSeries[0].GetValue(0);
|
||||
Assert.True(cgValue < 0, $"Downtrend should produce negative CG, got {cgValue}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -755,4 +755,4 @@ public class CgTests
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,4 +378,4 @@ public class CgValidationTests
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,4 +339,4 @@ public class DspIndicatorTests
|
||||
Assert.True(positiveCount > 0, "Should have positive DSP values");
|
||||
Assert.True(negativeCount > 0, "Should have negative DSP values");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,4 +451,4 @@ public class DspTests
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,4 +401,4 @@ public class DspValidationTests
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,4 +359,4 @@ public class EacpIndicatorTests
|
||||
Assert.True(double.IsFinite(indicatorEnhanced.LinesSeries[0].GetValue(0)));
|
||||
Assert.True(double.IsFinite(indicatorNormal.LinesSeries[0].GetValue(0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -521,4 +521,4 @@ public class EacpTests
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,4 +419,4 @@ public class EacpValidationTests
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,4 +383,4 @@ public class EbswIndicatorTests
|
||||
// Should have multiple zero crossings for oscillating price
|
||||
Assert.True(crossings >= 3, $"Should have multiple zero crossings, got {crossings}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,4 +505,4 @@ public class EbswTests
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -559,4 +559,4 @@ public class EbswValidationTests
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,4 +338,4 @@ public class HomodIndicatorTests
|
||||
double cycleValue = indicator.LinesSeries[0].GetValue(0);
|
||||
Assert.True(double.IsFinite(cycleValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,4 +482,4 @@ public class HomodTests
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,4 +378,4 @@ public class HomodValidationTests
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public sealed class HtDcperiodValidationTests : IDisposable
|
||||
var outPeriod = new double[input.Length];
|
||||
var rc = TALib.Functions.HtDcPeriod(input, 0..^0, outPeriod, out var outRange);
|
||||
|
||||
Assert.Equal(Core.RetCode.Success, rc);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, rc);
|
||||
|
||||
var q = new HtDcperiod();
|
||||
var qSeries = q.Update(_data.Data);
|
||||
@@ -65,7 +65,7 @@ public sealed class HtDcperiodValidationTests : IDisposable
|
||||
var outPeriod = new double[input.Length];
|
||||
var rc = TALib.Functions.HtDcPeriod(input, 0..^0, outPeriod, out var outRange);
|
||||
|
||||
Assert.Equal(Core.RetCode.Success, rc);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, rc);
|
||||
|
||||
var streaming = new List<double>(_data.Data.Count);
|
||||
var q = new HtDcperiod();
|
||||
|
||||
@@ -42,7 +42,7 @@ public sealed class HtDcphaseValidationTests : IDisposable
|
||||
var outPhase = new double[input.Length];
|
||||
var rc = TALib.Functions.HtDcPhase(input, 0..^0, outPhase, out var outRange);
|
||||
|
||||
Assert.Equal(Core.RetCode.Success, rc);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, rc);
|
||||
|
||||
var q = new HtDcphase();
|
||||
var qSeries = q.Update(_data.Data);
|
||||
@@ -65,7 +65,7 @@ public sealed class HtDcphaseValidationTests : IDisposable
|
||||
var outPhase = new double[input.Length];
|
||||
var rc = TALib.Functions.HtDcPhase(input, 0..^0, outPhase, out var outRange);
|
||||
|
||||
Assert.Equal(Core.RetCode.Success, rc);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, rc);
|
||||
|
||||
var streaming = new List<double>(_data.Data.Count);
|
||||
var q = new HtDcphase();
|
||||
|
||||
@@ -292,4 +292,4 @@ public class HtSineIndicatorTests
|
||||
Assert.Contains("github.com/mihakralj/QuanTAlib", indicator.SourceCodeLink, StringComparison.Ordinal);
|
||||
Assert.Contains("HtSine.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -487,4 +487,4 @@ public class HtSineTests
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public sealed class HtSineValidationTests : IDisposable
|
||||
var outLeadSine = new double[input.Length];
|
||||
var retCode = TALib.Functions.HtSine(input, 0..^0, outSine, outLeadSine, out var outRange);
|
||||
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
// Calculate QuanTAlib HtSine
|
||||
var htSine = new HtSine();
|
||||
@@ -83,7 +83,7 @@ public sealed class HtSineValidationTests : IDisposable
|
||||
var outLeadSine = new double[input.Length];
|
||||
var retCode = TALib.Functions.HtSine(input, 0..^0, outSine, outLeadSine, out var outRange);
|
||||
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
// Calculate QuanTAlib HtSine Streaming
|
||||
var htSine = new HtSine();
|
||||
|
||||
@@ -266,4 +266,4 @@ public class LunarIndicatorTests
|
||||
Assert.Contains("Lunar.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
|
||||
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,4 +306,4 @@ public class LunarTests
|
||||
|
||||
Assert.Equal(phase1, phase2, Tolerance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,4 +259,4 @@ public class SolarIndicatorTests
|
||||
Assert.Contains("Solar.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
|
||||
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,4 +295,4 @@ public class SolarTests
|
||||
|
||||
Assert.True(cycle > 0.95, $"Expected cycle > 0.95 at 2000 summer solstice, got {cycle}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,4 +269,4 @@ public class SsfdspIndicatorTests
|
||||
Assert.Contains("github.com/mihakralj/QuanTAlib", indicator.SourceCodeLink, StringComparison.Ordinal);
|
||||
Assert.Contains("Ssfdsp.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,4 +500,4 @@ public class SsfdspTests
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,4 +352,4 @@ public class SsfdspValidationTests
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public sealed class AdxValidationTests : IDisposable
|
||||
double[] outReal = new double[_data.Bars.Count];
|
||||
|
||||
var retCode = Functions.Adx(hData, lData, cData, 0..^0, outReal, out var outRange, 14);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = Functions.AdxLookback(14);
|
||||
ValidationHelper.VerifyData(results, outReal, outRange, lookback);
|
||||
|
||||
@@ -35,7 +35,7 @@ public sealed class AdxrValidationTests : IDisposable
|
||||
double[] outReal = new double[_data.Bars.Count];
|
||||
|
||||
var retCode = Functions.Adxr(hData, lData, cData, 0..^0, outReal, out var outRange, 14);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = Functions.AdxrLookback(14);
|
||||
ValidationHelper.VerifyData(results, outReal, outRange, lookback);
|
||||
|
||||
@@ -164,4 +164,4 @@ public sealed class AlligatorValidationTests : IDisposable
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ public sealed class AmatValidationTests : IDisposable
|
||||
|
||||
// Calculate TA-Lib EMA (fast period)
|
||||
var retCode = TALib.Functions.Ema<double>(tData, 0..^0, outEma, out var outRange, fastPeriod);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.EmaLookback(fastPeriod);
|
||||
|
||||
@@ -161,7 +161,7 @@ public sealed class AmatValidationTests : IDisposable
|
||||
|
||||
// Calculate TA-Lib EMA (slow period)
|
||||
var retCode = TALib.Functions.Ema<double>(tData, 0..^0, outEma, out var outRange, slowPeriod);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.EmaLookback(slowPeriod);
|
||||
|
||||
|
||||
@@ -70,11 +70,11 @@ public sealed class AroonValidationTests : IDisposable
|
||||
|
||||
// TA-Lib Aroon (Up/Down)
|
||||
var retCode = TALib.Functions.Aroon(hData, lData, 0..^0, outAroonDown, outAroonUp, out var outRange, 14);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
// TA-Lib AroonOsc
|
||||
var retCodeOsc = TALib.Functions.AroonOsc(hData, lData, 0..^0, outAroonOsc, out var outRangeOsc, 14);
|
||||
Assert.Equal(Core.RetCode.Success, retCodeOsc);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCodeOsc);
|
||||
|
||||
int lookback = TALib.Functions.AroonLookback(14);
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ public sealed class AroonOscValidationTests : IDisposable
|
||||
|
||||
// TA-Lib AroonOsc
|
||||
var retCodeOsc = TALib.Functions.AroonOsc(hData, lData, 0..^0, outAroonOsc, out var outRangeOsc, 14);
|
||||
Assert.Equal(Core.RetCode.Success, retCodeOsc);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCodeOsc);
|
||||
|
||||
int lookback = TALib.Functions.AroonLookback(14);
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ public sealed class DxValidationTests : IDisposable
|
||||
double[] outReal = new double[_data.Bars.Count];
|
||||
|
||||
var retCode = Functions.PlusDI(hData, lData, cData, 0..^0, outReal, out var outRange, 14);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = Functions.PlusDILookback(14);
|
||||
ValidationHelper.VerifyData(diPlusResults, outReal, outRange, lookback);
|
||||
@@ -96,7 +96,7 @@ public sealed class DxValidationTests : IDisposable
|
||||
double[] outReal = new double[_data.Bars.Count];
|
||||
|
||||
var retCode = Functions.MinusDI(hData, lData, cData, 0..^0, outReal, out var outRange, 14);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = Functions.MinusDILookback(14);
|
||||
ValidationHelper.VerifyData(diMinusResults, outReal, outRange, lookback);
|
||||
|
||||
@@ -162,7 +162,7 @@ public sealed class HtTrendmodeValidationTests : IDisposable
|
||||
int[] outInteger = new int[inReal.Length];
|
||||
|
||||
var retCode = Functions.HtTrendMode(inReal, 0..^0, outInteger, out var outRange);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
// Compare after warmup
|
||||
int lookback = Functions.HtTrendModeLookback();
|
||||
|
||||
@@ -52,10 +52,10 @@ public class QstickIndicatorTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DefaultMaType_IsSMA()
|
||||
public void DefaultTALib.Core.MAType_IsSMA()
|
||||
{
|
||||
var indicator = new QstickIndicator();
|
||||
Assert.Equal("SMA", indicator.MaType);
|
||||
Assert.Equal("SMA", indicator.TALib.Core.MAType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -68,7 +68,7 @@ public class QstickIndicatorTests
|
||||
// ── ShortName ───────────────────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public void ShortName_DefaultParameters_IncludesPeriodAndMaType()
|
||||
public void ShortName_DefaultParameters_IncludesPeriodAndTALib.Core.MAType()
|
||||
{
|
||||
var indicator = new QstickIndicator();
|
||||
Assert.Equal("QSTICK(14,SMA)", indicator.ShortName);
|
||||
@@ -84,7 +84,7 @@ public class QstickIndicatorTests
|
||||
[Fact]
|
||||
public void ShortName_EmaMode_IncludesEMA()
|
||||
{
|
||||
var indicator = new QstickIndicator { Period = 20, MaType = "EMA" };
|
||||
var indicator = new QstickIndicator { Period = 20, TALib.Core.MAType = "EMA" };
|
||||
Assert.Equal("QSTICK(20,EMA)", indicator.ShortName);
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ public class QstickIndicatorTests
|
||||
[Fact]
|
||||
public void Initialize_SmaMode_CreatesInternalIndicator()
|
||||
{
|
||||
var indicator = new QstickIndicator { MaType = "SMA" };
|
||||
var indicator = new QstickIndicator { TALib.Core.MAType = "SMA" };
|
||||
indicator.Initialize();
|
||||
|
||||
Assert.NotNull(indicator);
|
||||
@@ -118,7 +118,7 @@ public class QstickIndicatorTests
|
||||
[Fact]
|
||||
public void Initialize_EmaMode_CreatesInternalIndicator()
|
||||
{
|
||||
var indicator = new QstickIndicator { MaType = "EMA" };
|
||||
var indicator = new QstickIndicator { TALib.Core.MAType = "EMA" };
|
||||
indicator.Initialize();
|
||||
|
||||
Assert.NotNull(indicator);
|
||||
@@ -139,7 +139,7 @@ public class QstickIndicatorTests
|
||||
[Fact]
|
||||
public void ProcessUpdate_HistoricalBar_ComputesValue()
|
||||
{
|
||||
var indicator = new QstickIndicator { Period = 3, MaType = "SMA" };
|
||||
var indicator = new QstickIndicator { Period = 3, TALib.Core.MAType = "SMA" };
|
||||
indicator.Initialize();
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
@@ -156,7 +156,7 @@ public class QstickIndicatorTests
|
||||
[Fact]
|
||||
public void ProcessUpdate_HistoricalBar_BullishBars_PositiveValue()
|
||||
{
|
||||
var indicator = new QstickIndicator { Period = 3, MaType = "SMA" };
|
||||
var indicator = new QstickIndicator { Period = 3, TALib.Core.MAType = "SMA" };
|
||||
indicator.Initialize();
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
@@ -175,7 +175,7 @@ public class QstickIndicatorTests
|
||||
[Fact]
|
||||
public void ProcessUpdate_NewBar_ComputesValue()
|
||||
{
|
||||
var indicator = new QstickIndicator { Period = 3, MaType = "SMA" };
|
||||
var indicator = new QstickIndicator { Period = 3, TALib.Core.MAType = "SMA" };
|
||||
indicator.Initialize();
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
@@ -193,7 +193,7 @@ public class QstickIndicatorTests
|
||||
[Fact]
|
||||
public void ProcessUpdate_NewTick_ProcessesWithoutError()
|
||||
{
|
||||
var indicator = new QstickIndicator { Period = 3, MaType = "SMA" };
|
||||
var indicator = new QstickIndicator { Period = 3, TALib.Core.MAType = "SMA" };
|
||||
indicator.Initialize();
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
@@ -214,7 +214,7 @@ public class QstickIndicatorTests
|
||||
[Fact]
|
||||
public void SmaMode_BearishBars_ProducesNegativeQstick()
|
||||
{
|
||||
var indicator = new QstickIndicator { Period = 5, MaType = "SMA" };
|
||||
var indicator = new QstickIndicator { Period = 5, TALib.Core.MAType = "SMA" };
|
||||
indicator.Initialize();
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
@@ -231,7 +231,7 @@ public class QstickIndicatorTests
|
||||
[Fact]
|
||||
public void SmaMode_DojiBars_ProducesZeroQstick()
|
||||
{
|
||||
var indicator = new QstickIndicator { Period = 5, MaType = "SMA" };
|
||||
var indicator = new QstickIndicator { Period = 5, TALib.Core.MAType = "SMA" };
|
||||
indicator.Initialize();
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
@@ -247,7 +247,7 @@ public class QstickIndicatorTests
|
||||
[Fact]
|
||||
public void EmaMode_BullishBars_ProducesPositiveQstick()
|
||||
{
|
||||
var indicator = new QstickIndicator { Period = 5, MaType = "EMA" };
|
||||
var indicator = new QstickIndicator { Period = 5, TALib.Core.MAType = "EMA" };
|
||||
indicator.Initialize();
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
@@ -663,8 +663,8 @@ public class QstickIndicatorTests
|
||||
[Fact]
|
||||
public void DifferentPeriods_ProduceDifferentResults()
|
||||
{
|
||||
var indicator1 = new QstickIndicator { Period = 3, MaType = "SMA" };
|
||||
var indicator2 = new QstickIndicator { Period = 10, MaType = "SMA" };
|
||||
var indicator1 = new QstickIndicator { Period = 3, TALib.Core.MAType = "SMA" };
|
||||
var indicator2 = new QstickIndicator { Period = 10, TALib.Core.MAType = "SMA" };
|
||||
indicator1.Initialize();
|
||||
indicator2.Initialize();
|
||||
|
||||
@@ -687,8 +687,8 @@ public class QstickIndicatorTests
|
||||
[Fact]
|
||||
public void SmaVsEma_SameData_ProduceDifferentResults()
|
||||
{
|
||||
var smaIndicator = new QstickIndicator { Period = 5, MaType = "SMA" };
|
||||
var emaIndicator = new QstickIndicator { Period = 5, MaType = "EMA" };
|
||||
var smaIndicator = new QstickIndicator { Period = 5, TALib.Core.MAType = "SMA" };
|
||||
var emaIndicator = new QstickIndicator { Period = 5, TALib.Core.MAType = "EMA" };
|
||||
smaIndicator.Initialize();
|
||||
emaIndicator.Initialize();
|
||||
|
||||
@@ -715,7 +715,7 @@ public class QstickIndicatorTests
|
||||
[Fact]
|
||||
public void Reinitialize_WithDifferentParameters_ResetsState()
|
||||
{
|
||||
var indicator = new QstickIndicator { Period = 5, MaType = "SMA" };
|
||||
var indicator = new QstickIndicator { Period = 5, TALib.Core.MAType = "SMA" };
|
||||
indicator.Initialize();
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
@@ -726,7 +726,7 @@ public class QstickIndicatorTests
|
||||
}
|
||||
|
||||
indicator.Period = 10;
|
||||
indicator.MaType = "EMA";
|
||||
indicator.TALib.Core.MAType = "EMA";
|
||||
indicator.Initialize();
|
||||
|
||||
Assert.Equal("QSTICK(10,EMA)", indicator.ShortName);
|
||||
@@ -762,7 +762,7 @@ public class QstickIndicatorTests
|
||||
[Fact]
|
||||
public void MultipleBars_ThroughAdapter_ProducesExpectedValues()
|
||||
{
|
||||
var indicator = new QstickIndicator { Period = 3, MaType = "SMA" };
|
||||
var indicator = new QstickIndicator { Period = 3, TALib.Core.MAType = "SMA" };
|
||||
indicator.Initialize();
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
@@ -795,12 +795,12 @@ public class QstickIndicatorTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MaType_CanBeChanged()
|
||||
public void TALib.Core.MAType_CanBeChanged()
|
||||
{
|
||||
var indicator = new QstickIndicator();
|
||||
Assert.Equal("SMA", indicator.MaType);
|
||||
Assert.Equal("SMA", indicator.TALib.Core.MAType);
|
||||
|
||||
indicator.MaType = "EMA";
|
||||
Assert.Equal("EMA", indicator.MaType);
|
||||
indicator.TALib.Core.MAType = "EMA";
|
||||
Assert.Equal("EMA", indicator.TALib.Core.MAType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,4 +362,4 @@ public class MdapeTests
|
||||
|
||||
Assert.Equal(mdape1.Last.Value, mdape2.Last.Value, Precision);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,9 @@ public sealed class Edcf : AbstractBase
|
||||
private State _s;
|
||||
private State _ps;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an Ehlers Distance Coefficient Filter.
|
||||
/// </summary>
|
||||
/// <param name="length">Filter window length (≥ 2). Default: 15.</param>
|
||||
public Edcf(int length = 15)
|
||||
{
|
||||
@@ -51,6 +54,9 @@ public sealed class Edcf : AbstractBase
|
||||
Name = $"Edcf({_length})";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an EDCF indicator and subscribes it to a source publisher.
|
||||
/// </summary>
|
||||
/// <param name="source">Input data source for event-based chaining.</param>
|
||||
/// <param name="length">Filter window length (≥ 2). Default: 15.</param>
|
||||
public Edcf(ITValuePublisher source, int length = 15) : this(length)
|
||||
|
||||
@@ -191,4 +191,4 @@ public class GaussValidationTests : IDisposable
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,4 +154,4 @@ public class HpfValidationTests : IDisposable
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,4 +241,4 @@ public class BiasIndicatorTests
|
||||
indicator.Period = 100;
|
||||
Assert.Equal(100, indicator.Period);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -591,4 +591,4 @@ public class BiasTests
|
||||
// SMA = 0, Bias = (0-0)/0 = 0/0 -> should return 0 to avoid NaN
|
||||
Assert.Equal(0.0, bias.Last.Value, 1e-10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,4 +433,4 @@ public sealed class BiasValidationTests : IDisposable
|
||||
|
||||
_output.WriteLine($"Oscillating sequence: avg bias = {avgBias:F6}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public sealed class BopValidationTests : IDisposable
|
||||
var talibResult = new double[_data.Bars.Count];
|
||||
var retCode = TALib.Functions.Bop(open, high, low, close, 0..^0, talibResult, out var outRange);
|
||||
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
var quanTAlibResult = Bop.Batch(_data.Bars);
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ public sealed class CciValidationTests(ITestOutputHelper output) : IDisposable
|
||||
// TALib CCI
|
||||
double[] tOutput = new double[high.Length];
|
||||
var retCode = TALib.Functions.Cci<double>(high, low, close, 0..^0, tOutput, out var outRange, TestPeriod);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.CciLookback(TestPeriod);
|
||||
|
||||
@@ -86,7 +86,7 @@ public sealed class CciValidationTests(ITestOutputHelper output) : IDisposable
|
||||
// TALib CCI
|
||||
double[] tOutput = new double[high.Length];
|
||||
var retCode = TALib.Functions.Cci<double>(high, low, close, 0..^0, tOutput, out var outRange, TestPeriod);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.CciLookback(TestPeriod);
|
||||
|
||||
@@ -123,7 +123,7 @@ public sealed class CciValidationTests(ITestOutputHelper output) : IDisposable
|
||||
|
||||
double[] tOutput = new double[high.Length];
|
||||
var retCode = TALib.Functions.Cci<double>(high, low, close, 0..^0, tOutput, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.CciLookback(period);
|
||||
|
||||
|
||||
@@ -280,7 +280,7 @@ public sealed class CmoValidationTests(ITestOutputHelper output) : IDisposable
|
||||
// --- TALib CMO ---
|
||||
double[] taOut = new double[tData.Length];
|
||||
var retCode = Functions.Cmo<double>(tData, 0..^0, taOut, out var outRange, TestPeriod);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
var (taOffset, taLength) = outRange.GetOffsetAndLength(taOut.Length);
|
||||
Assert.True(taLength > 0, "TALib produced no output");
|
||||
|
||||
@@ -127,7 +127,7 @@ public sealed class MacdValidationTests : IDisposable
|
||||
|
||||
// Calculate TA-Lib MACD
|
||||
var retCode = TALib.Functions.Macd<double>(tData, 0..^0, outMacd, outSignal, outHist, out var outRange, fastPeriod, slowPeriod, signalPeriod);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.MacdLookback(fastPeriod, slowPeriod, signalPeriod);
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public sealed class MomValidationTests(ITestOutputHelper output) : IDisposable
|
||||
// TALib Mom
|
||||
double[] tOutput = new double[tData.Length];
|
||||
var retCode = TALib.Functions.Mom<double>(tData, 0..^0, tOutput, out var outRange, TestPeriod);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.MomLookback(TestPeriod);
|
||||
|
||||
@@ -81,7 +81,7 @@ public sealed class MomValidationTests(ITestOutputHelper output) : IDisposable
|
||||
// TALib Mom
|
||||
double[] tOutput = new double[tData.Length];
|
||||
var retCode = TALib.Functions.Mom<double>(tData, 0..^0, tOutput, out var outRange, TestPeriod);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.MomLookback(TestPeriod);
|
||||
|
||||
@@ -106,7 +106,7 @@ public sealed class MomValidationTests(ITestOutputHelper output) : IDisposable
|
||||
// TALib Mom
|
||||
double[] tOutput = new double[tData.Length];
|
||||
var retCode = TALib.Functions.Mom<double>(tData, 0..^0, tOutput, out var outRange, TestPeriod);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.MomLookback(TestPeriod);
|
||||
|
||||
@@ -129,7 +129,7 @@ public sealed class MomValidationTests(ITestOutputHelper output) : IDisposable
|
||||
|
||||
double[] tOutput = new double[tData.Length];
|
||||
var retCode = TALib.Functions.Mom<double>(tData, 0..^0, tOutput, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.MomLookback(period);
|
||||
|
||||
@@ -413,4 +413,4 @@ public sealed class MomValidationTests(ITestOutputHelper output) : IDisposable
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,11 +126,11 @@ public sealed class PpoValidationTests(ITestOutputHelper output) : IDisposable
|
||||
qPpo.Add(ppo.Last.Value);
|
||||
}
|
||||
|
||||
// TA-Lib PPO (must specify MAType.Ema — default is SMA which differs from our EMA-based PPO)
|
||||
var retCode = TALib.Functions.Ppo<double>(tData, 0..^0, outPpo, out var outRange, fastPeriod, slowPeriod, Core.MAType.Ema);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
// TA-Lib PPO (must specify TALib.Core.MAType.Ema — default is SMA which differs from our EMA-based PPO)
|
||||
var retCode = TALib.Functions.Ppo<double>(tData, 0..^0, outPpo, out var outRange, fastPeriod, slowPeriod, TALib.Core.MAType.Ema);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.PpoLookback(fastPeriod, slowPeriod, Core.MAType.Ema);
|
||||
int lookback = TALib.Functions.PpoLookback(fastPeriod, slowPeriod, TALib.Core.MAType.Ema);
|
||||
|
||||
// Compare
|
||||
ValidationHelper.VerifyData(qPpo, outPpo, outRange, lookback);
|
||||
|
||||
@@ -309,7 +309,7 @@ public sealed class RocValidationTests(ITestOutputHelper output) : IDisposable
|
||||
// TALib MOM (absolute momentum = price - prevPrice)
|
||||
double[] taOut = new double[tData.Length];
|
||||
var retCode = Functions.Mom<double>(tData, 0..^0, taOut, out var outRange, TestPeriod);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = Functions.MomLookback(TestPeriod);
|
||||
ValidationHelper.VerifyData(qOutput, taOut, outRange, lookback);
|
||||
@@ -333,7 +333,7 @@ public sealed class RocValidationTests(ITestOutputHelper output) : IDisposable
|
||||
// TALib MOM
|
||||
double[] taOut = new double[tData.Length];
|
||||
var retCode = Functions.Mom<double>(tData, 0..^0, taOut, out var outRange, TestPeriod);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = Functions.MomLookback(TestPeriod);
|
||||
ValidationHelper.VerifyData(qResults, taOut, outRange, lookback);
|
||||
@@ -355,7 +355,7 @@ public sealed class RocValidationTests(ITestOutputHelper output) : IDisposable
|
||||
|
||||
double[] taOut = new double[tData.Length];
|
||||
var retCode = Functions.Mom<double>(tData, 0..^0, taOut, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = Functions.MomLookback(period);
|
||||
ValidationHelper.VerifyData(qOutput, taOut, outRange, lookback);
|
||||
|
||||
@@ -52,7 +52,7 @@ public sealed class RocpValidationTests(ITestOutputHelper output) : IDisposable
|
||||
// TALib RocP (returns decimal fraction)
|
||||
double[] tOutput = new double[tData.Length];
|
||||
var retCode = TALib.Functions.RocP<double>(tData, 0..^0, tOutput, out var outRange, TestPeriod);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.RocPLookback(TestPeriod);
|
||||
|
||||
@@ -93,7 +93,7 @@ public sealed class RocpValidationTests(ITestOutputHelper output) : IDisposable
|
||||
// TALib RocP
|
||||
double[] tOutput = new double[tData.Length];
|
||||
var retCode = TALib.Functions.RocP<double>(tData, 0..^0, tOutput, out var outRange, TestPeriod);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.RocPLookback(TestPeriod);
|
||||
|
||||
@@ -137,7 +137,7 @@ public sealed class RocpValidationTests(ITestOutputHelper output) : IDisposable
|
||||
// TALib RocP
|
||||
double[] tOutput = new double[tData.Length];
|
||||
var retCode = TALib.Functions.RocP<double>(tData, 0..^0, tOutput, out var outRange, TestPeriod);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.RocPLookback(TestPeriod);
|
||||
|
||||
@@ -179,7 +179,7 @@ public sealed class RocpValidationTests(ITestOutputHelper output) : IDisposable
|
||||
|
||||
double[] tOutput = new double[tData.Length];
|
||||
var retCode = TALib.Functions.RocP<double>(tData, 0..^0, tOutput, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.RocPLookback(period);
|
||||
var (offset, length) = outRange.GetOffsetAndLength(tOutput.Length);
|
||||
|
||||
@@ -45,7 +45,7 @@ public sealed class RocrValidationTests(ITestOutputHelper output) : IDisposable
|
||||
// TALib RocR
|
||||
double[] tOutput = new double[tData.Length];
|
||||
var retCode = TALib.Functions.RocR<double>(tData, 0..^0, tOutput, out var outRange, TestPeriod);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.RocRLookback(TestPeriod);
|
||||
|
||||
@@ -78,7 +78,7 @@ public sealed class RocrValidationTests(ITestOutputHelper output) : IDisposable
|
||||
// TALib RocR
|
||||
double[] tOutput = new double[tData.Length];
|
||||
var retCode = TALib.Functions.RocR<double>(tData, 0..^0, tOutput, out var outRange, TestPeriod);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.RocRLookback(TestPeriod);
|
||||
|
||||
@@ -115,7 +115,7 @@ public sealed class RocrValidationTests(ITestOutputHelper output) : IDisposable
|
||||
// TALib RocR
|
||||
double[] tOutput = new double[tData.Length];
|
||||
var retCode = TALib.Functions.RocR<double>(tData, 0..^0, tOutput, out var outRange, TestPeriod);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.RocRLookback(TestPeriod);
|
||||
|
||||
@@ -150,7 +150,7 @@ public sealed class RocrValidationTests(ITestOutputHelper output) : IDisposable
|
||||
|
||||
double[] tOutput = new double[tData.Length];
|
||||
var retCode = TALib.Functions.RocR<double>(tData, 0..^0, tOutput, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.RocRLookback(period);
|
||||
var (offset, length) = outRange.GetOffsetAndLength(tOutput.Length);
|
||||
|
||||
@@ -65,7 +65,7 @@ public sealed class RsiValidationTests(ITestOutputHelper output) : IDisposable
|
||||
|
||||
double[] tOutput = new double[tData.Length];
|
||||
var retCode = TALib.Functions.Rsi<double>(tData, 0..^0, tOutput, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.RsiLookback(period);
|
||||
|
||||
@@ -143,7 +143,7 @@ public sealed class RsiValidationTests(ITestOutputHelper output) : IDisposable
|
||||
|
||||
// Calculate TA-Lib RSI
|
||||
var retCode = TALib.Functions.Rsi<double>(tData, 0..^0, tOutput, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.RsiLookback(period);
|
||||
|
||||
|
||||
@@ -142,4 +142,4 @@ public class RsxValidationTests
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public sealed class HighestValidationTests : IDisposable
|
||||
|
||||
// Calculate TA-Lib MAX
|
||||
var retCode = TALib.Functions.Max<double>(tData, 0..^0, output, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.MaxLookback(period);
|
||||
|
||||
@@ -81,7 +81,7 @@ public sealed class HighestValidationTests : IDisposable
|
||||
|
||||
// Calculate TA-Lib MAX
|
||||
var retCode = TALib.Functions.Max<double>(tData, 0..^0, output, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.MaxLookback(period);
|
||||
|
||||
@@ -107,7 +107,7 @@ public sealed class HighestValidationTests : IDisposable
|
||||
|
||||
// Calculate TA-Lib MAX
|
||||
var retCode = TALib.Functions.Max<double>(sourceData, 0..^0, talibOutput, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.MaxLookback(period);
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ public sealed class LowestValidationTests : IDisposable
|
||||
|
||||
// Calculate TA-Lib MIN
|
||||
var retCode = TALib.Functions.Min<double>(tData, 0..^0, output, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.MinLookback(period);
|
||||
|
||||
@@ -81,7 +81,7 @@ public sealed class LowestValidationTests : IDisposable
|
||||
|
||||
// Calculate TA-Lib MIN
|
||||
var retCode = TALib.Functions.Min<double>(tData, 0..^0, output, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.MinLookback(period);
|
||||
|
||||
@@ -107,7 +107,7 @@ public sealed class LowestValidationTests : IDisposable
|
||||
|
||||
// Calculate TA-Lib MIN
|
||||
var retCode = TALib.Functions.Min<double>(sourceData, 0..^0, talibOutput, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.MinLookback(period);
|
||||
|
||||
|
||||
@@ -197,4 +197,4 @@ public sealed class AcValidationTests
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,13 @@ namespace QuanTAlib;
|
||||
/// AO = SMA(Median Price, fastPeriod) - SMA(Median Price, slowPeriod)
|
||||
/// AC = AO - SMA(AO, acPeriod)
|
||||
///
|
||||
/// Design note: Ac implements <see cref="ITValuePublisher"/> directly rather than inheriting
|
||||
/// from AbstractBase. This is intentional: Ac is an OHLC-based indicator whose primary input
|
||||
/// is a <see cref="TBar"/> (requiring High and Low), not a single <see cref="TValue"/>.
|
||||
/// AbstractBase's contract (Update(TValue), Prime(ReadOnlySpan<double>)) does not fit
|
||||
/// OHLC indicators. The practical entry points are Update(TBar) and Prime(TBarSeries).
|
||||
/// If a future TBarIndicatorBase is introduced, Ac would be a candidate to migrate.
|
||||
///
|
||||
/// Sources:
|
||||
/// https://www.investopedia.com/terms/a/accelerationdeceleration-indicator.asp
|
||||
/// https://www.tradingview.com/support/solutions/43000501837-accelerator-oscillator-ac/
|
||||
|
||||
@@ -16,6 +16,13 @@ namespace QuanTAlib;
|
||||
/// Median Price = (High + Low) / 2
|
||||
/// AO = SMA(Median Price, 5) - SMA(Median Price, 34)
|
||||
///
|
||||
/// Design note: Ao implements <see cref="ITValuePublisher"/> directly rather than inheriting
|
||||
/// from AbstractBase. This is intentional: Ao is an OHLC-based indicator whose primary input
|
||||
/// is a <see cref="TBar"/> (requiring High and Low), not a single <see cref="TValue"/>.
|
||||
/// AbstractBase's contract (Update(TValue), Prime(ReadOnlySpan<double>)) does not fit
|
||||
/// OHLC indicators. The practical entry points are Update(TBar) and Prime(TBarSeries).
|
||||
/// If a future TBarIndicatorBase is introduced, Ao would be a candidate to migrate.
|
||||
///
|
||||
/// Sources:
|
||||
/// https://www.investopedia.com/terms/a/awesomeoscillator.asp
|
||||
/// https://www.tradingview.com/support/solutions/43000501826-awesome-oscillator-ao/
|
||||
|
||||
@@ -43,8 +43,8 @@ public sealed class ApoValidationTests : IDisposable
|
||||
double[] input = _testData.Data.Values.ToArray();
|
||||
double[] output = new double[input.Length];
|
||||
|
||||
// TA-Lib APO: double[] inReal, int optInFastPeriod, int optInSlowPeriod, int optInMAType
|
||||
// MAType 1 = EMA
|
||||
// TA-Lib APO: double[] inReal, int optInFastPeriod, int optInSlowPeriod, int optInTALib.Core.MAType
|
||||
// TALib.Core.MAType 1 = EMA
|
||||
var retCode = TALib.Functions.Apo<double>(input, 0..^0, output, out var outRange, fastPeriod, slowPeriod, TALib.Core.MAType.Ema);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
|
||||
@@ -308,4 +308,4 @@ public sealed class DemValidationTests(ITestOutputHelper output)
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,4 +243,4 @@ public sealed class DymoiValidationTests
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,4 +226,4 @@ public sealed class InertiaValidationTests : IDisposable
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,4 +350,4 @@ public sealed class LrsiValidationTests
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,4 +242,4 @@ public sealed class PgoValidationTests
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,4 +178,4 @@ public sealed class SmiValidationTests
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,10 +258,10 @@ public sealed class StochValidationTests : IDisposable
|
||||
// --- I) TALib cross-validation ---
|
||||
|
||||
/// <summary>
|
||||
/// TALib Stoch(fastKPeriod=14, slowKPeriod=1, slowKMAType=SMA, slowDPeriod=3, slowDMAType=SMA)
|
||||
/// TALib Stoch(fastKPeriod=14, slowKPeriod=1, slowKTALib.Core.MAType=SMA, slowDPeriod=3, slowDTALib.Core.MAType=SMA)
|
||||
/// with slowKPeriod=1 (no K smoothing) produces raw %K == our K output.
|
||||
/// slowD with SMA(3) matches our D output.
|
||||
/// Note: TALib Stoch uses SMA for both K and D smoothing (MAType=SMA).
|
||||
/// Note: TALib Stoch uses SMA for both K and D smoothing (TALib.Core.MAType=SMA).
|
||||
/// QuanTAlib Stoch also uses SMA. With slowKPeriod=1 (identity) the K lines match directly.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
|
||||
@@ -105,7 +105,7 @@ public sealed class TrixValidationTests(ITestOutputHelper output) : IDisposable
|
||||
|
||||
double[] tOutput = new double[tData.Length];
|
||||
var retCode = TALib.Functions.Trix<double>(tData, 0..^0, tOutput, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.TrixLookback(period);
|
||||
|
||||
@@ -132,7 +132,7 @@ public sealed class TrixValidationTests(ITestOutputHelper output) : IDisposable
|
||||
}
|
||||
|
||||
var retCode = TALib.Functions.Trix<double>(tData, 0..^0, tOutput, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.TrixLookback(period);
|
||||
|
||||
|
||||
@@ -243,7 +243,7 @@ public sealed class UltoscValidationTests : IDisposable
|
||||
var qResult = ultosc.Update(_data.Bars);
|
||||
|
||||
var retCode = TALib.Functions.UltOsc(hData, lData, cData, 0..^0, output, out var outRange, p1, p2, p3);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.UltOscLookback(p1, p2, p3);
|
||||
|
||||
@@ -279,7 +279,7 @@ public sealed class UltoscValidationTests : IDisposable
|
||||
}
|
||||
|
||||
var retCode = TALib.Functions.UltOsc(hData, lData, cData, 0..^0, output, out var outRange, p1, p2, p3);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.UltOscLookback(p1, p2, p3);
|
||||
|
||||
|
||||
@@ -259,4 +259,4 @@ public sealed class PivotValidationTests
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,4 +273,4 @@ public sealed class PivotcamValidationTests
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,4 +240,4 @@ public sealed class PivotdemValidationTests
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,4 +246,4 @@ public sealed class PivotfibValidationTests
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,4 +254,4 @@ public sealed class PivotwoodValidationTests
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user