CDouble & CDoubleVector – library MetaTrader 5

A library for common rounding methods used in MQL development, primitive wrapper class for type (double), and vector for CDouble objects. MQL5 and MQL4 compatible!

Version 1.02: (2018.02.18)

  • Fixed bug where rounded result would drift from expected result. THANKS AMRALI!

Version 1.01:

  • Fixed bug where arithmetic operators were not returning rounded values.
  • Added symbol setter method to set the symbol after the constructor has been called.

CDouble

The CDouble class wraps a value of the primitive type double in an object. Additionally, this class provides several methods and static methods for rounding doubles and arrays/collections of type double.

Declaration

class CDouble : public CObject

Title

#include <Double.mqh>

Inheritance hierarchy

  • CObject
    • CDouble

Virtual Methods implemented/overridden from class CObject: Type, Load, Save, Compare.

An object of type CDouble contains five data fields:

string
m_symbol
Symbol assigned to the class instance which is used to retrieve lot step and tick size for rounding.
double
m_value
Raw double value assigned to the instance.
uchar
m_step
Step for rounding represented as char to reduce memory footprint. e.g. 0.0025 becomes 25.
uchar
m_digits
Number of digits past the decimal.
ENUM_PRECISION
m_mode
Operating mode for locking rounding methods to a specific “step”.

Before we get any further into the docs, here is a quick practical example of the wrapper class in action:

MqlTick tick;
   SymbolInfoTick(_Symbol,tick);
   CDouble  price = tick.ask - 0.0087263487676283476,
            sl    = price - 500*_Point,
            tp    = price + 500*_Point,
            lots  = 5.25 / 3.78789;
   MqlTradeRequest r={0};
   r.symbol= _Symbol;
   r.price = price.AsRoundedTick();
   r.sl    = sl.AsRoundedTick();
   r.tp    = tp.AsRoundedTick();
   r.volume= lots.AsRoundedLots();

...

Another example using the static library methods:

MqlTick tick;
   SymbolInfoTick(_Symbol,tick);
   MqlTradeRequest r={0};
   r.symbol= _Symbol;
   r.price = tick.ask - 0.0087263487676283476,
   r.sl    = price - 500*_Point,
   r.tp    = price + 500*_Point,
   r.volume= 5.25 / 3.78789;
   ...
   CDouble::RoundTradeRequest(r);
   //automatically rounds the price fields to tick size
   //and the volume to lot step

Static Method Summary

Note: It is not necessary to know OOP or use a wrapper class instance in order to make use of this library. All one has to do is call the static functions with CDouble scope resolution. The syntax is as follows:

type variable_name = CDouble::Method(args);
Modifier and Type Method Description
static bool
IsEqual
(double number1,
 double number2,
 double step);
Compares two doubles and returns a boolean by subtracting the second number from the first, rounding the sum to the “step”, and comparing to 0.
static bool
IsEqual
(double number1,
 double number2,
 int digits);
Compares two doubles and returns an by subtracting the second number from the first, rounding the sum to the “digits”, and comparing to 0.
static int
Compare
(double number1,
 double number2,
 double step)
Compares two doubles and returns an integer:
  • 0 if equal.
  • 1 if number1 > number2.
  • -1 if number1 < number2.
static double
RoundToStep
(const double number, 
 double step)
Returns the rounded value to nearest step precision (e.g. 0.0025).
static double
RoundToDigit
(const double number, 
 int digits)
Returns the rounded value to the nearest digit (same as NormalizeDouble).
static double
RoundToStepUp
(const double number, 
 double step)
Returns the rounded up value to the step precision.
static double
RoundToStepDown
(const double number, 
 double step)
Returns the rounded down value to the step precision.
static double
RoundToTick
(const double number, 
 string symbol=NULL)
Returns the rounded value to the nearest tick size of the current symbol (symbol=NULL) or specified symbol in the symbol parameter.
static double
RoundToLots
(const double number,
 string symbol=NULL,
 bool always_return_valid=true)

Returns the rounded down value to the nearest lot step of the current symbol (symbol=NULL) or specified symbol in the symbol parameter.

