- Implemented unit tests for the following indicators: - KAMA (Kaufman Adaptive Moving Average) - SMA (Simple Moving Average) - T3 (Tillson T3 Moving Average) - TEMA (Triple Exponential Moving Average) - TRIMA (Triangular Moving Average) - WMA (Weighted Moving Average) - Each test class includes tests for constructor defaults, history depth, short name, initialization, processing updates, and source type handling. - Updated the Quantower.Tests.csproj to include all new test files in the lib directory.
7.0 KiB
Good Indicator Guidelines
This document defines the strict standards for creating high-quality technical indicators in the QuanTAlib library. All new indicators MUST adhere to these rules to ensure consistency, performance, and reliability.
1. Architecture & Design Principles
- Zero Allocation: The core calculation loop must not allocate memory on the heap. Use
stackalloc,Span<T>, and pinned memory where possible. - O(1) Complexity: Streaming updates must be O(1) whenever mathematically possible. Use running sums/products or circular buffers to avoid re-iterating over history.
- Dual API: Provide both a stateful object-oriented API (
Update) and a stateless static vector API (Calculate). - Bar Correction: Support intra-bar updates via the
isNewparameter. The indicator must be able to rollback the last update and apply a new value for the same timestamp. - Robustness: Handle
NaNandInfinitygracefully using last-valid-value substitution. Never propagate invalid values. - Reactive: Implement
ITValuePublisherto support event-driven architectures.
2. File Structure
Each indicator resides in its own directory such as lib/trends/, lib/indicators/, or lib/oscillators/.
Directory: lib/[category]/[name]/
| File | Purpose | Naming Convention |
|---|---|---|
| Source | Main implementation | [Name].cs (e.g., Sma.cs) |
| Tests | Unit tests | [Name].Tests.cs |
| Validation | Cross-library validation | [Name].Validation.Tests.cs |
| Docs | User documentation | [Name].md |
| Quantower | Quantower adapter | [Name].Quantower.cs |
| Quantower Tests | Quantower adapter tests | [Name].Quantower.Tests.cs |
3. Implementation Rules ([Name].cs)
Class Definition
- Namespace:
QuanTAlib - Attributes:
[SkipLocalsInit]for performance. - Modifiers:
public sealed class - Interface: Implements
ITValuePublisher
State Management
- Use
RingBufferfor sliding window data. - Maintain separate state variables for the current calculation (
_sum,_lastVal) and the previous valid state (_p_sum,_p_lastVal) to supportisNew=falseupdates. - Resync: Implement a periodic full recalculation (e.g., every 1000 ticks) to prevent floating-point drift in running sums.
Constructor
- Validate all parameters (throw
ArgumentExceptionfor invalid values). - Initialize
Nameproperty (e.g.,$"Sma({period})"); - Support chaining:
public [Name](ITValuePublisher source, ...)
Update Method
- Signature:
public TValue Update(TValue input, bool isNew = true) - Attribute:
[MethodImpl(MethodImplOptions.AggressiveInlining)] - Logic:
- Input Validation: Check
double.IsFinite. If not, use_lastValidValue. - State Management:
- If
isNew=true: Save current state to_p_*variables, then update. - If
isNew=false: Restore state from_p_*variables, then update.
- If
- Calculation: Perform the math.
- Publish: Update
Lastproperty, invokePubevent, returnLast.
- Input Validation: Check
Update Method (TSeries)
- Signature:
public TSeries Update(TSeries source) - Placement: Must be adjacent to the
Update(TValue)method. - Logic:
- Create output series.
- Call static
Calculate(Span)for performance. - Restore internal state by replaying the last
Periodbars.
Static Calculate (TSeries)
- Create a new instance of the indicator.
- Iterate through the source series.
- Return the resulting
TSeries.
Static Calculate (Span) - Critical for Performance
-
Signature:
public static void Calculate(ReadOnlySpan<double> source, Span<double> output, ...) -
Attribute:
[MethodImpl(MethodImplOptions.AggressiveInlining)] -
Optimization:
-
Check for SIMD support (
Avx2.IsSupported). -
Use
stackallocfor small buffers (threshold ~256). -
Implement a scalar fallback path that handles
NaNsafely. -
Implement a SIMD path for large, clean datasets (optional but recommended for simple averages).
4. Testing Standards
Unit Tests ([Name].Tests.cs)
-
Framework: xUnit
-
Coverage:
-
Constructor validation (invalid params).
-
Basic calculation correctness (compare against manual calc).
-
isNew=truevsisNew=falsebehavior (bar correction). -
Reset()functionality. -
IsHotproperty behavior. -
NaN/Infinityhandling (must not crash, must return finite values). -
Consistency between Object API, Static TSeries API, and Static Span API.
-
Edge cases: Period=1, empty input, single input.
Validation Tests ([Name].Validation.Tests.cs)
-
Purpose: Verify accuracy against established libraries (Skender, TA-Lib, Tulip).
-
Data: Use
GBM(Geometric Brownian Motion) to generate realistic test data. -
Scenarios:
-
Batch processing.
-
Streaming processing.
-
Span/Vector processing.
-
Tolerance: Typically
1e-6or1e-9depending on the algorithm.
5. Documentation Standards ([Name].md)
Follow the standard template and ensure strict adherence to Markdownlint rules, specifically:
- MD030: Ensure exactly one space after list markers (e.g.,
* Item, not*Itemor* Item). - MD032: Ensure lists are surrounded by blank lines (one blank line before the first item and one after the last item).
Template structure:
- Title & Overview: What is it? What does it do?
- Core Concepts: Key features (e.g., equal weighting, noise reduction).
- Parameters: Table of constructor parameters.
- Formula: LaTeX formatted math (
...). - C# Implementation: Code examples for:
- Standard usage.
- Span API (high performance).
- Bar correction (
isNew). - Eventing.
- Interpretation: How to use it in trading.
- References: Books or papers.
6. Performance Guidelines
- Inlining: Use
[MethodImpl(MethodImplOptions.AggressiveInlining)]on all hot path methods (Update,Calculate). - Locals Init: Use
[SkipLocalsInit]on the class to skip zero-initialization of locals. - Loops: Prefer
forloops overforeachfor arrays/spans. - Math: Use
System.MathorSystem.Numerics. Avoid LINQ in hot paths. - Memory: NEVER use
newinside theUpdatemethod. Pre-allocate everything in the constructor.
7. Checklist for New Indicators
- File Structure: Created all 6 required files?
- Constructor: Validates inputs? Sets
Name? - Update: Handles
isNewcorrectly? HandlesNaN? O(1)? - Static API: Implemented
Calculate(Span)? - Tests: Unit tests pass?
NaNtests included? - Validation: Matches external libraries (Skender/TA-Lib)?
- Docs: Markdown file created with formula and examples?
- Quantower: Adapter created in
[Name].Quantower.cs? - Quantower Tests: Adapter tests created in
[Name].Quantower.Tests.cs? - Index: Added to category
_index.mdwith link and description? - Performance: No allocations in
Update?[SkipLocalsInit]used?