mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-19 19:18:05 +00:00
Refactor documentation for various filters and indicators to enhance clarity and consistency
- Updated Bessel, Bilateral, Blma, Butter, Conv, Ema, Kama, LSMA, MAMA, MGDI, SSF, USF, ATR, ADL, and ADOSC documentation to use bullet points for key concepts and features. - Added a new Qodana configuration file for code analysis. - Removed coverage configuration from Quantower.Tests.csproj to streamline testing setup.
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
# PHASOR: Phasor Analysis (Ehlers)
|
||||
|
||||
[Pine Script Implementation of Phasor](https://github.com/mihakralj/pinescript/blob/main/indicators/cycles/phasor.pine)
|
||||
|
||||
## Overview and Purpose
|
||||
|
||||
The Phasor Analysis indicator, developed by John Ehlers, represents an advanced cycle analysis tool that identifies the phase of the dominant cycle component in a time series through complex signal processing techniques. This sophisticated indicator uses correlation-based methods to determine the real and imaginary components of the signal, converting them to a continuous phase angle that reveals market cycle progression. Unlike traditional oscillators, the Phasor provides unwrapped phase measurements that accumulate continuously, offering unique insights into market timing and cycle behavior.
|
||||
|
||||
## Core Concepts
|
||||
|
||||
* **Complex Signal Analysis** — Uses real and imaginary components to determine cycle phase
|
||||
* **Correlation-Based Detection** — Employs Ehlers' correlation method for robust phase estimation
|
||||
* **Unwrapped Phase Tracking** — Provides continuous phase accumulation without discontinuities
|
||||
* **Anti-Regression Logic** — Prevents phase angle from moving backward under specific conditions
|
||||
|
||||
Market Applications:
|
||||
* **Cycle Timing** — Precise identification of cycle peaks and troughs
|
||||
* **Market Regime Analysis** — Distinguishes between trending and cycling market conditions
|
||||
* **Turning Point Detection** — Advanced warning system for potential market reversals
|
||||
|
||||
## Common Settings and Parameters
|
||||
|
||||
| Parameter | Default | Function | When to Adjust |
|
||||
| ------ | ------ | ------ | ------ |
|
||||
| Period | 28 | Fixed cycle period for correlation analysis | Match to expected dominant cycle length |
|
||||
| Source | Close | Price series for phase calculation | Use typical price or other smoothed series |
|
||||
| Show Derived Period | false | Display calculated period from phase rate | Enable for adaptive period analysis |
|
||||
| Show Trend State | false | Display trend/cycle state variable | Enable for regime identification |
|
||||
|
||||
## Calculation and Mathematical Foundation
|
||||
|
||||
**Technical Formula:**
|
||||
|
||||
**Stage 1: Correlation Analysis**
|
||||
For period $n$ and source $x_t$:
|
||||
|
||||
Real component correlation with cosine wave:
|
||||
$$R = \frac{n \sum x_t \cos\left(\frac{2\pi t}{n}\right) - \sum x_t \sum \cos\left(\frac{2\pi t}{n}\right)}{\sqrt{D_{cos}}}$$
|
||||
|
||||
Imaginary component correlation with negative sine wave:
|
||||
$$I = \frac{n \sum x_t \left(-\sin\left(\frac{2\pi t}{n}\right)\right) - \sum x_t \sum \left(-\sin\left(\frac{2\pi t}{n}\right)\right)}{\sqrt{D_{sin}}}$$
|
||||
|
||||
where $D_{cos}$ and $D_{sin}$ are normalization denominators.
|
||||
|
||||
**Stage 2: Phase Angle Conversion**
|
||||
$$\theta_{raw} = \begin{cases}
|
||||
90° - \arctan\left(\frac{I}{R}\right) \cdot \frac{180°}{\pi} & \text{if } R \neq 0 \\
|
||||
0° & \text{if } R = 0, I > 0 \\
|
||||
180° & \text{if } R = 0, I \leq 0
|
||||
\end{cases}$$
|
||||
|
||||
**Stage 3: Phase Unwrapping**
|
||||
$$\theta_{unwrapped}(t) = \theta_{unwrapped}(t-1) + \Delta\theta$$
|
||||
|
||||
where $\Delta\theta$ is the normalized phase difference.
|
||||
|
||||
**Stage 4: Ehlers' Anti-Regression Condition**
|
||||
$$\theta_{final}(t) = \begin{cases}
|
||||
\theta_{final}(t-1) & \text{if regression conditions met} \\
|
||||
\theta_{unwrapped}(t) & \text{otherwise}
|
||||
\end{cases}$$
|
||||
|
||||
**Derived Calculations:**
|
||||
|
||||
Derived Period: $P_{derived} = \frac{360°}{\Delta\theta_{final}}$ (clamped to [1, 60])
|
||||
|
||||
Trend State:
|
||||
$$S_{trend} = \begin{cases}
|
||||
1 & \text{if } \Delta\theta \leq 6° \text{ and } |\theta| \geq 90° \\
|
||||
-1 & \text{if } \Delta\theta \leq 6° \text{ and } |\theta| < 90° \\
|
||||
0 & \text{if } \Delta\theta > 6°
|
||||
\end{cases}$$
|
||||
|
||||
> 🔍 **Technical Note:** The correlation-based approach provides robust phase estimation even in noisy market conditions, while the unwrapping mechanism ensures continuous phase tracking across cycle boundaries.
|
||||
|
||||
## Interpretation Details
|
||||
|
||||
* **Phasor Angle (Primary Output):**
|
||||
* **+90°**: Potential cycle peak region
|
||||
* **0°**: Mid-cycle ascending phase
|
||||
* **-90°**: Potential cycle trough region
|
||||
* **±180°**: Mid-cycle descending phase
|
||||
|
||||
* **Phase Progression:**
|
||||
* Continuous upward movement → Normal cycle progression
|
||||
* Phase stalling → Potential cycle extension or trend development
|
||||
* Rapid phase changes → Cycle compression or volatility spike
|
||||
|
||||
* **Derived Period Analysis:**
|
||||
* Period < 10 → High-frequency cycle dominance
|
||||
* Period 15-40 → Typical swing trading cycles
|
||||
* Period > 50 → Trending market conditions
|
||||
|
||||
* **Trend State Variable:**
|
||||
* **+1**: Long trend conditions (slow phase change in extreme zones)
|
||||
* **-1**: Short trend or consolidation (slow phase change in neutral zones)
|
||||
* **0**: Active cycling (normal phase change rate)
|
||||
|
||||
## Applications
|
||||
|
||||
* **Cycle-Based Trading:**
|
||||
* Enter long positions near -90° crossings (cycle troughs)
|
||||
* Enter short positions near +90° crossings (cycle peaks)
|
||||
* Exit positions during mid-cycle phases (0°, ±180°)
|
||||
|
||||
* **Market Timing:**
|
||||
* Use phase acceleration for early trend detection
|
||||
* Monitor derived period for cycle length changes
|
||||
* Combine with trend state for regime-appropriate strategies
|
||||
|
||||
* **Risk Management:**
|
||||
* Adjust position sizes based on cycle clarity (derived period stability)
|
||||
* Implement different risk parameters for trending vs. cycling regimes
|
||||
* Use phase velocity for stop-loss placement timing
|
||||
|
||||
## Limitations and Considerations
|
||||
|
||||
* **Parameter Sensitivity:**
|
||||
* Fixed period assumption may not match actual market cycles
|
||||
* Requires cycle period optimization for different markets and timeframes
|
||||
* Performance degrades when multiple cycles interfere
|
||||
|
||||
* **Computational Complexity:**
|
||||
* Correlation calculations over full period windows
|
||||
* Multiple mathematical transformations increase processing requirements
|
||||
* Real-time implementation requires efficient algorithms
|
||||
|
||||
* **Market Conditions:**
|
||||
* Most effective in markets with clear cyclical behavior
|
||||
* May provide false signals during strong trending periods
|
||||
* Requires sufficient historical data for correlation analysis
|
||||
|
||||
Complementary Indicators:
|
||||
* MESA Adaptive Moving Average (cycle-based smoothing)
|
||||
* Dominant Cycle Period indicators
|
||||
* Detrended Price Oscillator (cycle identification)
|
||||
|
||||
## References
|
||||
|
||||
1. Ehlers, J.F. "Cycle Analytics for Traders." Wiley, 2013.
|
||||
2. Ehlers, J.F. "Cybernetic Analysis for Stocks and Futures." Wiley, 2004.
|
||||
@@ -0,0 +1,119 @@
|
||||
// The MIT License (MIT)
|
||||
// © mihakralj (Implementation based on John Ehlers' "Phasor Analysis" and user-provided v6 function structure)
|
||||
//@version=6
|
||||
indicator("Ehlers Phasor Analysis (PHASOR)", shorttitle="PHASOR", overlay=false)
|
||||
|
||||
//@function Calculates the Ehlers Phasor Angle, Derived Period, and Trend State.
|
||||
//@doc https://github.com/mihakralj/pinescript/blob/main/indicators/cycles/phasor.md
|
||||
//@param src The source series to analyze.
|
||||
//@param period The fixed cycle period to correlate against. Default is 28.
|
||||
//@returns A tuple: `[float finalPhasorAngle, float derivedPeriod, int trendState]`.
|
||||
phasor(series float src, simple int period = 28) =>
|
||||
float sx_corr = 0.0
|
||||
float sy_cos_corr = 0.0
|
||||
float sxx_corr = 0.0
|
||||
float sxy_cos_corr = 0.0
|
||||
float syy_cos_corr = 0.0
|
||||
for i = 0 to period - 1
|
||||
float x_val = nz(src[i])
|
||||
float y_val_cos = math.cos(2 * math.pi * i / period)
|
||||
sx_corr += x_val
|
||||
sy_cos_corr += y_val_cos
|
||||
sxx_corr += x_val * x_val
|
||||
sxy_cos_corr += x_val * y_val_cos
|
||||
syy_cos_corr += y_val_cos * y_val_cos
|
||||
float real_part = 0.0
|
||||
float den_cos = (period * sxx_corr - sx_corr * sx_corr) * (period * syy_cos_corr - sy_cos_corr * sy_cos_corr)
|
||||
if den_cos > 0
|
||||
real_part := (period * sxy_cos_corr - sx_corr * sy_cos_corr) / math.sqrt(den_cos)
|
||||
sx_corr := 0.0
|
||||
sxx_corr := 0.0
|
||||
float sy_sin_corr = 0.0
|
||||
float sxy_sin_corr = 0.0
|
||||
float syy_sin_corr = 0.0
|
||||
for i = 0 to period - 1
|
||||
float x_val = nz(src[i])
|
||||
float y_val_sin = -math.sin(2 * math.pi * i / period) // Negative sine as per Ehlers
|
||||
sx_corr += x_val
|
||||
sxx_corr += x_val * x_val
|
||||
sy_sin_corr += y_val_sin
|
||||
sxy_sin_corr += x_val * y_val_sin
|
||||
syy_sin_corr += y_val_sin * y_val_sin
|
||||
float imag_part = 0.0
|
||||
float den_sin = (period * sxx_corr - sx_corr * sx_corr) * (period * syy_sin_corr - sy_sin_corr * sy_sin_corr)
|
||||
if den_sin > 0
|
||||
imag_part := (period * sxy_sin_corr - sx_corr * sy_sin_corr) / math.sqrt(den_sin)
|
||||
float current_raw_phase = 0.0
|
||||
if real_part != 0.0
|
||||
current_raw_phase := 90.0 - math.atan(imag_part / real_part) * 180.0 / math.pi
|
||||
if real_part < 0.0
|
||||
current_raw_phase -= 180.0
|
||||
else if imag_part != 0.0
|
||||
current_raw_phase := imag_part > 0.0 ? 0.0 : 180.0
|
||||
var float core_Phasor_unwrapped_state = na
|
||||
if not na(core_Phasor_unwrapped_state[1])
|
||||
float diff = current_raw_phase - core_Phasor_unwrapped_state[1]
|
||||
if diff > 180.0
|
||||
current_raw_phase -= 360.0
|
||||
else if diff < -180.0
|
||||
current_raw_phase += 360.0
|
||||
core_Phasor_unwrapped_state := na(core_Phasor_unwrapped_state[1]) ? current_raw_phase : core_Phasor_unwrapped_state[1] + (current_raw_phase - core_Phasor_unwrapped_state[1])
|
||||
float calculated_Phasor_val = core_Phasor_unwrapped_state
|
||||
var float final_Phasor_state = na
|
||||
if na(final_Phasor_state[1])
|
||||
final_Phasor_state := calculated_Phasor_val
|
||||
else
|
||||
if calculated_Phasor_val < final_Phasor_state[1] and ((calculated_Phasor_val > -135 and final_Phasor_state[1] < 135) or (calculated_Phasor_val < -90 and final_Phasor_state[1] < -90))
|
||||
final_Phasor_state := final_Phasor_state[1]
|
||||
else
|
||||
final_Phasor_state := calculated_Phasor_val
|
||||
var float derivedPeriod_calc_state = na
|
||||
float angle_Change_For_Period = final_Phasor_state - nz(final_Phasor_state[1], final_Phasor_state)
|
||||
if nz(angle_Change_For_Period) == 0 and not na(derivedPeriod_calc_state[1])
|
||||
if derivedPeriod_calc_state[1] != 0
|
||||
angle_Change_For_Period := 360.0 / derivedPeriod_calc_state[1]
|
||||
else
|
||||
angle_Change_For_Period := 0.0
|
||||
if nz(angle_Change_For_Period) <= 0 and not na(derivedPeriod_calc_state[1])
|
||||
if derivedPeriod_calc_state[1] != 0
|
||||
angle_Change_For_Period := 360.0 / derivedPeriod_calc_state[1]
|
||||
else
|
||||
angle_Change_For_Period := 0.0
|
||||
if nz(angle_Change_For_Period) != 0.0
|
||||
derivedPeriod_calc_state := 360.0 / angle_Change_For_Period
|
||||
else if not na(derivedPeriod_calc_state[1])
|
||||
derivedPeriod_calc_state := derivedPeriod_calc_state[1]
|
||||
else
|
||||
derivedPeriod_calc_state := 60.0
|
||||
derivedPeriod_calc_state := math.max(1.0, math.min(derivedPeriod_calc_state, 60.0))
|
||||
var int trendState_calc_state = 0
|
||||
float angle_Change_For_State = final_Phasor_state - nz(final_Phasor_state[1], final_Phasor_state)
|
||||
int currentTrendState_calc = 0
|
||||
if angle_Change_For_State <= 6.0
|
||||
if final_Phasor_state >= 90.0 or final_Phasor_state <= -90.0
|
||||
currentTrendState_calc := 1
|
||||
else if final_Phasor_state > -90.0 and final_Phasor_state < 90.0
|
||||
currentTrendState_calc := -1
|
||||
trendState_calc_state := currentTrendState_calc
|
||||
[final_Phasor_state, derivedPeriod_calc_state, trendState_calc_state]
|
||||
|
||||
// ---------- Inputs ----------
|
||||
i_period = input.int(28, "Period", minval=1, group="Phasor Settings")
|
||||
i_source = input.source(close, "Source", group="Phasor Settings")
|
||||
showDerivedPeriod = input.bool(false, "Show Derived Period", group="Optional Plots", inline="derived_period")
|
||||
showTrendState = input.bool(false, "Show Trend State Variable", group="Optional Plots", inline="trend_state")
|
||||
|
||||
// ---------- Calculations ----------
|
||||
// Call the main function to get all values
|
||||
[phasorAngle, derivedPeriodValue, trendStateValue] = phasor(i_source, i_period)
|
||||
|
||||
// ---------- Plotting Phasor Angle ----------
|
||||
plot(phasorAngle, "Phasor Angle", color=color.yellow, linewidth=2)
|
||||
|
||||
|
||||
// ---------- Optional Plots ----------
|
||||
// Plot for Derived Period
|
||||
plot(showDerivedPeriod ? derivedPeriodValue : na, "Derived Period", color=color.yellow, linewidth=2)
|
||||
|
||||
// Plot for Trend State
|
||||
plot(showTrendState ? trendStateValue : na, "Trend State", color=color.yellow, linewidth=2, style=plot.style_histogram)
|
||||
Reference in New Issue
Block a user