رباط

MQL5 EA 스크립트

명시

//+------------------------------------------------------------------+
//|                                            AdvancedPriceAction.mq5 |
//|                                 Copyright 2026, Trading Strategy AI |
//+------------------------------------------------------------------+
#property copyright "Trading Strategy AI"
#property version   "1.00"
#property strict

#include <Trade\Trade.mqh>

input group "Trading Settings"
input double RiskPercent      = 0.5;
input int    MagicNumber      = 123456;
input int    MaxSpread        = 20;
input int    SlippagePoints   = 10;
input bool   AllowAutoTrading = true;
input bool   AllowManualExit  = true;

input group "Timeframe Settings"
input ENUM_TIMEFRAMES StructureTF = PERIOD_M15;
input ENUM_TIMEFRAMES SwingTF     = PERIOD_M5;
input ENUM_TIMEFRAMES EntryTF     = PERIOD_M1;

input group "Logic Settings"
input int    SwingLookback     = 120;
input int    SwingDepth        = 2;
input int    LevelMergePoints  = 25;
input int    FanStepPoints     = 150;
input int    FanCount          = 4;
input int    StopBufferPoints  = 20;
input int    ReactionBufferPts = 15;
input double BreakoutRR        = 2.0;
input double ReactionRR        = 1.0;

CTrade trade;
string prefix = "APA_";
datetime last_entry_bar = 0;

double levels[];
double last_high = 0.0, last_low = 0.0;
datetime last_high_time = 0, last_low_time = 0;

double P() { return SymbolInfoDouble(_Symbol, SYMBOL_POINT); }
int SpreadPts() { return (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD); }

double Norm(double v) { return NormalizeDouble(v, _Digits); }

double ClampLot(double lot)
{
   double minv = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double maxv = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   lot = MathMax(minv, MathMin(maxv, lot));
   lot = MathFloor(lot / step) * step;
   return NormalizeDouble(lot, 2);
}

double LotsByRisk(double sl_points)
{
   if(sl_points <= 0) return ClampLot(SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN));
   double bal = AccountInfoDouble(ACCOUNT_BALANCE);
   double risk_money = bal * RiskPercent / 100.0;
   double tick_value = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
   double tick_size  = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   if(tick_value <= 0 || tick_size <= 0) return ClampLot(SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN));
   double value_per_point = tick_value * (P() / tick_size);
   return ClampLot(risk_money / (sl_points * value_per_point));
}

bool NewBar(ENUM_TIMEFRAMES tf, datetime &stamp)
{
   datetime t = iTime(_Symbol, tf, 0);
   if(t == 0 || t == stamp) return false;
   stamp = t;
   return true;
}

bool HasOpenPosition()
{
   for(int i = PositionsTotal() - 1; i >= 0; --i)
   {
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0) continue;
      if(PositionGetString(POSITION_SYMBOL) == _Symbol && (int)PositionGetInteger(POSITION_MAGIC) == MagicNumber)
         return true;
   }
   return false;
}

bool CloseByType(long pos_type = -1)
{
   bool ok = true;
   for(int i = PositionsTotal() - 1; i >= 0; --i)
   {
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0) continue;
      if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
      if((int)PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
      long type = PositionGetInteger(POSITION_TYPE);
      if(pos_type != -1 && type != pos_type) continue;
      if(!trade.PositionClose(ticket)) ok = false;
   }
   return ok;
}

void AddLevel(double price)
{
   double band = LevelMergePoints * P();
   for(int i = 0; i < ArraySize(levels); ++i)
   {
      if(MathAbs(levels[i] - price) <= band)
      {
         levels[i] = (levels[i] + price) * 0.5;
         return;
      }
   }
   int n = ArraySize(levels);
   ArrayResize(levels, n + 1);
   levels[n] = price;
}

bool SwingAt(MqlRates &r[], int i)
{
   for(int j = 1; j <= SwingDepth; ++j)
   {
      if(r[i].high <= r[i - j].high || r[i].high < r[i + j].high) return false;
   }
   return true;
}

bool SwingLowAt(MqlRates &r[], int i)
{
   for(int j = 1; j <= SwingDepth; ++j)
   {
      if(r[i].low >= r[i - j].low || r[i].low > r[i + j].low) return false;
   }
   return true;
}

void BuildStructure()
{
   MqlRates r[];
   int n = CopyRates(_Symbol, SwingTF, 1, SwingLookback, r);
   if(n <= SwingDepth * 2 + 1) return;

   ArrayResize(levels, 0);
   for(int i = SwingDepth; i < n - SwingDepth; ++i)
   {
      if(SwingAt(r, i))
      {
         last_high = r[i].high;
         last_high_time = r[i].time;
         AddLevel(r[i].high);
      }
      if(SwingLowAt(r, i))
      {
         last_low = r[i].low;
         last_low_time = r[i].time;
         AddLevel(r[i].low);
      }
   }
}

