EA doesn't calculate lot size on AUS cfds like it does on US cfds, currencies and cryptos.

 

Hi there,

Thanks for checking this out and offering your advice.

My EA places orders according to levels I manually specify.  I've only been using it on US share CFDs until yesterday when I used it on a AUS share CFD.  It looks like the function that calculates lot size doesn't work on AUS orders as it does on US orders. 

To demonstrate this error in action, the below screen shot shows wes.asx has a profit of $4.24 while gps.nyse has a profit of $49.13.

The below screenshot shows that wes is about 25% of the way to the TP while gps is less than that, however wes shows a tenth of the profit.  The distance to TP is the same as the initial SL.  2% of equity / available margin is intended to be used each trade.  


This is my code for calculating lot size:

double GetTradeVolume(string symbol)
  {
   double return_value = 0;
   m_symbol.Name(symbol);
   m_money.Init(GetPointer(m_symbol), (ENUM_TIMEFRAMES)GlobalVariableGet("g" + symbol + "_timeframe"), (double)SymbolInfoDouble(symbol, SYMBOL_POINT));
   m_money.Percent(risk_percent);

   if(isLong)
      return_value =  m_money.CheckOpenLong(GlobalVariableGet("g" + symbol + "_entry_level"), GlobalVariableGet("g" + symbol + "_sl"));
   if(isShort)
      return_value =  m_money.CheckOpenShort(GlobalVariableGet("g" + symbol + "_entry_level"), GlobalVariableGet("g" + symbol + "_sl"));

   return_value = NormalizeDouble(return_value, 2);

   return return_value;
  }


There has been no problem using the EA on US share cfds, currencies or cryptos.  I've only been doing demo trading with this.

What can I do so the EA doesn't allocate lot size differently to AUS share cfds as with other instruments?

Thanks.

 
I guess you (yes you!) are just as confused as me then.
 

Today on SHOP.nyse I lost about $1k on a position that my EA is supposed to allocate 2% of my account equity (started with $15k) on.  It's the same problem as described above i.e. the incorrect lot size being allocated but it is not just when trading AUS cfds.  But in all these cases the lot size has been 10 contracts.  For some stock cfd's that seems to mean different things or otherwise what am I missing.  Please help.

Time Position Symbol Type Volume Price S / L T / P Time Price Commission Swap Profit
2022.01.27 22:21:27 190685913 SHOP.NYSE.a sell 10 817.281 919.535 635.078 2022.01.31 16:45:27 920.405 0.00 -1.13 -1 031.24
 
brettles #: Today on SHOP.nyse I lost about $1k on a position that my EA is supposed to allocate 2% of my account equity (started with $15k) on.  It's the same problem as described above i.e. the incorrect lot size being allocated but it is not just when trading AUS cfds.  But in all these cases the lot size has been 10 contracts.  For some stock cfd's that seems to mean different things or otherwise what am I missing.  Please help.

You have described your problem in detail, but what you have not done is provide real code that can be studied in order to help you. The little bit of code you provided is of no use. We cannot "guess" what is in the rest of code and we are just left with even more questions.

For example what is "m_money"? We have no idea what class it is or what its methods do. If you want us to properly look at your code for errors or problems, then you would have to supply either full source code, or in the least a working skeleton example that can illustrate the problem.

Short of this, there is not much we can do to help.

 

How's this?


#include <Trade\Trade.mqh>
#include <Expert\Expert.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Expert\Money\MoneyFixedRisk.mqh>
#include <Tools\DateTime.mqh>

//CTrade trade;
CSymbolInfo m_symbol;
CMoneyFixedRisk m_money;
CTrade my_trade;

// Trade direction
input bool isLong;                        // Long
input bool isShort;                       // Short

// Position sizing
double risk_percent = 2;

void OnInit()
  {
// Set details for new orders
   if(!CheckPositionOpen(_Symbol) && !CheckPendingOrderPlaced(_Symbol) && CheckHLINESPlacedOnChart())
     {
      GlobalVariableSet("g" + _Symbol + "_position_opened", false);
      GlobalVariableSet("g" + _Symbol + "_timeframe", (ENUM_TIMEFRAMES)GetTradeTimeFrame(_Period));
      GlobalVariableSet("g" + _Symbol + "_entry_level", NormalizeDouble(GetEntryLevel(_Symbol), (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS)));
      GlobalVariableSet("g" + _Symbol + "_sl", NormalizeDouble(GetInitialStopLossLevel(), (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS)));
      GlobalVariableSet("g" + _Symbol + "_tp", NormalizeDouble(GetProfitTarget(), (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS)));
      GlobalVariableSet("g" + _Symbol + "_vol", NormalizeDouble(GetTradeVolume(_Symbol), 2));
      GlobalVariableSet("g" + _Symbol + "_deviation", GetMaxDeviationPointsAllowed(_Symbol, max_gap_r, GetEntryLevel(_Symbol), GetInitialStopLossLevel()));

      GlobalVariablesFlush();
     }

// Get open position details
   if(PositionSelect(_Symbol))
     {
      GlobalVariableSet("g" + _Symbol + "_position_opened", true);
      GlobalVariableSet("g" + _Symbol + "_timeframe", (ENUM_TIMEFRAMES)GetTradeTimeFrame(_Period));
      GlobalVariableSet("g" + _Symbol + "_entry_level", PositionGetDouble(POSITION_PRICE_OPEN));
      GlobalVariableSet("g" + _Symbol + "_sl", PositionGetDouble(POSITION_SL));
      GlobalVariableSet("g" + _Symbol + "_tp", PositionGetDouble(POSITION_TP));
      GlobalVariableSet("g" + _Symbol + "_vol", PositionGetDouble(POSITION_VOLUME));

      GlobalVariablesFlush();
     }
  }

