Deutsch
preview
Scalping Orderflow for MQL5

Scalping Orderflow for MQL5

MetaTrader 5Examples | 19 September 2024, 17:20
4 070 4
Javier Santiago Gaston De Iriarte Cabrera
Javier Santiago Gaston De Iriarte Cabrera

Introduction

An example of a sophisticated algorithmic trading system for MetaTrader 5 (MQL5) that uses the Scalping OrderFlow technique is this Expert Advisor (EA).

A short-term trading strategy known as "scalping order flow" focuses on identifying possible entry and exit points in the market by examining the real-time flow of orders. It makes quick trading decisions by combining the study of volume, price activity, and order book data. Typically, positions are held for a very short time—often within minutes or even seconds.

This EA finds trading opportunities based on order flow imbalances by using a variety of technical indicators and market analysis methodologies. Advanced risk management features including trailing stops, partial position closing, and dynamic position size are also included. In addition, the EA incorporates a method to prevent trading during significant news events and sets a limit on consecutive losses.

Predicting short-term price swings through the examination of real-time order book data and volume dynamics is the fundamental idea behind OrderFlow trading. By combining this idea with other established technical analysis indicators, this expert advisor develops a hybrid strategy that seeks to pinpoint high-probability trading opportunities.

The emphasis on risk management in this EA is one of its main characteristics. Effective risk control is essential in the turbulent world of forex trading, especially when using scalping tactics. In order to safeguard capital and optimize possible returns, this system includes trailing stops, partial position closure methods, and dynamic position sizing.

Because of its flexible design, traders can modify the EA's parameters to better fit their trading style and risk tolerance. Users can adjust several aspects of the system to match their trading objectives and market perspectives, such as volume thresholds and indicator periods.

It's crucial to understand that even though this EA trades automatically, it is not a "set and forget" solution. The basics of forex trading, the ideas behind OrderFlow, and the particular indicators included in this system should all be well understood by users. It is advisable to conduct routine monitoring and make necessary modifications to guarantee that the EA operates at its best under different market circumstances.

It's crucial to understand that even though this EA trades automatically, it is not a "set and forget" solution. The basics of forex trading, the ideas behind OrderFlow, and the particular indicators included in this system should all be well understood by users. It is advisable to conduct routine monitoring and make necessary modifications to guarantee that the EA operates at its best under different market circumstances.


The Code

This Expert Advisor (EA) is designed for MetaTrader 5 and implements an advanced Order Flow scalping strategy with sophisticated risk management features. The EA begins by initializing various technical indicators and validating input parameters during the OnInit() function. It sets up handles for indicators such as Moving Averages, ADX, ATR, RSI, and Bollinger Bands.

#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>

// Input parameters
input int VolumeThreshold = 35000;  // Volume threshold to consider imbalance
input int OrderFlowPeriod = 30;   // Number of candles to analyze order flow
input double RiskPercent = 1.0;   // Risk percentage per trade
input int ADXPeriod = 14;         // ADX Period
input int ADXThreshold = 25;      // ADX threshold for strong trend
input int MAPeriod = 200;         // Moving Average Period
input ENUM_TIMEFRAMES Timeframe = PERIOD_M15;  // Timeframe for analysis
input double MaxLotSize = 0.1;    // Maximum allowed lot size
input int ATRPeriod = 14;         // ATR Period
input double ATRMultiplier = 2.0; // ATR Multiplier
input int RSIPeriod = 14;         // RSI Period
input int RSIOverbought = 70;     // RSI Overbought level
input int RSIOversold = 30;       // RSI Oversold level
input int MAFastPeriod = 10;      // Fast Moving Average Period
input int MASlowPeriod = 30;      // Slow Moving Average Period
input int BollingerPeriod = 20;   // Bollinger Bands Period
input double BollingerDeviation = 2.5; // Bollinger Bands Standard Deviation
input int MaxConsecutiveLosses = 1; // Maximum number of consecutive losses before pausing
input int MinBarsBetweenTrades = 1; // Minimum number of bars between trades

// Global variables
CTrade trade;
CPositionInfo positionInfo;
int maHandle, adxHandle, atrHandle, rsiHandle, maFastHandle, maSlowHandle, bollingerHandle;
int consecutiveLosses = 0;
datetime lastTradeTime = 0;
int barsSinceLastTrade = 0;

