RangeMasterFX

Author: 2023, HARUKI TERANAKA.
Price Data Components
Series array that contains the highest prices of each barSeries array that contains the lowest prices of each barSeries array that contains close prices for each barSeries array that contains open prices of each barSeries array that contains open prices of each barSeries array that contains close prices for each bar
Orders Execution
It automatically opens orders when conditions are reachedIt can change open orders parameters, due to possible stepping strategyChecks for the total of open ordersIt Closes Orders by itself
Indicators Used
Moving average indicator
0 Views
0 Downloads
0 Favorites
RangeMasterFX
//+------------------------------------------------------------------+
//|                                                 RangeMasterFX.mq4|
//|                        Copyright 2024,          HARUKI TERANAKA. |
//|                                        https://blogsmile117.com/ |
//+------------------------------------------------------------------+
#property copyright "2023, HARUKI TERANAKA."
#property link      "https://blogsmile117.com/"
#property version   "1.6"
#property strict

#define VER "1.6"

input int MAGICMA = 3937;                // Magic Number
input int startTrade = 0;                // Trade Start Time
input int endTrade = 24;                 // Trade End Time
input bool closeAllAtEndTrade = true;    // Close all trades and orders after Trade End Time
input int maxOpenOrders = 5;             // Adjust this to your broker's maximum orders limit
input int numberOfOrders = 10;           // Number of pending orders to open
input double lotSize = 0.01;             // Lot size for each order
input bool resetOrdersDaily = true;      // Input parameter to reset pending orders every day
input double stopLossPoints = 60;        // Input parameter for the minimum stop loss in points
input double takeProfitPoints = 60;      // Input parameter for the minimum take profit in points
input double stopLossMultiplier = 3.0;   // Input parameter for stop loss multiplier
input double takeProfitMultiplier = 1.0; // Input parameter for take profit multiplier
input double targetPercentage = 8.0;     // Percentage of gain to trigger closing

// 適応型ロット管理のパラメータ
input int AdaptiveLotSize_ConsecutiveWins = 3;

input int AdaptiveLotSize_ConsecutiveLosses = 3;
input double AdaptiveLotSize_IncreaseFactor = 1.2;

input double AdaptiveLotSize_DecreaseFactor = 0.8;

input double AdaptiveLotSize_MinLotSize = 0.01;

input double AdaptiveLotSize_MaxLotSize = 1.0;

int consecutiveWins = 0;
int consecutiveLosses = 0;

int orderTickets[];
int orderTicketsCount = 0;

double executedOrderPrices[];
int executedOrdersCount = 0;
double StopLevel;

int openOrderCount = 0;
double adaptiveLotSize;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
StopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL);
//--- Check if trading is allowed
if(!IsTradeAllowedCustom())
{
    Print("Trading is not allowed. Expert Advisor will not run.");
    return(INIT_FAILED);
}

return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ResetPendingOrders();
// オブジェクトの削除
ObjectDelete(0, "Support");
ObjectDelete(0, "Resistance");
ObjectDelete(0, "Pivot");