void DrawLevels()
{
   for(int i = ObjectsTotal(0, 0, -1) - 1; i >= 0; --i)
   {
      string name = ObjectName(0, i, 0, -1);
      if(StringFind(name, prefix + "LVL_") == 0 || StringFind(name, prefix + "FAN_") == 0)
         ObjectDelete(0, name);
   }

   for(int i = 0; i < ArraySize(levels); ++i)
   {
      string name = prefix + "LVL_" + IntegerToString(i);
      ObjectCreate(0, name, OBJ_HLINE, 0, 0, levels[i]);
      ObjectSetInteger(0, name, OBJPROP_COLOR, clrSilver);
      ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DOT);
   }

   datetime t0 = (last_high_time > last_low_time ? last_high_time : last_low_time);
   double p0 = (last_high_time > last_low_time ? last_high : last_low);
   bool fromHigh = last_high_time > last_low_time;
   for(int k = 1; k <= FanCount; ++k)
   {
      string name = prefix + "FAN_" + IntegerToString(k);
      double p1 = fromHigh ? p0 - k * FanStepPoints * P() : p0 + k * FanStepPoints * P();
      ObjectCreate(0, name, OBJ_TREND, 0, t0, p0, TimeCurrent() + PeriodSeconds(EntryTF) * 300, p1);
      ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, true);
      ObjectSetInteger(0, name, OBJPROP_COLOR, fromHigh ? clrTomato : clrLimeGreen);
   }
}

bool CloseAbove(double level)
{
   MqlRates b[2];
   if(CopyRates(_Symbol, EntryTF, 1, 2, b) != 2) return false;
   return (b[0].close > level && b[1].close <= level);
}

bool CloseBelow(double level)
{
   MqlRates b[2];
   if(CopyRates(_Symbol, EntryTF, 1, 2, b) != 2) return false;
   return (b[0].close < level && b[1].close >= level);
}

bool BullReaction(double level)
{
   MqlRates b[1];
   if(CopyRates(_Symbol, EntryTF, 1, 1, b) != 1) return false;
   double buf = ReactionBufferPts * P();
   return (b[0].low <= level + buf && b[0].close > b[0].open && b[0].close > level);
}

bool BearReaction(double level)
{
   MqlRates b[1];
   if(CopyRates(_Symbol, EntryTF, 1, 1, b) != 1) return false;
   double buf = ReactionBufferPts * P();
   return (b[0].high >= level - buf && b[0].close < b[0].open && b[0].close < level);
}

bool NearLevel(double price, double &lvl)
{
   double best = DBL_MAX;
   bool found = false;
   for(int i = 0; i < ArraySize(levels); ++i)
   {
      double d = MathAbs(price - levels[i]);
      if(d < best)
      {
         best = d;
         lvl = levels[i];
         found = true;
      }
   }
   return found && best <= (LevelMergePoints + ReactionBufferPts) * P();
}

void Buy(double sl, double tp)
{
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double lot = LotsByRisk(MathAbs(ask - sl) / P());
   trade.SetExpertMagicNumber(MagicNumber);
   trade.SetDeviationInPoints(SlippagePoints);
   trade.Buy(lot, _Symbol, ask, Norm(sl), Norm(tp), "APA BUY");
}

void Sell(double sl, double tp)
{
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double lot = LotsByRisk(MathAbs(sl - bid) / P());
   trade.SetExpertMagicNumber(MagicNumber);
   trade.SetDeviationInPoints(SlippagePoints);
   trade.Sell(lot, _Symbol, bid, Norm(sl), Norm(tp), "APA SELL");
}

void EvaluateSignals()
{
   if(!AllowAutoTrading || SpreadPts() > MaxSpread || HasOpenPosition()) return;

   MqlRates b[1];
   if(CopyRates(_Symbol, EntryTF, 1, 1, b) != 1) return;
   double c = b[0].close;
   double lvl = 0.0;

   if(last_high > 0 && CloseAbove(last_high))
   {
      double sl = last_low - StopBufferPoints * P();
      double tp = c + (c - sl) * BreakoutRR;
      Buy(sl, tp);
      return;
   }
   if(last_low > 0 && CloseBelow(last_low))
   {
      double sl = last_high + StopBufferPoints * P();
      double tp = c - (sl - c) * BreakoutRR;
      Sell(sl, tp);
      return;
   }

   if(NearLevel(c, lvl))
   {
      if(BullReaction(lvl))
      {
         double sl = lvl - StopBufferPoints * P();
         double tp = c + (c - sl) * ReactionRR;
         Buy(sl, tp);
      }
      else if(BearReaction(lvl))
      {
         double sl = lvl + StopBufferPoints * P();
         double tp = c - (sl - c) * ReactionRR;
         Sell(sl, tp);
      }
   }
}

