Navigation´╝ÜHome > Content >

LuKu_EDiff_v15.mq4

Time: 2011-04-08 | Download file:LuKu_EDiff_v15.mq4

//+------------------------------------------------------------------+
//|                                               LuKu_EDiff_v15.mq4 |
//|                                                             LuKu |
//|                                               http://luku.cz/fx/ |
//+------------------------------------------------------------------+
/*
    Indicator displays differential curve by various method
    Inspired by http://www.forexfactory.com/showthread.php?t=160912&page=233
    
    Version 1.0 (12.1.2012)
      - core programming
      - several types of measurement deviations
      - added alert system
      - customizable value of alert lines
      - alert lines calculation by Percentile or value
      - added simulated profit calculation on close bars
      - added automated calculation of correlation and direction trades
      
    Version 1.1 (16.1.2012)
      - trade support
      - added close limit for value a Percentile
      - time limit for trading
      - show price label
      - spread filtering for trading
      - modify view
      - support AlertPercentileClose to zero
      
    Version 1.2 (18.1.2012)
      - support MinTickCount on alert lines (sometime values jump over alert limit and back bellow)
      - support Stochastic mode
      - bugfix in time filtration
      
    Version 1.3 (20.1.2012)
      - bugfix alert messages, painting system
      - check if loaded history bars + error messages and stop the indicator message
      - add MAE, MFE to file export, show and export to EA strategy
      - better direction setting
      - some minor changes
      
    Version 1.4 (22.1.2012)
      - better MAE a MFE calculation (optimization curve by corelation pairs)
      - add choice for precize MAE a MFE calculation by lower fimeframe (requires more lowerTF bars!)
      - add choice for trading only open new bar TradeOnlyOnNewBar (same as calculating simulated profit)
      - complete new calculation simulated profit, MAE and MFE calculation (calculateMaeMfeProfit)
      - bugfix on negative pair on stochastic mode
      - change some default parameters
      
    Version 1.5 (27.1.2012)
      - add show profit labels
      - big bugfix in simulated profit and main calculation (added protection for missing bars)
      - add recalculate after MAE and MFE + support export in file
      - show status FilterHours and Spread
      - bugfix in spread and time filtration
      - support automaticaly save alert status (in global variable) + add choice ResetAlertStatusAfterStart
      
    TODO:
      - dodat MAE a MFE profity jinou barvou (zlutou?)
      - add support time filtering to simulated profit
      - show shadows tick curve and save it (ShowShadows = true;)
      - re-calculateSimulatedProfit after X bars, no only first run
      
*/
#property copyright     "LuKu"
#property link          "http://luku.cz/fx/"
string Indicator_Name = "LuKu_EDIFF_v15";
string ShortName      = "EDI";

#property indicator_separate_window
#property indicator_buffers 5
#property indicator_color1 Red
#property indicator_color2 Green
#property indicator_color3 DodgerBlue
#property indicator_color4 White
#property indicator_color5 OrangeRed
#property indicator_style1 STYLE_DOT
#property indicator_style2 STYLE_DOT
#property indicator_style3 STYLE_SOLID
#property indicator_style4 STYLE_SOLID
#property indicator_style5 STYLE_SOLID
#property indicator_width1 1
#property indicator_width2 1
#property indicator_width3 1
#property indicator_width4 1
#property indicator_width5 1

// parameters
extern string    sDiffType             = "------- 1=StdDev 2=MAPips 3=Stoch";
extern int       DiffType              = 1;
extern string    DiffPair              = "GBPUSD";
extern string    sDirectionType        = "Direction [0=ByCorrelation,1=Positive,-1=Negative]";
extern int       DirectionType         = 0;
extern int       CorelationD1Period    = 50;

extern string    sStdDev          = "------- 1 StdDevMA settings";
extern int       StdDevPeriod     = 150;

extern string    sMAPips          = "------- 2 MAPips settings";
extern int       MaPipsPeriod     = 100;

extern string    sStoch           = "------- 3 Stochastic settings";
extern int       Kperiod          = 14;
extern int       Dperiod          = 3;
extern int       Slowing          = 3;
extern int       SmothCurveFactor = 0;
extern bool      NoSmothActualBar = true;

extern string    sAlertSystem        = "-------- Alert [Value|Percentile]";
extern string    AlertSystem         = "Percentile";
extern bool      SendAlert           = true;
extern bool      SendEmail           = false;
extern string    AlertPercentileArray  = "80,92,98";
extern double    AlertPercentileClose  = 10;
extern int       AlertPRecalcBars    = 10; // recalculate Percentile values every N bars
extern string    AlertValueArray     = "2.1,2.7,3.4";
extern double    AlertValueClose     = 0.3;
extern int       AlertMinTickCount   = 2; // fast jump over alert lines protection

extern string    sProfit   = "------- Profit calculation settings";
extern bool      CalculateProft = true;
extern double    SpreadBuy = 1.2;
extern double    SpreadSell = 1.2;
extern double    MAEPercentil = 3;  // 3% percentile for MAE decrease profit but decrease risk! (intervention etc)
extern double    MFEPercentil = 60; // 60% perceptile form MFE incease profit
extern bool      PreciseCalcMAEMFE = false; // requaire more lowTF bars!
extern string    PreciseTimeframe = "M1";
extern bool      ExportTradeToCsv = false;

extern string    sTrading   = "------- Trading settings";
extern bool      TradeEdiEAAllowed  = true;
extern bool      TradeOnlyOnNewBar  = false;
extern bool      AutoMagickNumber   = true;  // automaticaly generate ManualMagickNumber
extern int       ManualMagickNumber = 0;     // use this number in trades
extern bool      FilterHours        = false;  // time filtering
extern string    TradeFrom          = "0:30";
extern string    TradeTo            = "22:30";
extern bool      FilterSpread       = true;  // spread filtering - if greater no open trade
extern double    FSpreadMax         = 4.0;   // max tradable spread

extern string    sOther                  = "------- Others settings";
extern bool      ShowOnlyDiffCurve     = true;
extern int       MaxBarCount           = 10000; // num of calculated bars 0 = all
extern bool      ShowAlertLevelStatus  = true;
extern bool      ShowMagickNumber      = true;
extern bool      ShowPriceLabel             = true;
extern bool      ResetAlertStatusAfterStart = false;

// buffers
double BuyBuffer[];
double SellBuffer[];
double DiffBuffer[];
double ArrowStart[];
double ArrowStop[];

// promenne
double BBuff, SBuff, DBuff; // promenne na vymenu
double AlertArray[]; // pole s value / Percentile linkami
double AlertArrayValues[]; // pole s hodnotami linek
bool AlertStackArrayB[]; // pole s aktivovanymi alerty
bool AlertStackArrayS[]; // pole s aktivovanymi alerty
bool TradeStackArrayB[]; // pole s aktivovanymi alerty
bool TradeStackArrayS[]; // pole s aktivovanymi alerty
int TradeTickArrayB[];  // tick counting
int TradeTickArrayS[];  // tick counting
string sTradeStackArrayGlobalB, sTradeStackArrayGlobalS; // nazvy promennych ukladanych stavu alertu
int i;
double QData[]; // quantil data
int Direction = 1;
bool drawAlertLineOnlyOnce = false;
datetime newBar, newBar2;   // cas posledniho baru
int qRecalcBars = 0;
int HWND = -1; // ID okna po initu
bool isInit = false; // pro zobrazovani textu
double correlValue = 0; // hodnota korelace
int iPreciseTimeFrame = 0;
int ProfitStackArrayI[]; // pozice s simulovanymi obchody
bool calculatedProfit = false;
int drawLinesCount;
double StopLevelValue = 0.0;
double Spread = 0.0;
int iArraySize;
bool IndicatorErrorStoped = false;
double MAE = 0.0, MFE = 0.0;
double globalMAE = 0.0;
double globalMFE = 0.0;
bool bCalculatedBackData = false;
int ipCount = 0;
double profitLabelLevel = 0; // level pro zobrazovani profitu

bool jenjednou = true;

// trading EA parameter
string sClose, sOpenS, sOpenB, sMAE, sMFE; // nazev sledovane promenne
int iEAPeriod;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init(){
   // Name
   Indicator_Name = StringConcatenate(Indicator_Name, "_", Symbol(), DiffPair, DoubleToStr(Period()+MathRand(),0));
   IndicatorShortName(Indicator_Name);
   
   // Buy buffer
   SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(0,BuyBuffer);
   
   // Sell buffer
   SetIndexStyle(1,DRAW_LINE);
   SetIndexBuffer(1,SellBuffer);
   
   // Diff
   SetIndexStyle(2,DRAW_LINE);
   SetIndexBuffer(2,DiffBuffer);
   
   // START
   SetIndexStyle(3,DRAW_ARROW, 0, 1);
   SetIndexArrow(3,159);
   SetIndexBuffer(3,ArrowStart);
   
   // STOP
   SetIndexStyle(4,DRAW_ARROW, 0, 1);
   SetIndexArrow(4,159);
   SetIndexBuffer(4,ArrowStop);

   // Parsing values by type
   if(AlertSystem == "Percentile"){
     valuesToDoubleArray(AlertArray, AlertPercentileArray);
   }else{
     valuesToDoubleArray(AlertArray, AlertValueArray);
   }

   // Buffer alert values
   iArraySize = ArraySize(AlertArray);
   ArrayResize(AlertStackArrayB, iArraySize);
   ArrayResize(AlertStackArrayS, iArraySize);
   ArrayResize(TradeStackArrayB, iArraySize);
   ArrayResize(TradeStackArrayS, iArraySize);
   ArrayResize(TradeTickArrayB, iArraySize);
   ArrayResize(TradeTickArrayS, iArraySize);   
   ArrayResize(AlertArrayValues, iArraySize);
   arrayInitialize(AlertStackArrayB, false);
   arrayInitialize(AlertStackArrayS, false);
   arrayInitialize(TradeStackArrayB, false);
   arrayInitialize(TradeStackArrayS, false);
   ArrayInitialize(TradeTickArrayB, 0);
   ArrayInitialize(TradeTickArrayS, 0);

   // linky vykreslovat pouze jednou
   drawAlertLineOnlyOnce = false;
   
   // nastaveni baru na prepocet
   qRecalcBars = AlertPRecalcBars;
   
   // prepocet korelace
   calculateCorrelation();
   
   // Direction type
   if(DirectionType != 0){
     if(DirectionType > 0){
       Direction = 1;
     }else{
       Direction = -1;
     }
   }
   
   // automaticke nastavovani MagickNumber
   if(AutoMagickNumber == true){
     ManualMagickNumber = makeMagicNumber(Symbol()+DiffPair+timeFrameToString(Period())); // vygenerujeme nove
   }
   // trading
   if(TradeEdiEAAllowed == true){
     // names of global variables sets for EA
     sClose = StringConcatenate("EDI-CLOSE_",Symbol(),"_",DiffPair,"_",ManualMagickNumber);
     sOpenB = StringConcatenate("EDI-OPENB_",Symbol(),"_",DiffPair,"_",ManualMagickNumber);
     sOpenS = StringConcatenate("EDI-OPENS_",Symbol(),"_",DiffPair,"_",ManualMagickNumber);
     sMAE = StringConcatenate("EDI-MAE_",Symbol(),"_",DiffPair,"_",ManualMagickNumber);
     sMFE = StringConcatenate("EDI-MFE_",Symbol(),"_",DiffPair,"_",ManualMagickNumber);
   }
   // nazvy globalnich promenny pro ukladani stavu obchodu / alertu
   sTradeStackArrayGlobalB = StringConcatenate("EDI-GB_",Symbol(),"_",DiffPair,"_",ManualMagickNumber);
   sTradeStackArrayGlobalS = StringConcatenate("EDI-GS_",Symbol(),"_",DiffPair,"_",ManualMagickNumber);
   
   getHwnd();
   
   // prevod precizniho timeframe z textu na int
   if(PreciseCalcMAEMFE == true){
     iPreciseTimeFrame = stringToTimeFrame(PreciseTimeframe);
   }else{
     iPreciseTimeFrame = Period();
   }
   
   // check the all bars we need
   if(checkBarCount(Symbol(), 50, PERIOD_D1) != true)         IndicatorErrorStoped = true;
   if(checkBarCount(DiffPair, 50, PERIOD_D1) != true)         IndicatorErrorStoped = true;
   if(checkBarCount(Symbol(), MaxBarCount, Period()) != true) IndicatorErrorStoped = true;
   if(checkBarCount(DiffPair, MaxBarCount, Period()) != true) IndicatorErrorStoped = true;
   // if allowed precize mode
   if(PreciseCalcMAEMFE == true){
     if(checkBarCount(Symbol(), MaxBarCount * (Period() / PERIOD_M1), iPreciseTimeFrame, true) != true) IndicatorErrorStoped = true;
     if(checkBarCount(DiffPair, MaxBarCount * (Period() / PERIOD_M1), iPreciseTimeFrame, true) != true) IndicatorErrorStoped = true;
   }
   if(IndicatorErrorStoped == true){
     TextCreate("ERROR!!! Indicator stoped.",  1, Red, 10, 20, 20);
   }
   
   // cislo profit labelu
   ipCount = 0;
   
   // nahrani poslednich stavu aktivace linek / profitu a nebo reset zulozenych zprav
   if(ResetAlertStatusAfterStart == true){
     resetTradeStackArrayGlobal(sTradeStackArrayGlobalB);
     resetTradeStackArrayGlobal(sTradeStackArrayGlobalS);
   }else{
     loadTradeStackArrayGlobal(sTradeStackArrayGlobalB, TradeStackArrayB);
     loadTradeStackArrayGlobal(sTradeStackArrayGlobalS, TradeStackArrayS);
   }
   
   return(0);
}

// zjisteni korelace + nastaveni promennych
void calculateCorrelation(){
   // aktualni hodnota korelace, na zaklade ni se pak otaceji pary
   correlValue = getCorrelationPairs(Symbol(), DiffPair, PERIOD_D1, CorelationD1Period);
   if(correlValue < 0){
     Direction = -1;
   }else{
     Direction = 1;
   }
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit(){
  // delete objects
  for(int x=1;x<=16;x++) ObjectDelete(StringConcatenate(Indicator_Name,"_",x));
  // delete profitu
  for(x=1;x<=ipCount;x++) ObjectDelete(StringConcatenate(Indicator_Name,"_P",x));
  // delete alert lines
  for(x=0;x<=drawLinesCount;x++) SetLevelValue(x, EMPTY_VALUE);
  return(0);
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start(){
   if(IndicatorErrorStoped == true) return(0); // error?
   int limit;
   int counted_bars = IndicatorCounted();  // kolik jich uz bylo spocitano
   if(counted_bars < 0) return(-1);        // error protection
   if(counted_bars > 0) counted_bars--;    // recounted last bar
   limit = Bars - counted_bars;            // kolik jich mame jeste spocitat
   
   // je pozadovano pocitani pouze urciteho poctu baru (kvuli rychlosti)
   if(MaxBarCount > 0){
     if(limit > MaxBarCount){
       limit = MaxBarCount;
     }
   }
   
   // recounting bars by differend metods
   switch(DiffType){
     case 2:
       if(limit < MaPipsPeriod) limit = MaPipsPeriod +1;
       break;
     case 3:
       if(limit < Kperiod) limit = Kperiod +1;
       break;
     case 1:
     default:
       if(limit < StdDevPeriod) limit = StdDevPeriod +1;
       break;
   }
   
   // get indicator handle for drawing text labels
   getHwnd();

   // Main cycle *****************************************************
   for(i = limit; i>=0; i--){
     // get values
     getEDiffValues(i);
     // to graph buffers
     if(ShowOnlyDiffCurve == false){
       BuyBuffer[i] = BBuff;
       SellBuffer[i] = SBuff;
     }
     DiffBuffer[i] = DBuff;
     // drawing price label
     if(i == 0) createPriceLabel(DBuff);
   }
   
   // recalculate Percentile alert lines, every AlertQRecalcBars bars
   recalculateQuantilData(); 
   // draw alert lines only once
   drawAlertLines();

   // calculating spread
   if(FilterSpread == true){
     Spread = getSpreadBySymbol(Symbol()) + getSpreadBySymbol(DiffPair);
   }
   
   // vykreslime poprve body obchodu a potom je generujeme online
   calculateBackAlertSystem(limit);
   
   // resime alerty + vykreslujeme body na 0tem baru
   if(TradeOnlyOnNewBar == true){
     if(isNewBar(newBar2) == true){
       // trade only new bar!
       calculateAlertSystem();
     }
   }else{
     calculateAlertSystem();
   }

   // modify some texts
   initText();
    
   // simulated profit calculation - only once
   calculateSimulatedProfit(MaxBarCount);
  
   return(0);
}
//+------------------------------------------------------------------+

// ziska hodnoty
void getEDiffValues(int i){
   // prevod i na i pro oba pary
   int iB = i;
   int iS = iBarShift(DiffPair, Period(), iTime(Symbol(),Period(),i)); // synchonizace paru na shodne bary kvuli chybejicim barum v druhem paru kde pak i nesedi a je posunuto!
   switch(DiffType){
     case 2:
       getMAPipsType(iB, iS, MaPipsPeriod, Symbol(), DiffPair, Direction, Period(), MODE_SMA);
       break;
     case 3:
       getStochType(iB, iS, Symbol(), DiffPair, Direction, Period());
       break;
     case 1:
     default:
       getStdDevType(iB, iS, StdDevPeriod, Symbol(), DiffPair, Direction, Period(), MODE_SMA);
       break;
   }
}

// Stoch method
// function set global variable BBuff, SBuff, DBuff
// direction [1;-1]
void getStochType(int iB, int iS, string BuyPair, string SellPair, int direction = 1, int TimeFrame = 0){
   // stochastic
   BBuff = smothStoch(iB, TimeFrame, SmothCurveFactor, BuyPair,  Kperiod, Dperiod, Slowing);
   SBuff = smothStoch(iS, TimeFrame, SmothCurveFactor, SellPair, Kperiod, Dperiod, Slowing);
   if(Direction == 1){
     DBuff = BBuff - SBuff;
   }else{
     DBuff = BBuff - (100 - SBuff);
   }
}

// vyhlazeni krivky stochasticu
double smothStoch(int position, int TimeFrame, int period, string pair, int PK, int PD, int PS ){
   // vyzazeni vyhlazovani aktualniho baru
   if(NoSmothActualBar == true && position == 0){
     period = 0;
   }
   double result = 0.0;
   for(int x=0;x<=period;x++){
     result += iStochastic(pair, TimeFrame, PK, PD, PS, MODE_SMA, 0, MODE_SIGNAL, position+x);
   }
   result /= (period + 1);
   return(result);
}

// MAPips method
// function set global variable BBuff, SBuff, DBuff
// direction [1;-1]
void getMAPipsType(int iB, int iS, int period, string BuyPair, string SellPair, int direction = 1, int TimeFrame = 0, int MaMethod = MODE_SMA){
   // moving average
   double MAB = iMA(BuyPair,  TimeFrame, period, 0, MaMethod, PRICE_CLOSE, iB);
   double MAS = iMA(SellPair, TimeFrame, period, 0, MaMethod, PRICE_CLOSE, iS);
   
   // pips distance
   MAB = convertPointPrice(BuyPair, MAB - iClose(BuyPair, TimeFrame, iB));
   MAS = convertPointPrice(SellPair, MAS - iClose(SellPair, TimeFrame, iS));
    
   // global variables
   BBuff = MAB;
   SBuff = MAS * direction;
   DBuff = BBuff - SBuff;
}

// StdDev method
// function set global variable BBuff, SBuff, DBuff
// direction [1;-1]
void getStdDevType(int iB, int iS, int period, string BuyPair, string SellPair, int direction = 1, int TimeFrame = 0, int MaMethod = MODE_SMA){
   // moving average
   double MAB = iMA(BuyPair,  TimeFrame, period, 0, MaMethod, PRICE_CLOSE, iB);
   double MAS = iMA(SellPair, TimeFrame, period, 0, MaMethod, PRICE_CLOSE, iS);
      
   // standard deviation Buy
   double s = 0.0;
   for(int j = 0; j < period; j++) s += MathPow(MAB - iClose(BuyPair, TimeFrame, j+iB),2);      
   double DevB = MathSqrt(s / (period-1));
   if(DevB == 0) DevB = 0.00001; // divide zero protection ;)
   
   // standard deviation Sell  
   s = 0.0;
   for(j = 0; j < period; j++) s += MathPow(MAS - iClose(SellPair, TimeFrame, j+iS),2);      
   double DevS = MathSqrt(s / (period-1));
   if(DevS == 0) DevS = 0.00001; // divide zero protection ;)
      
   // global variables
   BBuff = (iClose(BuyPair, TimeFrame, iB) - MAB) / DevB;
   SBuff = ((iClose(SellPair, TimeFrame, iS) - MAS) / DevS) * direction;
   DBuff = BBuff - SBuff;
}

//prevede cenu na body (price1 - price2) => pips
double convertPointPrice(string symbol, double price){
 double point = MarketInfo(symbol, MODE_POINT);  
 if(point == 0.00001)
   return(price / (point*10));
 if(point == 0.0001)
   return(price / (point));
 if(point == 0.001)
   return(price / (point*10));
 if(point == 0.01)
   return(price / (point));
}

//prevede body na cenu
double convertPoint(string symbol, double price){
 double point = MarketInfo(symbol, MODE_POINT);  
 if(point == 0.00001)
   return(price * (point*10));
 if(point == 0.0001)
   return(price * (point));
 if(point == 0.001)
   return(price * (point*10));
 if(point == 0.01)
   return(price * (point));
}

// preparsovani hodnot oddelenych lomitkem do pole
void valuesToDoubleArray(double &aResult[], string &values, string delimiter = ","){
   // vymazani pole
   ArrayResize(aResult,0);
   int s = 0;
   int i = 0;
   string current;
   // dodani posledni carky kvuli podpore i jednoho 
   if (StringSubstr(values,StringLen(values),1) != delimiter){
     values = StringConcatenate(values, delimiter);
   }
   // prvni vyskyt
   i = StringFind(values, delimiter, s);
   // dokud tam neco je tak parsujeme
   while (i > 0){
     current = StringSubstr(values, s, i-s); // vyparsovani prvni hodnoty
     ArrayResize(aResult,ArraySize(aResult)+1); // pridame dalsi pozici
     aResult[ArraySize(aResult)-1] = StrToDouble(current); // pridame dalsi hodnotu
     s = i + 1;
     i = StringFind(values, delimiter, s); // dalsi vyskyt
   }
}

// vypocet hodnoty kvantilu dle vstupnich dat
// aData - double hodnoty v poli
// perceptil - hodnota v procentech (25 1.kvartil, 50 median/2. kvartil, 75 3.kvartil)
double calculatePercentile(double aData[], double perceptil = 50){
  double qKoef = perceptil * (ArraySize(aData) + 1) / 100.0; // koeficient, napr. 8.25
  // serazeni dat dle hodnot
  ArraySort(aData);
  // pokud je qKoef vetsi jak max hodnota vracime max hodnotu
  if(qKoef > ArraySize(aData)){
    return(aData[ArraySize(aData)-1]);
  }
  if(qKoef < 1){
    return(aData[0]);
  }
  // ziskani min a max hodnoty
  int qMin = MathFloor(qKoef); // 8
  int qMax = MathCeil(qKoef);  // 9
  // vytazeni vlastnich hodnot
  double dMin = aData[qMin-1]; // 10
  double dMax = aData[qMax-1]; // 20
  // linearni interpolace TODO lze interpolovat nekolika zpusoby
  double qValue = dMin + ((dMax - dMin) * (qKoef - qMin)); // 10 + ((20-10) * (8.25 - 8)) => 10 + (10*.25) = 12.5
  return(qValue);
}

// nakresli a stanovi linky
void drawAlertLines(){
   // pokud byly jiz vykresleny tak je nevykreslujeme
   if(drawAlertLineOnlyOnce == true) return(0);
   int pos = 0;
   // pokud se jedna o value tak vykreslime klasicke linky
   if(AlertSystem != "Percentile"){
     // klasicke linky dle hodnoty
     SetLevelValue(pos, 0);
     pos++;
     SetLevelStyle(STYLE_DOT, 0, DimGray);
     for(i=0; i=0; i--){
       getEDiffValues(i);
       qData[i] = MathAbs(DBuff);
     }
     double qValue;
     SetLevelStyle(STYLE_DOT, 0, DimGray);
     for(i=0; i 0){
    // obchodujeme!
    ArrowStart[0] = DBuff; // nova online hodnota, zaznamename hodnotu close
    sendEAOpenBuy(DBuff);
  }
}

// zobrazovani a vyskakovani alertu dle linek
void calculateBackAlertSystem(int limit){
  if(bCalculatedBackData == true) return; // pocitame pouze pri nacteni indi, pak uz jedeme online
  int iRes;
  for(i = limit; i>=0; i--){
    // ziskame data
    getEDiffValues(i);
    // projedeme alert pole
    iRes = raiseAlert(DBuff,i);
    if(iRes == -1){
      // Uzavirame!
      ArrowStop[i] = DBuff;
    }
    if(iRes > 0){
      // obchodujeme!
      ArrowStart[i] = DBuff;
    }
  }
  bCalculatedBackData = true;
}

// zobrazovani a vyskakovani alertu dle linek
void calculateSimulatedProfit(int limit){
  if(CalculateProft != true) return(0);
  if(calculatedProfit == true) return(0);
  // numovani promennych
  double aMAE[], aMFE[], acMAE[], acMFE[];
  if(ExportTradeToCsv == true){
    // exportujeme do CSV souboru
    int FileHandle;
    string FileName = ShortName+"_"+Symbol()+"_"+DiffPair+"_"+Period()+"_equity_pips.csv";
    FileHandle=FileOpen(FileName,FILE_CSV|FILE_WRITE);
    FileWrite(FileHandle,"Date","PIPS","MAE","MFE","EQUITY","   ","FINAL PIPS","FINAL EQUITY");
  }
  int iRes;
  int iSize;
  double dProfit;
  datetime iDate;
  // pro prepocitani profitu
  double aProfit[];
  int    aI[];
  // smycka vypoctu
  for(i = limit; i>=0; i--){
    // ziskame data
    getEDiffValues(i);
    // projedeme alert pole
    iRes = raiseAlert(DBuff, -1);
    if(iRes == -1){
      dProfit = simulatedCloseTrade(i, DBuff);
      // pridani popisku
      ProfitLabelCreate(dProfit, i);
      // pridani do MAE a MFE
      iSize = ArraySize(aMAE);
      ArrayResize(aMAE, iSize+1);
      ArrayResize(acMAE, iSize+1);
      ArrayResize(aMFE, iSize+1);
      ArrayResize(acMFE, iSize+1);
      ArrayResize(aProfit, iSize+1);
      ArrayResize(aI, iSize+1);
      aMAE[iSize]  = MAE;
      acMAE[iSize] = MAE;
      aMFE[iSize]  = MFE;
      acMFE[iSize] = MFE;
      aProfit[iSize] = dProfit;
      aI[iSize] = i;
    }
    if(iRes > 0){
      // obchodujeme!
      addSimulatedTrade(ProfitStackArrayI, i); // otevirana pozice
    }
  }
  
  // vyhodnoceni MAE a MFE
  globalMAE = calculatePercentile(acMAE, MAEPercentil);
  globalMFE = calculatePercentile(acMFE, MFEPercentil);

  // prepocet podle MAE a MFE
  double onlyProfit      = 0.0; // pouze hodnota puvodniho profitu
  double onlyAfterProfit = 0.0; // pouze hodnota noveho profitu
  int    afterTPMFE      = 0;   // kolikrat jsme zasahli MFE profit
  double onlyLoss        = 0.0; // jen puvodni ztraty
  double onlyAfterLoss   = 0.0; // jen nove ztraty
  int    afterSLMAE      = 0;   // kolikrat jsme zasahli MAE
  double pdProfit        = 0.0; // docasna promenna
  double SimulatedProfit = 0.0; // simulovanyu profit
  double SAfterProfit    = 0.0; // simulovanyu profit po MAE a MFE
  // projedeme zaznamenane obchody
  for(int j=0; j 0){
      onlyProfit += aProfit[j];
    }else{
      onlyLoss += aProfit[j];
    }
    SimulatedProfit += aProfit[j];
    // aktivovana MAE?
    pdProfit = 0.0;
    if(aMAE[j] <= globalMAE){
      // tak to jsme presahli, takze bereme ztratu
      pdProfit = globalMAE;
      afterSLMAE++;
    }else{
      // aktivovana MFE?
      if(aMFE[j] >= globalMFE){
        // dosahli jsme profitu
        afterTPMFE++;
        pdProfit = globalMFE;
      }else{
        // nevylo aktivovano nic, tedy profit tak jak je
        pdProfit = aProfit[j];
      }
    }
    // rozdeleni typu
    if(pdProfit > 0){
      onlyAfterProfit += pdProfit;
    }else{
      onlyAfterLoss += pdProfit;
    }
    SAfterProfit += pdProfit;
    if(ExportTradeToCsv == true){
      // ukladani do souboru
      iDate = iTime(Symbol(),0,aI[j]);
      FileWrite(FileHandle,TimeToStr(iDate, TIME_DATE|TIME_MINUTES), aProfit[j], aMAE[j], aMFE[j], SimulatedProfit, "", pdProfit, SAfterProfit);
    }
  }
  // Zobrazeni vysledku
  string profitFrom = TimeToStr(iTime(Symbol(), 0, limit),TIME_DATE);
  TextCreate(StringConcatenate("SimulatedProfit: ", DoubleToStr(SimulatedProfit,1)," pips from: ",profitFrom), 4, Gray, 4, 48);
  TextCreate(StringConcatenate("MAE: ", DoubleToStr(MathAbs(aMAE[ArrayMinimum(aMAE)]),1),", MFE: ",DoubleToStr(aMFE[ArrayMaximum(aMFE)],1),
             ", SL: ",DoubleToStr(MathAbs(globalMAE),1), " => TP: ",DoubleToStr(globalMFE,1)), 14, Gray, 4, 59);
  TextCreate(StringConcatenate("After MAE MFE Profit: ", DoubleToStr(SAfterProfit,1),", SL/TP: ",DoubleToStr(afterSLMAE,0),"/",DoubleToStr(afterTPMFE,0)), 15, Gray, 4, 70);
  TextCreate(StringConcatenate("Original P/L: ",DoubleToStr(onlyProfit,0),"/", DoubleToStr(onlyLoss,0), ", After P/L: ",DoubleToStr(onlyAfterProfit,0),"/",DoubleToStr(onlyAfterLoss,0)), 16, Gray, 4, 81);
  // uzavreni souboru
  if(ExportTradeToCsv == true){
    // uzavreni
    FileClose(FileHandle);
    // send message about file
    SendMessage(StringConcatenate(ShortName," Export to CSV done! saved in experts\files\\",FileName));
  }
  calculatedProfit = true;
}

// pridani zaznamu do pole
void addSimulatedTrade(int &PositionArray[], int position){
  int arrSize = ArraySize(PositionArray);
  ArrayResize(PositionArray, arrSize+1);
  PositionArray[arrSize] = position;
}

// simulovane uzavreni obchodu - vraci pocet pips
double simulatedCloseTrade(int position, double dBuffValue){
  // uzavirani a pocitani pozic
  MAE = 0.0;         // hlavni
  double dMAE = 0.0; // pomocna
  MFE = 0.0;         // hlavni
  double dMFE = 0.0; // pomocna
  // cena
  double dSPrice = 0.0; // docasna
  double dValue = 0.0;  // cilova
  // typ
  int iType = 0;
  int j;
  if(dBuffValue > 0){
    iType = 1;
  }else{
    iType = -1;
  }
  // profit calculation
  for(j=0; j 0 - alert cislo; -1 - close all
// dValue - aktualni hodnota (diff value)
int raiseAlert(double dValue, int i){
  // projedeme pole alertu
  if(i == 0) return(0);
  int iRet = 0;
  for(int j=0; j AlertArrayValues[j]){
        // mame prekrocenou hodnotu Alert!
        AlertStackArrayS[j] = true;
        // vracime znacku
        iRet = j+1;
      }
    }else{
      if(dValue <= (StopLevelValue * (-1))){
        // resetujeme promenne
        arrayInitialize(AlertStackArrayS, false);
        // vracime znacku
        return(-1);
      }
    }
    // pro buy 
    if(AlertStackArrayB[j] == false){
      // pokud jdme toto jeste preprojeli
      if(dValue < (AlertArrayValues[j] * (-1))){
        // mame prekrocenou hodnotu Alert!
        AlertStackArrayB[j] = true;
        // vracime znacku
        iRet = j+1;
      }
    }else{
      if(dValue >= StopLevelValue){
        // resetujeme promenne
        arrayInitialize(AlertStackArrayB, false);
        // TODO zavirame
        // vracime znacku
        return(-1);
      }
    }
  }
  return(iRet);
}

// mame vyvolat trade alert?
// trade alert funguje pouze pokud je aktualni bar 0
// vraci 0 - nic se nedeje; N > 0 - alert cislo; -1 - close all
// dValue - aktualni hodnota (diff value)
int tradeAlert(double dValue, int i){
  // projedeme pole alertu
  int iRet = 0;
  for(int j=0; j AlertArrayValues[j]){
        // filtrace spreadu
        if(FilterSpread == true && Spread > FSpreadMax) continue;
        // filtrace na cas
        if(FilterHours == true && isTradeHours(TradeFrom, TradeTo) != true) continue;
        // zvysime tick u tohoto pole a dokud nebude MinTickCount tak alert nevyvolavame
        TradeTickArrayS[j]++;
        // pokud jiz mame tak vyvolavame Alert
        if(TradeTickArrayS[j] >= AlertMinTickCount){
          // mame prekrocenou hodnotu Alert!
          TradeStackArrayS[j] = true;
          addTradeStackArrayGlobal(sTradeStackArrayGlobalS, j);
          // vracime znacku
          iRet = j+1;
          // reset tickcount
          TradeTickArrayS[j] = 0;
        }
      }else{
        TradeTickArrayS[j] = 0; // reset tickcount
      }
    }else{
      if(dValue <= (StopLevelValue * (-1))){
        // resetujeme promenne
        arrayInitialize(TradeStackArrayS, false);
        resetTradeStackArrayGlobal(sTradeStackArrayGlobalS); // reset globalnich promenny kvuli zapamatovani stavu
        ArrayInitialize(TradeTickArrayS, 0);
        // vracime znacku na zavreni
        return(-1);
      }
    }
    // pro buy 
    if(TradeStackArrayB[j] == false){
      // pokud jdme toto jeste preprojeli
      if(dValue < (AlertArrayValues[j] * (-1))){
        // filtrace spreadu
        if(FilterSpread == true && Spread > FSpreadMax) continue;
        // filtrace na cas
        if(FilterHours == true && isTradeHours(TradeFrom, TradeTo) != true) continue;
        // zvysime tick u tohoto pole a dokud nebude MinTickCount tak alert nevyvolavame
        TradeTickArrayB[j]++;
        // pokud jiz mame tak vyvolavame Alert
        if(TradeTickArrayB[j] >= AlertMinTickCount){
          // mame prekrocenou hodnotu Alert!
          TradeStackArrayB[j] = true;
          addTradeStackArrayGlobal(sTradeStackArrayGlobalB, j);
          // vracime znacku na otevreni
          iRet = j+1;
          // reset tickcount
          TradeTickArrayB[j] = 0;
        }
      }
    }else{
      if(dValue >= StopLevelValue){
        // resetujeme promenne
        arrayInitialize(TradeStackArrayB, false);
        resetTradeStackArrayGlobal(sTradeStackArrayGlobalB); // reset globalnich promenny kvuli zapamatovani stavu
        ArrayInitialize(TradeTickArrayB, 0);
        // vracime znacku
        return(-1);
      }
    }
  }
  return(iRet);
}

// prepocet quantil dat
void recalculateQuantilData(){
  if(AlertSystem != "Percentile") return(0); // nyni nic neresime
  if(isNewBar(newBar) == true){
    // mameno novy bar
    qRecalcBars--;
    if(qRecalcBars <= 0){
      // provadime prepocet
      qRecalcBars = AlertPRecalcBars;
      drawAlertLineOnlyOnce = false;
    }
  }
}

bool isNewBar(datetime &newBar){
  // obchodujeme pouze na novy bar
  if(newBar != iTime(NULL, Period(), 1)){
    newBar = iTime(NULL, Period(), 1);
    return(true);
  }else{
    return(false); // neobchodujeme
  }
}

// odesilani zprav
void SendMessage(string message, bool toComment = false){
  Print(message);
  if(SendAlert == true) Alert(message);
  if(SendEmail == true) SendMail(StringConcatenate(TimeToStr(TimeCurrent(), TIME_SECONDS)," ",message),"");
  if(toComment == true) Comment(message);
}

// zobrazi texty
void initText(){

   // zobrazovat aktualni stav levelu
   if(ShowAlertLevelStatus == true){
     string sLevelsB = "";
     string sLevelsS = "";
     for(int j=0; j FSpreadMax) Clr = Red;
     TextCreate("Spread: "+DoubleToStr(Spread, 2)+" / "+DoubleToStr(FSpreadMax, 2), 10, Clr, 4, 136);
   }else{
     TextCreate("Spread monitoring: OFF", 10, Clr, 4, 136);
   }
   
   // zobrazovani filtrace casu
   if(FilterHours == true){
     if(isTradeHours(TradeFrom, TradeTo) == true){
       Clr = SeaGreen;
     }else{
       Clr = Red;
     }
     TextCreate("TradeTime: "+TradeFrom+" - "+TradeTo, 8, Clr, 4, 125);
   }else{
     TextCreate("FilterHours: OFF", 8, SeaGreen, 4, 125);
   }
   
   if(isInit == true) return(true);
   
   // korelace
   TextCreate(StringConcatenate("Corelation: ", DoubleToStr(correlValue*100,0),"% / ",CorelationD1Period,"D1"), 3, Gold, 4, 37);
   
   // zobrazovani magickNumbers
   if(ShowMagickNumber == true){
     TextCreate("MagickNumber: "+ManualMagickNumber, 7, Peru, 4, 114);
   }
   
   if(Direction == 1){
     TextCreate(StringConcatenate("BUY:", Symbol()),  1, ForestGreen, 4, 26);
     TextCreate(StringConcatenate("SELL:", DiffPair), 2, Tomato,      4, 15);
   }else{
     TextCreate(StringConcatenate("BUY:",Symbol(),",",DiffPair),  1, ForestGreen, 4, 26);
     TextCreate("SELL:", 2, Tomato,      4, 15);
   }
   
   isInit = true; // provedeme pouze jednou
   return(true);
}

// vypisuje textove hlaseni do okna indikatoru
void TextCreate(string txt, int ObjId = 0, color col = White, int x = 0, int y = 0, int FontSize = 7){
   if(HWND < 0) return(0);
   string ID = StringConcatenate(Indicator_Name, "_", ObjId);
   if(ObjectFind(ID) != 1){
     ObjectCreate(ID, OBJ_LABEL, HWND, 0, 0);
     ObjectSet(ID, OBJPROP_XDISTANCE, x);
     ObjectSet(ID, OBJPROP_YDISTANCE, y);
   }
   ObjectSetText(ID, txt, FontSize, "Verdana", col);
}

// vypocet korelace
double getCorrelationPairs(string Symbol1, string Symbol2, int TimeFrame, int periods, int position = 0){
	datetime closeTime1	= iTime(Symbol1,TimeFrame,position),
				closeTime2	= iTime(Symbol2,TimeFrame,position),
				closeTime	= MathMin(closeTime1,closeTime2);
	int		shift1		= iBarShift(Symbol1,TimeFrame,closeTime),
				shift2		= iBarShift(Symbol2,TimeFrame,closeTime);
	double	Co,
	         close1[],
				close2[];
	ArrayCopySeries(close1,MODE_CLOSE,Symbol1,TimeFrame);
	ArrayCopySeries(close2,MODE_CLOSE,Symbol2,TimeFrame);
	int bars = MathMin(ArraySize(close1)-shift1,ArraySize(close2)-shift2);
	if ( periods > 0 )
	     bars = periods;
   Co = Correlation(close1,close2,shift1,shift2,bars);
   return(Co);
}

//+------------------------------------------------------------------+
//| Correlation Coefficient R														|
//+------------------------------------------------------------------+
double Correlation(double x[], double y[], int x_shift = 0, int y_shift = 0, int count = -1){
	int n = MathMin(ArraySize(x)-x_shift,ArraySize(y)-y_shift);
	if(n>count && count>0)
		n=count;
	if(n<2)
		return(-2);
	double	sum_sq_x,
				sum_sq_y,
				sum_coproduct,
				mean_x = x[x_shift],
				mean_y = y[y_shift];
	for(int i = 0; i < n; i++){
		double	sweep = i / (i+1.0),
					delta_x = x[i+x_shift] - mean_x,
					delta_y = y[i+y_shift] - mean_y;
		sum_sq_x += delta_x*delta_x * sweep;
		sum_sq_y += delta_y*delta_y * sweep;
    	sum_coproduct += delta_x*delta_y * sweep;
    	mean_x += delta_x / (i+1.0);
    	mean_y += delta_y / (i+1.0);
	}
	double	pop_sd_x = MathSqrt(sum_sq_x/n),
				pop_sd_y = MathSqrt(sum_sq_y/n),
				cov_x_y = sum_coproduct / n;
	if(pop_sd_x*pop_sd_y != 0.0)
		return(cov_x_y / (pop_sd_x*pop_sd_y));
	return(-3);
}

/**
* create a positive integer for the use as a magic number.
*
* The function takes a string as argument and calculates
* an 31 bit hash value from it. The hash does certainly not 
* have the strength of a real cryptographic hash function 
* but it should be more than sufficient for generating a
* unique ID from a string and collissions should not occur.
*
* use it in your init() function like this: 
*    magic = makeMagicNumber(WindowExpertName() + Symbol() + Period());
*
* where name would be the name of your EA. Your EA will then
* get a unique magic number for each instrument and timeframe
* and this number will always be the same, whenever you put
* the same EA onto the same chart.
*
* Numbers generated during testing mode will differ from those
* numbers generated on a live chart.
*/
int makeMagicNumber(string key){
   int i, k;
   int h = 0;
   if (IsTesting()){
      key = "_" + key;
   }
   for (i=0; i0; i--){   
      k = StringGetChar(key, i - 1);
      h = h + k;
      // rotate depending on the last 4 bits of h
      h = bitRotate(h, h & 0x0000000F); 
   }
   return(h & 0x7fffffff);
}

/**
* Rotate a 32 bit integer value bit-wise 
* the specified number of bits to the right.
* This function is needed for calculations
* in the hash function makeMacicNumber()
*/
int bitRotate(int value, int count){
   int i, tmp, mask;
   mask = (0x00000001 << count) - 1;
   tmp = value & mask;
   value = value >> count;
   value = value | (tmp << (32 - count));
   return(value);
}

// prevody timeframe
string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,15,30,60,240,1440,10080,43200};

// vraci timeframe podle retezce
int stringToTimeFrame(string tfs){
   tfs = StringUpperCase(tfs);
   for (int i=ArraySize(iTfTable)-1; i>=0; i--){
     if (tfs==sTfTable[i] || tfs==""+iTfTable[i]){
       //return(MathMax(iTfTable[i],Period()));
       return(iTfTable[i]);
     }
   }
   return(Period());
}
// vraci string timeframe podle hodnoty
string timeFrameToString(int tf){
   for (int i=ArraySize(iTfTable)-1; i>=0; i--){
     if (tf==iTfTable[i]){
       return(sTfTable[i]);
     }
   }
   return("");
}

// prevod na velka pismena
string StringUpperCase(string str){
   string   s = str;
   int      lenght = StringLen(str) - 1;
   int      char;
   while(lenght >= 0){
     char = StringGetChar(s, lenght);
     if((char > 96 && char < 123) || (char > 223 && char < 256)){
       s = StringSetChar(s, lenght, char - 32);
     }else {
       if(char > -33 && char < 0){
         s = StringSetChar(s, lenght, char + 224);
       }
     }
     lenght--;
   }
   return(s);
}

// odeslani uzavreni do EAcka
void sendEAClose(){
  if(TradeEdiEAAllowed != true) return;
  GlobalVariableSet(sClose, 1);
  sendEATick();
}

// otevreni obchodu v EA
void sendEAOpenBuy(double &DBuff){
  // open message
  SendMessage(StringConcatenate(ShortName," ",Symbol(),"/",DiffPair," TRADE!"));
  // filtrace na obchodovani
  if(TradeEdiEAAllowed != true) return;
  // smer obchodu
  if(DBuff > 0){
    // sell
    GlobalVariableSet(sOpenS, 1);
  }else{
    // buy
    GlobalVariableSet(sOpenB, 1);
  }
  // nastaveni MAE a MFE
  GlobalVariableSet(sMAE, globalMAE);
  GlobalVariableSet(sMFE, globalMFE);
  sendEATick();
}

#import "user32.dll"
   int PostMessageA(int hWnd, int Msg, int wParam, int lParam);
   int RegisterWindowMessageA(string lpString);
#import

// odeslani ticku EAck
void sendEATick(){
  int hWnd = WindowHandle(Symbol(), Period());
  if(hWnd == 0) return(0);
  int MT4InternalMsg = RegisterWindowMessageA("MetaTrader4_Internal_Message");
  PostMessageA(hWnd, MT4InternalMsg, 2, 1); // fake tick send
}

// Test zda jsme v danem case, POZOR v testu vraci true!
bool isTradeHours(string dFrom = "23:00", string dTo = "23:30"){
  if(IsTesting() == true) return(true); // v prubehu restovani 
  // prepocet casu na desetine cislo
  datetime FromHour = StrToTime(dFrom);
  datetime ToHour = StrToTime(dTo);
  datetime Now = StrToTime(StringConcatenate(Hour(),":",Minute()));
  if(FromHour < ToHour){
    // klasicke reseni
    if(FromHour <= Now && Now <= ToHour){
      return(true);
    }else{
      return(false);
    }
  }else{
    // je to obracene tedy musime do pulnoci a od pulnoci dal
    datetime MidnightB = StrToTime("23:59:59");
    datetime MidnightA = StrToTime("00:00:00");
    if((FromHour <= Now && Now <= MidnightB) || (Now >= MidnightA && Now <= ToHour)){
      return(true);
    }else{
      return(false);
    }
  }
}

// vytvori ukazatel ceny pokud o nej mame zajem
void createPriceLabel(double price){
   if(ShowPriceLabel != true) return;
   if(HWND < 0) return(0);
   string ID = StringConcatenate(Indicator_Name,"_9");
   if(ObjectFind(ID) != 1){
     ObjectCreate(ID, OBJ_ARROW, HWND, Time[0], price);
     ObjectSet(ID, OBJPROP_COLOR, DodgerBlue);
     ObjectSet(ID, OBJPROP_ARROWCODE, 6);
   }
   ObjectSet(ID, OBJPROP_PRICE1, price);
   ObjectSet(ID, OBJPROP_TIME1, Time[0]);
}

// velikost spreadu v bodech
double getSpreadBySymbol(string symbol){ 
 double point = MarketInfo(symbol, MODE_POINT);  
 if(point == 0.00001)
   return((MarketInfo(symbol, MODE_ASK) - MarketInfo(symbol, MODE_BID)) / (point*10));
 if(point == 0.0001)
   return((MarketInfo(symbol, MODE_ASK) - MarketInfo(symbol, MODE_BID)) / (point));
 if(point == 0.001)
   return((MarketInfo(symbol, MODE_ASK) - MarketInfo(symbol, MODE_BID)) / (point*10));
 if(point == 0.01)
   return((MarketInfo(symbol, MODE_ASK) - MarketInfo(symbol, MODE_BID)) / (point));
}

// vytvori linku
void createHorizontalLine(double value, color Clr, int number){
   if(HWND < 0) return(0);
   string ID = StringConcatenate(Indicator_Name,"_",number);
   ObjectCreate(ID, OBJ_HLINE, HWND, 0, value);
   ObjectSet(ID, OBJPROP_COLOR, Clr);
   ObjectSet(ID, OBJPROP_STYLE, STYLE_DOT);
   ObjectSet(ID, OBJPROP_WIDTH, 0);
   ObjectSet(ID, OBJPROP_BACK, true);
}

// premazavani promennych
void arrayInitialize(bool &array[], bool value){
  for(int j=0; jBuy, -1=>Sell
// iDirection: 1=>Positive, -1=>Negative
// nastavuje promenne dMAE, dMFE, dProfit
void calculateMaeMfeProfit(string sBuy, string sSell,
                           int iType, int iDirection,
                           int iOpenPosition, int iClosePosition,
                           double &dMAE, double &dMFE, double &dProfit,
                           int iFromTF = PERIOD_M5, int iToTF = PERIOD_M1,
                           double dBuySpread = 1.6, double dSellSpread = 1.6){
  // promenne
  double summ_sell_min    = 0.0,
         summ_sell_max    = 0.0,
         summ_buy_min     = 0.0,
         summ_buy_max     = 0.0,
         summ_buy_profit  = 0.0,
         summ_sell_profit = 0.0,
         summMAE          = 0.0,
         summMFE          = 0.0;
  double dBSpread         = convertPoint(sBuy,  dBuySpread);
  double dSSpread         = convertPoint(sSell, dSellSpread);
  // najdeme startovaci a ukoncovaci bar
  datetime DateFrom = iTime(sBuy, iFromTF, iOpenPosition);
  datetime DateTo   = iTime(sBuy, iFromTF, iClosePosition);
  // Buy svice
  int iShiftFromB = iBarShift(sBuy, iToTF, DateFrom)-(iFromTF / iToTF); // najdeme bar od ktereho budeme analyzu projizdet
  int iShiftToB   = iBarShift(sBuy, iToTF, DateTo)-(iFromTF / iToTF); // najdeme bar ktery je posledni
  // Sell svice (musi byt extra protoze u jenoho paru muze chybet nejaka svice a pak se to cele neprijeme posune)
  int iShiftFromS = iBarShift(sSell, iToTF, DateFrom)-(iFromTF / iToTF); // najdeme bar od ktereho budeme analyzu projizdet
  int iShiftToS   = iBarShift(sSell, iToTF, DateTo)-(iFromTF / iToTF); // najdeme bar ktery je posledni
/*
  if(jenjednou == true){
    jenjednou = false;
    Print("FROM: "+ TimeToStr(iTime(sSell, iFromTF, iOpenPosition),TIME_DATE|TIME_MINUTES|TIME_SECONDS)+" ="+iShiftFrom);
    Print("TO: "+ TimeToStr(iTime(sSell, iFromTF, iClosePosition),TIME_DATE|TIME_MINUTES|TIME_SECONDS)+" ="+iShiftTo);
    Print("TMFROM: "+ TimeToStr(iTime(sSell, iToTF, iShiftFrom),TIME_DATE|TIME_MINUTES|TIME_SECONDS)+" ="+iShiftFrom);
    Print("TMTO: "+ TimeToStr(iTime(sSell, iToTF, iShiftTo),TIME_DATE|TIME_MINUTES|TIME_SECONDS)+" ="+iShiftTo);
    Print("BUY 1OPEN: "+iOpen(sSell,  iToTF, iShiftFrom));
    Print("BUY 2OPEN: "+iOpen(sSell,  iToTF, iShiftTo));
          double sb1  = convertPointPrice(sBuy, iOpen(sBuy, iToTF, iShiftFrom) - (iOpen(sBuy, iToTF, iShiftTo) + dBSpread));
          double ss1 = convertPointPrice(sSell,  iOpen(sSell,  iToTF, iShiftTo) - (iOpen(sSell, iToTF, iShiftFrom) + dSSpread));
    Print("PROFIT = Buy:"+sb1+" Sell:"+ss1);
  }
*/
  // zjistime jaky pocet budeme projizdet, tim ze muze i nejakeho paru chybet svice bereme MAX pocet svici a ve vypoctu je pak omezujeme
  int iCount = MathMax(iShiftFromB - iShiftToB, iShiftFromS - iShiftToS);
  // projedeme Buy par a najdeme minimalni a maximalni hodnoty
  for(int q=iCount; q>=0; q--){
    //Print(iShiftFrom-q);
    // pocitame PL kvivku + max odnoty MAE a MFE
    if(iType == 1){
      // buy nakupujeme a sell prodavame
      if(iDirection == 1){
        // buy nakupujeme a sell prodavame
        // buy + spread za ask
        if(iShiftFromB-q >= iShiftToB){
          summ_buy_min = convertPointPrice(sBuy, iLow (sBuy, iToTF, iShiftFromB-q) - (iOpen(sBuy, iToTF, iShiftFromB) + dBSpread));
          summ_buy_max = convertPointPrice(sBuy, iHigh(sBuy, iToTF, iShiftFromB-q) - (iOpen(sBuy, iToTF, iShiftFromB) + dBSpread));
        }else{
          summ_buy_min = 0.0;
          summ_buy_max = 0.0;
        }
        // sell
        if(iShiftFromS-q >= iShiftToS){
          summ_sell_min = convertPointPrice(sSell, iOpen(sSell, iToTF, iShiftFromS) - (iHigh(sSell, iToTF, iShiftFromS-q) + dSSpread));
          summ_sell_max = convertPointPrice(sSell, iOpen(sSell, iToTF, iShiftFromS) - (iLow (sSell, iToTF, iShiftFromS-q) + dSSpread));
        }else{
          summ_sell_min = 0.0;
          summ_sell_max = 0.0;
        }
        // finalni profit pokud se jedna o posledni bar
        if(iShiftFromB-q == iShiftToB){
          summ_buy_profit = convertPointPrice(sBuy,  iOpen(sBuy,  iToTF, iShiftFromB-q) - (iOpen(sBuy, iToTF, iShiftFromB) + dBSpread));
        }
        if(iShiftFromS-q == iShiftToS){
          summ_sell_profit = convertPointPrice(sSell, iOpen(sSell, iToTF, iShiftFromS) - (iOpen(sSell, iToTF, iShiftFromS-q) + dSSpread));
        }
        summMAE = MathMin(summMAE, summ_buy_min + summ_sell_min);
        summMFE = MathMax(summMFE, summ_buy_max + summ_sell_max);
      }else{
        // buy nakupujeme a sell nakupujeme
        // buy + spread za ask
        if(iShiftFromB-q >= iShiftToB){
          summ_buy_min  = convertPointPrice(sBuy, iLow (sBuy, iToTF, iShiftFromB-q) - (iOpen(sBuy, iToTF, iShiftFromB) + dBSpread));
          summ_buy_max  = convertPointPrice(sBuy, iHigh(sBuy, iToTF, iShiftFromB-q) - (iOpen(sBuy, iToTF, iShiftFromB) + dBSpread));
        }else{
          summ_buy_min = 0.0;
          summ_buy_max = 0.0;
        }
        // sell
        if(iShiftFromS-q >= iShiftToS){
          summ_sell_min = convertPointPrice(sSell, iLow (sSell, iToTF, iShiftFromS-q) - (iOpen(sSell, iToTF, iShiftFromS) + dSSpread));
          summ_sell_max = convertPointPrice(sSell, iHigh(sSell, iToTF, iShiftFromS-q) - (iOpen(sSell, iToTF, iShiftFromS) + dSSpread));
        }else{
          summ_sell_min = 0.0;
          summ_sell_max = 0.0;
        }
        // finalni profit pokud se jedna o posledni bar
        if(iShiftFromB-q == iShiftToB){
          summ_buy_profit  = convertPointPrice(sBuy,  iOpen(sBuy,  iToTF, iShiftFromB-q) - (iOpen(sBuy,  iToTF, iShiftFromB) + dBSpread));
        }
        if(iShiftFromS-q == iShiftToS){
          summ_sell_profit = convertPointPrice(sSell, iOpen(sSell, iToTF, iShiftFromS-q) - (iOpen(sSell, iToTF, iShiftFromS) + dSSpread));
        }
        summMAE = MathMin(summMAE, summ_buy_min + summ_sell_min);
        summMFE = MathMax(summMFE, summ_buy_max + summ_sell_max);
      }
    }else{
      // buy prodavame a sell nakupujeme
      if(iDirection == 1){
        // buy prodavame a sell nakupujeme
        // buy prodavame
        if(iShiftFromB-q >= iShiftToB){
          summ_buy_min  = convertPointPrice(sBuy, iOpen(sBuy, iToTF, iShiftFromB) - (iHigh(sBuy, iToTF, iShiftFromB-q) + dBSpread));
          summ_buy_max  = convertPointPrice(sBuy, iOpen(sBuy, iToTF, iShiftFromB) - (iLow (sBuy, iToTF, iShiftFromB-q) + dBSpread));
        }else{
          summ_buy_min = 0.0;
          summ_buy_max = 0.0;
        }
        // sell nakupujeme
        if(iShiftFromS-q >= iShiftToS){
          summ_sell_min = convertPointPrice(sSell, iLow (sSell, iToTF, iShiftFromS-q) - (iOpen(sSell, iToTF, iShiftFromS) + dSSpread));
          summ_sell_max = convertPointPrice(sSell, iHigh(sSell, iToTF, iShiftFromS-q) - (iOpen(sSell, iToTF, iShiftFromS) + dSSpread));
        }else{
          summ_sell_min = 0.0;
          summ_sell_max = 0.0;
        }
        // finalni profit pokud se jedna o posledni bar
        if(iShiftFromB-q == iShiftToB){
          summ_buy_profit  = convertPointPrice(sBuy, iOpen(sBuy, iToTF, iShiftFromB) - (iOpen(sBuy, iToTF, iShiftFromB-q) + dBSpread));
        }
        if(iShiftFromS-q == iShiftToS){
          summ_sell_profit = convertPointPrice(sSell,  iOpen(sSell,  iToTF, iShiftFromS-q) - (iOpen(sSell, iToTF, iShiftFromS) + dSSpread));
        }
        summMAE = MathMin(summMAE, summ_buy_min + summ_sell_min);
        summMFE = MathMax(summMFE, summ_buy_max + summ_sell_max);
      }else{
        // buy prodavame a sell prodavame
        // buy prodavame
        if(iShiftFromB-q >= iShiftToB){
          summ_buy_min  = convertPointPrice(sBuy, iOpen(sBuy, iToTF, iShiftFromB) - (iHigh(sBuy, iToTF, iShiftFromB-q) + dBSpread));
          summ_buy_max  = convertPointPrice(sBuy, iOpen(sBuy, iToTF, iShiftFromB) - (iLow (sBuy, iToTF, iShiftFromB-q) + dBSpread));
        }else{
          summ_buy_min = 0.0;
          summ_buy_max = 0.0;
        }
        // sell
        if(iShiftFromS-q >= iShiftToS){
          summ_sell_min = convertPointPrice(sSell, iOpen(sSell, iToTF, iShiftFromS) - (iHigh(sSell, iToTF, iShiftFromS-q) + dSSpread));
          summ_sell_max = convertPointPrice(sSell, iOpen(sSell, iToTF, iShiftFromS) - (iLow (sSell, iToTF, iShiftFromS-q) + dSSpread));
        }else{
          summ_sell_min = 0.0;
          summ_sell_max = 0.0;
        }
        // finalni profit pokud se jedna o posledni bar
        if(iShiftFromB-q == iShiftToB){
          summ_buy_profit  = convertPointPrice(sBuy, iOpen(sBuy, iToTF, iShiftFromB) - (iOpen(sBuy, iToTF, iShiftFromB-q) + dBSpread));
        }
        if(iShiftFromS-q == iShiftToS){
          summ_sell_profit = convertPointPrice(sSell, iOpen(sSell, iToTF, iShiftFromS) - (iOpen(sSell, iToTF, iShiftFromS-q) + dSSpread));
        }
        summMAE = MathMin(summMAE, summ_buy_min + summ_sell_min);
        summMFE = MathMax(summMFE, summ_buy_max + summ_sell_max);
      }
    }
  }
  // nastavime finalni promenne
  dMAE = summMAE;
  dMFE = summMFE;
  dProfit = summ_buy_profit + summ_sell_profit;
}

void ProfitLabelCreate(double value, int pos = 0){
   if(HWND < 0) return(0);
   ipCount++;
   double price;
   string ID = StringConcatenate(Indicator_Name, "_P", ipCount);
   color clr;
   string s = "";
   if(value > 0){
     clr = Green;
     price = profitLabelLevel;
     s = "+";
   }else{
     clr = Red;
     price = profitLabelLevel * (-1);
   }
   clr = White;
   ObjectCreate(ID, OBJ_TEXT, HWND, Time[pos], price);
   ObjectSet(ID, OBJPROP_COLOR, clr);
   ObjectSetText(ID, StringConcatenate(s,DoubleToStr(value, 1)), 7, "Verdana", clr);
}

Recommend