How to count how many bars back the moving average crossed last? - mql4

I am writing an MQL4 Custom Indicator that would tell how many bars ago a particular set of moving averages crossed.
To be specific, I want the output to show me that
"The 20 period MA( .. PRICE_OPEN ) is below MA( .. PRICE_CLOSE ) for the past 10 bars".
in a form of an int number.
double ma1 = iMA( Symbol(), 10080, 20, 0, 0, PRICE_OPEN, 0 );
double ma2 = iMA( Symbol(), 10080, 20, 0, 0, PRICE_CLOSE, 0 );
I want to find out that ma1 has been above or below ma2 for how many bars since the current bar.

TLDR;
MQL4 Custom Indicator design is a bit schizophrenic task with 2 parts
Once decided to design a Custom Indicator, one has to pay attention to both sides of the coin.
MQL4 code has a non-trivial signature for a caller-side( normally an
Expert Advisor or a Script type of MQL4 code )and
Custom Indicator, on it's own, operates in a special mode, where it calculates & store it's values into one or more arrays called IndexBuffer-s.
Phase I.: design Caller-side interface ( what all do we need to set / receive ? )
Phase II.: design Custom Indicator implementation side
This way, the given indicator shall
set just one parameter: a period ... 20
receive just one int a value of days { +:above | 0: xoss | -: under }
Phase I. : Design Caller-side interface
Given the above parametrisation and the MQL4 concept of Custom Indicator construction, the following universal template ( recommended to be routinely maintained as a commented section right in CustomIndicator-file ) reflects details needed for the Caller-side interface ( which one benefits from by just a copy-paste mechanics, while the implementation-integrity responsibility is born by the CustomIndicator maintainer ):
// CALL-er SIDE INTERFACE |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//
// #define sIndicatorPathNAME "#AliceInTheWonderlands_msMOD_0.00"
//
// //_____________________________________INPUT(s)
// // iMA_PERIOD:
// extern int iMA_PERIOD = 20;
//
// //_____________________________________OUTPUT(s):
// #define iOutputDoubleUpOrDnBUFFER 0
//
// //_____________________________________CALL-SIGNATURE:
//
// double iCustom( _Symbol, // string symbol, // symbol: Symbol name on the data of which the indicator will be calculated. NULL means the current symbol.
// PERIOD_W1, // int timeframe, // timeframe
// sIndicatorPathNAME, // string name, // path/name of the custom indicator compiled program: Custom indicator compiled program name, relative to the root indicators directory (MQL4/Indicators/). If the indicator is located in subdirectory, for example, in MQL4/Indicators/Examples, its name must be specified as "Examples\\indicator_name" (double backslash "\\"must be specified as separator instead of a single one).
// iMA_PERIOD, // ...[1] ..., // custom indicator [1]-st input parameter
// <<N/A>>, // ...[2+] // custom indicator further input parameters (if necessary)
// iOutputDoubleUpOrDnBUFFER, // int mode, // line index: Line index. Can be from 0 to 7 and must correspond with the index, specified in call of the SetIndexBuffer() function.
// i // int bar_shift // shift
// );
// ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Typical Expert Advisor call looks like this:
int anIndicatorVALUE = iCustom( _Symbol,
PERIOD_W1,
sIndicatorPathNAME,
iMA_PERIOD,
iOutputDoubleUpOrDnBUFFER,
aCurrentBarPTR
);
if ( 0 > anIndicatorVALUE ) // on "line" under for <anIndicatorVALUE> [PERIOD]-s
{ ...
}
Phase II. : Design Custom Indicator implementation side
Preset an overall capacity
#property indicator_buffers 1 // compile time directive
Allocate memory for IndexBuffer(s) needed
IndicatorBuffers( 1 ); // upper limit of 512 is "far" enough
Declare IndexBuffer
double UpOrDnBUFFER[]; // mandatory to be a double
Associate IndexBuffer with an index
SetIndexBuffer( 0, UpOrDnBUFFER ); // index 0: UpOrDnBUFFER[]
ArraySetAsSeries( UpOrDnBUFFER, True ); // reverse AFTER association
The core logic of any Custom Indicator is inside an OnCalculate() function, where you
- implement desired calculusand- store resulting values into respective cells of the UpOrDnBUFFER[];
Writing a fully fledged code upon request is not the key objective of StackOverflow, but let me sketch a few notes on this, as Custom Indicator implementation side requires a bit practice:
because Custom Indicator OnCalculate() operates "progressively", so do design your calculation strategy & keep in mind the state-less-ness between "blocks" of forward-progressive blocks of calculations.
as given, crosses are tri-state system, so watch issues on cases, where decisions are made on a "live" bar, where the state { above | cross | under } may change many times during the bar-evolution.