double GetTradeVolume(string symbol)
  {
   double return_value = 0;
   ENUM_TIMEFRAMES timeframe = (ENUM_TIMEFRAMES)GlobalVariableGet("g" + symbol + "_timeframe");
   double entry = GlobalVariableGet("g" + symbol + "_entry_level");
   double sl = GlobalVariableGet("g" + symbol + "_sl");
   
   m_symbol.Name(symbol);
   m_money.Init(GetPointer(m_symbol), timeframe, (double)SymbolInfoDouble(symbol, SYMBOL_POINT));
   m_money.Percent(risk_percent);
   
   if(isLong)
      return_value =  m_money.CheckOpenLong(entry, sl);
   if(isShort)
      return_value =  m_money.CheckOpenShort(entry, sl);

   return_value = NormalizeDouble(return_value, 2);
   
   return return_value;
  }

The entry level and initial sl are derived from HLINES I drop on the chart around pivot levels and the TP is the same distance from the entry as the sl.

Thanks for your help I didn't think anyone would get back to me.

 
brettles #: How's this? The entry level and initial sl are derived from HLINES I drop on the chart around pivot levels and the TP is the same distance from the entry as the sl.

Thanks for your help I didn't think anyone would get back to me.

I’m going to help by making you test and debug your own code. It may not seem so “nice”, but it will help you learn and understand it better in the long run.

  1. Take your example code, put it into a “script” (not an EA) so it can be tested more easily.
  2. Simplify it as much as possible and remove all references to Terminal Global Variables. Just make it calculate the trade volume based on user supplied inputs for the variables you need, like stop-loss, etc.
  3. Add some code for it to “Print” the results of the "GetTradeVolume", as well as the inputs and symbol info, to the Experts tab log.
  4. Attach it to different charts of the various symbols you wish to test and look at the results.
  5. Compile a table of those "prints" for each symbol and post them here with your test code.

Why am I suggesting this? Well, we do not work with your broker, and we do not know if the “contract” details supplied by the broker are flawed or not, or if the values in the "Global variables" are correct or not. So by having your results to compare with tests we can run on our own setups, we should be able to find the cause or in the very least offer further guidance into further testing until a cause can be found.

As it stands now, we cannot possibly test your code on our end, nor do we have the foggiest idea about your setup and the symbols you are testing.

In summary, help us help you!

 
PS! Please charge your phone/tablet. If you leave a Lithium-Ion battery go below 40-50%, you are reducing its life-span. That's what vendors want so as to sell you a replacement sooner than required.
 

Also, as a matter of code consistency, your "init" line would be better like this:

m_money.Init( GetPointer( m_symbol ), timeframe, m_symbol.Point() );

It may not be that important in your example, but it helps for portability and future proofing.

 
Fernando Carreiro #:

Also, as a matter of code consistency, your "init" line would be better like this:

It may not be that important in your example, but it helps for portability and future proofing.

Thanks for that!

 
Fernando Carreiro #:

I’m going to help by making you test and debug your own code. It may not seem so “nice”, but it will help you learn and understand it better in the long run.

  1. Take your example code, put it into a “script” (not an EA) so it can be tested more easily.
  2. Simplify it as much as possible and remove all references to Terminal Global Variables. Just make it calculate the trade volume based on user supplied inputs for the variables you need, like stop-loss, etc.
  3. Add some code for it to “Print” the results of the "GetTradeVolume", as well as the inputs and symbol info, to the Experts tab log.
  4. Attach it to different charts of the various symbols you wish to test and look at the results.
  5. Compile a table of those "prints" for each symbol and post them here with your test code.

Why am I suggesting this? Well, we do not work with your broker, and we do not know if the “contract” details supplied by the broker are flawed or not, or if the values in the "Global variables" are correct or not. So by having your results to compare with tests we can run on our own setups, we should be able to find the cause or in the very least offer further guidance into further testing until a cause can be found.

As it stands now, we cannot possibly test your code on our end, nor do we have the foggiest idea about your setup and the symbols you are testing.

In summary, help us help you!

Thanks very much for this.

Ok, here is the script..

#include <Trade\Trade.mqh>
#include <Expert\Money\MoneyFixedRisk.mqh>

CSymbolInfo m_symbol;
CMoneyFixedRisk m_money;
CTrade my_trade;

bool isLong;
bool isShort = true;

