A buy grid has opened four legs. Price reaches the fifth entry, but the account cannot fund the additional margin. The four existing legs remain open. At what lower price would those positions reach the modeled stop-out level?
Those are two different calculations. The first tests whether an addition can be funded at its trigger. The second follows the positions that remain after that addition is blocked. Confusing them can produce a table that continues adding positions the account could never open, or a report that stops counting losses as soon as additions stop.
The example below follows one ladder through both decisions. Its prices and currency units are invented. It uses fixed margin per lot, a constant monetary value for a price move, zero spread and zero costs. These assumptions make the arithmetic reproducible without connecting to an account. They are not specifications for a tradable instrument, broker measurements, or output from a Quanition product.
This article uses AI-assisted writing and editing based on the author’s grid-risk concept. Its JavaScript reproduction was executed with Bun. No MetaEditor compilation or MT5 run is claimed.
Fix the volume rule before calculating exposure
The starting entry is 100.00, with 0.10 lots. Each raw lot is 1.5 times the previous raw lot. The first interval is 1.00 price unit, and successive intervals grow by 1.20. Each volume is rounded down to a 0.01 step.
For zero-based index i:
raw_lot[i] = 0.10 × 1.5^i
lot[i] = floor(raw_lot[i] / 0.01) × 0.01
entry[i] = 100.00 − sum(1.20^j, j = 0 .. i−1)
The empty sum for the first entry is zero. This gives the following ladder:
| Leg | Raw lot | Rounded lot | Entry | Cumulative lots |
|---|---|---|---|---|
| 0 | 0.10000 | 0.10 | 100.000 | 0.10 |
| 1 | 0.15000 | 0.15 | 99.000 | 0.25 |
| 2 | 0.22500 | 0.22 | 97.800 | 0.47 |
| 3 | 0.33750 | 0.33 | 96.360 | 0.80 |
| 4, proposed | 0.50625 | 0.50 | 94.632 | 1.30 if admitted |
Rounding the previous rounded lot before multiplying defines a different ladder. It would give 0.49 for leg 4 because floor(0.33 × 1.5 / 0.01) × 0.01 = 0.49. An implementation that changes between these rules changes exposure even though its input still says “multiplier 1.5”. The reference program calculates each raw lot from the original 0.10.
The invented ladder has no binding minimum, maximum or aggregate volume limit. On an MT5 symbol, inspect SYMBOL_VOLUME_MIN, SYMBOL_VOLUME_MAX, SYMBOL_VOLUME_STEP and SYMBOL_VOLUME_LIMIT. The last property concerns same-direction aggregate position and pending-order volume; checking the size of one proposed order is insufficient. MQL5 symbol properties
Choose what the model does when a requested volume is invalid. Rejecting a leg and clipping it to the maximum produce different baskets. Do not silently round a sub-minimum request upward: that increases exposure beyond the request.
Value the positions that actually exist
After four fills, cumulative volume is 0.80 lots. Its volume-weighted entry is:
weighted_entry = (0.10×100 + 0.15×99 + 0.22×97.8 + 0.33×96.36) / 0.80
= 97.706
Assume that a one-price-unit movement is worth 100 currency units per lot. The signed floating result of the four-leg long basket at Bid P is then:
floating(P) = 100 × sum(lot[i] × (P − entry[i]))
= 80 × (P − 97.706)
At Bid 95, floating P/L is −216.48. This is a loss on the existing basket, before commission or swap. It is not a realized account loss, a historical drawdown statistic, or a return percentage.
The weighted-entry shortcut works here because each leg has the same constant monetary slope. For a real symbol, converting a price move to account currency can depend on the instrument and current conversion conditions. A terminal implementation can evaluate the individual legs with OrderCalcProfit and sum the returned values, checking each Boolean return value before using its result. The function returns an estimate in account currency under the current market conditions; it does not establish future conversion rates. OrderCalcProfit reference
A long enters at Ask and is valued for closing at Bid. A short enters at Bid and is valued at Ask. The example sets spread to zero, so its entry and valuation prices can coincide. With spread, the new leg has an immediate floating loss. Subtracting spread again from a calculation that already uses Ask entry and Bid exit would count it twice.
Test the fifth order before inserting it into the basket
Set starting balance to 1,000 currency units and margin to 1,000 per lot. There is no credit or outside exposure. The modeled stop-out threshold is 50% of used margin, in percentage mode. For the existing basket:
equity(P) = 1000 + floating(P)
margin = 1000 × existing_lots
free = equity − margin
Each of the first four additions passes the model’s admission rule. The program prints these rows just after those fills:
| Leg | Bid | Existing lots | Equity | Used margin | Margin level |
|---|---|---|---|---|---|
| 0 | 100.000 | 0.10 | 1,000.00 | 100.00 | 1,000.00% |
| 1 | 99.000 | 0.25 | 990.00 | 250.00 | 396.00% |
| 2 | 97.800 | 0.47 | 960.00 | 470.00 | 204.26% |
| 3 | 96.360 | 0.80 | 892.32 | 800.00 | 111.54% |
At the next trigger, 94.632, the four existing legs have a floating loss of 245.92. Equity is 754.08 and used margin remains 800. The next 0.50-lot leg would require another 500. Under the example’s addition rule, equity must cover total margin after adding the leg:
required total margin = 800 + 500 = 1300
available equity = 754.08
decision = ADD_BLOCKED
The 0.50 lot is a proposal. It must not enter cumulative volume, weighted entry or future P/L after this rejection. The basket remains 0.80 lots, with weighted entry 97.706.
Its current margin level is 94.26%, still above this model’s 50% stop-out threshold. Negative free margin and stop-out are therefore different tests. There is no margin-call rule in this example. A production implementation must identify any additional broker restrictions rather than treating a margin-call label as a universal prohibition on trading.
MT5’s OrderCalcMargin can estimate a proposed order’s margin in account currency, but it explicitly ignores existing positions and pending orders. Summing such estimates does not reproduce portfolio margin, hedged margin relief, tiered requirements or account-wide order admission. The example’s additive margin is a declared assumption; it is not broker validation. OrderCalcMargin reference
Follow the frozen four-leg basket to its own boundary
After the blocked addition, keep the four positions fixed. Used margin remains 800 under the constant-margin assumption. The 50% modeled stop-out condition is:
equity(P) <= 0.50 × 800 = 400
1000 + 80 × (P − 97.706) = 400
P = 90.206
This is a conditional boundary for the four-leg basket. At 90.206, floating P/L is −600 and equity is 400. The failed fifth entry at 94.632 did not close those four legs or stop their losses from increasing.
The root calculation assumes continuous prices and unchanged margin. It is not rounded to a real symbol’s tick grid. In a real long-position check, evaluate the tradable Bid ticks around a candidate root; a computed price between ticks is not an executable quote. A gap can skip both the entry trigger and the root.
For example, let the next observed Bid jump from 96.36 directly to 89. With the same four positions, equity is 303.52, already below 400. The endpoint check must report STOPOUT_BEFORE_ADD before considering a fifth leg. Filling imaginary intermediate entries would create a different basket. This example does not simulate a broker’s liquidation sequence or the prices obtained during forced closure.
Percentage mode is a scope restriction. MT5 exposes both percentage and monetary stop-out modes through ACCOUNT_MARGIN_SO_MODE. Do not feed a money-mode threshold into equity / margin × 100, or assign it a percent sign. The reproduction implements only the declared percentage model. MQL5 account properties
Move one assumption and check the size of the change
For a frozen long basket with constant price value K per lot, cumulative volume V, weighted entry W, outside floating P/L F, outside margin O, aggregate costs C and stop fraction s, the same calculation is:
equity(P) = balance + F − C + K×V×(P − W)
margin = O + margin_per_lot×V
P_stop = W + (s×margin − balance − F + C) / (K×V)
C is a positive charge subtracted once. If commission has already reduced the supplied balance, subtracting it again would double count it. Future exit commission and swap need their own timing assumptions; they are zero in the baseline.
The companion program holds the four-leg basket fixed and changes one input at a time:
| Change from baseline | Modeled boundary | Movement toward the entries |
|---|---|---|
| None | 90.206 | 0 |
| Aggregate charge of 40 | 90.706 | +0.500 |
| Outside margin of 200 | 91.456 | +1.250 |
| Outside floating loss of 100 | 91.456 | +1.250 |
An extra 40 of costs shifts the boundary by 40 / 80 = 0.5. Outside margin of 200 raises the equity threshold by 50% × 200 = 100, producing a shift of 100 / 80 = 1.25. These are useful checks on the signs and units in an implementation.
Outside P/L is held constant in these comparisons. That assumption becomes weak when other positions move with the grid’s symbol or its conversion rate. A reader with unknown outside exposure has insufficient input for a precise account-level boundary; zero is an empty-account scenario, not a substitute for missing data.
Reproduce the calculation
Download grid-margin-boundary.mjs. It uses JavaScript’s standard library with no terminal, account, network or trading connection. Run it with Bun, or substitute node if Node.js is already installed:
bun grid-margin-boundary.mjs --check
bun grid-margin-boundary.mjs
The executed check output is:
PASS: 29 calculation/boundary checks; 9 invalid-input cases
The recorded model output includes:
next_trigger=94.632; existing_equity=754.08; existing_margin=800.00; next_margin=500.00; event=ADD_BLOCKED
fixed_four_leg_stop_boundary=90.206; equity=400.00; margin=800.00
gap_bid=89; existing_equity=303.52; event=STOPOUT_BEFORE_ADD
The checks cover the exact rounded lot sequence, the admission of the first four fills, the blocked fifth addition, both sides of the stop boundary, the gap, and the three sensitivity changes. BigInt integer division floors the lot sizes exactly in hundredths. Price and currency calculations use JavaScript floating-point numbers; numeric checks allow an absolute difference below 0.00000001. Printed prices are rounded for this example, not normalized to an MT5 symbol’s tick grid.
The script demonstrates the equations in this article. It does not read symbol specifications or determine whether a broker will admit an order. An MT5 implementation needs its own compilation and terminal checks, with the actual quote, account mode and portfolio margin rules. Those checks have not been performed for this JavaScript example.
When checking a grid calculation, first exclude rejected legs from its basket. Then follow the remaining positions under the stated assumptions. Here, adding stops at 94.632; the four-leg basket reaches the modeled stop threshold at 90.206.
For a separate check on each EA’s contribution to the account history and which positions remain open, see Compare EA Results by Magic Number. That history analysis does not supply the margin model used here.
Official references
- MQL5 Reference: OrderCalcMargin
- MQL5 Reference: OrderCalcProfit
- MQL5 Reference: Account Properties
- MQL5 Reference: Symbol Properties
Guide reviewed: 2026-10-23