EA MT5: Mudahkan Pengaturan Posisi Layering
EA ini dibuat untuk memudahkan pengaturan beberapa posisi yang dibuka secara layering.
Contoh Sederhana
Misalnya kita membuka 4 posisi BUY dengan harga berbeda:
BUY 1 → 4423
BUY 2 → 4425
BUY 3 → 4426
BUY 4 → 4429
Biasanya, jika ingin mengubah SL, kita harus mengaturnya satu per satu. Dengan EA ini, cukup geser SL pada satu posisi.
Misalnya SL digeser ke 4400, maka otomatis:
BUY 1 → SL 4400
BUY 2 → SL 4400
BUY 3 → SL 4400
BUY 4 → SL 4400
Jadi, cukup geser satu SL, semua SL posisi lainnya otomatis mengikuti.
TP Juga Bisa Mengikuti
Hal yang sama berlaku untuk TP. Jika TP pada satu posisi digeser, TP posisi lainnya juga otomatis mengikuti.
Jadi pengaturannya sederhana:
- Geser SL → semua SL mengikuti.
- Geser TP → semua TP mengikuti.
- BUY → hanya mengikuti BUY.
- SELL → hanya mengikuti SELL.
Risk/Reward 1:1
EA ini juga dapat digunakan dengan konsep Risk/Reward 1:1. Contohnya:
Risk = 20 poin
Reward = 20 poin
RR = 1:1
Dengan begitu, jarak risiko dan target dibuat sama.
Kesimpulan
EA ini cocok untuk trader yang menggunakan posisi layering dan ingin mengatur SL serta TP beberapa posisi dengan lebih cepat.
Tidak perlu mengubah satu per satu. Cukup ubah satu posisi, posisi lainnya akan otomatis mengikuti.
//+------------------------------------------------------------------+
//| AutoSyncSLTP_NoTrade.mq5 |
//| |
//| SL berubah -> hanya SL yang mengikuti |
//| TP berubah -> hanya TP yang mengikuti |
//| |
//| BUY -> BUY |
//| SELL -> SELL |
//| Symbol sama |
//| |
//| Tidak menggunakan Trade.mqh |
//+------------------------------------------------------------------+
#property strict
#property version "5.00"
input bool SyncSameSymbolOnly = true;
input bool SyncSameTypeOnly = true;
input int CheckIntervalMS = 200;
input int DeviationPoints = 20;
//--- data posisi sebelumnya
struct PositionData
{
ulong ticket;
string symbol;
long type;
double sl;
double tp;
};
PositionData PreviousPositions[];
//+------------------------------------------------------------------+
//| INIT |
//+------------------------------------------------------------------+
int OnInit()
{
EventSetMillisecondTimer(CheckIntervalMS);
SaveCurrentPositions();
Print("==========================================");
Print("AUTO SYNC SL + TP AKTIF");
Print("==========================================");
Print("SL -> hanya SL yang mengikuti");
Print("TP -> hanya TP yang mengikuti");
Print("BUY -> BUY");
Print("SELL -> SELL");
Print("==========================================");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| DEINIT |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
EventKillTimer();
Print("Auto Sync SL + TP berhenti.");
}
//+------------------------------------------------------------------+
//| TIMER |
//+------------------------------------------------------------------+
void OnTimer()
{
CheckPositions();
}
//+------------------------------------------------------------------+
//| CEK SEMUA POSISI |
//+------------------------------------------------------------------+
void CheckPositions()
{
int total = PositionsTotal();
for(int i = 0; i < total; i++)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0)
continue;
if(!PositionSelectByTicket(ticket))
continue;
string symbol = PositionGetString(POSITION_SYMBOL);
long type = PositionGetInteger(POSITION_TYPE);
double currentSL = PositionGetDouble(POSITION_SL);
double currentTP = PositionGetDouble(POSITION_TP);
int index = FindPosition(ticket);
// Posisi baru
if(index == -1)
{
AddPosition(
ticket,
symbol,
type,
currentSL,
currentTP
);
continue;
}
// Cek perubahan SL
bool slChanged = PriceChanged(
PreviousPositions[index].sl,
currentSL,
symbol
);
// Cek perubahan TP
bool tpChanged = PriceChanged(
PreviousPositions[index].tp,
currentTP,
symbol
);
//==============================================================
// SL BERUBAH
//==============================================================
if(slChanged)
{
Print("------------------------------------------");
Print("PERUBAHAN SL TERDETEKSI");
Print("Ticket : ", ticket);
Print("Symbol : ", symbol);
Print(
"SL Lama: ",
DoubleToString(
PreviousPositions[index].sl,
GetDigits(symbol)
)
);
Print(
"SL Baru: ",
DoubleToString(
currentSL,
GetDigits(symbol)
)
);
Print("------------------------------------------");
PreviousPositions[index].sl = currentSL;
SyncSL(
ticket,
symbol,
type,
currentSL
);
}
//==============================================================
// TP BERUBAH
//==============================================================
if(tpChanged)
{
Print("------------------------------------------");
Print("PERUBAHAN TP TERDETEKSI");
Print("Ticket : ", ticket);
Print("Symbol : ", symbol);
Print(
"TP Lama: ",
DoubleToString(
PreviousPositions[index].tp,
GetDigits(symbol)
)
);
Print(
"TP Baru: ",
DoubleToString(
currentTP,
GetDigits(symbol)
)
);
Print("------------------------------------------");
PreviousPositions[index].tp = currentTP;
SyncTP(
ticket,
symbol,
type,
currentTP
);
}
}
RemoveClosedPositions();
}
//+------------------------------------------------------------------+
//| SYNC SL |
//+------------------------------------------------------------------+
void SyncSL(
ulong masterTicket,
string masterSymbol,
long masterType,
double masterSL
)
{
int total = PositionsTotal();
for(int i = 0; i < total; i++)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0)
continue;
if(ticket == masterTicket)
continue;
if(!PositionSelectByTicket(ticket))
continue;
string symbol = PositionGetString(POSITION_SYMBOL);
long type = PositionGetInteger(POSITION_TYPE);
double currentTP =
PositionGetDouble(POSITION_TP);
//--- filter symbol
if(
SyncSameSymbolOnly &&
symbol != masterSymbol
)
continue;
//--- filter BUY / SELL
if(
SyncSameTypeOnly &&
type != masterType
)
continue;
int digits = GetDigits(symbol);
double newSL = masterSL;
//--- jika SL bukan 0, cek validitas
if(newSL > 0.0)
{
newSL = NormalizeDouble(
newSL,
digits
);
if(
!IsValidSL(
symbol,
type,
newSL
)
)
{
Print(
"SL tidak valid untuk ticket ",
ticket
);
continue;
}
}
//--- TP TIDAK DIUBAH
double newTP = currentTP;
//--- kirim request
bool result = ModifyPosition(
ticket,
symbol,
newSL,
newTP
);
if(result)
{
Print(
"SL berhasil mengikuti | Ticket: ",
ticket,
" | SL: ",
DoubleToString(
newSL,
digits
)
);
UpdateStoredSL(
ticket,
newSL
);
}
else
{
Print(
"GAGAL SYNC SL | Ticket: ",
ticket,
" | Retcode: ",
LastTradeRetcode,
" | ",
LastTradeComment
);
}
}
}
//+------------------------------------------------------------------+
//| SYNC TP |
//+------------------------------------------------------------------+
void SyncTP(
ulong masterTicket,
string masterSymbol,
long masterType,
double masterTP
)
{
int total = PositionsTotal();
for(int i = 0; i < total; i++)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0)
continue;
if(ticket == masterTicket)
continue;
if(!PositionSelectByTicket(ticket))
continue;
string symbol = PositionGetString(POSITION_SYMBOL);
long type = PositionGetInteger(POSITION_TYPE);
double currentSL =
PositionGetDouble(POSITION_SL);
//--- filter symbol
if(
SyncSameSymbolOnly &&
symbol != masterSymbol
)
continue;
//--- filter BUY / SELL
if(
SyncSameTypeOnly &&
type != masterType
)
continue;
int digits = GetDigits(symbol);
double newTP = masterTP;
//--- jika TP bukan 0, cek validitas
if(newTP > 0.0)
{
newTP = NormalizeDouble(
newTP,
digits
);
if(
!IsValidTP(
symbol,
type,
newTP
)
)
{
Print(
"TP tidak valid untuk ticket ",
ticket
);
continue;
}
}
//--- SL TIDAK DIUBAH
double newSL = currentSL;
//--- kirim request
bool result = ModifyPosition(
ticket,
symbol,
newSL,
newTP
);
if(result)
{
Print(
"TP berhasil mengikuti | Ticket: ",
ticket,
" | TP: ",
DoubleToString(
newTP,
digits
)
);
UpdateStoredTP(
ticket,
newTP
);
}
else
{
Print(
"GAGAL SYNC TP | Ticket: ",
ticket,
" | Retcode: ",
LastTradeRetcode,
" | ",
LastTradeComment
);
}
}
}
//+------------------------------------------------------------------+
//| GLOBAL HASIL REQUEST |
//+------------------------------------------------------------------+
uint LastTradeRetcode = 0;
string LastTradeComment = "";
//+------------------------------------------------------------------+
//| MODIFY POSITION |
//+------------------------------------------------------------------+
bool ModifyPosition(
ulong ticket,
string symbol,
double sl,
double tp
)
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_SLTP;
request.position = ticket;
request.symbol = symbol;
request.sl = sl;
request.tp = tp;
ResetLastError();
bool sent = OrderSend(
request,
result
);
LastTradeRetcode = result.retcode;
LastTradeComment = result.comment;
if(!sent)
{
Print(
"OrderSend gagal | Error: ",
GetLastError()
);
return false;
}
if(
result.retcode != TRADE_RETCODE_DONE &&
result.retcode != TRADE_RETCODE_DONE_PARTIAL
)
{
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| VALIDASI SL |
//+------------------------------------------------------------------+
bool IsValidSL(
string symbol,
long type,
double sl
)
{
double bid =
SymbolInfoDouble(
symbol,
SYMBOL_BID
);
double ask =
SymbolInfoDouble(
symbol,
SYMBOL_ASK
);
double point =
SymbolInfoDouble(
symbol,
SYMBOL_POINT
);
int stopsLevel =
(int)SymbolInfoInteger(
symbol,
SYMBOL_TRADE_STOPS_LEVEL
);
int freezeLevel =
(int)SymbolInfoInteger(
symbol,
SYMBOL_TRADE_FREEZE_LEVEL
);
double distance =
MathMax(
stopsLevel,
freezeLevel
) * point;
// BUY
if(type == POSITION_TYPE_BUY)
{
if(sl >= bid)
return false;
if(
distance > 0.0 &&
(bid - sl) < distance
)
return false;
}
// SELL
if(type == POSITION_TYPE_SELL)
{
if(sl <= ask)
return false;
if(
distance > 0.0 &&
(sl - ask) < distance
)
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| VALIDASI TP |
//+------------------------------------------------------------------+
bool IsValidTP(
string symbol,
long type,
double tp
)
{
double bid =
SymbolInfoDouble(
symbol,
SYMBOL_BID
);
double ask =
SymbolInfoDouble(
symbol,
SYMBOL_ASK
);
double point =
SymbolInfoDouble(
symbol,
SYMBOL_POINT
);
int stopsLevel =
(int)SymbolInfoInteger(
symbol,
SYMBOL_TRADE_STOPS_LEVEL
);
int freezeLevel =
(int)SymbolInfoInteger(
symbol,
SYMBOL_TRADE_FREEZE_LEVEL
);
double distance =
MathMax(
stopsLevel,
freezeLevel
) * point;
// BUY
if(type == POSITION_TYPE_BUY)
{
if(tp <= bid)
return false;
if(
distance > 0.0 &&
(tp - bid) < distance
)
return false;
}
// SELL
if(type == POSITION_TYPE_SELL)
{
if(tp >= ask)
return false;
if(
distance > 0.0 &&
(ask - tp) < distance
)
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| CEK PERUBAHAN HARGA |
//+------------------------------------------------------------------+
bool PriceChanged(
double oldPrice,
double newPrice,
string symbol
)
{
double point =
SymbolInfoDouble(
symbol,
SYMBOL_POINT
);
return(
MathAbs(
oldPrice - newPrice
) > point * 0.5
);
}
//+------------------------------------------------------------------+
//| SIMPAN POSISI |
//+------------------------------------------------------------------+
void SaveCurrentPositions()
{
ArrayResize(
PreviousPositions,
0
);
int total = PositionsTotal();
for(int i = 0; i < total; i++)
{
ulong ticket =
PositionGetTicket(i);
if(ticket == 0)
continue;
if(!PositionSelectByTicket(ticket))
continue;
string symbol =
PositionGetString(
POSITION_SYMBOL
);
long type =
PositionGetInteger(
POSITION_TYPE
);
double sl =
PositionGetDouble(
POSITION_SL
);
double tp =
PositionGetDouble(
POSITION_TP
);
AddPosition(
ticket,
symbol,
type,
sl,
tp
);
}
}
//+------------------------------------------------------------------+
//| TAMBAH POSISI |
//+------------------------------------------------------------------+
void AddPosition(
ulong ticket,
string symbol,
long type,
double sl,
double tp
)
{
int size =
ArraySize(
PreviousPositions
);
ArrayResize(
PreviousPositions,
size + 1
);
PreviousPositions[size].ticket = ticket;
PreviousPositions[size].symbol = symbol;
PreviousPositions[size].type = type;
PreviousPositions[size].sl = sl;
PreviousPositions[size].tp = tp;
}
//+------------------------------------------------------------------+
//| CARI POSISI |
//+------------------------------------------------------------------+
int FindPosition(
ulong ticket
)
{
int total =
ArraySize(
PreviousPositions
);
for(int i = 0; i < total; i++)
{
if(
PreviousPositions[i].ticket ==
ticket
)
{
return i;
}
}
return -1;
}
//+------------------------------------------------------------------+
//| HAPUS POSISI YANG SUDAH CLOSE |
//+------------------------------------------------------------------+
void RemoveClosedPositions()
{
for(
int i =
ArraySize(
PreviousPositions
) - 1;
i >= 0;
i--
)
{
if(
!PositionSelectByTicket(
PreviousPositions[i].ticket
)
)
{
int size =
ArraySize(
PreviousPositions
);
for(
int j = i;
j < size - 1;
j++
)
{
PreviousPositions[j] =
PreviousPositions[j + 1];
}
ArrayResize(
PreviousPositions,
size - 1
);
}
}
}
//+------------------------------------------------------------------+
//| UPDATE SL |
//+------------------------------------------------------------------+
void UpdateStoredSL(
ulong ticket,
double sl
)
{
int index =
FindPosition(ticket);
if(index >= 0)
{
PreviousPositions[index].sl = sl;
}
}
//+------------------------------------------------------------------+
//| UPDATE TP |
//+------------------------------------------------------------------+
void UpdateStoredTP(
ulong ticket,
double tp
)
{
int index =
FindPosition(ticket);
if(index >= 0)
{
PreviousPositions[index].tp = tp;
}
}
//+------------------------------------------------------------------+
//| DIGITS |
//+------------------------------------------------------------------+
int GetDigits(
string symbol
)
{
return(
(int)SymbolInfoInteger(
symbol,
SYMBOL_DIGITS
)
);
}
//+------------------------------------------------------------------+

Gabung dalam percakapan