Blog

How to size a position from account balance, not a fixed lot

TradeSmithy Team6 min read

Most Expert Advisors ship with a lot size typed into a box. It is the single most consequential number in the strategy and the one least connected to anything real — 0.1 lots is a rounding error on one account and a margin call on another.

The fix is not a bigger box. It is to compute the lot at runtime from values the terminal already knows, and TradeSmithy exposes those values as nodes you can wire.

The short version

The Lot Size port on a Buy or Sell node is optional. Leave it alone and the order uses the number you typed. Connect something to it and the typed number stays where it is, untouched, while the generated EA computes the lot on every trade instead.

What you connect is usually a small chain: an Account Info node for balance or equity, a Global Parameter for the risk percentage, some Math nodes, and a Symbol Info node for the broker's limits.

What the account and symbol nodes give you

An Account Info node reads the account the EA is running on. A Symbol Info node reads the instrument it is running on. Both have a single output port, and its type follows the property you pick — which is why wiring a text property such as the broker name into a math node is refused rather than generating a string subtraction.

The ones that matter for sizing:

PropertyNodeWhat it is
BalanceAccountClosed-trade balance
EquityAccountBalance plus floating profit
Free marginAccountWhat is left to open with
Tick valueSymbolAccount-currency profit from one tick on one lot
Tick sizeSymbolSmallest price change — not always the point size
Minimum lotSymbolSmallest volume the broker accepts
Maximum lotSymbolLargest volume in one order
Lot stepSymbolVolume granularity to round to
Min stop distanceSymbolHow far a stop must sit from price

The formula, as a graph

The standard risk-per-trade calculation is three steps:

  1. Risk amount = balance × risk percent. Two nodes: Account Info (Balance) and a Global Parameter (RiskPercent), into a multiply.
  2. Loss per lot = stop distance ÷ tick size × tick value. This is what one lot would actually cost you if the stop is hit, in the currency of your account.
  3. Lot = risk amount ÷ loss per lot, then clamped to the minimum and maximum lot and rounded to the lot step.

Step 3 is the one people skip, and it is the one the broker enforces. A calculated 0.037 lots on an instrument with a 0.01 step is not "close enough" — depending on the broker it is a rejected order or a silently different size.

Why these are nodes and not an instruction to the model

You could write "size the position at 1% of balance" in the AI chat and get code back. Sometimes it would be right.

The problem is the failure mode. A generator improvising an accessor reaches for MODE_STOPLEVEL when it wanted MODE_FREEZELEVEL, or reads the point size where it needed the tick size — and produces code that compiles. There is no error to notice. You find out from the trade history.

So every account and symbol property here is stored as a complete expression per platform and emitted verbatim. MQL5 uses SymbolInfoDouble; MQL4 uses MarketInfo, which works on every MT4 build there is rather than only the recent ones. The value in the graph is the value in the file.

Tick size is not point size, and this bites

SYMBOL_POINT is the smallest price increment. SYMBOL_TRADE_TICK_SIZE is the smallest change the instrument actually trades in. On most FX pairs they are equal, which is exactly why the mistake survives testing — it works on EURUSD and misprices your risk on indices, metals and anything with a tick size that is a multiple of the point.

Use tick size and tick value together. They are defined as a pair, and using one with the other's units gives you an answer that is wrong by a constant factor you will not notice until the loss.

Make the risk percentage a parameter

Wire the risk percentage from a Global Parameter node rather than typing it into a math node, and it becomes an input in the exported EA:

input double RiskPercent = 1.0;

Now it appears in the Inputs tab in MetaTrader, changes per chart without regenerating anything, and is a variable the Strategy Tester can sweep later. The same applies to any number in the chain — there is more on this in every indicator parameter can be a wire.

One parameter can also feed several nodes. Wire one AtrPeriod into both your ATR-based stop and your ATR-based sizing and they cannot drift apart, because there is only one value.

Respect the stop level, or the order is rejected

A broker will refuse a stop loss placed closer to price than its minimum stop distance. This is a common cause of an EA that "does nothing" on a live account after backtesting fine — the tester is more forgiving than the server.

Read Min stop distance from a Symbol Info node and take the larger of it and your intended stop. It costs one comparison node and removes an entire category of silent failure.

What this does not do

Sizing arithmetic makes your risk consistent. It does not make it safe.

  • The loss you modelled assumes the stop fills at the stop price. Gaps, weekend opens and thin liquidity mean it may not.
  • Tick value is not constant across instruments, and on cross-currency pairs it moves with the exchange rate of the profit currency.
  • Risking a fixed percentage of a falling balance shrinks your size as you lose, which is a property, not a protection.
  • Several positions open at once are several risks, and nothing in a per-trade calculation knows about the others unless you make it.

Automation removes the hesitation, not the risk. What sizing from account values buys you is that the same strategy behaves the same way on a $500 account and a $50,000 one — which is the difference between a strategy you can reason about and a number you typed once and forgot.

Keep reading

← More from the TradeSmithy blog