531 lines
22 KiB
MQL5
531 lines
22 KiB
MQL5
|
|
//╔════════════════════════════════════════════════════════════════════════╗
|
||
|
|
//║ ██████╗██╗ ██╗ █████╗ ██████╗ ██████╗ █████╗ █████╗ █████╗ ███╗ ██╗ ║
|
||
|
|
//║ ██╔═══╝╚██╗██╔╝██╔══██╗██╔══██╗██╔═══╝██╔══██╗██╔═══╝██╔══██╗████╗ ██║ ║
|
||
|
|
//║ █████╗ ╚███╔╝ ██║ ██║██████╔╝█████╗ ███████║██║ ██║ ██║██╔██╗██║ ║
|
||
|
|
//║ ██╔══╝ ██╔██╗ ██║ ██║██╔══██╗██╔══╝ ██╔══██║██║ ██║ ██║██║╚████║ ║
|
||
|
|
//║ ██████╗██╔╝ ██╗╚█████╔╝██████╔╝██████╗██║ ██║╚█████╗╚█████╔╝██║ ╚███║ ║
|
||
|
|
//║ ╚═════╝╚═╝ ╚═╝ ╚════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚════╝ ╚════╝ ╚═╝ ╚══╝ ║
|
||
|
|
//╚═══════ Algorithms that observe ══════ Signals that speak ══════════════╝
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Faithful MQL5 conversion of "UT Bot Alerts" by QuantNomad |
|
||
|
|
//| Original Pine Script: tradingview.com/script/n8ss8BID |
|
||
|
|
//| Originally developed by Yo_adriiiiaan, idea by HPotter |
|
||
|
|
//| Pine Script v4 alerts version by QuantNomad (Vadim Cissa) |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Algorithm: ATR-based adaptive trailing stop with crossover |
|
||
|
|
//| detection for buy/sell signal generation. |
|
||
|
|
//| |
|
||
|
|
//| The trailing stop uses a 4-branch recursive logic: |
|
||
|
|
//| 1. Uptrend continuation -> stop ratchets UP only |
|
||
|
|
//| 2. Downtrend continuation -> stop ratchets DOWN only |
|
||
|
|
//| 3. Bullish reversal -> reset stop = price - nLoss |
|
||
|
|
//| 4. Bearish reversal -> reset stop = price + nLoss |
|
||
|
|
//| |
|
||
|
|
//| Signals fire on the bar where price crosses the trailing stop. |
|
||
|
|
//| Non-repainting on confirmed (closed) bars. |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#property copyright "Exobeacon Labs"
|
||
|
|
#property link "https://www.exobeacon.com"
|
||
|
|
#property version "1.0"
|
||
|
|
#property description "UT Bot Alerts - ATR Trailing Stop System"
|
||
|
|
#property description "Converted from TradingView Pine Script by QuantNomad"
|
||
|
|
#property description " "
|
||
|
|
#property description "Generates Buy/Sell signals when price crosses an"
|
||
|
|
#property description "adaptive ATR-based trailing stop line."
|
||
|
|
#property description " "
|
||
|
|
#property description "〰〰〰〰〰((👽))〰〰〰〰〰"
|
||
|
|
#property description "🛸 mql5.com/en/users/ulisescalb"
|
||
|
|
#property description "🛸 github.com/Exobeacon-Labs"
|
||
|
|
#property strict
|
||
|
|
#property indicator_chart_window
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Buffer Layout (10 buffers, 4 plots) |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
// Plot 0: DRAW_COLOR_LINE -> Buf[0]=data, Buf[1]=color |
|
||
|
|
// Plot 1: DRAW_ARROW (Buy) -> Buf[2]=data |
|
||
|
|
// Plot 2: DRAW_ARROW (Sell)-> Buf[3]=data |
|
||
|
|
// Plot 3: DRAW_COLOR_CANDLES -> Buf[4..7]=OHLC, Buf[8]=color |
|
||
|
|
// Calc: Buf[9] = Position state |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#property indicator_buffers 10
|
||
|
|
#property indicator_plots 4
|
||
|
|
|
||
|
|
//--- Plot 0: ATR Trailing Stop Line
|
||
|
|
#property indicator_label1 "ATR Trailing Stop"
|
||
|
|
#property indicator_type1 DRAW_COLOR_LINE
|
||
|
|
#property indicator_color1 clrLime, clrRed, clrDodgerBlue
|
||
|
|
#property indicator_style1 STYLE_SOLID
|
||
|
|
#property indicator_width1 2
|
||
|
|
|
||
|
|
//--- Plot 1: Buy Signal Arrow
|
||
|
|
#property indicator_label2 "Buy Signal"
|
||
|
|
#property indicator_type2 DRAW_ARROW
|
||
|
|
#property indicator_color2 clrLime
|
||
|
|
#property indicator_style2 STYLE_SOLID
|
||
|
|
#property indicator_width2 2
|
||
|
|
|
||
|
|
//--- Plot 2: Sell Signal Arrow
|
||
|
|
#property indicator_label3 "Sell Signal"
|
||
|
|
#property indicator_type3 DRAW_ARROW
|
||
|
|
#property indicator_color3 clrRed
|
||
|
|
#property indicator_style3 STYLE_SOLID
|
||
|
|
#property indicator_width3 2
|
||
|
|
|
||
|
|
//--- Plot 3: Colored Candles (Bar Coloring)
|
||
|
|
#property indicator_label4 "Bar Color"
|
||
|
|
#property indicator_type4 DRAW_COLOR_CANDLES
|
||
|
|
#property indicator_color4 clrLime, clrRed, clrNONE
|
||
|
|
#property indicator_style4 STYLE_SOLID
|
||
|
|
#property indicator_width4 1
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Input Parameters |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Pine Script mapping: |
|
||
|
|
//| a = input(1, "Key Vaule...") -> InpKeyValue |
|
||
|
|
//| c = input(10, "ATR Period") -> InpATRPeriod |
|
||
|
|
//| h = input(false, "Signals from...") -> InpUseHeikinAshi |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
input group "============ UT Bot Core ============"
|
||
|
|
input double InpKeyValue = 1.0; // Key Value (ATR Multiplier / Sensitivity)
|
||
|
|
input int InpATRPeriod = 10; // ATR Period
|
||
|
|
input bool InpUseHeikinAshi = false; // Use Heikin Ashi Candles as Source
|
||
|
|
|
||
|
|
input group "============ Visuals ============"
|
||
|
|
input bool InpShowTrailLine = true; // Show Trailing Stop Line
|
||
|
|
input bool InpShowSignals = true; // Show Buy/Sell Arrows
|
||
|
|
input bool InpColorBars = true; // Color Price Bars
|
||
|
|
input int InpArrowOffset = 10; // Arrow Distance from Bar (points)
|
||
|
|
|
||
|
|
input group "============ Alerts ============"
|
||
|
|
input bool InpAlertPopup = true; // Popup Alert
|
||
|
|
input bool InpAlertSound = true; // Sound Alert
|
||
|
|
input bool InpAlertPush = false; // Push Notification
|
||
|
|
input bool InpAlertEmail = false; // Email Notification
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Indicator Buffers |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
double TrailLineBuffer[]; // [0] Trail stop values
|
||
|
|
double TrailColorBuffer[]; // [1] Trail stop color index
|
||
|
|
double BuyArrowBuffer[]; // [2] Buy arrow positions
|
||
|
|
double SellArrowBuffer[]; // [3] Sell arrow positions
|
||
|
|
double BarOpenBuffer[]; // [4] Candle Open for coloring
|
||
|
|
double BarHighBuffer[]; // [5] Candle High for coloring
|
||
|
|
double BarLowBuffer[]; // [6] Candle Low for coloring
|
||
|
|
double BarCloseBuffer[]; // [7] Candle Close for coloring
|
||
|
|
double BarColorBuffer[]; // [8] Candle color index
|
||
|
|
double PosBuffer[]; // [9] Position state (calculation only)
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Internal calculation arrays (not tied to plots) |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
double g_trail[]; // Internal trailing stop (always calculated)
|
||
|
|
double g_pos[]; // Internal position state (always calculated)
|
||
|
|
double g_src[]; // Source price array
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Global Variables |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int g_atrHandle = INVALID_HANDLE;
|
||
|
|
datetime g_lastAlertBar = 0;
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Custom indicator initialization |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int OnInit()
|
||
|
|
{
|
||
|
|
//--- Validate inputs
|
||
|
|
if(InpATRPeriod < 1)
|
||
|
|
{
|
||
|
|
PrintFormat("[UTBot] ATR Period must be >= 1 (got %d)", InpATRPeriod);
|
||
|
|
return INIT_PARAMETERS_INCORRECT;
|
||
|
|
}
|
||
|
|
if(InpKeyValue <= 0.0)
|
||
|
|
{
|
||
|
|
PrintFormat("[UTBot] Key Value must be > 0 (got %.4f)", InpKeyValue);
|
||
|
|
return INIT_PARAMETERS_INCORRECT;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Create ATR handle
|
||
|
|
// MT5 iATR uses Wilder's smoothing (RMA) = matches TradingView's atr()
|
||
|
|
g_atrHandle = iATR(_Symbol, PERIOD_CURRENT, InpATRPeriod);
|
||
|
|
if(g_atrHandle == INVALID_HANDLE)
|
||
|
|
{
|
||
|
|
Print("[UTBot] Failed to create ATR handle");
|
||
|
|
return INIT_FAILED;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Bind buffers to plots
|
||
|
|
// IMPORTANT: Never change PLOT_DRAW_TYPE after binding.
|
||
|
|
// Changing to DRAW_NONE corrupts the buffer-to-plot mapping
|
||
|
|
// in MT5. Visibility is controlled via EMPTY_VALUE in OnCalculate.
|
||
|
|
|
||
|
|
// Plot 0: Trailing Stop (DRAW_COLOR_LINE = 2 buffers)
|
||
|
|
SetIndexBuffer(0, TrailLineBuffer, INDICATOR_DATA);
|
||
|
|
SetIndexBuffer(1, TrailColorBuffer, INDICATOR_COLOR_INDEX);
|
||
|
|
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
|
||
|
|
|
||
|
|
// Plot 1: Buy Arrow (DRAW_ARROW = 1 buffer)
|
||
|
|
SetIndexBuffer(2, BuyArrowBuffer, INDICATOR_DATA);
|
||
|
|
PlotIndexSetInteger(1, PLOT_ARROW, 233); // Wingdings up arrow
|
||
|
|
PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
|
||
|
|
|
||
|
|
// Plot 2: Sell Arrow (DRAW_ARROW = 1 buffer)
|
||
|
|
SetIndexBuffer(3, SellArrowBuffer, INDICATOR_DATA);
|
||
|
|
PlotIndexSetInteger(2, PLOT_ARROW, 234); // Wingdings down arrow
|
||
|
|
PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);
|
||
|
|
|
||
|
|
// Plot 3: Colored Candles (DRAW_COLOR_CANDLES = 4 data + 1 color)
|
||
|
|
SetIndexBuffer(4, BarOpenBuffer, INDICATOR_DATA);
|
||
|
|
SetIndexBuffer(5, BarHighBuffer, INDICATOR_DATA);
|
||
|
|
SetIndexBuffer(6, BarLowBuffer, INDICATOR_DATA);
|
||
|
|
SetIndexBuffer(7, BarCloseBuffer, INDICATOR_DATA);
|
||
|
|
SetIndexBuffer(8, BarColorBuffer, INDICATOR_COLOR_INDEX);
|
||
|
|
PlotIndexSetDouble(3, PLOT_EMPTY_VALUE, EMPTY_VALUE);
|
||
|
|
|
||
|
|
// Calculation-only buffer
|
||
|
|
SetIndexBuffer(9, PosBuffer, INDICATOR_CALCULATIONS);
|
||
|
|
|
||
|
|
//--- All buffers: left-to-right indexing (index 0 = oldest bar)
|
||
|
|
ArraySetAsSeries(TrailLineBuffer, false);
|
||
|
|
ArraySetAsSeries(TrailColorBuffer, false);
|
||
|
|
ArraySetAsSeries(BuyArrowBuffer, false);
|
||
|
|
ArraySetAsSeries(SellArrowBuffer, false);
|
||
|
|
ArraySetAsSeries(BarOpenBuffer, false);
|
||
|
|
ArraySetAsSeries(BarHighBuffer, false);
|
||
|
|
ArraySetAsSeries(BarLowBuffer, false);
|
||
|
|
ArraySetAsSeries(BarCloseBuffer, false);
|
||
|
|
ArraySetAsSeries(BarColorBuffer, false);
|
||
|
|
ArraySetAsSeries(PosBuffer, false);
|
||
|
|
|
||
|
|
//--- Short name
|
||
|
|
IndicatorSetString(INDICATOR_SHORTNAME,
|
||
|
|
StringFormat("UT Bot (%.1f, %d%s)",
|
||
|
|
InpKeyValue, InpATRPeriod,
|
||
|
|
InpUseHeikinAshi ? ", HA" : ""));
|
||
|
|
IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
|
||
|
|
|
||
|
|
return INIT_SUCCEEDED;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Custom indicator deinitialization |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void OnDeinit(const int reason)
|
||
|
|
{
|
||
|
|
if(g_atrHandle != INVALID_HANDLE)
|
||
|
|
{
|
||
|
|
IndicatorRelease(g_atrHandle);
|
||
|
|
g_atrHandle = INVALID_HANDLE;
|
||
|
|
}
|
||
|
|
|
||
|
|
ArrayFree(g_trail);
|
||
|
|
ArrayFree(g_pos);
|
||
|
|
ArrayFree(g_src);
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Calculate Heikin Ashi Close |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Pine: security(heikinashi(syminfo.tickerid), ..., close) |
|
||
|
|
//| HA Close = (O + H + L + C) / 4 |
|
||
|
|
//| HA Open = (prev_HA_Open + prev_HA_Close) / 2 |
|
||
|
|
//| We only need HA Close as the source price for UT Bot. |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CalcHeikinAshiClose(const double &open[],
|
||
|
|
const double &high[],
|
||
|
|
const double &low[],
|
||
|
|
const double &close[],
|
||
|
|
double &ha_close[],
|
||
|
|
const int total)
|
||
|
|
{
|
||
|
|
if(total < 1) return;
|
||
|
|
|
||
|
|
double ha_open_val = open[0];
|
||
|
|
ha_close[0] = (open[0] + high[0] + low[0] + close[0]) / 4.0;
|
||
|
|
|
||
|
|
for(int i = 1; i < total; i++)
|
||
|
|
{
|
||
|
|
ha_open_val = (ha_open_val + ha_close[i - 1]) / 2.0;
|
||
|
|
ha_close[i] = (open[i] + high[i] + low[i] + close[i]) / 4.0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Fire alert (once per bar) |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void FireAlert(const bool is_buy, const datetime bar_time)
|
||
|
|
{
|
||
|
|
if(bar_time == g_lastAlertBar)
|
||
|
|
return;
|
||
|
|
g_lastAlertBar = bar_time;
|
||
|
|
|
||
|
|
string dir = is_buy ? "BUY" : "SELL";
|
||
|
|
string msg = StringFormat("[UT Bot] %s on %s %s | %s",
|
||
|
|
dir, _Symbol, EnumToString(_Period),
|
||
|
|
TimeToString(bar_time, TIME_DATE | TIME_MINUTES));
|
||
|
|
|
||
|
|
if(InpAlertPopup) Alert(msg);
|
||
|
|
if(InpAlertSound) PlaySound(is_buy ? "alert.wav" : "alert2.wav");
|
||
|
|
if(InpAlertPush) SendNotification(msg);
|
||
|
|
if(InpAlertEmail) SendMail("UT Bot: " + dir, msg);
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Main calculation |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
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[])
|
||
|
|
{
|
||
|
|
//--- Minimum bars required
|
||
|
|
int min_bars = InpATRPeriod + 2;
|
||
|
|
if(rates_total < min_bars)
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
//--- Set price arrays to left-to-right indexing
|
||
|
|
ArraySetAsSeries(time, false);
|
||
|
|
ArraySetAsSeries(open, false);
|
||
|
|
ArraySetAsSeries(high, false);
|
||
|
|
ArraySetAsSeries(low, false);
|
||
|
|
ArraySetAsSeries(close, false);
|
||
|
|
|
||
|
|
//--- Retrieve ATR values from built-in indicator
|
||
|
|
double atr[];
|
||
|
|
ArrayResize(atr, rates_total);
|
||
|
|
ArraySetAsSeries(atr, false);
|
||
|
|
if(CopyBuffer(g_atrHandle, 0, 0, rates_total, atr) != rates_total)
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
//--- Resize internal arrays
|
||
|
|
ArrayResize(g_trail, rates_total);
|
||
|
|
ArrayResize(g_pos, rates_total);
|
||
|
|
ArrayResize(g_src, rates_total);
|
||
|
|
|
||
|
|
//--- Build source price array
|
||
|
|
if(InpUseHeikinAshi)
|
||
|
|
CalcHeikinAshiClose(open, high, low, close, g_src, rates_total);
|
||
|
|
else
|
||
|
|
ArrayCopy(g_src, close, 0, 0, rates_total);
|
||
|
|
|
||
|
|
//--- Determine starting bar
|
||
|
|
int start;
|
||
|
|
if(prev_calculated <= 0)
|
||
|
|
{
|
||
|
|
//--- First run: initialize all output buffers
|
||
|
|
ArrayInitialize(TrailLineBuffer, EMPTY_VALUE);
|
||
|
|
ArrayInitialize(TrailColorBuffer, 0.0);
|
||
|
|
ArrayInitialize(BuyArrowBuffer, EMPTY_VALUE);
|
||
|
|
ArrayInitialize(SellArrowBuffer, EMPTY_VALUE);
|
||
|
|
ArrayInitialize(BarOpenBuffer, EMPTY_VALUE);
|
||
|
|
ArrayInitialize(BarHighBuffer, EMPTY_VALUE);
|
||
|
|
ArrayInitialize(BarLowBuffer, EMPTY_VALUE);
|
||
|
|
ArrayInitialize(BarCloseBuffer, EMPTY_VALUE);
|
||
|
|
ArrayInitialize(BarColorBuffer, 0.0);
|
||
|
|
ArrayInitialize(PosBuffer, 0.0);
|
||
|
|
|
||
|
|
//--- Initialize internal arrays
|
||
|
|
ArrayInitialize(g_trail, 0.0);
|
||
|
|
ArrayInitialize(g_pos, 0.0);
|
||
|
|
|
||
|
|
//--- Seed bar 0
|
||
|
|
// Pine Script: nz(xATRTrailingStop[1], 0) = 0 on first bar
|
||
|
|
// Since src > 0 always, branch 3 fires: trail = src - nLoss
|
||
|
|
// We seed directly with src for stability.
|
||
|
|
g_trail[0] = g_src[0];
|
||
|
|
g_pos[0] = 0.0;
|
||
|
|
|
||
|
|
start = 1;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
//--- Subsequent calls: recalculate from last bar
|
||
|
|
start = prev_calculated - 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
//=================================================================
|
||
|
|
// MAIN LOOP: Bar-by-bar processing (left to right)
|
||
|
|
// Mirrors Pine Script's execution model exactly.
|
||
|
|
//
|
||
|
|
// PHASE 1: Core algorithm on internal arrays (always runs)
|
||
|
|
// PHASE 2: Map results to display buffers (respects visibility)
|
||
|
|
//=================================================================
|
||
|
|
for(int i = start; i < rates_total; i++)
|
||
|
|
{
|
||
|
|
double curr_src = g_src[i];
|
||
|
|
double prev_src = g_src[i - 1];
|
||
|
|
double prev_trail = g_trail[i - 1];
|
||
|
|
double nLoss = InpKeyValue * atr[i];
|
||
|
|
|
||
|
|
//============================================================
|
||
|
|
// PHASE 1a: ATR Trailing Stop — 4-Branch Recursive Logic
|
||
|
|
//============================================================
|
||
|
|
// Pine Script:
|
||
|
|
// xATRTrailingStop := iff(
|
||
|
|
// src > nz(trail[1],0) and src[1] > nz(trail[1],0),
|
||
|
|
// max(nz(trail[1]), src - nLoss),
|
||
|
|
// iff(
|
||
|
|
// src < nz(trail[1],0) and src[1] < nz(trail[1],0),
|
||
|
|
// min(nz(trail[1]), src + nLoss),
|
||
|
|
// iff(src > nz(trail[1],0),
|
||
|
|
// src - nLoss,
|
||
|
|
// src + nLoss)))
|
||
|
|
//============================================================
|
||
|
|
double trail;
|
||
|
|
|
||
|
|
if(curr_src > prev_trail && prev_src > prev_trail)
|
||
|
|
{
|
||
|
|
// Branch 1: Uptrend continuation — ratchet up only
|
||
|
|
trail = MathMax(prev_trail, curr_src - nLoss);
|
||
|
|
}
|
||
|
|
else if(curr_src < prev_trail && prev_src < prev_trail)
|
||
|
|
{
|
||
|
|
// Branch 2: Downtrend continuation — ratchet down only
|
||
|
|
trail = MathMin(prev_trail, curr_src + nLoss);
|
||
|
|
}
|
||
|
|
else if(curr_src > prev_trail)
|
||
|
|
{
|
||
|
|
// Branch 3: Bullish reversal — reset below price
|
||
|
|
trail = curr_src - nLoss;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// Branch 4: Bearish reversal — reset above price
|
||
|
|
trail = curr_src + nLoss;
|
||
|
|
}
|
||
|
|
|
||
|
|
g_trail[i] = trail;
|
||
|
|
|
||
|
|
//============================================================
|
||
|
|
// PHASE 1b: Position State
|
||
|
|
//============================================================
|
||
|
|
// Pine Script:
|
||
|
|
// pos := iff(src[1] < nz(trail[1],0) and src > nz(trail[1],0), 1,
|
||
|
|
// iff(src[1] > nz(trail[1],0) and src < nz(trail[1],0), -1,
|
||
|
|
// nz(pos[1], 0)))
|
||
|
|
//============================================================
|
||
|
|
if(prev_src < prev_trail && curr_src > prev_trail)
|
||
|
|
g_pos[i] = 1.0; // Flip LONG
|
||
|
|
else if(prev_src > prev_trail && curr_src < prev_trail)
|
||
|
|
g_pos[i] = -1.0; // Flip SHORT
|
||
|
|
else
|
||
|
|
g_pos[i] = g_pos[i - 1]; // Hold
|
||
|
|
|
||
|
|
//============================================================
|
||
|
|
// PHASE 1c: Signal Detection (Crossovers)
|
||
|
|
//============================================================
|
||
|
|
// Pine Script:
|
||
|
|
// ema = ema(src, 1) <- equals src exactly (period 1)
|
||
|
|
// above = crossover(ema, xATRTrailingStop)
|
||
|
|
// below = crossover(xATRTrailingStop, ema)
|
||
|
|
// buy = src > xATRTrailingStop and above
|
||
|
|
// sell = src < xATRTrailingStop and below
|
||
|
|
//
|
||
|
|
// crossover(A,B) = A[now] > B[now] AND A[prev] <= B[prev]
|
||
|
|
//============================================================
|
||
|
|
bool above = (curr_src > trail) && (prev_src <= prev_trail);
|
||
|
|
bool below = (curr_src < trail) && (prev_src >= prev_trail);
|
||
|
|
|
||
|
|
bool buy_signal = (curr_src > trail) && above;
|
||
|
|
bool sell_signal = (curr_src < trail) && below;
|
||
|
|
|
||
|
|
//============================================================
|
||
|
|
// PHASE 2a: Trailing Stop Line Display
|
||
|
|
//============================================================
|
||
|
|
if(InpShowTrailLine)
|
||
|
|
{
|
||
|
|
TrailLineBuffer[i] = trail;
|
||
|
|
|
||
|
|
// Color: 0=Green(long), 1=Red(short), 2=Blue(neutral)
|
||
|
|
// NOTE: DRAW_COLOR_LINE in MT5 paints the incoming segment
|
||
|
|
// (from bar i-1 TO bar i) using TrailColorBuffer[i].
|
||
|
|
// Using g_pos[i-1] ensures the color change aligns visually
|
||
|
|
// with the signal arrow at bar i, not one bar before it.
|
||
|
|
double pos_for_color = (i >= 1) ? g_pos[i - 1] : 0.0;
|
||
|
|
if(pos_for_color > 0.5)
|
||
|
|
TrailColorBuffer[i] = 0.0;
|
||
|
|
else if(pos_for_color < -0.5)
|
||
|
|
TrailColorBuffer[i] = 1.0;
|
||
|
|
else
|
||
|
|
TrailColorBuffer[i] = 2.0;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
TrailLineBuffer[i] = EMPTY_VALUE;
|
||
|
|
TrailColorBuffer[i] = 0.0;
|
||
|
|
}
|
||
|
|
|
||
|
|
//============================================================
|
||
|
|
// PHASE 2b: Buy/Sell Arrows
|
||
|
|
//============================================================
|
||
|
|
BuyArrowBuffer[i] = EMPTY_VALUE;
|
||
|
|
SellArrowBuffer[i] = EMPTY_VALUE;
|
||
|
|
|
||
|
|
if(InpShowSignals)
|
||
|
|
{
|
||
|
|
if(buy_signal)
|
||
|
|
BuyArrowBuffer[i] = low[i] - InpArrowOffset * _Point;
|
||
|
|
|
||
|
|
if(sell_signal)
|
||
|
|
SellArrowBuffer[i] = high[i] + InpArrowOffset * _Point;
|
||
|
|
}
|
||
|
|
|
||
|
|
//============================================================
|
||
|
|
// PHASE 2c: Bar Coloring
|
||
|
|
//============================================================
|
||
|
|
// Pine Script:
|
||
|
|
// barbuy = src > xATRTrailingStop
|
||
|
|
// barsell = src < xATRTrailingStop
|
||
|
|
// barcolor(barbuy ? green : na)
|
||
|
|
// barcolor(barsell ? red : na)
|
||
|
|
//============================================================
|
||
|
|
if(InpColorBars)
|
||
|
|
{
|
||
|
|
BarOpenBuffer[i] = open[i];
|
||
|
|
BarHighBuffer[i] = high[i];
|
||
|
|
BarLowBuffer[i] = low[i];
|
||
|
|
BarCloseBuffer[i] = close[i];
|
||
|
|
|
||
|
|
if(curr_src > trail)
|
||
|
|
BarColorBuffer[i] = 0.0; // Green
|
||
|
|
else if(curr_src < trail)
|
||
|
|
BarColorBuffer[i] = 1.0; // Red
|
||
|
|
else
|
||
|
|
BarColorBuffer[i] = 2.0; // None
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
BarOpenBuffer[i] = EMPTY_VALUE;
|
||
|
|
BarHighBuffer[i] = EMPTY_VALUE;
|
||
|
|
BarLowBuffer[i] = EMPTY_VALUE;
|
||
|
|
BarCloseBuffer[i] = EMPTY_VALUE;
|
||
|
|
BarColorBuffer[i] = 0.0;
|
||
|
|
}
|
||
|
|
|
||
|
|
//============================================================
|
||
|
|
// PHASE 2d: Position buffer (for EA access via iCustom)
|
||
|
|
//============================================================
|
||
|
|
PosBuffer[i] = g_pos[i];
|
||
|
|
|
||
|
|
//============================================================
|
||
|
|
// PHASE 3: Alerts (last confirmed bar only)
|
||
|
|
//============================================================
|
||
|
|
if(i == rates_total - 2)
|
||
|
|
{
|
||
|
|
if(buy_signal) FireAlert(true, time[i]);
|
||
|
|
if(sell_signal) FireAlert(false, time[i]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return rates_total;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|