always_return_valid == true: will always return a valid lot volume (min_lots <= return_value <= max_lots)

static void (MQL5)
RoundTradeRequest
(MqlTradeRequest &request)

Modifies the price, sl, tp, and volume fields by the symbol identified in the request.

Rounds price, sl, and tp to the nearest tick size.

Rounds volume down to the nearest lot step.

static void
RoundArrayToStep

(double &arr[], double step = NULL)

Rounds an entire array to the specified step or to the tick size of the current symbol if step==NULL.
static void
RoundArrayToStep

(CArrayDouble &arr, double step = NULL)

Rounds an entire CArrayDouble collection to the specified step or to the tick size of the current symbol if step==NULL.
static int
GetDigits
(double floating_point)
Returns the number of digits until trailing zeros in a double. (e.g. 0.0002500… would return 5 digits).
static double 
GetPoint
(int digits)
Returns the double value of the specified digits. (e.g. 3 would return 0.001).
static string
ToString

(double number, int digits)

Returns a string of the floating point number rounded to the digits and will truncate any trailing zeros (e.g. CDouble::ToString(1.23400001, 6) would return “1.234”).

Examples:

MqlTick tick;
   SymbolInfoTick(_Symbol,tick);
   double rnd_by_step   = CDouble::RoundToStep(tick.bid*1.052565465,_Point);
   double rnd_by_digits = CDouble::RoundToDigit(tick.bid*1.052565465,_Digits);
   double by_lot_step   = CDouble::RoundToLots(0.123423,_Symbol);
   double by_tick_size  = CDouble::RoundToTick(tick.ask-100*_Point,_Symbol);
   double roundup       = CDouble::RoundToStepUp(3.999999999,_Point);
   double rounddn       = CDouble::RoundToStepDown(3.999999999,_Point);
   int    digits        = CDouble::GetDigits(0.0000025);
   double point         = CDouble::GetPoint(10);
   bool   equal         = CDouble::IsEqual(tick.bid,tick.bid+0.00000009,_Point);
   string tostr         = CDouble::ToString(3.1399999999999999);
   int    compare       = CDouble::Compare(tick.ask,tick.bid);
   
#ifdef __MQL5__
   MqlTradeRequest r={0};
   r.symbol= _Symbol;
   r.price = tick.ask+0.000089849847658759198199999;
   r.sl    = r.price - 503 * _Point;
   r.tp    = r.price + 503 * _Point;
   r.volume= 1.127984984;
   
   CDouble::RoundTradeRequest(r);
#endif 

Constructor Summary

Alternative:  EWO - indicator MetaTrader 5
Constructor Description
CDouble
(const ENUM_PRECISION mode = PRECISION_DEFAULT,
 const string symbol = NULL)

Note: It is not necessary to explicitly call the constructor since the args are initialized in the caller. It is also not necessary to specify a precision method since there are methods to return a rounded value based on the method call.

ENUM_PRECISION:

  • PRECISION_DEFAULT – Sets the default precision to a step of 1 and 8 digits, which can be overridden by calling Step() or Digits()
  • PRECISION_TICK_SIZE – Locks all rounding methods to the tick size of the specified symbol.
  • PRECISION_LOT_STEP – Locks all rounding methods to the lot step of the specified symbol.
CDouble
(const CDouble &other)
Copy constructor: copies all of the private fields from other object to this object.

Examples:

CDouble num;
CDouble bid(PRECISION_TICK_SIZE, _Symbol);
CDouble ask(bid)
CDouble ask2 = bid;
CDouble lots(PRECISION_LOT_STEP, _Symbol);

Assignment Summary – Overloaded Assignment Operators

Modifier and Type Method Description
void
Set(const double value)
assigns the raw double value to m_value.
void
Set(const CDouble &other)
Assigns the raw double value of CDouble object to m_value.
void
Overloaded operators =, +=, -=, *=, /= (double OR CDouble&) Assigns or modifies the raw double value to m_value.

Note: the = assignment operator can be called in the same line as the declaration.

Examples:

CDouble bid;
bid.Set(tick.bid);
CDouble ask = tick.ask;

CDouble pi = 3.14;
CDouble factor = 2;
pi*=factor;
Print(pi.ToString());
//6.28

Overloaded Arithmetic Operator Summary

Modifier and Type Method Description
double
Overloaded operators +, , *, / (double OR CDouble&) Can accept either type double or CDouble object as argument. Returns double value after the application of the arithmetic associated with the overloaded operator.

Note: Only one arithmetic operator can be used per statement.

Syntax for overloaded operator arithmetic:

type_double_result <-- CDouble_object <-- operator <-- double
//CDouble object always goes on the left side of the operator

type_double_result <-- CDouble_object1 <-- operator <-- CDouble_object2
//order doesn't matter when using two CDouble objects.

Examples:

CDouble foo    = 3.14;
CDouble bar    = 10;
CDouble foobar = bar + foo;          //13.14
CDouble err    = bar + foo + foobar; //error - illegal operation use

double var = bar / foo;

Overloaded Comparison Operator Summary

Modifier and Type Method Description
bool
Overloaded operators ==, !=, >, <, >=, <= (double OR CDouble&)

Can accept either type double or CDouble object as argument. Returns boolean of the value comparison.

Note: this is using the <static int>Compare method for comparison.

Examples:

CDouble foo = 3.14, bar = 3.139999999999999999999;
   
   Print(foo == bar); //true
   Print(foo <= bar); //true
   Print(foo >  bar); //false

Instance Method Summary

Precision Control (defaults): digits = 8; step = 1e-08

  • There are three ways to control precision: Step, Digits, or PrecisionMode(ENUM_PRECISION). Any call to either of these setter methods will override the previous settings.
  • Step is either the _Point or LOT_STEP or TickSize; represented as a floating point (e.g. 0.00001, 0.025, etc.)
  • It is not necessary to set the step since RoundToTick and RoundToLot automatically use the appropriate step values for the rounded-return.
Modifier and Type Method Description
void
PrecisionMode
(const ENUM_PRECISION mode)

Sets the default mode for rounding calculations and ToString. Overrides existing Step and Digit settings. Note: can also be set in the constructor.

ENUM_PRECISION:

  • PRECISION_DEFAULT – Sets the default precision to a step of 1 and 8 digits, which can be overridden by calling Step() or Digits().
  • PRECISION_TICK_SIZE – Locks all rounding methods to the tick size of the specified symbol.
  • PRECISION_LOT_STEP – Locks all rounding methods to the lot step of the specified symbol.
ENUM_PRECISION
PrecisionMode()
Returns the current working precision mode.
void
Step
(const double step_or_point)
Sets the step to the specified precision. Overrides the precision mode.
double
Step()
Returns the current value of Step.
void
Digits
(const int digits)
Sets the precision to the number of specified digits. Overrides the precision mode and sets the step to 1e-(digits).
int
Digits()
Returns the current working digit precision.
double
AsRawDouble()
Returns the raw value of stored double.
double
AsRounded()

Returns the rounded value to the nearest specified step. default = 1e-08.

Step is locked to tick size when PRECISION_TICK_SIZE.

Step is locked to lot step when PRECISION_LOT_STEP.

double
AsRoundedUp()
Returns the rounded up value to the specified step.
double
AsRoundedDown()
Returns the rounded down value to the specified step.
double
AsRoundedTick()
Returns the rounded value to the nearest tick – specified by the symbol’s tick size.
double
AsRoundedLots
(bool always_return_valid = true)
Returns the rounded value to the nearest lot – specified by the symbol’s lot step.
int
ToInt()
Returns the int value.
long
ToLong()
Returns the long value.
string
ToStringPrecision()
Returns a string with trailing zeros.
string
ToString()
Returns a string with truncated trailing zeros.
string
Symbol()
Returns the current working symbol.
string
Symbol(const string symbol)
Sets the working symbol to a symbol other than the chart symbol after the constructor has been called. Used when working with multiple symbols.
Alternative:  CashMachine 5min - EA MetaTrader 5

Examples:

CDouble pi2 = 3.14159265359;
   
   // getting value as... 
   double raw_double             = pi2.AsRawDouble();
   double round_double_to_step   = pi2.AsRounded();
   double tick_size_double       = pi2.AsRoundedTick();
   double lot_step_double        = pi2.AsRoundedLots();
   double rounded_up             = pi2.AsRoundedUp();
   double rounded_down           = pi2.AsRoundedDown();
   int    double_to_int          = pi2.ToInt();
   long   double_to_long         = pi2.ToLong();
   string precision_str          = pi2.ToStringPrecision();
   pi2 = 3.140000000009;
   pi2.Digits(8);
   string truncated_str          = pi2.ToString();

Virtual Method Summary

Methods overridden from CObject:

Modifier and Type Method Description
virtual int
Compare
(const CObject *node,
 const int mode=0)
Used for sorting and searching, the Compare method compares this object’s AsRounded value to the incoming node’s AsRounded value.
virtual int
Type()
Returns an int of TYPE_DOUBLE.
virtual bool
Save(const int file_handle)
Serializes and saves the member variables to the file of the incoming handle.
virtual bool
Load(const int file_handle)
Sets the member variables to the values saved in the file of the incoming handle.

See CDoubleVector below for examples.

CDoubleVector

The CDoubleVector class is an object pointer collection specialized for CDouble dynamic instances.

Declaration

class CDoubleVector : public CArrayObj

Title

#include <Double.mqh>

Inheritance hierarchy

  • CObject
    • CArray
      • CArrayObj
        • CDoubleVector

Virtual Methods implemented/overridden from class CArrayObj: CreateElement.

Instance Method Summary

**See CArrayObj for inherited public methods.

Modifier and Type Method Description
CDouble*
operator[]
(const int index)
Overloaded index operator. Returns the pointer to the object at n index in the vector.
bool
Add(const double value)
Takes a primitive double as argument and converts it to a CDouble object and adds it to the end of the vector.
bool
AssignDoubleArray
(const double &array[])
Takes an array of doubles and converts them to CDouble objects and assigns them to vector.
bool
CopyOut(double &arr[])
Copies the CDouble values in the vector to a primitive double array.
bool
CopyOut(CArrayDouble &arr)
Copies the CDouble values in the vector to a CDoubleArray collection.
virtual bool
Save(const int file_handle)
Saves the vector to the file specified by the incoming file handle.
virtual bool
Load(const int file_handle)
Loads the saved vector state from the file specified by the incoming file handle.

Examples:

CDoubleVector *vect = new CDoubleVector;
   
   double dubs[]={3.14,1.21,55.555};
   vect.AssignDoubleArray(dubs);
   vect.Add(tick.bid);
   
   //calling CDouble object by index
   Print(vect[vect.Total()-1].ToString());
   
   //add a new CDouble object
   CDouble *lot = new CDouble(PRECISION_LOT_STEP);
   lot = 1.22;
   vect.Add(lot);
   
   //sort vector ascending
   vect.Sort();
   
   int total = vect.Total();
   
   //save vector to file including CDouble object states and values
   string f = "testdub.bin";
   int    h = FileOpen(f,FILE_WRITE|FILE_BIN);
   if(vect.Save(h))
      Print("save successful");
   FileClose(h);
   delete vect;
   
   //load vector from file
   CDoubleVector vect_reborn;
   h=FileOpen(f,FILE_READ|FILE_BIN);
   if(vect_reborn.Load(h))
      Print("load successful");
   FileClose(h);
   total = vect_reborn.Total();
   Print("Total vector size = ",sizeof(vect_reborn)," bytes");
   for(int i=0;i<vect_reborn.Total();i++)
      Print(vect_reborn[i].ToString());
      
   //Copy out to double arr
   double arr2[];
   vect_reborn.CopyOut(arr2);
   Print(ArraySize(arr2));
📈 ROBOTFX MetaTrader Expert Advisors and Indicators to maximize profits and minimize the risks