ChartBuilder

Author: NavAlex
Price Data Components
Series array that contains close prices for each barSeries array that contains open prices of each barSeries array that contains the highest prices of each barSeries array that contains the lowest prices of each barSeries array that contains tick volumes of each bar
Indicators Used
Indicator of the average true rangeBollinger bands indicatorMoving average indicatorStandard Deviation indicatorAccumulation/Distribution indicatorMovement directional indexCommodity channel indexDeMarker indicatorEnvelopes indicatorMACD HistogramMomentum indicatorRelative strength indexStochastic oscillatorMoving average indicatorStandard Deviation indicatorCommodity channel indexEnvelopes indicatorMomentum indicatorRelative strength index
Miscellaneous
Implements a curve of type %1It issuies visual alerts to the screenIt reads information from a fileIt plays sound alertsUses files from the file systemIt writes information to fileIt reads information from a fileIt reads information from a file
1 Views
3 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

Markdown supported. Formatting help

Markdown Formatting Guide

Element Markdown Syntax
Heading # H1
## H2
### H3
Bold **bold text**
Italic *italicized text*
Link [title](https://www.example.com)
Image ![alt text](image.jpg)
Code `code`
Code Block ```
code block
```
Quote > blockquote
Unordered List - Item 1
- Item 2
Ordered List 1. First item
2. Second item
Horizontal Rule ---