// SmartHedge_v2p7_mq4

#property copyright  "Copyright 2024, EgoNoBueno"
#property link       "dhess10000@protonmail.com"
#property version    "2.70"
#property strict
#include <stderror.mqh>
#include <stdlib.mqh>

/*
EA NOTES - Following FOREX HEDGING CHANNEL METHOD
Final notes for version 2.2.
Works great until it gets orphaned trades. Takes trades close
to support and resistance, as desired. Does not do well when
there is a breakout.
Version 2.3 which will incorporate the first'
iteration of the Smart Hedge.

Version 2.4 created to stop placing tons of trades during recompiles
of the loaded EA. Works. Problems:
REduces take profit of the Primary trade to zero.
Protective hedge closes at profit and does not re=instantiate a new
hedge.

Version 2.5
To Do
If IBO price is greater than the current highest high.
reset the tp to 50 pips.
If ISO price is less than the current lowest low, reser
the tp to 50 pips.
Never more than two trades open. The Primary Trade and the Recovery
Hedge

Focus on pairs that pay positive swap when possible. On those pairs focus on the
side that pays swap first and take trades that have a good probability of going
straight to Take Profit (TP) target.Pronlem is that pairs that pay good swap
usually have high spreads.

If the Take Profit target is hit great. Do it again.
 Version 2.6
 Changed name to Black Wolf.
 Build the Trim The Primary Trade Engine.
 Note that the Primary and Hedge Trade roles may flip flop over the course of the
 trade.

 Just take the next natural trade?? let the price action dictate weather we balance
 the capacity or balance the hedge.

Terms:
Balance the Capacity: Use all the margin you can.
Balance the Hedge
Trim the hedge.
One trade we had extra profit on.
One trade we cleaned with
trim the furthest outside position.
draw down
operating capital

At support, Buy to Open at the Market, Immediately put up a protective SHO 25 pips away. Both trades target 40 pips Profit target. The opposite of all the above is done on the ISO side at the Resistance level.
There are no stop losses, Hedging is the complete risk mitigation method.

Notes
Unactivated Stop and Limit orders cannot be closed. They can only be deleted.

Initial Buy Order (IBO)
Second Buy Order (SecBO)
Third Buy Order (ThrdBO)

ISO Balancing Buy Hedge Order (BHO) These orders are always pending until activated. Then they become regular buy orders.
Second Buy Hedge Order (SecBHO)
Third But Hedge Order (ThrdBHO)


Initial Sell Order (ISO)
Second Sell Order (SecSO)
Third Sell Order (ThrdSO)

IBO Balancing Sell Hedge Order (SHO). These orders are always pending until activated. Then they become regular sell orders.
Second Sell Hedge Order (SecSHO)
Third Sell Hedge Order (ThrdSHO)

Tp = take profit


Always be hedged 25 50 ratio for hedge offset and tp.
The goal is not to get flat. The goal is to make money.You have to be in the market to make
money.

As soon as the IBO trade goes negative you are in Trim IBO Mode (TIBO MODE)
As soon as the ISO goes negative you are in Trim ISO Mode (TISO MODE)
No Position - waiting for price action.
In IBO Trade - Awaiting Porfit Target hit
In ISO Trade - Awaiting Profit Target hit
In IBO Trade is Negative (PL) - In TIBO MODE.
In ISO Trade  is Negative (PL) - In TISO MODE.
Squeeze the hedge
Build a Hedge from the inside.
Straddle


Units Lots  Apply Close %Closed  Left  Realized $  Percent_Pl
                                       DD
LONG                          SHORT              Bal
Draw Units Profit Keep Apply  Draw Units Profit Keep Apply


Stacking multiple positions.

When you enter a trade you set the Pending Order immediately.
Videos:
https://youtu.be/Fzh4dNhYga0?si=V6Xp9eG9AqO7_YSU

// Roll Off Engine
// Long Trade PL
// Short Trade PL
// Bank Balance

Dont keep all your money in one broker. Even the best ones can fail.
//=================================================================
To Do List
Spread Lock
What if IBO ticket closed but SHO was activated?

Finish swap decision function. Report swap in comments and during init.
Calculate days to get to $3M at 20 pips per day.

Hedge pay down. rehedge
Print(__LINE__, ", Function: ", __FUNCTION__, ", Made it here.");
*/
void AAReturnToTop() {;}
string EA_Name = "SmartHedge_v2p7_mq4";
double TakeProfit = 0.0;

extern double LS1 = 1.0; //Lotsize of Trade 1.
extern int OffsetToIncreaseOddsOfGettingAFill = 4; // Offset to ensure we get a take profit fill.
extern double TrailDistance = 10.5;
extern int RangeSeparation = 10; // Minimum Support Resistance separation distance.
extern int SuppResCalcBars = 40; // Look back period for SR.
extern int TesterVisualSpeed = 10000; // Speed throttle counter value.
extern int MagicSeed = 1000; //Number from which to compute MagicNumber
input int tradeSpacing = 20; // To be used if trading multiple orders.
extern bool ShowComment = true;

extern int PendingOrderTp = 50;
extern int HedgeDistanceOffset = 22; // Breathing room for the active trade.
// 10 is too tight, resolution takes longer. 30 too loose.
int hedgemagic = 0;
bool bSendBHO = false;
bool bSendSHO = false;
extern int InitialOrderTp = 40;
extern int fontSize = 16; // Font size for displaying the prices
int IBOTicket = 0; // Holds the ticket number of the IBO trade.
int ISOTicket = 0; // Holds the ticket number of the ISO trade.
int BHOTicket = 0; // Holds the ticket number of the BHO trade.
int SHOTicket = 0; // Holds the ticket number of the SHO trade.
int magic = 0;

int TradeCounter = 0; //Counts the number of total trades taken.
int ISOCounter = 0;
int IBOCounter = 0;
double pips = 0.0;
double MarginUsed = 0.0;
double MyFreeMargin = 0.0;
double highestHigh = 0.0;
double lowestLow = 0.0;
bool ISO_OK = false;
bool IBO_OK = false;
bool SpreadOk = false;

double currSpread = 0.0;
double point_value = 0.0;

double LotsLeftOnLongSide = 0.0;
double LotsLeftOnShortSide = 0.0;
double Banked = 0.0;
double Deposited = 0.0;
double ExtinguishedLots = 0.0;
double BalanceTheCapacity = 0.0;
double DrawDown = 0.0;
double UpPercent = 0.0;

// if there are pending SHO but no open IBO orders, cancel pending SHO Orders.
bool CancelPendingBHO = false;
bool CancelPendingSHO = false;
// Did we close a hedge order? Partial close the initial order and reinstatiate a pending order for lots left.
// What to do if the next pending order did not get hit? And the original order retraced towards profittabily?
// That is called Squeezing the Initial Order. Keep a pending orde in place 30 pips below the original order.
// Building from the inside. WE are still in the original position but we think the market is going  to go
// the other direction. We are going to take an opposite position. But we are going to protect it with a
// hedge in the opposite direction.


