mql5/Indicators/DexterrFX - SMC Bible/HyperSwings.mq5

322 строки
12 КиБ
MQL5
ИсходныйПостоянная ссылкаОбычный видИстория

2026-03-04 16:35:19 +02:00
//+------------------------------------------------------------------+
//| HyperSwings.mq5 |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#property indicator_chart_window
#property indicator_plots 4
#property indicator_buffers 8
//--- Swing High
#property indicator_label1 "SwingHigh"
#property indicator_type1 DRAW_COLOR_ARROW
#property indicator_color1 clrMaroon, clrLightCoral
#property indicator_width1 1
#property indicator_label2 "SwingLow"
#property indicator_type2 DRAW_COLOR_ARROW
#property indicator_color2 clrSeaGreen, clrLightGreen
#property indicator_width2 1
#property indicator_label3 "HighPoints"
#property indicator_type3 DRAW_ARROW
#property indicator_color3 clrCrimson
#property indicator_width3 1
#property indicator_label4 "LowPoints"
#property indicator_type4 DRAW_ARROW
#property indicator_color4 clrMediumSeaGreen
#property indicator_width4 1
input int InpLeftRightBars = 3; // Swing detection size
input int InpLeftRightBars0 = 1; // Minimum swing size between points
input ushort code = 170; // Arrow symbol
//--- Indicator buffers
double SwingHighBuffer[]; // Swing high prices
double SwingLowBuffer[]; // Swing low prices
double SwingHighColors[]; // Colors for swing highs (0=initial, 1=broken)
double SwingLowColors[]; // Colors for swing lows (0=initial, 1=broken)
double HighBufferPoints[]; // Points where swing highs occur
double LowBufferPoints[]; // Points where swing lows occur
double HighBuffer[]; // Swing high signals from external indicator
double LowBuffer[]; // Swing low signals from external indicator
//--- Internal tracking
int handle = INVALID_HANDLE;
datetime last_bar_time = 0;
//+------------------------------------------------------------------+
//| Initialize indicator |
//+------------------------------------------------------------------+
int OnInit() {
//--- Set index buffers
SetIndexBuffer(0, SwingHighBuffer, INDICATOR_DATA);
SetIndexBuffer(2, SwingLowBuffer, INDICATOR_DATA);
SetIndexBuffer(1, SwingHighColors, INDICATOR_COLOR_INDEX);
SetIndexBuffer(3, SwingLowColors, INDICATOR_COLOR_INDEX);
SetIndexBuffer(4, HighBufferPoints, INDICATOR_DATA);
SetIndexBuffer(5, LowBufferPoints, INDICATOR_DATA);
SetIndexBuffer(6, HighBuffer, INDICATOR_CALCULATIONS);
SetIndexBuffer(7, LowBuffer, INDICATOR_CALCULATIONS);
//--- Set arrow properties
PlotIndexSetInteger(0, PLOT_ARROW, 158);
PlotIndexSetInteger(1, PLOT_ARROW, 158);
PlotIndexSetInteger(2, PLOT_ARROW, code);
PlotIndexSetInteger(3, PLOT_ARROW, code);
//--- Set empty values
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetDouble(3, PLOT_EMPTY_VALUE, EMPTY_VALUE);
//--- Get swing indicator handle
handle = iCustom(_Symbol, _Period, "Arjo Indicators\\Swing", InpLeftRightBars);
if(handle == INVALID_HANDLE) {
Print("Error creating Swing iCustom handle. LastError=", GetLastError());
return INIT_FAILED;
}
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Find lowest low between two indices (inclusive) |
//+------------------------------------------------------------------+
int FindLowestLowIndex(const double &low[], int start_idx, int end_idx) {
int from_idx = MathMin(start_idx, end_idx);
int to_idx = MathMax(start_idx, end_idx);
int trough_index = -1;
double lowest_price = DBL_MAX;
for(int i = from_idx + 1; i < to_idx; i++)
{
// Structural rule: neighbors must be higher
if(low[i] < low[i - 1] && low[i] < low[i + 1])
{
if(low[i] < lowest_price)
{
lowest_price = low[i];
trough_index = i;
}
}
}
return trough_index;
}
//+------------------------------------------------------------------+
//| Find highest high between two indices (inclusive) |
//+------------------------------------------------------------------+
int FindHighestHighIndex(const double &high[], int start_idx, int end_idx) {
int from_idx = MathMin(start_idx, end_idx);
int to_idx = MathMax(start_idx, end_idx);
int peak_index = -1;
double highest_price = -DBL_MAX;
for(int i = from_idx + 1; i < to_idx; i++)
{
// Structural rule: neighbors must be lower
if(high[i] > high[i - 1] && high[i] > high[i + 1])
{
if(high[i] > highest_price)
{
highest_price = high[i];
peak_index = i;
}
}
}
return peak_index;
}
//+------------------------------------------------------------------+
//| Fill all bars between two indices with a specific price |
//+------------------------------------------------------------------+
void FillRange(double &buffer[], double &colorBuffer[], int start_idx, int end_idx, double price, int color_idx) {
int from_idx = MathMin(start_idx, end_idx);
int to_idx = MathMax(start_idx, end_idx);
for(int i = from_idx; i <= to_idx; i++) {
buffer[i] = price;
colorBuffer[i] = color_idx;
}
}
//+------------------------------------------------------------------+
//| Process the entire history from oldest to newest |
//+------------------------------------------------------------------+
void ProcessAllBars(const int rates_total,
const double &high[],
const double &low[],
const double &close[]) {
// Clear buffers
for(int i = 0; i < rates_total; i++) {
SwingHighBuffer[i] = EMPTY_VALUE;
SwingLowBuffer[i] = EMPTY_VALUE;
HighBufferPoints[i] = EMPTY_VALUE;
LowBufferPoints[i] = EMPTY_VALUE;
SwingHighColors[i] = 0;
SwingLowColors[i] = 0;
}
int current_high_index = -1;
int current_low_index = -1;
double current_high_price = 0;
double current_low_price = 0;
int last_high_break_index = -1;
int last_low_break_index = -1;
// Start from oldest (index 0) to newest (rates_total-1)
for(int i = 0; i < rates_total; i++) {
// Check for new swing high
if(HasValue(HighBuffer[i]) && current_high_index == -1) {
current_high_index = i;
current_high_price = high[i];
SwingHighBuffer[i] = high[i];
HighBufferPoints[i] = high[i];
SwingHighColors[i] = 0;
}
// Check for new swing low
if(HasValue(LowBuffer[i]) && current_low_index == -1) {
current_low_index = i;
current_low_price = low[i];
SwingLowBuffer[i] = low[i];
LowBufferPoints[i] = low[i];
SwingLowColors[i] = 0;
}
// If we have a current swing high, check for breakout above it
if(current_high_index != -1 && close[i] > current_high_price) {
// Find the lowest low between the swing high and breakout
int lowest_low_idx = FindLowestLowIndex(low, current_high_index, i);
if(lowest_low_idx != -1) {
// Record the low point
LowBufferPoints[lowest_low_idx] = low[lowest_low_idx];
SwingLowBuffer[lowest_low_idx] = low[lowest_low_idx];
SwingLowColors[lowest_low_idx] = 0;
// Fill the swing high line from the swing high to the breakout
FillRange(SwingHighBuffer, SwingHighColors, current_high_index, i, current_high_price, 0);
// Mark the swing high as broken (color index 1)
SwingHighColors[current_high_index] = 1;
// Update current low to this new low point
current_low_index = lowest_low_idx;
current_low_price = low[lowest_low_idx];
last_high_break_index = i;
}
// Clear current swing high to look for next one
current_high_index = -1;
current_high_price = 0;
}
// If we have a current swing low, check for breakdown below it
if(current_low_index != -1 && close[i] < current_low_price) {
// Find the highest high between the swing low and breakdown
int highest_high_idx = FindHighestHighIndex(high, current_low_index, i);
if(highest_high_idx != -1) {
// Record the high point
HighBufferPoints[highest_high_idx] = high[highest_high_idx];
SwingHighBuffer[highest_high_idx] = high[highest_high_idx];
SwingHighColors[highest_high_idx] = 0;
// Fill the swing low line from the swing low to the breakdown
FillRange(SwingLowBuffer, SwingLowColors, current_low_index, i, current_low_price, 0);
// Mark the swing low as broken (color index 1)
SwingLowColors[current_low_index] = 1;
// Update current high to this new high point
current_high_index = highest_high_idx;
current_high_price = high[highest_high_idx];
last_low_break_index = i;
}
// Clear current swing low to look for next one
current_low_index = -1;
current_low_price = 0;
}
}
// Fill the final swing to the end of chart
if(current_high_index != -1) {
FillRange(SwingHighBuffer, SwingHighColors, current_high_index, rates_total-1, current_high_price, 0);
}
if(current_low_index != -1) {
FillRange(SwingLowBuffer, SwingLowColors, current_low_index, rates_total-1, current_low_price, 0);
}
}
//+------------------------------------------------------------------+
//| Main calculation 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[]) {
if(rates_total <= 0) return 0;
if(handle == INVALID_HANDLE) return 0;
//--- Copy swing indicator buffers
if(CopyBuffer(handle, 0, 0, rates_total, HighBuffer) <= 0) {
Print("Error copying Swing HIGH buffer. LastError=", GetLastError());
return 0;
}
if(CopyBuffer(handle, 1, 0, rates_total, LowBuffer) <= 0) {
Print("Error copying Swing LOW buffer. LastError=", GetLastError());
return 0;
}
2026-03-04 16:41:59 +02:00
2026-03-04 16:35:19 +02:00
//--- Process on each new bar
if(time[rates_total - 1] != last_bar_time || prev_calculated == 0) {
ProcessAllBars(rates_total, high, low, close);
last_bar_time = time[rates_total - 1];
}
return rates_total;
}
//+------------------------------------------------------------------+
//| Deinitialization |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
if(handle != INVALID_HANDLE) {
IndicatorRelease(handle);
handle = INVALID_HANDLE;
}
}
//+------------------------------------------------------------------+
//| Helper function to check if a buffer value is valid |
//+------------------------------------------------------------------+
bool HasValue(const double v) {
if(v == EMPTY_VALUE) return false;
if(v <= 0.0) return false;
return true;
}
//+------------------------------------------------------------------+