mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-17 01:58:06 +00:00
82 lines
2.6 KiB
Markdown
82 lines
2.6 KiB
Markdown
# ADL - Accumulation/Distribution Line
|
|
|
|
The Accumulation/Distribution Line (ADL) measures the cumulative flow of money into and out of a security. It validates price trends by correlating volume with price close location within the high-low range.
|
|
|
|
## Architectural Design
|
|
|
|
We implement ADL as a stateful, streaming accumulator that maintains O(1) complexity for each new data point. Unlike window-based indicators, ADL carries its entire history in a single double-precision state variable.
|
|
|
|
### The "Close Location Value" (CLV)
|
|
|
|
The core mechanic relies on the Money Flow Multiplier (MFM), also known as CLV. This value ranges from -1 to +1:
|
|
|
|
* **+1**: Close equals High (Maximum Accumulation)
|
|
* **-1**: Close equals Low (Maximum Distribution)
|
|
* **0**: Close is exactly between High and Low
|
|
|
|
This approach avoids the noise of simple price changes, focusing instead on *where* the price settles relative to its intraday range.
|
|
|
|
$$MFM = \frac{(Close - Low) - (High - Close)}{High - Low}$$
|
|
|
|
$$MFV = MFM \times Volume$$
|
|
|
|
$$ADL_{current} = ADL_{previous} + MFV$$
|
|
|
|
### Zero-Allocation Implementation
|
|
|
|
Our implementation processes updates without heap allocations. The state consists of a single `double _lastAdl`.
|
|
|
|
* **Complexity**: O(1) per update.
|
|
* **Memory**: 16 bytes (state) + object overhead.
|
|
* **NaN Handling**: If `High == Low`, MFM is 0 to avoid division by zero. If inputs are `NaN`, the last valid ADL value is preserved.
|
|
|
|
## Usage
|
|
|
|
### Streaming API
|
|
|
|
The streaming API is designed for real-time event processing. It updates the state with each new bar and returns the latest value immediately.
|
|
|
|
```csharp
|
|
using QuanTAlib;
|
|
|
|
// Initialize
|
|
var adl = new Adl();
|
|
|
|
// Update loop
|
|
foreach (var bar in feed)
|
|
{
|
|
var result = adl.Update(bar);
|
|
Console.WriteLine($"ADL: {result.Value:F2}");
|
|
}
|
|
```
|
|
|
|
### Batch Processing
|
|
|
|
For historical analysis, the static `Calculate` method processes full datasets using optimized loops.
|
|
|
|
```csharp
|
|
var bars = GetHistory();
|
|
var adlSeries = Adl.Calculate(bars);
|
|
```
|
|
|
|
## Performance Benchmarks
|
|
|
|
Processing 10,000 bars on an Intel Core i9-13900K:
|
|
|
|
| Operation | Time | Allocations |
|
|
| :--- | :--- | :--- |
|
|
| Update (Single) | 2.1 ns | 0 bytes |
|
|
| Calculate (Batch) | 15 μs | 0 bytes (excluding output) |
|
|
|
|
## Validation
|
|
|
|
We validate correctness against three external authorities to 1e-9 precision:
|
|
|
|
| Library | Status | Notes |
|
|
| :--- | :--- | :--- |
|
|
| **Skender.Stock.Indicators** | ✅ Pass | Reference implementation |
|
|
| **TA-Lib** | ✅ Pass | Matches `AD` function |
|
|
| **Tulip Indicators** | ✅ Pass | Matches `ad` indicator |
|
|
|
|
See [Validation](../validation.md) for comprehensive test results.
|