//+------------------------------------------------------------------+
//| TPO_2026_GOLD.mq5 |
//| Propriété de Taupin Private Office (TPO) |
//| Conçu pour Prop Firms (High Stakes 2026) |
//+------------------------------------------------------------------+
#property copyright "Taupin Private Office (TPO)"
#property version "2.00"
#property strict
//--- PARAMÈTRES DE RISQUE
input group "=== Gestion du Risque ==="
input double CapitalInitial = 2500.00; // Capital initial du compte
input double RisquePourcent = 0.5; // Risque par trade (%)
input int MaxPositions = 1; // Nombre max de positions simultanées
input double PerteJourMaxPct = 4.0; // Perte journalière max (%) - Sécurité avant les 5%
input double DrawdownMaxPct = 9.0; // Drawdown max global (%) - Sécurité avant les 10%
//--- PARAMÈTRES DE CONSISTANCE
input group "=== Règle de Consistance ==="
input bool ActiverConsistance = true; // Activer la gestion de la consistance
input double SeuilConsistance = 40.0; // Seuil (%) de profit max par jour pour rester éligible
//--- PARAMÈTRES DE LA STRATÉGIE
input group "=== Stratégie TPO Gold (M5) ==="
input int FastEMA = 5; // Période EMA rapide
input int SlowEMA = 20; // Période EMA lente
input int TrendEMA = 200; // Période EMA de tendance
input int RSI_Period = 14; // Période RSI
input int SL_Points = 300; // Stop Loss en points (Or)
input double RatioRR = 2.0; // Ratio Risque/Récompense (TP = SL * Ratio)
//--- PARAMÈTRES DE SYMBOLE
input group "=== Symbole & Spread ==="
input string SYM_XAU = "XAUUSD"; // Nom du symbole de l'Or
input int SpreadMaxXAU = 80; // Spread maximum autorisé (points)
//--- PROTECTION DES GAINS
input group "=== Protection (Breakeven) ==="
input bool UtiliserBreakeven = true;
input int BreakevenTriggerPoints = 250; // Déclenche le BE à +250 points
input int BreakevenBufferPoints = 20; // Marge de sécurité
//--- FILTRE ANTI-NEWS
input group "=== Filtre Anti-News ==="
input int MinutesAvantNews = 2; // Minutes avant news
input int MinutesApresNews = 2; // Minutes après news
//--- CONSTANTES
const long MAGIC = 20261108; // ID unique TPO Gold
//--- VARIABLES GLOBALES
double ProfitTotal = 0.0;
double ProfitJour = 0.0;
datetime DateJourActuel = 0;
bool TradingSuspenduConsistance = false;
double SoldeDebutJour = 0.0;
datetime JourActuel = 0;
datetime DernierTick = 0;
int hFastEMA, hSlowEMA, hTrendEMA, hRSI;
bool OK = true;
//+------------------------------------------------------------------+
//| MODULE D'INTERFACE GRAPHIQUE (DASHBOARD) TPO |
//+------------------------------------------------------------------+
void DrawLabel(string name, string text, int x, int y, color clr, int size = 10, bool bold = false, string font = "Trebuchet MS")
{
if(ObjectFind(0, name) < 0)
ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
ObjectSetString(0, name, OBJPROP_TEXT, text);
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, size);
ObjectSetString(0, name, OBJPROP_FONT, font);
ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, name, OBJPROP_BACK, false);
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
}
void InitDashboard()
{
// --- 1. CONFIGURATION DU GRAPHIQUE EN FOND BLANC ---
ChartSetInteger(0, CHART_COLOR_BACKGROUND, clrWhite);
ChartSetInteger(0, CHART_COLOR_FOREGROUND, clrBlack);
ChartSetInteger(0, CHART_COLOR_GRID, clrWhiteSmoke);
ChartSetInteger(0, CHART_COLOR_CHART_UP, clrGreen);
ChartSetInteger(0, CHART_COLOR_CHART_DOWN, clrRed);
ChartSetInteger(0, CHART_COLOR_CHART_LINE, clrBlack);
ChartSetInteger(0, CHART_COLOR_CANDLE_BULL, clrWhite);
ChartSetInteger(0, CHART_COLOR_CANDLE_BEAR, clrBlack);
ChartSetInteger(0, CHART_SHOW_GRID, false);
// --- 2. COULEURS ADAPTÉES AU FOND BLANC ---
color clrTitre = clrDarkGoldenrod;
color clrTexte = clrBlack;
color clrValeur = clrDimGray;
// --- TITRE TPO ---
DrawLabel("TPO_Title", "TPO GOLD", 20, 20, clrTitre, 22, true, "Arial Black");
DrawLabel("TPO_Sub", "by TAUPIN Thierry", 22, 55, clrValeur, 9, false);
// --- COLONNE GAUCHE (INFOS TRADING) ---
int yInfos = 90;
int espacement = 20;
DrawLabel("TPO_Lbl1", "Lot attendu :", 20, yInfos, clrTexte, 10);
DrawLabel("TPO_Val1", "=", 120, yInfos, clrValeur, 10);
DrawLabel("TPO_Lbl2", "Levier :", 20, yInfos + espacement, clrTexte, 10);
DrawLabel("TPO_Val2", "=", 120, yInfos + espacement, clrValeur, 10);
DrawLabel("TPO_Lbl3", "Lots ouverts :", 20, yInfos + espacement*2, clrTexte, 10);
DrawLabel("TPO_Val3", "=", 120, yInfos + espacement*2, clrValeur, 10);
DrawLabel("TPO_Lbl4", "P/L Flottant :", 20, yInfos + espacement*3, clrTexte, 10);
DrawLabel("TPO_Val4", "=", 120, yInfos + espacement*3, clrValeur, 10);
DrawLabel("TPO_Lbl5", "Commentaire :", 20, yInfos + espacement*4, clrTexte, 10);
DrawLabel("TPO_Val5", "TPO", 120, yInfos + espacement*4, clrTitre, 10, true);
// --- BLOC NEWS (EN HAUT À DROITE) ---
int xNews = 250;
DrawLabel("TPO_NewsTitle", "News & Événements", xNews, 20, clrTitre, 12, true);
DrawLabel("TPO_NewsH1", "Time", xNews, 45, clrTexte, 9);
DrawLabel("TPO_NewsH2", "Currency", xNews + 60, 45, clrTexte, 9);
DrawLabel("TPO_NewsH3", "Impact", xNews + 130, 45, clrTexte, 9);
DrawLabel("TPO_NewsH4", "News Event", xNews + 190, 45, clrTexte, 9);
for(int i=0; i<3; i++)
{
int yL = 65 + (i*15);
DrawLabel("TPO_N1_"+IntegerToString(i), "==:==", xNews, yL, clrValeur, 9);
DrawLabel("TPO_N2_"+IntegerToString(i), "USD", xNews + 60, yL, clrValeur, 9);
DrawLabel("TPO_N3_"+IntegerToString(i), "===", xNews + 130, yL, clrDarkGoldenrod, 9);
DrawLabel("TPO_N4_"+IntegerToString(i), "En attente...", xNews + 190, yL, clrValeur, 9);
}
// --- BLOC RÉSUMÉ TRADING (EN BAS À DROITE) ---
int xRes = 250;
int yRes = 140;
DrawLabel("TPO_ResTitle", "Résumé du Trading", xRes, yRes, clrTitre, 12, true);
DrawLabel("TPO_ResH1", "Curr. pair", xRes, yRes + 25, clrTexte, 9);
DrawLabel("TPO_ResH2", "Trading time", xRes + 70, yRes + 25, clrTexte, 9);
DrawLabel("TPO_ResH3", "Day of week", xRes + 160, yRes + 25, clrTexte, 9);
DrawLabel("TPO_ResH4", "Bars Held", xRes + 240, yRes + 25, clrTexte, 9);
DrawLabel("TPO_ResH5", "Open/Start lot", xRes + 310, yRes + 25, clrTexte, 9);
DrawLabel("TPO_R1", "XAUUSD", xRes, yRes + 45, clrTexte, 9, true);
DrawLabel("TPO_R2", "==:==", xRes + 70, yRes + 45, clrValeur, 9);
DrawLabel("TPO_R3", "===", xRes + 160, yRes + 45, clrValeur, 9);
DrawLabel("TPO_R4", "0", xRes + 240, yRes + 45, clrValeur, 9);
DrawLabel("TPO_R5", "= / =", xRes + 310, yRes + 45, clrValeur, 9);
ChartRedraw();
}
void CleanDashboard()
{
ObjectsDeleteAll(0, "TPO_");
ChartRedraw();
}
void UpdateDashboardDynamic()
{
long levier = AccountInfoInteger(ACCOUNT_LEVERAGE);
ObjectSetString(0, "TPO_Val2", OBJPROP_TEXT, "1:" + IntegerToString(levier));
double lotsOuverts = 0;
double plFlottant = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket) && PositionGetInteger(POSITION_MAGIC) == MAGIC)
{
lotsOuverts += PositionGetDouble(POSITION_VOLUME);
plFlottant += PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP);
}
}
ObjectSetString(0, "TPO_Val3", OBJPROP_TEXT, DoubleToString(lotsOuverts, 2));
ObjectSetString(0, "TPO_Val4", OBJPROP_TEXT, DoubleToString(plFlottant, 2) + " $");
if(plFlottant > 0) ObjectSetInteger(0, "TPO_Val4", OBJPROP_COLOR, clrForestGreen);
else if(plFlottant < 0) ObjectSetInteger(0, "TPO_Val4", OBJPROP_COLOR, clrCrimson);
else ObjectSetInteger(0, "TPO_Val4", OBJPROP_COLOR, clrDimGray);
ChartRedraw();
}
//+------------------------------------------------------------------+
//| INITIALISATION |
//+------------------------------------------------------------------+
int OnInit()
{
if(!SymbolSelect(SYM_XAU, true)) return(INIT_FAILED);
hFastEMA = iMA(SYM_XAU, PERIOD_M5, FastEMA, 0, MODE_EMA, PRICE_CLOSE);
hSlowEMA = iMA(SYM_XAU, PERIOD_M5, SlowEMA, 0, MODE_EMA, PRICE_CLOSE);
hTrendEMA = iMA(SYM_XAU, PERIOD_M5, TrendEMA, 0, MODE_EMA, PRICE_CLOSE);
hRSI = iRSI(SYM_XAU, PERIOD_M5, RSI_Period, PRICE_CLOSE);
if(hFastEMA == INVALID_HANDLE || hSlowEMA == INVALID_HANDLE ||
hTrendEMA == INVALID_HANDLE || hRSI == INVALID_HANDLE)
return(INIT_FAILED);
SoldeDebutJour = AccountInfoDouble(ACCOUNT_EQUITY);
JourActuel = TimeCurrent() / 86400;
DateJourActuel = JourActuel;
ProfitTotal = AccountInfoDouble(ACCOUNT_BALANCE) - CapitalInitial;
ProfitJour = 0.0;
InitDashboard();
Print(">>> TPO 2026 GOLD PRÊT | Consistance: ", ActiverConsistance ? "ON" : "OFF");
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
IndicatorRelease(hFastEMA);
IndicatorRelease(hSlowEMA);
IndicatorRelease(hTrendEMA);
IndicatorRelease(hRSI);
CleanDashboard();
}
//+------------------------------------------------------------------+
//| CALCUL DU PROFIT JOURNALIER (HISTORIQUE) |
//+------------------------------------------------------------------+
double CalculerProfitJour()
{
datetime debutJour = TimeCurrent() - (TimeCurrent() % 86400);
datetime finJour = TimeCurrent();
double profitDuJour = 0.0;
if(HistorySelect(debutJour, finJour))
{
int dealsTotal = HistoryDealsTotal();
for(int i = 0; i < dealsTotal; i++)
{
ulong ticket = HistoryDealGetTicket(i);
if(HistoryDealGetInteger(ticket, DEAL_MAGIC) == MAGIC &&
HistoryDealGetInteger(ticket, DEAL_ENTRY) == DEAL_ENTRY_OUT)
{
profitDuJour += HistoryDealGetDouble(ticket, DEAL_PROFIT) +
HistoryDealGetDouble(ticket, DEAL_SWAP) +
HistoryDealGetDouble(ticket, DEAL_COMMISSION);
}
}
}
return profitDuJour;
}
//+------------------------------------------------------------------+
//| GESTION DE LA CONSISTANCE TPO |
//+------------------------------------------------------------------+
void MettreAJourConsistance()
{
ProfitTotal = AccountInfoDouble(ACCOUNT_BALANCE) - CapitalInitial;
datetime today = TimeCurrent() / 86400;
if(today != DateJourActuel)
{
DateJourActuel = today;
TradingSuspenduConsistance = false;
Print("TPO GOLD : Nouveau jour, réinitialisation du compteur de consistance.");
}
ProfitJour = CalculerProfitJour();
}
bool ConsistanceEstValide()
{
if(!ActiverConsistance || ProfitTotal <= 0 || ProfitJour <= 0) return true;
double pourcentageConsistance = (ProfitJour / ProfitTotal) * 100.0;
if(pourcentageConsistance >= SeuilConsistance)
{
if(!TradingSuspenduConsistance)
{
TradingSuspenduConsistance = true;
Print("!!! TPO GOLD ALERT : Consistance de ", DoubleToString(pourcentageConsistance, 1),
"% atteinte (Seuil: ", DoubleToString(SeuilConsistance, 1), "%). Trading suspendu pour aujourd'hui.");
}
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| FONCTIONS UTILITAIRES DE TRADING |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE_FILLING GetFillingType(string sym)
{
uint filling = (uint)SymbolInfoInteger(sym, SYMBOL_FILLING_MODE);
if((filling & SYMBOL_FILLING_FOK) != 0) return ORDER_FILLING_FOK;
if((filling & SYMBOL_FILLING_IOC) != 0) return ORDER_FILLING_IOC;
return ORDER_FILLING_RETURN;
}
int PositionsTotalMagic()
{
int count = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong t = PositionGetTicket(i);
if(PositionSelectByTicket(t) && PositionGetInteger(POSITION_MAGIC) == MAGIC) count++;
}
return count;
}
bool HasPosition(string sym)
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong t = PositionGetTicket(i);
if(PositionSelectByTicket(t) &&
PositionGetString(POSITION_SYMBOL) == sym &&
PositionGetInteger(POSITION_MAGIC) == MAGIC) return true;
}
return false;
}
void CloseAllPositions()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong t = PositionGetTicket(i);
if(!PositionSelectByTicket(t) || PositionGetInteger(POSITION_MAGIC) != MAGIC) continue;
MqlTradeRequest req; MqlTradeResult res;
ZeroMemory(req); ZeroMemory(res);
string sym = PositionGetString(POSITION_SYMBOL);
double vol = PositionGetDouble(POSITION_VOLUME);
long type = PositionGetInteger(POSITION_TYPE);
req.action = TRADE_ACTION_DEAL;
req.position = t;
req.symbol = sym;
req.volume = vol;
req.deviation = 20;
req.magic = MAGIC;
req.type = (type == POSITION_TYPE_BUY) ? ORDER_TYPE_SELL : ORDER_TYPE_BUY;
req.price = (type == POSITION_TYPE_BUY) ? SymbolInfoDouble(sym, SYMBOL_BID) : SymbolInfoDouble(sym, SYMBOL_ASK);
req.type_filling = GetFillingType(sym);
OrderSend(req, res);
}
}
double CalculateLot(string sym, int slPoints)
{
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
double riskAmount = equity * (RisquePourcent / 100.0);
if(riskAmount > equity * 0.02) riskAmount = equity * 0.02;
double tickValue = SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_VALUE);
double tickSize = SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_SIZE);
double point = SymbolInfoDouble(sym, SYMBOL_POINT);
if(tickValue <= 0 || tickSize <= 0 || point <= 0 || slPoints <= 0)
return SymbolInfoDouble(sym, SYMBOL_VOLUME_MIN);
double pointValuePerLot = (tickValue / tickSize) * point;
double lot = riskAmount / (slPoints * pointValuePerLot);
double lotMin = SymbolInfoDouble(sym, SYMBOL_VOLUME_MIN);
double lotMax = SymbolInfoDouble(sym, SYMBOL_VOLUME_MAX);
double lotStep = SymbolInfoDouble(sym, SYMBOL_VOLUME_STEP);
lot = MathFloor(lot / lotStep) * lotStep;
lot = MathMax(lot, lotMin);
lot = MathMin(lot, lotMax);
return NormalizeDouble(lot, 2);
}
bool IsNewsTime()
{
MqlCalendarValue values[];
datetime now = TimeCurrent();
datetime from = now - (MinutesApresNews * 60);
datetime to = now + (MinutesAvantNews * 60);
if(CalendarValueHistory(values, from, to, NULL, NULL))
{
for(int i = 0; i < ArraySize(values); i++)
{
MqlCalendarEvent event;
if(CalendarEventById(values[i].event_id, event))
{
if(event.importance == CALENDAR_IMPORTANCE_HIGH) return true;
}
}
}
return false;
}
//+------------------------------------------------------------------+
//| SIGNAUX ET GESTION |
//+------------------------------------------------------------------+
bool SignalTrend(bool &buy)
{
double fast[1], slow[1], trend[1], rsi[1];
if(CopyBuffer(hFastEMA, 0, 1, 1, fast) <= 0 ||
CopyBuffer(hSlowEMA, 0, 1, 1, slow) <= 0 ||
CopyBuffer(hTrendEMA, 0, 1, 1, trend) <= 0 ||
CopyBuffer(hRSI, 0, 1, 1, rsi) <= 0)
return false;
bool trendHaut = (fast[0] > slow[0] && slow[0] > trend[0]);
bool trendBas = (fast[0] < slow[0] && slow[0] < trend[0]);
if(trendHaut && rsi[0] > 50 && rsi[0] < 70)
{ buy = true; return true; }
if(trendBas && rsi[0] > 30 && rsi[0] < 50)
{ buy = false; return true; }
return false;
}
void ManageBreakeven()
{
if(!UtiliserBreakeven) return;
double point = SymbolInfoDouble(SYM_XAU, SYMBOL_POINT);
int digits = (int)SymbolInfoInteger(SYM_XAU, SYMBOL_DIGITS);
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong t = PositionGetTicket(i);
if(!PositionSelectByTicket(t) || PositionGetInteger(POSITION_MAGIC) != MAGIC) continue;
long type = PositionGetInteger(POSITION_TYPE);
double entry = PositionGetDouble(POSITION_PRICE_OPEN);
double currentSL = PositionGetDouble(POSITION_SL);
double currentTP = PositionGetDouble(POSITION_TP);
double bid = SymbolInfoDouble(SYM_XAU, SYMBOL_BID);
double ask = SymbolInfoDouble(SYM_XAU, SYMBOL_ASK);
double profitPoints = (type == POSITION_TYPE_BUY) ? (bid - entry) / point : (entry - ask) / point;
if(profitPoints < BreakevenTriggerPoints) continue;
double newSL = (type == POSITION_TYPE_BUY) ? entry + BreakevenBufferPoints * point : entry - BreakevenBufferPoints * point;
newSL = NormalizeDouble(newSL, digits);
bool dejaFait = (type == POSITION_TYPE_BUY) ? (currentSL >= newSL) : (currentSL != 0 && currentSL <= newSL);
if(dejaFait) continue;
MqlTradeRequest req; MqlTradeResult res;
ZeroMemory(req); ZeroMemory(res);
req.action = TRADE_ACTION_SLTP;
req.position = t;
req.symbol = SYM_XAU;
req.sl = newSL;
req.tp = currentTP;
OrderSend(req, res);
}
}
void ExecuteOrder(bool buy, int slPoints)
{
if(PositionsTotalMagic() >= MaxPositions || HasPosition(SYM_XAU)) return;
datetime currentBar = iTime(SYM_XAU, PERIOD_M5, 0);
if(DernierTick == currentBar) return;
DernierTick = currentBar;
double point = SymbolInfoDouble(SYM_XAU, SYMBOL_POINT);
double ask = SymbolInfoDouble(SYM_XAU, SYMBOL_ASK);
double bid = SymbolInfoDouble(SYM_XAU, SYMBOL_BID);
double lot = CalculateLot(SYM_XAU, slPoints);
int tpPoints = (int)MathRound(slPoints * RatioRR);
double price = buy ? ask : bid;
double sl = buy ? ask - slPoints * point : bid + slPoints * point;
double tp = buy ? ask + tpPoints * point : bid - tpPoints * point;
int digits = (int)SymbolInfoInteger(SYM_XAU, SYMBOL_DIGITS);
sl = NormalizeDouble(sl, digits);
tp = NormalizeDouble(tp, digits);
MqlTradeRequest req; MqlTradeResult res;
ZeroMemory(req); ZeroMemory(res);
req.action = TRADE_ACTION_DEAL;
req.symbol = SYM_XAU;
req.volume = lot;
req.type = buy ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
req.price = price;
req.sl = sl;
req.tp = tp;
req.deviation = 20;
req.magic = MAGIC;
req.comment = "TPO 2026 Gold";
req.type_filling = GetFillingType(SYM_XAU);
if(OrderSend(req, res))
{
Print(">>> TPO GOLD ENTRY | Lot: ", lot, " | Prix: ", price);
// Met à jour le lot attendu sur l'interface après un trade
ObjectSetString(0, "TPO_Val1", OBJPROP_TEXT, DoubleToString(lot, 2));
}
}
//+------------------------------------------------------------------+
//| ONTICK (BOUCLE PRINCIPALE) |
//+------------------------------------------------------------------+
void OnTick()
{
if(!OK) return;
// --- Animation de l'Interface en Temps Réel ---
UpdateDashboardDynamic();
// --- Mise à jour de la consistance (calcul sur historique) ---
MettreAJourConsistance();
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
// --- 1. Réinitialisation Solde Journalier ---
datetime today = TimeCurrent() / 86400;
if(today != JourActuel)
{
JourActuel = today;
SoldeDebutJour = equity;
}
// --- 2. Hard Stop : Drawdown Global (max 9%) ---
double ddGlobal = (CapitalInitial - equity) / CapitalInitial * 100.0;
if(ddGlobal >= DrawdownMaxPct)
{
CloseAllPositions();
ExpertRemove();
Print("!!! TPO GOLD CRITICAL : Drawdown global ", ddGlobal, "% atteint. EA désactivé.");
return;
}
// --- 3. Hard Stop : Perte Journalière (max 4%) ---
double ddJour = (SoldeDebutJour - equity) / SoldeDebutJour * 100.0;
if(ddJour >= PerteJourMaxPct)
{
CloseAllPositions();
return;
}
// --- 4. Règle de Consistance Prop Firm ---
if(!ConsistanceEstValide()) return;
// --- 5. Protection Breakeven ---
ManageBreakeven();
// --- 6. Filtre Macro-Économique (News) ---
if(IsNewsTime()) return;
// --- 7. Filtre Spread (Sécurité liquidité) ---
long spread = SymbolInfoInteger(SYM_XAU, SYMBOL_SPREAD);
if(spread > SpreadMaxXAU) return;
// --- 8. Moteur de Trading ---
bool buy;
if(SignalTrend(buy)) ExecuteOrder(buy, SL_Points);
}
//+------------------------------------------------------------------+