besoins aide amelioration prog avec "Expert Advisor Builder"
Modérateur : Administrateurs
besoins aide amelioration prog avec "Expert Advisor Builder"
bonjour,
j'ai fait un EA avec "Expert Advisor Builder for MetaTrader 4" et j'ai besoin d'aide sur plusieurs points :
- insérer un stoploss à "x" pips d'une MA (pour achat et vente)
- fermer vente et achat depuis un custom indcateur qui lui me place des croix sur mon graphique (fermer achat et vente dès qu'une croix apparaît....et si possible retarder cette action avec un paramètre de "x" bougies après achat ou vente.
merci d'avance
n'hésitez pas à me contacter car je suis novice donc il est possible que vous ne me comprenez pas vraiment.
ci-joint les paramètres d'entrée du custom indcateur
j'ai fait un EA avec "Expert Advisor Builder for MetaTrader 4" et j'ai besoin d'aide sur plusieurs points :
- insérer un stoploss à "x" pips d'une MA (pour achat et vente)
- fermer vente et achat depuis un custom indcateur qui lui me place des croix sur mon graphique (fermer achat et vente dès qu'une croix apparaît....et si possible retarder cette action avec un paramètre de "x" bougies après achat ou vente.
merci d'avance
n'hésitez pas à me contacter car je suis novice donc il est possible que vous ne me comprenez pas vraiment.
ci-joint les paramètres d'entrée du custom indcateur
- Pièces jointes
-
- custom indicator.jpg (134.81 Kio) Consulté 18072 fois
- Fabien Labrousse
- Administrateur
- Messages : 18056
- Inscription : 17 mars 2008, 19:41
- Localisation : Paris, France
Re: besoins aide amelioration prog avec "Expert Advisor Builder"
Je t'aurai bien aidé mais la je suis débordé et j'ai du retard dans mon travail. Peut-être que la semaine prochaine je trouverai le temps mais je peu rien te promettre. Désolé.
Comparatif brokers, courtiers, banques, néobanques et exchanges crypto
La Structure (par VideoBourse) : Formation bourse sur mesure et évolutive pour optimiser votre compréhension et vos résultats
Plateforme de Trading : ProRealTime | Broker : Interactive Brokers
Contact et échanges avec la communauté : Discord, téléphone, LinkedIn, X (Twitter), Youtube...
La Structure (par VideoBourse) : Formation bourse sur mesure et évolutive pour optimiser votre compréhension et vos résultats
-
xvilain
Réponse avec un léger retard — mais la question revient encore régulièrement
Ce fil date de 2013 et je n'avais jamais trouvé le temps d'y revenir. Comme les mêmes deux questions reviennent sans arrêt en message privé et que ce sujet remonte encore dans les recherches Google, autant y répondre proprement une bonne fois. philippou n'est probablement plus dans les parages, mais le contenu servira aux suivants.
Petit rappel de contexte : les générateurs graphiques de type Expert Advisor Builder produisent une ossature correcte, mais ils ne savent pas gérer deux choses — les stops calculés dynamiquement, et la lecture d'un indicateur personnalisé. Ce sont précisément les deux demandes du message #1. Il faut donc passer par un peu de code écrit à la main, et c'est plus simple qu'il n'y paraît.
Le code ci-dessous est en MQL4, comme le générateur de l'époque.
1. Le préalable que tout le monde rate : point n'est pas pip
Sur un courtier à 5 décimales (ou 3 sur les paires en yen), un "point" vaut un dixième de pip. Un stop de 15 pips codé avec Point donne donc un stop de 1,5 pip, qui sera rejeté ou touché immédiatement. C'est la première cause d'échec des EA générés automatiquement.
À utiliser partout où vous exprimez une distance en pips.
2. Le stop-loss à X pips d'une moyenne mobile
Le principe : on lit la valeur de la moyenne mobile sur la bougie clôturée (décalage 1, pas 0 — sinon la valeur bouge à chaque tick et votre stop danse), puis on retranche ou on ajoute la distance voulue.
Le contrôle indispensable avant d'envoyer l'ordre. Un courtier impose une distance minimale entre le prix et le stop. Si votre moyenne mobile est trop proche du cours, l'ordre sera rejeté avec une erreur 130 — l'erreur la plus fréquente chez les débutants, et celle qui fait croire que "l'EA ne fonctionne pas".
Deux décisions de conception à prendre consciemment :
3. Fermer les positions sur le signal d'un indicateur personnalisé
C'est la partie où il faut être méthodique, parce que tout dépend de la façon dont l'indicateur dessine ses croix. Deux cas, et un seul est exploitable simplement.
Cas A — les croix sont dans des buffers d'indicateur. C'est le cas si l'auteur a utilisé SetIndexBuffer et SetIndexStyle avec DRAW_ARROW. Vous pouvez alors lire les valeurs depuis l'EA avec iCustom.
Comment le vérifier en trente secondes : posez l'indicateur sur un graphique, ouvrez la fenêtre de données (Ctrl+D) et passez la souris sur une bougie portant une croix. Si une ligne affiche une valeur à cet endroit, l'information est dans un buffer, et le rang de cette ligne vous donne l'indice du buffer (le premier vaut 0).
Trois pièges classiques sur iCustom :
C'est fonctionnel mais fragile : ça dépend du nommage des objets, ça ne marche pas dans le testeur de stratégie de la même façon, et ça devient lent si le graphique est chargé. Si vous êtes dans ce cas, la vraie solution est de faire modifier l'indicateur pour qu'il expose ses signaux dans un buffer.
Le point le plus important, avant tout code : vérifiez que votre indicateur ne repeint pas. Beaucoup d'indicateurs à flèches affichent une croix sur la bougie en cours, puis la déplacent ou la font disparaître. En temps réel votre EA sortira sur des signaux qui n'existeront plus ensuite, et le backtest sera magnifique et faux. Le test est simple : laissez tourner en démo une semaine, faites des captures d'écran chaque jour, et comparez avec le graphique une semaine plus tard. Si les croix ont bougé, arrêtez tout — c'est irréparable côté EA.
C'est aussi pour cela que je lis le signal sur shift = 1, donc sur bougie clôturée, dans tout ce qui précède.
4. Le délai de X bougies après l'entrée
C'est la partie la plus simple. On récupère le rang de la bougie d'ouverture de la position, ce qui donne directement le nombre de bougies écoulées.
Et la boucle de gestion, à appeler dans start() :
Trois détails qui comptent :
Pour éviter que tout ne se déclenche à chaque tick, on ne traite qu'à l'ouverture d'une nouvelle bougie :
6. Deux conseils de méthode, qui valent plus que le code
Si quelqu'un bloque sur son propre indicateur, postez ici la liste de ses paramètres externes et une capture de la fenêtre de données sur une bougie portant une croix : avec ces deux éléments, l'appel iCustom correct s'écrit en une minute.
Petit rappel de contexte : les générateurs graphiques de type Expert Advisor Builder produisent une ossature correcte, mais ils ne savent pas gérer deux choses — les stops calculés dynamiquement, et la lecture d'un indicateur personnalisé. Ce sont précisément les deux demandes du message #1. Il faut donc passer par un peu de code écrit à la main, et c'est plus simple qu'il n'y paraît.
Le code ci-dessous est en MQL4, comme le générateur de l'époque.
1. Le préalable que tout le monde rate : point n'est pas pip
Sur un courtier à 5 décimales (ou 3 sur les paires en yen), un "point" vaut un dixième de pip. Un stop de 15 pips codé avec Point donne donc un stop de 1,5 pip, qui sera rejeté ou touché immédiatement. C'est la première cause d'échec des EA générés automatiquement.
Code : Tout sélectionner
double PipSize()
{
double p = Point;
if(Digits == 3 || Digits == 5) p = Point * 10;
return(p);
}
2. Le stop-loss à X pips d'une moyenne mobile
Le principe : on lit la valeur de la moyenne mobile sur la bougie clôturée (décalage 1, pas 0 — sinon la valeur bouge à chaque tick et votre stop danse), puis on retranche ou on ajoute la distance voulue.
Code : Tout sélectionner
extern int MAPeriod = 50;
extern int MAMethod = MODE_SMA; // MODE_EMA, MODE_SMMA, MODE_LWMA
extern int MAPrice = PRICE_CLOSE;
extern double SL_Pips = 15.0; // distance sous / au-dessus de la MM
double MaValue(int shift)
{
return(iMA(NULL, 0, MAPeriod, 0, MAMethod, MAPrice, shift));
}
double StopAchat()
{
double sl = MaValue(1) - SL_Pips * PipSize();
return(NormalizeDouble(sl, Digits));
}
double StopVente()
{
double sl = MaValue(1) + SL_Pips * PipSize();
return(NormalizeDouble(sl, Digits));
}
Code : Tout sélectionner
bool StopValide(int type, double sl)
{
double distMin = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point;
if(type == OP_BUY) return(sl > 0 && sl < Bid - distMin);
if(type == OP_SELL) return(sl > 0 && sl > Ask + distMin);
return(false);
}
- Stop figé ou stop suiveur ? Le code ci-dessus calcule le stop à l'entrée. Si vous voulez qu'il suive la moyenne mobile ensuite, il faut le recalculer et appeler OrderModify — mais uniquement si le nouveau stop est meilleur que l'ancien, sinon vous élargissez votre risque en cours de route, ce qui est exactement ce qu'il ne faut jamais faire.
- Ne modifiez pas à chaque tick. N'envoyez un OrderModify que si l'écart avec le stop actuel dépasse au moins un pip, sinon vous saturez le serveur et récoltez des erreurs 1 en série.
Code : Tout sélectionner
void SuivreStop(int ticket)
{
if(!OrderSelect(ticket, SELECT_BY_TICKET)) return;
double nouveau = 0;
if(OrderType() == OP_BUY)
{
nouveau = StopAchat();
if(nouveau > OrderStopLoss() + PipSize() && StopValide(OP_BUY, nouveau))
OrderModify(ticket, OrderOpenPrice(), nouveau, OrderTakeProfit(), 0, clrNONE);
}
if(OrderType() == OP_SELL)
{
nouveau = StopVente();
if((OrderStopLoss() == 0 || nouveau < OrderStopLoss() - PipSize())
&& StopValide(OP_SELL, nouveau))
OrderModify(ticket, OrderOpenPrice(), nouveau, OrderTakeProfit(), 0, clrNONE);
}
}
C'est la partie où il faut être méthodique, parce que tout dépend de la façon dont l'indicateur dessine ses croix. Deux cas, et un seul est exploitable simplement.
Cas A — les croix sont dans des buffers d'indicateur. C'est le cas si l'auteur a utilisé SetIndexBuffer et SetIndexStyle avec DRAW_ARROW. Vous pouvez alors lire les valeurs depuis l'EA avec iCustom.
Comment le vérifier en trente secondes : posez l'indicateur sur un graphique, ouvrez la fenêtre de données (Ctrl+D) et passez la souris sur une bougie portant une croix. Si une ligne affiche une valeur à cet endroit, l'information est dans un buffer, et le rang de cette ligne vous donne l'indice du buffer (le premier vaut 0).
Code : Tout sélectionner
extern string NomIndicateur = "MonIndicateur";
extern int BufferHaut = 0; // buffer de la croix haussiere
extern int BufferBas = 1; // buffer de la croix baissiere
bool CroixPresente(int shift)
{
// ATTENTION : les parametres doivent etre passes dans le MEME ORDRE
// et le MEME NOMBRE que la liste des "extern" de l'indicateur,
// avant l'indice de buffer et le shift.
double haut = iCustom(NULL, 0, NomIndicateur,
/* param1, param2, param3, */
BufferHaut, shift);
double bas = iCustom(NULL, 0, NomIndicateur,
/* param1, param2, param3, */
BufferBas, shift);
if(haut != EMPTY_VALUE && haut != 0) return(true);
if(bas != EMPTY_VALUE && bas != 0) return(true);
return(false);
}
- Le nom passé est celui du fichier, sans extension. Si l'indicateur est rangé dans un sous-dossier de Indicators, il faut écrire le chemin relatif, par exemple "MonDossier\\MonIndicateur".
- Il faut passer tous les paramètres externes de l'indicateur, dans l'ordre exact de sa déclaration. Un paramètre oublié ou décalé, et vous lisez silencieusement des valeurs fausses. C'est là que sert la copie d'écran des paramètres que philippou avait jointe à son message.
- Testez toujours contre EMPTY_VALUE et contre 0 : selon la façon dont l'auteur a initialisé ses buffers, les cases vides valent l'un ou l'autre.
Code : Tout sélectionner
bool CroixObjetSurBougie(int shift)
{
datetime t = Time[shift];
int total = ObjectsTotal();
for(int i = total - 1; i >= 0; i--)
{
string nom = ObjectName(i);
if(ObjectType(nom) != OBJ_ARROW) continue;
if(ObjectGet(nom, OBJPROP_TIME1) == t) return(true);
}
return(false);
}
Le point le plus important, avant tout code : vérifiez que votre indicateur ne repeint pas. Beaucoup d'indicateurs à flèches affichent une croix sur la bougie en cours, puis la déplacent ou la font disparaître. En temps réel votre EA sortira sur des signaux qui n'existeront plus ensuite, et le backtest sera magnifique et faux. Le test est simple : laissez tourner en démo une semaine, faites des captures d'écran chaque jour, et comparez avec le graphique une semaine plus tard. Si les croix ont bougé, arrêtez tout — c'est irréparable côté EA.
C'est aussi pour cela que je lis le signal sur shift = 1, donc sur bougie clôturée, dans tout ce qui précède.
4. Le délai de X bougies après l'entrée
C'est la partie la plus simple. On récupère le rang de la bougie d'ouverture de la position, ce qui donne directement le nombre de bougies écoulées.
Code : Tout sélectionner
extern int BougiesAvantSortie = 3;
int BougiesDepuisOuverture()
{
return(iBarShift(NULL, 0, OrderOpenTime(), false));
}
Code : Tout sélectionner
void GererSorties()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
if(OrderSymbol() != Symbol()) continue;
if(OrderMagicNumber() != MagicNumber) continue;
if(BougiesDepuisOuverture() < BougiesAvantSortie) continue;
if(!CroixPresente(1)) continue;
if(OrderType() == OP_BUY)
OrderClose(OrderTicket(), OrderLots(), Bid, 3, clrNONE);
if(OrderType() == OP_SELL)
OrderClose(OrderTicket(), OrderLots(), Ask, 3, clrNONE);
}
}
- La boucle part de la fin vers le début. Si vous fermez des ordres en parcourant dans l'autre sens, vous en sautez, parce que les positions se réindexent après chaque fermeture.
- Le filtre sur OrderMagicNumber isole vos ordres de ceux d'un autre EA ou de vos ordres manuels. À ne jamais omettre.
- Le filtre sur OrderSymbol évite d'aller fermer une position ouverte sur une autre paire.
Pour éviter que tout ne se déclenche à chaque tick, on ne traite qu'à l'ouverture d'une nouvelle bougie :
Code : Tout sélectionner
datetime derniereBarre = 0;
int start()
{
// gestion des sorties et du stop : a chaque tick
GererSorties();
// SuivreStop(...) si stop suiveur souhaite
// logique d'entree : une seule fois par bougie
if(Time[0] == derniereBarre) return(0);
derniereBarre = Time[0];
// ... vos conditions d'entree ici,
// avec OrderSend(..., StopAchat() ou StopVente(), ...)
return(0);
}
- Faites parler l'EA. Avant de le laisser trader, ajoutez des Print() affichant la valeur de la moyenne mobile, le stop calculé et le retour de l'indicateur à chaque bougie, et comparez avec ce que vous lisez sur le graphique. 90 % des bugs se voient en cinq minutes avec cette méthode, et se cherchent pendant des semaines sans elle.
- Contrôlez toujours le retour d'OrderSend et d'OrderModify. Le générateur ne le fait pas. Sans GetLastError(), un ordre rejeté est un ordre invisible : vous croyez être en position, vous ne l'êtes pas, et vous ne comprenez pas pourquoi.
Si quelqu'un bloque sur son propre indicateur, postez ici la liste de ses paramètres externes et une capture de la fenêtre de données sur une bougie portant une croix : avec ces deux éléments, l'appel iCustom correct s'écrit en une minute.