//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---Generate a magic number based on our MagicSeed
   magic = MagicNumberGenerator();
   Print(__LINE__, " The magic number is ", IntegerToString(magic));
   hedgemagic = magic + 200000;
   Print(__LINE__, " The Hedge magic number is ", IntegerToString(hedgemagic));

   pips = Point; //.00001 or .0001. .001 .01.
   if(Digits == 3 || Digits == 5)
      pips *= 10;


   Print(__LINE__, ", Function: ", __FUNCTION__, "The name of the broker = ", AccountInfoString(ACCOUNT_COMPANY),
         ", Deposit currency = ", AccountInfoString(ACCOUNT_CURRENCY));
   Print(__LINE__, ", Function: ", __FUNCTION__, "Client name = ", AccountInfoString(ACCOUNT_NAME),
         ", The name of the trade server = ", AccountInfoString(ACCOUNT_SERVER));

//--- show all the information available from the function AccountInfoDouble()
   Print("ACCOUNT_BALANCE = ", AccountInfoDouble(ACCOUNT_BALANCE), ", ACCOUNT_CREDIT = ", AccountInfoDouble(ACCOUNT_CREDIT),
         ", ACCOUNT_PROFIT = ", AccountInfoDouble(ACCOUNT_PROFIT), ", ACCOUNT_EQUITY =  ", AccountInfoDouble(ACCOUNT_EQUITY));
   Print("ACCOUNT_MARGIN =  ", AccountInfoDouble(ACCOUNT_MARGIN),  ", ACCOUNT_MARGIN_FREE =  ", AccountInfoDouble(ACCOUNT_FREEMARGIN),
         ", ACCOUNT_MARGIN_LEVEL =  ", AccountInfoDouble(ACCOUNT_MARGIN_LEVEL), ", ACCOUNT_MARGIN_SO_CALL = ", AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL),
         ", ACCOUNT_MARGIN_SO_SO = ", AccountInfoDouble(ACCOUNT_MARGIN_SO_SO));
//--- show all the information available from the function AccountInfoInteger()
   Print("ACCOUNT_LOGIN =  ", AccountInfoInteger(ACCOUNT_LOGIN), ", Account #", AccountNumber(), ", leverage is ", AccountLeverage());

   double HedgeMargin  = MarketInfo(_Symbol, MODE_MARGINHEDGED);
   Print(__LINE__, ", Function: ", __FUNCTION__, "Hedging Margin For ", _Symbol, " Is ", DoubleToStr(HedgeMargin, 4));

   bool thisAccountTradeAllowed = AccountInfoInteger(ACCOUNT_TRADE_ALLOWED);
   bool EATradeAllowed = AccountInfoInteger(ACCOUNT_TRADE_EXPERT);
   ENUM_ACCOUNT_TRADE_MODE tradeMode = (ENUM_ACCOUNT_TRADE_MODE)AccountInfoInteger(ACCOUNT_TRADE_MODE);
   ENUM_ACCOUNT_STOPOUT_MODE stopOutMode = (ENUM_ACCOUNT_STOPOUT_MODE)AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE);

   point_value = _Point * MarketInfo(_Symbol, MODE_TICKVALUE) / MarketInfo(_Symbol, MODE_TICKSIZE);
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
// Reset the background color to default when EA is removed
   ChartSetInteger(0, CHART_COLOR_BACKGROUND, clrBlack);

//DeleteAllObjects();

   Comment("Deinit Complete.");
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
// Slow Down The Strategy Tester So That You Can See the Trade Process.
   if(IsVisualMode() && IsTesting())
     {
      int  i = 0;
      if(OrdersTotal())
        {
         for(i = TesterVisualSpeed; i > 0; i--)
           {
            Comment(
               "\nEA Name: " + EA_Name + ", Tester Speed Throttling Is In Effect. Delay Value = " + IntegerToString(TesterVisualSpeed) + "  Throttle Speed Counter: " + IntegerToString(i) +
               "\nNUMBER OF IBO OPEN = " + (string)TotalOpenIBO() + ", TOTAL LOTS IN IBO BASKET = " + (string)TotalOpenIBOLots() +
               "\n\nNUMBER OF ISO OPEN = " + (string)TotalOpenISO() +  ", TOTAL LOTS IN ISO BASKET = " + (string)TotalOpenISOLots() +
               "\n\nTOTAL TRADES TAKEN: " + IntegerToString(TradeCounter) + ", TOTAL ISO TRADES TAKEN: " + IntegerToString(ISOCounter) + ", Total IBO TRADES TAKEN: " + IntegerToString(IBOCounter) +
               "\nActive BHO Lots: ", DoubleToStr(TotalOpenBHOLots(), 2) + ", Active SHO Lots: " + DoubleToStr(TotalOpenSHOLots(), 2) +
               "\n\nACCOUNT BALANCE = " + DoubleToStr(AccountBalance(), 2) + ", Account Margin: " +
               DoubleToStr(AccountMargin(), 2) + ", Account Free Margin: " + DoubleToStr(AccountFreeMargin(), 2) +     ", Open Profit / Loss: " + DoubleToStr(OpenPL(), 2) +
               "\nSuppRes Range Separation is ", DoubleToStr((highestHigh - lowestLow), 5), ", Spread: ", DoubleToStr(Ask - Bid, 5), ", ", ShowCurrentBarTime() +
               "\n" + SmartHedgeStatus()
               // Add pending hedge and active hedge orders.
            );
           }
        }
     }

// Display Bid Ask Spread
   DisplayBidAskSpread();

// WE WANT FRESH SUPPORT AND RESISTANCE LEVELS!
// If the market starts trending in the direction of your stoploss, then it is very common
// to get a take profit fill, followed by a breakout. It will appear that we have left money
// table. So one thing we could do is always have a Breakout pending order to be ready to
// take advantage of that situation. In the case of a ISO that would be a
// Buy Limit Order.
   DrawSuppRes();

// Check if the Spread is acceptable. Do nothing until the spread is ok.
   SpreadOk = SpreadIsAcceptable();
   if(!SpreadOk)
     {
      return;
     }
// ### 1st Priority: Close Trades

// If IBO hit TP , Delete SHO.
   if(TotalOpenIBO())
     {
      if(MonitorIBOClosure(IBOTicket))
        {
         DeleteSHO(SHOTicket);
        }
     }
   if(TotalOpenISO())
     {
      if(MonitorISOClosure(ISOTicket))
        {
         DeleteBHO(BHOTicket);
        }
     }

// monitor SHO and IBo profit
// bank realized profit.
// Trim IBO calculate trim.
//  Reopen SHO for hedge balancing lot amount.
// one lot per 10k.
// real time calvulator.
// auto trim.



// ### 2nd Priority: Perform Trade Maintenance
// CheckIfIBOOpenPriceIsAboveCurrentResistance(IBOTicket);
// TrailStopLoss(); // Trail the stop loss on every tick

// Check if BHO Order Got filled
   CheckBHOFilled(BHOTicket);

// Check if SHO order got filled.
   CheckSHOFilled(SHOTicket);

// Monitor the Initial Buy Trade for closure.
// Needs IBO Trade Ticket number whichi is generated in in the EnterIBO
// and EnterISO trade function. // Information needed to track profitability.
   if(MonitorIBOClosure(IBOTicket))
     {
      // The IBO trade closed, so no need for the protective SHO.
      DeleteSHO(SHOTicket);

     }// IBO Trade Number reset??

   if(MonitorISOClosure(ISOTicket))
     {
      // The ISO trade closed, so no need for the protective BHO order.
      DeleteBHO(BHOTicket);
     }

