Best practice for accurate monetary value calculation (Points to Money) across different instruments?

 

Hi everyone,

I'm working on a custom tool that needs to calculate position sizing based on risk percentage. My tool needs to convert distance (in Points/Pips) into a monetary value (e.g., how much $ I lose/gain if price moves X points).

I've been using MarketInfo(Symbol(), MODE_TICKVALUE) to do this, but I've noticed that the reliability of this data varies significantly depending on the broker and the instrument (Forex vs. Gold vs. Indices). Sometimes the data is accurate, and other times it's completely off, which messes up my lot size calculation.

I want to know how the professionals handle this. What is the most robust/accurate way to calculate the monetary value of a price movement in MQL4, so that it works correctly across all brokers and asset classes without having to manually patch the TickValue for every specific pair?

Is there a mathematical standard that ensures the conversion is always accurate, regardless of the broker's server settings?

Any advice or code snippets on how to approach this "Universal Calculation" would be greatly appreciated. Thanks!

 
DjuharjatiHi everyone, I'm working on a custom tool that needs to calculate position sizing based on risk percentage. My tool needs to convert distance (in Points/Pips) into a monetary value (e.g., how much $ I lose/gain if price moves X points). I've been using MarketInfo(Symbol(), MODE_TICKVALUE) to do this, but I've noticed that the reliability of this data varies significantly depending on the broker and the instrument (Forex vs. Gold vs. Indices). Sometimes the data is accurate, and other times it's completely off, which messes up my lot size calculation. I want to know how the professionals handle this. What is the most robust/accurate way to calculate the monetary value of a price movement in MQL4, so that it works correctly across all brokers and asset classes without having to manually patch the TickValue for every specific pair? Is there a mathematical standard that ensures the conversion is always accurate, regardless of the broker's server settings? Any advice or code snippets on how to approach this "Universal Calculation" would be greatly appreciated. Thanks!
Hi! Great question - and the issue you're hitting is very common. The unreliability usually isn't the broker's data being "wrong"; it's that MODE_TICKVALUE alone is not enough. You also need MODE_TICKSIZE to scale it correctly.
The key insight: MODE_TICKVALUE gives you the value of one tick, but a tick is not always equal to a point. For Forex it often is, but for Gold and Indices the tick size frequently differs - which is exactly why your calculation works for some instruments and breaks for others.

The universal formula is:

moneyValue = tickValue * volume * (priceDistance / tickSize)

where priceDistance = MathAbs(entryPrice - exitPrice).

Here's a robust MQL4 helper I use in my own EAs. It mirrors how MQL5's native OrderCalcProfit() works, combining tick value and tick size:

// Estimates profit/loss in account currency for a given price move.
// Works across Forex, metals, and indices without manual patching.
bool CalcProfit(string symbol, int type, double volume,
                double priceOpen, double priceClose, double &profit)
{
   if(volume <= 0.0 || priceOpen <= 0.0 || priceClose <= 0.0)
      return false;

   double tickValue = MarketInfo(symbol, MODE_TICKVALUE);
   double tickSize  = MarketInfo(symbol, MODE_TICKSIZE);

   if(tickValue == 0.0 || tickSize == 0.0)
      return false;   // invalid specs — never proceed (would oversize the lot)

   int sign = ((type == OP_BUY  && priceClose < priceOpen) ||
               (type == OP_SELL && priceClose > priceOpen)) ? -1 : 1;

   profit = NormalizeDouble(tickValue * volume *
            (MathAbs(priceOpen - priceClose) / tickSize) * sign, 2);
   return true;
}

And then position sizing becomes:

double profit;
if(!CalcProfit(symbol, OP_BUY, 1.0, entryPrice, slPrice, profit))
   return; // abort — invalid data

double lossPerLot = -profit;                       // loss for 1.0 lot
if(lossPerLot < 0.01) return;                       // safety check

double maxLoss = AccountBalance() * riskPercent / 100.0;
double lots    = maxLoss / lossPerLot;

// normalize to broker's lot step
double step = MarketInfo(symbol, MODE_LOTSTEP);
lots = MathFloor(lots / step) * step;

Two critical safety points (learned the hard way):

1) Always validate that tickValue and tickSize are > 0 before dividing. If the broker returns invalid specs and you proceed anyway, you can get a dangerously oversized lot.

2) Reject the trade (return early) rather than falling back to a guessed value when data is invalid - failing safe is better than sizing on bad data.


This is broker-agnostic because you're letting the terminal provide the pre-converted tick value (already in your account currency), rather than computing currency conversions yourself - which is the fragile part that breaks across brokers.

Hope this helps!

 
There is one important boundary to add: there is no broker-independent “universal” result if the symbol specification itself is wrong. MODE_TICKVALUE and MODE_TICKSIZE are still broker inputs, so multiplying them differently cannot repair bad metadata.

For a risk-sizing tool I would therefore use two paths and fail closed:

1. Primary path: priceDistance / MODE_TICKSIZE * MODE_TICKVALUE * lots.
2. Independent sanity path: derive the raw P/L from MODE_LOTSIZE and MODE_PROFITCALCMODE, then convert the profit currency to the account currency with a current conversion symbol.
3. Reject sizing if either required value is zero/stale or if both paths disagree beyond a small tolerance.

The test matrix matters more than one formula: EURUSD and USDJPY, XAUUSD, one index CFD, at least two deposit currencies, and both long and short moves. Use the minimum accepted lot and compare the predicted loss with the terminal's resulting deal P/L on a demo account; include commission separately because tick value does not cover it.

That gives you a defensible safety property: questionable symbol metadata stops the trade instead of silently oversizing it.

Disclosure: the technical conclusion and suggested A/B control are Arnold Holm's input; AI assistance was used to draft and structure this wording.
 
Arnold Holm #:
For a risk-sizing tool I would therefore use two paths and fail closed:
Would you use or do you use?
 
Djuharjati:
[C]alculate the monetary value of a price movement in MQL4...

Code Base

LotSize Calculation

Daniel Opoku, 2025.07.19 12:26

This is a simple script file to compute lot size either using risk percentage approach or the actual amount to risk.

 
Would use — that was a design recommendation, not a claim that I currently run this exact two-path implementation in a live account. I have not provided implementation evidence for the independent sanity path here, so “would use” is the accurate wording.

The part I do stand behind technically is the boundary: MODE_TICKVALUE/MODE_TICKSIZE remains the primary estimate; an independent path is a validation check only where the profit mode, contract size and account-currency conversion are known. If those inputs are missing or the paths disagree, sizing should stop rather than guess.

Thank you for making the tense explicit.

Disclosure: Arnold Holm verified the technical boundary and that no live-use claim is being made; AI assistance was used to draft and structure this clarification.
 
Arnold Holm #:
Would use — that was a design recommendation, not a claim that I currently run this exact two-path implementation in a live account. I have not provided implementation evidence for the independent sanity path here, so “would use” is the accurate wording.
Why don't you use what you recommended and what do you use instead?
 
Vinicius Pereira De Oliveira #:
MODE_TICKVALUE gives you the value of one tick, but a tick is not always equal to a point. For Forex it often is, but for Gold and Indices the tick size frequently differs - which is exactly why your calculation works for some instruments and breaks for others.
   point = SymbolInfoDouble(BaseSymbol, SYMBOL_POINT);
   tickSize = SymbolInfoDouble(BaseSymbol, SYMBOL_TRADE_TICK_SIZE);
   tickValue = SymbolInfoDouble(BaseSymbol, SYMBOL_TRADE_TICK_VALUE);
   pointValue = point * (tickValue / tickSize);