//+------------------------------------------------------------------+
//| PortfolioRiskCheck.mq5 - teaching script                         |
//| Prints naive vs correlation-adjusted portfolio risk              |
//+------------------------------------------------------------------+
#property script_show_inputs
input ENUM_TIMEFRAMES TF       = PERIOD_H1;
input int             LookBack = 200;

#define MAXP 30

//+------------------------------------------------------------------+
//| Money per unit of price move, per lot                            |
//+------------------------------------------------------------------+
double MoneyPerPrice(string s)
  {
   double tv=SymbolInfoDouble(s,SYMBOL_TRADE_TICK_VALUE);
   double ts=SymbolInfoDouble(s,SYMBOL_TRADE_TICK_SIZE);
   return (ts>0 ? tv/ts : 0);
  }

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   string sym[MAXP];
   double expo[MAXP];
   int n=0;

//--- 1. collect open positions as signed nominal exposure
   for(int i=0;i<PositionsTotal() && n<MAXP;i++)
     {
      ulong tk=PositionGetTicket(i);
      if(!PositionSelectByTicket(tk))
         continue;
      string s=PositionGetString(POSITION_SYMBOL);
      double vol=PositionGetDouble(POSITION_VOLUME);
      double pr =PositionGetDouble(POSITION_PRICE_CURRENT);
      double sgn=(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY? 1:-1);
      double nom=sgn*vol*MoneyPerPrice(s)*pr;
      int k=-1;
      for(int j=0;j<n;j++)
         if(sym[j]==s)
            k=j;
      if(k<0)
        {
         k=n;
         sym[n]=s;
         expo[n]=0;
         n++;
        }
      expo[k]+=nom;
     }
   if(n<2)
     {
      Print("Need at least 2 open positions.");
      return;
     }

//--- 2. time-aligned log returns for every symbol
   datetime t0[];
   if(CopyTime(sym[0],TF,0,LookBack+1,t0)<LookBack+1)
     { Print("Not enough history."); return; }
   ArraySetAsSeries(t0,true);
   static double ret[MAXP][512];
   int m=LookBack;
   if(m>511)
      m=511;
   for(int s2=0;s2<n;s2++)
      for(int t=0;t<m;t++)
        {
         double a=iClose(sym[s2],TF,iBarShift(sym[s2],TF,t0[t],false));
         double b=iClose(sym[s2],TF,iBarShift(sym[s2],TF,t0[t+1],false));
         ret[s2][t]=(a>0 && b>0 ? MathLog(a/b) : 0);
        }

//--- 3. covariance matrix
   static double mu[MAXP], cov[MAXP][MAXP];
   for(int i=0;i<n;i++)
     {
      double s3=0;
      for(int t=0;t<m;t++)
         s3+=ret[i][t];
      mu[i]=s3/m;
     }
   for(int i=0;i<n;i++)
      for(int j=i;j<n;j++)
        {
         double c=0;
         for(int t=0;t<m;t++)
            c+=(ret[i][t]-mu[i])*(ret[j][t]-mu[j]);
         c/=(m-1);
         cov[i][j]=c;
         cov[j][i]=c;
        }

//--- 4. naive risk vs true portfolio risk
   double naive2=0, pv=0, gross=0;
   for(int i=0;i<n;i++)
      gross+=MathAbs(expo[i]);
   for(int i=0;i<n;i++)
     {
      naive2 += expo[i]*expo[i]*cov[i][i];
      for(int j=0;j<n;j++)
         pv += expo[i]*expo[j]*cov[i][j];
     }
   double barsPerDay = 1440.0/MathMax(1,PeriodSeconds(TF)/60);
   double naive = MathSqrt(MathMax(naive2,0))*MathSqrt(barsPerDay);
   double truev = MathSqrt(MathMax(pv,0))    *MathSqrt(barsPerDay);

   PrintFormat("Positions: %d   Gross exposure: %.0f %s",
               n, gross, AccountInfoString(ACCOUNT_CURRENCY));
   PrintFormat("Naive daily risk (independence assumed): %.2f", naive);
   PrintFormat("TRUE daily risk (correlation included) : %.2f", truev);
   if(naive>0)
      PrintFormat("Hidden factor: your real risk is %.0f%% of the naive number.",
                  100.0*truev/naive);

//--- 5. who is actually driving it
   Print("Risk contribution per symbol:");
   for(int i=0;i<n && pv>0;i++)
     {
      double contr=0;
      for(int j=0;j<n;j++)
         contr += expo[i]*expo[j]*cov[i][j];
      PrintFormat("  %-10s %6.1f%%", sym[i], 100.0*contr/pv);
     }
  }
//+------------------------------------------------------------------+