// Trim IBO ISO

// ### 3rd Priority: Open New Trades

// If IBO but No SHO - Get one open after IBO trim.


// ISO Signal - Sell To Open when Bid is close to Resistance.
   if(BidGrtrHH()  && (TotalOpenISO() == 0) && (TotalOpenIBO() == 0) && ((highestHigh - lowestLow) > (RangeSeparation * pips)))
     {
      ISO_OK = true;
      //Print(__LINE__, " ", string(BidGrtrHH()), " ,", string(ISO_OK));
     }
   else
     {
      ISO_OK = false;
      //Print(__LINE__, " ", string(BidGrtrHH()), " ,", string(ISO_OK));
     }

// Buy Signal - Buy to Open IBO when Price is close to Support
   if(AskLessThanLowestLow() && (TotalOpenISO() == 0) && (TotalOpenIBO() == 0) && ((highestHigh - lowestLow) > (RangeSeparation * pips)))
     {
      IBO_OK = true;
      //Print(__LINE__, " ", string(AskLessThanLowestLow()), " ,", string(IBO_OK));
     }
   else
     {
      IBO_OK = false;
      // Print(__LINE__, " ", string(AskLessThanLowestLow()), " ,", string(IBO_OK));
     }

// One Check Per Bar for new Buy or ISO signals. IBO_OK, and ISO_OK are used for the check.
// Modifications to the profit target are handled first.
   static datetime candletime = 0;
   if(candletime != Time[0])
     {

      IBOTakeProfitModifyCheck();
      ISOTakeProfitModifyCheck();
      CheckForISOSignal();
      CheckForIBOSignal();

      // Conditions for sending pending Buy Hedge trade.
      if(bSendBHO == true)
        {
         double price = Ask + (HedgeDistanceOffset * pips);
         double lotSize = LS1;
         int slippage = 10;

         SendBHO(price, lotSize, slippage, 0.0, (Bid + ((HedgeDistanceOffset + PendingOrderTp) * pips)), " SmartHedge_v2p7 IBO");
        }

      // Condition for sending pending Sell Hedge trade.
      if(bSendSHO == true)
        {
         double price = Bid - (HedgeDistanceOffset * pips);
         double lotSize = LS1;
         int slippage = 10;

         SendSHO(price, lotSize, slippage, 0.0, (Ask - ((HedgeDistanceOffset + PendingOrderTp) * pips)), " SmartHedge_v2p7 Sell Order");
        }

      candletime = Time[0];
     }

// If high - low Support Resistance Range is less that 10 pips
// Change chart background. New trades are prohibited.
   ChangeBackgroundSuppRes();

// Change chart background color if spread is too wide
   ChangeBackgroundSpreadTooWide();

// Make Comment section look like the trim calculator.
   Comment(
      "\nEA Name: " + EA_Name +
      "\nNUMBER OF IBO OPEN = " + (string)TotalOpenIBO() + ", TOTAL LOTS IN IBO BASKET = " + (string)TotalOpenIBOLots() +
      "\n\nNUMBER OF ISO OPEN = " + (string)TotalOpenISO() +  ", TOTAL LOTS IN ISO BASKET = " + (string)TotalOpenISOLots() +
      "\n\nTOTAL TRADES TAKEN: " + IntegerToString(TradeCounter) + ", TOTAL ISO TRADES TAKEN: " + IntegerToString(ISOCounter) + ", Total IBO TRADES TAKEN: " + IntegerToString(IBOCounter) +
      "\nActive BHO Lots: ", DoubleToStr(TotalOpenBHOLots(), 2) + ", Active SHO Lots: " + DoubleToStr(TotalOpenSHOLots(), 2) +
      "\n\nACCOUNT BALANCE = " + DoubleToStr(AccountBalance(), 2) + ", Account Margin: " +
      DoubleToStr(AccountMargin(), 2) + ", Account Free Margin: " + DoubleToStr(AccountFreeMargin(), 2) +     ", Open Profit / Loss: " + DoubleToStr(OpenPL(), 2) +
      "\nRange Separation is ", DoubleToStr((highestHigh - lowestLow), 5), ", Spread: ", DoubleToStr(currSpread * 1000, 5), ", ", ShowCurrentBarTime() +
      "\n" + SmartHedgeStatus()
// Add pending hedge and active hedge orders.
   );

  }// End OnTick
//=================================================================
void AAStartFunctions() {;}
// Print(__LINE__, ", Function: ", __FUNCTION__, ",
//+------------------------------------------------------------------+
//|    Check if BHO filled                                           |
//+------------------------------------------------------------------+
bool CheckBHOFilled(int ticket)
  {
   if(OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
     {
      if(OrderType() != OP_BUYSTOP || OrderTicket() != ticket)
        {
         return false; // Not a buy stop order or not the specified ticket
        }
      double openPrice = OrderOpenPrice();
      double currentBid = SymbolInfoDouble(Symbol(), SYMBOL_BID);

      if(currentBid >= openPrice)
        {
         Print(__LINE__, ", Function: ", __FUNCTION__, ", BHO filled for ticket ", ticket);
         return true;
        }
     }
   return false;
  }

//+------------------------------------------------------------------+
//|    Check if SHO filled                                           |
//+------------------------------------------------------------------+
bool CheckSHOFilled(int ticket)
  {
   if(OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
     {
      if(OrderType() != OP_SELLSTOP || OrderTicket() != ticket)
         return false; // Not a buy stop order or not the specified ticket

      double openPrice = OrderOpenPrice();
      double currentAsk = SymbolInfoDouble(Symbol(), SYMBOL_ASK);

      if(currentAsk >= openPrice)
        {
         Print(__LINE__, ", Function: ", __FUNCTION__, ", SHO filled for ticket ", ticket);
         return true;
        }
     }
   return false;
  }

//+------------------------------------------------------------------+
//|  Change chart background color if spread is too wide             |
//+------------------------------------------------------------------+
void ChangeBackgroundSpreadTooWide()
  {
   if(SpreadOk)
     {
      // Chart background color default Black
      ChartSetInteger(0, CHART_COLOR_BACKGROUND, clrBlack);
     }
   else
     {
      // Set the background color to Gray when Spread is too wide.
      ChartSetInteger(0, CHART_COLOR_BACKGROUND, clrMistyRose);
      ChartSetInteger(0, CHART_COLOR_FOREGROUND, clrBlack);
     }
  }
//+------------------------------------------------------------------+
//|  Change chart background color if spread between Supp and Res is less than 10 pips.                                |
//+------------------------------------------------------------------+
void ChangeBackgroundSuppRes()
  {
   if((highestHigh - lowestLow) > (RangeSeparation * pips))
     {
      // Chart background color default Black
      ChartSetInteger(0, CHART_COLOR_BACKGROUND, clrBlack);
     }
   else
     {
      // Set the background color to Gray when range is too tight.
      ChartSetInteger(0, CHART_COLOR_BACKGROUND, clrDimGray);
     }
  }
//+------------------------------------------------------------------+
//|      Draw Support and Resistance                                 |
//+------------------------------------------------------------------+
void DrawSuppRes()
  {
// ### Resistance Level ###
// Sell the Resistance Bounce. If the price is at the highest high of the last 40 D1 bars.
   highestHigh = GetHighestHigh(SuppResCalcBars);
// Create a unique name for the line
   string highLineName = "HighestHighLine";
// Check if the line already exists and delete it if it does
   if(ObjectFind(0, highLineName) == 0)
     {
      ObjectDelete(0, highLineName);
     }
// Draw the line at the highest high level
   ObjectCreate(0, highLineName, OBJ_HLINE, 0, 0, highestHigh);
   ObjectSetInteger(0, highLineName, OBJPROP_WIDTH, 4);
   ObjectSetInteger(0, highLineName, OBJPROP_COLOR, clrMagenta);

// ### Support Level ###
// Buy the Support Bounce. If the price is at the lowest low of the last 40 D1 bars.
   lowestLow = GetLowestLow(SuppResCalcBars);
// Create a unique name for the line
   string lowLineName = "LowestLowLine";
// Check if the line already exists and delete it if it does
   if(ObjectFind(0, lowLineName) == 0)
     {
      ObjectDelete(0, lowLineName);
     }
// Draw the line at the lowest Low level
   ObjectCreate(0, lowLineName, OBJ_HLINE, 0, 0, lowestLow);
   ObjectSetInteger(0, lowLineName, OBJPROP_WIDTH, 4);
   ObjectSetInteger(0, lowLineName, OBJPROP_COLOR, clrDeepSkyBlue);
  }
//+------------------------------------------------------------------+
//|   Display Bid Ask Spread                                         |
//+------------------------------------------------------------------+
void DisplayBidAskSpread()
  {
   double bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
   double ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);

   string text = "Bid: " + DoubleToString(bid, _Digits) + "\n" +
                 "  Ask: " + DoubleToString(ask, _Digits) +
                 " Spread: " + DoubleToStr((ask - bid), _Digits) ;

// Delete the previous object if it exists
   ObjectDelete("BidAskDisplay");

// Draw text on the chart at the top middle
   long chartWidth = ChartGetInteger(0, CHART_WIDTH_IN_PIXELS);
   long x = chartWidth / 2;
   int y = ChartPriceOnDropped();

// Draw text on the chart
   ObjectCreate("BidAskDisplay", OBJ_TEXT, 0, Time[40], (GetHighestHighForBidAskDisplay() + (5 * pips)), 0);
   ObjectSetInteger(0, "BidAskDisplay", OBJPROP_XDISTANCE, x);
   ObjectSetInteger(0, "BidAskDisplay", OBJPROP_YDISTANCE, y);
   ObjectSetText("BidAskDisplay", text, fontSize, "Arial", clrBlue);
  }

//+------------------------------------------------------------------+
//|   Initial Buy Trade Profit and Loss                              |
//+------------------------------------------------------------------+
double IBOPL(int ticket)
  {
   double CumPL = 0.0;
   if(OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
     {
      CumPL += OrderProfit();
     }
   else
     {
      Print(__LINE__, ", Function: ", __FUNCTION__, ", Failed to select IBO ticket. ", ErrorDescription(GetLastError()));
     }
   NormalizeDouble(CumPL, 2);
   return(CumPL);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string SmartHedgeStatus()
  {
   string Message = " ";
   if(TotalOpenIBO() > 0)
     {
      double IBTPL = IBOPL(IBOTicket);
      if(IBTPL > 0.0)
        {
         Message = ("Initial Buy Trade PL is: " + DoubleToStr(IBTPL, 2) + ", Awaiting Profit Target Hit.");
        }
      else
        {
         Message = ("Initial Buy Trade PL is: " + DoubleToStr(IBTPL, 2) + ", In TIBO MODE. Protective Hedge is (add tiggered / not triggered).");
        }
     }
   return(Message);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double ReportISOFinalProfit(double finalProfit)
  {
// function is called localy in the monitor initial buy function.
// it update the global variable and is done.
   return(finalProfit);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double ReportIBOFinalProfit(double finalProfit)
  {
// function is called localy in the monitor initial buy function.
// it update the global variable and is done.
   return(finalProfit);
  }
//+------------------------------------------------------------------+
//| Function to display current bar time in comments                 |
//+------------------------------------------------------------------+
string ShowCurrentBarTime()
  {
   datetime currentBarTime = Time[0]; // Get the time of the current bar
   string commentText = "Current bar time: " + TimeToString(currentBarTime, TIME_DATE | TIME_MINUTES); // Format the comment text

// Draw the comment on the chart
   return(commentText);
  }

//+------------------------------------------------------------------+
//|   Reset ISO Ticket Number variable.                              |
//+------------------------------------------------------------------+
void ResetISOTicketNumberVar()
  {
   ISOTicket = 0;
   Print(__LINE__, ", Function: ", __FUNCTION__, ", Reset ISO ticket number variable. ");
  }

//+------------------------------------------------------------------+
//|   Reset IBO Ticket Number variable.                              |
//+------------------------------------------------------------------+
void ResetIBOTicketNumberVar()
  {
   IBOTicket = 0;
   Print(__LINE__, ", Function: ", __FUNCTION__, ", Reset IBO ticket number variable. ");
  }
//+------------------------------------------------------------------+
//| Function to close pending SHO                                    |
//+------------------------------------------------------------------+
void DeleteSHO(int ticket)
  {
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
        {
         if(OrderMagicNumber() == hedgemagic)
           {
            if(OrderType() == OP_SELLSTOP)
              {
               if(!OrderDelete(OrderTicket(), clrRed)) // Delete pending SHO.
                 {
                  Print(__LINE__, ", Function: ", __FUNCTION__, ", Could not DELETE pending SHO ", ErrorDescription(GetLastError()));
                 }
               else
                 {
                  // ok to reset SHO ticket number.
                  SHOTicket = 0;
                  Print(__LINE__, ", Function: ", __FUNCTION__, ", SHO Deleted. SHO Ticket NUmber reset to : ", IntegerToString(SHOTicket));
                 }
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+
//| Function to close BHO pending orders                        |
//+------------------------------------------------------------------+
void DeleteBHO(int ticket)
  {
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
        {
         if(OrderMagicNumber() == hedgemagic)
           {
            if(OrderType() == OP_BUYSTOP)
              {
               if(!OrderDelete(ticket, clrRed)) // Delete pending BHO Order
                 {
                  Print(__LINE__, ", Function: ", __FUNCTION__, ", Could not close pending BHO orders ", ErrorDescription(GetLastError()));
                 }
               else
                 {
                  // ok to reset BHO order ticket number.
                  BHOTicket = 0;
                  Print(__LINE__, ", Function: ", __FUNCTION__, ", BHO Deleted. BHO Ticket Number reset to : ", IntegerToString(BHOTicket));
                 }
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+
//| Function to monitor ISO SmartHedgeStatus                     |
//+------------------------------------------------------------------+
//Need ISO trade ticket. // need function to apply profit.
//need to delete pending orders. Resets ISOTicket variable.
bool MonitorISOClosure(int ticket)
  {
   double FinalProfit = OrderProfit();
   bool tradeClosed = false;
// Wait for the trade to close
   if(OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
     {
      if(OrderMagicNumber() == magic)
        {
         // Check if the trade was closed
         if(OrderCloseTime() > 0)
           {
            // Get the final profit
            FinalProfit = OrderProfit();
            ReportISOFinalProfit(FinalProfit);
            Print(__LINE__, ", Function: ", __FUNCTION__, ",ISO closed! Profit: ", FinalProfit, " USD");
            // Reset ISO Ticket number storage variable.
            tradeClosed = true;
            ResetISOTicketNumberVar();
           }
         else
           {
            tradeClosed = false;
            //Print(__LINE__, ", Function: ", __FUNCTION__, ",ISO is still open.");
           }
        }
     }
   return(tradeClosed);
  }
//+------------------------------------------------------------------+
//| Function to monitor Initial Buy Trade SmartHedgeStatus                     |
//+------------------------------------------------------------------+
// needx inital Buy trade ticket. // need function to apply profit.
//need to delete pending orders. Resets IBOTicket variable.
bool MonitorIBOClosure(int ticket)
  {
   double FinalProfit = OrderProfit();
   bool tradeClosed = false;
// Check if the Initial Buy trade closed.
   if(OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
     {
      if(OrderMagicNumber() == magic)
        {
         // Check if the trade was closed
         if(OrderCloseTime() > 0)
           {
            // Get the final profit
            FinalProfit = OrderProfit();
            ReportIBOFinalProfit(FinalProfit);
            Print(__LINE__, ", Function: ", __FUNCTION__, ",Initial Buy Trade closed! Profit: ", FinalProfit, " USD");
            // Reset Initial Buy Trade Ticket number storage variable.
            ResetIBOTicketNumberVar();
            tradeClosed = true;
           }
         else
           {
            tradeClosed = false;
            //Print(__LINE__, ", Function: ", __FUNCTION__, ",Initial Buy Trade is still open.");
           }
        }
     }
   return(tradeClosed);
  }
////+------------------------------------------------------------------+
////|   Reset IBO Tp due to Order Open Price above Highest High.       |
////+------------------------------------------------------------------+
//void ResetIBOTp(int IBOTicket)
//  {
//   int err = 0;
//   if(OrderSelect(IBOTicket, SELECT_BY_TICKET, MODE_TRADES))
//     {
//      if(OrderModify(IBOTicket, OrderOpenPrice(), 0, (OrderOpenPrice() + InitialOrderTp * pips), 0, clrAliceBlue))
//        {
//         Print(__LINE__, ", Function: ", __FUNCTION__, ", Completed Reset of IBO TP Ticket ", string(IBOTicket));
//        }
//      else
//        {
//         err = GetLastError();
//         Print(__LINE__, ", Function: ", __FUNCTION__, "Encountered an error during modification!" + (string)err + " " + ErrorDescription(err));
//        }
//      Print(__LINE__, ", "__FUNCTION__, ", Failed to select order ", GetLastError());
//     }
//  }
//+------------------------------------------------------------------+
//| Function to check if an IBO Open price is above the
//| current Highest High resistance point.
//+------------------------------------------------------------------+
//void ResetIBOTakeProfitOnce(int orderTicket, double newTakeProfit)
//  {
//// this means that there is a slim chance of making profit. Reset Order Tp.
//// Order will eventually be closed by reason of roll off trimming.
//// Check if the order ticket is valid
//   if(OrderSelect(orderTicket, SELECT_BY_TICKET, MODE_TRADES) == false)
//     {
//      Print("Invalid order ticket");
//      return;
//     }
//
//// Check if the order type is BUY or SELL
//   if(OrderType() != OP_BUY)
//     {
//      Print("Invalid order type");
//      return;
//     }
//
//// Check if the order's comment already indicates that take profit has been reset
//   string comment = OrderComment();
//   if(StringFind(comment, "TP_RESET") != -1)
//     {
//      Print("Take profit already reset for this order");
//      return;
//     }
//
//// Reset take profit
//   bool result = OrderModify(orderTicket, OrderOpenPrice(), newTakeProfit, 0, 0, clrBlue);
//   if(result)
//     {
//      // Append the flag to the order's comment to indicate that take profit has been reset
//      comment = "TP_RESET";
//      OrderModify(orderTicket, OrderOpenPrice(), newTakeProfit, OrderStopLoss(), 0, clrNONE, 0, comment);
//      Print("Take profit reset successfully");
//     }
//   else
//     {
//      Print("Failed to reset take profit");
//     }
//  }
//

//+------------------------------------------------------------------+
//|  Ask Less than Lowest Low - Offset Test                          |
//+------------------------------------------------------------------+
bool AskLessThanLowestLow()
  {
   bool LowestLowTest = false;
   if(Ask <= (lowestLow + (OffsetToIncreaseOddsOfGettingAFill * pips)))
     {
      LowestLowTest = true;
      //Print(__LINE__, ", Ask is less than Lowest Low.");
     }
   else
     {
      LowestLowTest = false;
     }
   return(LowestLowTest);
  }
//+------------------------------------------------------------------+
//|  Bid greater than Highest High - Offset Test                     |
//+------------------------------------------------------------------+
bool BidGrtrHH()
  {
   bool HighestHighTest = false;
   if(Bid >= (highestHigh - (OffsetToIncreaseOddsOfGettingAFill * pips)))
     {
      HighestHighTest = true;
      //Print(__LINE__, ", Bid Greater than Highest High");
     }
   else
     {
      HighestHighTest = false;
     }
   return(HighestHighTest);
  }

//+------------------------------------------------------------------+
//|   Send Pending BHO                                               |
//+------------------------------------------------------------------+
bool SendBHO(double price, double lotSize, int slippage, double stopLoss, double takeProfit, string comment)
  {
   int ticket;

// Normalize the price, stop loss, and take profit values to the correct number of digits
   double normalizedPrice = NormalizeDouble(price, Digits);
   double normalizedTakeProfit = NormalizeDouble(takeProfit, Digits);

// Send the pending BHO
   ticket = OrderSend(Symbol(), OP_BUYSTOP, lotSize, normalizedPrice, slippage, 0.0, normalizedTakeProfit, comment, hedgemagic, 0, clrBlue);
   Sleep(3000);
// Check if the order was sent successfully
   if(ticket < 0)
     {
      // If the order failed, print the error message
      Print(__LINE__, ", Function: ", __FUNCTION__, ", Error sending BHO order: ", ErrorDescription(GetLastError()));
      return false;
     }
   else
     {
      BHOTicket = ticket;
      bSendBHO = false;
      // If the order was successful, print the success message
      Print(__LINE__, ", Function: ", __FUNCTION__, ", SmartHedge_v2p7 BHO sent successfully. Ticket number: ", ticket, ". SendBHO lag reset to ", string(bSendBHO));
      return true;
     }
  }

//+------------------------------------------------------------------+
//|   Send Pending SHO                                               |
//+------------------------------------------------------------------+
bool SendSHO(double price, double lotSize, int slippage, double stopLoss, double takeProfit, string comment)
  {
   int ticket;

// Normalize the price, stop loss, and take profit values to the correct number of digits
   double normalizedPrice = NormalizeDouble(price, Digits);
   double normalizedTakeProfit = NormalizeDouble(takeProfit, Digits);

// Send the pending SHO
   ticket = OrderSend(Symbol(), OP_SELLSTOP, lotSize, normalizedPrice, slippage, 0.0, normalizedTakeProfit, comment, hedgemagic, 0, clrBlue);
   Sleep(3000);
// Check if the order was sent successfully
   if(ticket < 0)
     {
      // If the order failed, print the error message
      Print(__LINE__, ", Function: ", __FUNCTION__, ", Error sending SHO order: ", ErrorDescription(GetLastError()));
      return false;
     }
   else
     {
      SHOTicket = ticket;
      bSendSHO = false;
      // If the order was successful, print the success message
      Print(__LINE__, ", Function: ", __FUNCTION__, ", SmartHedge_v2p7 SHO sent successfully. Ticket number: ", ticket, ". SendSHO Flag reset to ", string(bSendSHO));
      return true;
     }
  }
//+------------------------------------------------------------------+
//|   IBO Modify Take Profit                                         |
//+------------------------------------------------------------------+
void IBOTakeProfitModifyCheck()
  {
   int err = 0;
   double sl = 0.0;
   double tp = 0.0;
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderMagicNumber() == magic)
           {
            if(OrderType() == OP_BUY)
              {
               tp = NormalizeDouble(highestHigh, _Digits) - (OffsetToIncreaseOddsOfGettingAFill * pips);
               if((tp < OrderTakeProfit()) && (tp > OrderOpenPrice()))
                 {
                  if(!OrderModify(OrderTicket(), OrderOpenPrice(), sl, tp, 0, clrWhite))
                    {
                     err = GetLastError();
                     Print(__LINE__, ", Function: ", __FUNCTION__, "Encountered an error during IBO TP modification!" + (string)err + " " + ErrorDescription(err));
                    }
                  else
                    {
                     Print(__LINE__, ", Function: ", __FUNCTION__, ", IBO TP Modified, new tp ", DoubleToStr(OrderTakeProfit(), _Digits));
                    }
                 }
              }
           }
        }
      //Print(__LINE__, ", Function: ", __FUNCTION__, ", Error selecting index. ", ErrorDescription(GetLastError()));
     }
  }

//+------------------------------------------------------------------+
//|   Sell Order Modify Take Profit                                  |
//+------------------------------------------------------------------+
void ISOTakeProfitModifyCheck()
  {
   int err = 0;
   double sl = 0.0;
   double tp = 0.0;

   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderMagicNumber() == magic)
           {
            if(OrderType() == OP_SELL)
              {
               tp = NormalizeDouble(lowestLow, _Digits) + (OffsetToIncreaseOddsOfGettingAFill * pips);
               // Change the take profit if the lowest low DID move up, AND the tp is less than the Order Open Price.
               if((tp > OrderTakeProfit()) && (tp < OrderOpenPrice()))
                 {
                  if(!OrderModify(OrderTicket(), OrderOpenPrice(), sl, tp, 0, clrWhite))
                    {
                     err = GetLastError();
                     Print(__LINE__, ", Function: ", __FUNCTION__, "Encountered an error during ISO TP modification!" + (string)err + " " + ErrorDescription(err));
                    }
                  else
                    {
                     Print(__LINE__, ", Function: ", __FUNCTION__, ", ISO TP Modified, new tp ", DoubleToStr(OrderTakeProfit(), _Digits));
                    }
                 }
              }
           }
        }
      // Print(__LINE__, ", Function: ", __FUNCTION__, ", Error selecting ticket. ", ErrorDescription(GetLastError()));
     }
  }
//+------------------------------------------------------------------+
//| Function to find the highest high of the last N Bars for Dispay  |
//+------------------------------------------------------------------+
double GetHighestHighForBidAskDisplay()
  {
   int periods = 200;
   double dhighestHigh = -DBL_MAX;
// Loop through the last N bars of the current period.
   for(int i = 0; i < periods; i++)
     {
      double high = iHigh(NULL, PERIOD_CURRENT, i);
      if(high > dhighestHigh)
        {
         dhighestHigh = high;
        }
     }
   return (dhighestHigh);
  }
//+------------------------------------------------------------------+
//| Function to find the highest high of the last N D1 bars          |
//+------------------------------------------------------------------+
double GetHighestHigh(int periods)
  {
   double dhighestHigh = -DBL_MAX;
// Loop through the last N bars of the current period.
   for(int i = 0; i < periods; i++)
     {
      double high = iHigh(NULL, PERIOD_CURRENT, i);
      if(high > dhighestHigh)
        {
         dhighestHigh = high;
        }
     }
   return (dhighestHigh);
  }
//+------------------------------------------------------------------+
//| Function to find the Lowest low of the last N D1 bars            |
//+------------------------------------------------------------------+
double GetLowestLow(int periods)
  {
   double dlowestLow = DBL_MAX;
// Loop through the last N bars of the current period.
   for(int i = 0; i < periods; i++)
     {
      double low = iLow(NULL, PERIOD_CURRENT, i);
      if(low <  dlowestLow)
        {
         dlowestLow = low;
        }
     }
   return dlowestLow;
  }

//+------------------------------------------------------------------+
//|       ISO TRADE TRIGGER FUNCTION                                 |
//+------------------------------------------------------------------+
void CheckForISOSignal()
  {
   if(ISO_OK)
     {
      EnterISO(OP_SELL);
     }
  }

//+------------------------------------------------------------------+
//|       IBO TRADE TRIGGER FUNCTION                                 |
//+------------------------------------------------------------------+
void CheckForIBOSignal()
  {
   if(IBO_OK)
     {
      EnterIBO(OP_BUY);
     }
  }

//+------------------------------------------------------------------+
//|     SELL TRADE PLACING FUNCTION                                  |
//+------------------------------------------------------------------+
void EnterISO(int type)
  {

   int err = 0;
   double price = Bid;
   double      sl = 0.0;
   double      tp = NormalizeDouble(lowestLow + (OffsetToIncreaseOddsOfGettingAFill * pips), _Digits); //NormalizeDouble(lowestLow,_Digits),
   double    lotsize = LS1;
   bSendBHO = false;//Set a boolean flag to send a Protective BHO.


//----
   int ticket = OrderSend(Symbol(), type, lotsize, price, 30, 0, tp, "ISO, SmartHedge_v2p7 Initial Order", magic, 0, clrMagenta);
   Sleep(3000);
   if(ticket > 0)
     {
      ISOTicket = ticket; // Needed to reset the take profit of the ISO order.
      TradeCounter++;
      ISOCounter++;
      bSendBHO = true; // Tells the program to open a BHO to protect this trade.
      //This will be reset in the SendBHO function.
     }
   else
     {
      //in case it fails to place the order and send us back a ticket number.
      err = GetLastError();
      Print(__LINE__, " ", __FUNCTION__, "  Encountered an error during ISO placement!" + (string)err + " " + ErrorDescription(err));
      if(err == ERR_TRADE_NOT_ALLOWED)
         MessageBox("You can not place a trade because \"Allow Live Trading\" is not checked in your options. Please check the \"Allow Live Trading\" Box!", "Check Your Settings!");
     }
  }

//+------------------------------------------------------------------+
//|     BUY TRADE PLACING FUNCTION                                   |
//+------------------------------------------------------------------+
void EnterIBO(int type)
  {

   int err = 0;
   double price = Ask;
   double     sl = 0.0;
   double      tp = NormalizeDouble(highestHigh - (OffsetToIncreaseOddsOfGettingAFill * pips), _Digits);
   double     lotsize = LS1;
   bSendSHO = false; // This will be reset in the SendSHO function.

//----
   int ticket = OrderSend(Symbol(), type, lotsize, price, 30, 0, tp, "BUY, SmartHedge_v2p7 Initial Order", magic, 0, clrLightBlue);
   Sleep(3000);
   if(ticket > 0)
     {
      IBOTicket = ticket;
      TradeCounter++;
      IBOCounter++;
      bSendSHO = true; // This will be reset in the SendSHO function.
     }
   else
     {
      //in case it fails to place the order and send us back a ticket number.
      err = GetLastError();
      Print(__LINE__, " ", __FUNCTION__, "  Encountered an error during IBO placement!" + (string)err + " " + ErrorDescription(err));
      if(err == ERR_TRADE_NOT_ALLOWED)
         MessageBox("You can not place a trade because \"Allow Live Trading\" is not checked in your options. Please check the \"Allow Live Trading\" Box!", "Check Your Settings!");
     }
  }

//+------------------------------------------------------------------+
//|Generate a Magic Number                                           |
//+------------------------------------------------------------------+
int MagicNumberGenerator()
  {
   string mySymbol = StringSubstr(_Symbol, 0, 6);
   int pairNumber = 0;
   int GeneratedNumber = 0;
   if(mySymbol == "AUDCAD")
      pairNumber = 1;
   else
      if(mySymbol == "AUDCHF")
         pairNumber = 2;
      else
         if(mySymbol == "AUDJPY")
            pairNumber = 3;
         else
            if(mySymbol == "AUDNZD")
               pairNumber = 4;
            else
               if(mySymbol == "AUDUSD")
                  pairNumber = 5;
               else
                  if(mySymbol == "CADCHF")
                     pairNumber = 6;
                  else
                     if(mySymbol == "CADJPY")
                        pairNumber = 7;
                     else
                        if(mySymbol == "CHFJPY")
                           pairNumber = 8;
                        else
                           if(mySymbol == "EURAUD")
                              pairNumber = 9;
                           else
                              if(mySymbol == "EURCAD")
                                 pairNumber = 10;
                              else
                                 if(mySymbol == "EURCHF")
                                    pairNumber = 11;
                                 else
                                    if(mySymbol == "EURGBP")
                                       pairNumber = 12;
                                    else
                                       if(mySymbol == "EURJPY")
                                          pairNumber = 13;
                                       else
                                          if(mySymbol == "EURNZD")
                                             pairNumber = 14;
                                          else
                                             if(mySymbol == "EURUSD")
                                                pairNumber = 15;
                                             else
                                                if(mySymbol == "GBPAUD")
                                                   pairNumber = 16;
                                                else
                                                   if(mySymbol == "GBPCAD")
                                                      pairNumber = 17;
                                                   else
                                                      if(mySymbol == "GBPCHF")
                                                         pairNumber = 18;
                                                      else
                                                         if(mySymbol == "GBPJPY")
                                                            pairNumber = 19;
                                                         else
                                                            if(mySymbol == "GBPNZD")
                                                               pairNumber = 20;
                                                            else
                                                               if(mySymbol == "GBPUSD")
                                                                  pairNumber = 21;
                                                               else
                                                                  if(mySymbol == "NZDCAD")
                                                                     pairNumber = 22;
                                                                  else
                                                                     if(mySymbol == "NZDJPY")
                                                                        pairNumber = 23;
                                                                     else
                                                                        if(mySymbol == "NZDCHF")
                                                                           pairNumber = 24;
                                                                        else
                                                                           if(mySymbol == "NZDUSD")
                                                                              pairNumber = 25;
                                                                           else
                                                                              if(mySymbol == "USDCAD")
                                                                                 pairNumber = 26;
                                                                              else
                                                                                 if(mySymbol == "USDCHF")
                                                                                    pairNumber = 27;
                                                                                 else
                                                                                    if(mySymbol == "USDJPY")
                                                                                       pairNumber = 28;
   GeneratedNumber = MagicSeed + (pairNumber * 1734);
   return(GeneratedNumber);
  }
//+------------------------------------------------------------------+
//Total of ALL orders placed by this expert.
//+------------------------------------------------------------------+
int TotalOpenOrders()
  {
   int total = 0;
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderMagicNumber() == magic)
           {
            total++;
           }
         Print(__LINE__, ", "__FUNCTION__, ", Failed to select order ", GetLastError());
        }
     }
   return (total);
  }
//+------------------------------------------------------------------+
//Total of all ISOs place by this expert.
//+------------------------------------------------------------------+
int TotalOpenISO()
  {
   int total = 0;
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderMagicNumber() == magic)
            if(OrderType() == OP_SELL)
               total++;
        }
      else
         Print(__LINE__, ", "__FUNCTION__, ", Failed to select ISO order ", i, " ", GetLastError());
     }
   return (total);
  }

//+------------------------------------------------------------------+
//Total of all SELL lots place by this expert.
//+------------------------------------------------------------------+
double TotalOpenISOLots()
  {
   double total = 0.0;
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderMagicNumber() == magic)
            if(OrderType() == OP_SELL)
               total += OrderLots();
        }
      else
         Print(__LINE__, ", "__FUNCTION__, ", Failed to select ISO order ", i, " ", GetLastError());
     }
   NormalizeDouble(total, 2);
   return (total);
  }

//+------------------------------------------------------------------+
//Total of all Hedge SELL lots place by this expert.
//+------------------------------------------------------------------+
double TotalOpenSHOLots()
  {
   double total = 0.0;
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderMagicNumber() == hedgemagic)
            if(OrderType() == OP_SELLSTOP)
               total += OrderLots();
        }
      else
         Print(__LINE__, ", "__FUNCTION__, ", Failed to select SHO order ", i, " ", GetLastError());
     }
   NormalizeDouble(total, 2);
   return (total);
  }

//+------------------------------------------------------------------+
//|   CalculateThe Open Profit And Loss Of This Currency Pair        |
//+------------------------------------------------------------------+
double OpenPL()
  {
   double       CumPL = 0.0;
   for(int cnt = 0; cnt < OrdersTotal(); cnt++)
     {
      if(OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES))
         if(OrderSymbol() == _Symbol && (OrderMagicNumber() == magic || OrderMagicNumber() == hedgemagic))
           {
            CumPL += OrderProfit();
           }
     }
   NormalizeDouble(CumPL, 2);
   return(CumPL);
  }

//+------------------------------------------------------------------+
//|   Close All Orders                                               |
//+------------------------------------------------------------------+
void CloseAllOrders()
  {
   int totalOrders = OrdersTotal();

// Iterate through all open orders
   for(int i = totalOrders - 1; i >= 0; i--)
     {
      if(OrderSelect(i, SELECT_BY_POS) == false)
         Print(__LINE__, " Failed to select order ", i);
      continue;
     }

// Check if the order is open
   if(OrderType() == OP_BUY || OrderType() == OP_SELL)
     {
      if(OrderMagicNumber() == magic)
        {
         // Close the order
         bool result = OrderClose(OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), 10, clrBlueViolet);
         if(result == false)
           {
            Print(__LINE__, " Failed to close order: ", GetLastError());
           }
        }
     }
  }
//+------------------------------------------------------------------+
//Total of all BUY lots placed by this expert.
//+------------------------------------------------------------------+
double TotalOpenIBOLots()
  {
   double total = 0.0;
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderMagicNumber() == magic)
            if(OrderType() == OP_BUY)
               total += OrderLots();
        }
      else
         Print(__FUNCTION__, "Failed to select order", GetLastError());
     }
   NormalizeDouble(total, 2);
   return (total);
  }
//+------------------------------------------------------------------+
//Total of all Hedge BUY lots placed by this expert.
//+------------------------------------------------------------------+
double TotalOpenBHOLots()
  {
   double total = 0.0;
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderMagicNumber() == hedgemagic)
            if(OrderType() == OP_BUYSTOP)
               total += OrderLots();
        }
      else
         Print(__FUNCTION__, "Failed to select order", GetLastError());
     }
   NormalizeDouble(total, 2);
   return (total);
  }
//+------------------------------------------------------------------+
//Total of all IBOs placed by this expert.
//+------------------------------------------------------------------+
int TotalOpenIBO()
  {
   int total = 0;
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderMagicNumber() == magic)
            if(OrderType() == OP_BUY)
               total++;
        }
      else
         Print(__FUNCTION__, "Failed to select order", GetLastError());
     }
   return (total);
  }
//+------------------------------------------------------------------+
//| Max Acceptable Spread                                            |
//+------------------------------------------------------------------+
double MaxAcceptableSpread() // https://www.investopedia.com/articles/forex/10/spread-pip-potential-pairs-day-trading.asp
// EUR/USD   1.5 , GBP/USD 1.7 , USD/CAD  2.0 , USD/JPY  1.4,  EUR/JPY  1.8,  EUR/CHF  1.5
  {
   string mySymbol = StringSubstr(_Symbol, 0, 6);
   double maxSpread = 0.0;
   if(mySymbol == "AUDCAD")
      maxSpread = 2.8;
   else
      if(mySymbol == "AUDCHF")
         maxSpread = 3.5;
      else
         if(mySymbol == "AUDJPY")
            maxSpread = 3.2;
         else
            if(mySymbol == "AUDNZD")
               maxSpread = 3.8;
            else
               if(mySymbol == "AUDUSD")
                  maxSpread = 2.1;
               else
                  if(mySymbol == "CADCHF")
                     maxSpread = 4.0;
                  else
                     if(mySymbol == "CADJPY")
                        maxSpread = 3.5;
                     else
                        if(mySymbol == "CHFJPY")
                           maxSpread = 3.9;
                        else
                           if(mySymbol == "EURAUD")
                              maxSpread = 4.1;
                           else
                              if(mySymbol == "EURCAD")
                                 maxSpread = 3.4;
                              else
                                 if(mySymbol == "EURCHF")
                                    maxSpread = 2.8;
                                 else
                                    if(mySymbol == "EURGBP")
                                       maxSpread = 2.0;
                                    else
                                       if(mySymbol == "EURJPY")
                                          maxSpread = 2.0;
                                       else
                                          if(mySymbol == "EURNZD")
                                             maxSpread = 8.4;
                                          else
                                             if(mySymbol == "EURUSD")
                                                maxSpread = 2.0;
                                             else
                                                if(mySymbol == "GBPAUD")
                                                   maxSpread = 5.6;
                                                else
                                                   if(mySymbol == "GBPCAD")
                                                      maxSpread = 5.1;
                                                   else
                                                      if(mySymbol == "GBPCHF")
                                                         maxSpread = 3.7;
                                                      else
                                                         if(mySymbol == "GBPJPY")
                                                            maxSpread = 4.4;
                                                         else
                                                            if(mySymbol == "GBPNZD")
                                                               maxSpread = 5.8;
                                                            else
                                                               if(mySymbol == "GBPUSD")
                                                                  maxSpread = 2.5;
                                                               else
                                                                  if(mySymbol == "NZDCAD")
                                                                     maxSpread = 7.5;
                                                                  else
                                                                     if(mySymbol == "NZDJPY")
                                                                        maxSpread = 3.2;
                                                                     else
                                                                        if(mySymbol == "NZDCHF")
                                                                           maxSpread = 5.8;
                                                                        else
                                                                           if(mySymbol == "NZDUSD")
                                                                              maxSpread = 3.2;
                                                                           else
                                                                              if(mySymbol == "USDCAD")
                                                                                 maxSpread = 3.0;
                                                                              else
                                                                                 if(mySymbol == "USDCHF")
                                                                                    maxSpread = 2.4;
                                                                                 else
                                                                                    if(mySymbol == "USDJPY")
                                                                                       maxSpread = 2.0;
                                                                                    else
                                                                                       if(mySymbol == "USDMXN")
                                                                                          maxSpread = 65.0;

   return(maxSpread * pips);
  }


