10 KiB
AGENTS.md - QuanTAlib Protocol
To all AI Agents: This file defines the laws, physics, and protocols of the QuanTAlib repository. Read this before writing a single line of code. Failure to adhere to these standards will result in rejected code.
1. Identity & Mission
QuanTAlib is a high-performance, zero-allocation C# library for quantitative technical analysis.
- Target: Quantower and custom C# trading engines.
- Core Philosophy: Speed, Correctness, and Memory Efficiency.
- Key Constraint: Hot paths must be allocation-free (GC pressure is the enemy).
2. Architecture & "Physics"
Memory Model: Structure of Arrays (SoA)
We do not store objects in lists. We store primitive arrays.
- TSeries: Internally uses
List<long> _t(timestamps) andList<double> _v(values). - Access: Expose data via
ReadOnlySpan<double>for SIMD operations.
Core Types
TValue: Struct (16 bytes).DateTime Time,double Value.TBar: Struct (48 bytes).DateTime Time,double Open, High, Low, Close, Volume.TSeries: The primary data structure for time series.ITValuePublisher: The interface for reactive data flow.
Design Principles
- Source Material: The algorithm and markdown documentation foundation should be sourced from https://github.com/mihakralj/pinescript/blob/main/indicators/.
- 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. - Time Handling: Always use
DateTime.UtcNowinstead ofDateTime.Nowto ensure consistent time handling across timezones.
Performance Rules
- Zero Allocation: The
Updatemethod MUST NOT allocate memory on the heap. Usestackallocor pre-allocated buffers. - O(1) Complexity: Streaming updates must be constant time. Use circular buffers (
RingBuffer) or running sums. - SIMD: Batch operations (
Calculate) should useSystem.Runtime.Intrinsics(AVX2) where possible. If SIMD is not possible due to recursive dependencies, usestackallocfor internal buffers to avoid heap allocations. - Inlining: Use
[MethodImpl(MethodImplOptions.AggressiveInlining)]on hot methods. - Locals: Use
[SkipLocalsInit]to avoid zero-init costs in tight loops.
3. Indicator Implementation Standards
Every indicator must follow the Good Indicator Guidelines strictly.
File Structure
Directory: lib/[category]/[name]/ (e.g., lib/trends/sma/)
| File | Naming | Purpose |
|---|---|---|
| Source | [Name].cs |
Main implementation. public sealed class. |
| Tests | [Name].Tests.cs |
xUnit tests (correctness, edge cases). |
| Validation | [Name].Validation.Tests.cs |
Compare against TA-Lib, Skender, etc. |
| Docs | [Name].md |
User documentation with formulas. |
| Adapter | [Name].Quantower.cs |
Quantower platform integration. |
| Adapter Tests | [Name].Quantower.Tests.cs |
Tests for the adapter. |
Class Definition
- Namespace:
QuanTAlib - Attributes:
[SkipLocalsInit]for performance. - Modifiers:
public sealed class - Interface: Implements
ITValuePublisher
State Management
- Scalar State: Use a
private record struct Stateto group all scalar state variables. This ensures value semantics, automaticIEquatableimplementation, and cleaner rollback logic. - State Variables: Maintain
private State _state;(current) andprivate State _p_state;(previous valid state). - Buffers: Use
RingBufferfor sliding window data. - 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, ...)
The Update Method Contract
The Update method is the heart of the indicator.
public TValue Update(TValue input, bool isNew = true)
- Attribute:
[MethodImpl(MethodImplOptions.AggressiveInlining)] - Logic:
-
State Rollback:
if (isNew) { _p_state = _state; // ... update state (e.g. counters) ... } else { _state = _p_state; // ... update state ... } -
Input Validation: Check
double.IsFinite. If not, use_lastValidValue(stored inState). -
Calculation: Perform the math.
-
Publish: Update
Lastproperty, invokePubevent, returnLast.
-
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 (or full series if recursive).
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) and for internal state buffers in recursive algorithms where SIMD is not applicable. - Implement a scalar fallback path that handles
NaNsafely. - Implement a SIMD path for large, clean datasets (optional but recommended for simple averages).
- Check for SIMD support (
4. Testing Protocol
Unit Tests ([Name].Tests.cs)
- Framework: xUnit
- Data Generation: Use
GBM(Geometric Brownian Motion) for generating realistic test data. Avoid usingSystem.Randomdirectly. - 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)
- Mandatory: You MUST validate against at least one external authority (TA-Lib, Skender, Tulip, OoplesFinance, Python libs).
- Tolerance: Typically
1e-6to1e-9. - Data: Use
ValidationTestDataclass which wrapsGBM(Geometric Brownian Motion) to generate realistic test data and provides pre-calculated Skender quotes.
External Library Usage Guide
-
Skender.Stock.Indicators:
- Use
_data.SkenderQuotes.Get[Indicator](...). - Compare using
ValidationHelper.VerifyData.
- Use
-
TA-Lib (TALib.NETCore):
- Namespace:
using TALib; - Method:
TALib.Functions.[Indicator]<double>(...). - Check
Assert.Equal(Core.RetCode.Success, retCode). - Use
ValidationHelper.VerifyDatawithoutRangeandlookback.
- Namespace:
-
Tulip (Tulip.NETCore):
- Namespace:
using Tulip; - Method:
Tulip.Indicators.[indicator].Run(...). - Handle lookback/offset manually (Tulip output is shorter than input).
- Use
ValidationHelper.VerifyDatawithlookback.
- Namespace:
-
OoplesFinance.StockIndicators:
- Namespace:
using OoplesFinance.StockIndicators; - Convert data:
_data.SkenderQuotes.Select(q => new TickerData { ... }).ToList(). - Use
new StockData(ooplesData).Calculate[Indicator](...). - Compare using
ValidationHelper.VerifyData.
- Namespace:
5. Documentation Standards
- Format: Markdown.
- Content: Title, Description, Parameters, Formula (LaTeX), C# Usage Examples.
- Index: Add the new indicator to the category index (e.g.,
lib/trends/_index.md). - Linting: Ensure that markdownlint shows no issues for the file.
- MD030: Ensure exactly one space after list markers.
- MD032: Ensure lists are surrounded by blank lines.
6. Quantower Adapter
- Implementation: Create a wrapper class in
[Name].Quantower.csthat adapts the QuanTAlib indicator for the Quantower platform. - Tests: Create unit tests in
[Name].Quantower.Tests.csto verify the adapter's functionality using mocks where necessary.
7. Code Review
- Tool: Run CodeRabbit on the changes.
- Requirement: Address and fix ALL issues identified by the CodeRabbit review before considering the task complete.
8. Development Checklist
When creating a new indicator, you are DONE only when:
- Source algorithm is verified.
- All 6 required files exist.
UpdatehandlesisNewandNaNcorrectly.- No heap allocations in
Update. - Static
Calculate(Span)is implemented. - Unit tests pass (including edge cases).
- Validation tests pass against external libs.
- Documentation is complete and linked in
_index.md. - Quantower adapter and tests are implemented.
- CodeRabbit review issues are resolved.
9. Forbidden Actions
- DO NOT use LINQ in hot paths (
UpdateorCalculate). - DO NOT use
newinsideUpdate. - DO NOT change
Directory.Build.propswithout explicit instruction. - DO NOT remove
[SkipLocalsInit]or[MethodImpl]attributes. - DO NOT ignore
NaNinputs; handle them safely.
10. Context & Resources
- Time: Use
DateTime.UtcNow. - Math: Use
System.MathorSystem.Numerics. - Root Namespace:
QuanTAlib.