void Panel()
{
   string b = prefix + "BTN_";
   if(ObjectFind(0, b + "ALL") < 0)
   {
      ObjectCreate(0, b + "ALL", OBJ_BUTTON, 0, 0, 0);
      ObjectSetInteger(0, b + "ALL", OBJPROP_XDISTANCE, 20);
      ObjectSetInteger(0, b + "ALL", OBJPROP_YDISTANCE, 20);
      ObjectSetInteger(0, b + "ALL", OBJPROP_XSIZE, 90);
      ObjectSetInteger(0, b + "ALL", OBJPROP_YSIZE, 22);
      ObjectSetString(0, b + "ALL", OBJPROP_TEXT, "Close All");
   }
   if(ObjectFind(0, b + "BUY") < 0)
   {
      ObjectCreate(0, b + "BUY", OBJ_BUTTON, 0, 0, 0);
      ObjectSetInteger(0, b + "BUY", OBJPROP_XDISTANCE, 120);
      ObjectSetInteger(0, b + "BUY", OBJPROP_YDISTANCE, 20);
      ObjectSetInteger(0, b + "BUY", OBJPROP_XSIZE, 90);
      ObjectSetInteger(0, b + "BUY", OBJPROP_YSIZE, 22);
      ObjectSetString(0, b + "BUY", OBJPROP_TEXT, "Close Buy");
   }
   if(ObjectFind(0, b + "SELL") < 0)
   {
      ObjectCreate(0, b + "SELL", OBJ_BUTTON, 0, 0, 0);
      ObjectSetInteger(0, b + "SELL", OBJPROP_XDISTANCE, 220);
      ObjectSetInteger(0, b + "SELL", OBJPROP_YDISTANCE, 20);
      ObjectSetInteger(0, b + "SELL", OBJPROP_XSIZE, 90);
      ObjectSetInteger(0, b + "SELL", OBJPROP_YSIZE, 22);
      ObjectSetString(0, b + "SELL", OBJPROP_TEXT, "Close Sell");
   }
}

void Status()
{
   string n = prefix + "STATUS";
   string txt = "APA | spread=" + IntegerToString(SpreadPts()) + " | levels=" + IntegerToString(ArraySize(levels));
   if(ObjectFind(0, n) < 0)
   {
      ObjectCreate(0, n, OBJ_LABEL, 0, 0, 0);
      ObjectSetInteger(0, n, OBJPROP_XDISTANCE, 20);
      ObjectSetInteger(0, n, OBJPROP_YDISTANCE, 52);
      ObjectSetInteger(0, n, OBJPROP_COLOR, clrWhite);
   }
   ObjectSetString(0, n, OBJPROP_TEXT, txt);
}

int OnInit()
{
   trade.SetExpertMagicNumber(MagicNumber);
   trade.SetDeviationInPoints(SlippagePoints);
   Panel();
   return INIT_SUCCEEDED;
}

void OnDeinit(const int reason) { Comment(""); }

void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   if(id != CHARTEVENT_OBJECT_CLICK || !AllowManualExit) return;
   if(sparam == prefix + "BTN_ALL")  CloseByType(-1);
   if(sparam == prefix + "BTN_BUY")  CloseByType(POSITION_TYPE_BUY);
   if(sparam == prefix + "BTN_SELL") CloseByType(POSITION_TYPE_SELL);
}

void OnTick()
{
   if(NewBar(EntryTF, last_entry_bar))
   {
      BuildStructure();
      DrawLevels();
      EvaluateSignals();
      Status();
   }
}

응답함

1
개발자 1
등급
프로젝트
0
0%
중재
0
기한 초과
0
무료
2
개발자 2
등급
(395)
프로젝트
509
23%
중재
60
57% / 25%
기한 초과
59
12%
로드됨
3
개발자 3
등급
프로젝트
0
0%
중재
0
기한 초과
0
무료
4
개발자 4
등급
(83)
프로젝트
95
32%
중재
9
22% / 56%
기한 초과
5
5%
작업중
5
개발자 5
등급
(3)
프로젝트
4
0%
중재
1
100% / 0%
기한 초과
1
25%
무료
6
개발자 6
등급
(1)
프로젝트
1
0%
중재
1
0% / 0%
기한 초과
0
작업중
7
개발자 7
등급
(5)
프로젝트
6
50%
중재
0
기한 초과
0
작업중
게재됨: 1 코드
8
개발자 8
등급
(1)
프로젝트
1
0%
중재
0
기한 초과
1
100%
무료
9
개발자 9
등급
프로젝트
0
0%
중재
0
기한 초과
0
무료
10
개발자 10
등급
프로젝트
0
0%
중재
0
기한 초과
0
무료
11
개발자 11
등급
프로젝트
0
0%
중재
0
기한 초과
0
무료
12
개발자 12
등급
프로젝트
1
0%
중재
0
기한 초과
0
무료
13
개발자 13
등급
(64)
프로젝트
144
46%
중재
20
40% / 20%
기한 초과
32
22%
무료
14
개발자 14
등급
프로젝트
0
0%
중재
0
기한 초과
0
무료
15
개발자 15
등급
프로젝트
0
0%
중재
0
기한 초과
0
무료
16
개발자 16
등급
(1)
프로젝트
1
0%
중재
0
기한 초과
0
무료
게재됨: 1 코드
17
개발자 17
등급
(2)
프로젝트
2
50%
중재
0
기한 초과
0
무료
18
개발자 18
등급
(298)
프로젝트
478
40%
중재
105
40% / 24%
기한 초과
82
17%
로드됨
게재됨: 2 코드

프로젝트 정보

예산
30+ USD

고객

넣은 주문1
중재 수0