ChartBuilder

Author: NavAlex
13 Views
4 Downloads
0 Favorites
ChartBuilder
//+------------------------------------------------------------------+
//|                                                 ChartBuilder.mq4 | 2.1 
//|                                                  Navoykov Alexey |
//|                                                alemail@yandex.ru |
//+------------------------------------------------------------------+

#property copyright "NavAlex"
#property link      "alemail@yandex.ru"

#property indicator_separate_window
#property indicator_buffers  8

#define CURRENT_SYMBOL  "%symbol%"

extern string Formula1              = CURRENT_SYMBOL;
extern string Formula2              = "";
extern string Formula3              = "";
extern string Formula4              = "";
extern string Formula5              = "";
extern string Formula6              = "";
extern string Formula7              = "";
extern string Formula8              = "";
extern string OnlyNumbers           = "";         // ðàçðåø¸ííûå íîìåðà ôîðìóë. Åñëè íè÷åãî íå óêàçàíî, òî èñïîëüçóþòñÿ âñå ôîðìóëû 
extern    int PrecisionDigits       = -1;         // òî÷íîñòü çíà÷åíèé (÷èñëî çíàêîâ ïîñëå çàïÿòîé). Åñëè -1, òî íàçíà÷àåòñÿ àâòîìàòè÷åñêè
extern   bool AutoScale             = false;      // àâòîìàñøòàáèðîâàíèå âñåõ ãðàôèêîâ
extern double TimeShiftFromMainChart_minutes = 0; // ñäâèæêà â ìèíóòàõ îòíîñèòåëüíî îñíîâíîãî ãðàôèêà
extern   bool BarTimeSyncMode_ByMinutes = true;   // åñëè true, òî ñèíõðîíèçàöèÿ ïî ìèíóòàì, èíà÷å ïî áàðàì
extern    int BarTimeSyncSize       = -1;         // èíòåðâàë ïðèâÿçêè äëÿ ñèíõðîíèçàöèè áàðîâ ÷óæèõ ñèìâîëîâ (êîëè÷åñòâî ìèíóò ëèáî êîëè÷åñòâî áàðîâ, â çàâèñèìîñòè îò ïàðàìåòðà BarTimeSyncMode_ByMinutes)
extern   bool OnlyClosePrice        = true;       // îòîáðàæàòü òîëüêî öåíû îòêðûòèÿ
extern    int DrawMode              = 0;          // ðåæèì îòðèñîâêè
extern string DrawModeDescription   =               "0-LINE, 1-SECTION, 2-HISTOGRAM, 3-POINTS";
extern  color Color1                = Yellow;   
extern  color Color2                = Lime;
extern  color Color3                = Aqua;
extern  color Color4                = DodgerBlue;
extern  color Color5                = Magenta;
extern  color Color6                = Red;
extern  color Color7                = Orange;
extern  color Color8                = White;
extern   bool LabelsOnTheRight      = 0;           // îòîáðàæàòü íàçâàíèÿ ãðàôèêîâ ñ ïðàâîé ñòîðîíû, èíà÷å ñ ëåâîé
extern   bool ShowBidAsk            = true;        // ïîêàçûâàòü áèä è àñê (ñèíòåòè÷åñêèå)
extern string Signal_ChartNumber    = "1";         // íîìåð ãðàôèêà, äëÿ êîòîðîãî óñòàíîâëåí ñèãíàë (ìîæíî óêàçàòü íåñêîëüêî ãðàôèêîâ)
extern string Signal_HighValue      = "";          // âåðõíåå ñèãíàëüíîå çíà÷åíèå
extern string Signal_LowValue       = "";          // íèæíåå cèãíàëüíîå çíà÷åíèå
extern string Signal_HighLine       = "";          // âåðõíÿÿ ñèãíàëüíàÿ ëèíèÿ
extern string Signal_LowLine        = "";          // íèæíÿÿ ñèãíàëüíàÿ ëèíèÿ
extern    int SaveToFile_ChartNumber= 0;           // íîìåð ãðàôèêà, çíà÷åíèÿ êîòîðîãî ñîõðàíÿþòñÿ â ôàéë
extern string SaveToFile_FileName   = "ChartBuilder.csv";
extern string SaveToFile_Delimiter  = ";";


double buffer0[], buffer1[], buffer2[], buffer3[], buffer4[], buffer5[], buffer6[], buffer7[];


bool   Exit;
bool   WrongWindow;
int    Window;
int    MainChartIndex;
int    IndDigits;
int    InitTime;
int    MaxCharts=8;
int    BuffersPerChart=1;
int    VLineTime;
bool   AllowGetPriceLine=0;
string VLine=" ";
string StatusLabel=" ";
string SignalLabel="";
string IndicatorName="";
string IndicatorPrefix="";
string DropWindowIdObject="ChartBuilder_DroppedWindowID";
string StartMessage="";

#define MAXCHARTS  8

string Formulas [MAXCHARTS];
string ChartLabels [MAXCHARTS];
string ChartLabels_ [MAXCHARTS];
string ChartErrorLabels [MAXCHARTS];
string ErrorChartText [MAXCHARTS];
string LineAsk [MAXCHARTS];
string LineBid [MAXCHARTS];
bool   ChartAllow [MAXCHARTS];
bool   ChartValid [MAXCHARTS];
color  Colors [MAXCHARTS];
int    PrintedError [MAXCHARTS][10];
bool   ChartCheckSignal[MAXCHARTS];
double AutoScaleRatio [MAXCHARTS];
double AutoScaleShift [MAXCHARTS];
int    AutoScale_BaseChart= 0;

#define FUNC_CLOSE      0
#define FUNC_OPEN       1
#define FUNC_HIGH       2
#define FUNC_LOW        3
#define FUNC_LINEOPEN   4
#define FUNC_LINECLOSE  5
#define FUNC_LINEHIGH   6
#define FUNC_LINELOW    7
#define FUNC_ATR        8
#define FUNC_MA         9
#define FUNC_STDDEV     10
#define FUNC_AD         11
#define FUNC_ADX        12
#define FUNC_CCI        13
#define FUNC_DEMARKER   14
#define FUNC_MACD       15
#define FUNC_RSI        16
#define FUNC_STOCHASTIC 17
#define FUNC_BANDS      18
#define FUNC_MOMENTUM   19
#define FUNC_ENVELOPES  20
#define FUNC_MYATR      21
#define FUNC_VOLUME     22
#define FUNC_ASK        23
#define FUNC_BID        24
#define FUNC_LAST       25
#define FUNC_MAXIMUM    26
#define FUNC_MINIMUM    27

#define FUNC_ABS        40
#define FUNC_LOG        41
#define FUNC_EXP        42
#define FUNC_MAX        43
#define FUNC_MIN        44
#define FUNC_RND        45
#define FUNC_ROUND      46
#define FUNC_FIXVALUE   50

#define DEFAULTFUNCCOUNT 100
#define PARAMCOUNT 10

string  DefaultFuncName [DEFAULTFUNCCOUNT];
int     DefaultFuncSymCount [DEFAULTFUNCCOUNT];
string  TemplateFuncName [200];
int     TemplateFuncParam [200][PARAMCOUNT];
double  FuncParam  [][PARAMCOUNT];
double  FuncParam1 [][PARAMCOUNT];
double  FuncParam2 [][PARAMCOUNT];
double  FuncParam3 [][PARAMCOUNT];
int     FuncTimeSerie[];
int     FuncCacheMinSize[];

int     FuncLastTime[100];
int     FuncLastType[100];
double  FuncLastValue[100];

#define CELLVALUE          0
#define CELLTYPE           1
#define CELLOPERATION      2
#define CELLNEXTCELL       3

#define SUMMAND            0
#define MULTIPLIER         1
#define POW                2

#define TYPE_VALUE         1
#define TYPE_FUNC          2

#define ERROR_FORMULA      1
#define ERROR_SYMBOL       2
#define ERROR_HISTORY      3
#define ERROR_ZERODIVIDE   4
#define ERROR_POW          5
#define ERROR_RECURSION    6

#define ALGORANGE1         100
#define ALGORANGE2         4
#define FUNCRANGE1         50

int     AlgoRange0;
double  Algorithms [][ALGORANGE1][ALGORANGE2];      // [formula][pos][cellparam]
double  AlgorithmsTotalPowRatio [][ALGORANGE1][2];  // [formula][pos][pow/ratio]
int     AlgoFunctions [][FUNCRANGE1];                // [formula][function]
bool    AlgoEnabled [100];             // [formula]
string  AlgoNames[];
int     Algo_BidAskAlgoIndex [100][4]; // [formula][pricetype]
string  Symbols[];
int     TimeSeries[][2];  //[][symindex/tf];
int     SymbolsIndexes [][FUNCRANGE1][2];  // [formula][symindex][param]
int     SymbolsFuncPos [][FUNCRANGE1][10]; // [formula][symindex][pos]
bool    FirstStart;
string  ErrorString;
int     Error;
double  CacheValueBuffer[];
int     CacheTimeBuffer[];
int     CacheStartPos[];
int     CachePos[];
int     CacheMinSize[];
bool    IsFormulaUsing[9];
bool    IsIndicator;
bool    Debug= 0;

bool    MyRatesAllow;    // ðàçðåøàåò ïîäñòàíîâêó ïîëüçîâàòåëüñêèõ ìàññèâîâ Rates âìåñòî èìåþùèõñÿ êîòèðîâîê ÌÒ4
double  MyRates[][6];   // ñþäà ïîìåùàåòñÿ ñòðóêòóðà Rates ñ ïîëüçîâàòåëüñêèìè çíà÷åíèÿìè äëÿ âñåõ èñïîëüçóåìûõ ñèìâîëîâ (äðóã çà äðóãîì)
int     MyRatesPos[][2]; // ñþäà ïîìåùàþòñÿ:  íà÷àëüíàÿ ïîçèöèÿ ìàññèâà Rates äëÿ êàæäîãî ñèìâîëà (ñóáèíäåêñ 0) è ðàçìåð ìàññèâà Rates äëÿ êàæäîãî ñèìâîëà (ñóáèíäåêñ 1)


//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
{ 
  //Debug=false;
  ArrayResize(Algorithms,0);
  ArrayResize(FuncParam,0);
  ArrayResize(Symbols,0);
  ArrayResize(TimeSeries,0);
  AlgoRange0=0;
  
  Exit=false;
  FirstStart=true;
  Window=-1;
  WrongWindow=false;
  StartMessage="";
  MaxCharts=0;
  int inittime=InitTime;
  InitTime=TimeLocal();
  if (inittime>0) return(0);
  
  SetFuncParameters("AD",        FUNC_AD, 0);
  SetFuncParameters("ADX",       FUNC_ADX, 0, 100);
  SetFuncParameters("ATR",       FUNC_ATR, 0, 100);
  SetFuncParameters("ATRD",      FUNC_ATR, PERIOD_D1, 100);
  SetFuncParameters("ATR2",      FUNC_MYATR, 1, 0, 100, 1);
  SetFuncParameters("Bands",     FUNC_BANDS, 0, 100);
  SetFuncParameters("CCI",       FUNC_CCI, 0, 100);
  SetFuncParameters("DeMarker",  FUNC_DEMARKER, 0, 100);
  SetFuncParameters("Envelopes", FUNC_ENVELOPES, 0, 100);
  SetFuncParameters("MA",        FUNC_MA, 0, 100); 
  SetFuncParameters("MAD",       FUNC_MA, PERIOD_D1, 100);
  SetFuncParameters("MACD",      FUNC_MACD, 0, 100, 200, 100);
  SetFuncParameters("Momentum",  FUNC_MOMENTUM, 0, 100);
  SetFuncParameters("RSI",       FUNC_RSI, 0, 100);
  SetFuncParameters("StdDev",    FUNC_STDDEV, 0, 100);
  SetFuncParameters("StdDevD",   FUNC_STDDEV, PERIOD_D1, 100);
  SetFuncParameters("Stochastic",FUNC_STOCHASTIC, 0, 100, 100, 1);
  SetFuncParameters("Open",      FUNC_OPEN);
  SetFuncParameters("Close",     FUNC_CLOSE);
  SetFuncParameters("High",      FUNC_HIGH);
  SetFuncParameters("Low",       FUNC_LOW);
  SetFuncParameters("Volume",    FUNC_VOLUME);
  SetFuncParameters("LineOpen",  FUNC_LINEOPEN);
  SetFuncParameters("LineClose", FUNC_LINECLOSE);
  SetFuncParameters("LineHigh",  FUNC_LINEHIGH);
  SetFuncParameters("LineLow",   FUNC_LINELOW);
  
  SetFuncParameters("Maximum",   FUNC_MAXIMUM, 0, 100, 0, MODE_CLOSE); // timeframe, period, shift
  SetFuncParameters("Minimum",   FUNC_MINIMUM, 0, 100, 0, MODE_CLOSE);
  
  SetFuncParameters("MaxClose",  FUNC_MAXIMUM, 0, 100, 0, MODE_CLOSE); //"Close");
  SetFuncParameters("MinClose",  FUNC_MINIMUM, 0, 100, 0, MODE_CLOSE);//"Close");
  SetFuncParameters("MaxOpen",   FUNC_MAXIMUM, 0, 100, 0, MODE_OPEN);//"Open");
  SetFuncParameters("MinOpen",   FUNC_MINIMUM, 0, 100, 0, MODE_OPEN);//"Open");
  SetFuncParameters("MaxHigh",   FUNC_MAXIMUM, 0, 100, 0, MODE_HIGH);//"High");
  SetFuncParameters("MinHigh",   FUNC_MINIMUM, 0, 100, 0, MODE_HIGH);
  SetFuncParameters("MaxLow",    FUNC_MAXIMUM, 0, 100, 0, MODE_LOW);
  SetFuncParameters("MinLow",    FUNC_MINIMUM, 0, 100, 0, MODE_LOW);
  SetFuncParameters("MaxVolume", FUNC_MAXIMUM, 0, 100, 0, MODE_VOLUME);
  SetFuncParameters("MinVolume", FUNC_MINIMUM, 0, 100, 0, MODE_VOLUME);
  
  SetFuncParameters("Abs",    FUNC_ABS);
  SetFuncParameters("Log",    FUNC_LOG);
  SetFuncParameters("Exp",    FUNC_EXP);
  SetFuncParameters("Rnd",    FUNC_RND);
  SetFuncParameters("Round",  FUNC_ROUND);
  SetFuncParameters("Max",    FUNC_MAX);
  SetFuncParameters("Min",    FUNC_MIN);
  SetFuncParameters("Ask",    FUNC_ASK);
  SetFuncParameters("Bid",    FUNC_BID);
  SetFuncParameters("Last",   FUNC_LAST);
  
  ArrayInitialize(DefaultFuncSymCount,1); 
  DefaultFuncSymCount[FUNC_RND]=0; 
  DefaultFuncSymCount[FUNC_MAX]=2; 
  DefaultFuncSymCount[FUNC_MIN]=2; 
}

//--------------------------------------------------------------------

