Add files via upload

This commit is contained in:
DinexSpace
2026-10-27 14:19:07 +07:00
committed by GitHub
parent 0f2a8b9c73
commit 3ede6bc520
@@ -0,0 +1,148 @@
#property strict
#property version "1.00"
#include <Trade\Trade.mqh>
input double InpLotSize = 0.01;
input int InpStopLoss = 300;
input int InpTakeProfit = 600;
input ulong InpMagicNumber = 130123;
input int InpSlippage = 10;
input bool InpUseBreakEven = true;
input int InpBreakEvenTrigger = 150;
input int InpBreakEvenOffset = 0;
input bool InpUseTrailingStop = true;
input int InpTrailingStart = 200;
input int InpTrailingDistance = 200;
input int InpMaxSpread = 30;
input int InpATRPeriod=14;
input int InpATRLookback=30;
input double InpLowATRFactor=0.7;
input int InpRangeBars=20;
input double InpWickBodyRatio=1.5;
int g_atr=INVALID_HANDLE;
bool ReadValue(int h,int b,int s,double &v){double a[1];if(CopyBuffer(h,b,s,1,a)!=1)return false;v=a[0];return MathIsValidNumber(v);}
CTrade trade;
datetime g_lastBar = 0;
bool IsNewBar()
{
datetime t = iTime(_Symbol, _Period, 0);
if(t == 0 || t == g_lastBar) return false;
g_lastBar = t;
return true;
}
bool SpreadAllowed()
{
MqlTick t;
return SymbolInfoTick(_Symbol, t) && (t.ask - t.bid) / _Point <= InpMaxSpread;
}
int CountMine()
{
int n = 0;
for(int i = PositionsTotal() - 1; i >= 0; --i)
if(PositionGetTicket(i) > 0 &&
PositionGetString(POSITION_SYMBOL) == _Symbol &&
(ulong)PositionGetInteger(POSITION_MAGIC) == InpMagicNumber) ++n;
return n;
}
double NormalizeVolume()
{
double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
if(step <= 0.0) return 0.0;
double v = MathMax(SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN),
MathMin(SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX), InpLotSize));
return NormalizeDouble(MathFloor(v / step + 1e-8) * step, 8);
}
bool OpenPosition(ENUM_ORDER_TYPE type, string comment)
{
MqlTick t;
if(!SymbolInfoTick(_Symbol, t)) return false;
double volume = NormalizeVolume();
if(volume <= 0.0) return false;
double price = (type == ORDER_TYPE_BUY) ? t.ask : t.bid;
double minStop = (double)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * _Point;
double slDist = MathMax((double)InpStopLoss * _Point, minStop);
double tpDist = MathMax((double)InpTakeProfit * _Point, minStop);
double sl = NormalizeDouble(price + ((type == ORDER_TYPE_BUY) ? -slDist : slDist), _Digits);
double tp = NormalizeDouble(price + ((type == ORDER_TYPE_BUY) ? tpDist : -tpDist), _Digits);
bool ok = (type == ORDER_TYPE_BUY)
? trade.Buy(volume, _Symbol, 0.0, sl, tp, comment)
: trade.Sell(volume, _Symbol, 0.0, sl, tp, comment);
if(!ok) Print("Order failed: ", trade.ResultRetcode(), " ", trade.ResultRetcodeDescription());
return ok;
}
void ManagePositions()
{
MqlTick t;
if(!SymbolInfoTick(_Symbol, t)) return;
for(int i = PositionsTotal() - 1; i >= 0; --i)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0 || PositionGetString(POSITION_SYMBOL) != _Symbol ||
(ulong)PositionGetInteger(POSITION_MAGIC) != InpMagicNumber) continue;
ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
double open = PositionGetDouble(POSITION_PRICE_OPEN);
double oldSL = PositionGetDouble(POSITION_SL);
double tp = PositionGetDouble(POSITION_TP);
double current = (type == POSITION_TYPE_BUY) ? t.bid : t.ask;
double profitPoints = (type == POSITION_TYPE_BUY) ? (current-open)/_Point : (open-current)/_Point;
double newSL = oldSL;
bool modify = false;
if(InpUseBreakEven && profitPoints >= InpBreakEvenTrigger)
{
double be = NormalizeDouble(open + ((type == POSITION_TYPE_BUY) ? 1.0 : -1.0) * InpBreakEvenOffset * _Point, _Digits);
if(type == POSITION_TYPE_BUY && (oldSL == 0.0 || be > newSL) && be < t.bid)
{ newSL = be; modify = true; }
else if(type == POSITION_TYPE_SELL && (oldSL == 0.0 || be < newSL) && be > t.ask)
{ newSL = be; modify = true; }
}
if(InpUseTrailingStop && profitPoints >= InpTrailingStart)
{
double tr = NormalizeDouble(current + ((type == POSITION_TYPE_BUY) ? -1.0 : 1.0) * InpTrailingDistance * _Point, _Digits);
if(type == POSITION_TYPE_BUY && tr < t.bid && (newSL == 0.0 || tr > newSL))
{ newSL = tr; modify = true; }
else if(type == POSITION_TYPE_SELL && tr > t.ask && (newSL == 0.0 || tr < newSL))
{ newSL = tr; modify = true; }
}
if(modify && !trade.PositionModify(ticket, newSL, tp))
Print("PositionModify failed: ", trade.ResultRetcode(), " ", trade.ResultRetcodeDescription());
}
}
int OnInit()
{
trade.SetExpertMagicNumber(InpMagicNumber);
trade.SetDeviationInPoints((ulong)InpSlippage);
trade.SetTypeFillingBySymbol(_Symbol);
g_atr=iATR(_Symbol,_Period,InpATRPeriod);
if(g_atr==INVALID_HANDLE) return INIT_FAILED;
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
if(g_atr!=INVALID_HANDLE) IndicatorRelease(g_atr);
}
void OnTick()
{
ManagePositions();
if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) ||
!MQLInfoInteger(MQL_TRADE_ALLOWED) ||
!AccountInfoInteger(ACCOUNT_TRADE_ALLOWED)) return;
if(!IsNewBar() || CountMine() >= 1 || !SpreadAllowed()) return;
if(InpATRLookback<2 || InpRangeBars<3) return;
double atr;
if(!ReadValue(g_atr,0,1,atr)) return;
double avg=0.0;
for(int i=2;i<2+InpATRLookback;i++){double x;if(!ReadValue(g_atr,0,i,x))return;avg+=x;}
avg/=InpATRLookback;
if(avg<=0.0 || atr>avg*InpLowATRFactor) return;
double hi=-DBL_MAX,lo=DBL_MAX;
for(int i=2;i<2+InpRangeBars;i++){hi=MathMax(hi,iHigh(_Symbol,_Period,i));lo=MathMin(lo,iLow(_Symbol,_Period,i));}
double o=iOpen(_Symbol,_Period,1),c=iClose(_Symbol,_Period,1);
double h=iHigh(_Symbol,_Period,1),l=iLow(_Symbol,_Period,1);
double body=MathMax(MathAbs(c-o),_Point);
double lower=MathMin(o,c)-l, upper=h-MathMax(o,c);
if(l<=lo+(hi-lo)*0.1 && c>o && lower>=body*InpWickBodyRatio) OpenPosition(ORDER_TYPE_BUY,"EA-130 BUY");
else if(h>=hi-(hi-lo)*0.1 && c<o && upper>=body*InpWickBodyRatio) OpenPosition(ORDER_TYPE_SELL,"EA-130 SELL");
}