New EA and Indi
This commit is contained in:
753
EMA Indi/Base_EMA_Reversal.mq5
Normal file
753
EMA Indi/Base_EMA_Reversal.mq5
Normal 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);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Reference in New Issue
Block a user