int Indicator_init()
{  
  IndicatorShortName("");
  for (int i=1; i<1000; i++)
  {
    IndicatorName="ChartBuilder ("+i+")";
    if (WindowFind(IndicatorName)<0) break;
  }
  IndicatorShortName(IndicatorName);
  IndicatorPrefix=IndicatorName;
  MainChartIndex=i;
  
  InitObjects(i,0);
  
  Signal_HighValue= StringTrimLeft(StringTrimRight(Signal_HighValue));
  Signal_LowValue= StringTrimLeft(StringTrimRight(Signal_LowValue));
  Signal_HighLine= StringTrimLeft(StringTrimRight(Signal_HighLine));
  Signal_LowLine= StringTrimLeft(StringTrimRight(Signal_LowLine));
  if (Signal_HighValue=="" && Signal_LowValue=="" && Signal_HighLine=="" && Signal_LowLine=="")
    Signal_ChartNumber= "";
  
  Formulas[0]=Formula1;
  Formulas[1]=Formula2;
  Formulas[2]=Formula3;
  Formulas[3]=Formula4;
  Formulas[4]=Formula5;
  Formulas[5]=Formula6;
  Formulas[6]=Formula7;
  Formulas[7]=Formula8;
  
  Colors[0]=Color1;
  Colors[1]=Color2;
  Colors[2]=Color3;
  Colors[3]=Color4;
  Colors[4]=Color5;
  Colors[5]=Color6;
  Colors[6]=Color7;
  Colors[7]=Color8;
  
  if (ArraySize(SymbolsIndexes)>0) ArrayInitialize(SymbolsIndexes,-1);
  ArrayInitialize(ChartAllow,0);
  ArrayInitialize(AlgoEnabled,0);
  ArrayInitialize(PrintedError,0);
  ArrayInitialize(ChartCheckSignal, 0);
  
  MaxCharts=8;
  if (!OnlyClosePrice) MaxCharts=2;
    else if (Formulas[4]+Formulas[5]+Formulas[6]+Formulas[7]=="") MaxCharts=4;
                 
  BuffersPerChart= 8/MaxCharts;
  int charts=0;
  ArrayInitialize(IsFormulaUsing,false);
  IsIndicator=true;
  OnlyNumbers= StringTrimLeft(StringTrimRight(OnlyNumbers));
  
  for (int n=0; n<MaxCharts; n++)
  {
    ErrorChartText[n]="";
    charts++;
    if (Formulas[n]=="") continue;
    
    if (SetFormula(Formulas[n],n+1)==true) //FormulaAlgoIndex[n]=AddFormula(Formulas[n]);
      { charts++; ChartAllow[n]=true; }
      else { ErrorChartText[n]= "- " +ErrorString;  Print(Formulas[n],":  ",ErrorString); }//Formulas[n]="";
    if (StringSubstr(Formulas[n], 0, 1)=="'") ChartAllow[n]=false;
  }
  SetLevelStyle(STYLE_SOLID, 1, DarkGray);
  for (i=0; i<8; i++)
  {
    if (OnlyNumbers!="")
      if (!FindWordInString(OnlyNumbers,i+1)) { ChartAllow[i]=false; if (!IsFormulaUsing[i+1]) Formulas[i]=""; }
    if (IsFormulaUsing[i]==true && CacheMinSize[i]==0) CacheMinSize[i]=1;
    SetLevelValue(i, 0);
    if (FindWordInString(Signal_ChartNumber, ""+(i+1)) == true)
      ChartCheckSignal[i]= true;
  }
  if (IsFormulaUsing[ArrayMaximum(IsFormulaUsing)] > 0)
    for (i=0; i<8; i++) if (Formulas[i]!="") 
      if (!LabelsOnTheRight) Formulas[i]= "F" +(i+1) +"= " +Formulas[i];
                       else  Formulas[i]= Formulas[i] +" =" +"F" +(i+1);
  //if (!true)
   //for (n=1; n<=ArrayRange(Algorithms,0); n++)
     //Alert(n,"   ",AlgoNames[n],"   ",CacheStartPos[n],"  ",CachePos[n],"  ",CacheMinSize[n]);
  
  if (charts==0)
   { 
     StartMessage="No formula";  //"Íå çàäàíà íè îäíà ôîðìóëà";
     Exit=true; return(0);
   }
  string txt=""; 
  if (!OnlyClosePrice && ArraySize(FuncParam)>0)
  {
    ArrayCopy(FuncParam1,FuncParam);
    ArrayCopy(FuncParam2,FuncParam);
    ArrayCopy(FuncParam3,FuncParam);
    for (int f=0; f<ArrayRange(FuncParam,0); f++)
    {
      if (FuncParam1[f][0]==FUNC_CLOSE && FuncParam1[f][2]==0) FuncParam1[f][0]=FUNC_OPEN;
      if (FuncParam2[f][0]==FUNC_CLOSE && FuncParam2[f][2]==0) FuncParam2[f][0]=FUNC_HIGH;
      if (FuncParam3[f][0]==FUNC_CLOSE && FuncParam3[f][2]==0) FuncParam3[f][0]=FUNC_LOW;
    }
  }

  int SymbolsCount= ArraySize(Symbols);
  
  IndDigits=PrecisionDigits;
  string errsymbols="";
 
  for (int s=0; s<SymbolsCount; s++)
  {
    string symbol= Symbols[s];
    if (symbol==StringUpperCase(CURRENT_SYMBOL)) Symbols[s]=Symbol();
    if (MarketInfo(symbol, MODE_TIME)<0 || GetLastError()==4106)  // íåèçâåñòíûé ñèìâîë
      if (MarketInfo(StringUpperCase(symbol), MODE_TIME) <0  || GetLastError()==4106)
        { errsymbols=errsymbols+symbol+" ";  continue; }
       else symbol= StringUpperCase(symbol);
    if (PrecisionDigits==-1) IndDigits= MathMax(IndDigits, MarketInfo(symbol,MODE_DIGITS));
  }
  if (errsymbols!="")
   { errsymbols="Symbols not found in MarketWatch:  "+errsymbols;  Print(errsymbols); StartMessage=errsymbols; } //"Ñèìâîëû íå íàéäåíû â "Îáçîðå Ðûíêà": "
   
  if (IndDigits==-1) IndDigits=2;
  IndicatorDigits(IndDigits);
   
  AllowGetPriceLine=false;
  for (f=ArrayRange(FuncParam,0)-1; f>=0; f--)
    switch (FuncParam[f][0])
      { case FUNC_LINEOPEN: case FUNC_LINECLOSE: case FUNC_LINEHIGH: case FUNC_LINELOW: 
          AllowGetPriceLine=true; f=0;
      }
  VLineTime=0;
  
  SetIndexBuffer(0, buffer0);  ArrayInitialize(buffer0,EMPTY_VALUE);
  SetIndexBuffer(1, buffer1);  ArrayInitialize(buffer1,EMPTY_VALUE);
  SetIndexBuffer(2, buffer2);  ArrayInitialize(buffer2,EMPTY_VALUE);
  SetIndexBuffer(3, buffer3);  ArrayInitialize(buffer3,EMPTY_VALUE);
  SetIndexBuffer(4, buffer4);  ArrayInitialize(buffer4,EMPTY_VALUE);
  SetIndexBuffer(5, buffer5);  ArrayInitialize(buffer5,EMPTY_VALUE);
  SetIndexBuffer(6, buffer6);  ArrayInitialize(buffer6,EMPTY_VALUE);
  SetIndexBuffer(7, buffer7);  ArrayInitialize(buffer7,EMPTY_VALUE);
 
  InitBuffersProperties();
  
  ArrayInitialize(AutoScaleRatio,0);
  ArrayInitialize(AutoScaleShift,0);
  AutoScale_BaseChart=0;
  
  return(0);
  
  // Ôóíêöèè, èñïîëüçóåìûå äëÿ ýêñïîðòà â äðóãèå ñîâåòíèêè
  double dblarr[];  int intarr[];  string strarr[];
  AddFormulaForOwnRates("");
  CountFormulaValue("",0);
  CountMyFormulaValue(0,0,dblarr);
  CountMyFormulaWithOwnValues(0,0,dblarr,strarr,dblarr);
  CountFormulaWithOwnSymRates(0,0,intarr,dblarr,intarr,dblarr);  
  GetFormulaSymbols(0,strarr);
  GetFormulaSymIndexes(0,intarr);
  GetAllFormulasSymbols(strarr);
  GetFormulaSymFuncNames(0,0,strarr);
  GetFormulaSymPowRatio(0,0,dblarr); 
}

//--------------------------

void InitBuffersProperties()
{  
  if (OnlyClosePrice)
    for (int i=0; i<8; i++)
    {
      int chart= i/BuffersPerChart+1;
      int drawmode=DrawMode;
      if (i%BuffersPerChart >0) drawmode=DRAW_ARROW;
      SetIndexLabel(i, "Chart "+chart+"  Close");
      SetIndexStyle(i, drawmode, STYLE_SOLID, 1, Colors[chart-1]); //DRAW_ARROW
      SetIndexArrow(i, 158);
   }
   else
     for (i=0; i<8; i+=4)
     {
       chart= i/4+1;
       SetIndexStyle(i, DRAW_ZIGZAG, STYLE_SOLID, 1, Colors[chart-1]);
       SetIndexStyle(i+1, DRAW_ZIGZAG, STYLE_SOLID, 1, Colors[chart-1]);
       SetIndexStyle(i+2, DRAW_HISTOGRAM, STYLE_SOLID, 1, Colors[chart-1]);//DRAW_HISTOGRAM
       SetIndexStyle(i+3, DRAW_HISTOGRAM, STYLE_SOLID, 0, Black); // ,STYLE_DOT
       SetIndexLabel(i, "Chart "+chart+"  Open");
       SetIndexLabel(i+1, "Chart "+chart+"  Close");
       SetIndexLabel(i+2, "Chart "+chart+"  High");
       SetIndexLabel(i+3, "Chart "+chart+"  Low");
     }
}

//--------------------------------------------------------------------

void InitObjects(int mainchart, int subchart)
{      
  string chartprefix= "ChartBuilder" +mainchart;
  if (subchart>0) chartprefix= chartprefix +"-" +subchart;
  for (int n=0; n<8; n++)
  {
    string prefix= chartprefix +"-" +(n+1) +" ";
    ChartLabels[n]= prefix +" Label";
    ChartLabels_[n]= prefix +" Label_";
    ChartErrorLabels[n]= prefix +" ErrorLabel";
    LineAsk[n]= prefix +" Ask";
    LineBid[n]= prefix +" Bid";
    VLine= chartprefix +" GetPriceLine";
    ObjectDelete(ChartLabels[n]);
    ObjectDelete(ChartLabels_[n]);
    ObjectDelete(ChartErrorLabels[n]);
    ObjectDelete(LineAsk[n]);
    ObjectDelete(LineBid[n]);
  }
  StatusLabel= chartprefix +" StatusLabel";
  SignalLabel= chartprefix +" SignalLabel";
}  

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
{
  if (!IsIndicator) return(0);
  DeleteObjects();
  ObjectDelete(DropWindowIdObject);
  return(0);
}
 
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
{ 
  if (FirstStart) Indicator_init();
  Window= FindIndicatorWindow();
  FirstStart=false;
  if (Exit) return(0);
  int ticks0= GetTickCount();
  //if (WrongWindow) Window=-1;
  if (Window>-1) DrawStatusLabel("");
  
  if (StartMessage!="" && Window>-1)
     { DrawStatusLabel(StartMessage); StartMessage=""; } 
    
  if (!AllowGetPriceLine) ObjectDelete(VLine);

  int counting_bars= Bars-IndicatorCounted();
  int ChartMinTime[];
  
  if (!CheckValidCharts(ChartMinTime, ChartValid, counting_bars)) return(0);
  
  if (Signal_ChartNumber!="")
    DrawChartLabel(8, "Signal chart: "+Signal_ChartNumber);
  
  if (IndicatorCounted()==0)
  {
    InitBuffersProperties();
    ArrayInitialize(CachePos,-1);
  }

  if (AllowGetPriceLine && Window>=0)
  {
    if (ObjectFind(VLine)==-1)
     { 
       int LineBar= MathMax(0, WindowFirstVisibleBar()-WindowBarsPerChart()/2);
       ObjectCreate(VLine,OBJ_VLINE,Window,Time[LineBar],0);
       if (GetLastError()==4206) { WrongWindow=true; AllowGetPriceLine=false; }
       ObjectSet(VLine,OBJPROP_BACK,0);
       ObjectSetText(VLine,"Get Price");
     }
    int time=ObjectGet(VLine,OBJPROP_TIME1);
    if (time!=VLineTime) counting_bars=Bars;
    VLineTime=time;  //VLineBar=iBarShift(NULL,0,time);
  }
  
  double PriceAsk[8], PriceBid[8];
  bool PriceAskOK[8], PriceBidOK[8];
  int  PriceTypes[]={ PRICE_OPEN, PRICE_CLOSE, PRICE_HIGH, PRICE_LOW};
  ArrayInitialize(FuncLastTime,-1);  // î÷èùàåì êýø ôóíêöèé
  
  int barsynctime=BarTimeSyncSize;
  if (BarTimeSyncSize>0)
  {
    barsynctime=BarTimeSyncSize*60; // ïðèâÿçêà ïî ìèíóòàì 
    if (!BarTimeSyncMode_ByMinutes) barsynctime*=Period();  // ïðèâÿçêà ïî áàðàì
  }
  int param[3];
  param[0]= Period();    
  param[1]= barsynctime;  
  param[2]= barsynctime;  
  int timeshift= TimeShiftFromMainChart_minutes*60; // timeshift
  int pricetype=PRICE_CLOSE;
  
  //int autoscale_basechart=-1;
  
  for (int chart=0; chart<8; chart++)  SetLevelValue(chart,0);
   //if (autoscale_basechart<0 && ChartValid[chart]==true && ChartAllow[chart]==true) autoscale_basechart=chart;
  //if (autoscale_basechart != AutoScale_BaseChart) { counting_bars= Bars;  AutoScale_BaseChart= autoscale_basechart; }

  int ticks1=GetTickCount();
  //if (counting_bars!=1) return(0);
    
  for (int i=counting_bars-1;  i>=-3;  i--)
  {   
    if (i==-1 || i==-2) if (!ShowBidAsk) continue;     // Bid/Ask

    int pricetypeindex=0;
    int lastchart=-1;
    
    for (chart=0; chart<MaxCharts; chart++)
    {
      if (i<0) if (AutoScale && chart>0) break;
      if (!ChartAllow[chart]) continue;
      if (!ChartValid[chart]) continue;
      if (chart!=lastchart) pricetypeindex=0;
      lastchart=chart;
      int buf0= chart * BuffersPerChart;
      if (Time[i]<ChartMinTime[chart] && i>=0)   // âûøëè çà ïðåäåëû ãðàôèêà îäíîãî èç ñèìâîëîâ
      {
        for (int b=0; b<BuffersPerChart; b++) SetBuffer(buf0+b, i, EMPTY_VALUE);   // î÷èùàåì çíà÷åíèå áóôåðà
        continue;
      }
      
      if (i>=0)
       if (OnlyClosePrice)
         for (b=0; b<BuffersPerChart; b++) SetBuffer(buf0+b, i, EMPTY_VALUE);
        else
         pricetype=PriceTypes[pricetypeindex];
      
      if (i<0) { pricetype=PRICE_CLOSE; if (pricetypeindex>0) continue; }
      
      double result[2];
      //if (!CountMyFormulaValueExt(chart,i,param,result)) continue;
      int f= chart+1;
      time= Time[i]-timeshift;
      if (i<0) time=i;
      bool ok=0;
      switch (pricetype)
      {
        case PRICE_CLOSE: ok= CountFormula(f, Algorithms, FuncParam,  Symbols, time, param, MyRates, MyRatesPos, result); break;
        case PRICE_OPEN:  ok= CountFormula(f, Algorithms, FuncParam1, Symbols, time, param, MyRates, MyRatesPos, result); break;
        case PRICE_HIGH:  ok= CountFormula(f, Algorithms, FuncParam2, Symbols, time, param, MyRates, MyRatesPos, result); break;
        case PRICE_LOW:   ok= CountFormula(f, Algorithms, FuncParam3, Symbols, time, param, MyRates, MyRatesPos, result); break;
      }
      if (!ok) 
      { 
        if (i>=0) SetBuffer(buf0+pricetypeindex, i, EMPTY_VALUE);
        if (Error>0) DrawErrorChartLabel(chart,"- "+ErrorString);
        if (Error>0 && Error!=ERROR_HISTORY && !PrintedError[chart][Error])
           { Print(AlgoNames[f]," :  ",ErrorString);  PrintedError[chart][Error]=true; }
        ErrorString="";
        if (Error==ERROR_FORMULA || Error==ERROR_RECURSION) { ChartValid[chart]=false;  Error=0;  break; }
        Error=0;
        continue;
      }
      double value=result[0];
      
      if (PrecisionDigits>=0) value= NormalizeDouble(value,IndDigits);
     
      if (i==-1) { PriceAsk[chart]=value;  DrawLine(Window,LineAsk[chart],value,"Ask",Colors[chart]);  PriceAskOK[chart]=true; } // Ask
      if (i==-2) { PriceBid[chart]=value;  DrawLine(Window,LineBid[chart],value,"Bid",Colors[chart]);  PriceBidOK[chart]=true; } // Bid
      if (i==-3) { SetLevelValue(chart, value);  // Last
                   if (!ShowBidAsk) { PriceAsk[chart]=value; PriceBid[chart]=value; PriceAskOK[chart]=true; PriceBidOK[chart]=true; }
                 }
      if (i<0) continue;
      if (AutoScale &&  chart != AutoScale_BaseChart) if (AutoScaleRatio[chart]>0)
        if (counting_bars!=Bars)
          if (value!=EMPTY_VALUE)
            value= value *AutoScaleRatio[chart] +AutoScaleShift[chart];
      
      if (OnlyClosePrice)
      {
        SetBuffer(buf0,i,value);  // çàïîëíÿåì òåêóùóþ ÿ÷åéêó îñíîâíîãî áóôåðà
        if (BuffersPerChart==1) continue;
        if (DrawMode!=DRAW_SECTION && DrawMode!=DRAW_ARROW && DrawMode!=DRAW_HISTOGRAM)
          if (GetBuffer(buf0,i+1)==EMPTY_VALUE)  // åñëè ïðåäûäóùàÿ ÿ÷åéêà îñíîâíîãî áóôåðà ïóñòàÿ (ò.å. îáðàçîâàëñÿ ðàçðûâ)
            SetBuffer(buf0+1, i, GetBuffer(buf0,i)); // çàïîëíÿåì òåêóùóþ ÿ÷åéêó äîïîëíèòåëüíîãî áóôåðà (ðèñóåì arrow)
           else
            SetBuffer(buf0+1, i+1, EMPTY_VALUE); // èíà÷å î÷èùàåì ïðåäûäóùóþ ÿ÷åéêó äîïîëíèòåëüíîãî áóôåðà (âîçìîæíî îíà áûëà çàïîëíåíà çðÿ íà ïðåäûäóùåì áàðå)
      }
      else    
      {
        int bufindex=buf0+pricetypeindex;
        if (pricetype==PRICE_LOW)
        {
          double highvalue= GetBuffer(buf0+2, i);
          if (MathAbs(value)>MathAbs(highvalue)) { SetBuffer(buf0+2, i, value);  value=highvalue; }  // ìåíÿåì áóôåðû ìåñòàìè
        }
        SetBuffer(bufindex,i,value);
        pricetypeindex= (pricetypeindex+1)%BuffersPerChart;
        if (pricetypeindex>0) chart--; 
      }
    }
  }
  ObjectDelete(StatusLabel);
  
  if (AutoScale && counting_bars==Bars)
    AutoScale_BaseChart= SetAutoScale();  //AutoScale_BaseChart);
    
  for (chart=0; chart<MAXCHARTS; chart++)
    if (ChartCheckSignal[chart]==true)
      CheckSignalLevels(chart, PriceBid[chart], PriceAsk[chart]);
  //if (WrongWindow && Window>=0) Print("Wrong window (",Window,")");
  
  if (SaveToFile_ChartNumber>0 && SaveToFile_ChartNumber<=8 && counting_bars==Bars)
    SaveToFile(SaveToFile_FileName, SaveToFile_ChartNumber, counting_bars);
  /*  
  int ticks2=GetTickCount();
  static bool firsttime=1;
  if (Debug && firsttime)
  {
    double res=0;
    for (int bar_=0; bar_<Bars; bar_++)
      for (int buf_=0; buf_<8; buf_++)
      {
        double res_= GetBuffer(buf_, bar_);
        if (res != EMPTY_VALUE) res += res_;
      }
    Alert("checksum: ", res,"    ",counting_bars,"  bars   ",ticks1-ticks0," ms, ",ticks2-ticks1," ms");
  }
  firsttime=0;
  */
  return(0);
}

//---------------------------------------------------------------------------------

