147 行
4.3 KiB
Text
147 行
4.3 KiB
Text
//+------------------------------------------------------------------+
| |||
//| 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];
| |||
}
| |||
//+------------------------------------------------------------------+
|