>Guppy's Multiple Moving Average (GMMA). It consists of:
>
>6 blue [short] EMA's - 3, 5, 8, 10, 12, 15 periods apiece.
>6 Red [long] EMA's - 30, 35, 40, 45, 50, 60 apiece.
>
>That's all. I figure it should be relatively simple to do.
Yeah, it’s really simple to do, so let’s start.
(Note: the full source code for this indicator is at the end of this topic)
(Note: Click on an image's thumbnail to open the full-size image)
At first, please read the article Definitions in the Indicore SDK documentation.
Then, we must “introduce” our indicator to the Marketscope. We would like to call it “GMMA” or “Guppy's Multiple Moving Average”.
GMMA is a short name of the indicator. The short name must be also the file name, so take your favorite text editor and create a file called “GMMA.lua”.
All “introducing” information must be specified in the Init function of the indicator, so let’s write it. Define a “human-friendly” name first.
Then we must tell the Marketscope what is the price we can apply the indicator to. In our case, the indicator does not use open, high, low and close prices at the same time and can be applied to any of these prices, for example to close prices only. Also, the indicator can be applied to a tick data. So, the prices required for this indicator are tick prices.
Then we must tell how to place our indicator on the chart. Our indicator will process the data which is similar to the source prices, so it can be drawn over these prices. However, users can specify that the indicator must be drawn in a separate area, but by default the Marketscope will recommend to draw the indicator over the prices.
And the last, but not least is to tell the Marketscope which parameters must be asked when the indicator is applied to the chart. Our indicator requires only two parameters: a color for the short EMA’s set and a color for the long EMA’s set. Let’s recommend blue for the first and red for the last parameter.
That’s all, now the Marketscope knows everything it needs to let the user apply our indicator to the chart.
The next step is to describe what to do when the user has already applied the indicator to the price chart. There is the Prepare function which is called every time the indicator is applied (or every time the user changes the instrument or the period of the chart).
At this step we have to tell the Marketscope what we will draw and prepare our code for calculation of the values in future.
Let’s start. At the first step add the Prepare function and put the price data into the global variable for easier access in future.
Then we have to create 12 lines which will show our EMA’s indicators. We have to remember the tables returned by the method (addStream) which is used for creating the indicator lines. These tables will be used for filling the calculated data. Please, pay attention to the last parameter of the addStream method. This is the first period which can be calculated for the line.
Follow me. The EMA’s formula is:
PRICE * K – PREVIOUS EMA x (1 - K),
where K is (2 /(PERIODS + 1))
The first EMA (when the PREVIOUS EMA is not defined) is calculated as the simple moving average for the PERIODS.
So, until we don’t have, for example, 3 periods of the prices for a 3-period EMA, we can’t start the calculation at all. So, the first period when we can start the calculation is period 2 (the period numeration is started from 0 (the oldest available price), so we have 3 periods: 0, 1 and 2).
Because the source can also start later than period 0 (for example when our indicator is applied to the results of another indicator), the first period when we can calculate EMA(3) is
FIRST SOURCE + 3 – 1.
We also store all our EMAs into the array and introduce the CreateEMA function to avoid duplicating the same code multiple times.
Now we can create our lines:
That’s all, our indicator explained what to draw and is ready to calculate the lines. Now we can write the most important part of the indicator: the Update function.
This function is called for each period, starting from the oldest one which is not calculated yet. So, the first time the Update function will be called for each period of the source price. Then it will be called only for newly appearing periods.
At first, write the function which calculates the EMA value for the particular period. There are three cases:
1) If the period is before the first period which can be calculated – do nothing.
2) If it’s the first period we can calculate – calculate the simple moving average
3) If it’s the next period(s) – calculate the EMA for the specified period.
Are you tired yet? The final step is to write the Update function itself and call the calculation function for each of our 12 indicator’s lines.
Install the indicator to the Marketscope and try it:
Everything looks fine except the name of the indicator in the top left corner of the chart area. We have just forgotten to tell the Marketscope how to call this instance of the indicator (it usually differs from the short name of the indicator because it also contains the specified parameters, for example MVA is an indicator, MVA(EUR/USD, 5) is a 5-period MVA applied to EUR/USD). Just add a few lines to the code:
Voila, the indicator is ready!
The code is below (copy-paste it into GMMA.lua):
- Code: Select all
function Init()
indicator:name("Guppy's Multiple Moving Average");
indicator:requiredSource(core.Tick);
indicator:type(core.Indicator);
indicator.parameters:addColor("S_COLOR", "Color for the short EMA group", "", core.rgb(0, 0, 255));
indicator.parameters:addColor("L_COLOR", "Color for the long EMA group", "", core.rgb(255, 0, 0));
end
local source = nil;
local EMAs = {}; -- an array of outputs
function CreateEMA(index, N, color, name)
local label;
-- line label
label = "EMA" .. N;
-- create the line
EMAs[index] = instance:addStream(label, core.Line, name .. label, label,
color, source:first() + N - 1);
end
function Prepare()
source = instance.source;
local name;
-- set the indicator name (use the short name of our indicator: GMMA)
name = profile:id() .. "(" .. source:name() .. ")";
instance:name(name);
CreateEMA(0, 3, instance.parameters.S_COLOR, name);
CreateEMA(1, 5, instance.parameters.S_COLOR, name);
CreateEMA(2, 8, instance.parameters.S_COLOR, name);
CreateEMA(3, 10, instance.parameters.S_COLOR, name);
CreateEMA(4, 12, instance.parameters.S_COLOR, name);
CreateEMA(5, 15, instance.parameters.S_COLOR, name);
CreateEMA(6, 30, instance.parameters.L_COLOR, name);
CreateEMA(7, 35, instance.parameters.L_COLOR, name);
CreateEMA(8, 40, instance.parameters.L_COLOR, name);
CreateEMA(9, 45, instance.parameters.L_COLOR, name);
CreateEMA(10, 50, instance.parameters.L_COLOR, name);
CreateEMA(11, 60, instance.parameters.L_COLOR, name);
end
function CalcEMA(index, N, period)
local first;
first = source:first() + N - 1;
if period < first then
return ;
elseif period == first then
-- range: period - N + 1, period - N + 2, ..., period
local range = core.rangeTo(period, N);
EMAs[index][period] = core.avg(source, range);
else
local k;
k = 2.0 / (N + 1.0);
-- EMA - PRICE * K - PREV EMA * (1 - K)
EMAs[index][period] = source[period] * k + EMAs[index][period - 1] * (1 - k);
end
end
function Update(period)
CalcEMA(0, 3, period);
CalcEMA(1, 5, period);
CalcEMA(2, 8, period);
CalcEMA(3, 10, period);
CalcEMA(4, 12, period);
CalcEMA(5, 15, period);
CalcEMA(6, 30, period);
CalcEMA(7, 35, period);
CalcEMA(8, 40, period);
CalcEMA(9, 45, period);
CalcEMA(10, 50, period);
CalcEMA(11, 60, period);
end
Or download it: