CopySpread is not the same as ASK-BID... Am I missing something?

 

I had some random results trying to compare brokers and their spreads...

So I wrote a little code to see where my spread values were going wrong - see below.

Now I'm not sure at all! - the CopySpread function seems to be making it up!?
See the example output (suggesting that the spread is either 6 or 11) ...
Grabbing Ask and Bid from SymbolInfoDouble at least gets close, but has annoying rounding errors...
Adding in NormaliseDouble seems to get rid of some of them, but not all...?! - as per example output.

Does anyone have any idea why SPREAD is not equal to ASK - BID in MQL5?
It seems to be consistently smaller in fact.

I assume there isn't any good solution for these annoying pseudo-rounding errors either?  "ask = 0.7031500000000001" - even after allegedly rounding?!

Ignore my #define'd code Diag(A) 'function' - it is just a simple way to quickly Print(VarName,VarValue) to the logs....

Am I missing something??


#define Diag(A) Comment(#A + " = " + (string)A);Print(#A + " = " + (string)A);
//+------------------------------------------------------------------+
void OnStart()
  {
   int copySpread[]; ArraySetAsSeries(copySpread,true);
   double askMinusBid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK) - SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
   double ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
   double bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
   CopySpread(_Symbol,PERIOD_CURRENT,0,1,copySpread);
   Diag(askMinusBid);
   Diag(ask);
   Diag(bid);
   Diag(copySpread[0]);
  }

This outputs...

2021.02.17 00:03:21.185    MicroTest (CADCHF,M5)    askMinusBid = 0.00011
2021.02.17 00:03:21.185    MicroTest (CADCHF,M5)    ask = 0.7031500000000001
2021.02.17 00:03:21.185    MicroTest (CADCHF,M5)    bid = 0.70304
2021.02.17 00:03:21.185    MicroTest (CADCHF,M5)    copySpread[0] = 6

 
Im not 100 percent sure but i think CopySpread returns the average spread in that period which could be H1 fo example but Ask and Bid is the current tick price not average
 
Khuman Bakhramirad:
Im not 100 percent sure but i think CopySpread returns the average spread in that period which could be H1 fo example but Ask and Bid is the current tick price not average
Thanks, I can't find anything in MQL5 Reference that gives me any more info... No idea, might do a few tests, but I can't see how its right just now...
 
  1. Spread is the maximum (IIRC) during the candle. Ask-Bid is the current value.

  2. mlbarnes: I assume there isn't any good solution for these annoying pseudo-rounding errors either?  "ask = 0.7031500000000001" - even after allegedly

    Floating-point has an infinite number of decimals, it's your not understanding floating-point and that some numbers can't be represented exactly. (like 1/10.)
              Double-precision floating-point format - Wikipedia

    See also The == operand. - MQL4 programming forum 2013.06.07

    If you want to see the correct number of digits, convert it to a string with the correct/wanted accuracy.
              question about decima of marketinfo() - MQL4 programming forum 2016.05.18

 
William Roeder:
  1. Spread is the maximum (IIRC) during the candle. Ask-Bid is the current value.

  2. Floating-point has an infinite number of decimals, it's your not understanding floating-point and that some numbers can't be represented exactly. (like 1/10.)
              Double-precision floating-point format - Wikipedia

    See also The == operand. - MQL4 programming forum 2013.06.07

    If you want to see the correct number of digits, convert it to a string with the correct/wanted accuracy.
              question about decima of marketinfo() - MQL4 programming forum 2016.05.18

Not ignoring you, just spending some time testing these and trying to figure out for sure what data they are returning.
My current plan is to completely avoid CopyRates.spread and CopySpread data and instead use CopyRates.Ask and CopyRates.bid to calculate my own spread info...
Thanks for your guidance!


Just looking at your rounding advice link too - thanks.
 
William Roeder:
  1. Spread is the maximum (IIRC) during the candle. Ask-Bid is the current value.

  2. Floating-point has an infinite number of decimals, it's your not understanding floating-point and that some numbers can't be represented exactly. (like 1/10.)
              Double-precision floating-point format - Wikipedia

    See also The == operand. - MQL4 programming forum 2013.06.07

    If you want to see the correct number of digits, convert it to a string with the correct/wanted accuracy.
              question about decima of marketinfo() - MQL4 programming forum 2016.05.18

Thanks again William...

I did some more tests, and your solution cerainly is tidier - e.g:

string bidString = DoubleToString(bid,_Digits); // Does a much more consistent job of rounding decimals!

I did read a lot of that wikipedia page you sent, but I can't quite figure out the mechanisms of all this, and I wouldn't ask you to try to get me up to speed!
The one thing I wanted to know is whether these FP system limitations mean that I can't even turn a number like the one above ( 0.7031500000000001 ) into a string and back then into a double to get rid of the trailing zeros (when Normalize doesn't)...
I answered my own question - see test code below... Fascinating!
I know that this is all a compromise to enable double variables to store enormous variations and all, so I can certainly live with it.
Thanks very much for helping me to at least understand the reason and implications, even if I don't fully understand how it works!

As far as the spread inconsistencies go, I haven't found an answer.

CopySpread usually gives a smaller value for spread than Ask-Bid does, so it can't be the maximum spread seen during the candle. Maybe the minimum??
Anyway, I'm going to just do my own maths (Ask-Bid) and avoid CopyRates and CopySpread data when trying to determine the current spread.

Thanks again! Martyn...


Here is my test code to illustrate Double Precision floating point limitations (hope someone else finds this helpful to understand) ...
My Diag 'function' just outputs the content variable's name and content to both the chart comments and expert output.

#define Diag(A) Comment(#A + " = " + (string)A);Print(#A + " = " + (string)A);  // add Diag(var); anywhere to Comment and Print the var name and value!

//+------------------------------------------------------------------+
void OnStart()
  {
  double test = 0.7031500000000001;
  double test2 = NormalizeDouble(test,5);
  string test3 = DoubleToString(test,5);
  double test4 = StringToDouble(test3);
  
  double test5 = 0.70315;        // An even simpler example!
  
  Diag(test);     // A troublesome number...
  Diag(test2);    // Not a solution...
  Diag(test3);    // Better!
  Diag(test4);    // ...but not when converted back again?
  Diag(test5);    // Even this is beyond the system's precision!
  }
//+------------------------------------------------------------------+

Output :

2021.02.22 17:59:47.798    MicroTest (McDonalds_Corporation_(MCD.N),M5)    test = 0.7031500000000001
2021.02.22 17:59:47.798    MicroTest (McDonalds_Corporation_(MCD.N),M5)    test2 = 0.7031500000000001
2021.02.22 17:59:47.798    MicroTest (McDonalds_Corporation_(MCD.N),M5)    test3 = 0.70315
2021.02.22 17:59:47.798    MicroTest (McDonalds_Corporation_(MCD.N),M5)    test4 = 0.7031500000000001
2021.02.22 17:59:47.798    MicroTest (McDonalds_Corporation_(MCD.N),M5)    test5 = 0.7031500000000001

 

All double numbers are correct. Read the wikipedia link again William posted.

As to spread. Why not just use 

SymbolInfoDouble(_Symbol,SYMBOL_SPREAD);

No need to calculate it yourself.

 
Enrique Dangeroux:

All double numbers are correct. Read the wikipedia link again William posted.

As to spread. Why not just use 

No need to calculate it yourself.

Aha! Another way... I shall check it out now... Thanks.

Checked : An even nicer solution, thanks.
I did need to adjust some syntax, as below - it is SymbolInfoInteger (which oddly yields a long!) - the below seems my best code candidate so far...
The MathPow adjustment and casting to double helps to get in on the same scale as price data like ask and bid... (is that the best way to do it all do you think?)...

double spread = (double)(SymbolInfoInteger(_Symbol,SYMBOL_SPREAD)/MathPow(10,_Digits));

All good, thanks to all three of you for your help.

Martyn

Documentation on MQL5: Common Functions / GetTickCount64
Documentation on MQL5: Common Functions / GetTickCount64
  • www.mql5.com
GetTickCount64 - Common Functions - MQL5 Reference - Reference on algorithmic/automated trading language for MetaTrader 5
 
  1. x / MathPow(10,_Digits) is simply x * _Point
  2. No need for the cast. long / double is a double.
 
William Roeder:
  1. x / MathPow(10,_Digits) is simply x * _Point
  2. No need for the cast. long / double is a double.

I have much to learn!

You are a star... new simple and much better looking code....

double spread = SymbolInfoInteger(_Symbol,SYMBOL_SPREAD)*_Point;
Reason: