//+------------------------------------------------------------------+
//|                                         PortfolioController.mq5  |
//|          Portfolio-level master EA for multi-currency framework  |
//+------------------------------------------------------------------+

#property version     "1.00"
#property strict

//--- Input parameters
input double inp_MaxPortfolioRiskPct  = 2.0;   // Maximum total portfolio risk %
input double inp_MaxLotsPerSymbol     = 5.0;   // Absolute lot ceiling per symbol
input int    inp_TimerIntervalSeconds = 10;    // Portfolio update interval (seconds)
input int    inp_ReadinessTimeoutSecs = 30;    // Startup readiness timeout (seconds)

//--- Global variable name constants
#define GV_READY            "PC_ControllerReady"
#define GV_RISK_BUDGET      "PC_RiskBudgetPct"
#define GV_MAX_LOTS         "PC_MaxLotsPerSymbol"
#define GV_GLOBAL_HALT      "SYS_GlobalHalt"

//--- Tracked symbols (extend as needed)
string g_ManagedSymbols[] = {"EURUSD","GBPUSD","USDJPY","AUDUSD","USDCAD"};
int    g_SymbolCount      = 5;

//--- Runtime state
double g_CurrentEquity    = 0.0;
double g_TotalOpenLots    = 0.0;
bool   g_HaltActive       = false;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Broadcast halt during initialization to block agents
   GlobalVariableSet(GV_GLOBAL_HALT,  1.0);
   GlobalVariableSet(GV_READY,        0.0);
   GlobalVariableSet(GV_RISK_BUDGET,  0.0);
   GlobalVariableSet(GV_MAX_LOTS,     0.0);

//--- Perform initial portfolio state calculation
   if(!UpdatePortfolioState())
     {
      Print("PortfolioController: Initial state update failed. Aborting init.");
      return(INIT_FAILED);
     }

//--- Broadcast valid initial state before releasing halt
   BroadcastPortfolioState();

//--- Release halt and signal readiness to agents
   GlobalVariableSet(GV_GLOBAL_HALT, 0.0);
   GlobalVariableSet(GV_READY,       1.0);

//--- Start periodic update timer
   EventSetTimer(inp_TimerIntervalSeconds);

   Print("PortfolioController: Initialized. Managing ",
         g_SymbolCount, " symbols.");
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Broadcast halt to all agents before shutdown
   GlobalVariableSet(GV_GLOBAL_HALT, 1.0);
   GlobalVariableSet(GV_READY,       0.0);

   EventKillTimer();

   Print("PortfolioController: Deinitialized. Reason code: ", reason);
  }

//+------------------------------------------------------------------+
//| Timer event: periodic portfolio state recalculation              |
//+------------------------------------------------------------------+
void OnTimer()
  {
   if(!UpdatePortfolioState())
     {
      Print("PortfolioController: State update failed on timer cycle.");
      return;
     }

//--- Check portfolio-level halt conditions
   EvaluateHaltConditions();

//--- Broadcast updated state to all agents
   BroadcastPortfolioState();
  }

//+------------------------------------------------------------------+
//| Recalculate portfolio metrics from current account state         |
//+------------------------------------------------------------------+
bool UpdatePortfolioState()
  {
   g_CurrentEquity = AccountInfoDouble(ACCOUNT_EQUITY);

   if(g_CurrentEquity <= 0.0)
     {
      Print("PortfolioController: Invalid equity reading: ", g_CurrentEquity);
      return(false);
     }

//--- Aggregate open lots across all managed symbols
   g_TotalOpenLots = 0.0;

   for(int i = 0; i < g_SymbolCount; i++)
     {
      string sym = g_ManagedSymbols[i];
      string varName = "IA_" + sym + "_OpenLots";

      if(GlobalVariableCheck(varName))
         g_TotalOpenLots += GlobalVariableGet(varName);
     }

   return(true);
  }

//+------------------------------------------------------------------+
//| Evaluate conditions that should trigger a global halt            |
//+------------------------------------------------------------------+
void EvaluateHaltConditions()
  {
   double balance  = AccountInfoDouble(ACCOUNT_BALANCE);
   double equity   = g_CurrentEquity;

//--- Halt if floating drawdown exceeds 3x the configured risk budget
   double floatingDrawdownPct = 0.0;

   if(balance > 0.0)
      floatingDrawdownPct = ((balance - equity) / balance) * 100.0;

   bool haltRequired = (floatingDrawdownPct >= inp_MaxPortfolioRiskPct * 3.0);

   if(haltRequired && !g_HaltActive)
     {
      Print("PortfolioController: Halt condition triggered. Drawdown: ",
            DoubleToString(floatingDrawdownPct, 2), "%");
      g_HaltActive = true;
     }
   else
      if(!haltRequired && g_HaltActive)
        {
         Print("PortfolioController: Halt condition cleared.");
         g_HaltActive = false;
        }
  }

//+------------------------------------------------------------------+
//| Broadcast current portfolio state to shared global variables     |
//+------------------------------------------------------------------+
void BroadcastPortfolioState()
  {
//--- Calculate remaining risk budget percentage
   double committedRiskPct = 0.0;

   if(g_CurrentEquity > 0.0)
      committedRiskPct = (g_TotalOpenLots / inp_MaxLotsPerSymbol)
                         * inp_MaxPortfolioRiskPct;

   double remainingBudgetPct = MathMax(0.0,
                                       inp_MaxPortfolioRiskPct - committedRiskPct);

//--- Write to shared globals
   GlobalVariableSet(GV_RISK_BUDGET, remainingBudgetPct);
   GlobalVariableSet(GV_MAX_LOTS,    inp_MaxLotsPerSymbol);
   GlobalVariableSet(GV_GLOBAL_HALT, g_HaltActive ? 1.0 : 0.0);
  }
//+------------------------------------------------------------------+