Let's we have a goal to detect the candle, which has:
a) The previous candle is a red candle and is below than it's previous to candle.
b) The current candle is a green candle and is below that the previous candle
c) The current candle closes above it's midpoint
or
a) The previous candle is a green candle and is above than it's previous to candle.
b) The current candle is a red candle and is above that the previous candle
c) The current candle closes below it's midpoint
In short, it's a Bullish and Bearish piercing line candle patterns (see, for example, here http://www.bipasforex.com/files/Candle.pdf).
So, we need to develop a… well, it is indicator too, which will mark the candles which satisfy to the conditions above.
There are two serious distinctions from the “numeric” indicators (like a guppy moving average we developed in the previous article).
1) The indicator does not show lines or bars. It must just mark candles.
To mark the candles we can use the alternative indicator output: the text output. The text output is a set of labels which can be applied on the particular bar at the particular price level.
You can read more in the online documentation. See: instance:createTextOutput
Let’s decide on how mark the candles. I suggest using the down arrow located above the candle for the bearish pierce and the up arrow located below the candle for the bullish pierce. There is the standard font called “Wingdings” which contains characters for arrows (note: for some reason Mozilla does not display windings correctly, so please use Internet Explorer to open the previous link). The up arrow has the code 225 and the down arrow has code 226.
Because the up arrow must be located below and the down arrow must be located above, we need for two outputs with different alignment settings. “Alignment” is a rule which describes how to locate the text against the center of the bar and the price level. For example, “Top” means “Locate the character ABOVE the price”, that is good for the marking above the candle high price, and “Bottom” means “Locate the label BELOW the price”, that is good for marking below the candle low price.
2) The indicator must process the closed candles only.
As you know, the indicator update function is called every time when the candle is changed. So, if there were 100 ticks in a 1-minute candle, the Update function will be called 100 times. In our indicator we should not process such “live” candles at all. We have to process only those candles which were recently closed.
To know when one candle is closed and another candle is started we can use so called “serial” number of the bar. The serial number is a number with is unique for each bar in the history. So, when a bar with a new serial number appears we have to process the previous (the recently closed!) bar.
Well. Nuff said about the theory. Let’s start.
As in the first article we have to “introduce” our indicator. Since we don’t have any parameters, the process is pretty simple. This is an indicator (i.e. we want to show the results immediately on the chart) and this indicator requires for bars.
- Code: Select all
function Init()
indicator:name("Piercing Line detector");
indicator:description("");
indicator:requiredSource(core.Bar);
indicator:type(core.Indicator);
indicator.parameters:addColor("clr", "Arrows color", "", core.COLOR_LABEL);
end
We have one parameter. It’s a color for the arrows. Pay attention that in this case we don’t specify the certain color. We use the value “core.COLOR_LABEL” instead. This means that the color must be the same as the color specified in the configuration for the labels.
Then we must prepare the indicator to work when the indicator is applied to chart. There is almost nothing to do except creating two text outputs. One for the up candles and another for the down candles.
- Code: Select all
local source;
local first;
function Prepare()
source = instance.source;
instance:name(profile:id());
up = instance:createTextOutput ("Up", "Up", "Wingdings", 10, core.H_Center, core.V_Top, instance.parameters.clr, 0);
down = instance:createTextOutput ("Dn", "Dn", "Wingdings", 10, core.H_Center, core.V_Bottom, instance.parameters.clr, 0);
first = source:first() + 3;
end
We also remember the source price series in the global variable and calculate the index of the first bar we can recognize (we need two bars before the bar we probe, yeah?). As in the previous indicator we do it just for the better performance.
Now we can start the Update function. First, let’s implement the code which will protect us from multiple calling for the “live” candles.
- Code: Select all
-- the variable to keep the serial number of the previous candle
local last = nil;
function Update(period, mode)
if last == nil or -- if it is first call or
last ~= source:serial(period) then -- another candle started
last = source:serial(period); -- remember the candle
period = period - 1; -- and process the previous period (the
-- candle which just has been closed).
else
-- if the current candle is being changed - do nothing
return ;
end
Please, pay attention on the period = period - 1; line. When we detected that the candle is closed and a new candle appears, the “period” value points us to the newly appeared candle. The recently closed candle is the previous candle. So, we have to subtract one to make “period” pointing to the recently closed candle.
Now we can check whether we have enough candles in history (i.e. period is bigger than the “first” value calculated in the “Init” procedure) and the start to probe the recently closed candle for our conditions.
Let’s translate the conditions into lua.
a) The previous candle is a red candle
source.open[period – 1] > source.close[period – 1]
and is below than it's previous to candle.
source.low[period – 1] < source.low[period – 2] and
source.high[period – 1] < source.high[period – 2]
b) The current candle is a green candle and
source.open[period] < source.close[period]
is below that the previous candle
source.low[period] < source.low[period – 1] and
source.high[period] < source.high[period – 1]
c) The current candle closes above it's midpoint
source.close[period] > (source.high[period] + source.low[period]) / 2
To get the bearish conditions – just invert all comparisons.
If conditions are satisfied – just put the down directed candle (code “226”) above the candle (“up” output, using the high price) or the up directed candle (code “225”) below the candle (“down” output, using the low price).
- Code: Select all
if period > first then
-- detect piercing line bullish
-- the recently closed candle must be completely below the previous candle.
-- the previous candle must be completely below it's previous candle
-- and the close of the current candle must be above the mid point (H + L / 2)
if source.low[period] < source.low[period - 1] and
source.high[period] < source.high[period - 1] and
source.open[period] < source.close[period] and
source.low[period - 1] < source.low[period - 2] and
source.high[period - 1] < source.high[period - 2] and
source.open[period - 1] > source.close[period - 1] and
source.close[period] > (source.high[period] + source.low[period]) / 2 then
down:set(period, source.low[period], "\225");
end
-- detect piercing line bearish
-- the recently closed candle must be completely above the previous candle.
-- the previous candle must be completely above it's previous candle
-- and the close of the current candle must be below the mid point (H + L / 2)
if source.low[period] > source.low[period - 1] and
source.high[period] > source.high[period - 1] and
source.open[period] > source.close[period] and
source.low[period - 1] > source.low[period - 2] and
source.high[period - 1] > source.high[period - 2] and
source.open[period - 1] < source.close[period - 1] and
source.close[period] < (source.high[period] + source.low[period]) / 2 then
up:set(period, source.high[period], "\226");
end
end
end
Let’s see the whole code of the indicator:
- Code: Select all
function Init()
indicator:name("Piercing Line detector");
indicator:description("");
indicator:requiredSource(core.Bar);
indicator:type(core.Indicator);
indicator.parameters:addColor("clr", "Arrow color", "", core.COLOR_LABEL);
end
local source;
local first;
function Prepare()
source = instance.source;
instance:name(profile:id());
up = instance:createTextOutput ("Up", "Up", "Wingdings", 10, core.H_Center, core.V_Top, instance.parameters.clr, 0);
down = instance:createTextOutput ("Dn", "Dn", "Wingdings", 10, core.H_Center, core.V_Bottom, instance.parameters.clr, 0);
first = source:first() + 3;
end
-- the variable to keep the serial number of the previous candle
local last = nil;
function Update(period, mode)
if last == nil or -- if it is first call or
last ~= source:serial(period) then -- another candle started
last = source:serial(period); -- remember the candle
period = period - 1; -- and process the previous period (the
-- candle which just has been closed).
else
-- if the current candle is being changed - do nothing
return ;
end
if period > first then
-- detect piercing line bullish
-- the recently closed candle must be completely below the previous candle.
-- the previous candle must be completely below it's previous candle
-- and the close of the current candle must be above the mid point (H + L / 2)
if source.low[period] < source.low[period - 1] and
source.high[period] < source.high[period - 1] and
source.open[period] < source.close[period] and
source.low[period - 1] < source.low[period - 2] and
source.high[period - 1] < source.high[period - 2] and
source.open[period - 1] > source.close[period - 1] and
source.close[period] > (source.high[period] + source.low[period]) / 2 then
down:set(period, source.low[period], "\225");
end
-- detect piercing line bearish
-- the recently closed candle must be completely above the previous candle.
-- the previous candle must be completely above it's previous candle
-- and the close of the current candle must be below the mid point (H + L / 2)
if source.low[period] > source.low[period - 1] and
source.high[period] > source.high[period - 1] and
source.open[period] > source.close[period] and
source.low[period - 1] > source.low[period - 2] and
source.high[period - 1] > source.high[period - 2] and
source.open[period - 1] < source.close[period - 1] and
source.close[period] < (source.high[period] + source.low[period]) / 2 then
up:set(period, source.high[period], "\226");
end
end
end
Download the indicator: