// Описание индикатора FF_FP
// Индикатор рассчитывает размер позиции по методу фиксированной пропорции Райана Джонса.
// Формула фиксированной пропорции:

//         Lot = MinLot * ( Sqrt [ 0.25 + 2 * ( Balance - Delta ) / Delta ] + 0.5 )

// Lot это размер позиции,
// MinLot - минимальный лот у брокера,
// Sqrt - квадратный корень.
// Например при Delta = 10000 и при начальном балансе счета  Balance = 10000 таблица результатов некоторых вычислений 
// по этой формуле будет иметь такой вид

//                          n   | Balance
//                          -------------
//                          1   |   10000
//                          2   |   20000
//                          3   |   40000
//                          4   |   70000
//                          5   |  110000
//                          6   |  160000
//                          7   |  220000
//                          8   |  290000


// Где n равно количеству  минимальных лотов.
// Значение Delta после прибыльной сделки принимает значение Delta_Growth или значение ставки роста, а после убыточной Delta
// присваивает значение Delta_Decrease или значение ставки снижения
// Величины Delta_Growth и Delta_Decrease это вводные параметры в окне настроек индикатора.

// В окне индикатора рисуется гистограмма баланса счета вкупе со скользящей средней баланса счета по экспоненциальному или
// простому усреднению 

// Индикатор помимо прочих параметров рассчитывает Математическое ожидание  или  Mathematical еxpectation.

// Индикатор также рассчитывает оптимальную фракцию F или Optimum fraction  F  ( Ральф Винс )

// Current Drowdown  проседание счета которое равно расстоянию от максимального баланса счета который был достигнут в ходе
// торгов и с учетом пополнения и снятия средств до минимума баланса который находится между максимальным балансом счета и
// текущим значением баланса счета 
// Net Profit today (%) это профит в течении дня, Net Profit this week (%) - за текущую неделю и Net Profit this month (%)
// за текущий месяц
//------------------------------------------------------------------------------------------------------------------ 
#property indicator_separate_window           // индикатор в отдельном окне
#property indicator_buffers 2                 // количество отображаемых линий 
#property indicator_minimum 0                 // минимальные показания индикатора
#property indicator_color1 LightSteelBlue     // цвет гистограммы баланса счета 
#property indicator_color2 LightSlateGray     // цвет скользящей средней баланса счета
#property indicator_levelcolor SlateGray      // цвет уровня 
#property indicator_style1 0                  // стиль отрисовки столбиков гистограммы баланса счета 
#property indicator_width1 1                  // толщина столбиков гистограммы баланса счета ( вбирается при стеле = 0 )
#property indicator_style2 2                  // стиль отрисовки скользящей средней баланса счета 
#property indicator_width2 1                  // толщина скользящей средней баланса счета ( вбирается при стеле = 0 )
#property indicator_levelstyle 0              // стиль отрисовки уровня 
#property indicator_levelwidth 1              // толщина уровня ( вбирается при стеле = 0 )
#property indicator_level1 0                  // значение уровня 
//---- вводные параметры

    extern double Delta_Growth = 10;          // Значение Delta для ставки роста 
    extern double Delta_Decrease = 12;        // Значение Delta для ставки снижения
    extern bool Get_report = false;           // Показать отчет по торговле => true / Не показывать => false
    extern int MA_period = 8;                 // Период скользящей средней баланса
    extern bool EMA_true_SMA_false = false;   // Метод вычисления скользящей средней баланса  EMA => true / SMA => false
//---------------------------------------------------------------------------------
      double T[2000];                         // массив только для сделок типа покупка / продажа  buy / sell
      double B[2000];                         // массив для данных о состоянии счета после каждой сделки, пополнение
      double Buffer[];                        // и снятие включительно ( 2 буфера для построения гистограммы баланса
      double Buffer1[];                       // и скользящих средних баланса )
//------------
      int init( )
      {
      IndicatorBuffers( 2 );
      IndicatorDigits( 2 ); 
      SetIndexStyle( 0, DRAW_HISTOGRAM );
      SetIndexStyle( 1, DRAW_LINE );
      SetIndexBuffer( 0, Buffer );
      SetIndexBuffer( 1, Buffer1 );
      string name = "Balance";
      string Method = "SMA";
      if( EMA_true_SMA_false == true )
      {
      Method = "EMA";
      }
      string name1 = "Average Balance  "+Method+" ("+MA_period+")";
      IndicatorShortName( name );
      SetIndexLabel( 0, name );
      SetIndexLabel( 1, name1 );
      return(0);
      }
//----
      int deinit( )
      {

      return(0);
      }
//----
      int start( )
      {
      double balance = AccountBalance( );
   	if( Get_report == true )
   	{			
      int i;
      int cmd;
      double swap;
      double commission;
      double orderprofit;
      string ordercomment;
      double loss;
      double profit;
      double nles;
      double nprofi;
      double Dd = 0;
      double s;
      double sum = 0;
      double sum1 = 0;
      double fs = 0;
      double Lp;
      double Ll;
      double u;
      int o1 = 0;
      int j = 0;
      double mk = 0;
      double en = 0;
      double b1 = 0;
      double b2 = 0;
      int y5;
      double SU = 0;
      double EJ = 0;
      int ii;
      int yy = 0;
      int xx = 0;
      int re;
      int es;
      double gb;
      double cn;
      double de3;
      int z = 0;
      double short;
      double long;
      int Total_short;
      int Total_long;
      double SOC;
      double C1;
      double NT1;
      double NW2;
      double NM3;
      int xc;
      datetime closetime;
      double ny;
      int w;

      while( i < OrdersHistoryTotal( ) )
      {
      if( OrderSelect( i, SELECT_BY_POS, MODE_HISTORY ) == true )
      {
      swap = OrderSwap( );
      closetime = OrderCloseTime( );
      cmd = OrderType( );
      commission = OrderCommission( );
      orderprofit = OrderProfit( );
      //----
      if( ( cmd != 2 ) && ( cmd != 3 ) && ( cmd != 4 ) && ( cmd != 5 ) )
      {
      xc++;                                                // считает все изменения в балансе счета
      if( ( cmd == 6 ) && ( orderprofit > 0 ) )
      {
      b1 = b1 + orderprofit;                               // депозит / Deposit
      }
      else
      {
      if( ( cmd == 6 ) && ( orderprofit < 0 ) )
      {
      w = xc + 1;
      b2 = b2 + orderprofit;                               // снятие / Withdrawal
      }
      }
      //----
      C1 = swap + orderprofit + commission;
      de3 = de3 + C1;                                      // баланс
      B[xc] = de3;
      //------------------------------------------
      if( cmd <= 1 )
      {
      SOC = swap + orderprofit + commission;
      if( closetime >= iTime( NULL, PERIOD_D1, 0 ) )
      {
      NT1 = NT1 + SOC;                                     // для Net Profit today (%)
      } 
      if( closetime >= iTime( NULL, PERIOD_W1, 0 ) )
      {
      NW2 = NW2 + SOC;                                     // для Net Profit this week (%)
      }
      if( closetime >= iTime( NULL, PERIOD_MN1, 0 ) )
      {
      NM3 = NM3 + SOC;                                     // для Net Profit this month (%)
      }
      //----
      z++;                                                 // счетчик всех сделок buy / sell 
      T[z] = SOC;                                          // массив для этих сделок 
      if( SOC < 0 )
      {
      sum = sum + SOC;                                     // сумма всех убыточных сделок 
      o1++;                                                // серии убыточных сделок
      y5++;                                                // счетчик макс. серий убыт. сделок или Maximum consecutive losses
      if( mk > sum  )                                      // сделок
      {
      mk = sum;                                            // Maximal consecutive loss ( re )
      re = y5;                                             // серия при Maximal consecutive loss
      }
      if( xx <= y5 )
      {
      xx = y5;                                             // максимальная серия xx убыточных сделок
      }
      if( Ll > SOC )
      {
      Ll = SOC;                                            // самый большой убыток от одной сделки или Largest loss trade
      }
      nles++;                                              // количество убыточных сделок
      loss = loss - SOC;                                   // суммарный убыток или Gross loss
      }
      else
      {
      if( SOC >= 0 )
      {
      if( cmd == 0 )
      {
      long++;                                              // все прибыльные сделки на длинной стороне
      }                                                    // или Long profit trade
      else
      {
      if( cmd == 1 )
      {
      short++;                                             // все прибыльные сделки на короткой стороне
      }                                                    // или Short profit trade
      }
      sum = 0;                                             // обнулим сумму максимального убытка от максимальной серии
      if( o1 != 0 )
      {
      gb++;                                                // суммарное количество серий убыточных сделок
      }
      o1 = 0;                                              // обнуляем серию убыточных сделок
      y5 = 0;                                              // присвоим 0 максимальным значениям серий убыточных сделок или
      sum1 = sum1 + SOC;                                   // Maximal consecutive count / loss
      j++;                                                 // серии прибыльных сделок
      ii++;                                                // счетчик макс. серий приб. сделок или Maximum consecutive wins
      if( en < sum1 )                                      // сделок
      {
      en = sum1;                                           // Maximal consecutive profit ( es )
      es = ii;                                             // серия при Maximal consecutive profit
      }
      if( yy <= ii )
      {
      yy = ii;                                             // максимальная серия yy прибыльных сделок
      }
      if( Lp < SOC )
      {
      Lp = SOC;                                            // самая большая прибыль от одной сделки или Largest profit trade
      } 
      nprofi++;                                            // количество прибыльных сделок
      profit = profit + SOC;                               // суммарная прибыль или Gross profit
      }
      }
      //---
      if( SOC < 0 )
      { 
      sum1 = 0;                                            // обнулим сумму максимальной прибыли от максимальной серии
      if( j != 0 )
      {
      cn++;                                                // суммарное количество серий прибыльных сделок
      }  
      j = 0;                                               // обнуляем серию прибыльных сделок
      ii = 0;                                              // обнулим максимальные значениям серий прибыльных сделок или
      }                                                    // Maximal consecutive count / profit
      }                                                    // граница для if( cmd <= 1 )    
      //----
      if( cmd == 0 )
      {
      Total_long++;                                        // все сделки на длинной стороне
      }                                                    // или Long Positions
      else
      {
      if( cmd == 1 )
      {
      Total_short++;                                       // все сделки на короткой стороне
      }                                                    // или Short Positions 
      }
      //----
      }                                                    // граница для if( cmd != 2 && cmd != 3 && cmd != 4 && cmd != 5 )
      }                                                    // граница для if( OrderSelect( i, SELECT_BY_POS, MODE_HISTORY ) == true )
      i++;
      }                                                    // граница для цикла while( i < OrdersHistoryTotal( ) ) 
      //                                                   // текущее проседание или Current Drowdown(%)
      int oi = 0;
      int maxindex = ArrayMaximum( B, xc, 0 );             // индекс максимума в массиве 
      double max = B[maxindex];                            // поиск пика или вершины счета
      while( oi <= xc - maxindex )                         // задаем окно поиска  xc - maxindex
      {
      static double min = 1000000;
      if( ( min > B[xc - oi] ) && ( xc - oi > w ) )        // поиск минимума баланса между максимумом баланса и текущим 
      {                                                    // значением баланса для Current Drowdown(%)
      min = B[xc - oi];                                    // нашелся минимум баланса
      }
      oi++;                                                // счетчик цикла
      }
      Dd = max - min;                                   // максимальное проседание счета или Current Drowdown это расстояние между
      if( max != 0 )                                    // историческим максимумом баланса и минимумом баланса. минимум баланса
      {                                                 // находится между историческим максимумом баланса и текущем значение
      u = 100 * Dd / max;                               // баланса и Current Drowdownв процентном выражении
      } 
      // поиск суммарного убытка и прибыли при максимальных сериях, или поиск параметров Maximum consecutive wins ($)
      int ie = 0;                                // и Maximum consecutive losses ($) ( то что в скобках )
      int t = 0;
      int k2 = 0;
      double org = 0;
      double fgh = 0;
      double owq = 0;
      double css = 0;
      
      while( ie < xc )
      {
      if( ( T[ie] < 0 ) && ( t < xx ) )          // для суммы убытка
      {
      t++;
      SU = SU + T[ie];
      if( owq > SU )
      {
      owq = SU;
      if( t == xx )
      {
      css = owq;                                 // нашли суммарный убыток при максимальной серии
      }                                          // убыточных сделок
      }
      }
      else
      {
      if( ( T[ie] >= 0 ) && ( t < xx ) )
      {
      t = 0;
      SU = 0;
      }
      }
      if( t == xx )
      {
      t = 0;
      SU = 0;
      }
      //----
      if( ( T[ie] >= 0 ) && ( k2 < yy ) )       // для cуммы прибыли
      {
      k2++;
      EJ = EJ + T[ie];
      if( org < EJ )
      {
      org = EJ;
      if( k2 == yy )
      {
      fgh = org;                                // нашли суммарную прибыль при максимальной серии
      }                                         // прибыльных сделок
      }
      }
      else
      {
      if( ( T[ie] < 0 ) && ( k2 < yy ) )
      {
      k2 = 0;
      EJ = 0;
      }
      }
      if( k2 == yy )
      {
      k2 = 0;
      EJ = 0;
      }
      Buffer[ie] = B[xc - ie];
      ie++;
      }
      //                                        скользящая средняя баланса ( методы расчета - SMA и EMA )
      int nb = xc - MA_period - 1;
      double vol;
      int iz;
      while( nb >= 0 )
      {
      if( EMA_true_SMA_false == false )
      {
      vol = 0;
      for( iz = nb; iz <= nb + MA_period - 1; iz++ )
      {
      vol = vol + Buffer[iz];
      }
      if( MA_period != 0 )
      {
      Buffer1[nb] = vol / MA_period;         // простая скользящая средняя баланса
      }
      }
      else
      {
      if( EMA_true_SMA_false == true )
      {
      if( nb == xc - MA_period - 1 )
      { 
      Buffer1[nb + 1] = Buffer[nb + 1];
      }                                      // экспоненциальная скользящая средняя баланса
      Buffer1[nb]=( ( MA_period - 1 ) * Buffer1[nb + 1] + 2 * Buffer[nb] ) / ( MA_period + 1 );
      }
      }
      //---
      if( Bars - nb - 1 < MA_period )
      {
      Buffer1[nb] = 0;
      SetIndexEmptyValue( 1, 0.0 );
      }
      nb--;
      }
      //----                                        // поиск оптимальной фракции F
      int h = 1;
      double TWR = 1;
      double HPR;
      double g;
      double f;
      double F;
      double G;
      while( h < 99 )
      {
      f = f + 0.01;                                 // перебор HPR с шагом в 1 %
      int o = 1;
      int i9 = z;
      while( o <= i9 )
      {
      if( Ll != 0 )
      { 
      HPR = 1 - f * T[o] / Ll;                      // HPR - относительная прибыль / максимальный убыток от
      }                                             // сделки в статистике
      TWR  = TWR * HPR;                             // относительный конечный капитал - TWR
      o++;                                          // счетчик сделок по всему массиву T[]
      }
      G = MathPow( TWR, MathPow( z, -1 ) );         // вычисление среднего геометрического от TWR
      if( G <= g )                                  // как только G начнет уменьшаться значит
      {
      F = 100 * f - 1;                              // нашли  оптимальную фракцию F
      break;                                        // и тогда уходим из цикла
      }
      g = G;
      h++;
      TWR = 1;                                      // после каждого цикла в o <= i9 возвращаем TWR значение 1
      }
      //---
      if( ( Total_long != 0 ) && ( Total_short != 0 ) )
      {
      double pctLong = 100 * long / Total_long;           // процент прибыльных длинных сделок во всех длинных сделках
      double pctShort = 100 * short / Total_short;        // процент прибыльных коротких сделок во всех коротких сделках
      }
      double Gp = profit;                                 // общая  прибыль или Gross profit
      double Gl = loss;                                   // общий  убыток или Gross loss
      double TN = profit - loss;                          // полная чистая прибыль или Total Net Profit
      if( ( nles != 0 ) && ( nprofi != 0 ) )
      {
      double alt = loss / nles;                           // средняя убыточная сделка или Average loss trade
      double apt = profit / nprofi;                       // средняя прибыльная сделка или Average profit trade
      }
      double total = z;                                   // суммарное количество сделок или Total trades
      if( ( total != 0 ) && ( cn != 0 ) && ( gb != 0 ) )
      {
      double EP = TN / total;                             // Ожидаемые выплаты  или  Expected Payoff
      double acw = nprofi / cn;                           // средняя серия для прибыльных сделок или Average consecutive wins
      double acl = nles / gb;                             // средняя серия для убыточных сделок или Average consecutive losses
      double won = 100 * nprofi / total;                  // процент прибыльных сделок от общего количества сделок
      double lS = 100 * nles / total;                     // процент убыточных сделок от общего количества сделок
      }
      if( ( alt != 0 ) && ( loss != 0 ) )
      {
      double ME = 0.01 * ( 1 + apt / alt ) * won - 1;     // математическое ожидание или Mathematical еxpectation
      double pf = profit / loss;                          // отношение общей прибыли к общему убытку или Profit factor
      }
      //---
      double nt1pct = 100 * NT1 / ( balance - NT1 );      // процент дневной прибыли / убытка 
      double nw2pct = 100 * NW2 / ( balance - NW2 );      // процент прибыли / убытка текущей недели
      double nm3pct = 100 * NM3 / ( balance - NM3 );      // процент прибыли / убытка текущего месяца
      SetIndexDrawBegin( 0, Bars - xc );                  // номер бара для начала отрисовки гистограмы баланса счета
      SetIndexDrawBegin( 1, Bars - xc + MA_period );      // номер бара для начала отрисовки скользящей средней баланса счета
      //---
      Comment( " Profit factor   "+DoubleToStr( pf, 2 )+" ", // информ табло
      "\n ", "Profit trades ( % of total )   "+DoubleToStr( nprofi, 0 )+" ("+DoubleToStr( won, 2 )+" %) ",
      "\n ", "Loss trades ( % of total )   "+DoubleToStr( nles, 0 )+" ("+DoubleToStr( lS, 2 )+" %) ",
      "\n ", "Total trades   "+z+" ",
      "\n ", "Short Positions (won %)   "+Total_short+" ("+DoubleToStr( pctShort, 2 )+" %) ",
      "\n ", "Long Positions (won %)   "+Total_long+" ("+DoubleToStr( pctLong, 2 )+" %) ",
      "\n ", "Gross Profit    "+DoubleToStr( Gp, 2 )+" ",
      "\n ", "Gross Loss    "+DoubleToStr( Gl, 2 )+" ",
      "\n ", "Total Net Profit    "+DoubleToStr( TN, 2 )+" ",
      "\n ", "Expected Payoff   "+DoubleToStr( EP, 2 )+" ",
      "\n ", "Mathematical еxpectation   "+DoubleToStr( ME, 2 )+"",
      "\n ", "Optimum fraction  F   "+DoubleToStr( F, 0 )+" % ",
      "\n ", "Current Drowdown  "+DoubleToStr( Dd, 2 )+"  ("+DoubleToStr( u, 2 )+" %)",
      "\n ", "Net Profit today (%)  "+DoubleToStr( NT1, 2 )+"  ("+DoubleToStr( nt1pct, 2 )+" %)", 
      "\n ", "Net Profit this week (%)  "+DoubleToStr( NW2, 2 )+"  ("+DoubleToStr( nw2pct, 2 )+" %)",
      "\n ", "Net Profit this month (%)  "+DoubleToStr( NM3, 2 )+"  ("+DoubleToStr( nm3pct, 2 )+" %)",
      "\n ", "Largest profit trade   "+DoubleToStr( Lp, 2 )+" ",
      "\n ", "Largest loss trade   "+DoubleToStr( Ll, 2 )+" ",
      "\n ", "Average profit trade   "+DoubleToStr( apt, 2 )+" ",
      "\n ", "Average loss trade   "+DoubleToStr( -alt, 2 )+" ",
      "\n ", "Average consecutive wins   "+DoubleToStr( acw, 0 )+" ",
      "\n ", "Average consecutive losses   "+DoubleToStr( acl, 0 )+" ",
      "\n ", "Maximum consecutive wins($)    "+yy+" ("+DoubleToStr( fgh, 2 )+") ",
      "\n ", "Maximum consecutive losses($)   "+xx+" ("+DoubleToStr( css, 2 )+") ",
      "\n ", "Maximal consecutive profit (count)   "+DoubleToStr( en, 2 )+"  ("+es+")",
      "\n ", "Maximal consecutive loss  (count)   "+DoubleToStr( mk, 2 )+"  ("+re+")" );
      }
      else                                                                // вычисление фиксированной пропорции FP
      {
   	if( Get_report == false )
   	{
      double last_trade;
      int ei;
      while( ei < OrdersHistoryTotal( ) )
      {
      if( OrderSelect( ei, SELECT_BY_POS, MODE_HISTORY ) == true )
      {
      if( OrderType( ) <= 1 )
      {
      last_trade = OrderSwap( ) + OrderProfit( ) + OrderCommission( );    // последняя сделка
      }
      }
      ei++;
      }
		double minlot = MarketInfo( Symbol( ), MODE_MINLOT );               // размер минимального лота
		double Delta;
		if( last_trade < 0 )                                                // если последняя сделка убыточна то 
		{
		Delta = Delta_Decrease;                                             // дельта равна ставке снижения 
		}
		else
		{
		if( last_trade >= 0 )                                               // если последняя сделка 0 или положительна то
		{
		Delta = Delta_Growth;                                               // дельта равна ставке роста
		}
		} 
		double fp = ( MathSqrt( 0.25 + 2 * ( balance - Delta ) / Delta ) + 0.5 );
	   double lot = NormalizeDouble( minlot * MathRound( fp - 0.5 ), 2 );
		string dD = "Delta_Decrease   "+DoubleToStr( Delta_Decrease, 2 )+"";
		string dG = "Delta_Growth     "+DoubleToStr( Delta_Growth, 2 )+"";
		string v = "Lot                      "+DoubleToStr( lot, 2 )+" ";
      Comment( " "+v+"", "\n ", dG, "\n ", dD );
		}
      }

      return(0);
      }





