193 lines
5.8 KiB
MQL5
193 lines
5.8 KiB
MQL5
|
//+------------------------------------------------------------------+
|
||
|
//| ArrayWorker.mq5 |
|
||
|
//| Copyright 2021, MetaQuotes Ltd. |
|
||
|
//| https://www.mql5.com |
|
||
|
//+------------------------------------------------------------------+
|
||
|
|
||
|
#define PRTS(A) Print(#A, "=", (string)(A) + " / status:" + (string)GetLastError())
|
||
|
#define LIMIT 5000
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Simple class for array processing with struct sorting support |
|
||
|
//+------------------------------------------------------------------+
|
||
|
template<typename T,typename R>
|
||
|
class Worker
|
||
|
{
|
||
|
T array[];
|
||
|
|
||
|
union Overlay
|
||
|
{
|
||
|
T r;
|
||
|
R d[sizeof(T) / sizeof(R)];
|
||
|
};
|
||
|
|
||
|
bool simpleSort(R &r[])
|
||
|
{
|
||
|
return ArraySort(r);
|
||
|
}
|
||
|
|
||
|
template<typename X>
|
||
|
bool simpleSort(X &x[])
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool arrayStructSort(const int field)
|
||
|
{
|
||
|
const int n = ArraySize(array);
|
||
|
const int m = sizeof(T) / sizeof(R);
|
||
|
if(field < 0 || field >= m) return false;
|
||
|
|
||
|
if(m == 1)
|
||
|
{
|
||
|
return simpleSort(array);
|
||
|
}
|
||
|
|
||
|
R temp[][2];
|
||
|
Overlay overlay;
|
||
|
|
||
|
ArrayResize(temp, n);
|
||
|
for(int i = 0; i < n; ++i)
|
||
|
{
|
||
|
overlay.r = array[i];
|
||
|
temp[i][0] = overlay.d[field];
|
||
|
temp[i][1] = i;
|
||
|
}
|
||
|
|
||
|
if(!ArraySort(temp)) return false;
|
||
|
|
||
|
T result[];
|
||
|
|
||
|
ArrayResize(result, n);
|
||
|
for(int i = 0; i < n; ++i)
|
||
|
{
|
||
|
result[i] = array[(int)(temp[i][1] + 0.1)];
|
||
|
}
|
||
|
|
||
|
return ArraySwap(result, array);
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
Worker(T &source[])
|
||
|
{
|
||
|
ArraySwap(source, array);
|
||
|
}
|
||
|
|
||
|
bool process(const int mode)
|
||
|
{
|
||
|
if(ArraySize(array) == 0) return false;
|
||
|
switch(mode)
|
||
|
{
|
||
|
case -4:
|
||
|
// TODO: shuffle
|
||
|
break;
|
||
|
case -3:
|
||
|
// TODO: apply logarithmic scale
|
||
|
break;
|
||
|
case -2:
|
||
|
// TODO: add gaussian noise to array
|
||
|
break;
|
||
|
case -1:
|
||
|
ArrayReverse(array);
|
||
|
break;
|
||
|
default: // sorting by field ('mode')
|
||
|
arrayStructSort(mode);
|
||
|
break;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
T operator[](int i)
|
||
|
{
|
||
|
return array[i];
|
||
|
}
|
||
|
|
||
|
bool get(T &result[])
|
||
|
{
|
||
|
return ArraySwap(array, result);
|
||
|
}
|
||
|
|
||
|
int size() const
|
||
|
{
|
||
|
return ArraySize(array);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Helper function to print a single struct via ArrayPrint |
|
||
|
//+------------------------------------------------------------------+
|
||
|
template<typename S>
|
||
|
void StructPrint(const S &s)
|
||
|
{
|
||
|
S temp[1];
|
||
|
temp[0] = s;
|
||
|
ArrayPrint(temp);
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Sort MqlRates array by Worker object by given field 'offset' |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void sort(Worker<MqlRates,double> &worker, const int offset, const string title)
|
||
|
{
|
||
|
Print(title);
|
||
|
worker.process(offset);
|
||
|
Print("First struct");
|
||
|
StructPrint(worker[0]);
|
||
|
Print("Last struct");
|
||
|
StructPrint(worker[worker.size() - 1]);
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Script program start function |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void OnStart()
|
||
|
{
|
||
|
MqlRates rates[];
|
||
|
int n = CopyRates(_Symbol, _Period, 0, LIMIT, rates);
|
||
|
if(n <= 0)
|
||
|
{
|
||
|
Print("CopyRates error: ", _LastError);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Worker<MqlRates,double> worker(rates);
|
||
|
|
||
|
sort(worker, offsetof(MqlRates, open) / sizeof(double), "Sorting by open price...");
|
||
|
sort(worker, offsetof(MqlRates, tick_volume) / sizeof(double), "Sorting by tick volume...");
|
||
|
sort(worker, offsetof(MqlRates, time) / sizeof(double), "Sorting by time...");
|
||
|
|
||
|
// this will tear down data from internal array:
|
||
|
// worker.get(rates);
|
||
|
// ArrayPrint(rates); // can view all array (may need to adjust ArrayPrint params)
|
||
|
// so consecutive calls to worker.process become impossible:
|
||
|
// worker.process(...); // will do nothing
|
||
|
|
||
|
/*
|
||
|
example output (depends from symbol/timeframe settings)
|
||
|
|
||
|
Sorting by open price...
|
||
|
First struct
|
||
|
[time] [open] [high] [low] [close] [tick_volume] [spread] [real_volume]
|
||
|
[0] 2021.07.21 10:30:00 1.17557 1.17584 1.17519 1.17561 1073 0 0
|
||
|
Last struct
|
||
|
[time] [open] [high] [low] [close] [tick_volume] [spread] [real_volume]
|
||
|
[0] 2021.05.25 15:15:00 1.22641 1.22664 1.22592 1.22618 852 0 0
|
||
|
Sorting by tick volume...
|
||
|
First struct
|
||
|
[time] [open] [high] [low] [close] [tick_volume] [spread] [real_volume]
|
||
|
[0] 2021.05.24 00:00:00 1.21776 1.21811 1.21764 1.21794 52 20 0
|
||
|
Last struct
|
||
|
[time] [open] [high] [low] [close] [tick_volume] [spread] [real_volume]
|
||
|
[0] 2021.06.16 21:30:00 1.20436 1.20489 1.20149 1.20154 4817 0 0
|
||
|
Sorting by time...
|
||
|
First struct
|
||
|
[time] [open] [high] [low] [close] [tick_volume] [spread] [real_volume]
|
||
|
[0] 2021.05.14 16:15:00 1.21305 1.21411 1.21289 1.21333 888 0 0
|
||
|
Last struct
|
||
|
[time] [open] [high] [low] [close] [tick_volume] [spread] [real_volume]
|
||
|
[0] 2021.07.27 22:45:00 1.18197 1.18227 1.18191 1.18225 382 0 0
|
||
|
|
||
|
*/
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|