208 lines
11 KiB
MQL5
208 lines
11 KiB
MQL5
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| B2BIndicator.mq5 |
|
||
|
|
//| Copyright 2026, Delawa xyz |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#property copyright "Copyright 2026"
|
||
|
|
#property indicator_chart_window
|
||
|
|
#property indicator_plots 0
|
||
|
|
|
||
|
|
//--- INPUT PARAMETERS
|
||
|
|
input group "=== Risk Settings ==="
|
||
|
|
input double InpATR_Multiplier_SL = 2.0;
|
||
|
|
input double InpATR_Multiplier_TP = 3.0;
|
||
|
|
|
||
|
|
input group "=== Indicator Settings ==="
|
||
|
|
input int InpBB1_Period = 200;
|
||
|
|
input double InpBB1_Deviation = 1.3;
|
||
|
|
input int InpBB2_Period = 20;
|
||
|
|
input double InpBB2_Deviation = 2.3;
|
||
|
|
input int InpEMA8_Period = 8;
|
||
|
|
input int InpSMA21_Period = 21;
|
||
|
|
input int InpEMA50_Period = 50;
|
||
|
|
input double InpPSAR_Step = 0.02;
|
||
|
|
input double InpPSAR_Maximum = 0.2;
|
||
|
|
input int InpRSI_Period = 14; // Periode standar RSI
|
||
|
|
input int InpADX_Period = 14; // Periode standar ADX
|
||
|
|
|
||
|
|
//--- GLOBAL HANDLES
|
||
|
|
int handle_bb1, handle_bb2, handle_ema8, handle_sma21, handle_ema50, handle_psar, handle_atr, handle_rsi, handle_adx;
|
||
|
|
datetime time_last_bar;
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Custom indicator initialization function |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int OnInit()
|
||
|
|
{
|
||
|
|
time_last_bar = 0;
|
||
|
|
|
||
|
|
// Inisialisasi Indikator Bawaan
|
||
|
|
handle_bb1 = iBands(_Symbol, _Period, InpBB1_Period, 0, InpBB1_Deviation, PRICE_CLOSE);
|
||
|
|
handle_bb2 = iBands(_Symbol, _Period, InpBB2_Period, 0, InpBB2_Deviation, PRICE_CLOSE);
|
||
|
|
handle_ema8 = iMA(_Symbol, _Period, InpEMA8_Period, 0, MODE_EMA, PRICE_CLOSE);
|
||
|
|
handle_sma21 = iMA(_Symbol, _Period, InpSMA21_Period, 0, MODE_SMA, PRICE_CLOSE);
|
||
|
|
handle_ema50 = iMA(_Symbol, _Period, InpEMA50_Period, 0, MODE_EMA, PRICE_CLOSE);
|
||
|
|
handle_psar = iSAR(_Symbol, _Period, InpPSAR_Step, InpPSAR_Maximum);
|
||
|
|
handle_atr = iATR(_Symbol, _Period, 14);
|
||
|
|
handle_rsi = iRSI(_Symbol, _Period, InpRSI_Period, PRICE_CLOSE);
|
||
|
|
handle_adx = iADX(_Symbol, _Period, InpADX_Period);
|
||
|
|
|
||
|
|
if(handle_bb1 == INVALID_HANDLE || handle_bb2 == INVALID_HANDLE || handle_ema8 == INVALID_HANDLE ||
|
||
|
|
handle_sma21 == INVALID_HANDLE || handle_ema50 == INVALID_HANDLE || handle_psar == INVALID_HANDLE ||
|
||
|
|
handle_atr == INVALID_HANDLE || handle_rsi == INVALID_HANDLE || handle_adx == INVALID_HANDLE)
|
||
|
|
{
|
||
|
|
return(INIT_FAILED);
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- MEMBUAT OBJEK LAYOUT BARU ---
|
||
|
|
CreateLabel("DB_Title", 20, 20, "=== M1 HYBRID MONITOR PANEL ===", 11, clrWhite);
|
||
|
|
CreateLabel("DB_Status", 20, 45, "STATUS: LOADING...", 12, clrYellow);
|
||
|
|
|
||
|
|
CreateLabel("DB_BB1", 20, 75, "BB1 (200): Upper: - | Mid: - | Lower: -", 9, clrCyan);
|
||
|
|
CreateLabel("DB_BB2", 20, 95, "BB2 (20): Upper: - | Mid: - | Lower: -", 9, clrCyan);
|
||
|
|
CreateLabel("DB_EMA8", 20, 115, "EMA 8: -", 9, clrLightPink);
|
||
|
|
CreateLabel("DB_SMA21", 20, 135, "SMA 21: -", 9, clrLightSkyBlue);
|
||
|
|
CreateLabel("DB_EMA50", 20, 155, "EMA 50: -", 9, clrDarkGray); // clrLightBlack diganti clrDarkGray (Aman dari error)
|
||
|
|
|
||
|
|
// Tambahan Info Baru Sesuai Request Anda
|
||
|
|
CreateLabel("DB_Targets", 20, 180, "Proyeksi Jarak SL Manual: - | Jarak TP: -", 9, clrLightGray);
|
||
|
|
CreateLabel("DB_DailyOpen", 20, 200, "Daily Open: -", 9, clrWhite);
|
||
|
|
CreateLabel("DB_OpenPip", 20, 220, "Open Pip: -", 9, clrKhaki);
|
||
|
|
CreateLabel("DB_Time", 20, 240, "Time (Sisa Candle M1): - detik", 9, clrOrange);
|
||
|
|
CreateLabel("DB_RSI", 20, 260, "RSI: -", 9, clrSpringGreen);
|
||
|
|
CreateLabel("DB_ADX", 20, 280, "ADX: -", 9, clrGold);
|
||
|
|
|
||
|
|
return(INIT_SUCCEEDED);
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Custom indicator deinitialization function |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void OnDeinit(const int reason)
|
||
|
|
{
|
||
|
|
ObjectsDeleteAll(0, "DB_");
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Custom indicator iteration function |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int OnCalculate(const int rates_total,
|
||
|
|
const int prev_calculated,
|
||
|
|
const datetime &time[],
|
||
|
|
const double &open[],
|
||
|
|
const double &high[],
|
||
|
|
const double &low[],
|
||
|
|
const double &close[],
|
||
|
|
const long &tick_volume[],
|
||
|
|
const long &volume[],
|
||
|
|
const int &spread[])
|
||
|
|
{
|
||
|
|
// Array buffers
|
||
|
|
double bb1_upper[2], bb1_mid[2], bb1_lower[2];
|
||
|
|
double bb2_upper[2], bb2_mid[2], bb2_lower[2];
|
||
|
|
double ema8[2], sma21[2], ema50[2], psar[2], atr[2], rsi[2], adx[2], close_price[2], low_p[2], high_p[2];
|
||
|
|
|
||
|
|
if(CopyBuffer(handle_bb1, 1, 0, 2, bb1_upper) < 0 || CopyBuffer(handle_bb1, 0, 0, 2, bb1_mid) < 0 || CopyBuffer(handle_bb1, 2, 0, 2, bb1_lower) < 0 ||
|
||
|
|
CopyBuffer(handle_bb2, 1, 0, 2, bb2_upper) < 0 || CopyBuffer(handle_bb2, 0, 0, 2, bb2_mid) < 0 || CopyBuffer(handle_bb2, 2, 0, 2, bb2_lower) < 0 ||
|
||
|
|
CopyBuffer(handle_ema8, 0, 0, 2, ema8) < 0 || CopyBuffer(handle_sma21, 0, 0, 2, sma21) < 0 || CopyBuffer(handle_ema50, 0, 0, 2, ema50) < 0 ||
|
||
|
|
CopyBuffer(handle_psar, 0, 0, 2, psar) < 0 || CopyBuffer(handle_atr, 0, 0, 2, atr) < 0 ||
|
||
|
|
CopyBuffer(handle_rsi, 0, 0, 2, rsi) < 0 || CopyBuffer(handle_adx, 0, 0, 2, adx) < 0 ||
|
||
|
|
CopyClose(_Symbol, _Period, 0, 2, close_price) < 0 || CopyLow(_Symbol, _Period, 0, 2, low_p) < 0 || CopyHigh(_Symbol, _Period, 0, 2, high_p) < 0)
|
||
|
|
{
|
||
|
|
return(rates_total);
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- DATA HITUNGAN BARU ---
|
||
|
|
// 1. Mengambil Harga Daily Open (Harga pembukaan lilin harian/D1)
|
||
|
|
MqlRates daily_rates[];
|
||
|
|
ArraySetAsSeries(daily_rates, true);
|
||
|
|
if(CopyRates(_Symbol, PERIOD_D1, 0, 1, daily_rates) > 0)
|
||
|
|
{
|
||
|
|
double daily_open = daily_rates[0].open;
|
||
|
|
ObjectSetString(0, "DB_DailyOpen", OBJPROP_TEXT, "Daily Open : " + DoubleToString(daily_open, _Digits));
|
||
|
|
|
||
|
|
// 2. Hitung Open Pip (Selisih Running Price Saat Ini terhadap Daily Open)
|
||
|
|
double current_price = close_price[0]; // Harga tick saat ini
|
||
|
|
double diff_pips = (current_price - daily_open) / (_Point * 10);
|
||
|
|
if(_Digits == 3 || _Digits == 5) diff_pips = (current_price - daily_open) / (_Point * 10); // Menyesuaikan broker 3/5 digit
|
||
|
|
else diff_pips = (current_price - daily_open) / _Point;
|
||
|
|
|
||
|
|
ObjectSetString(0, "DB_OpenPip", OBJPROP_TEXT, StringFormat("Open Pip : %.1f pips", diff_pips));
|
||
|
|
}
|
||
|
|
|
||
|
|
// 3. Hitung Waktu Sisa Candle (Countdown dalam detik)
|
||
|
|
datetime current_time = TimeCurrent();
|
||
|
|
datetime candle_open_time = iTime(_Symbol, _Period, 0);
|
||
|
|
int period_seconds = PeriodSeconds(_Period); // Jika M1, ini bernilai 60 detik
|
||
|
|
int time_left = (int)(candle_open_time + period_seconds - current_time);
|
||
|
|
if(time_left < 0) time_left = 0;
|
||
|
|
|
||
|
|
ObjectSetString(0, "DB_Time", OBJPROP_TEXT, StringFormat("Time : %d detik menuju bar baru", time_left));
|
||
|
|
|
||
|
|
// 4. Update Teks Indikator Standar & Baru
|
||
|
|
ObjectSetString(0, "DB_BB1", OBJPROP_TEXT, StringFormat("BB1 (200) : Upper: %s | Mid: %s | Lower: %s", DoubleToString(bb1_upper[1], _Digits), DoubleToString(bb1_mid[1], _Digits), DoubleToString(bb1_lower[1], _Digits)));
|
||
|
|
ObjectSetString(0, "DB_BB2", OBJPROP_TEXT, StringFormat("BB2 (20) : Upper: %s | Mid: %s | Lower: %s", DoubleToString(bb2_upper[1], _Digits), DoubleToString(bb2_mid[1], _Digits), DoubleToString(bb2_lower[1], _Digits)));
|
||
|
|
ObjectSetString(0, "DB_EMA8", OBJPROP_TEXT, "EMA 8 : " + DoubleToString(ema8[1], _Digits));
|
||
|
|
ObjectSetString(0, "DB_SMA21", OBJPROP_TEXT, "SMA 21 : " + DoubleToString(sma21[1], _Digits));
|
||
|
|
ObjectSetString(0, "DB_EMA50", OBJPROP_TEXT, "EMA 50 : " + DoubleToString(ema50[1], _Digits));
|
||
|
|
ObjectSetString(0, "DB_RSI", OBJPROP_TEXT, StringFormat("RSI : %.2f", rsi[1]));
|
||
|
|
ObjectSetString(0, "DB_ADX", OBJPROP_TEXT, StringFormat("ADX : %.2f", adx[1]));
|
||
|
|
|
||
|
|
// --- EVALUASI LOGIKA ALARM ---
|
||
|
|
double vwap_sim = bb1_mid[1];
|
||
|
|
double bb1_u_cross[3], bb1_m_cross[3], bb1_l_cross[3], bb2_m_cross[3];
|
||
|
|
CopyBuffer(handle_bb1, 1, 0, 3, bb1_u_cross);
|
||
|
|
CopyBuffer(handle_bb1, 0, 0, 3, bb1_m_cross);
|
||
|
|
CopyBuffer(handle_bb1, 2, 0, 3, bb1_l_cross);
|
||
|
|
CopyBuffer(handle_bb2, 0, 0, 3, bb2_m_cross);
|
||
|
|
|
||
|
|
bool L1_Buy = (bb2_m_cross[1] > bb1_u_cross[1] && bb2_m_cross[2] <= bb1_u_cross[2]) || (bb2_m_cross[1] > bb1_m_cross[1] && bb2_m_cross[2] <= bb1_m_cross[2]) || (bb2_m_cross[1] > bb1_l_cross[1] && bb2_m_cross[2] <= bb1_l_cross[2]);
|
||
|
|
bool L1_Sell = (bb2_m_cross[1] < bb1_u_cross[1] && bb2_m_cross[2] >= bb1_u_cross[2]) || (bb2_m_cross[1] < bb1_m_cross[1] && bb2_m_cross[2] >= bb1_m_cross[2]) || (bb2_m_cross[1] < bb1_l_cross[1] && bb2_m_cross[2] >= bb1_l_cross[2]);
|
||
|
|
bool L2_Buy = (ema8[1] > sma21[1]) && (close_price[1] > ema50[1]);
|
||
|
|
bool L2_Sell = (ema8[1] < sma21[1]) && (close_price[1] < ema50[1]);
|
||
|
|
bool L3_Buy = (psar[1] < low_p[1]);
|
||
|
|
bool L3_Sell = (psar[1] > high_p[1]);
|
||
|
|
bool L4_Buy = (close_price[1] > vwap_sim);
|
||
|
|
bool L4_Sell = (close_price[1] < vwap_sim);
|
||
|
|
|
||
|
|
// Ganti warna status rekomendasi utama
|
||
|
|
datetime current_bar_time = iTime(_Symbol, _Period, 0);
|
||
|
|
if(L1_Buy && L2_Buy && L3_Buy && L4_Buy)
|
||
|
|
{
|
||
|
|
ObjectSetString(0, "DB_Status", OBJPROP_TEXT, "STATUS: REKOMENDASI >>> BUY SIGNAL VALID <<<");
|
||
|
|
ObjectSetInteger(0, "DB_Status", OBJPROP_COLOR, clrLime);
|
||
|
|
if(current_bar_time != time_last_bar) { Alert(_Symbol+" M1 - BUY VALID!"); time_last_bar = current_bar_time; }
|
||
|
|
}
|
||
|
|
else if(L1_Sell && L2_Sell && L3_Sell && L4_Sell)
|
||
|
|
{
|
||
|
|
ObjectSetString(0, "DB_Status", OBJPROP_TEXT, "STATUS: REKOMENDASI >>> SELL SIGNAL VALID <<<");
|
||
|
|
ObjectSetInteger(0, "DB_Status", OBJPROP_COLOR, clrRed);
|
||
|
|
if(current_bar_time != time_last_bar) { Alert(_Symbol+" M1 - SELL VALID!"); time_last_bar = current_bar_time; }
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
ObjectSetString(0, "DB_Status", OBJPROP_TEXT, "STATUS: REKOMENDASI >>> WAIT (WAITING SIGNAL) <<<");
|
||
|
|
ObjectSetInteger(0, "DB_Status", OBJPROP_COLOR, clrYellow);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Update Jarak Target ATR
|
||
|
|
double sl_dist = NormalizeDouble(atr[1] * InpATR_Multiplier_SL, _Digits);
|
||
|
|
double tp_dist = NormalizeDouble(atr[1] * InpATR_Multiplier_TP, _Digits);
|
||
|
|
ObjectSetString(0, "DB_Targets", OBJPROP_TEXT, StringFormat("Proyeksi Jarak SL Manual: %s | Jarak TP: %s", DoubleToString(sl_dist, _Digits), DoubleToString(tp_dist, _Digits)));
|
||
|
|
|
||
|
|
return(rates_total);
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Fungsi Pembantu Membuat Label Teks |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CreateLabel(string name, int x, int y, string text, int size, color col)
|
||
|
|
{
|
||
|
|
ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
|
||
|
|
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
|
||
|
|
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
|
||
|
|
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, size);
|
||
|
|
ObjectSetString(0, name, OBJPROP_FONT, "Consolas"); // Menggunakan font berspasi seragam agar sejajar rapi
|
||
|
|
ObjectSetString(0, name, OBJPROP_TEXT, text);
|
||
|
|
ObjectSetInteger(0, name, OBJPROP_COLOR, col);
|
||
|
|
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
|
||
|
|
}
|