//+------------------------------------------------------------------+
//| Check if Spread is acceptable                                    |
//+------------------------------------------------------------------+
bool SpreadIsAcceptable()
// Uses the Max Acceptable Spread If Ladder to check max spread allowed.
  {
   bool SpreadBueno = false;
   if(!IsTesting())   // Only use this booleen if not using the strategy tester.
     {
      if(currSpread > MaxAcceptableSpread())
        {
         SpreadBueno = false;
        }
      else
        {
         SpreadBueno = true;
        }
     }
   else
     {
      SpreadBueno = true; // Always true if using the Strategy Tester.
     }
   return (SpreadBueno);
  }

// Function to delete all objects on a chart
void DeleteAllObjects()
  {
// Get the total number of objects on the chart
   int totalObjects = ObjectsTotal();

// Loop through all objects and delete them
   for(int i = totalObjects - 1; i >= 0; i--)
     {
      string objectName = ObjectName(i);
      ObjectDelete(objectName);
     }

// Print a message to the Experts tab
   Print(__LINE__, ", Function: ", __FUNCTION__, "All objects on the chart have been deleted.");
  }
//+------------------------------------------------------------------+
//| Function to trail stop loss of open positions                    |
//+------------------------------------------------------------------+
void TrailStopLoss()
  {
   for(int i = 0; i < OrdersTotal(); i++)
     {
      if(OrderSelect(i, SELECT_BY_POS) == true)
        {
         if(OrderSymbol() != Symbol())
            continue; // Skip orders for other symbols

         if(OrderType() == OP_BUY && OrderMagicNumber() == magic)
           {
            double currentStopLoss = NormalizeDouble(OrderStopLoss(), Digits);
            double newStopLoss = NormalizeDouble(Bid - TrailDistance * pips, Digits);

            // If the new stop loss is greater than the current stop loss, modify the stop loss
            if(newStopLoss > currentStopLoss)
              {
               if(!OrderModify(OrderTicket(), OrderOpenPrice(), newStopLoss, OrderTakeProfit(), 0, clrPink))
                 {
                  Print(__LINE__, " Failed to Modify IBO.", GetLastError());
                 }
              }
           }
         else
            if(OrderType() == OP_SELL && OrderMagicNumber() == magic)
              {
               double currentStopLoss = NormalizeDouble(OrderStopLoss(), Digits);
               double newStopLoss = NormalizeDouble(Ask + TrailDistance * pips, Digits);

               // If the new stop loss is less than the current stop loss, modify the stop loss
               if(newStopLoss < currentStopLoss)
                 {
                  if(!OrderModify(OrderTicket(), OrderOpenPrice(), newStopLoss, OrderTakeProfit(), 0, clrPink))
                    {
                     Print(__LINE__, " Failed to Modify ISO.", GetLastError());
                    }
                 }
              }
        }
     }
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+


//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
