mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-23 04:58:08 +00:00
Add Savitzky-Golay Moving Average (SGMA) Indicator Implementation
- Implemented SgmaIndicator class in C# with properties for Period, Degree, and Source. - Added unit tests for SgmaIndicator covering constructor defaults, initialization, and various update scenarios. - Created a new Quantower adapter for the SGMA indicator, including input parameters and line series setup. - Removed legacy SGMA implementation and tests to streamline the codebase. - Updated project files to include new indicator and tests in the build process. - Generated a missing indicators report and outlined a plan for oscillator documentation rewrite.
This commit is contained in:
@@ -13,9 +13,9 @@ Momentum indicators measure the velocity and acceleration of price changes. Unli
|
||||
| [CFB](cfb/Cfb.md) | Composite Fractal Behavior | Measures trend duration and quality via fractal efficiency across 96 time scales. |
|
||||
| [CMO](cmo/Cmo.md) | Chande Momentum Oscillator | Momentum using both up and down changes, bounded but not clamped like RSI. |
|
||||
| [MACD](macd/Macd.md) | Moving Average Convergence Divergence | Relationship between two EMAs, identifies momentum and trend direction. |
|
||||
| MOM | Momentum | Raw price change over specified period. |
|
||||
| PMO | Price Momentum Oscillator | Double-smoothed ROC oscillator. |
|
||||
| PPO | Percentage Price Oscillator | MACD expressed as percentage for cross-instrument comparison. |
|
||||
| [MOM](mom/Mom.md) | Momentum | Raw price change over specified period. |
|
||||
| [PMO](pmo/Pmo.md) | Price Momentum Oscillator | Double-smoothed ROC oscillator. |
|
||||
| [PPO](ppo/Ppo.md) | Percentage Price Oscillator | MACD expressed as percentage for cross-instrument comparison. |
|
||||
| [PRS](prs/Prs.md) | Price Relative Strength | Performance ratio between two assets. |
|
||||
| [ROC](roc/Roc.md) | Rate of Change | Absolute price change over N periods. |
|
||||
| [ROCP](rocp/Rocp.md) | Rate of Change Percentage | Percentage price change over N periods. |
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
# MOM: Momentum (Absolute Price Change)
|
||||
|
||||
> "The market's simplest question answered: how much has price moved in N bars? No ratios, no percentages. Just the raw delta."
|
||||
|
||||
MOM (Momentum) calculates the absolute price difference between the current value and the value N periods ago. It is the purest expression of directional price movement, returning a signed value in the same units as the input. Positive MOM indicates rising prices; negative indicates falling. This is functionally identical to ROC but with a configurable lookback period (default 10 vs ROC's convention), and maps directly to TA-Lib's `MOM` function.
|
||||
|
||||
## Historical Context
|
||||
|
||||
Momentum is arguably the oldest quantitative concept in technical analysis. Before oscillators, before moving averages, traders measured "how much has price changed" by simple subtraction. The term appears in Gerald Appel's work on MACD (1979) and in Martin Pring's "Technical Analysis Explained" as a foundation concept.
|
||||
|
||||
Different libraries handle the naming inconsistently:
|
||||
|
||||
- **TA-Lib / Tulip**: `MOM` = absolute change (this calculation)
|
||||
- **TradingView / PineScript**: `ta.mom` = absolute change
|
||||
- **QuanTAlib**: `Mom` = absolute change, `Roc` = absolute change (same formula, different default period), `Change` = percentage change
|
||||
|
||||
The implementation uses a ring buffer of size `period + 1` for O(1) streaming with zero allocations on the hot path.
|
||||
|
||||
## Architecture & Physics
|
||||
|
||||
### 1. Ring Buffer Storage
|
||||
|
||||
The indicator maintains a sliding window of `period + 1` values:
|
||||
|
||||
$$
|
||||
\text{buffer} = [v_{t-n}, v_{t-n+1}, \ldots, v_{t-1}, v_t]
|
||||
$$
|
||||
|
||||
where $n$ is the lookback period. Only the oldest and newest values participate in the calculation.
|
||||
|
||||
### 2. Absolute Change Calculation
|
||||
|
||||
$$
|
||||
\text{MOM}_t = v_t - v_{t-n}
|
||||
$$
|
||||
|
||||
The result is in the same units as the input (dollars, points, ticks). No normalization is applied.
|
||||
|
||||
### 3. State Management
|
||||
|
||||
The indicator uses `record struct State` with `_state` / `_p_state` pairs for bar correction:
|
||||
|
||||
```text
|
||||
if isNew:
|
||||
_p_state = _state // snapshot for rollback
|
||||
else:
|
||||
_state = _p_state // restore on correction
|
||||
```
|
||||
|
||||
NaN/Infinity inputs are sanitized via last-valid-value substitution stored in `State.LastValid`.
|
||||
|
||||
## Mathematical Foundation
|
||||
|
||||
### Core Formula
|
||||
|
||||
$$
|
||||
\text{MOM}_t = P_t - P_{t-n}
|
||||
$$
|
||||
|
||||
where:
|
||||
|
||||
- $P_t$ = current price
|
||||
- $P_{t-n}$ = price from $n$ periods ago
|
||||
- Default $n = 10$
|
||||
|
||||
### Relationship to Other Momentum Variants
|
||||
|
||||
| Indicator | Formula | Output |
|
||||
|-----------|---------|--------|
|
||||
| **MOM** | $P_t - P_{t-n}$ | Absolute (price units) |
|
||||
| **ROC** | $P_t - P_{t-n}$ | Absolute (same formula) |
|
||||
| **ROCP** | $\frac{P_t - P_{t-n}}{P_{t-n}} \times 100$ | Percentage (%) |
|
||||
| **ROCR** | $\frac{P_t}{P_{t-n}}$ | Ratio (dimensionless) |
|
||||
| **CHANGE** | $\frac{P_t - P_{t-n}}{P_{t-n}}$ | Decimal fraction |
|
||||
|
||||
### Conversions
|
||||
|
||||
$$
|
||||
\text{ROCP} = \frac{\text{MOM}}{P_{t-n}} \times 100
|
||||
$$
|
||||
|
||||
$$
|
||||
\text{ROCR} = \frac{P_t}{P_{t-n}} = \frac{\text{MOM}}{P_{t-n}} + 1
|
||||
$$
|
||||
|
||||
## Performance Profile
|
||||
|
||||
### Operation Count (Streaming Mode)
|
||||
|
||||
| Operation | Count | Notes |
|
||||
| :--- | :---: | :--- |
|
||||
| SUB | 1 | current - past |
|
||||
| Buffer add | 1 | O(1) ring buffer |
|
||||
| State copy | 1 | rollback support |
|
||||
| **Total** | **~3 ops** | Extremely lightweight |
|
||||
|
||||
### Batch Mode (Span-based)
|
||||
|
||||
| Operation | Complexity | Notes |
|
||||
| :--- | :---: | :--- |
|
||||
| Per-element | O(1) | Single subtraction |
|
||||
| Total | O(n) | Linear scan |
|
||||
| Memory | O(1) | No additional allocation |
|
||||
|
||||
### Quality Metrics
|
||||
|
||||
| Metric | Score | Notes |
|
||||
| :--- | :---: | :--- |
|
||||
| **Accuracy** | 10/10 | Exact arithmetic, no approximation |
|
||||
| **Timeliness** | 10/10 | Zero lag by definition |
|
||||
| **Smoothness** | 3/10 | No smoothing, reflects raw volatility |
|
||||
| **Simplicity** | 10/10 | Single subtraction |
|
||||
|
||||
## Validation
|
||||
|
||||
| Library | Status | Notes |
|
||||
| :--- | :---: | :--- |
|
||||
| **Skender** | ✅ | Matches exactly |
|
||||
| **TA-Lib** | ✅ | MOM function matches |
|
||||
| **Tulip** | ✅ | MOM matches exactly |
|
||||
| **Ooples** | ✅ | Matches within tolerance |
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
1. **Unit confusion**: MOM returns absolute values in price units, not percentages. A MOM of 5 means price moved 5 dollars/points, not 5%.
|
||||
|
||||
2. **Scale dependency**: MOM values are not comparable across instruments with different price levels. Use ROCP or CHANGE for normalized comparisons.
|
||||
|
||||
3. **Warmup period**: The first `period` values return 0.0 because there is no historical reference point yet. `IsHot` becomes true after `period + 1` bars.
|
||||
|
||||
4. **Zero handling**: Unlike percentage-based variants, MOM has no division-by-zero risk.
|
||||
|
||||
5. **Sign interpretation**: Positive MOM indicates price increase over the lookback window; negative indicates decrease. The magnitude indicates the size of the move.
|
||||
|
||||
6. **ROC vs MOM naming**: In QuanTAlib, both `Mom` and `Roc` compute the same formula ($P_t - P_{t-n}$). The difference is the default period (MOM=10, ROC=10) and naming convention alignment with different library ecosystems.
|
||||
|
||||
## References
|
||||
|
||||
- Pring, M. J. (2014). "Technical Analysis Explained." McGraw-Hill.
|
||||
- Murphy, J. J. (1999). "Technical Analysis of the Financial Markets." New York Institute of Finance.
|
||||
- Appel, G. (2005). "Technical Analysis: Power Tools for Active Investors." FT Press.
|
||||
- TA-Lib documentation: MOM function reference
|
||||
- TradingView PineScript Reference: ta.mom
|
||||
@@ -0,0 +1,150 @@
|
||||
# PMO: Price Momentum Oscillator
|
||||
|
||||
> "Double-smooth the rate of change and you get something that actually tells you where momentum is headed, not where it was five bars ago."
|
||||
|
||||
PMO (Price Momentum Oscillator), developed by Carl Swenlin at DecisionPoint, is a double-smoothed 1-bar rate of change. It applies two custom EMA passes to a percentage ROC, producing a momentum oscillator that is smoother than raw ROC yet more responsive than triple-smoothed alternatives like TRIX. The custom EMA uses $\alpha = 2/N$ rather than the standard $2/(N+1)$, and seeds with the SMA of the first N values. PMO oscillates around zero: positive values indicate upward momentum, negative values indicate downward momentum.
|
||||
|
||||
## Historical Context
|
||||
|
||||
Carl Swenlin introduced PMO through DecisionPoint.com as a refinement of the standard rate of change. The insight was that raw ROC (percentage change) is too noisy for reliable signal generation, but standard smoothing methods introduce too much lag. Swenlin's solution was a two-stage custom EMA pipeline applied to a 1-bar ROC, scaled by a factor of 10 after the first smoothing stage.
|
||||
|
||||
The implementation details matter: Swenlin specified $\alpha = 2/N$, not the standard EMA formula $2/(N+1)$. This subtle difference produces a slightly more responsive filter. Both Skender.Stock.Indicators and OoplesFinance implement this custom alpha, confirming the specification.
|
||||
|
||||
PMO is frequently used with a signal line (an EMA of the PMO itself) to generate crossover signals, similar to MACD. The default parameters (35, 20, 10) provide a balance between responsiveness and smoothness on daily charts.
|
||||
|
||||
## Architecture & Physics
|
||||
|
||||
### 1. One-Bar Percentage ROC
|
||||
|
||||
$$
|
||||
\text{ROC}_t = \left(\frac{P_t}{P_{t-1}} - 1\right) \times 100
|
||||
$$
|
||||
|
||||
This is always a 1-bar lookback regardless of parameters. The percentage form normalizes across price levels.
|
||||
|
||||
### 2. First Custom EMA (ROC Smoothing)
|
||||
|
||||
$$
|
||||
\text{RocEma}_t = \text{CustomEMA}(\text{ROC}, \text{timePeriods}) \times 10
|
||||
$$
|
||||
|
||||
The custom EMA uses $\alpha_1 = 2 / \text{timePeriods}$ and is seeded with the SMA of the first N ROC values. The $\times 10$ scaling amplifies the signal to a more readable range.
|
||||
|
||||
### 3. Second Custom EMA (PMO Smoothing)
|
||||
|
||||
$$
|
||||
\text{PMO}_t = \text{CustomEMA}(\text{RocEma}, \text{smoothPeriods})
|
||||
$$
|
||||
|
||||
The second pass uses $\alpha_2 = 2 / \text{smoothPeriods}$, also seeded with SMA. This produces the final PMO value.
|
||||
|
||||
### 4. State Management
|
||||
|
||||
The indicator uses `record struct State` with 12 fields tracking both EMA pipelines, seeding progress, and bar correction state. The `_state` / `_p_state` pattern enables rollback for streaming bar corrections.
|
||||
|
||||
## Mathematical Foundation
|
||||
|
||||
### Core Formulas
|
||||
|
||||
**Step 1 - Percentage ROC (1-bar):**
|
||||
|
||||
$$
|
||||
\text{ROC}_t = \left(\frac{P_t}{P_{t-1}} - 1\right) \times 100
|
||||
$$
|
||||
|
||||
**Step 2 - Custom EMA smoothing:**
|
||||
|
||||
The custom EMA differs from standard EMA:
|
||||
|
||||
| Property | Standard EMA | Custom EMA (PMO) |
|
||||
|----------|-------------|-----------------|
|
||||
| Alpha | $\frac{2}{N+1}$ | $\frac{2}{N}$ |
|
||||
| Seed | First value | SMA of first N values |
|
||||
|
||||
$$
|
||||
\text{CustomEMA}_t = \alpha \cdot x_t + (1 - \alpha) \cdot \text{CustomEMA}_{t-1}
|
||||
$$
|
||||
|
||||
**Step 3 - Scale and second smooth:**
|
||||
|
||||
$$
|
||||
\text{RocEma}_t = \text{CustomEMA}_1(\text{ROC}_t) \times 10
|
||||
$$
|
||||
|
||||
$$
|
||||
\text{PMO}_t = \text{CustomEMA}_2(\text{RocEma}_t)
|
||||
$$
|
||||
|
||||
### Default Parameters
|
||||
|
||||
| Parameter | Default | Purpose |
|
||||
|-----------|---------|---------|
|
||||
| timePeriods | 35 | First EMA smoothing of 1-bar ROC |
|
||||
| smoothPeriods | 20 | Second EMA smoothing for PMO |
|
||||
| signalPeriods | 10 | Signal line EMA (future use) |
|
||||
|
||||
### Warmup
|
||||
|
||||
$$
|
||||
\text{WarmupPeriod} = \text{timePeriods} + \text{smoothPeriods}
|
||||
$$
|
||||
|
||||
## Performance Profile
|
||||
|
||||
### Operation Count (Streaming Mode)
|
||||
|
||||
| Operation | Count | Notes |
|
||||
| :--- | :---: | :--- |
|
||||
| DIV | 1 | ROC percentage calculation |
|
||||
| MUL | 3 | alpha multiplications + scale |
|
||||
| ADD/SUB | 4 | EMA updates + ROC |
|
||||
| State copy | 1 | rollback support |
|
||||
| **Total** | **~9 ops** | Lightweight double-EMA |
|
||||
|
||||
### Batch Mode (Span-based)
|
||||
|
||||
| Operation | Complexity | Notes |
|
||||
| :--- | :---: | :--- |
|
||||
| Per-element | O(1) | Fixed operations per bar |
|
||||
| Total | O(n) | Linear scan |
|
||||
| Memory | O(1) | No additional allocation beyond state |
|
||||
|
||||
### Quality Metrics
|
||||
|
||||
| Metric | Score | Notes |
|
||||
| :--- | :---: | :--- |
|
||||
| **Accuracy** | 9/10 | Custom EMA matches DecisionPoint spec |
|
||||
| **Timeliness** | 7/10 | Double smoothing adds moderate lag |
|
||||
| **Smoothness** | 8/10 | Substantially smoother than raw ROC |
|
||||
| **Simplicity** | 6/10 | Two-stage pipeline with custom alpha |
|
||||
|
||||
## Validation
|
||||
|
||||
| Library | Status | Notes |
|
||||
| :--- | :---: | :--- |
|
||||
| **Skender** | ✅ | Matches within 1e-9 tolerance |
|
||||
| **TA-Lib** | N/A | No PMO function |
|
||||
| **Tulip** | N/A | No PMO function |
|
||||
| **Ooples** | ✅ | Matches within 1e-6 tolerance |
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
1. **Custom alpha confusion**: PMO uses $\alpha = 2/N$, not the standard $2/(N+1)$. Using standard EMA alpha produces different results that do not match the DecisionPoint specification.
|
||||
|
||||
2. **SMA seeding**: The custom EMA must be seeded with the SMA of the first N values, not with the first value. This affects the convergence behavior during warmup.
|
||||
|
||||
3. **Scale factor**: The $\times 10$ multiplier is applied after the first EMA pass, not before. Misplacing this scaling produces values off by an order of magnitude.
|
||||
|
||||
4. **1-bar ROC only**: PMO always uses a 1-bar ROC regardless of the timePeriods parameter. The timePeriods parameter controls only the first EMA smoothing length.
|
||||
|
||||
5. **Division by zero**: When `PrevClose` is zero, the ROC calculation would produce Infinity. The implementation guards against this with last-valid-value substitution.
|
||||
|
||||
6. **Warmup length**: PMO requires `timePeriods + smoothPeriods` bars before producing stable values. Early values are heavily influenced by the SMA seed.
|
||||
|
||||
7. **Signal line**: The signalPeriods parameter is reserved for future signal line implementation. Currently only the PMO line is computed.
|
||||
|
||||
## References
|
||||
|
||||
- Swenlin, C. "DecisionPoint Price Momentum Oscillator (PMO)." DecisionPoint.com.
|
||||
- StockCharts.com: "DecisionPoint Price Momentum Oscillator (PMO)" Technical Analysis documentation.
|
||||
- Murphy, J. J. (1999). "Technical Analysis of the Financial Markets." New York Institute of Finance.
|
||||
@@ -0,0 +1,155 @@
|
||||
# PPO: Percentage Price Oscillator
|
||||
|
||||
> "MACD told you the spread in dollars. PPO tells you the spread in percent. One of those actually works across instruments."
|
||||
|
||||
PPO (Percentage Price Oscillator) measures the percentage difference between a fast EMA and a slow EMA. It is functionally equivalent to MACD normalized by the slow EMA, producing values that are comparable across instruments with different price levels. The implementation outputs three components: the PPO line, a signal line (EMA of PPO), and a histogram (PPO minus Signal).
|
||||
|
||||
## Historical Context
|
||||
|
||||
PPO emerged as a direct answer to MACD's most significant architectural limitation: scale dependency. Gerald Appel's MACD (1979) reports the absolute spread between two EMAs, meaning a MACD value of 2.0 on a \$200 stock represents a 1% divergence, while the same value on a \$20 stock represents 10%. PPO normalizes this by dividing by the slow EMA, producing a percentage that is directly comparable across any price level.
|
||||
|
||||
The formula appears in most technical analysis textbooks as the "normalized MACD" or "percentage MACD." StockCharts.com popularized the PPO terminology. The default parameters (12, 26, 9) mirror MACD's defaults, making PPO a drop-in replacement for cross-instrument analysis.
|
||||
|
||||
This implementation uses compensated EMAs internally (via the `Ema` class) for improved warmup accuracy, and applies FMA where applicable for performance.
|
||||
|
||||
## Architecture & Physics
|
||||
|
||||
### 1. Dual EMA Pipeline
|
||||
|
||||
Two independent EMA instances process the same input:
|
||||
|
||||
$$
|
||||
\text{FastEMA}_t = \text{EMA}(P_t, \text{fastPeriod})
|
||||
$$
|
||||
|
||||
$$
|
||||
\text{SlowEMA}_t = \text{EMA}(P_t, \text{slowPeriod})
|
||||
$$
|
||||
|
||||
### 2. Percentage Normalization
|
||||
|
||||
$$
|
||||
\text{PPO}_t = 100 \times \frac{\text{FastEMA}_t - \text{SlowEMA}_t}{\text{SlowEMA}_t}
|
||||
$$
|
||||
|
||||
Division by SlowEMA normalizes the result to a percentage. When SlowEMA is zero (startup edge case), the result defaults to 0.0.
|
||||
|
||||
### 3. Signal and Histogram
|
||||
|
||||
$$
|
||||
\text{Signal}_t = \text{EMA}(\text{PPO}_t, \text{signalPeriod})
|
||||
$$
|
||||
|
||||
$$
|
||||
\text{Histogram}_t = \text{PPO}_t - \text{Signal}_t
|
||||
$$
|
||||
|
||||
### 4. State Management
|
||||
|
||||
The indicator delegates state management to three internal `Ema` instances. The `_state` / `_p_state` pattern handles only the `LastValid` value for NaN sanitization.
|
||||
|
||||
## Mathematical Foundation
|
||||
|
||||
### Core Formulas
|
||||
|
||||
$$
|
||||
\text{PPO}_t = 100 \times \frac{\text{EMA}(P, f)_t - \text{EMA}(P, s)_t}{\text{EMA}(P, s)_t}
|
||||
$$
|
||||
|
||||
where $f$ = fast period, $s$ = slow period.
|
||||
|
||||
### Relationship to MACD
|
||||
|
||||
| Property | MACD | PPO |
|
||||
|----------|------|-----|
|
||||
| Formula | $\text{Fast} - \text{Slow}$ | $100 \times \frac{\text{Fast} - \text{Slow}}{\text{Slow}}$ |
|
||||
| Units | Price units | Percentage |
|
||||
| Cross-instrument | No | Yes |
|
||||
| Zero crossover | Identical timing | Identical timing |
|
||||
| Signal crossover | Same concept | Same concept |
|
||||
|
||||
### Conversion
|
||||
|
||||
$$
|
||||
\text{PPO} = \frac{\text{MACD}}{\text{SlowEMA}} \times 100
|
||||
$$
|
||||
|
||||
### Default Parameters
|
||||
|
||||
| Parameter | Default | Purpose |
|
||||
|-----------|---------|---------|
|
||||
| fastPeriod | 12 | Fast EMA period |
|
||||
| slowPeriod | 26 | Slow EMA period |
|
||||
| signalPeriod | 9 | Signal line EMA period |
|
||||
|
||||
### Constraints
|
||||
|
||||
- `fastPeriod >= 1`
|
||||
- `slowPeriod >= 1`
|
||||
- `fastPeriod < slowPeriod` (enforced in constructor)
|
||||
- `signalPeriod >= 1`
|
||||
|
||||
### Warmup
|
||||
|
||||
$$
|
||||
\text{WarmupPeriod} = \text{slowPeriod} + \text{signalPeriod}
|
||||
$$
|
||||
|
||||
## Performance Profile
|
||||
|
||||
### Operation Count (Streaming Mode)
|
||||
|
||||
| Operation | Count | Notes |
|
||||
| :--- | :---: | :--- |
|
||||
| EMA updates | 3 | fast + slow + signal |
|
||||
| SUB | 2 | fast-slow, ppo-signal |
|
||||
| DIV | 1 | normalization by slow |
|
||||
| MUL | 1 | scale to percentage |
|
||||
| **Total** | **~7 ops** | Plus internal EMA ops |
|
||||
|
||||
### Batch Mode (Span-based)
|
||||
|
||||
| Operation | Complexity | Notes |
|
||||
| :--- | :---: | :--- |
|
||||
| Per-element | O(1) | Fixed operations per bar |
|
||||
| Total | O(n) | Linear scan |
|
||||
| Memory | O(1) | Internal EMA state only |
|
||||
|
||||
### Quality Metrics
|
||||
|
||||
| Metric | Score | Notes |
|
||||
| :--- | :---: | :--- |
|
||||
| **Accuracy** | 9/10 | Compensated EMA for warmup precision |
|
||||
| **Timeliness** | 6/10 | EMA lag from both smoothing stages |
|
||||
| **Smoothness** | 7/10 | Dual EMA provides good noise rejection |
|
||||
| **Simplicity** | 7/10 | Straightforward composition of EMAs |
|
||||
|
||||
## Validation
|
||||
|
||||
| Library | Status | Notes |
|
||||
| :--- | :---: | :--- |
|
||||
| **Skender** | ✅ | Matches within 1e-9 tolerance |
|
||||
| **TA-Lib** | ✅ | PPO function matches |
|
||||
| **Tulip** | ✅ | PPO matches exactly |
|
||||
| **Ooples** | ✅ | Matches within 1e-6 tolerance |
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
1. **Period ordering**: `fastPeriod` must be strictly less than `slowPeriod`. The constructor enforces this with an `ArgumentException`.
|
||||
|
||||
2. **Division by zero**: When SlowEMA is zero (only during initial startup), the PPO defaults to 0.0. This is a transient condition that resolves after the first few bars.
|
||||
|
||||
3. **Signal vs PPO**: The histogram (`PPO - Signal`) is the derivative of momentum. Histogram shrinking toward zero indicates momentum deceleration, not necessarily a reversal.
|
||||
|
||||
4. **Warmup asymmetry**: The fast EMA becomes hot before the slow EMA. `IsHot` requires both EMAs to be warmed up, which depends on the slow period.
|
||||
|
||||
5. **Three outputs**: PPO exposes `Last` (PPO line), `Signal`, and `Histogram` as separate `TValue` properties. Consumers must access the appropriate property for their use case.
|
||||
|
||||
6. **MACD equivalence**: PPO zero crossovers occur at exactly the same points as MACD zero crossovers. The only difference is the vertical scale.
|
||||
|
||||
## References
|
||||
|
||||
- Appel, G. (2005). "Technical Analysis: Power Tools for Active Investors." FT Press.
|
||||
- Murphy, J. J. (1999). "Technical Analysis of the Financial Markets." New York Institute of Finance.
|
||||
- StockCharts.com: "Percentage Price Oscillator (PPO)" Technical Analysis documentation.
|
||||
- TA-Lib documentation: PPO function reference.
|
||||
Reference in New Issue
Block a user