Array sorting is a fundamental operation in algorithmic trading, enabling efficient data processing for tasks like finding the highest/lowest values, ranking indicators, or processing historical data. While MQL5’s built-in ArraySort function defaults to ascending order, obtaining a descending sort requires a slightly different approach. This article explores standard and custom methods to achieve descending array sorting in MQL5.
Introduction to Array Sorting in MQL5
Processing data efficiently is paramount in high-frequency and quantitative trading. Arrays serve as primary data structures for storing sequences of values, such as price data, indicator buffers, or custom calculations. Ordering these arrays allows for streamlined analysis and logic implementation.
Understanding Arrays in MQL5
MQL5 supports various array types, including simple one-dimensional arrays, multi-dimensional arrays, and dynamic arrays. Arrays can hold primitive data types like int, double, string, bool, as well as custom structures. Their zero-based indexing and contiguous memory allocation make them suitable for numerical computations and iterative processes.
The Need for Descending Order Sorting
While ascending order sorting is common, many trading scenarios require data ordered from largest to smallest. Examples include:
- Identifying the top N values of an indicator (e.g., highest RSI readings).
- Ranking symbols based on a performance metric.
- Processing historical trade data from most recent to oldest based on a timestamp.
- Finding the largest deviations from a mean.
Directly obtaining a descending order simplifies the logic for these tasks compared to sorting ascending and then iterating backward.
Overview of Sorting Techniques in MQL5
MQL5 provides a powerful built-in function, ArraySort, capable of sorting arrays of various data types. However, it sorts exclusively in ascending order. To achieve descending order using the standard library, a subsequent operation is required. Alternatively, developers can implement custom sorting algorithms for specific needs or learning purposes.
Built-in ArraySort() Function
MQL5’s standard library offers a robust function for sorting arrays, which is the go-to method for most sorting tasks due to its performance optimizations.
Description of ArraySort() Function
ArraySort is a global function designed to sort elements of an array. Its signature is:
int ArraySort(void& array[], uint count=WHOLE_ARRAY, uint start=0, ENUM_SORT_MODE mode=MODE_ASCEND);
Key parameters:
array[]: The array to be sorted (passed by reference).count: The number of elements to sort.WHOLE_ARRAYsorts all elements.start: The starting index for sorting.mode: The sorting mode (MODE_ASCENDorMODE_DESCEND).
Crucially, while the documentation includes MODE_DESCEND, this mode is not actually implemented for most array types in MQL5 (as of current builds). The function effectively only sorts in ascending order (MODE_ASCEND). Attempts to use MODE_DESCEND will either result in ascending sort or a compile/runtime warning depending on context and build.
How to Use ArraySort() for Ascending Order (Default)
Sorting in ascending order is straightforward:
int data[] = {5, 2, 8, 1, 9, 4};
ArraySort(data);
// After sort: data is {1, 2, 4, 5, 8, 9}
This default behavior covers many use cases.
Achieving Descending Order with ArrayReverse()
Since ArraySort de facto only supports ascending order, the standard approach for descending order is a two-step process:
- Sort the array in ascending order using
ArraySort(). This arranges elements from smallest to largest. - Reverse the entire array using
ArrayReverse(). This swaps the order, placing the largest element first and the smallest last, effectively creating a descending order.
ArrayReverse is efficient as it performs an in-place reversal by swapping pairs of elements from opposite ends of the array towards the center.
Code Example: Sorting an Array in Descending Order Using ArraySort() and ArrayReverse()
Here’s a practical example demonstrating the combined use of ArraySort and ArrayReverse to achieve a descending sort:
void OnStart()
{
double values[] = {10.5, 3.1, 15.7, 6.2, 9.9, 1.8};
int size = ArraySize(values);
Print("Original array:");
for(int i = 0; i < size; i++)
{
Print(values[i]);
}
// Step 1: Sort in ascending order
ArraySort(values);
Print("\nArray after ascending sort:");
for(int i = 0; i < size; i++)
{
Print(values[i]);
}
// Step 2: Reverse the sorted array to get descending order
ArrayReverse(values);
Print("\nArray after reversing (descending sort):");
for(int i = 0; i < size; i++)
{
Print(values[i]);
}
}
/*
Expected output:
Original array:
10.5
3.1
15.7
6.2
9.9
1.8
Array after ascending sort:
1.8
3.1
6.2
9.9
10.5
15.7
Array after reversing (descending sort):
15.7
10.5
9.9
6.2
3.1
1.8
*/
This two-step method is the standard and most efficient way to sort arrays in descending order in MQL5 using built-in functions.
Implementing Custom Sorting Functions for Descending Order
While ArraySort + ArrayReverse is recommended, understanding custom sorting algorithms is valuable. It can be necessary for complex data structures, sorting based on multiple criteria, or educational purposes. Custom sorts involve implementing a comparison logic and an algorithm like Bubble Sort or Selection Sort.
Writing a Custom Comparison Function
Custom sorting algorithms often rely on a comparison function that determines the relative order of two elements. For descending order, the comparison should return true if the first element should come before the second element in the descending sequence (i.e., if the first is greater than the second).
bool CompareDescending(double a, double b)
{
return a > b; // Return true if 'a' should come before 'b' in descending order
}
This function would be used by a custom sorting algorithm.
Bubble Sort Implementation for Descending Order
Bubble Sort is a simple comparison-based algorithm. It repeatedly steps through the list, compares adjacent elements, and swaps them if they are in the wrong order. For descending sort, swap if the left element is smaller than the right.
void BubbleSortDescending(double& array[])
{
int size = ArraySize(array);
bool swapped;
for (int i = 0; i < size - 1; i++)
{
swapped = false;
for (int j = 0; j < size - i - 1; j++)
{
// If element j is less than element j+1, swap them
if (array[j] < array[j+1])
{
double temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
swapped = true;
}
}
// If no two elements were swapped by inner loop, then break
if (swapped == false)
break;
}
}
Bubble Sort is generally inefficient for large arrays (O(n^2) complexity) and primarily serves as an educational example.
Selection Sort Implementation for Descending Order
Selection Sort divides the input list into two parts: a sorted sublist built from left to right at the front and a sublist of the remaining unsorted elements. For a descending sort, the algorithm finds the largest element from the unsorted sublist and swaps it with the leftmost element of the unsorted sublist, extending the sorted sublist.
void SelectionSortDescending(double& array[])
{
int size = ArraySize(array);
for (int i = 0; i < size - 1; i++)
{
// Find the maximum element in unsorted array
int max_idx = i;
for (int j = i + 1; j < size; j++)
{
if (array[j] > array[max_idx])
max_idx = j;
}
// Swap the found maximum element with the first element
if (max_idx != i)
{
double temp = array[i];
array[i] = array[max_idx];
array[max_idx] = temp;
}
}
}
Selection Sort also has an O(n^2) time complexity, making it inefficient for large datasets compared to built-in functions.
Code Example: Custom Sorting Function for Descending Order
Using the SelectionSortDescending function:
void OnStart()
{
double values[] = {10.5, 3.1, 15.7, 6.2, 9.9, 1.8};
int size = ArraySize(values);
Print("Original array:");
for(int i = 0; i < size; i++)
{
Print(values[i]);
}
// Sort using the custom Selection Sort descending function
SelectionSortDescending(values);
Print("\nArray after custom descending sort:");
for(int i = 0; i < size; i++)
{
Print(values[i]);
}
}
/*
Expected output:
Original array:
10.5
3.1
15.7
6.2
9.9
1.8
Array after custom descending sort:
15.7
10.5
9.9
6.2
3.1
1.8
*/
This demonstrates that custom functions can achieve the desired result, though they are generally less efficient than the optimized built-in functions.
Optimizations and Considerations
Choosing the right sorting method has significant performance implications, especially in time-sensitive trading applications or when dealing with large datasets.
Performance Comparison: Built-in vs. Custom Sorting
ArraySort is highly optimized, likely using an algorithm with O(n log n) average time complexity (like QuickSort or MergeSort). Custom O(n^2) algorithms like Bubble Sort or Selection Sort are significantly slower for arrays of considerable size. Benchmarking is crucial if performance is critical, but generally, ArraySort + ArrayReverse will be the fastest option for primitive type arrays.
Handling Large Arrays
For extremely large arrays (e.g., millions of elements), the difference between O(n log n) and O(n^2) becomes astronomical. Using ArraySort followed by ArrayReverse is strongly recommended in such cases. Custom O(n^2) sorts can lead to unacceptable delays or even freeze the terminal script execution.
Memory usage is also a consideration. Both ArraySort (depending on implementation, MergeSort might use auxiliary space) and in-place custom sorts (like Bubble Sort and Selection Sort) are generally memory efficient. ArrayReverse is always in-place.
Data Types and Sorting Stability
ArraySort works on primitive types (int, double, float, long, bool, char, ushort, uint, ulong) and simple structures without dynamic arrays or objects. Sorting complex structures might require manual implementation or careful use of comparison logic if possible.
Sorting stability refers to whether the relative order of equal elements is preserved. The stability of ArraySort is not explicitly guaranteed across all MQL5 builds or types. Custom sorts like Insertion Sort or Merge Sort can be implemented to be stable if required, but this adds complexity. For most trading use cases with numerical data, stability is not a primary concern.
Conclusion
Sorting arrays in descending order is a common requirement in MQL5 programming for various analytical and operational tasks within Expert Advisors, indicators, and scripts.
Summary of Methods for Descending Order Sorting
The primary and most efficient method to sort arrays in descending order in MQL5 is to combine the built-in functions:
- First, use
ArraySort()to sort the array in ascending order. - Second, use
ArrayReverse()to reverse the entire array, thereby achieving descending order.
Custom sorting algorithms like Bubble Sort or Selection Sort can also achieve descending order by implementing appropriate comparison logic (> instead of <). However, these are generally less performant than the optimized built-in functions and are more suitable for educational purposes or specific, non-performance-critical tasks.
Best Practices and Recommendations
- Prefer Built-in Functions: For primitive data types and performance-critical applications, always use
ArraySortfollowed byArrayReversefor descending order. It is the most optimized and reliable approach provided by the MQL5 standard library. - Understand Performance: Be aware that custom O(n^2) sorting algorithms are unsuitable for large arrays and can lead to significant performance issues.
- Choose the Right Data Structure: Ensure the array contains compatible data types for
ArraySort. For complex data structures, consider extracting relevant values into a simpler array for sorting or implementing a custom sort logic specific to the structure.
By effectively utilizing the built-in array manipulation functions, MQL5 developers can efficiently sort data in descending order, laying a solid foundation for advanced algorithmic trading logic.