bool CheckValidCharts(int& ChartMinTime[], bool& ChartValid[], int& counting_bars)
{  
  int validcharts=0;
  bool loadinghistory=false;
  int SymbolsCount= ArraySize(Symbols);
  int Periods[]={ 1, 5, 15, 30, PERIOD_H1, PERIOD_H4, PERIOD_D1, PERIOD_W1, PERIOD_MN1 };
  static int LastSymBars[100][9];  ArrayResize(LastSymBars,SymbolsCount);
  bool AccountConnected= (AccountNumber()>0); 
  int timeshift= TimeShiftFromMainChart_minutes*60;
  ArrayResize(ChartMinTime, MaxCharts);
  ArrayInitialize(ChartMinTime, 0);
  ArrayInitialize(ChartValid, 1);
  //ArrayResize(MySymRatesPos, SymbolsCount);
  //ArrayInitialize(MySymRatesPos, -1);
  static int ReadRatesPos[][2];
  static int inittime;
  int ts_count= ArrayRange(TimeSeries, 0);
  if (inittime!=InitTime && ts_count>0) { ArrayResize(ReadRatesPos, ts_count);  ArrayInitialize(ReadRatesPos, -2); } //ArrayInitialize(MySymRatesPos, -2);
  inittime= InitTime;
  if (ArraySize(ReadRatesPos)>0) ArrayCopy(MyRatesPos, ReadRatesPos);  else ArrayResize(MyRatesPos, 0);
  int ratespos=0;
  
  for (int n=0; n<MaxCharts; n++)
  {
    if (Formulas[n]=="") continue;
    DrawChartLabel(n, Formulas[n]);
    if (ChartAllow[n]==0)  { DrawErrorChartLabel(n,ErrorChartText[n]); continue; }
    string UnknownCharts="";
    string UnknownSymbols="";
    int unknownsymbolscount=0;
    ErrorString="";
    string LoadingSymbolsStr="";
    bool   error=0;
    int nestinglevel=0;  // óðîâåíü âëîæåííîñòè ôóíêöèè
    int nestingparam[20][3]; // ïàðàìåòðû âëîæåííîñòè
    int a=n+1;     
    for (int f=0;  f< ArrayRange(AlgoFunctions,1);  f++)
    {
      int s=1;
      if (AlgoFunctions[a][f]<0)  // âëîæåííàÿ ôîðìóëà
      {  
        nestinglevel--; if (nestinglevel<0) break;
        a= nestingparam[nestinglevel][0];  f= nestingparam[nestinglevel][1];  s= nestingparam[nestinglevel][2]+1;
      }
      int func= AlgoFunctions[a][f];
      int functype= FuncParam[func][0];
      for (s=s; s<=DefaultFuncSymCount[functype]; s++)
      {
        int sym=FuncParam[func][s];
        if (sym==EMPTY_VALUE) continue;
        if (sym<0)  // âëîæåííàÿ ôóíêöèÿ
         { 
           int algo=-sym-1;
           if (algo<=8) continue;
           nestingparam[nestinglevel][0]= a;  nestingparam[nestinglevel][1]= f;  nestingparam[nestinglevel][2]= s;
           nestinglevel++;  a=algo;  f=-1;
           break;
         }
        string symbol= Symbols[sym];
        int ts= FuncTimeSerie[func];
        //Alert(symbol);
        int tf= FuncParam[func][2];
        if (tf==0) tf= Period();
        int ibars, mintime;
        if (MarketInfo(symbol,MODE_TIME)<0 || GetLastError()==4106)
        {
          if (MarketInfo(StringUpperCase(symbol),MODE_TIME)>=0 && GetLastError()!=4106)
            { symbol= StringUpperCase(symbol);  Symbols[sym]=symbol; }
           else 
            if (FindSymbolInSymbolsRow(symbol)==false)  // ñèìâîë íå íàéäåí â ôàéëå symbols.row
            {
              int readcount=0;
              if (ReadRatesPos[ts][1]==-2)  // çíà÷èò ýòî ïåðâàÿ ïðîâåðêà
              {
                readcount= ReadSymbolHistory(symbol, tf, MyRates, ratespos);
                ReadRatesPos[ts][0]= ratespos;
                ReadRatesPos[ts][1]= readcount;
                ArrayCopy0Int(MyRatesPos, ReadRatesPos, ts, ts, 1);
              }
              if (MyRatesPos[ts][1]<0)  { UnknownSymbols=UnknownSymbols+symbol+"  ";  unknownsymbolscount++;  continue; } 
              ratespos += readcount;
              ibars= MyRatesPos[ts][1];
              mintime= MyRates [MyRatesPos[ts][0]] [0];
            }
        }
        if (MyRatesPos[ts][1]<=0)
        { 
          ibars= iBars(symbol,tf);
          if (ibars>0)
          if (functype==FUNC_CLOSE || functype==FUNC_OPEN || functype==FUNC_HIGH || functype==FUNC_LOW)
          {  // Ñîõðàíÿåì öåíîâûå çíà÷åíèÿ â ìàññèâ, ÷òîáû ïðè ðàñ÷¸òå áðàòü èõ îòòóäà - ýòî çíà÷èòåëüíî áûñòðåå, ÷åì èñïîëüçîâàòü ôóíêöèè äîñòóïà ê òàéìñåðèÿì
            double rates[][6];
            ibars= ArrayCopyRates(rates, symbol, tf);
            if (ibars>0)
            {
              int newratespos=0;
              int maxratesposserie= ArrayMaximum(MyRatesPos, ts_count);
              //for (int ss=0; ss<SymbolsCount; ss++)
                //if (ss==sym) break;
              if (MyRatesPos[maxratesposserie][0]>=0 && MyRatesPos[maxratesposserie][1]>=0)
                newratespos= MyRatesPos[maxratesposserie][0] + MyRatesPos[maxratesposserie][1];
              //ArraySetAsSeries(MyRates, 1);
              ArrayCopy0(MyRates, rates, newratespos, 0, ibars);
              ArraySetAsSeries(MyRates, 0);
              //Alert(ibars,"  ",newratespos,"  ",TimeToStr(MySymRates[0][0]));
              MyRatesPos[ts][0]= newratespos;
              MyRatesPos[ts][1]= ibars;
              //Alert(func,"  ",ts,"  ",(MyRates[newratespos][4]),"  ",(MyRates[newratespos+ibars-1][4]));//,"  ",MyRatesPos[ts][1]);
            }   
          }
          mintime= iTime(symbol, tf, ibars-1);
        }
        int tfindex= ArrayBsearch(Periods, tf);
        if (ibars< LastSymBars[sym][tfindex] || ibars> LastSymBars[sym][tfindex]+1) // âåðîÿòíî áûëè ïîäãðóæåíû íîâûå áàðû
          counting_bars= Bars;
        LastSymBars[sym][tfindex]= ibars;

        if (GetLastError()==4066 && AccountConnected)   // èñòîðèÿ ïîäãðóæàåòñÿ
         { 
           error=true;
           loadinghistory=true;
           LoadingSymbolsStr= LoadingSymbolsStr+symbol+", "+GetPeriodName(tf)+" ";
           LastSymBars[sym][tfindex]=0;
         } 
         else if (ibars<=0)
           UnknownCharts= UnknownCharts+symbol+", "+GetPeriodName(tf)+"  ";
        if (ibars>0)
          ChartMinTime[n]= MathMax(ChartMinTime[n], mintime+timeshift);
      }
    }
    if (UnknownCharts!="")  { ErrorString="Charts not found:  "+UnknownCharts+ErrorString; error=true; }  //"Íå íàéäåí ÷àðò:  "
    else
     if (unknownsymbolscount==1) { ErrorString="Unknown symbol:  "+UnknownSymbols+ErrorString; error=true; } else    //"- Íåèçâåñòíûé ñèìâîë:  "
     if (unknownsymbolscount>1) { ErrorString="Unknown symbols:  "+UnknownSymbols+ErrorString; error=true; }   // "- Íåèçâåñòíûå ñèìâîëû:  "
    if (LoadingSymbolsStr!="") ErrorString="Loading history... "+LoadingSymbolsStr;           // - Ïîäãðóçêà èñòîðèè... "
    if (ErrorString!="") DrawErrorChartLabel(n,"- "+ErrorString); else DrawErrorChartLabel(n,"");
    if (error==0) { validcharts++; continue; }
    ChartValid[n]=false;
  }
  //Alert(OwnSymRatesParam[0][0],"  ",OwnSymRatesParam[0][1]);
  //int x=OwnSymRatesParam[0][1]-1;
  //Alert(TimeToStr(OwnSymRates[x][0]),"  ",OwnSymRates[x][1],"  ",OwnSymRates[x][2],"  ",OwnSymRates[x][3],"  ",OwnSymRates[x][4],"  ",OwnSymRates[x][5]);
  if (loadinghistory) return(0);
  if (validcharts==0) return(0);
  return(true);
}

//-----------------

int SetAutoScale()
{
  int leftvisiblebar= WindowFirstVisibleBar();
  int rightvisiblebar= MathMax(leftvisiblebar-WindowBarsPerChart()+1, 0);
  int visiblebars= leftvisiblebar-rightvisiblebar+1;
  double max[MAXCHARTS],  min[MAXCHARTS];
  int chartbufcount= MAXCHARTS/MaxCharts;
  int firstchart=-1;
  
  for (int chart=-1; chart<MaxCharts; chart++)
  {
    if (!ChartAllow[chart] || !ChartValid[chart]) continue;
    if (firstchart==-1) firstchart=chart;
    int startbuf=chart*chartbufcount;
    int maxbuf=startbuf;
    int minbuf=startbuf;
    if (!OnlyClosePrice)
    {
      maxbuf=startbuf+2;
      minbuf=startbuf+3;
    }
    max[chart]=EMPTY_VALUE;
    min[chart]=EMPTY_VALUE;
    for (int b=leftvisiblebar; b>=rightvisiblebar; b--)
    {
      double maxvalue=GetBuffer(maxbuf,b);
      if (maxvalue==EMPTY_VALUE) continue;
      if (maxvalue>max[chart] || max[chart]==EMPTY_VALUE) max[chart]=maxvalue;
      double minvalue=GetBuffer(minbuf,b);
      if (minvalue==EMPTY_VALUE) continue;
      if (minvalue<min[chart] || min[chart]==EMPTY_VALUE) min[chart]=minvalue;
    }
    if (chart==0) continue;
    if (max[chart]==min[chart]) continue;
    double ratio= (max[firstchart]-min[firstchart])/(max[chart]-min[chart]);
    double shift= min[firstchart]-min[chart]*ratio;
    
    for (int subbuf=0; subbuf<chartbufcount; subbuf++)
    {
      int buf= startbuf+subbuf;
      for (b=0; b<Bars; b++)
      {
        double value= GetBuffer(buf, b);
        if (value!=EMPTY_VALUE)
          SetBuffer(buf, b, value*ratio+shift);
      }
    }
    AutoScaleRatio[chart]= ratio;
    AutoScaleShift[chart]= shift;
  }
  return(firstchart);
}

//--------------------------------------------------------------------------------------

bool CountMyFormulaValueExt(int n, int time, int param[], double& results[])
{
  if (AlgoRange0==0) { Error=ERROR_FORMULA; return(0); }
  if (!IsIndicator)
    { if (ArraySize(CachePos)>0) ArrayInitialize(CachePos,-1); if (ArraySize(FuncLastTime)>0) ArrayInitialize(FuncLastTime,-1); }
  Error=0;
  double rates[][];  int ratespos[][];
  bool ok= CountFormula(n, Algorithms, FuncParam, Symbols, time, param, rates, ratespos, results);
  return(ok);
}

//-----------------------------------------------------------

bool CountMyFormulaValue(int n, int time, double& results[])
{
  int param[3]= {0, -1, -1};
  bool result= CountMyFormulaValueExt(n, time, param, results);
  return(result);
}

//----------------------------------------------------------------------------------------------

bool CountMyFormulaWithOwnValuesEx(int n, int time, int param[], double& results[], string symbols[], double ownvalues[])
{
  if (AlgoRange0==0) { Error=ERROR_FORMULA; return(0); }
  double FuncParamOwn[][PARAMCOUNT];
  if (ArrayRange(FuncParam,0)>0)  ArrayCopy(FuncParamOwn,FuncParam);
  int v=0;
  
  for (int i=0; i<ArrayRange(AlgoFunctions,1); i++)
  {
    int func=AlgoFunctions[n][i];
    if (func<0) break;
    int symindex=FuncParam[func][1];
    switch (FuncParam[func][0])
    { 
      case FUNC_OPEN: case FUNC_CLOSE: case FUNC_HIGH: case FUNC_LOW:
        for (int s=0; s<ArraySize(symbols); s++)
          if (symbols[s]==Symbols[symindex]) break;
        if (s==ArraySize(symbols)) continue;
        FuncParamOwn[func][0]= FUNC_FIXVALUE;
        FuncParamOwn[func][1]= ownvalues[v];
        v++;
    }
  }
  ArrayInitialize(CachePos,-1); ArrayInitialize(FuncLastTime,-1); 
  Error=0;
  double rates[][]; int ratespos[][];
  bool ok= CountFormula(n ,Algorithms, FuncParamOwn, Symbols, time, param, rates, ratespos, results);
  return(ok);
}
//----------------------------------------
  
bool CountMyFormulaWithOwnValues(int n, int time, double& results[], string symbols[], double myvalues[])
{
  int param[2];
  bool result= CountMyFormulaWithOwnValuesEx(n, time, param, results, symbols, myvalues);
  return(result);
}

//--------------------------------------------------------------------------

double CountFormulaValue(string formula, int time)
{
  int n= AddFormula(formula);
  double results[2];
  CountMyFormulaValue(n, time, results);
  return(results[0]);
}

//--------------------------------------------------------

bool CountFormulaWithOwnSymRates(int n, int time, int param[], double myrates[][], int myratespos[][2], double& results[])  
{
  if (ArraySize(myrates)==0) return(0);
  Error=0;
  //UseOwnSymRates=true;
  bool result= CountFormula(n, Algorithms, FuncParam, Symbols, time, param, myrates, myratespos, results);
  return(result);
}  

//--------------Ðàñ÷¸ò ôîðìóëû ------------------------------------

bool CountFormula(int n, double algorithms[][][], double funcparam[][], string symbols[],
                  int maintime, int& parameters[], double history[][6], int historypos[][2], double& result[])
{ 
  int period=   parameters[0];
  int synctime= parameters[1];   // ìàêñèìàëüíàÿ ñèíõðîíèçàöèÿ ìåæäó çàäàííûì âðåìåíåì è âðåìåíåì ñàìîé ðàííåé ôóíêöèè
  int synctime1= parameters[2];  // ìàêñèìàëüíàÿ ñèíõðîíèçàöèÿ ìåæäó âñåì ôóíêöèÿìè ôîðìóëû  
  if (period==0) period=Period();
  int maintime0= maintime;
  if (maintime <0)     //maintime= (maintime/period/60)*period*60;
  { 
    n= GetBidAskFormula(n,maintime);
    if (n<0) return(0);
    ArrayInitialize(CachePos,-1); 
    maintime=TimeCurrent();
  }
  static bool CacheAllow=true;  
  
  int mycachepos=CachePos[n];
  if (false)
  if (maintime0>=0)
    if (mycachepos>=CacheStartPos[n])
      if (CacheTimeBuffer[mycachepos]==maintime) { result[0]=CacheValueBuffer[mycachepos]; result[1]=maintime; return(true); }
   
  int maxfunctime=0;  // íàèáîëüøåå âðåìÿ áàðà, ïîëó÷åííîå èç ôóíêöèè
  result[0]=EMPTY_VALUE;
   
  for (int f=0; f<FUNCRANGE1; f++)     // Âû÷èñëÿåì çíà÷åíèÿ âñåõ ôóíêöèé
  {
    int funcindex= AlgoFunctions[n][f];
    if (funcindex<0) break;
    int functype= funcparam[funcindex][0];
    if (!true)
    if (functype==FuncLastType[funcindex] && maintime==FuncLastTime[funcindex])  continue; // åñëè ðåçóëüòàò ôóíêöèè óæå åñòü â êýø-áóôåðå, òî áåð¸ì åãî îòòóäà
 
    FuncLastTime[funcindex]=-1;
    FuncLastType[funcindex]=functype;
       
    if (functype==FUNC_FIXVALUE)
      { FuncLastValue[funcindex]=funcparam[funcindex][1]; continue; }
    
    int funcsymindexcount=DefaultFuncSymCount[functype];

    for (int s=1; s<=funcsymindexcount; s++)
    {     
      int symindex= funcparam[funcindex][s];
      if (symindex==EMPTY_VALUE) break;
      
      int findtime= maintime;
        
      if (functype==FUNC_LINECLOSE || functype==FUNC_LINEOPEN || functype==FUNC_LINEHIGH || functype==FUNC_LINELOW)
        if (!WrongWindow) findtime=VLineTime;  else return(0);
      //if (functype!=FUNC_OPEN && functype!=FUNC_LINEOPEN) findtime= (maintime/period/60+1)*60*period-1;
      //if (symindex>=0 && maintime0<0) return(0);
      
      if (symindex<0)  // çíà÷èò èñïîëüçóåòñÿ ññûëêà íà ôîðìóëó
      { 
        static int recurslevel=0;
        int formindex= -symindex-1;
        if (!AlgoEnabled[formindex])
        { 
          Error=ERROR_FORMULA;  ErrorString="Wrong formula!";  if (recurslevel>0) ErrorString="Wrong formula:  "+AlgoNames[n]; // Íåêîððåêòíàÿ ôîðìóëà
          return(0);
        }
        //if (maintime0<0) return(0); 
        int formtf= funcparam[funcindex][2];  if (formtf==0) formtf=period;
        if (funcsymindexcount>1) formtf=period;
        static int param[3];
        param[0]= formtf;
        param[1]= synctime;//-1;  // synctime
        param[2]= synctime1;
        recurslevel++; 
        if (recurslevel>20) { recurslevel--;  Error=ERROR_RECURSION;  ErrorString="Recursion overflow!"; return(0); }  //"Ïðåâûøåí ïðåäåë ðåêóðñèè"
        int funccachesize= FuncCacheMinSize[funcindex];
        int newbars=funccachesize;
        
        if (CachePos[formindex]>=CacheStartPos[formindex] && CachePos[n]>=CacheStartPos[n] && funccachesize>0) 
          newbars= (maintime-CacheTimeBuffer[CachePos[n]])/formtf/60;   //  fillcache=true; // || formtf<period 
        
        bool cachefilled=true;
        if (newbars==1) cachefilled= CountFormula(formindex,algorithms,funcparam,symbols,findtime,param,history,historypos,result);
        
        if (newbars>1)
        {  
          int lefttimelimit=0;
          if (CachePos[n]>=CacheStartPos[n]) lefttimelimit= CacheTimeBuffer[CachePos[n]];
          if (CachePos[formindex] >=CacheStartPos[formindex])
            { lefttimelimit= MathMax(lefttimelimit, CacheTimeBuffer[CachePos[formindex]]); }  
          int formcachesize= CacheMinSize[formindex];
         
          CacheMinSize[formindex]= 0;  // âðåìåííî îòêëþ÷àåì êýøèðîâàíèå äëÿ ôîðìóëû, ò.ê. áóäåì ñàìè çàïîëíÿòü áóôåð
          double pricebuffer[1000];
          int    timebuffer[1000];
          static int buffersize=0;  
          int startbuffersize=buffersize;  // çíà÷åíèå buffersize ìîæåò ìåíÿòüñÿ â õîäå ðåêóðñèâíûõ âûçîâîâ, ïîýòîìó ñîõðàíÿåì åãî íà÷àëüíîå çíà÷åíèå
          if (funccachesize>0) buffersize+=funccachesize; else buffersize+=1000;
          if (buffersize > ArraySize(pricebuffer))  { ArrayResize(pricebuffer,buffersize);  ArrayResize(timebuffer,buffersize); }

          findtime= findtime/60/formtf*formtf*60;
          int ftime=findtime;
          
          for (int count=0;  count<funccachesize || funccachesize<0;  count++)
          {
            if (!CountFormula(formindex, algorithms, funcparam, symbols, ftime, param, history, historypos, result)) break;
            if (count==buffersize) // áóôåð çàïîëíåí
              { 
                ArrayCopy(pricebuffer, pricebuffer, 1000, 0);
                ArrayCopy(timebuffer, timebuffer, 1000, 0);  // ñäâèíóëè âåñü ìàññèâ íà 1000 ýëåìåíòîâ âïðàâî
                buffersize+=1000;
              }
            if (result[1]<=lefttimelimit) break;
            pricebuffer[buffersize-count-1]= result[0]; // çàïîëíÿåì ëåâóþ ÷àñòü ìàññèâà â îáðàòíîì ïîðÿäêå (ñïðàâà íàëåâî)
            timebuffer[buffersize-count-1]= result[1];   //if (result[1]==timebuffer[buffersize-(count-1)-1]) Alert(TimeToStr(lefttimelimit)," !!! ",TimeToStr(ftime),"  ",TimeToStr(result[1]));
            
            ftime= result[1]-formtf*60;
            
            param[2]= formtf; // òàéìôðåéì
          }
          
          if (count>0)   // && (mainbar>=0 || mainbar<-3))
          {
            if (CacheStartPos[formindex]+count > CacheStartPos[formindex+1]  &&  formindex < ArraySize(CacheStartPos)-1)
              ResizeCache(formindex,+1000); 
            if (CachePos[formindex]<0) CachePos[formindex]= CacheStartPos[formindex]-1;
            int oldcount= CachePos[formindex]-CacheStartPos[formindex]+1;  // èìåþùèåñÿ ñòàðûå ýëåìåíòû â áóôåðå
            if (funccachesize>0) oldcount= MathMin(oldcount, funccachesize-count);  // îñòàâëÿåì òîëüêî ìèíèìàëüíî íåîáõîäèìîå êîëè÷åñòâî ñòàðûõ ýëåìåíòîâ
            if (oldcount>0 && funccachesize>0)
            {  // ñîõðàíÿåì ÷àñòü ñòàðûõ çíà÷åíèé (ñäâèãàåì èõ ê íà÷àëüíîé ïîçèöèè áóôåðà)
              ArrayCopy(CacheValueBuffer, CacheValueBuffer, CacheStartPos[formindex], CachePos[formindex]-oldcount+1, oldcount);
              ArrayCopy(CacheTimeBuffer, CacheTimeBuffer, CacheStartPos[formindex], CachePos[formindex]-oldcount+1, oldcount);
            }  // ñîõðàíÿåì íîâûå çíà÷åíèÿ ñëåäîì çà ñòàðûìè
            ArrayCopy(CacheValueBuffer, pricebuffer, CacheStartPos[formindex]+oldcount, buffersize-count, count);
            ArrayCopy(CacheTimeBuffer, timebuffer, CacheStartPos[formindex]+oldcount, buffersize-count, count);

            CachePos[formindex]= CacheStartPos[formindex]+oldcount+count-1;
          }
          CacheMinSize[formindex]=formcachesize; //{ Alert(formindex,"  ",formcachesize); }
          buffersize=startbuffersize;
          if (lefttimelimit==0) if (count<funccachesize)  cachefilled=false;
        } 
        recurslevel--;
        if (!cachefilled) return(0);
      }
    }
    if (s<=funcsymindexcount) return(0);
    double value=0; 
    
    if (!CountFunction(funcparam, funcindex, period, findtime, synctime, history, historypos, value))  return(0);  // â ïåðåìåííóþ cellvalue ïîëó÷àåì çíà÷åíèå 
   
    if (GetLastError()==4066) { Error=ERROR_HISTORY;  ErrorString="Loading history...";  return(0); }  // Ïîäãðóçêà èñòîðèè...

    if (maxfunctime-findtime > synctime1  && synctime1>=0) return(0);
    
    maxfunctime= MathMax(findtime, maxfunctime);

    FuncLastTime[funcindex]= maintime;
    FuncLastValue[funcindex]= value; // êýøèðóåì ïîëó÷åííîå çíà÷åíèå ôóíêöèè
  }
  static double array[][ALGORANGE1][ALGORANGE2];
  int totalrange= ALGORANGE1 * ALGORANGE2;
  ArrayCopy(array, algorithms, 0, n*totalrange, totalrange);
  
  for (int i=0; ; i++)    // Ðàññ÷èòûâàåì àëãîðèòì ôîðìóëû
  {
    double cellvalue= array[0][i][CELLVALUE];
    int    maincell= array[0][i][CELLNEXTCELL];
    int    celltype= array[0][i][CELLTYPE];
    funcindex=cellvalue;
    if (celltype==TYPE_FUNC) cellvalue= FuncLastValue[funcindex];
    if (maincell <=0) break; 
    if (array[0][maincell][CELLTYPE]==TYPE_FUNC)
    {
      funcindex= array[0][maincell][CELLVALUE];
      array[0][maincell][CELLVALUE]= FuncLastValue[funcindex];
      array[0][maincell][CELLTYPE]= TYPE_VALUE;
    }
    switch (array[0][i][CELLOPERATION])
    {
      case '+':   array[0][maincell][CELLVALUE]+=cellvalue;  break;
      case '-':   array[0][maincell][CELLVALUE]= cellvalue - array[0][maincell][CELLVALUE];  break;
      case '*':   array[0][maincell][CELLVALUE]*=cellvalue;  break;
      case '/':   if (array[0][maincell][CELLVALUE]==0) { Error=ERROR_ZERODIVIDE;  ErrorString="Zero divide!";  return(0); }
                  array[0][maincell][CELLVALUE]= cellvalue / array[0][maincell][CELLVALUE];  break;
      case '^':    
                  double pow= array[0][maincell][CELLVALUE];
                  if (cellvalue==0 && pow<0)  { Error=ERROR_ZERODIVIDE;  ErrorString="Zero divide!";  Exit=true; return(0); } // "Äåëåíèå íà íîëü!"
                  if (cellvalue<0) if (MathMod(pow,1)>0)  { Error=ERROR_POW;  ErrorString="Exponentiation error!"; return(0); }   //Îøèáêà âîçâåäåíèÿ â ñòåïåíü! (äðîáíûé ïîêàçàòåëü è îòðèöàòåëüíîå îñíîâàíèå)");
                  if (pow==-1)  array[0][maincell][CELLVALUE]= 1/cellvalue;
                          else  array[0][maincell][CELLVALUE]= MathPow(cellvalue, array[0][maincell][CELLVALUE]);
                  break;
      default:    return(0);
    }
  }  
  
  result[0]=cellvalue;
  result[1]=maxfunctime;

  if (maintime0<0) return(true); //if (mainbar<0 && mainbar>=-3) return(true);
  
  if (CacheMinSize[n]==0) return(true);
  
  // Êýøèðóåì ïîëó÷åííîå çíà÷åíèå ôîðìóëû
  
  //maintime= maintime/period/60*period*60;
  int cachepos= CachePos[n];
  if (cachepos==-1) cachepos= CacheStartPos[n]-1;
  if (CacheMinSize[n]!=1)
  {
    if (cachepos>=0) if (maxfunctime<=CacheTimeBuffer[cachepos]) cachepos--;
    cachepos++;
    int endcache= CacheStartPos[n+1];
    if (endcache==0) endcache=ArraySize(CacheValueBuffer);
    if (cachepos >= endcache)  //CacheStartPos[n]+CacheMinSize[n]);
      if (CacheMinSize[n]<0) ResizeCache(n,+1000);
       else
       { 
         int newcachepos= CacheStartPos[n] + CacheMinSize[n]-1;
         ArrayCopy(CacheValueBuffer, CacheValueBuffer, CacheStartPos[n], cachepos-CacheMinSize[n], CacheMinSize[n]);
         ArrayCopy(CacheTimeBuffer, CacheTimeBuffer, CacheStartPos[n], cachepos-CacheMinSize[n], CacheMinSize[n]);
         cachepos=newcachepos;
       }
  }
  else cachepos= CacheStartPos[n];
  
  CachePos[n]= cachepos;  
  CacheValueBuffer[cachepos] = cellvalue;
  CacheTimeBuffer[cachepos] = maxfunctime;//maintime;
  
  return(true);
}

//---------------------------------------

bool ResizeCache(int index, int addsize)
{ 
  int buffersize=ArraySize(CacheValueBuffer);
  if (index+1>=ArraySize(CacheStartPos))
     { ArrayResize(CacheValueBuffer,buffersize+addsize); ArrayResize(CacheTimeBuffer,buffersize+addsize); return(0); }
  int nextstartpos=CacheStartPos[index+1];
  ArrayCopy(CacheTimeBuffer, CacheTimeBuffer, nextstartpos+addsize, nextstartpos);
  ArrayCopy(CacheValueBuffer, CacheValueBuffer, nextstartpos+addsize, nextstartpos);
  for (int i=index+1; i<ArraySize(CacheStartPos); i++)
  {
    CacheStartPos[i]+=addsize;
    CachePos[i]+=addsize;
  }
}

//------ Ðàñ÷¸ò çíà÷åíèÿ ôóíêöèè ----------------------------------------------------

bool CountFunction(double Param[][], int n, int maintf, int& findtime, int synctime, double Rates[][], int RatesPos[][], double& value)
{
  int oldtime=findtime;
  int functype= Param[n][0];
  int bartime;
  int symindex=EMPTY_VALUE;
  int symindexcount= DefaultFuncSymCount[functype];
  int pos[PARAMCOUNT];
  if (symindexcount==1) int tf= Param[n][2];
  if (tf==0) tf=maintf;
  int maxtime=0;
  int ts= FuncTimeSerie[n];
  
  for (int s=1; s<=symindexcount; s++)
  {
    symindex= Param[n][s];
    if (symindex==EMPTY_VALUE) return(0);
    if (maintf==0) maintf=Period();
    
    if (functype==FUNC_BID || functype==FUNC_ASK || functype==FUNC_LAST)
    {
      if (symindex<0) return(0);
      if (RatesPos[tf][1]>0) return(0);
      string symbol= Symbols[symindex];
      if (functype==FUNC_BID || functype==FUNC_ASK)  symbol= GetQuoteSymbol(symbol);
      if (functype==FUNC_BID || functype==FUNC_LAST)  value= MarketInfo(symbol,MODE_BID); else
      if (functype==FUNC_ASK) value= MarketInfo(symbol,MODE_ASK);  else return(0);
      if (GetLastError()==4106) { Error=ERROR_SYMBOL;  ErrorString="Unknown symbol:  "+symbol;  return(0); } // íå íàéäåí òàêîé èíñòðóìåíò
      findtime= MarketInfo(symbol,MODE_TIME);
      return(true);
    }
    if (symindex>=0)  // òðåáóåòñÿ ðàññ÷èòàòü ôóíêöèþ íà äàííûõ èç òàéì-ñåðèè ëèáî èç ïîëüçîâàòåëüñêîãî ìàññèâà
    {  
      if (RatesPos[ts][1]<=0)  //if (!UseOwnSymRates)
      {
        symbol= Symbols[symindex];
        int bar= iBarShift(symbol,tf,findtime);
        bartime= iTime(symbol,tf,bar);
        int ibars= iBars(symbol,tf);
      }
      else
      { // áàðû èäóò ñëåâà íàïðàâî
        int i= ArrayBsearch(Rates, findtime, RatesPos[ts][1], RatesPos[ts][0], MODE_ASCEND);
        bartime= Rates[i][0];
        bar= i-RatesPos[ts][0];
        ibars= RatesPos[ts][1];
      }
      if (bartime>findtime || ibars==0)  { findtime=0; return(0); }
    }
    else  // òðåáóåòñÿ ðàññ÷èòàòü ôóíêöèþ íà äàííûõ èç êýø-áóôåðà
    { 
      int formula_index= -symindex-1;
      int formula_cachepos= CachePos[formula_index]; 
      if (formula_cachepos==-1) formula_cachepos= CacheStartPos[formula_index]-1; 
      int formula_cachestartpos= CacheStartPos[formula_index];

      if (findtime < CacheTimeBuffer[formula_cachestartpos]) { findtime=0; return(0); }
      int formula_cachesize= formula_cachepos - formula_cachestartpos + 1;  
      i= formula_cachepos;
      if (formula_cachesize > 0)
        i= ArrayBsearch(CacheTimeBuffer, findtime, formula_cachesize, formula_cachestartpos, MODE_ASCEND);
      bartime= CacheTimeBuffer[i];
      bar= formula_cachepos - i;
      ibars= formula_cachesize;
      pos[s]= i;
    }

    maxtime=MathMax(maxtime,bartime);
    if (synctime>=0)
    {
      bartime= bartime/60/maintf*maintf*60;
      if (tf>=maintf)
        { if (findtime >= bartime+tf*60+synctime) return(0); }
       else if (findtime < bartime+synctime) return(0);
    }
    if (bar + MathAbs(FuncCacheMinSize[n]) > ibars) return(0);
  }
  
  findtime=maxtime;
  
  if (ts>=0 && RatesPos[ts][1]>0 && symindex>=0)  //UseOwnSymRates==true)
  {
    switch (functype)
    {
      case FUNC_OPEN:  value= Rates[i][1]; break;
      case FUNC_LOW:  value= Rates[i][2]; break;
      case FUNC_HIGH: value= Rates[i][3]; break;
      case FUNC_CLOSE: value= Rates[i][4]; break;
      case FUNC_VOLUME: value= Rates[i][5]; break;
      default:  Error=ERROR_FORMULA; return(0);
    }
    return(true);
  }
  
  int period= Param[n][3];
  if (period<=0) period+=ibars-bar;
  if (functype==FUNC_MACD)
    { int period2=Param[n][4]; int period3=Param[n][5];  if (period2<=0) period2+=ibars-bar;  if (period3<=0) period3+=ibars-bar; }
  
  if (symindex>=0 && symindex!=EMPTY_VALUE) 
   switch (functype)
   {  
    case FUNC_ATR:
      value= iATR(symbol, tf, period, Param[n][4]+bar); break;
    case FUNC_BANDS:
      value= iBands(symbol, tf, period, Param[n][4], Param[n][5], Param[n][6], Param[n][7], Param[n][8]+bar); break;
    case FUNC_MA:
      value= iMA(symbol, tf, period, Param[n][4], Param[n][5], Param[n][6], Param[n][7]+bar); break;
    case FUNC_STDDEV: 
      value= iStdDev(symbol, tf, period, Param[n][4], Param[n][5], Param[n][6], Param[n][7]+bar); break;
    case FUNC_AD:
      value= iAD(symbol, tf, Param[n][3]+bar); break;
    case FUNC_ADX:
      value= iADX(symbol, tf, period, Param[n][4], Param[n][5], Param[n][6]+bar); break;
    case FUNC_CCI:
      value= iCCI(symbol, tf, period, Param[n][4], Param[n][5]+bar); break;
    case FUNC_DEMARKER:
      value= iDeMarker(symbol, tf, period, Param[n][4]+bar); break;
    case FUNC_ENVELOPES:
      value= iEnvelopes(symbol, tf, period, Param[n][4], Param[n][5], Param[n][6], Param[n][7], Param[n][8], Param[n][9]+bar); break;
    case FUNC_MACD:
      value= iMACD(symbol, tf, period, period2, period3, Param[n][6], Param[n][7], Param[n][8]+bar); break;
    case FUNC_MOMENTUM:
      value= iMomentum(symbol, tf, period, Param[n][4], Param[n][5]+bar); break;
    case FUNC_RSI:
      value= iRSI(symbol, tf, period, Param[n][4], Param[n][5]+bar); break;
    case FUNC_STOCHASTIC:
      value= iStochastic(symbol, tf, period, Param[n][4], Param[n][5], Param[n][6], Param[n][7], Param[n][8], Param[n][9]+bar); break;
    case FUNC_CLOSE: case FUNC_LINECLOSE:
      value= iClose(symbol, tf, bar+Param[n][3]); break;
    case FUNC_OPEN: case FUNC_LINEOPEN:
      value= iOpen(symbol, tf, bar+Param[n][3]); break;
    case FUNC_HIGH: case FUNC_LINEHIGH:
      value= iHigh(symbol, tf, bar+Param[n][3]); break;
    case FUNC_LOW:  case FUNC_LINELOW:
      value= iLow(symbol, tf, bar+Param[n][3]); break;
    case FUNC_VOLUME:
      value= iVolume(symbol, tf, bar+Param[n][3]); break;
    case FUNC_MAXIMUM: case FUNC_MINIMUM:
      if (functype==FUNC_MAXIMUM) bar= iHighest(symbol, tf, Param[n][5], period, Param[n][4]+bar);
                            else  bar= iLowest(symbol, tf, Param[n][5], period, Param[n][4]+bar);
      if (Param[n][5]==MODE_CLOSE) { value= iClose(symbol, tf, bar);  break; }
      if (Param[n][5]==MODE_HIGH)  { value= iHigh(symbol, tf, bar);  break; }
      if (Param[n][5]==MODE_LOW)   { value= iLow(symbol, tf, bar);  break; }
      if (Param[n][5]==MODE_OPEN)  { value= iOpen(symbol, tf, bar);  break; }
      if (Param[n][5]==MODE_VOLUME){ value= iVolume(symbol, tf, bar);  break; }
    default:  Error=ERROR_FORMULA;  ErrorString="Unsupported function: "+DefaultFuncName[functype];  return(0);
   }
   else  // if (if (symindex<0)
   switch (functype)
   {
    case FUNC_MYATR:
      value= MyFunc_ATR(CacheValueBuffer, CacheTimeBuffer, i, i-formula_cachestartpos+1, Param[n][3], Param[n][4], Param[n][5]); break;
    case FUNC_BANDS:
      value=iBandsOnArray(CacheValueBuffer, i+1, period, Param[n][4], Param[n][5], Param[n][7], Param[n][7]+bar); break;
    case FUNC_MA:
      value= iMAOnArray(CacheValueBuffer, i+1, period, Param[n][4], Param[n][5], Param[n][7]+bar); break;
    case FUNC_STDDEV:
      value= iStdDevOnArray(CacheValueBuffer, i+1, period, Param[n][4], Param[n][5], Param[n][7]+bar); break;
    case FUNC_CCI: 
      value= iCCIOnArray(CacheValueBuffer, i+1, period, Param[n][5]+bar); break;
    case FUNC_ENVELOPES:
      value= iEnvelopesOnArray(CacheValueBuffer,i+1,period,Param[n][4],Param[n][5],Param[n][7],Param[n][8],Param[n][9]+bar); break;
    case FUNC_MOMENTUM:
      value= iMomentumOnArray(CacheValueBuffer,i+1,period,Param[n][5]+bar); break;
    case FUNC_RSI:
      value= iRSIOnArray(CacheValueBuffer,i+1,period,Param[n][5]+bar); break;
    case FUNC_CLOSE: case FUNC_LINECLOSE: case FUNC_OPEN: case FUNC_LINEOPEN: case FUNC_VOLUME:
      i-=Param[n][3];
      value= CacheValueBuffer[i]; break;
    case FUNC_MAXIMUM:
      value= CacheValueBuffer[ArrayMaximum(CacheValueBuffer, period, i-period+1-Param[n][4])]; break; //if (bartime>=Time[2]) Alert(CacheValueBuffer[0],"  ",CacheValueBuffer[1],"  ",CacheValueBuffer[2],"  ",CacheValueBuffer[3]);  break;
    case FUNC_MINIMUM:
      value= CacheValueBuffer[ArrayMinimum(CacheValueBuffer, period, i-period+1-Param[n][4])]; break;
    case FUNC_ABS:
      value= MathAbs(CacheValueBuffer[i]); break;
    case FUNC_LOG:
      value= MathLog(CacheValueBuffer[i]);  if (Param[n][2]!=0) value/=MathLog(Param[n][2]);  break;
    case FUNC_EXP:
      value= MathExp(CacheValueBuffer[i]); break;
    case FUNC_RND:
      static bool rndinit;  if (!rndinit) { MathSrand(TimeLocal()); rndinit=true; }
      value= MathRand(); break;
    case FUNC_ROUND:
      value= MathRound(CacheValueBuffer[i]); break;
    case FUNC_MAX:
      value= MathMax(CacheValueBuffer[pos[1]], CacheValueBuffer[pos[2]]); break;
    case FUNC_MIN:
      value= MathMin(CacheValueBuffer[pos[1]], CacheValueBuffer[pos[2]]); break;
    default: Error=ERROR_FORMULA; ErrorString="Unsupported function: "+DefaultFuncName[functype]; return(0);
   }
       
  return(true);
}

