//+------------------------------------------------------------------+ //| BOS.mq5 | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #include CTrade obj_Trade; //+------------------------------------------------------------------+ //| 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; // Check if a new bar has formed if (prevBars == currBars) isNewBar = false; else { isNewBar = true; prevBars = currBars; } // Swing calculation parameters const int length = 20; // Length for swing calculations const int limit = 20; // Limit for bar checks // Variables to hold swing points static double swing_H = -1.0, swing_L = -1.0; int curr_bar = limit; if (isNewBar) { handleSwingPoints(curr_bar, length, swing_H, swing_L); } // Get market prices double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits); double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits); // Check for breakouts if (checkBreakUp(Bid, swing_H)) { Print("BREAK UP NOW"); int swing_H_index = findSwingIndex(swing_H, length, true); drawBreakLevel(TimeToString(time(0)), time(swing_H_index), high(swing_H_index), time(0 + 1), high(swing_H_index), clrBlue, -1); swing_H = -1.0; // Reset swing high after breakout } else if (checkBreakDown(Ask, swing_L)) { Print("BREAK DOWN NOW"); int swing_L_index = findSwingIndex(swing_L, length, false); drawBreakLevel(TimeToString(time(0)), time(swing_L_index), low(swing_L_index), time(0 + 1), low(swing_L_index), clrRed, 1); swing_L = -1.0; // Reset swing low after breakout } } //+------------------------------------------------------------------+ //| Helper Functions | //+------------------------------------------------------------------+ double high(int index) { return (iHigh(_Symbol, _Period, index)); } double low(int index) { return (iLow(_Symbol, _Period, index)); } double close(int index) { return (iClose(_Symbol, _Period, index)); } datetime time(int index) { return (iTime(_Symbol, _Period, index)); } // Handle swing points void handleSwingPoints(int curr_bar, int length, double &swing_H, double &swing_L) { bool isSwingHigh = true, isSwingLow = true; // Check for swing high and low for (int j = 1; j <= length; j++) { int right_index = curr_bar - j; int left_index = curr_bar + j; // Determine if current bar is a swing high or low if ((high(curr_bar) <= high(right_index)) || (high(curr_bar) < high(left_index))) isSwingHigh = false; // Not a swing high if ((low(curr_bar) >= low(right_index)) || (low(curr_bar) > low(left_index))) isSwingLow = false; // Not a swing low } // Handle identified swing points if (isSwingHigh) { swing_H = high(curr_bar); Print("UP @ BAR INDEX ", curr_bar, " of High: ", swing_H); drawSwingPoint(TimeToString(time(curr_bar)), time(curr_bar), swing_H, 77, clrBlue, -1); } if (isSwingLow) { swing_L = low(curr_bar); Print("DOWN @ BAR INDEX ", curr_bar, " of Low: ", swing_L); drawSwingPoint(TimeToString(time(curr_bar)), time(curr_bar), swing_L, 77, clrRed, 1); } } // Check for breakout upwards bool checkBreakUp(double Bid, double swing_H) { return (swing_H > 0 && Bid > swing_H && close(1) > swing_H); } // Check for breakout downwards bool checkBreakDown(double Ask, double swing_L) { return (swing_L > 0 && Ask < swing_L && close(1) < swing_L); } // Find the index of the swing high/low int findSwingIndex(double swingValue, int length, bool isHigh) { for (int i = 0; i <= length * 2 + 1000; i++) { double selectedValue = isHigh ? high(i) : low(i); if (selectedValue == swingValue) { Print(isHigh ? "BREAK HIGH @ BAR " : "BREAK LOW @ BAR ", i); return i; } } return 0; // Default return } // Draw a swing point 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); ObjectSetInteger(0, objName, OBJPROP_ANCHOR, direction > 0 ? ANCHOR_TOP : ANCHOR_BOTTOM); string txt = " BoS"; string objNameDescr = objName + txt; ObjectCreate(0, objNameDescr, OBJ_TEXT, 0, time, price); ObjectSetInteger(0, objNameDescr, OBJPROP_COLOR, clr); ObjectSetInteger(0, objNameDescr, OBJPROP_FONTSIZE, 10); ObjectSetInteger(0, objNameDescr, OBJPROP_ANCHOR, direction > 0 ? ANCHOR_LEFT_UPPER : ANCHOR_LEFT_LOWER); ObjectSetString(0, objNameDescr, OBJPROP_TEXT, " " + txt); } ChartRedraw(0); } // Draw a break level on the chart 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 txt = " Break "; string objNameDescr = objName + txt; ObjectCreate(0, objNameDescr, OBJ_TEXT, 0, time2, price2); ObjectSetInteger(0, objNameDescr, OBJPROP_COLOR, clr); ObjectSetInteger(0, objNameDescr, OBJPROP_FONTSIZE, 10); ObjectSetInteger(0, objNameDescr, OBJPROP_ANCHOR, direction > 0 ? ANCHOR_RIGHT_UPPER : ANCHOR_RIGHT_LOWER); ObjectSetString(0, objNameDescr, OBJPROP_TEXT, " " + txt); } ChartRedraw(0); } //+------------------------------------------------------------------+