Related

16 bit logic/computer simulation in Swift

I’m trying to make a basic simulation of a 16 bit computer with Swift. The computer will feature
An ALU
2 registers
That’s all. I have enough knowledge to create these parts visually and understand how they work, but it has become increasingly difficult to make larger components with more inputs while using my current approach.
My current approach has been to wrap each component in a struct. This worked early on, but is becoming increasingly difficult to manage multiple inputs while staying true to the principles of computer science.
The primary issue is that the components aren’t updating with the clock signal. I have the output of the component updating when get is called on the output variable, c. This, however, neglects the idea of a clock signal and will likely cause further problems later on.
It’s also difficult to make getters and setters for each variable without getting errors about mutability. Although I have worked through these errors, they are annoying and slow down the development process.
The last big issue is updating the output. The output doesn’t update when the inputs change; it updates when told to do so. This isn’t accurate to the qualities of real computers and is a fundamental error.
This is an example. It is the ALU I mentioned earlier. It takes two 16 bit inputs and outputs 16 bits. It has two unary ALUs, which can make a 16 bit number zero, negate it, or both. Lastly, it either adds or does a bit wise and comparison based on the f flag and inverts the output if the no flag is selected.
struct ALU {
//Operations are done in the order listed. For example, if zx and nx are 1, it first makes input 1 zero and then inverts it.
var x : [Int] //Input 1
var y : [Int] //Input 2
var zx : Int //Make input 1 zero
var zy : Int //Make input 2 zero
var nx : Int //Invert input 1
var ny : Int //Invert input 2
var f : Int //If 0, do a bitwise AND operation. If 1, add the inputs
var no : Int //Invert the output
public var c : [Int] { //Output
get {
//Numbers first go through unary ALUs. These can negate the input (and output the value), return 0, or return the inverse of 0. They then undergo the operation specified by f, either addition or a bitwise and operation, and are negated if n is 1.
var ux = UnaryALU(z: zx, n: nx, x: x).c //Unary ALU. See comments for more
var uy = UnaryALU(z: zy, n: ny, x: y).c
var fd = select16(s: f, d1: Add16(a: ux, b: uy).c, d0: and16(a: ux, b: uy).c).c //Adds a 16 bit number or does a bitwise and operation. For more on select16, see the line below.
var out = select16(s: no, d1: not16(a: fd).c, d0: fd).c //Selects a number. If s is 1, it returns d1. If s is 0, it returns d0. d0 is the value returned by fd, while d1 is the inverse.
return out
}
}
public init(x:[Int],y:[Int],zx:Int,zy:Int,nx:Int,ny:Int,f:Int,no:Int) {
self.x = x
self.y = y
self.zx = zx
self.zy = zy
self.nx = nx
self.ny = ny
self.f = f
self.no = no
}
}
I use c for the output variable, store values with multiple bits in Int arrays, and store single bits in Int values.
I’m doing this on Swift Playgrounds 3.0 with Swift 5.0 on a 6th generation iPad. I’m storing each component or set of components in a separate file in a module, which is why some variables and all structs are marked public. I would greatly appreciate any help. Thanks in advance.
So, I’ve completely redone my approach and have found a way to bypass the issues I was facing. What I’ve done is make what I call “tracker variables” for each input. When get is called for each variable, it returns that value of the tracker assigned to it. When set is called it calls an update() function that updates the output of the circuit. It also updates the value of the tracker. This essentially creates a ‘copy’ of each variable. I did this to prevent any infinite loops.
Trackers are unfortunately necessary here. I’ll demonstrate why
var variable : Type {
get {
return variable //Calls the getter again, resulting in an infinite loop
}
set {
//Do something
}
}
In order to make a setter, Swift requires a getter to be made as well. In this example, calling variable simply calls get again, resulting in a never-ending cascade of calls to get. Tracker variables are a workaround that use minimal extra code.
Using an update method makes sure the output responds to a change in any input. This also works with a clock signal, due to the architecture of the components themselves. Although it appears to act as the clock, it does not.
For example, in data flip-flops, the clock signal is passed into gates. All a clock signal does is deactivate a component when the signal is off. So, I can implement that within update() while remaining faithful to reality.
Here’s an example of a half adder. Note that the tracker variables I mentioned are marked by an underscore in front of their name. It has two inputs, x and y, which are 1 bit each. It also has two outputs, high and low, also known as carry and sum. The outputs are also one bit.
struct halfAdder {
private var _x : Bool //Tracker for x
public var x: Bool { //Input 1
get {
return _x //Return the tracker’s value
}
set {
_x = x //Set the tracker to x
update() //Update the output
}
}
private var _y : Bool //Tracker for y
public var y: Bool { //Input 2
get {
return _y
}
set {
_y = y
update()
}
}
public var high : Bool //High output, or ‘carry’
public var low : Bool //Low output, or ‘sum’
internal mutating func update(){ //Updates the output
high = x && y //AND gate, sets the high output
low = (x || y) && !(x && y) //XOR gate, sets the low output
}
public init(x:Bool, y:Bool){ //Initializer
self.high = false //This will change when the variables are set, ensuring a correct output.
self.low = false //See above
self._x = x //Setting trackers and variables
self._y = y
self.x = x
self.y = y
}
}
This is a very clean way, save for the trackers, do accomplish this task. It can trivially be expanded to fit any number of bits by using arrays of Bool instead of a single value. It respects the clock signal, updates the output when the inputs change, and is very similar to real computers.

Can't calculate the right Volume RSI in MQL4 with a functioning Pine-Script Example

I want to "translate" a Pine-Script to MQL4 but I get the wrong output in MQL4 compared to the Pine-Script in Trading-view.
I wrote the Indicator in Pine-Script since it seems fairly easy to do so.
After I got the result that I was looking for I shortened the Pine-Script.
Here the working Pine-Script:
// Pinescript - whole Code to recreate the Indicator
study( "Volume RSI", shorttitle = "VoRSI" )
periode = input( 3, title = "Periode", minval = 1 )
VoRSI = rsi( volume, periode )
plot( VoRSI, color = #000000, linewidth = 2 )
Now I want to translate that code to MQL4 but I keep getting different outputs.
Here is the MQL4 code I wrote so far:
// MQL4 Code
input int InpRSIPeriod = 3; // RSI Period
double sumn = 0.0;
double sump = 0.0;
double VoRSI = 0.0;
int i = 0;
void OnTick() {
for ( i; i < InpRSIPeriod; i++ ) {
// Check if the Volume is buy or sell
double close = iClose( Symbol(), 0, i );
double old_close = iClose( Symbol(), 0, i + 1 );
if ( close - old_close < 0 )
{
// If the Volume is positive, add it up to the positive sum "sump"
sump = sump + iVolume( Symbol(), 0, i + 1 );
}
else
{
// If the Volume is negative, add it up to the negative sum "sumn"
sumn = sumn + iVolume( Symbol(), 0, i + 1 );
}
}
// Get the MA of the sump and sumn for the Input Period
double Volume_p = sump / InpRSIPeriod;
double Volume_n = sumn / InpRSIPeriod;
// Calculate the RSI for the Volume
VoRSI = 100 - 100 / ( 1 + Volume_p / Volume_n );
// Print Volume RSI for comparison with Tradingview
Print( VoRSI );
// Reset the Variables for the next "OnTick" Event
i = 0;
sumn = 0;
sump = 0;
}
I already checked if the Period, Symbol and timeframe are the same and also have a Screenshoot of the different outputs.
I already tried to follow the function-explanations in the pine-script for the rsi, max, rma and sma function but I cant get any results that seem to be halfway running.
I expect to translate the Pine-Script into MQL4.
I do not want to draw the whole Volume RSI as a Indicator in the Chart.
I just want to calculate the value of the Volume RSI of the last whole periode (when new candel opens) to check if it reaches higher than 80.
After that I want to check when it comes back below 80 again and use that as a threshold wether a trade should be opened or not.
I want a simple function that gets the Period as an input and takes the current pair and Timeframe to return the desired value between 0 and 100.
Up to now my translation persists to provide the wrong output value.
What am I missing in the Calculation? Can someone tell me what is the right way to calculate my Tradingview-Indicator with MQL4?
Q : Can someone tell me what is the right way to calculate my Tradingview-Indicator with MQL4?
Your main miss of the target is in putting the code into a wrong type of MQL4-code. MetaTrader Terminal can place an indicator via a Custom Indicator-type of MQL4-code.
There you have to declare so called IndicatorBuffer(s), that contain pre-computed values of the said indicator and these buffers are separately mapped onto indicator-lines ( depending on the type of the GUI-presentation style - lines, area-between-lines, etc ).
In case you insist on having a Custom-Indicator-less indicator, which is pretty legal and needed in some use-cases, than you need to implement you own "mechanisation" of drawing lines into a separate sub-window of the GUI in the Expert-Advisor-code, where you will manage all the settings and plotting "manually" as you wish, segment by segment ( we use this for many reasons during prototyping, so as to avoid all the Custom-Indicator dependencies and calling-interface gritty-nitties during the complex trading exosystem integration - so pretty well sure about doability and performance benefits & costs of going this way ).
The decision is yours, MQL4 can do it either way.
Q : What am I missing in the Calculation?
BONUS PART : A hidden gem for improving The Performance ...
In either way of going via Custom-Indicator-type-of-MQL4-code or an Expert-Advisor-type-of-MQL4-code a decision it is possible to avoid a per-QUOTE-arrival re-calculation of the whole "depth" of the RSI. There is a frozen-part and a one, hot-end of the indicator line and performance-wise it is more than wise to keep static records of "old" and frozen data and just update the "live"-hot-end of the indicator-line. That saves a lot of the response-latency your GUI consumes from any real-time response-loop...

Google Lighthouse Speed Index 100% visually completed frame definition

I'm looking for a way to optimize our website's Speed Index metric on Lighthouse
I found this helpful article describe Speed Index metric very well, and help me understand how Speed Index is calculated.
https://calendar.perfplanet.com/2016/speed-index-tips-and-tricks/
But there is a key concept not being described clear on the article, and I search for a lot of other Speed Index related blogs still can't found the answer.
What is the 100% visual completeness frame?
We all know the First Frame is 0% VC because it's blank, but the VC keep increasing during the page load process, so what frame will be consider as 100% visual completeness?
The definition of 100% VC frame is important because it's the baseline for calculate all other frame's visual completeness.
If I have a page that simply print from 1 to 100 with interval 100ms and just enough to fill in the viewport, will the 100% VC frame be the frame that number 100 is printed?
Lighthouse
According to Google's description of the Lighthouse "Speed Index" audit:
Lighthouse uses a node module called Speedline to generate the Speed Index score.
sends Speedline
Speedline's Github readme says
The Speed Index, introduced by WebpageTest.org, aims to solve this issue. It measures how fast the page content is visually displayed. The current implementation is based on the Visual Progress from Video Capture calculation method described on the Speed Index page. The visual progress is calculated by comparing the distance between the histogram of the current frame and the final frame.
(Italics mine.)
a timeline of paints
The Speed Index page goes into painful detail about how visual progress is calculated. Here's a snippet:
In the case of Webkit-based browsers, we collect the timeline data which includes paint rects as well as other useful events.
I believe "timeline data" refers to a JSON object retrieved via the Performance Timeline API.
It seems Lighthouse passes the JSON timeline to Speedline, which then extracts an array of "frames," describing the page load's paint events:
/**
* #param {string|Array<TraceEvent>|{traceEvents: Array<TraceEvent>}} timeline
* #param {Options} opts
*/
function extractFramesFromTimeline(timeline, opts) {
which calculates histograms
Speedline converts the image data from each paint event to an image histogram, interestingly excluding pixels that are "close enough" to pass as white:
/**
* #param {number} i
* #param {number} j
* #param {ImageData} img
*/
function isWhitePixel(i, j, img) {
return getPixel(i, j, 0, img.width, img.data) >= 249 &&
getPixel(i, j, 1, img.width, img.data) >= 249 &&
getPixel(i, j, 2, img.width, img.data) >= 249;
}
A lot of math goes into calculating and comparing histograms. The project maintainer is the right person to ask about that. But this is where the eventual determination of the "visually complete" happens:
// find visually complete
for (let i = 0; i < frames.length && !visuallyCompleteTs; i++) {
if (frames[i][progressToUse]() >= 100) {
visuallyCompleteTs = frames[i].getTimeStamp();
}
}
and infers "progress",
The "progress" of a given frame seems to be calculated by this function:
/**
* #param {Frame} current
* #param {Frame} initial
* #param {Frame} target
*/
function calculateFrameProgress(current, initial, target) {
let total = 0;
let match = 0;
const currentHist = current.getHistogram();
const initialHist = initial.getHistogram();
const targetHist = target.getHistogram();
for (let channel = 0; channel < 3; channel++) {
for (let pixelVal = 0; pixelVal < 256; pixelVal++) {
const currentCount = currentHist[channel][pixelVal];
const initialCount = initialHist[channel][pixelVal];
const targetCount = targetHist[channel][pixelVal];
const currentDiff = Math.abs(currentCount - initialCount);
const targetDiff = Math.abs(targetCount - initialCount);
match += Math.min(currentDiff, targetDiff);
total += targetDiff;
}
}
let progress;
if (match === 0 && total === 0) { // All images are the same
progress = 100;
} else { // When images differs
progress = Math.floor(match / total * 100);
}
return progress;
}
and "visually complete" is the first frame with 100% progress.
Without fully auditing the code, my interpretation is that the "visually complete frame" is the first frame calculated to have the same total difference from the initial frame as the final frame (which is determined by which frames Lighthouse chooses to send to Speedline).
Or, in other words, it's complicated.
Visually complete is when the page in the viewport stops changing. I.e. the visuals are not changing.
It is calculated by taking screenshots throughout the load and comparing them to each other and to the final end state. So yes in your example when all numbers 1-100 are printed and the page stops changing you are “visually complete”.
So if a page loads the data in view quickly but renders “below the fold” content (e.g. off screen images) more slowly then you will get a quick visually complete, even if the page overall load time is still long.
Similarly if most of the on screen content is drawn early on but one small part is drawn later (perhaps a “click to chat” option) you will get mostly visually complete early on and so a good speed index, even if not as good as the above example.
On the other hand if you load fonts, or perhaps a large hero image, last and it redraws large parts of the page in view you will get a slow visual complete time and also a slow speed index score.
More details here: https://sites.google.com/a/webpagetest.org/docs/using-webpagetest/metrics/speed-index
I just got the answer from Lighthouse repo contributor, pls check this link guys.
https://github.com/GoogleChrome/lighthouse/issues/8148

How to avoid array out of range

Does somebody know how to avoid the error array out of range when trying to display long number of bars (lets say 7000) in an indicator buffer?
I had a similar issue, that I always got "Array out of range" errors for one of my buffers. I checked with ArraySize(), which returned 0. In the end I just forgot to call SetIndexBuffer(...) for this buffer array in onInit() {...} of my indicator.
Since I was using an internal buffer without drawing lines, I used the IndicatorBuffers() function to increase the amount of buffers first and then registered my additonal buffer using SetIndexBuffer(...).
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
IndicatorBuffers(5);
//buffers with #properties settings
SetIndexBuffer(0,Buffer1);
SetIndexBuffer(1,Buffer2);
SetIndexBuffer(2,Buffer3);
SetIndexBuffer(3,Buffer4);
//additional buffer without #properties
SetIndexBuffer(4,AdditionalBuffer);
While the arrays (problem) look similar, there is a major difference
MQL4 Indicators use "other" mechanics for handling arrays than "ordinary" arrays have.
... Testing pass stopped due to a critical error in the EA
... array out of range in '!2015-09-08___!EA 2xAMA 01 2015-09-08_msMOD_0.00.mq4' (519,39)
Yes, MT4 throws Fatal Error on an attempt to handle a wrong ptr->array[aStaticSIZE] and one has to take due care to either avoid such case, or trim ptr ( alike in low-latency circular-buffer scenarios ) not to direct past the array boundary ( underflow / overflow ) or extend the array[] via ArrayResize() so as to keep pace with the ptr growth ( until memory allows ) ) on arrays declared as dynamic double Array[];, however MQL4 Technical Indicators have completely other situation.
Limits? Yes. . . . . . ( And one ought to review on each New-MQL4.56789 stealth update )
As of a "New"-MQL4.56789-Build-840, your "ordinary" array cannot have more than 2.147.483.647 elements, if O/S memory-pool manager allows, so you ought to have plenty of space, even if using higher dimensionality mappings { 2D | 3D | 4D }.
Years ago 've used many parallel 2D / 3D-arrays for fast and private ( safely encapsulated ) heap / stack-handlers for maintaining highly dynamic entities in scales of 100k+ rows / 2D-planes and all worked well-oiled in old-MQL4.
So some 7k+ elements should not make you any worries.
Indicators use array indirectly, via an automated Buffer-handler
In this sense, your code need not care about these issues.
/*
#property "pragmas" help MQL4-compiler decide about setup of internal handlers
so this part of code "speaks" to MetaLang.exe at compile-time*/
#property indicator_buffers 3 // .DEF N-Buffs
#property indicator_color1 White // .SET Buf[0].color
#property indicator_color2 SeaGreen // .SET Buf[1].color
#property indicator_color3 FireBrick // .SET Buf[2].color
#property indicator_width1 1 // .SET Buf[0].width
#property indicator_width2 2 // .SET Buf[1].width
#property indicator_width3 2 // .SET Buf[2].width
double buffer_line_up[], // .DEF Arrays as dynamic ...[]
buffer_line_dn[], // with human-readable-names
buffer_line_ax[]; // and MT4 will take care
int init() {
SetIndexBuffer( 0, buffer_line_ax ); // .ASSOC IndexBuffer.0<-array[]
SetIndexLabel( 0, "SuperTrend" );
SetIndexBuffer( 1, buffer_line_up ); // .ASSOC IndexBuffer.0<-array[]
SetIndexLabel( 1, "Up Trend" );
SetIndexStyle( 1, DRAW_LINE,
STYLE_SOLID,
1 + int( ATR_Multiplier / 5 ),
SeaGreen
);
SetIndexBuffer( 2, buffer_line_dn ); // .ASSOC IndexBuffer.0<-array[]
SetIndexLabel( 2, "Down Trend" );
SetIndexStyle( 2, DRAW_LINE,
STYLE_SOLID,
1 + int( ATR_Multiplier / 5 ),
FireBrick
);
SetIndexDrawBegin(0, ATR_Period ); // .DEF initial depth of Buffer before 1st GUI output
IndicatorShortName( "xxxx[" + ATR_Period + "," + ATR_Multiplier + "]" );
IndicatorDigits( MarketInfo( Symbol(), MODE_DIGITS ) );

MQL4 iCustom returns always the same (wrong) value (0x7FFFFFFF)

I wrote a custom indicator Speed.mq4 as follows:
double SpeedBuffer[]; // a Custom Indicator BUFFER
int OnInit() {
SetIndexBuffer( 0, SpeedBuffer ); // an access INDEX 0->BUFFER
...
}
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 start;
if ( prev_calculated == 0 ) start = 1;
else start = prev_calculated - 1;
for ( int i = start; i < rates_total - 1 ; i++ ) { // CPU-WASTED BY AN INEFFICIENT BACK-STEPPING IN TIME
double curTypical = typical( high[i], low[i], close[i] );
double prevTypical = typical( high[i+1],low[i+1],close[i+1] ); // CPU-WASTED, NO NEED TO RECALC ...
double curSpeed = curTypical - prevTypical;
SpeedBuffer[i] = curSpeed;
}
//--- return value of prev_calculated for next call
return( rates_total );
}
The indicator works fine in the application and the chart is plotted correctly.
When I try retrieving the last value in the ExpertAdvisor I always receive the same value:
double speed = iCustom( NULL, 0, "Speed", 2, 0, 0 );
Print( "speed is: " + speed );
prints:
speed is: 2147483647
It's always the same number. I'm not sure where's the problem.
from the Print in the indicator I can see the values are calculated correctly. but when I use iCustom I receive only that value.
MQL4 Custom Indicator iCustom() mechanics
MQL4 and even the New-MQL4 ( sometime called an MQL4.5 ) use a rather complicated interfacing model to handle Expert Advisor call / Custom Indicator computations.
A first thing to realise is, that iCustom() is not a call to a function, but rather a method, that indirectly "asks" a by-a-filename referred Custom Indicator to retrieve one, specific, value from a "pre-calculated" DataSTORE.
While it may sound complicated, it is the very nature of a CPU-efficient calculation factory, that the Custom Indicators were designed for in the early days of MQL4 world.
iCustom() is thus just a syntax-sugar to initiate the retrieval method, that gets the relevant piece of pre-calculated value back into the hands of Expert Advisor.
Custom Indicators put all the pre-calculated values into BUFFER(s), co-aligned with the TimeSeries style of ordering the DataSTORE cells ( [0] == "Now, the current Bar", going forwards [1], [2], [3], ... deeper and deeper back into the history )
The iCustom() passes the shift value, as a number of bars -- i.e. how deep into the history the retrieving method has to go, so as to pick the requested value from the respective BUFFER, and also the BUFFER identification INDEX ( 0 in our case above, as there is just a single BUFFER, with INDEX == 0 ). This is used for the sake of the EA being fully agnostic of the Custom Indicator internal variable names et al.
Just ask which BufferINDEX for which BarNUMBER one wants the value to be read from.
The Buffer is the one, who is to be blamed for the (wrong) value
The first line of the code says:
double SpeedBuffer[]; // a Custom Indicator BUFFER
If not handled otherwise in OnInit(){} all cells in the SpeedBuffer will have
EMPTY_VALUE
Empty value in an indicator buffer has by default this value == 2147483647 (0x7FFFFFFF) as has been objected above.
Q.E.D.
One may state in OnInit(){ ArrayInitialize( SpeedBuffer, 0.123456 ); } to have any other value for a cell-initialisation ( that for a TimeSeries-alligned BUFFERs happens upon each new-Bar event ( all cells get reshuffled by one backwards & cell[0] becomes "empty", pre-loaded with a default value discussed here ) ).
One may also add a step in an indicator OnCalculate(){ ... SpeedBuffer[0] = -9.87654; ...} so as to avoid leaving the cell[0] in a context-inconsistent state, not in a "just"-initialised state / value.
Caller-side interface ( how to reduce a risk on a weak-integration interface )
Nevertheless, the responsibility of the value retrieval is on the Expert Advisor side, as it fills the parameters of the iCustom() interface-proxy.
One may use preventive steps as shown in >>> https://stackoverflow.com/a/26389823/3666197
to minimise a risk of improper parameters ordering / values once calling an external Custom Indicator(s) to retrieve a set of values.
This simple method may save you literally tens of man*days of testing/debugging once a rich-extern-parametrised Custom Indicator with several indicator buffers has fallen into suspects due to serving "wrong" numbers ( just due to iCustom() call parameters being "invisibly" out of proper order/context )
Another thing to keep in mind when a custom indicator shows different values on the chart then are reported to the ExpertAdvisor, is that the execution flow through OnCalculate() needs to be different for an ExpertAdvisor than it is for a chart; specifically, the chart initially kicks off a call to OnCalculate() with prev_calculated = 0, whereas an EA (whether run with Strategy Tester or live) will always have prev_calculated = rates_total-1, so that the number of bars to compute the indicator value for is rates_total - prev_calcualted = 1 (ie. just the current bar).
You do account for this in your code, by setting start, but in general for a complicated indicator (that often involves referencing more than just the previous bar) one needs to be mindful of this difference and never assume that if the indicator looks good on the chart that means it's actually working. It needs to be tested separately with an EA.
I reviewed my code and finally figured that:
double speed=iCustom(NULL,0,"Speed",2,0,0);
was using the last value, which was not yet calculated by the custom indicator,
changing it to:
double speed=iCustom(NULL,0,"Speed",2,0,1);
did the trick.

Resources