//-------------------------------------------------------------------------

int GetFunctionMinCacheSize(double& Param[][], int n)
{  
  int size=0;
  int functype=Param[n][0];  
  switch(functype)
  {
    case FUNC_ATR:         size= Param[n][3]+Param[n][4];  if (Param[n][3]==0) Param[n][3]=-size-1;     break;
    case FUNC_MYATR:       if (Param[n][2]==0) Param[n][2]=Period();
                           size= Param[n][3] * (Param[n][4]+Param[n][5]+1) / Param[n][2]; break;
    case FUNC_AD:          size= Param[n][3]; break;
    case FUNC_ADX:         size= Param[n][3]+Param[n][6];  if (Param[n][3]==0) Param[n][3]=-size;  break;
    case FUNC_BANDS:       size= Param[n][3]+Param[n][5]+Param[n][8];  if (Param[n][3]==0) Param[n][3]=-size;  break;
    case FUNC_CCI:         size= Param[n][3]+Param[n][5];  if (Param[n][3]==0) Param[n][3]=-size;  break;
    case FUNC_DEMARKER:    size= Param[n][3]+Param[n][4];  if (Param[n][3]==0) Param[n][3]=-size;  break;
    case FUNC_ENVELOPES:   size= Param[n][3]+Param[n][9];  if (Param[n][3]==0) Param[n][3]=-size;  break;
    case FUNC_MA:          size= Param[n][3]+Param[n][4]+Param[n][7];  if (Param[n][3]==0) Param[n][3]=-size;  break;
    case FUNC_MACD:        size= Param[n][8]+MathMax(MathMax(Param[n][3],Param[n][4]),Param[n][5]);
                           if (Param[n][3]==0) Param[n][3]=-Param[n][8];
                           if (Param[n][4]==0) Param[n][4]=-Param[n][8];
                           if (Param[n][5]==0) Param[n][5]=-Param[n][8];                                  break; 
    case FUNC_MOMENTUM:    size= Param[n][3]+Param[n][5]+1;  if (Param[n][3]==0) Param[n][3]=-size;  break;
    case FUNC_RSI:         size= Param[n][3]+Param[n][5]+1;  if (Param[n][3]==0) Param[n][3]=-size;  break;
    case FUNC_STDDEV:      size= Param[n][3]+Param[n][4]+Param[n][7];  if (Param[n][3]==0) Param[n][3]=-size;  break;
    case FUNC_STOCHASTIC:  size= Param[n][9]+MathMax(Param[n][3],Param[n][4]);  if (Param[n][3]==0) Param[n][3]=-size;  break;
    case FUNC_OPEN: 
    case FUNC_CLOSE:
    case FUNC_HIGH:
    case FUNC_LOW:         
    case FUNC_VOLUME:      size= Param[n][3]+1; break;
    case FUNC_LINEOPEN:
    case FUNC_LINECLOSE:
    case FUNC_LINEHIGH:
    case FUNC_LINELOW:     size= Param[n][3]; break;
    case FUNC_MAXIMUM:
    case FUNC_MINIMUM:     size= Param[n][3]+Param[n][4];  if (Param[n][3]==0) Param[n][3]=-size;  break;
    case FUNC_LOG:
    case FUNC_EXP:
    case FUNC_ROUND:       size= 1; break;
    case FUNC_MAX:
    case FUNC_MIN:         size= 1; 
  }
  if (Param[n][3]<=0 || ((Param[n][4]<=0 || Param[n][5]<=0) && functype==FUNC_MACD))
    switch (functype)
     { case FUNC_ATR: case FUNC_MA: case FUNC_ADX: case FUNC_BANDS: case FUNC_CCI: case FUNC_DEMARKER: case FUNC_ENVELOPES: case FUNC_MACD:
       case FUNC_MOMENTUM: case FUNC_RSI: case FUNC_STDDEV: case FUNC_STOCHASTIC: case FUNC_MAXIMUM: case FUNC_MINIMUM:
         size=-MathMax(size,1);
     }
  
  return(size);
} 
/*
//--------- Âû÷èñëÿåì ìàêñèìàëüíîå âðåìÿ êîòèðîâîê Bid/Ask äëÿ äàííîé ôîðìóëû ---------
int GetBidAskMaxTime(int n)
{
  int maxtime=0;
  for (int f=0; f<ArrayRange(AlgoFunctions,1); f++)
  {
    int funcindex=AlgoFunctions[n][f];
    if (funcindex<0) break;
    int functype=FuncParam[funcindex][0];
    if (functype!=FUNC_BID && functype!=FUNC_ASK && functype!=FUNC_LAST) continue;
    int symindex=FuncParam[funcindex][1];
    string symbol=Symbols[symindex];
    maxtime=MathMax(maxtime, MarketInfo(GetQuoteSymbol(symbol),MODE_TIME));      
  }
  return(maxtime);
}
*/
//--------------------------------------------------------

int GetBidAskFormula(int baseformulaindex, int& priceindex)
{
  int n= baseformulaindex;
  int existindex= Algo_BidAskAlgoIndex[n][-priceindex];
  if (existindex>0)  return(existindex);   //{ int maxtime=GetBidAskMaxTime(existindex);  priceindex=maxtime;   }
  if (!AlgoEnabled[n]) return(-1);
  static bool getpowratio[100];
  
  if (priceindex==-1 || priceindex==-2)
    if (!getpowratio[n])
       if (!GetAlgoAllPowAndRatio(n, AlgorithmsTotalPowRatio)) return(-1);
         else getpowratio[n]=true;
  
  double algo[ALGORANGE1][ALGORANGE2];
  
  for (int i=0; i<ALGORANGE1; i++)
  {
    for (int j=0; j<ALGORANGE2; j++) algo[i][j]=Algorithms[n][i][j];
    if (i>0) if (Algorithms[n][i-1][CELLNEXTCELL]<=i-1) break;
    if (Algorithms[n][i][CELLTYPE]!=TYPE_FUNC) continue;
    int funcindex= Algorithms[n][i][CELLVALUE];
    if (FuncParam[funcindex][0]!=FUNC_CLOSE) continue;
    if (FuncParam[funcindex][2]!=0) continue;
    int symindex= FuncParam[funcindex][1];
    if (symindex<0) continue;
    double totalratio= AlgorithmsTotalPowRatio[n][i][0] * AlgorithmsTotalPowRatio[n][i][1];
    int functype=FUNC_BID;
    if ((totalratio>0)==(priceindex==-1)) functype=FUNC_ASK;
    if (priceindex==-3) functype=FUNC_LAST;
    int functotal= ArrayRange(FuncParam,0); 
    for (int f=0; f<functotal; f++)
      if (FuncParam[f][0]==functype && FuncParam[f][1]==symindex) break;
    if (f==functotal)
    {    
      ArrayResize(FuncParam,f+1); ArrayResize(FuncCacheMinSize,f+1); //ArrayResize(FuncCopies,f+1);
      FuncParam[f][0]=functype;  FuncParam[f][1]=symindex;
      //FuncCacheMinSize[f]= 0; // GetFunctionMinCacheSize(FuncParam,f);
    }
    algo[i][CELLVALUE]=f;
  }
  int new= SaveAlgoArray(algo, i, -1, -1);
   
  Algo_BidAskAlgoIndex[n][-priceindex]= new;  
  return(new);
} 

//----------------------------------------------------------------------------------------------------

bool GetAlgoAllPowAndRatio(int n, double& AlgorithmsTotalPowRatio[][][])
{  
  double results[2];
  bool result= CountMyFormulaValue(n, -3, results);
  ArrayInitialize(CachePos,-1);
  if (result==false) return(0);

  int nlast= Algo_BidAskAlgoIndex[n][3];
  double algovalues[ALGORANGE1];
  int cellscount= ArrayRange(Algorithms,1);

  for (int i=0;  i<cellscount;  i++)
  {
    if (i>0) if (Algorithms[n][i-1][CELLNEXTCELL] <= i-1) break;
    if (Algorithms[n][i][CELLTYPE]==TYPE_VALUE) { algovalues[i]= Algorithms[n][i][CELLVALUE]; continue; }
    int funcindex=Algorithms[nlast][i][CELLVALUE];
    if (FuncLastTime[funcindex] <=0) return(0); 
    algovalues[i]= FuncLastValue[funcindex];
  }
  if (ArrayRange(AlgorithmsTotalPowRatio,0) <=n) ArrayResize(AlgorithmsTotalPowRatio, n+1);
  cellscount=i;
  for (i=0;  i<cellscount;  i++)
  {
    GetAlgoPositionPowAndRatio(n, i, algovalues, results);
    AlgorithmsTotalPowRatio[n][i][0]= results[0];
    AlgorithmsTotalPowRatio[n][i][1]= results[1];
  }
  return(true);
}

//--------------------------------------------------------------------------------------------

bool SaveExistAlgo(int N)   
{ 
  bool foundlinks=0;               
  for (int n=0; n<ArrayRange(Algorithms,0); n++)
    if (n!=N)
      for (int i=0; ; i++)
      {
        if (Algorithms[n,i,CELLTYPE]==TYPE_FUNC)
        {
          int funcindex= Algorithms[n][i][CELLVALUE];
          if (FuncParam[funcindex][1] != -N-1) continue; //  íå ðàâíî èíäåêñó èñêîìîé ôîðìóëû
          FuncParam[funcindex][1]= -ArrayRange(Algorithms,0)-1; 
          foundlinks=true;
        }
        if (Algorithms[n,i,CELLNEXTCELL]<=0) break;
      }
  if (!foundlinks) return(0);  // ññûëêè íà ìàññèâ ñ ýòèì èíäåêñîì íå íàéäåíû
  ArrayResize(Algorithms,n+1);              ArrayCopy0(Algorithms, Algorithms, n, N, 1);
  ArrayResize(AlgorithmsTotalPowRatio,n+1); ArrayCopy0(AlgorithmsTotalPowRatio, AlgorithmsTotalPowRatio, n, N, 1);
  ArrayResize(SymbolsIndexes,n+1);          ArrayCopy0Int(SymbolsIndexes, SymbolsIndexes, n, N, 1);
  ArrayResize(SymbolsFuncPos,n+1);          ArrayCopy0Int(SymbolsFuncPos, SymbolsFuncPos, n, N, 1);
  ArrayResize(CacheStartPos,n+1);  CacheStartPos[n]= ArraySize(CacheValueBuffer); 
  ArrayResize(CachePos,n+1);       CachePos[n]= CacheStartPos[n]-1;
  ArrayResize(CacheMinSize,n+1);   CacheMinSize[n]= CacheMinSize[N];
  ArrayResize(AlgoNames,n+1);      AlgoNames[n]= AlgoNames[N];   
  
  return(true);
}   

//------------------------------------------------------------------------------------

int AddFormulaForOwnRates(string formula)
{
  MyRatesAllow=true;
  double value= AddFormula(formula);
  MyRatesAllow=false;
  return(value);
}

//------------------------------------------------------------------------------------

bool SetFormula(string formula, int n)
{
  return( AddFormula(formula,n)>=0 );
}

//-----------------------------------------------------------------------------------

int AddFormula(string formula, int N=-1, int defaulttf=0, int defaultfunc=FUNC_CLOSE)
{
  ErrorString="";
  if (DefaultFuncSymCount[FUNC_CLOSE]==0) { InitTime=0; init(); } 
  int len=StringLen(CURRENT_SYMBOL);
  int findpos= StringFind(formula,CURRENT_SYMBOL);
  if (findpos==0)  formula= Symbol()+StringSubstr(formula,findpos+len); else
  if (findpos>0)  formula= StringSubstr(formula,0,findpos)+Symbol()+StringSubstr(formula,findpos+len);
  
  double algo[ALGORANGE1][ALGORANGE2];
  static int ParentN=-1;
  if (N>=0) ParentN=N;
  
  int cellscount= CreateFormulaArray(formula,algo,FuncParam,Symbols,defaulttf,defaultfunc);
  if (N==ParentN) ParentN=-1;  // çíà÷èò ýòî îñíîâíîé àëãîðèòì
  if (cellscount<=0) return(-1);
  
  int n= SaveAlgoArray(algo, cellscount, N, ParentN);
  AlgoNames[n]=formula;
  return(n);
}

//------------------------------------------------------
  
int SaveAlgoArray(double algo[][], int cellscount, int N, int ParentN)
{  
  int n=0;
  if (N>=0) n=N;
  for (n=n; n<ArrayRange(Algorithms,0); n++)  // Èùåì òàêîé æå àëãîðèòì ñðåäè èìåþùèõñÿ àëãîðèòìîâ
  {
    if (n==ParentN) continue;  
    for (int i=0; i<=cellscount && i>=0; i++)
      for (int j=0; j<ArrayRange(algo,1); j++)
        if (Algorithms[n][i][j] != algo[i][j]) { i=-2;  break; }
    if (i>0) return(n);  // ñîâïàäåíèå íàéäåíî, çíà÷èò âîçâðàùàåì èíäåêñ ñóùåñòâóþùåãî àëãîðèòìà 
    if (N>=0) break; 
  }
  if (n==ParentN) n++;  // äî÷åðíèé àëãîðèòì ñîâïàäàåò ñ ðîäèòåëüñêèì
  if (N>=0 && !IsIndicator)  // åñëè ÿâíî óêàçàí èíäåêñ ñîõðàíÿìîãî àëãîðèòìà, òî ñíà÷àëà ïðîâåðÿåì, ñóùåñòâóþò ëè ñðåäè äðóãèõ àëãîðèòìîâ ññûëêè íà àëãîðèòì ïîä òàêèì èíäåêñîì, è åñëè äà, òî ïåðåìåùàåì ñóùåñòâóþùèé àëãîðèòì â äðóãîå ìåñòî, à ññûëêè êîððåêòèðóåì
    if (N<ArrayRange(Algorithms,0)) SaveExistAlgo(N);
  
  if (N<0 && IsIndicator) n= MathMax(n, 10);  // èíäåêñ ñîõðàíÿåìîãî àëãîðèòìà íàçíà÷àåì >= 10, ò.ê. ýòî íå îñíîâíîé àëãîðèòì (îñíîâíàÿ ôîðìóëà), à äî÷åðíèé àëãîðèòì
  if (ArrayRange(Algorithms,0)<=n) ArrayResize(Algorithms,n+1);
  if (ArrayRange(AlgorithmsTotalPowRatio,0)<=n) ArrayResize(AlgorithmsTotalPowRatio,n+1);
  if (ArrayRange(AlgoFunctions,0)<=n) ArrayResize(AlgoFunctions,n+1);
  if (ArrayRange(SymbolsIndexes,0)<=n) ArrayResize(SymbolsIndexes,n+1);
  if (ArrayRange(SymbolsFuncPos,0)<=n) ArrayResize(SymbolsFuncPos,n+1);
 
  if (ArraySize(CachePos)<=n) ArrayResize(CachePos,n+1);
  if (ArraySize(CacheStartPos)<=n) ArrayResize(CacheStartPos,n+1);
  if (ArraySize(CacheMinSize)<=n) ArrayResize(CacheMinSize,n+1);
  if (ArraySize(AlgoNames)<=n) ArrayResize(AlgoNames,n+1);
  AlgoRange0= MathMax(AlgoRange0, ArrayRange(Algorithms,0));
  Algo_BidAskAlgoIndex[n][1]=-1;  Algo_BidAskAlgoIndex[n][2]=-1;  Algo_BidAskAlgoIndex[n][3]=-1; 
  int ss=0;
  int nf=-1;
  int funccount=0;
  
  for (i=0; i<cellscount; i++)
  {
    for (j=0; j<ArrayRange(algo,1); j++)
      Algorithms[n][i][j]=algo[i][j];
    
    if (algo[i][CELLTYPE]==0) continue;
    if (algo[i][CELLTYPE]==TYPE_VALUE) continue;
    
    int funcindex= algo[i][CELLVALUE];
    
    for (int f=0; f<funccount; f++)
      if (AlgoFunctions[n][f]==funcindex) break;
    AlgoFunctions[n][f]=funcindex;
    if (f==funccount) funccount++;
    
    FuncCacheMinSize[funcindex]= GetFunctionMinCacheSize(FuncParam, funcindex);
    int functype=FuncParam[funcindex][0];
    int symindexcount=DefaultFuncSymCount[functype];
    
    for (int p=1; p<=symindexcount; p++)
    {
      int symindex= FuncParam[funcindex][p];
      if (symindex==EMPTY_VALUE) continue;
      if (symindex<0)  // èíäåêñ ôîðìóëû
      { 
        nf= -symindex-1; 
        if (nf>=ArraySize(CacheMinSize)) { ArrayResize(CacheMinSize,nf+1); ArrayResize(CacheStartPos,nf+1); ArrayResize(CachePos,nf+1); }
        if (FuncCacheMinSize[funcindex]<0) CacheMinSize[nf]= MathMin(CacheMinSize[nf], FuncCacheMinSize[funcindex]);
          else CacheMinSize[nf]= MathMax(CacheMinSize[nf], FuncCacheMinSize[funcindex]);
        if (!AlgoEnabled[nf])
          if (!IsIndicator) return(-1); else continue;
        CacheMinSize[n]= MathMax(CacheMinSize[n], 1);
        for (int s1=0;  SymbolsIndexes[nf][s1][0] >=0;  s1++)
        {
          for (int s=0; s<ss; s++)
            if (SymbolsIndexes[n][s][0]==SymbolsIndexes[nf][s1][0] || s>=ArrayRange(SymbolsIndexes,1)) break;
          if (s==ss) { SymbolsIndexes[n][s][0]= SymbolsIndexes[nf][s1][0];  ss++; }
        }
        continue;
      }
      else  // èíäåêñ ñèìâîëà
        for (s=0; s<ss; s++)
          if (SymbolsIndexes[n][s][0]==symindex) break;
      
      SymbolsIndexes[n][s][0]=symindex;
      if (s==ss) { ss++; SymbolsIndexes[n][s][1]=0; }
      int pos=SymbolsIndexes[n][s][1];    //Alert(n," ",s," ",pos," = ",i); //return(0);
      SymbolsFuncPos[n][s][pos]=i;  // Çàïèñûâàåì ïîçèöèþ äàííîé ôóíêöèè â ìàññèâå [ñèìâîë][ôóíêöèÿ]
      SymbolsIndexes[n][s][1]++;
      
      int tf= FuncParam[funcindex][symindexcount+1];     
      for (int ts=0; ts<ArrayRange(TimeSeries,0); ts++)
        if (TimeSeries[ts][0]==symindex && TimeSeries[ts][1]==tf) break;
      FuncTimeSerie[funcindex]= ts;
      if (ts<ArrayRange(TimeSeries,0)) continue;
      ArrayResize(TimeSeries, ts+1);
      TimeSeries[ts][0]= symindex;
      TimeSeries[ts][1]= tf;
    }
  }
  SymbolsIndexes[n][ss][0]=-1; // óñòàíàâëèâàåì îêîí÷àíèå ìàññèâà èíäåêñîâ
  AlgoFunctions[n][funccount]=-1;
    
  //if (nf>=0)
  {
    int totalsize=0;
    for (int m=0; m<ArraySize(CacheMinSize); m++)
    {
      totalsize+=CacheMinSize[m];
      if (CacheMinSize[m]>1) totalsize+=100;
      if (CacheMinSize[m]<0) totalsize+=CacheMinSize[m]+1000;
      CacheStartPos[m+1]= totalsize;   //CacheStartPos[a]+CacheMinSize[a]+100;
      CachePos[m]=CacheStartPos[m]-1;
    }
    ArrayResize(CacheValueBuffer, totalsize);
    ArrayResize(CacheTimeBuffer, totalsize);
  }
  AlgoEnabled[n]=true;
  
  return(n);
}

//-----------------------------------------------------------------------------------

bool GetAlgoPositionPowAndRatio(int n, int i, double algovalues[], double& results[])
{      
    double pow=1;
    double ratio=1;
    double log=1;
    double values[];
    ArrayCopy(values,algovalues);
    int mycell=i;
    int maxcellscount= ArrayRange(Algorithms,1);
    for (int cell=0;  cell<maxcellscount;  cell++)
    {
      int nextcell= Algorithms[n][cell][CELLNEXTCELL];
      if (nextcell<=cell) break;
      double cellvalue= values[cell];
      double nextcellvalue= values[nextcell];
      int operation= Algorithms[n][cell][CELLOPERATION];
      switch (operation)
      {
        case '-':  if (nextcell==mycell) ratio*=-1; else values[nextcell]*=-1;     //if (algo[nextcell][CELLTYPE]==TYPE_FUNC) values[nextcell]*=-1;
        case '+':  if (cell!=mycell && nextcell!=mycell) values[nextcell]+=cellvalue;
                   break;
        case '/':  if (nextcell==mycell) pow*=-1; else values[nextcell]= 1/values[nextcell];
        case '*':  if (cell==mycell) ratio*=nextcellvalue; else
                   if (nextcell==mycell) ratio*=cellvalue; else values[nextcell]*=cellvalue;
                   break;
        case '^':  if (nextcell==mycell) log*=MathLog(cellvalue); else 
                   if (cell==mycell) pow*=nextcellvalue; else
                   values[nextcell]= MathPow(cellvalue,nextcellvalue);      //if (cellvalue<1 && MathMod(nextcellvalue,2)>0) 
      }
      if (cell==mycell) mycell=nextcell;
    }
    results[0]= pow*log;
    results[1]= ratio;
    return( results[0]*results[1] );
}

//----- Ñ÷èòûâàíèå ïàðàìåòðîâ ôóíêöèè -------------------------------------------------------------
 
bool GetFunctionParam(string formula, int& startpos, int templateindex, string& symbols[], int last_sym, int& param[])
{
  static int Periods[]={ PERIOD_M1,PERIOD_M5,PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H4,PERIOD_D1,PERIOD_W1,PERIOD_MN1 };
  static string PeriodNames[]={"M1",     "M5",     "M15",     "M30",     "H1",     "H4",     "D1",     "W1",     "MN1"};
  
  string paramstr[PARAMCOUNT];
  int paramcount=PARAMCOUNT;
  int functype= TemplateFuncParam[templateindex][0];       
  param[0]=functype;
  int p=0;
  int bracket=0;
  int endpos=StringLen(formula);
  
  for (int i=startpos; i<=endpos; i++)
  { 
    int char=StringGetChar(formula,i);
    if (char=='(') bracket++;
    if (char==')') bracket--;
    if (bracket<0) endpos=i;
    if (i<endpos)
      if (bracket>0 || char!=',') continue;
    p++;
    if (p==paramcount) break;
    
    int paramlenght= i-startpos;
    string paramstring="";
    if (paramlenght>0) paramstring= StringTrimLeft(StringTrimRight(StringSubstr(formula, startpos, paramlenght)));
    paramstr[p]=paramstring;
    startpos=i+1;
  }
  
  if (functype==FUNC_RND) { paramcount=0;  param[1]=EMPTY_VALUE; }
  int symparamcount= DefaultFuncSymCount[functype];
  int tfparam=2;
  switch (functype) { case FUNC_ABS: case FUNC_LOG: case FUNC_EXP: case FUNC_ROUND: case FUNC_MAX: case FUNC_MIN:  tfparam=-1; }
  int pp=p;
  
  for (p=paramcount-1;  p>=1;  p--)
  {
    paramstring= paramstr[p];
    if (p > pp) paramstring="";
    param[p]=StrToInteger(paramstring);

    if (paramstring!="" && paramstring!="0")
      if (p==tfparam || (p==3 && functype==FUNC_MYATR))  // ïàðàìåòð ÿâëÿåòñÿ íàçâàíèåì ïåðèîäà
      {
        if (DoubleToStr(param[p],0) ==paramstring)   // ïàðàìåòð ÿâëÿåòñÿ ÷èñëîì
          int n= ArrayBsearch(Periods, param[p]);
        else
          for (n=ArraySize(PeriodNames)-1; n>=0; n--)
            if (paramstring==PeriodNames[n]) { param[p]=Periods[n]; break; }
        if (Periods[n]!=param[p]) return(0); // { ErrorString="Wrong timeframe: "+paramstring; 
        continue;
      }
    if (functype==FUNC_MAXIMUM || functype==FUNC_MINIMUM)
      if (p==5)
        if (paramstring=="OPEN") param[p]=MODE_OPEN; else
        if (paramstring=="CLOSE") param[p]=MODE_CLOSE; else
        if (paramstring=="HIGH") param[p]=MODE_HIGH; else
        if (paramstring=="LOW") param[p]=MODE_LOW; else
        if (paramstring=="VOLUME") param[p]=MODE_VOLUME;
       
    if (paramstring=="" && p>symparamcount)  // åñëè ïàðàìåòð íå çàäàí è ýòîò ïàðàìåòð íå ÿâëÿåòñÿ íàçâàíèåì ñèìâîëà
       param[p]= TemplateFuncParam[templateindex][p-1];
       
    if (p>symparamcount) continue; // ïàðàìåòð íå ÿâëÿåòñÿ íàçâàíèåì ñèìâîëà
    string symbol=paramstring;
    param[p]=0;
    switch(functype)
    { 
      case FUNC_ABS: case FUNC_LOG: case FUNC_EXP: case FUNC_ROUND: case FUNC_MAX: case FUNC_MIN:
        param[p]=-1; 
        if (symbol=="") { param[p]=EMPTY_VALUE; continue; }
        break;
      case FUNC_BANDS: case FUNC_CCI: case FUNC_ENVELOPES: case FUNC_MA: case FUNC_MOMENTUM: case FUNC_STDDEV: case FUNC_RSI:
      case FUNC_MAXIMUM: case FUNC_MINIMUM:
        if (param[3]<=0) param[1]=-1;  // èñïîëüçóåòñÿ ïåðåìåííûé ïåðèîä óñðåäíåíèÿ ôóíêöèé. Ñòàíäàðòíûå ôóíêöèè iMa, iStdDev è ò.ä. â ýòîì ñëó÷àå ðàñc÷èòûâàþòñÿ î÷åíü ìåäëåííî, ïîýòîìó áóäåì èñïîëüçîâàòü ôóíêöèè íà ïîëüçîâàòåëüñêèõ ìàññèâàõ: iMaOnArray, iStdDevOnArray è ò.ä.
    }
    string mathsign[]= { "+", "-", "*", "/", "^", "(" };
    for (int m= ArraySize(mathsign)-1;  m>=0;  m--)
      if (StringFind(symbol,mathsign[m])>=0)
        break;
    if (m>=0 || functype==FUNC_MYATR || MyRatesAllow) param[p]=-1;
    
    if (param[p]>=0)
      if (functype!=FUNC_OPEN && functype!=FUNC_CLOSE && functype!=FUNC_HIGH && functype!=FUNC_LOW && functype!=FUNC_VOLUME)
        if (!FindSymbolInSymbolsRow(symbol)) param[p]=-1; // åñëè ñèìâîë íå íàéäåí â ôàéëå symbols.row, çíà÷èò ñòàíäàðòíûå èíäèêàòîðíûå ôóíêöèè èñïîëüçîâàòü íà í¸ì íåëüçÿ, ïîýòîìó ñîçäà¸ì íîâóþ ôîðìóëó ñ ýòèì ñèìâîëîì, ÷òîáû èñïîëüçîâàòü èíäèêàòîðû íà ìàññèâàõ (...OnArray)
    
    if (param[p]<0)  // ôîðìóëà
    {
      static int recurslevel=0;
      string oldparamstr[PARAMCOUNT];
      int    oldparam[PARAMCOUNT];
      ArrayCopy(oldparamstr, paramstr, recurslevel*PARAMCOUNT, 0, PARAMCOUNT);      
      ArrayCopy(oldparam, param, recurslevel*PARAMCOUNT, 0, PARAMCOUNT); 
      recurslevel++;
      int defaulttf= param[2];
      int defaultfunc= FUNC_CLOSE;
      if (functype==FUNC_VOLUME) defaultfunc=FUNC_VOLUME;
      if (functype==FUNC_MAXIMUM || functype==FUNC_MINIMUM)
        if (param[5]==MODE_OPEN) defaultfunc=FUNC_OPEN; else
        if (param[5]==MODE_VOLUME) defaultfunc=FUNC_VOLUME;
       
      int newformulaindex= AddFormula(symbol, -1, defaulttf, defaultfunc);
      recurslevel--;
      ArrayCopy (paramstr, oldparamstr, 0, recurslevel*PARAMCOUNT, PARAMCOUNT);
      ArrayCopy (param, oldparam, 0, recurslevel*PARAMCOUNT, PARAMCOUNT);
      if (newformulaindex<0)  { if (ErrorString=="") ErrorString="Failed to create formula  "+symbol;  return(0); }  // "Íå óäàëîñü çàïèñàòü ôîðìóëó  "
      param[p]= -newformulaindex-1;        // çàïèñûâàåì èíäåêñ íîâîé ôóíêöèè âìåñòî èíäåêñà ñèìâîëà
    } 
    if (param[p]>=0 && param[p]!=EMPTY_VALUE)  param[p]= SetSymbol(symbol, last_sym); 
  }
  
  if (functype==FUNC_MYATR)
  {
    if (param[2]==0) param[2]=Period();
    if (param[3]==0) param[3]=Period();
  }
  startpos= endpos+1;
  return(true);
}

//------------------------------------------------------

bool FindSymbolInSymbolsRow(string symbol)
{
  MarketInfo(symbol,MODE_TIME);
  if (GetLastError()!=4106) return(true);
  static string symbols[];
  static int inittime;
  if (InitTime!=inittime)
  {
    int h=FileOpenHistory("symbols.raw",FILE_BIN|FILE_READ);
    if (h<0) { Print("Íå óäàëîñü îòêðûòü ôàéë symbols.raw"); return(0); }
    int arraysize=FileSize(h)/1936;
    ArrayResize(symbols,arraysize);
    string txt="";
    for (int n=0; n<arraysize; n++)
    {
      if (!FileSeek(h,n*1936,SEEK_SET)) { symbols[n]=""; break; }
      symbols[n]=FileReadString(h,12); // òèêåð
    }
    Print("Ñ÷èòàíî ",n," êîíòðàêòîâ èç ôàéëà symbols.raw");
    FileClose(h);
    inittime=InitTime;
  }
  for (int i=ArraySize(symbols)-1; i>=0; i--)
    if (symbols[i]==symbol) break;
  if (i<0) return(0);      
  return(true);
}

//-----------------------------------------

int SetSymbol(string symbol, int& last_sym)
{
  if (symbol=="0") symbol=Symbol();
  if (symbol=="")
    if (last_sym>=0) symbol=Symbols[last_sym]; else symbol=Symbol();

  // Ïðîâåðÿåì, ÿâëÿåòñÿ ëè íàçâàíèå ñèìâîëà ññûëêîé íà äðóãóþ ôîðìóëó
  string upcasesymbol= StringUpperCase(symbol);
  int finddigitpos=10000;
  if (StringFind(upcasesymbol,"FORMULA")==0) finddigitpos=7;  else if (StringFind(upcasesymbol,"F")==0) finddigitpos=1;
  for (int d=finddigitpos; d<StringLen(symbol); d++)
    if (StringGetChar(symbol,d)<'0' || StringGetChar(symbol,d)>'9') break;
  if (d==StringLen(symbol) && d>1)
  {
    int formulaindex= StrToInteger(StringSubstr(symbol,finddigitpos));
    int index= -formulaindex-1;
    IsFormulaUsing[formulaindex]= true;
    return(index);
  }
  for (int s=0; s<ArraySize(Symbols); s++)
    if (Symbols[s]==symbol) break; 
  if (s==ArraySize(Symbols)) ArrayResize(Symbols,s+1);  
  Symbols[s]=symbol;
  last_sym= s;  // çàïîìèíàåì èíäåêñ ïîñëåäíåãî ñèìâîëà   
  
  return(s);
}  

//--------------------------------------------------------

int CreateFormulaArray(string Formula,double& Algo[][],double& AllFuncParam[][],string& AllSymbols[],int defaultTF,int defaultFunc)
{ 
  Formula= StringTrimLeft(StringTrimRight(Formula));
  if (StringSubstr(Formula,0,1)=="'") Formula=StringSubstr(Formula,1);
  int    strlen= StringLen(Formula);
  bool   symbolfound=0;
  bool   digitfound=0;
  int    last_sym= -1;
  int    funccount= ArrayRange(AllFuncParam,0);
  if (funccount==0) ArrayResize(AllSymbols,0);
  int    startlevel=0;
  int    maxlevel=0;
  int    signchar=0;
  int    member=0;
  static int recurslevel=0;
  #define ARRAYRANGE1     6
  double Array[20][ARRAYRANGE1];   // [member][param]
  ArrayInitialize(Array,0);
  #define CELLLEVEL       4
  #define CELLPARENTLEVEL 5
  int lastlevel=-1;
  int LevelInvert[100];
  int  startpos=0;
  int squarebracket=0;
  
  for (int i=0; startpos <= strlen; i++)
  {
    int char=StringGetChar(Formula,i);
    if (char=='[') { squarebracket++;  symbolfound=true; }
    if (char==']')  squarebracket--;
    if (squarebracket>0 && i<strlen) continue;
    
    if ((char>='0' && char<='9') || char=='.')
     { 
       if (!symbolfound) digitfound=true;
       continue;
     }
    if (char==' ' && !symbolfound)  { if (i==startpos) startpos++;  continue; }
        
    if (char=='+' || char=='-' || char=='*' || char=='/' || char=='^')
     { 
       if (!symbolfound && !digitfound) signchar=char;
       if (i==startpos) { startpos++; continue; }
     }
     else
     if (char!='(' && char!=')' && i<strlen)
      { symbolfound=true; digitfound=false; continue; }
      
    int operand;
    string charstr=CharToStr(signchar);
    if (StringFind("+-)",charstr)>=0)  operand=SUMMAND; else
    if (StringFind("*/",charstr)>=0)  operand=MULTIPLIER; else
    if (StringFind("^",charstr)>=0)  operand=POW;
    
    int level= startlevel+operand;
    
    if (level < Array[member-1][CELLLEVEL])// lastlevel)
     for (int lev=Array[member-1][CELLLEVEL];  lev>level || (lev==level && startpos==strlen);  lev--) // 
      {
        Array[member][CELLLEVEL]= lev;
        Array[member][CELLTYPE]=TYPE_VALUE;
        if (lev%3==SUMMAND) Array[member][CELLVALUE]=0; else Array[member][CELLVALUE]=1;
        int plev= lev-1;
        if (LevelInvert[plev]==true)  { Array[member][CELLVALUE]=-1;  LevelInvert[plev]=false; } //    if (Array[member][CELLPARENTLEVEL]=plev; }Alert("inv ",member,"  ",Array[member][CELLLEVEL]); Array[member][CELLVALUE]=-1; LevelInvert[lev-1]=false; Array[member][CELLLEVEL]=lev; }
        //if (lev%3==SUMMAND && lev>level) plev=MathMax(level,lastlevel);
        Array[member][CELLPARENTLEVEL]= plev;
        member++;
      }
    if (lastlevel>=0 && member>0) lastlevel= Array[member-1][CELLLEVEL];
                            else  lastlevel= level;

    if (level>lastlevel && lastlevel>=0)
      { Array[member-1][CELLLEVEL]= level;  Array[member-1][CELLPARENTLEVEL]= level; } //Alert(member-1,"  ",lastlevel,"  ",level); 
    
    if (signchar=='-') { operand=MULTIPLIER;  LevelInvert[level]=true; }
    if (signchar=='/') { operand=POW;  LevelInvert[level]=true; }
    level= startlevel+operand;
    
    Array[member][CELLTYPE]=TYPE_VALUE;
    
    if (operand==SUMMAND) Array[member][CELLVALUE]=0; else Array[member][CELLVALUE]=1;
    Array[member][CELLLEVEL]= level; //startlevel+operand;
    Array[member][CELLPARENTLEVEL]= level; //startlevel+operand;
    
    if (digitfound) 
      Array[member][CELLVALUE]= StrToDouble(StringSubstr(Formula,startpos,i-startpos));
   
    if (symbolfound)
    { 
      string name= StringTrimLeft(StringTrimRight(StringSubstr(Formula, startpos, i-startpos)));
      if (StringGetChar(Formula, startpos)=='[')
      {
        name= StringSubstr(name, 1);   //startpos++;
        if (StringGetChar(Formula, i-1)==']')  name= StringSubstr(name, 0, StringLen(name)-1);
      }   
      int param[PARAMCOUNT]; ArrayInitialize(param,0);
      if (char!='(')   // ýòî íå èìÿ ôóíêöèè, çíà÷èò ýòî íàçâàíèå ñèìâîëà
      {
        param[0]= defaultFunc;
        param[1]= SetSymbol(name, last_sym);
        param[2]= defaultTF;
      } 
      else  // èìÿ ôóíêöèè
      {
        i++;
        int tempcount= ArraySize(TemplateFuncName);
        for (int t=0; t<tempcount; t++)
          if (StringLen(TemplateFuncName[t])==0)  t=tempcount;
           else if (StringUpperCase(TemplateFuncName[t])==StringUpperCase(name))  break;
            
        if (t>=tempcount) { ErrorString="Unknown function:  "+name+"(...)"; break; }     // "Íåèçâåñòíàÿ ôóíêöèÿ: "
        recurslevel++;
        ArrayCopy0 (Array, Array, recurslevel*100, 0, 100);  // áýêàïèì èñõîäíûå ìàññèâû, ò.ê. îíè ìîãóò áûòü çàìåíåíû â õîäå ðåêóðñèè
        ArrayCopy(LevelInvert, LevelInvert, recurslevel*100, 0, 100);
        bool result= GetFunctionParam(StringUpperCase(Formula), i, t, AllSymbols, last_sym, param);
        ArrayCopy0 (Array, Array, 0, recurslevel*100, 100);  // âîññòàíàâëèâàåì èñõîäíûå ìàññèâû
        ArrayCopy(LevelInvert, LevelInvert, 0, recurslevel*100, 100);
        recurslevel--;
        if (result==false) { ErrorString="Wrong parameter of function "+name+"()";  break; }   // "Íåâåðíûé ïàðàìåòð ôóíêöèè "
      }
      // Èùåì òàêóþ æå ôóíêöèþ ñ òàêèìè æå ïàðàìåòðàìè â îáùåì ìàññèâå ôóíêöèé
      int functotal=ArrayRange(AllFuncParam,0); 
      for (int f=0; f<functotal; f++)
       {
         for (int p=0; p<PARAMCOUNT; p++)
           if (AllFuncParam[f][p]!=param[p]) break;
         if (p==PARAMCOUNT) break;  // âñå ïàðàìåòðû ñîâïàäàþò, çíà÷èò ïðåêðàùàåì ïîèñê
       }
      if (f==functotal)
       { 
         ArrayResize(AllFuncParam, f+1);
         ArrayResize(FuncCacheMinSize, f+1);
         ArrayResize(FuncTimeSerie, f+1);
         for (p=0; p<PARAMCOUNT; p++) AllFuncParam[f][p]=param[p];  // íå íàéäåíî ôóíêöèé ñ ñîâïàäàþùèìè ïàðàìåòðàìè, çíà÷èò äîáàâëÿåì ôóíêöèþ â ìàññèâ
       }
      Array[member][CELLVALUE]= f;
      Array[member][CELLTYPE]= TYPE_FUNC;
    }
    
    maxlevel= MathMax(maxlevel, Array[member][CELLLEVEL]);
     
    if (char=='(' && !symbolfound) // ïåðåä ñêîáêîé íå áûëî ñèìâîëîâ, çíà÷èò ýòî íå ôóíêöèÿ
    { 
      startlevel+=3;
      lastlevel=-1;
      i++;
    }
    if (char==')')
    {
      startlevel-=3;
      for (int m=member-1; m>=0; m--) if (MathFloor(Array[m][CELLLEVEL]/3)*3==startlevel) break;
      lastlevel= Array[m][CELLLEVEL];
      i++;
    }
    
    if (symbolfound || digitfound || char==')' || member==0)
      member++;

    if (startlevel<0) ErrorString="')' - Unbalanced right bracket!";  //"Ëèøíÿÿ çàêðûâàþùàÿ ñêîáêà!";
    if (ErrorString!="") break;
    startpos=i;
    if (i<strlen) i--;
    symbolfound=false;
    digitfound=false;
    squarebracket=0;
    signchar=0; 
  }
  if (ErrorString!="") { if (recurslevel==0) Print(Formula," :  ",ErrorString);  return(0); } // Alert(Symbol()+" "+WindowExpertName()+":  ",ErrorString);
  member--;
  
  FormulaArrayOptimization(Array, member, maxlevel);

  string sourcestring= GetSourceAlgoString(Array, member, maxlevel);
  if (Debug)
    Alert(Formula, "\n\n", sourcestring);
  
  double array[][ARRAYRANGE1];
  ArrayCopy(array, Array, 0, CELLPARENTLEVEL);  // êîïèðóåì ìàññèâ, ñäâèãàÿ çíà÷åíèÿ ñóáèíäåêñà CELLPARENTLEVEL íà íóëåâîé ñóáèíäåêñ
  int posmemb[100];
  //string txt="";  
  for (m=0; m<=member; m++) { posmemb[m]= ArrayMaximum(array,member+1);  array[posmemb[m],0]=-2; }   //txt=txt+posmemb[m]+"  ";}
  int sign[3][2]={ '+', '-',  '*', '/',  '^', '?'};
  int InvertedLevels[100];  ArrayInitialize(InvertedLevels, 1<<30);
  //Alert(txt);
  for (int pos=0;  pos<=member;  pos++)
  {
    int memb= posmemb[pos];
    level= Array[memb][CELLLEVEL];
    int plevel= Array[memb][CELLPARENTLEVEL];
    int nextpos= -1;
    for (p=pos+1; p<=member; p++)
      if (posmemb[p]>memb && Array[posmemb[p]][CELLPARENTLEVEL]<=plevel)
        if (posmemb[p]<posmemb[nextpos] || nextpos<0) nextpos=p;
    int nextmemb= posmemb[nextpos];
    
    if (Array[nextmemb][CELLVALUE]==-1 && Array[nextmemb][CELLTYPE]==TYPE_VALUE && Array[nextmemb][CELLLEVEL]==plevel+1)
      if (plevel%3!=POW)// && Array[nextmemb-1][CELLPARENTLEVEL]==Array[nextmemb][CELLLEVEL])
      { // èíâåðòèðóåì ÿ÷åéêó (óìíîæåíèå ïîòîì áóäåò çàìåíåíî íà äåëåíèå, à ñëîæåíèå íà âû÷èòàíèå)
        for (p=0; p<nextpos; p++) if (Algo[p][CELLNEXTCELL]==nextpos) break;// if (Array[posmemb[[p]][CELLPARENTLEVEL]<=; for (p=0; p<nextpos; p++) if (posmemb[p]==nextmemb-1) break;
        if (Array[posmemb[p]][CELLPARENTLEVEL]==Array[nextmemb][CELLLEVEL])
        { 
          Array[posmemb[p]][CELLPARENTLEVEL]= Array[nextmemb][CELLPARENTLEVEL];
          InvertedLevels[posmemb[p]] |= 1<<plevel;
          posmemb[nextpos]=posmemb[p];
          ArrayCopy(posmemb, posmemb, p, p+1);  //InvertedLevels[p-1]= plevel;
          member--;  pos=-1;
          continue;
        }
      }
    Algo[pos][CELLNEXTCELL]= nextpos;
    Algo[pos][CELLVALUE]= Array[memb][CELLVALUE];
    Algo[pos][CELLTYPE]= Array[memb][CELLTYPE];
    bool nextmembinvert= (InvertedLevels[nextmemb] & (1<<plevel)) > 0;  // && Array[nextmemb][CELLLEVEL]==plevel+1; //level+1;
    Algo[pos][CELLOPERATION]= sign[plevel%3][nextmembinvert*1];
  }
        
  Algo[member][CELLNEXTCELL]= 0;
  int algolen= member+1;
  if (Debug)
    Alert(Formula, "\n\n", sourcestring, GetResultAlgoString(Algo, algolen));
  
  if (ErrorString!="") algolen=0;

  return(algolen);
} 

//-------------------------------------------------------------------

//int DblToInt(double value)  { return(value); }

//--------------------------------------------------------------------------

bool FormulaArrayOptimization(double& Array[][], int& member, int& maxlevel)
{
  double temparray[][ARRAYRANGE1];
  bool memb0positive;
  int membsize=0;
  int memb0size=0;
  int membcount=0;
  int lastvaluememb;
  
 for (int level=maxlevel; level>=0; level--)
 {
  int leveltype= level%3;
  int memb0=-1;
  for (int memb=0;  memb<=member;  memb++)
  {
    int lev= Array[memb][CELLLEVEL];
    int plev= Array[memb][CELLPARENTLEVEL];
    if (memb0==-1) { membsize=0; membcount=0; memb0=-2; }
    if (lev<level) { membsize=0; continue; }
    if (lev==level) membsize=1; else
    if (memb>0 && Array[memb-1][CELLPARENTLEVEL]==level) membsize=1; else
    if (lev>level) membsize++;
    //if (plev>=level) membsize++;
    if (lev>level && plev>level) continue;
    if (memb==member) plev=-1;
    membcount++;
    
    int    celltype= Array[memb][CELLTYPE]; //int    level= Array[memb][CELLLEVEL];
    double membvalue= Array[memb][CELLVALUE];
    
    if (memb0<0)
    {
      memb0=memb;
      memb0size=membsize;
      memb0positive=false;
      int funcindex=membvalue;
      if (leveltype==POW && lev==level) //memb0size==1)
        if ((celltype==TYPE_VALUE && membvalue>=0) || (celltype==TYPE_FUNC && FuncParam[funcindex][1]>=0))
          memb0positive=true;  // îñíîâàíèåì ñòåïåíè ÿâëÿåòñÿ åäèíè÷íûé ÷ëåí, ïðåäñòàâëÿþùèé ñîáîé ïîëîæèòåëüíîå ÷èñëî ëèáî èíäåêñ ñèìâîëà
      bool basepositive=memb0positive;
      lastvaluememb=-1;
    }
    //if (memb==1) Alert("memb: ",memb,"   value: ",membvalue,"   type: ",celltype,"   level: ",level,"   plev: ",plev,"   invert: ",Array[1][CELLINVERT],"   memb0: ",memb0,"    count: ",membcount);
    /*
    if (membsize>1 && Array[memb-membsize][CELLLEVEL]==level && memb!=memb0) // åñëè òåêóùèé ÷ëåí ÿâëÿåòñÿ ñîñòàâíûì (äëèíà áîëüøå 1), à ïðîøëûé ÷ëåí áûë åäèíè÷íûì, òî ìåíÿåì èõ ìåñòàìè
      if (membcount>2 || leveltype!=POW) 
      {
        ArrayCopy0(temparray, Array, 0, memb-membsize, 1);   // ñîõðàíÿåì ïðåäûäóùèé ÷ëåí
        ArrayCopy0(Array, Array, memb-membsize, memb-membsize+1, membsize);   // êîïèðóåì òåêóùèé ÷ëåí íà ìåñòî ïðåäûäóùåãî
        ArrayCopy0(Array, temparray, memb, 0, 1);   // ïîìåùàåì ïðåäûäóùèé ÷ëåí âñëåä çà òåêóùèì
        //Alert("!! ",level,"  ",memb,"  ",membsize,"  ",membcount,"  ",Array[memb0][CELLPARENTLEVEL]);
        level=maxlevel+1; level=-1; break;
      }
    */
    if (lev>level) continue;
    
    if (celltype==TYPE_VALUE)
    {
      double resultvalue= Array[lastvaluememb][CELLVALUE];
      if (lastvaluememb<0) { resultvalue=membvalue; lastvaluememb=memb; }//if (leveltype==SUMMAND) resultvalue=0; else resultvalue=1;
      else
      switch (leveltype)
      {
        case SUMMAND:    resultvalue+=membvalue; break;
        case MULTIPLIER: resultvalue*=membvalue; break; // || memb>memb0
        case POW:
          if (lastvaluememb==memb0)
            if (basepositive || MathMod(membvalue,2)==1 || memb==memb0+1)
            { 
              if (resultvalue==0 && membvalue<0) { ErrorString="Zero divide!"; continue; }
              if (resultvalue<0 && MathMod(membvalue,1)>0) { ErrorString="Exponentiation error!"; continue; }
              resultvalue= MathPow(resultvalue, membvalue);
              if (MathMod(membvalue,2)==0) { basepositive=true; memb0positive=true; }
            }
            else lastvaluememb=-1;
          else
          {
            if ((MathMod(resultvalue,2)==0 && MathMod(membvalue,1)==0)
             || (MathMod(resultvalue,1)>0 && MathMod(membvalue,1)>0) || (MathMod(resultvalue,2)==1 && lastvaluememb==memb-1)
             || MathMod(membvalue,2)==1 || basepositive)
               resultvalue*=membvalue; 
             else lastvaluememb=-1;
            if (MathMod(resultvalue,2)==0) basepositive=true;
          }
          if (lastvaluememb<0) { lastvaluememb=memb; resultvalue=membvalue; }
      }
      Array[lastvaluememb][CELLVALUE]=resultvalue;
        
      bool delete= (lastvaluememb!=memb);
      if (delete) if (leveltype==SUMMAND) Array[memb][CELLVALUE]=0; else Array[memb][CELLVALUE]=1;
        
      membvalue=Array[memb][CELLVALUE];
      if (membvalue==0 && leveltype==SUMMAND) delete=true;
      if (membvalue==1 && leveltype!=SUMMAND) if (leveltype==MULTIPLIER || memb>memb0) delete=true;
      //if (memb==member) Alert("memb: ",memb,"   value: ",membvalue,"   level: ",level,"   plev: ",plev,"    count: ",membcount);
      if (delete)
        if (memb>memb0 || (level==0 && member>1))// && Array[memb-1][CELLLEVEL]==level) || plev==level || (plev<level && memb==memb0) || membcount==2)
        {  
          if (plev<level && memb>memb0) { Array[memb-1][CELLPARENTLEVEL]=plev; } // åñëè ýòî êîíå÷íàÿ ÿ÷åéêà, òî ìåíÿåì ðîäèòåëüñêèé óðîâåíü ó ïðåäûäóùåé ÿ÷åéêè
          ArrayCopy0(Array, Array, memb-membsize+1, memb+1);  // óäàëÿåì äàííóþ ÷èñëîâóþ ÿ÷åéêó èç ìàññèâà
          member--;  membcount--;  membsize=0;  memb--;//memb0=-1;//continue;
          if (plev<level || memb<memb0) { memb=memb0-memb0size; memb0=-1; }
          continue;  
        }
    }
    if (plev>=level) continue;
    /*
    if (leveltype==POW)
      if (Array[memb0][CELLLEVEL]==level && Array[memb0][CELLTYPE]==TYPE_FUNC && Array[memb0][CELLVALUE]==1)
        { memb=memb0-memb0size-1; ArrayCopy0(Array, Array, memb, memb+1);       
    */
    //if (plev<level)
    if (membcount>2 && memb0positive && leveltype==POW)// && Array[memb][CELLLEVEL]==level)  // åñëè îñíîâàíèå ñòåïåíè ïîëîæèòåëüíîå, òî ïðåîáðàçóåì ïîêàçàòåëè â ìíîæèòåëè (ïîìåùàÿ èõ â ñêîáêè)
    {  
      int startmemb=memb;
      if (membvalue==-1 && celltype==TYPE_VALUE && lev==level) if (membcount>3) startmemb--; else startmemb=0;
      for (int i=startmemb; i>=memb0+1; i--)
      {
        if (Array[i][CELLLEVEL]==level)  Array[i][CELLLEVEL]+=2;  else Array[i][CELLLEVEL]+=3;
        if (Array[i][CELLPARENTLEVEL]>=level && i<startmemb)
          if (Array[i][CELLPARENTLEVEL]==level)  Array[i][CELLPARENTLEVEL]+=2; else Array[i][CELLPARENTLEVEL]+=3;
        maxlevel= MathMax(Array[i][CELLLEVEL], maxlevel);
      }
      if (i<startmemb) { memb=memb0-memb0size; memb0=-1;  continue; }
    }
    if (true)
    if (membcount==1 && membsize==1 && plev>=0) // åñëè èìååòñÿ âñåãî îäèí ÷ëåí íà ýòîì óðîâíå, òî ïåðåìåùàåì åãî íà ðîäèòåëüñêèé óðîâåíü
    {
      Array[memb][CELLLEVEL]= plev;
      Array[memb][CELLPARENTLEVEL]= plev;
    }
    memb0=-1;
  }
 }
 return(true);
}
  
//--------------------------------------------------------------------
 
string GetSourceAlgoString(double Array[][], int member, int maxlevel)
{
  string txt="";
  for (int y=0; y<=maxlevel; y++)
  {
    txt= txt+y+"\t";
    for (int x=0; x<=member; x++)
      if (Array[x,CELLLEVEL]==y)
      {
        string valuestr=StringConcatenate(Array[x,CELLVALUE],"");
        if (Array[x,CELLTYPE]==TYPE_FUNC) valuestr="f"+valuestr;
        //if (Array[x,CELLINVERTLEVEL]==true) if (y%3==SUMMAND) valuestr="-"+valuestr; else valuestr="/"+valuestr;
        txt=StringConcatenate(txt, StrFmt(valuestr,3.5)," ", StrFmt(StringConcatenate(Array[x,CELLPARENTLEVEL],""),3.5), "\t"); //,"   ",Array[x,y,CELLMAINCELL],"\t");
      }  
      else txt=txt+"----  "+"----  "+"\t";
    txt=txt+"\n";
  }
  txt=txt+"\n";
  return(txt);
}

//-------------------------------------
string StrFmt(string str, double len)
{
  string spaces="                                ";
  str= str+ StringSubstr( spaces, StringLen(spaces)-MathRound((len-StringLen(str))*2), 0);
  return(str);
} 

//----------------------------------------- ------------
 
string GetResultAlgoString(double Algo[][], int algolen)
{  
  string CellParamNames[4];
  CellParamNames[CELLVALUE]="Value";
  CellParamNames[CELLTYPE]="Type";
  CellParamNames[CELLOPERATION]="Action";
  CellParamNames[CELLNEXTCELL]="ToCell";
  bool symbolsrow=false;
  string txt="";
  
  for (int y=-1; y<ArraySize(CellParamNames); y++)
  {
    if (y==-1) txt= txt+ "Cell\t";
         else if (symbolsrow) txt= txt+ "\t";
         else txt= txt+ CellParamNames[y]+ "\t";
    for (int x=0; x<algolen; x++)
    {
      if (y==-1) { txt= txt+ x+ "\t";  continue; }
      string valstr= StringConcatenate(Algo[x][y], "");
      if (symbolsrow) valstr="";
      if (Algo[x][CELLTYPE]==TYPE_FUNC)
      {
        int valueindex= Algo[x][CELLVALUE];
        int symindex= FuncParam[valueindex][1];
        if (y==CELLTYPE)  valstr= StringConcatenate("Func ", FuncParam[valueindex][0]);
        else if (y==CELLVALUE) valstr= "f" +valueindex;
        if (symbolsrow) if (symindex>=0) valstr= "."+Symbols[symindex];  else valstr= "(F"+ (-symindex-1)+ ")";
      }
      else if (y==CELLTYPE) valstr="Value";
      
      if (y==CELLOPERATION) valstr= CharToStr(Algo[x][y]);
      txt= StringConcatenate(txt, valstr, "\t");
    }    
    txt= txt+ "\n";
    if (symbolsrow)  { symbolsrow=false;  continue; }
    if (y==CELLVALUE) { symbolsrow=true;  y--; }
  }
  return(txt);  
}

//------------------------------------------------------------

string StringUpperCase(string text)
{
  for (int i=0; i<StringLen(text); i++)
  {  
    int char=StringGetChar(text,i);
    if (char>='a' && char<='z') { text= StringSetChar(text, i, char+'A'-'a'); }
  }
  return(text);
}

//-----------------------------------------------------------------------------------

int ArrayCopy0(double& array1[], double& array2[], int start1=0, int start2=0, int count=0)
{
  int range=1;
  for (int i=ArrayDimension(array1)-1; i>0; i--)  range*=ArrayRange(array1,i);
  return( ArrayCopy(array1, array2, start1*range, start2*range, count*range) / range); 
}
//--------------------------------------------------------------------------------------
int ArrayCopy0Int(int& array1[], int& array2[], int start1=0, int start2=0, int count=0)
{
  int range=1;
  for (int i=ArrayDimension(array1)-1; i>0; i--)  range*=ArrayRange(array1,i);
  return( ArrayCopy(array1, array2, start1*range, start2*range, count*range) / range); 
}
 
//--------------------------------------------------------------------------------------

string GetQuoteSymbol(string symbol)
{             
  //if (StringFind(AccountCompany(),"BroCo")>=0)
  {
    int marginmode=MarketInfo(symbol,MODE_MARGINCALCMODE);
    if (marginmode==1 || marginmode==2)  // CFD ëèáî ôüþ÷åðñ
      if (StringFind(symbol,"_CONT")<0 && StringFind(symbol,"#I")!=StringLen(symbol)-2)
      {
        string quotesymbol=symbol+"#I";
        MarketInfo(quotesymbol,MODE_TIME);
        if (GetLastError()!=4106) symbol=quotesymbol;
      }
  }
  return(symbol);
}

//----------------------------------------------  
 
string GetPeriodName(int period)
{
  int periods[]= { PERIOD_M1, PERIOD_M5, PERIOD_M15, PERIOD_M30, PERIOD_H1, PERIOD_H4, PERIOD_D1, PERIOD_W1, PERIOD_MN1 };
  string names[]= { "M1", "M5", "M15", "M30", "H1", "H4", "D1", "W1", "MN" };
  int findindex= ArrayBsearch(periods,period);
  if (periods[findindex]==period) return(names[findindex]);
  return("M"+period);
}
 
//--------------------------------------------------------------------------
 
void DrawLine(int window, string object, double price, string text, int clr)
{
  if (window<0) return;
  int foundwindow=ObjectFind(object);
  if (foundwindow==-1)
  {
    if (!ObjectCreate(object,OBJ_HLINE,window,TimeCurrent(),price))
      if (GetLastError()==4051) { WrongWindow=true; return; } 
    ObjectSet(object,OBJPROP_STYLE,STYLE_DOT);
    ObjectSet(object,OBJPROP_COLOR,clr); 
    ObjectSetText(object,text);
    return;
  }
  else if (foundwindow!=window) return;
  
  ObjectMove(object,0,TimeCurrent(),price);
}
 
//--------------------------------------

bool DrawLabel(string name, int x, int y, int corner, string text, int fontsize, string font, int clr)
{
  int wnd=ObjectFind(name);
  if (wnd!=Window || ObjectType(name)!=OBJ_LABEL)
    { ObjectDelete(name); wnd=-1; }
  if (wnd<0) if (!ObjectCreate(name,OBJ_LABEL,Window,0,0)) return(0);
  ObjectSet(name,OBJPROP_XDISTANCE,x);
  ObjectSet(name,OBJPROP_YDISTANCE,y);
  ObjectSetText(name,text,fontsize,font,clr);
  ObjectSet(name,OBJPROP_CORNER,corner);
  return(true);
} 
   
//----------------------------------------------------------------------
 
void DrawStatusLabel(string text, int clr=White)
{
  int corner=0;
  int y=56;
  if (LabelsOnTheRight) { corner=1; y=40; }
  if (!DrawLabel(StatusLabel, 5, y, corner, text, 7, "Arial", clr)) 
    if (GetLastError()==4051) { WrongWindow=true; Print("Wrong window"); }
} 

//---------------------------------------------------------
bool BoolChartLabels[8];


void DrawChartLabel(int n, string text)
{
  if (Window<0) return(0);
  int corner=0;
  int x1=5;
  int y=16;
  if (LabelsOnTheRight) { corner=1; y=2; }
  for (int i=0; i<n; i++) if (BoolChartLabels[i]==true) y+=14;
  if (n==8)
    { DrawLabel(SignalLabel, x1, y, corner, text, 8, "Courier", Red);  return; }
    
  BoolChartLabels[n]=true;
  int len=StringLen(text);
  if (len>63)
  {
    int x2= x1+63*8;
    if (LabelsOnTheRight) { x2=x1;  x1+= (len-63)*8; }
    DrawLabel(ChartLabels_[n], x2, y, corner, StringSubstr(text,63), 8, "Courier", Colors[n]);
  }
  if (!DrawLabel(ChartLabels[n], x1, y, corner, text, 8, "Courier", Colors[n]))
    if (GetLastError()==4051) { WrongWindow=true; Print("Wrong window"); }
}

//---------------------------------------------------------------

void DrawErrorChartLabel(int n, string text)
{  
  if (Window<0) return;
  string object=ChartErrorLabels[n];
  if (text=="") { ObjectDelete(object); return; }
  int corner=0;
  int x= 5 + (StringLen(Formulas[n])+2) * 8;
  int y= 16;
  if (LabelsOnTheRight) { corner=1; y=2; }
  for (int i=0; i<n; i++) if (BoolChartLabels[i]==true) y+=14;
  BoolChartLabels[n]=true;
  if (!DrawLabel(object, x, y, corner, text, 8, "Arial", Red))
    if (GetLastError()==4051) { WrongWindow=true; Print("Wrong window"); }
}

//---------------------------------------------

bool FindWordInString(string text, string word)
{
  int textlen=StringLen(text);
  int wordlen=StringLen(word);
  for (int pos=0; ; pos++)
  {
    pos=StringFind(text,word,pos);
    if (pos<0) break;
    int prevchar=StringGetChar(text,pos-1);
    int postchar=StringGetChar(text,pos+wordlen);
    if (pos>0) if (prevchar!=' ' && prevchar!=',') continue;
    if (pos<textlen-wordlen) if (postchar!=' ' && postchar!=',') continue;
    return(true);
  }
  return(0);
}

//---------------------------------------------------------------------------

bool CheckSignalLevels(int chart, double bid, double ask)
{  
  static int AlertTime[MAXCHARTS][4];
  string SignalLines[4]={"",""};
  double SignalValue[4];
  int    SignalType[4]= {-1,-1,-1,-1};
  if (Signal_HighValue!="") { SignalValue[0]= StrToDouble(Signal_HighValue);  SignalType[0]=MODE_HIGH; }
  if (Signal_LowValue!="") { SignalValue[1]= StrToDouble(Signal_LowValue);  SignalType[1]=MODE_LOW; }
  if (Signal_HighLine!="") { SignalLines[2]= Signal_HighLine;  SignalType[2]=MODE_HIGH; }
  if (Signal_LowLine!="")  { SignalLines[3]= Signal_LowLine;   SignalType[3]=MODE_LOW; }
  int digits=IndDigits;
  bid= NormalizeDouble(bid,digits);
  ask= NormalizeDouble(ask,digits);
  bool signal=false;
  for (int i=0; i<4; i++)
  {
    if (SignalType[i]<0) continue;
    if (TimeLocal()-AlertTime[chart][i] < 5) continue;
    double signalvalue= NormalizeDouble(SignalValue[i],digits);
    string object=SignalLines[i];
    if (object!="")
    {
      if (ObjectFind(object)!=Window) continue;
      string modetext="High";  if (SignalType[i]==MODE_LOW) modetext="Low";
      ObjectSetText(object, "Signal Line "+modetext);
      if (ObjectType(object)==OBJ_HLINE)
        signalvalue= ObjectGet(object,OBJPROP_PRICE1);
      else signalvalue= ObjectGetValueByShift(object,0);
      if (GetLastError()==4205) continue;  // îøèáêà êîîðäèíàò îáúåêòà
    }
    string txt="";
    string BidStr="Bid ",  AskStr="Ask ";
    if (!ShowBidAsk) { BidStr="";  AskStr=""; }
    if (SignalType[i]==MODE_HIGH)
      if (bid!=EMPTY_VALUE && bid>=signalvalue)
        txt= StringConcatenate(Formulas[chart],":  ",BidStr,DoubleToStr(bid,digits)," >= ",DoubleToStr(signalvalue,digits));
    if (SignalType[i]==MODE_LOW)
      if (ask!=EMPTY_VALUE && ask<=signalvalue)
        txt= StringConcatenate(Formulas[chart],":  ",AskStr,DoubleToStr(ask,digits)," <= ",DoubleToStr(signalvalue,digits));
    if (txt=="") continue;
    if (object!="") txt= txt+" ("+object+")";
    static int lastinittime=0;
    if (InitTime!=lastinittime) { ArrayInitialize(AlertTime,0);  lastinittime=InitTime; }
    if (AlertTime[chart][i]==0) Alert(txt); else Print(txt);
    AlertTime[chart][i]= TimeLocal();
    signal=true;
  }
  if (signal) PlaySound("alert2.wav");
  return(signal);
}

//----------------------------------------------------------------------------------

int GetFormulaSymbols(int n, string& symbols[])
{
  for(int s=0; s<ArrayRange(SymbolsIndexes,1); s++)
  {
    int symindex= SymbolsIndexes[n][s][0];
    if (symindex<0) break;
    symbols[s]= Symbols[symindex];
  }
  return(s);
}
//-------------------------------------------------

int GetFormulaSymIndexes(int n, int& indexes[])
{
  for(int s=0; s<ArrayRange(SymbolsIndexes,1); s++)
  {
    int symindex= SymbolsIndexes[n][s][0];
    if (symindex<0) break;
    indexes[s]= symindex;
  }
  return(s);
}
//------------------------------------------------

int GetAllFormulasSymbols(string& symbols[])
{
  ArrayCopy(symbols, Symbols);
  return( ArraySize(Symbols) );
}
//--------------------------------------------------------------

int GetFormulaSymFuncNames(int n, int s, string& funcnames[])
{
  if (SymbolsIndexes[n][s][0]<0) return(0);
  int pp= SymbolsIndexes[n][s][1]; // îáùåå êîëè÷åñòâî ïîÿâëåíèé äåííîãî ñèìâîëà â ôîðìóëå
  ArrayResize(funcnames, MathMax(ArrayRange(funcnames,0),pp));
  for (int p=0; p<pp; p++)
  {
    int pos= SymbolsFuncPos[n][s][p];
    int funcindex= Algorithms[n][pos][CELLVALUE];
    int functype= FuncParam[funcindex][0];  //if (functype!=FUNC_CLOSE && functype!=FUNC_OPEN && functype!=FUNC_HIGH && functype!=FUNC_LOW) continue;
    funcnames[p]= DefaultFuncName[functype];
  }
  return(pp);
}
//-----------------------------------------------------------------------------------------------------
  
int GetFormulaSymPowRatio(int n, int s, double& totalpowratio[][2])  
{  
  if (!GetAlgoAllPowAndRatio(n, AlgorithmsTotalPowRatio)) return(0);
  if (SymbolsIndexes[n][s][0]<0) return(0);
  int pp= SymbolsIndexes[n][s][1]; // îáùåå êîëè÷åñòâî ïîÿâëåíèé äåííîãî ñèìâîëà â ôîðìóëå
  ArrayResize(totalpowratio, MathMax(ArrayRange(totalpowratio,0),pp));
  ArrayInitialize(totalpowratio,0);
  for (int p=0; p<pp; p++)
  {
    int pos= SymbolsFuncPos[n][s][p];
    totalpowratio[p][0]= AlgorithmsTotalPowRatio[n][pos][0];
    totalpowratio[p][1]= AlgorithmsTotalPowRatio[n][pos][1];
  }
  return(pp); 
}

//------------------------------------------------------------

int FindIndicatorWindow()
{  
  static int LastSubChartIndex=0;
  static int LastWindow=0;
  
  int SubChartIndex=1;
  int window= WindowFind(IndicatorName);
  if (window>0)
   {  
     ObjectCreate(DropWindowIdObject,OBJ_VLINE,window,0,0); // ñîçäà¸ì èäåíòèôèöèðóþùèé îáúåêò
     ObjectSet(DropWindowIdObject,OBJPROP_COLOR,CLR_NONE);
     ObjectSetText(DropWindowIdObject,window+"-"+MainChartIndex+"-0");
     SubChartIndex=0;
   }
   else
   {
     if (ObjectFind(DropWindowIdObject)<0) return(-1);
     string txt= ObjectDescription(DropWindowIdObject);
     window= StrToInteger(txt);
     int findpos= StringFind(txt, "-");
     MainChartIndex= StrToInteger(StringSubstr(txt, findpos+1));
     findpos= StringFind(txt, "-", findpos+2);
     if (findpos>=0)
       SubChartIndex= StrToInteger(StringSubstr(txt, findpos+1))+1;
     ObjectSetText(DropWindowIdObject, window+"-"+MainChartIndex+"-"+SubChartIndex);
   }
  
  if (SubChartIndex!=LastSubChartIndex || window!=LastWindow) 
   {
     DeleteObjects();
     InitObjects(MainChartIndex, SubChartIndex);
     IndicatorName= "ChartBuilder ("+MainChartIndex;
     if (SubChartIndex>0) IndicatorName= IndicatorName+"-"+SubChartIndex;
     IndicatorName= IndicatorName+")";
     IndicatorShortName(IndicatorName); 
     LastSubChartIndex= SubChartIndex;
     LastWindow=window;
   }
  return(window);  
}     

//-----------------------------------------------------------------------------------

void DeleteObjects()
{
  if (StringLen(StatusLabel)>0) ObjectDelete(StatusLabel);
  if (StringLen(SignalLabel)>0) ObjectDelete(SignalLabel);
  for (int i=0; i<8; i++)
  {
    if (StringLen(LineAsk[i])>0) ObjectDelete(LineAsk[i]);
    if (StringLen(LineBid[i])>0) ObjectDelete(LineBid[i]);
    if (StringLen(ChartLabels[i])>0) ObjectDelete(ChartLabels[i]);
    if (StringLen(ChartLabels_[i])>0) ObjectDelete(ChartLabels_[i]);
    if (StringLen(ChartErrorLabels[i])>0) ObjectDelete(ChartErrorLabels[i]);
  }
}

//-----------------------------------------------------------------------------------------------------------------

double MyFunc_ATR(double arrayprice[], int arraytime[], int currentpos, int maxcount, int period, int periodscount, int shift)
{
  if (period==0 || periodscount==0) return(EMPTY_VALUE);
  double sumvalue=0;
  int periods=0;
  int startperiodtime=0;
  int lastpos;
  for (int i=0; i<maxcount; i++)
  {
    int pos= currentpos-i;
    int time= arraytime[pos];
    if (startperiodtime==0)
    {
      startperiodtime= time/(period*60)*period*60;
      lastpos=pos;
    }
    if (time>=startperiodtime) continue;
    startperiodtime=0;
    periods++;
    if (periods < shift+1) { i--; continue; }
    if (shift>0) { shift=0; periods=1; }
    double maxvalue= arrayprice[ ArrayMaximum(arrayprice,lastpos-pos+1,pos) ];
    double minvalue= arrayprice[ ArrayMinimum(arrayprice,lastpos-pos+1,pos) ];
    sumvalue += maxvalue-minvalue;
    i--;
    if (periods==periodscount) break; 
  }
  if (periods < periodscount + shift) return(EMPTY_VALUE);
  return( sumvalue/periods ); 
}

//---------------------------------------------------------------

bool SaveToFile(string filename, int chartnumber, int savingbars)
{
  int delimiter= StringGetChar(SaveToFile_Delimiter, 0);
  if (delimiter==0) delimiter='\t';
  int h= FileOpen(filename, FILE_WRITE|FILE_CSV, delimiter);
  if (h<0) { Print("Error opening file ",filename); return(0); }
  int buf= (chartnumber-1)*BuffersPerChart;
  if (!OnlyClosePrice) buf++;
  for (int i=0; i<Bars; i++)
  {
    double value= GetBuffer(buf,i);
    if (value!=EMPTY_VALUE) FileWrite(h, TimeToStr(Time[i]+Period()*60-1), value);
  }
  FileClose(h);
  return(true);
}

//---------------------------------------------------------

int ReadSymbolHistory(string symbol, int tf, double& rates[][6], int ratespos)
{  
  string file= symbol+tf+".hst";
  int handle=FileOpenHistory(file, FILE_BIN|FILE_READ);
  if (handle<0)  { Print("Íå óäàëîñü íàéòè ôàéë ",file); return(-1); }
  if (FileSeek(handle,148,SEEK_SET)==false)
    { Print("Íå óäàëîñü íàéòè ñòàðòîâóþ ïîçèöèþ èñòîðèè â ôàéëå ",file); return(0); }
  int historysize= (FileSize(handle)-148)/44;
  //Alert(symbol," history size: ",historysize);
  int minarraysize= ratespos+historysize;
  ArrayResize (rates, MathMax(ArrayRange(rates,0),minarraysize));
  int i=ratespos;
  int n=0;
  while(true)
  { 
    datetime readtime= FileReadInteger(handle, LONG_VALUE);
    if (FileIsEnding(handle)) { Print("Ôàéë ",file," çàêîí÷åí äëÿ ÷òåíèÿ"); break; }
    rates[i][0]=readtime;
    FileReadArray(handle, rates, i*6+1, 5); // ñ÷èòûâàåì çíà÷åíèÿ öåí è îáú¸ìà
    i++;
  }
  FileClose(handle);
  return (i-ratespos);
}


//---------------------------------------------------------------
void SetParameters(int& arr[][], int i, int p0, int p1=0, int p2=0, int p3=0, int p4=0, int p5=0, int p6=0, int p7=0, int p8=0)
  { arr[i][0]=p0; arr[i][1]=p1; arr[i][2]=p2; arr[i][3]=p3; arr[i][4]=p4; arr[i][5]=p5; arr[i][6]=p6; arr[i][7]=p7; arr[i][8]=p8; }
  

void SetFuncParameters(string name, int funcindex, int p1=0, int p2=0, int p3=0, int p4=0, int p5=0, int p6=0, int p7=0, int p8=0) 
{
  static int i;
  TemplateFuncName[i]= name;
  SetParameters(TemplateFuncParam, i, funcindex, p1, p2, p3, p4, p5, p6, p7, p8);
  if (StringLen(DefaultFuncName[funcindex])==0) DefaultFuncName[funcindex]=name;
  i++;
}//---------------------------------------


void SetBuffer(int index, int bar, double value)
{
  switch(index)
  {
    case 0: buffer0[bar]=value; break;
    case 1: buffer1[bar]=value; break;
    case 2: buffer2[bar]=value; break;
    case 3: buffer3[bar]=value; break;
    case 4: buffer4[bar]=value; break;
    case 5: buffer5[bar]=value; break;
    case 6: buffer6[bar]=value; break;
    case 7: buffer7[bar]=value; break;
  }
}
//-------------------------------------
double GetBuffer(int index, int bar)
{
  switch(index)
  {
    case 0: return(buffer0[bar]);
    case 1: return(buffer1[bar]);
    case 2: return(buffer2[bar]);
    case 3: return(buffer3[bar]);
    case 4: return(buffer4[bar]);
    case 5: return(buffer5[bar]);
    case 6: return(buffer6[bar]);
    case 7: return(buffer7[bar]);
  }
}


Comments