Robust MQL5 Trading System Design: Signals, Filters, Risk Checks, and OrderCheck

目次

Conclusion of This Article

To build a robust trading system in MQL5, you need to design not only trading signals but also filters, risk checks, pre-order checks, position management, and validation conditions as separate parts.
An EA is less likely to fail when it checks market conditions, account conditions, symbol specifications, and execution conditions in order, instead of simply placing an order when conditions match.
The core flow for improving robustness is to create the required handles in OnInit, evaluate conditions in OnTick, retrieve values with CopyBuffer, and confirm order validity with OrderCheck before sending an order.
However, no matter how well the design is organized, backtest results do not guarantee future profit. Before live operation, you must use forward testing to check differences in spreads, execution, and broker specifications.

1. Role of This Logic

[Conclusion]
A robust MQL5 trading system is a design that controls EA behavior through multiple validation steps instead of relying on a single trading condition.
Its purpose is not to guarantee profit. Its purpose is to reduce malfunctions, overtrading, unchecked orders, and logic that cannot be properly validated.

[Definition]
A robust trading system is an EA design that separates signals, filters, risk management, order handling, position management, and validation procedures so that behavior is easier to verify when conditions change.

EA robustness is not determined only by the complexity of entry conditions.
Even a simple moving average crossover can become easy to validate if spread checks, lot limits, margin checks, existing position checks, and exit conditions are organized.

By contrast, an EA that only adds more signals makes it harder to know which condition affected performance.
In a robust design, the following flow is considered separately.

Market recognition
↓
Filter evaluation
↓
Signal evaluation
↓
Risk check
↓
Pre-order check
↓
Order submission
↓
Post-execution management
↓
Exit and stop evaluation

1.1 When Robustness Becomes Necessary

In MQL5 EAs, a system may work in a backtest but fail to behave the same way in live operation.
The main reason is that spreads, execution methods, slippage, trading hours, stop levels, account types, and symbol specifications differ by environment.

A robust EA does not force an order when conditions are not suitable.
It logs the reason why an order could not be placed and uses a structure that can evaluate the conditions again on the next tick.

1.2 Difference Between Logic and System Design

Trading logic is the part that decides whether to buy, sell, or stay out.
Trading system design is the overall structure that allows the trading logic to run safely.

In an MQL5 EA, you can write all processing inside OnTick.
However, if processing is not separated, it becomes difficult to isolate the cause of errors, performance deterioration, or execution failures.

2. Basic Concept

[Conclusion]
In a robust EA design, you check whether trading is allowed before checking the signal.
The basic structure is to confirm market conditions, account conditions, symbol conditions, existing positions, and risk tolerance before moving to entry evaluation.

MQL5 EAs mainly run using OnInit, OnTick, and OnDeinit.
OnInit handles initialization, OnTick performs evaluation on each tick, and OnDeinit performs cleanup when the EA stops.

When using indicator values, many MQL5 indicator functions return handles instead of returning values directly.
The EA creates handles in OnInit and retrieves values in OnTick by using CopyBuffer.

2.1 Evaluate Tradability First

In a robust EA, check the following items before checking trading signals.

  • Whether automated trading is allowed
  • Whether the symbol is tradable
  • Whether the spread is within the allowed range
  • Whether existing positions violate the rules
  • Whether margin is insufficient
  • Whether the lot size matches the minimum lot, maximum lot, and lot step
  • Whether stop levels and freeze levels are violated
  • Whether it is outside trading hours

Performing these checks first makes it easier to exclude situations where an order should not be placed even if a signal appears.

2.2 Separate Signals and Filters

A signal is a condition that determines entry direction or timing.
A filter is a condition that determines whether to accept or skip the signal.

For example, a design may use a moving average crossover as the signal, ATR to exclude low-volatility markets, and a higher-timeframe moving average to confirm direction.
In this case, logging each condition separately makes it easier to confirm which condition stopped the trade.

3. Common Design Patterns

[Conclusion]
In a robust trading system, a staged design that separates signals, filters, risk control, and pre-order checks is easier to manage than a single-signal design.
However, adding too many conditions can increase the risk of over-optimization.

Common design patterns are as follows.

MethodAdvantagesDisadvantagesBest Use Case
Single-signal typeEasy to implement and validateWeak against changes in market conditionsInitial validation and learning EAs
Signal + trend filter typeEasy to confirm directionMay increase missed opportunities in ranging marketsTrend-following EAs
Signal + volatility filter typeEasy to exclude low volatility or sudden volatilityBecomes highly dependent on thresholds such as ATRBreakouts and stop-loss width adjustment
State management typeEasy to handle position status and stop conditionsRequires more implementation workEAs intended for live operation
Risk-control-first typeEasy to include drawdown managementMay reduce trading opportunitiesEAs focused on money management

3.1 Single-Signal Type

The single-signal type is a structure that makes trading decisions using a small number of conditions, such as a moving average crossover or RSI condition.
It is suitable for learning and initial validation, but it may not sufficiently avoid spread widening or ranging markets.

Even when using a single-signal type, it is safer not to omit pre-order checks and lot limits.

3.2 State Management Type

In the state management type, the EA state is clearly separated.
For example, you can use states such as waiting, holding a buy position, holding a sell position, trading stopped, and rechecking after an error.

Separating states makes it easier to reduce problems such as placing multiple orders on the same tick or unintentionally re-entering immediately after closing a position.

4. Implementation Method

[Conclusion]
When implementing a robust EA in MQL5, use a flow that creates indicator handles in OnInit, retrieves values and evaluates conditions in OnTick, and checks validity with OrderCheck before sending an order.
Separating processing into functions makes cause analysis and validation easier.

The minimum implementation units can be separated as follows.

  • UpdateMarketData(): Updates indicator values and price information
  • IsTradingAllowedNow(): Checks whether trading is currently allowed
  • CheckFilters(): Evaluates filter conditions
  • CheckSignal(): Evaluates trading signals
  • CalculateLot(): Calculates lot size
  • SendCheckedOrder(): Sends an order after OrderCheck
  • ManagePosition(): Manages open positions

4.1 Initialize Indicator Handles

In MQL5, when using indicators such as moving averages or ATR in an EA, the usual flow is to create a handle first and then retrieve values with CopyBuffer.
If a handle is INVALID_HANDLE, stopping the EA as an initialization failure makes it easier to identify the cause.

4.2 Evaluate on Closed Bars

The latest bar is still forming, so its value changes on each tick.
If you want to stabilize signals, use array index 1 and evaluate conditions using the value of the closed bar.

Some designs use the latest bar, but behavior can differ more easily between backtests and live operation.
For beginner to intermediate EA development, a structure that evaluates closed bars first is easier to handle.

MQL5 robust EA execution flow with OnInit, CopyBuffer, OrderCheck, risk control, and OrderSend validation

5. Sample Code

[Conclusion]
The following code is a validation sample of an MQL5 EA that separates filters using moving averages and ATR, and performs OrderCheck before placing an order.
For live operation, you must additionally validate symbol specifications, account type, execution method, stop-loss width, and logging design.

#property strict

input int    FastMAPeriod      = 20;
input int    SlowMAPeriod      = 50;
input int    ATRPeriod         = 14;
input double RiskPercent       = 1.0;
input int    StopLossPoints    = 300;
input int    TakeProfitPoints  = 600;
input int    MaxSpreadPoints   = 30;

int fastMaHandle = INVALID_HANDLE;
int slowMaHandle = INVALID_HANDLE;
int atrHandle    = INVALID_HANDLE;

enum SignalType
{
   SIGNAL_NONE = 0,
   SIGNAL_BUY  = 1,
   SIGNAL_SELL = -1
};

int OnInit()
{
   fastMaHandle = iMA(_Symbol, _Period, FastMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   slowMaHandle = iMA(_Symbol, _Period, SlowMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   atrHandle    = iATR(_Symbol, _Period, ATRPeriod);

   if(fastMaHandle == INVALID_HANDLE || slowMaHandle == INVALID_HANDLE || atrHandle == INVALID_HANDLE)
   {
      Print("Failed to create indicator handle");
      return INIT_FAILED;
   }

   return INIT_SUCCEEDED;
}

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

   if(slowMaHandle != INVALID_HANDLE)
      IndicatorRelease(slowMaHandle);

   if(atrHandle != INVALID_HANDLE)
      IndicatorRelease(atrHandle);
}

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

   if(PositionSelect(_Symbol))
   {
      ManagePosition();
      return;
   }

   SignalType signal = CheckSignal();

   if(signal == SIGNAL_NONE)
      return;

   double lot = CalculateLot(StopLossPoints);

   if(lot <= 0.0)
   {
      Print("Lot calculation failed");
      return;
   }

   SendCheckedOrder(signal, lot);
}

bool IsTradingAllowedNow()
{
   long tradeMode = 0;

   if(!SymbolInfoInteger(_Symbol, SYMBOL_TRADE_MODE, tradeMode))
   {
      Print("Failed to get symbol trade mode");
      return false;
   }

   if(tradeMode == SYMBOL_TRADE_MODE_DISABLED)
   {
      Print("Trading is disabled for this symbol");
      return false;
   }

   MqlTick tick;

   if(!SymbolInfoTick(_Symbol, tick))
   {
      Print("Failed to get current tick");
      return false;
   }

   int spreadPoints = (int)MathRound((tick.ask - tick.bid) / _Point);

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

   return true;
}

SignalType CheckSignal()
{
   double fastMa[];
   double slowMa[];
   double atr[];

   ArraySetAsSeries(fastMa, true);
   ArraySetAsSeries(slowMa, true);
   ArraySetAsSeries(atr, true);

   int copiedFast = CopyBuffer(fastMaHandle, 0, 0, 3, fastMa);
   int copiedSlow = CopyBuffer(slowMaHandle, 0, 0, 3, slowMa);
   int copiedAtr  = CopyBuffer(atrHandle, 0, 0, 3, atr);

   if(copiedFast < 3 || copiedSlow < 3 || copiedAtr < 3)
   {
      Print("CopyBuffer failed or not enough data");
      return SIGNAL_NONE;
   }

   double minAtr = 50 * _Point;

   int closedBar = 1;
   int previousClosedBar = 2;

   if(atr[closedBar] < minAtr)
      return SIGNAL_NONE;

   bool bullishCross = fastMa[previousClosedBar] <= slowMa[previousClosedBar] && fastMa[closedBar] > slowMa[closedBar];
   bool bearishCross = fastMa[previousClosedBar] >= slowMa[previousClosedBar] && fastMa[closedBar] < slowMa[closedBar];

   if(bullishCross)
      return SIGNAL_BUY;

   if(bearishCross)
      return SIGNAL_SELL;

   return SIGNAL_NONE;
}

double CalculateLot(int stopLossPoints)
{
   double equity = AccountInfoDouble(ACCOUNT_EQUITY);
   double riskMoney = equity * RiskPercent / 100.0;

   double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
   double tickSize  = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   double minLot    = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double maxLot    = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double lotStep   = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

   if(equity <= 0.0 || riskMoney <= 0.0 || tickValue <= 0.0 || tickSize <= 0.0 || lotStep <= 0.0)
      return 0.0;

   double lossPerLot = (stopLossPoints * _Point / tickSize) * tickValue;

   if(lossPerLot <= 0.0)
      return 0.0;

   double rawLot = riskMoney / lossPerLot;
   double steppedLot = MathFloor(rawLot / lotStep) * lotStep;
   double normalizedLot = MathMax(minLot, MathMin(maxLot, steppedLot));

   return NormalizeDouble(normalizedLot, 2);
}

void SendCheckedOrder(SignalType signal, double lot)
{
   MqlTick tick;

   if(!SymbolInfoTick(_Symbol, tick))
   {
      Print("Failed to get current tick before order");
      return;
   }

   MqlTradeRequest request;
   MqlTradeCheckResult check;
   MqlTradeResult result;

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

   request.action = TRADE_ACTION_DEAL;
   request.symbol = _Symbol;
   request.volume = lot;
   request.deviation = 20;
   request.type_filling = ORDER_FILLING_FOK;

   if(signal == SIGNAL_BUY)
   {
      request.type = ORDER_TYPE_BUY;
      request.price = tick.ask;
      request.sl = NormalizeDouble(tick.ask - StopLossPoints * _Point, _Digits);
      request.tp = NormalizeDouble(tick.ask + TakeProfitPoints * _Point, _Digits);
   }
   else if(signal == SIGNAL_SELL)
   {
      request.type = ORDER_TYPE_SELL;
      request.price = tick.bid;
      request.sl = NormalizeDouble(tick.bid + StopLossPoints * _Point, _Digits);
      request.tp = NormalizeDouble(tick.bid - TakeProfitPoints * _Point, _Digits);
   }
   else
   {
      return;
   }

   if(!OrderCheck(request, check))
   {
      Print("OrderCheck call failed");
      return;
   }

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

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

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

   Print("Order completed. Ticket: ", result.order);
}

void ManagePosition()
{
   if(!PositionSelect(_Symbol))
      return;

   double profit = PositionGetDouble(POSITION_PROFIT);

   if(profit < 0.0)
   {
      Print("Position is currently in drawdown: ", profit);
   }
}

5.1 Code Review Points

This sample separates OnInit, OnTick, and OnDeinit according to the basic MQL5 structure.
Indicator values are retrieved with CopyBuffer, and trading evaluation stops if the number of retrieved values is insufficient.

Before placing an order, the EA uses OrderCheck to confirm margin and trading condition issues in advance.
It also checks the OrderSend result with retcode and logs the result if the order is not completed.

5.2 Points to Adjust During Implementation

ORDER_FILLING_FOK may not match the execution method of some brokers or symbols.
Before live operation, check the execution method for each symbol and change order conditions as needed.

In a netting account, positions for the same symbol are consolidated.
In a hedging account, multiple positions can be held for the same symbol, so PositionSelect alone may not be enough for management.

6. Comparison by Pattern

[Conclusion]
In a robust MQL5 EA, choose the design by comparing not only signal accuracy but also risk control, pre-order checks, and ease of validation.
The closer the EA is to live operation, the more important stop conditions and logging design become compared with simple trading conditions.

Design ElementAdvantagesDisadvantagesBest Use CaseOver-Optimization Risk
Moving average signalEasy to understand and implementFalse signals are common in rangesInitial design and trend evaluationMedium
ATR filterCan reflect volatilityEasy to depend on threshold settingsAvoiding low volatility and adjusting stop-loss widthMedium
Higher-timeframe filterEasy to align with the larger directionEntries can be delayedTrend followingMedium
Risk-percentage lot sizingEasy to connect stop-loss width with allowed lossRequires checking tick value and symbol specificationsMoney management focusLow to medium
Pre-order checkEasy to detect issues before executionRequires more implementation workEAs intended for live operationLow
State managementEasy to reduce mistaken orders and duplicate processingDesign becomes more complexMulti-condition EAs and production EAsLow to medium

6.1 More Conditions Are Not Always Better

Adding filters may improve backtest performance.
However, an EA with too many conditions can easily become over-optimized for only a specific period.

You need to distinguish between adding conditions to improve robustness and tuning too closely to historical data.
When adding a condition, check trade count, period dependency, and parameter dependency.

7. Situations Where Malfunctions Are Likely

[Conclusion]
MQL5 EAs are likely to malfunction due to failed indicator value retrieval, evaluation on forming bars, spread widening, account type differences, and mismatched execution methods.
In a robust design, these are checked as preconditions, and the EA skips orders when the conditions are not met.

7.1 CopyBuffer Retrieval Failure

CopyBuffer may not return the expected number of values when the required number of bars has not been calculated or when handle creation has failed.
Reading an array when retrieved values are insufficient can lead to incorrect signal evaluation.

When using indicator values, check the number of retrieved values and stop trading evaluation for that tick if the data is insufficient.

7.2 Signal Fluctuation on the Latest Bar

