Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: aider (openrouter/anthropic/claude-sonnet-4) <aider@aider.chat> Co-authored-by: Warp <agent@warp.dev>
19 KiB
QuanTAlib Master Protocol (AI Agents)
WARN: repo laws/physics. Read relevant sections bf code. Noncompliance→reject.
DCT{ 1:Hot paths allocation-free (no heap alloc); GC pressure enemy; 2:Streaming updates O(1) when math allows; 3:Dual API: stateful Update + stateless static Calculate; 4:Bar correction via isNew rollback (same timestamp rewrite); 5:Robustness: handle NaN/Infinity via last-valid-value substitution; never propagate invalids; 6:SoA: store primitives in concrete List fields + expose spans via CollectionsMarshal.AsSpan; 7:SIMD in Calculate where possible; scalar fallback else; 8:Docs: technical correctness + measurable evidence + skeptical-architect tone; markdownlint strict. }
QUICKSTART: DO:{Create Indicator}#p1; DO:{Create Adapters for Quantower + other platforms}#p1; DO:{Write comprehensive Tests + validations}#p1; DO:{Write Stylistically + Structurally correct Docs}#p2; DO:{Performance Tuning}#p1.
CRIT_PATTERNS:
- State: use
private record struct State - Stack-only: prefer
readonly ref structwhen something should absolutely never leave the stack - Imports: prefer
using staticfor math-heavy/pure helper classes to reduce ceremony and keep expressions readable - Types: prefer nullable annotations for optional refs; prefer
record/record structfor value-like models/state - Code clarity: prioritize self-documenting names/structure; use comments for “why”, not “what”
- Encapsulation: prefer
filetypes for internal-only helpers - Closures: prefer
staticlocal functions to avoid accidental captures - Discards: use explicit discard (
_ = expr;) when intentionally ignoring a return value - Lifetimes: use
scoped refparameters for internal APIs to constrain lifetimes - Events:
source.Pub += Handle; - Args:
ArgumentException+nameof(param) - FMA:
Math.FusedMultiplyAdd(a, b, c)fora*b+c - Storage:
List<T>fields for SoA (suppress MA0016 narrowly around those fields) - Time: always
DateTime.UtcNow(neverDateTime.Now) - Tests: use
GBMfor data; neverSystem.Random
- IDENTITY & MISSION
- QuanTAlib: high-perf, ^1 C# lib for quantitative technical analysis.
- Model: IF PineScript exists in same indicator dir → use as foundation.
- Target: Quantower + custom C# trading engines.
- Philosophy: Speed + Correctness + Memory Efficiency.
- ARCHITECTURE & PHYSICS 2.1 Memory model (^6)
- No objects-in-lists; primitives-in-arrays.
- TSeries internal:
List<long> _t(timestamps),List<double> _v(values). - Access: expose
ReadOnlySpan<double>for SIMD. - Analyzer note: MA0016 suggests abstractions; suppress only around core List fields by design.
2.2 Core types
TValuestruct (16 bytes):DateTime Time,double Value.TBarstruct (48 bytes):DateTime Time,double Open, High, Low, Close, Volume.TSeriesprimary time-series DS;ITValuePublisherreactive flow.
2.3 Design principles
- Source material: PineScript at [U1].
- ^1: use
Span<T>,stackalloc, pinned mem where needed. - ^2: running sums/products or RingBuffer; avoid history re-iter.
- ^3: Update + Calculate.
- ^4: isNew rollback required.
- ^5: NaN/Infinity safe.
- Reactive: implement
ITValuePublisher. - Time handling:
DateTime.UtcNow.
2.4 Performance rules (hard constraints)
- Update MUST satisfy ^1 and ^2.
- SIMD: Calculate should use
System.Runtime.Intrinsics(AVX2) orSystem.Numerics.Vector<T>; useVector.ConditionalSelectfor branchless edge handling (eg div0). If recursion blocks SIMD → preferstackallocbuffers. - Hot methods:
[MethodImpl(MethodImplOptions.AggressiveInlining)]. - Tight loops:
[SkipLocalsInit].
2.5 FMA patterns (use in hot paths)
- EMA smoothing:
x + alpha * (y - x)→Math.FusedMultiplyAdd(x, decay, alpha * y)wheredecay = 1 - alpha - Weighted sum:
a*w1 + b*w2→Math.FusedMultiplyAdd(a, w1, b * w2) - Linear combo:
3.0*a - b→Math.FusedMultiplyAdd(3.0, a, -b) - Cross product:
(a*b) + (c*d)→Math.FusedMultiplyAdd(a, b, c * d) - IIR:
coef*input + feedback*state→Math.FusedMultiplyAdd(coef, input, feedback * state)Use FMA for EMA-style smoothing, IIR (Butterworth/Chebyshev/SSF), HTIT/MAMA-style homodyne, anya*b+c. Avoid FMA for simple ops, when intermediate rounding required, or in SIMD paths (useFma.MultiplyAdd/Avx512F.FusedMultiplyAdd/AdvSimd.Arm64.FusedMultiplyAdd). Precompute decay constants:private readonly double _alpha; private readonly double _decay; // = 1 - _alphaHot path:result = Math.FusedMultiplyAdd(prevState, _decay, _alpha * newInput);
- IMPLEMENTATION STANDARDS (every indicator)
3.1 File layout
DIR:
lib/[category]/[name]/(eglib/trends/sma/) REQ files:
[Name].cs(main impl,public sealed class)[Name].Tests.cs(xUnit)[Name].Validation.Tests.cs(vs TA-Lib/Skender/Tulip/Ooples)[Name].md(docs + formulas)[Name].Quantower.cs(adapter)[Name].Quantower.Tests.cs(adapter tests)
3.2 Class definition
- Namespace
QuanTAlib;[SkipLocalsInit];public sealed class; implementsITValuePublisher.
3.3 State mgmt
- Scalar state:
private record struct Stategrouping all scalar vars. - Maintain
_state(current) +_p_state(prev valid). - Buffers:
RingBufferfor sliding windows. - Resync: periodic full recalculation (eg every 1000 ticks) to limit floating drift in running sums.
3.4 Constructor rules
- Validate params: throw
ArgumentException+nameof(). - Set Name: eg
$\"Sma({period})\". - Support chaining ctor:
public [Name](ITValuePublisher source, ...). - Event subscribe:
source.Pub += Handle;(no defensive null checks when source is non-nullable).
3.5 Update(TValue) contract
SIG: public TValue Update(TValue input, bool isNew = true) w/ [MethodImpl(MethodImplOptions.AggressiveInlining)]
FLOW:
- IF isNew→
_p_state=_statethen advance counters; ELSE rollback_state=_p_state. - Validate input: if
!double.IsFinite→ substitute last-valid (stored in State). - Compute (apply FMA where relevant).
- Publish: update
Last, invokePub, returnLast.
3.6 Update(TSeries)
SIG: public TSeries Update(TSeries source) adjacent to Update(TValue)
- Create output series
- Call static
Calculate(ReadOnlySpan<double>, Span<double>, ...) - Restore internal state by replaying last Period bars (or full series if recursive).
3.7 Static Calculate(TSeries)
- Create indicator instance
- Iterate source series
- Return output TSeries
3.8 Static Calculate(Span) (perf-critical)
SIG: public static void Calculate(ReadOnlySpan<double> source, Span<double> output, ...)
RULES:
- Validate args w/
ArgumentExceptioninclnameof(output)etc (MA0015-friendly). - SIMD path optional-but-recommended for simple/non-recursive; check
Avx2.IsSupported. - Use
stackallocfor small buffers (threshold ~256) + internal state buffers when SIMD not applicable. - Scalar fallback must handle NaN safely.
- DOCUMENTATION STANDARDS (^8) Mission: persuade skeptical architects via correctness + architecture evidence + benevolent curmudgeon wit; ruthless w/ math, kind to humans. Audience: practitioners who value implementation + trade-offs. Voice: GRINGE blend (Bryson warmth; Roach curiosity; Sedaris self-own; O'Rourke cynicism). Argumentation: steel-man opponents, rebut w/ data; Evidence chain: Why→How→Proof→So what; Feel-Felt-Found ok. Language: direct cadence; precise nums; avoid "we"; deliberate sentence-length variation; "code as evidence". Humor: allowed for complexity/context; NOT in perf/security/math correctness claims. Anti-slop:
- Forbidden words SET{Delve|leverage|pivotal|tapestry|landscape|furthermore|"is all about"|"unlock the power"|transformative|foster|seamless|ecosystem}
- Avoid em-dashes; avoid formulaic perfectly balanced pro/con tropes. Markdown: strict CommonMark + markdownlint; watch MD022/MD031, MD030, MD032; include perf env specs (AVX2, Turbo status, sample sizes).
4.1 DOC_TMPL (required sections)
Reference: lib/trends_IIR/jma/Jma.md as canonical exemplar.
# [ABBREV]: [Full Name]
> "[Memorable quote that captures the indicator's essence or challenges common assumptions]"
[Opening paragraph: What it is + key differentiator. State what makes THIS implementation unique vs common approximations. Include measurable claims (e.g., "within floating-point tolerance", "3-4% divergence during 3-sigma events").]
## Historical Context
[Origin story: Who created it, when, why. Address the knowledge gap: what was publicly known vs actual implementation details. Acknowledge prior approximations and explain how/why this implementation differs. 2-4 paragraphs.]
## Architecture & Physics
[System overview: Describe the indicator as interconnected components. Use numbered subsections for each major component.]
### 1. [Component Name]
[Describe component purpose + behavior. Include conditional logic with mathematical notation:]
$$
X_t = \begin{cases}
P_t & \text{if condition A} \\
f(X_{t-1}, P_t) & \text{otherwise}
\end{cases}
$$
[Explain WHY this design choice matters. Note alternative naming conventions if applicable.]
### 2. [Component Name]
[Continue pattern for each component. Include epsilon guards, buffer sizes, smoothing mechanisms.]
### N. [Final Component / Core Filter]
[For IIR/FIR filters, include transfer function in z-domain if applicable:]
$$
H(z) = \frac{...}{...}
$$
[Explain state-space form and coupled recursions.]
## Mathematical Foundation
[Detailed derivations for each calculation step. Use subsections for logical groupings.]
### [Calculation Name] (e.g., Dynamic Exponent Calculation)
$$
r_t = \frac{|\Delta_t|}{\hat{V}_t}
$$
$$
d_t = \text{clamp}(r_t^{P_{exp}}, 1, \text{logParam})
$$
where:
- $P_{exp} = ...$
- $\text{logParam} = ...$
[Continue for each derived quantity: coefficients, decay rates, recursions.]
### [Recursion Name] (e.g., IIR Recursion)
[State equations in sequence:]
$$
C_{0,t} = (1 - \alpha_t) \cdot P_t + \alpha_t \cdot C_{0,t-1}
$$
[Include parameter mappings (e.g., phase [-100,100] → [0.5,2.5]).]
## Performance Profile
### Operation Count (Streaming Mode, Scalar)
[Itemize computational cost per bar:]
| Operation | Count | Cost (cycles) | Subtotal |
| :--- | :---: | :---: | :---: |
| ADD/SUB | N | 1 | N |
| MUL | N | 3 | 3N |
| DIV | N | 15 | 15N |
| CMP/ABS | N | 1 | N |
| SQRT | N | 15 | 15N |
| EXP/POW | N | 50-80 | ... |
| SORT (if applicable) | 1 | ~O(n log n) | ... |
| **Total** | **sum** | — | **~X cycles** |
[Identify dominant cost contributor with percentage.]
### Batch Mode (512 values, SIMD/FMA)
[Explain SIMD applicability. For recursive indicators, acknowledge limitations:]
| Operation | Scalar Ops | SIMD Ops (AVX2) | Speedup |
| :--- | :---: | :---: | :---: |
| [Vectorizable op] | N | N/8 | 8× |
| FMA operations | N | N/3 | 3× |
**Per-bar savings with SIMD/FMA:**
| Optimization | Cycles Saved | New Total |
| :--- | :---: | :---: |
| [Optimization 1] | ~X | Y |
| **Total SIMD/FMA savings** | **~X cycles** | **~Y cycles** |
**Batch efficiency (512 bars):**
| Mode | Cycles/bar | Total (512 bars) | Overhead |
| :--- | :---: | :---: | :---: |
| Scalar streaming | X | 512X | — |
| SIMD/FMA streaming | Y | 512Y | — |
| **Improvement** | **Z%** | **N saved** | — |
[Explain why improvement is modest/significant based on algorithm characteristics.]
### Quality Metrics
| Metric | Score | Notes |
| :--- | :---: | :--- |
| **Accuracy** | N/10 | [Brief justification] |
| **Timeliness** | N/10 | [Brief justification] |
| **Overshoot** | N/10 | [Brief justification] |
| **Smoothness** | N/10 | [Brief justification] |
| **[Custom metric if applicable]** | N/10 | [Brief justification] |
## Validation
[State validation context: proprietary, open-source availability, reference sources.]
| Library | Status | Notes |
| :--- | :---: | :--- |
| **TA-Lib** | ✅/N/A | [Implementation status or match notes] |
| **Skender** | ✅/N/A | [Implementation status or match notes] |
| **Tulip** | ✅/N/A | [Implementation status or match notes] |
| **Ooples** | ✅/N/A | [Implementation status or match notes] |
| **[Other reference]** | ✅ | [Match notes] |
## Common Pitfalls
1. **[Pitfall Category]**: [Specific issue + quantified impact. Include formulas for warmup periods, memory footprints, etc.]
2. **[Pitfall Category]**: [Parameter confusion, default behaviors, migration gotchas.]
3. **[Pitfall Category]**: [Computational cost awareness with concrete numbers.]
4. **[Pitfall Category]**: [Memory footprint with per-instance and scaled estimates.]
5. **[Pitfall Category]**: [Edge case limitations.]
6. **[Pitfall Category]**: [API usage (isNew, Reset, etc.).]
## References
- [Author]. ([Year]). "[Title]." *[Source]*.
- [Author]. ([Year]). "[Title]." *[Source]*.
4.2 Section requirements checklist
- Title:
# ABBREV: Full Name+ memorable quote - Intro: 1 paragraph, key differentiator, measurable claims
- Historical Context: origin, knowledge gap, prior art, this impl's difference
- Architecture & Physics: numbered subsections per component, conditional math, z-domain transfer functions
- Mathematical Foundation: all derivations with LaTeX, parameter mappings
- Performance Profile: operation count table, SIMD analysis, quality metrics (1-10 scale)
- Validation: library comparison table with status + notes
- Common Pitfalls: 5-7 numbered items with quantified impacts
- References: academic/forum sources
4.3 Doc linking reqs when adding indicator
Update: lib/[category]/_index.md, lib/_index.md, docs/_sidebar.md, docs/integration.md, docs/indicators.md, docs/validation.md.
- TESTING PROTOCOL
REQ test files:
[Name].Tests.cs,[Name].Validation.Tests.cs,[Name].Quantower.Tests.cs. 5.2 Unit tests (xUnit)
- Data: MUST use
GBMhelper. NeverSystem.Random. - Required coverage buckets:
A) ctor validation (throws
ArgumentExceptionw/ ParamName) B) basic calc (Update returns TValue; Last/IsHot/Name accessible; known-value check) C) state + bar correction (critical): isNew true advances; isNew false rewrites; iterative corrections restore; Reset clears state + last-valid tracking D) warmup/convergence: IsHot flips when buffer full; WarmupPeriod period-dependent E) robustness (critical): NaN + Infinity use last-valid; batch NaN safe F) consistency (critical): BatchCalc == streaming == span == eventing (All 4 modes match) G) span API tests: validates lengths w/ ParamName; matches TSeries; handles NaN; avoid stack overflow large data H) chainability:Pubfires; event-based chaining works 5.3 Validation tests - Compare vs Skender.Stock.Indicators, TA-Lib (TALib.NETCore), Tulip (Tulip.NETCore), OoplesFinance.
- For each external lib: validate Batch + Streaming + Span where supported.
- Tolerances:
ValidationHelper.SkenderTolerance=1e-9;TalibTolerance=1e-9;TulipTolerance=1e-9;OoplesTolerance=1e-6. 5.4 Quantower adapter tests (req): Constructor defaults; MinHistoryDepths; Initialize creates internal indicator; ProcessUpdate historical/new; different OHLC source types. 5.5 Checklists - Mandatory unit tests include ctor validation, isNew behavior, iterative correction restore, Reset, IsHot warmup, NaN/Infinity handling, mode consistency, span validation.
- At least one full validation suite (Skender batch/stream/span) + Quantower minimal set.
- QUANTOWER ADAPTER 6.1 File locations
- Preferred: Place
[Name].Quantower.cs+[Name].Quantower.Tests.csinlib/[category]/[name]/alongside the indicator. - Alternative: Place in
quantower/[Category]/subdirectory (legacy pattern). - Both locations are auto-included in
quantower/Quantower.Tests.csproj.
6.2 Test project inclusion (automatic)
The quantower/Quantower.Tests.csproj includes:
<Compile Include="..\lib\**\*.Quantower.cs" />- all adapters from lib<Compile Include="..\lib\**\*.Quantower.Tests.cs" />- all adapter tests from lib<Compile Include="[Category]\*.cs" />- adapters from quantower folder per category<Compile Include="**\*.Tests.cs" />- all tests from quantower folder
6.3 Implementation requirements
- Inherit from Quantower's
Indicatorbase class. - Use
IndicatorExtensionshelpers for OHLC source mapping. - Implement
MinHistoryDepthsfor warmup period. - Handle both historical and streaming updates in
ProcessUpdate. - Use mocks from
quantower/Mocks/for unit tests.
6.4 Adding new adapter checklist
- Create
[Name].Quantower.cs(in lib or quantower folder) - Create
[Name].Quantower.Tests.cs(same folder as adapter) - Verify tests compile:
dotnet build quantower/Quantower.Tests.csproj - Run tests:
dotnet test quantower/Quantower.Tests.csproj --filter "[Name]" - Add to category-specific csproj if adapter in quantower folder (eg
quantower/Trends.csproj)
- WORKFLOW & TOOLS Tools:
- seq-think-mcp: decomposition/planning
- tavily-mcp: fresh API/lib info, .NET updates, perf patterns
- ref-tools-mcp: .NET docs, API specs, SIMD intrinsics
- wolfram-mcp: math validation
- git-mcp: codebase search + conventions
- qdrant-mcp: persist decisions/benchmarks/patterns (no secrets) Priority: ref-tools → tavily for .NET specifics; seq-think for complex; qdrant for context. Dev cycle (compact): 1 Recall(qdrant)→2 Analyze(profile)→3 Investigate(git+debug)→4 Research(ref-tools+tavily)→5 Plan(seq-think, STS)→6 Implement(C# 13, SIMD/Span/stackalloc, minimal comments, no regions, no XML in impl)→7 Debug(BenchmarkDotNet, codegen verify)→8 Test(edge cases)→9 Validate(correct+perf, store bench)→10 Memorize(qdrant JSON record). Git policy:
- No auto-commit; explicit user command only.
- Pre-commit: tests pass; verify no hotpath alloc; verify SIMD codegen.
Commit msg:
<type>: <imperative verb> <what> [scope]+ why + perf delta + refs + benchmarks. Types SET{feat|perf|fix|refactor|test|docs}. Comms: concise tech; bullets for lists; code blocks for examples; perf nums include baseline+optimized+%.
-
CONTEXT MGMT (qdrant) Store: arch decisions, benchmarks, proven patterns, deprecated approaches. Record format:
{decision, benchmark, pattern, src, date, tags}. Query strategy: Before/During/After work. Event flow (commitd7dbd70): ForITValuePublisherindicators: subscribe in ctor w/source.Pub += Handle;(don’t store source solely for subscription). Use struct-based event args (TBarEventArgs,TValueEventArgs). If MA0046 flags non-EventArgs signature, suppress locally w/ targeted pragma + perf rationale. -
REFERENCE (pitfalls + prohibitions + done criteria) Common pitfalls: LINQ in hot paths;
newinside Update; ignore NaN; inconsistent 4 API modes; missing ParamName inArgumentException; missing Quantower adapter/tests; forgettingdocs/validation.md; usingSystem.Randomin tests. Forbidden actions:
- DO NOT LINQ in Update/Calculate
- DO NOT
newinside Update - DO NOT change
Directory.Build.propsw/o explicit instruction - DO NOT remove
[SkipLocalsInit]/[MethodImpl] - DO NOT ignore NaN/Infinity
- DO NOT skip
[Name].Quantower.cs+[Name].Quantower.Tests.cs - DO NOT skip updating
docs/validation.mdDone checklist (condensed): Source verified (PineScript or equiv); C# 13 optimized; O(1) where possible; SIMD where possible; FMA in hot paths where applicable; all 6 files exist; Update handles isNew + NaN; Update alloc-free; Calculate(Span) implemented + ParamName validation; unit+validation+adapter tests pass; docs complete + markdownlint; all required indices updated; CodeRabbit issues resolved; benchmarks run + stored in qdrant.