//+------------------------------------------------------------------+
//|                                 StreakProbabilityCalculator.mqh  |
//+------------------------------------------------------------------+
#ifndef STREAKPROBABILITYCALCULATOR_MQH
#define STREAKPROBABILITYCALCULATOR_MQH

#include "RiskTypes.mqh"

//+------------------------------------------------------------------+
//| CStreakProbabilityCalculator                                     |
//| Computes the probability of a losing streak of a given length,   |
//| using the geometric distribution's tail formula.                 |
//+------------------------------------------------------------------+
class CStreakProbabilityCalculator
  {
public:
                     CStreakProbabilityCalculator(void);
                    ~CStreakProbabilityCalculator(void);

   double                ComputeStreakProbability(double win_rate, int streak_length) const;
   int                   BuildProbabilityTable(double win_rate, const int &streak_lengths[],
         int count, CStreakProbability &table_out[]) const;
  };

//+------------------------------------------------------------------+
//| Constructor: no member state to initialize.                      |
//+------------------------------------------------------------------+
CStreakProbabilityCalculator::CStreakProbabilityCalculator(void)
  {
  }

//+------------------------------------------------------------------+
//| Destructor: no dynamic resources to release.                     |
//+------------------------------------------------------------------+
CStreakProbabilityCalculator::~CStreakProbabilityCalculator(void)
  {
  }

//+------------------------------------------------------------------+
//| ComputeStreakProbability                                         |
//| Returns the probability of at least streak_length consecutive    |
//| losses in a row, computed as the loss rate raised to that power. |
//+------------------------------------------------------------------+
double CStreakProbabilityCalculator::ComputeStreakProbability(double win_rate, int streak_length) const
  {
   if(streak_length <= 0)
      return(1.0);
//--- clamp an out-of-range win rate to a valid probability before using it
   double clamped_win_rate = win_rate;
   if(clamped_win_rate < 0.0)
      clamped_win_rate = 0.0;
   if(clamped_win_rate > 1.0)
      clamped_win_rate = 1.0;
   double loss_rate = 1.0 - clamped_win_rate;
   return(::MathPow(loss_rate, streak_length));
  }

//+------------------------------------------------------------------+
//| BuildProbabilityTable                                            |
//| Computes the streak probability for every requested streak       |
//| length and returns the number of rows populated.                 |
//+------------------------------------------------------------------+
int CStreakProbabilityCalculator::BuildProbabilityTable(double win_rate, const int &streak_lengths[],
      int count, CStreakProbability &table_out[]) const
  {
   ::ArrayResize(table_out, count);
   for(int i = 0; i < count; i++)
     {
      table_out[i].streak_length = streak_lengths[i];
      table_out[i].probability   = ComputeStreakProbability(win_rate, streak_lengths[i]);
     }
   return(count);
  }

#endif // STREAKPROBABILITYCALCULATOR_MQH
//+------------------------------------------------------------------+