Viewing the resource: BOS (Break of Structure) CHOCH (Change of Character) EA: Trade Breakouts with Precision

BOS (Break of Structure) CHOCH (Change of Character) EA: Trade Breakouts with Precision

Allan Munene Mutiiria 2025-06-20 23:39:10 239 Views
Join our fun, beginner-friendly guide to the BOS CHOCH EA MQL5 code! We’ll explain every function ...

Introduction

Hey there, future forex navigator! Imagine the forex market as a mighty river, its price action carving out peaks and valleys that hint at powerful currents. The BOS CHOCH EA is your expert river scout, identifying Break of Structure (BOS) and Change of Character (CHOCH) patterns—moments when price surges past key highs or lows, signaling a breakout. This article is your river map, guiding you through the MQL5 code on MetaTrader 5 with vivid detail. We’ll unpack every major function with clarity for beginners, weaving humor and flow like a storyteller by a campfire. By the end, you’ll be ready to let this Expert Advisor (EA) chart breakout trades for you. Let’s set sail!

Strategy Blueprint

The BOS CHOCH EA focuses on price action patterns:

  • Break of Structure (BOS): When price breaks above a swing high (bullish) or below a swing low (bearish), confirming a trend shift.
  • Change of Character (CHOCH): A reversal signal when new swing highs or lows form, indicating a change in momentum.

The EA scans 10 candles on each side of a target candle to identify swing highs (higher than neighbors) and lows (lower than neighbors). A buy signal triggers when price breaks above a swing high, marked by a blue arrow and line; a sell signal fires when price breaks below a swing low, marked by a red arrow and line. Signals occur only on new candles, ensuring precision. It’s like spotting a river’s bend and betting on its next surge. See below.

Code Implementation

Let’s navigate the MQL5 code like river explorers charting a course, unfolding the logic as a seamless story. Each function builds on the last, flowing from initializing the EA, to detecting swing points, to signaling breakouts, and finally to marking them visually. We’ll explain every major function in detail, quoting variables (e.g., "swing_H") and functions (e.g., "OnInit()") for clarity, keeping it beginner-friendly with a playful river theme.

Charting the Course: Header and Standard Functions

Our journey begins by setting up the river map, preparing the EA to scan the market’s currents.

//+------------------------------------------------------------------+
//|                                                 BOS CHOCH EA.mq5 |
//|                        Copyright 2025, Allan Munene Mutiiria      |
//|                            https://t.me/Forex_Algo_Trader         |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Allan Munene Mutiiria"
#property link      "https://t.me/Forex_Algo_Trader"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){
   static bool isNewBar = false;
   int currBars = iBars(_Symbol,_Period);
   static int prevBars = currBars;
   if (prevBars == currBars){isNewBar = false;}
   else if (prevBars != currBars){isNewBar = true; prevBars = currBars;}
   // ... (rest of OnTick follows)
}

The header declares the EA as “BOS CHOCH EA,” crafted by Allan in 2025, with a link to your Telegram channel and version 1.00, setting the stage for our adventure.

  • "OnInit()": The EA’s launch point, called when attached to a chart. It returns INIT_SUCCEEDED, a constant signaling successful startup, as no indicators need loading. It’s like hoisting the sail with a clear horizon.
  • "OnDeinit()": The cleanup function, called when removed. It’s empty, like leaving the riverbank pristine, as no resources require freeing.
  • "OnTick()": The EA’s heartbeat, running on every price tick to scan for patterns. It starts by checking for new candles using "iBars()", which returns the chart’s bar count, stored in "currBars". A static "prevBars" tracks the previous count, and a boolean "isNewBar" flags new candles when "currBars" differs from "prevBars", updating "prevBars". This ensures pattern detection occurs only on fresh candles, like checking the river’s flow at dawn.

These functions lay the foundation, preparing the EA to navigate the market’s waves.


Mapping the River: Helper Functions (high, low, time)

Before charting the main course, we define tools to measure the river’s peaks and valleys.

double high(int index){return (iHigh(_Symbol,_Period,index));}
double low(int index){return (iLow(_Symbol,_Period,index));}
datetime time(int index){return (iTime(_Symbol,_Period,index));}

