mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-27 17:27:43 +00:00
71 lines
2.6 KiB
Plaintext
71 lines
2.6 KiB
Plaintext
// Licensed under the Apache License, Version 2.0
|
|
// © mihakralj
|
|
//@version=6
|
|
indicator("MA Envelope (MAE)", "MAE", overlay=true)
|
|
|
|
//@function Calculates MA Envelope bands using a fixed percentage
|
|
//@param source Series to calculate moving average from
|
|
//@param length Lookback period for MA calculation
|
|
//@param percentage Distance of bands from MA as percentage
|
|
//@param ma_type Type of moving average (0:SMA, 1:EMA, 2:WMA)
|
|
//@returns tuple with [middle, upper, lower] band values
|
|
//@optimized SMA uses circular buffer O(1), EMA uses warmup O(1), WMA is O(n)
|
|
mae(series float source, simple int length, simple float percentage, simple int ma_type = 1) =>
|
|
if length <= 0 or percentage <= 0.0
|
|
runtime.error("Length and percentage must be greater than 0")
|
|
float middle = na
|
|
if ma_type == 0
|
|
var int head = 0
|
|
var int count = 0
|
|
var array<float> buffer = array.new_float(length, na)
|
|
var float sum = 0.0
|
|
float oldest = array.get(buffer, head)
|
|
if not na(oldest)
|
|
sum -= oldest
|
|
count -= 1
|
|
float current = nz(source)
|
|
sum += current
|
|
count += 1
|
|
array.set(buffer, head, current)
|
|
head := (head + 1) % length
|
|
middle := sum / count
|
|
else if ma_type == 1
|
|
var float alpha = 2.0 / (length + 1)
|
|
var float sum = 0.0
|
|
var float weight = 0.0
|
|
if na(sum)
|
|
sum := source
|
|
weight := 1.0
|
|
sum := sum * (1.0 - alpha) + source * alpha
|
|
weight := weight * (1.0 - alpha) + alpha
|
|
middle := sum / weight
|
|
else if ma_type == 2
|
|
float norm = 0.0
|
|
float sum = 0.0
|
|
for i = 0 to length - 1
|
|
float w = float((length - i) * length)
|
|
norm += w
|
|
sum += nz(source[i]) * w
|
|
middle := sum / norm
|
|
else
|
|
runtime.error("MA type must be 0 (SMA), 1 (EMA), or 2 (WMA)")
|
|
float dist = middle * percentage / 100.0
|
|
[middle, middle + dist, middle - dist]
|
|
|
|
// ---------- Main loop ----------
|
|
|
|
// Inputs
|
|
i_source = input.source(close, "Source")
|
|
i_length = input.int(20, "Length", minval=1)
|
|
i_percentage = input.float(1.0, "Percentage", minval=0.001)
|
|
i_ma_type = input.int(1, "MA Type", minval=0, maxval=2, tooltip="0:SMA, 1:EMA, 2:WMA")
|
|
|
|
// Calculation
|
|
[middle, upper, lower] = mae(i_source, i_length, i_percentage, i_ma_type)
|
|
|
|
// Plot
|
|
plot(middle, "Middle", color=color.yellow, linewidth=2)
|
|
p1 = plot(upper, "Upper", color=color.yellow, linewidth=2)
|
|
p2 = plot(lower, "Lower", color=color.yellow, linewidth=2)
|
|
fill(p1, p2, color=color.new(color.blue, 90), title="Band Fill")
|