Terminal
MQL5
Web Terminal
Web Terminal
MQL5
MQL5: Added COPY_TICKS_VERTICAL and COPY_RATES_VERTICAL flags for the CopyTicks, CopyTicksRange and CopyRates methods respectively.
By default, ticks and series are copied to the matrix along the horizontal axis, which means the data is added to the right, at the line end. In trained ONNX model running tasks, such a matrix needs to be transposed in order to feed the input data:
const long ExtOutputShape[] = {1,1}; // model's output shape const long ExtInputShape [] = {1,10,4}; // model's input shape #resource "Python/model.onnx" as uchar ExtModel[]// model as a resource //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ int OnStart(void) { matrix rates; //--- get 10 bars if(!rates.CopyRates("EURUSD",PERIOD_H1,COPY_RATES_OHLC,2,10)) return(-1); //--- input a set of OHLC vectors matrix x_norm=rates.Transpose(); vector m=x_norm.Mean(0); vector s=x_norm.Std(0); matrix mm(10,4); matrix ms(10,4);
By specifying the additional flag COPY_RATES_VERTICAL (COPY_TICKS_VERTICAL for ticks) when calling the method, you can eliminate the extra data transposition operation:
//+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ int OnStart(void) { matrix rates; //--- get 10 bars if(!rates.CopyRates("EURUSD",PERIOD_H1,COPY_RATES_OHLC|COPY_RATES_VERTICAL,2,10)) return(-1); //--- input a set of OHLC vectors
MetaEditor
Terminal
Terminal
MQL5
Compile the project and run it on EURUSD H1 to see the result.
In
addition to the model and the MQL5 code which runs it, the project also
includes the PricePredictionTraining.py Python script. It shows how you
can create an ONNX model yourself. To run the script, install Python on
your computer and the required modules from the prompt line:
#import "mmlib.dll" bool sgemm(uint flags,matrix<float> &C,const matrix<float> &A,const matrix<float> &B,ulong M,ulong N,ulong K,float alpha,float beta); #importC++
extern "C" __declspec(dllexport) bool sgemm(UINT flags,float *C,const float *A,const float *B,UINT64 M,UINT64 N,UINT64 K,float alpha,float beta)In addition to buffers, you should pass matrix and vector sizes for correct processing.
Added new CopySeries function for copying synchronized timeseries from MqlRates into separate arrays.
The CopySeries function allows obtaining only the necessary timeseries into different specified arrays during one call, while all of timeseries data will be synchronized. This means that all values in the resulting arrays at a certain index N will belong to the same bar on the specified Symbol/Timeframe pair. Therefore, there is no need for the programmer to additionally synchronize the received timeseries by the bar opening time.
Unlike CopyRates, which returns the full set of timeseries as an MqlRates array, the CopySeries function allows obtaining specific required timeseries into separate arrays. This can be done by specifying a combination of flags to select the type of timeseries. The order of the arrays passed to the function must match the order of the fields in the MqlRates structure:
struct MqlRates { datetime time; // period beginning time double open; // open price double high; // high price for the period double low; // low price for the period double close; // close price long tick_volume; // tick volume int spread; // spread long real_volume; // exchange volume }
Thus, if you need to get the values of the 'time', 'close' and 'real_volume' timeseries for the last 100 bars of the current Symbol/Timeframe, you should use the following call:
datetime time[]; double close[]; long volume[]; CopySeries(NULL,0,0,100,COPY_RATES_TIME|COPY_RATES_CLOSE|COPY_RATES_VOLUME_REAL,time,close,volume);
The order of the arrays "time, close, volume" must match the order of the fields in the MqlRates structure. The order of values in the rates_mask is ignored. The mask could be as follows:
COPY_RATES_VOLUME_REAL|COPY_RATES_TIME|COPY_RATES_CLOSE
Example
//--- input parameters input datetime InpDateFrom=D'2022.01.01 00:00:00'; input datetime InpDateTo =D'2023.01.01 00:00:00'; input uint InpCount =20; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart(void) { //--- arrays to get timeseries from the Rates structure double open[]; double close[]; float closef[]; datetime time1[], time2[]; //---request close prices to a double array ResetLastError(); int res1=CopySeries(NULL, PERIOD_CURRENT, 0, InpCount, COPY_RATES_TIME|COPY_RATES_CLOSE, time1, close); PrintFormat("1. CopySeries returns %d values. Error code=%d", res1, GetLastError()); ArrayPrint(close); //--- now also request open prices; use float array for close prices ResetLastError(); int res2=CopySeries(NULL, PERIOD_CURRENT, 0, InpCount, COPY_RATES_TIME|COPY_RATES_CLOSE|COPY_RATES_OPEN, time2, open, closef); PrintFormat("2. CopySeries returns %d values. Error code=%d", res2, GetLastError()); ArrayPrint(closef); //--- compare the received data if((res1==res2) && (time1[0]==time2[0])) { Print(" | Time | Open | Close double | Close float |"); for(int i=0; i<10; i++) { PrintFormat("%d | %s | %.5f | %.5f | %.5f |", i, TimeToString(time1[i]), open[i], close[i], closef[i]); } } /* Result 1. CopySeries returns 0 values. Error code=0 [ 0] 1.06722 1.06733 1.06653 1.06520 1.06573 1.06649 1.06694 1.06675 1.06684 1.06604 [10] 1.06514 1.06557 1.06456 1.06481 1.06414 1.06394 1.06364 1.06386 1.06239 1.06247 2. CopySeries returns 0 values. Error code=0 [ 0] 1.06722 1.06733 1.06653 1.06520 1.06573 1.06649 1.06694 1.06675 1.06684 1.06604 [10] 1.06514 1.06557 1.06456 1.06481 1.06414 1.06394 1.06364 1.06386 1.06239 1.06247 | Time | Open | Close double | Close float | 0 | 2023.03.01 17:00 | 1.06660 | 1.06722 | 1.06722 | 1 | 2023.03.01 18:00 | 1.06722 | 1.06733 | 1.06733 | 2 | 2023.03.01 19:00 | 1.06734 | 1.06653 | 1.06653 | 3 | 2023.03.01 20:00 | 1.06654 | 1.06520 | 1.06520 | 4 | 2023.03.01 21:00 | 1.06520 | 1.06573 | 1.06573 | 5 | 2023.03.01 22:00 | 1.06572 | 1.06649 | 1.06649 | 6 | 2023.03.01 23:00 | 1.06649 | 1.06694 | 1.06694 | 7 | 2023.03.02 00:00 | 1.06683 | 1.06675 | 1.06675 | 8 | 2023.03.02 01:00 | 1.06675 | 1.06684 | 1.06684 | 9 | 2023.03.02 02:00 | 1.06687 | 1.06604 | 1.06604 | */ }
MetaEditor
Tester
MetaTrader 5 Web Terminal build 3620
Terminal
Web Terminal
Web Terminal
Terminal
MQL5
long preferred_workgroup_size_multiple=OpenCL.GetDeviceInfo(0x1067);
void OnStart() { string cpu,os; //--- cpu=TerminalInfoString(TERMINAL_CPU_NAME); os=TerminalInfoString(TERMINAL_OS_VERSION); PrintFormat("CPU: %s, OS: %s",cpu,os); }Result:
MetaEditor
Terminal
MQL5
//--- the first handle parameter is ignored when obtaining the last error code int code = (int)CLGetInfoInteger(0,CL_LAST_ERROR);
//--- get the code of the last OpenCL error int code = (int)CLGetInfoInteger(0,CL_LAST_ERROR); string desc; // to get the text description of the error //--- use the error code to get the text description of the error if(!CLGetInfoString(code,CL_ERROR_DESCRIPTION,desc)) desc = "cannot get OpenCL error description, " + (string)GetLastError(); Print(desc); //--- to get the description of the last OpenCL error without receiving the code, pass CL_LAST_ERROR if(!CLGetInfoString(CL_LAST_ERROR,CL_ERROR_DESCRIPTION, desc)) desc = "cannot get OpenCL error description, " + (string)GetLastError(); Print(desc);The internal enumeration name is passed as the error description. Its explanation can be found at https://registry.khronos.org/OpenCL/specs/3.0-unified/html/OpenCL_API.html#CL_SUCCESS. For example, the CL_INVALID_KERNEL_ARGS value means "Returned when enqueuing a kernel when some kernel arguments have not been set or are invalid."
MetaTrader 5 WebTerminal
Terminal
MQL5
class A { }; void OnStart(void) { const A *const arr[][2][3]={}; Print(typename(arr)); }Result:
"class A const * const [][2][3]"
Terminal
MQL5
Fixed errors reported in crash logs.
MetaTrader 5 WebTerminal build 3500
The new Web Terminal provides full-featured support for mobile devices. The interface will automatically adapt to the screen size, enabling efficient operations from iOS and Android phones and tablets:
Also, the Web Terminal features a lot of fixes and improvements.
The new MetaTrader 5 Web Terminal supports the full set of trading functions. It enables users to:
Terminal
MQL5
bool matrix::CopyTicks(string symbol,uint flags,ulong from_msc,uint count); bool vector::CopyTicks(string symbol,uint flags,ulong from_msc,uint count); bool matrix::CopyTicksRange(string symbol,uint flags,ulong from_msc,ulong to_msc); bool matrix::CopyTicksRange(string symbol,uint flags,ulong from_msc,ulong to_msc);The copied data type is specified in the 'flags' parameter using the ENUM_COPY_TICKS enumeration. The following values are available:
COPY_TICKS_INFO = 1, // ticks resulting from Bid and/or Ask changes COPY_TICKS_TRADE = 2, // ticks resulting from Last and Volume changes COPY_TICKS_ALL = 3, // all ticks having changes COPY_TICKS_TIME_MS = 1<<8, // time in milliseconds COPY_TICKS_BID = 1<<9, // Bid price COPY_TICKS_ASK = 1<<10, // Ask price COPY_TICKS_LAST = 1<<11, // Last price COPY_TICKS_VOLUME = 1<<12, // volume COPY_TICKS_FLAGS = 1<<13, // tick flagsIf multiple data types are selected (only available for matrices), the order of the rows in the matrix will correspond to the order of values in the enumeration.
bool matrix::Assign(const vector &vec);The result will be a one-row matrix.
bool vector::Assign(const matrix &mat);
bool vector::Swap(vector &vec); bool vector::Swap(matrix &vec); bool vector::Swap(double &arr[]); bool matrix::Swap(vector &vec); bool matrix::Swap(matrix &vec); bool matrix::Swap(double &arr[]);Each array, vector or matrix refers to a memory buffer which contains the elements of that object. The Swap method actually swaps pointers to these buffers without writing the elements to memory. Therefore, a matrix remains a matrix, and a vector remains a vector. Swapping a matrix and a vector will result in a one-row matrix with vector elements and a vector with matrix elements in a flat representation (see the Flat method).
//+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- matrix a= {{1, 2, 3}, {4, 5, 6}}; Print("a before Swap: \n", a); matrix b= {{5, 10, 15, 20}, {25, 30, 35, 40}, {45, 50, 55, 60}}; Print("b before Swap: \n", b); //--- swap matrix pointers a.Swap(b); Print("a after Swap: \n", a); Print("b after Swap: \n", b); /* a before Swap: [[1,2,3] [4,5,6]] b before Swap: [[5,10,15,20] [25,30,35,40] [45,50,55,60]] a after Swap: [[5,10,15,20] [25,30,35,40] [45,50,55,60]] b after Swap: [[1,2,3] [4,5,6]] */ vector v=vector::Full(10, 7); Print("v before Swap: \n", v); Print("b before Swap: \n", b); v.Swap(b); Print("v after Swap: \n", v); Print("b after Swap: \n", b); /* v before Swap: [7,7,7,7,7,7,7,7,7,7] b before Swap: [[1,2,3] [4,5,6]] v after Swap: [1,2,3,4,5,6] b after Swap: [[7,7,7,7,7,7,7,7,7,7]] */ }The Swap() method also enables operations with dynamic arrays (fixed-sized arrays cannot be passed as parameters). The array can be of any dimension but of an agreed size, which means that the total size of a matrix or vector must be a multiple of the array's zero dimension. The array's zero dimension is the number of elements contained at the first index. For example, for a dynamic three-dimensional array 'double array[][2][3]', the zero dimension is the product of the second and third dimension sizes: 2x3=6. So, such an array can only be used in the Swap method with matrices and vectors whose total size is a multiple of 6: 6, 12, 18, 24, etc.
//+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- fill the 1x10 matrix with the value 7.0 matrix m= matrix::Full(1, 10, 7.0); Print("matrix before Swap:\n", m); //--- try to swap the matrix and the array double array_small[2][5]= {{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}}; Print("array_small before Swap:"); ArrayPrint(array_small); if(m.Swap(array_small)) { Print("array_small after Swap:"); ArrayPrint(array_small); Print("matrix after Swap: \n", m); } else // the matrix size is not a multiple of the first array dimension { Print("m.Swap(array_small) failed. Error ", GetLastError()); } /* matrix before Swap: [[7,7,7,7,7,7,7,7,7,7]] array_small before Swap: [,0] [,1] [,2] [,3] [,4] [0,] 1.00000 2.00000 3.00000 4.00000 5.00000 [1,] 6.00000 7.00000 8.00000 9.00000 10.00000 m.Swap(array_small) failed. Error 4006 */ //--- use a larger matrix and retry the swap operation double array_static[3][10]= {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, {2, 4, 6, 8, 10, 12, 14, 16, 18, 20}, {3, 6, 9, 12, 15, 18, 21, 24, 27, 30} }; Print("array_static before Swap:"); ArrayPrint(array_static); if(m.Swap(array_static)) { Print("array_static after Swap:"); ArrayPrint(array_static); Print("matrix after Swap: \n", m); } else // a static array cannot be used to swap with a matrix { Print("m.Swap(array_static) failed. Error ", GetLastError()); } /* array_static before Swap: [,0] [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [0,] 1.00000 2.00000 3.00000 4.00000 5.00000 6.00000 7.00000 8.00000 9.00000 10.00000 [1,] 2.00000 4.00000 6.00000 8.00000 10.00000 12.00000 14.00000 16.00000 18.00000 20.00000 [2,] 3.00000 6.00000 9.00000 12.00000 15.00000 18.00000 21.00000 24.00000 27.00000 30.00000 m.Swap(array_static) failed. Error 4006 */ //--- another attempt to swap an array and a matrix double array_dynamic[][10]; // dynamic array ArrayResize(array_dynamic, 3); // set the first dimension size ArrayCopy(array_dynamic, array_static); //--- now use a dynamic array for swap if(m.Swap(array_dynamic)) { Print("array_dynamic after Swap:"); ArrayPrint(array_dynamic); Print("matrix after Swap: \n", m); } else // no error { Print("m.Swap(array_dynamic) failed. Error ", GetLastError()); } /* array_dynamic after Swap: [,0] [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [0,] 7.00000 7.00000 7.00000 7.00000 7.00000 7.00000 7.00000 7.00000 7.00000 7.00000 matrix after Swap: [[1,2,3,4,5,6,7,8,9,10,2,4,6,8,10,12,14,16,18,20,3,6,9,12,15,18,21,24,27,30]] */ }
vector vector::LossGradient(const vector &expected,ENUM_LOSS_FUNCTION loss) const; matrix matrix::LossGradient(const matrix &expected,ENUM_LOSS_FUNCTION loss) const;
CREATE TABLE artist( artistid INTEGER PRIMARY KEY, artistname TEXT ); CREATE TABLE track( trackid INTEGER, trackname TEXT, trackartist INTEGER, FOREIGN KEY(trackartist) REFERENCES artist(artistid) );
MetaEditor
MetaTester
Fixed errors reported in crash logs.
Terminal
MQL5
bool vector<TDst>::Assign(const vector<TSrc> &assign); bool matrix<TDst>::Assign(const matrix<TSrc> &assign);Example:
//--- copying matrices matrix b={}; matrix a=b; a.Assign(b); //--- copying an array to a matrix double arr[5][5]={{1,2},{3,4},{5,6}}; Print("array arr"); ArrayPrint(arr); b.Assign(arr); Print("matrix b \n",b); /* array arr [,0] [,1] [,2] [,3] [,4] [0,] 1.00000 2.00000 0.00000 0.00000 0.00000 [1,] 3.00000 4.00000 0.00000 0.00000 0.00000 [2,] 5.00000 6.00000 0.00000 0.00000 0.00000 [3,] 0.00000 0.00000 0.00000 0.00000 0.00000 [4,] 0.00000 0.00000 0.00000 0.00000 0.00000 matrix b [[1,2,0,0,0] [3,4,0,0,0] [5,6,0,0,0] [0,0,0,0,0] [0,0,0,0,0]] */
bool matrix::CopyRates(string symbol,ENUM_TIMEFRAMES period,ulong rates_mask,ulong from,ulong count); bool vector::CopyRates(string symbol,ENUM_TIMEFRAMES period,ulong rates_mask,ulong from,ulong count);The copied data type is specified in the rates_mask parameter using the ENUM_COPY_RATES enumeration. The following values are available:
Fixed error when changing a constant parameter which has been passed to a function as an object pointer reference.
The const specifier declares a variable as a constant to prevent it from being changed during program execution. It only allows one-time variable initialization during declaration. An example of constant variables in the OnCalculate function:
int OnCalculate (const int rates_total, // price[] array size const int prev_calculated, // bars processed on previous call const int begin, // meaningful data starts at const double& price[] // array for calculation );
The below example contains a compiler error which allowed an implicit pointer casting for reference parameters:
class A {}; const A *a = new A; void foo( const A*& b ) { b = a; } void OnStart() { A *b; foo(b); // not allowed Print( a,":",b ); }The compiler will detect such illegal operations and will return the relevant error.
MetaEditor
New MetaTrader 5 Web Terminal
We
have released a revised MetaTrader 5 Web Terminal which features an
updated interface and a redesigned core. The new interface is similar to
the terminal version for iPad:
It also features a plethora of new functions:
Try the new web terminal at www.mql5.com right now. It will soon become available for your brokers.
Terminal
MQL5
//--- matrix a= {{1, 4}, {9, 16}}; Print("matrix a=\n",a); a=MathSqrt(a); Print("MatrSqrt(a)=\n",a); /* matrix a= [[1,4] [9,16]] MatrSqrt(a)= [[1,2] [3,4]] */For MathMod and MathPow, the second element can be either a scalar or a matrix/vector of the appropriate size.
//+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- Use the initializing function to populate the vector vector r(10, ArrayRandom); // Array of random numbers from 0 to 1 //--- Calculate the average value double avr=r.Mean(); // Array mean value vector d=r-avr; // Calculate an array of deviations from the mean Print("avr(r)=", avr); Print("r=", r); Print("d=", d); vector s2=MathPow(d, 2); // Array of squared deviations double sum=s2.Sum(); // Sum of squared deviations //--- Calculate standard deviation in two ways double std=MathSqrt(sum/r.Size()); Print(" std(r)=", std); Print("r.Std()=", r.Std()); } /* avr(r)=0.5300302133243813 r=[0.8346201971495713,0.8031556138798182,0.6696676534318063,0.05386516922513505,0.5491195410016175,0.8224433118686484,... d=[0.30458998382519,0.2731254005554369,0.1396374401074251,-0.4761650440992462,0.01908932767723626,0.2924130985442671, ... std(r)=0.2838269732183663 r.Std()=0.2838269732183663 */ //+------------------------------------------------------------------+ //| Fills the vector with random values | //+------------------------------------------------------------------+ void ArrayRandom(vector& v) { for(ulong i=0; i<v.Size(); i++) v[i]=double(MathRand())/32767.; }
Improved mathematical functions for operations with the float
type. The newly implemented possibility to apply mathematical functions
to 'float' matrix and vectors has enabled an improvement in
mathematical functions applied to 'float' scalars. Previously, these
function parameters were unconditionally cast to the 'double' type, then
the corresponding implementation of the mathematical function was
called, and the result was cast back to the 'float' type. Now the
operations are implemented without extra type casting.
The following example shows the difference in the mathematical sine calculations:
//+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- Array of random numbers from 0 to 1 vector d(10, ArrayRandom); for(ulong i=0; i<d.Size(); i++) { double delta=MathSin(d[i])-MathSin((float)d[i]); Print(i,". delta=",delta); } } /* 0. delta=5.198186103783087e-09 1. delta=8.927621308885136e-09 2. delta=2.131878673594656e-09 3. delta=1.0228555918923021e-09 4. delta=2.0585739779477308e-09 5. delta=-4.199390279957527e-09 6. delta=-1.3221741035351897e-08 7. delta=-1.742922250969059e-09 8. delta=-8.770715820283215e-10 9. delta=-1.2543186267421902e-08 */ //+------------------------------------------------------------------+ //| Fills the vector with random values | //+------------------------------------------------------------------+ void ArrayRandom(vector& v) { for(ulong i=0; i<v.Size(); i++) v[i]=double(MathRand())/32767.; }
The neural network activation function determines how the weighted input signal sum is converted into a node output signal at the network level. The selection of the activation function has a big impact on the neural network performance. Different parts of the model can use different activation functions. In addition to all known functions, MQL5 also offers derivatives. Derivative functions enable fast calculation of adjustments based on the error received in learning.
AF_ELU Exponential Linear Unit AF_EXP Exponential AF_GELU Gaussian Error Linear Unit AF_HARD_SIGMOID Hard Sigmoid AF_LINEAR Linear AF_LRELU Leaky REctified Linear Unit AF_RELU REctified Linear Unit AF_SELU Scaled Exponential Linear Unit AF_SIGMOID Sigmoid AF_SOFTMAX Softmax AF_SOFTPLUS Softplus AF_SOFTSIGN Softsign AF_SWISH Swish AF_TANH Hyperbolic Tangent AF_TRELU Thresholded REctified Linear Unit
The loss function evaluates the quality of model predictions. The model construction targets the minimization of the function value at each stage. The approach depends on the specific dataset. Also, the loss function can depend on weight and offset. The loss function is one-dimensional and is not a vector since it provides a general evaluation of the neural network.
LOSS_MSE Mean Squared Error LOSS_MAE Mean Absolute Error LOSS_CCE Categorical Crossentropy LOSS_BCE Binary Crossentropy LOSS_MAPE Mean Absolute Percentage Error LOSS_MSLE Mean Squared Logarithmic Error LOSS_KLD Kullback-Leibler Divergence LOSS_COSINE Cosine similarity/proximity LOSS_POISSON Poisson LOSS_HINGE Hinge LOSS_SQ_HINGE Squared Hinge LOSS_CAT_HINGE Categorical Hinge LOSS_LOG_COSH Logarithm of the Hyperbolic Cosine LOSS_HUBER Huber
int cl_ctx; //--- Initializing the OpenCL context if((cl_ctx=CLContextCreate(CL_USE_GPU_DOUBLE_ONLY))==INVALID_HANDLE) { Print("OpenCL not found"); return; }
CalendarValueLast(change, result, "", "EUR")
MetaEditor
'levels.bmp' as 'uint levels[18990]'
Terminal
MQL5
MetaTester
MetaEditor
Fixed errors reported in crash logs.
Terminal
MQL5
double vector.RegressionError(const enum lr_error); double matrix.RegressionError(const enum lr_error); vector matrix.RegressionError(const enum lr_error,const int axis);The following variables can be used as metrics:
enum REGRESSION_ERROR { REGRESSION_MAE, // Mean absolute error REGRESSION_MSE, // Mean square error REGRESSION_RMSE, // Root mean square error REGRESSION_R2, // R squared REGRESSION_MAPE, // Mean absolute percentage error REGRESSION_MSPE, // Mean square percentage error REGRESSION_RMSLE // Root mean square logarithmic error };
MetaEditor
Tester
Fixed errors reported in crash logs.
Terminal
Terminal
Terminal
MQL5
void OnStart() { int arr[4][5]= { {22, 34, 11, 20, 1}, {10, 36, 2, 12, 5}, {33, 37, 25, 13, 4}, {14, 9, 26, 21, 59} }; ulong indexes[4][5]; //--- Sort the array arr.ArgSort(indexes,-1,0); Print("indexes"); ArrayPrint(indexes); } // Result log: // indexes // [,0][,1][,2][,3][,4] // [0,] 4 2 3 0 1 // [1,] 2 4 0 3 1 // [2,] 4 3 2 0 1 // [3,] 1 0 3 2 4
void OnStart() { string test="some string"; PrintFormat("String length is %d",test.Length()); } // Result log: // String length is 11
MQL5
double matrix::Flat(ulong index) const; // getter void matrix::Flat(ulong index,double value); // setter
Pseudocode for calculating the address of a matrix element:
ulong row=index / mat.Cols(); ulong col=index % mat.Cols(); mat[row,col]
For example, for 'matrix mat(3,3)', access to elements can be written as follows:
Tester
Terminal
Terminal
MQL5
VPS
MetaEditor
Tester