These helper functions streamline price and time data retrieval:

  • "high()": Returns the high price of a candle at "index" using "iHigh()", which fetches the high for the current symbol ("_Symbol", e.g., EURUSD) and timeframe ("_Period", e.g., H1). It’s like spotting a river’s crest.
  • "low()": Returns the low price using "iLow()", capturing the river’s trough.
  • "time()": Returns the candle’s timestamp using "iTime()", marking when the crest or trough occurred, like noting the time of a wave.

These functions act as our binoculars, simplifying data access as we scout the market’s flow.

Scouting the Peaks and Valleys: OnTick (Swing Detection)

Now we dive into the heart of "OnTick()", where the EA scouts swing highs and lows—the river’s peaks and valleys.

// Inside OnTick()
const int length = 10; // >2
int right_index, left_index;
int curr_bar = length;
bool isSwingHigh = true, isSwingLow = true;
static double swing_H = -1.0, swing_L = -1.0;

if (isNewBar){
   for (int a=1; a<=length; a++){
      right_index = curr_bar - a;
      left_index = curr_bar + a;
      if ( (high(curr_bar) <= high(right_index)) || (high(curr_bar) < high(left_index)) ){
         isSwingHigh = false;
      }
      if ( (low(curr_bar) >= low(right_index)) || (low(curr_bar) > low(left_index)) ){
         isSwingLow = false;
      }
   }
   
   if (isSwingHigh){
      swing_H = high(curr_bar);
      Print("WE DO HAVE A SWING HIGH @ BAR INDEX ",curr_bar," H: ",high(curr_bar));
      drawSwingPoint(TimeToString(time(curr_bar)),time(curr_bar),high(curr_bar),77,clrBlue,-1);
   }
   if (isSwingLow){
      swing_L = low(curr_bar);
      Print("WE DO HAVE A SWING LOW @ BAR INDEX ",curr_bar," L: ",low(curr_bar));
      drawSwingPoint(TimeToString(time(curr_bar)),time(curr_bar),low(curr_bar),77,clrRed,+1);
   }
}

This segment of "OnTick()" identifies swing points when a new candle forms ("isNewBar"). Here’s how it flows:

  • Setup: Defines "length" (10) as the number of candles to check on each side, "curr_bar" (set to "length") as the target candle (10 bars back), and booleans "isSwingHigh" and "isSwingLow" to flag swing points. Static variables "swing_H" and "swing_L" store the latest swing high/low prices, initialized to -1.0.
  • Swing Detection: Loops through 10 candles left ("left_index") and right ("right_index") of "curr_bar". If "curr_bar"’s high isn’t the highest ("high()") compared to neighbors, "isSwingHigh" becomes false. If its low isn’t the lowest ("low()"), "isSwingLow" becomes false.
  • Swing Confirmation: If "isSwingHigh" remains true, "swing_H" stores the high, logs it with "Print()", and calls "drawSwingPoint()". If "isSwingLow" is true, "swing_L" stores the low, logs it, and calls "drawSwingPoint()".
  • "Print()": Logs messages to the journal, like “WE DO HAVE A SWING HIGH @ BAR INDEX 10 H: 1.23456”, marking discoveries.
  • "TimeToString()": Converts a timestamp to a string for object naming in "drawSwingPoint()".

This logic maps the river’s peaks and valleys, marking significant swing points with arrows, like planting flags on a charted course.

Riding the Breakout: OnTick (BOS Detection)

With swing points marked, the EA watches for price breaking past them, signaling a BOS.

// Inside OnTick()
double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);

