Học cách làm việc với arrays, từ khai báo, resize, copy đến xử lý price data và indicator buffers.
Arrays (mảng) là cấu trúc dữ liệu lưu trữ nhiều giá trị cùng kiểu trong một biến. Rất quan trọng cho việc xử lý historical data, indicator values, và price series.
// Static array (fixed size)
double prices[100]; // Array of 100 doubles
int signals[50]; // Array of 50 integers
string symbols[10]; // Array of 10 strings
// Dynamic array (size can change)
double dynamicPrices[]; // Size = 0 initially
int dynamicSignals[];
string dynamicSymbols[];
// Initialize with values
double fixedPrices[5] = {1.12345, 1.12445, 1.12545, 1.12645, 1.12745};
int weekDays[7] = {1, 2, 3, 4, 5, 6, 7};
double prices[5] = {1.1, 1.2, 1.3, 1.4, 1.5};
// Access by index (0-based)
double first = prices[0]; // 1.1
double second = prices[1]; // 1.2
double last = prices[4]; // 1.5
// Modify element
prices[2] = 1.35; // Change 1.3 to 1.35
// Loop through array
for(int i = 0; i < 5; i++) {
Print("prices[", i, "] = ", prices[i]);
}
// ⚠️ Index out of bounds (no runtime check!)
// double invalid = prices[10]; // Undefined behavior!
// Dynamic array - must resize before use
double dynamicArray[];
// Get current size
int size = ArraySize(dynamicArray); // 0 initially
Print("Size: ", size);
// Resize array
ArrayResize(dynamicArray, 100); // Now has 100 elements
Print("New size: ", ArraySize(dynamicArray)); // 100
// Resize to smaller size
ArrayResize(dynamicArray, 50); // Now has 50 elements
// Fill array with values
for(int i = 0; i < ArraySize(dynamicArray); i++) {
dynamicArray[i] = i * 1.5;
}
// Free array memory
ArrayFree(dynamicArray); // Size becomes 0
// Normal indexing: [0] = oldest, [size-1] = newest
double normalArray[5] = {1.0, 2.0, 3.0, 4.0, 5.0};
Print(normalArray[0]); // 1.0 (first element)
Print(normalArray[4]); // 5.0 (last element)
// As series indexing: [0] = newest, [size-1] = oldest
double seriesArray[];
ArrayResize(seriesArray, 5);
ArraySetAsSeries(seriesArray, true); // Enable series indexing
// Fill with data
for(int i = 0; i < 5; i++) {
seriesArray[i] = (i + 1) * 1.0;
}
// Now: [0] = 5.0, [1] = 4.0, ..., [4] = 1.0
Print(seriesArray[0]); // 5.0 (newest)
Print(seriesArray[4]); // 1.0 (oldest)
// ⚠️ Practical: Price data is always "as series"
double close[];
ArraySetAsSeries(close, true); // Must do this!
CopyClose(_Symbol, PERIOD_CURRENT, 0, 100, close);
// close[0] = current bar, close[1] = previous bar, etc.
// Copy historical prices
double high[], low[], close[], open[];
// Set as series (important!)
ArraySetAsSeries(high, true);
ArraySetAsSeries(low, true);
ArraySetAsSeries(close, true);
ArraySetAsSeries(open, true);
// Copy last 100 bars
int bars = 100;
CopyHigh(_Symbol, PERIOD_CURRENT, 0, bars, high);
CopyLow(_Symbol, PERIOD_CURRENT, 0, bars, low);
CopyClose(_Symbol, PERIOD_CURRENT, 0, bars, close);
CopyOpen(_Symbol, PERIOD_CURRENT, 0, bars, open);
// Access data
Print("Current High: ", high[0]);
Print("Previous High: ", high[1]);
Print("10 bars ago: ", high[10]);
// Calculate highest high in last 20 bars
double highestHigh = high[ArrayMaximum(high, 0, 20)];
Print("Highest High (20 bars): ", highestHigh);
// Calculate lowest low in last 20 bars
double lowestLow = low[ArrayMinimum(low, 0, 20)];
Print("Lowest Low (20 bars): ", lowestLow);
double data[] = {1.5, 3.2, 2.1, 4.8, 1.9, 5.5, 2.7};
// ArraySize: Get array length
int size = ArraySize(data); // 7
// ArrayMaximum: Find index of maximum value
int maxIndex = ArrayMaximum(data); // 5 (value 5.5)
double maxValue = data[maxIndex]; // 5.5
// ArrayMinimum: Find index of minimum value
int minIndex = ArrayMinimum(data); // 0 (value 1.5)
double minValue = data[minIndex]; // 1.5
// ArrayMaximum with range
int maxInRange = ArrayMaximum(data, 2, 3); // Check indices 2,3,4
// Returns 3 (value 4.8 is max in range)
// ArraySort: Sort array
ArraySort(data); // Ascending: 1.5, 1.9, 2.1, 2.7, 3.2, 4.8, 5.5
// ArrayBsearch: Binary search (array must be sorted!)
int index = ArrayBsearch(data, 2.7);
if(index >= 0) {
Print("Found at index: ", index);
}
// ArrayFill: Fill with same value
double filledArray[];
ArrayResize(filledArray, 10);
ArrayFill(filledArray, 0, 10, 1.5); // All elements = 1.5
// ArrayInitialize: Initialize all elements
int intArray[10];
ArrayInitialize(intArray, 0); // All elements = 0
double source[] = {1.0, 2.0, 3.0, 4.0, 5.0};
double destination[];
// Copy entire array
ArrayResize(destination, ArraySize(source));
ArrayCopy(destination, source);
// destination now: {1.0, 2.0, 3.0, 4.0, 5.0}
// Copy partial (start from source index 2, copy 2 elements)
double partial[];
ArrayResize(partial, 2);
ArrayCopy(partial, source, 0, 2, 2); // Copy source[2..3] to partial[0..1]
// partial now: {3.0, 4.0}
// Copy to specific position in destination
double dest[];
ArrayResize(dest, 10);
ArrayCopy(dest, source, 3, 0, ArraySize(source));
// dest[3..7] = source[0..4]
// Calculate Simple Moving Average manually
double CalculateSMA(const double &prices[], int period, int shift) {
// Check if enough data
if(shift + period > ArraySize(prices)) {
return 0;
}
double sum = 0;
for(int i = shift; i < shift + period; i++) {
sum += prices[i];
}
return sum / period;
}
// Calculate custom indicator for all bars
void CalculateCustomIndicator(double &buffer[]) {
double close[];
ArraySetAsSeries(close, true);
ArraySetAsSeries(buffer, true);
int bars = 100;
CopyClose(_Symbol, PERIOD_CURRENT, 0, bars, close);
ArrayResize(buffer, bars);
int period = 20;
for(int i = 0; i < bars - period + 1; i++) {
buffer[i] = CalculateSMA(close, period, i);
}
}
// Usage
void OnTick() {
double customMA[];
CalculateCustomIndicator(customMA);
Print("Custom MA[0]: ", customMA[0]);
Print("Custom MA[1]: ", customMA[1]);
}
// Copy indicator values to array
int maHandle = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_SMA, PRICE_CLOSE);
int rsiHandle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
double maBuffer[], rsiBuffer[];
ArraySetAsSeries(maBuffer, true);
ArraySetAsSeries(rsiBuffer, true);
// Copy last 100 values
CopyBuffer(maHandle, 0, 0, 100, maBuffer);
CopyBuffer(rsiHandle, 0, 0, 100, rsiBuffer);
// Access values
Print("MA[0]: ", maBuffer[0]); // Current bar
Print("MA[1]: ", maBuffer[1]); // Previous bar
Print("RSI[0]: ", rsiBuffer[0]);
// Find MA crossover
for(int i = 1; i < ArraySize(maBuffer) - 1; i++) {
if(maBuffer[i] > maBuffer[i+1] && maBuffer[i-1] <= maBuffer[i]) {
Print("MA crossed up at bar ", i);
break;
}
}
// ❌ SLOW: Resize in loop
double slowArray[];
for(int i = 0; i < 1000; i++) {
ArrayResize(slowArray, i + 1); // Resize every iteration!
slowArray[i] = i * 1.5;
}
// ✅ FAST: Resize once
double fastArray[];
ArrayResize(fastArray, 1000); // Resize once
for(int i = 0; i < 1000; i++) {
fastArray[i] = i * 1.5;
}
// ❌ SLOW: Copy in loop
for(int i = 0; i < 100; i++) {
double close[];
ArraySetAsSeries(close, true);
CopyClose(_Symbol, PERIOD_CURRENT, 0, 100, close); // Copy every time!
}
// ✅ FAST: Copy once, use many times
double close[];
ArraySetAsSeries(close, true);
CopyClose(_Symbol, PERIOD_CURRENT, 0, 100, close); // Copy once
for(int i = 0; i < 100; i++) {
// Use close[i]
}
ArraySetAsSeries(array, true) cho price dataArraySize() trước khi access elementsconst cho array parameters không modify: func(const double &arr[])ArrayFree()double ArraySum(const double &arr[])