Files
mt5_news_eas/InstitutionalTickHybridNewsFilter.mq5
T

503 lines
12 KiB
Plaintext

//+------------------------------------------------------------------+
//| InstitutionalTickHybridEA.mq5 |
//| FIXED VERSION + HIGH IMPACT NEWS FILTER |
//+------------------------------------------------------------------+
#property strict
#property version "1.20"
#include <Trade/Trade.mqh>
CTrade trade;
//====================================================
// INPUTS
//====================================================
input ulong MagicNumber = 880001;
input double ForexLot = 0.01;
input double GoldLot = 0.01;
input int EMAFastPeriod = 20;
input int EMATrendPeriod = 200;
input int ATRPeriod = 14;
input double ATRMultiplierSL = 2.0;
input double ATRTrailingMultiplier = 1.5;
input int TickBufferSize = 30;
input double ZScoreThreshold = 1.3;
input int CooldownSeconds = 10;
input int MaxPositionsPerSymbol = 3;
input double MaxSpreadPoints = 40;
input double MinATRPointsForex = 15;
input double MinATRPointsGold = 150;
input double ProfitTargetPerLot = 20.0;
input bool UseBreakeven = true;
input double BreakevenOffsetPoints = 10;
input bool EnableDebug = true;
//====================================================
// NEWS FILTER
//====================================================
input bool UseNewsFilter = true;
input int NewsPauseBeforeMin = 60;
input int NewsPauseAfterMin = 60;
//====================================================
// GLOBALS
//====================================================
double TickBuffer[];
datetime LastTradeTime = 0;
int emaFastHandle;
int emaTrendHandle;
int atrHandle;
//====================================================
// INIT
//====================================================
int OnInit()
{
ArrayResize(TickBuffer, TickBufferSize);
emaFastHandle = iMA(_Symbol,_Period,EMAFastPeriod,0,MODE_EMA,PRICE_CLOSE);
emaTrendHandle = iMA(_Symbol,_Period,EMATrendPeriod,0,MODE_EMA,PRICE_CLOSE);
atrHandle = iATR(_Symbol,_Period,ATRPeriod);
if(emaFastHandle==INVALID_HANDLE || emaTrendHandle==INVALID_HANDLE || atrHandle==INVALID_HANDLE)
{
Print("Indicator init failed");
return INIT_FAILED;
}
Print("EA WITH NEWS FILTER INITIALIZED");
return INIT_SUCCEEDED;
}
//====================================================
// DEINIT
//====================================================
void OnDeinit(const int reason)
{
IndicatorRelease(emaFastHandle);
IndicatorRelease(emaTrendHandle);
IndicatorRelease(atrHandle);
}
//====================================================
// ON TICK
//====================================================
void OnTick()
{
UpdateTickBuffer();
//================================================
// HIGH IMPACT NEWS FILTER
//================================================
if(UseNewsFilter && IsHighImpactNewsTime())
{
CloseAllPositions();
Debug("Trading paused due to HIGH IMPACT NEWS");
return;
}
ManagePositions();
if(!CanTrade())
return;
if(CountPositionsBySymbol() >= MaxPositionsPerSymbol)
return;
double z = CalculateZScore();
double emaFast = GetEMA(emaFastHandle);
double emaTrend = GetEMA(emaTrendHandle);
double atr = GetATR();
double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
bool bullish = bid > emaTrend;
bool bearish = bid < emaTrend;
bool reversalBuy = (z < -1.0);
bool reversalSell = (z > 1.0);
if(bullish && reversalBuy)
OpenBuy(atr);
if(bearish && reversalSell)
OpenSell(atr);
}
//====================================================
// NEWS FILTER FUNCTION
//====================================================
//====================================================
// NEWS FILTER FUNCTION
//====================================================
bool IsHighImpactNewsTime()
{
MqlCalendarValue values[];
datetime now = TimeCurrent();
datetime from = now - 60;
datetime to = now + (NewsPauseBeforeMin * 60);
int count = CalendarValueHistory(values, from, to);
if(count <= 0)
return false;
string symbolCurrency1 = StringSubstr(_Symbol,0,3);
string symbolCurrency2 = StringSubstr(_Symbol,3,3);
for(int i=0; i<count; i++)
{
MqlCalendarEvent event;
if(!CalendarEventById(values[i].event_id,event))
continue;
// HIGH IMPACT ONLY
if(event.importance != CALENDAR_IMPORTANCE_HIGH)
continue;
//================================================
// FIXED CURRENCY ACCESS
//================================================
MqlCalendarCountry country;
if(!CalendarCountryById(event.country_id,country))
continue;
string currency = country.currency;
bool relevant = false;
// GOLD -> USD NEWS ONLY
if(StringFind(_Symbol,"XAU") >= 0 ||
StringFind(_Symbol,"GOLD") >= 0)
{
if(currency == "USD")
relevant = true;
}
else
{
if(currency == symbolCurrency1 ||
currency == symbolCurrency2)
relevant = true;
}
if(!relevant)
continue;
datetime eventTime = values[i].time;
datetime blockStart =
eventTime - (NewsPauseBeforeMin * 60);
datetime blockEnd =
eventTime + (NewsPauseAfterMin * 60);
if(now >= blockStart && now <= blockEnd)
{
Debug("High impact news detected");
return true;
}
}
return false;
}
//====================================================
// CLOSE ALL POSITIONS
//====================================================
void CloseAllPositions()
{
for(int i=PositionsTotal()-1;i>=0;i--)
{
ulong ticket=PositionGetTicket(i);
if(ticket==0)
continue;
if(!PositionSelectByTicket(ticket))
continue;
if(PositionGetInteger(POSITION_MAGIC)!=MagicNumber)
continue;
if(PositionGetString(POSITION_SYMBOL)!=_Symbol)
continue;
trade.PositionClose(ticket);
}
}
//====================================================
// UPDATE TICKS
//====================================================
void UpdateTickBuffer()
{
for(int i=TickBufferSize-1;i>0;i--)
TickBuffer[i]=TickBuffer[i-1];
TickBuffer[0]=SymbolInfoDouble(_Symbol,SYMBOL_BID);
}
//====================================================
// Z SCORE
//====================================================
double CalculateZScore()
{
double sum=0;
for(int i=0;i<TickBufferSize;i++)
sum+=TickBuffer[i];
double mean=sum/TickBufferSize;
double var=0;
for(int i=0;i<TickBufferSize;i++)
var += MathPow(TickBuffer[i]-mean,2);
var/=TickBufferSize;
double std=MathSqrt(var);
if(std==0)
return 0;
return (TickBuffer[0]-mean)/std;
}
//====================================================
// INDICATORS
//====================================================
double GetEMA(int handle)
{
double buf[];
if(CopyBuffer(handle,0,0,1,buf)<=0)
return 0;
return buf[0];
}
double GetATR()
{
double buf[];
if(CopyBuffer(atrHandle,0,0,1,buf)<=0)
return 0;
return buf[0];
}
//====================================================
// CAN TRADE
//====================================================
bool CanTrade()
{
double spread =
(SymbolInfoDouble(_Symbol,SYMBOL_ASK)
-SymbolInfoDouble(_Symbol,SYMBOL_BID))/_Point;
if(spread > MaxSpreadPoints)
{
Debug("Spread too high");
return false;
}
double atrPoints = GetATR()/_Point;
string sym=_Symbol;
StringToUpper(sym);
double minATR = MinATRPointsForex;
if(StringFind(sym,"XAU")>=0 || StringFind(sym,"GOLD")>=0)
minATR = MinATRPointsGold;
if(atrPoints < minATR)
{
Debug("ATR too low: " + DoubleToString(atrPoints,1));
return false;
}
if(TimeCurrent()-LastTradeTime < CooldownSeconds)
return false;
return true;
}
//====================================================
// OPEN BUY
//====================================================
void OpenBuy(double atr)
{
double ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
double sl=ask-(atr*ATRMultiplierSL);
AdjustStopsForBroker(sl,true);
double lot=GetLotSize();
trade.SetExpertMagicNumber(MagicNumber);
if(trade.Buy(lot,_Symbol,ask,sl,0,"BUY WITH NEWS FILTER"))
LastTradeTime=TimeCurrent();
}
//====================================================
// OPEN SELL
//====================================================
void OpenSell(double atr)
{
double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);
double sl=bid+(atr*ATRMultiplierSL);
AdjustStopsForBroker(sl,false);
double lot=GetLotSize();
trade.SetExpertMagicNumber(MagicNumber);
if(trade.Sell(lot,_Symbol,bid,sl,0,"SELL WITH NEWS FILTER"))
LastTradeTime=TimeCurrent();
}
//====================================================
// LOT SIZE
//====================================================
double GetLotSize()
{
string s=_Symbol;
StringToUpper(s);
if(StringFind(s,"XAU")>=0 || StringFind(s,"GOLD")>=0)
return GoldLot;
return ForexLot;
}
//====================================================
// POSITION COUNT
//====================================================
int CountPositionsBySymbol()
{
int c=0;
for(int i=PositionsTotal()-1;i>=0;i--)
{
ulong t=PositionGetTicket(i);
if(t==0)
continue;
if(!PositionSelectByTicket(t))
continue;
if(PositionGetInteger(POSITION_MAGIC)!=MagicNumber)
continue;
if(PositionGetString(POSITION_SYMBOL)!=_Symbol)
continue;
c++;
}
return c;
}
//====================================================
// POSITION MANAGEMENT
//====================================================
void ManagePositions()
{
for(int i=PositionsTotal()-1;i>=0;i--)
{
ulong t=PositionGetTicket(i);
if(t==0)
continue;
if(!PositionSelectByTicket(t))
continue;
if(PositionGetInteger(POSITION_MAGIC)!=MagicNumber)
continue;
if(PositionGetString(POSITION_SYMBOL)!=_Symbol)
continue;
double vol=PositionGetDouble(POSITION_VOLUME);
double sl=PositionGetDouble(POSITION_SL);
double profit=PositionGetDouble(POSITION_PROFIT);
double atr=GetATR();
double target=vol*ProfitTargetPerLot;
if(profit>=target)
{
trade.PositionClose(t);
continue;
}
ENUM_POSITION_TYPE type=
(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(type==POSITION_TYPE_BUY)
{
double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);
double newSL=bid-(atr*ATRTrailingMultiplier);
if(newSL>sl)
trade.PositionModify(t,newSL,0);
}
if(type==POSITION_TYPE_SELL)
{
double ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
double newSL=ask+(atr*ATRTrailingMultiplier);
if(sl==0 || newSL<sl)
trade.PositionModify(t,newSL,0);
}
}
}
//====================================================
// BROKER SAFETY
//====================================================
void AdjustStopsForBroker(double &sl,bool buy)
{
double stop=
(double)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL)*_Point;
double freeze=
(double)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_FREEZE_LEVEL)*_Point;
double min=MathMax(stop,freeze);
double ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);
if(buy && (ask-sl)<min)
sl=ask-(min+10*_Point);
if(!buy && (sl-bid)<min)
sl=bid+(min+10*_Point);
}
//====================================================
// DEBUG
//====================================================
void Debug(string txt)
{
if(EnableDebug)
Print("[",_Symbol,"] ",txt);
}
//+------------------------------------------------------------------+