#property show_inputs
#define OP_DEPOSIT 6
#define SORTBY     0
#define COMMISSION 1
#define TYPE       2
#define PROFIT     3
#define OPENTIME   4
#define CLOSETIME  5
#define BALANCE    6
#define GAIN       7
#define COMGAIN    8
extern datetime StartTime = D'2011.10.01';
extern double BrokerCommission = 0.5;
extern string FileName = "GainCommission.prn";
double OrdersTable[][9];
// Ïîñëå ñîçäàíèÿ òàáëèöà îòñîðòèðîâàíà ïî OPENTIME (ïî âîçðàñòàíèþ) == SortOrdersTable(OPENTIME)
int GetOrdersTable()
{
  int i, Total = OrdersHistoryTotal();
  int Type, Amount = 0;
  ArrayResize(OrdersTable, Total);
  for (i = 0; i < Total; i++)
  {
    OrderSelect(i, SELECT_BY_POS, MODE_HISTORY);
    Type = OrderType();
    if ((Type == OP_BUY) || (Type == OP_SELL) || (Type == OP_DEPOSIT))
    {
      if (OrderOpenTime() >= StartTime)
      {
        OrdersTable[Amount][COMMISSION] = -OrderCommission();
        OrdersTable[Amount][TYPE] = Type;
        OrdersTable[Amount][PROFIT] = OrderProfit() + OrderSwap() + OrderCommission();
        OrdersTable[Amount][OPENTIME] = OrderOpenTime();
        OrdersTable[Amount][CLOSETIME] = OrderCloseTime();
        Amount++;
      }
    }
  }
  ArrayResize(OrdersTable, Amount);
  return(Amount);
}
void SortOrdersTable( int SortBy,  int SortDir = MODE_ASCEND )
{
  int Amount = ArrayRange(OrdersTable, 0);
  for (int i = 0; i < Amount; i++)
    OrdersTable[i][SORTBY] = OrdersTable[i][SortBy];
  ArraySort(OrdersTable, WHOLE_ARRAY, 0, SortDir);
  return;
}
double GetStartBalance()
{
  int Amount = ArrayRange(OrdersTable, 0);
  double Balance = AccountBalance();
  for (int i = 0; i < Amount; i++)
    Balance -= OrdersTable[i][PROFIT];
  Balance = NormalizeDouble(Balance, 2);
  return(Balance);
}
void GetGain( double Koef, double &Gain, double &Commission )
{
  double GainTmp;
  double Koef2;
  int i = 0, Amount = ArrayRange(OrdersTable, 0);
  if (Koef != 0)
    Koef2 = 1 - (1 - BrokerCommission) / Koef;
  while (i < Amount)
  {
    if (OrdersTable[i][GAIN] != 0)
      break;
    i++;
  }
  Commission = 0;
  Gain = 1;
  while (i < Amount)
  {
    if (OrdersTable[i][GAIN] != 0)
    {
      GainTmp = OrdersTable[i][GAIN] / (1 + Koef * OrdersTable[i][COMGAIN]);
      Commission += GainTmp * OrdersTable[i][COMGAIN] * Gain;
      Gain *= GainTmp + 1;
    }
    i++;
  }
  Gain -= 1;
  Commission *= Koef * Koef2;
  return;
}
void GetAccountGain()
{
  int i = 0, Amount = GetOrdersTable();
  double Balance = GetStartBalance(), Commission = 0;
  double Profit, BalanceAdd = 0, ProfitAdd = 0, CommissionAdd = 0;
  bool FlagNegative = FALSE;
  SortOrdersTable(CLOSETIME);
  while (i < Amount)
  {
    OrdersTable[i][BALANCE] = Balance;
    OrdersTable[i][BALANCE] += Commission;
    if (Balance >= 0)
      break;
    Balance += OrdersTable[i][PROFIT];
    Commission += OrdersTable[i][COMMISSION];
    OrdersTable[i][GAIN] = 0;
    OrdersTable[i][COMGAIN] = 0;
    i++;
  }
  Commission = 0;
  while (i < Amount)
  {
    OrdersTable[i][BALANCE] = Balance;
    Profit = OrdersTable[i][PROFIT];
    Commission += OrdersTable[i][COMMISSION];
    if (OrdersTable[i][TYPE] == OP_DEPOSIT)
    {
      OrdersTable[i][GAIN] = 0;
      OrdersTable[i][COMGAIN] = 0;
      BalanceAdd += Profit;
    }
    else if (Balance + Profit <= 0)
    {
      OrdersTable[i][GAIN] = 0;
      OrdersTable[i][COMGAIN] = 0;
      ProfitAdd += Profit;
      CommissionAdd += Commission;
      FlagNegative = TRUE;
    }
    else
    {
      if (!FlagNegative)
      {
        OrdersTable[i][GAIN] = (Profit + Commission) / Balance;
        if (Profit != 0)
        {
          OrdersTable[i][COMGAIN] = Commission / Profit;
          Commission = 0;
        }
        else
          OrdersTable[i][COMGAIN] = 0;
      }
      else if (BalanceAdd < 0)
      {
        OrdersTable[i][GAIN] = (Profit + ProfitAdd + Commission) / (Balance - ProfitAdd - BalanceAdd);
        if (Profit + ProfitAdd != 0)
        {
          OrdersTable[i][COMGAIN] = Commission / (Profit + ProfitAdd);
          Commission = 0;
        }
        else
          OrdersTable[i][COMGAIN] = 0;
      }
      else
      {
        OrdersTable[i][GAIN] = (Profit + ProfitAdd + Commission) / (Balance - ProfitAdd);
        if (Profit + ProfitAdd != 0)
        {
          OrdersTable[i][COMGAIN] = Commission / (Profit + ProfitAdd);
          Commission = 0;
        }
        else
          OrdersTable[i][COMGAIN] = 0;
      }
      BalanceAdd = 0;
      ProfitAdd = 0;
      FlagNegative = FALSE;
    }
    Balance += Profit;
    i++;
  }
  if (FlagNegative)
  {
    if (BalanceAdd < 0)
    {
      if (Balance - ProfitAdd - BalanceAdd <= 0)
      {
        Alert("Error: Unknown Gain!");
        return;
      }
      OrdersTable[Amount - 1][GAIN] = (ProfitAdd + Commission) / (Balance - ProfitAdd - BalanceAdd);
    }
    else
    {
      if (Balance - ProfitAdd <= 0)
      {
        Alert("Error: Unknown Gain!");
        return;
      }
      OrdersTable[Amount - 1][GAIN] = (ProfitAdd + Commission) / (Balance - ProfitAdd);
    }
  }
  return;
}
void start()
{
  double MaxCommission = -1, MaxGain;
  double Gain, Commission;
  double GainInit, CommissionInit;
  int MaxI, handle = FileOpen(FileName, FILE_CSV|FILE_WRITE);
  GetAccountGain();
  GetGain(1, GainInit, CommissionInit);
  for (int i = 0; i < 200; i++)
  {
    GetGain(i / 100.0, Gain, Commission);
    Gain /= GainInit;
    Commission /= CommissionInit;
    if (Commission > MaxCommission)
    {
      MaxCommission = Commission;
      MaxGain = Gain;
      MaxI = i;
    }
    FileWrite(handle, DoubleToStr(Gain, 8) + " " + DoubleToStr(Commission, 8));
  }
  FileClose(handle);
  MessageBox("Optimal Broker Commission is " + MaxI + "% of current commission.\n" +
             "Summary Commission is " + DoubleToStr(100 * MaxCommission, 2) + "% of current commission.\n" +
             "Gain is " + DoubleToStr(100 * MaxGain, 2) + "% of current gain.\n" +
             "See details in " + FileName + " file.");
  return;
}
Comments