What 1 pip is on EURUSD
EUR/USD is quoted in US dollars: the price says how many dollars one euro costs. A 0.0001 move on 100,000 euros changes the position's value by 100,000 × 0.0001 = 10 dollars, and since the profit is already in dollars there is nothing to convert for a USD account. That's why the pip value of EUR/USD is the same at 1.05 as at 1.20.
Brokers quote the pair with 5 digits (1.16253): the last digit is a tenth of a pip, which MetaTrader calls a point. One pip = 10 points, and the tick size MT5 reports is 0.00001, worth $1 per lot. For an account in euros, the same $10 is converted at the current rate: about €8.62 at 1.16.
EURUSD pip value per lot
Value of one pip (0.0001 in price): 0.0001 × 100,000 = $10 per 1.00 lot.
| Position | 1 pip | 20 pips (0.0020) |
|---|---|---|
| 1.00 lot | $10.00 | $200.00 |
| 0.10 lot | $1.00 | $20.00 |
| 0.01 lot | $0.10 | $2.00 |
Worked example: 1% of $10,000
- Risk: 1% × $10,000 = $100.00.
- Stop: 20 pips = 0.0020 in price.
- Value of 1 pip per 1.00 lot: $10.00.
- Lot size = $100.00 ÷ (20 × $10.00) = 0.5000, rounded down to the 0.01 step: 0.50 lots.
Twenty pips is a common intraday stop on EUR/USD. Double the stop and the same $100 buys half the size: the risk stays fixed, the lot size gives way.
Same $100 risk with a 40-pip stop: $100.00 ÷ (40 × $10.00) = 0.25 lots.
Contract size and tick value in MT5
In MetaTrader 5, right-click EURUSD in Market Watch and choose Specification: it shows Contract size, Digits, Profit currency and the volume limits. Tick size and tick value are what MQL5 reads with SYMBOL_TRADE_TICK_SIZE and SYMBOL_TRADE_TICK_VALUE; the script below prints them for your account.
| Contract size | 100,000 EUR |
|---|---|
| Digits | 5 (e.g. 1.16253) at most brokers |
| Tick size (SYMBOL_TRADE_TICK_SIZE) | 0.00001 |
| 1 pip | 0.0001 = 10 ticks (10 MT5 points) |
| Profit currency | USD |
| Tick value, 1.00 lot (SYMBOL_TRADE_TICK_VALUE) | $1.00 in a USD account |
| Volume step | Shown in Specification; 0.01 at most retail brokers |
MQL5: lot size from a money risk
A script that sends no order: it reads the contract size, tick size, tick value and volume limits your broker sets for EURUSD, then prints the lot size that risks 1% of the balance at the stop. The stop is a price distance (0.0020), so the result is the same on 2-, 3- or 5-digit quotes. Save it as MQL5/Scripts/LotSize_EURUSD.mq5 and compile it in MetaEditor (F7): 0 errors, 0 warnings.
//+------------------------------------------------------------------+
//| LotSize_EURUSD.mq5 |
//| Lot size that risks a % of the balance at a given stop distance|
//+------------------------------------------------------------------+
#property script_show_inputs
input string InpSymbol = "EURUSD"; // Symbol, exactly as in Market Watch
input double InpRiskPercent = 1.0; // Risk per trade, % of balance
input double InpStopDistance = 0.0020; // Stop-loss distance in price (0.0020 = 20 pips)
// Lots that lose about riskMoney at the stop, rounded down to the volume step.
// Returns 0 when even the minimum volume would risk more than riskMoney.
double LotsForRisk(const string symbol, const double riskMoney, const double stopDistance)
{
double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); // 1.00 lot, one tick, account currency
double step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
if(tickSize <= 0.0 || tickValue <= 0.0 || step <= 0.0 || stopDistance <= 0.0)
return 0.0;
double lossPerLot = stopDistance / tickSize * tickValue; // money lost by 1.00 lot at the stop
double lots = MathFloor(riskMoney / lossPerLot / step + 1e-9) * step;
if(lots < minLot)
return 0.0;
int volumeDigits = (int)MathMax(0.0, MathCeil(-MathLog10(step) - 1e-9));
return NormalizeDouble(MathMin(lots, maxLot), volumeDigits);
}
void OnStart()
{
if(!SymbolSelect(InpSymbol, true))
{
PrintFormat("%s not found: use the exact name from Market Watch (some brokers add a suffix)", InpSymbol);
return;
}
int digits = (int)SymbolInfoInteger(InpSymbol, SYMBOL_DIGITS);
double point = SymbolInfoDouble(InpSymbol, SYMBOL_POINT);
double contract = SymbolInfoDouble(InpSymbol, SYMBOL_TRADE_CONTRACT_SIZE);
double tickSize = SymbolInfoDouble(InpSymbol, SYMBOL_TRADE_TICK_SIZE);
double tickVal = SymbolInfoDouble(InpSymbol, SYMBOL_TRADE_TICK_VALUE);
string currency = AccountInfoString(ACCOUNT_CURRENCY);
double risk = AccountInfoDouble(ACCOUNT_BALANCE) * InpRiskPercent / 100.0;
double lots = LotsForRisk(InpSymbol, risk, InpStopDistance);
PrintFormat("%s: contract size %g, %d digits, tick size %s, tick value %g %s per lot",
InpSymbol, contract, digits, DoubleToString(tickSize, digits), tickVal, currency);
PrintFormat("Stop %s = %.0f points. Risk %.2f %s",
DoubleToString(InpStopDistance, digits), InpStopDistance / point, risk, currency);
if(lots > 0.0)
PrintFormat("Lot size: %g", lots);
else
Print("Even the minimum volume risks more than that: widen the risk or tighten the stop");
}
The key line is stopDistance / tickSize * tickValue: the money one lot loses at the stop, already converted to your account currency by the terminal. Dividing the risk by it and flooring to SYMBOL_VOLUME_STEP gives the volume to pass to CTrade::Buy() or CTrade::Sell().
Pine Script v6 equivalent
The same sizing on a TradingView chart, from syminfo.pointvalue (money per 1.0 of price per unit) and syminfo.mintick (the chart's tick). Checked by Edgoro Pine Check; paste it into TradingView's Pine Editor to add it to a chart.
//@version=6
indicator("EURUSD lot size for a money risk", overlay = true)
riskMoney = input.float(100.0, "Risk per trade (account currency)", minval = 0.01)
accountCcy = input.string("USD", "Account currency")
stopDistance = input.float(0.0020, "Stop-loss distance (price)", minval = 0.0)
contractSize = input.float(100000.0, "Units per 1.00 lot at your broker", minval = 0.0)
// One unit of the symbol gains or loses syminfo.pointvalue (in syminfo.currency) per 1.0 of price
fx = request.currency_rate(syminfo.currency, accountCcy)
lossPerUnit = stopDistance * syminfo.pointvalue * fx
units = lossPerUnit > 0 ? riskMoney / lossPerUnit : na
lots = contractSize > 0 ? math.floor(units / contractSize * 100) / 100 : na
var table info = table.new(position.top_right, 2, 3, bgcolor = color.new(color.gray, 80))
if barstate.islast
table.cell(info, 0, 0, "Stop")
table.cell(info, 1, 0, str.tostring(stopDistance / syminfo.mintick, "#") + " ticks of " + str.tostring(syminfo.mintick))
table.cell(info, 0, 1, "Units")
table.cell(info, 1, 1, str.tostring(units, "#.####"))
table.cell(info, 0, 2, "Lots (rounded down)")
table.cell(info, 1, 2, str.tostring(lots, "#.##"))
On a TradingView forex chart, syminfo.pointvalue is 1: units is an amount of EUR, and 100,000 of them make a lot. request.currency_rate() converts the USD result into your account currency.
Common mistakes on EURUSD
- Typing points as pips. A 20-pip stop is 200 points in MT5. An EA input of
StopLoss = 20on a 5-digit quote is a 2-pip stop, and an EA that sizes from risk then opens ten times the intended volume. - Forgetting the account currency. $10 per pip holds for a USD account. A EUR account risking €100 can buy slightly more: €100 is $116 at 1.16, so 0.58 lots with the same 20-pip stop.
- Rounding up. 0.505 lots must become 0.50, not 0.51: rounding up makes the loss at the stop larger than the risk you chose. The calculator and the code below round down to the volume step.
Lot size sets how much a trade loses if the stop is hit at its price. It doesn't make a trade a good one, and gaps or slippage can make the loss larger. Trading involves substantial risk of loss and is not suitable for every investor. Edgoro is a software tool, not a broker or financial adviser: nothing it produces is investment advice, and past or backtested performance does not guarantee future results.