Overview To fully integrate the enhanced external trade management system, updates are required to 5 out of 7 existing modules. The updates maintain backward compatibility while adding new functionality for external trade handling. Module Update Requirements 🟢 No Updates Required (2 modules) TechnicalAnalysis.mqh - Already provides necessary calculations EntrySystem.mqh - Only handles EA's own entry signals 🟡 Minor Updates (2 modules) DataTypes.mqh - Add external trade structures and fields Utilities.mqh - Enhanced logging for external trades 🟠 Moderate Updates (3 modules) RiskManager.mqh - Enhanced risk enforcement methods TradeManager.mqh - Improved stop management for externals Dashboard.mqh - Display external trade information Integration Steps Phase 1: Data Structures (DataTypes.mqh) Add ENUM_EXTERNAL_STATUS enumeration Extend ManagedTrade structure with external-specific fields Add ExternalTradeStats structure for metrics Update DashboardConfig with show_external flag Key additions: external_status - Track state of external trade source_name - Identify where trade came from stops_modified - Track if we modified the trade original_sl/tp - Store original values for comparison Phase 2: Risk Management (RiskManager.mqh) Add EnforceRiskRulesEnhanced() method Implement GetExternalExposure() for risk aggregation Add UpdateExternalStats() for tracking Enhance ValidateAndAdjustRiskExternal() method Key features: Separate risk calculation for external trades Cache mechanism for performance Statistical tracking of external positions Smart risk adjustment without closing trades Phase 3: Trade Management (TradeManager.mqh) Add ApplyDefaultStopsEnhanced() with better logic Implement OverrideExternalStops() with smart override Create ManageExternalTrade() with different rules Add ApplyBreakevenExternal() with wider triggers Key features: Smart stop override (only improve, never worsen) Different management rules for external trades Respect minimum broker distances Track modification success/failure rates Phase 4: User Interface (Dashboard.mqh) Add CreateExternalSection() for display area Implement UpdateExternalSection() for real-time updates Add SetCustomText() for flexible display Create ShowExternalTrades() toggle method Key features: Real-time external trade count and risk Color-coded risk warnings List of active external positions Modification statistics display Phase 5: Logging (Utilities.mqh) Add LogExternalTrade() for detailed event logging Create separate CSV log for external trades Enhance GenerateReportEnhanced() with external section Add IdentifyTradeSource() for magic number interpretation Key features: Separate CSV log for external trade events Detailed tracking of all modifications Source identification from magic numbers Enhanced reporting with external statistics
1186 lines
No EOL
38 KiB
MQL5
1186 lines
No EOL
38 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| TechnicalAnalysis_v71.mqh |
|
|
//| Enhanced Technical Analysis Module v7.1 |
|
|
//| Market Structure, Correlations, Advanced Indicators |
|
|
//+------------------------------------------------------------------+
|
|
#ifndef TECHNICAL_ANALYSIS_V71_MQH
|
|
#define TECHNICAL_ANALYSIS_V71_MQH
|
|
|
|
#include "DataTypes_v71.mqh"
|
|
#include <Math/Stat/Math.mqh>
|
|
#include <Indicators/Indicators.mqh>
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Market Structure |
|
|
//+------------------------------------------------------------------+
|
|
struct MarketStructure
|
|
{
|
|
double swing_highs[];
|
|
double swing_lows[];
|
|
int trend_direction; // 1=up, -1=down, 0=neutral
|
|
double trend_strength;
|
|
int structure_breaks;
|
|
datetime last_break_time;
|
|
bool is_ranging;
|
|
double range_high;
|
|
double range_low;
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Support/Resistance Level |
|
|
//+------------------------------------------------------------------+
|
|
struct SRLevel
|
|
{
|
|
double price;
|
|
int touches;
|
|
double strength;
|
|
datetime first_touch;
|
|
datetime last_touch;
|
|
bool is_broken;
|
|
bool is_support;
|
|
double volume_at_level;
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Fibonacci Level |
|
|
//+------------------------------------------------------------------+
|
|
struct FibLevel
|
|
{
|
|
double level;
|
|
double price;
|
|
string description;
|
|
bool is_touched;
|
|
int bounce_count;
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Technical Analysis Class - Enhanced |
|
|
//+------------------------------------------------------------------+
|
|
class CTechnicalAnalysisV71
|
|
{
|
|
private:
|
|
//--- Indicator handles
|
|
int m_atr_handle;
|
|
int m_rsi_handle;
|
|
int m_macd_handle;
|
|
int m_bb_handle;
|
|
int m_ma_handles[];
|
|
int m_adx_handle;
|
|
int m_cci_handle;
|
|
int m_stoch_handle;
|
|
int m_ichimoku_handle;
|
|
|
|
//--- Market structure
|
|
MarketStructure m_structure;
|
|
SRLevel m_sr_levels[];
|
|
int m_sr_count;
|
|
|
|
//--- Correlation tracking
|
|
CorrelationMatrix m_correlation_matrix;
|
|
datetime m_last_correlation_update;
|
|
|
|
//--- Multi-timeframe data
|
|
struct MTFData
|
|
{
|
|
ENUM_TIMEFRAMES timeframe;
|
|
double trend_direction;
|
|
double momentum;
|
|
double volatility;
|
|
};
|
|
MTFData m_mtf_data[];
|
|
|
|
//--- Pattern detection
|
|
bool m_pattern_double_top;
|
|
bool m_pattern_double_bottom;
|
|
bool m_pattern_head_shoulders;
|
|
bool m_pattern_triangle;
|
|
|
|
//--- Helper methods
|
|
void DetectSwings(string symbol, int lookback);
|
|
void IdentifyStructure(string symbol);
|
|
void FindSRLevels(string symbol);
|
|
bool IsSwingHigh(double &highs[], int index, int lookback);
|
|
bool IsSwingLow(double &lows[], int index, int lookback);
|
|
double CalculateLevelStrength(SRLevel &level, string symbol);
|
|
|
|
public:
|
|
CTechnicalAnalysisV71();
|
|
~CTechnicalAnalysisV71();
|
|
|
|
//--- Initialization
|
|
bool Initialize();
|
|
bool InitializeEnhanced(int correlation_period);
|
|
void Deinitialize();
|
|
|
|
//--- Market analysis
|
|
MarketConditionsV71 AnalyzeMarket(string symbol);
|
|
void UpdateMarketStructure(string symbol);
|
|
ENUM_MARKET_REGIME IdentifyRegime(string symbol);
|
|
|
|
//--- Technical indicators
|
|
double GetATR(int period, int shift = 0);
|
|
double GetRSI(int shift = 0);
|
|
double GetMACD(int buffer, int shift = 0);
|
|
double GetBB(int buffer, int shift = 0);
|
|
double GetMA(int index, int shift = 0);
|
|
double GetADX(int shift = 0);
|
|
double GetSymbolATR(string symbol, int period);
|
|
|
|
//--- Support/Resistance
|
|
void FindSupportResistance(string symbol, SRLevel &levels[], int &count);
|
|
double GetNearestSupport(string symbol, double price);
|
|
double GetNearestResistance(string symbol, double price);
|
|
bool IsPriceAtLevel(double price, double level, double tolerance);
|
|
|
|
//--- Fibonacci analysis
|
|
void CalculateFibonacci(double high, double low, FibLevel &levels[]);
|
|
double GetNearestFibLevel(double price, FibLevel &levels[]);
|
|
|
|
//--- Market structure
|
|
int GetTrendDirection() { return m_structure.trend_direction; }
|
|
double GetTrendStrength() { return m_structure.trend_strength; }
|
|
bool IsStructureBroken() { return m_structure.structure_breaks > 0; }
|
|
bool IsRanging() { return m_structure.is_ranging; }
|
|
|
|
//--- Correlation analysis
|
|
CorrelationMatrix CalculateCorrelationMatrix(string symbols[], int period);
|
|
double GetCorrelation(string symbol1, string symbol2, int period = 100);
|
|
void UpdateCorrelations(string symbols[]);
|
|
|
|
//--- Multi-timeframe
|
|
void AnalyzeMTF(string symbol, ENUM_TIMEFRAMES timeframes[], int count);
|
|
double GetMTFScore(string symbol);
|
|
bool IsMTFAligned(string symbol);
|
|
|
|
//--- Pattern recognition
|
|
bool DetectChartPatterns(string symbol);
|
|
bool IsDoubleTop() { return m_pattern_double_top; }
|
|
bool IsDoubleBottom() { return m_pattern_double_bottom; }
|
|
bool IsHeadShoulders() { return m_pattern_head_shoulders; }
|
|
|
|
//--- Volatility analysis
|
|
double GetHistoricalVolatility(string symbol, int period);
|
|
double GetImpliedVolatility(string symbol); // Placeholder
|
|
double GetVolatilityRank(string symbol, int lookback);
|
|
|
|
//--- Advanced metrics
|
|
double GetHurstExponent(string symbol, int period);
|
|
double GetMarketEfficiency(string symbol, int period);
|
|
double GetFractalDimension(string symbol, int period);
|
|
|
|
//--- Pivot points
|
|
void GetPivotPoints(string symbol, double &pp, double &r1, double &r2,
|
|
double &r3, double &s1, double &s2, double &s3);
|
|
void GetCamarillaPivots(string symbol, double &levels[]);
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Constructor |
|
|
//+------------------------------------------------------------------+
|
|
CTechnicalAnalysisV71::CTechnicalAnalysisV71()
|
|
{
|
|
m_atr_handle = INVALID_HANDLE;
|
|
m_rsi_handle = INVALID_HANDLE;
|
|
m_macd_handle = INVALID_HANDLE;
|
|
m_bb_handle = INVALID_HANDLE;
|
|
m_adx_handle = INVALID_HANDLE;
|
|
m_cci_handle = INVALID_HANDLE;
|
|
m_stoch_handle = INVALID_HANDLE;
|
|
m_ichimoku_handle = INVALID_HANDLE;
|
|
m_sr_count = 0;
|
|
m_last_correlation_update = 0;
|
|
|
|
//--- Initialize patterns
|
|
m_pattern_double_top = false;
|
|
m_pattern_double_bottom = false;
|
|
m_pattern_head_shoulders = false;
|
|
m_pattern_triangle = false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Destructor |
|
|
//+------------------------------------------------------------------+
|
|
CTechnicalAnalysisV71::~CTechnicalAnalysisV71()
|
|
{
|
|
Deinitialize();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Initialize enhanced version |
|
|
//+------------------------------------------------------------------+
|
|
bool CTechnicalAnalysisV71::InitializeEnhanced(int correlation_period)
|
|
{
|
|
//--- Standard initialization
|
|
if(!Initialize())
|
|
return false;
|
|
|
|
//--- Additional indicators
|
|
m_cci_handle = iCCI(_Symbol, PERIOD_CURRENT, 14, PRICE_TYPICAL);
|
|
m_stoch_handle = iStochastic(_Symbol, PERIOD_CURRENT, 14, 3, 3, MODE_SMA, STO_LOWHIGH);
|
|
m_ichimoku_handle = iIchimoku(_Symbol, PERIOD_CURRENT, 9, 26, 52);
|
|
|
|
//--- Multiple MAs for analysis
|
|
ArrayResize(m_ma_handles, 5);
|
|
m_ma_handles[0] = iMA(_Symbol, PERIOD_CURRENT, 10, 0, MODE_EMA, PRICE_CLOSE);
|
|
m_ma_handles[1] = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_EMA, PRICE_CLOSE);
|
|
m_ma_handles[2] = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_EMA, PRICE_CLOSE);
|
|
m_ma_handles[3] = iMA(_Symbol, PERIOD_CURRENT, 100, 0, MODE_EMA, PRICE_CLOSE);
|
|
m_ma_handles[4] = iMA(_Symbol, PERIOD_CURRENT, 200, 0, MODE_EMA, PRICE_CLOSE);
|
|
|
|
//--- Initialize MTF array
|
|
ArrayResize(m_mtf_data, 4);
|
|
m_mtf_data[0].timeframe = PERIOD_M5;
|
|
m_mtf_data[1].timeframe = PERIOD_M15;
|
|
m_mtf_data[2].timeframe = PERIOD_H1;
|
|
m_mtf_data[3].timeframe = PERIOD_H4;
|
|
|
|
//--- Initialize correlation matrix
|
|
m_correlation_matrix.period = correlation_period;
|
|
m_correlation_matrix.last_update = 0;
|
|
|
|
Print("TechnicalAnalysisV71 initialized with enhanced features");
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Standard initialization |
|
|
//+------------------------------------------------------------------+
|
|
bool CTechnicalAnalysisV71::Initialize()
|
|
{
|
|
//--- Initialize basic indicators
|
|
m_atr_handle = iATR(_Symbol, PERIOD_CURRENT, 14);
|
|
m_rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
|
|
m_macd_handle = iMACD(_Symbol, PERIOD_CURRENT, 12, 26, 9, PRICE_CLOSE);
|
|
m_bb_handle = iBands(_Symbol, PERIOD_CURRENT, 20, 0, 2.0, PRICE_CLOSE);
|
|
m_adx_handle = iADX(_Symbol, PERIOD_CURRENT, 14);
|
|
|
|
if(m_atr_handle == INVALID_HANDLE || m_rsi_handle == INVALID_HANDLE ||
|
|
m_macd_handle == INVALID_HANDLE || m_bb_handle == INVALID_HANDLE ||
|
|
m_adx_handle == INVALID_HANDLE)
|
|
{
|
|
Print("Failed to initialize technical indicators");
|
|
return false;
|
|
}
|
|
|
|
//--- Initialize structure
|
|
m_structure.trend_direction = 0;
|
|
m_structure.trend_strength = 0;
|
|
m_structure.structure_breaks = 0;
|
|
m_structure.is_ranging = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Analyze market conditions |
|
|
//+------------------------------------------------------------------+
|
|
MarketConditionsV71 CTechnicalAnalysisV71::AnalyzeMarket(string symbol)
|
|
{
|
|
MarketConditionsV71 conditions;
|
|
|
|
//--- Update market structure
|
|
UpdateMarketStructure(symbol);
|
|
|
|
//--- Identify regime
|
|
conditions.regime = IdentifyRegime(symbol);
|
|
|
|
//--- Get trend metrics
|
|
conditions.trend_strength = m_structure.trend_strength;
|
|
conditions.is_trending = (MathAbs(m_structure.trend_direction) > 0.7);
|
|
|
|
//--- Get volatility
|
|
double atr_buffer[1];
|
|
if(CopyBuffer(m_atr_handle, 0, 0, 1, atr_buffer) > 0)
|
|
{
|
|
conditions.volatility = atr_buffer[0] / SymbolInfoDouble(symbol, SYMBOL_BID) * 100;
|
|
}
|
|
|
|
//--- Check if volatile
|
|
double vol_rank = GetVolatilityRank(symbol, 100);
|
|
conditions.is_volatile = (vol_rank > 70);
|
|
|
|
//--- Get momentum
|
|
double rsi_buffer[1];
|
|
if(CopyBuffer(m_rsi_handle, 0, 0, 1, rsi_buffer) > 0)
|
|
{
|
|
conditions.momentum = (rsi_buffer[0] - 50) / 50; // Normalized -1 to 1
|
|
}
|
|
|
|
//--- Find S/R levels
|
|
FindSRLevels(symbol);
|
|
|
|
//--- Get nearest levels
|
|
double current_price = SymbolInfoDouble(symbol, SYMBOL_BID);
|
|
conditions.support_level = GetNearestSupport(symbol, current_price);
|
|
conditions.resistance_level = GetNearestResistance(symbol, current_price);
|
|
|
|
//--- Count trend bars
|
|
conditions.trend_bars = 0;
|
|
double ma_buffer[1];
|
|
if(m_ma_handles[1] != INVALID_HANDLE && CopyBuffer(m_ma_handles[1], 0, 0, 1, ma_buffer) > 0)
|
|
{
|
|
for(int i = 0; i < 20; i++)
|
|
{
|
|
double close = iClose(symbol, PERIOD_CURRENT, i);
|
|
if((m_structure.trend_direction > 0 && close > ma_buffer[0]) ||
|
|
(m_structure.trend_direction < 0 && close < ma_buffer[0]))
|
|
{
|
|
conditions.trend_bars++;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
//--- Calculate average range
|
|
double total_range = 0;
|
|
for(int i = 0; i < 20; i++)
|
|
{
|
|
double high = iHigh(symbol, PERIOD_CURRENT, i);
|
|
double low = iLow(symbol, PERIOD_CURRENT, i);
|
|
total_range += (high - low);
|
|
}
|
|
conditions.avg_range = total_range / 20;
|
|
|
|
//--- Market microstructure
|
|
conditions.bid_ask_spread = SymbolInfoInteger(symbol, SYMBOL_SPREAD);
|
|
conditions.vwap = 0; // Placeholder
|
|
conditions.liquidity_depth = 1.0; // Placeholder
|
|
|
|
conditions.last_update = TimeCurrent();
|
|
|
|
return conditions;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Update market structure |
|
|
//+------------------------------------------------------------------+
|
|
void CTechnicalAnalysisV71::UpdateMarketStructure(string symbol)
|
|
{
|
|
//--- Detect swing points
|
|
DetectSwings(symbol, 10);
|
|
|
|
//--- Identify structure
|
|
IdentifyStructure(symbol);
|
|
|
|
//--- Detect patterns
|
|
DetectChartPatterns(symbol);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Detect swing highs and lows |
|
|
//+------------------------------------------------------------------+
|
|
void CTechnicalAnalysisV71::DetectSwings(string symbol, int lookback)
|
|
{
|
|
//--- Arrays for price data
|
|
double highs[], lows[];
|
|
int bars = 100;
|
|
|
|
ArraySetAsSeries(highs, true);
|
|
ArraySetAsSeries(lows, true);
|
|
|
|
if(CopyHigh(symbol, PERIOD_CURRENT, 0, bars, highs) <= 0 ||
|
|
CopyLow(symbol, PERIOD_CURRENT, 0, bars, lows) <= 0)
|
|
return;
|
|
|
|
//--- Clear previous swings
|
|
ArrayResize(m_structure.swing_highs, 0);
|
|
ArrayResize(m_structure.swing_lows, 0);
|
|
|
|
//--- Find swing points
|
|
for(int i = lookback; i < bars - lookback; i++)
|
|
{
|
|
if(IsSwingHigh(highs, i, lookback))
|
|
{
|
|
int size = ArraySize(m_structure.swing_highs);
|
|
ArrayResize(m_structure.swing_highs, size + 1);
|
|
m_structure.swing_highs[size] = highs[i];
|
|
}
|
|
|
|
if(IsSwingLow(lows, i, lookback))
|
|
{
|
|
int size = ArraySize(m_structure.swing_lows);
|
|
ArrayResize(m_structure.swing_lows, size + 1);
|
|
m_structure.swing_lows[size] = lows[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check if point is swing high |
|
|
//+------------------------------------------------------------------+
|
|
bool CTechnicalAnalysisV71::IsSwingHigh(double &highs[], int index, int lookback)
|
|
{
|
|
double high = highs[index];
|
|
|
|
//--- Check left side
|
|
for(int i = index - lookback; i < index; i++)
|
|
{
|
|
if(i >= 0 && highs[i] >= high)
|
|
return false;
|
|
}
|
|
|
|
//--- Check right side
|
|
for(int i = index + 1; i <= index + lookback; i++)
|
|
{
|
|
if(i < ArraySize(highs) && highs[i] > high)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check if point is swing low |
|
|
//+------------------------------------------------------------------+
|
|
bool CTechnicalAnalysisV71::IsSwingLow(double &lows[], int index, int lookback)
|
|
{
|
|
double low = lows[index];
|
|
|
|
//--- Check left side
|
|
for(int i = index - lookback; i < index; i++)
|
|
{
|
|
if(i >= 0 && lows[i] <= low)
|
|
return false;
|
|
}
|
|
|
|
//--- Check right side
|
|
for(int i = index + 1; i <= index + lookback; i++)
|
|
{
|
|
if(i < ArraySize(lows) && lows[i] < low)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Identify market structure |
|
|
//+------------------------------------------------------------------+
|
|
void CTechnicalAnalysisV71::IdentifyStructure(string symbol)
|
|
{
|
|
int high_count = ArraySize(m_structure.swing_highs);
|
|
int low_count = ArraySize(m_structure.swing_lows);
|
|
|
|
if(high_count < 2 || low_count < 2)
|
|
return;
|
|
|
|
//--- Check for higher highs and higher lows (uptrend)
|
|
bool higher_highs = true;
|
|
bool higher_lows = true;
|
|
|
|
for(int i = 1; i < MathMin(3, high_count); i++)
|
|
{
|
|
if(m_structure.swing_highs[i] >= m_structure.swing_highs[i-1])
|
|
higher_highs = false;
|
|
}
|
|
|
|
for(int i = 1; i < MathMin(3, low_count); i++)
|
|
{
|
|
if(m_structure.swing_lows[i] >= m_structure.swing_lows[i-1])
|
|
higher_lows = false;
|
|
}
|
|
|
|
//--- Check for lower highs and lower lows (downtrend)
|
|
bool lower_highs = true;
|
|
bool lower_lows = true;
|
|
|
|
for(int i = 1; i < MathMin(3, high_count); i++)
|
|
{
|
|
if(m_structure.swing_highs[i] <= m_structure.swing_highs[i-1])
|
|
lower_highs = false;
|
|
}
|
|
|
|
for(int i = 1; i < MathMin(3, low_count); i++)
|
|
{
|
|
if(m_structure.swing_lows[i] <= m_structure.swing_lows[i-1])
|
|
lower_lows = false;
|
|
}
|
|
|
|
//--- Determine trend
|
|
if(higher_highs && higher_lows)
|
|
{
|
|
m_structure.trend_direction = 1;
|
|
m_structure.trend_strength = 0.8;
|
|
}
|
|
else if(lower_highs && lower_lows)
|
|
{
|
|
m_structure.trend_direction = -1;
|
|
m_structure.trend_strength = 0.8;
|
|
}
|
|
else
|
|
{
|
|
m_structure.trend_direction = 0;
|
|
m_structure.trend_strength = 0.2;
|
|
}
|
|
|
|
//--- Check for ranging market
|
|
double highest = m_structure.swing_highs[0];
|
|
double lowest = m_structure.swing_lows[0];
|
|
|
|
for(int i = 1; i < MathMin(5, high_count); i++)
|
|
{
|
|
if(m_structure.swing_highs[i] > highest)
|
|
highest = m_structure.swing_highs[i];
|
|
}
|
|
|
|
for(int i = 1; i < MathMin(5, low_count); i++)
|
|
{
|
|
if(m_structure.swing_lows[i] < lowest)
|
|
lowest = m_structure.swing_lows[i];
|
|
}
|
|
|
|
double range = highest - lowest;
|
|
double avg_price = (highest + lowest) / 2;
|
|
double range_pct = range / avg_price * 100;
|
|
|
|
//--- Ranging if range is small and no clear trend
|
|
if(range_pct < 2 && m_structure.trend_direction == 0)
|
|
{
|
|
m_structure.is_ranging = true;
|
|
m_structure.range_high = highest;
|
|
m_structure.range_low = lowest;
|
|
}
|
|
else
|
|
{
|
|
m_structure.is_ranging = false;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Find support and resistance levels |
|
|
//+------------------------------------------------------------------+
|
|
void CTechnicalAnalysisV71::FindSRLevels(string symbol)
|
|
{
|
|
//--- Clear previous levels
|
|
ArrayResize(m_sr_levels, 0);
|
|
m_sr_count = 0;
|
|
|
|
//--- Get price data
|
|
double highs[], lows[], closes[];
|
|
int bars = 200;
|
|
|
|
ArraySetAsSeries(highs, true);
|
|
ArraySetAsSeries(lows, true);
|
|
ArraySetAsSeries(closes, true);
|
|
|
|
if(CopyHigh(symbol, PERIOD_CURRENT, 0, bars, highs) <= 0 ||
|
|
CopyLow(symbol, PERIOD_CURRENT, 0, bars, lows) <= 0 ||
|
|
CopyClose(symbol, PERIOD_CURRENT, 0, bars, closes) <= 0)
|
|
return;
|
|
|
|
//--- Find levels from swing points
|
|
for(int i = 0; i < ArraySize(m_structure.swing_highs); i++)
|
|
{
|
|
SRLevel level;
|
|
level.price = m_structure.swing_highs[i];
|
|
level.touches = 1;
|
|
level.is_support = false;
|
|
level.is_broken = false;
|
|
level.first_touch = TimeCurrent() - i * PeriodSeconds();
|
|
level.last_touch = level.first_touch;
|
|
|
|
//--- Count touches
|
|
for(int j = 0; j < bars; j++)
|
|
{
|
|
if(IsPriceAtLevel(highs[j], level.price, 10 * SymbolInfoDouble(symbol, SYMBOL_POINT)) ||
|
|
IsPriceAtLevel(lows[j], level.price, 10 * SymbolInfoDouble(symbol, SYMBOL_POINT)))
|
|
{
|
|
level.touches++;
|
|
}
|
|
}
|
|
|
|
level.strength = CalculateLevelStrength(level, symbol);
|
|
|
|
if(level.touches >= 2 && m_sr_count < 20)
|
|
{
|
|
ArrayResize(m_sr_levels, m_sr_count + 1);
|
|
m_sr_levels[m_sr_count] = level;
|
|
m_sr_count++;
|
|
}
|
|
}
|
|
|
|
//--- Add levels from swing lows
|
|
for(int i = 0; i < ArraySize(m_structure.swing_lows); i++)
|
|
{
|
|
SRLevel level;
|
|
level.price = m_structure.swing_lows[i];
|
|
level.touches = 1;
|
|
level.is_support = true;
|
|
level.is_broken = false;
|
|
level.first_touch = TimeCurrent() - i * PeriodSeconds();
|
|
level.last_touch = level.first_touch;
|
|
|
|
//--- Count touches
|
|
for(int j = 0; j < bars; j++)
|
|
{
|
|
if(IsPriceAtLevel(highs[j], level.price, 10 * SymbolInfoDouble(symbol, SYMBOL_POINT)) ||
|
|
IsPriceAtLevel(lows[j], level.price, 10 * SymbolInfoDouble(symbol, SYMBOL_POINT)))
|
|
{
|
|
level.touches++;
|
|
}
|
|
}
|
|
|
|
level.strength = CalculateLevelStrength(level, symbol);
|
|
|
|
if(level.touches >= 2 && m_sr_count < 20)
|
|
{
|
|
ArrayResize(m_sr_levels, m_sr_count + 1);
|
|
m_sr_levels[m_sr_count] = level;
|
|
m_sr_count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Calculate level strength |
|
|
//+------------------------------------------------------------------+
|
|
double CTechnicalAnalysisV71::CalculateLevelStrength(SRLevel &level, string symbol)
|
|
{
|
|
double strength = 0;
|
|
|
|
//--- More touches = stronger level
|
|
strength += level.touches * 0.2;
|
|
|
|
//--- Recent touches are more important
|
|
double time_factor = 1.0 - (TimeCurrent() - level.last_touch) / (86400 * 30); // 30 days
|
|
strength += time_factor * 0.3;
|
|
|
|
//--- Volume at level (simplified)
|
|
strength += 0.2;
|
|
|
|
//--- Round number bonus
|
|
double round_distance = MathMod(level.price, 100 * SymbolInfoDouble(symbol, SYMBOL_POINT));
|
|
if(round_distance < 10 * SymbolInfoDouble(symbol, SYMBOL_POINT))
|
|
strength += 0.3;
|
|
|
|
return MathMin(1.0, strength);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check if price is at level |
|
|
//+------------------------------------------------------------------+
|
|
bool CTechnicalAnalysisV71::IsPriceAtLevel(double price, double level, double tolerance)
|
|
{
|
|
return MathAbs(price - level) <= tolerance;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get nearest support level |
|
|
//+------------------------------------------------------------------+
|
|
double CTechnicalAnalysisV71::GetNearestSupport(string symbol, double price)
|
|
{
|
|
double nearest = 0;
|
|
double min_distance = DBL_MAX;
|
|
|
|
for(int i = 0; i < m_sr_count; i++)
|
|
{
|
|
if(m_sr_levels[i].price < price && m_sr_levels[i].is_support)
|
|
{
|
|
double distance = price - m_sr_levels[i].price;
|
|
if(distance < min_distance)
|
|
{
|
|
min_distance = distance;
|
|
nearest = m_sr_levels[i].price;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nearest;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get nearest resistance level |
|
|
//+------------------------------------------------------------------+
|
|
double CTechnicalAnalysisV71::GetNearestResistance(string symbol, double price)
|
|
{
|
|
double nearest = 0;
|
|
double min_distance = DBL_MAX;
|
|
|
|
for(int i = 0; i < m_sr_count; i++)
|
|
{
|
|
if(m_sr_levels[i].price > price && !m_sr_levels[i].is_support)
|
|
{
|
|
double distance = m_sr_levels[i].price - price;
|
|
if(distance < min_distance)
|
|
{
|
|
min_distance = distance;
|
|
nearest = m_sr_levels[i].price;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nearest;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Identify market regime |
|
|
//+------------------------------------------------------------------+
|
|
ENUM_MARKET_REGIME CTechnicalAnalysisV71::IdentifyRegime(string symbol)
|
|
{
|
|
//--- Get ADX for trend strength
|
|
double adx_buffer[1];
|
|
double adx_value = 0;
|
|
|
|
if(CopyBuffer(m_adx_handle, 0, 0, 1, adx_buffer) > 0)
|
|
adx_value = adx_buffer[0];
|
|
|
|
//--- Get volatility
|
|
double volatility = GetHistoricalVolatility(symbol, 20);
|
|
|
|
//--- Strong trend
|
|
if(adx_value > 40)
|
|
{
|
|
if(m_structure.trend_direction > 0)
|
|
return REGIME_TRENDING_UP;
|
|
else if(m_structure.trend_direction < 0)
|
|
return REGIME_TRENDING_DOWN;
|
|
}
|
|
|
|
//--- Ranging market
|
|
if(m_structure.is_ranging || adx_value < 20)
|
|
{
|
|
if(volatility > 0.02)
|
|
return REGIME_VOLATILE;
|
|
else
|
|
return REGIME_RANGING;
|
|
}
|
|
|
|
//--- Moderate trend
|
|
if(adx_value > 20 && adx_value <= 40)
|
|
{
|
|
if(m_structure.trend_direction > 0)
|
|
return REGIME_TRENDING_UP;
|
|
else if(m_structure.trend_direction < 0)
|
|
return REGIME_TRENDING_DOWN;
|
|
}
|
|
|
|
//--- Low volatility
|
|
if(volatility < 0.005)
|
|
return REGIME_QUIET;
|
|
|
|
//--- Check for regime change
|
|
static ENUM_MARKET_REGIME last_regime = REGIME_RANGING;
|
|
ENUM_MARKET_REGIME current_regime = REGIME_RANGING;
|
|
|
|
if(last_regime != current_regime)
|
|
{
|
|
last_regime = current_regime;
|
|
return REGIME_TRANSITIONING;
|
|
}
|
|
|
|
return current_regime;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Calculate correlation matrix |
|
|
//+------------------------------------------------------------------+
|
|
CorrelationMatrix CTechnicalAnalysisV71::CalculateCorrelationMatrix(string symbols[], int period)
|
|
{
|
|
CorrelationMatrix matrix;
|
|
int symbol_count = ArraySize(symbols);
|
|
|
|
//--- Initialize matrix
|
|
ArrayResize(matrix.symbols, symbol_count);
|
|
ArrayResize(matrix.matrix, symbol_count);
|
|
|
|
for(int i = 0; i < symbol_count; i++)
|
|
{
|
|
matrix.symbols[i] = symbols[i];
|
|
ArrayResize(matrix.matrix[i], symbol_count);
|
|
}
|
|
|
|
matrix.period = period;
|
|
matrix.last_update = TimeCurrent();
|
|
|
|
//--- Calculate correlations
|
|
for(int i = 0; i < symbol_count; i++)
|
|
{
|
|
for(int j = i; j < symbol_count; j++)
|
|
{
|
|
if(i == j)
|
|
{
|
|
matrix.matrix[i][j] = 1.0;
|
|
}
|
|
else
|
|
{
|
|
double corr = GetCorrelation(symbols[i], symbols[j], period);
|
|
matrix.matrix[i][j] = corr;
|
|
matrix.matrix[j][i] = corr; // Symmetric
|
|
}
|
|
}
|
|
}
|
|
|
|
m_correlation_matrix = matrix;
|
|
m_last_correlation_update = TimeCurrent();
|
|
|
|
return matrix;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Calculate correlation between two symbols |
|
|
//+------------------------------------------------------------------+
|
|
double CTechnicalAnalysisV71::GetCorrelation(string symbol1, string symbol2, int period)
|
|
{
|
|
//--- Get returns for both symbols
|
|
double returns1[], returns2[];
|
|
ArrayResize(returns1, period);
|
|
ArrayResize(returns2, period);
|
|
|
|
for(int i = 1; i <= period; i++)
|
|
{
|
|
double close1_curr = iClose(symbol1, PERIOD_H1, i-1);
|
|
double close1_prev = iClose(symbol1, PERIOD_H1, i);
|
|
double close2_curr = iClose(symbol2, PERIOD_H1, i-1);
|
|
double close2_prev = iClose(symbol2, PERIOD_H1, i);
|
|
|
|
if(close1_prev > 0 && close2_prev > 0)
|
|
{
|
|
returns1[i-1] = (close1_curr - close1_prev) / close1_prev;
|
|
returns2[i-1] = (close2_curr - close2_prev) / close2_prev;
|
|
}
|
|
}
|
|
|
|
//--- Calculate correlation coefficient
|
|
double mean1 = 0, mean2 = 0;
|
|
for(int i = 0; i < period; i++)
|
|
{
|
|
mean1 += returns1[i];
|
|
mean2 += returns2[i];
|
|
}
|
|
mean1 /= period;
|
|
mean2 /= period;
|
|
|
|
double cov = 0, var1 = 0, var2 = 0;
|
|
for(int i = 0; i < period; i++)
|
|
{
|
|
cov += (returns1[i] - mean1) * (returns2[i] - mean2);
|
|
var1 += MathPow(returns1[i] - mean1, 2);
|
|
var2 += MathPow(returns2[i] - mean2, 2);
|
|
}
|
|
|
|
if(var1 > 0 && var2 > 0)
|
|
return cov / MathSqrt(var1 * var2);
|
|
|
|
return 0;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Detect chart patterns |
|
|
//+------------------------------------------------------------------+
|
|
bool CTechnicalAnalysisV71::DetectChartPatterns(string symbol)
|
|
{
|
|
//--- Reset patterns
|
|
m_pattern_double_top = false;
|
|
m_pattern_double_bottom = false;
|
|
m_pattern_head_shoulders = false;
|
|
m_pattern_triangle = false;
|
|
|
|
int high_count = ArraySize(m_structure.swing_highs);
|
|
int low_count = ArraySize(m_structure.swing_lows);
|
|
|
|
if(high_count < 2 || low_count < 2)
|
|
return false;
|
|
|
|
//--- Double top detection
|
|
if(high_count >= 2)
|
|
{
|
|
double high1 = m_structure.swing_highs[0];
|
|
double high2 = m_structure.swing_highs[1];
|
|
double tolerance = high1 * 0.002; // 0.2% tolerance
|
|
|
|
if(MathAbs(high1 - high2) < tolerance)
|
|
{
|
|
m_pattern_double_top = true;
|
|
}
|
|
}
|
|
|
|
//--- Double bottom detection
|
|
if(low_count >= 2)
|
|
{
|
|
double low1 = m_structure.swing_lows[0];
|
|
double low2 = m_structure.swing_lows[1];
|
|
double tolerance = low1 * 0.002;
|
|
|
|
if(MathAbs(low1 - low2) < tolerance)
|
|
{
|
|
m_pattern_double_bottom = true;
|
|
}
|
|
}
|
|
|
|
//--- Head and shoulders (simplified)
|
|
if(high_count >= 3)
|
|
{
|
|
double left_shoulder = m_structure.swing_highs[2];
|
|
double head = m_structure.swing_highs[1];
|
|
double right_shoulder = m_structure.swing_highs[0];
|
|
|
|
if(head > left_shoulder && head > right_shoulder &&
|
|
MathAbs(left_shoulder - right_shoulder) < left_shoulder * 0.002)
|
|
{
|
|
m_pattern_head_shoulders = true;
|
|
}
|
|
}
|
|
|
|
return (m_pattern_double_top || m_pattern_double_bottom || m_pattern_head_shoulders);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get historical volatility |
|
|
//+------------------------------------------------------------------+
|
|
double CTechnicalAnalysisV71::GetHistoricalVolatility(string symbol, int period)
|
|
{
|
|
double returns[];
|
|
ArrayResize(returns, period);
|
|
|
|
//--- Calculate returns
|
|
for(int i = 1; i <= period; i++)
|
|
{
|
|
double close_curr = iClose(symbol, PERIOD_H1, i-1);
|
|
double close_prev = iClose(symbol, PERIOD_H1, i);
|
|
|
|
if(close_prev > 0)
|
|
returns[i-1] = MathLog(close_curr / close_prev);
|
|
}
|
|
|
|
//--- Calculate standard deviation
|
|
double mean = 0;
|
|
for(int i = 0; i < period; i++)
|
|
mean += returns[i];
|
|
mean /= period;
|
|
|
|
double variance = 0;
|
|
for(int i = 0; i < period; i++)
|
|
variance += MathPow(returns[i] - mean, 2);
|
|
variance /= period;
|
|
|
|
//--- Annualize (assuming hourly data)
|
|
return MathSqrt(variance) * MathSqrt(24 * 252);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get volatility rank |
|
|
//+------------------------------------------------------------------+
|
|
double CTechnicalAnalysisV71::GetVolatilityRank(string symbol, int lookback)
|
|
{
|
|
//--- Calculate current volatility
|
|
double current_vol = GetHistoricalVolatility(symbol, 20);
|
|
|
|
//--- Calculate volatility over lookback period
|
|
double vol_array[];
|
|
ArrayResize(vol_array, lookback);
|
|
|
|
for(int i = 0; i < lookback; i++)
|
|
{
|
|
//--- Simplified: use ATR as proxy
|
|
double atr = iATR(symbol, PERIOD_H1, 14, i);
|
|
double price = iClose(symbol, PERIOD_H1, i);
|
|
if(price > 0)
|
|
vol_array[i] = atr / price;
|
|
}
|
|
|
|
//--- Count how many periods had lower volatility
|
|
int lower_count = 0;
|
|
for(int i = 0; i < lookback; i++)
|
|
{
|
|
if(vol_array[i] < current_vol)
|
|
lower_count++;
|
|
}
|
|
|
|
//--- Return percentile rank
|
|
return (double)lower_count / lookback * 100;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Calculate Fibonacci levels |
|
|
//+------------------------------------------------------------------+
|
|
void CTechnicalAnalysisV71::CalculateFibonacci(double high, double low, FibLevel &levels[])
|
|
{
|
|
double range = high - low;
|
|
|
|
//--- Standard Fibonacci levels
|
|
ArrayResize(levels, 9);
|
|
|
|
levels[0].level = 0.0;
|
|
levels[0].price = low;
|
|
levels[0].description = "0.0%";
|
|
|
|
levels[1].level = 0.236;
|
|
levels[1].price = low + range * 0.236;
|
|
levels[1].description = "23.6%";
|
|
|
|
levels[2].level = 0.382;
|
|
levels[2].price = low + range * 0.382;
|
|
levels[2].description = "38.2%";
|
|
|
|
levels[3].level = 0.5;
|
|
levels[3].price = low + range * 0.5;
|
|
levels[3].description = "50.0%";
|
|
|
|
levels[4].level = 0.618;
|
|
levels[4].price = low + range * 0.618;
|
|
levels[4].description = "61.8%";
|
|
|
|
levels[5].level = 0.786;
|
|
levels[5].price = low + range * 0.786;
|
|
levels[5].description = "78.6%";
|
|
|
|
levels[6].level = 1.0;
|
|
levels[6].price = high;
|
|
levels[6].description = "100.0%";
|
|
|
|
levels[7].level = 1.272;
|
|
levels[7].price = low + range * 1.272;
|
|
levels[7].description = "127.2%";
|
|
|
|
levels[8].level = 1.618;
|
|
levels[8].price = low + range * 1.618;
|
|
levels[8].description = "161.8%";
|
|
|
|
//--- Initialize other fields
|
|
for(int i = 0; i < 9; i++)
|
|
{
|
|
levels[i].is_touched = false;
|
|
levels[i].bounce_count = 0;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get multi-timeframe score |
|
|
//+------------------------------------------------------------------+
|
|
double CTechnicalAnalysisV71::GetMTFScore(string symbol)
|
|
{
|
|
double score = 0;
|
|
int aligned = 0;
|
|
|
|
//--- Check each timeframe
|
|
for(int i = 0; i < ArraySize(m_mtf_data); i++)
|
|
{
|
|
//--- Get trend for timeframe
|
|
int ma_handle = iMA(symbol, m_mtf_data[i].timeframe, 20, 0, MODE_EMA, PRICE_CLOSE);
|
|
double ma_buffer[2];
|
|
|
|
if(CopyBuffer(ma_handle, 0, 0, 2, ma_buffer) > 0)
|
|
{
|
|
double current_price = iClose(symbol, m_mtf_data[i].timeframe, 0);
|
|
|
|
//--- Determine trend
|
|
if(current_price > ma_buffer[0] && ma_buffer[0] > ma_buffer[1])
|
|
{
|
|
m_mtf_data[i].trend_direction = 1;
|
|
aligned++;
|
|
}
|
|
else if(current_price < ma_buffer[0] && ma_buffer[0] < ma_buffer[1])
|
|
{
|
|
m_mtf_data[i].trend_direction = -1;
|
|
aligned++;
|
|
}
|
|
else
|
|
{
|
|
m_mtf_data[i].trend_direction = 0;
|
|
}
|
|
}
|
|
|
|
IndicatorRelease(ma_handle);
|
|
}
|
|
|
|
//--- Calculate alignment score
|
|
score = (double)aligned / ArraySize(m_mtf_data);
|
|
|
|
//--- Check if all aligned in same direction
|
|
bool same_direction = true;
|
|
double first_direction = m_mtf_data[0].trend_direction;
|
|
|
|
for(int i = 1; i < ArraySize(m_mtf_data); i++)
|
|
{
|
|
if(m_mtf_data[i].trend_direction != first_direction)
|
|
{
|
|
same_direction = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(same_direction && aligned == ArraySize(m_mtf_data))
|
|
score = 1.0;
|
|
|
|
return score;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get pivot points |
|
|
//+------------------------------------------------------------------+
|
|
void CTechnicalAnalysisV71::GetPivotPoints(string symbol, double &pp, double &r1, double &r2,
|
|
double &r3, double &s1, double &s2, double &s3)
|
|
{
|
|
//--- Get previous day's data
|
|
double high = iHigh(symbol, PERIOD_D1, 1);
|
|
double low = iLow(symbol, PERIOD_D1, 1);
|
|
double close = iClose(symbol, PERIOD_D1, 1);
|
|
|
|
//--- Calculate pivot point
|
|
pp = (high + low + close) / 3;
|
|
|
|
//--- Calculate support and resistance levels
|
|
r1 = 2 * pp - low;
|
|
s1 = 2 * pp - high;
|
|
|
|
r2 = pp + (high - low);
|
|
s2 = pp - (high - low);
|
|
|
|
r3 = high + 2 * (pp - low);
|
|
s3 = low - 2 * (high - pp);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get ATR value |
|
|
//+------------------------------------------------------------------+
|
|
double CTechnicalAnalysisV71::GetATR(int period, int shift)
|
|
{
|
|
double buffer[1];
|
|
if(CopyBuffer(m_atr_handle, 0, shift, 1, buffer) > 0)
|
|
return buffer[0];
|
|
return 0;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get symbol-specific ATR |
|
|
//+------------------------------------------------------------------+
|
|
double CTechnicalAnalysisV71::GetSymbolATR(string symbol, int period)
|
|
{
|
|
int handle = iATR(symbol, PERIOD_CURRENT, period);
|
|
if(handle == INVALID_HANDLE)
|
|
return 0;
|
|
|
|
double buffer[1];
|
|
if(CopyBuffer(handle, 0, 0, 1, buffer) > 0)
|
|
{
|
|
IndicatorRelease(handle);
|
|
return buffer[0];
|
|
}
|
|
|
|
IndicatorRelease(handle);
|
|
return 0;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Deinitialize indicators |
|
|
//+------------------------------------------------------------------+
|
|
void CTechnicalAnalysisV71::Deinitialize()
|
|
{
|
|
if(m_atr_handle != INVALID_HANDLE) IndicatorRelease(m_atr_handle);
|
|
if(m_rsi_handle != INVALID_HANDLE) IndicatorRelease(m_rsi_handle);
|
|
if(m_macd_handle != INVALID_HANDLE) IndicatorRelease(m_macd_handle);
|
|
if(m_bb_handle != INVALID_HANDLE) IndicatorRelease(m_bb_handle);
|
|
if(m_adx_handle != INVALID_HANDLE) IndicatorRelease(m_adx_handle);
|
|
if(m_cci_handle != INVALID_HANDLE) IndicatorRelease(m_cci_handle);
|
|
if(m_stoch_handle != INVALID_HANDLE) IndicatorRelease(m_stoch_handle);
|
|
if(m_ichimoku_handle != INVALID_HANDLE) IndicatorRelease(m_ichimoku_handle);
|
|
|
|
for(int i = 0; i < ArraySize(m_ma_handles); i++)
|
|
{
|
|
if(m_ma_handles[i] != INVALID_HANDLE)
|
|
IndicatorRelease(m_ma_handles[i]);
|
|
}
|
|
}
|
|
|
|
#endif // TECHNICAL_ANALYSIS_V71_MQH |