Hon-Matrix
Похожие материалы по тегам
Сообщите нам, если считаете, что материал размещён без разрешения.
Сообщить о материале
Обращение по товару «hon-matrix.mq5» отправится на рассмотрение. Укажите контакт для ответа и опишите причину.
О программе
Hon-Matrix — это торговый советник для MetaTrader 5, предназначенный для автоматической торговли на одном символе с использованием сеточного подхода. Советник анализирует рыночные данные через индикаторы (скользящие средние, ATR, RSI), определяет фазу рынка и направление тренда, после чего принимает решения об открытии начальной позиции и добавлении ордеров в сетку. В коде предусмотрены несколько режимов входа: по уровням Фибоначчи, по уровням поддержки и сопротивления, по границам канала, а также простой трендовый вход.
Встроенный фильтр новостей позволяет приостанавливать торговлю в заданные интервалы до и после важных экономических событий, используя внутренний календарь MetaTrader 5 или внешний источник. Советник поддерживает управление рисками: ограничение просадки и прибыли в процентах от счёта, контроль максимальной экспозиции, ограничение количества ордеров в сетке, а также настройки трейлинг-стопа и перевода в безубыток.
Для удобства мониторинга реализована информационная панель на графике, отображающая состояние счёта, рыночную аналитику, статус новостного фильтра и элементы ручного управления позициями. Советник обрабатывает события OnTick, OnTrade и OnChartEvent, использует торговые функции MetaTrader 5 и не является индикатором или библиотекой.
Настройки программы
| Настройка | Описание |
|---|---|
| Start_Date | Дата начала периода тестирования. |
| StartCapital | Начальный капитал для проверки периода тестирования. |
| EnableBacktestValidation | Включает или отключает проверку периода тестирования. |
| CloseLosesAtPercent | Процент убытка от счёта, при достижении которого все позиции закрываются. Значение 0 отключает функцию. |
| CloseProfitsAtPercent | Процент прибыли от счёта, при достижении которого все позиции закрываются. Значение 0 отключает функцию. |
| InitialLotSize | Начальный размер лота для первой позиции. |
| MaxLotSize | Максимально допустимый размер лота. |
| LotMultiplier | Множитель лота для последующих ордеров сетки. |
| MaxGridOrders | Максимальное количество ордеров в сетке. |
| TakeProfitPips | Целевой уровень прибыли в пунктах для закрытия корзины позиций. |
| BreakevenTrigger | Прибыль в пунктах, при достижении которой позиция переводится в безубыток. |
| TrailingDistance | Расстояние трейлинг-стопа в пунктах. |
| UseTrailingStop | Включает или отключает трейлинг-стоп и перевод в безубыток. |
| EnableNewsFilter | Включает или отключает новостной фильтр. |
| StopBeforeNewsMin | Количество минут до новости, в течение которых торговля приостанавливается. |
| StopAfterNewsMin | Количество минут после новости, в течение которых торговля приостанавливается. |
| EnableHighImpact | Включает или отключает фильтр новостей высокой важности. |
| EnableMediumImpact | Включает или отключает фильтр новостей средней важности. |
| EnableLowImpact | Включает или отключает фильтр новостей низкой важности. |
| UseInternalCalendar | Включает или отключает использование внутреннего календаря MetaTrader 5. |
| NewsSymbols | Список валют, учитываемых новостным фильтром, через запятую. |
| ClosePositionsBeforeNews | Включает или отключает закрытие всех позиций перед новостями. |
| AlertOnUpcomingNews | Включает или отключает уведомления о предстоящих новостях. |
| DrawNewsLines | Включает или отключает отрисовку вертикальных линий новостей на графике. |
| HighImpactColor | Цвет линий новостей высокой важности. |
| MediumImpactColor | Цвет линий новостей средней важности. |
| LowImpactColor | Цвет линий новостей низкой важности. |
| AMA_Period | Период скользящей средней, используемой в анализе рыночной фазы. |
| ATR_Period | Период индикатора ATR для оценки волатильности. |
| ATR_Threshold | Пороговое значение волатильности ATR для определения рыночной фазы. |
| TrendTimeframe | Таймфрейм для фильтра тренда. |
| TrendMA_Period | Период скользящей средней для определения тренда. |
| SwingLookback | Количество баров для поиска экстремумов. |
| UseFibonacciGrid | Включает или отключает использование сетки Фибоначчи. |
| FibLevel1 | Первый уровень Фибоначчи для сетки. |
| FibLevel2 | Второй уровень Фибоначчи для сетки. |
| FibLevel3 | Третий уровень Фибоначчи для сетки. |
| FibLevel4 | Четвёртый уровень Фибоначчи для сетки. |
| UseEnhancedEntry | Включает или отключает расширенную систему входа по уровням поддержки и сопротивления. |
| SR_LookbackPeriod | Количество баров для поиска уровней поддержки и сопротивления. |
| SR_MinStrength | Минимальное количество касаний для уровня поддержки или сопротивления. |
| SR_ZoneBuffer | Буфер зоны поддержки и сопротивления в пунктах. |
| UseChannelTrading | Включает или отключает торговлю по каналу. |
| ChannelMinBars | Минимальное количество баров для определения канала. |
| ChannelThreshold | Пороговое значение силы канала. |
| UseDynamicLotSizing | Включает или отключает динамический расчёт лота на основе силы уровней. |
| BreakoutMinPips | Минимальное расстояние пробоя в пунктах. |
| BreakoutMaxPips | Максимальное расстояние пробоя в пунктах. |
| UseMomentumFilter | Включает или отключает фильтр импульса. |
| MomentumThreshold | Пороговое значение импульса для фильтра. |
| UseVolumeFilter | Включает или отключает фильтр объёма. |
| VolumeMultiplier | Множитель объёма для фильтра. |
| FalseBreakoutFilter | Порог фильтра ложных пробоев в диапазоне от 0 до 1. |
| VolumeConfirmPeriod | Период подтверждения объёма. |
| BreakoutConfirmBars | Количество баров для подтверждения пробоя. |
| UseRSIFilter | Включает или отключает фильтр RSI. |
| RSI_Period | Период индикатора RSI. |
| RSI_Oversold | Уровень перепроданности RSI. |
| RSI_Overbought | Уровень перекупленности RSI. |
| EntryDistance | Расстояние от уровня Фибоначчи для входа в пунктах. |
| UseSimpleEntry | Включает или отключает простой вход по тренду. |
| UseTimeFilter | Включает или отключает фильтр времени торговли. |
| StartTime | Время начала торговли в формате часы:минуты. |
| EndTime | Время окончания торговли в формате часы:минуты. |
| MagicNumber | Уникальный идентификатор ордеров советника. |
| Commentary | Текст комментария, добавляемый к торговым ордерам. |
| ShowPanel | Включает или отключает отображение информационной панели на графике. |
Поиск по коду файла
#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\OrderInfo.mqh>
#property version "1.2";
#property strict
enum ENUM_MARKET_PHASE
{
MARKET_RANGING,
MARKET_TRENDING,
MARKET_CONSOLIDATING,
MARKET_UNKNOWN
};
enum ENUM_TREND_DIRECTION
{
TREND_BULLISH,
TREND_BEARISH,
TREND_NEUTRAL
};
input group "=== BACKTEST VALIDATION ===";
input datetime Start_Date = D'2020.01.01'; // Backtest Start Date (Min 1 Year)
input double StartCapital = 10000; // Starting Capital for Validation
input bool EnableBacktestValidation = true; // Enable Backtest Validation
input group "=== RISK MANAGEMENT ===";
input double MaxAccountExposure = 15.0; // Max Account Exposure (%)
input double CloseLosesAtPercent = 30.0; // Close all if loss reaches this % of account (0=disable)
input double CloseProfitsAtPercent = 40.0; // Close all if profit reaches this % of account (0=disable)
input double InitialLotSize = 0.06; // Initial Lot Size
input double MaxLotSize = 1.0; // Maximum Lot Size
input double LotMultiplier = 1.1; // Lot Multiplier (Safe Default)
input int MaxGridOrders = 5; // Max Grid Orders (Safe Default)
input double TakeProfitPips = 50.0; // Ultimate Take Profit (Pips)
input double BreakevenTrigger = 20.0; // Breakeven Trigger (Pips)
input double TrailingDistance = 15.0; // Trailing Stop Distance (Pips)
input bool UseTrailingStop = true; // Use Trailing Stop & Breakeven
input group "=== NEWS FILTER SETTINGS ===";
input bool EnableNewsFilter = true; // Enable/Disable the news filter
input int StopBeforeNewsMin = 30; // Stop trading Before News (minutes)
input int StopAfterNewsMin = 30; // Stop trading After News (minutes)
input bool EnableHighImpact = true; // Enable high impact news filter
input bool EnableMediumImpact = true; // Enable medium impact news filter
input bool EnableLowImpact = false; // Enable low impact news filter
input bool UseInternalCalendar = true; // Use MT5 internal calendar (recommended)
input string NewsSymbols = "USD,EUR,GBP,CHF,CAD,AUD,NZD,JPY"; // Currencies for news filter
input bool ClosePositionsBeforeNews = false; // Close all positions before news
input bool AlertOnUpcomingNews = true; // Alert for upcoming news
input bool DrawNewsLines = true; // Draw news lines on chart
input color HighImpactColor = clrRed; // High impact news line color
input color MediumImpactColor = clrOrange; // Medium impact news line color
input color LowImpactColor = clrYellow; // Low impact news line color
input group "=== MARKET ANALYSIS ===";
input int AMA_Period = 21; // AMA Period
input int ATR_Period = 14; // ATR Period
input double ATR_Threshold = 1.5; // ATR Volatility Threshold
input ENUM_TIMEFRAMES TrendTimeframe = PERIOD_H4; // Trend Filter Timeframe
input int TrendMA_Period = 100; // Trend MA Period
input group "=== FIBONACCI SETTINGS ===";
input int SwingLookback = 50; // Swing Points Lookback
input bool UseFibonacciGrid = true; // Use Fibonacci Grid Spacing
input double FibLevel1 = 38.2; // Fibonacci Level 1
input double FibLevel2 = 50.0; // Fibonacci Level 2
input double FibLevel3 = 61.8; // Fibonacci Level 3
input double FibLevel4 = 78.6; // Fibonacci Level 4
input group "=== ENHANCED SIMPLE ENTRY ===";
input bool UseEnhancedEntry = true; // Use Enhanced S/R Entry System
input int SR_LookbackPeriod = 100; // S/R Detection Lookback Period
input double SR_MinStrength = 3.0; // Minimum S/R Touch Count
input double SR_ZoneBuffer = 20.0; // S/R Zone Buffer (Pips)
input bool UseChannelTrading = true; // Enable Channel Trading
input int ChannelMinBars = 50; // Minimum Channel Length
input double ChannelThreshold = 0.8; // Channel Strength Threshold
input bool UseDynamicLotSizing = true; // Dynamic Lot Sizing based on S/R strength
input group "=== BREAKOUT DETECTION SETTINGS ===";
input double BreakoutMinPips = 5.0; // Minimum Breakout Distance (Pips)
input double BreakoutMaxPips = 50.0; // Maximum Breakout Distance (Pips)
input bool UseMomentumFilter = true; // Use Momentum Filter
input double MomentumThreshold = 1.2; // Momentum Threshold
input bool UseVolumeFilter = true; // Use Volume Filter
input double VolumeMultiplier = 1.5; // Volume Multiplier
input double FalseBreakoutFilter = 0.6; // False Breakout Filter (0-1)
input int VolumeConfirmPeriod = 10; // Volume Confirmation Period
input int BreakoutConfirmBars = 3; // Breakout Confirmation Bars
input group "=== ENTRY FILTERS ===";
input bool UseRSIFilter = false; // Use RSI Filter
input int RSI_Period = 14; // RSI Period
input double RSI_Oversold = 30.0; // RSI Oversold Level
input double RSI_Overbought = 70.0; // RSI Overbought Level
input double EntryDistance = 30.0; // Entry Distance from Fib (Pips)
input bool UseSimpleEntry = false; // Use simple trend-following entry
input group "=== TIME FILTER ===";
input bool UseTimeFilter = false; // Use Time Filter
input string StartTime = "08:00"; // Trading Start Time
input string EndTime = "18:00"; // Trading End Time
input group "=== ADVANCED ===";
input int MagicNumber = 777777; // Magic Number
input string Commentary = "Hon-Matrix"; // Order Comment
input bool ShowPanel = true; // Show Control Panel
CTrade trade;
CPositionInfo position;
COrderInfo order;
double g_live_multiplier = 0.0; // 0.0 = use input parameter
double g_live_start_lot = 0.0; // 0.0 = use input parameter
bool g_live_adjustments_active = false;
struct NewsWebData
{
string time_str;
string currency;
string impact;
string title;
NewsWebData()
{
time_str = "";
currency = "";
impact = "";
title = "";
}
};
struct NewsEvent
{
datetime time;
string currency;
string title;
int impact; // 1=Low, 2=Medium, 3=High
bool processed;
NewsEvent()
{
time = 0;
currency = "";
title = "";
impact = 0;
processed = false;
}
NewsEvent(const NewsEvent &other)
{
time = other.time;
currency = other.currency;
title = other.title;
impact = other.impact;
processed = other.processed;
}
};
struct SRLevel
{
double price;
int touch_count;
datetime first_touch;
datetime last_touch;
bool is_support;
double strength;
bool is_active;
SRLevel()
{
price = 0.0;
touch_count = 0;
first_touch = 0;
last_touch = 0;
is_support = true;
strength = 0.0;
is_active = false;
}
SRLevel(const SRLevel &other)
{
price = other.price;
touch_count = other.touch_count;
first_touch = other.first_touch;
last_touch = other.last_touch;
is_support = other.is_support;
strength = other.strength;
is_active = other.is_active;
}
};
struct ChannelInfo
{
double upper_line;
double lower_line;
double slope;
int bar_count;
double strength;
bool is_active;
datetime start_time;
ChannelInfo()
{
upper_line = 0.0;
lower_line = 0.0;
slope = 0.0;
bar_count = 0;
strength = 0.0;
is_active = false;
start_time = 0;
}
};
struct BreakoutInfo
{
double sr_level;
bool is_resistance_break;
datetime break_time;
double break_price;
double momentum_score;
double volume_score;
bool is_confirmed;
int confirmation_bars;
BreakoutInfo()
{
sr_level = 0.0;
is_resistance_break = false;
break_time = 0;
break_price = 0.0;
momentum_score = 0.0;
volume_score = 0.0;
is_confirmed = false;
confirmation_bars = 0;
}
};
class CAdvancedNewsFilter
{
private:
NewsEvent m_news_events[];
int m_news_count;
datetime m_last_update;
datetime m_last_alert_time;
bool m_trading_halted;
string m_halt_reason;
string m_filtered_symbols[];
NewsWebData m_web_news_records[];
int m_web_news_count;
public:
CAdvancedNewsFilter() : m_news_count(0), m_last_update(0), m_last_alert_time(0),
m_trading_halted(false), m_web_news_count(0)
{
ParseFilteredSymbols();
}
bool Initialize()
{
if(!EnableNewsFilter)
return true;
Print("News Filter: Initializing advanced news filter...");
Print("News Filter: Please ensure WebRequest is enabled in Tools->Options->Expert Advisors");
UpdateNewsData();
m_last_update = TimeCurrent();
Print("News Filter: Initialized successfully with ", m_news_count, " upcoming events");
return true;
}
private:
void ParseFilteredSymbols()
{
string symbols = NewsSymbols;
StringReplace(symbols, " ", "");
string parts[];
int total = StringSplit(symbols, ',', parts);
ArrayResize(m_filtered_symbols, total);
for(int i = 0; i < total; i++)
{
m_filtered_symbols[i] = parts[i];
StringToUpper(m_filtered_symbols[i]);
}
}
bool IsSymbolFiltered(string currency)
{
StringToUpper(currency);
for(int i = 0; i < ArraySize(m_filtered_symbols); i++)
{
if(m_filtered_symbols[i] == currency)
return true;
}
return false;
}
void UpdateNewsData()
{
m_news_count = 0;
m_trading_halted = false;
m_halt_reason = "";
if(UseInternalCalendar)
{
LoadFromInternalCalendar();
}
else
{
LoadFromWebSource();
}
SortNewsByTime();
if(DrawNewsLines)
{
DrawNewsVerticalLines();
}
}
void LoadFromInternalCalendar()
{
MqlCalendarValue calendar_values[];
datetime from_time = TimeCurrent();
datetime to_time = from_time + 7 * 24 * 3600; // Next 7 days
int total = CalendarValueHistory(calendar_values, from_time, to_time);
if(total <= 0)
{
Print("News Filter: No calendar data available from internal calendar");
return;
}
ArrayResize(m_news_events, total);
for(int i = 0; i < total && m_news_count < total; i++)
{
MqlCalendarEvent event_info;
MqlCalendarCountry country_info;
if(!CalendarEventById(calendar_values[i].event_id, event_info))
continue;
if(!CalendarCountryById(event_info.country_id, country_info))
continue;
if(!ShouldProcessImpact(event_info.importance))
continue;
if(!IsSymbolFiltered(country_info.currency))
continue;
m_news_events[m_news_count].time = calendar_values[i].time;
m_news_events[m_news_count].currency = country_info.currency;
m_news_events[m_news_count].title = event_info.name;
m_news_events[m_news_count].impact = (int)event_info.importance;
m_news_events[m_news_count].processed = false;
m_news_count++;
}
Print("News Filter: Loaded ", m_news_count, " events from internal calendar");
}
void LoadFromWebSource()
{
string html_content = FetchWebNewsData();
if(StringLen(html_content) == 0)
{
Print("News Filter: Web source unavailable, using internal calendar only");
return;
}
ParseWebNewsData(html_content);
ArrayResize(m_news_events, m_web_news_count);
for(int i = 0; i < m_web_news_count; i++)
{
m_news_events[i].time = ParseWebTime(m_web_news_records[i].time_str);
m_news_events[i].currency = m_web_news_records[i].currency;
m_news_events[i].title = m_web_news_records[i].title;
m_news_events[i].impact = ParseWebImpact(m_web_news_records[i].impact);
m_news_events[i].processed = false;
}
m_news_count = m_web_news_count;
Print("News Filter: Loaded ", m_news_count, " events from web source");
}
string FetchWebNewsData()
{
string cookie = NULL, headers;
string reqheaders = "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36\r\n";
char post[], result[];
string news_url = "";
ResetLastError();
int timeout = 10000;
int res = WebRequest("GET", news_url, reqheaders, timeout, post, result, headers);
if(res == -1)
{
int error_code = GetLastError();
Print("News Filter: WebRequest failed. Error: ", error_code);
if(error_code == 4060) // ERR_FUNCTION_NOT_CONFIRMED
{
Print("News Filter: Please add ", news_url, " to allowed URLs in terminal settings");
}
return "";
}
return CharArrayToString(result);
}
void ParseWebNewsData(string html_content)
{
m_web_news_count = 0;
ArrayResize(m_web_news_records, 100); // Reasonable initial size
Print("News Filter: Web parsing completed (placeholder implementation)");
}
datetime ParseWebTime(string time_str)
{
return StringToTime(time_str);
}
int ParseWebImpact(string impact_str)
{
if(StringFind(impact_str, "High") >= 0 || StringFind(impact_str, "3") >= 0)
return 3;
if(StringFind(impact_str, "Medium") >= 0 || StringFind(impact_str, "Moderate") >= 0 || StringFind(impact_str, "2") >= 0)
return 2;
return 1;
}
bool ShouldProcessImpact(ENUM_CALENDAR_EVENT_IMPORTANCE importance)
{
switch(importance)
{
case CALENDAR_IMPORTANCE_LOW:
return EnableLowImpact;
case CALENDAR_IMPORTANCE_MODERATE:
return EnableMediumImpact;
case CALENDAR_IMPORTANCE_HIGH:
return EnableHighImpact;
default:
return false;
}
}
void SortNewsByTime()
{
for(int i = 0; i < m_news_count - 1; i++)
{
for(int j = 0; j < m_news_count - i - 1; j++)
{
if(m_news_events[j].time > m_news_events[j + 1].time)
{
NewsEvent temp = m_news_events[j];
m_news_events[j] = m_news_events[j + 1];
m_news_events[j + 1] = temp;
}
}
}
}
void DrawNewsVerticalLines()
{
ObjectsDeleteAll(0, "NewsLine_");
for(int i = 0; i < m_news_count; i++)
{
datetime news_time = m_news_events[i].time;
if(news_time < TimeCurrent())
continue; // Skip past events
color line_color = GetImpactColor(m_news_events[i].impact);
string obj_name = "NewsLine_" + IntegerToString((int)news_time);
ObjectCreate(0, obj_name, OBJ_VLINE, 0, news_time, 0);
ObjectSetInteger(0, obj_name, OBJPROP_COLOR, line_color);
ObjectSetInteger(0, obj_name, OBJPROP_STYLE, STYLE_DOT);
ObjectSetInteger(0, obj_name, OBJPROP_WIDTH, 2);
ObjectSetInteger(0, obj_name, OBJPROP_BACK, true);
string tooltip = StringFormat("%s\n%s - %s\nImpact: %s",
TimeToString(news_time),
m_news_events[i].currency,
m_news_events[i].title,
GetImpactString(m_news_events[i].impact));
ObjectSetString(0, obj_name, OBJPROP_TOOLTIP, tooltip);
}
}
color GetImpactColor(int impact)
{
switch(impact)
{
case 3:
return HighImpactColor;
case 2:
return MediumImpactColor;
case 1:
return LowImpactColor;
default:
return clrGray;
}
}
string GetImpactString(int impact)
{
switch(impact)
{
case 3:
return "HIGH";
case 2:
return "MEDIUM";
case 1:
return "LOW";
default:
return "UNKNOWN";
}
}
public:
bool IsTradingAllowed()
{
if(!EnableNewsFilter)
return true;
if(TimeCurrent() - m_last_update >= 21600)
{
UpdateNewsData();
m_last_update = TimeCurrent();
}
datetime current_time = TimeCurrent();
m_trading_halted = false;
m_halt_reason = "";
for(int i = 0; i < m_news_count; i++)
{
datetime news_time = m_news_events[i].time;
datetime start_halt = news_time - StopBeforeNewsMin * 60;
datetime end_halt = news_time + StopAfterNewsMin * 60;
if(current_time >= start_halt && current_time <= end_halt)
{
m_trading_halted = true;
m_halt_reason = StringFormat("NEWS: %s %s (%s) in %d min",
m_news_events[i].currency,
m_news_events[i].title,
GetImpactString(m_news_events[i].impact),
(int)((news_time - current_time) / 60));
if(AlertOnUpcomingNews && (current_time - m_last_alert_time > 300)) // 5 min cooldown
{
Alert("Trading Halted: ", m_halt_reason);
m_last_alert_time = current_time;
}
if(ClosePositionsBeforeNews && current_time <= news_time && !m_news_events[i].processed)
{
CloseAllNewsPositions();
m_news_events[i].processed = true;
}
return false;
}
}
return true;
}
void CloseAllNewsPositions()
{
Print("News Filter: Closing all positions due to upcoming high-impact news");
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(position.SelectByIndex(i) && position.Magic() == MagicNumber && position.Symbol() == _Symbol)
{
trade.PositionClose(position.Ticket());
Sleep(100);
}
}
double freeze_level = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_FREEZE_LEVEL) * _Point;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(order.SelectByIndex(i) && order.Magic() == MagicNumber && order.Symbol() == _Symbol)
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double order_price = order.PriceOpen();
bool is_frozen = false;
if(order.OrderType() == ORDER_TYPE_BUY_LIMIT || order.OrderType() == ORDER_TYPE_BUY_STOP)
{
if(MathAbs(ask - order_price) <= freeze_level) is_frozen = true;
}
else if(order.OrderType() == ORDER_TYPE_SELL_LIMIT || order.OrderType() == ORDER_TYPE_SELL_STOP)
{
if(MathAbs(bid - order_price) <= freeze_level) is_frozen = true;
}
if(!is_frozen)
{
trade.OrderDelete(order.Ticket());
Sleep(100);
}
else
{
Print("⚠️ News Filter: Order #", order.Ticket(), " is frozen and cannot be canceled.");
}
}
}
}
bool IsTradingHalted() { return m_trading_halted; }
string GetHaltReason() { return m_halt_reason; }
string GetNextNewsInfo()
{
if(!EnableNewsFilter || m_news_count == 0)
return "No upcoming news";
datetime current_time = TimeCurrent();
for(int i = 0; i < m_news_count; i++)
{
if(m_news_events[i].time > current_time)
{
int minutes_to_news = (int)((m_news_events[i].time - current_time) / 60);
return StringFormat("%s %s in %d min (%s)",
m_news_events[i].currency,
m_news_events[i].title,
minutes_to_news,
GetImpactString(m_news_events[i].impact));
}
}
return "No upcoming news today";
}
void Cleanup()
{
ObjectsDeleteAll(0, "NewsLine_");
}
};
class CMarketAnalyzer
{
private:
int m_ema_fast_handle;
int m_ema_slow_handle;
int m_atr_handle;
int m_rsi_handle;
int m_trend_ma_handle;
double m_ema_fast_buffer[];
double m_ema_slow_buffer[];
double m_atr_buffer[];
double m_rsi_buffer[];
double m_trend_ma_buffer[];
public:
CMarketAnalyzer() : m_ema_fast_handle(INVALID_HANDLE), m_ema_slow_handle(INVALID_HANDLE),
m_atr_handle(INVALID_HANDLE), m_rsi_handle(INVALID_HANDLE),
m_trend_ma_handle(INVALID_HANDLE) {}
~CMarketAnalyzer() { Release(); }
bool Initialize()
{
m_ema_fast_handle = iMA(_Symbol, PERIOD_CURRENT, 10, 0, MODE_EMA, PRICE_CLOSE);
m_ema_slow_handle = iMA(_Symbol, PERIOD_CURRENT, AMA_Period, 0, MODE_EMA, PRICE_CLOSE);
m_atr_handle = iATR(_Symbol, PERIOD_CURRENT, ATR_Period);
if(UseRSIFilter)
m_rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, RSI_Period, PRICE_CLOSE);
m_trend_ma_handle = iMA(_Symbol, TrendTimeframe, TrendMA_Period, 0, MODE_EMA, PRICE_CLOSE);
ArraySetAsSeries(m_ema_fast_buffer, true);
ArraySetAsSeries(m_ema_slow_buffer, true);
ArraySetAsSeries(m_atr_buffer, true);
ArraySetAsSeries(m_rsi_buffer, true);
ArraySetAsSeries(m_trend_ma_buffer, true);
return (m_ema_fast_handle != INVALID_HANDLE && m_ema_slow_handle != INVALID_HANDLE &&
m_atr_handle != INVALID_HANDLE && m_trend_ma_handle != INVALID_HANDLE);
}
void Release()
{
if(m_ema_fast_handle != INVALID_HANDLE)
IndicatorRelease(m_ema_fast_handle);
if(m_ema_slow_handle != INVALID_HANDLE)
IndicatorRelease(m_ema_slow_handle);
if(m_atr_handle != INVALID_HANDLE)
IndicatorRelease(m_atr_handle);
if(m_rsi_handle != INVALID_HANDLE)
IndicatorRelease(m_rsi_handle);
if(m_trend_ma_handle != INVALID_HANDLE)
IndicatorRelease(m_trend_ma_handle);
}
bool UpdateData()
{
bool result = true;
result &= (CopyBuffer(m_ema_fast_handle, 0, 0, 3, m_ema_fast_buffer) > 0);
result &= (CopyBuffer(m_ema_slow_handle, 0, 0, 3, m_ema_slow_buffer) > 0);
result &= (CopyBuffer(m_atr_handle, 0, 0, 3, m_atr_buffer) > 0);
result &= (CopyBuffer(m_trend_ma_handle, 0, 0, 3, m_trend_ma_buffer) > 0);
if(UseRSIFilter && m_rsi_handle != INVALID_HANDLE)
result &= (CopyBuffer(m_rsi_handle, 0, 0, 3, m_rsi_buffer) > 0);
return result;
}
ENUM_MARKET_PHASE GetMarketPhase()
{
if(!UpdateData())
return MARKET_UNKNOWN;
double ema_diff = MathAbs(m_ema_fast_buffer[0] - m_ema_slow_buffer[0]) / _Point;
double atr_current = m_atr_buffer[0] / _Point;
double atr_avg = (m_atr_buffer[0] + m_atr_buffer[1] + m_atr_buffer[2]) / 3.0 / _Point;
if(ema_diff > 50 && atr_current > atr_avg * 2.0)
return MARKET_TRENDING;
return MARKET_RANGING;
}
ENUM_TREND_DIRECTION GetTrendDirection()
{
if(!UpdateData())
return TREND_NEUTRAL;
double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double trend_ma = m_trend_ma_buffer[0];
if(current_price > trend_ma * 1.0005)
return TREND_BULLISH;
else
if(current_price < trend_ma * 0.9995)
return TREND_BEARISH;
double ma_slope = (m_trend_ma_buffer[0] - m_trend_ma_buffer[2]) / _Point;
if(ma_slope > 5)
return TREND_BULLISH;
if(ma_slope < -5)
return TREND_BEARISH;
return TREND_NEUTRAL;
}
bool IsRSIOversold()
{
if(!UseRSIFilter || m_rsi_handle == INVALID_HANDLE)
return true;
return m_rsi_buffer[0] < 40.0;
}
bool IsRSIOverbought()
{
if(!UseRSIFilter || m_rsi_handle == INVALID_HANDLE)
return true;
return m_rsi_buffer[0] > 60.0;
}
bool GetSwingLevels(double &swing_high, double &swing_low)
{
double high_buffer[], low_buffer[];
ArraySetAsSeries(high_buffer, true);
ArraySetAsSeries(low_buffer, true);
if(CopyHigh(_Symbol, PERIOD_CURRENT, 0, SwingLookback, high_buffer) <= 0 ||
CopyLow(_Symbol, PERIOD_CURRENT, 0, SwingLookback, low_buffer) <= 0)
return false;
swing_high = high_buffer[ArrayMaximum(high_buffer)];
swing_low = low_buffer[ArrayMinimum(low_buffer)];
return true;
}
double CalculateFibonacciLevel(double high, double low, double fib_percent, bool is_retracement = true)
{
if(is_retracement)
return high - (high - low) * fib_percent / 100.0;
else
return low + (high - low) * fib_percent / 100.0;
}
double GetATR() { return UpdateData() ? m_atr_buffer[0] : 0; }
double GetRSI() { return (UseRSIFilter && UpdateData()) ? m_rsi_buffer[0] : 50; }
};
class CEnhancedSRDetector
{
private:
SRLevel m_sr_levels[];
int m_sr_count;
ChannelInfo m_current_channel;
bool m_in_channel;
BreakoutInfo m_last_breakout;
bool m_breakout_pending;
public:
CEnhancedSRDetector() : m_sr_count(0), m_in_channel(false) {}
bool Initialize()
{
ArrayResize(m_sr_levels, 50); // Max 50 S/R levels
DetectSupportResistanceLevels();
DetectCurrentChannel();
return true;
};
bool DetectBreakout(double current_price, double &breakout_level, bool &is_bullish_breakout, double &confidence_score)
{
if(!IsNewBar())
return false; // Only check on new bars
double nearest_resistance, nearest_support;
double resistance_strength, support_strength;
bool near_resistance = IsNearResistanceLevel(current_price, nearest_resistance, resistance_strength);
bool near_support = IsNearSupportLevel(current_price, nearest_support, support_strength);
if(CheckResistanceBreakout(current_price, nearest_resistance, resistance_strength, breakout_level, confidence_score))
{
is_bullish_breakout = true;
return true;
}
if(CheckSupportBreakdown(current_price, nearest_support, support_strength, breakout_level, confidence_score))
{
is_bullish_breakout = false;
return true;
}
return false;
}
bool IsBreakoutPending() { return m_breakout_pending; }
private:
void DetectSupportResistanceLevels()
{
double high_buffer[], low_buffer[];
ArraySetAsSeries(high_buffer, true);
ArraySetAsSeries(low_buffer, true);
if(CopyHigh(_Symbol, PERIOD_CURRENT, 0, SR_LookbackPeriod, high_buffer) <= 0 ||
CopyLow(_Symbol, PERIOD_CURRENT, 0, SR_LookbackPeriod, low_buffer) <= 0)
return;
m_sr_count = 0;
for(int i = 5; i < SR_LookbackPeriod - 5; i++)
{
if(IsSwingHigh(high_buffer, i, 3))
{
double level = high_buffer[i];
AddOrUpdateSRLevel(level, false); // resistance
}
if(IsSwingLow(low_buffer, i, 3))
{
double level = low_buffer[i];
AddOrUpdateSRLevel(level, true); // support
}
}
CalculateSRStrengths();
SortSRLevelsByStrength();
Print("✓ Detected ", m_sr_count, " S/R levels");
}
bool IsSwingHigh(const double &highs[], int index, int lookback)
{
double current = highs[index];
for(int i = index - lookback; i <= index + lookback; i++)
{
if(i != index && highs[i] >= current)
return false;
}
return true;
}
bool IsSwingLow(const double &lows[], int index, int lookback)
{
double current = lows[index];
for(int i = index - lookback; i <= index + lookback; i++)
{
if(i != index && lows[i] <= current)
return false;
}
return true;
}
void AddOrUpdateSRLevel(double price, bool is_support)
{
double buffer = SR_ZoneBuffer * _Point;
for(int i = 0; i < m_sr_count; i++)
{
if(MathAbs(m_sr_levels[i].price - price) <= buffer &&
m_sr_levels[i].is_support == is_support)
{
m_sr_levels[i].touch_count++;
m_sr_levels[i].last_touch = TimeCurrent();
return;
}
}
if(m_sr_count < ArraySize(m_sr_levels))
{
m_sr_levels[m_sr_count].price = price;
m_sr_levels[m_sr_count].is_support = is_support;
m_sr_levels[m_sr_count].touch_count = 1;
m_sr_levels[m_sr_count].first_touch = TimeCurrent();
m_sr_levels[m_sr_count].last_touch = TimeCurrent();
m_sr_levels[m_sr_count].is_active = true;
m_sr_count++;
}
}
void CalculateSRStrengths()
{
for(int i = 0; i < m_sr_count; i++)
{
double time_factor = 1.0;
double touch_factor = m_sr_levels[i].touch_count;
double age_hours = (TimeCurrent() - m_sr_levels[i].first_touch) / 3600.0;
if(age_hours < 24)
time_factor = 1.2;
else
if(age_hours < 168)
time_factor = 1.0; // 1 week
else
time_factor = 0.8;
m_sr_levels[i].strength = touch_factor * time_factor;
}
}
void SortSRLevelsByStrength()
{
for(int i = 0; i < m_sr_count - 1; i++)
{
for(int j = 0; j < m_sr_count - i - 1; j++)
{
if(m_sr_levels[j].strength < m_sr_levels[j + 1].strength)
{
SRLevel temp = m_sr_levels[j];
m_sr_levels[j] = m_sr_levels[j + 1];
m_sr_levels[j + 1] = temp;
}
}
}
if(m_sr_count > 20)
m_sr_count = 20;
}
void DetectCurrentChannel()
{
m_in_channel = false;
double high_buffer[], low_buffer[];
ArraySetAsSeries(high_buffer, true);
ArraySetAsSeries(low_buffer, true);
if(CopyHigh(_Symbol, PERIOD_CURRENT, 0, ChannelMinBars, high_buffer) <= 0 ||
CopyLow(_Symbol, PERIOD_CURRENT, 0, ChannelMinBars, low_buffer) <= 0)
return;
double upper_slope, upper_intercept, lower_slope, lower_intercept;
double upper_correlation = CalculateLinearRegression(high_buffer, ChannelMinBars, upper_slope, upper_intercept);
double lower_correlation = CalculateLinearRegression(low_buffer, ChannelMinBars, lower_slope, lower_intercept);
if(MathAbs(upper_correlation) > ChannelThreshold &&
MathAbs(lower_correlation) > ChannelThreshold &&
MathAbs(upper_slope - lower_slope) < 0.0001) // Parallel lines
{
m_current_channel.upper_line = upper_intercept;
m_current_channel.lower_line = lower_intercept;
m_current_channel.slope = (upper_slope + lower_slope) / 2.0;
m_current_channel.strength = (MathAbs(upper_correlation) + MathAbs(lower_correlation)) / 2.0;
m_current_channel.is_active = true;
m_current_channel.start_time = TimeCurrent();
m_in_channel = true;
Print("✓ Channel detected - Upper: ", m_current_channel.upper_line,
" Lower: ", m_current_channel.lower_line,
" Strength: ", m_current_channel.strength);
}
}
double CalculateLinearRegression(const double &prices[], int period, double &slope, double &intercept)
{
double sum_x = 0, sum_y = 0, sum_xy = 0, sum_x2 = 0;
for(int i = 0; i < period; i++)
{
sum_x += i;
sum_y += prices[i];
sum_xy += i * prices[i];
sum_x2 += i * i;
}
slope = (period * sum_xy - sum_x * sum_y) / (period * sum_x2 - sum_x * sum_x);
intercept = (sum_y - slope * sum_x) / period;
double sum_y2 = 0;
for(int i = 0; i < period; i++)
sum_y2 += prices[i] * prices[i];
double numerator = period * sum_xy - sum_x * sum_y;
double denominator = MathSqrt((period * sum_x2 - sum_x * sum_x) * (period * sum_y2 - sum_y * sum_y));
return (denominator != 0) ? numerator / denominator : 0;
}
bool IsNewBar()
{
static datetime last_bar_time = 0;
datetime current_bar_time = iTime(_Symbol, PERIOD_CURRENT, 0);
if(current_bar_time != last_bar_time)
{
last_bar_time = current_bar_time;
return true;
}
return false;
}
bool CheckResistanceBreakout(double current_price, double resistance_level, double strength,
double &breakout_level, double &confidence_score)
{
if(resistance_level == 0 || strength < SR_MinStrength)
return false;
double breakout_distance = (current_price - resistance_level) / _Point;
if(breakout_distance < BreakoutMinPips || breakout_distance > BreakoutMaxPips)
return false;
double momentum_score = CalculateMomentumScore(true);
if(UseMomentumFilter && momentum_score < MomentumThreshold)
return false;
double volume_score = CalculateVolumeScore();
if(UseVolumeFilter && volume_score < VolumeMultiplier)
return false;
if(!PassesFalseBreakoutFilter(current_price, resistance_level, true))
return false;
confidence_score = CalculateBreakoutConfidence(strength, momentum_score, volume_score, breakout_distance);
if(confidence_score >= FalseBreakoutFilter)
{
breakout_level = resistance_level;
m_last_breakout.sr_level = resistance_level;
m_last_breakout.is_resistance_break = true;
m_last_breakout.break_time = TimeCurrent();
m_last_breakout.break_price = current_price;
m_last_breakout.momentum_score = momentum_score;
m_last_breakout.volume_score = volume_score;
m_last_breakout.is_confirmed = false;
m_last_breakout.confirmation_bars = 0;
m_breakout_pending = true;
return true;
}
return false;
}
bool CheckSupportBreakdown(double current_price, double support_level, double strength,
double &breakout_level, double &confidence_score)
{
if(support_level == 0 || strength < SR_MinStrength)
return false;
double breakout_distance = (support_level - current_price) / _Point;
if(breakout_distance < BreakoutMinPips || breakout_distance > BreakoutMaxPips)
return false;
double momentum_score = CalculateMomentumScore(false);
if(UseMomentumFilter && momentum_score < MomentumThreshold)
return false;
double volume_score = CalculateVolumeScore();
if(UseVolumeFilter && volume_score < VolumeMultiplier)
return false;
if(!PassesFalseBreakoutFilter(current_price, support_level, false))
return false;
confidence_score = CalculateBreakoutConfidence(strength, momentum_score, volume_score, breakout_distance);
if(confidence_score >= FalseBreakoutFilter)
{
breakout_level = support_level;
m_last_breakout.sr_level = support_level;
m_last_breakout.is_resistance_break = false;
m_last_breakout.break_time = TimeCurrent();
m_last_breakout.break_price = current_price;
m_last_breakout.momentum_score = momentum_score;
m_last_breakout.volume_score = volume_score;
m_last_breakout.is_confirmed = false;
m_last_breakout.confirmation_bars = 0;
m_breakout_pending = true;
return true;
}
return false;
}
double CalculateMomentumScore(bool bullish_breakout)
{
double atr_current = g_market_analyzer.GetATR();
double atr_buffer[];
ArraySetAsSeries(atr_buffer, true);
int atr_handle = iATR(_Symbol, PERIOD_CURRENT, 14);
if(CopyBuffer(atr_handle, 0, 0, 10, atr_buffer) <= 0)
return 0;
double atr_avg = 0;
for(int i = 1; i < 10; i++) // Skip current bar
atr_avg += atr_buffer[i];
atr_avg /= 9;
double momentum_ratio = (atr_avg > 0) ? atr_current / atr_avg : 1.0;
double close_buffer[];
ArraySetAsSeries(close_buffer, true);
if(CopyClose(_Symbol, PERIOD_CURRENT, 0, 5, close_buffer) <= 0)
return momentum_ratio;
double price_velocity = 0;
if(bullish_breakout)
price_velocity = (close_buffer[0] - close_buffer[4]) / (4 * _Point);
else
price_velocity = (close_buffer[4] - close_buffer[0]) / (4 * _Point);
double velocity_score = MathMax(0, price_velocity / 20.0); // Normalize velocity
return momentum_ratio + velocity_score;
}
double CalculateVolumeScore()
{
if(!UseVolumeFilter)
return VolumeMultiplier; // Pass if not using volume
long volume_buffer[];
ArraySetAsSeries(volume_buffer, true);
if(CopyTickVolume(_Symbol, PERIOD_CURRENT, 0, VolumeConfirmPeriod + 1, volume_buffer) <= 0)
return 1.0; // Default if no volume data
long current_volume = volume_buffer[0];
long avg_volume = 0;
for(int i = 1; i <= VolumeConfirmPeriod; i++)
avg_volume += volume_buffer[i];
avg_volume /= VolumeConfirmPeriod;
return (avg_volume > 0) ? (double)current_volume / (double)avg_volume : 1.0;
}
bool PassesFalseBreakoutFilter(double current_price, double sr_level, bool is_resistance_break)
{
double close_buffer[];
ArraySetAsSeries(close_buffer, true);
if(CopyClose(_Symbol, PERIOD_CURRENT, 0, 3, close_buffer) <= 0)
return true; // Default pass if no data
double min_penetration = BreakoutMinPips * _Point;
if(is_resistance_break)
{
return (close_buffer[0] > sr_level + min_penetration);
}
else
{
return (close_buffer[0] < sr_level - min_penetration);
}
}
double CalculateBreakoutConfidence(double sr_strength, double momentum_score, double volume_score, double breakout_distance)
{
double strength_score = MathMin(sr_strength / 10.0, 1.0); // Max 10 touches
double momentum_normalized = MathMin(momentum_score / 3.0, 1.0); // Max 3x momentum
double volume_normalized = MathMin(volume_score / 3.0, 1.0); // Max 3x volume
double distance_score = MathMin(breakout_distance / BreakoutMaxPips, 1.0);
double confidence = (strength_score * 0.3) +
(momentum_normalized * 0.3) +
(volume_normalized * 0.2) +
(distance_score * 0.2);
return confidence;
}
public:
bool IsNearSupportLevel(double price, double &support_level, double &strength)
{
double buffer = SR_ZoneBuffer * _Point;
for(int i = 0; i < m_sr_count; i++)
{
if(m_sr_levels[i].is_support && m_sr_levels[i].is_active &&
m_sr_levels[i].strength >= SR_MinStrength)
{
if(MathAbs(price - m_sr_levels[i].price) <= buffer)
{
support_level = m_sr_levels[i].price;
strength = m_sr_levels[i].strength;
return true;
}
}
}
return false;
}
bool IsNearResistanceLevel(double price, double &resistance_level, double &strength)
{
double buffer = SR_ZoneBuffer * _Point;
for(int i = 0; i < m_sr_count; i++)
{
if(!m_sr_levels[i].is_support && m_sr_levels[i].is_active &&
m_sr_levels[i].strength >= SR_MinStrength)
{
if(MathAbs(price - m_sr_levels[i].price) <= buffer)
{
resistance_level = m_sr_levels[i].price;
strength = m_sr_levels[i].strength;
return true;
}
}
}
return false;
}
bool IsInChannel() { return m_in_channel && UseChannelTrading; }
bool IsNearChannelSupport(double price)
{
if(!m_in_channel)
return false;
double buffer = SR_ZoneBuffer * _Point;
return MathAbs(price - m_current_channel.lower_line) <= buffer;
}
bool IsNearChannelResistance(double price)
{
if(!m_in_channel)
return false;
double buffer = SR_ZoneBuffer * _Point;
return MathAbs(price - m_current_channel.upper_line) <= buffer;
}
double GetChannelSupport() { return m_current_channel.lower_line; }
double GetChannelResistance() { return m_current_channel.upper_line; }
double GetChannelStrength() { return m_current_channel.strength; }
void UpdateSRLevels()
{
DetectSupportResistanceLevels();
DetectCurrentChannel();
}
bool IsBreakoutConfirmed(double current_price)
{
if(!m_breakout_pending)
return false;
m_last_breakout.confirmation_bars++;
bool still_valid = false;
double min_distance = BreakoutMinPips * _Point * 0.5; // Half the minimum distance
if(m_last_breakout.is_resistance_break)
{
still_valid = (current_price > m_last_breakout.sr_level + min_distance);
}
else
{
still_valid = (current_price < m_last_breakout.sr_level - min_distance);
}
if(!still_valid)
{
m_breakout_pending = false; // Failed breakout
return false;
}
if(m_last_breakout.confirmation_bars >= BreakoutConfirmBars)
{
m_last_breakout.is_confirmed = true;
m_breakout_pending = false;
return true;
}
return false;
}
bool CheckSRBreakoutEntry(double current_price, ENUM_TREND_DIRECTION trend, datetime &last_trade_time)
{
static datetime last_breakout_trade = 0;
if(TimeCurrent() - last_breakout_trade < 7200)
return false; // 2 hours minimum
double breakout_level = 0, confidence_score = 0;
bool is_bullish_breakout = false;
if(DetectBreakout(current_price, breakout_level, is_bullish_breakout, confidence_score))
{
Print("⚡ Potential breakout detected at level: ", breakout_level,
" Direction: ", is_bullish_breakout ? "BULLISH" : "BEARISH",
" Confidence: ", confidence_score);
return false; // Wait for confirmation
}
if(IsBreakoutConfirmed(current_price))
{
bool is_resistance_break = (current_price > breakout_level);
if(!PassesBreakoutFilters(is_resistance_break, trend))
return false;
double base_lot = g_risk_manager.CalculatePositionSize(1);
double confidence_multiplier = MathMin(confidence_score * 2.0, 1.5); // Max 1.5x
double lot_size = base_lot * confidence_multiplier;
lot_size = MathMin(lot_size, MaxLotSize);
lot_size = NormalizeLots(lot_size);
if(is_resistance_break)
{
if(g_risk_manager.ValidateTrade(lot_size, ORDER_TYPE_BUY))
{
if(g_trade_manager.OpenInitialPosition(ORDER_TYPE_BUY, lot_size, Commentary + "_Breakout_Buy"))
{
Print("✅ BREAKOUT BUY executed at: ", current_price,
" Breaking resistance: ", breakout_level,
" Lot size: ", lot_size,
" Confidence: ", confidence_score);
last_trade_time = TimeCurrent();
last_breakout_trade = TimeCurrent();
return true;
}
}
}
else
{
if(g_risk_manager.ValidateTrade(lot_size, ORDER_TYPE_SELL))
{
if(g_trade_manager.OpenInitialPosition(ORDER_TYPE_SELL, lot_size, Commentary + "_Breakout_Sell"))
{
Print("✅ BREAKOUT SELL executed at: ", current_price,
" Breaking support: ", breakout_level,
" Lot size: ", lot_size,
" Confidence: ", confidence_score);
last_trade_time = TimeCurrent();
last_breakout_trade = TimeCurrent();
return true;
}
}
}
}
return false;
}
bool PassesBreakoutFilters(bool is_bullish_breakout, ENUM_TREND_DIRECTION trend)
{
if(trend != TREND_NEUTRAL)
{
if(is_bullish_breakout && trend == TREND_BEARISH)
return false;
if(!is_bullish_breakout && trend == TREND_BULLISH)
return false;
}
double atr_current = g_market_analyzer.GetATR();
if(atr_current < 20 * _Point)
return false; // Minimum volatility required
if(UseRSIFilter)
{
double rsi = g_market_analyzer.GetRSI();
if(is_bullish_breakout && rsi > 80)
return false; // Avoid extreme overbought
if(!is_bullish_breakout && rsi < 20)
return false; // Avoid extreme oversold
}
MqlDateTime current_time;
TimeToStruct(TimeCurrent(), current_time);
if(current_time.hour >= 22 || current_time.hour <= 6)
return false;
return true;
}
void UpdateBreakoutInfo()
{
string breakout_status = "No active breakouts";
if(g_sr_detector.IsBreakoutPending())
{
breakout_status = "Breakout pending confirmation...";
}
}
};
void CheckEnhancedSimpleEntry()
{
if(!UseEnhancedEntry)
return;
static datetime last_update = 0;
static datetime last_trade_time = 0;
if(TimeCurrent() - last_update > 3600)
{
g_sr_detector.UpdateSRLevels();
last_update = TimeCurrent();
}
if(TimeCurrent() - last_trade_time < 14400)
return; // 4 hours minimum
double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
ENUM_MARKET_PHASE market_phase = g_market_analyzer.GetMarketPhase();
ENUM_TREND_DIRECTION trend = g_market_analyzer.GetTrendDirection();
if(g_sr_detector.IsInChannel() && market_phase == MARKET_RANGING)
{
if(CheckChannelEntry(current_price, last_trade_time))
return;
}
if(market_phase == MARKET_TRENDING && trend != TREND_NEUTRAL)
{
if(CheckSRBounceEntry(current_price, trend, last_trade_time))
return;
}
if(CheckSRBreakoutEntry(current_price, trend, last_trade_time))
return;
}
bool CheckChannelEntry(double current_price, datetime &last_trade_time)
{
if(g_sr_detector.IsNearChannelSupport(current_price))
{
if(g_market_analyzer.IsRSIOversold())
{
double lot_size = CalculateEnhancedLotSize(g_sr_detector.GetChannelStrength());
if(g_risk_manager.ValidateTrade(lot_size, ORDER_TYPE_BUY))
{
if(g_trade_manager.OpenInitialPosition(ORDER_TYPE_BUY, lot_size, Commentary + "_Channel_Support"))
{
Print("✓ CHANNEL BUY at support: ", g_sr_detector.GetChannelSupport(),
" Strength: ", g_sr_detector.GetChannelStrength());
last_trade_time = TimeCurrent();
return true;
}
}
}
}
if(g_sr_detector.IsNearChannelResistance(current_price))
{
if(g_market_analyzer.IsRSIOverbought())
{
double lot_size = CalculateEnhancedLotSize(g_sr_detector.GetChannelStrength());
if(g_risk_manager.ValidateTrade(lot_size, ORDER_TYPE_SELL))
{
if(g_trade_manager.OpenInitialPosition(ORDER_TYPE_SELL, lot_size, Commentary + "_Channel_Resistance"))
{
Print("✓ CHANNEL SELL at resistance: ", g_sr_detector.GetChannelResistance(),
" Strength: ", g_sr_detector.GetChannelStrength());
last_trade_time = TimeCurrent();
return true;
}
}
}
}
return false;
}
bool CheckSRBounceEntry(double current_price, ENUM_TREND_DIRECTION trend, datetime &last_trade_time)
{
double level, strength;
if(trend == TREND_BULLISH && g_sr_detector.IsNearSupportLevel(current_price, level, strength))
{
if(g_market_analyzer.IsRSIOversold())
{
double lot_size = CalculateEnhancedLotSize(strength);
if(g_risk_manager.ValidateTrade(lot_size, ORDER_TYPE_BUY))
{
if(g_trade_manager.OpenInitialPosition(ORDER_TYPE_BUY, lot_size, Commentary + "_SR_Support"))
{
Print("✓ S/R BUY bounce at: ", level, " Strength: ", strength);
last_trade_time = TimeCurrent();
return true;
}
}
}
}
if(trend == TREND_BEARISH && g_sr_detector.IsNearResistanceLevel(current_price, level, strength))
{
if(g_market_analyzer.IsRSIOverbought())
{
double lot_size = CalculateEnhancedLotSize(strength);
if(g_risk_manager.ValidateTrade(lot_size, ORDER_TYPE_SELL))
{
if(g_trade_manager.OpenInitialPosition(ORDER_TYPE_SELL, lot_size, Commentary + "_SR_Resistance"))
{
Print("✓ S/R SELL bounce at: ", level, " Strength: ", strength);
last_trade_time = TimeCurrent();
return true;
}
}
}
}
return false;
}
bool CheckSRBreakoutEntry(double current_price, ENUM_TREND_DIRECTION trend, datetime &last_trade_time)
{
static datetime last_breakout_trade = 0;
if(TimeCurrent() - last_breakout_trade < 7200)
return false; // 2 hours minimum
double resistance_level, resistance_strength;
if(g_sr_detector.IsNearResistanceLevel(current_price, resistance_level, resistance_strength))
{
double breakout_distance = (current_price - resistance_level) / _Point;
if(breakout_distance >= BreakoutMinPips && breakout_distance <= BreakoutMaxPips)
{
if(trend == TREND_BEARISH)
return false; // Don't trade against strong trend
if(UseMomentumFilter)
{
double atr_current = g_market_analyzer.GetATR();
if(atr_current < 20 * _Point)
return false; // Minimum volatility required
}
if(UseRSIFilter)
{
double rsi = g_market_analyzer.GetRSI();
if(rsi > 80)
return false; // Avoid extreme overbought
}
double confidence_score = MathMin(resistance_strength / 5.0, 1.0); // Normalize strength
double base_lot = g_risk_manager.CalculatePositionSize(1);
double lot_size = base_lot * (0.5 + confidence_score * 0.5); // 50%-100% based on confidence
lot_size = MathMin(lot_size, MaxLotSize);
lot_size = NormalizeLots(lot_size);
if(g_risk_manager.ValidateTrade(lot_size, ORDER_TYPE_BUY))
{
if(g_trade_manager.OpenInitialPosition(ORDER_TYPE_BUY, lot_size, Commentary + "_Breakout_Buy"))
{
Print("✅ RESISTANCE BREAKOUT BUY at: ", current_price,
" Breaking resistance: ", resistance_level,
" Distance: ", breakout_distance, " pips",
" Strength: ", resistance_strength,
" Lot size: ", lot_size);
last_trade_time = TimeCurrent();
last_breakout_trade = TimeCurrent();
return true;
}
}
}
}
double support_level, support_strength;
if(g_sr_detector.IsNearSupportLevel(current_price, support_level, support_strength))
{
double breakout_distance = (support_level - current_price) / _Point;
if(breakout_distance >= BreakoutMinPips && breakout_distance <= BreakoutMaxPips)
{
if(trend == TREND_BULLISH)
return false; // Don't trade against strong trend
if(UseMomentumFilter)
{
double atr_current = g_market_analyzer.GetATR();
if(atr_current < 20 * _Point)
return false; // Minimum volatility required
}
if(UseRSIFilter)
{
double rsi = g_market_analyzer.GetRSI();
if(rsi < 20)
return false; // Avoid extreme oversold
}
double confidence_score = MathMin(support_strength / 5.0, 1.0); // Normalize strength
double base_lot = g_risk_manager.CalculatePositionSize(1);
double lot_size = base_lot * (0.5 + confidence_score * 0.5); // 50%-100% based on confidence
lot_size = MathMin(lot_size, MaxLotSize);
lot_size = NormalizeLots(lot_size);
if(g_risk_manager.ValidateTrade(lot_size, ORDER_TYPE_SELL))
{
if(g_trade_manager.OpenInitialPosition(ORDER_TYPE_SELL, lot_size, Commentary + "_Breakout_Sell"))
{
Print("✅ SUPPORT BREAKDOWN SELL at: ", current_price,
" Breaking support: ", support_level,
" Distance: ", breakout_distance, " pips",
" Strength: ", support_strength,
" Lot size: ", lot_size);
last_trade_time = TimeCurrent();
last_breakout_trade = TimeCurrent();
return true;
}
}
}
}
return false;
}
double CalculateEnhancedLotSize(double sr_strength)
{
int current_positions = g_risk_manager.GetGridPositionCount();
double base_lot = g_risk_manager.CalculatePositionSize(current_positions);
if(!UseDynamicLotSizing)
return base_lot;
double strength_multiplier = 1.0;
if(sr_strength >= 5.0)
strength_multiplier = 1.2; // Reduced from 1.5 to avoid over-sizing
else
if(sr_strength >= 3.0)
strength_multiplier = 1.1;
else
strength_multiplier = 0.9;
double final_lot = base_lot * strength_multiplier;
return NormalizeLots(final_lot);
}
class CRiskManager
{
private:
double m_initial_balance;
datetime m_last_check_time;
public:
CRiskManager() : m_initial_balance(AccountInfoDouble(ACCOUNT_BALANCE)), m_last_check_time(0) {}
double GetCurrentExposure()
{
double total_profit = 0.0;
double total_floating = 0.0;
for(int i = 0; i < PositionsTotal(); i++)
{
if(position.SelectByIndex(i) && position.Magic() == MagicNumber && position.Symbol() == _Symbol)
{
total_profit += position.Profit();
total_floating += position.Swap() + position.Commission();
}
}
double current_equity = AccountInfoDouble(ACCOUNT_EQUITY);
if(current_equity <= 0)
return 0;
return ((total_profit + total_floating) / current_equity) * 100.0;
}
bool IsExposureAcceptable()
{
Показано первые 50% кода (символов: 79149)
Открыть по тарифу
Купите тариф с пакетом открытий или войдите, если тариф уже есть. Открытый файл останется в вашем кабинете навсегда.
Разовая покупка файла
На этой странице откроется полный исходный код файла вместо ознакомительного фрагмента.
Зачем нужен email? После подтверждения оплаты файл сохранится в кабинете на этот email. Если аккаунта ещё нет, мы создадим его и пришлём ссылку для задания пароля. Если аккаунт уже есть, покупка добавится в него. Укажите адрес, к которому у вас есть доступ.
Чтобы оформить заказ, введите email и перейдите к оплате.