This commit is contained in:
Miha Kralj
2025-12-18 13:51:06 -08:00
parent 5d03dec741
commit 35e5571237
41 changed files with 2505 additions and 1617 deletions
+85
View File
@@ -208,6 +208,91 @@ Example: "We implement every indicator as streaming algo maintaining O(1) comput
**Performance Data:** Include test env specs, sample size, comparison baseline, statistical significance
## MARKDOWN LINTING RULES
Strict adherence to the following rules is required to ensure clean, consistent rendering:
- **MD022 (Headers)**: Headers must be surrounded by blank lines.
- *Incorrect*:
```markdown
# Header
Text
```
- *Correct*:
```markdown
# Header
Text
```
- **MD030 (List Spacing)**: Exactly one space after list markers.
- *Incorrect*: `* Item` or `*Item`
- *Correct*: `* Item`
- **MD032 (Lists)**: Lists must be surrounded by blank lines.
- *Incorrect*:
```markdown
Text
* Item 1
* Item 2
Text
```
- *Correct*:
```markdown
Text
* Item 1
* Item 2
Text
```
- **MD012 (Multiple Blank Lines)**: No multiple consecutive blank lines.
- *Incorrect*:
```markdown
Text
Text
```
- *Correct*:
```markdown
Text
Text
```
- **MD031 (Code Blocks)**: Fenced code blocks must be surrounded by blank lines.
- *Incorrect*:
```markdown
Text
```csharp
code
```
Text
```
- *Correct*:
```markdown
Text
```csharp
code
```
Text
```
## FINAL PRINCIPLES
1. Uncompromising standards, kind about people
+41 -172
View File
@@ -15,173 +15,15 @@ TA libraries face a fundamental choice: accept approximations for simplicity OR
**Quan**titative **TA** **lib**rary (QuanTAlib) is a C# library built on the premise that you shouldn't have to choose. Modern CPUs process 4-8 FLOPS per cycle via SIMD. Modern .NET exposes memory layouts making hardware acceleration trivial. QuanTAlib exploits both. **Result:** mathematically rigorous indicators at speeds making real-time multi-symbol analysis practical on ordinary hardware.
## What You Get
## Key Features
QuanTAlib provides technical indicators organized into mathematical families, often found in common charting software. Understanding these families helps choose the right tool for the analytical problem you're actually solving.
- **Zero Allocation**: Hot paths are allocation-free. No GC pauses during trading.
- **SIMD Accelerated**: Uses AVX2/AVX-512 for 8x throughput on modern CPUs.
- **O(1) Streaming**: Constant time updates regardless of lookback period.
- **Platform Agnostic**: Runs on .NET 8/9/10, compatible with Quantower, NinjaTrader, QuantConnect.
- **Mathematically Rigorous**: Validated against original research papers and established libraries.
### [All Available Indicators](/_index.md)
| Category | What It Measures | Representative Indicators | When You Need It |
|----------|------------------|---------------------------|------------------|
| [**Trends**](trends/_index.md) | Direction and strength of price movement through smoothing and filtering | Simple Moving Average, Exponential Moving Aaverage, Weighted Moving Average, Hull Moving Average, Jurik Moving Average, Kaufmann Adaptive Moving Average | Starting point for most analysis. If you're looking at a chart, you're probably using at least one moving average. The simpler variants (SMA, EMA) work for trend identification. The exotic ones (Jurik, Ehlers) trade CPU cycles for reduced lag. It's a fair exchange — silicon is cheap, timing is expensive. |
| [**Volatility**](volatility/_index.md) | Size and variability of price movements | Average True Range, Standard Deviation, Bollinger Bands, Keltner Channels, Historical Volatility | Position sizing, stop-loss placement, and understanding market regime. ATR tells you how much instruments typically move—essential for risk management. Bollinger Bands show when volatility expands or contracts, helping identify potential breakouts or mean-reversion opportunities. |
| [**Momentum**](momentum/_index.md) | Speed and magnitude of price changes | Relative Strength Index, Stochastic, CCI, Williams %R, MACD, Momentum, ROC | Identifying overbought/oversold conditions and divergences. RSI oscillates between 0-100 by construction—it's the ratio of average gains to average losses. MACD compares two EMAs to show changes in trend strength. These get overused but remain useful when combined with other analysis. |
| [**Volume**](volume/_index.md) | Trading activity and price-volume relationships | OBV, VWAP, Volume Rate of Change, Accumulation/Distribution, MFI | Confirming price movements with volume participation. VWAP shows where institutional traders executed—prices far from VWAP suggest pressure in one direction. OBV accumulates volume on up days and subtracts it on down days, revealing whether volume confirms price trends. |
| [**Channels**](channels/_index.md) | Price boundaries and range definitions | Donchian Channels, Keltner Channels, Price Channels | Breakout strategies and range-bound trading. Donchian Channels mark highest high and lowest low over a period—breaks above/below suggest potential trend changes. Keltner uses ATR for volatility-adjusted bands. Less common than Bollinger Bands but useful for different trading styles. |
| [**Statistics**](statistics/_index.md) | Mathematical relationships between price series | Correlation, Covariance, Beta, Z-Score, Linear Regression | Portfolio analysis, pairs trading, and statistical arbitrage. Correlation measures how two instruments move together (ranging from -1 to +1). Beta quantifies systematic risk relative to a benchmark. Z-Score normalizes values for statistical comparison. These require understanding basic statistics to use correctly. |
| [**Numerics**](numerics/_index.md) | Mathematical transformations and signal processing | Convolution, Filters, Integration, Differentiation, Smoothing functions | Custom indicator development and advanced signal processing. This is the toolkit you use to build your own indicators rather than indicators you apply directly. Convolution lets you create custom filters. Differentiation extracts rate of change. Toolkit for building indicators rather than using them. If you need to differentiate a signal before smoothing it, you know who you are. If not, safe to ignore. |
| [**Errors**](errors/_index.md) | Measurement accuracy and model fit quality | MAE (Mean Absolute Error), RMSE, Residuals, R-Squared | Model validation and forecast quality assessment. After building a predictive model or regression, these metrics tell you how wrong you are on average. RMSE penalizes large errors more heavily than MAE. R-Squared explains what percentage of variance your model captures. Critical for anyone building quantitative strategies. |
| [**Forecasts**](forecasts/_index.md) | Future price prediction and projection | Linear Regression Forecast, Moving Average Projection, Trend Extrapolation | Predictive modeling and systematic strategy development. These attempt to project where prices will go based on historical patterns. Projects price based on historical patterns. Works beautifully until market changes regime, usually 5 minutes after you deploy capital. Useful as inputs to larger systems, dangerous when used as sole decision criteria. |
| [**Cycles**](cycles/_index.md) | Periodic patterns and dominant frequencies in price data | Hilbert Transform, Dominant Cycle, Instantaneous Phase, Sine Wave, MESA | Identifying and trading cyclical market behavior. John Ehlers (who apparently decided financial markets could be analyzed like electrical signals) developed most of these. They use signal processing techniques to decompose price into cycle components. They work beautifully when markets are cyclical. They work poorly when markets trend or trade randomly. The math is complex—phase relationships, frequency analysis—and knowing which market regime you're in becomes harder than using the indicators themselves. |
The categories aren't rigid boundaries—many indicators could fit multiple categories. KAMA is both a trend indicator and uses momentum calculations. Keltner Channels combine trends (moving average centerline) with volatility (ATR bands). The organization helps you understand what analytical problem each indicator solves rather than memorizing which arbitrary category someone assigned it to.
Start with Trends, Volatility, and Momentum if you're new to technical analysis. These provide the foundation most traders need. The specialized categories (Numerics, Errors, Forecasts, Cycles) solve specific problems you'll recognize when you encounter them.
## The Architecture That Makes This Possible
Three design decisions define QuanTAlib's performance characteristics:
**Structure of Arrays (SoA) memory layout** stores timestamps and values in separate contiguous arrays rather than interleaving them. This seemingly minor change enables direct SIMD vectorization—CPU processes eight values in a single instruction instead of one at a time. The performance difference is measurable: averaging 10,000 values takes 2.4μs with SIMD versus 18.7μs with scalar operations. That's an 8x improvement just from rearranging memory.
**O(1) streaming algorithms** maintain constant computational complexity per incoming data point regardless of lookback period. A 14-period RSI and a 200-period RSI both process new bars in 0.4μs. Traditional batch recalculation approaches scale linearly with period length, introducing variable latency that makes real-time processing unpredictable. QuanTAlib accepts higher memory overhead (40-60 bytes per indicator instance) to guarantee predictable timing when processing hundreds of symbols simultaneously.
**Explicit initialization handling** returns meaningful values from the first bar while exposing confidence through the `IsHot` property. A 14-period SMA calculates results starting at bar 1 using whatever data is available—the math to calculate averages works with limited history, just not at full precision for a period of 14. Other libraries either hide these early values (returning NaN or null) or output numbers without indicating their veracity. QuanTAlib returns usable values immediately and sets `IsHot = true` when the indicator has accumulated enough data to guarantee correctness of results. Bar 1-13 gives you working SMA values based on partial history. Bar 14 onwards gives you high-confidence results with complete mathematical foundation. Developer can use early indicator values as needed while knowing exactly when the indicator reaches full reliability.
These aren't novel inventions. They're established techniques from numerical computing applied to financial indicators. The architecture is straightforward once you decide that correctness and performance aren't trade-offs.
### Four Operating Modes for Different Requirements
Trading systems have different needs. Backtesting engines process years of historical data in batch. Real-time systems update indicators bar-by-bar as new data arrives. Event-driven architectures react to indicator changes asynchronously. QuanTAlib provides four modes optimized for these distinct patterns.
#### Span Mode: Direct Memory Operations
Operates directly on `Span<double>` without allocating objects. You provide raw arrays, QuanTAlib returns calculated arrays. Zero garbage collection pressure, maximum speed, minimal abstraction. This mode exists for one purpose: processing large datasets as fast as physically possible on current hardware.
**When to use:** Batch processing historical data, backtesting engines, research environments where you're calculating thousands of indicators across years of data. If you're profiling your system and indicator calculations appear in the trace, switch to Span mode.
**Trade-off:** No metadata, no time alignment, no validation. You manage memory, handle edge cases, and ensure your input arrays match in length. The performance gain justifies the responsibility.
#### Batch Mode: TSeries Objects
Wraps calculations in TSeries objects that maintain timestamps, handle array resizing, and provide time-based indexing. You add price data with timestamps, QuanTAlib returns a time-aligned series with metadata. This is Span mode with a protective wrapper that handles the tedious details.
**When to use:** Historical analysis where you want time alignment without sacrificing too much performance. Research notebooks, strategy prototyping, exploratory analysis. The 2-3x performance cost compared to Span mode is negligible when you're processing data once and analyzing results interactively.
**Trade-off:** Memory overhead from TSeries objects (16 bytes per value for timestamp-value pairs) and 2-3x slower than Span due to bounds checking and metadata management. Still faster than most libraries' fastest mode.
#### Streaming Mode: Real-Time Updates
Processes one bar at a time, maintaining internal state between updates. Call `Update(TValue, isNew)` with each new price, get the current indicator value. The `isNew` parameter distinguishes between new bars and updates to the current bar (handling the common pattern where the last bar's values change as new ticks arrive).
**When to use:** Live trading systems, real-time charting, tick-by-tick analysis. Any scenario where data arrives sequentially and you need immediate results. This is the natural mode for production trading systems that can't wait for batch processing.
**Trade-off:** Higher per-calculation cost (2-6x slower than Span) due to state management and single-value processing overhead. The flip side: predictable latency regardless of lookback period, which matters more in real-time systems than raw throughput.
#### Eventing Mode: Reactive Architectures
Extends streaming mode with full event infrastructure. Indicators raise events when values change, when warmup completes (`IsHot`), or when significant conditions occur. Build reactive chains where one indicator's output triggers another's calculation, creating complex analytical pipelines that respond to market conditions.
**When to use:** Complex trading systems with conditional logic ("calculate indicator B only when indicator A crosses threshold X"), risk management systems that react to volatility changes, or any architecture where indicators need to communicate state changes rather than just return values.
**Trade-off:** Event infrastructure adds 5-15x overhead compared to Span mode. You're paying for flexibility—the ability to build sophisticated reactive systems without manually checking every indicator's state on every update. Whether this cost is worth it depends on your architecture's complexity.
#### Choosing the Right Mode
The performance hierarchy is clear: **Span** > **Batch** > **Streaming** > **Eventing**. But faster isn't always better. A backtesting engine running historical analysis benefits from Span mode's raw speed. A live trading system needs Streaming mode's state management even though it's slower. An event-driven risk system justifies Eventing mode's overhead for the architectural benefits.
Most systems use multiple modes: Span or Batch for historical analysis and strategy validation, Streaming for live trading. The modes share identical mathematical implementations — you get the same calculated results regardless of mode. The difference is how you interact with the calculation, not what gets calculated.
## The Evidence
Performance claims require measurement. We benchmark QuanTAlib against established libraries: TA-Lib and Tulip (industry-standard C libraries accessed via P/Invoke), Skender.Stock.Indicators and Ooples.FinancialIndicators (popular .NET implementations).
All benchmark tests process 500,000 bars with period 220 — sufficient scale to expose algorithmic inefficiencies and realistic parameters for practical analysis.
**Test environment:** .NET 10.0 with AOT compilation on hardware supporting AVX-512 instructions. These results represent what current-generation server CPUs achieve in production.
### Simple Moving Average (SMA)
QuanTAlib's Span mode calculates 500,000 SMA values in 318 microseconds with zero memory allocations. That's 0.64 nanoseconds per value. For context, a single L1 cache access takes approximately 1 nanosecond on modern CPUs — we're calculating moving averages faster than fetching data from the nearest cache level.
| Library | Mean Time | Allocations | Relative Speed |
|---------|-----------|-------------|----------------|
| **QuanTAlib (Span)** | **318.3 μs** | **0 B** | **1.00x (baseline)** |
| TA-Lib | 356.4 μs | 34 B | 1.12x slower |
| Tulip | 359.3 μs | 0 B | 1.13x slower |
| Skender | 71,277 μs | 50.8 MB | 224x slower |
| Ooples | 500,793 μs | 151 MB | 1,573x slower |
### Exponential Moving Average (EMA)
QuanTAlib matches C library performance at 711 microseconds — within measurement error of Tulip's 708μs and TA-Lib's 713μs. Pure C# matching heavily optimized C code demonstrates what modern .NET achieves when you align memory layouts with hardware capabilities.
| Library | Mean Time | Allocations | Relative Speed |
|---------|-----------|-------------|----------------|
| **QuanTAlib (Span)** | **711.0 μs** | **0 B** | **1.00x** |
| TA-Lib | 712.9 μs | 36 B | 1.00x slower |
| Tulip | 708.1 μs | 0 B | 1.00x faster |
| Skender | 31,393 μs | 50.8 MB | 44x slower |
| Ooples | 18,860 μs | 79.3 MB | 27x slower |
### Weighted Moving Average (WMA)
QuanTAlib's WMA beats both C libraries — 296 microseconds versus Tulip's 372μs and TA-Lib's 360μs. This isn't a measurement error. Pure C# with proper SIMD vectorization outperforms C code that predates AVX-512 optimizations.
| Library | Mean Time | Allocations | Relative Speed |
|---------|-----------|-------------|----------------|
| **QuanTAlib (Span)** | **296.0 μs** | **0 B** | **1.00x (baseline)** |
| TA-Lib | 360.0 μs | 34 B | 1.22x slower |
| Tulip | 372.1 μs | 0 B | 1.26x slower |
| Skender | 103,254 μs | 50.8 MB | 349x slower |
| Ooples | 73,983 μs | 70.9 MB | 250x slower |
### Hull Moving Average (HMA)
HMA requires multiple moving average calculations — traditionally expensive. QuanTAlib processes 500,000 bars in 1,008 microseconds. Tulip takes 2,266 microseconds. Skender requires 251,694 microseconds. (TALib doesn't include HMA calculation) That's a 2.25x improvement over optimized C and a 250x improvement over standard .NET implementations.
| Library | Mean Time | Allocations | Relative Speed |
|---------|-----------|-------------|----------------|
| **QuanTAlib (Span)** | **1,007.8 μs** | **0 B** | **1.00x (baseline)** |
| TA-Lib | -- | -- | -- |
| Tulip | 2,266.0 μs | 152 B | 2.25x slower |
| Skender | 251,694 μs | 235.9 MB | 250x slower |
| Ooples | 123,234 μs | 108.7 MB | 122x slower |
### Zero-Allocation Execution
Notice the allocation column. QuanTAlib's Span mode allocates zero bytes during calculation. No garbage collection pauses, no memory pressure, no non-deterministic latency spikes. When processing thousands of indicators across hundreds of symbols, this matters — system's behavior becomes predictable.
### Multiple Operating Modes Performance
The benchmarks above show Span mode. Here's how all four modes compare using EMA as representative:
| QuanTAlib Mode | Mean Time | Allocations | Use Case |
|----------------|-----------|-------------|----------|
| Span | 711.0 μs | 0 B | Maximum speed, batch processing |
| Streaming | 721.9 μs | 44 B | Real-time updates, minimal overhead |
| Batch (TSeries) | 1,311.7 μs | 8.0 MB | Time-aligned series with metadata |
| Eventing | 2,928.4 μs | 16.8 MB | Reactive architectures with event infrastructure |
Even QuanTAlib's slowest mode (Eventing with complete event infrastructure and 16MB of allocations) processes 500,000 EMA values in 3 milliseconds — faster than Ooples' 19 milliseconds and Skender's 31 milliseconds for the same calculation.
### What This Means Practically
Processing 100 symbols with 20 indicators each in streaming mode requires approximately 15ms total computation time per bar update. System will spend more time deserializing market data from network protocols than calculating indicators.
The numbers reveal something important: QuanTAlib isn't just fast for a C# library. It's competitive with heavily optimized C implementations and exceeds them when the algorithm benefits from modern SIMD instructions that those C libraries haven't been updated to use.
Correctness matters more than speed. Every indicator is validated against the original research papers and cross-checked with established libraries. When implementations disagree, differences are documented. For example, Wilder's original RSI specification differs slightly from the TA-Lib implementation — we follow Wilder's 1978 paper and note where other libraries made different choices.
## Practical Considerations
QuanTAlib works with [Quantower](https://www.quantower.com/), NinjaTrader, QuantConnect, and other C#-based trading platforms. The library targets .NET 8.0, 9.0, and 10.0. SIMD acceleration requires hardware with AVX or SSE support, which includes essentially every processor manufactured since 2011. The performance improvements are substantial enough that running on hardware without SIMD support means accepting 5-8x slower execution.
Memory usage scales with the number of active indicators and their lookback periods. A typical setup (20-30 indicators across 100 symbols) requires approximately 50MB. This fits comfortably in L3 cache on modern CPUs, enabling the high-speed memory access patterns that make O(1) streaming performance possible.
Each indicator includes unit tests for edge cases (insufficient data, NaN inputs, zero-length series) and validation tests comparing results against reference implementations. When you find a bug—and you will, because all software has bugs—the test infrastructure makes fixes verifiable and prevents regressions.
## Getting Started
## Quick Start
Install from NuGet:
@@ -189,13 +31,40 @@ Install from NuGet:
dotnet add package QuanTAlib
```
Start with the simpler indicators (EMA, RSI, BBANDS) to understand the streaming model. The exotic stuff (Jurik dark arts indicators, Ehlers arcane magic calculations) can wait until you need them and understand them.
Calculate an SMA in real-time:
## Contributing
```csharp
using QuanTAlib;
Contributions that add indicators, improve performance, or fix bugs are welcome. Each indicator should include:
var sma = new Sma(period: 14);
double price = 100.0;
1. Core implementation maintaining O(1) streaming complexity if possible
2. Unit tests covering edge cases and initialization behavior
3. Validation tests against at least one reference library (TA-Lib, Tulip, Skender Indicators)
4. Documentation with mathematical formulas and parameter guidance
// Update with new price
var result = sma.Update(new TValue(DateTime.UtcNow, price));
if (result.IsHot)
{
Console.WriteLine($"SMA: {result.Value}");
}
```
## Performance Snapshot
QuanTAlib is designed for speed. Here is how it compares calculating a 500,000 bar SMA against other libraries:
| Library | Mean Time | Allocations | Relative Speed |
|---------|-----------|-------------|----------------|
| **QuanTAlib (Span)** | **318.3 μs** | **0 B** | **1.00x (baseline)** |
| TA-Lib | 356.4 μs | 34 B | 1.12x slower |
| Tulip | 359.3 μs | 0 B | 1.13x slower |
| Skender | 71,277 μs | 50.8 MB | 224x slower |
*See [Benchmarks](docs/BENCHMARKS.md) for full details and methodology.*
## Documentation
- [**Architecture**](docs/ARCHITECTURE.md): Learn about SoA layout, SIMD, and design philosophy.
- [**Indicators**](docs/INDICATORS.md): Full catalog of available indicators and their mathematical families.
- [**Usage Guides**](docs/USAGE.md): Detailed patterns for Span, Streaming, Batch, and Eventing modes.
- [**Integration**](docs/INTEGRATION.md): Setup guides for Quantower, NinjaTrader, and QuantConnect.
- [**Benchmarks**](docs/BENCHMARKS.md): Detailed performance evidence and test methodology.
+66
View File
@@ -0,0 +1,66 @@
# Architecture
QuanTAlib is built on a specific set of architectural decisions designed to maximize performance on modern hardware while maintaining mathematical correctness.
## Three Core Decisions
Three design decisions define QuanTAlib's performance characteristics:
### 1. Structure of Arrays (SoA) Memory Layout
We store timestamps and values in separate contiguous arrays rather than interleaving them in objects. This seemingly minor change enables direct SIMD vectorization—CPU processes eight values in a single instruction instead of one at a time. The performance difference is measurable: averaging 10,000 values takes 2.4μs with SIMD versus 18.7μs with scalar operations. That's an 8x improvement just from rearranging memory.
### 2. O(1) Streaming Algorithms
We maintain constant computational complexity per incoming data point regardless of lookback period. A 14-period RSI and a 200-period RSI both process new bars in 0.4μs. Traditional batch recalculation approaches scale linearly with period length, introducing variable latency that makes real-time processing unpredictable. QuanTAlib accepts higher memory overhead (40-60 bytes per indicator instance) to guarantee predictable timing when processing hundreds of symbols simultaneously.
### 3. Explicit Initialization Handling
We return meaningful values from the first bar while exposing confidence through the `IsHot` property. A 14-period SMA calculates results starting at bar 1 using whatever data is available—the math to calculate averages works with limited history, just not at full precision for a period of 14. Other libraries either hide these early values (returning NaN or null) or output numbers without indicating their veracity. QuanTAlib returns usable values immediately and sets `IsHot = true` when the indicator has accumulated enough data to guarantee correctness of results.
## Four Operating Modes
Trading systems have different needs. Backtesting engines process years of historical data in batch. Real-time systems update indicators bar-by-bar as new data arrives. Event-driven architectures react to indicator changes asynchronously. QuanTAlib provides four modes optimized for these distinct patterns.
### Span Mode: Direct Memory Operations
Operates directly on `Span<double>` without allocating objects. You provide raw arrays, QuanTAlib returns calculated arrays. Zero garbage collection pressure, maximum speed, minimal abstraction. This mode exists for one purpose: processing large datasets as fast as physically possible on current hardware.
**When to use:** Batch processing historical data, backtesting engines, research environments where you're calculating thousands of indicators across years of data.
### Batch Mode: TSeries Objects
Wraps calculations in TSeries objects that maintain timestamps, handle array resizing, and provide time-based indexing. You add price data with timestamps, QuanTAlib returns a time-aligned series with metadata. This is Span mode with a protective wrapper that handles the tedious details.
**When to use:** Historical analysis where you want time alignment without sacrificing too much performance. Research notebooks, strategy prototyping, exploratory analysis.
### Streaming Mode: Real-Time Updates
Processes one bar at a time, maintaining internal state between updates. Call `Update(TValue, isNew)` with each new price, get the current indicator value. The `isNew` parameter distinguishes between new bars and updates to the current bar (handling the common pattern where the last bar's values change as new ticks arrive).
**When to use:** Live trading systems, real-time charting, tick-by-tick analysis. Any scenario where data arrives sequentially and you need immediate results.
### Eventing Mode: Reactive Architectures
Extends streaming mode with full event infrastructure. Indicators raise events when values change, when warmup completes (`IsHot`), or when significant conditions occur. Build reactive chains where one indicator's output triggers another's calculation, creating complex analytical pipelines that respond to market conditions.
**When to use:** Complex trading systems with conditional logic, risk management systems that react to volatility changes, or any architecture where indicators need to communicate state changes rather than just return values.
## Memory Layout Details
The library uses a Structure of Arrays (SoA) approach for its core data structures.
- **TSeries**: Internally maintains two `List<T>` collections:
- `List<long> _t`: Timestamps (ticks)
- `List<double> _v`: Values
- **Access**: Data is exposed via `ReadOnlySpan<double>` properties, allowing zero-copy access to the underlying memory for SIMD operations.
This layout is cache-friendly. When calculating an average, the CPU loads a cache line filled entirely with values, without wasting space on interleaved timestamps or object headers.
## SIMD Implementation
QuanTAlib leverages .NET's `System.Runtime.Intrinsics` to access hardware-specific instructions (AVX2, AVX-512).
- **Vectorization**: Operations like summation, min/max finding, and element-wise arithmetic are vectorized.
- **Fallback**: The library checks for hardware support at runtime. If AVX2 is not available, it falls back to scalar implementations, ensuring compatibility with older hardware (though at reduced speed).
- **Zero-Allocation**: SIMD operations are performed on `Span<T>` and `ReadOnlySpan<T>`, ensuring no heap allocations occur during the calculation phase.
## Design Philosophy
1. **Correctness First**: We validate against original research papers and established libraries.
2. **Performance by Default**: We choose algorithms and data structures that are naturally fast.
3. **No Hidden Allocations**: Hot paths are allocation-free to prevent GC pauses.
4. **Transparency**: We expose the internal state (like `IsHot`) so you know exactly what the indicator is doing.
+105
View File
@@ -0,0 +1,105 @@
# Benchmarks
Performance claims require measurement. We benchmark QuanTAlib against established libraries: TA-Lib and Tulip (industry-standard C libraries accessed via P/Invoke), Skender.Stock.Indicators and Ooples.FinancialIndicators (popular .NET implementations).
## Test Environment
- **Framework**: .NET 10.0 with AOT compilation
- **Hardware**: Modern CPU supporting AVX-512 instructions
- **Data**: 500,000 bars
- **Parameters**: Period 220 (sufficient scale to expose algorithmic inefficiencies)
These results represent what current-generation server CPUs achieve in production.
## Benchmark Results
### Simple Moving Average (SMA)
QuanTAlib's Span mode calculates 500,000 SMA values in 318 microseconds with zero memory allocations. That's 0.64 nanoseconds per value. For context, a single L1 cache access takes approximately 1 nanosecond on modern CPUs — we're calculating moving averages faster than fetching data from the nearest cache level.
| Library | Mean Time | Allocations | Relative Speed |
|---------|-----------|-------------|----------------|
| **QuanTAlib (Span)** | **318.3 μs** | **0 B** | **1.00x (baseline)** |
| TA-Lib | 356.4 μs | 34 B | 1.12x slower |
| Tulip | 359.3 μs | 0 B | 1.13x slower |
| Skender | 71,277 μs | 50.8 MB | 224x slower |
| Ooples | 500,793 μs | 151 MB | 1,573x slower |
### Exponential Moving Average (EMA)
QuanTAlib matches C library performance at 711 microseconds — within measurement error of Tulip's 708μs and TA-Lib's 713μs. Pure C# matching heavily optimized C code demonstrates what modern .NET achieves when you align memory layouts with hardware capabilities.
| Library | Mean Time | Allocations | Relative Speed |
|---------|-----------|-------------|----------------|
| **QuanTAlib (Span)** | **711.0 μs** | **0 B** | **1.00x** |
| TA-Lib | 712.9 μs | 36 B | 1.00x slower |
| Tulip | 708.1 μs | 0 B | 1.00x faster |
| Skender | 31,393 μs | 50.8 MB | 44x slower |
| Ooples | 18,860 μs | 79.3 MB | 27x slower |
### Weighted Moving Average (WMA)
QuanTAlib's WMA beats both C libraries — 296 microseconds versus Tulip's 372μs and TA-Lib's 360μs. This isn't a measurement error. Pure C# with proper SIMD vectorization outperforms C code that predates AVX-512 optimizations.
| Library | Mean Time | Allocations | Relative Speed |
|---------|-----------|-------------|----------------|
| **QuanTAlib (Span)** | **296.0 μs** | **0 B** | **1.00x (baseline)** |
| TA-Lib | 360.0 μs | 34 B | 1.22x slower |
| Tulip | 372.1 μs | 0 B | 1.26x slower |
| Skender | 103,254 μs | 50.8 MB | 349x slower |
| Ooples | 73,983 μs | 70.9 MB | 250x slower |
### Hull Moving Average (HMA)
HMA requires multiple moving average calculations — traditionally expensive. QuanTAlib processes 500,000 bars in 1,008 microseconds. Tulip takes 2,266 microseconds. Skender requires 251,694 microseconds. (TALib doesn't include HMA calculation) That's a 2.25x improvement over optimized C and a 250x improvement over standard .NET implementations.
| Library | Mean Time | Allocations | Relative Speed |
|---------|-----------|-------------|----------------|
| **QuanTAlib (Span)** | **1,007.8 μs** | **0 B** | **1.00x (baseline)** |
| TA-Lib | -- | -- | -- |
| Tulip | 2,266.0 μs | 152 B | 2.25x slower |
| Skender | 251,694 μs | 235.9 MB | 250x slower |
| Ooples | 123,234 μs | 108.7 MB | 122x slower |
## Multi-mode Comparison
The benchmarks above show Span mode. Here's how all four modes compare using EMA as representative:
| QuanTAlib Mode | Mean Time | Allocations | Use Case |
|----------------|-----------|-------------|----------|
| Span | 711.0 μs | 0 B | Maximum speed, batch processing |
| Streaming | 721.9 μs | 44 B | Real-time updates, minimal overhead |
| Batch (TSeries) | 1,311.7 μs | 8.0 MB | Time-aligned series with metadata |
| Eventing | 2,928.4 μs | 16.8 MB | Reactive architectures with event infrastructure |
Even QuanTAlib's slowest mode (Eventing with complete event infrastructure and 16MB of allocations) processes 500,000 EMA values in 3 milliseconds — faster than Ooples' 19 milliseconds and Skender's 31 milliseconds for the same calculation.
## Methodology
We use [BenchmarkDotNet](https://benchmarkdotnet.org/) for all performance testing. This ensures:
- Warmup iterations to stabilize JIT compilation
- Statistical analysis of results (mean, standard deviation)
- Memory allocation tracking
- Environment isolation
## How to Run Benchmarks Yourself
You can run the benchmarks on your own hardware to verify these results.
1. Clone the repository:
```bash
git clone https://github.com/mihakralj/QuanTAlib.git
cd QuanTAlib
```
2. Navigate to the performance project:
```bash
cd perf
```
3. Run the benchmarks:
```bash
dotnet run -c Release
```
*Note: Benchmarks must be run in Release configuration to enable optimizations.*
+44
View File
@@ -0,0 +1,44 @@
# Indicator Catalog
QuanTAlib provides technical indicators organized into mathematical families. Understanding these families helps choose the right tool for the analytical problem you're actually solving.
## Full Category Table
| Category | What It Measures | Representative Indicators | When You Need It |
|----------|------------------|---------------------------|------------------|
| [**Trends**](../lib/trends/_index.md) | Direction and strength of price movement through smoothing and filtering | SMA, EMA, WMA, HMA, JMA, KAMA, ALMA, DEMA, TEMA, T3 | Starting point for most analysis. Simpler variants (SMA, EMA) work for trend identification. Exotic ones (Jurik, Ehlers) trade CPU cycles for reduced lag. |
| [**Volatility**](../lib/volatility/_index.md) | Size and variability of price movements | ATR, StdDev, Bollinger Bands, Keltner Channels, Historical Volatility | Position sizing, stop-loss placement, and understanding market regime. ATR tells you how much instruments typically move. |
| [**Momentum**](../lib/momentum/_index.md) | Speed and magnitude of price changes | RSI, Stochastic, CCI, Williams %R, MACD, Momentum, ROC | Identifying overbought/oversold conditions and divergences. RSI oscillates between 0-100 by construction. |
| [**Volume**](../lib/volume/_index.md) | Trading activity and price-volume relationships | OBV, VWAP, Volume ROC, A/D, MFI | Confirming price movements with volume participation. VWAP shows where institutional traders executed. |
| [**Channels**](../lib/channels/_index.md) | Price boundaries and range definitions | Donchian Channels, Keltner Channels, Price Channels | Breakout strategies and range-bound trading. Donchian Channels mark highest high and lowest low. |
| [**Statistics**](../lib/statistics/_index.md) | Mathematical relationships between price series | Correlation, Covariance, Beta, Z-Score, Linear Regression | Portfolio analysis, pairs trading, and statistical arbitrage. Correlation measures how two instruments move together. |
| [**Numerics**](../lib/numerics/_index.md) | Mathematical transformations and signal processing | Convolution, Filters, Integration, Differentiation, Smoothing | Custom indicator development and advanced signal processing. Toolkit for building indicators rather than using them. |
| [**Errors**](../lib/errors/_index.md) | Measurement accuracy and model fit quality | MAE, RMSE, Residuals, R-Squared | Model validation and forecast quality assessment. Critical for anyone building quantitative strategies. |
| [**Forecasts**](../lib/forecasts/_index.md) | Future price prediction and projection | Linear Regression Forecast, Moving Average Projection | Predictive modeling. Projects price based on historical patterns. |
| [**Cycles**](../lib/cycles/_index.md) | Periodic patterns and dominant frequencies | Hilbert Transform, Dominant Cycle, Instantaneous Phase, Sine Wave | Identifying and trading cyclical market behavior. Works beautifully when markets are cyclical. |
## When to Use Each Category
The categories aren't rigid boundaries—many indicators could fit multiple categories. KAMA is both a trend indicator and uses momentum calculations. Keltner Channels combine trends (moving average centerline) with volatility (ATR bands). The organization helps you understand what analytical problem each indicator solves rather than memorizing which arbitrary category someone assigned it to.
- **New to TA?** Start with **Trends**, **Volatility**, and **Momentum**. These provide the foundation most traders need.
- **Building a Strategy?** Use **Statistics** for pairs trading, **Volume** for confirmation, and **Channels** for breakouts.
- **Advanced Quant?** **Numerics**, **Errors**, and **Cycles** provide the raw mathematical tools for custom signal processing and model validation.
## Mathematical Families Explanation
### Moving Averages (Trends)
Moving averages are low-pass filters. They remove high-frequency noise (random price fluctuations) to reveal the underlying low-frequency signal (trend).
- **SMA**: Equal weight to all points. Slowest to react.
- **EMA/WMA**: More weight to recent data. Faster reaction.
- **HMA/JMA/ALMA**: Advanced math to reduce lag while maintaining smoothness.
### Oscillators (Momentum)
Oscillators measure the velocity of price changes. They are typically bounded (e.g., 0-100) or centered around zero.
- **RSI**: Ratio of average gains to average losses.
- **MACD**: Difference between two moving averages (convergence/divergence).
### Dispersion (Volatility)
These measure the spread of data points around the mean.
- **StdDev**: Standard statistical measure of variance.
- **ATR**: Volatility measure that accounts for gaps (high-low range).
+126
View File
@@ -0,0 +1,126 @@
# Integration Guides
QuanTAlib is designed to be platform-agnostic. It can be integrated into any .NET environment.
## Quantower
Quantower allows custom indicators via C#.
1. **Reference the DLL**:
- Build QuanTAlib or download the NuGet package.
- In your Quantower indicator project, add a reference to `QuanTAlib.dll`.
2. **Wrapper Class**:
- Create a class that inherits from `Indicator`.
- Instantiate the QuanTAlib indicator in `OnInit`.
- Call `Update` in `OnUpdate`.
```csharp
using Quantower.API.Indicators;
using QuanTAlib;
public class MySmaIndicator : Indicator
{
private Sma _sma;
[InputParameter("Period", 10, 1000, 1, 0)]
public int Period = 14;
public override void OnInit()
{
_sma = new Sma(Period);
AddLineSeries("SMA", Color.Yellow, LineStyle.Solid, 2);
}
public override void OnUpdate(UpdateArgs args)
{
// Get price from Quantower
double price = ClosePrice;
// Update QuanTAlib
// Note: Quantower handles bar updates, so we check if it's a new bar or update
bool isNew = args.Reason == UpdateReason.NewBar;
var result = _sma.Update(new TValue(DateTime.UtcNow, price), isNew);
// Set value to Quantower series
SetValue(result.Value);
}
}
```
## NinjaTrader 8
NinjaTrader 8 uses .NET Framework 4.8, but can interop with .NET Standard libraries.
1. **Copy DLL**: Place `QuanTAlib.dll` in `Documents\NinjaTrader 8\bin\Custom`.
2. **Add Reference**: In NinjaScript Editor, right-click > References > Add `QuanTAlib.dll`.
```csharp
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Name = "QuanTAlib SMA";
// ...
}
else if (State == State.DataLoaded)
{
_sma = new QuanTAlib.Sma(Period);
}
}
protected override void OnBarUpdate()
{
// NinjaTrader calls OnBarUpdate for every tick (if Calculate = OnEachTick)
// or once per bar (if Calculate = OnBarClose)
bool isNew = IsFirstTickOfBar; // Logic depends on Calculate mode
var result = _sma.Update(new TValue(Time[0], Close[0]), isNew);
Value[0] = result.Value;
}
```
## QuantConnect (LEAN)
LEAN supports custom libraries.
1. **NuGet**: Add `QuanTAlib` to your `config.json` or project file.
2. **Usage**: Use inside `OnData`.
```csharp
public class MyAlgorithm : QCAlgorithm
{
private Sma _mySma;
public override void Initialize()
{
_mySma = new Sma(14);
}
public override void OnData(Slice data)
{
if (data.Bars.ContainsKey("SPY"))
{
var bar = data.Bars["SPY"];
var result = _mySma.Update(new TValue(bar.EndTime, (double)bar.Close));
if (_mySma.IsHot)
{
Plot("Indicators", "SMA", result.Value);
}
}
}
}
```
## Custom Platform Integration
For proprietary trading engines, the **Streaming Mode** is usually the best fit.
### Key Considerations
1. **Time Handling**: QuanTAlib uses `DateTime.UtcNow`. Ensure your platform provides UTC timestamps or convert them.
2. **Double Precision**: All calculations use `double`. If your platform uses `decimal`, cast to `double` for input and back to `decimal` for output.
3. **State Management**: Persist the indicator instance for the lifetime of the symbol/strategy. Do not recreate the indicator on every tick.
4. **Concurrency**: `Update` is not thread-safe for the same instance. If processing multiple symbols in parallel, use separate indicator instances for each symbol.
+127
View File
@@ -0,0 +1,127 @@
# Usage Guides
QuanTAlib supports four distinct operating modes to handle different architectural requirements.
## 1. Span Mode (High Performance)
**Best for:** Backtesting, batch processing, research.
Operates directly on `Span<double>` or arrays. Zero allocations, maximum speed.
```csharp
using QuanTAlib;
// 1. Prepare data
double[] prices = GetPrices(); // Your data source
double[] results = new double[prices.Length];
// 2. Calculate
// Sma.Calculate(source, destination, period)
Sma.Calculate(prices, results, 14);
// 3. Use results
Console.WriteLine($"Last SMA: {results[^1]}");
```
## 2. Streaming Mode (Real-Time)
**Best for:** Live trading, tick-by-tick analysis.
Updates one value at a time. Maintains internal state.
```csharp
using QuanTAlib;
// 1. Initialize
var sma = new Sma(period: 14);
// 2. Update loop (e.g., connected to a feed)
void OnData(double price)
{
// Update returns a TValue struct { Time, Value, IsHot }
TValue result = sma.Update(new TValue(DateTime.UtcNow, price));
if (result.IsHot)
{
Console.WriteLine($"SMA: {result.Value}");
}
}
// 3. Handle bar updates (correction)
// If your feed sends updates for the *same* bar multiple times:
sma.Update(new TValue(time, openPrice), isNew: true); // New bar opens
sma.Update(new TValue(time, currentPrice), isNew: false); // Price changes within bar
```
## 3. Batch Mode (TSeries)
**Best for:** Exploratory analysis, notebooks.
Wraps calculations in `TSeries` objects that handle timestamps and alignment.
```csharp
using QuanTAlib;
// 1. Create series
TSeries prices = new TSeries();
prices.Add(DateTime.Now, 100.0);
prices.Add(DateTime.Now.AddMinutes(1), 101.0);
// ... add more data ...
// 2. Calculate
// Returns a new TSeries aligned with input
TSeries smaSeries = new Sma(prices, period: 14);
// 3. Access
Console.WriteLine($"Last Value: {smaSeries.Last.Value}");
Console.WriteLine($"Value at index 5: {smaSeries[5].Value}");
```
## 4. Event-Driven Architecture
**Best for:** Complex reactive systems.
Indicators can subscribe to other indicators or data sources.
```csharp
using QuanTAlib;
// 1. Setup chain
var source = new TSeries();
var smaFast = new Sma(source, 10);
var smaSlow = new Sma(source, 20);
// 2. Subscribe to events
smaFast.Pub += (sender, args) => {
Console.WriteLine($"Fast SMA updated: {args.Tick.Value}");
};
// 3. Feed data
// This triggers the chain: source -> smaFast -> event handler
source.Add(DateTime.UtcNow, 105.0);
```
## Common Patterns
### Handling Warmup
Always check `IsHot` or `Count` before using values.
```csharp
var rsi = new Rsi(14);
// ... feed data ...
if (rsi.IsHot) {
// Safe to use rsi.Value
}
```
### Combining Indicators
You can feed the output of one indicator into another.
```csharp
var ema = new Ema(period: 12);
var rsiOfEma = new Rsi(period: 14);
void OnData(double price) {
var emaResult = ema.Update(new TValue(DateTime.UtcNow, price));
var finalResult = rsiOfEma.Update(emaResult);
}
+65
View File
@@ -0,0 +1,65 @@
- **Core concepts**
- [Architecture](ARCHITECTURE.md)
- [Benchmarks](BENCHMARKS.md)
- [Indicators](INDICATORS.md)
- [Usage Guides](USAGE.md)
- [Integration](INTEGRATION.md)
- **Trends**
- [Overview](../lib/trends/_index.md)
- [ALMA - Arnaud Legoux MA](../lib/trends/alma/Alma.md)
- [CONV - Convolution](../lib/trends/conv/Conv.md)
- [DEMA - Double Exponential MA](../lib/trends/dema/Dema.md)
- [DWMA - Double Weighted MA](../lib/trends/dwma/Dwma.md)
- [EMA - Exponential MA](../lib/trends/ema/Ema.md)
- [HMA - Hull MA](../lib/trends/hma/Hma.md)
- [HTIT - Hilbert Transform Instant Trendline](../lib/trends/htit/Htit.md)
- [JMA - Jurik MA](../lib/trends/jma/Jma.md)
- [KAMA - Kaufman Adaptive MA](../lib/trends/kama/Kama.md)
- [LSMA - Least Squares MA](../lib/trends/lsma/Lsma.md)
- [MAMA - MESA Adaptive MA](../lib/trends/mama/Mama.md)
- [MGDI - McGinley Dynamic](../lib/trends/mgdi/Mgdi.md)
- [PWMA - Pascal Weighted MA](../lib/trends/pwma/Pwma.md)
- [RMA - Rolling MA](../lib/trends/rma/Rma.md)
- [SMA - Simple MA](../lib/trends/sma/Sma.md)
- [SUPER - SuperTrend](../lib/trends/super/Super.md)
- [T3 - Tillson T3 MA](../lib/trends/t3/T3.md)
- [TEMA - Triple Exponential MA](../lib/trends/tema/Tema.md)
- [TRIMA - Triangular MA](../lib/trends/trima/Trima.md)
- [VIDYA - Variable Index Dynamic Average](../lib/trends/vidya/Vidya.md)
- [WMA - Weighted MA](../lib/trends/wma/Wma.md)
- **Momentum**
- [Overview](../lib/momentum/_index.md)
- [ADX - Average Directional Index](../lib/momentum/adx/Adx.md)
- [AO - Awesome Oscillator](../lib/momentum/ao/Ao.md)
- [AROON - Aroon Oscillator](../lib/momentum/aroon/Aroon.md)
- [CFB - Composite Fractal Behavior](../lib/momentum/cfb/Cfb.md)
- [DMX - Jurik Directional Movement Index](../lib/momentum/dmx/Dmx.md)
- [RSX - Jurik Relative Strength X](../lib/momentum/rsx/Rsx.md)
- [VEL - Jurik Velocity](../lib/momentum/vel/Vel.md)
- **Volatility**
- [Overview](../lib/volatility/_index.md)
- [ATR - Average True Range](../lib/volatility/atr/Atr.md)
- **Volume**
- [Overview](../lib/volume/_index.md)
- **Channels**
- [Overview](../lib/channels/_index.md)
- **Statistics**
- [Overview](../lib/statistics/_index.md)
- **Numerics**
- [Overview](../lib/numerics/_index.md)
- **Errors**
- [Overview](../lib/errors/_index.md)
- **Forecasts**
- [Overview](../lib/forecasts/_index.md)
- **Cycles**
- [Overview](../lib/cycles/_index.md)
+164
View File
@@ -0,0 +1,164 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>QuanTAlib Documentation</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="Quantitative Technical Analysis Library in C#">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/dark.css">
<style>
:root {
--base-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
--base-font-size: 16px;
--theme-color: #58a6ff;
--text-color: #c9d1d9;
--background-color: #0d1117;
--code-background: #161b22;
--sidebar-background: #010409;
--sidebar-text: #c9d1d9;
--sidebar-border-color: #30363d;
}
body {
font-family: var(--base-font-family);
background-color: var(--background-color);
color: var(--text-color);
}
.sidebar {
background-color: var(--sidebar-background);
border-right: 1px solid var(--sidebar-border-color);
color: var(--sidebar-text);
}
.sidebar-nav li {
margin: 0;
}
.sidebar-nav ul {
padding-left: 0;
}
.sidebar-nav > ul > li {
font-weight: 600;
margin-top: 1.5em;
margin-bottom: 0.5em;
}
.sidebar-nav a {
color: var(--theme-color);
text-decoration: none;
}
.sidebar-nav a:hover {
text-decoration: underline;
}
.app-name-link {
color: var(--text-color) !important;
font-weight: 600;
font-size: 1.5em;
}
.markdown-section {
max-width: 1012px;
margin: 0 auto;
padding: 30px 40px;
}
.markdown-section h1, .markdown-section h2, .markdown-section h3 {
color: var(--text-color);
font-weight: 600;
}
.markdown-section h1 {
border-bottom: 1px solid #21262d;
padding-bottom: 0.3em;
}
.markdown-section h2 {
border-bottom: 1px solid #21262d;
padding-bottom: 0.3em;
}
.markdown-section code {
background-color: rgba(110,118,129,0.4);
border-radius: 6px;
font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;
font-size: 85%;
padding: 0.2em 0.4em;
}
.markdown-section pre {
background-color: var(--code-background);
border-radius: 6px;
border: 1px solid #30363d;
}
.markdown-section pre > code {
background-color: transparent;
padding: 0;
font-size: 85%;
}
.markdown-section a {
color: var(--theme-color);
text-decoration: none;
}
.markdown-section a:hover {
text-decoration: underline;
}
.markdown-section table {
display: block;
width: 100%;
overflow: auto;
border-spacing: 0;
border-collapse: collapse;
}
.markdown-section table tr {
background-color: var(--background-color);
border-top: 1px solid #30363d;
}
.markdown-section table tr:nth-child(2n) {
background-color: #161b22;
}
.markdown-section table th, .markdown-section table td {
padding: 6px 13px;
border: 1px solid #30363d;
}
.markdown-section blockquote {
color: #8b949e;
border-left: 0.25em solid #30363d;
}
</style>
</head>
<body>
<div id="app"></div>
<script>
globalThis.$docsify = {
name: 'QuanTAlib',
repo: 'https://github.com/mihakralj/QuanTAlib',
loadSidebar: true,
subMaxLevel: 0,
auto2top: true,
homepage: '../README.md'
}
</script>
<!-- Docsify v4 -->
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
<!-- Sidebar Collapse Plugin -->
<script src="//cdn.jsdelivr.net/npm/docsify-sidebar-collapse/dist/docsify-sidebar-collapse.min.js"></script>
<!-- MathJax -->
<script src="//cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
<script src="//cdn.jsdelivr.net/npm/docsify-latex@0"></script>
<!-- Prism for C# syntax highlighting -->
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-csharp.min.js"></script>
</body>
</html>
-13
View File
@@ -1,13 +0,0 @@
- [**QuanTAlib**](/)
- **Trends**
- [Overview](trends/)
- [ALMA - Arnaud Legoux MA](trends/alma/Alma.md)
- [DEMA - Double Exponential MA](trends/dema/Dema.md)
- [EMA - Exponential MA](trends/ema/Ema.md)
- [HMA - Hull MA](trends/hma/Hma.md)
- [SMA - Simple MA](trends/sma/Sma.md)
- [T3 - Tillson T3 MA](trends/t3/T3.md)
- [TEMA - Triple Exponential MA](trends/tema/Tema.md)
- [TRIMA - Triangular MA](trends/trima/Trima.md)
- [WMA - Weighted MA](trends/wma/Wma.md)
-30
View File
@@ -1,30 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>QuanTAlib Documentation</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="Quantitative Technical Analysis Library in C#">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css">
</head>
<body>
<div id="app"></div>
<script>
globalThis.$docsify = {
name: 'QuanTAlib',
repo: 'https://github.com/mihakralj/QuanTAlib',
loadSidebar: true,
subMaxLevel: 2,
auto2top: true
}
</script>
<!-- Docsify v4 -->
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
<!-- MathJax -->
<script src="//cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
<script src="//cdn.jsdelivr.net/npm/docsify-latex@0"></script>
<!-- Prism for C# syntax highlighting -->
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-csharp.min.js"></script>
</body>
</html>
+7 -7
View File
@@ -5,20 +5,20 @@ Momentum indicators measure the speed or strength of price movements. This inclu
| Indicator | Full Name | Description |
| :--- | :--- | :--- |
| AC | Acceleration Oscillator | |
| [ADX](adx/Adx.md) | Average Directional Index | Measures the strength of a trend, regardless of its direction. |
| [ADX](adx/Adx.md) | Average Directional Index | Quantifies trend intensity by smoothing the expansion of daily ranges, independent of direction. |
| ADXR | Average Directional Movement Rating | |
| [AO](ao/Ao.md) | Awesome Oscillator | Measures market momentum using the difference between 34-period and 5-period SMAs of median price. |
| [AO](ao/Ao.md) | Awesome Oscillator | Measures immediate velocity vs. broader trend using the difference between fast and slow median-price SMAs. |
| APO | Absolute Price Oscillator | |
| [AROON](aroon/Aroon.md) | Aroon | Identifies trend changes and strength using time since high/low. |
| [AROON](aroon/Aroon.md) | Aroon | Gauges trend freshness by measuring the time elapsed since the last high and low. |
| AROONOSC | Aroon Oscillator | |
| BBB | Bollinger %B | |
| BBS | Bollinger Band Squeeze | |
| BOP | Balance of Power | |
| CCI | Commodity Channel Index | |
| [CFB](cfb/Cfb.md) | Jurik Composite Fractal Behavior | Trend Duration Index using fractal efficiency. |
| [CFB](cfb/Cfb.md) | Jurik Composite Fractal Behavior | Measures trend duration and quality by analyzing fractal efficiency across multiple time scales. |
| CHOP | Choppiness Index | |
| CMO | Chande Momentum Oscillator | |
| [DMX](dmx/Dmx.md) | Jurik Directional Movement Index | Advanced replacement for DMI/ADX using JMA smoothing. |
| [DMX](dmx/Dmx.md) | Jurik Directional Movement Index | A low-lag, bipolar replacement for DMI/ADX that combines trend direction and strength. |
| DPO | Detrended Price Oscillator | |
| DX | Directional Movement Index | |
| FISHER | Ehlers Fisher Transform | |
@@ -36,7 +36,7 @@ Momentum indicators measure the speed or strength of price movements. This inclu
| ROCP | Rate of Change Percentage | |
| ROCR | Rate of Change Ratio | |
| RSI | Relative Strength Index | |
| [RSX](rsx/Rsx.md) | Jurik Relative Strength X | Noise-free, zero-lag version of RSI |
| [RSX](rsx/Rsx.md) | Jurik Relative Strength X | A "noise-free" version of RSI that eliminates jaggedness without adding lag. |
| SMI | Stochastic Momentum Index | |
| STOCH | Stochastic Oscillator | |
| STOCHF | Stochastic Fast | |
@@ -44,6 +44,6 @@ Momentum indicators measure the speed or strength of price movements. This inclu
| TRIX | Triple Exponential Average | |
| TSI | True Strength Index | |
| ULTOSC | Ultimate Oscillator | |
| [VEL](vel/Vel.md) | Jurik Velocity | Momentum oscillator calculated as the difference between Parabolic Weighted MA and Weighted MA. |
| [VEL](vel/Vel.md) | Jurik Velocity | Measures market "acceleration" by comparing parabolic vs. linear weighting schemes. |
| VORTEX | Vortex Indicator | |
| WILLR | Williams %R | |
+133 -53
View File
@@ -1,80 +1,160 @@
# ADX - Average Directional Index
# ADX: Average Directional Index
The Average Directional Index (ADX) is a technical analysis indicator used to determine the strength of a trend. The trend can be either up or down, and this is shown by two accompanying indicators, the Negative Directional Indicator (-DI) and the Positive Directional Indicator (+DI). Therefore, ADX consists of three separate lines.
## What It Does
## Core Concepts
The Average Directional Index (ADX) quantifies trend strength without regard to trend direction. It answers the critical question: "Is the market trending?" rather than "Which way is it going?" By isolating strength from direction, ADX allows traders to filter their strategies—deploying trend-following logic only when a trend is statistically present, and switching to mean-reversion when the market is ranging.
- **Trend Strength:** ADX measures the strength of the trend, not the direction.
- **Directional Movement:** +DI and -DI show the direction of the trend.
- **Range:** ADX values range from 0 to 100. Values above 25 usually indicate a strong trend.
## Historical Context
## Parameters
J. Welles Wilder Jr. introduced the ADX in his seminal 1978 book, *New Concepts in Technical Trading Systems*. Wilder, a mechanical engineer turned real estate developer and trader, designed the ADX (along with RSI, ATR, and Parabolic SAR) to bring mathematical rigor to the then-subjective field of technical analysis. His goal was to create a system that could objectively distinguish between trending and non-trending markets.
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| Period | int | 14 | The number of periods used for the calculation. |
## How It Works
## Formula
### The Core Idea
1. **Calculate True Range (TR), +DM, and -DM:**
$$TR = \max(High - Low, |High - PreviousClose|, |Low - PreviousClose|)$$
$$+DM = \text{if } (High - PreviousHigh) > (PreviousLow - Low) \text{ and } (High - PreviousHigh) > 0 \text{ then } (High - PreviousHigh) \text{ else } 0$$
$$-DM = \text{if } (PreviousLow - Low) > (High - PreviousHigh) \text{ and } (PreviousLow - Low) > 0 \text{ then } (PreviousLow - Low) \text{ else } 0$$
ADX is built on the concept of "Directional Movement" (DM).
2. **Smooth TR, +DM, -DM:**
Using Wilder's Moving Average (RMA) over `Period`.
$$TR_{smooth} = RMA(TR, Period)$$
$$+DM_{smooth} = RMA(+DM, Period)$$
$$-DM_{smooth} = RMA(-DM, Period)$$
1. **Expansion:** It compares today's high/low with yesterday's high/low to see if the range has expanded up (+DM) or down (-DM).
2. **Normalization:** These expansions are normalized by the True Range (volatility) to create Directional Indicators (+DI and -DI).
3. **Difference:** The difference between +DI and -DI is calculated to find the "Directional Index" (DX).
4. **Smoothing:** The DX is smoothed (typically over 14 periods) to produce the ADX.
3. **Calculate +DI and -DI:**
$$+DI = \frac{+DM_{smooth}}{TR_{smooth}} \times 100$$
$$-DI = \frac{-DM_{smooth}}{TR_{smooth}} \times 100$$
### Mathematical Foundation
4. **Calculate DX:**
$$DX = \frac{|+DI - -DI|}{+DI + -DI} \times 100$$
1. **Directional Movement (DM):**
$$+DM = \text{if } (H_t - H_{t-1}) > (L_{t-1} - L_t) \text{ and } (H_t - H_{t-1}) > 0 \text{ then } H_t - H_{t-1} \text{ else } 0$$
$$-DM = \text{if } (L_{t-1} - L_t) > (H_t - H_{t-1}) \text{ and } (L_{t-1} - L_t) > 0 \text{ then } L_{t-1} - L_t \text{ else } 0$$
5. **Calculate ADX:**
$$ADX = RMA(DX, Period)$$
2. **Directional Indicators (DI):**
$$+DI = 100 \times \frac{RMA(+DM, n)}{ATR(n)}$$
$$-DI = 100 \times \frac{RMA(-DM, n)}{ATR(n)}$$
## C# Implementation
3. **Directional Index (DX):**
$$DX = 100 \times \frac{|+DI - -DI|}{+DI + -DI}$$
### Standard Usage
4. **Average Directional Index (ADX):**
$$ADX = RMA(DX, n)$$
```csharp
// Create ADX with period 14
var adx = new Adx(14);
Where $RMA$ is Wilder's Moving Average (an EMA with $\alpha = 1/n$).
// Update with TBar
var result = adx.Update(new TBar(time, open, high, low, close, volume));
Console.WriteLine($"ADX: {result.Value}");
```
### Implementation Details
### Streaming with TBarSeries
Our implementation focuses on numerical stability and performance.
```csharp
var adx = new Adx(14);
var series = new TBarSeries();
// ... populate series ...
var results = adx.Update(series);
```
- **Zero-Allocation Updates:** The streaming `Update` method uses `stackalloc` for internal state calculations, ensuring zero heap allocations on the hot path.
- **Stabilization:** ADX is a "derivative of a derivative" (smoothed price -> smoothed range -> smoothed ratio -> smoothed result). It requires significant history to stabilize. We implement a proper warmup phase to prevent early erratic values.
- **Precision:** All internal calculations use double-precision floating point to minimize rounding errors in the recursive RMA steps.
### Batch Calculation
## Configuration
```csharp
var results = Adx.Batch(series, 14);
```
| Parameter | Default | Purpose | Adjustment Guidelines |
|-----------|---------|---------|----------------------|
| Period | 14 | Lookback window | Wilder's standard is 14. Lower (7-10) = faster reaction; Higher (20-30) = smoother trend filter. |
**Configuration note:** ADX is notoriously slow to turn. Shortening the period makes it more responsive but increases noise.
## Performance Profile
| Operation | Complexity | Description |
|-----------|------------|-------------------|
| Streaming update | O(1) | Constant time recursive calculation |
| Bar correction | O(1) | Efficient state rollback |
| Batch processing | O(N) | Single pass through data |
| Memory footprint | O(1) | Minimal state (previous High/Low/Close + smoothed values) |
## Interpretation
- **ADX < 20:** Weak trend or non-trending market.
- **ADX > 25:** Strong trend.
- **ADX > 40:** Very strong trend.
- **ADX > 50:** Extremely strong trend.
### Trading Signals
Traders typically use ADX to determine whether to use a trend-following system or a range-trading system. When ADX is high, trend-following strategies are preferred. When ADX is low, range-trading strategies are preferred.
#### Trend Strength
- **ADX < 20:** Weak trend or ranging market. Strategies: Mean reversion, oscillators.
- **ADX > 25:** Trend is emerging. Strategies: Breakout, trend following.
- **ADX > 40:** Strong trend. Strategies: Pullback entries.
- **ADX > 50:** Extremely strong trend. Watch for exhaustion (climax).
#### Trend Direction
- **+DI > -DI:** Bullish dominance.
- **-DI > +DI:** Bearish dominance.
- **Crossover:** +DI crossing -DI is often used as an entry signal, filtered by ADX > 20.
### When It Works Best
- **Trend Filtering:** The primary use case. Use ADX to decide *which* strategy to run. If ADX is rising, trade the trend. If ADX is falling or low, trade the range.
### When It Struggles
- **V-Reversals:** Because of the multiple smoothing layers, ADX lags significantly at sharp market turns. It may still indicate a strong trend when the market has already reversed.
## Architecture Notes
This implementation makes specific trade-offs:
### Choice: Recursive RMA
- **Alternative:** Simple Moving Average (SMA).
- **Trade-off:** History dependence.
- **Rationale:** Wilder specifically defined ADX using his own smoothing method (RMA). Using SMA would yield incorrect values compared to standard platforms.
### Choice: True Range Dependency
- **Alternative:** Simplified range (High - Low).
- **Trade-off:** Complexity.
- **Rationale:** True Range accounts for gaps between bars, which is critical for accurate volatility measurement in 24/7 markets or daily charts with overnight gaps.
## References
- Wilder, J. Welles. "New Concepts in Technical Trading Systems." Trend Research, 1978.
- [Investopedia - Average Directional Index (ADX)](https://www.investopedia.com/terms/a/adx.asp)
- Wilder, J. Welles. *New Concepts in Technical Trading Systems*. Trend Research, 1978.
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var adx = new Adx(period: 14);
// Process each new bar
// Note: ADX requires High, Low, and Close prices
TBar bar = new TBar(time, open, high, low, close, volume);
TValue result = adx.Update(bar);
Console.WriteLine($"ADX: {result.Value:F2}");
// Check if buffer is full (ADX needs significant warmup)
if (adx.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TBarSeries API
TBarSeries bars = ...;
TSeries adxValues = Adx.Batch(bars, period: 14);
// Span API (High Performance)
// Requires separate arrays for High, Low, Close
double[] high = ...;
double[] low = ...;
double[] close = ...;
double[] output = new double[high.Length];
Adx.Calculate(high.AsSpan(), low.AsSpan(), close.AsSpan(), output.AsSpan(), period: 14);
```
### Bar Correction (isNew Parameter)
```csharp
var adx = new Adx(14);
// New bar
adx.Update(new TBar(time, o, h, l, c, v), isNew: true);
// Intra-bar update
adx.Update(new TBar(time, o, h, l, c, v), isNew: false); // Replaces last value
+103 -37
View File
@@ -1,8 +1,24 @@
# AO - Awesome Oscillator
The Awesome Oscillator (AO) is a momentum indicator used to measure market momentum. It calculates the difference between a 34-period and 5-period Simple Moving Average (SMA) of the median prices (High + Low) / 2.
A momentum indicator that strips away noise to reveal the market's immediate velocity compared to its broader trend. It quantifies the gap between short-term and long-term market consensus using median prices rather than closes.
## Formula
## What It Does
The Awesome Oscillator (AO) measures market momentum by comparing the last 5 bars of activity against the last 34 bars. Unlike traditional oscillators that fixate on closing prices, AO uses the **Median Price** (`(High + Low) / 2`) to capture the true center of the day's trading range.
The result is a histogram that fluctuates above and below a zero line. When the histogram is positive, short-term momentum is outpacing the long-term trend (bullish). When negative, the long-term trend is dominating (bearish). It serves as a non-lagging confirmation of trend direction and a precise tool for spotting reversals.
## Historical Context
Bill Williams introduced the Awesome Oscillator in his "Chaos Theory" of trading, presumably because "Reasonably Good Oscillator" didn't have the same marketing punch. Williams argued that standard indicators using closing prices missed the volatility that happens *during* the bar. By focusing on the median price, AO attempts to reflect the market's "balance point" rather than just its finish line.
It is a core component of the Williams Trading System, often used in conjunction with the Alligator indicator to confirm trend entries.
## How It Works
The calculation is elegantly simple, relying on the difference between two Simple Moving Averages (SMA) of the Median Price.
### The Math
$$Median Price = \frac{High + Low}{2}$$
@@ -10,51 +26,101 @@ $$AO = SMA(Median Price, 5) - SMA(Median Price, 34)$$
Where:
- $SMA$ is the Simple Moving Average.
- **Fast SMA (5)**: Represents the current market momentum.
- **Slow SMA (34)**: Represents the broader market trend.
## Usage
### The Logic
### C# Code
1. **Median Price Calculation**: For every bar, we first determine the midpoint of the trading range.
2. **Smoothing**: We smooth these midpoints over two distinct timeframes.
3. **Differential**: We subtract the slow average from the fast average.
- **Positive AO**: The fast average is above the slow average (Momentum is Up).
- **Negative AO**: The fast average is below the slow average (Momentum is Down).
## Configuration
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `fastPeriod` | `int` | 5 | The lookback period for the short-term momentum. |
| `slowPeriod` | `int` | 34 | The lookback period for the long-term trend. |
*Note: While 5 and 34 are the canonical "Williams" settings, the architecture supports any positive integer values.*
## Performance Profile
The AO implementation is designed for high-frequency and zero-allocation environments.
- **Complexity**: $O(1)$ per update. The calculation relies on two internal SMA instances, which maintain running sums.
- **Memory**: Constant space. It stores only the state required for the two SMAs (circular buffers for the periods).
- **Allocations**: Zero heap allocations during the `Update` cycle.
| Operation | Time Complexity | Space Complexity |
|-----------|-----------------|------------------|
| Update | $O(1)$ | $O(1)$ |
| Batch | $O(N)$ | $O(N)$ |
## Interpretation
AO is primarily a histogram, and its signals come from the bars' color (direction) and position relative to zero.
### 1. Zero Line Crossover
The most basic signal.
- **Bullish Cross**: AO crosses from negative to positive. The short-term momentum is overtaking the long-term trend.
- **Bearish Cross**: AO crosses from positive to negative. The short-term momentum is collapsing below the long-term trend.
### 2. Twin Peaks
A divergence pattern.
- **Bullish Twin Peaks**: Two lows below the zero line, where the second low is higher (closer to zero) than the first, followed by a green bar.
- **Bearish Twin Peaks**: Two highs above the zero line, where the second high is lower than the first, followed by a red bar.
### 3. The Saucer
A continuation signal.
- **Bullish Saucer**: AO is above zero. The histogram creates a "dip" (Red, Red, Green). The signal is the first Green bar.
- **Bearish Saucer**: AO is below zero. The histogram creates a "rally" (Green, Green, Red). The signal is the first Red bar.
## Architecture Notes
The `Ao` class is a composite indicator. It does not implement the smoothing logic itself but rather orchestrates two `Sma` instances.
- **Input Handling**: The `Update(TBar)` method automatically extracts the `(High + Low) / 2` median price before passing it to the internal SMAs.
- **State Management**: Resetting the AO propagates the reset to both internal SMAs, ensuring complete state clearance.
- **Warmup**: The `IsHot` property is tied to the `slowPeriod` SMA. The indicator is considered valid only when the slow SMA has filled its buffer.
## References
- Williams, Bill. *Trading Chaos: Maximize Profits with Proven Technical Techniques*. Wiley, 1995.
- Investopedia: [Awesome Oscillator](https://www.investopedia.com/terms/a/awesomeoscillator.asp)
## C# Usage
```csharp
using QuanTAlib;
// Create AO with default periods (5, 34)
// 1. Standard Initialization (Williams defaults: 5, 34)
var ao = new Ao();
// Or specify custom periods
var aoCustom = new Ao(5, 34);
// 2. Custom Initialization
var customAo = new Ao(fastPeriod: 10, slowPeriod: 50);
// Update with a bar
// 3. Processing a Bar (Standard Use Case)
// AO requires High and Low prices to calculate Median Price
var bar = new TBar(DateTime.UtcNow, open: 100, high: 105, low: 95, close: 102, volume: 1000);
var result = ao.Update(bar);
// Result contains the AO value
Console.WriteLine($"AO: {result.Value}");
Console.WriteLine($"AO: {result.Value:F2}");
// Batch calculation
var series = new TBarSeries();
var results = Ao.Batch(series, 5, 34);
```
// 4. Processing a Value (Advanced Use Case)
// If you pre-calculate Median Price or want to use Close price instead
double medianPrice = (bar.High + bar.Low) / 2;
var valueResult = ao.Update(new TValue(bar.Time, medianPrice));
### Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| fastPeriod | int | 5 | The period for the fast SMA. |
| slowPeriod | int | 34 | The period for the slow SMA. |
## Properties
| Property | Type | Description |
|----------|------|-------------|
| Last | TValue | The latest calculated AO value. |
| IsHot | bool | Indicates if the indicator has enough data to be valid (slow period reached). |
| Name | string | The name of the indicator, e.g., "Ao(5,34)". |
## Methods
| Method | Description |
|--------|-------------|
| Update(TBar bar) | Updates the indicator with a new bar. |
| Update(TValue val) | Updates the indicator with a new value (assumed to be Median Price). |
| Reset() | Resets the indicator state. |
// 5. Batch Calculation
var series = new TBarSeries();
// ... populate series ...
var aoSeries = Ao.Batch(series);
+95 -45
View File
@@ -1,66 +1,116 @@
# Aroon Indicator
# Aroon
The Aroon indicator is a technical indicator used to identify trend changes in the price of an asset, as well as the strength of that trend. It consists of two lines: Aroon Up and Aroon Down.
A trend-following indicator that measures the *time* elapsed since the last highest high and lowest low. Unlike price-based oscillators, Aroon focuses on the temporal freshness of price extremes to gauge trend strength.
## Calculation
## What It Does
The Aroon indicator measures the time between highs and the time between lows over a time period.
The Aroon indicator answers a simple question: "How long has it been since we saw a new high or low?"
$$
\text{Aroon Up} = \frac{\text{Period} - \text{Days Since Period High}}{\text{Period}} \times 100
$$
It consists of two lines (Up and Down) and a derived Oscillator.
$$
\text{Aroon Down} = \frac{\text{Period} - \text{Days Since Period Low}}{\text{Period}} \times 100
$$
- **Aroon Up**: Quantifies how recent the last high was.
- **Aroon Down**: Quantifies how recent the last low was.
- **Aroon Oscillator**: The net difference, showing the dominant trend.
$$
\text{Aroon Oscillator} = \text{Aroon Up} - \text{Aroon Down}
$$
When a new high occurs today, Aroon Up hits 100. If no new high appears for the entire period, it drops to 0. This creates a clear metric for trend "staleness."
Where:
## Historical Context
- **Period**: The lookback period (typically 25).
- **Days Since Period High**: The number of days since the highest high within the period.
- **Days Since Period Low**: The number of days since the lowest low within the period.
Developed by Tushar Chande in 1995, the name "Aroon" is derived from the Sanskrit word for "Dawn's Early Light." Chande designed it to spot the beginning of a new trend (the dawn) rather than just confirming an existing one. While moving averages lag significantly, Aroon attempts to signal the moment price behavior shifts from consolidation to trending.
## How It Works
The calculation is purely time-based, normalized to a 0-100 scale.
### The Math
$$ \text{Aroon Up} = \frac{\text{Period} - \text{Days Since High}}{\text{Period}} \times 100 $$
$$ \text{Aroon Down} = \frac{\text{Period} - \text{Days Since Low}}{\text{Period}} \times 100 $$
$$ \text{Oscillator} = \text{Aroon Up} - \text{Aroon Down} $$
### The Logic
1. **Track Extremes**: We maintain a sliding window of the last $N$ bars.
2. **Find Distance**: We locate the index of the highest high and lowest low within that window.
3. **Normalize**:
- If the high was today, `Days Since High` is 0, and Aroon Up is 100.
- If the high was $N$ days ago, Aroon Up is 0.
## Configuration
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `period` | `int` | 14 | The lookback window for finding highs and lows. |
## Performance Profile
The implementation is optimized for minimal memory footprint, though computational complexity scales linearly with the period.
- **Complexity**: $O(P)$ per update, where $P$ is the period. The algorithm must scan the buffer to find the min/max indices.
- **Memory**: $O(P)$. It uses two circular buffers (`RingBuffer`) to store Highs and Lows.
- **Allocations**: Zero heap allocations during the `Update` cycle.
| Operation | Time Complexity | Space Complexity |
|-----------|-----------------|------------------|
| Update | $O(P)$ | $O(P)$ |
| Batch | $O(N \cdot P)$ | $O(N)$ |
*Note: For very large periods (e.g., >1000), the linear scan may become measurable, but for standard technical analysis periods (14-50), it is negligible.*
## Interpretation
- **Aroon Up**: Measures the strength of the uptrend. Values close to 100 indicate a strong uptrend, while values close to 0 indicate a weak uptrend.
- **Aroon Down**: Measures the strength of the downtrend. Values close to 100 indicate a strong downtrend, while values close to 0 indicate a weak downtrend.
- **Crossovers**: When Aroon Up crosses above Aroon Down, it signals a potential uptrend. When Aroon Down crosses above Aroon Up, it signals a potential downtrend.
- **Extremes**: Values above 70 indicate a strong trend, while values below 30 indicate a weak trend.
Aroon is interpreted through specific thresholds and crossovers.
## Usage
### 1. Trend Strength (The 70/30 Rule)
### C# code
- **Strong Uptrend**: Aroon Up > 70.
- **Strong Downtrend**: Aroon Down > 70.
- **Consolidation**: Both lines < 50.
### 2. The Crossover (Trend Change)
- **Bullish**: Aroon Up crosses above Aroon Down.
- **Bearish**: Aroon Down crosses above Aroon Up.
### 3. The Oscillator
- **Positive**: Uptrend bias.
- **Negative**: Downtrend bias.
- **Zero Line Cross**: Confirms the trend reversal signaled by the Up/Down crossover.
## Architecture Notes
The `Aroon` class is a self-contained indicator that manages its own history buffers.
- **Data Requirements**: Requires `High` and `Low` prices. If updated with a single `TValue` (Close), it assumes High=Low=Close, which degrades the indicator's utility to a simple "time since highest close" metric.
- **Buffer Sizing**: The internal buffer size is `Period + 1` to correctly handle the "days since" calculation inclusive of the 0th day.
- **Properties**: The class exposes `Up`, `Down`, and `Last` (Oscillator) as separate `TValue` properties, allowing access to all three components from a single instance.
## References
- Chande, Tushar. *Beyond Technical Analysis: How to Develop and Implement a Winning Trading System*. Wiley, 1995.
- Investopedia: [Aroon Indicator](https://www.investopedia.com/terms/a/aroon.asp)
## C# Usage
```csharp
using QuanTAlib;
// Create Aroon with period 14
var aroon = new Aroon(14);
// 1. Initialize
var aroon = new Aroon(period: 25);
// Update with a TBar
var bar = new TBar(DateTime.UtcNow, 100, 105, 95, 102, 1000);
// 2. Process a Bar
var bar = new TBar(DateTime.UtcNow, open: 100, high: 105, low: 95, close: 102, volume: 1000);
var result = aroon.Update(bar);
// Access values
var osc = result.Value;
var up = aroon.Up.Value;
var down = aroon.Down.Value;
// 3. Access Components
Console.WriteLine($"Oscillator: {result.Value:F2}"); // Main output
Console.WriteLine($"Aroon Up: {aroon.Up.Value:F2}");
Console.WriteLine($"Aroon Down: {aroon.Down.Value:F2}");
Console.WriteLine($"Aroon Osc: {osc:F2}, Up: {up:F2}, Down: {down:F2}");
```
### Quantower
The Aroon indicator is available in Quantower as "Aroon".
- **Period**: The lookback period (default: 14).
- **Show cold values**: Whether to show values before the indicator is fully warmed up.
## References
- [Investopedia: Aroon Indicator](https://www.investopedia.com/terms/a/aroon.asp)
- Tushar Chande (1995)
// 4. Batch Calculation
var series = new TBarSeries();
// ... populate series ...
var aroonSeries = Aroon.Batch(series, period: 14);
+83 -76
View File
@@ -1,103 +1,110 @@
# CFB - Jurik Composite Fractal Behavior
# CFB - Composite Fractal Behavior
## Overview and Purpose
A sophisticated trend duration index that measures the "fractal efficiency" of price movements across multiple time scales. It answers the question: "How long has the market been trending efficiently?"
Composite Fractal Behavior (CFB) is a sophisticated trend duration index developed by Jurik Research. It measures the "fractal efficiency" of price movements across multiple time scales to determine the quality and duration of a trend. Unlike traditional trend indicators that look at a single period, CFB analyzes a spectrum of lookback periods to create a composite index.
## What It Does
CFB is designed to answer the question: "How long has the market been trending efficiently?" It is particularly useful for:
Composite Fractal Behavior (CFB) analyzes the market's geometry to determine the quality and persistence of a trend. Unlike standard indicators that rely on a single fixed period (e.g., RSI-14), CFB scans a wide spectrum of lookback lengths (e.g., from 2 to 192 bars) simultaneously.
* Adjusting the period of other indicators (adaptive indicators).
* Filtering out choppy markets.
* Identifying the breakdown of long-term trends.
It calculates the "fractal efficiency"—how straight the price path is—for each length. It then combines the lengths that show efficient trending behavior into a single composite index. The result is a value representing the approximate duration (in bars) of the current trend.
## Core Concepts
## Historical Context
* **Fractal Efficiency:** Measures how "straight" the price movement is. A straight line has high efficiency; a choppy path has low efficiency.
* **Composite Index:** Instead of relying on a single lookback length, CFB evaluates a wide range of lengths (e.g., 4 to 192 bars) and combines them based on their efficiency.
* **Adaptive:** The indicator adapts to the market's current fractal structure, giving more weight to timeframes where trending behavior is evident.
* **Trend Duration:** The output value represents the approximate duration (in bars) of the current trend.
Developed by Mark Jurik of Jurik Research, CFB addresses the "lag vs. noise" dilemma by avoiding it entirely. Instead of smoothing price data (which adds lag), it measures the structural integrity of the price action itself. It was designed to be an adaptive input for other indicators, allowing them to adjust their speed based on whether the market is trending or chopping.
## Common Settings and Parameters
## How It Works
| Parameter | Default | Function |
|-----------|---------|----------|
| Lengths | `[2, 4, ..., 192]` | Array of lookback periods to analyze. Default is a dense array from 2 to 192. |
| Source | Close | Price data used for calculation. |
The algorithm evaluates the "straightness" of price movement over many different timeframes and aggregates the results.
**Pro Tip:** CFB values typically range from 0 to the maximum lookback length. A rising CFB indicates a strengthening trend (either up or down), while a falling CFB suggests the trend is breaking down or the market is entering a consolidation phase.
### The Math
## Calculation and Mathematical Foundation
For each lookback length $L$ in the configured set:
The CFB calculation involves several steps for each lookback length $L$ in the provided set:
1. **Calculate Efficiency Ratio**:
$$ \text{Ratio}_L = \frac{|\text{Price}_t - \text{Price}_{t-L}|}{\sum_{i=0}^{L-1} |\text{Price}_{t-i} - \text{Price}_{t-i-1}|} $$
*Numerator*: Net distance traveled (straight line).
*Denominator*: Total path length (volatility).
1. **Calculate Efficiency Ratio:**
For each length $L$, calculate the ratio of the net price movement to the total volatility (path length) over that period.
$$Ratio_L = \frac{|Price_t - Price_{t-L}|}{\sum_{i=0}^{L-1} |Price_{t-i} - Price_{t-i-1}|}$$
2. **Filter**:
We discard any length where $\text{Ratio}_L < 0.25$. If the efficiency is below 25%, the movement is considered "noise" or "chop" at that timeframe.
2. **Filter:**
Only consider lengths where the efficiency ratio exceeds a threshold (typically 0.25). This filters out noise and weak trends.
3. **Composite Weighting**:
We calculate a weighted average of the qualifying lengths, using the efficiency ratio itself as the weight.
$$ \text{CFB} = \frac{\sum (L \cdot \text{Ratio}_L)}{\sum \text{Ratio}_L} $$
3. **Weighted Average:**
Calculate the weighted average of the qualifying lengths, using the efficiency ratio as the weight.
$$CFB = \frac{\sum (L \cdot Ratio_L)}{\sum Ratio_L}$$
where the summation is over all $L$ such that $Ratio_L > 0.25$.
4. **Decay**:
If no lengths qualify (the market is chaotic at all scales), the CFB value decays toward 1.0.
4. **Decay:**
If no lengths qualify (i.e., the market is very choppy), the CFB value decays towards 1.0.
## Configuration
## C# Implementation
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `lengths` | `int[]` | `[2, 4, ..., 192]` | An array of lookback periods to analyze. The default is a dense set of even numbers from 2 to 192. |
The library provides a high-performance implementation that uses `RingBuffer` for O(1) updates of the volatility sums.
## Performance Profile
### Single CFB (`Cfb`)
Despite its complexity, the implementation is optimized for real-time use.
- **Complexity**: $O(K)$ per update, where $K$ is the number of lengths analyzed (default 96).
- **Optimization**: It maintains running sums of volatility for each length, ensuring that the denominator calculation is $O(1)$ rather than $O(L)$.
- **Memory**: $O(L_{max} + K)$. It requires a history buffer equal to the maximum lookback length, plus state for each length's running sum.
| Operation | Time Complexity | Space Complexity |
|-----------|-----------------|------------------|
| Update | $O(K)$ | $O(L_{max})$ |
| Batch | $O(N \cdot K)$ | $O(N)$ |
## Interpretation
CFB is primarily a "state" indicator rather than a directional one.
### 1. Trend Duration
The output value roughly corresponds to the number of bars the current trend has been valid.
- **High Values**: Strong, persistent trend.
- **Low Values**: Choppy, sideways market.
### 2. Trend Strength
- **Rising CFB**: The trend is becoming more efficient or extending in duration.
- **Falling CFB**: The trend is breaking down; volatility is increasing relative to net movement.
### 3. Adaptive Input
CFB is ideal for driving the parameters of other indicators. For example, you can use CFB to dynamically adjust the period of a Moving Average:
- **High CFB** $\rightarrow$ Use a longer period (capture the trend).
- **Low CFB** $\rightarrow$ Use a shorter period (react to chop).
## Architecture Notes
- **Running Sums**: The class maintains an array of running sums for volatility. When a new bar arrives, it adds the new volatility and subtracts the volatility from $L$ bars ago. This keeps the efficiency calculation fast.
- **State Management**: The `Update` method handles `isNew` logic carefully to ensure running sums are rolled back correctly during intra-bar updates.
- **Default Lengths**: If no lengths are provided, the constructor generates a dense array `[2, 4, 6, ..., 192]`.
## References
- Jurik Research: [CFB - Composite Fractal Behavior](http://jurikres.com/catalog1/ms_cfb.htm)
## C# Usage
```csharp
using QuanTAlib;
// Initialize with default lengths
// 1. Standard Initialization (Default lengths 2..192)
var cfb = new Cfb();
// Or specify custom lengths
var cfbCustom = new Cfb(new int[] { 10, 20, 30, 40, 50 });
// 2. Custom Initialization (Specific lengths)
var customCfb = new Cfb(new int[] { 10, 20, 50, 100 });
// Streaming update
TValue result = cfb.Update(new TValue(time, price));
Console.WriteLine($"Current Trend Duration: {result.Value}");
```
// 3. Process a Bar
// CFB uses Close price by default (or whatever value is passed)
var result = cfb.Update(new TValue(DateTime.UtcNow, 105.5));
### Zero-Allocation Span API
Console.WriteLine($"Trend Duration: {result.Value:F1} bars");
For performance-critical scenarios:
```csharp
double[] prices = ...;
double[] output = new double[prices.Length];
// Calculate using default lengths
Cfb.Batch(prices.AsSpan(), output.AsSpan());
```
### Bar Correction (isNew Parameter)
`Cfb` supports intra-bar updates:
```csharp
// Real-time: receive initial tick for new bar
cfb.Update(new TValue(time, 100.5), isNew: true);
// Real-time: price updates within same bar
cfb.Update(new TValue(time, 101.0), isNew: false);
```
## Interpretation Details
* **High Values:** Indicate a strong, persistent trend. The value roughly corresponds to the number of bars the trend has been in effect.
* **Low Values:** Indicate a choppy, non-trending market.
* **Rising CFB:** The trend is gaining strength or duration.
* **Falling CFB:** The trend is losing consistency or ending.
CFB is often used as an input to other adaptive indicators (e.g., JMA) to dynamically adjust their smoothing period based on market conditions.
## References
* Jurik Research: [CFB - Composite Fractal Behavior](http://jurikres.com/catalog1/ms_cfb.htm)
// 4. Batch Calculation
var series = new TBarSeries();
// ... populate series ...
var cfbSeries = Cfb.Batch(series);
+95 -75
View File
@@ -1,99 +1,119 @@
# DMX - Jurik Directional Movement Index
DMX is Jurik's advanced replacement for Welles Wilder's DMI/ADX trend indicators. Traditional DMI consists of +DI, -DI (directional movement lines) and ADX (trend strength), but they suffer from noise and lag due to simplistic smoothing (Wilder's moving average). Jurik's DMX addresses this by using the ultra-low-lag Jurik Moving Average (JMA) in place of Wilder's smoothing.
A high-fidelity replacement for Welles Wilder's DMI/ADX that eliminates the "lag vs. noise" trade-off. By substituting Jurik Moving Average (JMA) for standard smoothing, DMX delivers a cleaner, faster-reacting signal that combines trend direction and strength into a single bipolar oscillator.
The result: DMX+ and DMX- lines that are significantly smoother than classical +DI/-DI, and a combined DMX oscillator that crosses zero to signal trend direction changes with minimal lag. In fact, DMX is so smooth that a separate ADX line becomes unnecessary the DMX oscillator itself is both a direction and strength indicator (larger magnitude = stronger trend, sign = trend direction).
## What It Does
## Core Concepts
DMX answers two questions simultaneously: "Which way is the market going?" and "How strong is the move?"
- **JMA Smoothing:** Uses Jurik Moving Average instead of Wilder's Smoothing for DM+, DM-, and TR.
- **Zero-Lag:** JMA provides superior noise reduction with minimal lag compared to EMA/RMA.
- **Bipolar Oscillator:** DMX is calculated as $DI^+ - DI^-$, resulting in a single oscillator ranging from -100 to +100.
- **Trend Detection:**
- Positive values indicate an uptrend.
- Negative values indicate a downtrend.
- Magnitude indicates trend strength.
It takes the core logic of Wilder's Directional Movement System—comparing daily highs and lows to determine directional bias—but upgrades the engine. Instead of the sluggish Wilder's Smoothing (RMA), DMX uses the adaptive JMA to process the raw directional components.
## Parameters
The result is a single line that oscillates between -100 and +100:
- **Positive**: Bulls are in control.
- **Negative**: Bears are in control.
- **Magnitude**: The distance from zero indicates the intensity of the trend.
## Historical Context
Welles Wilder's DMI (1978) is a classic, but its reliance on simple smoothing makes it notoriously slow. To filter out noise, traders had to increase the period, which introduced unacceptable lag. Mark Jurik developed DMX to solve this specific problem. By applying his proprietary JMA smoothing to the raw directional vectors, he created an indicator that could filter noise *without* sacrificing timeliness.
## How It Works
The calculation mirrors the classic DMI structure but swaps the smoothing mechanism.
### The Math
1. **Raw Directional Movement**:
We compare today's range to yesterday's range to see if the expansion is Up or Down.
$$ \text{UpMove} = \text{High}_t - \text{High}_{t-1} $$
$$ \text{DownMove} = \text{Low}_{t-1} - \text{Low}_t $$
$$ DM^+_{raw} = \begin{cases} \text{UpMove} & \text{if } \text{UpMove} > \text{DownMove} \text{ and } \text{UpMove} > 0 \\ 0 & \text{otherwise} \end{cases} $$
$$ DM^-_{raw} = \begin{cases} \text{DownMove} & \text{if } \text{DownMove} > \text{UpMove} \text{ and } \text{DownMove} > 0 \\ 0 & \text{otherwise} \end{cases} $$
2. **True Range (TR)**:
The greatest of: current high-low, high-prevClose, or low-prevClose.
3. **JMA Smoothing** (The Secret Sauce):
Instead of RMA, we use JMA to smooth the components.
$$ DM^+_{smooth} = \text{JMA}(DM^+_{raw}, \text{Period}) $$
$$ DM^-_{smooth} = \text{JMA}(DM^-_{raw}, \text{Period}) $$
$$ \text{ATR}_{smooth} = \text{JMA}(\text{TR}, \text{Period}) $$
4. **Normalization**:
$$ DI^+ = 100 \times \frac{DM^+_{smooth}}{\text{ATR}_{smooth}} $$
$$ DI^- = 100 \times \frac{DM^-_{smooth}}{\text{ATR}_{smooth}} $$
5. **The Oscillator**:
$$ \text{DMX} = DI^+ - DI^- $$
## Configuration
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| Period | int | 14 | The lookback period for JMA smoothing. |
| `period` | `int` | 14 | The lookback period for the internal JMA smoothing. |
## Formula
## Performance Profile
1. **Calculate Raw Directional Movement:**
$$
UpMove = High_t - High_{t-1}
$$
$$
DownMove = Low_{t-1} - Low_t
$$
$$
DM^+_{raw} = \begin{cases} UpMove & \text{if } UpMove > DownMove \text{ and } UpMove > 0 \\ 0 & \text{otherwise} \end{cases}
$$
$$
DM^-_{raw} = \begin{cases} DownMove & \text{if } DownMove > UpMove \text{ and } DownMove > 0 \\ 0 & \text{otherwise} \end{cases}
$$
DMX is computationally heavier than standard DMI due to the JMA calculations, but remains efficient enough for high-frequency use.
2. **Calculate True Range:**
$$
TR_{raw} = \max(High_t - Low_t, |High_t - Close_{t-1}|, |Low_t - Close_{t-1}|)
$$
- **Complexity**: $O(1)$ per update. The heavy lifting is done by the three internal JMA instances.
- **Memory**: Constant space. Stores state for the three JMAs and the previous bar.
- **Allocations**: Zero heap allocations during the `Update` cycle.
3. **Smooth with JMA:**
$$
DM^+_{smooth} = JMA(DM^+_{raw}, Period)
$$
$$
DM^-_{smooth} = JMA(DM^-_{raw}, Period)
$$
$$
ATR_{smooth} = JMA(TR_{raw}, Period)
$$
| Operation | Time Complexity | Space Complexity |
|-----------|-----------------|------------------|
| Update | $O(1)$ | $O(1)$ |
| Batch | $O(N)$ | $O(N)$ |
4. **Calculate Directional Indicators:**
$$
DI^+ = 100 \times \frac{DM^+_{smooth}}{ATR_{smooth}}
$$
$$
DI^- = 100 \times \frac{DM^-_{smooth}}{ATR_{smooth}}
$$
## Interpretation
5. **Calculate DMX:**
$$
DMX = DI^+ - DI^-
$$
DMX simplifies the traditional three-line DMI system (ADX, DI+, DI-) into a single, intuitive metric.
## C# Implementation
### 1. Direction (Zero Cross)
### Standard Usage
- **Bullish**: DMX crosses above 0.
- **Bearish**: DMX crosses below 0.
*Note: Because JMA is low-lag, these crossovers occur significantly earlier than in standard DMI.*
### 2. Strength (Magnitude)
- **Strong Trend**: Values > 25 (or < -25).
- **Extreme Trend**: Values > 50 (or < -50).
- **Chop/Range**: Values hovering near 0.
### 3. Divergence
- **Bearish Divergence**: Price makes a higher high, but DMX makes a lower high (momentum is waning).
- **Bullish Divergence**: Price makes a lower low, but DMX makes a higher low (selling pressure is exhausting).
## Architecture Notes
- **Composite Indicator**: `Dmx` is a wrapper around three `Jma` instances (`_jmaDMp`, `_jmaDMm`, `_jmaTR`).
- **Input Requirement**: Requires `TBar` (High, Low, Close) to calculate directional movement. It cannot be calculated from a simple stream of `double` values.
- **Initialization**: The first bar establishes the baseline; valid values begin appearing immediately, but the indicator warms up over the specified `period`.
## References
- Jurik Research: [DMX - Directional Movement Index](http://www.jurikres.com/catalog/ms_dmx.htm)
- Wilder, J. Welles. *New Concepts in Technical Trading Systems*. Trend Research, 1978.
## C# Usage
```csharp
using QuanTAlib;
var dmx = new Dmx(14);
var bars = new TBarSeries();
// ... add bars ...
// 1. Initialize
var dmx = new Dmx(period: 14);
foreach(var bar in bars) {
var result = dmx.Update(bar);
Console.WriteLine($"DMX: {result.Value}");
}
```
// 2. Process a Bar
var bar = new TBar(DateTime.UtcNow, open: 100, high: 105, low: 95, close: 102, volume: 1000);
var result = dmx.Update(bar);
### Batch Processing
Console.WriteLine($"DMX: {result.Value:F2}");
```csharp
var resultSeries = Dmx.Batch(bars, 14);
```
## Interpretation
- **Crossover:** DMX crossing above 0 signals a potential uptrend start. Crossing below 0 signals a potential downtrend start.
- **Strength:** Higher absolute values indicate a stronger trend. Values near 0 indicate a ranging market.
- **Divergence:** Divergence between price and DMX can signal potential reversals.
## References
- Jurik Research: [DMX Description](http://www.jurikres.com/catalog/ms_dmx.htm)
// 3. Batch Calculation
var series = new TBarSeries();
// ... populate series ...
var dmxSeries = Dmx.Batch(series, period: 14);
+78 -45
View File
@@ -1,68 +1,101 @@
# RSX - Jurik Relative Strength X
RSX is a noise-free version of the Relative Strength Index (RSI) developed by Mark Jurik. It eliminates the lag and choppiness associated with standard RSI and its smoothed variants. RSX preserves the 0-100 bounded range and turning points of RSI but provides a much smoother signal, making it easier to identify trends and reversals without false signals from whipsaw movements.
A "noise-free" version of the Relative Strength Index (RSI) that eliminates the jaggedness of the original without introducing the lag of traditional smoothing. It produces a silky-smooth 0-100 oscillator that preserves the precise timing of market turns.
## Core Concepts
## What It Does
- **Zero Lag:** Uses a specialized IIR filter chain to smooth the data without introducing significant delay.
- **Noise Reduction:** Filters out high-frequency noise while retaining the underlying trend.
- **Bounded Range:** Output is strictly bounded between 0 and 100, similar to RSI.
- **Smoothness:** Produces a clean, continuous curve suitable for precise peak/valley detection.
RSX solves the classic RSI dilemma: standard RSI is too twitchy (generating false signals), but smoothing it makes it too slow (missing the trade).
## Parameters
RSX replaces the simple moving averages in RSI with a sophisticated, cascading filter chain. This allows it to strip out high-frequency noise while tracking the underlying momentum with near-zero latency. The result is a curve that looks like a sine wave—clean, continuous, and devoid of the "jitter" that plagues standard oscillators.
## Historical Context
Mark Jurik developed RSX as part of his suite of "zero-lag" indicators. He recognized that the jagged nature of RSI made it difficult to programmatically detect peaks and valleys. By applying advanced signal processing techniques (similar to those used in guidance systems), he created an indicator that retains the familiar 0-100 scale of RSI but behaves with the smoothness of a much slower moving average.
## How It Works
The algorithm is significantly more complex than standard RSI, employing a multi-stage filter architecture.
### The Math
1. **Momentum Calculation**:
$$ \text{Momentum} = (\text{Price}_t - \text{Price}_{t-1}) \times 100 $$
2. **Cascading Filters**:
The momentum and the absolute momentum are each passed through a chain of three filter stages. Each stage consists of two coupled IIR filters.
$$ \text{Stage}_1 \rightarrow \text{Stage}_2 \rightarrow \text{Stage}_3 $$
This creates a "higher-order" smoothing effect that suppresses noise aggressively while maintaining phase alignment (low lag).
3. **Normalization**:
$$ \text{RSX} = \left( \frac{\text{Smoothed Momentum}}{\text{Smoothed Abs Momentum}} + 1 \right) \times 50 $$
## Configuration
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| Period | int | 14 | The smoothing period (typically 8-40). |
| `period` | `int` | 14 | The smoothing period. Typical values range from 8 to 40. |
## Formula
## Performance Profile
RSX uses a cascading filter structure. The smoothing factor $\alpha$ is derived from the period:
While mathematically dense, the RSX implementation is highly optimized for execution speed.
$$ \alpha = \frac{3}{Period + 2} $$
- **Complexity**: $O(1)$ per update. The filter chain involves a fixed number of floating-point operations regardless of the period.
- **Memory**: Constant space. It stores the state variables for the 12 internal filter nodes (6 for momentum, 6 for absolute momentum).
- **Allocations**: Zero heap allocations during the `Update` cycle.
The algorithm processes price changes ($v_8$) through multiple smoothing stages for both the raw momentum and its absolute value. The final RSX is calculated as:
| Operation | Time Complexity | Space Complexity |
|-----------|-----------------|------------------|
| Update | $O(1)$ | $O(1)$ |
| Batch | $O(N)$ | $O(N)$ |
$$ RSX = \left( \frac{v_{14}}{v_{20}} + 1 \right) \times 50 $$
## Interpretation
Where $v_{14}$ is the smoothed momentum and $v_{20}$ is the smoothed absolute momentum.
RSX is interpreted exactly like RSI, but with higher confidence due to the lack of noise.
## C# Implementation
### 1. Overbought / Oversold
### Standard Usage
- **Overbought**: > 70 (or 80).
- **Oversold**: < 30 (or 20).
*Note: Because RSX is smoother, it spends less time "wiggling" in the extreme zones. An exit from the zone is a cleaner signal.*
### 2. Divergence
RSX is exceptional for spotting divergence because its peaks and valleys are distinct.
- **Bearish Divergence**: Price makes a higher high, RSX makes a lower high.
- **Bullish Divergence**: Price makes a lower low, RSX makes a higher low.
### 3. Trend Confirmation
- **Bullish**: RSX > 50.
- **Bearish**: RSX < 50.
## Architecture Notes
- **Filter Chain**: The class implements the Jurik filter chain directly rather than relying on external classes. This ensures maximum performance and encapsulation.
- **Warmup**: The filter requires a warmup period to stabilize. The `IsHot` property indicates when the internal state has converged.
- **Input**: Accepts `TValue` (Close price). Unlike DMX, it does not require High/Low data.
## References
- Jurik Research: [RSX - Relative Strength Quality Index](http://www.jurikres.com/catalog/ms_rsx.htm)
- ProRealCode: [Jurik RSX Implementation](https://www.prorealcode.com/prorealtime-indicators/jurik-rsx/)
## C# Usage
```csharp
using QuanTAlib;
var rsx = new Rsx(14);
var result = rsx.Update(new TValue(DateTime.UtcNow, price));
Console.WriteLine($"RSX: {result.Value}");
```
// 1. Initialize
var rsx = new Rsx(period: 14);
### Span API (High Performance)
// 2. Process a Value
// RSX typically uses Close price
var result = rsx.Update(new TValue(DateTime.UtcNow, 105.5));
```csharp
double[] prices = { ... };
double[] results = new double[prices.Length];
Console.WriteLine($"RSX: {result.Value:F2}");
Rsx.Batch(prices, results, 14);
```
### Chaining
```csharp
var rsx = new Rsx(14);
var sma = new Sma(rsx, 3); // Smooth the RSX further
```
## Interpretation
- **Overbought/Oversold:** Values above 70 (or 80) indicate overbought conditions, while values below 30 (or 20) indicate oversold conditions.
- **Trend Confirmation:** RSX crossing 50 can signal a trend change.
- **Divergence:** Divergence between price and RSX often precedes a reversal.
- **Smoothness:** Due to its smoothness, RSX slope changes are more significant than RSI slope changes.
## References
- [Jurik Research](http://www.jurikres.com/)
- [ProRealCode - Jurik RSX](https://www.prorealcode.com/prorealtime-indicators/jurik-rsx/)
// 3. Batch Calculation
var series = new TBarSeries();
// ... populate series ...
var rsxSeries = Rsx.Batch(series.Close, period: 14);
+80 -44
View File
@@ -1,66 +1,102 @@
# VEL - Jurik Velocity
VEL (Jurik's Velocity) is a momentum oscillator that measures the rate of change of price. It is calculated as the difference between a Parabolic Weighted Moving Average (PWMA) and a Weighted Moving Average (WMA) of the same period.
A momentum oscillator that measures the market's "acceleration" by comparing two different weighting schemes. It isolates the rate of change without the noise inherent in simple price differencing.
## Core Concepts
## What It Does
- **Momentum:** Measures the speed of price movement.
- **Smoothing:** Uses moving averages to reduce noise compared to raw ROC (Rate of Change).
- **Parabolic vs Linear:** By subtracting a linear weighted average from a parabolic weighted average, VEL isolates the acceleration component of the price movement.
VEL answers the question: "Is the trend speeding up or slowing down?"
## Formula
Standard momentum indicators (like ROC) simply compare today's price to the price $N$ days ago. This is noisy and laggy. VEL takes a smarter approach: it compares a **Parabolic Weighted Moving Average (PWMA)** to a **Linear Weighted Moving Average (WMA)** of the same period.
$$
VEL_t = PWMA_t(n) - WMA_t(n)
$$
Because PWMA weights recent data more aggressively (parabolically) than WMA (linearly), the difference between them reveals the "velocity" of the price movement. If prices are accelerating, the parabolic average pulls away from the linear one.
## Historical Context
Mark Jurik designed VEL to be a smoother, more responsive alternative to Momentum and ROC. By using the differential between two smoothed averages, he created a "derivative" indicator that captures the second-order characteristics of price movement (acceleration) while filtering out the high-frequency jitter that plagues raw rate-of-change calculations.
## How It Works
The magic lies in the weighting curves of the two underlying averages.
### The Math
$$ \text{VEL} = \text{PWMA}(n) - \text{WMA}(n) $$
Where:
- $n$ is the period.
- $PWMA_t(n)$ is the Parabolic Weighted Moving Average.
- $WMA_t(n)$ is the Weighted Moving Average.
- **PWMA**: Parabolic Weighted Moving Average. Weights decrease rapidly as you go back in time ($weight \propto x^2$).
- **WMA**: Weighted Moving Average. Weights decrease linearly as you go back in time ($weight \propto x$).
## Parameters
### The Logic
1. **Uptrend Acceleration**: Price is rising fast. The aggressive PWMA reacts quicker than the linear WMA. VEL becomes positive and rising.
2. **Uptrend Deceleration**: Price is still rising, but slower. The PWMA starts to converge with the WMA. VEL peaks and turns down (while price is still going up).
3. **Zero Cross**: The momentum has shifted. The "speed" is now zero, marking a potential reversal or transition to a downtrend.
## Configuration
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| Period | int | - | The number of data points used in the calculation. Must be >= 1. |
| `period` | `int` | 14 | The lookback period for both underlying averages. |
## Usage
## Performance Profile
### Standard Usage
VEL is a composite indicator that delegates its work to two efficient moving averages.
- **Complexity**: $O(1)$ per update. Both PWMA and WMA are implemented with $O(1)$ running sum algorithms.
- **Memory**: Constant space. Stores state for the two internal averages.
- **Allocations**: Zero heap allocations during the `Update` cycle.
| Operation | Time Complexity | Space Complexity |
|-----------|-----------------|------------------|
| Update | $O(1)$ | $O(1)$ |
| Batch | $O(N)$ | $O(N)$ |
## Interpretation
VEL is a classic centered oscillator.
### 1. Zero Line Crossover
- **Bullish Cross**: VEL crosses above 0. Momentum has shifted from negative to positive.
- **Bearish Cross**: VEL crosses below 0. Momentum has shifted from positive to negative.
### 2. Leading Indicator
VEL often turns *before* the price.
- **Peak**: A peak in VEL indicates that the *rate* of the price rise has maxed out. Price may continue to rise, but the "fuel" is running low.
- **Valley**: A trough in VEL indicates that the selling pressure has maxed out.
### 3. Divergence
- **Bearish Divergence**: Price makes a higher high, VEL makes a lower high. The trend is exhausting.
- **Bullish Divergence**: Price makes a lower low, VEL makes a higher low. The sell-off is losing steam.
## Architecture Notes
- **Composite Structure**: `Vel` wraps instances of `Pwma` and `Wma`.
- **Batch Optimization**: The static `Batch` method uses SIMD vector subtraction (`SimdExtensions.Subtract`) to compute the difference between the two averages efficiently over large datasets.
- **Warmup**: The indicator is considered "hot" when both underlying averages are hot.
## References
- Jurik Research: [VEL - Velocity](http://www.jurikres.com/catalog/ms_vel.htm)
## C# Usage
```csharp
using QuanTAlib;
var vel = new Vel(14);
var result = vel.Update(new TValue(DateTime.UtcNow, 100.0));
Console.WriteLine($"VEL: {result.Value}");
```
// 1. Initialize
var vel = new Vel(period: 14);
### Chaining
// 2. Process a Value
var result = vel.Update(new TValue(DateTime.UtcNow, 105.5));
```csharp
var source = new Sma(10);
var vel = new Vel(source, 14);
```
Console.WriteLine($"Velocity: {result.Value:F2}");
### Batch Calculation (Span)
For high-performance scenarios, use the static `Batch` method with `Span<double>`.
```csharp
double[] prices = { ... };
double[] results = new double[prices.Length];
Vel.Batch(prices, results, 14);
```
## Interpretation
- **Zero Line Crossovers:** Crossing above zero indicates increasing upward momentum (acceleration). Crossing below zero indicates increasing downward momentum (deceleration).
- **Divergence:** Divergence between price and VEL can signal potential reversals.
- **Extremes:** High positive or negative values indicate strong momentum, which might precede a reversal or consolidation.
## References
- Jurik Research
// 3. Batch Calculation
var series = new TBarSeries();
// ... populate series ...
var velSeries = Vel.Batch(series, period: 14);
+64 -64
View File
@@ -51,70 +51,6 @@ For the calculation, we use a **RingBuffer** to store the price window. The weig
**Configuration note:** The default combination (Period 9, Offset 0.85, Sigma 6) is widely used as a responsive trend filter.
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var alma = new Alma(period: 9, offset: 0.85, sigma: 6.0);
// Process each new bar
TValue result = alma.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"ALMA: {result.Value:F2}");
// Check if buffer is full
if (alma.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TSeries API (object-oriented)
TSeries prices = ...;
TSeries almaValues = Alma.Batch(prices, period: 9, offset: 0.85, sigma: 6.0);
// High-performance Span API (zero allocation)
double[] prices = new double[10000];
double[] output = new double[10000];
Alma.Calculate(prices.AsSpan(), output.AsSpan(), period: 9, offset: 0.85, sigma: 6.0);
```
### Bar Correction (isNew Parameter)
```csharp
var alma = new Alma(9);
// New bar arrives
alma.Update(new TValue(time, 100.5), isNew: true);
// Intra-bar price updates (real-time tick data)
alma.Update(new TValue(time, 101.0), isNew: false); // Updates current bar
alma.Update(new TValue(time, 100.8), isNew: false); // Updates current bar
// Next bar
alma.Update(new TValue(time + 60, 101.2), isNew: true); // Advances state
```
### Event-Driven Architecture
```csharp
var source = new TSeries();
var alma = new Alma(source, period: 9);
// Subscribe to ALMA output
alma.Pub += (value) => {
Console.WriteLine($"New ALMA value: {value.Value}");
};
// Feeding source automatically triggers the chain
source.Add(new TValue(DateTime.Now, 105.2));
```
## Performance Profile
| Operation | Complexity | Description |
@@ -201,3 +137,67 @@ This implementation makes specific trade-offs:
## References
- Legoux, Arnaud. "ALMA: Arnaud Legoux Moving Average."
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var alma = new Alma(period: 9, offset: 0.85, sigma: 6.0);
// Process each new bar
TValue result = alma.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"ALMA: {result.Value:F2}");
// Check if buffer is full
if (alma.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TSeries API (object-oriented)
TSeries prices = ...;
TSeries almaValues = Alma.Batch(prices, period: 9, offset: 0.85, sigma: 6.0);
// High-performance Span API (zero allocation)
double[] prices = new double[10000];
double[] output = new double[10000];
Alma.Calculate(prices.AsSpan(), output.AsSpan(), period: 9, offset: 0.85, sigma: 6.0);
```
### Bar Correction (isNew Parameter)
```csharp
var alma = new Alma(9);
// New bar arrives
alma.Update(new TValue(time, 100.5), isNew: true);
// Intra-bar price updates (real-time tick data)
alma.Update(new TValue(time, 101.0), isNew: false); // Updates current bar
alma.Update(new TValue(time, 100.8), isNew: false); // Updates current bar
// Next bar
alma.Update(new TValue(time + 60, 101.2), isNew: true); // Advances state
```
### Event-Driven Architecture
```csharp
var source = new TSeries();
var alma = new Alma(source, period: 9);
// Subscribe to ALMA output
alma.Pub += (value) => {
Console.WriteLine($"New ALMA value: {value.Value}");
};
// Feeding source automatically triggers the chain
source.Add(new TValue(DateTime.Now, 105.2));
```
+43 -43
View File
@@ -42,49 +42,6 @@ The `Conv` indicator uses a **RingBuffer** to store the price history efficientl
**Note:** The kernel is not automatically normalized. If you want a moving average that tracks price levels, the sum of your kernel weights should equal 1.0. If the sum is 0 (e.g., `[-1, 1]`), it will act as an oscillator.
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
// Create a custom kernel (e.g., a 3-period weighted average)
double[] weights = { 0.1, 0.3, 0.6 };
var conv = new Conv(weights);
// Process each new bar
TValue result = conv.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"Conv: {result.Value:F2}");
```
### Batch Processing (Historical Data)
```csharp
// TSeries API
TSeries prices = ...;
double[] kernel = { 0.2, 0.2, 0.2, 0.2, 0.2 }; // 5-period SMA
TSeries sma5 = Conv.Batch(prices, kernel);
// Span API (High Performance)
double[] prices = new double[1000];
double[] output = new double[1000];
double[] edgeDetector = { -1, 1 }; // Simple difference
Conv.Batch(prices.AsSpan(), output.AsSpan(), edgeDetector);
```
### Bar Correction (isNew Parameter)
```csharp
var conv = new Conv(new[] { 0.5, 0.5 });
// New bar
conv.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
conv.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
## Performance Profile
| Operation | Complexity | Description |
@@ -129,3 +86,46 @@ This implementation makes specific trade-offs:
- Smith, Steven W. "The Scientist and Engineer's Guide to Digital Signal Processing." California Technical Publishing, 1997.
- Ehlers, John F. "Cycle Analytics for Traders." Wiley, 2013.
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
// Create a custom kernel (e.g., a 3-period weighted average)
double[] weights = { 0.1, 0.3, 0.6 };
var conv = new Conv(weights);
// Process each new bar
TValue result = conv.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"Conv: {result.Value:F2}");
```
### Batch Processing (Historical Data)
```csharp
// TSeries API
TSeries prices = ...;
double[] kernel = { 0.2, 0.2, 0.2, 0.2, 0.2 }; // 5-period SMA
TSeries sma5 = Conv.Batch(prices, kernel);
// Span API (High Performance)
double[] prices = new double[1000];
double[] output = new double[1000];
double[] edgeDetector = { -1, 1 }; // Simple difference
Conv.Batch(prices.AsSpan(), output.AsSpan(), edgeDetector);
```
### Bar Correction (isNew Parameter)
```csharp
var conv = new Conv(new[] { 0.5, 0.5 });
// New bar
conv.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
conv.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
+45 -45
View File
@@ -43,51 +43,6 @@ Our implementation uses a zero-lag initialization technique for the internal EMA
**Configuration note:** Because DEMA is faster than EMA, you may need to use a slightly longer period (e.g., 14 instead of 10) to get comparable smoothness with better responsiveness.
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var dema = new Dema(period: 10);
// Process each new bar
TValue result = dema.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"DEMA: {result.Value:F2}");
// Check if buffer is full
if (dema.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TSeries API
TSeries prices = ...;
TSeries demaValues = Dema.Calculate(prices, period: 10);
// Span API (High Performance)
double[] prices = new double[1000];
double[] output = new double[1000];
Dema.Calculate(prices.AsSpan(), output.AsSpan(), period: 10);
```
### Bar Correction (isNew Parameter)
```csharp
var dema = new Dema(10);
// New bar
dema.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
dema.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
## Performance Profile
| Operation | Complexity | Description |
@@ -151,3 +106,48 @@ This implementation makes specific trade-offs:
## References
- Mulloy, Patrick G. "Smoothing Data With Faster Moving Averages." Technical Analysis of Stocks & Commodities, Jan. 1994.
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var dema = new Dema(period: 10);
// Process each new bar
TValue result = dema.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"DEMA: {result.Value:F2}");
// Check if buffer is full
if (dema.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TSeries API
TSeries prices = ...;
TSeries demaValues = Dema.Calculate(prices, period: 10);
// Span API (High Performance)
double[] prices = new double[1000];
double[] output = new double[1000];
Dema.Calculate(prices.AsSpan(), output.AsSpan(), period: 10);
```
### Bar Correction (isNew Parameter)
```csharp
var dema = new Dema(10);
// New bar
dema.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
dema.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
+45 -45
View File
@@ -42,51 +42,6 @@ Our implementation wraps two instances of the `Wma` class.
**Configuration note:** A DWMA(10) will have roughly the same lag as a WMA(15-20) but will be significantly smoother.
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var dwma = new Dwma(period: 14);
// Process each new bar
TValue result = dwma.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"DWMA: {result.Value:F2}");
// Check if buffer is full
if (dwma.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TSeries API
TSeries prices = ...;
TSeries dwmaValues = Dwma.Batch(prices, period: 14);
// Span API (High Performance)
double[] prices = new double[1000];
double[] output = new double[1000];
Dwma.Calculate(prices.AsSpan(), output.AsSpan(), period: 14);
```
### Bar Correction (isNew Parameter)
```csharp
var dwma = new Dwma(14);
// New bar
dwma.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
dwma.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
## Performance Profile
| Operation | Complexity | Description |
@@ -150,3 +105,48 @@ This implementation makes specific trade-offs:
## References
- Kaufman, Perry J. "Trading Systems and Methods." Wiley, 2013.
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var dwma = new Dwma(period: 14);
// Process each new bar
TValue result = dwma.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"DWMA: {result.Value:F2}");
// Check if buffer is full
if (dwma.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TSeries API
TSeries prices = ...;
TSeries dwmaValues = Dwma.Batch(prices, period: 14);
// Span API (High Performance)
double[] prices = new double[1000];
double[] output = new double[1000];
Dwma.Calculate(prices.AsSpan(), output.AsSpan(), period: 14);
```
### Bar Correction (isNew Parameter)
```csharp
var dwma = new Dwma(14);
// New bar
dwma.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
dwma.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
+45 -45
View File
@@ -60,51 +60,6 @@ Standard EMAs usually start at 0 or the first price, requiring a long "warmup" p
**Configuration note:** The 200-day EMA is a standard institutional benchmark for long-term trend direction.
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var ema = new Ema(period: 14);
// Process each new bar
TValue result = ema.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"EMA: {result.Value:F2}");
// Check if buffer is full
if (ema.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TSeries API
TSeries prices = ...;
TSeries emaValues = Ema.Batch(prices, period: 14);
// Span API (High Performance)
double[] prices = new double[1000];
double[] output = new double[1000];
Ema.Batch(prices.AsSpan(), output.AsSpan(), period: 14);
```
### Bar Correction (isNew Parameter)
```csharp
var ema = new Ema(14);
// New bar
ema.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
ema.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
## Performance Profile
| Operation | Complexity | Description |
@@ -176,3 +131,48 @@ This implementation makes specific trade-offs:
- Brown, Robert G. "Statistical Forecasting for Inventory Control." McGraw-Hill, 1959.
- Appel, Gerald. "Technical Analysis: Power Tools for Active Investors." FT Press, 2005.
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var ema = new Ema(period: 14);
// Process each new bar
TValue result = ema.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"EMA: {result.Value:F2}");
// Check if buffer is full
if (ema.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TSeries API
TSeries prices = ...;
TSeries emaValues = Ema.Batch(prices, period: 14);
// Span API (High Performance)
double[] prices = new double[1000];
double[] output = new double[1000];
Ema.Batch(prices.AsSpan(), output.AsSpan(), period: 14);
```
### Bar Correction (isNew Parameter)
```csharp
var ema = new Ema(14);
// New bar
ema.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
ema.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
+45 -45
View File
@@ -48,51 +48,6 @@ Our implementation orchestrates three internal `Wma` instances.
**Configuration note:** HMA is significantly faster than SMA or EMA. An HMA(20) is often faster than an EMA(10).
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var hma = new Hma(period: 14);
// Process each new bar
TValue result = hma.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"HMA: {result.Value:F2}");
// Check if buffer is full
if (hma.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TSeries API
TSeries prices = ...;
TSeries hmaValues = Hma.Batch(prices, period: 14);
// Span API (High Performance)
double[] prices = new double[1000];
double[] output = new double[1000];
Hma.Calculate(prices.AsSpan(), output.AsSpan(), period: 14);
```
### Bar Correction (isNew Parameter)
```csharp
var hma = new Hma(14);
// New bar
hma.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
hma.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
## Performance Profile
| Operation | Complexity | Description |
@@ -154,3 +109,48 @@ This implementation makes specific trade-offs:
- Hull, Alan. "Active Investing." Wrightbooks, 2005.
- [Alan Hull's Official HMA Description](https://alan.hull.com.au/hma.html)
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var hma = new Hma(period: 14);
// Process each new bar
TValue result = hma.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"HMA: {result.Value:F2}");
// Check if buffer is full
if (hma.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TSeries API
TSeries prices = ...;
TSeries hmaValues = Hma.Batch(prices, period: 14);
// Span API (High Performance)
double[] prices = new double[1000];
double[] output = new double[1000];
Hma.Calculate(prices.AsSpan(), output.AsSpan(), period: 14);
```
### Bar Correction (isNew Parameter)
```csharp
var hma = new Hma(14);
// New bar
hma.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
hma.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
+45 -45
View File
@@ -42,51 +42,6 @@ Our implementation follows Ehlers' original code structure but optimized for C#.
**Configuration note:** The lack of parameters is a feature, not a bug. It prevents "curve fitting" and ensures the indicator relies on measured market properties rather than user guesses.
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var htit = new Htit();
// Process each new bar
TValue result = htit.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"HTIT: {result.Value:F2}");
// Check if buffer is full (requires some history to establish cycle)
if (htit.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TSeries API
TSeries prices = ...;
TSeries htitValues = Htit.Batch(prices);
// Span API (High Performance)
double[] prices = new double[1000];
double[] output = new double[1000];
Htit.Batch(prices.AsSpan(), output.AsSpan());
```
### Bar Correction (isNew Parameter)
```csharp
var htit = new Htit();
// New bar
htit.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
htit.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
## Performance Profile
| Operation | Complexity | Description |
@@ -138,3 +93,48 @@ This implementation makes specific trade-offs:
- Ehlers, John F. "Rocket Science for Traders: Digital Signal Processing Applications." Wiley, 2001.
- Ehlers, John F. "Cybernetic Analysis for Stocks and Futures." Wiley, 2004.
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var htit = new Htit();
// Process each new bar
TValue result = htit.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"HTIT: {result.Value:F2}");
// Check if buffer is full (requires some history to establish cycle)
if (htit.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TSeries API
TSeries prices = ...;
TSeries htitValues = Htit.Batch(prices);
// Span API (High Performance)
double[] prices = new double[1000];
double[] output = new double[1000];
Htit.Batch(prices.AsSpan(), output.AsSpan());
```
### Bar Correction (isNew Parameter)
```csharp
var htit = new Htit();
// New bar
htit.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
htit.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
+45 -45
View File
@@ -47,51 +47,6 @@ Our implementation is optimized for performance:
**Configuration note:** The `Phase` parameter is unique to JMA. A phase of 100 makes it act like a TEMA (very fast, some overshoot), while -100 makes it act like a Gaussian filter (no overshoot, more lag). 0 is the optimal balance.
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var jma = new Jma(period: 10, phase: 0);
// Process each new bar
TValue result = jma.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"JMA: {result.Value:F2}");
// Check if buffer is full (JMA needs a long warmup)
if (jma.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TSeries API
TSeries prices = ...;
TSeries jmaValues = Jma.Batch(prices, period: 10, phase: 0);
// Span API (High Performance)
double[] prices = new double[1000];
double[] output = new double[1000];
Jma.Batch(prices.AsSpan(), output.AsSpan(), period: 10, phase: 0);
```
### Bar Correction (isNew Parameter)
```csharp
var jma = new Jma(10);
// New bar
jma.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
jma.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
## Performance Profile
| Operation | Complexity | Description |
@@ -146,3 +101,48 @@ This implementation makes specific trade-offs:
- Jurik, Mark. "Jurik Research." [http://www.jurikres.com/](http://www.jurikres.com/)
- "JMA - Jurik Moving Average." Technical Analysis of Stocks & Commodities.
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var jma = new Jma(period: 10, phase: 0);
// Process each new bar
TValue result = jma.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"JMA: {result.Value:F2}");
// Check if buffer is full (JMA needs a long warmup)
if (jma.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TSeries API
TSeries prices = ...;
TSeries jmaValues = Jma.Batch(prices, period: 10, phase: 0);
// Span API (High Performance)
double[] prices = new double[1000];
double[] output = new double[1000];
Jma.Batch(prices.AsSpan(), output.AsSpan(), period: 10, phase: 0);
```
### Bar Correction (isNew Parameter)
```csharp
var jma = new Jma(10);
// New bar
jma.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
jma.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
+45 -45
View File
@@ -50,51 +50,6 @@ Our implementation is fully optimized for O(1) updates.
**Configuration note:** The default settings (10, 2, 30) are widely used and robust. Adjusting the Slow Period to 80 or 100 can create an extremely stable filter for long-term trend following.
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var kama = new Kama(period: 10, fastPeriod: 2, slowPeriod: 30);
// Process each new bar
TValue result = kama.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"KAMA: {result.Value:F2}");
// Check if buffer is full
if (kama.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TSeries API
TSeries prices = ...;
TSeries kamaValues = Kama.Batch(prices, period: 10);
// Span API (High Performance)
double[] prices = new double[1000];
double[] output = new double[1000];
Kama.Batch(prices.AsSpan(), output.AsSpan(), period: 10, fastPeriod: 2, slowPeriod: 30);
```
### Bar Correction (isNew Parameter)
```csharp
var kama = new Kama(10);
// New bar
kama.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
kama.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
## Performance Profile
| Operation | Complexity | Description |
@@ -140,3 +95,48 @@ This implementation makes specific trade-offs:
- Kaufman, Perry J. "Smarter Trading: Improving Performance in Changing Markets." McGraw-Hill, 1995.
- Kaufman, Perry J. "Trading Systems and Methods." Wiley, 2013.
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var kama = new Kama(period: 10, fastPeriod: 2, slowPeriod: 30);
// Process each new bar
TValue result = kama.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"KAMA: {result.Value:F2}");
// Check if buffer is full
if (kama.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TSeries API
TSeries prices = ...;
TSeries kamaValues = Kama.Batch(prices, period: 10);
// Span API (High Performance)
double[] prices = new double[1000];
double[] output = new double[1000];
Kama.Batch(prices.AsSpan(), output.AsSpan(), period: 10, fastPeriod: 2, slowPeriod: 30);
```
### Bar Correction (isNew Parameter)
```csharp
var kama = new Kama(10);
// New bar
kama.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
kama.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
+53 -53
View File
@@ -56,6 +56,59 @@ This allows the LSMA to update in constant time regardless of the period length.
| Offset | 0 | Projection shift | 0 = current bar; >0 projects future; <0 retrieves past regression value |
| Source | Close | Price input | Can be applied to any data series |
## Performance Profile
| Operation | Complexity | Description |
|-----------|------------|-------------------|
| Streaming update | O(1) | Constant time regression update |
| Bar correction | O(1) | Efficient state rollback for real-time feeds |
| Batch processing | O(n) | Fast sequential processing |
| Memory footprint | O(period) | Uses a RingBuffer to store the lookback window |
## Interpretation
### Trading Signals
#### Trend Direction
- **Bullish:** LSMA is rising and price is above LSMA.
- **Bearish:** LSMA is falling and price is below LSMA.
#### Crossovers
- **Price Crossover:** Price crossing the LSMA line is often used as a signal of trend change.
- **Slope Change:** A change in the slope of the LSMA (e.g., from positive to negative) indicates a potential reversal.
### When It Works Best
- **Trending Markets:** LSMA provides a smooth, responsive trend line that hugs price action closer than SMA.
- **Reversals:** Due to its regression nature, it can identify turning points relatively quickly.
### When It Struggles
- **Sideways Markets:** Like other moving averages, it can produce whipsaws in ranging conditions, though the regression fit may offer slightly better noise filtering than a raw SMA.
### Architecture Notes
This implementation makes specific trade-offs:
### Choice: O(1) Regression Update
- **Alternative:** Recalculate regression sums every bar (O(n)).
- **Trade-off:** Requires maintaining running sums for $\sum y$ and $\sum xy$.
- **Rationale:** Essential for performance when using long periods or processing high-frequency data.
### Choice: Periodic Resync
- **Alternative:** Rely solely on incremental updates.
- **Trade-off:** Small CPU cost every 1,000 ticks.
- **Rationale:** Prevents floating-point error accumulation in the $\sum xy$ term, ensuring long-term accuracy.
## References
- [Linear Regression in Technical Analysis](https://www.investopedia.com/terms/l/linearregression.asp)
- [Least Squares Moving Average](https://www.tradingview.com/support/solutions/43000502584-least-squares-moving-average-lsma/)
## C# Usage
### Streaming Updates (Single Instance)
@@ -129,56 +182,3 @@ lsma.Update(new TValue(time, 100));
lsma.Update(new TValue(time, double.NaN)); // Uses last valid value (100)
lsma.Update(new TValue(time, 110)); // Resumes normal calculation
```
## Performance Profile
| Operation | Complexity | Description |
|-----------|------------|-------------------|
| Streaming update | O(1) | Constant time regression update |
| Bar correction | O(1) | Efficient state rollback for real-time feeds |
| Batch processing | O(n) | Fast sequential processing |
| Memory footprint | O(period) | Uses a RingBuffer to store the lookback window |
## Interpretation
### Trading Signals
#### Trend Direction
- **Bullish:** LSMA is rising and price is above LSMA.
- **Bearish:** LSMA is falling and price is below LSMA.
#### Crossovers
- **Price Crossover:** Price crossing the LSMA line is often used as a signal of trend change.
- **Slope Change:** A change in the slope of the LSMA (e.g., from positive to negative) indicates a potential reversal.
### When It Works Best
- **Trending Markets:** LSMA provides a smooth, responsive trend line that hugs price action closer than SMA.
- **Reversals:** Due to its regression nature, it can identify turning points relatively quickly.
### When It Struggles
- **Sideways Markets:** Like other moving averages, it can produce whipsaws in ranging conditions, though the regression fit may offer slightly better noise filtering than a raw SMA.
### Architecture Notes
This implementation makes specific trade-offs:
### Choice: O(1) Regression Update
- **Alternative:** Recalculate regression sums every bar (O(n)).
- **Trade-off:** Requires maintaining running sums for $\sum y$ and $\sum xy$.
- **Rationale:** Essential for performance when using long periods or processing high-frequency data.
### Choice: Periodic Resync
- **Alternative:** Rely solely on incremental updates.
- **Trade-off:** Small CPU cost every 1,000 ticks.
- **Rationale:** Prevents floating-point error accumulation in the $\sum xy$ term, ensuring long-term accuracy.
## References
- [Linear Regression in Technical Analysis](https://www.investopedia.com/terms/l/linearregression.asp)
- [Least Squares Moving Average](https://www.tradingview.com/support/solutions/43000502584-least-squares-moving-average-lsma/)
+48 -49
View File
@@ -42,6 +42,54 @@ The implementation uses a Homodyne Discriminator to measure the cycle period and
| Fast Limit | 0.5 | Maximum adaptation rate | Controls sensitivity in trending markets. Higher = faster response. |
| Slow Limit | 0.05 | Minimum adaptation rate | Controls stability in ranging markets. Lower = smoother. |
## Performance Profile
| Operation | Complexity | Description |
|-----------|------------|-------------------|
| Streaming update | O(1) | Constant time DSP calculation |
| Batch processing | O(n) | Fast sequential processing |
| Memory footprint | O(1) | Fixed-size RingBuffers (7 elements) |
## Interpretation
### Trading Signals
#### Crossovers
- **Bullish:** MAMA crosses above FAMA. This typically happens early in a new uptrend.
- **Bearish:** MAMA crosses below FAMA. This signals the start of a downtrend.
#### Trend Strength
- **Separation:** The distance between MAMA and FAMA indicates the strength of the trend. Wide separation suggests a strong trend; convergence suggests consolidation.
### When It Works Best
- **Cycle-to-Trend Transitions:** MAMA excels at identifying when a market breaks out of a cycle into a trend, adapting its speed instantly.
### When It Struggles
- **Erratic Volatility:** Extremely noisy markets with no discernible cycle or trend can cause the phase calculation to be erratic, leading to false signals.
### Architecture Notes
This implementation makes specific trade-offs:
### Choice: Fixed-Size Buffers
- **Implementation:** Uses `RingBuffer` of size 7.
- **Rationale:** The Hilbert Transform and smoothing filters used by Ehlers have fixed coefficients requiring exactly 7 historical points. This ensures O(1) memory usage.
### Choice: Stack Allocation for Batch
- **Implementation:** Uses `stackalloc` for internal buffers in the static `Calculate` method.
- **Rationale:** Eliminates heap allocations during batch processing, maximizing performance for large datasets.
## References
- Ehlers, John F. "MESA and Trading Market Cycles." John Wiley & Sons, 2001.
- Ehlers, John F. "Cycle Analytics for Traders." John Wiley & Sons, 2013.
## C# Usage
### Streaming Updates (Single Instance)
@@ -90,52 +138,3 @@ mama.Pub += (value) => {
// Feeding source automatically triggers the chain
source.Add(new TValue(DateTime.Now, 105.2));
```
## Performance Profile
| Operation | Complexity | Description |
|-----------|------------|-------------------|
| Streaming update | O(1) | Constant time DSP calculation |
| Batch processing | O(n) | Fast sequential processing |
| Memory footprint | O(1) | Fixed-size RingBuffers (7 elements) |
## Interpretation
### Trading Signals
#### Crossovers
- **Bullish:** MAMA crosses above FAMA. This typically happens early in a new uptrend.
- **Bearish:** MAMA crosses below FAMA. This signals the start of a downtrend.
#### Trend Strength
- **Separation:** The distance between MAMA and FAMA indicates the strength of the trend. Wide separation suggests a strong trend; convergence suggests consolidation.
### When It Works Best
- **Cycle-to-Trend Transitions:** MAMA excels at identifying when a market breaks out of a cycle into a trend, adapting its speed instantly.
### When It Struggles
- **Erratic Volatility:** Extremely noisy markets with no discernible cycle or trend can cause the phase calculation to be erratic, leading to false signals.
### Architecture Notes
This implementation makes specific trade-offs:
### Choice: Fixed-Size Buffers
- **Implementation:** Uses `RingBuffer` of size 7.
- **Rationale:** The Hilbert Transform and smoothing filters used by Ehlers have fixed coefficients requiring exactly 7 historical points. This ensures O(1) memory usage.
### Choice: Stack Allocation for Batch
- **Implementation:** Uses `stackalloc` for internal buffers in the static `Calculate` method.
- **Rationale:** Eliminates heap allocations during batch processing, maximizing performance for large datasets.
## References
- Ehlers, John F. "MESA and Trading Market Cycles." John Wiley & Sons, 2001.
- Ehlers, John F. "Cycle Analytics for Traders." John Wiley & Sons, 2013.
+47 -48
View File
@@ -41,54 +41,6 @@ Where:
| Period | 14 | Base lookback window | Standard is 14. Adjust based on the timeframe (e.g., 10 for short-term, 20+ for long-term). |
| K | 0.6 | Sensitivity constant | 0.6 (60%) is the standard. Lower values make it more sensitive; higher values make it smoother. |
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var mgdi = new Mgdi(period: 14, k: 0.6);
// Process each new bar
TValue result = mgdi.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"MGDI: {result.Value:F2}");
// Check if buffer is full
if (mgdi.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TSeries API (object-oriented)
TSeries prices = ...;
TSeries mgdiValues = Mgdi.Batch(prices, period: 14, k: 0.6);
// High-performance Span API (zero allocation)
double[] prices = new double[10000];
double[] output = new double[10000];
Mgdi.Calculate(prices.AsSpan(), output.AsSpan(), period: 14, k: 0.6);
```
### Event-Driven Architecture
```csharp
var source = new TSeries();
var mgdi = new Mgdi(source, period: 14);
// Subscribe to MGDI output
mgdi.Pub += (value) => {
Console.WriteLine($"New MGDI value: {value.Value}");
};
// Feeding source automatically triggers the chain
source.Add(new TValue(DateTime.Now, 105.2));
```
## Performance Profile
| Operation | Complexity | Description |
@@ -138,3 +90,50 @@ This implementation makes specific trade-offs:
- [Investopedia: McGinley Dynamic Indicator](https://www.investopedia.com/terms/m/mcginley-dynamic.asp)
- [Stock Indicators for .NET: McGinley Dynamic](https://dotnet.stockindicators.dev/indicators/Dynamic/)
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var mgdi = new Mgdi(period: 14, k: 0.6);
// Process each new bar
TValue result = mgdi.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"MGDI: {result.Value:F2}");
// Check if buffer is full
if (mgdi.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TSeries API (object-oriented)
TSeries prices = ...;
TSeries mgdiValues = Mgdi.Batch(prices, period: 14, k: 0.6);
// High-performance Span API (zero allocation)
double[] prices = new double[10000];
double[] output = new double[10000];
Mgdi.Calculate(prices.AsSpan(), output.AsSpan(), period: 14, k: 0.6);
```
### Event-Driven Architecture
```csharp
var source = new TSeries();
var mgdi = new Mgdi(source, period: 14);
// Subscribe to MGDI output
mgdi.Pub += (value) => {
Console.WriteLine($"New MGDI value: {value.Value}");
};
// Feeding source automatically triggers the chain
source.Add(new TValue(DateTime.Now, 105.2));
+48 -49
View File
@@ -51,6 +51,54 @@ This allows the indicator to update in constant time, regardless of the period l
|-----------|---------|---------|----------------------|
| Period | 14 | Lookback window | Shorter (5-10) for momentum; Longer (20+) for trend smoothing. |
## Performance Profile
| Operation | Complexity | Description |
|-----------|------------|-------------------|
| Streaming update | O(1) | Constant time triple-sum update |
| Bar correction | O(1) | Efficient state rollback |
| Batch processing | O(n) | Fast sequential processing |
| Memory footprint | O(period) | Uses a RingBuffer to store the lookback window |
## Interpretation
### Trading Signals
#### Momentum
- **Rapid Turns:** PWMA is excellent for identifying the exact moment a trend loses momentum, often turning before the price itself peaks or troughs.
#### Velocity
- **PWMA - WMA:** Subtracting a WMA from a PWMA of the same period creates a powerful momentum oscillator (Velocity) that is smoother than ROC but with less lag.
### When It Works Best
- **Fast Trends:** Markets that move parabolically or have sharp V-bottoms/tops.
### When It Struggles
- **Noise:** The extreme sensitivity to recent data means PWMA can be noisy in choppy markets. It is often best used as part of a composite indicator rather than a standalone filter.
## Architecture Notes
This implementation makes specific trade-offs:
### Choice: Triple Running Sums
- **Implementation:** Maintains S1, S2, and S3.
- **Rationale:** Enables O(1) updates. A naive implementation would be O(n), which is unacceptable for large periods or high-frequency trading.
### Choice: Periodic Resync
- **Implementation:** Recalculates sums from scratch every 1,000 ticks.
- **Rationale:** Floating-point errors accumulate rapidly in the $S3$ term (which involves $n^2$). Periodic resync ensures long-term stability.
## References
- Colby, Robert W. "The Encyclopedia of Technical Market Indicators." McGraw-Hill, 2002.
- Jurik Research. "Velocity."
## C# Usage
### Streaming Updates (Single Instance)
@@ -113,52 +161,3 @@ pwma.Pub += (value) => {
// Feeding source automatically triggers the chain
source.Add(new TValue(DateTime.Now, 105.2));
```
## Performance Profile
| Operation | Complexity | Description |
|-----------|------------|-------------------|
| Streaming update | O(1) | Constant time triple-sum update |
| Bar correction | O(1) | Efficient state rollback |
| Batch processing | O(n) | Fast sequential processing |
| Memory footprint | O(period) | Uses a RingBuffer to store the lookback window |
## Interpretation
### Trading Signals
#### Momentum
- **Rapid Turns:** PWMA is excellent for identifying the exact moment a trend loses momentum, often turning before the price itself peaks or troughs.
#### Velocity
- **PWMA - WMA:** Subtracting a WMA from a PWMA of the same period creates a powerful momentum oscillator (Velocity) that is smoother than ROC but with less lag.
### When It Works Best
- **Fast Trends:** Markets that move parabolically or have sharp V-bottoms/tops.
### When It Struggles
- **Noise:** The extreme sensitivity to recent data means PWMA can be noisy in choppy markets. It is often best used as part of a composite indicator rather than a standalone filter.
## Architecture Notes
This implementation makes specific trade-offs:
### Choice: Triple Running Sums
- **Implementation:** Maintains S1, S2, and S3.
- **Rationale:** Enables O(1) updates. A naive implementation would be O(n), which is unacceptable for large periods or high-frequency trading.
### Choice: Periodic Resync
- **Implementation:** Recalculates sums from scratch every 1,000 ticks.
- **Rationale:** Floating-point errors accumulate rapidly in the $S3$ term (which involves $n^2$). Periodic resync ensures long-term stability.
## References
- Colby, Robert W. "The Encyclopedia of Technical Market Indicators." McGraw-Hill, 2002.
- Jurik Research. "Velocity."
+39 -40
View File
@@ -44,6 +44,45 @@ Our implementation uses the recursive formula for O(1) updates.
|-----------|---------|---------|----------------------|
| Period | 14 | Lookback window | Standard is 14 (Wilder's default). |
## Performance Profile
| Operation | Complexity | Description |
|-----------|------------|-------------------|
| Streaming update | O(1) | Simple scalar math |
| Bar correction | O(1) | Efficient state rollback |
| Batch processing | O(N) | Single pass through data |
| Memory footprint | O(1) | Minimal state (previous value only) |
## Interpretation
### Trading Signals
#### Trend Filter
- **Direction:** Because RMA is slower than EMA, it acts as an excellent long-term trend filter.
- **Support/Resistance:** In strong trends, price often respects the RMA line as dynamic support/resistance.
### When It Works Best
- **Smoothing Volatility:** RMA is the gold standard for smoothing volatile sub-indicators (like True Range to get ATR) because it doesn't react jerkily to single spikes.
### When It Struggles
- **Fast Reversals:** Due to its lag (approx $2N-1$ EMA equivalent), it is too slow for catching rapid market turns.
## Architecture Notes
This implementation makes specific trade-offs:
### Choice: Wilder's Initialization
- **Implementation:** The first value is the SMA of the first $N$ bars.
- **Rationale:** Strict adherence to Wilder's definition ensures values match standard platforms (TradingView, etc.) exactly.
## References
- Wilder, J. Welles Jr. "New Concepts in Technical Trading Systems." Trend Research, 1978.
## C# Usage
### Streaming Updates (Single Instance)
@@ -87,43 +126,3 @@ rma.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
rma.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
## Performance Profile
| Operation | Complexity | Description |
|-----------|------------|-------------------|
| Streaming update | O(1) | Simple scalar math |
| Bar correction | O(1) | Efficient state rollback |
| Batch processing | O(N) | Single pass through data |
| Memory footprint | O(1) | Minimal state (previous value only) |
## Interpretation
### Trading Signals
#### Trend Filter
- **Direction:** Because RMA is slower than EMA, it acts as an excellent long-term trend filter.
- **Support/Resistance:** In strong trends, price often respects the RMA line as dynamic support/resistance.
### When It Works Best
- **Smoothing Volatility:** RMA is the gold standard for smoothing volatile sub-indicators (like True Range to get ATR) because it doesn't react jerkily to single spikes.
### When It Struggles
- **Fast Reversals:** Due to its lag (approx $2N-1$ EMA equivalent), it is too slow for catching rapid market turns.
## Architecture Notes
This implementation makes specific trade-offs:
### Choice: Wilder's Initialization
- **Implementation:** The first value is the SMA of the first $N$ bars.
- **Rationale:** Strict adherence to Wilder's definition ensures values match standard platforms (TradingView, etc.) exactly.
## References
- Wilder, J. Welles Jr. "New Concepts in Technical Trading Systems." Trend Research, 1978.
+44 -45
View File
@@ -38,51 +38,6 @@ This ensures that calculating an SMA(200) takes the exact same amount of CPU tim
|-----------|---------|---------|----------------------|
| Period | 10 | Lookback window | Short (10-20) for short-term trends; Medium (50) for intermediate; Long (200) for major trends. |
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var sma = new Sma(period: 20);
// Process each new bar
TValue result = sma.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"SMA: {result.Value:F2}");
// Check if buffer is full
if (sma.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TSeries API
TSeries prices = ...;
TSeries smaValues = Sma.Batch(prices, period: 20);
// Span API (High Performance)
double[] prices = new double[1000];
double[] output = new double[1000];
Sma.Calculate(prices.AsSpan(), output.AsSpan(), period: 20);
```
### Bar Correction (isNew Parameter)
```csharp
var sma = new Sma(20);
// New bar
sma.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
sma.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
## Performance Profile
| Operation | Complexity | Description |
@@ -135,3 +90,47 @@ This implementation makes specific trade-offs:
## References
- Murphy, John J. "Technical Analysis of the Financial Markets." New York Institute of Finance, 1999.
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var sma = new Sma(period: 20);
// Process each new bar
TValue result = sma.Update(new TValue(timestamp, closePrice));
Console.WriteLine($"SMA: {result.Value:F2}");
// Check if buffer is full
if (sma.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TSeries API
TSeries prices = ...;
TSeries smaValues = Sma.Batch(prices, period: 20);
// Span API (High Performance)
double[] prices = new double[1000];
double[] output = new double[1000];
Sma.Calculate(prices.AsSpan(), output.AsSpan(), period: 20);
```
### Bar Correction (isNew Parameter)
```csharp
var sma = new Sma(20);
// New bar
sma.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
sma.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
+42 -43
View File
@@ -46,49 +46,6 @@ Our implementation maintains the state of the trend and the trailing bands.
| Period | 10 | ATR Lookback | 10 is standard. Shorter = more volatile ATR. |
| Multiplier | 3.0 | Band width | 3.0 is standard. Lower (e.g., 2.0) = tighter stops, more signals. Higher (e.g., 4.0) = wider stops, fewer signals. |
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var super = new SuperTrend(period: 10, multiplier: 3.0);
// Process each new bar
TBar bar = new TBar(time, open, high, low, close, volume);
TValue result = super.Update(bar);
Console.WriteLine($"SuperTrend: {result.Value:F2}");
Console.WriteLine($"Trend: {(result.IsBullish ? "Bullish" : "Bearish")}");
// Check if buffer is full
if (super.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TBarSeries API
TBarSeries bars = ...;
TSeries superValues = SuperTrend.Batch(bars, period: 10, multiplier: 3.0);
```
### Bar Correction (isNew Parameter)
```csharp
var super = new SuperTrend(10, 3.0);
// New bar
super.Update(bar, isNew: true);
// Intra-bar update
super.Update(updatedBar, isNew: false); // Replaces last calculation
```
## Performance Profile
| Operation | Complexity | Description |
@@ -131,3 +88,45 @@ This implementation makes specific trade-offs:
## References
- Seban, Olivier. "Tout le monde mérite d'être riche" (Everyone Deserves to Be Rich).
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var super = new SuperTrend(period: 10, multiplier: 3.0);
// Process each new bar
TBar bar = new TBar(time, open, high, low, close, volume);
TValue result = super.Update(bar);
Console.WriteLine($"SuperTrend: {result.Value:F2}");
Console.WriteLine($"Trend: {(result.IsBullish ? "Bullish" : "Bearish")}");
// Check if buffer is full
if (super.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TBarSeries API
TBarSeries bars = ...;
TSeries superValues = SuperTrend.Batch(bars, period: 10, multiplier: 3.0);
```
### Bar Correction (isNew Parameter)
```csharp
var super = new SuperTrend(10, 3.0);
// New bar
super.Update(bar, isNew: true);
// Intra-bar update
super.Update(updatedBar, isNew: false); // Replaces last calculation
+39 -40
View File
@@ -49,6 +49,45 @@ Our implementation uses the recursive GD formula for O(1) updates.
| Period | 14 | Smoothing period | Standard lookback. |
| Volume Factor (v) | 0.7 | Responsiveness | 0.7 is standard. Lower (0.1-0.5) = smoother/slower. Higher (0.8-1.0) = faster/responsive. |
## Performance Profile
| Operation | Complexity | Description |
|-----------|------------|-------------------|
| Streaming update | O(1) | 6 layers of GD calculation |
| Bar correction | O(1) | Efficient state rollback |
| Batch processing | O(N) | Single pass through data |
| Memory footprint | O(1) | Stores state for 6 internal layers |
## Interpretation
### Trading Signals
#### Trend Identification
- **Smoothness:** T3 is famous for filtering out "noise" better than almost any other MA. If T3 is rising, the trend is likely real, not just a blip.
- **Crossovers:** Price crossing T3 is a significant event due to the indicator's smoothness.
### When It Works Best
- **Noisy Markets:** T3 shines in markets with lots of wicks and erratic movement, where standard EMAs would get chopped up.
### When It Struggles
- **Lag:** Despite its clever math, applying a filter 6 times introduces lag. It will turn after the market turns, not with it.
## Architecture Notes
This implementation makes specific trade-offs:
### Choice: 6 Layers
- **Implementation:** We implement the standard "T3" which implies 6 layers of smoothing.
- **Rationale:** While "T2" or "T4" are possible, "T3" (6 layers) is the industry standard definition.
## References
- Tillson, Tim. "Smoothing Techniques for More Accurate Signals." *Technical Analysis of Stocks & Commodities*, V. 16:1 (33-37), 1998.
## C# Usage
### Streaming Updates (Single Instance)
@@ -92,43 +131,3 @@ t3.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
t3.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
## Performance Profile
| Operation | Complexity | Description |
|-----------|------------|-------------------|
| Streaming update | O(1) | 6 layers of GD calculation |
| Bar correction | O(1) | Efficient state rollback |
| Batch processing | O(N) | Single pass through data |
| Memory footprint | O(1) | Stores state for 6 internal layers |
## Interpretation
### Trading Signals
#### Trend Identification
- **Smoothness:** T3 is famous for filtering out "noise" better than almost any other MA. If T3 is rising, the trend is likely real, not just a blip.
- **Crossovers:** Price crossing T3 is a significant event due to the indicator's smoothness.
### When It Works Best
- **Noisy Markets:** T3 shines in markets with lots of wicks and erratic movement, where standard EMAs would get chopped up.
### When It Struggles
- **Lag:** Despite its clever math, applying a filter 6 times introduces lag. It will turn after the market turns, not with it.
## Architecture Notes
This implementation makes specific trade-offs:
### Choice: 6 Layers
- **Implementation:** We implement the standard "T3" which implies 6 layers of smoothing.
- **Rationale:** While "T2" or "T4" are possible, "T3" (6 layers) is the industry standard definition.
## References
- Tillson, Tim. "Smoothing Techniques for More Accurate Signals." *Technical Analysis of Stocks & Commodities*, V. 16:1 (33-37), 1998.
+42 -43
View File
@@ -43,6 +43,48 @@ Our implementation uses three internal EMA instances.
|-----------|---------|---------|----------------------|
| Period | 14 | Lookback window | Short (5-10) for scalping; Medium (20-50) for swing trading. |
## Performance Profile
| Operation | Complexity | Description |
|-----------|------------|-------------------|
| Streaming update | O(1) | 3 EMA updates + scalar math |
| Bar correction | O(1) | Efficient state rollback |
| Batch processing | O(N) | Single pass through data |
| Memory footprint | O(1) | Stores state for 3 internal EMAs |
## Interpretation
### Trading Signals
#### Trend Direction
- **Fast Response:** TEMA turns much faster than SMA or EMA. A turn in TEMA often precedes a turn in price trend.
#### Crossovers
- **Price Crossover:** Because TEMA hugs price so closely, crossovers are frequent. They are best used for short-term entries in the direction of a larger trend.
### When It Works Best
- **Momentum Trading:** TEMA is excellent for capturing short-term bursts of momentum.
### When It Struggles
- **Overshoot:** In a sudden V-shaped reversal, TEMA can "overshoot" the price briefly due to the momentum of its internal calculation components.
## Architecture Notes
This implementation makes specific trade-offs:
### Choice: Composition
- **Implementation:** Composed of 3 `Ema` objects.
- **Rationale:** Reusing the robust `Ema` class ensures consistent behavior (like initialization and NaN handling) across the library.
## References
- Mulloy, Patrick G. "Smoothing Data with Faster Moving Averages." *Technical Analysis of Stocks & Commodities*, Jan 1994.
## C# Usage
### Streaming Updates (Single Instance)
@@ -86,46 +128,3 @@ tema.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
tema.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
## Performance Profile
| Operation | Complexity | Description |
|-----------|------------|-------------------|
| Streaming update | O(1) | 3 EMA updates + scalar math |
| Bar correction | O(1) | Efficient state rollback |
| Batch processing | O(N) | Single pass through data |
| Memory footprint | O(1) | Stores state for 3 internal EMAs |
## Interpretation
### Trading Signals
#### Trend Direction
- **Fast Response:** TEMA turns much faster than SMA or EMA. A turn in TEMA often precedes a turn in price trend.
#### Crossovers
- **Price Crossover:** Because TEMA hugs price so closely, crossovers are frequent. They are best used for short-term entries in the direction of a larger trend.
### When It Works Best
- **Momentum Trading:** TEMA is excellent for capturing short-term bursts of momentum.
### When It Struggles
- **Overshoot:** In a sudden V-shaped reversal, TEMA can "overshoot" the price briefly due to the momentum of its internal calculation components.
## Architecture Notes
This implementation makes specific trade-offs:
### Choice: Composition
- **Implementation:** Composed of 3 `Ema` objects.
- **Rationale:** Reusing the robust `Ema` class ensures consistent behavior (like initialization and NaN handling) across the library.
## References
- Mulloy, Patrick G. "Smoothing Data with Faster Moving Averages." *Technical Analysis of Stocks & Commodities*, Jan 1994.
+38 -39
View File
@@ -45,6 +45,44 @@ Our implementation uses the Double SMA method for O(1) efficiency.
|-----------|---------|---------|----------------------|
| Period | 14 | Lookback window | Standard lookback. |
## Performance Profile
| Operation | Complexity | Description |
|-----------|------------|-------------------|
| Streaming update | O(1) | Two sliding window sums |
| Bar correction | O(1) | Efficient state rollback |
| Batch processing | O(N) | Single pass through data |
| Memory footprint | O(period) | RingBuffers for the two internal SMAs |
## Interpretation
### Trading Signals
#### Trend Identification
- **Primary Trend:** TRIMA is excellent for visualizing the "major" trend. If TRIMA is rising, the long-term direction is up, regardless of short-term chops.
### When It Works Best
- **Visual Clarity:** Traders often use TRIMA not for signals, but to declutter charts and see the underlying market structure.
### When It Struggles
- **Timing Entries:** Due to its significant lag, TRIMA is poor for timing entries or exits. It is a lagging indicator, not a leading one.
## Architecture Notes
This implementation makes specific trade-offs:
### Choice: Double SMA Composition
- **Implementation:** Composed of two `Sma` objects.
- **Rationale:** This is mathematically equivalent to the weighted sum method but allows us to reuse the O(1) optimization of the `Sma` class.
## References
- Merrill, Arthur A. "Filtered Waves." *Technical Analysis of Stocks & Commodities*.
## C# Usage
### Streaming Updates (Single Instance)
@@ -88,42 +126,3 @@ trima.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
trima.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
## Performance Profile
| Operation | Complexity | Description |
|-----------|------------|-------------------|
| Streaming update | O(1) | Two sliding window sums |
| Bar correction | O(1) | Efficient state rollback |
| Batch processing | O(N) | Single pass through data |
| Memory footprint | O(period) | RingBuffers for the two internal SMAs |
## Interpretation
### Trading Signals
#### Trend Identification
- **Primary Trend:** TRIMA is excellent for visualizing the "major" trend. If TRIMA is rising, the long-term direction is up, regardless of short-term chops.
### When It Works Best
- **Visual Clarity:** Traders often use TRIMA not for signals, but to declutter charts and see the underlying market structure.
### When It Struggles
- **Timing Entries:** Due to its significant lag, TRIMA is poor for timing entries or exits. It is a lagging indicator, not a leading one.
## Architecture Notes
This implementation makes specific trade-offs:
### Choice: Double SMA Composition
- **Implementation:** Composed of two `Sma` objects.
- **Rationale:** This is mathematically equivalent to the weighted sum method but allows us to reuse the O(1) optimization of the `Sma` class.
## References
- Merrill, Arthur A. "Filtered Waves." *Technical Analysis of Stocks & Commodities*.
+43 -44
View File
@@ -44,6 +44,49 @@ Our implementation calculates CMO and VIDYA in a single pass.
|-----------|---------|---------|----------------------|
| Period | 14 | Lookback window | Standard lookback for both CMO and the base EMA. |
## Performance Profile
| Operation | Complexity | Description |
|-----------|------------|-------------------|
| Streaming update | O(1) | CMO update + EMA update |
| Bar correction | O(1) | Efficient state rollback |
| Batch processing | O(N) | Single pass through data |
| Memory footprint | O(period) | RingBuffer for CMO calculation |
## Interpretation
### Trading Signals
#### Trend Following
- **Support/Resistance:** VIDYA is excellent at identifying dynamic support and resistance levels because it flattens out during consolidations (providing a clear "shelf" of support) and slopes steeply during trends.
#### Crossovers
- **Price Crossover:** Price crossing VIDYA is a standard trend entry signal. Because VIDYA adapts to volatility, these signals are often more reliable than SMA crossovers in choppy markets.
### When It Works Best
- **Breakouts:** VIDYA excels at catching breakouts from low-volatility consolidations because its effective period shortens (speeds up) as soon as volatility expands.
### When It Struggles
- **Grinding Trends:** In a slow, low-volatility grind upwards, VIDYA might lag more than a standard EMA because the low volatility keeps the smoothing factor small.
## Architecture Notes
This implementation makes specific trade-offs:
### Choice: CMO as Volatility Index
- **Implementation:** Uses Chande Momentum Oscillator.
- **Rationale:** This is the original definition by Chande. Other variants (like using Efficiency Ratio) exist but are technically different indicators (e.g., KAMA).
## References
- Chande, Tushar. "The New Technical Trader." Wiley, 1994.
- Chande, Tushar. "Adapting Moving Averages To Market Volatility." *Technical Analysis of Stocks & Commodities*, Mar 1992.
## C# Usage
### Streaming Updates (Single Instance)
@@ -87,47 +130,3 @@ vidya.Update(new TValue(time, 100), isNew: true);
// Intra-bar update
vidya.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
```
## Performance Profile
| Operation | Complexity | Description |
|-----------|------------|-------------------|
| Streaming update | O(1) | CMO update + EMA update |
| Bar correction | O(1) | Efficient state rollback |
| Batch processing | O(N) | Single pass through data |
| Memory footprint | O(period) | RingBuffer for CMO calculation |
## Interpretation
### Trading Signals
#### Trend Following
- **Support/Resistance:** VIDYA is excellent at identifying dynamic support and resistance levels because it flattens out during consolidations (providing a clear "shelf" of support) and slopes steeply during trends.
#### Crossovers
- **Price Crossover:** Price crossing VIDYA is a standard trend entry signal. Because VIDYA adapts to volatility, these signals are often more reliable than SMA crossovers in choppy markets.
### When It Works Best
- **Breakouts:** VIDYA excels at catching breakouts from low-volatility consolidations because its effective period shortens (speeds up) as soon as volatility expands.
### When It Struggles
- **Grinding Trends:** In a slow, low-volatility grind upwards, VIDYA might lag more than a standard EMA because the low volatility keeps the smoothing factor small.
## Architecture Notes
This implementation makes specific trade-offs:
### Choice: CMO as Volatility Index
- **Implementation:** Uses Chande Momentum Oscillator.
- **Rationale:** This is the original definition by Chande. Other variants (like using Efficiency Ratio) exist but are technically different indicators (e.g., KAMA).
## References
- Chande, Tushar. "The New Technical Trader." Wiley, 1994.
- Chande, Tushar. "Adapting Moving Averages To Market Volatility." *Technical Analysis of Stocks & Commodities*, Mar 1992.
+62 -63
View File
@@ -46,6 +46,68 @@ This reduces the calculation to two subtractions, two additions, and one multipl
| Period | 14 | Lookback window | Shorter (5-10) = scalping/intraday; Longer (20-50) = swing/trend following |
| Source | Close | Price input | Typical usage is Close, but HL2 or HLC3 can provide smoother inputs |
## Performance Profile
| Operation | Complexity | Description |
|-----------|------------|-------------------|
| Streaming update | O(1) | Constant time regardless of period length |
| Bar correction | O(1) | Efficient state rollback for real-time feeds |
| Batch processing | O(n) | SIMD-optimized (AVX2/AVX512/Neon) for high throughput |
| Memory footprint | O(period) | Uses a RingBuffer to store the lookback window |
**Note:** The batch implementation automatically selects the best available SIMD instruction set (AVX512, AVX2, or ARM Neon) for the running hardware, falling back to a scalar implementation if necessary.
## Interpretation
### Trading Signals
#### Trend Identification
- **Uptrend:** Price is consistently above the WMA, and the WMA slope is positive.
- **Downtrend:** Price is consistently below the WMA, and the WMA slope is negative.
#### Crossovers
- **Price Crossover:** Price crossing above the WMA suggests a potential bullish reversal. Price crossing below suggests a bearish reversal.
- **Dual WMA:** Using two WMAs (e.g., 20 and 50). Fast crossing above Slow is a "Golden Cross" (bullish). Fast crossing below Slow is a "Death Cross" (bearish).
### When It Works Best
- **Trending Markets:** WMA excels in clearly defined trends where its reduced lag allows traders to enter and exit positions earlier than with an SMA.
- **Swing Trading:** The linear weighting aligns well with swing trading timeframes, capturing momentum shifts effectively.
### When It Struggles
- **Choppy/Sideways Markets:** Like all moving averages, WMA will generate false signals in range-bound markets.
- **Drop-off Effect:** Because the oldest price drops off the calculation entirely (weight goes from 1 to 0), a large price spike exiting the window can cause the WMA to move counter-intuitively, though less severely than an SMA.
## Architecture Notes
This implementation makes specific trade-offs:
### Choice: Dual Running Sums for O(1)
- **Alternative:** Recalculate weighted sum every bar (O(n)).
- **Trade-off:** Requires maintaining two state variables ($S$ and $W$) and a RingBuffer.
- **Rationale:** Critical for performance in real-time systems monitoring thousands of assets with long periods.
### Choice: Periodic Resync
- **Alternative:** Never resync.
- **Trade-off:** Small CPU cost every 10,000 ticks.
- **Rationale:** Floating-point errors accumulate in running sums. Periodic recalculation ensures long-running server stability.
#### Choice: SIMD for Batch
- **Alternative:** Scalar loop.
- **Trade-off:** Code complexity (multiple execution paths).
- **Rationale:** Batch processing is often the bottleneck in backtesting. SIMD provides 4-8x throughput improvement.
## References
- Colby, Robert W. "The Encyclopedia of Technical Market Indicators." McGraw-Hill, 2002.
- Murphy, John J. "Technical Analysis of the Financial Markets." New York Institute of Finance, 1999.
## C# Usage
### Streaming Updates (Single Instance)
@@ -121,66 +183,3 @@ var wma = new Wma(14);
wma.Update(new TValue(time, 100));
wma.Update(new TValue(time, double.NaN)); // Uses last valid value (100)
wma.Update(new TValue(time, 110)); // Resumes normal calculation
```
## Performance Profile
| Operation | Complexity | Description |
|-----------|------------|-------------------|
| Streaming update | O(1) | Constant time regardless of period length |
| Bar correction | O(1) | Efficient state rollback for real-time feeds |
| Batch processing | O(n) | SIMD-optimized (AVX2/AVX512/Neon) for high throughput |
| Memory footprint | O(period) | Uses a RingBuffer to store the lookback window |
**Note:** The batch implementation automatically selects the best available SIMD instruction set (AVX512, AVX2, or ARM Neon) for the running hardware, falling back to a scalar implementation if necessary.
## Interpretation
### Trading Signals
#### Trend Identification
- **Uptrend:** Price is consistently above the WMA, and the WMA slope is positive.
- **Downtrend:** Price is consistently below the WMA, and the WMA slope is negative.
#### Crossovers
- **Price Crossover:** Price crossing above the WMA suggests a potential bullish reversal. Price crossing below suggests a bearish reversal.
- **Dual WMA:** Using two WMAs (e.g., 20 and 50). Fast crossing above Slow is a "Golden Cross" (bullish). Fast crossing below Slow is a "Death Cross" (bearish).
### When It Works Best
- **Trending Markets:** WMA excels in clearly defined trends where its reduced lag allows traders to enter and exit positions earlier than with an SMA.
- **Swing Trading:** The linear weighting aligns well with swing trading timeframes, capturing momentum shifts effectively.
### When It Struggles
- **Choppy/Sideways Markets:** Like all moving averages, WMA will generate false signals in range-bound markets.
- **Drop-off Effect:** Because the oldest price drops off the calculation entirely (weight goes from 1 to 0), a large price spike exiting the window can cause the WMA to move counter-intuitively, though less severely than an SMA.
## Architecture Notes
This implementation makes specific trade-offs:
### Choice: Dual Running Sums for O(1)
- **Alternative:** Recalculate weighted sum every bar (O(n)).
- **Trade-off:** Requires maintaining two state variables ($S$ and $W$) and a RingBuffer.
- **Rationale:** Critical for performance in real-time systems monitoring thousands of assets with long periods.
### Choice: Periodic Resync
- **Alternative:** Never resync.
- **Trade-off:** Small CPU cost every 10,000 ticks.
- **Rationale:** Floating-point errors accumulate in running sums. Periodic recalculation ensures long-running server stability.
#### Choice: SIMD for Batch
- **Alternative:** Scalar loop.
- **Trade-off:** Code complexity (multiple execution paths).
- **Rationale:** Batch processing is often the bottleneck in backtesting. SIMD provides 4-8x throughput improvement.
## References
- Colby, Robert W. "The Encyclopedia of Technical Market Indicators." McGraw-Hill, 2002.
- Murphy, John J. "Technical Analysis of the Financial Markets." New York Institute of Finance, 1999.
+41 -42
View File
@@ -43,48 +43,6 @@ Our implementation uses the `Rma` indicator internally to smooth the calculated
|-----------|---------|---------|----------------------|
| Period | 14 | Lookback window | Standard is 14. Shorter (e.g., 7) = more sensitive to recent volatility spikes. Longer (e.g., 21) = smoother measure of volatility. |
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var atr = new Atr(period: 14);
// Process each new bar
TBar bar = new TBar(time, open, high, low, close, volume);
TValue result = atr.Update(bar);
Console.WriteLine($"ATR: {result.Value:F2}");
// Check if buffer is full
if (atr.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TBarSeries API
TBarSeries bars = ...;
TSeries atrValues = Atr.Batch(bars, period: 14);
```
### Bar Correction (isNew Parameter)
```csharp
var atr = new Atr(14);
// New bar
atr.Update(bar, isNew: true);
// Intra-bar update
atr.Update(updatedBar, isNew: false); // Replaces last calculation
```
## Performance Profile
| Operation | Complexity | Description |
@@ -128,3 +86,44 @@ This implementation makes specific trade-offs:
## References
- Wilder, J. Welles Jr. "New Concepts in Technical Trading Systems." Trend Research, 1978.
## C# Usage
### Streaming Updates (Single Instance)
```csharp
using QuanTAlib;
var atr = new Atr(period: 14);
// Process each new bar
TBar bar = new TBar(time, open, high, low, close, volume);
TValue result = atr.Update(bar);
Console.WriteLine($"ATR: {result.Value:F2}");
// Check if buffer is full
if (atr.IsHot)
{
// Indicator is fully initialized
}
```
### Batch Processing (Historical Data)
```csharp
// TBarSeries API
TBarSeries bars = ...;
TSeries atrValues = Atr.Batch(bars, period: 14);
```
### Bar Correction (isNew Parameter)
```csharp
var atr = new Atr(14);
// New bar
atr.Update(bar, isNew: true);
// Intra-bar update
atr.Update(updatedBar, isNew: false); // Replaces last calculation