Trying calculate trade result / OrderCalcProfit

 

Hi,

I am pretty new to programming MQL, although I have quite some experience in programming in general so maybe you can help me with this?

Trying to make the first steps with MQL in MT5, one obvious thing is to prepare and calculate a trade. So I come across this:

OrderCalcProfit(ORDER_TYPE_BUY,"Ger40Jun26", 1, 1000, 800, profit);

Stripped it down to the main thing. Once considering the contract size connected with the market, I would guess result could be around 5.000.

However, profit contains -2.000 when returns.

I checked some values that came across my mind:

double vmin = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double vstep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
int stopLevel = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
int tradeCalcMode = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_CALC_MODE);
double contract = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_CONTRACT_SIZE);
//double roundedSL = MathRound(desiredSL / tickSize) * tickSize;
Print("Symbol: ", _Symbol, " Min=", DoubleToString(vmin, 2), " Step=", DoubleToString(vstep, 2), " stopLevel=", stopLevel, " Point=", DoubleToString(point, 2),
   " TickSize=", DoubleToString(tickSize, 2), " TickValue=", DoubleToString(tickValue, 2), " tradeCalcMode=", IntegerToString(tradeCalcMode), " contract=", DoubleToString(contract, 2));

Result:

2026.05.19 15:28:31.311 Core 1  2026.01.20 00:00:00   Symbol: Ger40Jun26 Min=0.01 Step=0.01 stopLevel=10 Point=0.10 TickSize=0.50 TickValue=12.50 tradeCalcMode=4 contract=25.00

Just for chance trying this:

OrderCalcProfit(ORDER_TYPE_BUY,"Ger40", 1, 1000, 800, profit);

Contract size should be 1, so -200 could be appealing, but the result is -20.000. Here KI pushes me to believe there is a "EuroPerLot" Faktor which simply is 100 but can't be queried anywhere you just have to believe. Well, that's strange to me...

So I suppose there must be a rather simple (did I mention that I am quite new to this?) solution. Can you point me to it? BTW I used the search function but nothing that I found was of much help for this.

Thanks a lot,

Stephan Wöbbeking

 
Additional finding: When trying to open a trade (demo account) with minimum volume (0,25 Lot), I get the error "not enough money". Well, that's odd, in manual mode its no deal to open it, by code its impossible. So its not only the profit calculation but the trade itself. Following this, the profit calculation might be fine. But the factor of 100 as outlined above is still my problem. Still I don't know where it comes from. Any hints are welcome. Even when accompanied by "that was st*pid", I guess I can handle it.
 
Stephan Wöbbeking #:
Additional finding: When trying to open a trade (demo account) with minimum volume (0,25 Lot), I get the error "not enough money". Well, that's odd, in manual mode its no deal to open it, by code its impossible. So its not only the profit calculation but the trade itself. Following this, the profit calculation might be fine. But the factor of 100 as outlined above is still my problem. Still I don't know where it comes from. Any hints are welcome. Even when accompanied by "that was st*pid", I guess I can handle it.
To open a trade (manual or by code, it's the same), you need enough margin. What is the margin for the symbol you trade ? What is your free margin ?
 
Alain Verleyen #:
To open a trade (manual or by code, it's the same), you need enough margin. What is the margin for the symbol you trade ? What is your free margin ?

Hi, thanks for your answer as first!

Well, I know about the margin. I admit I haven't checked for it now, but I work in test mode with 10.000 EUR demo account and buying some Ger40future should be no problem. Also, the minimum amout of 0,25 then puzzles me, should be 0,01 afaik?

The main problem persists and is in connection what you say: Yes, you are right, I don't have enough margin, because the expected loss is 100 times what I plan for. And that's exactly my point, where is this factor of 100 coming from? Its not there in my real money account.

 
One more finding: Trying the same thing in "GOLD" market, works perfectly fine and as expected...
 
Stephan Wöbbeking #:

Hi, thanks for your answer as first!

Well, I know about the margin. I admit I haven't checked for it now, but I work in test mode with 10.000 EUR demo account and buying some Ger40future should be no problem. Also, the minimum amout of 0,25 then puzzles me, should be 0,01 afaik?

The main problem persists and is in connection what you say: Yes, you are right, I don't have enough margin, because the expected loss is 100 times what I plan for. And that's exactly my point, where is this factor of 100 coming from? Its not there in my real money account.

If you want clear answer, you need to provide clear information (screenshots, logs, etc...). No idea about the factor so you are talking about (100 ?).

Are you trading real futures or CFD ? 

 
Comments that do not relate to this topic, have been moved to "Off-topic posts".
 
Stephan Wöbbeking #:

The main problem persists and is in connection what you say: Yes, you are right, I don't have enough margin, because the expected loss is 100 times what I plan for. And that's exactly my point, where is this factor of 100 coming from? Its not there in my real money account.

could the ger40 have been closed at that time? some brokers have very limited trading times, compared to some other brokers where you can trade it from ger40 open to close; while other brokers, price action works on the charts but trading period might not be for another 1 or even 2 hours after that markets opening.

and dont forget that spreads are often much higher in that first hour of markets opening and again in last hour of a market closing. This can give unexplained errors if your requested price is too far from the live prices.

But without seeing the actual code that you used to make the order attempt, these are only guesses. Like Alain said, if you want more specific answers, then you need to provide specific code for us to analyse.

But a suggestion: search the site for the ordercalcprofit. There are several threads discussing its formulae, however, i am sure that i remember a couple of them coming to same conclusion that the known forumulae does not always explain the functions result, ie known to mq devs only.

 
Alain Verleyen #:

If you want clear answer, you need to provide clear information (screenshots, logs, etc...). No idea about the factor so you are talking about (100 ?).

Are you trading real futures or CFD ? 

Hey, sorry for the late answer, its quite a hobby project, so every now and then...

I am happy to share the code and happy to receive comments if you feel like. Specific lines pointed out in text below it.

//+------------------------------------------------------------------+
//|                                                       Test01.mq5 |
//|                  Crossover zweier moving averages aus Perplexity |
//|                                                Stephan Wöbbeking |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property strict
#property copyright "Stephan Wöbbeking"
#property link      "https://www.mql5.com"
#property version   "1.00"

#include <Trade/Trade.mqh>

input int      FastMAPeriod   = 20;
input int      SlowMAPeriod   = 50;
input ENUM_MA_METHOD MaMethod = MODE_EMA;
input double   Lots           = 0.25;
input int      StopLossPoints = 20000;
input int      TakeProfitPoints = 100000;
input ulong    MagicNumber    = 20260409;

CTrade trade;

int fastHandle = INVALID_HANDLE;
int slowHandle = INVALID_HANDLE;

datetime lastBarTime = 0;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit() {
   trade.SetExpertMagicNumber((int)MagicNumber);

   Print("--- Symbol-Info für ", _Symbol, " ---");
   Print("Contract Size: ", SymbolInfoDouble(_Symbol, SYMBOL_TRADE_CONTRACT_SIZE));
   Print("Tick Value: ", SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE));
   Print("Tick Size: ", SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE));
   Print("Profit Mode: ", SymbolInfoInteger(_Symbol, SYMBOL_TRADE_CALC_MODE));
   
   // Hier berechnet der MT5 den Wert eines Ticks für dein Konto:
   double tickValueProfit = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE_PROFIT);
   Print("Tick Value Profit: ", tickValueProfit);
   
   double vmin = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double vstep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   int stopLevel = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
   int tradeCalcMode = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_CALC_MODE);
   double contract = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_CONTRACT_SIZE);
   //double roundedSL = MathRound(desiredSL / tickSize) * tickSize;
   Print("Symbol: ", _Symbol, " Min=", DoubleToString(vmin, 2), " Step=", DoubleToString(vstep, 2), " stopLevel=", stopLevel, " Point=", DoubleToString(point, 2), " TickSize=", DoubleToString(tickSize, 2), " TickValue=", DoubleToString(tickValue, 2), " tradeCalcMode=", IntegerToString(tradeCalcMode), " contract=", DoubleToString(contract, 2));

   double profit;
   OrderCalcProfit(ORDER_TYPE_BUY,"Ger40Jun26", 1, 1000, 800, profit); // Contract 25
   Print("Ger40Jun26 (expect -5000) OrderCalcProfit=", DoubleToString(profit, 4));
   OrderCalcProfit(ORDER_TYPE_BUY,"Ger40", 1, 1000, 800, profit); // Contract 1
   Print("Ger40      (expect  -200) OrderCalcProfit=", DoubleToString(profit, 4));
   OrderCalcProfit(ORDER_TYPE_BUY,"GOLD", 0.1, 1000, 800, profit); // Contract 100
   Print("Gold       (expect -2000) OrderCalcProfit=", DoubleToString(profit, 4));
   
// Moving Average indicators
   fastHandle = iMA(_Symbol, _Period, FastMAPeriod, 0, MaMethod, PRICE_CLOSE);
   slowHandle = iMA(_Symbol, _Period, SlowMAPeriod, 0, MaMethod, PRICE_CLOSE);

   if(fastHandle == INVALID_HANDLE || slowHandle == INVALID_HANDLE) {
      Print("Failed to create MA handles");
      return(INIT_FAILED);
   }

   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
   if(fastHandle != INVALID_HANDLE)
      IndicatorRelease(fastHandle);
   if(slowHandle != INVALID_HANDLE)
      IndicatorRelease(slowHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
bool IsNewBar() {
   datetime currentBarTime = iTime(_Symbol, _Period, 0);
   if(currentBarTime != lastBarTime) {
      lastBarTime = currentBarTime;
      return true;
   }
   return false;
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool HasOpenPosition() {
   for(int i = 0; i < PositionsTotal(); i++) {
      ulong ticket = PositionGetTicket(i);
      if(PositionSelectByTicket(ticket)) {
         if(PositionGetString(POSITION_SYMBOL) == _Symbol && (long)PositionGetInteger(POSITION_MAGIC) == MagicNumber)
            return true;
      }
   }
   return false;
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CloseOppositePositions(bool wantBuy) {
   for(int i = PositionsTotal() - 1; i >= 0; i--) {
      ulong ticket = PositionGetTicket(i);
      if(!PositionSelectByTicket(ticket))
         continue;

      string sym = PositionGetString(POSITION_SYMBOL);
      ulong magic = (ulong)PositionGetInteger(POSITION_MAGIC);
      long type = PositionGetInteger(POSITION_TYPE);

      if(sym != _Symbol || magic != MagicNumber)
         continue;

      if(wantBuy && type == POSITION_TYPE_SELL)
         trade.PositionClose(ticket);

      if(!wantBuy && type == POSITION_TYPE_BUY)
         trade.PositionClose(ticket);
   }
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick() {
   if(!IsNewBar())
      return;

   // Aktueller Kontostand (realisiert)
   double balance = AccountInfoDouble(ACCOUNT_BALANCE);
   double equity  = AccountInfoDouble(ACCOUNT_EQUITY);
   Print("Balance: ", balance, " | Equity: ", equity);
   
   double fast[3], slow[3];
   ArraySetAsSeries(fast, true);
   ArraySetAsSeries(slow, true);

   if(CopyBuffer(fastHandle, 0, 0, 3, fast) < 3)
      return;
   if(CopyBuffer(slowHandle, 0, 0, 3, slow) < 3)
      return;

   bool buySignal  = (fast[1] <= slow[1] && fast[0] > slow[0]);
   bool sellSignal = (fast[1] >= slow[1] && fast[0] < slow[0]);

   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double point = _Point;

   if (buySignal || sellSignal ) {
      Print("Time: ", TimeToString(TimeCurrent(), TIME_DATE));
   }
   if(buySignal) {
      CloseOppositePositions(true);
      if(!HasOpenPosition()) {
         double sl = MathMax(0, ask - StopLossPoints * point);
         double tp = MathMax(0, ask + TakeProfitPoints * point);
         trade.Buy(Lots, _Symbol, ask, sl, tp, "MA Crossover Buy");
      }
   } else if(sellSignal) {
      CloseOppositePositions(false);
      if(!HasOpenPosition()) {
         double sl = MathMax(0, ask - StopLossPoints * point);
         double tp = MathMax(0, ask + TakeProfitPoints * point);
         trade.Sell(Lots, _Symbol, bid, sl, tp, "MA Crossover Sell");
      }
   }

   // Aktueller Kontostand (realisiert)
   balance = AccountInfoDouble(ACCOUNT_BALANCE);
   equity  = AccountInfoDouble(ACCOUNT_EQUITY);
   Print("Balance: ", balance, " | Equity: ", equity);
}
//+------------------------------------------------------------------+

That's the overall file. As mentioned, its a first try, just to see how the thing goes. For my understanding, all that's needed for the topic I opened here is the Init function and only these lines:

   double vmin = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double vstep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   int stopLevel = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
   int tradeCalcMode = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_CALC_MODE);
   double contract = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_CONTRACT_SIZE);
   //double roundedSL = MathRound(desiredSL / tickSize) * tickSize;
   Print("Symbol: ", _Symbol, " Min=", DoubleToString(vmin, 2), " Step=", DoubleToString(vstep, 2), " stopLevel=", stopLevel, " Point=", DoubleToString(point, 2), " TickSize=", DoubleToString(tickSize, 2), " TickValue=", DoubleToString(tickValue, 2), " tradeCalcMode=", IntegerToString(tradeCalcMode), " contract=", DoubleToString(contract, 2));

   double profit;
   OrderCalcProfit(ORDER_TYPE_BUY,"Ger40Jun26", 1, 1000, 800, profit); // Contract 25
   Print("Ger40Jun26 (expect -5000) OrderCalcProfit=", DoubleToString(profit, 4));
   OrderCalcProfit(ORDER_TYPE_BUY,"Ger40", 1, 1000, 800, profit); // Contract 1
   Print("Ger40      (expect  -200) OrderCalcProfit=", DoubleToString(profit, 4));
   OrderCalcProfit(ORDER_TYPE_BUY,"GOLD", 0.1, 1000, 800, profit); // Contract 100
   Print("Gold       (expect -2000) OrderCalcProfit=", DoubleToString(profit, 4));

Here is the resulting log:

2025.01.01 00:00:00   --- Symbol-Info für Ger40Jun26 ---
2025.01.01 00:00:00   Contract Size: 25.0
2025.01.01 00:00:00   Tick Value: 12.5
2025.01.01 00:00:00   Tick Size: 0.5
2025.01.01 00:00:00   Profit Mode: 4
2025.01.01 00:00:00   Tick Value Profit: 12.5
2025.01.01 00:00:00   Symbol: Ger40Jun26 Min=0.01 Step=0.01 stopLevel=10 Point=0.10 TickSize=0.50 TickValue=12.50 tradeCalcMode=4 contract=25.00
2025.01.01 00:00:00   Ger40Jun26 (expect -5000) OrderCalcProfit=-2000.0000
Ger40: symbol to be synchronized
Ger40: symbol synchronized, 3880 bytes of symbol info received
Ger40: history synchronization started
Ger40: load 2.47 Mb of history data to synchronize in 0:00:00.878
Ger40: history synchronized from 2024.01.02 to 2026.04.28
2025.01.01 00:00:00   Ger40      (expect  -200) OrderCalcProfit=-20000.0000
GOLD: symbol to be synchronized
GOLD: symbol synchronized, 3880 bytes of symbol info received
GOLD: history synchronization started
GOLD: load 2.34 Mb of history data to synchronize in 0:00:00.522
GOLD: history synchronized from 2024.01.02 to 2026.02.13
2025.01.01 00:00:00   Gold       (expect -2000) OrderCalcProfit=-2000.0000

Its only an extract of it do not bother to much. Mainly its the lines with "(expect...)". For Gold it works great, expectation fits the result. But for GER... Far off what I could explain. And the vast factor plus the exact results do not speak for spread deviation or something. I looks like a clear factor.

I just don't get it, but it seems to be so big that it should be jumping on me... Maybe you can spot it?

BTW: I am mainly in the CFD symbols but not only. I use ActiveTrades as Broker. Asked them already, but they send me to this forum. Plus, I don't think they have much idea about it. Plus, I believe the answer I am looking for should be in MQL, client side, not in the broker side. But that's just my gutt-feeling.

Thanks a lot,
Stephan

 
Michael Charles Schefe #:

could the ger40 have been closed at that time? some brokers have very limited trading times, compared to some other brokers where you can trade it from ger40 open to close; while other brokers, price action works on the charts but trading period might not be for another 1 or even 2 hours after that markets opening.

and dont forget that spreads are often much higher in that first hour of markets opening and again in last hour of a market closing. This can give unexplained errors if your requested price is too far from the live prices.

But without seeing the actual code that you used to make the order attempt, these are only guesses. Like Alain said, if you want more specific answers, then you need to provide specific code for us to analyse.

But a suggestion: search the site for the ordercalcprofit. There are several threads discussing its formulae, however, i am sure that i remember a couple of them coming to same conclusion that the known forumulae does not always explain the functions result, ie known to mq devs only.

Thanks for your effort, I have posted the code in the message above.

BTW I checked for OrderCalcProfit threads, but nothing did any help for me. Either it was much to specific for little, little effects I think I am not looking for. It's not about half a percent off expectation, but we are talking about a factor of 100 (!!!) I am missing. Well, quite a few of those threads are to high-level for me, I was simply not able to understand...

 

Hi,

Great to see you starting with MQL5.

Good luck with your journey.