double entry = 16.471;
double sl = 19.000;
int risk_percent = 2;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   double vol = GetTradeVolume(_Symbol);

   Print("entry: ", entry);
   Print("sl: ", sl);
   Print("lots: ", vol);
   Print("point: ", SymbolInfoDouble(_Symbol, SYMBOL_POINT));
   Print("tick_size: ", SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE));
   Print("tick_value: ", SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE));
   Print("contract_size: ", SymbolInfoDouble(_Symbol, SYMBOL_TRADE_CONTRACT_SIZE));
   Print("vol_min: ", SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN));
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double GetTradeVolume(string symbol)
  {
   double return_value = 0;
   ENUM_TIMEFRAMES timeframe = _Period;

   m_symbol.Name(symbol);
   m_money.Init(GetPointer(m_symbol), timeframe, m_symbol.Point());
   m_money.Percent(risk_percent);

   if(isLong)
      return_value =  m_money.CheckOpenLong(entry, sl);
   if(isShort)
      return_value =  m_money.CheckOpenShort(entry, sl);

   return_value = NormalizeDouble(return_value, 2);

   return return_value;
  }

And here is the output.  I've added a couple rows from data taken from the transaction statment marked with an "*".  The calculated lot size will differ because of a different account balance now than before.

SHOP.nyse GPS.nyse WES.asx
stop entry 817.539 16.471 53.738
initial sl 1000.000 19.000 56.000
lots calc 10.0 99.0 10.0
lots used* 10 114 10
point 0.001 0.001 0.001
tick_size 0.001 0.001 0.001
tick_value 0.001 0.001 0.0
contract_size 1.0 1.0 1.0
vol_min 10.0 10.0 10.0
exit* 920.405 17.022 51.48
points to exit -102.87 -0.55 2.26
actual profit* -1 031.24 -63.04 16.02
 

The starting account balance was $15k so for risking 2%/trade it doesn't make sense that SHOP would have a -$1k loss when there wasn't a gap or significant slippage and that GPS would represent a bigger loss than WES's profit margin.

 
brettles #: The starting account balance was $15k so for risking 2%/trade it doesn't make sense that SHOP would have a -$1k loss when there wasn't a gap or significant slippage and that GPS would represent a bigger loss than WES's profit margin.

Please note that according to your table, WES.asx is reporting a Tick Value of 0.0, which is invalid and will mess with your calculation. Your broker is not reporting it correctly.

Here is my take on the script:

#include <Trade\AccountInfo.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Expert\Money\MoneyFixedRisk.mqh>

input double
   i_dbEntryPrice     = 16.471,
   i_dbStopLossPrice  = 19.000,
   i_dbRiskPercentage = 2.0;

void OnStart()
{
   bool
      bIsLong  = i_dbEntryPrice > i_dbStopLossPrice,
      bIsShort = i_dbEntryPrice < i_dbStopLossPrice;

   if( bIsLong || bIsShort )
   {
      CSymbolInfo oSymbol;
      if( oSymbol.Name( _Symbol ) )
      {
         CMoneyFixedRisk oMoney;
         if( oMoney.Init( GetPointer( oSymbol ), _Period, oSymbol.Point() ) )
         {
            oMoney.Percent( i_dbRiskPercentage );
            CAccountInfo oAccountInfo;
            double dbVolume = bIsLong
                            ? oMoney.CheckOpenLong(  i_dbEntryPrice, i_dbStopLossPrice )
                            : oMoney.CheckOpenShort( i_dbEntryPrice, i_dbStopLossPrice );

            Print( "Inputs:"                                                                          );
            Print( "   Entry:               ", DoubleToString( i_dbEntryPrice,     oSymbol.Digits() ) );
            Print( "   S/L:                 ", DoubleToString( i_dbStopLossPrice,  oSymbol.Digits() ) );
            Print( "   Risk %:              ", DoubleToString( i_dbRiskPercentage, 3                ) );
            Print( "Output:"                                                                          );
            Print( "   Volume:              ", dbVolume                                               );
            Print( "Account:"                                                                         );
            Print( "   Balance:             ", DoubleToString( oAccountInfo.Balance(), 2 ),
                                               " (", oAccountInfo.Currency(), ")"                     );
            Print( "Symbol:"                                                                          );
            Print( "   Point size:          ", DoubleToString( oSymbol.Point(),    oSymbol.Digits() ) );
            Print( "   Tick size:           ", DoubleToString( oSymbol.TickSize(), oSymbol.Digits() ) );
            Print( "   Tick value:          ", oSymbol.TickValue()                                    );
            Print( "   Tick value (profit): ", oSymbol.TickValueProfit()                              );
            Print( "   Tick value (loss):   ", oSymbol.TickValueLoss()                                );
            Print( "   Lots (minimum):      ", oSymbol.LotsMin()                                      );
            Print( "   Lots (maximum):      ", oSymbol.LotsMax()                                      );
            Print( "   Lots (step):         ", oSymbol.LotsStep()                                     );
         }
         else
            Print( "Error: Unable to initialise fixed risk money management!" );
      }
      else
         Print( "Error: Unable to assign symbol name!" );
   }
   else
      Print( "Error: Invalid entry and/or stop-loss price!" );
};
Reason: