Add files via upload
This commit is contained in:
+83
@@ -0,0 +1,83 @@
|
||||
FROM python:3.11-slim-bookworm
|
||||
|
||||
USER root
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV DISPLAY=:1
|
||||
ENV WINEPREFIX=/root/.wine
|
||||
ENV WINEARCH=win64
|
||||
ENV WINEDEBUG=-all
|
||||
|
||||
RUN dpkg --add-architecture i386 && apt-get update && apt-get install -y --no-install-recommends \
|
||||
wine wine64 wine32:i386 winbind xvfb fluxbox x11vnc novnc websockify \
|
||||
wget curl procps cabextract unzip dos2unix xdotool \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN pip install --no-cache-dir mt5linux rpyc
|
||||
|
||||
RUN wget -q https://download.mql5.com/cdn/web/metaquotes.software.corp/mt5/mt5setup.exe \
|
||||
-O /root/mt5setup.exe
|
||||
|
||||
# Copy EA files
|
||||
COPY ["Volatility_Breakout_Pro_News_Filter.mq5", "/root/Volatility_Breakout_Pro_News_Filter.mq5"]
|
||||
COPY ["InstitutionalTickHybridNewsFilter.mq5", "/root/InstitutionalTickHybridNewsFilter.mq5"]
|
||||
COPY ["Tick_Reversion_Pro_NEWS_FILTER.mq5", "/root/Tick_Reversion_Pro_NEWS_FILTER.mq5"]
|
||||
|
||||
|
||||
|
||||
RUN cat > /entrypoint.sh <<EOF
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
rm -rf /tmp/.X*
|
||||
|
||||
Xvfb :1 -screen 0 1280x1024x24 -ac &
|
||||
sleep 2
|
||||
|
||||
fluxbox &
|
||||
|
||||
x11vnc -display :1 -forever -shared -nopw -rfbport 5900 &
|
||||
|
||||
websockify --web=/usr/share/novnc 8080 0.0.0.0:5900 &
|
||||
|
||||
wineboot --init
|
||||
sleep 5
|
||||
|
||||
MT5_EXE="/root/.wine/drive_c/Program Files/MetaTrader 5/terminal64.exe"
|
||||
|
||||
if [ ! -f "\$MT5_EXE" ]; then
|
||||
wine /root/mt5setup.exe /auto
|
||||
sleep 90
|
||||
fi
|
||||
|
||||
wine "\$MT5_EXE" &
|
||||
sleep 30
|
||||
|
||||
DATA_DIR=\$(find /root/.wine -type d -path "*MetaQuotes/Terminal/*/MQL5" | head -n 1)
|
||||
|
||||
if [ -z "\$DATA_DIR" ]; then
|
||||
DATA_DIR="/root/.wine/drive_c/Program Files/MetaTrader 5/MQL5"
|
||||
fi
|
||||
|
||||
mkdir -p "\$DATA_DIR/Experts"
|
||||
|
||||
cp "/root/Volatility_Breakout_Pro_News_Filter.mq5" "\$DATA_DIR/Experts/"
|
||||
cp "/root/InstitutionalTickHybridNewsFilter.mq5" "\$DATA_DIR/Experts/"
|
||||
cp "/root/Tick_Reversion_Pro_NEWS_FILTER.mq5" "\$DATA_DIR/Experts/"
|
||||
|
||||
|
||||
|
||||
echo "✅ Copied EAs to \$DATA_DIR/Experts/"
|
||||
|
||||
ls -la "\$DATA_DIR/Experts/"
|
||||
|
||||
python3 -m mt5linux --host 0.0.0.0 --port 8001 &
|
||||
|
||||
tail -f /dev/null
|
||||
EOF
|
||||
|
||||
RUN chmod +x /entrypoint.sh && dos2unix /entrypoint.sh
|
||||
|
||||
EXPOSE 8080 8001
|
||||
|
||||
CMD ["/bin/bash", "/entrypoint.sh"]
|
||||
@@ -0,0 +1,503 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,384 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Tick_Reversion_Pro.mq5 |
|
||||
//| WITH HIGH IMPACT NEWS FILTER |
|
||||
//+------------------------------------------------------------------+
|
||||
#property strict
|
||||
#include <Trade/Trade.mqh>
|
||||
|
||||
input double ForexLotSize=0.10;
|
||||
input double OtherLotSize=0.01;
|
||||
input int LookbackTicks=50;
|
||||
input double DeviationThreshold=1.5;
|
||||
input int ATRPeriod=14;
|
||||
input double ATRMultiplier=2.5;
|
||||
input double RiskReward=4.0;
|
||||
input int MaxPositionsPerSymbol=2;
|
||||
input bool UseEMA200=true;
|
||||
input double ProfitTargetPerLot=100.0;
|
||||
input ulong MagicNumber=777777;
|
||||
|
||||
//====================================================
|
||||
// NEWS FILTER
|
||||
//====================================================
|
||||
input bool UseNewsFilter=true;
|
||||
input int NewsPauseBeforeMin=60;
|
||||
input int NewsPauseAfterMin=60;
|
||||
|
||||
double TickBuffer[];
|
||||
int atrHandle;
|
||||
int emaHandle;
|
||||
CTrade trade;
|
||||
|
||||
//====================================================
|
||||
// LOT SIZE
|
||||
//====================================================
|
||||
double GetLotSize()
|
||||
{
|
||||
string s=_Symbol;
|
||||
|
||||
if(StringFind(s,"XAU")>=0 || StringFind(s,"XAG")>=0 ||
|
||||
StringFind(s,"BTC")>=0 || StringFind(s,"ETH")>=0 ||
|
||||
StringFind(s,"US30")>=0 || StringFind(s,"NAS")>=0 ||
|
||||
StringFind(s,"GER")>=0)
|
||||
return OtherLotSize;
|
||||
|
||||
return ForexLotSize;
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// POSITION COUNT
|
||||
//====================================================
|
||||
int CountPositionsForSymbol()
|
||||
{
|
||||
int count=0;
|
||||
|
||||
for(int i=PositionsTotal()-1;i>=0;i--)
|
||||
{
|
||||
ulong ticket=PositionGetTicket(i);
|
||||
|
||||
if(!PositionSelectByTicket(ticket))
|
||||
continue;
|
||||
|
||||
if(PositionGetInteger(POSITION_MAGIC)!=MagicNumber)
|
||||
continue;
|
||||
|
||||
if(PositionGetString(POSITION_SYMBOL)!=_Symbol)
|
||||
continue;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// TREND FILTER
|
||||
//====================================================
|
||||
bool TrendFilter(ENUM_ORDER_TYPE type)
|
||||
{
|
||||
if(!UseEMA200)
|
||||
return true;
|
||||
|
||||
double ema[1];
|
||||
|
||||
if(CopyBuffer(emaHandle,0,1,1,ema)<1)
|
||||
return false;
|
||||
|
||||
double close=iClose(_Symbol,_Period,1);
|
||||
|
||||
if(type==ORDER_TYPE_BUY)
|
||||
return close>ema[0];
|
||||
|
||||
return close<ema[0];
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// DYNAMIC STOP
|
||||
//====================================================
|
||||
double DynamicStopDistance()
|
||||
{
|
||||
double atr[1];
|
||||
|
||||
if(CopyBuffer(atrHandle,0,0,1,atr)<1)
|
||||
return 100*_Point;
|
||||
|
||||
double stopLevel=SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL)*_Point;
|
||||
double freezeLevel=SymbolInfoInteger(_Symbol,SYMBOL_TRADE_FREEZE_LEVEL)*_Point;
|
||||
double spread=SymbolInfoDouble(_Symbol,SYMBOL_ASK)-SymbolInfoDouble(_Symbol,SYMBOL_BID);
|
||||
|
||||
double brokerMin=MathMax(MathMax(stopLevel,freezeLevel),spread*10.0);
|
||||
|
||||
return MathMax(atr[0]*ATRMultiplier,brokerMin*3.0);
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// MANAGE PROFIT TARGET
|
||||
//====================================================
|
||||
void ManageProfitTarget()
|
||||
{
|
||||
for(int i=PositionsTotal()-1;i>=0;i--)
|
||||
{
|
||||
ulong ticket=PositionGetTicket(i);
|
||||
|
||||
if(!PositionSelectByTicket(ticket))
|
||||
continue;
|
||||
|
||||
if(PositionGetInteger(POSITION_MAGIC)!=MagicNumber)
|
||||
continue;
|
||||
|
||||
if(PositionGetString(POSITION_SYMBOL)!=_Symbol)
|
||||
continue;
|
||||
|
||||
double profit=PositionGetDouble(POSITION_PROFIT);
|
||||
double volume=PositionGetDouble(POSITION_VOLUME);
|
||||
|
||||
if(profit>=volume*ProfitTargetPerLot)
|
||||
trade.PositionClose(ticket);
|
||||
}
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// MANAGE TRAILING
|
||||
//====================================================
|
||||
void ManageTrailing()
|
||||
{
|
||||
double dist=DynamicStopDistance();
|
||||
|
||||
for(int i=PositionsTotal()-1;i>=0;i--)
|
||||
{
|
||||
ulong ticket=PositionGetTicket(i);
|
||||
|
||||
if(!PositionSelectByTicket(ticket))
|
||||
continue;
|
||||
|
||||
if(PositionGetInteger(POSITION_MAGIC)!=MagicNumber)
|
||||
continue;
|
||||
|
||||
if(PositionGetString(POSITION_SYMBOL)!=_Symbol)
|
||||
continue;
|
||||
|
||||
ENUM_POSITION_TYPE pos=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
|
||||
double sl=PositionGetDouble(POSITION_SL);
|
||||
double tp=PositionGetDouble(POSITION_TP);
|
||||
|
||||
double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);
|
||||
double ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
|
||||
|
||||
if(pos==POSITION_TYPE_BUY)
|
||||
{
|
||||
double newSL=NormalizeDouble(bid-dist,_Digits);
|
||||
|
||||
if(newSL>sl)
|
||||
trade.PositionModify(ticket,newSL,tp);
|
||||
}
|
||||
else
|
||||
{
|
||||
double newSL=NormalizeDouble(ask+dist,_Digits);
|
||||
|
||||
if(sl==0 || newSL<sl)
|
||||
trade.PositionModify(ticket,newSL,tp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// NEWS FILTER
|
||||
//====================================================
|
||||
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;
|
||||
|
||||
if(event.importance!=CALENDAR_IMPORTANCE_HIGH)
|
||||
continue;
|
||||
|
||||
MqlCalendarCountry country;
|
||||
|
||||
if(!CalendarCountryById(event.country_id,country))
|
||||
continue;
|
||||
|
||||
string currency=country.currency;
|
||||
|
||||
bool relevant=false;
|
||||
|
||||
// GOLD/SILVER/CRYPTO/INDICES -> USD NEWS
|
||||
if(StringFind(_Symbol,"XAU")>=0 ||
|
||||
StringFind(_Symbol,"XAG")>=0 ||
|
||||
StringFind(_Symbol,"BTC")>=0 ||
|
||||
StringFind(_Symbol,"ETH")>=0 ||
|
||||
StringFind(_Symbol,"US30")>=0 ||
|
||||
StringFind(_Symbol,"NAS")>=0 ||
|
||||
StringFind(_Symbol,"GER")>=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)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// EXECUTE DEAL
|
||||
//====================================================
|
||||
void ExecuteDeal(ENUM_ORDER_TYPE type)
|
||||
{
|
||||
double dist=DynamicStopDistance();
|
||||
|
||||
double price=(type==ORDER_TYPE_BUY)
|
||||
? SymbolInfoDouble(_Symbol,SYMBOL_ASK)
|
||||
: SymbolInfoDouble(_Symbol,SYMBOL_BID);
|
||||
|
||||
double sl=(type==ORDER_TYPE_BUY) ? price-dist : price+dist;
|
||||
double tp=(type==ORDER_TYPE_BUY) ? price+dist*RiskReward : price-dist*RiskReward;
|
||||
|
||||
trade.PositionOpen(
|
||||
_Symbol,
|
||||
type,
|
||||
GetLotSize(),
|
||||
price,
|
||||
NormalizeDouble(sl,_Digits),
|
||||
NormalizeDouble(tp,_Digits),
|
||||
"TickReversionProNews"
|
||||
);
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// INIT
|
||||
//====================================================
|
||||
int OnInit()
|
||||
{
|
||||
ArrayResize(TickBuffer,LookbackTicks);
|
||||
ArrayInitialize(TickBuffer,0);
|
||||
|
||||
atrHandle=iATR(_Symbol,_Period,ATRPeriod);
|
||||
emaHandle=iMA(_Symbol,_Period,200,0,MODE_EMA,PRICE_CLOSE);
|
||||
|
||||
trade.SetExpertMagicNumber(MagicNumber);
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// ON TICK
|
||||
//====================================================
|
||||
void OnTick()
|
||||
{
|
||||
double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);
|
||||
|
||||
for(int i=LookbackTicks-1;i>0;i--)
|
||||
TickBuffer[i]=TickBuffer[i-1];
|
||||
|
||||
TickBuffer[0]=bid;
|
||||
|
||||
//================================================
|
||||
// NEWS FILTER
|
||||
//================================================
|
||||
if(UseNewsFilter && IsHighImpactNewsTime())
|
||||
{
|
||||
CloseAllPositions();
|
||||
return;
|
||||
}
|
||||
|
||||
ManageProfitTarget();
|
||||
ManageTrailing();
|
||||
|
||||
if(TickBuffer[LookbackTicks-1]==0)
|
||||
return;
|
||||
|
||||
if(CountPositionsForSymbol()>=MaxPositionsPerSymbol)
|
||||
return;
|
||||
|
||||
double sum=0;
|
||||
|
||||
for(int i=0;i<LookbackTicks;i++)
|
||||
sum+=TickBuffer[i];
|
||||
|
||||
double avg=sum/LookbackTicks;
|
||||
|
||||
double var=0;
|
||||
|
||||
for(int i=0;i<LookbackTicks;i++)
|
||||
var+=MathPow(TickBuffer[i]-avg,2);
|
||||
|
||||
double sd=MathSqrt(var/LookbackTicks);
|
||||
|
||||
if(sd<=0)
|
||||
return;
|
||||
|
||||
double z=(bid-avg)/sd;
|
||||
|
||||
//================================================
|
||||
// ORIGINAL STRATEGY LOGIC UNCHANGED
|
||||
//================================================
|
||||
if(z<=-DeviationThreshold && TrendFilter(ORDER_TYPE_BUY))
|
||||
ExecuteDeal(ORDER_TYPE_BUY);
|
||||
|
||||
if(z>=DeviationThreshold && TrendFilter(ORDER_TYPE_SELL))
|
||||
ExecuteDeal(ORDER_TYPE_SELL);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,300 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Volatility_Breakout_Pro.mq5 |
|
||||
//| WITH HIGH IMPACT NEWS FILTER |
|
||||
//+------------------------------------------------------------------+
|
||||
#property strict
|
||||
#include <Trade/Trade.mqh>
|
||||
|
||||
input double ForexLotSize=0.01;
|
||||
input double OtherLotSize=0.01;
|
||||
input int ATRPeriod=14;
|
||||
input int EMAFast=50;
|
||||
input int EMASlow=200;
|
||||
input double ATRMultiplierSL=2.5;
|
||||
input double RiskReward=3.0;
|
||||
input double ProfitTargetPerLot=20.0;
|
||||
input int MaxPositionsPerSymbol=10;
|
||||
input ulong MagicNumber=888888;
|
||||
|
||||
//====================================================
|
||||
// NEWS FILTER
|
||||
//====================================================
|
||||
input bool UseNewsFilter=true;
|
||||
input int NewsPauseBeforeMin=60;
|
||||
input int NewsPauseAfterMin=60;
|
||||
|
||||
CTrade trade;
|
||||
int atrHandle, fastHandle, slowHandle;
|
||||
|
||||
//====================================================
|
||||
// LOT SIZE
|
||||
//====================================================
|
||||
double GetLotSize()
|
||||
{
|
||||
string s=_Symbol;
|
||||
|
||||
if(StringFind(s,"XAU")>=0 || StringFind(s,"XAG")>=0 ||
|
||||
StringFind(s,"BTC")>=0 || StringFind(s,"ETH")>=0 ||
|
||||
StringFind(s,"US30")>=0 || StringFind(s,"NAS")>=0)
|
||||
return OtherLotSize;
|
||||
|
||||
return ForexLotSize;
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// POSITION COUNT
|
||||
//====================================================
|
||||
int CountPositionsForSymbol()
|
||||
{
|
||||
int count=0;
|
||||
|
||||
for(int i=PositionsTotal()-1;i>=0;i--)
|
||||
{
|
||||
ulong ticket=PositionGetTicket(i);
|
||||
|
||||
if(!PositionSelectByTicket(ticket)) continue;
|
||||
if(PositionGetInteger(POSITION_MAGIC)!=MagicNumber) continue;
|
||||
if(PositionGetString(POSITION_SYMBOL)!=_Symbol) continue;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// DYNAMIC STOP
|
||||
//====================================================
|
||||
double DynamicStop()
|
||||
{
|
||||
double atr[1];
|
||||
|
||||
if(CopyBuffer(atrHandle,0,0,1,atr)<1)
|
||||
return 100*_Point;
|
||||
|
||||
double stopLevel=SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL)*_Point;
|
||||
double freezeLevel=SymbolInfoInteger(_Symbol,SYMBOL_TRADE_FREEZE_LEVEL)*_Point;
|
||||
double spread=SymbolInfoDouble(_Symbol,SYMBOL_ASK)-SymbolInfoDouble(_Symbol,SYMBOL_BID);
|
||||
|
||||
return MathMax(atr[0]*ATRMultiplierSL,
|
||||
MathMax(stopLevel,freezeLevel)+spread*10.0);
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// MANAGE POSITIONS
|
||||
//====================================================
|
||||
void ManagePositions()
|
||||
{
|
||||
for(int i=PositionsTotal()-1;i>=0;i--)
|
||||
{
|
||||
ulong ticket=PositionGetTicket(i);
|
||||
|
||||
if(!PositionSelectByTicket(ticket)) continue;
|
||||
if(PositionGetInteger(POSITION_MAGIC)!=MagicNumber) continue;
|
||||
if(PositionGetString(POSITION_SYMBOL)!=_Symbol) continue;
|
||||
|
||||
double profit=PositionGetDouble(POSITION_PROFIT);
|
||||
double volume=PositionGetDouble(POSITION_VOLUME);
|
||||
|
||||
if(profit>=volume*ProfitTargetPerLot)
|
||||
{
|
||||
trade.PositionClose(ticket);
|
||||
continue;
|
||||
}
|
||||
|
||||
double tp=PositionGetDouble(POSITION_TP);
|
||||
double sl=PositionGetDouble(POSITION_SL);
|
||||
double dist=DynamicStop();
|
||||
|
||||
ENUM_POSITION_TYPE pos=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
|
||||
if(pos==POSITION_TYPE_BUY)
|
||||
{
|
||||
double newSL=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID)-dist,_Digits);
|
||||
|
||||
if(newSL>sl)
|
||||
trade.PositionModify(ticket,newSL,tp);
|
||||
}
|
||||
else
|
||||
{
|
||||
double newSL=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK)+dist,_Digits);
|
||||
|
||||
if(sl==0 || newSL<sl)
|
||||
trade.PositionModify(ticket,newSL,tp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// NEWS FILTER
|
||||
//====================================================
|
||||
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;
|
||||
|
||||
if(event.importance!=CALENDAR_IMPORTANCE_HIGH)
|
||||
continue;
|
||||
|
||||
// FIXED MT5 COMPATIBILITY
|
||||
MqlCalendarCountry country;
|
||||
|
||||
if(!CalendarCountryById(event.country_id,country))
|
||||
continue;
|
||||
|
||||
string currency=country.currency;
|
||||
|
||||
bool relevant=false;
|
||||
|
||||
// GOLD/SILVER/INDICES/CRYPTO -> USD NEWS
|
||||
if(StringFind(_Symbol,"XAU")>=0 ||
|
||||
StringFind(_Symbol,"XAG")>=0 ||
|
||||
StringFind(_Symbol,"BTC")>=0 ||
|
||||
StringFind(_Symbol,"ETH")>=0 ||
|
||||
StringFind(_Symbol,"US30")>=0 ||
|
||||
StringFind(_Symbol,"NAS")>=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)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// INIT
|
||||
//====================================================
|
||||
int OnInit()
|
||||
{
|
||||
trade.SetExpertMagicNumber(MagicNumber);
|
||||
|
||||
atrHandle=iATR(_Symbol,_Period,ATRPeriod);
|
||||
fastHandle=iMA(_Symbol,_Period,EMAFast,0,MODE_EMA,PRICE_CLOSE);
|
||||
slowHandle=iMA(_Symbol,_Period,EMASlow,0,MODE_EMA,PRICE_CLOSE);
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// ON TICK
|
||||
//====================================================
|
||||
void OnTick()
|
||||
{
|
||||
//================================================
|
||||
// NEWS FILTER
|
||||
//================================================
|
||||
if(UseNewsFilter && IsHighImpactNewsTime())
|
||||
{
|
||||
CloseAllPositions();
|
||||
return;
|
||||
}
|
||||
|
||||
ManagePositions();
|
||||
|
||||
if(CountPositionsForSymbol()>=MaxPositionsPerSymbol)
|
||||
return;
|
||||
|
||||
double fast[2], slow[2];
|
||||
|
||||
if(CopyBuffer(fastHandle,0,0,2,fast)<2) return;
|
||||
if(CopyBuffer(slowHandle,0,0,2,slow)<2) return;
|
||||
|
||||
double high=iHigh(_Symbol,_Period,1);
|
||||
double low=iLow(_Symbol,_Period,1);
|
||||
|
||||
double ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
|
||||
double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);
|
||||
|
||||
double slDist=DynamicStop();
|
||||
|
||||
bool upTrend=fast[0]>slow[0];
|
||||
bool downTrend=fast[0]<slow[0];
|
||||
|
||||
//================================================
|
||||
// ORIGINAL STRATEGY LOGIC UNCHANGED
|
||||
//================================================
|
||||
if(upTrend && ask>high)
|
||||
{
|
||||
trade.Buy(GetLotSize(),
|
||||
_Symbol,
|
||||
ask,
|
||||
ask-slDist,
|
||||
ask+slDist*RiskReward,
|
||||
"BreakoutBuyNews");
|
||||
}
|
||||
|
||||
if(downTrend && bid<low)
|
||||
{
|
||||
trade.Sell(GetLotSize(),
|
||||
_Symbol,
|
||||
bid,
|
||||
bid+slDist,
|
||||
bid-slDist*RiskReward,
|
||||
"BreakoutSellNews");
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Reference in New Issue
Block a user