//+------------------------------------------------------------------+ //| MarkovAnalysis.mqh | //| Copyright 2024, Trading Agent | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, Trading Agent" #property link "https://www.mql5.com" #property strict // Define States enum ENUM_MARKOV_STATE { STATE_STRONG_BEAR = 0, // Strong Bearish STATE_WEAK_BEAR = 1, // Weak Bearish STATE_NEUTRAL = 2, // Neutral/Doji STATE_WEAK_BULL = 3, // Weak Bullish STATE_STRONG_BULL = 4, // Strong Bullish STATE_COUNT = 5 }; //+------------------------------------------------------------------+ //| Class CMarkovChain | //+------------------------------------------------------------------+ class CMarkovChain { private: double m_matrix[STATE_COUNT][STATE_COUNT]; // Transition Counts int m_total_transitions[STATE_COUNT]; // Total exits from each state ENUM_MARKOV_STATE m_last_state; double m_threshold_pct; // Percentage of ADR or similar to define "Strong" public: CMarkovChain(double threshold_pct = 0.5); ~CMarkovChain() {} void Reset(); void AddTransition(ENUM_MARKOV_STATE from, ENUM_MARKOV_STATE to); ENUM_MARKOV_STATE CalculateState(double open, double high, double low, double close, double point); double GetProbability(ENUM_MARKOV_STATE from, ENUM_MARKOV_STATE to); void GetProbabilities(ENUM_MARKOV_STATE from, double &probs[]); ENUM_MARKOV_STATE GetLastState() { return m_last_state; } void SetLastState(ENUM_MARKOV_STATE state) { m_last_state = state; } }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CMarkovChain::CMarkovChain(double threshold_pct) { m_threshold_pct = threshold_pct; Reset(); } //+------------------------------------------------------------------+ //| Reset Matrix | //+------------------------------------------------------------------+ void CMarkovChain::Reset() { ArrayFill(m_matrix, 0, STATE_COUNT * STATE_COUNT, 0); ArrayFill(m_total_transitions, 0, STATE_COUNT, 0); m_last_state = STATE_NEUTRAL; } //+------------------------------------------------------------------+ //| Add a transition to the matrix | //+------------------------------------------------------------------+ void CMarkovChain::AddTransition(ENUM_MARKOV_STATE from, ENUM_MARKOV_STATE to) { if(from < 0 || from >= STATE_COUNT || to < 0 || to >= STATE_COUNT) return; m_matrix[from][to]++; m_total_transitions[from]++; } //+------------------------------------------------------------------+ //| Calculate state from OHLC | //+------------------------------------------------------------------+ ENUM_MARKOV_STATE CMarkovChain::CalculateState(double open, double high, double low, double close, double point) { double body = close - open; double range = high - low; if(MathAbs(body) < 10 * point) return STATE_NEUTRAL; // Very small body // We'll use a simple fixed threshold for now, can be improved with volatility scaling double threshold = 50 * point; if(body > 0) { return (body > threshold) ? STATE_STRONG_BULL : STATE_WEAK_BULL; } else { return (MathAbs(body) > threshold) ? STATE_STRONG_BEAR : STATE_WEAK_BEAR; } } //+------------------------------------------------------------------+ //| Get probability of transition | //+------------------------------------------------------------------+ double CMarkovChain::GetProbability(ENUM_MARKOV_STATE from, ENUM_MARKOV_STATE to) { if(from < 0 || from >= STATE_COUNT || to < 0 || to >= STATE_COUNT) return 0; if(m_total_transitions[from] == 0) return 0; return m_matrix[from][to] / m_total_transitions[from]; } //+------------------------------------------------------------------+ //| Get all probabilities from a specific state | //+------------------------------------------------------------------+ void CMarkovChain::GetProbabilities(ENUM_MARKOV_STATE from, double &probs[]) { ArrayResize(probs, STATE_COUNT); for(int i = 0; i < STATE_COUNT; i++) { probs[i] = GetProbability(from, (ENUM_MARKOV_STATE)i); } }