mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-04 20:17:43 +00:00
3dd05f23e4
- Updated the name and description of the Hilbert Trendline (HTIT) to "Ehlers Hilbert Transform Instantaneous Trend (HTIT)". - Changed the name and description of the MESA Adaptive Moving Average (MAMA) to "Ehlers MESA Adaptive Moving Average". - Modified the Center of Gravity (CG) indicator to "Ehlers Center of Gravity (CG)". - Renamed the Detrended Synthetic Price (DSP) to "Ehlers Detrended Synthetic Price (DSP)". - Updated the Autocorrelation Periodogram (EACP) to "Ehlers Autocorrelation Periodogram (EACP)". - Changed the Homodyne Discriminator (HOMOD) to "Ehlers Homodyne Discriminator (HOMOD)". - Updated the Hilbert Transform Dominant Cycle Period and Phase indicators to include "Ehlers" in their names. - Renamed the Hilbert Transform Phasor Components to "Ehlers Hilbert Transform Phasor Components (HT_PHASOR)". - Updated the SineWave indicator to "Ehlers Hilbert Transform SineWave (HT_SINE)". - Changed the Phasor Analysis indicator to "Ehlers Hilbert Transform Phasor Components (HT_PHASOR)". - Updated the SSF-Based Detrended Synthetic Price to "Ehlers SSF Detrended Synthetic Price (SSFDSP)". - Renamed the Ultimate Channel to "Ehlers Ultimate Channel (UCHANNEL)". - Added new indicators: Moving Average Variable Period (MAVP), Ehlers Predictive Moving Average (PMA), Ehlers Reverse EMA (REVERSEEMA), and Ehlers Trendflex Indicator (TRENDFLEX). - Updated various SVG badges to reflect changes in classes, comments, source files, lines of code, methods, and public types.
119 lines
5.6 KiB
Plaintext
119 lines
5.6 KiB
Plaintext
// The MIT License (MIT)
|
|
// © mihakralj
|
|
//@version=6
|
|
indicator("Ehlers Hilbert Transform Phasor Components (HT_PHASOR)", shorttitle="HT_PHASOR", overlay=false)
|
|
|
|
//@function Calculates the Ehlers Phasor Angle, Derived Period, and Trend State.
|
|
//@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)
|