// Clear the chart comment
Comment("");
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
datetime lastBarTime = 0;
void OnTick()
{
datetime currentBarTime = Time[0];
if (Hour() >= startTrade && Hour() < endTrade)
{
    // Check if a new bar has opened
    if (currentBarTime != lastBarTime)
    {
        lastBarTime = currentBarTime;
        
        double tradingRange, rangeHigh, rangeLow;
        CalculateTradingRange(tradingRange, rangeHigh, rangeLow);
        
        double distance = tradingRange / numberOfOrders;
        double currentPrice = Bid;
        
        double pivot, s1, s2, r1, r2;
        CalculatePivotPoints(pivot, s1, s2, r1, r2);
        
        double fastMA = 0, slowMA = 0;
        CalculateMovingAverages(fastMA, slowMA);
        
        if (tradingRange > 0)
        {
            if ((IsNewDay() || orderTicketsCount == 0) && CheckMultiTimeframeTrend())
            {
                if (resetOrdersDaily)
                {
                    ResetPendingOrders();
                }
                if (orderTicketsCount == 0)
                {
                    for (int i = 0; i < numberOfOrders; i++)
                    {
                        double price = NormalizeDouble(rangeLow + distance * i, Digits);

                        // Check if the order price is within the stop level distance
                        if (!CheckStopLevel(price, OP_BUYLIMIT) || !CheckStopLevel(price, OP_SELLLIMIT))
                        {
                            Print("Order price is too close to the stop level. Order not placed.");
                            continue;
                        }

                        if (price > pivot && fastMA > slowMA && price > fastMA)
                            PlaceSellLimitOrder(price);
                        else if (price < pivot && fastMA < slowMA && price < fastMA)
                            PlaceBuyLimitOrder(price);
                    }
                }
            }
        }
        
        CheckExecutedOrders();
        
        CloseOrdersOnGain();
        
        if (executedOrdersCount > 1 && orderTicketsCount == numberOfOrders - 2)
        {
            double penultimateExecutedPrice = executedOrderPrices[executedOrdersCount - 2];
            if (penultimateExecutedPrice > currentPrice)
                PlaceSellLimitOrder(penultimateExecutedPrice);
            else
                PlaceBuyLimitOrder(penultimateExecutedPrice);
        }
    }
}
else
{
    if (closeAllAtEndTrade)
    {
        CloseAllOrders();
        ResetPendingOrders();
    }
}
}

//+------------------------------------------------------------------+
bool IsNewDay()
{
static datetime lastCheckedTime = 0;
datetime currentTime = TimeCurrent();
if(TimeDay(currentTime) != TimeDay(lastCheckedTime))
{
    lastCheckedTime = currentTime;
    return true;
}

return false;
}

