Files
fimathe-trend-ea/Fimathe_Trend_EA.mq5
adalbertodasilva2580asf-collab bc6f403b28 feat: Fimathe Trend EA v1.00 — Expert Advisor MQL5
EA profissional baseado na Técnica Fimathe de Marcelo Ferreira.
Inclui identificação de tendência (EMA + estrutura), detecção de
pullback em zona Fibonacci (0.618/0.786), gestão de capital por
risco percentual, breakeven e trailing stop automáticos.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 08:14:36 -03:00

762 lines
30 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//+------------------------------------------------------------------+
//| Fimathe_Trend_EA.mq5 |
//| Baseado na Técnica Fimathe de Marcelo Ferreira |
//| Expert Advisor para MetaTrader 5 |
//+------------------------------------------------------------------+
#property copyright "Fimathe Trend EA"
#property link ""
#property version "1.00"
#property description "EA profissional baseado na técnica Fimathe de Marcelo Ferreira"
#property strict
/*
================================================================================
CABEÇALHO — REGRAS DA TÉCNICA FIMATHE (Marcelo Ferreira)
================================================================================
FUNDAMENTOS:
┌──────────────────────────────────────────────────────────────────┐
│ 1. TENDÊNCIA É SOBERANA │
│ - Opere SEMPRE a favor da tendência principal (TF superior) │
│ - Alta : sequência de topos e fundos ASCENDENTES │
│ - Baixa : sequência de topos e fundos DESCENDENTES │
│ - Jamais entre contra a tendência principal identificada │
├──────────────────────────────────────────────────────────────────┤
│ 2. ESTRUTURA DE MERCADO (Canais / Zonas) │
│ - Máximas e mínimas recentes formam suportes e resistências │
│ - O preço respeita e reage a estruturas formadas anteriormente │
│ - Breakout confirma novo movimento direcional │
├──────────────────────────────────────────────────────────────────┤
│ 3. CORREÇÕES FIBONACCI │
│ - Após o impulso, aguardar a correção (pullback) │
│ - Níveis principais de entrada: 0.618 e 0.786 │
│ - A correção deve respeitar a estrutura anterior │
│ - Não entrar antes do preço atingir a zona Fibonacci │
├──────────────────────────────────────────────────────────────────┤
│ 4. CONFIRMAÇÃO DE ENTRADA (corpo da vela) │
│ - Aguardar FECHAMENTO do corpo da vela na direção da tendência │
│ - Compra : vela de alta com corpo relevante │
│ - Venda : vela de baixa com corpo relevante │
│ - Evitar doji e velas de indecisão │
├──────────────────────────────────────────────────────────────────┤
│ 5. GESTÃO DE RISCO │
│ - Stop Loss ABAIXO da mínima do pullback (compra) │
│ - Stop Loss ACIMA da máxima do pullback (venda) │
│ - Take Profit em próxima estrutura ou % do capital │
│ - Risco fixo por operação (% do saldo) │
├──────────────────────────────────────────────────────────────────┤
│ 6. HORÁRIO E LIQUIDEZ │
│ - Priorizar horários de maior volume │
│ - Londres : 08h12h | Nova York : 13h17h (hora servidor) │
│ - Evitar entrada em horários de baixo volume │
├──────────────────────────────────────────────────────────────────┤
│ 7. DISCIPLINA OPERACIONAL │
│ - Máximo 1 posição aberta por vez │
│ - Não reentrar em sequência imediata após stop │
│ - Aguardar novo setup completo antes de reentrar │
└──────────────────────────────────────────────────────────────────┘
FLUXO DE DECISÃO:
Tendência TF Superior → Impulso Identificado → Aguardar Pullback
→ Zona Fibonacci (0.618 / 0.786) → Confirmação de Vela → Entrada
→ Gestão com SL estrutural + TP percentual + Trailing/Breakeven
================================================================================
*/
#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\AccountInfo.mqh>
//=============================================================================
// INPUTS
//=============================================================================
sinput string sep_cap = "════ GESTÃO DE CAPITAL ════";
input bool UseMoneyMgmt = true; // Usar gestão de capital por risco
input double RiskPercent = 1.0; // % do saldo a arriscar por operação
input double TargetPct = 2.0; // % de lucro alvo por operação
input double LotSize = 0.01; // Lote fixo (se gestão desativada)
sinput string sep_tf = "════ TIMEFRAMES ════";
input ENUM_TIMEFRAMES TrendTF = PERIOD_H1; // Timeframe de identificação da tendência
input ENUM_TIMEFRAMES OperTF = PERIOD_M5; // Timeframe operacional de entrada
sinput string sep_fib = "════ FIBONACCI ════";
input double FibLvl1 = 0.618; // Nível Fibonacci 1 (entrada principal)
input double FibLvl2 = 0.786; // Nível Fibonacci 2 (entrada secundária)
input double FibTolerance = 0.015; // Tolerância da zona Fib (fração do range)
sinput string sep_struct = "════ ESTRUTURA / SETUP ════";
input int StructBars = 35; // Barras para detectar estrutura de swing
input int MinBodyPts = 60; // Pontos mínimos no corpo da vela de conf.
input bool NeedBodyClose = true; // Exigir corpo mínimo na vela de confirmação
sinput string sep_sl = "════ STOP LOSS ════";
input bool UseATR = true; // Calcular SL via ATR
input int ATRPeriod = 14; // Período do ATR
input double ATRMult = 2.0; // Multiplicador do ATR para o SL
input double SLBuffer = 150.0; // Buffer além da estrutura em pontos (sem ATR)
sinput string sep_be = "════ BREAKEVEN / TRAILING ════";
input bool UseBreakEven = true; // Ativar breakeven automático
input double BEPct = 0.5; // % de lucro no saldo para ativar BE
input bool UseTrailing = true; // Ativar trailing stop automático
input double TSPct = 1.0; // % de lucro no saldo para ativar trailing
input double TSPoints = 250.0; // Distância do trailing em pontos
sinput string sep_time = "════ HORÁRIO ════";
input bool UseTimeFilter = true; // Filtrar horário de operação
input int StartHour = 9; // Hora de início (servidor)
input int StartMin = 0; // Minuto de início
input int EndHour = 18; // Hora de fim (servidor)
input int EndMin = 0; // Minuto de fim
input bool CloseAtEnd = false; // Fechar posições ao atingir hora fim
sinput string sep_id = "════ IDENTIFICAÇÃO ════";
input int MagicNumber = 202536; // Número mágico
input string EAComment = "Fimathe Trend EA"; // Comentário nas ordens
//=============================================================================
// ENUMERAÇÕES
//=============================================================================
enum ENUM_FTREND
{
FT_UP = 1, // Tendência de Alta
FT_DOWN = -1, // Tendência de Baixa
FT_NEUTRAL = 0 // Sem tendência definida
};
//=============================================================================
// ESTRUTURA DO SETUP FIMATHE
//=============================================================================
struct SSetup
{
bool valid;
bool isBuy;
double entry;
double sl;
double tp;
double lots;
double swHigh;
double swLow;
double fib618;
double fib786;
};
//=============================================================================
// CLASSE: GERENCIADOR DE TRADES
//=============================================================================
class CManager
{
private:
CTrade m_trade;
CPositionInfo m_pos;
CAccountInfo m_acc;
int m_magic;
string m_sym;
string m_comment;
public:
CManager(int magic, string sym, string comment)
{
m_magic = magic;
m_sym = sym;
m_comment = comment;
m_trade.SetExpertMagicNumber(magic);
m_trade.SetDeviationInPoints(30);
m_trade.SetTypeFilling(ORDER_FILLING_FOK);
m_trade.LogLevel(LOG_LEVEL_ERRORS);
}
bool HasPos(ENUM_POSITION_TYPE type)
{
for(int i = PositionsTotal()-1; i >= 0; i--)
{
if(!m_pos.SelectByIndex(i)) continue;
if(m_pos.Symbol() == m_sym && m_pos.Magic() == m_magic &&
m_pos.PositionType() == type) return true;
}
return false;
}
bool HasAny() { return HasPos(POSITION_TYPE_BUY) || HasPos(POSITION_TYPE_SELL); }
bool Buy(double lots, double sl, double tp)
{
int d = (int)SymbolInfoInteger(m_sym, SYMBOL_DIGITS);
double ask = SymbolInfoDouble(m_sym, SYMBOL_ASK);
bool ok = m_trade.Buy(lots, m_sym, ask, NormalizeDouble(sl,d), NormalizeDouble(tp,d), m_comment);
if(!ok) Print("[Fimathe] BUY falhou: ", m_trade.ResultRetcode(), " - ", m_trade.ResultRetcodeDescription());
else Print("[Fimathe] BUY aberto | Lots=",lots," SL=",NormalizeDouble(sl,d)," TP=",NormalizeDouble(tp,d));
return ok;
}
bool Sell(double lots, double sl, double tp)
{
int d = (int)SymbolInfoInteger(m_sym, SYMBOL_DIGITS);
double bid = SymbolInfoDouble(m_sym, SYMBOL_BID);
bool ok = m_trade.Sell(lots, m_sym, bid, NormalizeDouble(sl,d), NormalizeDouble(tp,d), m_comment);
if(!ok) Print("[Fimathe] SELL falhou: ", m_trade.ResultRetcode(), " - ", m_trade.ResultRetcodeDescription());
else Print("[Fimathe] SELL aberto | Lots=",lots," SL=",NormalizeDouble(sl,d)," TP=",NormalizeDouble(tp,d));
return ok;
}
// Breakeven: move SL para o preço de entrada após X% de lucro no saldo
void DoBreakEven(double actPct)
{
double bal = m_acc.Balance();
if(bal <= 0) return;
int d = (int)SymbolInfoInteger(m_sym, SYMBOL_DIGITS);
double spread = (double)SymbolInfoInteger(m_sym, SYMBOL_SPREAD) * SymbolInfoDouble(m_sym, SYMBOL_POINT);
for(int i = PositionsTotal()-1; i >= 0; i--)
{
if(!m_pos.SelectByIndex(i)) continue;
if(m_pos.Symbol() != m_sym || m_pos.Magic() != m_magic) continue;
if((m_pos.Profit() / bal) * 100.0 < actPct) continue;
double op = m_pos.PriceOpen();
double csl = m_pos.StopLoss();
if(m_pos.PositionType() == POSITION_TYPE_BUY)
{
double nsl = NormalizeDouble(op + spread, d);
if(nsl > csl)
{
if(m_trade.PositionModify(m_pos.Ticket(), nsl, m_pos.TakeProfit()))
Print("[Fimathe] Breakeven BUY ativado | SL=", nsl);
}
}
else
{
double nsl = NormalizeDouble(op - spread, d);
if(csl == 0.0 || nsl < csl)
{
if(m_trade.PositionModify(m_pos.Ticket(), nsl, m_pos.TakeProfit()))
Print("[Fimathe] Breakeven SELL ativado | SL=", nsl);
}
}
}
}
// Trailing stop: segue o preço após X% de lucro no saldo
void DoTrailing(double actPct, double stepPts)
{
double bal = m_acc.Balance();
if(bal <= 0) return;
double pt = SymbolInfoDouble(m_sym, SYMBOL_POINT);
int d = (int)SymbolInfoInteger(m_sym, SYMBOL_DIGITS);
double step = stepPts * pt;
for(int i = PositionsTotal()-1; i >= 0; i--)
{
if(!m_pos.SelectByIndex(i)) continue;
if(m_pos.Symbol() != m_sym || m_pos.Magic() != m_magic) continue;
if((m_pos.Profit() / bal) * 100.0 < actPct) continue;
double csl = m_pos.StopLoss();
if(m_pos.PositionType() == POSITION_TYPE_BUY)
{
double bid = SymbolInfoDouble(m_sym, SYMBOL_BID);
double nsl = NormalizeDouble(bid - step, d);
if(nsl > csl) m_trade.PositionModify(m_pos.Ticket(), nsl, m_pos.TakeProfit());
}
else
{
double ask = SymbolInfoDouble(m_sym, SYMBOL_ASK);
double nsl = NormalizeDouble(ask + step, d);
if(csl == 0.0 || nsl < csl) m_trade.PositionModify(m_pos.Ticket(), nsl, m_pos.TakeProfit());
}
}
}
void CloseAll()
{
for(int i = PositionsTotal()-1; i >= 0; i--)
{
if(!m_pos.SelectByIndex(i)) continue;
if(m_pos.Symbol() == m_sym && m_pos.Magic() == m_magic)
m_trade.PositionClose(m_pos.Ticket());
}
}
};
//=============================================================================
// VARIÁVEIS GLOBAIS
//=============================================================================
CManager* g_mgr = NULL;
CAccountInfo g_acc;
int g_hATR = INVALID_HANDLE;
int g_hEMA20T = INVALID_HANDLE; // EMA 20 no TF de tendência
int g_hEMA50T = INVALID_HANDLE; // EMA 50 no TF de tendência
int g_hEMA200T = INVALID_HANDLE; // EMA 200 no TF de tendência
datetime g_lastBar = 0;
int g_digits = 5;
double g_point = 0.00001;
//=============================================================================
// UTILITÁRIOS
//=============================================================================
bool IsNewBar()
{
datetime t[];
ArraySetAsSeries(t, true);
if(CopyTime(_Symbol, OperTF, 0, 1, t) < 1) return false;
if(t[0] == g_lastBar) return false;
g_lastBar = t[0];
return true;
}
bool InTradingHours()
{
if(!UseTimeFilter) return true;
MqlDateTime dt;
TimeToStruct(TimeCurrent(), dt);
int now = dt.hour * 60 + dt.min;
int start = StartHour * 60 + StartMin;
int end = EndHour * 60 + EndMin;
if(start <= end) return (now >= start && now < end);
return (now >= start || now < end);
}
bool PastEndTime()
{
if(!CloseAtEnd) return false;
MqlDateTime dt;
TimeToStruct(TimeCurrent(), dt);
int now = dt.hour * 60 + dt.min;
int end = EndHour * 60 + EndMin;
return (now >= end);
}
double NormLots(double lots)
{
double mn = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double mx = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double st = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
if(st <= 0) st = 0.01;
lots = MathFloor(lots / st) * st;
return NormalizeDouble(MathMax(mn, MathMin(mx, lots)), 2);
}
// Calcula lote por risco percentual sobre o saldo
double CalcLots(double slDist)
{
if(!UseMoneyMgmt) return NormLots(LotSize);
if(slDist <= 0) return NormLots(LotSize);
double bal = g_acc.Balance();
double risk = bal * (RiskPercent / 100.0);
double ts = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
double tv = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
if(ts <= 0 || tv <= 0) return NormLots(LotSize);
double lpl = (slDist / ts) * tv; // perda por lote
if(lpl <= 0) return NormLots(LotSize);
return NormLots(risk / lpl);
}
// Calcula Take Profit baseado em % do saldo para o lote especificado
double CalcTP(double entry, bool buy, double lots)
{
if(lots <= 0) return 0;
double bal = g_acc.Balance();
double target = bal * (TargetPct / 100.0);
double ts = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
double tv = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
if(ts <= 0 || tv <= 0) return 0;
double tpDist = (target / (lots * tv)) * ts;
return NormalizeDouble(buy ? entry + tpDist : entry - tpDist, g_digits);
}
double GetATR()
{
double buf[];
ArraySetAsSeries(buf, true);
if(CopyBuffer(g_hATR, 0, 1, 1, buf) < 1) return 0;
return buf[0];
}
//=============================================================================
// IDENTIFICAÇÃO DE TENDÊNCIA (TF Superior)
//=============================================================================
/*
Critérios combinados:
1. Estrutura de topos/fundos (Higher High + Higher Low = alta; Lower High + Lower Low = baixa)
2. Alinhamento das EMAs 20/50/200
Tendência confirmada quando ambos os critérios concordam.
Se apenas estrutura ou apenas EMAs disponíveis, usa o que está disponível.
*/
ENUM_FTREND IdentifyTrend()
{
// --- EMAs ---
double ema20[], ema50[], ema200[];
ArraySetAsSeries(ema20, true);
ArraySetAsSeries(ema50, true);
ArraySetAsSeries(ema200, true);
bool emasOk = (CopyBuffer(g_hEMA20T, 0, 0, 3, ema20) >= 3 &&
CopyBuffer(g_hEMA50T, 0, 0, 3, ema50) >= 3 &&
CopyBuffer(g_hEMA200T, 0, 0, 3, ema200) >= 3);
// --- Dados OHLC do TF de tendência ---
MqlRates tr[];
ArraySetAsSeries(tr, true);
int needed = StructBars + 10;
bool ratesOk = (CopyRates(_Symbol, TrendTF, 0, needed, tr) >= needed);
// --- Análise de estrutura (topos e fundos locais) ---
double h1 = 0, h2 = 0, l1 = DBL_MAX, l2 = DBL_MAX;
int hc = 0, lc = 0;
if(ratesOk)
{
for(int i = 2; i < StructBars - 2; i++)
{
if(hc < 2)
{
if(tr[i].high > tr[i-1].high && tr[i].high > tr[i+1].high &&
tr[i].high > tr[i-2].high && tr[i].high > tr[i+2].high)
{
if(hc == 0) h1 = tr[i].high;
else h2 = tr[i].high;
hc++;
}
}
if(lc < 2)
{
if(tr[i].low < tr[i-1].low && tr[i].low < tr[i+1].low &&
tr[i].low < tr[i-2].low && tr[i].low < tr[i+2].low)
{
if(lc == 0) l1 = tr[i].low;
else l2 = tr[i].low;
lc++;
}
}
if(hc >= 2 && lc >= 2) break;
}
}
bool structUp = (hc >= 2 && lc >= 2 && h1 > h2 && l1 > l2);
bool structDown = (hc >= 2 && lc >= 2 && h1 < h2 && l1 < l2);
bool emaUp = emasOk && (ema20[0] > ema50[0] && ema50[0] > ema200[0]);
bool emaDown = emasOk && (ema20[0] < ema50[0] && ema50[0] < ema200[0]);
// Confirmação forte (estrutura + EMA)
if(structUp && emaUp) return FT_UP;
if(structDown && emaDown) return FT_DOWN;
// Confirmação parcial
if(structUp && !structDown) return FT_UP;
if(structDown && !structUp) return FT_DOWN;
if(emaUp && !emaDown) return FT_UP;
if(emaDown && !emaUp) return FT_DOWN;
return FT_NEUTRAL;
}
//=============================================================================
// DETECÇÃO DO SETUP FIMATHE (Pullback → Fibonacci → Confirmação)
//=============================================================================
/*
COMPRA (uptrend):
- Localizar swing high e swing low recentes no TF operacional
- O swing high deve ser MAIS RECENTE que o swing low (impulso de alta concluído)
- Preço recuou do topo e está na zona Fibonacci (0.6180.786 do range)
- Vela confirmação: bullish, corpo >= MinBodyPts, fechando acima da mínima da zona
- SL: abaixo do swing low + buffer | TP: % do saldo
VENDA (downtrend):
- O swing low deve ser MAIS RECENTE que o swing high (impulso de baixa concluído)
- Preço recuperou do fundo e está na zona Fibonacci (0.6180.786 do range)
- Vela confirmação: bearish, corpo >= MinBodyPts, fechando abaixo do máximo da zona
- SL: acima do swing high + buffer | TP: % do saldo
*/
SSetup DetectSetup(ENUM_FTREND trend)
{
SSetup s;
ZeroMemory(s);
s.valid = false;
if(trend == FT_NEUTRAL) return s;
// Barras do TF operacional (índice 0 = barra em formação, excluída)
MqlRates r[];
ArraySetAsSeries(r, true);
if(CopyRates(_Symbol, OperTF, 0, StructBars + 5, r) < StructBars + 5) return s;
// Localizar swing high e swing low no lookback (barras 1..StructBars)
double swH = 0, swL = DBL_MAX;
int iH = 0, iL = 0;
for(int i = 1; i <= StructBars; i++)
{
if(r[i].high > swH) { swH = r[i].high; iH = i; }
if(r[i].low < swL) { swL = r[i].low; iL = i; }
}
if(swH <= 0 || swL >= DBL_MAX || swH <= swL) return s;
double range = swH - swL;
// Exigir range mínimo de 50 pontos para evitar noise
if(range < 50.0 * g_point) return s;
// Níveis Fibonacci
double fib618_buy = swH - range * FibLvl1; // zona suporte Fib para compra
double fib786_buy = swH - range * FibLvl2;
double fib618_sel = swL + range * FibLvl1; // zona resistência Fib para venda
double fib786_sel = swL + range * FibLvl2;
double tol = range * FibTolerance;
// Vela de confirmação = barra 1 (último candle fechado)
double cClose = r[1].close;
double cOpen = r[1].open;
double body = MathAbs(cClose - cOpen);
bool okBody = (!NeedBodyClose || body >= (double)MinBodyPts * g_point);
double atr = GetATR();
//--- SETUP DE COMPRA ---
// iH < iL: swing high mais recente → impulso de alta concluído, agora em correção
if(trend == FT_UP && iH < iL && iH >= 2)
{
bool inZone = (cClose >= fib786_buy - tol && cClose <= fib618_buy + tol);
bool bullish = (cClose > cOpen); // vela bullish
bool turning = (cClose > r[2].close); // preço retomando a subida
if(inZone && bullish && okBody && turning)
{
s.valid = true;
s.isBuy = true;
s.swHigh = swH;
s.swLow = swL;
s.fib618 = fib618_buy;
s.fib786 = fib786_buy;
s.entry = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
s.sl = UseATR && atr > 0
? s.entry - atr * ATRMult
: swL - SLBuffer * g_point;
s.sl = NormalizeDouble(s.sl, g_digits);
s.lots = CalcLots(s.entry - s.sl);
s.tp = CalcTP(s.entry, true, s.lots);
}
}
//--- SETUP DE VENDA ---
// iL < iH: swing low mais recente → impulso de baixa concluído, agora em correção
if(trend == FT_DOWN && iL < iH && iL >= 2)
{
bool inZone = (cClose <= fib786_sel + tol && cClose >= fib618_sel - tol);
bool bearish = (cClose < cOpen);
bool turning = (cClose < r[2].close);
if(inZone && bearish && okBody && turning)
{
s.valid = true;
s.isBuy = false;
s.swHigh = swH;
s.swLow = swL;
s.fib618 = fib618_sel;
s.fib786 = fib786_sel;
s.entry = SymbolInfoDouble(_Symbol, SYMBOL_BID);
s.sl = UseATR && atr > 0
? s.entry + atr * ATRMult
: swH + SLBuffer * g_point;
s.sl = NormalizeDouble(s.sl, g_digits);
s.lots = CalcLots(s.sl - s.entry);
s.tp = CalcTP(s.entry, false, s.lots);
}
}
return s;
}
//=============================================================================
// EXECUÇÃO DO SETUP
//=============================================================================
void ExecuteSetup(SSetup &s)
{
if(!s.valid || s.lots <= 0) return;
// Verificar distância mínima de stop exigida pelo broker
double minStop = (double)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL)
* SymbolInfoDouble(_Symbol, SYMBOL_POINT);
if(s.isBuy)
{
if(g_mgr.HasPos(POSITION_TYPE_BUY))
{ Print("[Fimathe] Já existe BUY aberto. Ignorando."); return; }
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if(ask - s.sl < minStop)
{ Print("[Fimathe] SL BUY muito próximo. Ignorando."); return; }
s.entry = ask;
s.tp = CalcTP(ask, true, s.lots);
g_mgr.Buy(s.lots, s.sl, s.tp);
}
else
{
if(g_mgr.HasPos(POSITION_TYPE_SELL))
{ Print("[Fimathe] Já existe SELL aberto. Ignorando."); return; }
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(s.sl - bid < minStop)
{ Print("[Fimathe] SL SELL muito próximo. Ignorando."); return; }
s.entry = bid;
s.tp = CalcTP(bid, false, s.lots);
g_mgr.Sell(s.lots, s.sl, s.tp);
}
}
//=============================================================================
// OnInit
//=============================================================================
int OnInit()
{
if(StructBars < 10)
{ Alert("[Fimathe] StructBars deve ser >= 10!"); return INIT_PARAMETERS_INCORRECT; }
if(RiskPercent <= 0 || RiskPercent > 20)
{ Alert("[Fimathe] RiskPercent deve estar entre 0.1 e 20!"); return INIT_PARAMETERS_INCORRECT; }
if(TargetPct <= 0)
{ Alert("[Fimathe] TargetPct deve ser > 0!"); return INIT_PARAMETERS_INCORRECT; }
g_digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
g_point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
g_mgr = new CManager(MagicNumber, _Symbol, EAComment);
if(g_mgr == NULL) { Print("[Fimathe] Falha ao criar CManager!"); return INIT_FAILED; }
g_hEMA20T = iMA(_Symbol, TrendTF, 20, 0, MODE_EMA, PRICE_CLOSE);
g_hEMA50T = iMA(_Symbol, TrendTF, 50, 0, MODE_EMA, PRICE_CLOSE);
g_hEMA200T = iMA(_Symbol, TrendTF, 200, 0, MODE_EMA, PRICE_CLOSE);
g_hATR = iATR(_Symbol, OperTF, ATRPeriod);
if(g_hEMA20T == INVALID_HANDLE || g_hEMA50T == INVALID_HANDLE ||
g_hEMA200T == INVALID_HANDLE || g_hATR == INVALID_HANDLE)
{ Print("[Fimathe] Falha ao criar indicadores!"); return INIT_FAILED; }
Print("════════════════════════════════════════════════");
Print(" Fimathe Trend EA — Iniciado com sucesso!");
Print(" Símbolo : ", _Symbol);
Print(" TF Tendência : ", EnumToString(TrendTF));
Print(" TF Operac. : ", EnumToString(OperTF));
Print(" Gestão Cap. : ", UseMoneyMgmt
? "Sim — Risco=" + DoubleToString(RiskPercent,1) + "% / Alvo=" + DoubleToString(TargetPct,1) + "%"
: "Não — Lote fixo=" + DoubleToString(LotSize,2));
Print(" Fib Levels : ", FibLvl1, " / ", FibLvl2);
Print(" Magic : ", MagicNumber);
Print("════════════════════════════════════════════════");
return INIT_SUCCEEDED;
}
//=============================================================================
// OnDeinit
//=============================================================================
void OnDeinit(const int reason)
{
if(CloseAtEnd && g_mgr != NULL) g_mgr.CloseAll();
if(g_hEMA20T != INVALID_HANDLE) IndicatorRelease(g_hEMA20T);
if(g_hEMA50T != INVALID_HANDLE) IndicatorRelease(g_hEMA50T);
if(g_hEMA200T != INVALID_HANDLE) IndicatorRelease(g_hEMA200T);
if(g_hATR != INVALID_HANDLE) IndicatorRelease(g_hATR);
if(g_mgr != NULL) { delete g_mgr; g_mgr = NULL; }
Comment("");
Print("[Fimathe] EA desativado. Razão: ", reason);
}
//=============================================================================
// OnTick — Lógica principal
//=============================================================================
void OnTick()
{
if(g_mgr == NULL) return;
// Gestão contínua a cada tick (trailing e breakeven)
if(UseBreakEven) g_mgr.DoBreakEven(BEPct);
if(UseTrailing) g_mgr.DoTrailing(TSPct, TSPoints);
// Fechar ao atingir hora fim
if(PastEndTime())
{
g_mgr.CloseAll();
Comment("Fimathe Trend EA | Horário encerrado — posições fechadas");
return;
}
// Processar apenas no fechamento de cada nova barra
if(!IsNewBar()) return;
// Verificar janela de horário
if(!InTradingHours())
{
Comment("Fimathe Trend EA | Fora do horário | ",
StartHour, ":", StringFormat("%02d", StartMin),
" — ", EndHour, ":", StringFormat("%02d", EndMin));
return;
}
// 1) Identificar tendência principal no TF superior
ENUM_FTREND trend = IdentifyTrend();
string tStr = (trend == FT_UP) ? "ALTA ▲" :
(trend == FT_DOWN) ? "BAIXA ▼" : "NEUTRA ●";
if(trend == FT_NEUTRAL)
{
Comment("Fimathe Trend EA | Tendência: NEUTRA — aguardando definição");
return;
}
// 2) Se há posição aberta, apenas gerir (trailing/BE já aplicados acima)
if(g_mgr.HasAny())
{
Comment("Fimathe Trend EA | Tendência: ", tStr, " | Posição aberta — gerenciando");
return;
}
// 3) Detectar setup Fimathe (pullback para zona Fibonacci + confirmação)
SSetup setup = DetectSetup(trend);
if(setup.valid)
{
string dir = setup.isBuy ? "COMPRA ▲" : "VENDA ▼";
Print("[Fimathe] Setup ", dir, " | SwH=", setup.swHigh, " SwL=", setup.swLow,
" | Fib618=", setup.fib618, " Fib786=", setup.fib786,
" | Lots=", setup.lots, " SL=", setup.sl, " TP=", setup.tp);
Comment("Fimathe Trend EA | Tendência: ", tStr, " | Setup ", dir,
" | Lots=", DoubleToString(setup.lots,2),
" SL=", DoubleToString(setup.sl, g_digits),
" TP=", DoubleToString(setup.tp, g_digits));
ExecuteSetup(setup);
}
else
{
Comment("Fimathe Trend EA | Tendência: ", tStr,
" | Aguardando pullback para zona Fibonacci (",
DoubleToString(FibLvl1,3), " / ", DoubleToString(FibLvl2,3), ")...");
}
}
//+------------------------------------------------------------------+
//| FIM — Fimathe Trend EA v1.00 |
//+------------------------------------------------------------------+