mql5/Experts/AILevels backup.mq5
abel324d 7064aa44db
2026-01-12 09:52:49 +03:00

2254 行
166 KiB
MQL5

//given this whole file, what mql5 programming skills does the writer have and what skills does he need to get to a consistently profitable expert advisor??
//+------------------------------------------------------------------+
//| ValueLevelsEA |
//| Copyright 2023, MetaQuotes Software Corp. |
//| https://www.metaquotes.net |
//+------------------------------------------------------------------+
#property strict
#property version "1.4"
// Define session times (in GMT)
#define ASIAN_START_HOUR 1
#define ASIAN_END_HOUR 9
#define LONDON_START_HOUR 8
#define LONDON_END_HOUR 16
#define NY_START_HOUR 13
#define NY_END_HOUR 21
#include <Trade\Trade.mqh>
CTrade trade;
// Define the structure for the neural network
input int PositionsThreshold = 4;
input int Grid_Step = 1400;
int Level_Step = 5;
input double Lots = 1;
int lookbackDays = 16;
int LevelsToCheck = 1400;
input double RiskToReward = 2;
ENUM_TIMEFRAMES LevelsUpdatePeriod = PERIOD_H1;
ENUM_TIMEFRAMES FractalPeriod = PERIOD_H1;
input ENUM_TIMEFRAMES timeframe = PERIOD_M1;
input double SigThresh = 0.1;
input double learningRate = 0.1;
// Variables to store Value Area High and Low for each session
double bid, ask, meanprice;
int bars, bars1;
bool ASFlag, LDFlag, NYFlag;
datetime asianStart;
datetime asianEnd;
datetime londonStart;
datetime londonEnd;
datetime nyStart;
datetime nyEnd;
double HlineArray[], mom[], atr[], obv[], rsi[], opens[], highs[], lows[], closes[];
long tradeVolume[];
int momH, atrH, obvH, rsiH;
MqlRates Bar2[];
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Initialization of the Expert Advisor
atrH = iATR(_Symbol, PERIOD_CURRENT,11);
obvH = iOBV(_Symbol, PERIOD_M15,VOLUME_TICK);
rsiH = iRSI(_Symbol, PERIOD_CURRENT,14,PRICE_MEDIAN);
//momH = iMomentum(_Symbol,PERIOD_H2 ,50,PRICE_MEDIAN);
ArraySetAsSeries(atr,true);
ArraySetAsSeries(mom,true);
//ArraySetAsSeries(inputData,true);
ArraySetAsSeries(opens,true);
ArraySetAsSeries(highs,true);
ArraySetAsSeries(lows,true);
ArraySetAsSeries(closes,true);
ArraySetAsSeries(tradeVolume,true);
Print("Value Area Expert Advisor initialized.");
int totalBars = Bars(_Symbol,timeframe);
CopyOpen(_Symbol,timeframe,0,totalBars,opens);
CopyHigh(_Symbol, timeframe, 0, totalBars, highs);
CopyLow(_Symbol, timeframe, 0, totalBars, lows);
CopyClose(_Symbol, timeframe, 0, totalBars, closes);
CopyTickVolume(_Symbol, timeframe, 0, totalBars, tradeVolume);
// Initialize the neural network
NeuralNetwork nn;
InitializeNeuralNetwork(nn);
double expected_outputs[];
ArrayResize(expected_outputs,totalBars);
for(int i=1;i<totalBars;i++)
{
expected_outputs[i-1] = opens[i] - closes[i];
}
int size = totalBars;
// Create an array of InputData structures
double inputData[][5];
CalculateDifferences(opens, highs, lows, closes, tradeVolume, inputData, size);
// Initialize the neural network
InitializeNeuralNetwork(nn);
// Prepare input data for training
double inputs[][5];
ArrayResize(inputs,size);
for(int i = 0; i < size-1; i++)
{
inputs[i][0] = inputData[i][0];
inputs[i][1] = inputData[i][1];
inputs[i][2] = inputData[i][2];
inputs[i][3] = inputData[i][3];
inputs[i][4] = (double)inputData[i][4];
}
// Example expected outputs for training (this should be your target values)
// Train the neural network
int epochs = 10000;
Train(nn, inputs, expected_outputs, epochs, learningRate);
// Predict using the trained network
double hidden_layer[5];
double output;
double result = Predict(nn, inputs, output, hidden_layer);
Print("Prediction: ", result);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Deinitialization of the Expert Advisor
Print("Value Area Expert Advisor deinitialized.");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Calculate value areas for each session
datetime currentTime = TimeCurrent();
asianStart = currentTime - (currentTime % 86400) + ASIAN_START_HOUR * 3600;
asianEnd = currentTime - (currentTime % 86400) + ASIAN_END_HOUR * 3600;
londonStart = currentTime - (currentTime % 86400) + LONDON_START_HOUR * 3600;
londonEnd = currentTime - (currentTime % 86400) + LONDON_END_HOUR * 3600;
nyStart = currentTime - (currentTime % 86400) + NY_START_HOUR * 3600;
nyEnd = currentTime - (currentTime % 86400) + NY_END_HOUR * 3600;
if(bars < Bars(_Symbol, timeframe))
{
int totalBars = Bars(_Symbol,timeframe);
CopyHigh(_Symbol, timeframe, 0, totalBars, highs);
CopyOpen(_Symbol, timeframe, 0, totalBars, opens);
CopyLow(_Symbol, timeframe, 0, totalBars, lows);
CopyClose(_Symbol, timeframe, 0, totalBars, closes);
CopyTickVolume(_Symbol, timeframe, 0, totalBars, tradeVolume);
//copy time and extract the day of the week, month, hour and minute and add them to their respective arrays just like open, high low and close are added above
// Create an array of InputData structures
double inputData[][5];
CalculateDifferences(opens, highs, lows, closes, tradeVolume, inputData, totalBars);
// Initialize the neural network
NeuralNetwork nn;
InitializeNeuralNetwork(nn);
// Prepare input data for training
double inputs[][5];
ArrayResize(inputs,totalBars);
for(int i = 0; i < totalBars-1; i++)
{
inputs[i][0] = inputData[i][0];
inputs[i][1] = inputData[i][1];
inputs[i][2] = inputData[i][2];
inputs[i][3] = inputData[i][3];
inputs[i][4] = (double)inputData[i][4];
}
double expected_outputs[];
ArrayResize(expected_outputs,totalBars);
for(int i=1;i<totalBars;i++)
{
expected_outputs[i-1] = opens[i] - closes[i];
}
//Example expected outputs for training (this should be your target values)
int epochs = 1000;
Train(nn, inputs, expected_outputs, epochs, learningRate);
// Train the neural network
// Predict using the trained network
double hidden_layer[5];
double output;
double result = Predict(nn, inputs, output, hidden_layer);
Print("Prediction: ", result);
ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
meanprice = (ask+bid)/2;
if(IsMarketOpen())
{
CopyBuffer(atrH,0,0,10,atr);
// Define lookback period in hours and level step in points
double levelStep = _Point*Level_Step;
datetime timeStart = asianStart;
datetime timeEnd = nyEnd;
// Declare arrays to store volume and price levels
double volumeArray[];
double priceLevelArray[];
CalculateVolumeDistribution(lookbackDays,levelStep,timeStart,timeEnd,volumeArray,priceLevelArray);
for(int i = 0; i < ArraySize(volumeArray); i++)
{
//Print("Level: ", priceLevelArray[i], " Volume: ", volumeArray[i], " Index: ", i);
}
// Calculate the volume distribution
if(currentTime > timeStart && currentTime < timeEnd)
{
int peaks[];
int peak_count = ArrayPeaks(volumeArray, peaks, levelStep);
//Print("Number of modes found: ", peak_count);
ArrayResize(HlineArray, peak_count);
double lastHigh = -DBL_MAX;
double lastLow = DBL_MAX;
FindLastHighLow(5,lookbackDays, LevelsUpdatePeriod, lastHigh, lastLow);
DrawTwoHorizontalLines(lastHigh,lastLow,clrRed,clrRed,STYLE_DASHDOT,1, "lastHighLow");
double vaHigh = -DBL_MAX;
double vaLow = DBL_MAX;
CalculateValueArea(priceLevelArray, volumeArray,vaHigh,vaLow, 50.0);
DrawTwoHorizontalLines(vaHigh,vaLow,clrBlue, clrGreen, STYLE_DASHDOT,1, "VAHighLow");
double buyVolume = Lots * (1+BuyPositionsCount());
double sellVolume = Lots * (1+SellPositionsCount());
//double buyStop = lastHigh;
//double sellStop = lastLow;
double buySL = ask - atr[0]*RiskToReward;
double buyTP = ask + atr[0];
double sellSL = bid + atr[0]*RiskToReward;
double sellTP = bid - atr[0];
if(!OtherBuyPosition() && !OtherSellPosition()
&& PositionsTotal() < PositionsThreshold
&& CheckMoneyForTrade(_Symbol,buyVolume,ORDER_TYPE_BUY)
&& atr[0] > SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL)
&& result > 1-SigThresh-SigThresh
&& result < 1-SigThresh
)
{
//trade.BuyLimit(Volume,GetLowestVAL(),_Symbol,GetLowestVAL() - atr,GetHighestVAH(),0,0,"VALAsian");
//trade.BuyStop(Volume,buyStop,_Symbol,buySL,buyTP,0,0,NULL);
trade.Buy(buyVolume,_Symbol,0,buySL,buyTP,NULL);
}
if(!OtherBuyPosition() && !OtherSellPosition()
&& PositionsTotal() < PositionsThreshold
&& CheckMoneyForTrade(_Symbol,sellVolume,ORDER_TYPE_SELL)
&& atr[0] > SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL)
&& result > SigThresh
&& result < SigThresh+SigThresh
)
{
//trade.SellLimit(Volume,GetHighestVAH(),_Symbol,GetHighestVAH() + atr,GetLowestVAL(),0,0,"VAHNY");
//trade.SellStop(Volume,sellStop,_Symbol,sellSL,sellTP,0,0,NULL);
trade.Sell(sellVolume,_Symbol,0,sellSL,sellTP,NULL);
}
TrailingSL();
//CloseWinning();
}
bars = Bars(_Symbol,timeframe);
}
}
}
//+------------------------------------------------------------------+
//| Trade transaction handler |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction &trans, const MqlTradeRequest &request, const MqlTradeResult &result)
{
// Check if the transaction is a deal and if it's a pending order activation
if(trans.type == TRADE_TRANSACTION_DEAL_ADD &&(trans.deal_type == DEAL_TYPE_BUY || trans.deal_type == DEAL_TYPE_SELL))
{
// Get the order ticket of the executed order
ulong executedOrderTicket = trans.order;
// Cancel other pending orders
CancelOtherPendingOrders(executedOrderTicket);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// define a function that takes an array and normalizes the values from 0 to 1
// To create a function in MQL5 that normalizes the values of an array from 0 to 1, you can follow these steps. The normalization process involves scaling the values so that the minimum value of the array becomes 0 and the maximum value becomes 1. Here's how you can implement this:
//
//+------------------------------------------------------------------+
//| Function to normalize an array's values to the range [0, 1] |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void NormalizeArrayTo01(double &array[][5])
{
int arraySize = ArrayRange(array,0);
if(arraySize <= 0)
return; // Check if the array size is valid
// Find the minimum and maximum values in the array
for(int j=0;j<5;j++)
{
double minValue = array[0][j];
double maxValue = array[0][j];
for(int i = 0; i < arraySize-1; i++)
{
if(array[i][j] < minValue)
minValue = array[i][j];
if(array[i][j] > maxValue)
maxValue = array[i][j];
}
// Calculate the range
double range = maxValue - minValue;
// Normalize the array values
for(int i = 0; i < arraySize; i++)
{
if(range != 0) // Avoid division by zero
array[i][j] = (array[i][j] - minValue) / range;
else
array[i][j] = 0; // If all values are the same, set them to zero after normalization
}
}
}
//
// ### Explanation:
// 1. **Parameters:**
// - The `NormalizeArrayTo01` function takes a reference to a double array and its size. The reference allows the function to modify the array in place.
//
// 2. **Finding Min and Max:**
// - The function first finds the minimum and maximum values in the array, which are necessary for the normalization formula.
//
// 3. **Normalization:**
// - It computes the range (difference between the max and min values). Each element is then transformed using the formula: \((\text{value} - \text{minValue}) / \text{range}\).
//
// 4. **Edge Case Handling:**
// - If all elements in the array are the same, the range will be 0, which would cause division by zero. In this case, it sets all normalized values to 0.
//
// 5. **Example Usage:**
// - The `OnStart` function demonstrates how to use the normalization function with an example array.
//
// This code will print the original and normalized array to the output, showing the transformation of the data.
//
//// Define a structure for the input data
//struct InputData {
// double highDiff;
// double lowDiff;
// double closeDiff;
// long volumeDiff;
//};
struct NeuralNetwork
{
double input_to_hidden_weights[5][5]; // Weights from input layer to hidden layer
double hidden_biases[5]; // Biases for hidden layer
double hidden_to_output_weights[5]; // Weights from hidden layer to output layer
double output_bias; // Bias for output layer
};
// Function to calculate differences
void CalculateDifferences(double &open[], double &high[], double &low[], double &close[], long &volume[], double &inputData[][5], int size)
{
ArrayResize(inputData, size);
for(int i = 0; i < size-1; i++)
{
inputData[i][3] = open[i+1] - open[i];
inputData[i][0] = high[i+1] - high[i];
inputData[i][1] = low[i+1] - low[i];
inputData[i][2] = close[i+1] - close[i];
inputData[i][4] = (double) volume[i+1] - volume[i];
}
NormalizeArrayTo01(inputData);
}
// Function to initialize the neural network with random weights and biases
void InitializeNeuralNetwork(NeuralNetwork &nn)
{
for(int i = 0; i < 5; i++)
{
for(int j = 0; j < 5; j++)
{
nn.input_to_hidden_weights[i][j] = MathRand() / 32767.0 * 2.0 - 1.0; // Random values between -1 and 1
}
nn.hidden_biases[i] = MathRand() / 32767.0 * 2.0 - 1.0; // Random values between -1 and 1
nn.hidden_to_output_weights[i] = MathRand() / 32767.0 * 2.0 - 1.0; // Random values between -1 and 1
}
nn.output_bias = MathRand() / 32767.0 * 2.0 - 1.0; // Random value between -1 and 1
}
// Activation function (e.g., sigmoid)
double Sigmoid(double x)
{
return 1.0 / (1.0 + MathExp(-x));
}
// Derivative of the sigmoid function
double SigmoidDerivative(double x)
{
return x * (1.0 - x);
}
// Forward pass for prediction
double Predict(NeuralNetwork &nn, double &inputs[][5], double &output, double &hidden_layer[])
{
// Calculate hidden layer activations
for(int i = 0; i < 5; i++)
{
hidden_layer[i] = 0.0;
for(int j = 0; j < 5; j++)
{
hidden_layer[i] += inputs[i][j] * nn.input_to_hidden_weights[j][i];
}
hidden_layer[i] += nn.hidden_biases[i];
hidden_layer[i] = Sigmoid(hidden_layer[i]); // Apply activation function
}
// Calculate output layer activation
output = 0.0;
for(int i = 0; i < 5; i++)
{
output += hidden_layer[i] * nn.hidden_to_output_weights[i];
}
output += nn.output_bias;
output = Sigmoid(output); // Apply activation function
// Return the final output
return output;
}
// Train the network using backpropagation
void Train(NeuralNetwork &nn, double &inputs[][5], double &expected_outputs[], int epochs, double learning_rate)
{
int num_samples = 0;
for(int epoch = 0; epoch < epochs; epoch++)
{
for(int sample = 0; sample < num_samples; sample++)
{
double hidden_layer[5];
double output = 0;
// Forward pass
double predicted = Predict(nn, inputs, output, hidden_layer);
// Calculate the error
double error = expected_outputs[sample] - predicted;
double d_output = error * SigmoidDerivative(output);
// Backpropagation
double d_hidden[5];
for(int i = 0; i < 5; i++)
{
d_hidden[i] = d_output * nn.hidden_to_output_weights[i] * SigmoidDerivative(hidden_layer[i]);
}
// Update the weights and biases
for(int i = 0; i < 5; i++)
{
nn.hidden_to_output_weights[i] += learning_rate * d_output * hidden_layer[i];
}
nn.output_bias += learning_rate * d_output;
for(int i = 0; i < 5; i++)
{
for(int j = 0; j < 5; j++)
{
nn.input_to_hidden_weights[j][i] += learning_rate * d_hidden[i] * inputs[sample][j];
}
nn.hidden_biases[i] += learning_rate * d_hidden[i];
}
}
}
}
// use the InputData structure for training and prediction.
// The given code defines a simple neural network in MQL5 for processing financial data, specifically designed to work with differences in high, low, close prices, and volume. Here's how you can use the `InputData` structure for training and prediction:
//
// ### Step-by-step Guide:
//
// 1. **Calculate Differences:**
// - Use the `CalculateDifferences` function to preprocess your price and volume data into differences. This will populate an array of `InputData` structures.
//
// 2. **Initialize the Neural Network:**
// - Call `InitializeNeuralNetwork` to set up the neural network with random weights and biases.
//
// 3. **Prepare Training Data:**
// - Organize your `InputData` into an array that can be fed into the neural network. You'll need to extract the `highDiff`, `lowDiff`, `closeDiff`, and `volumeDiff` into a 2D array suitable for the `Train` function.
//
// 4. **Train the Neural Network:**
// - Use the `Train` function to train the neural network. You'll need to define the number of epochs and the learning rate. Also, set up the expected outputs for your samples.
//
// 5. **Make Predictions:**
// - Use the `Predict` function to obtain predictions from the neural network once it's trained.
//
// ### Example Implementation:
//
// Below is an example to illustrate how you might set up your data and use the neural network functions:
//
// Example usage
// ### Explanation:
// - **Data Preparation:** We calculate differences using `CalculateDifferences` and store them in `InputData`.
// - **Neural Network Initialization:** Random weights and biases are set up using `InitializeNeuralNetwork`.
// - **Training:** The `Train` function adjusts the weights using backpropagation.
// - **Prediction:** The `Predict` function provides an output based on the neural network's current state.
//
// Ensure that you have your expected outputs correctly defined based on the problem you're trying to solve. The neural network's performance will depend significantly on the quality and nature of your data and expected outputs.
//
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Function to cancel other pending orders |
//+------------------------------------------------------------------+
void CancelOtherPendingOrders(ulong executedOrderTicket)
{
// Loop through all orders
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
// Select the order by index
if(OrderSelect(OrderGetTicket(i)))
{
// Check if the order is a pending order and not the executed one
if((OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_LIMIT || OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_LIMIT ||
OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP || OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_STOP) &&
OrderGetInteger(ORDER_TICKET) != executedOrderTicket
)
{
// Prepare a request to delete the order
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_REMOVE;
request.order = OrderGetInteger(ORDER_TICKET);
// Send the request
if(!OrderSend(request, result))
{
//Print("Failed to cancel order: ", result.comment);
}
}
}
}
}
//+------------------------------------------------------------------+
//| Identifying fractal levels maxima/minima within n bars |
//| |
//+------------------------------------------------------------------+
/// Global arrays to store fractal highs and lows
double fractalHighs[];
double fractalLows[];
double fractalHighsTime[];
double fractalLowsTime[];
int fractalHighsIndex[];
int fractalLowsIndex[];
MqlRates Bar3[];
//Function to identify fractal bars and store their levels
void IdentifyFractalLevels(int period, int n, ENUM_TIMEFRAMES TF)
{
// Ensure the period is valid
if(period < n)
{
//Print("Period must be at least ", n);
return;
}
// Resize arrays to the specified period
double highs[];
double lows[];
ArrayResize(highs, period);
ArrayResize(lows, period);
// Copy high and low prices for the given period
if(CopyHigh(_Symbol, TF, 0, period, highs) <= 0 || CopyLow(_Symbol, TF, 0, period, lows) <= 0) // || CopyTime(_Symbol, TF, 0, period, time) <= 0)
{
//Print("Failed to copy price data.");
return;
}
if(CopyRates(_Symbol, TF, 0, period, Bar3) <= 0)
{
//Print("Failed to copy rates");
return;
}
// Clear previous fractal data
ArrayResize(fractalHighs, 0);
ArrayResize(fractalLows, 0);
ArrayResize(fractalHighsTime, 0);
ArrayResize(fractalLowsTime, 0);
ArrayResize(fractalHighsIndex,0);
ArrayResize(fractalLowsIndex,0);
// Adjust the loop to find local maxima and minima for n bars around the highest/lowest bar
for(int i = n; i < period - n; i++)
{
bool isLocalMax = true;
bool isLocalMin = true;
// Check for local maximum
for(int j = 1; j <= n; j++)
{
if(highs[i] <= highs[i + j] || highs[i] <= highs[i - j])
{
isLocalMax = false;
break;
}
}
if(isLocalMax)
{
ArrayResize(fractalHighs, ArraySize(fractalHighs) + 1);
fractalHighs[ArraySize(fractalHighs) - 1] = highs[i];
ArrayResize(fractalHighsTime, ArraySize(fractalHighsTime) + 1);
fractalHighsTime[ArraySize(fractalHighsTime) - 1] = (double) Bar3[i].time;
ArrayResize(fractalHighsIndex, ArraySize(fractalHighsIndex) + 1);
fractalHighsIndex[ArraySize(fractalHighsIndex) - 1] = i;
DrawArrow(highs[i],i,"top", clrRed);
}
// Check for local minimum
for(int j = 1; j <= n; j++)
{
if(lows[i] >= lows[i + j] || lows[i] >= lows[i - j])
{
isLocalMin = false;
break;
}
}
if(isLocalMin)
{
ArrayResize(fractalLows, ArraySize(fractalLows) + 1);
fractalLows[ArraySize(fractalLows) - 1] = lows[i];
ArrayResize(fractalLowsTime, ArraySize(fractalLowsTime) + 1);
fractalLowsTime[ArraySize(fractalLowsTime) - 1] = (double) Bar3[i].time;
ArrayResize(fractalLowsIndex, ArraySize(fractalLowsIndex) + 1);
fractalLowsIndex[ArraySize(fractalLowsIndex) - 1] = i;
DrawArrow(lows[i],i,"bottom", clrRed);
}
}
//Print the fractal highs and lows for debugging
for(int i = 0; i < ArraySize(fractalHighs); i++)
{
//Print("Fractal High at index ", i, ": ", fractalHighs[i]);
}
for(int i = 0; i < ArraySize(fractalLows); i++)
{
//Print("Fractal Low at index ", i, ": ", fractalLows[i]);
}
}
//draw arrows either above or below bars given arguments: price level, index, arrow position(top, bottom), arrow code, arrow color
//
// To draw arrows on a chart in MQL5, you can use the `ObjectCreate` and `ObjectSetInteger` functions to create and customize the arrow objects. Below is a sample code snippet that demonstrates how to draw arrows either above or below bars on a chart based on the given arguments: price level, index, arrow position (top, bottom), arrow code, and arrow color.
//
// Function to draw an arrow on the chart
void DrawArrow(double priceLevel, int index, string arrowPosition, color arrowColor)
{
// Create a unique name for the arrow object
string arrowName = "Arrow_" + IntegerToString(index) + "_" + arrowPosition;
int arrowCode = 0;
// Determine the y-coordinate for the arrow based on the position (top or bottom)
double yCoordinate = priceLevel;
if(arrowPosition == "top")
{
// Place the arrow above the bar
yCoordinate += 10 * Point(); // Adjust the multiplier as needed
arrowCode = 233;
}
else
if(arrowPosition == "bottom")
{
// Place the arrow below the bar
yCoordinate -= 10 * Point(); // Adjust the multiplier as needed
arrowCode = 234;
}
// Create the arrow object
if(!ObjectCreate(0, arrowName, OBJ_ARROW, 0,index, yCoordinate))
{
//Print("Failed to create arrow object: ", arrowName);
return;
}
// Set the properties of the arrow
ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, arrowCode);
ObjectSetInteger(0, arrowName, OBJPROP_COLOR, arrowColor);
ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 1); // Set the width of the arrow
ObjectSetInteger(0, arrowName, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, arrowName, OBJPROP_HIDDEN, true);
ObjectSetInteger(0, arrowName, OBJPROP_ZORDER, 0);
}
//+------------------------------------------------------------------+
//| Draw Arrows at level - time coordinates | |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void DrawArrowsAtLevels(double &levels[], int &barIndexes[], int arrowCode, color arrowColor)
{
// Ensure the levels and barIndexes arrays have the same size
int size = ArraySize(levels);
if(size != ArraySize(barIndexes))
{
//Print("Error: The levels and barIndexes arrays must have the same size.");
return;
}
// Loop through each level and draw an arrow
for(int i = 0; i < size; i++)
{
// Create a unique name for each arrow object
string arrowName = "Arrow_" + ColorToString(arrowColor) + IntegerToString(i);
// Check if the object already exists and delete it if it does
if(ObjectFind(0, arrowName) != -1)
{
ObjectDelete(0, arrowName);
}
// Create the arrow object
if(!ObjectCreate(0, arrowName, OBJ_ARROW, 0,iTime(_Symbol,PERIOD_CURRENT,barIndexes[i]),levels[i]))
{
//Print("Error creating arrow object: ", arrowName);
continue;
}
// Set the properties of the arrow
ObjectSetInteger(0, arrowName, OBJPROP_COLOR, arrowColor);
ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, arrowCode);
ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 1); // Set the width of the arrow
}
}
//-----------------------------------------------------------------------+
// Function to determine the trend based on fractal highs and lows |
//-----------------------------------------------------------------------+
string CheckFractalTrend(int n)
{
// Ensure there are enough data points to analyze
if(ArraySize(fractalHighs) < 2 || ArraySize(fractalLows) < 2)
{
//Print("Not enough fractal data to determine trend.");
return "Not enough fractal data to determine trend.";
}
// Initialize flags for trend detection
bool higherHighs = false;
bool lowerLows = false;
bool higherLows = false;
bool lowerHighs = false;
// modify to Check only the last n values from fractal highs and lows
// To modify the code to check only the last `n` values from fractal highs and lows, you need to iterate over the last `n` elements of the `fractalHighs` and `fractalLows` arrays. You can achieve this by using a loop that starts from the end of the array and goes back `n` elements. Here's how you can modify your code:
//
// Define the number of last values to check
// Check the last n values for fractal highs
for(int i = ArraySize(fractalHighs) - 1; i >= ArraySize(fractalHighs) - n; i--)
{
if(i <= 0)
break; // Ensure we don't go out of bounds
if(fractalHighs[i] < fractalHighs[i - 1])
{
higherHighs = false;
break;
}
}
// Check the last n values for fractal lows
for(int i = ArraySize(fractalLows) - 1; i >= ArraySize(fractalLows) - n; i--)
{
if(i <= 0)
break; // Ensure we don't go out of bounds
if(fractalLows[i] > fractalLows[i - 1])
{
lowerLows = false;
break;
}
}
// Now higherHighs and lowerLows will reflect the result of checking the last n values
//
// ### Explanation:
// - **Loop Setup**: The loops iterate from the last element of the array to the element `n` positions back. This ensures that only the last `n` elements are checked.
// - **Boundary Check**: The `if(i <= 0) break;` statement ensures that the loop does not attempt to access an element before the start of the array, which would cause an out-of-bounds error.
// - **Condition Check**: The conditions inside the loops check if the current element is less than or greater than the previous one, updating the `higherHighs` and `lowerLows` flags accordingly.
// - **Flags**: The `higherHighs` and `lowerLows` flags are set to `true` initially and are only set to `false` if a condition is not met during the iteration. This means that if all conditions are met, the flags remain `true`.
//
// Determine and print the trend
if(higherHighs && lowerLows)
{
//Print("The fractals are making undefined moves (notrend).");
Comment("Notrend");
return "undefined";
}
else
if(higherHighs)
{
//Print("The fractals are making higher highs (uptrend).");
Comment("BULL");
return "Bullish";
}
else
if(lowerLows)
{
//Print("The fractals are making lower lows (downtrend).");
Comment("Bear");
return "Bearish";
}
else
{
//Print("The fractals do not show a clear trend.");
Comment("???");
return "The fractals do not show a clear trend.";
}
}
//+------------------------------------------------------------------+
//| Function to calculate the moving average of n elements |
//| from a time series array |
//+------------------------------------------------------------------+
double CalculateMovingAverage(double &modifiedArray[], const double &sourceArray[], int n)
{
int arraySize = ArraySize(sourceArray);
// Check if the period n is valid
if(n <= 0 || n > arraySize)
{
//Print("Invalid period for moving average calculation.");
return 0;
}
// Initialize the modifiedArray with the same size as sourceArray
ArrayResize(modifiedArray, arraySize);
// Calculate the moving average
for(int i = 0; i < arraySize; i++)
{
double sum = 0;
int count = 0;
// Sum up the n elements
for(int j = i; j > i - n && j >= 0; j--)
{
sum += sourceArray[j];
count++;
}
// Calculate the average
modifiedArray[i] = sum / count;
}
return 1; // Return 1 to indicate successful calculation
}
//+------------------------------------------------------------------+
//| Function to find the last highest high and lowest low |
//| on a specified timeframe. |
//| Parameters: |
//| n - Number of bars around the high/low to consider |
//| timeframe - The timeframe to use for the calculation |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void FindLastHighLow(int n, int kDays, ENUM_TIMEFRAMES timefram, double &lastHigh, double &lastLow)
{
// Ensure 'n' and 'kDays' are positive numbers
if(n <= 0 || kDays <= 0)
{
//Print("Error: 'n' and 'kDays' must be greater than 0.");
return;
}
// Initialize variables to store the last highest high and lowest low
lastHigh = -DBL_MAX;
lastLow = DBL_MAX;
// Get the total number of bars on the specified timeframe
int totalBars = Bars(_Symbol, timefram);
// Calculate the number of bars in one day for the given timeframe
int barsPerDay = 0;
switch(timeframe)
{
case PERIOD_M1:
barsPerDay = 1440;
break;
case PERIOD_M2:
barsPerDay = 720;
break;
case PERIOD_M3:
barsPerDay = 480;
break;
case PERIOD_M4:
barsPerDay = 360;
break;
case PERIOD_M5:
barsPerDay = 288;
break;
case PERIOD_M6:
barsPerDay = 240;
break;
case PERIOD_M10:
barsPerDay = 144;
break;
case PERIOD_M12:
barsPerDay = 120;
break;
case PERIOD_M15:
barsPerDay = 96;
break;
case PERIOD_M20:
barsPerDay = 72;
break;
case PERIOD_M30:
barsPerDay = 48;
break;
case PERIOD_H1:
barsPerDay = 24;
break;
case PERIOD_H2:
barsPerDay = 12;
break;
case PERIOD_H3:
barsPerDay = 8;
break;
case PERIOD_H4:
barsPerDay = 6;
break;
case PERIOD_H6:
barsPerDay = 4;
break;
case PERIOD_H8:
barsPerDay = 3;
break;
case PERIOD_H12:
barsPerDay = 2;
break;
case PERIOD_D1:
barsPerDay = 1;
break;
default:
//Print("Error: Unsupported timeframe.");
return;
}
// Calculate the number of bars to look back
int barsToLookBack = kDays * barsPerDay;
// Ensure 'barsToLookBack' does not exceed the total number of bars
if(barsToLookBack > totalBars)
{
//Print("Error: 'kDays' exceeds the total number of days available in bars.");
return;
}
// Loop through the last 'barsToLookBack' bars, starting from the most recent
for(int i = 0; i < barsToLookBack; i++)
{
bool isHighest = true;
bool isLowest = true;
// Check the 'n' bars around the current bar
for(int j = 1; j <= n; j++)
{
if(i - j >= 0 && i + j < totalBars)
{
if(iHigh(_Symbol, timefram, i) <= iHigh(_Symbol, timefram, i - j) ||
iHigh(_Symbol, timefram, i) <= iHigh(_Symbol, timefram, i + j))
{
isHighest = false;
}
if(iLow(_Symbol, timefram, i) >= iLow(_Symbol, timefram, i - j) ||
iLow(_Symbol, timefram, i) >= iLow(_Symbol, timefram, i + j))
{
isLowest = false;
}
}
// If both conditions are false, break early
if(!isHighest && !isLowest)
break;
}
// Update the last highest high and lowest low if conditions are met
if(isHighest && iHigh(_Symbol, timefram, i) > lastHigh)
{
lastHigh = iHigh(_Symbol, timefram, i);
}
if(isLowest && iLow(_Symbol, timefram, i) < lastLow)
{
lastLow = iLow(_Symbol, timefram, i);
}
}
}
//+------------------------------------------------------------------+
//| Function to calculate differences between consecutive elements |
//+------------------------------------------------------------------+
void DifferencesArray(const double &inputArray[], double &outputArray[])
{
int inputSize = ArraySize(inputArray);
// Ensure the output array has the correct size (one less than the input array)
ArrayResize(outputArray, inputSize - 1);
// Calculate the differences
for(int i = 0; i < inputSize - 1; i++)
{
outputArray[i] = inputArray[i] - inputArray[i+1];
}
}
//+------------------------------------------------------------------+
//| Function to draw horizontal lines at specified price levels |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void DrawHorizontalLines(double &priceLevels[], color lineColor = clrRed, int lineStyle = STYLE_SOLID, int lineWidth = 1)
{
int arraySize = ArraySize(priceLevels);
//Print("Array Size: ", arraySize); // Debugging: Print the size of the array
// Clear existing horizontal lines with the naming pattern "HL_"
for(int i = ObjectsTotal(0) - 1; i >= 0; i--)
{
string name = ObjectName(0,i);
if(StringFind(name, "HL_") == 0) // If the name starts with "HL_"
{
ObjectDelete(0, name);
}
}
for(int i = 0; i < arraySize; i++)
{
// Normalize the price level
double normalizedPrice = NormalizeDouble(priceLevels[i], _Digits);
// Create a unique name for each line
string lineName = ("HL_" + DoubleToString(normalizedPrice, _Digits));
// Check if the line already exists, if not, create it
if(ObjectFind(0, lineName) == -1)
{
// Create a horizontal line
if(ObjectCreate(0, lineName, OBJ_HLINE, 0, 0, normalizedPrice))
{
//Print("Created line: ", lineName, " at price level: ", normalizedPrice); // Debugging: Confirm line creation
// Set line properties
ObjectSetInteger(0, lineName, OBJPROP_COLOR, lineColor);
ObjectSetInteger(0, lineName, OBJPROP_STYLE, lineStyle);
ObjectSetInteger(0, lineName, OBJPROP_WIDTH, lineWidth);
ObjectSetDouble(0, lineName, OBJPROP_PRICE, normalizedPrice);
}
else
{
int errorcode = GetLastError();
//Print("Failed to create line: ", lineName, " Error: ", errorcode);
continue;
}
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void DrawTwoHorizontalLines(double priceLevel1, double priceLevel2, color lineColor1 = clrBlue, color lineColor2 = clrGreen, int lineStyle = STYLE_SOLID, int lineWidth = 1, string comment = NULL)
{
// Normalize the price levels
double normalizedPrice1 = NormalizeDouble(priceLevel1, _Digits);
double normalizedPrice2 = NormalizeDouble(priceLevel2, _Digits);
// Clear existing horizontal lines with the naming pattern "HL_"
for(int i = ObjectsTotal(0) - 1; i >= 0; i--)
{
string name = ObjectName(0, i);
if(StringFind(name, "HL__") == 0) // If the name starts with "HL_"
{
ObjectDelete(0, name);
}
}
// Create a unique name for each line
string lineName1 = "HL__Below" + comment;
string lineName2 = "HL__Above" + comment;
// Check if the first line already exists, if not, create it
if(ObjectFind(0, lineName1) == -1)
{
if(ObjectCreate(0, lineName1, OBJ_HLINE, 0, 0, normalizedPrice1))
{
//Print("Created line: ", lineName1, " at price level: ", normalizedPrice1); // Debugging: Confirm line creation
// Set line properties
ObjectSetInteger(0, lineName1, OBJPROP_COLOR, lineColor1);
ObjectSetInteger(0, lineName1, OBJPROP_STYLE, lineStyle);
ObjectSetInteger(0, lineName1, OBJPROP_WIDTH, lineWidth);
ObjectSetDouble(0, lineName1, OBJPROP_PRICE, normalizedPrice1);
}
else
{
int errorcode = GetLastError();
//Print("Failed to create line: ", lineName1, " Error: ", errorcode);
}
}
// Check if the second line already exists, if not, create it
if(ObjectFind(0, lineName2) == -1)
{
if(ObjectCreate(0, lineName2, OBJ_HLINE, 0, 0, normalizedPrice2))
{
//Print("Created line: ", lineName2, " at price level: ", normalizedPrice2); // Debugging: Confirm line creation
// Set line properties
ObjectSetInteger(0, lineName2, OBJPROP_COLOR, lineColor2);
ObjectSetInteger(0, lineName2, OBJPROP_STYLE, lineStyle);
ObjectSetInteger(0, lineName2, OBJPROP_WIDTH, lineWidth);
ObjectSetDouble(0, lineName2, OBJPROP_PRICE, normalizedPrice2);
}
else
{
int errorcode = GetLastError();
Print("Failed to create line: ", lineName2, " Error: ", errorcode);
}
}
}
//+------------------------------------------------------------------+
//| Function to find indices where a given value is between two |
//| consecutive elements in a double array |
//+------------------------------------------------------------------+
int FindIndices(double value, double &arr[], int &index1, int &index2)
{
int size = ArraySize(arr);
// Check if the array has at least two elements
if(size < 2)
{
Print("Array must have at least two elements.");
// return -1; // Return -1 to indicate an error
}
// Iterate through the array to find the indices
for(int i = 0; i < size - 1; i++)
{
if((value > arr[i] && value < arr[i+1]) || (value < arr[i] && value > arr[i+1]))
{
index1 = i;
index2 = i + 1;
return 0; // Return 0 to indicate success
}
}
// If no such indices are found
Print("No indices found where the value is between two consecutive elements.");
return -1; // Return -1 to indicate failure
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int ArrayPeaks(const double &array[], int &peaks[], double min_distance)
{
int array_size = ArraySize(array);
if(array_size < LevelsToCheck)
return 0; // Return 0 if the array is too small to have peaks
int peak_count = 0;
ArrayResize(peaks, array_size); // Resize peaks array to the maximum possible size initially
// Iterate through the array to find peaks
for(int i = (int)(LevelsToCheck/2); i < array_size - (int)(LevelsToCheck/2); i++) // Start from level index and end at array_size - level index
{
bool is_peak = true;
// Check if the current element is greater than the elements in the range of indices around it
for(int j = i - (int)(LevelsToCheck/2); j <= i + (int)(LevelsToCheck/2); j++)
{
if(j != i && array[i] <= array[j])
{
is_peak = false;
break;
}
}
if(is_peak)
{
bool is_far_enough = true;
for(int j = 0; j < peak_count; j++)
{
if(MathAbs(i - peaks[j]) < min_distance)
{
is_far_enough = false;
break;
}
}
if(is_far_enough)
{
peaks[peak_count] = i;
peak_count++;
}
}
}
ArrayResize(peaks, peak_count); // Resize peaks array to the actual number of peaks found
return peak_count; // Return the number of peaks found
}
// create a function that is given a price level array and a volume array and finds the high and low levels where 70% (adjustable) of the volume took place aka value area. it modifies two variables valHigh and valLow
// To create a function in MQL5 that calculates the value area where a specified percentage of the volume took place, you can follow these steps. We'll define a function that takes in a price level array, a volume array, and the percentage of volume to consider for the value area. The function will then modify two variables, `valHigh` and `valLow`, to represent the high and low levels of this value area.
//
// Here's a sample implementation:
//
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CalculateValueArea(const double &priceLevels[], const double &volumes[], double &valAreaHigh, double &valAreaLow, double percentage = 70.0)
{
int size = ArraySize(volumes);
if(size <= 0 || size != ArraySize(priceLevels))
{
Print("Array Issue: Price Levels and Volumes don't match or are empty.");
return;
}
// Calculate total volume
double totalVolume = 0.0;
for(int i = 0; i < size; i++)
{
totalVolume += volumes[i];
}
// Target volume for the value area
double targetVolume = totalVolume * (percentage / 100.0);
// Find the POC
int pocIndex = 0;
double maxVolume = volumes[0];
for(int i = 1; i < size; i++)
{
if(volumes[i] > maxVolume)
{
maxVolume = volumes[i];
pocIndex = i;
}
}
// Initialize the value area with the POC
valAreaLow = priceLevels[pocIndex];
valAreaHigh = priceLevels[pocIndex];
double cumulativeVolume = maxVolume;
// Expand the value area around the POC
int leftIndex = pocIndex - 1;
int rightIndex = pocIndex + 1;
while(cumulativeVolume < targetVolume)
{
// Consider both directions and choose the one with larger volume
if(leftIndex >= 0 && (rightIndex >= size || volumes[leftIndex] >= volumes[rightIndex]))
{
cumulativeVolume += volumes[leftIndex];
valAreaLow = priceLevels[leftIndex];
leftIndex--;
}
else
if(rightIndex < size)
{
cumulativeVolume += volumes[rightIndex];
valAreaHigh = priceLevels[rightIndex];
rightIndex++;
}
else
{
// No more price levels to consider
break;
}
}
}
// function to extract hour from TimeCurrent() without using TimeHour()
// In MQL5, if you want to extract the hour from the current time without using the built-in `TimeHour()` function, you can do so by using the `TimeToStruct()` function. This function converts a `datetime` value into a `MqlDateTime` structure, which contains various components of the time, including the hour. Here is how you can implement this:
//
// Function to extract the hour from the current time
int GetHour(datetime time)
{
// Get the current time
// Define a structure to hold the date and time components
MqlDateTime timeStruct;
// Convert the current time into the MqlDateTime structure
TimeToStruct(time, timeStruct);
// Return the hour component from the structure
return timeStruct.hour;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int GetMinute(datetime time)
{
// Get the current time
// Define a structure to hold the date and time components
MqlDateTime timeStruct;
// Convert the current time into the MqlDateTime structure
TimeToStruct(time, timeStruct);
// Return the hour component from the structure
return timeStruct.min;
}
//
// In this example:
//
// - We define a function `GetCurrentHour()` that retrieves the hour from the current server time.
// - We use `TimeCurrent()` to get the current time as a `datetime` value.
// - `MqlDateTime timeStruct;` is defined to hold the date and time components.
// - `TimeToStruct(currentTime, timeStruct);` converts the `datetime` into `MqlDateTime`, populating `timeStruct`.
// - We then simply return `timeStruct.hour` to get the hour component.
//
//+------------------------------------------------------------------+
//| Volume Distributuion |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CalculateVolumeDistribution(int Days, double levelStep, datetime startTime, datetime endTime, double &volumeArray[], double &priceLevelArray[])
{
// Determine the number of bars in a full day
int barsInFullDay = 1440; // 1440 minutes in a day
int barsInDays = Days * barsInFullDay;
// Calculate the number of bars that have elapsed today
datetime currentTime = TimeCurrent();
datetime startOfDay = currentTime - (currentTime % 86400); // Start of the current day
int barsElapsedToday = (int)((currentTime - startOfDay) / 60); // Convert seconds to minutes
// Total lookback bars
int lookbackBars = barsInDays + barsElapsedToday;
// Initialize variables to store the lowest low and highest high
double lowestLow = DBL_MAX;
double highestHigh = -DBL_MAX;
// Arrays to store the data
double lowArray[];
double highArray[];
long volumeArrayRaw[];
datetime timeArray[];
// Copy the data for the specified number of bars
if(CopyLow(_Symbol, PERIOD_M1, 0, lookbackBars, lowArray) <= 0 ||
CopyHigh(_Symbol, PERIOD_M1, 0, lookbackBars, highArray) <= 0 ||
CopyTickVolume(_Symbol, PERIOD_M1, 0, lookbackBars, volumeArrayRaw) <= 0 ||
CopyTime(_Symbol, PERIOD_M1, 0, lookbackBars, timeArray) <= 0)
{
Print("Error copying data");
return;
}
// Convert startTime and endTime to MqlDateTime
MqlDateTime startDT, endDT;
TimeToStruct(startTime, startDT);
TimeToStruct(endTime, endDT);
// Loop through the lookback period to find the lowest low and highest high within the specified interval
for(int i = 0; i < lookbackBars; i++)
{
MqlDateTime currentDT;
TimeToStruct(timeArray[i], currentDT);
// Check if the current time is within the specified time interval
if((currentDT.hour < startDT.hour || (currentDT.hour == startDT.hour && currentDT.min < startDT.min)) ||
(currentDT.hour > endDT.hour || (currentDT.hour == endDT.hour && currentDT.min > endDT.min)))
continue;
double low = lowArray[i];
double high = highArray[i];
if(low < lowestLow)
lowestLow = low;
if(high > highestHigh)
highestHigh = high;
}
//Print("Lowest Level: ", lowestLow);
//Print("Highest Level: ", highestHigh);
// Calculate the number of levels
int numberOfLevels = int((highestHigh - lowestLow) / levelStep) + 1;
// Resize the arrays to hold the data
ArrayResize(volumeArray, numberOfLevels);
ArrayResize(priceLevelArray, numberOfLevels);
// Initialize arrays
for(int i = 0; i < numberOfLevels; i++)
{
volumeArray[i] = 0;
priceLevelArray[i] = lowestLow + i * levelStep;
}
// Aggregate volume for each level within the specified interval
for(int i = 0; i < lookbackBars; i++)
{
MqlDateTime currentDT;
TimeToStruct(timeArray[i], currentDT);
// Check if the current time is within the specified time interval
if((currentDT.hour < startDT.hour || (currentDT.hour == startDT.hour && currentDT.min < startDT.min)) ||
(currentDT.hour > endDT.hour || (currentDT.hour == endDT.hour && currentDT.min > endDT.min)))
continue;
double low = lowArray[i];
double high = highArray[i];
double volume = (double)volumeArrayRaw[i];
// Determine which levels the current bar's range covers
int startLevel = int((low - lowestLow) / levelStep);
int endLevel = int((high - lowestLow) / levelStep);
// Distribute volume across the levels covered by the bar
for(int level = startLevel; level <= endLevel; level++)
{
if(level >= 0 && level < numberOfLevels)
{
volumeArray[level] += volume;
}
}
}
}
//+------------------------------------------------------------------+
//| session flag |
//+------------------------------------------------------------------+
bool Flag(string comment)
{
datetime time = TimeCurrent();
if(time >= asianStart && time <= asianEnd && comment == "AS")
{
return true;
Print("Asian Sesh");
}
if(time >= londonStart && time <= londonEnd && comment == "LD")
{
return true;
Print("London Sesh");
}
if(time >= nyStart && time <= nyEnd && comment == "NY")
{
return true;
Print("NY Sesh");
}
return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int BuyPositionsCount()
{
int Buys = 0;
for(int i = PositionsTotal()-1; i>=0; i--)
{
PositionGetTicket(i);
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && PositionGetString(POSITION_SYMBOL) == _Symbol)
{
Buys++;
}
}
return Buys;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int SellPositionsCount()
{
int Sells = 0;
for(int i = PositionsTotal()-1; i>=0; i--)
{
PositionGetTicket(i);
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && PositionGetString(POSITION_SYMBOL) == _Symbol)
{
Sells++;
}
}
return Sells;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool OtherBuyPosition()
{
bool other = false;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
{
double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
long positionType = PositionGetInteger(POSITION_TYPE);
if(MathAbs(currentPrice - openPrice) < Grid_Step * _Point && positionType == POSITION_TYPE_BUY)
{
other = true;
break;
}
}
}
return other;
}
//write same function for orders instead of positions
//+------------------------------------------------------------------+
// To create a similar function for orders instead of positions in MQL5, you can use the `OrdersTotal()`, `OrderGetTicket()`, and `OrderSelect()` functions. Here's how you can write a function that checks for other buy orders with similar conditions:
//
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool OtherBuyOrder()
{
bool other = false;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
ulong ticket = OrderGetTicket(i);
if(OrderSelect(ticket))
{
double currentPrice = OrderGetDouble(ORDER_PRICE_CURRENT);
double openPrice = OrderGetDouble(ORDER_PRICE_OPEN);
long orderType = OrderGetInteger(ORDER_TYPE);
if(MathAbs(currentPrice - openPrice) < Grid_Step * _Point && orderType == ORDER_TYPE_BUY)
{
other = true;
break;
}
}
}
return other;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool OtherSellPosition()
{
bool other = false;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
{
double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
long positionType = PositionGetInteger(POSITION_TYPE);
if(MathAbs(currentPrice - openPrice) < Grid_Step * _Point && positionType == POSITION_TYPE_SELL)
{
other = true;
break;
}
}
}
return other;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool OtherSellOrder()
{
bool other = false;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
ulong ticket = OrderGetTicket(i);
if(OrderSelect(ticket))
{
double currentPrice = OrderGetDouble(ORDER_PRICE_CURRENT);
double openPrice = OrderGetDouble(ORDER_PRICE_OPEN);
long orderType = OrderGetInteger(ORDER_TYPE);
if(MathAbs(currentPrice - openPrice) < Grid_Step * _Point && orderType == ORDER_TYPE_SELL)
{
other = true;
break;
}
}
}
return other;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CloseWinning()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(PositionSelect(PositionGetSymbol(i)))
{
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double currentPrice = SymbolInfoDouble(PositionGetSymbol(i), SYMBOL_BID);
ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
long ticket = PositionGetInteger(POSITION_TICKET);
if((type == POSITION_TYPE_BUY && currentPrice > openPrice) ||
(type == POSITION_TYPE_SELL && currentPrice < openPrice))
{
trade.PositionClose(ticket);
}
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CloseLosing()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(PositionSelect(PositionGetSymbol(i)))
{
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double currentPrice = SymbolInfoDouble(PositionGetSymbol(i), SYMBOL_BID);
ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
long ticket = PositionGetInteger(POSITION_TICKET);
if((type == POSITION_TYPE_BUY && currentPrice < openPrice) ||
(type == POSITION_TYPE_SELL && currentPrice > openPrice))
{
trade.PositionClose(ticket);
}
}
}
}
// function that cancels other pending orders when one pending order is hit
// In MQL5, you can create a function to cancel other pending orders when one pending order is hit by utilizing the `OnTradeTransaction` event handler. This event is triggered whenever a trade transaction occurs, such as when a pending order is executed. Here's a basic example of how you might implement such a function:
//
//+------------------------------------------------------------------+
//| mean of array |
//+------------------------------------------------------------------+
long ArrayAverage(const long &array[])
{
int size = ArraySize(array);
if(size <= 0)
return 0.0; // Return 0 if the array size is zero or negative
long sum = 0.0;
for(int i = 0; i < size; i++)
{
sum += array[i];
}
return sum / size;
}
//+------------------------------------------------------------------+
//| Update stoploss |
//+------------------------------------------------------------------+
void UpdateTrailingStopLoss(double trailingPoints)
{
// Check if there are any open positions
int totalPositions = PositionsTotal();
if(totalPositions <= 0)
return;
// Get current bid and ask prices
// Loop through all open positions
for(int i = 0; i < totalPositions; i++)
{
// Get position ticket
ulong positionTicket = PositionGetTicket(i);
// Get position details
if(PositionSelectByTicket(positionTicket))
{
double positionPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double positionStopLoss = PositionGetDouble(POSITION_SL);
ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
// Calculate new stop loss based on trailing points
double newStopLoss;
if(positionType == POSITION_TYPE_BUY)
{
newStopLoss = (bid + positionPrice)/2;
if(newStopLoss > positionStopLoss)
{
// Update stop loss for buy position
TradePositionModify(positionTicket, newStopLoss, PositionGetDouble(POSITION_TP));
}
}
else
if(positionType == POSITION_TYPE_SELL)
{
newStopLoss = (ask + positionPrice)/2;
if(newStopLoss < positionStopLoss)
{
// Update stop loss for sell position
TradePositionModify(positionTicket, newStopLoss, PositionGetDouble(POSITION_TP));
}
}
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void TrailingSL()
{
// Check if there are any open positions
int totalPositions = PositionsTotal();
if(totalPositions <= 0)
return;
// Get current bid and ask prices
// Loop through all open positions
for(int i = 0; i < totalPositions; i++)
{
// Get position ticket
ulong positionTicket = PositionGetTicket(i);
// Get position details
if(PositionSelectByTicket(positionTicket))
{
double newStopLoss;
//double newTakeProfit;
ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(positionType == POSITION_TYPE_BUY
//&& bid > Grid_Step*_Point + PositionGetDouble(POSITION_PRICE_OPEN)
&& bid > (PositionGetDouble(POSITION_TP) + PositionGetDouble(POSITION_PRICE_OPEN))/2
&& (bid + PositionGetDouble(POSITION_PRICE_OPEN))/2 > PositionGetDouble(POSITION_SL)
)
{
newStopLoss = (ask + PositionGetDouble(POSITION_PRICE_OPEN))/2;
//newTakeProfit = HlineAbove;
TradePositionModify(positionTicket, newStopLoss, PositionGetDouble(POSITION_TP));
}
else
if(positionType == POSITION_TYPE_SELL
//&& ask < PositionGetDouble(POSITION_PRICE_OPEN) - Grid_Step*_Point
&& ask < (PositionGetDouble(POSITION_TP) + PositionGetDouble(POSITION_PRICE_OPEN))/2
&& (ask + PositionGetDouble(POSITION_PRICE_OPEN))/2 < PositionGetDouble(POSITION_SL)
)
{
newStopLoss = (bid + PositionGetDouble(POSITION_PRICE_OPEN))/2;
//newTakeProfit = HlineBelow;
TradePositionModify(positionTicket, newStopLoss, PositionGetDouble(POSITION_TP));
}
}
}
}
//update stoploss to become a given double value that is normalized and position modified using the following function
//+------------------------------------------------------------------+
//| Function to modify a trade position |
//+------------------------------------------------------------------+
bool TradePositionModify(ulong ticket, double newStopLoss, double takeProfit)
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_SLTP;
request.position = ticket;
request.symbol = _Symbol;
request.sl = newStopLoss;
request.tp = takeProfit;
if(!OrderSend(request, result))
{
Print("Error modifying position: ", result.retcode);
return false;
}
return true;
}
// function that populates a 2 d array with price and volume data from the M1 period.
// for every minute
// To create a function that populates a 2D array with price and volume data from the M1 period for every minute, you can use the `CopyRates` function in MQL5. This function retrieves historical price data, including open, high, low, close prices, and volume. Here’s how you can implement such a function:
//
//+------------------------------------------------------------------+
//| Function to populate a 2D array with price and volume data |
//| from the M1 period for every minute |
//+------------------------------------------------------------------+
void PopulatePriceVolumeData(datetime startTime, datetime endTime, double &dataArray[][5])
{
// Calculate the number of minutes (bars) between startTime and endTime
int barsCount = (int)((endTime - startTime) / 60);
// Resize the 2D array to hold the data
ArrayResize(dataArray, barsCount);
// Create an array to hold the rates data
MqlRates rates[];
// Copy the rates data from the M1 period
if(CopyRates(_Symbol, PERIOD_M1, startTime, barsCount, rates) <= 0)
{
Print("Error copying rates data");
return;
}
// Populate the 2D array with price and volume data
for(int i = 0; i < barsCount; i++)
{
dataArray[i][0] = rates[i].open; // Open price
dataArray[i][1] = rates[i].high; // High price
dataArray[i][2] = rates[i].low; // Low price
dataArray[i][3] = rates[i].close; // Close price
dataArray[i][4] = (double)rates[i].tick_volume; // Volume
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CheckMoneyForTrade(string symb,double lots,ENUM_ORDER_TYPE type)
{
//--- Getting the opening price
MqlTick mqltick;
SymbolInfoTick(symb,mqltick);
double price=mqltick.ask;
if(type==ORDER_TYPE_SELL)
price=mqltick.bid;
//--- values of the required and free margin
double margin,free_margin=AccountInfoDouble(ACCOUNT_MARGIN_FREE);
//--- call of the checking function
if(!OrderCalcMargin(type,symb,lots,price,margin))
{
//--- something went wrong, report and return false
Print("Error in ",__FUNCTION__," code=",GetLastError());
return(false);
}
//--- if there are insufficient funds to perform the operation
if(margin>free_margin)
{
//--- report the error and return false
Print("Not enough money for ",EnumToString(type)," ",lots," ",symb," Error code=",GetLastError());
return(false);
}
//--- checking successful
return(true);
}// The provided code is an MQL5 script for a MetaTrader 5 Expert Advisor (EA) named "ValueAreaEA". This EA is designed to trade based on volume distribution levels, also known as value areas, calculated over a specified lookback period. Here's a breakdown of the key components and functionalities of the script:
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool IsMarketOpen()
{
// Check if the trading status indicates that the market is open
if(TimeCurrent() > SymbolInfoInteger(_Symbol,SYMBOL_TIME) && TimeCurrent() < SymbolInfoInteger(_Symbol,SYMBOL_START_TIME))
{
return false; // Market is open
}
else
{
return true; // Market is closed
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Check the correctness of the order volume |
//+------------------------------------------------------------------+
bool CheckVolumeValue(double volume)
{
string description;
//--- minimal allowed volume for trade operations
double min_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN);
if(volume<min_volume)
{
description=StringFormat("Volume is less than the minimal allowed SYMBOL_VOLUME_MIN=%.2f",min_volume);
return(false);
}
//--- maximal allowed volume of trade operations
double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
if(volume>max_volume)
{
description=StringFormat("Volume is greater than the maximal allowed SYMBOL_VOLUME_MAX=%.2f",max_volume);
return(false);
}
//--- get minimal step of volume changing
double volume_step=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP);
int ratio=(int)MathRound(volume/volume_step);
if(MathAbs(ratio*volume_step-volume)>0.0000001)
{
description=StringFormat("Volume is not a multiple of the minimal step SYMBOL_VOLUME_STEP=%.2f, the closest correct volume is %.2f",
volume_step,ratio*volume_step);
return(false);
}
description="Correct volume value";
return(true);
}
//+------------------------------------------------------------------+
bool CheckStopLoss_Takeprofit(ENUM_ORDER_TYPE type,double SL,double TP)
{
//--- get the SYMBOL_TRADE_STOPS_LEVEL level
int stops_level=(int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL);
if(stops_level!=0)
{
PrintFormat("SYMBOL_TRADE_STOPS_LEVEL=%d: StopLoss and TakeProfit must"+
" not be nearer than %d points from the closing price",stops_level,stops_level);
}
//---
bool SL_check=false,TP_check=false;
//--- check only two order types
switch(type)
{
//--- Buy operation
case ORDER_TYPE_BUY:
{
//--- check the StopLoss
SL_check=(bid-SL>stops_level*_Point);
if(!SL_check)
PrintFormat("For order %s StopLoss=%.5f must be less than %.5f"+
" (Bid=%.5f - SYMBOL_TRADE_STOPS_LEVEL=%d points)",
EnumToString(type),SL,bid-stops_level*_Point,bid,stops_level);
//--- check the TakeProfit
TP_check=(TP-bid>stops_level*_Point);
if(!TP_check)
PrintFormat("For order %s TakeProfit=%.5f must be greater than %.5f"+
" (Bid=%.5f + SYMBOL_TRADE_STOPS_LEVEL=%d points)",
EnumToString(type),TP,bid+stops_level*_Point,bid,stops_level);
//--- return the result of checking
return(SL_check&&TP_check);
}
//--- Sell operation
case ORDER_TYPE_SELL:
{
//--- check the StopLoss
SL_check=(SL-ask>stops_level*_Point);
if(!SL_check)
PrintFormat("For order %s StopLoss=%.5f must be greater than %.5f "+
" (Ask=%.5f + SYMBOL_TRADE_STOPS_LEVEL=%d points)",
EnumToString(type),SL,ask+stops_level*_Point,ask,stops_level);
//--- check the TakeProfit
TP_check=(ask-TP>stops_level*_Point);
if(!TP_check)
PrintFormat("For order %s TakeProfit=%.5f must be less than %.5f "+
" (Ask=%.5f - SYMBOL_TRADE_STOPS_LEVEL=%d points)",
EnumToString(type),TP,ask-stops_level*_Point,ask,stops_level);
//--- return the result of checking
return(TP_check&&SL_check);
}
break;
}
//--- a slightly different function is required for pending orders
return false;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
// The provided MQL5 code is quite comprehensive, indicating that the writer has a solid understanding of several key aspects of MQL5 programming. Here's an analysis of the skills the writer possesses and what they might need to develop further to create a consistently profitable Expert Advisor (EA):
//
// ### Skills the Writer Has:
// 1. **Basic MQL5 Syntax and Structure:**
// - Understanding of the basic structure of an MQL5 script, including event handlers like `OnInit()`, `OnDeinit()`, and `OnTick()`.
//
// 2. **Using Preprocessor Directives and Includes:**
// - Use of `#define` for constants and `#include` for importing necessary libraries, such as `Trade\Trade.mqh` for trading operations.
//
// 3. **Handling Arrays:**
// - Proficiency in using arrays to store and manipulate data, such as price levels, volume data, and technical indicators.
//
// 4. **Technical Indicator Functions:**
// - Use of built-in MQL5 functions to calculate technical indicators like ATR, OBV, and RSI.
//
// 5. **Time and Date Manipulations:**
// - Competence in working with `datetime` and converting time using `TimeToStruct()`.
//
// 6. **Order and Position Management:**
// - Skills in handling trading orders and positions, including placing, modifying, and closing trades.
//
// 7. **Custom Function Creation:**
// - Ability to write custom utility functions for specific tasks, such as calculating moving averages, drawing on charts, and finding peaks in an array.
//
// 8. **Conditional Logic and Control Structures:**
// - Use of `if`, `for`, and `switch` statements to control the flow of the program based on conditions.
//
// ### Skills the Writer Needs to Develop:
// 1. **Risk Management:**
// - Implementing robust risk management strategies, such as dynamically calculating position sizes based on account balance, setting appropriate stop-loss levels, and managing leverage.
//
// 2. **Backtesting and Optimization:**
// - Proficiency in using the MetaTrader Strategy Tester for backtesting the EA with historical data, as well as optimizing parameters for better performance.
//
// 3. **Robust Error Handling:**
// - Implementing comprehensive error handling and logging to diagnose and fix potential issues during live trading.
//
// 4. **Advanced Market Analysis:**
// - Developing a deeper understanding of market dynamics and incorporating more advanced analysis methods, such as machine learning or sentiment analysis.
//
// 5. **Performance Monitoring and Adaptation:**
// - Creating mechanisms to monitor the performance of the EA in real-time and adapt strategies based on changing market conditions.
//
// 6. **Strategy Development:**
// - Focusing on developing and testing various trading strategies to identify ones that can achieve consistent profitability.
//
// 7. **Code Optimization:**
// - Improving code efficiency and minimizing computational overhead, especially for operations that are executed on every tick.
//
// By enhancing these areas, the writer could increase the likelihood of developing a consistently profitable EA. Additionally, continuous learning and adaptation to new trading methodologies and technological advancements in algorithmic trading would be beneficial.
//
// how would you correct the risk management in this file?
// To provide a precise correction to risk management code in an MQL5 file, I'll need to understand the existing logic and any specific issues you might be facing. However, I can offer some general advice on implementing and improving risk management in a trading algorithm using MQL5.
//
// Here's a basic framework for risk management you might consider incorporating or checking against your existing code:
//
// 1. **Determine Account Risk**: Define the percentage of your account balance that you are willing to risk per trade. A common rule is to risk 1-2% of your account balance on a single trade.
//
// 2. **Calculate Lot Size**: Use the account risk, stop loss distance, and pip value to calculate the appropriate lot size for the trade.
//
// 3. **Set Stop Loss and Take Profit**: Always use a stop loss to limit potential losses and a take profit to secure profits. These can be set based on technical analysis or a fixed risk-reward ratio.
//
// 4. **Check Margin Requirements**: Ensure that the trade complies with margin requirements to prevent over-leveraging.
//
// 5. **Monitor Maximum Drawdown**: Implement logic to stop trading if the drawdown exceeds a certain percentage of the account balance.
//
// 6. **Implement Position Sizing**: Adjust position size dynamically based on account equity or market conditions.
//
// Here is a simple example in MQL5 that incorporates some of these principles:
//
// Example parameters
double accountRiskPercent = 1.0; // Risk 1% of account balance
double stopLossPips = 50.0; // Stop loss in pips
double takeProfitPips = 100.0; // Take profit in pips
// Function to calculate the lot size
double CalculateLotSize()
{
double riskAmount = AccountInfoDouble(ACCOUNT_BALANCE) * accountRiskPercent / 100.0;
double pipValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double lotSize = (riskAmount / (Grid_Step * pipValue)) * SymbolInfoDouble(_Symbol, SYMBOL_TRADE_CONTRACT_SIZE);
return NormalizeDouble(lotSize, 2); // Normalize to 2 decimal places
}
// Example of placing a trade
void PlaceTrade()
{
double lotSize = CalculateLotSize();
double stopLossPrice = 0.0;
double takeProfitPrice = 0.0;
// Determine if the trade is a buy or sell
bool isBuy = true; // Example: set to true for buy, false for sell
if(isBuy)
{
stopLossPrice = ask - stopLossPips * _Point;
takeProfitPrice = ask + takeProfitPips * _Point;
// Place a buy order
trade.Buy(lotSize, _Symbol, ask, stopLossPrice, takeProfitPrice);
}
else
{
stopLossPrice = bid + stopLossPips * _Point;
takeProfitPrice = bid - takeProfitPips * _Point;
// Place a sell order
trade.Sell(lotSize, _Symbol, bid, stopLossPrice, takeProfitPrice);
}
}
// Example of checking maximum drawdown
bool CheckMaxDrawdown(double maxDrawdownPercent)
{
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
double drawdown = ((balance - equity) / balance) * 100.0;
return drawdown < maxDrawdownPercent;
}
//
//
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+