Bonjour à tous,

MetaTrader 4 est une très bonne plateforme selon moi. Pour les particuliers, elle offre une versatilité sans égale et l'accès à de nombreux experts, scripts et indicateurs en tout genre. Néanmoins, un de ses gros défauts qui est paradoxalement lié à sa versatilité est le besoin constant de la mettre à jour avec certains "petits' et gros changements plus ou moins gênants. Par exemple, l'apparition de la cinquième décimale qui a permis aux courtiers de proposer des spreads intermédiaires mais a compliqué le calcul pour de nombreux programmes ou encore la possibilité de spéculer sur d'autres types d'actifs que le Forex (CFDs et métaux) ouvrant les horizons d'investissement mais nécessitant une nouvelle fois des ajustements pour certains calculs.

Je vais ici vous présenter un code simplifié permettant d'uniformiser les calculs du volume d'une position pour tous les différents actifs et tous les types de plateformes (4, 5 décimales ou avec une devise de base différente).

Pour accroître la facilité d'adaptation, ce code vous est fourni sous forme d'une fonction externe à ajouter à la fin de votre programme (certains ajustements seront néanmoins nécessaires). S'agissant du calcul d'une position en fonction d'un pourcentage de risque maximal, celui-ci n'est utile que si votre position comporte un stop fixe.

Les deux variables requises sont donc le niveau d'entrée et le niveau stop (ou le nombre de pips si le stop est fixe).

double fCalculLots(double dEntree, double dStop)
  {
  }
// remplacez double dStop par int iStop si le nombre de pips est fixe pour le stop



Nous devons maintenant calculer et obtenir 3 variables différentes: le risque maximale par rapport à notre risque maximal par position, la valeur de la plus petite variation du cours possible et la grandeur de la plus petite variation possible. Pour des paires de devises, la seule différence serait dans le nombre de décimales (0.0001, 0.00001 ou 0.001 et 0.01) mais certains actifs utilisent des sauts de 5 comme plus petites variations (0.5 pour le CFD du CAC40 par exemple).

double dRisqueMax = (RisqueMaxPourcentage/100) * AccountBalance(); 
double dValeurPip = MarketInfo(Symbol(), MODE_TICKVALUE);
double dTaillePip = MarketInfo(Symbol(), MODE_TICKSIZE);



La variable RisqueMaxPourcentage doit être déclaré au début de votre programme dans les variables externes et représente le pourcentage de risque maximale par position par rapport à la balance du compte (2 équivaut à 2% soit pour un compte de 1000 euros, 20 euros).

extern double RisqueMaxPourcentage = 2;



Pour rendre le calcul compatible avec les courtiers affichant une décimale supplémentaire, il faut maintenant adapter les variables dValeurPip et dTaillePip.

if(Point == 0.001 || Point == 0.00001)
 {
 dValeurPip = dValeurPip * 10;
 dValeurTick = dValeurTick * 10;
 }




Calculons maintenant le volume de la position en nous basant sur le stop de la position.

double dStoploss = (MathAbs(dEntree-dStop)/dValeurTick);
// inutile si votre stop est en pip
double dLots = (dRisqueMax / dStoploss) / dValeurPip;
// si le stop est en pips, remplacez dStopLoss par iStopLoss




Finalement, il ne reste plus qu'à nous assurer que le format du volume respecte les normes du courtier.

if(dLots < MarketInfo(Symbol(),MODE_MINLOT))
 dLots = MarketInfo(Symbol(),MODE_MINLOT);
if(dLots > MarketInfo(Symbol(),MODE_MAXLOT)) 
 dLots = MarketInfo(Symbol(),MODE_MAXLOT);
if(MarketInfo(Symbol(), MODE_LOTSTEP) == 0.01)
 dLots = NormalizeDouble(dLots, 2);
else 
 dLots = NormalizeDouble(dLots, 1);



Les deux premières instructions conditionnelles vérifient que le volume est plus grand que le volume minimum autorisé et plus petit que le volume maximal et l'ajuste au besoin. La dernière instruction vérifie l'arrondi requis par le courtiers (un compte micro, mini et standard autorise en général un arrondi à 0.01 près tandis qu'un compte de type interbanquaires requiert un arrondi à 0.1 près).

Il ne reste plus qu'à retourner la valeur obtenue.

return(dLots);



Le code de la fonction au complet est donc:

double fCalculLots(double dEntree, double dStop)
  {
  double dRisqueMax = (RisqueMaxPourcentage/100) * AccountBalance(); 
  double dValeurPip = MarketInfo(Symbol(), MODE_TICKVALUE);
  double dValeurTick = MarketInfo(Symbol(), MODE_TICKSIZE);
 if(Point == 0.001 || Point == 0.00001)
   {
   dValeurPip = dValeurPip * 10;
   dValeurTick = dValeurTick * 10;
   }
 double dStoploss = (MathAbs(dEntree-dStop)/dValeurTick); 
 double dLots = (dRisqueMax / dStoploss) / dValeurPip;
 if(dLots < MarketInfo(Symbol(),MODE_MINLOT))
   dLots = MarketInfo(Symbol(),MODE_MINLOT);
 if(dLots > MarketInfo(Symbol(),MODE_MAXLOT)) 
   dLots = MarketInfo(Symbol(),MODE_MAXLOT);
 if(MarketInfo(Symbol(), MODE_LOTSTEP) == 0.01)
   dLots = NormalizeDouble(dLots, 2);
 else 
   dLots = NormalizeDouble(dLots, 1); 
 return(dLots); 
 }



Il ne reste qu'à insérer un appel de fonction dans votre fonction de passage d'ordre. Par exemple:

OrderSend(Symbol(), OP_SELL, fCalculLots(PrixEntree, PrixStop) , PrixEntree, 5, PrixStop , PrixLimite, "Commentaire", iNumeroMagic, 0, Red);




N'oubliez pas de remplacer les variables de la fonction par les valeurs correspondantes au prix d'entrée et prix stop.

Sur ce, je vous souhaite de bons codes!

'