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:
|
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 |
Rounds an entire array to the specified step or to the tick size of the current symbol if step==NULL. |
static void |
RoundArrayToStep |
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 |
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
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:
|
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:
|
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. |
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
- CArrayObj
- CArray
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));