This is my first post on Stackoverflow although I've visited here for years.
I have read the message guidelines so I'll be as succinct and specific as possible.
I have been attempting to embed the code of a Custom Indicator directly in an Expert Advisor without having to call iCustom:
iCustom(Symbol(),60,"MB",3D,0,1)>0;
Thus far I've failed and whilst I believe it is probably a trivial thing to do for many, if you don't know, you don't know.
The iCustom code in question is the following and I'd be grateful for any assistance:
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 Blue
#property indicator_color2 Red
#property indicator_width1 5
#property indicator_width2 5
extern int 3D= 5
double AIAIAI[];
double B1B1B1[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
SetIndexBuffer( 0, AIAIAI );
SetIndexEmptyValue( 0, 0.0 );
SetIndexStyle( 0, DRAW_ARROW );
SetIndexArrow( 0, 250 );
SetIndexLabel( 0, NULL );
SetIndexBuffer( 1, B1B1B1);
SetIndexEmptyValue( 1, 0.0 );
SetIndexStyle( 1, DRAW_ARROW );
SetIndexArrow( 1, 250 );
SetIndexLabel( 1, NULL );
IndicatorDigits( 5 );
//---- name for DataWindow and indicator subwindow label
IndicatorShortName( MB(" + 3D+ ")" );
return( 0 );
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
return( 0 );
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
int counted_bars = IndicatorCounted();
if (counted_bars < 0) return (-1);
if (counted_bars > 0) counted_bars--;
int intLimit = Bars - counted_bars;
int LO, HI;
for( int NINI = intLimit; NINI >= 0; NINI-- )
{
AIAIAI[NINI] = 0.0;
B1B1B1[NINI] = 0.0;
LO = iLowest( Symbol(), Period(), MODE_LOW, 3D, NINI );
if ( LO == NINI )
{
AIAIAI[NINI] = Low[NINI];
}
HI = iHighest( Symbol(), Period(), MODE_HIGH, 3D, NINI );
if ( HI == NINI )
{
B1B1B1[NINI] = High[NINI];
}
}
return( 0 );
}
Thank you
The best way to package the indicator code with the compiled EA is to include it as a resource and continue to call it using icustom. When you do it this way, there is no need to refactor and extract indicator logic.
The syntax is as follows:
#resource "MyCustomIndicator.ex4"
double my_custom_zero_buffer(string symbol, int period, int setting, int i)
{
return iCustom(symbol, period, "::MyCustomIndicator.ex4", setting, 0, i);
}
When you compile this EA the Indicator will also be compiled and packaged together so you can use/distribute it without exposing the indicator logic
If you use the indicator as an example only, that is probably not a good indicator as it does not use buffers and overall very simple indicator. It should be quite easy to recompute the buffer value from the ea when you need it.
double iCustomValue(const int param,const int buffer,const int shift)
{
switch(buffer)
{
case 0:
if(iLowest(_Symbol,0,MODE_LOW,param,shift)==shift)
return iLow(_Symbol,0,shift);
break;
case 1:
if(iHighest(_Symbol,0,MODE_HIGH,param,shift)==shift)
return iLow(_Symbol,0,shift);
break;
}
return(0.0);
}
and use the function instead of your indicator. For more complicated indicators - keep in mind that calling indicators is slower of course but allows to test easier.
Related
My logic in my code right now is this
Step1. Scan for 100 candlesstick or more from the past
Step2. Collect and store the date of all 100 to find out the high of each candlestick
Step3. Go through all the candlestick high data and find the one that are near each other (Still dont know how i would do that)
Step4. Plot HLine
Now the first problem im having is how would i code it where i would be able to find which candlestick numbers are close to each other in order to plot the HLine.
extern int candleCount = 100;
int totalHigh;
int FinishingTotalHigh;
int totalLow;
int FinishingTotalLow;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
totalHigh = 0;
totalLow = 0;
// Initializing the variables.
double Highest = High[0];
double Lowest = Low[0];
Alert("");
Alert("");
Alert("");
Alert("");
Alert("");
// Scan the 100 candles and update the values of the highest and lowest.
for (int i = 0; i <= candleCount; i++)
{
//Alert(i+"Index Data: "+High[i]);
totalHigh = High[i] + totalHigh;
totalLow = Low[i] + totalLow;
if (High[i] > Highest) Highest = High[i];
if (Low[i] < Lowest) Lowest = Low[i];
}
FinishingTotalHigh = totalHigh/candleCount;
FinishingTotalLow = totalLow/candleCount;
// Print the result.
Alert("Highest price found is "+Highest);
Alert("Lowest price found is "+Lowest);
Alert("TotalHigh: "+FinishingTotalHigh);
Alert("TotalLow: "+FinishingTotalLow);
}
//+------------------------------------------------------------------+
I have this TEMA indicator which worked fine. I added a piece of code in order to limit the amount of bars to process but the indicator line gets messed up in the back in an abnormal way and when I limit the amount of bars to process to a small value like 500 the indicator doesn't display properly at all it just throws lines up and down.
This is the modified code which I use.
Can someone help me shed some light on this.
If I limit the bars for a simple moving average code I do not get these above mentioned problems.
I for one believe it has something to do with the IMAOnArray() part in the code.
I also attached an image to display the problem.
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 DarkBlue
#property indicator_width1 2
//---- input parameters
extern int EMA_period=14;
//code added to limit amount of bars.
extern int BarsBack=1500;
//---- buffers
double TemaBuffer[];
double Ema[];
double EmaOfEma[];
double EmaOfEmaOfEma[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
//---- indicators
IndicatorBuffers(4);
SetIndexStyle(0,DRAW_LINE);
SetIndexBuffer(0,TemaBuffer);
SetIndexBuffer(1,Ema);
SetIndexBuffer(2,EmaOfEma);
SetIndexBuffer(3,EmaOfEmaOfEma);
SetIndexDrawBegin(0, Bars - BarsBack);
IndicatorShortName("TEMA("+EMA_period+")");
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
int i,limit,limit2,limit3,counted_bars=IndicatorCounted();
//---++
//coded added to limit bars
if(Bars>BarsBack)
{
limit=BarsBack;
}
else
{
limit=Bars-counted_bars-1;
}
limit2=limit;
limit3=limit2;
for (i=limit;i>=0;i--) Ema[i]=iMA(NULL,0,EMA_period,0,MODE_EMA,PRICE_CLOSE,i);
for (i=limit2;i>=0;i--) EmaOfEma[i]=iMAOnArray(Ema,0,EMA_period,0,MODE_EMA,i);
for (i=limit3;i>=0;i--) EmaOfEmaOfEma[i]=iMAOnArray(EmaOfEma,0,EMA_period,0,MODE_EMA,i);
for (i=limit3;i>=0;i--) TemaBuffer[i]=3*Ema[i]-3*EmaOfEma[i]+EmaOfEmaOfEma[i];
//----
return(0);
}
//+------------------------------------------------------------------+
Q : Can someone help me shed some light on this?
Triple Exponential Moving Average was created by Patrick Mulloy and first published in the February 1994 issue of Technical Analysis of Stocks & Commodities magazine – Smoothing Data With Less Lag.
You shall not "limit" the depth of TEMA-triple-"self"-convolution by reducing the depth of input data-window, as it results but in damaged values processed, you rather ought say the CustomIndicator-code, how long does it take to "stabilise" the TEMA-values at the far left edge, before it's left-edge computed values start to make some sense:
SetIndexDrawBegin
Sets the bar number (from the data beginning) from which the drawing of the given indicator line must start.
void SetIndexDrawBegin(
int index, // line index
int begin // position
);
Parameters :
index [in] Line index. Must lie between 0 and 7.
begin [in] First drawing bar position number.
Returned value: None.
Note:
The indicators are drawn from left to right. The indicator array values that are to the left of the given bar will not be shown in the chart or in the DataWindow. 0 will be set as default, and all data will be drawn.
Your modified TEMA-code simply ignores all the ( Bars - BarsBack ) candles and starts green-field computing but for the BarsBack ( which produces all the triple-self-convolution artifacts to happen "near" the hot-end current bar [0] ).
Delete this part of the code and check all your IndicatorBuffer{ 0 | 1 | 2 | 3 }-lines on the far left edge, how fast they "consolidate" their values and only after that visual check, set:
SetIndexDrawBegin( { 0 | 1 | ... | 3 }, <_N_bars_To_Converge_STABLE_> );
Or may keep the computing-avoidance-code beck in-place, but need to increase the BarsBack >> <_N_bars_To_Converge_STABLE_>
Iteratively computed values' code-efficiency may get improved :
While MQL4 (as of 2020-Q1) lacks a support for vectorised-math, there is still a room for performance improvement here:
/*
for ( i = limit; i >= 0; i-- ) Ema[i] = iMA( NULL, 0, EMA_period, 0, MODE_EMA, PRICE_CLOSE, i );
for ( i = limit2; i >= 0; i-- ) EmaOfEma[i] = iMAOnArray( Ema, 0, EMA_period, 0, MODE_EMA, i );
for ( i = limit3; i >= 0; i-- ) EmaOfEmaOfEma[i] = iMAOnArray( EmaOfEma, 0, EMA_period, 0, MODE_EMA, i );
for ( i = limit3; i >= 0; i-- ) TemaBuffer[i] = EmaOfEmaOfEma[i]
+ 3*Ema[i]
- 3*EmaOfEma[i];
*/
////////////////////////////////////////////////////////////////////
// 25% MORE EFFICIENT PROCESSING:
// PROGRESSIVE BUILDUP, AVOIDS DOUBLE limit3-DEEP RE-ITERATIONS:
////////////////////////////////////////////////////////////////////
for ( i = limit; i >= 0; i-- ) { Ema[i] = iMA( NULL, 0, EMA_period, 0, MODE_EMA, PRICE_CLOSE, i ); TemaBuffer[i] = Ema[i]; }
for ( i = limit2; i >= 0; i-- ) { EmaOfEma[i] = iMAOnArray( Ema, 0, EMA_period, 0, MODE_EMA, i ); TemaBuffer[i] -= EmaOfEma[i]; TemaBuffer[i] *= 3; }
for ( i = limit3; i >= 0; i-- ) { EmaOfEmaOfEma[i] = iMAOnArray( EmaOfEma, 0, EMA_period, 0, MODE_EMA, i ); TemaBuffer[i] += EmaOfEmaOfEma[i]; }
Last, but not least, even more processing efficient TEMA computing-strategies exist here around for nanoseconds latency shaving further off :o)
For a learning purpose, I am trying to code a simple MA indicator that changes color when price crosses. Though there are no errors, it draws nothing. Could you review the attached code to show me my mistake?
#property indicator_chart_window
#property indicator_buffers 2
extern int maperiod = 20;
extern int maprice = PRICE_CLOSE;
extern int mamethod = MODE_SMA;
extern color colorup = Green;
extern color colordn = Red;
double mamain[];
double bufferup[];
double bufferdn[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init(){
//--- indicator buffers mapping
SetIndexBuffer( 0, bufferup );
SetIndexStyle( 0, DRAW_LINE, 0, 2, colorup );
SetIndexBuffer( 1, bufferdn );
SetIndexStyle( 1, DRAW_LINE, 0, 2, colordn );
//---
return( 0 );
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start(){
//---
int counted_bars = IndicatorCounted();
if ( counted_bars < 0 ) return( -1 );
if ( counted_bars > 0 ) counted_bars--;
int limit = Bars - counted_bars;
for ( int i = limit; i >= 0 ; i-- )
{ mamain[i] = iMA( NULL, 0, maperiod, 0, 0, 0, i );
if ( mamain[i] >= iClose( NULL, 0, i ) ) bufferup[i] = mamain[i];
if ( mamain[i] <= iClose( NULL, 0, i ) ) bufferdn[i] = mamain[i];
}
//--- return value of prev_calculated for next call
return( 0 );
}
//+------------------------------------------------------------------+
"Old"-MQL4 may work for some time, but still, get used to new features:
extern ENUM_APPLIED_PRICE MAprice = PRICE_CLOSE; // AVOIDS incompatible values
extern ENUM_MA_METHOD MAmethod = MODE_SMA; // AVOIDS incompatible values
#define MAshift 0 // ADDS code == intent match-robustness
extern int MAperiod = 20;
extern color colorUP = clrGreen;
extern color colorDN = clrRed;
double bufferUP[];
double bufferDN[];
int init(){
ArrayInitialize bufferUP, EMPTY_VALUE );
SetIndexBuffer( 0, bufferUP );
SetIndexStyle( 0, DRAW_LINE, EMPTY, 2, colorUP );
SetIndexLabel( 0, "MA_ABOVE_Close" );
ArrayInitialize bufferDN, EMPTY_VALUE );
SetIndexBuffer( 1, bufferDN );
SetIndexStyle( 1, DRAW_LINE, EMPTY, 2, colorDN );
SetIndexLabel( 1, "MA_UNDER_Close" );
return( 0 );
}
int start(){
int counted_bars = IndicatorCounted();
if ( counted_bars < 0 ) return( -1 );
if ( counted_bars > 0 ) counted_bars--;
for ( int i = Bars - counted_bars; i >= 0 ; i-- ){
double C = iClose( _Symbol, PERIOD_CURRENT, i ),
A = iMA( _Symbol, PERIOD_CURRENT,
MAperiod,
MAshift,
MAmethod,
MAprice,
i
);
if ( A >= C ) bufferUP[i] = A;
if ( A <= C ) bufferDN[i] = A;
}
return( 0 );
}
New-MQL4.56789 uses another call-signature if #property strict:
int OnCalculate( const int rates_total,
const int prev_calculated,
const datetime &time_______ARR[],
const double &open_______ARR[],
const double &high_______ARR[],
const double &low________ARR[],
const double &close______ARR[],
const long &tick_volumeARR[],
const long &volume_____ARR[],
const int &spread_____ARR[]
){
//--- the main loop of calculations
for( int i = prev_calculated - 1;
( i < rates_total
&& !IsStopped() ); // AVOID SHARED (!) solo-THREAD BLOCKING
i++
){
// -----------------------------------------------------------------
double A = iMA( _Symbol, PERIOD_CURRENT,
MAperiod,
MAshift,
MAmethod,
MAprice,
i
);
if ( A >= close______ARR[i] ) bufferUP[i] = A;
if ( A <= close______ARR[i] ) bufferDN[i] = A;
// -----------------------------------------------------------------
}
return( rates_total );
}
your buffer mamain[] is not initialized.
int init(){
IndicatorBuffers(3);
SetIndexBuffer(2,mamain);
}
rates_total and prev_calculated seems preferred but of course you can use IndicatorCounted() but keep in mind the corner situation with the first bar: when you first attach the indicator to the chart, your counted_bars = 0 and limit = Bars, but mamain[] and other indicator buffers have Bars elements only, from 0 to Bars-1. so better to use
int limit = Bars - counted_bars - 1;
About resolving issues - in addition to asking here you can always try to attach your indicator to a chart and see it there's no error (terminal window - Experts folder), that will make delevopment faster
I am trying to make an indicator that shows when x candles of the same color appear on the chart. But I am getting an array out of range error.
There is a up and down array buffer (an arrow pointing up or down)
minCandles is an extern integer that determines after how many bars to point the arrow.
the bear part works but from right to left.
I think the problem may be in down[i] = Low[i] but I don't know why.
Here is the code:
//+------------------------------------------------------------------+
//| SlayEm.mq4 |
//| Copyright 2016, Sebastian Bonilla. |
//| https://www.sebastianbonilla.me |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, Sebastian Bonilla."
#property link "https://www.sebastianbonilla.me"
#property description "show X amount of candles of the same color."
#property version "1.00"
#property strict
#property indicator_chart_window
//--- input parameters
extern int minCandles = 4;
double up[];
double down[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
SetIndexBuffer(0,up); //assign up to the first buffer
SetIndexStyle(0,DRAW_ARROW);
SetIndexArrow(0,233);
SetIndexLabel(0, "Up Arrow");
//stuff for 1
SetIndexBuffer(1,down); //assign down to the second buffer
SetIndexStyle(1,DRAW_ARROW);
SetIndexArrow(1,234);
SetIndexLabel(1, "Down Arrow");
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{//------------------------------------------
int limit = MathMax(rates_total-prev_calculated,2);
int i;
int bull_count = 0;
int bear_count = 0;
for (i = 1; i < limit; i++){
//--bears-----------------------------------------------------------------------------------
if(Open[i] >= Open[i-1]){
bear_count++;
if (bear_count > minCandles) up[i] = High[i];
}
else bear_count = 0; // this by itself works but from right to left
// --- bulls ----------------------------------------
if(Open[i] < Open[i-1]){
bull_count++;
if (bull_count > minCandles) down[i] = Low[i];
}
else bull_count = 0; //this part creates the array out of range error*/
}
Comment((string)bear_count+ " --- ", (string)bull_count +" --- ", (string)i);
//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+
There are a few strange things behind the writing a fast and efficient [ Custom Indicator ] MQL4-code.
First, the real-time headache coming from a design decision to accumulate all the computational efforts from all the present [ Custom Indicator ] into a single thread.
While this is hidden, it increases the pressure to minimise all execution latencies at a cost of the colculus being operated in segmented mini-batches, from the deepest history ( the bars farthest back to the left ) proceeding iteratively forwards to the right, towards the current Bar.
One might get confused from the concept of reversed-numbering of the Bars, starting from [0]-for the most recent Bar ( the live Bar ), counting up, while going deeper and deeper towards the history on the far left.
If it were not enough, there are some additional prohibited things inside a [ Custom Indicator ], but as your web-page shows that you provide [ Custom Indicator ] programming on a commercial basis, it is worthless to repeat 'em here again.
Production-grade code for [Custom Indicator] ought have at least:
protective fuses
minimised main duty-cycle overheads
zero raw-Comment()-s to avoid damages to GUI/MMI
#property strict
//--- input parameters
extern int minCandles = 4;
//--- input PROTECTIVE FUSES:
int minCandlesFUSED = MathMax( 2, minCandles ); // assign no less than 2 irrespective of the extern
double up[];
double down[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit() {
// indicator buffers mapping
SetIndexBuffer( 0, up ); // assign up[] to the first buffer
SetIndexStyle( 0, DRAW_ARROW );
SetIndexArrow( 0, 233 );
SetIndexLabel( 0, "Up Arrow" );
// stuff for 1
SetIndexBuffer( 1, down ); // assign down[] to the second buffer
SetIndexStyle( 1, DRAW_ARROW );
SetIndexArrow( 1, 234 );
SetIndexLabel( 1, "Down Arrow" );
// RET
return( INIT_SUCCEEDED );
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate( const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[]
) {
// ------------------------------------------
int limit = rates_total
- prev_calculated
+ minCandlesFUSED;
if ( Bars + limit < minCandlesFUSED + 1 ) return( 0 ); // --> JIT/RET( 0 )
// ^--------------------^--- MEANING-FULL value, ref prev_calculated mechanisation
// makes no sense to start indicator w/o at least minCandlesFUSED + 1 Bars ready
int bull_count = 0;
int bear_count = 0;
for ( int i = limit + 1; // iterator .SET to start [limit + 1] Bars back in time (towards left), moving forwards -> [0]
i > 0; // iterator .PRE-CONDITION to keep looping while i > [0] points to already exist. Bars->[1], leaving [0] out
i-- // iterator .DEC on loop-end, before re-testing next loop .PRE-CONDITION
){
// --------------------------------------------------------------BEARS
if ( Open[i] >= Open[i-1] ){
bear_count++;
if ( bear_count > minCandlesFUSED ) up[i] = High[i]; // ref. above the
}
else bear_count = 0; // this by itself works
// --------------------------------------------------------------BULLS
if ( Open[i] < Open[i-1] ){
bull_count++;
if ( bull_count > minCandlesFUSED ) down[i] = Low[i];
}
else bull_count = 0; // this part creates the array out of range error*/
}
Comment( (string)bear_count // rather use StringFormat( "TEMPLATE: %d UP --- %d DN --- ", bear_count,
+ " --- ", // bull_count
(string)bull_count // )
+ " --- "
);
return( rates_total ); // return( rates_total ) value becomes -> prev_calculated for the next call
}
//+------------------------------------------------------------------+
I have this code working without error. Basically, this code is to show value of Moving Averages on five previous bars per 5 minutes. MA's current value is omitted.
int TrendMinDurationBar = 5,
SlowPeriod = 14,
FastPeriod = 7;
void OnTick()
{
if ( NewBar( PERIOD_M5 ) == true ) MA( PERIOD_M5 );
}
void MA( int TF )
{
double Slow[], Fast[];
ArrayResize( Slow, TrendMinDurationBar + 1 );
ArrayResize( Fast, TrendMinDurationBar + 1 );
for ( int i = 1; i <= TrendMinDurationBar; i++ )
{ Slow[i] = NormalizeDouble( iMA( Symbol(), TF, SlowPeriod, 0, MODE_EMA, PRICE_OPEN, i ), Digits );
Fast[i] = NormalizeDouble( iMA( Symbol(), TF, FastPeriod, 0, MODE_EMA, PRICE_OPEN, i ), Digits );
Alert( "DataSlow" + ( string )i + ": " + DoubleToStr( Slow[i], Digits ) );
}
}
bool NewBar( int TF )
{
static datetime lastbar = 0;
datetime curbar = iTime( Symbol(), TF, 0 );
if ( lastbar != curbar )
{ lastbar = curbar; return( true );
}
else return( false );
}
When #property strict is included, the code is only working once after compiled. After new bar on M5 chart exist, it doesn't make any iteration.
What's the solution if I insist to use #property strict?
Works perfectly well with #property strict as an EA in MT4 Build 950.
Are you sure you are running it as EA and not as Script or Indicator?
Welcome to another New-MQL4.56789 Catch-22
My candidate from Help > MQL4 Reference > Updated MQL4
is
this one ( column [New MQL4 with #property strict] )
Functions of any type should return a value
and
one more to be reviewed,
code simply loses the logic even for static double alternative it would be extremely inefficient under these circumstances:
Local arrays are released when exiting {} block