// New global variables for statistics
int totalTrades = 0;
int winningTrades = 0;
double totalProfit = 0;
int OnInit()
{
    // Logging initialization
    Print("Starting Order Flow EA v13...");
    
    // Verify trading permissions
    if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
    {
        Print("Error: Automated trading is not allowed in the terminal.");
        return INIT_FAILED;
    }
    
    if(!MQLInfoInteger(MQL_TRADE_ALLOWED))
    {
        Print("Error: Automated trading is not allowed for this EA.");
        return INIT_FAILED;
    }
    
    // Initialize trading object
    trade.SetExpertMagicNumber(123456);
    trade.SetMarginMode();
    trade.SetTypeFillingBySymbol(_Symbol);
    trade.SetDeviationInPoints(10); // 1 pip deviation allowed
    Print("Trading object initialized.");
    
    // Initialize indicators
    maHandle = iMA(_Symbol, Timeframe, MAPeriod, 0, MODE_SMA, PRICE_CLOSE);
    adxHandle = iADX(_Symbol, Timeframe, ADXPeriod);
    atrHandle = iATR(_Symbol, Timeframe, ATRPeriod);
    rsiHandle = iRSI(_Symbol, Timeframe, RSIPeriod, PRICE_CLOSE);
    maFastHandle = iMA(_Symbol, Timeframe, MAFastPeriod, 0, MODE_EMA, PRICE_CLOSE);
    maSlowHandle = iMA(_Symbol, Timeframe, MASlowPeriod, 0, MODE_EMA, PRICE_CLOSE);
    bollingerHandle = iBands(_Symbol, Timeframe, BollingerPeriod, 0, BollingerDeviation, PRICE_CLOSE);
    
    // Verify indicator initialization
    if(maHandle == INVALID_HANDLE || adxHandle == INVALID_HANDLE || atrHandle == INVALID_HANDLE || 
       rsiHandle == INVALID_HANDLE || maFastHandle == INVALID_HANDLE || maSlowHandle == INVALID_HANDLE ||
       bollingerHandle == INVALID_HANDLE)
    {
        Print("Error initializing indicators:");
        if(maHandle == INVALID_HANDLE) Print("- Invalid MA");
        if(adxHandle == INVALID_HANDLE) Print("- Invalid ADX");
        if(atrHandle == INVALID_HANDLE) Print("- Invalid ATR");
        if(rsiHandle == INVALID_HANDLE) Print("- Invalid RSI");
        if(maFastHandle == INVALID_HANDLE) Print("- Invalid Fast MA");
        if(maSlowHandle == INVALID_HANDLE) Print("- Invalid Slow MA");
        if(bollingerHandle == INVALID_HANDLE) Print("- Invalid Bollinger Bands");
        return INIT_FAILED;
    }
    
    Print("All indicators initialized successfully.");
    
    // Verify input parameters
    if(VolumeThreshold <= 0 || OrderFlowPeriod <= 0 || RiskPercent <= 0 || RiskPercent > 100 ||
       ADXPeriod <= 0 || ADXThreshold <= 0 || MAPeriod <= 0 || MaxLotSize <= 0 || ATRPeriod <= 0 ||
       ATRMultiplier <= 0 || RSIPeriod <= 0 || RSIOverbought <= RSIOversold || MAFastPeriod <= 0 ||
       MASlowPeriod <= 0 || BollingerPeriod <= 0 || BollingerDeviation <= 0 || MaxConsecutiveLosses < 0 ||
       MinBarsBetweenTrades < 0)
    {
        Print("Error: Invalid input parameters.");
        return INIT_FAILED;
    }
    
    Print("Input parameters validated.");
    
    // Initialize global variables
    consecutiveLosses = 0;
    lastTradeTime = 0;
    barsSinceLastTrade = MinBarsBetweenTrades;

The main trading logic is executed in the OnTick() function, which is called on each price tick. The EA first checks if a new bar has formed and if trading is allowed. It then analyzes the order flow by comparing buy and sell volumes over a specified period. The EA uses multiple technical indicators to confirm trading signals, including trend strength (ADX), price position relative to moving averages, and RSI levels.

void OnTick()
{
    if(!IsNewBar())
        return;
    
    Print("Current state - Consecutive losses: ", consecutiveLosses, 
          ", Bars since last trade: ", barsSinceLastTrade);
    
    if(!IsTradeAllowed())
    {
        Print("Trading not allowed. Check EA configuration and account permissions.");
        return;
    }
    
    // Check if there's an open position and manage it
    if(PositionExists())
    {
        ManageOpenPositions();
        return; // Exit if there's an open position
    }
    
    barsSinceLastTrade++; // Increment only if there's no open position
    
    if(!IsRiskAcceptable())
    {
        Print("Risk not acceptable.");
        return;
    }
    
    double buyVolume = 0, sellVolume = 0;
    AnalyzeOrderFlow(buyVolume, sellVolume);
    
    double adxValue[], maValue[], atrValue[], rsiValue[], maFastValue[], maSlowValue[], bollingerUpper[], bollingerLower[];
    if(!GetIndicatorData(adxValue, maValue, atrValue, rsiValue, maFastValue, maSlowValue, bollingerUpper, bollingerLower))
        return;
    
    bool strongTrend = (adxValue[0] > ADXThreshold);
    bool aboveMA = (SymbolInfoDouble(_Symbol, SYMBOL_LAST) > maValue[0]);
    bool fastAboveSlow = (maFastValue[0] > maSlowValue[0]);
    
    int dynamicSL = (int)(atrValue[0] * ATRMultiplier / SymbolInfoDouble(_Symbol, SYMBOL_POINT));
    int dynamicTP = dynamicSL * 3;  // Risk/Reward ratio of 1:3
    
    double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    
    // Conditions for a buy trade
    if(strongTrend && aboveMA && fastAboveSlow && buyVolume > sellVolume + VolumeThreshold &&
       rsiValue[0] < RSIOverbought && currentPrice < bollingerUpper[0] &&
       barsSinceLastTrade >= MinBarsBetweenTrades)
    {
        Print("Buy conditions met. Attempting to open position...");
        if(ExecuteTrade(ORDER_TYPE_BUY, dynamicSL, dynamicTP))
        {
            Print("Buy position opened successfully.");
            barsSinceLastTrade = 0;
        }
    }
    // Conditions for a sell trade
    else if(strongTrend && !aboveMA && !fastAboveSlow && sellVolume > buyVolume + VolumeThreshold &&
            rsiValue[0] > RSIOversold && currentPrice > bollingerLower[0] &&
            barsSinceLastTrade >= MinBarsBetweenTrades)
    {
        Print("Sell conditions met. Attempting to open position...");
        if(ExecuteTrade(ORDER_TYPE_SELL, dynamicSL, dynamicTP))
        {
            Print("Sell position opened successfully.");
            barsSinceLastTrade = 0;
        }
    }
}

For risk management, the EA implements dynamic position sizing based on a percentage of account balance and the current market volatility (using ATR). It also includes a trailing stop mechanism and partial position closing to lock in profits. The EA limits risk by enforcing a maximum number of consecutive losses and a minimum number of bars between trades.

bool IsRiskAcceptable()
{
    if(IsHighImpactNews())
    {
        Print("Risk not acceptable: High impact news detected.");
        return false;
    }
    
    if(consecutiveLosses >= MaxConsecutiveLosses)
    {
        Print("Risk not acceptable: Maximum consecutive losses reached (", consecutiveLosses, "/", MaxConsecutiveLosses, ").");
        return false;
    }
    
    if(barsSinceLastTrade < MinBarsBetweenTrades)
    {
        Print("Risk not acceptable: Not enough bars since last trade (", barsSinceLastTrade, "/", MinBarsBetweenTrades, ").");
        return false;
    }
    
    double equity = AccountInfoDouble(ACCOUNT_EQUITY);
    double balance = AccountInfoDouble(ACCOUNT_BALANCE);
    double drawdown = (balance - equity) / balance * 100;
    if(drawdown > 20) // Increased from 10% to 20%
    {
        Print("Risk not acceptable: Excessive drawdown (", DoubleToString(drawdown, 2), "%).");
        return false;
    }
    
    Print("Risk acceptable. Consecutive losses: ", consecutiveLosses, 
          ", Bars since last trade: ", barsSinceLastTrade, 
          ", Current drawdown: ", DoubleToString(drawdown, 2), "%");
    return true;
}

The CalculateLotSize() function determines the appropriate position size based on the account balance, risk percentage, and current market conditions. The ManageOpenPositions() function handles existing trades, implementing trailing stops and partial closures.

double CalculateLotSize(double stopLossDistance)
{
    double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
    double maxRiskAmount = accountBalance * (RiskPercent / 100);
    double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
    double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
    
    if(tickValue == 0 || stopLossDistance == 0)
    {
        Print("Error: Tick value or Stop Loss distance is 0");
        return 0;
    }
    
    double lotSize = NormalizeDouble(maxRiskAmount / (stopLossDistance * tickValue), 2);
    lotSize = MathFloor(lotSize / lotStep) * lotStep;
    
    double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
    double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
    
    lotSize = MathMax(MathMin(lotSize, maxLot), minLot);
    lotSize = MathMin(lotSize, MaxLotSize);
    
    double margin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
    double requiredMargin = SymbolInfoDouble(_Symbol, SYMBOL_MARGIN_INITIAL) * lotSize;
    
    if(requiredMargin > margin)
    {
        Print("Not enough free margin to open this position. Required: ", requiredMargin, " Available: ", margin);
        return 0;
    }
    
    Print("Calculated lot size: ", lotSize, " Risk: $", NormalizeDouble(lotSize * stopLossDistance * tickValue, 2));
    
    return lotSize;
}

Error handling is comprehensively addressed through the HandleTradingErrors() function, which provides detailed feedback on various trading-related errors. The EA also includes functions for logging trading statistics and checking for high-impact news events (though the latter is left as a placeholder for users to implement).

//+------------------------------------------------------------------+
//| Function for error handling                                      |
//+------------------------------------------------------------------+
void HandleTradingErrors(int errorCode)
{
    switch(errorCode)
    {
        case TRADE_RETCODE_REQUOTE:
            Print("Error: Requote");
            break;
        case TRADE_RETCODE_REJECT:
            Print("Error: Request rejected");
            break;
        case TRADE_RETCODE_CANCEL:
            Print("Error: Request cancelled by trader");
            break;
        case TRADE_RETCODE_PLACED:
            Print("Order placed successfully");
            break;
        case TRADE_RETCODE_DONE:
            Print("Request completed");
            break;
        case TRADE_RETCODE_DONE_PARTIAL:
            Print("Request partially completed");
            break;
        case TRADE_RETCODE_ERROR:
            Print("Request processing error");
            break;
        case TRADE_RETCODE_TIMEOUT:
            Print("Error: Request cancelled by timeout");
            break;
        case TRADE_RETCODE_INVALID:
            Print("Error: Invalid request");
            break;
        case TRADE_RETCODE_INVALID_VOLUME:
            Print("Error: Invalid volume in request");
            break;
        case TRADE_RETCODE_INVALID_PRICE:
            Print("Error: Invalid price in request");
            break;
        case TRADE_RETCODE_INVALID_STOPS:
            Print("Error: Invalid stops in request");
            break;
        case TRADE_RETCODE_TRADE_DISABLED:
            Print("Error: Trading is disabled");
            break;
        case TRADE_RETCODE_MARKET_CLOSED:
            Print("Error: Market is closed");
            break;
        case TRADE_RETCODE_NO_MONEY:
            Print("Error: Not enough money to complete request");
            break;
        case TRADE_RETCODE_PRICE_CHANGED:
            Print("Error: Prices changed");
            break;
        case TRADE_RETCODE_PRICE_OFF:
            Print("Error: No quotes to process request");
            break;
        case TRADE_RETCODE_INVALID_EXPIRATION:
            Print("Error: Invalid order expiration date");
            break;
        case TRADE_RETCODE_ORDER_CHANGED:
            Print("Error: Order state changed");
            break;
        case TRADE_RETCODE_TOO_MANY_REQUESTS:
            Print("Error: Too many requests");
            break;
        case TRADE_RETCODE_NO_CHANGES:
            Print("Error: No changes in request");
            break;
        case TRADE_RETCODE_SERVER_DISABLES_AT:
            Print("Error: Autotrading disabled by server");
            break;
        case TRADE_RETCODE_CLIENT_DISABLES_AT:
            Print("Error: Autotrading disabled by client terminal");
            break;
        case TRADE_RETCODE_LOCKED:
            Print("Error: Request locked for processing");
            break;
        case TRADE_RETCODE_FROZEN:
            Print("Error: Order or position frozen");
            break;
        case TRADE_RETCODE_INVALID_FILL:
            Print("Error: Invalid order filling type");
            break;
        case TRADE_RETCODE_CONNECTION:
            Print("Error: No connection to trading server");
            break;
        case TRADE_RETCODE_ONLY_REAL:
            Print("Error: Operation allowed only for live accounts");
            break;
        case TRADE_RETCODE_LIMIT_ORDERS:
            Print("Error: Pending orders limit reached");
            break;
        case TRADE_RETCODE_LIMIT_VOLUME:
            Print("Error: Volume limit for orders and positions reached");
            break;
        default:
            Print("Unknown error: ", errorCode);
            break;
    }
}

Overall, this EA represents a complex trading system that combines order flow analysis with traditional technical indicators and advanced risk management techniques. It's designed for experienced traders and should be thoroughly tested before live deployment.

Note:  High-impact news events function is not done, this I will leave it for you to finish it.



Backtesting

This EA also works in 5, 15 and 30 minutes time periods.

You must analyze well all time periods and Optimize the EA before thinking of trading with it.

This are the results for 15 minutes time period

Settings 15 min

Inputs 15 min

Graph 15 min

Backtesting 15 min

Using data from 15-minute charts, this backtesting research sheds light on how a trading strategy performed on the EURUSD currency pair from 2000 to 2025. With a 1:100 leverage ratio and a starting deposit of $3000 USD, the account size was comparatively modest, and the high leverage may magnify both profits and losses. During the backtesting period, the approach yielded a modest 4.19% return on the initial 3000 USD deposit, with a total net profit of 125.83 USD.

With 1.13 USD in earnings for every $1 in losses, the strategy appears to have been slightly profitable overall, as indicated by the profit factor of 1.13. 364 trades were performed in total, comprising 167 long trades and 197 short trades. Good trade selection was indicated by the high win rates, which were 73.60% for short trades and 86.23% for long transactions.

The method appeared to have tiny wins but higher losses when trades went against it, since the average profit per winning transaction (3.71) was considerably smaller than the average loss per losing trade (-12.62 USD). There was a maximum of 15 deals with wins and a maximum of 5 trades with losses. The biggest trade that resulted in a profit was 50.22 USD, while the biggest loss was -66.10 USD.

The strategy's greatest drawdown on the equity curve was 5.63%, which is an acceptable amount of loss and indicates prudent risk management. The strategy produced returns that adequately offset the degree of risk assumed, as evidenced by the 1.83 Sharpe ratio.

All things considered, it looks like this is a high-frequency scalping approach that seeks to make lots of little, successful trades while occasionally suffering bigger losses. CopyRetryClaude can make mistakes, as evidenced by its high win rate and smaller profit factor, which might make it vulnerable to significant losses in the event that market conditions shift. Please check your answers again.

5 minutes time frame

Settings 5 min

Inputs 5 min

Graph 5 min

Backtesting 5 min

Using data from 5-minute charts, this backtesting research looks at how a trading strategy performed on the EURUSD currency pair between January 1, 2000, and February 1, 2025. The technique uses an initial deposit of $3000 USD with a 1:100 leverage, which indicates a relatively small account size with high leverage that has the potential to magnify gains as well as losses.

According to the backtesting results, the initial 3000 USD deposit resulted in a total net profit of 150.32 USD, or a modest 5.01% return over the course of 25 years. A total of 1732 transactions were completed using the strategy, comprising 1023 short trades and 709 long positions. Good trade selection was evident in both directions as seen by the high win rates of 81.82% and 81.95% for the short and long trades, respectively.

The method appeared to have many minor wins but huge losses when trades went against it, as the average profit per winning trade (2.27) was much smaller than the average loss per losing trade (-9.79 USD). With 1.05 USD in gains for every $1 in losses, the strategy was only slightly lucrative overall, as indicated by the profit factor of 1.05. The strategy's greatest drawdown on the equity curve was 9.95%, which is a reasonable amount but might raise questions for risk management.

The approach appears to have produced returns that only marginally offset the level of risk incurred, as indicated by the Sharpe ratio of 0.92. The equity curve generally indicates an upward tendency, however there are notable oscillations and downturns.

The method parameters recommend using a complicated multi-factor approach to trade decisions by using a variety of technical indicators, such as ADX, RSI moving averages, and Bollinger Bands. All things considered, it looks like this is a high-frequency scalping approach that seeks to make lots of little, successful trades while occasionally suffering bigger losses. It may find it difficult to provide substantial returns over time and may be susceptible to major drawdowns in unfavorable market situations given its high win rate but low profit component.


Conclusion

Using cutting edge risk management tools, this expert advisor for MetaTrader 5 applies a complex Order Flow scalping approach. It uses a combination of various technical indicators, order flow analysis, and dynamic position size to find high-probability forex trading opportunities. Backtesting the EA on different timeframes for the EURUSD pair, especially on 15-minute and 5-minute intervals, indicates potential.

Still, the outcomes point to both advantages and disadvantages. Despite the strategy's high win rates and modest profitability, it may not be able to produce large returns due to its low profit factor and relatively minor gains over extended testing durations. Due to its propensity for frequent small wins to be offset by bigger, sporadic losses, the method may be susceptible to significant drawdowns in the event of unfavorable market conditions.



Attached files |
SO_Final.mq5 (58.46 KB)
Last comments | Go to discussion (4)
Kevin Spreier
Kevin Spreier | 19 Sep 2024 at 19:20
Where is AnalyzeOrderFlow()?
Javier Santiago Gaston De Iriarte Cabrera
Kevin Spreier #:
Where is AnalyzeOrderFlow()?

line 285                      

damhi
damhi | 21 Sep 2024 at 02:16
Javier Santiago Gaston De Iriarte Cabrera #:

line 285                      

Where is the other functions ()?
Javier Santiago Gaston De Iriarte Cabrera
damhi #:
Where is the other functions ()?

I will have it in mind for next Articles. You can still download the script, and look them.

Introduction to Connexus (Part 1): How to Use the WebRequest Function? Introduction to Connexus (Part 1): How to Use the WebRequest Function?
This article is the beginning of a series of developments for a library called “Connexus” to facilitate HTTP requests with MQL5. The goal of this project is to provide the end user with this opportunity and show how to use this helper library. I intended to make it as simple as possible to facilitate study and to provide the possibility for future developments.
Self Optimizing Expert Advisor With MQL5 And Python (Part IV): Stacking Models Self Optimizing Expert Advisor With MQL5 And Python (Part IV): Stacking Models
Today, we will demonstrate how you can build AI-powered trading applications capable of learning from their own mistakes. We will demonstrate a technique known as stacking, whereby we use 2 models to make 1 prediction. The first model is typically a weaker learner, and the second model is typically a more powerful model that learns the residuals of our weaker learner. Our goal is to create an ensemble of models, to hopefully attain higher accuracy.
MQL5 Wizard Techniques you should know (Part 40): Parabolic SAR MQL5 Wizard Techniques you should know (Part 40): Parabolic SAR
The Parabolic Stop-and-Reversal (SAR) is an indicator for trend confirmation and trend termination points. Because it is a laggard in identifying trends its primary purpose has been in positioning trailing stop losses on open positions. We, however, explore if indeed it could be used as an Expert Advisor signal, thanks to custom signal classes of wizard assembled Expert Advisors.
Developing a Replay System (Part 46): Chart Trade Project (V) Developing a Replay System (Part 46): Chart Trade Project (V)
Tired of wasting time searching for that very file that you application needs in order to work? How about including everything in the executable? This way you won't have to search for the things. I know that many people use this form of distribution and storage, but there is a much more suitable way. At least as far as the distribution of executable files and their storage is concerned. The method that will be presented here can be very useful, since you can use MetaTrader 5 itself as an excellent assistant, as well as MQL5. Furthermore, it is not that difficult to understand.