| //+------------------------------------------------------------------+
|
| //| Trend + Pullback EA (Default Version) |
|
| //| Works on NASDAQ100 & GOLD |
|
| //+------------------------------------------------------------------+
|
| #property strict
|
|
|
| input int EMA_Fast = 20;
|
| input int EMA_Trend = 200;
|
| input double RiskPercent = 1.0;
|
| input double RR = 2.0;
|
|
|
| //--- Handles
|
| int fastEMA, trendEMA;
|
|
|
| //+------------------------------------------------------------------+
|
| int OnInit()
|
| {
|
| fastEMA = iMA(_Symbol, _Period, EMA_Fast, 0, MODE_EMA, PRICE_CLOSE);
|
| trendEMA = iMA(_Symbol, _Period, EMA_Trend, 0, MODE_EMA, PRICE_CLOSE);
|
|
|
| if (fastEMA == INVALID_HANDLE || trendEMA == INVALID_HANDLE)
|
| {
|
| Print("Error creating indicators.");
|
| return INIT_FAILED;
|
| }
|
|
|
| return INIT_SUCCEEDED;
|
| }
|
| //+------------------------------------------------------------------+
|
|
|
| void OnTick()
|
| {
|
| if(!IsNewCandle()) return;
|
|
|
| double fastEMA_val = CopyBufferVal(fastEMA, 0);
|
| double trendEMA_val = CopyBufferVal(trendEMA, 0);
|
|
|
| double prevHigh = iHigh(_Symbol, _Period, 1);
|
| double prevLow = iLow(_Symbol, _Period, 1);
|
|
|
| double close1 = iClose(_Symbol, _Period, 1); // previous candle close
|
| double open1 = iOpen (_Symbol, _Period, 1); // previous candle open
|
| double low1 = iLow (_Symbol, _Period, 1);
|
| double high1 = iHigh (_Symbol, _Period, 1);
|
|
|
| // Trend Filters
|
| bool upTrend = (close1 > trendEMA_val);
|
| bool downTrend = (close1 < trendEMA_val);
|
|
|
| // Pullback Check = price touches EMA20
|
| bool touchedFastEMA = (low1 <= fastEMA_val && high1 >= fastEMA_val);
|
|
|
| // Engulfing Conditions
|
| bool bullishEngulf =
|
| (close1 > open1) &&
|
| (close1 > iOpen(_Symbol, _Period, 2)) &&
|
| (open1 < iClose(_Symbol, _Period, 2));
|
|
|
| bool bearishEngulf =
|
| (close1 < open1) &&
|
| (close1 < iOpen(_Symbol, _Period, 2)) &&
|
| (open1 > iClose(_Symbol, _Period, 2));
|
|
|
| // BUY CONDITIONS
|
| if (upTrend && touchedFastEMA && bullishEngulf)
|
| {
|
| double sl = prevLow; // swing low
|
| double entry = close1;
|
| double tp = entry + (entry - sl) * RR; // RR = 2
|
|
|
| OpenTrade(ORDER_TYPE_BUY, entry, sl, tp);
|
| }
|
|
|
| // SELL CONDITIONS
|
| if (downTrend && touchedFastEMA && bearishEngulf)
|
| {
|
| double sl = prevHigh; // swing high
|
| double entry = close1;
|
| double tp = entry - (sl - entry) * RR;
|
|
|
| OpenTrade(ORDER_TYPE_SELL, entry, sl, tp);
|
| }
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| // Risk-based Lot Calculation
|
| //+------------------------------------------------------------------+
|
| double LotByRisk(double slPrice, ENUM_ORDER_TYPE type)
|
| {
|
| double riskMoney = AccountBalance() * (RiskPercent / 100.0);
|
| double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
|
| double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
|
|
|
| double slDistance = MathAbs(slPrice - SymbolInfoDouble(_Symbol, SYMBOL_BID));
|
| double costPerLot = slDistance / tickSize * tickValue;
|
|
|
| if (costPerLot <= 0) return 0.1;
|
| return NormalizeDouble(riskMoney / costPerLot, 2);
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| void OpenTrade(ENUM_ORDER_TYPE type, double price, double sl, double tp)
|
| {
|
| if (PositionsTotal() > 0) return; // one trade at a time
|
|
|
| double lots = LotByRisk(sl, type);
|
|
|
| MqlTradeRequest req;
|
| MqlTradeResult res;
|
| ZeroMemory(req);
|
|
|
| req.action = TRADE_ACTION_DEAL;
|
| req.symbol = _Symbol;
|
| req.volume = lots;
|
| req.type = type;
|
| req.price = (type == ORDER_TYPE_BUY ? SymbolInfoDouble(_Symbol, SYMBOL_ASK)
|
| : SymbolInfoDouble(_Symbol, SYMBOL_BID));
|
| req.sl = sl;
|
| req.tp = tp;
|
| req.magic = 12345;
|
|
|
| OrderSend(req, res);
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| bool IsNewCandle()
|
| {
|
| static datetime lastTime = 0;
|
| datetime current = iTime(_Symbol, _Period, 0);
|
|
|
| if (current != lastTime)
|
| {
|
| lastTime = current;
|
| return true;
|
| }
|
| return false;
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| double CopyBufferVal(int handle, int index)
|
| {
|
| double val[];
|
| if(CopyBuffer(handle, 0, index, 1, val) < 1)
|
| return EMPTY_VALUE;
|
| return val[0];
|
| }
|
| //+------------------------------------------------------------------+
|