New EA and Indi

This commit is contained in:
Kunthawat Greethong
2026-01-25 10:34:54 +07:00
parent 39ce46877e
commit 04aa2eb2e6
37 changed files with 17051 additions and 0 deletions

View File

@@ -0,0 +1,753 @@
//+------------------------------------------------------------------+
//| Base_EMA_Reversal.mq5 |
//| Multi-Stage EMA Reversal Signal Indicator |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025"
#property link ""
#property version "1.00"
#property indicator_chart_window
// Properties
#property indicator_buffers 15
#property indicator_plots 6
// Plot configurations - Signal plots (6)
#property indicator_label1 "BUY_SIGNAL"
#property indicator_type1 DRAW_ARROW
#property indicator_color1 clrLime
#property indicator_style1 STYLE_SOLID
#property indicator_width1 2
#property indicator_label2 "SELL_SIGNAL"
#property indicator_type2 DRAW_ARROW
#property indicator_color2 clrRed
#property indicator_style2 STYLE_SOLID
#property indicator_width2 2
#property indicator_label3 "BUY_SL"
#property indicator_type3 DRAW_ARROW
#property indicator_color3 clrGray
#property indicator_style3 STYLE_SOLID
#property indicator_width3 1
#property indicator_label4 "SELL_SL"
#property indicator_type4 DRAW_ARROW
#property indicator_color4 clrGray
#property indicator_style4 STYLE_SOLID
#property indicator_width4 1
#property indicator_label5 "BUY_TP"
#property indicator_type5 DRAW_ARROW
#property indicator_color5 clrBlue
#property indicator_style5 STYLE_SOLID
#property indicator_width5 1
#property indicator_label6 "SELL_TP"
#property indicator_type6 DRAW_ARROW
#property indicator_color6 clrBlue
#property indicator_style6 STYLE_SOLID
#property indicator_width6 1
// EMA Line plots (7)
#property indicator_label7 "EMA_50"
#property indicator_type7 DRAW_LINE
#property indicator_color7 clrRed
#property indicator_style7 STYLE_SOLID
#property indicator_width7 1
#property indicator_label8 "EMA_100"
#property indicator_type8 DRAW_LINE
#property indicator_color8 clrOrange
#property indicator_style8 STYLE_SOLID
#property indicator_width8 1
#property indicator_label9 "EMA_200"
#property indicator_type9 DRAW_LINE
#property indicator_color9 clrYellow
#property indicator_style9 STYLE_SOLID
#property indicator_width9 1
#property indicator_label10 "EMA_300"
#property indicator_type10 DRAW_LINE
#property indicator_color10 clrGreen
#property indicator_style10 STYLE_SOLID
#property indicator_width10 1
#property indicator_label11 "EMA_400"
#property indicator_type11 DRAW_LINE
#property indicator_color11 clrBlue
#property indicator_style11 STYLE_SOLID
#property indicator_width11 1
#property indicator_label12 "EMA_500"
#property indicator_type12 DRAW_LINE
#property indicator_color12 clrPurple
#property indicator_style12 STYLE_SOLID
#property indicator_width12 1
#property indicator_label13 "EMA_600"
#property indicator_type13 DRAW_LINE
#property indicator_color13 clrMagenta
#property indicator_style13 STYLE_SOLID
#property indicator_width13 1
//+------------------------------------------------------------------+
//| Input Parameters |
//+------------------------------------------------------------------+
input group "=== EMA Settings ==="
input int InpEMA50_Period = 50;
input int InpEMA100_Period = 100;
input int InpEMA200_Period = 200;
input int InpEMA300_Period = 300;
input int InpEMA400_Period = 400;
input int InpEMA500_Period = 500;
input int InpEMA600_Period = 600;
input group "=== Setup Settings ==="
input int InpLookbackPeriod = 100; // Lookback bars for base detection
input double InpBaseThreshold = 50; // Pullback threshold (points)
input int InpPullbackBars = 2; // Max bars to wait for pullback
input int InpSkipBars = 50; // Bars to skip at startup
input group "=== ATR Settings ==="
input int InpATRPeriod = 14; // ATR period for TP fallback
input group "=== Display Settings ==="
input bool InpShowStageLabels = true; // Show stage labels on chart
//+------------------------------------------------------------------+
//| Indicator Buffers |
//+------------------------------------------------------------------+
double BuySignalBuffer[];
double SellSignalBuffer[];
double BuySLBuffer[];
double SellSLBuffer[];
double BuyTPBuffer[];
double SellTPBuffer[];
double BuyStateBuffer[];
double SellStateBuffer[];
// EMA Line buffers for display
double EMA50_Buffer[];
double EMA100_Buffer[];
double EMA200_Buffer[];
double EMA300_Buffer[];
double EMA400_Buffer[];
double EMA500_Buffer[];
double EMA600_Buffer[];
//+------------------------------------------------------------------+
//| EMA Handles |
//+------------------------------------------------------------------+
int h_ema50, h_ema100, h_ema200;
int h_ema300, h_ema400, h_ema500, h_ema600;
int h_atr;
//+------------------------------------------------------------------+
//| State Tracking Variables |
//+------------------------------------------------------------------+
int buy_state = 0;
int sell_state = 0;
double BaseLow = 0;
double BaseHigh = 0;
datetime last_signal_time = 0;
// EMA touch tracking
bool buy_ema_touched = false;
bool sell_ema_touched = false;
int ema_touch_bar = -1;
int buy_touch_ema_count = 0;
int sell_touch_ema_count = 0;
//+------------------------------------------------------------------+
//| OnInit |
//+------------------------------------------------------------------+
int OnInit()
{
// Create EMA handles
h_ema50 = iMA(_Symbol, _Period, InpEMA50_Period, 0, MODE_EMA, PRICE_CLOSE);
h_ema100 = iMA(_Symbol, _Period, InpEMA100_Period, 0, MODE_EMA, PRICE_CLOSE);
h_ema200 = iMA(_Symbol, _Period, InpEMA200_Period, 0, MODE_EMA, PRICE_CLOSE);
h_ema300 = iMA(_Symbol, _Period, InpEMA300_Period, 0, MODE_EMA, PRICE_CLOSE);
h_ema400 = iMA(_Symbol, _Period, InpEMA400_Period, 0, MODE_EMA, PRICE_CLOSE);
h_ema500 = iMA(_Symbol, _Period, InpEMA500_Period, 0, MODE_EMA, PRICE_CLOSE);
h_ema600 = iMA(_Symbol, _Period, InpEMA600_Period, 0, MODE_EMA, PRICE_CLOSE);
h_atr = iATR(_Symbol, _Period, InpATRPeriod);
// Validate handles
if(h_ema50 == INVALID_HANDLE || h_ema100 == INVALID_HANDLE || h_ema200 == INVALID_HANDLE ||
h_ema300 == INVALID_HANDLE || h_ema400 == INVALID_HANDLE || h_ema500 == INVALID_HANDLE ||
h_ema600 == INVALID_HANDLE || h_atr == INVALID_HANDLE)
{
Print("Error creating indicator handles");
return(INIT_FAILED);
}
// Set buffers
SetIndexBuffer(0, BuySignalBuffer, INDICATOR_DATA);
SetIndexBuffer(1, SellSignalBuffer, INDICATOR_DATA);
SetIndexBuffer(2, BuySLBuffer, INDICATOR_DATA);
SetIndexBuffer(3, SellSLBuffer, INDICATOR_DATA);
SetIndexBuffer(4, BuyTPBuffer, INDICATOR_DATA);
SetIndexBuffer(5, SellTPBuffer, INDICATOR_DATA);
SetIndexBuffer(6, BuyStateBuffer, INDICATOR_CALCULATIONS);
SetIndexBuffer(7, SellStateBuffer, INDICATOR_CALCULATIONS);
// EMA Line buffers
SetIndexBuffer(8, EMA50_Buffer, INDICATOR_DATA);
SetIndexBuffer(9, EMA100_Buffer, INDICATOR_DATA);
SetIndexBuffer(10, EMA200_Buffer, INDICATOR_DATA);
SetIndexBuffer(11, EMA300_Buffer, INDICATOR_DATA);
SetIndexBuffer(12, EMA400_Buffer, INDICATOR_DATA);
SetIndexBuffer(13, EMA500_Buffer, INDICATOR_DATA);
SetIndexBuffer(14, EMA600_Buffer, INDICATOR_DATA);
// Configure plots
PlotIndexSetInteger(0, PLOT_ARROW, 233); // Up arrow for buy
PlotIndexSetInteger(1, PLOT_ARROW, 234); // Down arrow for sell
PlotIndexSetInteger(2, PLOT_ARROW, 159); // Dot for SL
PlotIndexSetInteger(3, PLOT_ARROW, 159); // Dot for SL
PlotIndexSetInteger(4, PLOT_ARROW, 160); // Plus for TP
PlotIndexSetInteger(5, PLOT_ARROW, 160); // Plus for TP
// Set empty values for all plots
for(int i = 0; i < 14; i++)
{
PlotIndexSetDouble(i, PLOT_EMPTY_VALUE, EMPTY_VALUE);
}
Print("Base_EMA_Reversal initialized successfully");
Print("EMA Periods: ", InpEMA50_Period, ", ", InpEMA100_Period, ", ", InpEMA200_Period, ", ",
InpEMA300_Period, ", ", InpEMA400_Period, ", ", InpEMA500_Period, ", ", InpEMA600_Period);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| OnDeinit |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Release handles
if(h_ema50 != INVALID_HANDLE) IndicatorRelease(h_ema50);
if(h_ema100 != INVALID_HANDLE) IndicatorRelease(h_ema100);
if(h_ema200 != INVALID_HANDLE) IndicatorRelease(h_ema200);
if(h_ema300 != INVALID_HANDLE) IndicatorRelease(h_ema300);
if(h_ema400 != INVALID_HANDLE) IndicatorRelease(h_ema400);
if(h_ema500 != INVALID_HANDLE) IndicatorRelease(h_ema500);
if(h_ema600 != INVALID_HANDLE) IndicatorRelease(h_ema600);
if(h_atr != INVALID_HANDLE) IndicatorRelease(h_atr);
// Delete all stage label objects
ObjectsDeleteAll(0, "EMA_Stage_");
Print("Base_EMA_Reversal deinitialized");
}
//+------------------------------------------------------------------+
//| OnCalculate |
//+------------------------------------------------------------------+
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[])
{
// Set arrays as series (index 0 = current bar)
ArraySetAsSeries(time, true);
ArraySetAsSeries(open, true);
ArraySetAsSeries(high, true);
ArraySetAsSeries(low, true);
ArraySetAsSeries(close, true);
ArraySetAsSeries(BuySignalBuffer, true);
ArraySetAsSeries(SellSignalBuffer, true);
ArraySetAsSeries(BuySLBuffer, true);
ArraySetAsSeries(SellSLBuffer, true);
ArraySetAsSeries(BuyTPBuffer, true);
ArraySetAsSeries(SellTPBuffer, true);
ArraySetAsSeries(BuyStateBuffer, true);
ArraySetAsSeries(SellStateBuffer, true);
// Check minimum data requirement
if(rates_total < InpSkipBars + InpLookbackPeriod + InpEMA600_Period)
{
return(0);
}
// Copy EMA data
double ema50[], ema100[], ema200[];
double ema300[], ema400[], ema500[], ema600[];
double atr[];
ArraySetAsSeries(ema50, true);
ArraySetAsSeries(ema100, true);
ArraySetAsSeries(ema200, true);
ArraySetAsSeries(ema300, true);
ArraySetAsSeries(ema400, true);
ArraySetAsSeries(ema500, true);
ArraySetAsSeries(ema600, true);
ArraySetAsSeries(atr, true);
ArraySetAsSeries(EMA50_Buffer, true);
ArraySetAsSeries(EMA100_Buffer, true);
ArraySetAsSeries(EMA200_Buffer, true);
ArraySetAsSeries(EMA300_Buffer, true);
ArraySetAsSeries(EMA400_Buffer, true);
ArraySetAsSeries(EMA500_Buffer, true);
ArraySetAsSeries(EMA600_Buffer, true);
if(CopyBuffer(h_ema50, 0, 0, rates_total, ema50) <= 0) return(0);
if(CopyBuffer(h_ema100, 0, 0, rates_total, ema100) <= 0) return(0);
if(CopyBuffer(h_ema200, 0, 0, rates_total, ema200) <= 0) return(0);
if(CopyBuffer(h_ema300, 0, 0, rates_total, ema300) <= 0) return(0);
if(CopyBuffer(h_ema400, 0, 0, rates_total, ema400) <= 0) return(0);
if(CopyBuffer(h_ema500, 0, 0, rates_total, ema500) <= 0) return(0);
if(CopyBuffer(h_ema600, 0, 0, rates_total, ema600) <= 0) return(0);
if(CopyBuffer(h_atr, 0, 0, rates_total, atr) <= 0) return(0);
// Copy EMA values to display buffers
if(CopyBuffer(h_ema50, 0, 0, rates_total, EMA50_Buffer) <= 0) return(0);
if(CopyBuffer(h_ema100, 0, 0, rates_total, EMA100_Buffer) <= 0) return(0);
if(CopyBuffer(h_ema200, 0, 0, rates_total, EMA200_Buffer) <= 0) return(0);
if(CopyBuffer(h_ema300, 0, 0, rates_total, EMA300_Buffer) <= 0) return(0);
if(CopyBuffer(h_ema400, 0, 0, rates_total, EMA400_Buffer) <= 0) return(0);
if(CopyBuffer(h_ema500, 0, 0, rates_total, EMA500_Buffer) <= 0) return(0);
if(CopyBuffer(h_ema600, 0, 0, rates_total, EMA600_Buffer) <= 0) return(0);
// Calculate start position
int bars_to_process;
int start_bar;
if(prev_calculated == 0)
{
// First calculation - initialize base levels
bars_to_process = rates_total - InpSkipBars - 1;
start_bar = InpSkipBars;
// Initialize BaseLow/BaseHigh from lookback period
int lookback_start = InpSkipBars + InpLookbackPeriod;
int lookback_end = InpSkipBars + 1;
BaseLow = low[lookback_start];
BaseHigh = high[lookback_start];
for(int i = lookback_start; i >= lookback_end; i--)
{
if(low[i] < BaseLow) BaseLow = low[i];
if(high[i] > BaseHigh) BaseHigh = high[i];
}
// Initialize states
buy_state = 1;
sell_state = 1;
buy_ema_touched = false;
sell_ema_touched = false;
ema_touch_bar = -1;
Print("Initialization: BaseLow = ", BaseLow, ", BaseHigh = ", BaseHigh);
// Clear buffers
ArrayInitialize(BuySignalBuffer, EMPTY_VALUE);
ArrayInitialize(SellSignalBuffer, EMPTY_VALUE);
ArrayInitialize(BuySLBuffer, EMPTY_VALUE);
ArrayInitialize(SellSLBuffer, EMPTY_VALUE);
ArrayInitialize(BuyTPBuffer, EMPTY_VALUE);
ArrayInitialize(SellTPBuffer, EMPTY_VALUE);
ArrayInitialize(BuyStateBuffer, 0);
ArrayInitialize(SellStateBuffer, 0);
ArrayInitialize(EMA50_Buffer, EMPTY_VALUE);
ArrayInitialize(EMA100_Buffer, EMPTY_VALUE);
ArrayInitialize(EMA200_Buffer, EMPTY_VALUE);
ArrayInitialize(EMA300_Buffer, EMPTY_VALUE);
ArrayInitialize(EMA400_Buffer, EMPTY_VALUE);
ArrayInitialize(EMA500_Buffer, EMPTY_VALUE);
ArrayInitialize(EMA600_Buffer, EMPTY_VALUE);
}
else if(rates_total > prev_calculated)
{
// New bars added - process only new bars
bars_to_process = rates_total - prev_calculated;
start_bar = 0;
}
else
{
// Recalculate last bar only
bars_to_process = 1;
start_bar = 0;
}
// Process bars
for(int i = start_bar; i < start_bar + bars_to_process && i < rates_total - InpSkipBars; i++)
{
// Skip initialization area
if(i >= rates_total - InpSkipBars) continue;
// Default buffer values (EMPTY_VALUE for all signal/SL/TP buffers)
BuySignalBuffer[i] = EMPTY_VALUE;
SellSignalBuffer[i] = EMPTY_VALUE;
BuySLBuffer[i] = EMPTY_VALUE;
SellSLBuffer[i] = EMPTY_VALUE;
BuyTPBuffer[i] = EMPTY_VALUE;
SellTPBuffer[i] = EMPTY_VALUE;
// Copy EMA values to display buffers
EMA50_Buffer[i] = ema50[i];
EMA100_Buffer[i] = ema100[i];
EMA200_Buffer[i] = ema200[i];
EMA300_Buffer[i] = ema300[i];
EMA400_Buffer[i] = ema400[i];
EMA500_Buffer[i] = ema500[i];
EMA600_Buffer[i] = ema600[i];
// Update state buffers
BuyStateBuffer[i] = buy_state;
SellStateBuffer[i] = sell_state;
// State 1: Finding Base (continuous tracking)
if(buy_state == 1 || buy_state == 0)
{
if(low[i] < BaseLow)
{
BaseLow = low[i];
}
buy_state = 1;
}
if(sell_state == 1 || sell_state == 0)
{
if(high[i] > BaseHigh)
{
BaseHigh = high[i];
}
sell_state = 1;
}
// Check for EMA touch (State 1 -> State 2)
// BUY SIDE: Price touches EMA from below (close below -> close above)
if(buy_state == 1 && !buy_ema_touched)
{
// Find lowest EMA (most resistance from below)
double lowest_ema = ema50[i];
if(ema100[i] < lowest_ema) lowest_ema = ema100[i];
if(ema200[i] < lowest_ema) lowest_ema = ema200[i];
// Previous bar close
double prev_close = (i < rates_total - 1) ? close[i + 1] : close[i];
// EMA touch from below (previous close at/below, current close above)
if(prev_close <= lowest_ema && close[i] > lowest_ema)
{
buy_ema_touched = true;
ema_touch_bar = i;
// Count EMAs crossed
buy_touch_ema_count = 0;
if(close[i] > ema50[i]) buy_touch_ema_count++;
if(close[i] > ema100[i]) buy_touch_ema_count++;
if(close[i] > ema200[i]) buy_touch_ema_count++;
buy_state = 2;
BuyStateBuffer[i] = 2;
}
}
// SELL SIDE: Price touches EMA from above (close above -> close below)
if(sell_state == 1 && !sell_ema_touched)
{
// Find highest EMA (most support from above)
double highest_ema = ema50[i];
if(ema100[i] > highest_ema) highest_ema = ema100[i];
if(ema200[i] > highest_ema) highest_ema = ema200[i];
// Previous bar close
double prev_close = (i < rates_total - 1) ? close[i + 1] : close[i];
// EMA touch from above (previous close at/above, current close below)
if(prev_close >= highest_ema && close[i] < highest_ema)
{
sell_ema_touched = true;
ema_touch_bar = i;
// Count EMAs crossed
sell_touch_ema_count = 0;
if(close[i] < ema50[i]) sell_touch_ema_count++;
if(close[i] < ema100[i]) sell_touch_ema_count++;
if(close[i] < ema200[i]) sell_touch_ema_count++;
sell_state = 2;
SellStateBuffer[i] = 2;
}
}
// State 3: Decision (within pullback window)
// BUY SIDE DECISION
if(buy_ema_touched)
{
int bars_since_touch = ema_touch_bar - i;
// Timeout check - if more than pullback bars passed, cancel
if(bars_since_touch > InpPullbackBars)
{
buy_ema_touched = false;
buy_state = 1;
BuyStateBuffer[i] = 1;
continue;
}
// Cancel condition: crossed EMA below again
double lowest_ema_current = ema50[i];
if(ema100[i] < lowest_ema_current) lowest_ema_current = ema100[i];
if(ema200[i] < lowest_ema_current) lowest_ema_current = ema200[i];
if(close[i] < lowest_ema_current)
{
buy_ema_touched = false;
buy_state = 1;
BuyStateBuffer[i] = 1;
continue;
}
// Pullback check
double pullback_distance = MathAbs(low[i] - BaseLow) / _Point;
if(pullback_distance <= InpBaseThreshold)
{
// GENERATE BUY SIGNAL
BuySignalBuffer[i] = close[i];
BuySLBuffer[i] = BaseLow;
BuyTPBuffer[i] = CalculateBuyTP(close[i], ema300[i], ema400[i], ema500[i], ema600[i], atr[i]);
BuyStateBuffer[i] = 3;
// Create signal label
if(InpShowStageLabels)
{
UpdateStageLabels(time[i], 3, sell_state, low[i] - 50 * _Point, i);
}
// Reset
buy_ema_touched = false;
buy_state = 1;
last_signal_time = time[i];
// Recalculate BaseLow from bar before signal
RecalculateBaseBuy(i, rates_total, low);
Print("BUY SIGNAL at ", TimeToString(time[i]), " Price: ", close[i], " SL: ", BaseLow,
" TP: ", BuyTPBuffer[i]);
}
}
// SELL SIDE DECISION
if(sell_ema_touched)
{
int bars_since_touch = ema_touch_bar - i;
// Timeout check - if more than pullback bars passed, cancel
if(bars_since_touch > InpPullbackBars)
{
sell_ema_touched = false;
sell_state = 1;
SellStateBuffer[i] = 1;
continue;
}
// Cancel condition: crossed EMA above again
double highest_ema_current = ema50[i];
if(ema100[i] > highest_ema_current) highest_ema_current = ema100[i];
if(ema200[i] > highest_ema_current) highest_ema_current = ema200[i];
if(close[i] > highest_ema_current)
{
sell_ema_touched = false;
sell_state = 1;
SellStateBuffer[i] = 1;
continue;
}
// Pullback check
double pullback_distance = MathAbs(high[i] - BaseHigh) / _Point;
if(pullback_distance <= InpBaseThreshold)
{
// GENERATE SELL SIGNAL
SellSignalBuffer[i] = close[i];
SellSLBuffer[i] = BaseHigh;
SellTPBuffer[i] = CalculateSellTP(close[i], ema300[i], ema400[i], ema500[i], ema600[i], atr[i]);
SellStateBuffer[i] = 3;
// Create signal label
if(InpShowStageLabels)
{
UpdateStageLabels(time[i], 3, sell_state, high[i] + 50 * _Point, i);
}
// Reset
sell_ema_touched = false;
sell_state = 1;
last_signal_time = time[i];
// Recalculate BaseHigh from bar before signal
RecalculateBaseSell(i, rates_total, high);
Print("SELL SIGNAL at ", TimeToString(time[i]), " Price: ", close[i], " SL: ", BaseHigh,
" TP: ", SellTPBuffer[i]);
}
}
}
return(rates_total);
}
//+------------------------------------------------------------------+
//| Calculate Buy Take Profit |
//+------------------------------------------------------------------+
double CalculateBuyTP(double entry_price, double ema300, double ema400,
double ema500, double ema600, double atr)
{
double tp = 0;
// Find lowest valid EMA ABOVE price (closest = best risk/reward)
if(ema300 > entry_price)
{
if(tp == 0 || ema300 < tp) tp = ema300;
}
if(ema400 > entry_price)
{
if(tp == 0 || ema400 < tp) tp = ema400;
}
if(ema500 > entry_price)
{
if(tp == 0 || ema500 < tp) tp = ema500;
}
if(ema600 > entry_price)
{
if(tp == 0 || ema600 < tp) tp = ema600;
}
// ATR fallback: if no valid EMA above price
if(tp == 0 && atr > 0)
{
tp = entry_price + atr * 2;
}
return NormalizeDouble(tp, _Digits);
}
//+------------------------------------------------------------------+
//| Calculate Sell Take Profit |
//+------------------------------------------------------------------+
double CalculateSellTP(double entry_price, double ema300, double ema400,
double ema500, double ema600, double atr)
{
double tp = 0;
// Find highest valid EMA BELOW price (closest = best risk/reward)
if(ema300 < entry_price)
{
if(tp == 0 || ema300 > tp) tp = ema300;
}
if(ema400 < entry_price)
{
if(tp == 0 || ema400 > tp) tp = ema400;
}
if(ema500 < entry_price)
{
if(tp == 0 || ema500 > tp) tp = ema500;
}
if(ema600 < entry_price)
{
if(tp == 0 || ema600 > tp) tp = ema600;
}
// ATR fallback: if no valid EMA below price
if(tp == 0 && atr > 0)
{
tp = entry_price - atr * 2;
}
return NormalizeDouble(tp, _Digits);
}
//+------------------------------------------------------------------+
//| Recalculate Buy Base Level After Signal |
//+------------------------------------------------------------------+
void RecalculateBaseBuy(int signal_bar, int total_bars, const double &low_arr[])
{
// Start from bar before signal
BaseLow = low_arr[signal_bar + 1];
// Find new base from that point forward
for(int j = signal_bar + 1; j < total_bars - InpSkipBars; j++)
{
if(low_arr[j] < BaseLow)
{
BaseLow = low_arr[j];
}
}
// Print("BaseLow recalculated: ", BaseLow, " after buy signal");
}
//+------------------------------------------------------------------+
//| Recalculate Sell Base Level After Signal |
//+------------------------------------------------------------------+
void RecalculateBaseSell(int signal_bar, int total_bars, const double &high_arr[])
{
// Start from bar before signal
BaseHigh = high_arr[signal_bar + 1];
// Find new base from that point forward
for(int j = signal_bar + 1; j < total_bars - InpSkipBars; j++)
{
if(high_arr[j] > BaseHigh)
{
BaseHigh = high_arr[j];
}
}
// Print("BaseHigh recalculated: ", BaseHigh, " after sell signal");
}
//+------------------------------------------------------------------+
//| Update Stage Labels |
//+------------------------------------------------------------------+
void UpdateStageLabels(datetime label_time, int buy_st, int sell_st, double price, int bar_index)
{
string label_name = "EMA_Stage_" + IntegerToString(bar_index);
string text = "";
color label_color;
// Format: "BUY/SELL" for signal bars
if(buy_st == 3)
{
text = "BUY SIGNAL";
label_color = clrLime;
}
else if(sell_st == 3)
{
text = "SELL SIGNAL";
label_color = clrRed;
}
else
{
// Show state only when not in signal
text = StringFormat("B:%d S:%d", buy_st, sell_st);
label_color = clrGray;
switch(buy_st)
{
case 0: label_color = clrGray; break;
case 1: label_color = clrBlue; break;
case 2: label_color = clrOrange; break;
case 3: label_color = clrGreen; break;
default: label_color = clrGray;
}
}
// Create or update label
if(ObjectFind(0, label_name) < 0)
{
ObjectCreate(0, label_name, OBJ_TEXT, 0, label_time, price);
}
ObjectSetString(0, label_name, OBJPROP_TEXT, text);
ObjectSetInteger(0, label_name, OBJPROP_COLOR, label_color);
ObjectSetInteger(0, label_name, OBJPROP_FONTSIZE, 14);
ObjectSetInteger(0, label_name, OBJPROP_ANCHOR, ANCHOR_UPPER);
ObjectSetInteger(0, label_name, OBJPROP_SELECTABLE, false);
}
//+------------------------------------------------------------------+