//+------------------------------------------------------------------+
//| Function to get the trading range                                |
//+------------------------------------------------------------------+
void CalculateTradingRange(double &outRange, double &outHigh, double &outLow)
{
int weeklyTimeframe = PERIOD_W1;
int shiftedIndex = 0;
double pivot = (iHigh(NULL, weeklyTimeframe, shiftedIndex) + iLow(NULL, weeklyTimeframe, shiftedIndex) + iClose(NULL, weeklyTimeframe, shiftedIndex)) / 3.0;
double support = iLow(NULL, weeklyTimeframe, iLowest(NULL, weeklyTimeframe, MODE_LOW, 2, shiftedIndex));
double resistance = iHigh(NULL, weeklyTimeframe, iHighest(NULL, weeklyTimeframe, MODE_HIGH, 2, shiftedIndex));

int dailyTimeframe = PERIOD_D1;
double dailySupport = iLow(NULL, dailyTimeframe, iLowest(NULL, dailyTimeframe, MODE_LOW, 2, 0));
double dailyResistance = iHigh(NULL, dailyTimeframe, iHighest(NULL, dailyTimeframe, MODE_HIGH, 2, 0));

int h4Timeframe = PERIOD_H4;
double h4Support = iLow(NULL, h4Timeframe, iLowest(NULL, h4Timeframe, MODE_LOW, 2, 0));
double h4Resistance = iHigh(NULL, h4Timeframe, iHighest(NULL, h4Timeframe, MODE_HIGH, 2, 0));

int shortTimeframes[] = {PERIOD_H1, PERIOD_M30, PERIOD_M15};
double shortSupport = DBL_MAX;
double shortResistance = DBL_MIN;

for (int i = 0; i < ArraySize(shortTimeframes); i++)
{
    double timeframeSupport = iLow(NULL, shortTimeframes[i], iLowest(NULL, shortTimeframes[i], MODE_LOW, 2, 0));
    double timeframeResistance = iHigh(NULL, shortTimeframes[i], iHighest(NULL, shortTimeframes[i], MODE_HIGH, 2, 0));
    
    shortSupport = MathMin(shortSupport, timeframeSupport);
    shortResistance = MathMax(shortResistance, timeframeResistance);
}

outLow = MathMin(MathMin(MathMin(support, dailySupport), h4Support), shortSupport);
outHigh = MathMax(MathMax(MathMax(resistance, dailyResistance), h4Resistance), shortResistance);
outRange = outHigh - outLow;

double fibLevels[] = {0.236, 0.382, 0.5, 0.618, 0.786};
string fibLineNames[] = {"Fib_23.6", "Fib_38.2", "Fib_50.0", "Fib_61.8", "Fib_78.6"};
color fibColors[] = {clrGreen, clrYellow, clrBlue, clrMagenta, clrRed};

for (int i = 0; i < ArraySize(fibLevels); i++)
{
    double fibLevel = outHigh - (outHigh - outLow) * fibLevels[i];
    
    if (ObjectFind(0, fibLineNames[i]) < 0)
    {
        ObjectCreate(0, fibLineNames[i], OBJ_HLINE, 0, TimeCurrent(), fibLevel);
        ObjectSetInteger(0, fibLineNames[i], OBJPROP_COLOR, fibColors[i]);
        ObjectSetInteger(0, fibLineNames[i], OBJPROP_WIDTH, 1);
    }
    else
    {
        ObjectMove(0, fibLineNames[i], 0, TimeCurrent(), fibLevel);
    }
}

if (ObjectFind(0, "Support") < 0)
{
    ObjectCreate(0, "Support", OBJ_HLINE, 0, TimeCurrent(), outLow);
    ObjectSetInteger(0, "Support", OBJPROP_COLOR, clrBlue);
    ObjectSetInteger(0, "Support", OBJPROP_WIDTH, 2);
}
else
{
    ObjectMove(0, "Support", 0, TimeCurrent(), outLow);
}

if (ObjectFind(0, "Resistance") < 0)
{
    ObjectCreate(0, "Resistance", OBJ_HLINE, 0, TimeCurrent(), outHigh);
    ObjectSetInteger(0, "Resistance", OBJPROP_COLOR, clrRed);
    ObjectSetInteger(0, "Resistance", OBJPROP_WIDTH, 2);
}
else
{
    ObjectMove(0, "Resistance", 0, TimeCurrent(), outHigh);
}

if (ObjectFind(0, "Pivot") < 0)
{
    ObjectCreate(0, "Pivot", OBJ_HLINE, 0, TimeCurrent(), pivot);
    ObjectSetInteger(0, "Pivot", OBJPROP_COLOR, clrGray);
    ObjectSetInteger(0, "Pivot", OBJPROP_WIDTH, 1);
}
else
{
    ObjectMove(0, "Pivot", 0, TimeCurrent(), pivot);
}
}

void CalculatePivotPoints(double &outPivot, double &outS1, double &outS2, double &outR1, double &outR2)
{
double prevHigh = iHigh(NULL, PERIOD_D1, 1);
double prevLow = iLow(NULL, PERIOD_D1, 1);
double prevClose = iClose(NULL, PERIOD_D1, 1);
outPivot = (prevHigh + prevLow + prevClose) / 3;
outS1 = (2 * outPivot) - prevHigh;
outS2 = outPivot - (prevHigh - prevLow);
outR1 = (2 * outPivot) - prevLow;
outR2 = outPivot + (prevHigh - prevLow);
}

bool CheckMultiTimeframeTrend()
{
int dailyTimeframe = PERIOD_D1;
double dailyOpen = iOpen(NULL, dailyTimeframe, 0);
double dailyClose = iClose(NULL, dailyTimeframe, 0);
bool isDailyBullish = dailyClose > dailyOpen;
int h4Timeframe = PERIOD_H4;
double h4Open = iOpen(NULL, h4Timeframe, 0);
double h4Close = iClose(NULL, h4Timeframe, 0);
bool isH4Bullish = h4Close > h4Open;

return ((isDailyBullish && isH4Bullish && Bid < Ask) || (!isDailyBullish && !isH4Bullish && Bid > Ask));
}

