Moving Average Envelopes or MAE indicator consists of 2 offset lines calculated off Simple Moving Average. Sometimes 3rd line of actual moving average is displayed between 2 offsetting lines.
These 2 offsetting lines are called “Envelope Factor” and their offset can be set in indicator parameters.
The moving average envelopes can be useful in identifying overbought or oversold conditions, where instrument prices hit the top or bottom of their trading range.
Calculation (N - number of periods, W - distance in 1/10 of percent):
Top Line = Moving Average(N) + (Moving Average(N) x W ÷ 1000)
Bottom Line = Moving Average(N) - (Moving Average(N) x W ÷ 1000)
Source Code:
- Code: Select all
-- The indicator corresponds to the Moving Average indicator in MetaTrader.
-- The formula is described in the Kaufman "Trading Systems and Methods" chapter 4 "Trend Calculations" (page 67-70)
-- initializes the indicator
function Init()
indicator:name("Moving Average Envelope (Custom Version)");
indicator:description("Moving Average Envelope which supports 1/10 of percent in parameters");
indicator:requiredSource(core.Tick);
indicator:type(core.Indicator);
indicator.parameters:addInteger("N", "Number of periods of Moving Average", "", 20, 2, 300);
indicator.parameters:addDouble("W", "Band Offset in 1/10 of percent", "", 2.5, 0.001, 1000);
indicator.parameters:addString("SM", "Show MVA?", "", "No");
indicator.parameters:addStringAlternative("SM", "Yes", "", "Yes");
indicator.parameters:addStringAlternative("SM", "No", "", "No");
indicator.parameters:addColor("clrBand", "Color of envelope band", "", core.rgb(0, 0, 255));
indicator.parameters:addColor("clrMva", "Color of moving average", "", core.rgb(255, 0, 0));
end
local first = 0; -- first period we can calculate
local n = 0; -- MVA parameter
local w = 0; -- band width
local source = nil; -- source
local mva = nil; -- moving average
local up = nil; -- upper band
local low = nil; -- lower band
-- initializes the instance of the indicator
function Prepare()
source = instance.source;
n = instance.parameters.N;
w = instance.parameters.W;
first = n + source:first() - 1;
local name = profile:id() .. "(" .. source:name() .. "," .. n .. "," .. w .. ")";
instance:name(name);
if instance.parameters.SM == "Yes" then
mva = instance:addStream("MVA", core.Line, name .. ".MVA", "MVA", instance.parameters.clrMva, first)
end
up = instance:addStream("UP", core.Line, name .. ".UP", "UP", instance.parameters.clrBand, first)
low = instance:addStream("LOW", core.Line, name .. ".LOW", "LOW", instance.parameters.clrBand, first)
end
-- calculate the value
function Update(period)
if (period >= first) then
local v;
v = core.avg(source, core.rangeTo(period, n));
if mva ~= nil then
mva[period] = v;
end
up[period] = v * (1 + w / 1000);
low[period] = v * (1 - w / 1000);
end
end
Download: