https://www.tradingview.com/script/AlUa … lopes-TAE/
Код для правки
-------------------------
--------------------
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// The_Peaceful_Lizard
//@version=5
indicator("True Amplitude Envelopes (TAE)")
// { <FUNCTIONS>
// color {
method scale_alpha(float self, float alpha = 80)=>
float invert = 100 - alpha
self * invert / 100
method new_alpha(color self, float alpha = 80)=>
color.new(self, alpha + color.t(self).scale_alpha(alpha))
// color }
// auto period {
auto_period(float source, simple float minimum, simple float maximum, simple bool extra_hpf = true)=>
float period = 0
float coef_1 = 0.0962
float coef_2 = 0.5769
float coef_3 = 0.075 * nz(period[1]) + 0.54
float smooth = (4 * source + 3 * nz(source[1]) + 2 * nz(source[2]) + nz(source[3])) / 10.0
float detrend = switch extra_hpf
true => coef_3 * (coef_1 * smooth + coef_2 * nz(smooth[2]) - coef_2 * nz(smooth[4]) - coef_1 * nz(smooth[6]))
=> smooth
float quad_1 = coef_3 * (coef_1 * detrend + coef_2 * nz(detrend[2]) - coef_2 * nz(detrend[4]) - coef_1 * nz(detrend[6]))
float phase_1 = nz(detrend[3])
float phase_advanced = coef_3 * (coef_1 * phase_1 + coef_2 * nz(phase_1[2]) - coef_2 * nz(phase_1[4]) - coef_1 * nz(phase_1[6]))
float quad_advanced = coef_3 * (coef_1 * quad_1 + coef_2 * nz(quad_1[2]) - coef_2 * nz(quad_1[4]) - coef_1 * nz(quad_1[6]))
float phase_2 = phase_1 - quad_advanced
float quad_2 = quad_1 + phase_advanced
phase_2 := 0.2 * phase_2 + 0.8 * nz(phase_2[1])
quad_2 := 0.2 * quad_2 + 0.8 * nz(quad_2[1])
float real_part = phase_2 * nz(phase_2[1]) + quad_2 * nz(quad_2[1])
float imaginary_part = phase_2 * nz(quad_2[1]) - quad_2 * nz(phase_2[1])
real_part := 0.2 * real_part + 0.8 * nz(real_part[1])
imaginary_part := 0.2 * imaginary_part + 0.8 * nz(imaginary_part[1])
period := (real_part != 0 and imaginary_part != 0) ? 2 * math.pi / math.atan(imaginary_part / real_part) : 0
period := math.min(period, 1.5 * nz(period[1], period))
period := math.max(period, (2.0 / 3.0) * nz(period[1], period))
period := math.min(math.max(period, minimum), maximum)
period := period * 0.2 + nz(period[1]) * 0.8
period
// auto period }
// filter {
ema(float source = close, float length = 9)=>
float alpha = 2.0 / (length + 1)
var float smoothed = na
smoothed := alpha * source + (1 - alpha) * nz(smoothed[1])
smoothed
biquad_lpf(float source = close, float length = 10, float Q = 0.5, simple bool enable = true)=>
if enable
var float a1 = na
var float a2 = na
var float b0 = na
var float b1 = na
var float b2 = na
if barstate.isfirst or length != length[1] or Q != Q[1]
float fc = 1 / math.max(2, length)
float omega = 2 * math.pi * fc
float cos_omega = math.cos(omega)
float alpha = math.sin(omega)/(2 * Q)
float a0 = 1 / (1 + alpha)
float b = 1 - cos_omega
a1 := -2 * cos_omega * a0
a2 := (1 - alpha) * a0
b0 := b / 2 * a0
b1 := b * a0
b2 := b0
var float biquad = nz(source)
float x = nz(source)
float x1 = nz(source[1], x)
float x2 = nz(source[2], x1)
float y1 = nz(biquad[1], biquad)
float y2 = nz(biquad[2], y1)
biquad := b0 * x + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2
biquad
else
source
biquad_hpf(float source = close, float length = 50, bool style)=>
var float a1 = na
var float a2 = na
var float b0 = na
var float b1 = na
var float b2 = na
if barstate.isfirst or length != length[1]
float fc = 1 / math.max(2, length)
float omega = 2 * math.pi * fc
float cos_omega = math.cos(omega)
float alpha = switch style
true => math.sin(omega) / math.sqrt(2)
false => math.sin(omega)
float a0 = 1 / (1 + alpha)
float b = 1 + cos_omega
a1 := -2 * cos_omega * a0
a2 := (1 - alpha) * a0
b0 := b / 2 * a0
b1 := -b * a0
b2 := b0
var float biquad = source
float x = source
float x1 = nz(source[1], x)
float x2 = nz(source[2], x1)
float y1 = nz(biquad[1], biquad)
float y2 = nz(biquad[2], y1)
biquad := b0 * x + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2
biquad
// filter }
// kde {
type coefficients
float[] weights
float sumw
sinc(series float source, series float bandwidth) =>
float omega = math.pi * source / bandwidth
source != 0.0 ? math.sin(omega) / omega : 1.0
gaussian(float source, float bandwidth) =>
math.exp(-math.pow(source / bandwidth, 2) / 2) / math.sqrt(2 * math.pi)
epanechnikov(float source, float bandwidth) =>
math.abs(source / bandwidth) <= 1 ? (3/4.) * (1 - math.pow(source / bandwidth, 2)) : 0.0
logistic(float source, float bandwidth) =>
1 / (math.exp(source / bandwidth) + 2 + math.exp(-source / bandwidth))
triangular(float source, float bandwidth) =>
math.abs(source / bandwidth) <= 1 ? 1 - math.abs(source / bandwidth) : 0.0
kernel(float source, float bandwidth, string style)=>
switch str.lower(style)
"sinc" => sinc(source, bandwidth)
"gaussian" => gaussian(source, bandwidth)
"epanechnikov" => epanechnikov(source, bandwidth)
"logistic" => logistic(source, bandwidth)
"triangular" => triangular(source, bandwidth)
precalculate(float bandwidth, int length, string style)=>
var coefficients[] c = array.new<coefficients>()
if barstate.isfirst
for i = 0 to length
coefficients w = coefficients.new(array.new<float>(), 0)
float sumw = 0
for j = 0 to length
diff = i - j
weight = kernel(diff, bandwidth, style)
sumw += weight
w.weights.push(weight)
w.sumw := sumw
c.push(w)
c
else
c
method kde_static(series array<float> source, coefficients[] weights)=>
int source_size = source.size()
array<float> est = array.new<float>(source_size)
if source_size > 0
for int i = 0 to source_size - 1
float sum = 0.0
float[] weight = weights.get(i).weights
float sumw = weights.get(i).sumw
for int j = 0 to source_size - 1
float w = weight.get(j)
sum += w * array.get(source, j)
float current_price = sum / sumw
est.set(i, current_price >= 0.0 ? current_price : 0.0)
est
else
source
method kde_dynamic(series array<float> source, float bandwidth, string style)=>
int source_size = source.size()
array<float> est = array.new<float>(source_size)
if source_size > 0
for int i = 0 to source_size - 1
float sum = 0.0
float sumw = 0
for int j = 0 to source_size - 1
int diff = i - j
weight = kernel(diff, bandwidth, style)
sumw += weight
sum += weight * array.get(source, j)
float current_price = sum / sumw
est.set(i, current_price >= 0.0 ? current_price : 0.0)
est
// kde }
// tae helpers {
get_data(float source, int length)=>
var float[] data = array.new<float>(length, 0)
data.unshift(source)
data.pop()
data
get_data_dynamic(float source, int length)=>
float[] data = array.new<float>(length, 0)
for i = 0 to length - 1
data.set(i, nz(source[i]))
data
method half_wave_rectify(float[] self)=>
int size = self.size()
float[] top = array.new<float>(size, 0)
float[] bottom = array.new<float>(size, 0)
for i = 0 to size - 1
float val = self.get(i)
if val > 0
top.set(i, val)
else
bottom.set(i, math.abs(val))
[top, bottom]
method full_wave_rectify(float[] self)=>
int size = self.size()
float[] rectify = array.new<float>(size, 0)
for i = 0 to size - 1
rectify.set(i, math.abs(self.get(i)))
rectify
method array_max(float[] self, float[] a, float[] b)=>
for i = 0 to self.size() - 1
self.set(i, math.max(a.get(i), b.get(i)))
method tae_static(float[] source, int its, coefficients[] weights, bool extra_smooth)=>
float[] a = source.copy()
for i = 0 to its - 1
float[] c = a.copy().kde_static(weights)
a.array_max(source, c)
if extra_smooth
a.kde_static(weights).first()
else
a.first()
method tae_dynamic(float[] source, int its, float period, string style, bool extra_smooth)=>
float[] a = source.copy()
if its > 0
for i = 0 to its - 1
float[] c = a.copy().kde_dynamic(period, style)
a.array_max(source, c)
if extra_smooth
a.kde_dynamic(period, style).first()
else
a.first()
// tae helpers }
// envelope {
tae_envelopes_static( series float source
, simple bool filter_q
, simple float length
, simple int tae_its
, simple int tae_length
, simple float tae_smoothing
, simple string tae_filter_style
, simple bool symetric
, simple bool extra_smooth
, simple int history_length)=>
float hpf = biquad_hpf(source, length, filter_q)
float carrier = source - hpf
float[] hpf_series = get_data(hpf, tae_length)
coefficients[] filter_coefs = precalculate(tae_smoothing, tae_length, tae_filter_style)
bool calculate_flag = history_length > 0 ? bar_index >= (last_bar_index - history_length) : true
if calculate_flag
if symetric
float[] signal = hpf_series.full_wave_rectify()
float tae = signal.tae_static(tae_its, filter_coefs, extra_smooth)
float top = carrier + tae
float bottom = carrier - tae
[carrier, top, bottom, hpf, tae, -tae]
else
[top_signal, bottom_signal] = hpf_series.half_wave_rectify()
float top_tae = top_signal.tae_static(tae_its, filter_coefs, extra_smooth)
float bottom_tae = bottom_signal.tae_static(tae_its, filter_coefs, extra_smooth)
float top = carrier + top_tae
float bottom = carrier - bottom_tae
[carrier, top, bottom, hpf, top_tae, -bottom_tae]
tae_envelopes_dynamic( series float source
, simple bool filter_q
, simple int its
, simple float filter_period_multiplier
, simple float filter_min_period
, simple float filter_max_period
, simple float tae_period_multiplier
, simple float tae_min_period
, simple float tae_max_period
, simple string tae_filter_style
, simple bool symetric
, simple bool extra_smooth
, simple bool extra_hpf
, simple int history_length)=>
float period = nz(auto_period(source, filter_min_period, filter_max_period), filter_min_period) * filter_period_multiplier
float hpf = biquad_hpf(source, period, filter_q)
float carrier = source - hpf
float hpf_period = nz(auto_period(hpf, tae_min_period, tae_max_period, extra_hpf), tae_min_period) * tae_period_multiplier
int int_period = math.max(1, int(hpf_period))
float[] hpf_series = get_data_dynamic(hpf, int_period)
bool calculate_flag = history_length > 0 ? bar_index >= (last_bar_index - history_length) : true
if calculate_flag
if symetric
float[] signal = hpf_series.full_wave_rectify()
float tae = signal.tae_dynamic(its, hpf_period, tae_filter_style, extra_smooth)
float top = carrier + tae
float bottom = carrier - tae
[carrier, top, bottom, hpf, tae, -tae]
else
[top_signal, bottom_signal] = hpf_series.half_wave_rectify()
float top_tae = top_signal.tae_dynamic(its, hpf_period * 0.5, tae_filter_style, extra_smooth)
float bottom_tae = bottom_signal.tae_dynamic(its, hpf_period * 0.5, tae_filter_style, extra_smooth)
float top = carrier + top_tae
float bottom = carrier - bottom_tae
[carrier, top, bottom, hpf, top_tae, -bottom_tae]
tae_envelopes( series float source
, simple bool filter_q
, simple float length
, simple int tae_its
, simple int tae_length
, simple float tae_smoothing
, simple float filter_period_multiplier
, simple float filter_min_period
, simple float filter_max_period
, simple float tae_period_multiplier
, simple float tae_min_period
, simple float tae_max_period
, simple string tae_filter_style
, simple bool symetric
, simple string envelope_style
, simple bool extra_smooth
, simple bool extra_hpf
, simple int history_length)=>
if envelope_style == "Static"
[carrier, top, bottom, hpf, top_tae, bottom_tae] = tae_envelopes_static( source
, filter_q
, length
, tae_its
, tae_length
, tae_smoothing
, tae_filter_style
, symetric
, extra_smooth
, history_length)
else
[carrier, top, bottom, hpf, top_tae, bottom_tae] = tae_envelopes_dynamic(source
, filter_q
, tae_its
, filter_period_multiplier
, filter_min_period
, filter_max_period
, tae_period_multiplier
, tae_min_period
, tae_max_period
, tae_filter_style
, symetric
, extra_smooth
, extra_hpf
, history_length)
// envelope }
// } <FUNCTIONS>
// { <INPUTS>
// main settings {
const string main_settings = "Main Settings"
const string history_tip = "Pick how much historical data to show. When set to 0 it will display all."
const string iteration_tip = "Number of iterations used in the envelope algorithm."
const string kernel_tip = "Filter kernel used in the kernel density estimator for smoothing the envelope."
const string envelope_style_tip = "Dynamic utilizes automatic dominant period analysis. Static allows you to pick a static setting for the envelope."
const string symmetry_tip = "Allows you to have symmetric or asymmetric envelopes."
const string extra_smooth_tip = "Makes the envelop smoother but reduces responsiveness."
const string q_tip = "Has the effect of increasing the period of the filter."
float source = input.source(close, "Source", group = main_settings)
int history_length = input.int(2000, "History", minval = 0, tooltip = history_tip, group = main_settings)
int tae_its = input.int(10, "Iterations", minval = 1, tooltip = iteration_tip, group = main_settings)
string tae_filter_style = input.string("Epanechnikov", "Kernel Style", ["Sinc", "Gaussian", "Epanechnikov", "Logistic", "Triangular"], tooltip = kernel_tip, group = main_settings)
string envelope_style = input.string("Dynamic", "Envelope Style", ["Static", "Dynamic"], tooltip = envelope_style_tip, group = main_settings)
bool filter_q = input.bool(false, "High Q", tooltip = q_tip, group = main_settings)
bool symetric = input.bool(false, "Symetric", tooltip = symmetry_tip, group = main_settings)
bool extra_smooth = input.bool(true, "Smooth Envelopes", tooltip = extra_smooth_tip, group = main_settings)
// main settings }
// dynamic settings {
const string dynamic_group = "Dynamic Settings"
const string detrend_tip = "Enable when using a long filter period."
bool extra_hpf = input.bool(false, "Extra Detrend", tooltip = detrend_tip, group = dynamic_group)
float filter_period_multiplier = input.float(2, "Filter Period Multiplier", minval = 0.125, step = 0.125, group = dynamic_group)
float filter_min_period = input.float(9, "Filter Period | Min: ", minval = 0.125, step = 0.125, inline = "Filter Dynamic", group = dynamic_group)
float filter_max_period = input.float(128, "Max: ", minval = 0.125, step = 0.125, inline = "Filter Dynamic", group = dynamic_group)
float tae_period_multiplier = input.float(1, "Envelope Period Multiplier", minval = 0.125, step = 0.125, group = dynamic_group)
float tae_min_period = input.float(9, "Envelope Period | Min: ", minval = 0.125, step = 0.125, inline = "Envelope Dynamic", group = dynamic_group)
float tae_max_period = input.float(64, "Max: ", minval = 0.125, step = 0.125, inline = "Envelope Dynamic", group = dynamic_group)
// dynamic settings }
// static settings {
const string static_group = "Static Settings"
float length = input.float(100, "Filter Period", minval = 2, step = 0.5, group = static_group)
int tae_length = input.int(20, "Envelope Period", minval = 1, group = static_group)
float tae_smoothing = input.float(40, "TAE Smoothing", minval = 0, step = 0.125, group = static_group)
// static settings }
// oscillator settings {
const string osc_settings = "Oscillator Settings"
bool enable_osc_smoothing = input.bool(true, "Enable Smoothing", group = osc_settings)
float osc_period = input.float(10, "Oscillator Period", minval = 2, step = 0.5, group = osc_settings)
float osc_q = input.float(0.5, "Oscillator Q", minval = 0.125, step = 0.125, group = osc_settings)
float signal_period = input.float(10, "Signal Period", minval = 2, step = 0.5, group = osc_settings)
// oscillator settings }
// visual settings {
const string visual_group = "Visual Settings"
bool show_overlay = input.bool(true, "Show Overlay", group = visual_group)
color filter_color = input.color(#1C7FD0, "Center", group = visual_group)
color top_band_color = input.color(#17CC35, "Top Band", group = visual_group)
color bottom_band_color = input.color(#EF292C, "Bottom Band", group = visual_group)
color osc_signal_color = input.color(#F5BB00, "Oscillator Signal", group = visual_group)
int line_width = input.int(1, "Line Width", minval = 1, group = visual_group)
int fill_alpha = input.int(90, "Fill Alpha", minval = 0, maxval = 100, group = visual_group)
// visual settings }
// } <INPUTS>
// { <CALCULATIONS>
// tae {
[carrier, top, bottom, hpf, top_tae, bottom_tae] = tae_envelopes(source
, filter_q
, length
, tae_its
, tae_length
, tae_smoothing
, filter_period_multiplier
, filter_min_period
, filter_max_period
, tae_period_multiplier
, tae_min_period
, tae_max_period
, tae_filter_style
, symetric
, envelope_style
, extra_smooth
, extra_hpf
, history_length)
// tae }
// oscillator {
float hpf_signal = biquad_lpf(hpf, osc_period, osc_q, enable_osc_smoothing)
float osc_signal = ema(hpf_signal, signal_period)
// oscillator }
// } <CALCULATIONS>
// { <PLOT>
// overlay {
display_overlay_main = show_overlay ? display.all : display.none
display_overlay_glow = show_overlay ? display.pane : display.none
top_band = plot(top, "Envelope Top", top_band_color, line_width, display = display_overlay_main, force_overlay = true)
plot(top, "Envelope Top", top_band_color.new_alpha(80), line_width + 2, display = display_overlay_glow, force_overlay = true)
plot(top, "Envelope Top", top_band_color.new_alpha(80), line_width + 3, display = display_overlay_glow, force_overlay = true)
plot(top, "Envelope Top", top_band_color.new_alpha(90), line_width + 5, display = display_overlay_glow, force_overlay = true)
bottom_band = plot(bottom, "Envelope Bottom", bottom_band_color, line_width, display = display_overlay_main, force_overlay = true)
plot(bottom, "Envelope Bottom", bottom_band_color.new_alpha(80), line_width + 2, display = display_overlay_glow, force_overlay = true)
plot(bottom, "Envelope Bottom", bottom_band_color.new_alpha(80), line_width + 3, display = display_overlay_glow, force_overlay = true)
plot(bottom, "Envelope Bottom", bottom_band_color.new_alpha(90), line_width + 5, display = display_overlay_glow, force_overlay = true)
filter = plot(carrier, "Filter", filter_color, line_width, display = display_overlay_main, force_overlay = true)
plot(carrier, "Filter", filter_color.new_alpha(80), line_width + 2, display = display_overlay_glow, force_overlay = true)
plot(carrier, "Filter", filter_color.new_alpha(80), line_width + 3, display = display_overlay_glow, force_overlay = true)
plot(carrier, "Filter", filter_color.new_alpha(90), line_width + 5, display = display_overlay_glow, force_overlay = true)
fill(top_band, filter, top, carrier, top_band_color.new_alpha(fill_alpha), color.new(top_band_color, 100), "Top Fill", display_overlay_main)
fill(filter, bottom_band, carrier, bottom, color.new(bottom_band_color, 100), bottom_band_color.new_alpha(fill_alpha), "Bottom Fill", display_overlay_main)
// overlay }
// osc {
zero_line = plot(0, "Zero Line", color.silver)
upper_band = plot(top_tae, "Oscillator Envelope Top", top_band_color, line_width)
plot(top_tae, "Oscillator Envelope Top", top_band_color.new_alpha(80), line_width + 3, display = display.pane)
plot(top_tae, "Oscillator Envelope Top", top_band_color.new_alpha(90), line_width + 5, display = display.pane)
lower_band = plot(bottom_tae, "Oscillator Envelope Bottom", bottom_band_color, line_width)
plot(bottom_tae, "Oscillator Envelope Bottom", bottom_band_color.new_alpha(80), line_width + 3, display = display.pane)
plot(bottom_tae, "Oscillator Envelope Bottom", bottom_band_color.new_alpha(90), line_width + 5, display = display.pane)
plot(osc_signal, "Oscillator Signal", osc_signal_color, line_width)
plot(osc_signal, "Oscillator Signal", osc_signal_color.new_alpha(80), line_width + 3, display = display.pane)
plot(osc_signal, "Oscillator Signal", osc_signal_color.new_alpha(90), line_width + 5, display = display.pane)
plot(hpf_signal, "Oscillator", filter_color, line_width)
plot(hpf_signal, "Oscillator", filter_color.new_alpha(80), line_width + 3, display = display.pane)
plot(hpf_signal, "Oscillator", filter_color.new_alpha(90), line_width + 5, display = display.pane)
fill(upper_band, zero_line, top_tae, 0, top_band_color.new_alpha(fill_alpha), color.new(top_band_color, 100), "Top Fill")
fill(zero_line, lower_band, 0, bottom_tae, color.new(bottom_band_color, 100), bottom_band_color.new_alpha(fill_alpha), "Bottom Fill")
// osc }
// } <PLOT>