//+------------------------------------------------------------------+
//|                                              PortfolioTypes.mqh  |
//|          Shared types, constants and small helpers for the       |
//|          multi-currency portfolio Expert Advisor.                |
//|          Money values are expressed in the deposit currency.     |
//+------------------------------------------------------------------+
#ifndef __PORTFOLIO_TYPES_MQH__
#define __PORTFOLIO_TYPES_MQH__

#define PF_MAX_SYMBOLS   16     // hard cap of the tradable universe
#define PF_EPS           1e-12  // numeric tolerance

//--- direction of a trade / of the persistent trend state
enum ENUM_PF_SIDE
{
   PF_SIDE_NONE  =  0,
   PF_SIDE_LONG  =  1,
   PF_SIDE_SHORT = -1
};

//--- parameters that are identical for every instrument of the universe
struct SPFParams
{
   ENUM_TIMEFRAMES tf_signal;        // bar timeframe used for signals
   ENUM_TIMEFRAMES tf_corr;          // bar timeframe used for correlation
   int             fast_period;      // fast moving average
   int             slow_period;      // slow moving average
   int             atr_period;       // ATR period (stops and volatility)
   int             corr_bars;        // number of returns used by the correlation
   ENUM_MA_METHOD  ma_method;        // moving average smoothing
   bool            use_trend_filter; // require a slope confirmation of the slow MA
};

//--- aggregated exposure of the whole portfolio
struct SPFExposure
{
   double gross;        // sum of absolute notionals
   double net;          // signed notional, long positive
   double open_risk;    // money at risk until the stop losses
   double margin_used;
   int    positions;
};

//--- one position that belongs to this Expert Advisor
struct SPFPosition
{
   ulong  ticket;
   string symbol;
   int    side;         // ENUM_PF_SIDE
   double volume;
   double open_price;
   double sl;
   double tp;
   double notional;     // signed, deposit currency
   double risk_money;   // distance to the stop loss in money, >= 0
   double profit;
   double swap;
};

//--- signed exposure of a single currency
struct SPFCurrencyBucket
{
   string currency;
   double amount;       // signed, deposit currency
};

//--- helpers --------------------------------------------------------

double PFClamp(const double value, const double low, const double high)
{
   if(value < low)  return low;
   if(value > high) return high;
   return value;
}

double PFSafeDiv(const double numerator, const double denominator, const double fallback = 0.0)
{
   if(MathAbs(denominator) <= PF_EPS) return fallback;
   return numerator / denominator;
}

bool PFIsZero(const double value)
{
   return (MathAbs(value) <= PF_EPS);
}

string PFTrim(const string text)
{
   string result = text;
   StringTrimLeft(result);
   StringTrimRight(result);
   return result;
}

string PFSideText(const int side)
{
   if(side == PF_SIDE_LONG)  return "LONG";
   if(side == PF_SIDE_SHORT) return "SHORT";
   return "-";
}

//--- split a "EURUSD, GBPUSD;AUDCAD" style list into unique symbols
int PFParseSymbols(const string list, string &out[])
{
   ArrayResize(out, 0);
   string buffer = list;
   StringReplace(buffer, ";", ",");
   StringReplace(buffer, "\t", ",");
   StringReplace(buffer, "\r", ",");
   StringReplace(buffer, "\n", ",");
   StringReplace(buffer, " ", ",");

   string parts[];
   int total = StringSplit(buffer, ',', parts);
   for(int i = 0; i < total; i++)
   {
      string symbol = PFTrim(parts[i]);
      if(symbol == "") continue;

      bool duplicate = false;
      for(int k = 0; k < ArraySize(out); k++)
      {
         if(StringCompare(out[k], symbol, false) == 0)
         {
            duplicate = true;
            break;
         }
      }
      if(duplicate) continue;

      int size = ArraySize(out);
      if(size >= PF_MAX_SYMBOLS) break;
      ArrayResize(out, size + 1);
      out[size] = symbol;
   }
   return ArraySize(out);
}

#endif // __PORTFOLIO_TYPES_MQH__
//+------------------------------------------------------------------+