// 適応型ロットサイズの計算
double CalculateAdaptiveLotSize()
{
double adaptiveLotSize = lotSize;
if (consecutiveWins >= AdaptiveLotSize_ConsecutiveWins)
{
    adaptiveLotSize *= AdaptiveLotSize_IncreaseFactor;
    consecutiveWins = 0;
}
else if (consecutiveLosses >= AdaptiveLotSize_ConsecutiveLosses)
{
    adaptiveLotSize *= AdaptiveLotSize_DecreaseFactor;
    consecutiveLosses = 0;
}

adaptiveLotSize = MathMin(MathMax(adaptiveLotSize, AdaptiveLotSize_MinLotSize), AdaptiveLotSize_MaxLotSize);
return adaptiveLotSize;
}

//+------------------------------------------------------------------+
//| Function to place a SELL LIMIT order                            |
//+------------------------------------------------------------------+
void PlaceSellLimitOrder(double price)
{
CountOpenMarketOrders();
CountOpenPendingOrders();
int totalOpenOrders = openOrderCount;
if (totalOpenOrders > maxOpenOrders)
{
    Print("Maximum open orders reached. Cannot place a new order.");
    return;
}

ResetLastError();
double stopLoss = NormalizeDouble(price + (price - Ask) * stopLossMultiplier, Digits);
double takeProfit = NormalizeDouble(price - (price - Ask) * takeProfitMultiplier, Digits);

double minStopLoss = NormalizeDouble(price + (stopLossPoints * Point), Digits);
double minTakeProfit = NormalizeDouble(price - (takeProfitPoints * Point), Digits);

if (stopLoss < minStopLoss || takeProfit > minTakeProfit)
{
    Print("Warning: Stop Loss or Take Profit values too small. Order not placed.");
    return;
}

string description = "";
adaptiveLotSize =CalculateAdaptiveLotSize();
if (CheckVolumeValue(adaptiveLotSize, description) && CheckMoneyForTrade(Symbol(), adaptiveLotSize, OP_SELL))
{
    int ticket = OrderSend(Symbol(), OP_SELLLIMIT, adaptiveLotSize, price, 2, 0, 0, "RangeEA_" + VER, MAGICMA, 0, clrRed);
    if (ticket > 0)
    {
        if (OrderModify(ticket, price, stopLoss, takeProfit, 0, clrNONE))
        {
            ArrayResize(orderTickets, orderTicketsCount + 1);
            orderTickets[orderTicketsCount] = ticket;
            orderTicketsCount++;
        }
        else
        {
            int error = GetLastError();
            if (error == 130)
            {
                Print("Error 130 (ERR_INVALID_STOPS) while modifying SELL LIMIT order. Details:");
                Print("Order Type: OP_SELLLIMIT");
                Print("Open Price: ", price);
                Print("Stop Loss: ", stopLoss);
                Print("Take Profit: ", takeProfit);
            }
            else
            {
                Print("Error modifying SELL LIMIT order. Error code: ", error);
            }
        }

        if (GetLastError())
        {
            if (!OrderDelete(ticket, clrNONE))
            {
                Print("WARNING: Could not delete the wrong order ticket: ", ticket);
            }
        }
    }
    else
    {
        int error = GetLastError();
        if (error == 130)
        {
            Print("Error 130 (ERR_INVALID_STOPS) while placing SELL LIMIT order. Details:");
            Print("Order Type: OP_SELLLIMIT");
            Print("Open Price: ", price);
            Print("Stop Loss: ", stopLoss);
            Print("Take Profit: ", takeProfit);
        }
        else
        {
            Print("Error placing SELL LIMIT order. Error code: ", error);
        }
    }
}
}

void CalculateMovingAverages(double &outFastMA, double &outSlowMA)
{
int fastPeriod = 10;
int slowPeriod = 20;
outFastMA = iMA(NULL, 0, fastPeriod, 0, MODE_SMA, PRICE_CLOSE, 0);
outSlowMA = iMA(NULL, 0, slowPeriod, 0, MODE_SMA, PRICE_CLOSE, 0);
}

