Add Choppiness Index (CHOP) implementation and tests

- Implemented ChopIndicator for Quantower with configurable period and cold value display.
- Created Chop class for calculating the Choppiness Index with detailed documentation.
- Added comprehensive unit tests for Chop functionality, covering various market conditions and edge cases.
- Developed markdown documentation for CHOP, detailing its historical context, mathematical foundation, and usage examples.
- Established a remediation plan for channel indicators documentation, identifying gaps and prioritizing updates.
This commit is contained in:
Miha Kralj
2026-02-05 19:42:49 -08:00
parent 95838a6435
commit 26280ce80b
73 changed files with 8485 additions and 5254 deletions
File diff suppressed because one or more lines are too long
+156
View File
@@ -0,0 +1,156 @@
# QuanTAlib Agent Playbook (v2026-01-11)
> This file is the onboarding packet for any autonomous agent touching QuanTAlib. Read it end-to-end before issuing a single command.
## 0. Scope & Signals
- Targets the entire repo (library, docs, Quantower adapters, tooling).
- Applies to GitHub Actions, MCP agents, and local shells.
- No Cursor or Copilot rule files exist right now; follow this document plus `.clinerules/AGENTS.md` for deeper philosophy.
- Root namespace: `QuanTAlib`. Target frameworks: net8.0 + net10.0 preview features.
## 1. Toolchain Baseline
- SDK: `.globalconfig` pins none; install .NET 8/10 SDKs.
- Solution: `QuanTAlib.sln` aggregates `lib` + `quantower` projects.
- Implicit usings disabled for library projects (`DisableImplicitNamespaceImports=true`), so import explicitly.
- Nullable + analyzers enforced in `Directory.Build.props`; warnings become errors on Release.
- Unsafe code, SIMD, intrinsics, stackalloc, `[SkipLocalsInit]`, `[AggressiveInlining]` allowed and encouraged.
## 2. Build & Restore Commands (run from repo root)
1. Restore everything:
```powershell
dotnet restore QuanTAlib.sln
```
2. Build library quickly (Debug, net10.0):
```powershell
dotnet build lib/quantalib.csproj --configuration Debug --framework net10.0 --no-restore
```
3. Build full solution (Release):
```powershell
dotnet build QuanTAlib.sln --configuration Release --no-restore
```
4. Build Quantower adapters bundle (Release, example subset):
```powershell
dotnet build quantower/Momentum.csproj --configuration Release --no-restore
dotnet build quantower/Trends.csproj --configuration Release --no-restore
dotnet build quantower/Volume.csproj --configuration Release --no-restore
```
5. Generate SARIF + coverage + NDepend badges (long runner, Windows PowerShell 7+):
```powershell
pwsh ndepend/ndepend.ps1
```
## 3. Test Commands
- **All QuanTAlib unit + validation tests (Debug):**
```powershell
dotnet test lib/QuanTAlib.Tests.csproj --configuration Debug --no-build
```
- **Quantower adapter tests (Debug):**
```powershell
dotnet test quantower/Quantower.Tests.csproj --configuration Debug --no-build
```
- **Full coverage run with Coverlet + runsettings (matches CI):**
```powershell
dotnet test lib/QuanTAlib.Tests.csproj --configuration Debug --no-build \
--collect:"XPlat Code Coverage" --settings coverlet.runsettings \
--results-directory ./TestResults
dotnet test quantower/Quantower.Tests.csproj --configuration Debug --no-build \
--collect:"XPlat Code Coverage" --settings coverlet.runsettings \
--results-directory ./TestResults
```
- **Single test / filtered suite:** Replace the predicate with any substring of `FullyQualifiedName`.
```powershell
dotnet test lib/QuanTAlib.Tests.csproj --no-build --configuration Debug \
--filter "FullyQualifiedName~EmaValidation"
```
- **Quick span-path smoke (example)**
```powershell
dotnet test lib/QuanTAlib.Tests.csproj --configuration Release --no-build --filter "Category=Span"
```
- **CI parity (Ubuntu)** uses `dotnet test --no-build --configuration Debug --collect:"XPlat Code Coverage;Format=opencover,cobertura,lcov" --results-directory ./TestResults --logger "trx;LogFileName=test_results.trx"`. Replicate locally when debugging pipeline-only regressions.
## 4. Lint / Quality Gates
- `dotnet build` (any configuration) enforces Roslyn, Sonar, Meziantou, Roslynator, SourceLink analyzers; fix warnings locally.
- `pwsh ndepend/ndepend.ps1` cleans, rebuilds, runs coverage, executes NDepend analysis, and emits badges + `.sarif/quantalib.sarif`.
- Qodana & SonarCloud pipelines read from SARIF plus coverage; keep `.sarif` directory clean.
- `ndepend/ndepend.ps1` expects env var `NDEPEND_LICENSE`; script still runs but warns if missing.
- `qodana.yaml` is present; locally you may execute `docker run -v ${PWD}:/data/project jetbrains/qodana-dotnet ...` (optional, not required for every change).
## 5. Repository Structure Highlights
- `lib/` core indicators, tests, validation, docs per indicator folder.
- `quantower/` platform adapters, per-category csproj plus shared tests.
- `docs/` architecture, indicator catalog, integration notes, validation matrices.
- `perf/` BenchmarkDotNet harnesses; results must go to `temp/benchmarks` during dev, never committed.
- `temp/` gitignored scratch (scripts, datasets, logs). Create subdirs like `temp/scripts/run_bench_YYYYMMDD_hhmmss.ps1`.
- `.clinerules/AGENTS.md` canonical philosophy file. Treat this AGENTS.md as quickstart + commands; consult `.clinerules` for deep rules.
## 6. Coding Style & Formatting (superset of .editorconfig)
1. **Whitespace & files**
- LF endings, UTF-8, trim trailing whitespace, final newline required.
- Indent with 4 spaces; no tabs.
2. **Var usage** (`.editorconfig` enforced)
- Prefer explicit types for primitive math values (int, double, string) to document formulas.
- Allow `var` only when RHS makes the type obvious (e.g., `new RingBuffer(capacity)` or Linq-free aggregator returns).
3. **Imports**
- No implicit namespaces: add explicit `using` statements (file-scoped) for every dependency.
- Sort system namespaces first, then QuanTAlib/local.
4. **Types & naming**
- `public` members: PascalCase; private fields: `_camelCase`; constants: `SCREAMING_CASE` only for static readonly calibration.
- Accept well-known abbreviations (Sma, Ema, Rsi, Atr, Dmx, Jma, Vidya) per library convention.
- Use `record struct` for aggregated state, `readonly struct` for data carriers (`TValue`, `TBar`).
5. **Attributes & perf toggles**
- `[SkipLocalsInit]` atop performance-critical classes/methods.
- `[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]` for hot path helpers (`GetFiniteValue`, `Update`, `Calculate`).
6. **Memory & SIMD canon (DCT from .clinerules)**
- Zero heap allocations inside `Update` and span-based `Calculate`; prefer `stackalloc` <=256 bytes, `ArrayPool` when bigger.
- Maintain Structure-of-Arrays (SoA) layout: `List<long> _t`, `List<double> _v`, exposures via `CollectionsMarshal.AsSpan`.
- Use `System.Runtime.Intrinsics` (AVX2/AVX-512) or `System.Numerics.Vector<T>` for batch loops; pair with scalar fallback for recursive cases.
- Apply `Math.FusedMultiplyAdd` for every `a*b + c` in smoothing / IIR patterns.
7. **State & streaming rules**
- Always implement `_state` / `_p_state` record structs for rollback when `isNew=false` (bar correction).
- Maintain `Last`, `IsHot`, `WarmupPeriod`, and `Name` consistently.
- Validate every constructor argument and throw `ArgumentException(nameof(param))` (MA0001-friendly).
8. **Error handling**
- Never swallow exceptions. Guard invalid parameters early; prefer `ArgumentOutOfRangeException` for bounds.
- Replace non-finite input with last valid value; never propagate NaN/Infinity to downstream spans or events.
9. **Events & reactive**
- Subscribe directly (`source.Pub += Handle;`) without extra null guards if parameter non-nullable.
- Custom delegates (`TValuePublishedHandler`) are acceptable; MA0046 suppressed repo-wide.
10. **Date/time & culture**
- Always use `DateTime.UtcNow`. No `DateTime.Now`, `DateTimeOffset.Now`, or culture-specific string formatting in hot paths.
11. **Docs**
- Markdown lint strict (MD022/30/31/32). Use skeptical, data-driven voice as described in `.clinerules/AGENTS.md` Section 4.
- Every new indicator requires doc + validation entries in all indexes.
## 7. Testing Doctrine
- Test files live alongside sources (`[Name].Tests.cs`, `[Name].Validation.Tests.cs`, `[Name].Quantower.Tests.cs`).
- Data generation uses GBM helpers in `lib/feeds/gbm`; do NOT instantiate `System.Random` directly inside tests.
- Validation tests must compare against TA-Lib, Skender, Tulip, or Ooples with tight tolerances (see `ValidationHelper`).
- Always assert streaming vs batch vs span parity (last 100 bars).
- Include `isNew=false` correction tests, NaN/Infinity handling, `Reset`, `IsHot` transitions.
## 8. Workflow Expectations
1. Query qdrant memory before designing new algorithm; store decisions/benchmarks after validation.
2. Use `temp/` for generated artifacts, never commit.
3. When performance changes are made, capture BenchmarkDotNet tables (before/after) and summarize in PR/commit descriptions.
4. Do not push commits unless explicitly asked; run `git status`/`git diff` before staging.
5. Pull requests must mention which external validation suites ran (TA-Lib, Skender, etc.).
## 9. Common Pitfalls (avoid immediately)
- LINQ, `new` allocations, boxing, or string concatenation inside hot loops.
- Forgetting `docs/validation.md` rows when adding indicators.
- Failing to update Quantower adapters/tests when changing indicator APIs.
- Leaving Coverlet residue outside `TestResults/`.
- Using `DateTime.Now` or culture-specific formatting.
- Omitting `nameof(...)` in exceptions, breaking analyzer expectations.
## 10. Ready Checklist Before PR
- [ ] `dotnet build QuanTAlib.sln --configuration Release --no-restore` passes.
- [ ] `dotnet test lib/QuanTAlib.Tests.csproj --configuration Debug --no-build` passes.
- [ ] `dotnet test quantower/Quantower.Tests.csproj --configuration Debug --no-build` passes.
- [ ] Validation suite compares against at least one external library per indicator change.
- [ ] Docs + indexes updated, markdownlint clean.
- [ ] Benchmarks (if perf-sensitive change) captured under `temp/benchmarks` and summarized.
- [ ] `.sarif` regenerated if analyzer rules change.
- [ ] qdrant updated with new decisions/benchmarks.
Stay fast, stay precise, keep the garbage collector asleep.
+97
View File
@@ -0,0 +1,97 @@
# [CODE: Full name of the indicator]
> short witty quote or insight about the indicator
One paragraph describing the indicator and its purpose to a trader.
## Historical Context
2-3 paragraphs about the origin of the indicator, who created it, and any relevant historical context. This should include the motivation behind its creation and how it fits into the broader landscape of technical analysis.
## Architecture & Physics
High-level description of calculation steps - both standard/naive and the optimized version. Use Mermaid diagram describing calculation pipeline if indicator is complex.
### Calculation Step 1..n
Mathematical formulas in LaTeX format, followed by with explanations of what each variable represents and how it contributes to the final output.
## Performance Profile
Describe the computational complexity of the indicator, including any optimizations that have been made. Explain if original is O(n) and how it was optimized to O(1) or O(log n) if applicable.
### Operation Count - Single value
| Operation | Count | Cost (cycles) | Subtotal |
| :--- | :---: | :---: | :---: |
| SUB (Sum - oldest) | 1 | 1 | 1 |
| ADD (Sum + newest) | 1 | 1 | 1 |
| DIV (Sum / N) | 1 | 15 | 15 |
| **Total** | **3** | — | **~17 cycles** |
### Operation Count - Batch processing
Explain if/why vectorization accelerates calculations.
| Operation | Scalar Ops | SIMD Ops (AVX-512) | Acceleration |
| :--- | :---: | :---: | :---: |
| Initial N-sum | N | N/8 | 8× |
| Running update (per bar) | 3 | ~1 | ~3× |
## Validation
What are validation sources - if any. If no external sources, describe how the indicator was validated.
| Library | Status | Notes |
| :--- | :--- | :--- |
| **TA-Lib** | ✅ | Matches `TA_FUNC` |
| **Skender** | ✅ | Matches `Indicator` |
| **Pandas-TA**| ✅ | Matches `ta.func` |
## Usage & Pitfalls
- List of practical tips for using the indicator effectively, including common pitfalls to avoid.
## API
Mermaid class diagram describing the public API of the indicator, including constructors, properties, and methods.
```mermaid
```
### Class: `[ClassName]`
| Parameter | Type | Default | Range | Description |
| :--- | :--- | :--- | :--- | :--- |
| `period` | `int` | `14` | `>0` | The window size for the calculation. |
| `input` | `TValue` | — | `any` | Initial input source (optional). |
### Properties
- `Value` (`double`): The current value of the indicator.
- `IsHot` (`bool`): Returns `true` if valid data is available (warmup complete).
### Methods
- `Calc(TValue input)`: Updates the indicator with a new data point and returns the result.
## C# Example
```csharp
using QuanTAlib;
// Initialize
var indicator = new [ClassName](period: 14);
// Update Loop
foreach (var bar in quotes)
{
var result = indicator.Calc(bar.Close);
// Use valid results
if (indicator.IsHot)
{
Console.WriteLine($"{bar.Date}: {result.Value}");
}
}
```