How can I get current milliseconds from MQL4 using an Expert Advisor.
i.e.: in Java we can get current milliseconds using system.currenttimemillis()
This MT4 "Get millisecond" problem has been around for ages. This is a hack I created to solve this problem.
//+------------------------------------------------------------------+
//| timeInMs.mq4 |
//| Copyright 2017, Joseph Lee |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, Joseph Lee"
#property link "https://www.facebook.com/joseph.fhlee"
#property version "1.00"
#property strict
int prevSecondTime = 0;
uint prevSecondTick = 0;
int OnInit() {
// Create an Event that triggers every 1 millisecond.
// **NOTE: GetTickCount() is accurate to 16ms only, so
// in practice, no need to trigger every 1ms.
EventSetMillisecondTimer(1);
return(INIT_SUCCEEDED);
}
void OnTick() {
Comment( "Now: " + TimeLocal() + " :: " + getCurrentMs() + " ms. +- 16ms accuracy.");
}
int getCurrentMs() {
return(GetTickCount() - prevSecondTick);
}
// This is an EVENT function that will be called every
// x milliseconds [see EventSetMillisecondTimer() in OnInit()]
void OnTimer() {
// If a new "second" occurs, record GetTickCount()
if(TimeLocal() > prevSecondTime) {
prevSecondTick = GetTickCount();
prevSecondTime = TimeLocal();
}
}
Can have relative [ms] or even [us]:
Be careful as both are relative, but one with respect to the system start, the other with respect to the MQL4 code-execution unit start.
The GetTickCount() function returns the number of milliseconds that elapsed since the system start.
uint GetTickCount();
Counter is limited by the restrictions of the system timer. Time is stored as an unsigned integer, so it's overfilled every 49.7 days if a computer works uninterruptedly.
The GetMicrosecondCount() function returns the number of microseconds that have elapsed since the start of MQL program.
ulong GetMicrosecondCount();
Can have absolute [ms] or even [us], with const(!) ABSOLUTE ERROR,
that will exhibit neither any drift, nor jitter in exact measuring of time.
Isn't this great for FOREX domain, where milliseconds are "full of events" and microseconds ( nanoseconds in recent professional-grade designs ) matter ?!
// -----------------------------------------------------------------
ulong system_currenttimemillis(){
return( OnStart_GLOB_MILLISECONDS // ABS [ms] SYNC-ed OnStart() WITH [s]-EDGE-ALIGNMENT
+ ( GetMicrosecondCount() // + DELTA ------------------
- OnStart_BASE_MICROSECONDS // since SYNC-ing OnStart()
) / 1000 // =================== // DELTA [ms] =============
);
}
// -----------------------------------------------------------------
static ulong OnStart_GLOB_MICROSECONDS;
static ulong OnStart_GLOB_MILLISECONDS;
static ulong OnStart_EoDY_MICROSECONDS;
static datetime OnStart_EoDY_DATETIME;
static datetime OnStart_BASE_DATETIME;
static uint OnStart_BASE_MILLISECONDS;
static ulong OnStart_BASE_MICROSECONDS;
// -----------------------------------------------------------------
void OnStart(){ /* { SCRIPT | EXPERT ADVISOR | CUSTOM INDICATOR } CALL
THIS */
OnStart_BASE_DATETIME = TimeLocal(); // .SET int == the number of seconds elapsed since January 01, 1970.
while( OnStart_BASE_DATETIME == TimeLocal() ){ // ---- // EDGE-ALIGNMENT -------------------------------------------------------
OnStart_BASE_MICROSECONDS = GetMicrosecondCount(); // .SET ulong, since MQL4 program launch
OnStart_BASE_MILLISECONDS = GetTickCount(); // .SET uint, since system start
} // ==[ MAX 1 SECOND ]=============================== NOW // EDGE-ALIGNED TO [s] ==================================================
OnStart_BASE_DATETIME = TimeLocal(); // .SET date and time as the number of seconds elapsed since January 01, 1970.
OnStart_GLOB_MICROSECONDS = ( (ulong) OnStart_BASE_DATETIME ) * 1000000;
OnStart_GLOB_MILLISECONDS = ( (ulong) OnStart_BASE_DATETIME ) * 1000;
OnStart_EoDY_DATETIME = OnStart_BASE_DATETIME
- ( OnStart_BASE_DATETIME % 86400 );
OnStart_EoDY_MICROSECONDS = ( TimeSecond( OnStart_BASE_DATETIME )
+ ( TimeMinute( OnStart_BASE_DATETIME )
+ TimeHour( OnStart_BASE_DATETIME ) * 60 ) * 60 ) * 1000000;
}
// -----------------------------------------------------------------
int OnInit() {
OnStart(); /* HACK 4 { EXPERT ADVISOR | CUSTOM INDICATOR } CALL
... THAT */
..
return( INIT_SUCCEEDED );
}
// -----------------------------------------------------------------
ulong Get_a_Microsecond_of_a_Day(){ // THIS HAS A !!_CONSTANT_!! ONLY ABSOLUTE SYSTEMATIC TIMING ERROR
return( ( OnStart_EoDY_MICROSECONDS // EDGE-SYNC OnStart_EoDY + DELTA-SINCE-OnStart-SYNC-ed:
+ ( GetMicrosecondCount() // == NOW ( 8B ulong ) ROLL-OVER ~ 213M504 DAYS AFTER THE PROGRAM START, WAY LONGER, THAN WE WILL LIVE UNDER THE SUN
- OnStart_BASE_MICROSECONDS // // - OnStart_BASE_MICROSECONDS
)
) // ================== // SECONDS-EDGE-SYNC-ed DISTANCE FROM EoDY-EDGE
% 86400000000 // MODULO DAY-LENGTH ROLL-OVER
); // ALL DST-MOVs TAKE PLACE OVER WEEKENDS, SO NOT DURING TRADING-HOURS, SHOULD BE JUST-ENOUGH GOOD SOLUTION :o)
}
// -----------------------------------------------------------------
uint Get_a_Millisecond_of_a_Day(){ // IMMUNE TO A uint ROLL-OVER ~ 49.7 DAYS
return( Get_a_Microsecond_of_a_Day()
/ 1000
);
}
This solution runs in all { Script | Expert Advisor | Custom Indicator }
something like this:
ulong time = GetTickCount();
// function();
time = GetTickCount()-time;
dt1 = TimeLocal()+2;
do
{
dt2 = TimeLocal();
}
while(TimeSecons(dt2) < TimeSecons(dt1));
after finish you may count time from 0.000
Just cast values to ulong and make sure to multiply TimeGMT() with 1000
for print result cast to string :
ulong time = (ulong) TimeGMT()*1000 - (ulong) GetTickCount() ;
Print("milliseconds: ", (string)time);
Another way seems to be using the WinAPI (kernel32.dll). This seems to be more integrated with MQL5 by using #include <WinAPI/windef.mqh> but can be used with MQL4 too by defining the required structs.
The following snippet shows how to get it in MQL4 –in MQL5 you don't need to define the structs as they can be included:
// MQL5 seems to have Include/WinAPI/windef.mqh - constants, structures and enumerations
#ifdef __MQL4__
//+------------------------------------------------------------------+
//| MQL4 equivalent of Windows _FILETIME struct: GetSystemTimeAsFileTime().
//| #see: https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
//+------------------------------------------------------------------+
struct FILETIME {
uint dwLowDateTime;
uint dwHighDateTime;
};
//+------------------------------------------------------------------+
//| MQL4 equivalent of Windows GetSystemTime()/GetLocalTime()/... struct.
//| Credits: https://www.mql5.com/en/forum/146837/page3#comment_3702187
//+------------------------------------------------------------------+
struct SYSTEMTIME {
ushort wYear; // 2014 etc
ushort wMonth; // 1 - 12
ushort wDayOfWeek; // 0 - 6 with 0 = Sunday
ushort wDay; // 1 - 31
ushort wHour; // 0 - 23
ushort wMinute; // 0 - 59
ushort wSecond; // 0 - 59
ushort wMilliseconds; // 0 - 999
string toString() {
return StringFormat("%hu-%02hu-%02hu %02hu:%02hu:%02hu.%03hu", wYear, wMonth, wDay, wHour, wMinute, wSecond, wMilliseconds);
}
};
#endif
#import "kernel32.dll"
// Millisecond (ms) precision, but limited by Windows timer configuration?? (15-16 ms by default)
void GetSystemTime(SYSTEMTIME &time); // (struct version)
void GetLocalTime(SYSTEMTIME &time); // (struct version)
// Microsecond (us) precision, limited by Windows timer configuration?? (15-16 ms by default)
void GetSystemTimeAsFileTime(FILETIME& t); // (ulong version) Returns the system time in 100-nsec units
#import
Then you can define user-friendly functions to get the time around the above ones, e.g.
//+------------------------------------------------------------------+
//| Get the system time (UTC) in milliseconds.
//| Credits: https://www.mql5.com/en/forum/146837/page4#comment_13522420
//+------------------------------------------------------------------+
ulong systemTimeMillis(){
FILETIME t; // time measured in 100-nano second units
GetSystemTimeAsFileTime(t);
ulong time = (long)t.dwHighDateTime << 32 | t.dwLowDateTime;
ulong diffTo1970 = 11644473600000; // FILETIME starts at January 1, 1601 (UTC)
return (ulong)(time * 0.0001 - diffTo1970); // 100-ns to ms (divide 10_000)
}
ulong localTimeMillis() {
return systemTimeMillis() - TimeGMTOffset() * 1000;
}
More references
https://www.mql5.com/en/forum/146837/page3#comment_3702187
Windows Timer Resolution: Megawatts Wasted
Timers, Timer Resolution, and Development of Efficient Code
Related
Hello Im wondering if there is a way I can somehow view ATR by hour, so when it calculates results in has 24 different values from 00:00 to 23:00. I would like the average to be of the ranges for that hour only in the lookback period. (for example hour 02:00 compares it range to the other 02:00 ranges in the look back period)
Original ATR Code
//| ATR.mq4 |
//| Copyright 2005-2014, MetaQuotes Software Corp. |
//| http://www.mql4.com |
//+------------------------------------------------------------------+
#property copyright "2005-2014, MetaQuotes Software Corp."
#property link "http://www.mql4.com"
#property description "Average True Range"
#property strict
//--- indicator settings
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1 DodgerBlue
//--- input parameter
input int InpAtrPeriod=14; // ATR Period
//--- buffers
double ExtATRBuffer[];
double ExtTRBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit(void)
{
string short_name;
//--- 1 additional buffer used for counting.
IndicatorBuffers(2);
IndicatorDigits(Digits);
//--- indicator line
SetIndexStyle(0,DRAW_LINE);
SetIndexBuffer(0,ExtATRBuffer);
SetIndexBuffer(1,ExtTRBuffer);
//--- name for DataWindow and indicator subwindow label
short_name="ATR("+IntegerToString(InpAtrPeriod)+")";
IndicatorShortName(short_name);
SetIndexLabel(0,short_name);
//--- check for input parameter
if(InpAtrPeriod<=0)
{
Print("Wrong input parameter ATR Period=",InpAtrPeriod);
return(INIT_FAILED);
}
//---
SetIndexDrawBegin(0,InpAtrPeriod);
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Average True Range |
//+------------------------------------------------------------------+
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 i,limit;
//--- check for bars count and input parameter
if(rates_total<=InpAtrPeriod || InpAtrPeriod<=0)
return(0);
//--- counting from 0 to rates_total
ArraySetAsSeries(ExtATRBuffer,false);
ArraySetAsSeries(ExtTRBuffer,false);
ArraySetAsSeries(open,false);
ArraySetAsSeries(high,false);
ArraySetAsSeries(low,false);
ArraySetAsSeries(close,false);
//--- preliminary calculations
if(prev_calculated==0)
{
ExtTRBuffer[0]=0.0;
ExtATRBuffer[0]=0.0;
//--- filling out the array of True Range values for each period
for(i=1; i<rates_total; i++)
ExtTRBuffer[i]=MathMax(high[i],close[i-1])-MathMin(low[i],close[i-1]);
//--- first AtrPeriod values of the indicator are not calculated
double firstValue=0.0;
for(i=1; i<=InpAtrPeriod; i++)
{
ExtATRBuffer[i]=0.0;
firstValue+=ExtTRBuffer[i];
}
//--- calculating the first value of the indicator
firstValue/=InpAtrPeriod;
ExtATRBuffer[InpAtrPeriod]=firstValue;
limit=InpAtrPeriod+1;
}
else
limit=prev_calculated-1;
//--- the main loop of calculations
for(i=limit; i<rates_total; i++)
{
ExtTRBuffer[i]=MathMax(high[i],close[i-1])-MathMin(low[i],close[i-1]);
ExtATRBuffer[i]=ExtATRBuffer[i-1]+(ExtTRBuffer[i]-ExtTRBuffer[i-InpAtrPeriod])/InpAtrPeriod;
}
//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+````
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);
}
//+------------------------------------------------------------------+
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.
I am new to MT4, know little basic programming for MQL4. I am trading in UTC+5:30 in Indian Stocks. I just want a small piece of code to get today's First candles HIGH and LOW in current TimeFrame. Our trading starts at 9:15 AM IST and ends at 3:30 PM IST.
e.g. if I select PERIOD_M15 (15 min chart) then I need to have day's first candle (i.e. from 9:15AM to 9:30AM) HIGH and LOW.
thanks in advance.
welcome to SOF!
you need input parameters (time of the day start):
input int InpTimeStartHour=9;
input int InpTimeStartMinute=15;
this can be as a one string but for simplicity such fields
bool getHighLowFistCandle(double &high,double &low){
//check if first candle (zero-current) is after 9:15
datetime lastCandle=iTime(Symbol(),0,1);
if(TimeHour(lastCandle)<InpTimeStartHour ||
(TimeHour(lastCandle)==InpTimeStartHour && TimeMinute(lastCandle)<InpTimeStartMinute){
return(false);
}
//looking for that time candle starting from day start
datetime todayStart=iTime(Symbol(),PERIOD_D1,0);
int shift=iBarShift(Symbol(),0,todayStart);
for(int i=shift;i>0;i--){
datetime iCandleTime=iTime(Symbol(),0,i);
if(TimeHour(iCandleTime)==InpTimeStartHour &&
TimeMinute(iCandleTime)==InpTimeStartMinute){
high=iHigh(Symbol(),0,i);
low=iLow(Symbol(),0,i);
return(true);
}
}
return(false);
}
Below is my indicator code,
//+------------------------------------------------------------------+
//| ProjectName |
//| Copyright 2018, CompanyName |
//| http://www.companyname.net |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020,ANKUR SONI."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
#property indicator_buffers 1
#property indicator_chart_window
#property indicator_width1 5
#property indicator_color1 clrYellow
double engulfing[];
input int InpTimeStartHour=8;
input int InpTimeStartMinute=45;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int OnInit()
{
SetIndexBuffer(0, engulfing);
SetIndexStyle(0, DRAW_ARROW);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
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[])
{
for(int i = (Bars - 2) ; i > 0 ; i--)
{
if(TimeHour(time[i]) == InpTimeStartHour && TimeMinute(time[i]) == InpTimeStartMinute)
{
double currentHigh = High[i];
double currentLow = Low[i];
double nextHigh = High[i-1];
double nextLow = Low[i-1];
if(nextHigh > currentHigh && nextLow < currentLow)
{
engulfing[i-1] = High[i-1] + 15;
}
}
}
return(rates_total);
}
//+------------------------------------------------------------------+
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
}
//+------------------------------------------------------------------+