//+------------------------------------------------------------------+
//| Function to place a BUY LIMIT order                             |
//+------------------------------------------------------------------+
void PlaceBuyLimitOrder(double price)
{
CountOpenMarketOrders();
CountOpenPendingOrders();
int totalOpenOrders = openOrderCount;
if (totalOpenOrders > maxOpenOrders)
{
    Print("Maximum open orders reached. Cannot place a new order.");
    return;
}

ResetLastError();
double stopLoss = NormalizeDouble(price - (Bid - price) * stopLossMultiplier, Digits);
double takeProfit = NormalizeDouble(price + (Bid - price) * takeProfitMultiplier, Digits);

double minStopLoss = NormalizeDouble(price - (stopLossPoints * Point), Digits);
double minTakeProfit = NormalizeDouble(price + (takeProfitPoints * Point), Digits);

if (stopLoss > minStopLoss || takeProfit < minTakeProfit)
{
    Print("Warning: Stop Loss or Take Profit values too small. Order not placed.");
    return;
}

string description = "";
adaptiveLotSize = CalculateAdaptiveLotSize();

if (CheckVolumeValue(adaptiveLotSize, description) && CheckMoneyForTrade(Symbol(), adaptiveLotSize, OP_BUY))
{
    int ticket = OrderSend(Symbol(), OP_BUYLIMIT, adaptiveLotSize, price, 2, 0, 0, "RangeEA_" + VER, MAGICMA, 0, clrBlue);
    if (ticket > 0)
    {
        if (OrderModify(ticket, price, stopLoss, takeProfit, 0, clrNONE))
        {
            ArrayResize(orderTickets, orderTicketsCount + 1);
            orderTickets[orderTicketsCount] = ticket;
            orderTicketsCount++;
        }
        else
        {
            int error = GetLastError();
            if (error == 130)
            {
                Print("Error 130 (ERR_INVALID_STOPS) while modifying BUY LIMIT order. Details:");
                Print("Order Type: OP_BUYLIMIT");
                Print("Open Price: ", price);
                Print("Stop Loss: ", stopLoss);
                Print("Take Profit: ", takeProfit);
            }
            else
            {
                Print("Error modifying BUY LIMIT order. Error code: ", error);
            }
        }

        if (GetLastError())
        {
            if (!OrderDelete(ticket, clrNONE))
            {
                Print("WARNING: Could not delete the wrong order ticket: ", ticket);
            }
        }
    }
    else
    {
        int error = GetLastError();
        if (error == 130)
        {
            Print("Error 130 (ERR_INVALID_STOPS) while placing BUY LIMIT order. Details:");
            Print("Order Type: OP_BUYLIMIT");
            Print("Open Price: ", price);
            Print("Stop Loss: ", stopLoss);
            Print("Take Profit: ", takeProfit);
        }
        else
        {
            Print("Error placing BUY LIMIT order. Error code: ", error);
        }
    }
}
}

//+------------------------------------------------------------------+
//| Function to check and remove executed orders                     |
//+------------------------------------------------------------------+
void CheckExecutedOrders()
{
for (int i = orderTicketsCount - 1; i >= 0; i--)
{
if (OrderSelect(orderTickets[i], SELECT_BY_TICKET, MODE_TRADES))
{
if (OrderSymbol() == Symbol())
{
if (OrderMagicNumber() != MAGICMA)
{
continue;
}
if (OrderType() == OP_BUY || OrderType() == OP_SELL)
            {
                if (OrderCloseTime() > 0)
                {
                    double executedPrice = OrderOpenPrice();
                    ArrayRemove(orderTickets, i);
                    
                    if (OrderProfit() > 0)
                    {
                        consecutiveWins++;
                        consecutiveLosses = 0;
                    }
                    else if (OrderProfit() < 0)
                    {
                        consecutiveLosses++;
                        consecutiveWins = 0;
                    }

                    ArrayResize(executedOrderPrices, executedOrdersCount + 1);
                    executedOrderPrices[executedOrdersCount] = executedPrice;
                    executedOrdersCount++;
                    orderTicketsCount--;
                }
            }
        }
    }
}
}