if (swing_H > 0 && Ask > swing_H){
   Print("$$$$$$$$$ BUY SIGNAL NOW. BREAK OF SWING HIGH");
   int swing_H_index = 0;
   for (int i=0; i<=length*2+1000; i++){
      double high_sel = high(i);
      if (high_sel == swing_H){
         swing_H_index = i;
         Print("BREAK HIGH FOUND @ BAR INDEX ",swing_H_index);
         break;
      }
   }
   drawBreakLevel(TimeToString(time(0)),time(swing_H_index),high(swing_H_index),
   time(0),high(swing_H_index),clrBlue,-1);
   
   swing_H = -1.0;
   return;
}
if (swing_L > 0 && Bid < swing_L){
   Print("$$$$$$$$$ SELL SIGNAL NOW. BREAK OF SWING LOW");
   int swing_L_index = 0;
   for (int i=0; i<=length*2+1000; i++){
      double low_sel = low(i);
      if (low_sel == swing_L){
         swing_L_index = i;
         Print("BREAK LOW FOUND @ BAR INDEX ",swing_L_index);
         break;
      }
   }
   drawBreakLevel(TimeToString(time(0)),time(swing_L_index),low(swing_L_index),
   time(0),low(swing_L_index),clrRed,+1);

   swing_L = -1.0;
   return;
}

This segment detects BOS events, continuing the river’s flow:

  • "SymbolInfoDouble()": Fetches the ask price ("SYMBOL_ASK", "Ask") and bid price ("SYMBOL_BID", "Bid") for real-time trading.
  • "NormalizeDouble()": Rounds prices to the symbol’s decimal places ("_Digits", e.g., 5 for EURUSD), ensuring trade-ready formatting.
  • Buy Signal: If "swing_H" is valid (>0) and "Ask" exceeds "swing_H", it’s a bullish BOS. The EA logs “BUY SIGNAL” with "Print()", searches for the swing high’s candle index ("swing_H_index") by comparing "high()" values, logs the break, and calls "drawBreakLevel()". It resets "swing_H" to -1.0 and exits.
  • Sell Signal: If "swing_L" is valid (>0) and "Bid" falls below "swing_L", it’s a bearish BOS. The EA logs “SELL SIGNAL”, finds the swing low’s index ("swing_L_index"), logs the break, calls "drawBreakLevel()", resets "swing_L", and exits.

This logic rides the river’s surge, signaling breakouts when price breaches key levels, like a raft hitting a rapid.


Marking the Path: drawSwingPoint Function

To visualize swing points, the EA paints arrows and labels on the chart.

void drawSwingPoint(string objName,datetime time,double price,int arrCode,
   color clr,int direction){
   if (ObjectFind(0,objName) < 0){
      ObjectCreate(0,objName,OBJ_ARROW,0,time,price);
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,objName,OBJPROP_FONTSIZE,10);
      
      if (direction > 0) {ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);}
      if (direction < 0) {ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);}
      
      string text = "BoS";
      string objName_Descr = objName + text;
      ObjectCreate(0,objName_Descr,OBJ_TEXT,0,time,price);
      ObjectSetInteger(0,objName_Descr,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,objName_Descr,OBJPROP_FONTSIZE,10);
      
      if (direction > 0) {
         ObjectSetString(0,objName_Descr,OBJPROP_TEXT,"  "+text);
         ObjectSetInteger(0,objName_Descr,OBJPROP_ANCHOR,ANCHOR_LEFT_UPPER);
      }
      if (direction < 0) {
         ObjectSetString(0,objName_Descr,OBJPROP_TEXT,"  "+text);
         ObjectSetInteger(0,objName_Descr,OBJPROP_ANCHOR,ANCHOR_LEFT_LOWER);
      }
   }
   ChartRedraw(0);
}

The "drawSwingPoint()" function marks swing highs/lows with arrows and “BoS” labels, continuing the visual journey:

  • "ObjectFind()": Checks if an object ("objName") exists, returning <0 if not, preventing duplicates.
  • "ObjectCreate()": Creates an arrow ("OBJ_ARROW") at "time" and "price", and a text object ("OBJ_TEXT") labeled “BoS”.
  • "ObjectSetInteger()": Sets arrow properties like style ("OBJPROP_ARROWCODE", 77), color ("OBJPROP_COLOR", blue for highs, red for lows), font size ("OBJPROP_FONTSIZE", 10), and anchor ("OBJPROP_ANCHOR", top for lows, bottom for highs).
  • "ObjectSetString()": Sets the text object’s label, adding spaces for alignment.
  • "ChartRedraw()": Refreshes the chart to display the objects.

This function paints the river’s landmarks, making swing points clear, like flags on a trail.

Charting the Break: drawBreakLevel Function

Finally, the EA draws lines to mark BOS levels, completing the map.

void drawBreakLevel(string objName,datetime time1,double price1,
   datetime time2,double price2,color clr,int direction){
   if (ObjectFind(0,objName) < 0){
      ObjectCreate(0,objName,OBJ_ARROWED_LINE,0,time1,price1,time2,price2);
      ObjectSetInteger(0,objName,OBJPROP_TIME,0,time1);
      ObjectSetDouble(0,objName,OBJPROP_PRICE,0,price1);
      ObjectSetInteger(0,objName,OBJPROP_TIME,1,time2);
      ObjectSetDouble(0,objName,OBJPROP_PRICE,1,price2);

      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,objName,OBJPROP_WIDTH,2);
      
      string text = "Break";
      string objName_Descr = objName + text;
      ObjectCreate(0,objName_Descr,OBJ_TEXT,0,time2,price2);
      ObjectSetInteger(0,objName_Descr,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,objName_Descr,OBJPROP_FONTSIZE,10);
      
      if (direction > 0) {
         ObjectSetString(0,objName_Descr,OBJPROP_TEXT,text+"  ");
         ObjectSetInteger(0,objName_Descr,OBJPROP_ANCHOR,ANCHOR_RIGHT_UPPER);
      }
      if (direction < 0) {
         ObjectSetString(0,objName_Descr,OBJPROP_TEXT,text+"  ");
         ObjectSetInteger(0,objName_Descr,OBJPROP_ANCHOR,ANCHOR_RIGHT_LOWER);
      }
   }
   ChartRedraw(0);
}

The "drawBreakLevel()" function draws an arrowed line at the break level, labeled “Break”:

  • "ObjectCreate()": Creates an arrowed line ("OBJ_ARROWED_LINE") from ("time1", "price1") to ("time2", "price2") and a text object for “Break”.
  • "ObjectSetInteger()", "ObjectSetDouble()": Set line properties like times, prices, color ("clrBlue" for buys, "clrRed" for sells), width (2), and text anchor.
  • "ChartRedraw()": Refreshes the chart to show the line and label.

This function completes the river map, marking BOS events like drawing a path through rapids.

Putting It All Together

To launch this EA:

  1. Open MetaEditor in MetaTrader 5.
  2. Paste the code into a new Expert Advisor file.
  3. Compile (F5). If errors appear, double-check your copy-paste.
  4. Drag the EA onto your chart, enable AutoTrading, and watch for blue/red arrows and lines signaling buy/sell opportunities.
  5. Trade smart—don’t bet your raft on one breakout! Manually place trades based on signals or add trade execution code.

Conclusion

The BOS CHOCH EA is your river guide, spotting swing highs/lows and BOS breakouts with arrows and lines. We’ve navigated its MQL5 code with clear, detailed explanations, so you understand every move like a seasoned explorer. Now you’re set to automate pattern detection and trade breakouts like a pro. Want to see it in action? Check our video tutorial on the website!

Disclaimer: Trading’s like navigating a wild river—thrilling but risky. Losses can exceed deposits. Test on a demo account before going live.

Disclaimer: The ideas and strategies presented in this resource are solely those of the author and are intended for informational and educational purposes only. They do not constitute financial advice, and past performance is not indicative of future results. All materials, including but not limited to text, images, files, and any downloadable content, are protected by copyright and intellectual property laws and are the exclusive property of Forex Algo-Trader or its licensors. Reproduction, distribution, modification, or commercial use of these materials without prior written consent from Forex Algo-Trader is strictly prohibited and may result in legal action. Users are advised to exercise extreme caution, perform thorough independent research, and consult with qualified financial professionals before implementing any trading strategies or decisions based on this resource, as trading in financial markets involves significant risk of loss.

Recent Comments

Go to discussion to Comment or View other Comments

No comments yet. Be the first to comment!