bc6f403b28
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>
762 lines
30 KiB
Plaintext
762 lines
30 KiB
Plaintext
//+------------------------------------------------------------------+
|
||
//| 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 : 08h–12h | Nova York : 13h–17h (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.618–0.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.618–0.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 |
|
||
//+------------------------------------------------------------------+
|