Price Data Components
Orders Execution
Miscellaneous
0
Views
0
Downloads
0
Favorites
Colibri
//+------------------------------------------------------------------+
//| Colibri.mq4
//| Copyright © 2010, Laurent Béville (LoBev)
//| http://fr-fr.facebook.com/pages/La-Martinique-Fleur-des-Caraibes/13968306412
//+------------------------------------------------------------------+
#property copyright "Copyright © 2010, Laurent Béville"
#property link "http://fr-fr.facebook.com/pages/La-Martinique-Fleur-des-Caraibes/13968306412"
#define n.Tentatives.Connection 5 // try to connect to server 5 times
#define n.Tentatives.Clôture 5 // try to close orders 5 times
#define Temps.De.Référence 3 // wait 3 Seconds before opening or closing
#define Durée.Max.Tentative 10 // ea try to send orders during 10 seconds
#define Add.Slippage 1 // Slippage
#define Expiration.Trade.en.heures 48 // Pending orders erased after 48 hours
#define Dist.Min.Entr.Niv 5 // Minimum distance between levels
#define Perte.Max.Par.Jour 0.06 // System is allowed to risk a maximum of 6% of equity every day
#define Exposition.Maximale 0.1 // You are allowed to risk 10% of equity when taking into account all openend positions
// ############# GESTION - URGENCE ############# //
extern string ________1________ = "********* GEST. - URGENCES *********";
extern bool FERMER.TOUTES.LES.POSES = false; // Close all opened orders
extern bool FERMER.POSES.ACHETEUSES = false; // Close all buy orders
extern bool FERMER.POSES.VENDEUSES = false; // Close All sell orders
extern string Cible = "--- Fermeture Ciblée ---";
extern string MAGIC.NUM.POUR.FERM. = ""; // see below
extern bool FERMER.POSE = false; // Close a specific order by entering its magic number
extern bool RUN.ON.INIT = false; // Start ea when placed on chart
// ############# TRADES-PARAMETRES ############# //
extern string ________2________ = "*********** PARAM.-ORDRES **********";
// Choix du MODE ENTRY :
extern bool Afficher.Montant.Perte = false; // Show the amount of losses
extern string INFO.ORDRE = "0:Rien 1:Comptant 2:Stop 3:Limite 4:Stop Suiv.";
extern int Type.Ordre = 0; // Order type you want to send (4 types)
extern string INFO.ORDRE.2 = "0:Pas dépendant ; Si ordre mère exécuté -> 1:Exécuter 2:Effacer 3:Clôturer";
extern int MagicNum.Ordre.Mère = 0; // Magic number of mother order
extern int Dépendance = 0; // Action to do with others orders (Execute/Erase/Close) when mother order is executed
extern string Mini.Sep = "----------";
extern int Trailing.Stop = 0; //
extern int Trail.Entry.Pips = 0; // Level in points at which ea start trailing stops
extern double Exposition.Au.Risque = 0.02; // Risk exposure in %
extern int Dist.Stop.Min.En.pips = 50; // Minimum distance between stop and entry point
extern int Ecart.Entre.Niveaux = 2; // Distance defined between levels
extern string ________3________ = "-----------------------------------------------------";
extern bool ACHETER = false; // BUY
extern bool VENDRE = false; // or SELL
// ############# GRILLE - OPTIONS ############# //
extern string ________4________ = "******* CHOIX OPTIONS GRILLE *******";
extern bool UTILISATION_GRILLE = false; // Security Use Grid : must be set to TRUE
extern string ________5________ = "-----------------------------------------------------";
extern double Niveau.De.Protection = 0; // Stopping price level
extern double Prix.Achat = 0; // Buying price
extern double Prix.Vente = 0; // Selling Price
extern string ________6________ = "-----------------------------------------------------";
// Choose calculation type :
extern bool Grille.Centrée.? = false; // Level calculated from Grid Center level or by its boundering levels
// if you choose boundering levels calculation mode :
extern double Grille.Borne.Sup = 0; // Highest level price
extern double Grille.Borne.Inf = 0; // Lowest level price
// if you choose grid center calculation mode :
extern double Grille.LC.Niv = 0; // Grid center price
extern double Grille.LC.Pas = 0; // Levels step in points
// Maximum levels number :
extern double Grille.Nbre.Niveaux = 0; // Levels number
// ############# EFFACER - TRACES - ORDRE ############# //
extern string ________7________ = "****** PROCEDURES NETTOYAGE ******";
extern bool Clean.Trace.Prise.Profit = true; // Clean profits arrows
extern bool Clean.Trace.Stop.Perte = true; // Clean stops arrows
extern bool Clean.Trace.Entree.Sortie = false; // Clean entry arrows
// ****************************************************************** //
// ******************* CODES MAGIC NUMBER - ORDRES ****************** //
// ****************************************************************** //
// Sens = Achat : 1 ; Vente : 2
// Type = Au Marché : 0 ; Comptant : 1 ; Stop : 2 ; Limite : 3
// Stop Suiveur : 4
// Rang = Rang de l'ordre (< 10)
// Dépendance = 0 : Pas de dépendance ;
// 1 : Effacer si ordre mère exécuté
// 2 : Ouvrir si ordre mère exécuté
// 3 : Clôturer si ordre mère exécuté
//
// Calcul du Magic-Number =
// Sens + Type + Rang + Dépendance
//
// Dans OrderComment() : mettre le magic number de l'ordre mère ou rien
// ***************************************************************** //
double Taille.Pos.Global = 0, Taille.Pos.par.Niv = 0;
// Variables globales
string Content[10];
string str.Comment = "";
//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+
int init()
{
//----
// Initialisation importante : en cas de changement de compte
GlobalVariableSet("Montant.Journalier.En.Compte", AccountBalance());
// Création des variables globales en cas de non-existence
if (!GlobalVariableCheck("$_ACTIVATION_EXPERT_$"))
GlobalVariableSet("$_ACTIVATION_EXPERT_$", 0);
// L'expert commence à tourner à l'initialisation
if (RUN.ON.INIT) start();
//----
return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
//----
return(0);
}
//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+
int start()
{
//----
// :::::::::: Sous Module Stop Suiveurs :::::::::: //
Stop_Suiveurs();
// :::::::::: Fermeture de positions dans l'urgence :::::::::: //
Fermetures();
// ******************************************************************* //
// !!! SECURITE !!!
if (Perte.Max.Atteinte.?()) return(0);
// ******************************************************************* //
// :::::::::: Utilisation Grille :::::::::: //
if (UTILISATION_GRILLE && Params_Are_Ok_?(Grille.Nbre.Niveaux))
Prog_Grille_Is_Ok_?(Type.Ordre, Niveau.De.Protection, Grille.Centrée.?, Grille.Nbre.Niveaux,
Grille.Borne.Sup, Grille.Borne.Inf, Grille.LC.Niv, Grille.LC.Pas);
//----
return(0);
}
//+------------------------------------------------------------------+
// ****************************************************************** //
// ************************ Programme Grille ************************ //
// ****************************************************************** //
bool Prog_Grille_Is_Ok_?(int _Type.Ord, double _Stop.Protect.en.$, bool _Grille.Centrée.?,
int _Nbre.Niv, double _Grille.Borne.Sup, double _Grille.Borne.Inf,
double _Grille.LC.Niv, double _Grille.LC.Pas)
{
double NivPas = 0, Premier.Niv = 0, Adjust.Lot = 0, mult = 0;
int sens = 0;
// :::::::::: Ajustement du Nombre de niveaux :::::::::: //
if ((!_Grille.Centrée.? && _Grille.Borne.Sup != 0 && _Grille.Borne.Inf != 0) ||
(_Grille.Centrée.? && _Grille.LC.Niv != 0 && _Grille.LC.Pas != 0))
Ajust_Nbre_Niveaux_Max(_Type.Ord, _Stop.Protect.en.$, _Grille.Centrée.?, _Nbre.Niv,
_Grille.Borne.Sup, _Grille.Borne.Inf, _Grille.LC.Niv, _Grille.LC.Pas);
// :::::::::: Formattage des tailles de positions :::::::::: //
// En principe les tailles de position sont calculées dans Ajust_Nbre_Niveaux_Max(...)
Formattage_Tailles_Pos();
// :::::::::: Calcul Pas de Progression entre Niveaux :::::::::: //
NivPas = Calc_Pas_Progression(_Grille.Centrée.?, _Nbre.Niv, _Grille.Borne.Sup, _Grille.Borne.Inf,
_Grille.LC.Niv, _Grille.LC.Pas);
// :::::::::: Calcul du Premier Niveau par défaut :::::::::: //
Premier.Niv = Init_Premier_Niveau(_Grille.Centrée.?, _Nbre.Niv, _Grille.Borne.Sup, _Grille.Borne.Inf,
_Grille.LC.Niv, _Grille.LC.Pas);
// :::::::::: Calcul du nombre de mini-lots compl. :::::::::: //
double Nbre.MiniLots.Compl = MathRound((Taille.Pos.Global - (Taille.Pos.par.Niv * _Nbre.Niv)) /
MarketInfo(Symbol(), MODE_LOTSTEP));
// :::::::::: Remplissage de la var. Adjust.Lot :::::::::: //
Adjust.Lot = Taille.Pos.par.Niv;
// :::::::::: Calcul du Magic Number :::::::::: //
if (ACHETER) sens = 1;
else if (VENDRE) sens = 2;
int Magic.Num = Calc_Magic_Num(sens, Type.Ordre, Dépendance);
// --- Filtre sur la longueur maximale du magic number ---
// Autrement dit : pas plus de 9 ordres par préfixe "sens + type"
if (StringLen(DoubleToStr(Magic.Num, 0)) > 4) return;
// :::::::::: Passer les ordres grille :::::::::: //
int Solde.Niv = _Nbre.Niv;
double Objectif.Niv = Premier.Niv; // Initialisation au premier niveau
if (Condit_Pass_Ord_are_Ok_?() && !FERMER.TOUTES.LES.POSES && !FERMER.POSE)
{
// Passer en boucle n ordres tel que n = _Nbre.Niv
for (int i = 1; i <= _Nbre.Niv; i++)
{
// Réinitialisation de Adjust.Lot
Adjust.Lot = Taille.Pos.par.Niv;
// Conditions pour augmenter la var. Adjust.Lot
if (Test_Sur_Nbre_Aléat(Nbre.MiniLots.Compl, Solde.Niv)
&& Nbre.MiniLots.Compl > 0 && Nbre.MiniLots.Compl >= Solde.Niv)
{
Adjust.Lot += MarketInfo(Symbol(), MODE_LOTSTEP);
Nbre.MiniLots.Compl--;
}
// Décrémentation pour calcul du nombre de TP restant à ajuster
Solde.Niv--;
// Avant de passer un ordre s'assurer que c'est possible
Attendre_Disponibilité_pr_Ordre();
// Etablir le commentaire de l'ordre
str.Comment = Order_Comment();
// Ne passer des ordres que si l'expert a été activé manuellement
// sinon retour
if (GlobalVariableGet("$_ACTIVATION_EXPERT_$") == 1)
{
if (mult >= (_Nbre.Niv - 1) &&
Succès_Ordre_?(mult, Symbol(), Type.Ordre, Adjust.Lot,
MarketInfo(Symbol(), MODE_SPREAD) + Add.Slippage,
Niveau.De.Protection, Objectif.Niv, str.Comment, Magic.Num,
(3600 * Expiration.Trade.en.heures + TimeLocal())))
GlobalVariableSet("$_ACTIVATION_EXPERT_$", 0);
}
else return(0);
// Incrémentation pour prochain niveau
mult++;
// Recherche du prochain niveau
if (ACHETER) Objectif.Niv += NivPas;
if (VENDRE) Objectif.Niv -= NivPas;
}
}
}
// ****************************************************************** //
// ************************ Commentaire Ordre *********************** //
// ****************************************************************** //
string Order_Comment()
{
string Str.Com = StringConcatenate(MagicNum.Ordre.Mère, "#", Trailing.Stop, "#", Trail.Entry.Pips);
// Renvoi de la chaîne
return(Str.Com);
}
// ****************************************************************** //
// ****** Attendre la disponibilité du serveur pour transaction ***** //
// ****************************************************************** //
void Attendre_Disponibilité_pr_Ordre()
{
int timer1 = TimeLocal(), timer2 = TimeLocal();
// ----- TEST de disponibilité ----- //
while (!IsConnected() || IsTradeContextBusy() || !IsTradeAllowed())
{
Sleep(10); // Attendre 10 ms
timer2 = TimeLocal();
if (timer2 - timer1 > 2000) break; // Sortie après + de 2 secondes
}
}
// ****************************************************************** //
// ************************* Passer un ordre ************************ //
// ****************************************************************** //
bool Succès_Ordre_?(int _mult, string _Symbol, int _Type.Ordre, double _Volume, int _Slippage,
double _Stoploss, double _Takeprofit, string _Comment = "", int _Magic.Num = 0,
datetime _Expiration = 0)
{
int err = GetLastError();
err = 0;
// --- Vérification de la validité du stop --- //
if (MathAbs(_Stoploss - (Ask + Bid) / 2) < MarketInfo(Symbol(), MODE_STOPLEVEL) * Point)
{
GlobalVariableSet("$_ACTIVATION_EXPERT_$", 0);
Alert("La distance Stop - Entrée est insuffisante");
return(false);
}
// --- Rafraîchir les cotations ---
RefreshRates();
// :::::::::: ACHAT AU MARCHE :::::::::: //
if (_Type.Ordre == 1 && ACHETER)
Passer_Un_Ordre(Symbol(), OP_BUY, _Volume, Ask, _Slippage, _Stoploss, _Takeprofit,
_Comment, _Magic.Num, _Expiration, Green);
// :::::::::: VENTE AU MARCHE :::::::::: //
if (_Type.Ordre == 1 && VENDRE)
Passer_Un_Ordre(Symbol(), OP_SELLSTOP, _Volume, Bid, _Slippage, _Stoploss, _Takeprofit,
_Comment, _Magic.Num, _Expiration, Red);
// :::::::::: ACHAT STOP :::::::::: //
if ((_Type.Ordre == 2 || _Type.Ordre == 4) && ACHETER)
Passer_Un_Ordre(Symbol(), OP_BUYSTOP, _Volume, Prix.Achat + _mult * Ecart.Entre.Niveaux * Point,
_Slippage, _Stoploss, _Takeprofit, _Comment, _Magic.Num, _Expiration, Teal);
// :::::::::: VENTE STOP :::::::::: //
if ((_Type.Ordre == 2 || _Type.Ordre == 4) && VENDRE)
Passer_Un_Ordre(Symbol(), OP_SELLSTOP, _Volume, Prix.Vente - _mult * Ecart.Entre.Niveaux * Point,
_Slippage, _Stoploss, _Takeprofit, _Comment, _Magic.Num, _Expiration, Orchid);
// :::::::::: ACHAT LIMITE :::::::::: //
if (_Type.Ordre == 3 && ACHETER)
Passer_Un_Ordre(Symbol(), OP_BUYLIMIT, _Volume, Prix.Achat + _mult * Ecart.Entre.Niveaux * Point,
_Slippage, _Stoploss, _Takeprofit, _Comment, _Magic.Num, _Expiration, Teal);
// :::::::::: VENTE LIMITE :::::::::: //
if (_Type.Ordre == 3 && VENDRE)
Passer_Un_Ordre(Symbol(), OP_SELLLIMIT, _Volume, Prix.Vente - _mult * Ecart.Entre.Niveaux * Point,
_Slippage, _Stoploss, _Takeprofit, _Comment, _Magic.Num, _Expiration, Orchid);
err = GetLastError();
Print("err : ", GetLastError());
// Renvoi de true par défaut
return(true);
}
// ****************************************************************** //
// ************************* Passer un ordre ************************ //
// ****************************************************************** //
bool Passer_Un_Ordre(string _Symbol, int _Cmd, double _Volume, double _Price, int _Slippage,
double _Stoploss, double _Takeprofit, string _Comment = "", int _Magic.Num = 0,
datetime _Expiration = 0, color _Arrow.Color = CLR_NONE)
{
int ticket = -1;
// La plateforme est-elle connectée ?
if (!IsConnected())
{
Print("La plateforme n\'est pas connectée. IsConnected() == false");
return(-1);
}
// L'expert a t-il été désactivé ?
if (IsStopped())
{
Print("L\'expert a été désactivé. IsStopped() == false");
return(-1);
}
int cnt = 0;
// Attente jusqu'à ce qu'il soit permis de passer un trade
// dans la limite d'un certain délai
while (!IsTradeAllowed() && cnt < n.Tentatives.Connection)
{
Temps_Attente_Aleatoire();
cnt ++;
}
// Une fois le délai maximum passé, trader est-il permis ?
// Si oui continuer, sinon sortie de la sous-procédure
if(!IsTradeAllowed()) return(-1);
// Calibrage des objectifs : Stop, Prix d'entrée, Prise de profit
// selon le format requis par la devise en cours
_Price = NormalizeDouble(_Price, Digits);
_Stoploss = NormalizeDouble(_Stoploss, Digits);
_Takeprofit = NormalizeDouble(_Takeprofit, Digits);
// Passer les ordres
ticket =OrderSend(_Symbol, _Cmd, _Volume, _Price, _Slippage, _Stoploss,
_Takeprofit,_Comment,_Magic.Num, _Expiration,_Arrow.Color);
}
// ****************************************************************** //
// ********************* Temps Attente Aleatoire ******************** //
// ****************************************************************** //
void Temps_Attente_Aleatoire()
{
// Conversion du temps de référence en dixième de secondes
double Dixièmes.De.Secondes = MathCeil(Temps.De.Référence / 0.1);
if (Dixièmes.De.Secondes <= 0) return;
// Définition en dixième de secondes la durée maximum pendant laquelle
// l'ordre tentera de passer
int Durée.Tentative.dsec = MathRound(Durée.Max.Tentative / 0.1);
double p = 1.0 - 1.0 / Dixièmes.De.Secondes;
// Repos pendant 1 dixième de seconde
Sleep(100);
for (int i = 0; i < Durée.Tentative.dsec; i++)
{
if (MathRand() >= 32768 * p)
{
break;
}
// Repos pendant 1 dixième de seconde
Sleep(100);
}
}
// ****************************************************************** //
// ************** Conditions Passage Ordres Remplies ? ************** //
// ****************************************************************** //
bool Condit_Pass_Ord_are_Ok_?()
{
double Risque.Résid. = 0, Margin.Lots.Risk = 0;
// Calcul du risque résiduel pouvant être pris sous forme de lots
if (OrdersTotal() > 0)
{
// :::::::::::::::: EXPOSITION ::::::::::::::: //
for (int i = OrdersTotal(); i >= 0; i--)
{
OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
// Ne considérer que les ordres déjà en cours
if (OrderType() <= OP_SELL)
{
Margin.Lots.Risk += MathAbs((OrderOpenPrice() - OrderStopLoss()) / Point)
* OrderLots() * MarketInfo(Symbol(), MODE_TICKVALUE);
}
}
// ---
Risque.Résid. = Exposition.Maximale - (Margin.Lots.Risk / AccountBalance());
}
// :::::::::::::::: TEST CONDITION ::::::::::::::: //
return(Risque.Résid. > Exposition.Au.Risque);
}
// ****************************************************************** //
// ********************* Test sur Nombre Aléatoire ****************** //
// ****************************************************************** //
bool Test_Sur_Nbre_Aléat(int _Nbre.MiniLots.Compl, int _Nbre.Niv)
{
// Alerte sur valeurs incohérentes
if (_Nbre.Niv < _Nbre.MiniLots.Compl)
Alert("Erreur : _Nbre.Niv < _Nbre.MiniLots.Compl. Le test aléatoire ne peut avoir lieu");
// Initialisation du générateur de nombre aléatoire
MathSrand(TimeLocal());
int Nombre.Aléatoire = MathRand();
double Seuil = 32767 * (_Nbre.MiniLots.Compl / _Nbre.Niv);
// Renvoi de la valeur du test proprement dit
return(Nombre.Aléatoire < Seuil);
}
// ****************************************************************** //
// ****************** Initialisation Premier Niveau ***************** //
// ****************************************************************** //
double Init_Premier_Niveau(bool _Grille.Centrée.?, int _Nbre.Niv, double _Grille.Borne.Sup,
double _Grille.Borne.Inf, double _Grille.LC.Niv, double _Grille.LC.Pas)
{
// --- CAS : GRILLE NON CENTREE ---
// Achat :
if (!_Grille.Centrée.? && ACHETER) return(_Grille.Borne.Inf);
// Vente :
if (!_Grille.Centrée.? && VENDRE) return(_Grille.Borne.Sup);
// --- CAS : GRILLE CENTREE ---
// Achat :
if (_Grille.Centrée.? && ACHETER)
return(_Grille.LC.Niv - ((_Nbre.Niv - 1) / 2) * _Grille.LC.Niv * Point);
// Vente :
if (_Grille.Centrée.? && VENDRE)
return(_Grille.LC.Niv + ((_Nbre.Niv - 1) / 2) * _Grille.LC.Niv * Point);
// Renvoi de - 10000 par défaut
return(-10000);
}
// ****************************************************************** //
// ***************** Pas de Progression des Niveaux ***************** //
// ****************************************************************** //
double Calc_Pas_Progression(bool _Grille.Centrée.?, int _Nbre.Niv, double _Grille.Borne.Sup,
double _Grille.Borne.Inf, double _Grille.LC.Niv, double _Grille.LC.Pas)
{
double Pas = 0;
// Grille Canal : définition du pas de progression
if (!_Grille.Centrée.?)
{
Pas = (MathAbs(_Grille.Borne.Sup - _Grille.Borne.Inf)
+ MarketInfo(Symbol(), MODE_TICKSIZE)) / _Nbre.Niv;
}
// Grille Centrée : définition du pas de progression
if (_Grille.Centrée.?)
{
Pas = _Grille.LC.Pas * Point;
}
// Formatter la var. Pas
return(NormalizeDouble(Pas, Digits));
}
// ****************************************************************** //
// ******************* Formattage Tailles Position******************* //
// ****************************************************************** //
bool Formattage_Tailles_Pos()
{
if (MarketInfo(Symbol(), MODE_LOTSTEP) == 0.1)
{
if (Taille.Pos.par.Niv >= NormalizeDouble(Taille.Pos.par.Niv, 1))
Taille.Pos.par.Niv = NormalizeDouble(Taille.Pos.par.Niv, 1);
if (Taille.Pos.par.Niv < NormalizeDouble(Taille.Pos.par.Niv, 1))
Taille.Pos.par.Niv = NormalizeDouble(Taille.Pos.par.Niv, 1)
- MarketInfo(Symbol(), MODE_LOTSTEP);
// Renvoi
return(true);
}
if (MarketInfo(Symbol(), MODE_LOTSTEP) == 0.01)
{
if (Taille.Pos.par.Niv >= NormalizeDouble(Taille.Pos.par.Niv, 2))
Taille.Pos.par.Niv = NormalizeDouble(Taille.Pos.par.Niv, 2);
if (Taille.Pos.par.Niv < NormalizeDouble(Taille.Pos.par.Niv, 2))
Taille.Pos.par.Niv = NormalizeDouble(Taille.Pos.par.Niv, 2)
- MarketInfo(Symbol(), MODE_LOTSTEP);
// Renvoi
return(true);
}
// Renvoi
return(false);
}
// ****************************************************************** //
// ***************** Ajustement du nombre de niveaux **************** //
// ****************************************************************** //
double Ajust_Nbre_Niveaux_Max(int _Type.Ord, double _Stop.Protect.en.$, bool _Grille.Centrée.?,
int _Nbre.Niv, double _Grille.Borne.Sup, double _Grille.Borne.Inf,
double _Grille.LC.Niv, double _Grille.LC.Pas)
{
double Max.Niv.Théoriq = 0;
// ----------------------------------------------------------- //
// ------------------------ SECURITE 1 ----------------------- //
// ----------------------------------------------------------- //
// Ajustement du nombre de niveaux en fonction du point
// d'entrée et des objectifs de profit
// OBJECTIF CANAL
if (!_Grille.Centrée.?)
{
// Calcul du nombre max. de niveaux possibles entre les bornes supérieures
// et inférieures, compte tenu de la distance min. autorisée entre les niveaux
Max.Niv.Théoriq = MathAbs(MathFloor((1/Point) * (_Grille.Borne.Sup - _Grille.Borne.Inf)
/ Dist.Min.Entr.Niv));
// Test de validité : Ajustement éventuel
if (_Nbre.Niv > Max.Niv.Théoriq) _Nbre.Niv = Max.Niv.Théoriq;
}
// OBJECTIF LIGNE CENTRALE + ORDRE AU MARCHE
if (_Grille.Centrée.? && _Type.Ord == 1)
{
// Calcul du nombre max. de niveaux autorisés, compte tenu de la distance entre
// La ligne centrale de prise de profit et le cours d'entrée
Max.Niv.Théoriq = 2 * MathAbs(MathFloor((1/Point) * (_Grille.LC.Niv - ((Ask+Bid)/2))
/ Dist.Min.Entr.Niv));
// Test de validité : Ajustement éventuel
if (_Nbre.Niv > Max.Niv.Théoriq) _Nbre.Niv = Max.Niv.Théoriq;
}
// OBJECTIF LIGNE CENTRALE + (ORDRE STOP ACHAT OU ORDRE LIMITE ACHAT)
if ( _Grille.Centrée.? &&
(_Type.Ord == 2 || _Type.Ord == 3 || (_Type.Ord == 4 && ACHETER && !VENDRE)) &&
Prix.Achat != 0 && Prix.Vente == 0)
{
// Calcul du nombre max. de niveaux autorisés, compte tenu de la distance entre
// La ligne centrale de prise de profit et le prix d'achat envisagé
Max.Niv.Théoriq = 2 * MathAbs(MathFloor((1/Point) * (_Grille.LC.Niv - Prix.Achat)
/ Dist.Min.Entr.Niv));
// Test de validité : Ajustement éventuel
if (_Nbre.Niv > Max.Niv.Théoriq) _Nbre.Niv = Max.Niv.Théoriq;
}
// OBJECTIF LIGNE CENTRALE + (ORDRE STOP VENTE OU ORDRE LIMITE VENTE)
if ( _Grille.Centrée.? &&
(_Type.Ord == 2 || _Type.Ord == 3 || (_Type.Ord == 4 && !ACHETER && VENDRE)) &&
Prix.Achat == 0 && Prix.Vente != 0)
{
// Calcul du nombre max. de niveaux autorisés, compte tenu de la distance entre
// La ligne centrale de prise de profit et le prix de vente envisagé
Max.Niv.Théoriq = 2 * MathAbs(MathFloor((1/Point) * (_Grille.LC.Niv - Prix.Vente)
/ Dist.Min.Entr.Niv));
// Test de validité : Ajustement éventuel
if (_Nbre.Niv > Max.Niv.Théoriq) _Nbre.Niv = Max.Niv.Théoriq;
}
// ----------------------------------------------------------- //
// ----------------------------------------------------------- //
// ------------------------ SECURITE 2 ----------------------- //
// ----------------------------------------------------------- //
// Si la taille de position envisagée est trop petite pour être
// répartie entre x lignes de niveaux => Réajuster le nombre de
// lignes de sortie envisagées.
// On calcule ici la taille de position globale
Taille.Pos.par.Niv = Calc.Taille.Pos.par.Niv(_Type.Ord, _Nbre.Niv, _Stop.Protect.en.$);
Taille.Pos.Global = _Nbre.Niv * Taille.Pos.par.Niv;
// Test : condition de validité portant sur _Nbre.Niv
if (Taille.Pos.Global < (_Nbre.Niv * MarketInfo(Symbol(), MODE_LOTSTEP)))
{
// Ajustement _Nbre.Niv
_Nbre.Niv = MathFloor(Taille.Pos.Global / MarketInfo(Symbol(), MODE_LOTSTEP));
// Recalcul des tailles de position global/par Niveau
Taille.Pos.par.Niv = MarketInfo(Symbol(), MODE_LOTSTEP);
Taille.Pos.Global = _Nbre.Niv * Taille.Pos.par.Niv;
}
// ----------------------------------------------------------- //
}
// ****************************************************************** //
// **** Calcul de la taille de position par niveau de la grille ***** //
// ****************************************************************** //
double Calc.Taille.Pos.par.Niv(int _Type.Ord, int _Nbre.Niv, double _Stop.Protect.en.$)
{
double dist.Stop.Protect.en.Pips = 0;
// Alerte + Retour si le nombre de niveau = 0
if (_Nbre.Niv == 0)
{
Alert("Erreur : Spécifiez un nombre de niveaux > 0 !!!");
return(0);
}
// Calcul de la distance du stop au point d'entrée théorique
if (_Type.Ord == 1)
dist.Stop.Protect.en.Pips = MathAbs((_Stop.Protect.en.$ - (Ask+Bid)/2)) * (1/Point);
else if((_Type.Ord == 2 || _Type.Ord == 3 || _Type.Ord == 4) && ACHETER)
dist.Stop.Protect.en.Pips = MathAbs((_Stop.Protect.en.$ - (Prix.Achat + 0.5 *
Ecart.Entre.Niveaux * Point * (_Nbre.Niv - 1))))
* (1/Point);
else if((_Type.Ord == 2 || _Type.Ord == 3 || _Type.Ord == 4) && VENDRE)
dist.Stop.Protect.en.Pips = MathAbs((_Stop.Protect.en.$ - (Prix.Vente - 0.5 *
Ecart.Entre.Niveaux * Point * (_Nbre.Niv - 1))))
* (1/Point);
// Calcul du montant risqué en $ compte tenu du stop pour 1 lot standard
double Lot.Margin.en.$ = dist.Stop.Protect.en.Pips * MarketInfo(Symbol(), MODE_TICKVALUE);
// Calcul de la TP pour un niveau
return((AccountBalance() * Exposition.Au.Risque) / (Lot.Margin.en.$ * _Nbre.Niv));
}
// ****************************************************************** //
// **************** Calcul du Magic Number approprié **************** //
// ****************************************************************** //
int Calc_Magic_Num(int _sens, int _type, int _dépendance)
{
// Initialisation
int Somme = 0;
int rang = Calc_Rang_Ordre(_sens, _type);
// Calcul Magic Number
Somme = StrToInteger(StringConcatenate(_sens, _type, rang, _dépendance));
// Renvoi de la valeur calculée
return(Somme);
}
// ****************************************************************** //
// ******************* Calcul du rang de l'ordre ******************** //
// ****************************************************************** //
int Calc_Rang_Ordre(int _sens, int _type)
{
int total = OrdersTotal();
int rang, num = 0;
// Définition du préfixe : sens + type
string Magic.Prefix = StringConcatenate(_sens, _type);
// ...
string MA.to.Str = "";
// Parcourir l'ensemble des ordres en cours
for(int i = total; i > 0; i--)
{
OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
// Conversion du magic number sélectionné en chaîne de caractère
MA.to.Str = DoubleToStr(OrderMagicNumber(), 0);
// Le préfixe en question est reconnu parmi les magic numbers en cours
if (StringSubstr(MA.to.Str, 0, 2) == Magic.Prefix)
{
// Place le rang de l'ordre analysé dans une var. temp.
num = StrToInteger(StringSubstr(MA.to.Str, 2, 1));
// Rafraîchissement de la variable rang ssi nécessaire
if (num > rang) rang = num;
}
}
// Incrémentation du rang
rang++;
// Renvoi de la valeur rang incrémenté de +1
return(rang);
}
// ****************************************************************** //
// ********************** Contrôle Paramétrage ********************** //
// ****************************************************************** //
bool Params_Are_Ok_?(int _Nbre.Niv)
{
// :::::::::::::::: SECURITE ::::::::::::::: //
// Alerte + Retour si le nombre de niveau = 0
if (_Nbre.Niv == 0 && (ACHETER || VENDRE))
{
Alert("Erreur : Spécifiez un nombre de niveaux > 0 !!!");
return(false);
}
// :::::::::::::::: SECURITE ::::::::::::::: //
// :::::::::::::::: RETOUR PAR DEFAUT ::::::::::::::: //
return (true);
}
// ****************************************************************** //
// ****************** Perte Max. Autorisée par Jour ***************** //
// ****************************************************************** //
bool Perte.Max.Atteinte.?()
{
int total = OrdersHistoryTotal();
double Pertes.Journalières.Accumulées = 0, Part.Representative.Pertes = 0;
// Calculer le montant du compte en dollars chaque jour
// Réactualisation entre 0 et 4h du matin
if (Hour() < 3 && Hour() >= 0)
GlobalVariableSet("Montant.Journalier.En.Compte", AccountBalance());
if (!GlobalVariableCheck("Montant.Journalier.En.Compte")
|| GlobalVariableGet("Montant.Journalier.En.Compte") == 0)
GlobalVariableSet("Montant.Journalier.En.Compte", AccountBalance());
// Initialisation de la variable calculant le % des pertes
Pertes.Journalières.Accumulées = 0;
for(int i = total; i > 0; i--)
{
OrderSelect(i,SELECT_BY_POS, MODE_HISTORY);
if(OrderSymbol() == Symbol() && TimeDayOfYear(OrderOpenTime()) == DayOfYear()
&& OrderProfit() < 0)
{
Pertes.Journalières.Accumulées += OrderProfit();
Part.Representative.Pertes = Pertes.Journalières.Accumulées
/ GlobalVariableGet("Montant.Journalier.En.Compte");
if (Part.Representative.Pertes > Perte.Max.Par.Jour) return(true);
}
}
// Renvoi par défaut :
return(false);
}
// ****************************************************************** //
// *************************** Fermetures *************************** //
// ****************************************************************** //
int Fermetures()
{
// Fermer l'intégralité des positions
if (FERMER.TOUTES.LES.POSES) Fermer_Positions();
// Ne fermer que les positions acheteuses
if (FERMER.POSES.ACHETEUSES) {
Fermer_Positions(0, OP_BUY);
Fermer_Positions(0, OP_BUYSTOP);
Fermer_Positions(0, OP_BUYLIMIT);}
// Ne fermer que les positions vendeuses
if (FERMER.POSES.VENDEUSES) {
Fermer_Positions(0, OP_SELL);
Fermer_Positions(0, OP_SELLSTOP);
Fermer_Positions(0, OP_SELLLIMIT); }
// Ne fermer qu'une seule position bien ciblée
if (FERMER.POSE) Fermer_Positions(StrToInteger(MAGIC.NUM.POUR.FERM.));
// :::::::::: Réinitialisation de la variable d'activation de l'ea :::::::::: //
if (FERMER.TOUTES.LES.POSES || FERMER.POSES.ACHETEUSES
|| FERMER.POSES.VENDEUSES ||FERMER.POSE)
GlobalVariableSet("$_ACTIVATION_EXPERT_$", 0);
}
// ****************************************************************** //
// ******************* Fermer (Toutes) Position(s) ****************** //
// ****************************************************************** //
int Fermer_Positions(int _Identifiant = 0, int _Fermer.Ordre.Type = 6)
{
bool Ordre.Clôturé.? = false;
string Nom.Arrow.Clean.CodeUn = "";
string Nom.Arrow.Clean.CodeQuatre.Tp = "";
string Nom.Arrow.Clean.CodeQuatre.Stp = "";
for (int i = OrdersTotal(); i >= 0; i--)
{
OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
// Initialisation à false de la variable de fermeture après chaque fermeture
Ordre.Clôturé.? = false;
// *************************************************************** //
// ---------------- CREATION NOM OBJET A EFFACER ----------------- //
// *************************************************************** //
// Effacer les objets graphiques associés au trade
Nom.Arrow.Clean.CodeUn = Creation_Nom_Objet_A_Effacer("Arrow", 1, "",
OrderSymbol(), OrderTicket(), OrderType(), OrderLots(), OrderOpenPrice(),
OrderTakeProfit(), OrderStopLoss());
Nom.Arrow.Clean.CodeQuatre.Tp = Creation_Nom_Objet_A_Effacer("Arrow", 4, "Tp",
OrderSymbol(), OrderTicket(), OrderType(), OrderLots(), OrderOpenPrice(),
OrderTakeProfit(), OrderStopLoss());
Nom.Arrow.Clean.CodeQuatre.Stp = Creation_Nom_Objet_A_Effacer("Arrow", 4, "Stp",
OrderSymbol(), OrderTicket(), OrderType(), OrderLots(), OrderOpenPrice(),
OrderTakeProfit(), OrderStopLoss());
// *************************************************************** //
// :::::::::::::::: FERMER L'INTEGRALITE DES ORDRES ::::::::::::::: //
// :::::::::::::::: OU FERMER UN ORDRE SPECIFIQUE ::::::::::::::: //
if ((Symbol() == OrderSymbol() && _Identifiant == 0) ||
(Symbol() == OrderSymbol() && _Identifiant != 0 && OrderMagicNumber() == _Identifiant))
{
if (
// ...
(OrderType() == OP_BUY && (_Fermer.Ordre.Type == OP_BUY || _Fermer.Ordre.Type == 6)) ||
(OrderType() == OP_SELL && (_Fermer.Ordre.Type == OP_SELL || _Fermer.Ordre.Type == 6)) ||
(OrderType() == OP_BUYSTOP && (_Fermer.Ordre.Type == OP_BUYSTOP || _Fermer.Ordre.Type == 6)) ||
(OrderType() == OP_SELLSTOP && (_Fermer.Ordre.Type == OP_SELLSTOP || _Fermer.Ordre.Type == 6)) ||
(OrderType() == OP_BUYLIMIT && (_Fermer.Ordre.Type == OP_BUYLIMIT || _Fermer.Ordre.Type == 6)) ||
(OrderType() == OP_SELLLIMIT && (_Fermer.Ordre.Type == OP_SELLLIMIT || _Fermer.Ordre.Type == 6))
// ...
)
{
int incr. = 0;
while (!Ordre.Clôturé.? && incr. < n.Tentatives.Clôture)
{
incr.++;
// Attendre en cas de problème : déconnexion ou occupation
int timer1 = TimeLocal();
int timer2 = TimeLocal();
// Attente aléatoire si les conditions ne sont pas réunies
Attendre_Disponibilité_pr_Ordre();
// Rafraîchir cotation
RefreshRates();
// Tentative de clôture
if (OrderType() == OP_BUY && OrderType() == OP_SELL)
Ordre.Clôturé.? = OrderClose(OrderTicket(),OrderLots(), Bid, MarketInfo(Symbol(), MODE_SPREAD)+10, Violet);
if (OrderType() != OP_BUY && OrderType() != OP_SELL)
Ordre.Clôturé.? = OrderDelete(OrderTicket(), Violet);
if (!Ordre.Clôturé.?) Sleep(150); // Attente si seulement échec
}
// ------ EFFACER ------
if (Clean.Trace.Entree.Sortie)
Effacer.Objet(Nom.Arrow.Clean.CodeUn);
if (Clean.Trace.Prise.Profit)
Effacer.Objet(Nom.Arrow.Clean.CodeQuatre.Tp);
if (Clean.Trace.Stop.Perte)
Effacer.Objet(Nom.Arrow.Clean.CodeQuatre.Stp);
}
}
}
}
// ****************************************************************** //
// ******************* Dénomination Objet à Effacer ***************** //
// ****************************************************************** //
string Creation_Nom_Objet_A_Effacer(string _Type.Objet, int _Code.Objet, string _Code.Sous.Objet,
string _Devise.Ordre, int _Ticket.Ordre, int _Type.Ordre, double _Quantité.Lots,
double _Prix.Ouverture, double _Prix.Prise.Profit, double _Prix.Stop.Perte)
{
// ex : Arrow (code 1) : "#30900169 buy stop 0.03 EURUSDm at 1.2864"
// ex : Arrow (code 4) : "#31235132 buy stop 0.03 EURUSDm at 1.2658 take profit at 1.325"
// ex : Arrow (code 4) : "#31010932 buy stop 0.02 EURUSDm at 1.2874 stop loss at 1.2706"
string Nom.Objet.A.Effacer = "";
if (_Type.Objet == "Arrow")
{
// ----- Ajout du ticket de l'ordre -----
Nom.Objet.A.Effacer = StringConcatenate("#", DoubleToStr(_Ticket.Ordre, 0));
// ----- Ajout du type de l'ordre -----
string Ord.Typ[6] = {" buy ", " sell ", " buy stop ", " sell stop ", " buy limit ", " sell limit "};
Nom.Objet.A.Effacer = StringConcatenate(Nom.Objet.A.Effacer, Ord.Typ[_Type.Ordre]);
// ----- Ajout du volume -----
int decim. = Lots.Decimals();
string str.Q = DoubleToStr(NormalizeDouble(_Quantité.Lots, decim.), decim.);
Nom.Objet.A.Effacer = StringConcatenate(Nom.Objet.A.Effacer, str.Q);
// ----- Ajout de la devise d'intervention -----
Nom.Objet.A.Effacer = StringConcatenate(Nom.Objet.A.Effacer, " ", _Devise.Ordre, " ");
// ----- Ajout du prix d'ouverture -----
string str.Pr = DoubleToStr(_Prix.Ouverture, Digits);
Nom.Objet.A.Effacer = StringConcatenate(Nom.Objet.A.Effacer, "at ", str.Pr);
// --- Pré-Calculs ---
if (Digits > 5) Print("Trop de chiffres après la virgule. Devise impossible à traiter correctement",
"Sous-Module : Creation.Nom.Objet.A.Effacer(...)");
int add.cf = 0;
if (Bid >= 0 && Ask < 10) add.cf = 0; // ex. type : 1.xx..
if (Bid >= 10 && Ask < 100) add.cf = 1; // ex. type : 12.xx..
if (Bid >= 100 && Ask < 1000) add.cf = 2; // ex. type : 125.xx..
if (Bid >= 1000) Print("Impossible de continuer : valeur monnaie trop grande (>1000).,",
"Sous-Module : Creation.Nom.Objet.A.Effacer(...)");
// ---
// ****** CAS CODE 4 ******
if (_Code.Objet == 4 && _Code.Sous.Objet == "Tp")
{
Nom.Objet.A.Effacer = StringConcatenate(Nom.Objet.A.Effacer, " take profit at ");
string str.Tp = "";
// Découpage du nombre str.Tp, dg.Pow chiffres après la virgule
str.Tp = DoubleToStr(_Prix.Prise.Profit, Digits);
for (int i = 1; i <= 5; i++)
if (MathMod(10^Digits * _Prix.Prise.Profit, 10^i) == 0 && Digits > (i-1))
str.Tp = StringSubstr(str.Tp, 0, add.cf + Digits - ((i-1) + (Digits==i)));
Nom.Objet.A.Effacer = StringConcatenate(Nom.Objet.A.Effacer, str.Tp);
}
if (_Code.Objet == 4 && _Code.Sous.Objet == "Stp")
{
Nom.Objet.A.Effacer = StringConcatenate(Nom.Objet.A.Effacer, " stop loss at ");
string str.Stp = "";
// Découpage du nombre str.Stp, dg.Pow chiffres après la virgule
str.Stp = DoubleToStr(_Prix.Stop.Perte, Digits);
for (i = 1; i <= 5; i++)
if (MathMod(10^Digits * _Prix.Stop.Perte, 10^i) == 0 && Digits > (i-1))
str.Stp = StringSubstr(str.Stp, 0, add.cf + Digits - ((i-1) + (Digits==i)));
Nom.Objet.A.Effacer = StringConcatenate(Nom.Objet.A.Effacer, str.Stp);
}
}
// Renvoi du nom de l'objet
return(Nom.Objet.A.Effacer);
}
// ****************************************************************** //
// ************* Calcul du nombre de décimales pour la TP *********** //
// ****************************************************************** //
int Lots.Decimals()
{
int Pos.Point = StringFind(MarketInfo(Symbol(), MODE_LOTSTEP), ".");
// ---
return (StringLen(MarketInfo(Symbol(), MODE_LOTSTEP)) - (1 + Pos.Point));
}
// ****************************************************************** //
// ********************* Fonction Objet à Effacer ******************* //
// ****************************************************************** //
void Effacer.Objet(string _Nom.Objet.A.Effacer)
{
for(int i = 0; i < 4; i++)
{
if (i==0 && !ObjectDelete(_Nom.Objet.A.Effacer)) _Nom.Objet.A.Effacer =
StringSubstr(_Nom.Objet.A.Effacer, 0, StringLen(_Nom.Objet.A.Effacer) - 1);
if (i==1 && !ObjectDelete(_Nom.Objet.A.Effacer)) _Nom.Objet.A.Effacer =
StringSubstr(_Nom.Objet.A.Effacer, 0, StringLen(_Nom.Objet.A.Effacer) - 2);
if (i==2 && !ObjectDelete(_Nom.Objet.A.Effacer)) _Nom.Objet.A.Effacer =
StringSubstr(_Nom.Objet.A.Effacer, 0, StringLen(_Nom.Objet.A.Effacer) - 3);
if (i==3) ObjectDelete(_Nom.Objet.A.Effacer);
}
}
// ****************************************************************** //
// ************************** Stops Suiveurs ************************ //
// ****************************************************************** //
int Stop_Suiveurs()
{
string Dépendance = "";
int Trail.Entry.Pips = 0;
// Parcours de l'ensemble des trades en cours
for (int i = OrdersTotal(); i >= 0; i--)
{
OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
// Extraction du numéro de la dépendance
Dépendance = StringSubstr(DoubleToStr(OrderMagicNumber(), 0), 2, 3);
// Il s'agit d'un stop suiveur ...Et uniquement un STOP
if (Dépendance == "4" && (OrderType() == OP_BUYSTOP || OrderType() == OP_SELLSTOP))
{
// Initialisation du tableau Content[]
for (int j = 0; j < ArrayRange(Content, 1) ; j++) Content[j] = "";
// Extraction des données de la chaîne Comment
Comment_Extract(OrderComment());
// La valeur du Trail.Entry.Pips se trouve dans Content[2]
Trail.Entry.Pips = StrToInteger(Content[2]);
// Ajuster le stop suiveur en fonction de cette valeur
if (Trail.Entry.Pips != 0)
Ajust_Stops_Suiveurs_?(OrderTicket(), Trail.Entry.Pips);
else continue;
}
else continue;
}
}
// ****************************************************************** //
// ************ Extraction du commentaire de chaque ordre *********** //
// ****************************************************************** //
//
// Architecture du commentaire :
// Info1#Info2#...#Info3 (séparateur = #)
//
// ****************************************************************** //
int Comment_Extract(string _Commentaire)
{
// Initialisations
int start = 0, pos = 0, n.sep = 0;
string chn = "";
// Extraction du contenu de la chaîne commentaire dans Content[]
// Type commentaire : 0103#456#910
while (StringLen(chn) < StringLen(_Commentaire) - n.sep)
{
// Lecture de la position du caractère séparateur #
pos = StringFind(_Commentaire, "#", start);
// Extraction de la chaine de caract. comprise entre start et pos
if (pos != -1)
Content[n.sep] = StringSubstr(_Commentaire, start, pos - start);
else if (pos == -1 && start > 0)
Content[n.sep] = StringSubstr(_Commentaire, start, StringLen(_Commentaire) - start);
else break;
// Incrémentation de start à la position qui suit immédiatement Pos
start = pos + 1;
// Incrémentation indice tableau
n.sep++;
// Construction de chn (chaîne comparative)
chn = StringConcatenate(chn, Content[n.sep]);
}
}
// ****************************************************************** //
// ******************* Ajustement Stops Suiveurs ? ****************** //
// ****************************************************************** //
bool Ajust_Stops_Suiveurs_?(int _Order.Ticket, int _Trail.Entry.Pips)
{
double bsl = 0, b.tsl.ent = 0, ssl = 0, s.tsl.ent = 0;
int cnt = 0;
// Sauvegarde de la distance entre le Stoploss et le point d'entrée théorique
double dStop = MathAbs(OrderOpenPrice() - OrderStopLoss());
// Rafraîchir les cotations
RefreshRates();
// Sélectionner l'ordre
OrderSelect(_Order.Ticket, SELECT_BY_TICKET);
// Si on cherche à ajuster un stop pending achat
if (OrderType() == OP_BUYSTOP)
{
bsl = _Trail.Entry.Pips * Point;
// Le point d'entrée achat doit-il être modifié ?
if (Bid < (OrderOpenPrice() - bsl))
{
// Ajustement du nouveau point d'entrée théorique
b.tsl.ent = NormalizeDouble(OrderOpenPrice() - ((OrderOpenPrice() - bsl) - Bid), Digits);
// Attente aléatoire si les conditions ne sont pas réunies
Attendre_Disponibilité_pr_Ordre();
// Tentative de modification de l'ordre
while (cnt < n.Tentatives.Connection && !OrderModify(_Order.Ticket, b.tsl.ent,
b.tsl.ent - dStop, OrderTakeProfit(), OrderExpiration(), MediumVioletRed))
{
if (!IsTradeAllowed() || IsTradeContextBusy() || !IsConnected())
Temps_Attente_Aleatoire(); // Attente
}
}
}
// Si on cherche à ajuster un stop pending vente
if (OrderType() == OP_SELLSTOP)
{
ssl = _Trail.Entry.Pips * Point;
// Le stop perte doit-il être modifié ?
if (Ask > (OrderOpenPrice() + ssl))
{
// Ajustement du nouveau point d'entrée théorique
s.tsl.ent = NormalizeDouble(OrderOpenPrice() + (Ask - (OrderOpenPrice() + ssl)), Digits);
// Attente aléatoire si les conditions ne sont pas réunies
Attendre_Disponibilité_pr_Ordre();
// Tentative de modification de l'ordre
while (cnt < n.Tentatives.Connection && !OrderModify(_Order.Ticket, s.tsl.ent,
s.tsl.ent + dStop, OrderTakeProfit(), OrderExpiration(), MediumVioletRed))
{
if (!IsTradeAllowed() || IsTradeContextBusy() || !IsConnected())
Temps_Attente_Aleatoire(); // Attente
}
}
}
}
Comments
Markdown Formatting Guide
# H1
## H2
### H3
**bold text**
*italicized text*
[title](https://www.example.com)

`code`
```
code block
```
> blockquote
- Item 1
- Item 2
1. First item
2. Second item
---