//+------------------------------------------------------------------+
//| Close orders if gain exceeds target percentage                   |
//+------------------------------------------------------------------+
void CloseOrdersOnGain()
{
double gainPercentage = (AccountProfit() / AccountBalance()) * 100;
if(gainPercentage >= targetPercentage)
{
    int totalClosed = 0;
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            if(OrderSymbol()==Symbol())
            {
                if(OrderMagicNumber()!=MAGICMA)
                {
                    continue;
                }

                if(OrderType() <= OP_SELL)
                {
                    double orderClosePrice = MarketInfo(OrderSymbol(), MODE_BID);
                    RefreshRates();

                    if(OrderType() == OP_BUY)
                        orderClosePrice = Bid;
                    if(OrderType() == OP_SELL)
                        orderClosePrice = Ask;
                    bool result = false;

                    for(int retryCount = 0; retryCount < 3; retryCount++)
                    {
                        result = OrderClose(OrderTicket(), OrderLots(), orderClosePrice, 2, clrAntiqueWhite);

                        if(result)
                        {
                            Print("Order closed successfully: ", OrderType(), " ", OrderLots(), " lots at price ", orderClosePrice);
                            totalClosed++;
                            break;
                        }
                        else
                        {
                            if(GetLastError() == 138)
                            {
                                orderClosePrice = MarketInfo(OrderSymbol(), MODE_BID) + MarketInfo(OrderSymbol(), MODE_POINT) * retryCount;
                                Sleep(1000);
                            }
                            else
                            {
                                Print("Error closing order: ", GetLastError());
                                break;
                            }
                        }
                    }
                }
            }
        }
    }

    if(totalClosed > 0)
    {
        ResetPendingOrders();
    }
}
}

//--- Function to remove an element from an array
void ArrayRemove(int& array[], int index)
{
if(index >= 0 && index < ArraySize(array))
{
for(int i = index; i < ArraySize(array) - 1; i++)
array[i] = array[i + 1];
ArrayResize(array, ArraySize(array) - 1);
}
}

//---------------------------------------------------------------------------
void CloseAllOrders()
{
RefreshRates();

bool   Result=false;
int    i,Pos,Error=GetLastError();
int    Total=OrdersTotal();

if(Total>0)
{

    for(i=Total-1; i>=0; i--)
    {
        if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
        {
            if(OrderSymbol()==Symbol())
            {
                if(OrderMagicNumber()!=MAGICMA)
                {
                    continue;
                }

                Pos=OrderType();
                if(Pos==OP_BUY)
                {
                    Result=OrderClose(OrderTicket(), OrderLots(), Bid, 2, clrBlue);
                }
                if(Pos==OP_SELL)
                {
                    Result=OrderClose(OrderTicket(), OrderLots(), Ask, 2, clrRed);
                }
                if((Pos==OP_BUYSTOP)||(Pos==OP_SELLSTOP)||(Pos==OP_BUYLIMIT)||(Pos==OP_SELLLIMIT))
                {
                    Result=OrderDelete(OrderTicket(), CLR_NONE);
                }
                //-----------------------
                if(Result!=true)
                {
                    Error=GetLastError();
                }
                else
                    Error=0;
                //-----------------------
            }//if
        }//if
    }//for
}//if

Sleep(20);
return;
}

//+------------------------------------------------------------------+
void ResetPendingOrders()
{
orderTicketsCount = 0;
executedOrdersCount = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
        if(OrderSymbol()==Symbol())
        {
            if(OrderMagicNumber()!=MAGICMA)
            {
                continue;
            }

            if(OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLLIMIT)
            {
                if(OrderDelete(OrderTicket()))
                {
                    Print("Pending order deleted. Ticket: ", OrderTicket());
                }
                else
                {
                    Print("Error deleting pending order. Ticket: ", OrderTicket(), " Error: ", GetLastError());
                }
            }
        }
    }
}
}

//+------------------------------------------------------------------+
//| Check the correctness of the order volume                        |
//+------------------------------------------------------------------+
bool CheckVolumeValue(double volume,string &description)
{
    if(AccountBalance() < 10)
{
    Comment("minimum balances is $10");
    return(false);
}

//--- 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 CheckMoneyForTrade(string symb, double lots,int type)
{
double free_margin=AccountFreeMarginCheck(symb,type, lots);
//-- if there isnot enough money
if(free_margin<0)
{
string oper=(type==OP_BUY)? "Buy":"Sell";
Print("Not enough money for ", oper," ",lots, " ", symb, " Error code=",GetLastError());
return(false);
}
//--- checking successful
return(true);
}

//+------------------------------------------------------------------+
double CheckLotSize()
{
double minLotSize = MarketInfo(Symbol(), MODE_MINLOT);
double maxLotSize = MarketInfo(Symbol(), MODE_MAXLOT);
if(lotSize < minLotSize)
{
    Print("Warning: Lot size is too small. Minimum lot size for ", Symbol(), " is ", minLotSize);
    return minLotSize;
}
else
    if(lotSize > maxLotSize)
    {
        Print("Warning: Lot size is too large. Maximum lot size for ", Symbol(), " is ", maxLotSize);
        return maxLotSize;
    }

//--- Lot size is within the valid range
return lotSize;
}

//+------------------------------------------------------------------+
//--- Function to count open market orders
void CountOpenMarketOrders()
{
openOrderCount = 0;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol()==Symbol())
{
if(OrderMagicNumber()!=MAGICMA)
{
continue;
}
if(OrderType() == OP_BUY || OrderType() == OP_SELL)
            {
                openOrderCount++;
            }
        }
    }
}
}

//--- Function to count open pending orders
void CountOpenPendingOrders()
{
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol()==Symbol())
{
if(OrderMagicNumber()!=MAGICMA)
{
continue;
}
if(OrderType() == OP_BUYSTOP || OrderType() == OP_SELLSTOP ||
               OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLLIMIT)
            {
                openOrderCount++;
            }
        }
    }
}
}

//+------------------------------------------------------------------+
// Function to check if the order price is within the stop level distance
bool CheckStopLevel(double price, int type)
{
double stopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point;
double openPrice = (type == OP_BUY || type == OP_BUYLIMIT) ? Ask : Bid;
return MathAbs(price - openPrice) >= stopLevel;
}

//+------------------------------------------------------------------+
// Function to check if trading is allowed
bool IsTradeAllowedCustom()
{
return IsTradeAllowedCustom(Symbol(), TimeCurrent());
}

//+------------------------------------------------------------------+
// Function to check if trading is allowed for a specific symbol and time
bool IsTradeAllowedCustom(string symbol, datetime time)
{
return TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) && MQLInfoInteger(MQL_TRADE_ALLOWED) &&
SymbolInfoInteger(symbol, SYMBOL_TRADE_MODE) == SYMBOL_TRADE_MODE_FULL &&
SymbolInfoInteger(symbol, SYMBOL_TRADE_EXEMODE) == SYMBOL_TRADE_EXECUTION_INSTANT &&
!IsTradeContextBusy();
}

//+------------------------------------------------------------------+

Comments

Markdown supported. Formatting help

Markdown Formatting Guide

Element Markdown Syntax
Heading # H1
## H2
### H3
Bold **bold text**
Italic *italicized text*
Link [title](https://www.example.com)
Image ![alt text](image.jpg)
Code `code`
Code Block ```
code block
```
Quote > blockquote
Unordered List - Item 1
- Item 2
Ordered List 1. First item
2. Second item
Horizontal Rule ---