The value at index 0 belongs to the forming bar.
If you use the latest bar, the signal may appear and disappear on each tick.

In a design that uses closed bars, indexes 1 and 2 are used to evaluate crossovers and condition fulfillment.
This method may delay entries, but it makes signal reproducibility easier to verify.

7.3 Changes in Spread and Execution Conditions

When the spread widens, even the same signal may be harder to execute at the expected price.
If execution delays or slippage occur, trades may be executed at a worse price than in the backtest.

In live operation, pay attention to behavior around major economic announcements, low-liquidity periods, market open after the weekend, and the period near the weekend close.

8. Items to Check in Backtesting

[Conclusion]
In backtesting, check not only total profit and loss but also maximum drawdown, trade count, profit factor or reward-risk balance, losing streaks, spread conditions, period dependency, and parameter dependency.
Even if a setting looks profitable, reproducibility is hard to judge when the trade count is too low or the result is concentrated in a specific period.

The main items to check in a backtest are as follows.

Check ItemReason to Review ItNote
Total profit and lossUnderstand the overall resultDo not judge by this alone
Maximum drawdownCheck the size of equity declineDecide the acceptable level in advance
Win rateCheck the tendency of winning and losing tradesReview it together with the profit/loss ratio
Profit/loss ratioCheck the relationship between average profit and average lossWin rate alone is not enough
Trade countConfirm the amount of validation dataIf too low, random effects become large
Losing streaksCheck psychological and financial toleranceReview together with lot design
Spread conditionsCheck differences from live operationDo not rely only on fixed spreads
Period dependencyCheck bias toward specific market conditionsReview multiple periods
Parameter dependencyCheck over-optimizationBe careful with settings that break after small changes

8.1 Do Not Overtrust Optimization Results

Parameters found through optimization may only fit historical data.
Settings that perform well only during a specific period often break down in forward testing.

Do not look at only one parameter point. Check whether nearby values also avoid extreme deterioration.

8.2 Review Trade Count and Period Separately

An EA with a low trade count may look profitable because of a few large winning trades.
To verify robustness, you need to check whether trades occur across multiple market phases.

9. Items to Check in Forward Testing

[Conclusion]
In forward testing, check the difference between backtest assumptions and real execution conditions.
Focus on execution differences, spread widening, trading frequency, drawdown, broker differences, and stability in a VPS environment.

The main items to check in forward testing are as follows.

  • Whether execution prices are worse than expected
  • Whether trades are skipped when spreads widen
  • Whether trading frequency is not significantly different from the backtest
  • Whether drawdown remains within the expected range
  • Whether behavior changes by broker or account type
  • Whether the EA runs stably in a VPS environment
  • Whether logs allow you to trace skip reasons and order failure reasons

9.1 Difference Between Demo and Live Accounts

Execution conditions and slippage may differ between demo accounts and live accounts.
Even if an EA is stable on a demo account, it does not mean the same result will occur on a live account.

Before live operation, it is important to include a stage where behavior is checked with a small amount or low-risk settings.

9.2 Keep Logs So Causes Can Be Traced

In forward testing, the reasons for not trading are as important as the reasons for trading.
Logging spread excess, CopyBuffer failure, OrderCheck rejection, existing positions, and out-of-hours conditions makes it easier to find improvements.

10. Notes for Live Operation

[Conclusion]
In live operation, an EA may not run under the same conditions as the backtest.
You must check spreads, execution, leverage, margin, symbol specifications, account type, and VPS environment, and prepare for unexpected drawdowns.

EA robustness is evaluated not by the size of profit, but by whether the EA can stop, skip trades, and trace causes in unexpected situations.

10.1 Leverage and Drawdown

The higher the leverage, the larger the position you can hold with a smaller amount of margin.
At the same time, profit and loss changes more sharply with price movement, and drawdown can expand more easily.

In lot calculation, check not only account balance but also equity, stop-loss width, the symbol’s tick value, and tick size.

10.2 Differences in Broker Specifications

Minimum lot, maximum lot, lot step, stop level, freeze level, execution method, and trading hours differ by broker and symbol.
It is preferable for an EA to retrieve and check these values with SymbolInfo functions instead of treating them as fixed values.

10.3 Differences in Account Type

In a netting account, positions for the same symbol are consolidated into one position.
In a hedging account, multiple positions can be held for the same symbol.

When designing position management, the meaning of “existing position” changes depending on the account type.
An EA that handles multiple positions may need ticket-level management.

11. Improvements and Alternatives

[Conclusion]
Improving robustness is not only about adding more signals.
Improving stop conditions, lot control, logging, pre-order checks, and validation procedures makes EA behavior easier to manage.

Possible improvements are as follows.

  • Adjust the stop-loss width according to ATR
  • Pause trading according to the maximum number of consecutive losses
  • Stop trading when the daily maximum loss amount is exceeded
  • Exclude time periods with wide spreads
  • Design the EA to avoid trading around major events
  • Separate logs for signals, filters, and order handling
  • Avoid making the optimization range too wide

11.1 Comparison of Lot Calculation Methods

MethodAdvantagesDisadvantagesBest Use Case
Fixed lotEasy to implementDifficult to adapt to equity changesInitial validation and small-size testing
Balance-proportionalEasy to adjust according to capitalDifficult to reflect stop-loss widthLong-term validation
Risk-percentage basedEasy to connect allowed loss with stop-loss widthRequires retrieving symbol specificationsEAs intended for live operation
Volatility-adjustedEasy to adapt to market volatilityDepends on settings such as ATRSymbols with large price movement

11.2 Semi-Automated Operation as an Alternative

If full automation is difficult, another design is to use the EA for signal alerts or pre-order checks and let a human make the final decision.
Semi-automated operation can reduce technical malfunctions, but consistency of judgment becomes an issue.

12. Summary

[Conclusion]
To build a robust trading system in MQL5, you need to separate trading signals, filters, risk management, pre-order checks, position management, and validation procedures.
In particular, CopyBuffer retrieval checks, pre-order confirmation with OrderCheck, lot limits, account type differences, and spread and execution condition checks are important.

A robust EA is not simply an EA with many conditions.
It is an EA that skips unsuitable situations, records why an order could not be placed, and allows reproducibility to be checked through backtesting and forward testing.

Backtest results do not guarantee future profit.
In live operation, forward testing, broker condition checks, drawdown tolerance settings, and VPS stability checks are necessary.

FAQ

What is a robust trading system in MQL5?

A robust trading system in MQL5 is an EA design that separates not only trading signals but also filters, risk management, pre-order checks, position management, and validation procedures. Its purpose is to make causes easier to trace even in unexpected environments.

Which processes should be separated first to make an EA robust?

The first processes to separate are signal evaluation, filter evaluation, lot calculation, pre-order checks, and position management. Creating functions by role makes validation easier than writing everything inside OnTick.

What should I watch for when using indicator values in MQL5?

In MQL5, many indicator functions return handles rather than values. You need to create handles in OnInit, use CopyBuffer in OnTick, and stop trading evaluation if the retrieved data count is insufficient.

Why should OrderCheck be used before OrderSend?

OrderCheck is used to confirm margin and trading condition validity before placing an order. If you rely only on OrderSend, it may be harder to isolate the reason for failure.

Does adding many filters always make an EA more robust?

No. Adding filters does not always make an EA robust. Too many conditions can cause over-optimization, so each filter’s purpose and effect should be checked separately in backtesting and forward testing.

Which items are important in backtesting?

In backtesting, check maximum drawdown, win rate, profit/loss ratio, trade count, losing streaks, spread conditions, period dependency, and parameter dependency, not only total profit and loss. If the trade count is low, even good-looking results require caution.

What should be checked in forward testing?

In forward testing, check execution differences, behavior during spread widening, trading frequency, drawdown, broker differences, and VPS stability. Backtest conditions and live operation conditions may differ.

Does EA design change between netting and hedging accounts?

Yes. Position management differs between netting and hedging accounts. In a netting account, positions for the same symbol are consolidated, while in a hedging account, multiple positions can be held, so the management unit must be designed accordingly.