//+------------------------------------------------------------------+
//|                                         EfficiencyStatistics.mqh |
//+------------------------------------------------------------------+
#ifndef EFFICIENCYSTATISTICS_MQH
#define EFFICIENCYSTATISTICS_MQH

#include "TradeExcursionTypes.mqh"

//+---------------------------------------------------------------------+
//| CEfficiencyStatistics                                               |
//| Reduces an array of CTradeExcursion records into the aggregate      |
//| figures the histogram chart needs: a mean efficiency, a set of      |
//| histogram bin counts, and a win/loss/breakeven split. Every method  |
//| here is a pure function over plain data, with no dependency on      |
//| CCanvas or any live account, which is what makes this class directly|
//| testable with synthetic trade records.                              |
//+---------------------------------------------------------------------+
class CEfficiencyStatistics
  {
public:
                     CEfficiencyStatistics(void);
                    ~CEfficiencyStatistics(void);
   bool              ComputeMeanEfficiency(const CTradeExcursion &trades[], int count, double &mean_out) const;
   void              ComputeHistogramBins(const CTradeExcursion &trades[], int count, int bin_count, int &bins_out[]) const;
   void              ComputeWinLossCounts(const CTradeExcursion &trades[], int count,
                                          int &win_count, int &loss_count, int &breakeven_count) const;
  };

//+------------------------------------------------------------------+
//| Constructor                                                      |
//| The statistics helper holds no state between calls, so           |
//| construction performs no work beyond default object creation.    |
//+------------------------------------------------------------------+
CEfficiencyStatistics::CEfficiencyStatistics(void)
  {
  }

//+------------------------------------------------------------------+
//| Destructor                                                       |
//| No resources are owned by this class, so no cleanup is required. |
//+------------------------------------------------------------------+
CEfficiencyStatistics::~CEfficiencyStatistics(void)
  {
  }

//+------------------------------------------------------------------------+
//| ComputeMeanEfficiency                                                  |
//| Averages m_efficiency across every trade whose m_efficiency_defined    |
//| flag is true, skipping any trade with no tick data or no observed      |
//| price movement. Returns false when no trade in the array has a defined |
//| efficiency, rather than reporting a mean of zero that could be mistaken|
//| for a genuinely poor average.                                          |
//+------------------------------------------------------------------------+
bool CEfficiencyStatistics::ComputeMeanEfficiency(const CTradeExcursion &trades[],const int count,double &mean_out) const
  {
   double sum = 0.0;
   int defined_count = 0;
   for(int i = 0; i < count; i++)
     {
      if(trades[i].m_efficiency_defined)
        {
         sum += trades[i].m_efficiency;
         defined_count++;
        }
     }
   if(defined_count <= 0)
     {
      mean_out = 0.0;
      return(false);
     }
   mean_out = sum / defined_count;
   return(true);
  }

//+---------------------------------------------------------------------------+
//| ComputeHistogramBins                                                      |
//| Distributes every trade's efficiency value, from 0.0 to 1.0, into         |
//| bin_count equal-width bins. A trade with no defined efficiency is         |
//| skipped entirely rather than being folded into bin zero, which would      |
//| otherwise silently overweight the low end of the distribution. The        |
//| one case that needs explicit handling is a trade with an efficiency of    |
//| exactly 1.0: multiplying by bin_count lands exactly on bin_count itself,  |
//| one past the last valid index, so that result is clamped back into the    |
//| final bin. Because this method resizes and writes into bins_out, it cannot|
//| be declared const, the same array-parameter rule that applies throughout  |
//| this project.                                                             |
//+---------------------------------------------------------------------------+
void CEfficiencyStatistics::ComputeHistogramBins(const CTradeExcursion &trades[],const int count,
      const int bin_count,int &bins_out[]) const
  {
   ::ArrayResize(bins_out, bin_count);
   ::ArrayInitialize(bins_out, 0);
   for(int i = 0; i < count; i++)
     {
      if(!trades[i].m_efficiency_defined)
         continue;
      int bin_index = (int)(trades[i].m_efficiency * bin_count);
      //--- an efficiency of exactly 1.0 must land in the last bin, not one past it
      if(bin_index >= bin_count)
         bin_index = bin_count - 1;
      if(bin_index < 0)
         bin_index = 0;
      bins_out[bin_index]++;
     }
  }

//+-----------------------------------------------------------------------+
//| ComputeWinLossCounts                                                  |
//| Classifies every trade by the sign of its realized net profit. A      |
//| trade whose net profit is exactly zero is counted as breakeven, its   |
//| own explicit third category, and is never folded into either the win  |
//| or the loss count.                                                    |
//+-----------------------------------------------------------------------+
void CEfficiencyStatistics::ComputeWinLossCounts(const CTradeExcursion &trades[],const int count,
      int &win_count,int &loss_count,int &breakeven_count) const
  {
   win_count       = 0;
   loss_count      = 0;
   breakeven_count = 0;
   for(int i = 0; i < count; i++)
     {
      if(trades[i].m_net_profit > 0.0)
         win_count++;
      else
         if(trades[i].m_net_profit < 0.0)
            loss_count++;
         else
            breakeven_count++;
     }
  }

#endif // EFFICIENCYSTATISTICS_MQH
//+------------------------------------------------------------------+