MQL5 Algorithmic Trading Architecture: EA Design, Risk Control, and Order Flow

目次

Key Takeaway

MQL5 algorithmic trading architecture is the idea of designing an EA as more than a set of entry and exit conditions. It separates state management, risk control, pre-order checks, and post-execution management.
When market analysis, filter checks, signal checks, lot calculation, order submission, and position management are separated, the EA becomes easier to test and maintain.
In MQL5, the basic structure is to place processing around event functions such as OnInit, OnTick, and OnDeinit, then create indicator handles and retrieve indicator values with CopyBuffer.
For live trading, you should not judge an EA by backtest results alone. You need to confirm spreads, execution differences, broker specifications, and acceptable drawdown through forward testing.

1. Why This Design Is Necessary

Conclusion:
In MQL5 EA design, you need an overall structure that includes state management and risk control, not just trading conditions.
Because an EA is processed on every tick, you need to manage the current market state, existing positions, order availability, and stop conditions separately.

An MQL5 Expert Advisor mainly receives new ticks and processes them in OnTick.
However, if every condition is written directly inside OnTick, adding conditions and investigating bugs becomes difficult.

In algorithmic trading architecture, an EA is designed as the following process flow.

Market analysis
->
Filter check
->
Signal check
->
Risk check
->
Pre-order check
->
Order submission
->
Post-execution management
->
Exit and stop decision

With this structure, it becomes easier to track which condition allowed a trade and which condition blocked it.

1.1 Why EAs Built Only with Conditional Branches Break Easily

An EA built only with conditional branches becomes harder to understand as more features are added.
For example, if trend detection, lot calculation, existing position checks, and order submission are all written in the same place, one change can easily affect another process.

In an MQL5 EA, trading state changes depending on the account type and symbol specifications.
In a netting account, positions for the same symbol are merged. In a hedging account, multiple positions can be held, so the assumptions for position management are different.

1.2 Separating the Design Makes Testing Easier

When EA processing is separated, it becomes easier to isolate causes during backtesting.
If the number of trades is low, the filters may be too strict.
If losses are large, you can check lot calculation, stop-loss width, spread conditions, and exit logic individually.

MQL5 algorithmic trading architecture does not guarantee the accuracy of trade decisions.
The purpose of separating the design is to make testing, maintenance, and risk review easier.

2. Overall EA Design Concept

Conclusion:
An MQL5 EA should be designed around event-driven processing, with initialization, tick processing, and shutdown processing separated.
The basic structure is to prepare in OnInit, make decisions in OnTick, and perform cleanup in OnDeinit.

In MQL5 EA design, it is important to separate responsibilities by event function.
An EA is not a single process that runs continuously. It processes ticks, timers, trade events, and other events as they occur.

Event FunctionMain RoleUse in EA Design
OnInitInitialization processingCreate indicator handles, validate input values, set the initial state
OnTickProcessing when a tick is receivedSignal checks, pre-order checks, position management
OnDeinitCleanup processing at shutdownRelease handles, output logs, perform shutdown processing
OnTimerTimer processingPeriodic monitoring and time-based state updates
OnTradeTransactionDetailed trade event processingTrack orders, executions, and position changes
MQL5 EA architecture diagram showing OnInit, OnTick, CopyBuffer, OrderCheck, OrderSend, and risk control flow

2.1 What to Prepare in OnInit

In OnInit, you prepare what the EA needs in order to run.
When using indicators such as moving averages, ATR, and RSI, MQL5 functions often return an indicator handle instead of returning a value directly.

After creating a handle, check that it is not INVALID_HANDLE.
If OnTick processing continues after initialization has failed, CopyBuffer can fail and trade decisions can become unstable.

2.2 What to Run in OnTick

In OnTick, the EA runs its main process each time it receives a new tick.
However, order processing does not need to run on every tick.

A practical EA usually processes tasks in this order.

  1. Check whether trading is allowed
  2. Retrieve the required indicator values
  3. Check existing positions
  4. Evaluate filter conditions
  5. Evaluate signal conditions
  6. Check lot size and risk
  7. Run a pre-order check with OrderCheck
  8. Submit the order with OrderSend
  9. Log the result

2.3 Why Cleanup Belongs in OnDeinit

In OnDeinit, you perform cleanup when the EA ends.
If you created indicator handles, release them with IndicatorRelease as needed.

When shutdown processing is clearly defined, it becomes easier to manage state during chart changes, EA stops, and parameter changes.

3. Basic Structure

Conclusion:
The basic structure of an MQL5 EA separates initialization, tick processing, and shutdown processing, then builds each process as functions.
Instead of writing all processing directly inside OnTick, separating the logic into role-based functions makes the EA easier to maintain.

The basic structure looks like this.

#property strict

int maHandle = INVALID_HANDLE;

int OnInit()
{
   maHandle = iMA(_Symbol, _Period, 20, 0, MODE_SMA, PRICE_CLOSE);

   if(maHandle == INVALID_HANDLE)
   {
      Print("Failed to create MA handle");
      return INIT_FAILED;
   }

   return INIT_SUCCEEDED;
}

void OnDeinit(const int reason)
{
   if(maHandle != INVALID_HANDLE)
   {
      IndicatorRelease(maHandle);
      maHandle = INVALID_HANDLE;
   }
}

void OnTick()
{
   if(!IsTradingEnvironmentReady())
      return;

   if(!UpdateMarketData())
      return;

   if(HasOpenPosition())
   {
      ManageOpenPosition();
      return;
   }

   if(!PassesFilters())
      return;

   if(!HasEntrySignal())
      return;

   ExecuteEntry();
}

This code is a test sample that shows the design skeleton.
In live trading, you also need to check symbol specifications, account type, stop levels, spreads, margin, and trading hours.

3.1 Separate State with Functions

The purpose of separating functions is to make each process responsible for one clear role.
For example, PassesFilters evaluates market conditions, while HasEntrySignal evaluates only the trade signal.

This separation lets you check filter bugs and signal bugs separately.

3.2 Use Return Values to Show Whether Processing Can Continue

In an MQL5 EA, using bool return values for decision functions makes the processing flow easier to read.
If processing cannot continue, return false and return from the OnTick side.

A design that records nothing when an error occurs should be avoided.
Logging CopyBuffer failures, pre-order check failures, and OrderSend failures makes it easier to investigate differences between backtests and live operation.

4. Roles of the Main Modules

Conclusion:
The main EA modules should be separated into market analysis, filters, signals, lot calculation, pre-order checks, order execution, position management, and risk control.
Separating each module clarifies what needs to be tested and makes over-optimization easier to avoid.

ModuleRoleMain Items to Check
Market analysisDetermines trend, range, and volatilityMA, ATR, ADX, higher timeframes
Filter checkDetermines whether the environment is suitable for tradingSpread, time of day, volatility
Signal checkDetermines entry conditionsCrossovers, breakouts, reversal conditions
Lot calculationDetermines position size based on acceptable riskMinimum lot, maximum lot, lot step
Pre-order checkChecks whether the order can be placedOrderCheck, margin, stop level
Order executionSends the order with MqlTradeRequestOrderSend, MqlTradeResult
Position managementManages open positionsExit, trailing stop, partial close
Risk controlLimits expanding losses and excessive tradingDrawdown, losing streaks, daily loss

4.1 Market Analysis Module

The market analysis module is the part where the EA judges the current market state.
It may check direction with a moving average, measure volatility with ATR, or confirm the broader trend on a higher timeframe.

When using indicators, create the handle in OnInit and retrieve values from CopyBuffer in OnTick.
Because the latest bar is still forming and its value changes, you need to decide during design whether to use the closed bar or the latest bar.

4.2 Risk Control Module

The risk control module is a mechanism for limiting expanding losses, not for increasing trade opportunities.
You can design the EA to pause trading based on daily loss, maximum drawdown, number of consecutive losses, number of trades, spread expansion, and similar conditions.

Backtest results do not guarantee future profit.
Risk control should be designed to prepare for unexpected market changes and worsening execution conditions.

4.3 Pre-Order Check Module

In the pre-order check, confirm whether trading is possible before OrderSend.
In MQL5, you set order details in MqlTradeRequest and use OrderCheck as needed to confirm margin and trading conditions.

The items to check are as follows.

  • Whether trading is allowed
  • Whether the spread is within the acceptable range
  • Whether the lot size matches the minimum lot, maximum lot, and lot step
  • Whether the stop loss and take profit satisfy the stop level
  • Whether the required margin is available
  • Whether the symbol is within trading hours
  • Whether the differences between netting and hedging accounts are considered

5. Implementation Patterns

Conclusion:
Common MQL5 EA implementation patterns include the single-function pattern, function-separated pattern, class-separated pattern, and state-management pattern.
For intermediate and more advanced EAs, the function-separated pattern or state-management pattern is better for testing and expansion.

Choose the implementation pattern based on the size and purpose of the EA.
A simple structure may be enough for a small testing EA, but an EA intended for live trading needs clear state management.

5.1 Function-Separated Pattern

The function-separated pattern calls multiple decision functions from OnTick.
It is not too difficult to implement, and it is a practical way for beginner to intermediate developers to organize the design.

bool PassesSpreadFilter()
{
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

   if(ask <= 0.0 || bid <= 0.0)
   {
      Print("Invalid bid or ask");
      return false;
   }

   double spreadPoints = (ask - bid) / _Point;
   int maxSpreadPoints = 30;

   if(spreadPoints > maxSpreadPoints)
   {
      Print("Spread is too wide: ", spreadPoints);
      return false;
   }

   return true;
}

This sample shows the basic form of a spread filter.
In live trading, you need to test the threshold while considering the symbol’s normal spread, time of day, and volatility before and after major economic releases.

5.2 State-Management Pattern

The state-management pattern explicitly defines the EA’s state and switches processing based on that state.
For example, the EA can have states such as WAIT_SIGNAL, READY_TO_ORDER, POSITION_OPEN, and STOPPED.

enum EAState
{
   STATE_WAIT_SIGNAL,
   STATE_READY_TO_ORDER,
   STATE_POSITION_OPEN,
   STATE_STOPPED
};

EAState currentState = STATE_WAIT_SIGNAL;

void UpdateState()
{
   if(IsRiskLimitReached())
   {
      currentState = STATE_STOPPED;
      return;
   }

   if(HasOpenPosition())
   {
      currentState = STATE_POSITION_OPEN;
      return;
   }

   if(PassesFilters() && HasEntrySignal())
   {
      currentState = STATE_READY_TO_ORDER;
      return;
   }

   currentState = STATE_WAIT_SIGNAL;
}

When state is explicit, it becomes easier to explain why the EA is not placing orders or why it has stopped.
For multi-currency EAs and multi-logic EAs, state management has a large impact on maintainability.

6. Sample Code

Conclusion:
In an MQL5 architecture sample, indicator handles, CopyBuffer, lot normalization, OrderCheck, and OrderSend should be implemented separately.
Treat order processing as a testing example, and check symbol specifications and account conditions before live operation.

The following code is a simple design sample using a moving average.
It does not demonstrate an advantage in the trading logic. It is an implementation example for explaining the structure of an MQL5 EA.

#property strict

input double RiskPercent = 1.0;
input int    MAPeriod = 20;
input int    MaxSpreadPoints = 30;

int maHandle = INVALID_HANDLE;

int OnInit()
{
   maHandle = iMA(_Symbol, _Period, MAPeriod, 0, MODE_SMA, PRICE_CLOSE);

   if(maHandle == INVALID_HANDLE)
   {
      Print("Failed to create MA handle");
      return INIT_FAILED;
   }

   return INIT_SUCCEEDED;
}

void OnDeinit(const int reason)
{
   if(maHandle != INVALID_HANDLE)
   {
      IndicatorRelease(maHandle);
      maHandle = INVALID_HANDLE;
   }
}

void OnTick()
{
   if(!PassesBasicChecks())
      return;

   if(HasOpenPosition())
      return;

   double maValue = 0.0;
   if(!GetMAValue(maValue))
      return;

   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double closePrice = iClose(_Symbol, _Period, 1);

   if(closePrice > maValue)
   {
      SendBuyOrder(0.10);
   }
}

bool PassesBasicChecks()
{
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

   if(ask <= 0.0 || bid <= 0.0)
   {
      Print("Invalid market price");
      return false;
   }

   double spreadPoints = (ask - bid) / _Point;
   if(spreadPoints > MaxSpreadPoints)
   {
      Print("Spread filter blocked trading: ", spreadPoints);
      return false;
   }

   long tradeMode = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_MODE);
   if(tradeMode == SYMBOL_TRADE_MODE_DISABLED)
   {
      Print("Trading is disabled for this symbol");
      return false;
   }

   return true;
}

bool GetMAValue(double &value)
{
   if(BarsCalculated(maHandle) < MAPeriod)
   {
      Print("Not enough calculated bars");
      return false;
   }

   double maBuffer[];
   ArraySetAsSeries(maBuffer, true);

   int copied = CopyBuffer(maHandle, 0, 1, 1, maBuffer);
   if(copied < 1)
   {
      Print("CopyBuffer failed or not enough data");
      return false;
   }

   value = maBuffer[0];
   return true;
}

bool HasOpenPosition()
{
   return PositionSelect(_Symbol);
}

void SendBuyOrder(double lots)
{
   double normalizedLots = NormalizeLots(lots);
   if(normalizedLots <= 0.0)
   {
      Print("Invalid lot size");
      return;
   }

   MqlTradeRequest request;
   MqlTradeResult result;
   MqlTradeCheckResult check;

   ZeroMemory(request);
   ZeroMemory(result);
   ZeroMemory(check);

   request.action = TRADE_ACTION_DEAL;
   request.symbol = _Symbol;
   request.volume = normalizedLots;
   request.type = ORDER_TYPE_BUY;
   request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   request.deviation = 20;
   request.type_filling = ORDER_FILLING_FOK;

   if(!OrderCheck(request, check))
   {
      Print("OrderCheck failed. Retcode: ", check.retcode);
      return;
   }

   if(check.retcode != TRADE_RETCODE_DONE)
   {
      Print("OrderCheck rejected request. Retcode: ", check.retcode);
      return;
   }

   if(!OrderSend(request, result))
   {
      Print("OrderSend failed. Retcode: ", result.retcode);
      return;
   }

   if(result.retcode != TRADE_RETCODE_DONE && result.retcode != TRADE_RETCODE_PLACED)
   {
      Print("Order was not completed. Retcode: ", result.retcode);
      return;
   }

   Print("Buy order sent. Ticket: ", result.order);
}

double NormalizeLots(double lots)
{
   double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double stepLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

   if(minLot <= 0.0 || maxLot <= 0.0 || stepLot <= 0.0)
      return 0.0;

   lots = MathMax(minLot, MathMin(maxLot, lots));
   lots = MathFloor(lots / stepLot) * stepLot;

   return NormalizeDouble(lots, 2);
}

6.1 Important Points in the Code

In this sample, OnInit creates a moving average handle, and OnTick makes decisions using the value of a closed bar.
Because CopyBuffer specifies shift 1, it retrieves the value of the most recently closed bar, not the latest bar that is still forming.

Using OrderCheck before OrderSend lets you check margin and trading conditions in advance.
However, passing OrderCheck does not guarantee actual execution.
OrderSend results can change depending on market movement, spreads, execution method, and broker conditions.

6.2 Do Not Stop at Fixed Lot Calculation

The sample passes a fixed lot size to keep the explanation simple.
In a real design, lot size is calculated using account balance, equity, stop-loss width, tick value, tick size, minimum lot, maximum lot, and lot step.

Fixed lots are easy to implement, but they do not adapt well to changes in account capital.
Risk-percentage-based lot calculation makes it easier to connect stop-loss width with acceptable loss.

7. Design Pattern Comparison

Conclusion:
In MQL5 EA design, state-management and module-separated patterns become more useful as the EA grows.
However, excessive abstraction makes testing harder, so split only what is necessary for the EA’s purpose.

MethodAdvantagesDisadvantagesBest Use CaseImplementation Difficulty
Single-function patternCan be written quicklyBreaks easily as conditions increaseSmall testing EALow
Function-separated patternEasy to follow processingRequires care when sharing state between functionsMedium-size EAMedium
Class-separated patternEasy to modularizeDesign can become excessiveEA with multiple featuresHigh
State-management patternEasy to explain the EA’s stateRequires state transition designEA intended for live tradingMedium to high
Multi-currency management patternSuitable for portfolio managementState management for each symbol becomes complexMulti-currency EAHigh

7.1 A Good Structure for Intermediate Developers

For intermediate developers, a good structure is to use the function-separated pattern as the base and add state management only where needed.
If you start with a large class design, the design itself can become more complex than the trading logic.

If the EA’s purpose is testing a single logic, the function-separated pattern may be enough.
If the EA handles multiple logics, multiple currencies, risk stops, or re-entry control, consider the state-management pattern.

7.2 How to Avoid Over-Engineering

The purpose of separating the design is not to make the EA complicated.
The purpose is to separate what you want to test and make the results easier to explain.

If market analysis and signal checks are mixed, it becomes hard to identify what affected performance.
If lot calculation and entry conditions are mixed, changing risk settings may also change the trading conditions.

8. What to Check in Backtesting

Conclusion:
In backtesting, check not only total profit and loss but also maximum drawdown, number of trades, losing streaks, spread conditions, and parameter dependency.
Even if an EA appears to perform well, reproducibility tends to be low when it depends only on a specific period or specific parameters.

Backtesting is the process of checking whether the EA structure works as intended.
It does not guarantee future profit.

The items to check are as follows.

Check ItemReason to CheckNotes
Total profit and lossUnderstand the overall profit and loss trendDo not judge by this alone
Maximum drawdownCheck the size of capital declineDecide the acceptable range in advance
Win rateCheck the percentage of successful tradesReview together with the profit/loss ratio
Profit/loss ratioCheck the relationship between average profit and average lossA high win rate can still have a poor profit/loss ratio
Number of tradesConfirm the sample sizeIf it is too low, judgment becomes difficult
Losing streaksCheck the impact on money managementReview together with lot design
Spread conditionsCheck differences from live tradingDo not depend only on fixed spreads
Period dependencyCheck whether the EA is strong only in a specific marketTest across multiple periods
Parameter dependencyFind over-optimizationCheck whether performance collapses at nearby values

8.1 Check for Over-Optimization

Over-optimization means the EA has been fitted too closely to past data.
If performance is good only for a specific MA period, ATR multiplier, or time of day, it can break down easily in forward testing.

If performance worsens sharply after only a small parameter change, you need to carefully check the reproducibility of the logic.

8.2 Use Logs to Find Design Mistakes

EA logs become easier to use for testing when they record why trades were not placed.
For example, record spread exceeded, filter mismatch, OrderCheck failure, existing position present, risk limit reached, and similar reasons.

An EA without logs makes it hard to later trace why the number of trades was low in a backtest.

9. What to Check in Forward Testing

Conclusion:
In forward testing, check execution differences, spread expansion, trading frequency, and stability in a VPS environment, which are hard to see in backtesting.
It is common for backtest and forward-test results to differ, so test with the assumption that differences will occur.

Forward testing is the process of checking how the EA behaves in the current market environment.
Execution conditions may differ between demo accounts and live accounts.

The items to check are as follows.

  • The difference between executed price and expected price
  • Behavior when spreads widen
  • Actual trading frequency
  • How drawdown appears
  • Deviation from backtesting
  • Differences between brokers
  • Operating stability in a VPS environment
  • Whether trading stop conditions work as intended

9.1 Check Differences in Execution Conditions

Execution delay, slippage, and spread expansion are factors that cannot be fully reproduced in backtesting.
Especially for short-term trading EAs or EAs targeting small profit margins, even a small execution difference can greatly affect performance.

Even if OrderSend succeeds, execution at the expected price is not guaranteed.
Order results change depending on the execution method and liquidity.

9.2 Confirm That Stop Conditions Work

In forward testing, also check loss limits and trading stop conditions.
If maximum drawdown, daily loss, losing streak count, spread limits, and similar controls do not work correctly, losses may exceed expectations.

Stop conditions are design elements that are just as important as trading conditions.

10. Notes for Live Operation

Conclusion:
When running an MQL5 EA live, check not only the logic’s performance but also broker specifications, account type, spreads, execution method, leverage, and VPS stability.
EA design is not a mechanism that eliminates losses. It is a structure that makes risk easier to understand.

In live operation, differences can appear that are hard to see in backtests or demo accounts.
Spread expansion, order rejection, out-of-hours trading, stop-level changes, and insufficient margin can occur.

10.1 Differences in Account Type

In a netting account, positions for the same symbol are merged into one position.
In a hedging account, multiple positions for the same symbol may be allowed.

If the design relies only on PositionSelect, account type may cause management that differs from your intent.
For EAs that handle multiple positions, also consider ticket-level management and magic number management.

10.2 Differences in Symbol Specifications

Minimum lot, maximum lot, lot step, tick size, tick value, stop level, and freeze level differ by symbol.
If lot calculation or stop-loss width is handled as a fixed value, orders may fail on another symbol.

When using an EA across multiple symbols, retrieve symbol specifications with SymbolInfoDouble and SymbolInfoInteger before making decisions.

10.3 Leverage and Drawdown

Higher leverage allows larger positions with less margin.
At the same time, profit and loss changes from price movement can become larger, and drawdown may expand.

In live operation, it is important to decide the acceptable maximum drawdown in advance and set trading stop conditions in the EA.

11. Common Design Mistakes

Conclusion:
Common design mistakes include writing all processing in OnTick, ignoring CopyBuffer failures, skipping checks before OrderSend, and ignoring lot limits.
These mistakes can be hard to notice in backtesting and may lead to unstable behavior in live operation.

11.1 Confusing the Latest Bar with a Closed Bar

The latest bar is still forming, and its value changes on each tick.
A closed bar has already closed, and its value is fixed.

Using shift 0 in CopyBuffer retrieves the latest bar.
Using shift 1 retrieves the most recently closed bar.
You need to make clear which one the logic assumes.

11.2 Not Checking the Return Value of CopyBuffer

CopyBuffer does not always retrieve the requested number of values.
If processing continues when the number of retrieved values is insufficient, decisions may be made using uninitialized or old values.

If the number of retrieved values is less than expected, a safer design is to avoid order decisions, log the issue, and return.

11.3 Judging Orders Only with OrderSend

If you rely only on OrderSend, it becomes easy to miss problems that could be checked before order submission.
Using OrderCheck lets you confirm margin, trading conditions, and request details in advance.

However, passing OrderCheck does not guarantee execution.
Results can change depending on price movement and broker conditions at the time the order is sent.

11.4 Ignoring Lot Limits

Lot calculation must always consider minimum lot, maximum lot, and lot step.
If the calculated lot does not match the symbol specifications, the order may fail.

For risk-percentage-based lot calculation, also check stop-loss width, tick value, tick size, and equity.

12. Summary

Conclusion:
In MQL5 algorithmic trading architecture, an EA is designed by separating market analysis, filters, signals, risk management, pre-order checks, order execution, and position management.
Separating the design creates an EA that is easier to test, easier to trace, and easier to manage for live trading risk.

In MQL5, the basic structure is to prepare in OnInit, make decisions in OnTick, and clean up in OnDeinit.
When using indicator values, create handles, retrieve values with CopyBuffer, and always include processing for retrieval failures.

For order processing, use MqlTradeRequest, MqlTradeResult, and MqlTradeCheckResult, then check order details with OrderCheck before OrderSend.
In live operation, do not rely only on backtesting. Run forward tests and check spreads, execution differences, broker specifications, account type, and drawdown.

FAQ

Q1. What is MQL5 algorithmic trading architecture?

MQL5 algorithmic trading architecture is the practice of designing an EA by separating state management, risk control, pre-order checks, and position management instead of building it only from trading conditions. This makes testing easier and helps trace issues during live operation.

Q2. Can I write all processing inside OnTick in an MQL5 EA?

You can do this for a small testing EA, but practical EAs are easier to maintain when processing is separated into functions or modules. A clear structure is to keep the process flow in OnTick and move detailed checks into separate functions.

Q3. What is the basic way to get indicator values in MQL5?

The basic MQL5 structure is to create an indicator handle in OnInit and retrieve values with CopyBuffer in OnTick. If the number of retrieved values is insufficient, the EA should stop before making a trade decision.

Q4. Is OrderCheck necessary before OrderSend?

Using OrderCheck before OrderSend makes it easier to find margin and trading-condition problems before submitting the order. However, passing OrderCheck does not guarantee actual execution.

Q5. What is the problem with using only fixed lots in EA design?

Fixed lots are easy to implement, but they do not adapt well to changes in account balance or stop-loss width. For live operation, the design should consider minimum lot, maximum lot, lot step, acceptable risk, and stop-loss width.

Q6. What should I pay the most attention to in backtesting?

In backtesting, check maximum drawdown, number of trades, losing streaks, spread conditions, and parameter dependency, not only total profit and loss. Backtest results do not guarantee future profit, so forward testing is also necessary.

Q7. Do netting and hedging account differences affect EA design?

Yes. In a netting account, positions for the same symbol are merged, while in a hedging account, multiple positions may be held for the same symbol. This affects position management, exit management, and magic number management.

Q8. What risks should be checked before live operation?

Before live operation, check spread expansion, execution delay, slippage, broker specifications, leverage, maximum drawdown, and VPS stability. Demo and live accounts may have different execution conditions.