#property copyright "Your Name" #property link "https://www.example.com" #property version "1.00" #property indicator_chart_window #property indicator_buffers 0 #property indicator_plots 0 // Input parameters input int SwingPeriod = 5; // Lookback period for swing detection // Global variables double LastSwingHigh = 0, LastSwingLow = 0; bool IsBullish = false; //+------------------------------------------------------------------+ int OnInit() { return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { // Start from the latest bar for(int i = rates_total - prev_calculated - 1; i >= 0; i--) { // Detect swing high and low if(IsSwingHigh(high, low, i, SwingPeriod)) { LastSwingHigh = high[i]; CheckStructure(i, high[i], low[i], time[i]); } if(IsSwingLow(high, low, i, SwingPeriod)) { LastSwingLow = low[i]; CheckStructure(i, high[i], low[i], time[i]); } } return(rates_total); } //+------------------------------------------------------------------+ bool IsSwingHigh(const double &high[], const double &low[], int index, int period) { if(index < period || index >= ArraySize(high) - period) return false; for(int i = 1; i <= period; i++) { if(high[index] <= high[index - i] || high[index] <= high[index + i]) return false; } return true; } //+------------------------------------------------------------------+ bool IsSwingLow(const double &high[], const double &low[], int index, int period) { if(index < period || index >= ArraySize(low) - period) return false; for(int i = 1; i <= period; i++) { if(low[index] >= low[index - i] || low[index] >= low[index + i]) return false; } return true; } //+------------------------------------------------------------------+ void CheckStructure(int index, double high, double low, datetime time) { // Determine trend direction if(LastSwingHigh > 0 && LastSwingLow > 0) { IsBullish = (LastSwingHigh > LastSwingLow); // Check for BOS if(IsBullish && high > LastSwingHigh) { LastSwingHigh = high; ObjectCreate(0, "BOS_" + TimeToString(time), OBJ_TEXT, 0, time, high); ObjectSetString(0, "BOS_" + TimeToString(time), OBJPROP_TEXT, "BOS"); ObjectSetInteger(0, "BOS_" + TimeToString(time), OBJPROP_COLOR, clrGreen); Alert("Break of Structure (BOS) detected at " + DoubleToString(high, 5)); } else if(!IsBullish && low < LastSwingLow) { LastSwingLow = low; ObjectCreate(0, "BOS_" + TimeToString(time), OBJ_TEXT, 0, time, low); ObjectSetString(0, "BOS_" + TimeToString(time), OBJPROP_TEXT, "BOS"); ObjectSetInteger(0, "BOS_" + TimeToString(time), OBJPROP_COLOR, clrRed); Alert("Break of Structure (BOS) detected at " + DoubleToString(low, 5)); } // Check for CHoCH if(IsBullish && low < LastSwingLow) { LastSwingLow = low; ObjectCreate(0, "CHoCH_" + TimeToString(time), OBJ_TEXT, 0, time, low); ObjectSetString(0, "CHoCH_" + TimeToString(time), OBJPROP_TEXT, "CHoCH"); ObjectSetInteger(0, "CHoCH_" + TimeToString(time), OBJPROP_COLOR, clrRed); Alert("Change of Character (CHoCH) detected at " + DoubleToString(low, 5)); IsBullish = false; // Trend may reverse } else if(!IsBullish && high > LastSwingHigh) { LastSwingHigh = high; ObjectCreate(0, "CHoCH_" + TimeToString(time), OBJ_TEXT, 0, time, high); ObjectSetString(0, "CHoCH_" + TimeToString(time), OBJPROP_TEXT, "CHoCH"); ObjectSetInteger(0, "CHoCH_" + TimeToString(time), OBJPROP_COLOR, clrGreen); Alert("Change of Character (CHoCH) detected at " + DoubleToString(high, 5)); IsBullish = true; // Trend may reverse } } } //+------------------------------------------------------------------+ void OnDeinit(const int reason) { ObjectsDeleteAll(0, "BOS_"); ObjectsDeleteAll(0, "CHoCH_"); }