English 中文 Español Deutsch 日本語 Português 한국어 Français Italiano Türkçe
Последний крестовый поход

Последний крестовый поход

MetaTrader 5Примеры | 13 марта 2012, 11:15
6 104 12
Roman Zamozhnyy
Roman Zamozhnyy

Введение

В терминале МetaТrader 5, (впрочем, как и в МetaТrader 4) по умолчанию доступны три способа отображения котировки инструмента: бары, японские свечи, линия. Все они, по сути, являются примерно одним и тем же: временными графиками. Наряду с традиционным способом временного отображения котировок до сих пор живы и пользуются известным успехом инвесторов и спекулянтов способы отображения котировок, не зависящие от времени: графики ренко, каги, трехлинейного прорыва и крестики-нолики.

Не берусь утверждать их преимущество перед классикой, но некоторым торговцам изъятие из поля зрения одной переменной - времени, помогает сосредоточиться на второй переменной - цене. Предлагаю рассмотреть в статье графики крестики-нолики, алгоритм их построения, известные рыночные продукты, предлагающие эти графики и написать самим простенький скрипт, реализующий алгоритм. Нашим букварем будет книга Томаса Дж. Дорси "Метод графического анализа крестики-нолики" (оригинал "Point and Figure Charting: The Essential Application for Forecasting and Tracking Market Prices").

Самым известным продуктом для построения оффлайн-графиков является программа Bull's-Eye Broker. Релиз программы предоставляется на ознакомление сроком на 21 день (знакомится можно много раз), новая бета-версия - до вывода ее в релиз. По релизу мы будем сверять результаты работы нашего скрипта. Одним из лучших онлайн-ресурсов, предоставляющем возможность построения крестиков-ноликов, является StockCharts. Сайт ориентирован на биржевую торговлю, поэтому найти на нем котировки по инструментам форекс, к сожалению, невозможно.

Для контроля результатов работы написанного нами скрипта построим аналогичные графики в программе и на сайте по инструментам: фьючерс на золото, фьючерс на нефть сорта Light crude oil, контракт на разницу S&P 500; только в Bull's-Eye Broker построим график EURUSD (помним об ограничениях StockChart).


Алгоритм построения графиков "крестики-нолики"

Итак, алгоритм.

Ключевыми понятиями при построении графиков крестики-нолики являются лишь два понятия:

  1. Размер бокса - минимальное изменение котировки инструмента, менее которого не происходит никаких изменений на графике;
  2. Разворот - количество боксов, проходимых котировкой в направлении, противоположном текущему направлению графика, после которого это движение будет отображено в новой колонке.

Поскольку для построения графика мы вынуждены использовать историю котировок, хранимой в виде цен Open-High-Low-Close, то принимаются следующие допущения:

  1. График строится по ценам High-Low;
  2. Цена High округляется до размера бокса вниз (MathFloor), цена Low округляется до размера бокса вверх (MathCeil).

Поясню на примере. Допустим, мы хотим строить график Light crude oil, размер бокса принимаем равным 1 (один) $ и разворот устанавливаем в 3 (три) бокса. Это значит, что все цены High мы округляем вниз с точностью 1$, а все цены Low - вверх с той же точностью:

Дата High Low XO High XO Low
2012.02.13 100.86 99.08 100 100
2012.02.14 101.83 100.28 101 101
2012.02.15 102.53 100.62 102 101
2012.02.16 102.68 100.84 102 101
2012.02.17 103.95 102.24 103 102


Движение цены вверх на графике отображается символом "Х" (крестик), движение вниз отображается символом "О" (нолик).

Как принимается решение о первоначальном направлении движения цены (первая колонка - это колонка Х или О):

Запоминаем значения XO High и XO Low бара Bars-1 и ждем, когда:

  • цена XO Low станет на Разворотное число боксов меньше первоначальной XO High (первая колонка - колонка "О") или
  • цена XO High станет на Разворотное число боксов больше первоначальной XO Low (первая колонка - колонка "Х").

В нашем примере с нефтью мы запомним цену XO High[Bars-1]=100 и XO Low[Bars-1]=100.

Далее ждем, что случится раньше:

  • цена XO Low[i] очередного бара станет равна или меньше 97$ и у нас первая колонка будет колонкой "О", или
  • цена XO High[i] очередного бара станет равна или больше 103$ и у нас первая колонка будет колонкой "Х".

17-го февраля мы получаем представление о первой колонке: цена XO High стала равна 103$ и наша первая колонка - это колонка "Х". Строим ее в виде четырех Х начиная с 100$ и завершая на 103$.

Как принимается решение о дальнейшем построении:

Если текущая колонка - колонка "Х", то проверяем: цена XO High текущего бара больше на Размер бокса текущей цены XO (т.е. 20-го февраля мы сначала будем проверять, цена XO High не стала равна или больше 104$). Если цена XO High[2012.02.20] будет 104$, или 105$, или еще больше, то мы в существующей колонке "Х" просто достраиваем сверху нужное количество "Х".

Если цена XO High текущего бара не больше на Размер бокса текущей цены XO, тогда проверяем, а цена XO Low текущего бара не меньше цены XO High на разворотное число боксов (в примере - цена XO Low[2012.02.20] равна или меньше 103$-3*1$=100$, или 99$, или еще ниже). Если меньше, то справа рядом, начиная со 102$ и продолжая до 100$, строим колонку "О".

При текущей колонке - колонке "О" все вышеприведенные соображения инвертируются.

ВАЖНО: новая колонка "О" всегда начинает строиться справа и на один бокс ниже верхнего значения предыдущей колонки "Х" и новая колонка "Х" всегда начинает строится справа и на один бокс выше нижнего значения предыдущей колонки "О".

С самим графиком разобрались. Теперь о линиях поддержки-сопротивления.

На ортодоксальных графиках крестиков-ноликов линии поддержки-сопротивления всегда идут под углом 45 градусов.

Построение первоначальной линии начинается в зависимости от значения первой колонки. Если первая колонка - колонка "Х", то первая линия будет линией сопротивления, и начнется она на один бокс выше максимума первой колонки, идти она будет под углом 45 градусов ВНИЗ и вправо. Если первая колонка - колонка "О", то первая линия будет линией поддержки и начнется она на один бокс ниже минимума первой колонки, идти она будет под углом 45 градусов ВВЕРХ и вправо. Линия поддержки-сопротивления строится до ее пересечения с графиком цены.

Как только линия поддержки/сопротивления пересекается с графиком цены, начинаем строить соответственно линию сопротивления/поддержки. Главным требованием при построении является то, чтобы построенная линия выходила на графике правее предыдущей трендовой линии. Таким образом, для построения линии поддержки мы выбираем сначала минимальное значение графика под только что завершенной линией сопротивления, строим линию поддержки от одного бокса ниже этого минимума ВВЕРХ вправо до пересечения с графиком, либо с последней колонкой графика.

Если линия от минимума под предыдущей линией сопротивления ушла и воткнулась в график по этой же линией сопротивления то сдвигаемся вправо, ищем новый минимум цены уже в диапазоне от минимального минимума под сопротивлением и окончанием линии сопротивления. Продолжаем, пока трендовая линия при построении не выйдет вправо за предыдущую трендовую линию.

Все вышесказанное проще всего будет представлено в дальнейшем на примере реальных графиков.

С алгоритмом построения самого графика к этому моменту мы с вами разобрались. Теперь прикрутим к нашему скрипту несколько приятных функций:

  • Возможность выбрать режим: построение графика только для текущего символа, либо для всех символов в MarketWatch;
  • Возможность выбора таймфрейма (графики в 100 pips логичнее строить на Daily, а графики в 1-3 pips на M1);
  • Возможность выбора размера бокса в пипсах;
  • Возможность выбора количества боксов для разворота;
  • Возможность выбора количества символов для отображения объемов (в скрипте - тиковых, потому как реальных объемов пока у брокеров не видел) по колонкам и по строкам (типа индикатора MarketDepth);
  • Возможность выбора глубины истории, на которой будем строить график;
  • Возможность выбора режима построения результатов - вывод результатов в текстовые файлы, или также сохранять их в графические файлы;
  • И, наконец, фича для новичков - автопостроение (автоматический выбор размера бокса исходя из желаемой высоты графика).

Алгоритм и требования описаны - скрипт в студию.

//+------------------------------------------------------------------+
//|                                         Point&Figure text charts |
//|                                        BSD Lic. 2012, Roman Rich |
//|                                           http://www.FXRays.info |
//+------------------------------------------------------------------+
#property               copyright "Roman Rich"
#property               link      "http://www.FXRays.info"
#property               version   "1.00"
#property               script_show_inputs
#include                "cIntBMP.mqh"                                       // Включаем файл с классом cIntBMP

input bool              mw=true;                                    // Весь MarketWatch?
input ENUM_TIMEFRAMES   tf=PERIOD_M1;                                 // Таймфрейм
input long              box=2;                                      // Размер бокса в пипсах (0 - авто)
enum                    cChoice{c10=10,c25=25,c50=50,c100=100};
input cChoice           count=c50;                                 // Высота графика в боксах для авто
enum                    rChoice{Two=2,Three,Four,Five,Six,Seven};
input rChoice           reverse=Five;                              // Кол-во боксов для разворота
enum                    vChoice{v10=10,v25=25,v50=50};
input vChoice           vd=v10;                                    // Символов для отображения объемов
enum                    dChoice{Little=15000,Middle=50000,Many=100000,Extremely=1000000};
input dChoice           depth=Little;                              // Глубина истории
input bool              pic=true;                                   // Файл рисунка?
input int               cellsize=10;                                // Размер ячейки в пикселах
//+------------------------------------------------------------------+
//| Класс-наследник cIntBMP                                          |
//+------------------------------------------------------------------+
class cIntBMPEx : public cIntBMP
  {
public:
   void              Rectangle(int aX1,int aY1,int aSizeX,int aSizeY,int aColor);
   void              Bar(int aX1,int aY1,int aSizeX,int aSizeY,int aColor);
   void              LineH(int aX1,int aY1,int aSizeX,int aColor);
   void              LineV(int aX1,int aY1,int aSizeY,int aColor);
   void              DrawBar(int aX1,int aY1,int aX2,int aY2,int aColor);
   void              TypeTextV(int aX,int aY,string aText,int aColor);
  };
cIntBMPEx bmp;    // Экземпляр класса cIntBMPEx
uchar Mask_O[192]= // Наши нолики
  {
   217,210,241,111,87,201,124,102,206,165,150,221,237,234,248,255,255,255,255,255,255,255,255,255,
   73,42,187,137,117,211,201,192,235,140,120,212,60,27,182,178,165,226,255,255,255,255,255,255,
   40,3,174,250,249,253,255,255,255,255,255,255,229,225,245,83,54,190,152,135,216,255,255,255,
   68,36,185,229,225,245,255,255,255,255,255,255,255,255,255,247,246,252,78,48,188,201,192,235,
   140,120,212,145,126,214,255,255,255,255,255,255,255,255,255,255,255,255,188,177,230,124,102,206,
   237,234,248,58,24,181,209,201,238,255,255,255,255,255,255,255,255,255,168,153,222,124,102,206,
   255,255,255,199,189,234,63,30,183,186,174,229,247,246,252,204,195,236,60,27,182,204,195,236,
   255,255,255,255,255,255,232,228,246,117,93,203,52,18,179,83,54,190,196,186,233,255,255,255
  };
uchar Mask_X[192]= // Наши крестики
  {
   254,252,252,189,51,51,236,195,195,255,255,255,255,255,255,235,192,192,248,234,234,255,255,255,
   255,255,255,202,90,90,184,33,33,251,243,243,212,120,120,173,0,0,173,0,0,255,255,255,
   255,255,255,254,252,252,195,69,69,192,60,60,178,15,15,233,186,186,253,249,249,255,255,255,
   255,255,255,255,255,255,241,210,210,173,0,0,209,111,111,255,255,255,255,255,255,255,255,255,
   255,255,255,255,255,255,205,99,99,192,60,60,181,24,24,241,210,210,255,255,255,255,255,255,
   255,255,255,249,237,237,176,9,9,241,213,213,226,165,165,189,51,51,254,252,252,255,255,255,
   255,255,255,230,177,177,185,36,36,255,255,255,255,255,255,189,51,51,222,153,153,255,255,255,
   255,255,255,240,207,207,200,84,84,255,255,255,255,255,255,227,168,168,211,117,117,255,255,255
  };
//+------------------------------------------------------------------+
//| Выбор инструмента                                                |
//+------------------------------------------------------------------+
void OnStart()
  {
   int    mwSymb;
   string symb;
   int    height=0,width=0;
   string pnfArray[];
   if(mw==true)
     {
      mwSymb=0;
      while(mwSymb<SymbolsTotal(true))
        {
         symb=SymbolName(mwSymb,true);
         ArrayFree(pnfArray);
         ArrayResize(pnfArray,0,0);
         PNF(symb,pnfArray,height,width,pic,cellsize);
         pnf2file(symb,pnfArray,0,height);
         mwSymb++;
        };
     }
   else
     {
      symb=Symbol();
      ArrayFree(pnfArray);
      ArrayResize(pnfArray,0,0);
      PNF(symb,pnfArray,height,width,pic,cellsize);
      pnf2file(symb,pnfArray,0,height);
     };
   Alert("Ok.");
  }
//+------------------------------------------------------------------+
//| Непосредственно расчет и построение графика                      |
//+------------------------------------------------------------------+
void PNF(string sName,      // инструмент
         string& array[],  // массив, куда направляем вывод
         int& y,           // высота массива
         int& z,           // ширина массива
         bool toPic,       // если true-выведем и рисунок
         int cs)           // примем размер ячейки для рисования
  {
   string      s,ps;
   datetime    d[];
   double      o[],h[],l[],c[];
   long        v[];
   uchar       matrix[];
   long        VolByPrice[],VolByCol[],HVolumeMax,VVolumeMax;
   int         tMin[],tMax[];
   datetime    DateByCol[];
   MqlDateTime bMDT,eMDT;
   string      strDBC[];
   uchar       pnf='.';
   int         sd;
   int         b,i,j,k=0,m=0;
   int         GlobalMin,GlobalMax,StartMin,StartMax,CurMin,CurMax,RevMin,RevMax,ContMin,ContMax;
   int         height,width,beg=0,end=0;
   double      dBox,price;
   int         thBeg=1,thEnd=2,tv=0;
   uchar       trend='.';
// --------------------------------- BMP -----------------------------------------
   int RowVolWidth=10*cs;
//--- отступ для цен
   int startX=5*cs;
   int yshift=cs*7;
// --------------------------------- BMP -----------------------------------------
   if(SymbolInfoInteger(sName,SYMBOL_DIGITS)<=3) sd=2; else sd=4;
   b=MathMin(Bars(sName,tf),depth);
   ArrayFree(d);
   ArrayFree(o);
   ArrayFree(h);
   ArrayFree(l);
   ArrayFree(c);
   ArrayFree(v);
   ArrayFree(matrix);
   ArrayFree(VolByPrice);
   ArrayFree(VolByCol);
   ArrayFree(DateByCol);
   ArrayFree(tMin);
   ArrayFree(tMax);
   ArrayResize(d,b,0);
   ArrayResize(o,b,0);
   ArrayResize(h,b,0);
   ArrayResize(l,b,0);
   ArrayResize(c,b,0);
   ArrayResize(v,b,0);
   ArrayInitialize(d,NULL);
   ArrayInitialize(o,NULL);
   ArrayInitialize(h,NULL);
   ArrayInitialize(l,NULL);
   ArrayInitialize(c,NULL);
   ArrayInitialize(v,NULL);
   CopyTime(sName,tf,0,b,d);
   CopyOpen(sName,tf,0,b,o);
   CopyHigh(sName,tf,0,b,h);
   CopyLow(sName,tf,0,b,l);
   CopyClose(sName,tf,0,b,c);
   CopyTickVolume(sName,tf,0,b,v);
   if(box!=0)
     {
      dBox=box/MathPow(10.0,(double)sd);
     }
   else
     {
      dBox=MathNorm((h[ArrayMaximum(h,0,WHOLE_ARRAY)]-l[ArrayMinimum(l,0,WHOLE_ARRAY)])/count,
                      1/MathPow(10.0,(double)sd),true)/MathPow(10.0,(double)sd);
     };
   GlobalMin=MathNorm(l[ArrayMinimum(l,0,WHOLE_ARRAY)],dBox,true)-(int)(reverse);
   GlobalMax=MathNorm(h[ArrayMaximum(h,0,WHOLE_ARRAY)],dBox,false)+(int)(reverse);
   StartMin=MathNorm(l[0],dBox,true);
   StartMax=MathNorm(h[0],dBox,false);
   ContMin=(int)(StartMin-1);
   ContMax=(int)(StartMax+1);
   RevMin=(int)(StartMax-reverse);
   RevMax=(int)(StartMin+reverse);
   height=(int)(GlobalMax-GlobalMin);
   width=1;
   ArrayResize(matrix,height*width,0);
   ArrayInitialize(matrix,'.');
   ArrayResize(VolByPrice,height,0);
   ArrayInitialize(VolByPrice,0);
   ArrayResize(VolByCol,width,0);
   ArrayInitialize(VolByCol,0);
   ArrayResize(DateByCol,width,0);
   ArrayInitialize(DateByCol,D'01.01.1971');
   ArrayResize(tMin,width,0);
   ArrayInitialize(tMin,0);
   ArrayResize(tMax,width,0);
   ArrayInitialize(tMax,0);
   for(i=1;i<b;i++)
     {
      CurMin=MathNorm(l[i],dBox,true);
      CurMax=MathNorm(h[i],dBox,false);
      switch(pnf)
        {
         case '.':
           {
            if(CurMax>=RevMax)
              {
               pnf='X';
               ContMax=(int)(CurMax+1);
               RevMin=(int)(CurMax-reverse);
               beg=(int)(StartMin-GlobalMin-1);
               end=(int)(CurMax-GlobalMin-1);
               SetMatrix(matrix,beg,end,height,(int)(width-1),pnf);
               SetVector(VolByPrice,beg,end,v[i]);
               VolByCol[width-1]=VolByCol[width-1]+v[i];
               DateByCol[width-1]=d[i];
               trend='D';
               break;
              };
            if(CurMin<=RevMin)
              {
               pnf='O';
               ContMin=(int)(CurMin-1);
               RevMax=(int)(CurMin+reverse);
               beg=(int)(CurMin-GlobalMin-1);
               end=(int)(StartMax-GlobalMin-1);
               SetMatrix(matrix,beg,end,height,(int)(width-1),pnf);
               SetVector(VolByPrice,beg,end,v[i]);
               VolByCol[width-1]=VolByCol[width-1]+v[i];
               DateByCol[width-1]=d[i];
               trend='U';
               break;
              };
            break;
           };
         case 'X':
           {
            if(CurMax>=ContMax)
              {
               pnf='X';
               ContMax=(int)(CurMax+1);
               RevMin=(int)(CurMax-reverse);
               end=(int)(CurMax-GlobalMin-1);
               SetMatrix(matrix,beg,end,height,(int)(width-1),pnf);
               SetVector(VolByPrice,beg,end,v[i]);
               VolByCol[width-1]=VolByCol[width-1]+v[i];
               DateByCol[width-1]=d[i];
               break;
              };
            if(CurMin<=RevMin)
              {
               pnf='O';
               ContMin=(int)(CurMin-1);
               RevMax=(int)(CurMin+reverse);
               tMin[width-1]=beg-1;
               tMax[width-1]=end+1;
               beg=(int)(CurMin-GlobalMin-1);
               end--;
               width++;
               ArrayResize(matrix,height*width,0);
               ArrayResize(VolByCol,width,0);
               ArrayResize(DateByCol,width,0);
               ArrayResize(tMin,width,0);
               ArrayResize(tMax,width,0);
               SetMatrix(matrix,0,(int)(height-1),height,(int)(width-1),'.');
               SetMatrix(matrix,beg,end,height,(int)(width-1),pnf);
               SetVector(VolByPrice,beg,end,v[i]);
               VolByCol[width-1]=0;
               VolByCol[width-1]=VolByCol[width-1]+v[i];
               DateByCol[width-1]=d[i];
               tMin[width-1]=beg-1;
               tMax[width-1]=end+1;
               break;
              };
            break;
           };
         case 'O':
           {
            if(CurMin<=ContMin)
              {
               pnf='O';
               ContMin=(int)(CurMin-1);
               RevMax=(int)(CurMin+reverse);
               beg=(int)(CurMin-GlobalMin-1);
               SetMatrix(matrix,beg,end,height,(int)(width-1),pnf);
               SetVector(VolByPrice,beg,end,v[i]);
               VolByCol[width-1]=VolByCol[width-1]+v[i];
               DateByCol[width-1]=d[i];
               break;
              };
            if(CurMax>=RevMax)
              {
               pnf='X';
               ContMax=(int)(CurMax+1);
               RevMin=(int)(CurMax-reverse);
               tMin[width-1]=beg-1;
               tMax[width-1]=end+1;
               beg++;
               end=(int)(CurMax-GlobalMin-1);
               width++;
               ArrayResize(matrix,height*width,0);
               ArrayResize(VolByCol,width,0);
               ArrayResize(DateByCol,width,0);
               ArrayResize(tMin,width,0);
               ArrayResize(tMax,width,0);
               SetMatrix(matrix,0,(int)(height-1),height,(int)(width-1),'.');
               SetMatrix(matrix,beg,end,height,(int)(width-1),pnf);
               SetVector(VolByPrice,beg,end,v[i]);
               VolByCol[width-1]=0;
               VolByCol[width-1]=VolByCol[width-1]+v[i];
               DateByCol[width-1]=d[i];
               tMin[width-1]=beg-1;
               tMax[width-1]=end+1;
               break;
              };
            break;
           };
        };
     };
//--- не забываем себя
   s="BSD License, 2012, FXRays.info by Roman Rich";
   k++;
   ArrayResize(array,k,0);
   array[k-1]=s;
   s=SymbolInfoString(sName,SYMBOL_DESCRIPTION)+",
                      Box-"+DoubleToString(box,0)+",Reverse-"+DoubleToString(reverse,0);
   k++;
   ArrayResize(array,k,0);
   array[k-1]=s;
// --------------------------------- BMP -----------------------------------------
   if(toPic==true)
     {
      //-- размеры изображения BMP на экране графика
      int XSize=cs*width+2*startX+RowVolWidth;
      int YSize=cs*height+yshift+70;
      //-- создаем bmp-картинку размером XSize x YSize c фоном цвета clrWhite
      bmp.Create(XSize,YSize,clrWhite);
      //-- отображение клеток основного поля
      for(i=height-1;i>=0;i--)
         for(j=0;j<=width-1;j++)
           {
            bmp.Bar(RowVolWidth+startX+cs*j,yshift+cs*i,cs,cs,clrWhite);
            bmp.Rectangle(RowVolWidth+startX+cs*j,yshift+cs*i,cs,cs,clrLightGray);
           }
      bmp.TypeText(10,yshift+cs*(height)+50,array[k-2],clrDarkGray);
      bmp.TypeText(10,yshift+cs*(height)+35,array[k-1],clrGray);
     }
// --------------------------------- BMP -----------------------------------------
//--- рассчитываем линии тренда
   i=0;
   while(thEnd<width-1)
     {
      while(thBeg+i<thEnd)
        {
         if(trend=='U')
           {
            i=ArrayMinimum(tMin,thBeg,thEnd-thBeg);
            j=tMin[i];
           }
         else
           {
            i=ArrayMaximum(tMax,thBeg,thEnd-thBeg);
            j=tMax[i];
           }
         thBeg=i;
         tv=j;
         i=0;
         while(GetMatrix(matrix,j,height,(long)(thBeg+i))=='.')
           {
            i++;
            if(trend=='U') j++; else j--;
            if(thBeg+i==width-1)
              {
               thEnd=width-1;
               break;
              };
           };
         if(thBeg+i<thEnd)
           {
            thBeg=thBeg+2;
            i=0;
           };
        };
      thEnd=thBeg+i;
      if(thEnd==thBeg) thEnd++;
      for(i=thBeg;i<thEnd;i++)
        {
         SetMatrix(matrix,tv,tv,height,(long)(i),'+');
         // --------------------------------- BMP -----------------------------------------
         if(toPic==true)
           {
            //--- линии поддержки и сопротивления
            if(trend=='U') { bmp.DrawLine(RowVolWidth+startX+i*cs,yshift+tv*cs,
                                         RowVolWidth+startX+(i+1)*cs,yshift+(tv+1)*cs,clrGreen); }
            if(trend=='D') { bmp.DrawLine(RowVolWidth+startX+i*cs,yshift+(tv+1)*cs,
                                         RowVolWidth+startX+(i+1)*cs,yshift+(tv)*cs,clrRed); }
            //--- "уширение" линий поддержки/сопротивления
            if(trend=='U') { bmp.DrawLine(RowVolWidth+1+startX+i*cs,yshift+tv*cs,
                                         RowVolWidth+1+startX+(i+1)*cs,yshift+(tv+1)*cs,clrGreen); }
            if(trend=='D') { bmp.DrawLine(RowVolWidth+1+startX+i*cs,yshift+(tv+1)*cs,
                                         RowVolWidth+1+startX+(i+1)*cs,yshift+(tv)*cs,clrRed); }
           }
         // --------------------------------- BMP -----------------------------------------
         if(trend=='U') tv++; else tv--;
        };
      if(trend=='U') trend='D'; else trend='U';
      i=0;
     };
//--- отображаем даты по столбцам
   ArrayResize(strDBC,width,0);
   TimeToStruct(DateByCol[0],bMDT);
   TimeToStruct(DateByCol[width-1],eMDT);
   if((DateByCol[width-1]-DateByCol[0])>=50000000)
     {
      for(i=0;i<=width-1;i++) StringInit(strDBC[i],4,' ');
      for(i=1;i<=width-1;i++)
        {
         TimeToStruct(DateByCol[i-1],bMDT);
         TimeToStruct(DateByCol[i],eMDT);
         if(bMDT.year!=eMDT.year) strDBC[i]=DoubleToString(eMDT.year,0);
        };
      for(i=0;i<=3;i++)
        {
         StringInit(s,vd,' ');
         s=s+"            : ";
         for(j=0;j<=width-1;j++) s=s+StringSubstr(strDBC[j],i,1);
         s=s+" : ";
         k++;
         ArrayResize(array,k,0);
         array[k-1]=s;
        };
     }
   else
     {
      if((DateByCol[width-1]-DateByCol[0])>=5000000)
        {
         for(i=0;i<=width-1;i++) StringInit(strDBC[i],7,' ');
         for(i=1;i<=width-1;i++)
           {
            TimeToStruct(DateByCol[i-1],bMDT);
            TimeToStruct(DateByCol[i],eMDT);
            if(bMDT.mon!=eMDT.mon)
              {
               if(eMDT.mon<10) strDBC[i]=DoubleToString(eMDT.year,0)+".0"+DoubleToString(eMDT.mon,0);
               if(eMDT.mon>=10) strDBC[i]=DoubleToString(eMDT.year,0)+"."+DoubleToString(eMDT.mon,0);
              }
           };
         for(i=0;i<=6;i++)
           {
            StringInit(s,vd,' ');
            s=s+"            : ";
            for(j=0;j<=width-1;j++) s=s+StringSubstr(strDBC[j],i,1);
            s=s+" : ";
            k++;
            ArrayResize(array,k,0);
            array[k-1]=s;
           };
        }
      else
        {
         for(i=0;i<=width-1;i++) StringInit(strDBC[i],10,' ');
         for(i=1;i<=width-1;i++)
           {
            TimeToStruct(DateByCol[i-1],bMDT);
            TimeToStruct(DateByCol[i],eMDT);
            if(bMDT.day!=eMDT.day)
              {
               if(eMDT.mon<10 && eMDT.day<10) strDBC[i]=DoubleToString(eMDT.year,0)+".0"
                                                       +DoubleToString(eMDT.mon,0)+".0"+DoubleToString(eMDT.day,0);
               if(eMDT.mon<10 && eMDT.day>=10) strDBC[i]=DoubleToString(eMDT.year,0)+".0"
                                                       +DoubleToString(eMDT.mon,0)+"."+DoubleToString(eMDT.day,0);
               if(eMDT.mon>=10&&eMDT.day< 10) strDBC[i]=DoubleToString(eMDT.year,0)+"." 
                                                      +DoubleToString(eMDT.mon,0)+".0"+DoubleToString(eMDT.day,0);
               if(eMDT.mon>=10&&eMDT.day>=10) strDBC[i]=DoubleToString(eMDT.year,0)+"." 
                                                      +DoubleToString(eMDT.mon,0)+"." +DoubleToString(eMDT.day,0);
              }
           };
         for(i=0;i<=9;i++)
           {
            StringInit(s,vd,' ');
            s=s+"            : ";
            for(j=0;j<=width-1;j++) s=s+StringSubstr(strDBC[j],i,1);
            s=s+" : ";
            k++;
            ArrayResize(array,k,0);
            array[k-1]=s;
           };
        };
     };
   StringInit(s,25+vd+width,'-');
   k++;
   ArrayResize(array,k,0);
   array[k-1]=s;
//--- отображаем ценовой график
   price=GlobalMax*dBox;
   HVolumeMax=VolByPrice[ArrayMaximum(VolByPrice,0,WHOLE_ARRAY)];
   s="";
   for(i=height-1;i>=0;i--)
     {
      StringInit(ps,8-StringLen(DoubleToString(price,sd)),' ');
      s=s+ps+DoubleToString(price,sd)+" : ";
      for(j=0;j<vd;j++) if(VolByPrice[i]>HVolumeMax*j/vd) s=s+"*"; else s=s+" ";
      s=s+" : ";
      for(j=0;j<=width-1;j++) s=s+CharToString(matrix[j*height+i]);
      s=s+" : "+ps+DoubleToString(price,sd);
      k++;
      ArrayResize(array,k,0);
      array[k-1]=s;
      s="";
      price=price-dBox;
     };
   StringInit(s,25+vd+width,'-');
   k++;
   ArrayResize(array,k,0);
   array[k-1]=s;
//--- простенькая разметка через 10-ку
   StringInit(s,vd,' ');
   s=s+"            : ";
   for(j=0;j<=width-1;j++) if(StringGetCharacter(DoubleToString(j,0),
                                                    StringLen(DoubleToString(j,0))-1)==57) s=s+"|"; else s=s+" ";
   s=s+" : ";
   k++;
   ArrayResize(array,k,0);
   array[k-1]=s;
//--- отображаем график объемов по столбцам
   VVolumeMax=VolByCol[ArrayMaximum(VolByCol,0,WHOLE_ARRAY)];
   for(i=vd-1;i>=0;i--)
     {
      StringInit(s,vd,' ');
      s=s+"            : ";
      for(j=0;j<=width-1;j++) if(VolByCol[j]>VVolumeMax*i/vd) s=s+"*"; else s=s+" ";
      s=s+" : ";
      k++;
      ArrayResize(array,k,0);
      array[k-1]=s;
     };
   StringInit(s,25+vd+width,'-');
   k++;
   ArrayResize(array,k,0);
   array[k-1]=s;
//--- история колонок
   s="     | Start Date/Time     | End Date/Time       | ";
   k++;
   ArrayResize(array,k,0);
   array[k-1]=s;
   TimeToStruct(DateByCol[0],bMDT);
   s="   1 | 0000/00/00 00:00:00 | ";
   s=s+DoubleToString(bMDT.year,0)+"/";
   if(bMDT.mon >=10) s=s+DoubleToString(bMDT.mon ,0)+"/"; else s=s+"0"+DoubleToString(bMDT.mon ,0)+"/";
   if(bMDT.day >=10) s=s+DoubleToString(bMDT.day ,0)+" "; else s=s+"0"+DoubleToString(bMDT.day ,0)+" ";
   if(bMDT.hour>=10) s=s+DoubleToString(bMDT.hour,0)+":"; else s=s+"0"+DoubleToString(bMDT.hour,0)+":";
   if(bMDT.min >=10) s=s+DoubleToString(bMDT.min ,0)+":"; else s=s+"0"+DoubleToString(bMDT.min ,0)+":";
   if(bMDT.sec >=10) s=s+DoubleToString(bMDT.sec ,0)+" | "; else s=s+"0"+DoubleToString(bMDT.sec ,0)+" | ";
   k++;
   ArrayResize(array,k,0);
   array[k-1]=s;
   for(i=1;i<=width-1;i++)
     {
      TimeToStruct(DateByCol[i-1],bMDT);
      TimeToStruct(DateByCol[i],eMDT);
      s="";
      StringInit(ps,4-StringLen(DoubleToString(i+1,0)),' ');
      s=s+ps+DoubleToString(i+1,0)+" | ";
      s=s+DoubleToString(bMDT.year,0)+"/";
      if(bMDT.mon >=10) s=s+DoubleToString(bMDT.mon ,0)+"/"; else s=s+"0"+DoubleToString(bMDT.mon ,0)+"/";
      if(bMDT.day >=10) s=s+DoubleToString(bMDT.day ,0)+" "; else s=s+"0"+DoubleToString(bMDT.day ,0)+" ";
      if(bMDT.hour>=10) s=s+DoubleToString(bMDT.hour,0)+":"; else s=s+"0"+DoubleToString(bMDT.hour,0)+":";
      if(bMDT.min >=10) s=s+DoubleToString(bMDT.min ,0)+":"; else s=s+"0"+DoubleToString(bMDT.min ,0)+":";
      if(bMDT.sec >=10) s=s+DoubleToString(bMDT.sec ,0)+" | "; else s=s+"0"+DoubleToString(bMDT.sec ,0)+" | ";
      s=s+DoubleToString(eMDT.year,0)+"/";
      if(eMDT.mon >=10) s=s+DoubleToString(eMDT.mon ,0)+"/"; else s=s+"0"+DoubleToString(eMDT.mon ,0)+"/";
      if(eMDT.day >=10) s=s+DoubleToString(eMDT.day ,0)+" "; else s=s+"0"+DoubleToString(eMDT.day ,0)+" ";
      if(eMDT.hour>=10) s=s+DoubleToString(eMDT.hour,0)+":"; else s=s+"0"+DoubleToString(eMDT.hour,0)+":";
      if(eMDT.min >=10) s=s+DoubleToString(eMDT.min ,0)+":"; else s=s+"0"+DoubleToString(eMDT.min ,0)+":";
      if(eMDT.sec >=10) s=s+DoubleToString(eMDT.sec ,0)+" | "; else s=s+"0"+DoubleToString(eMDT.sec ,0)+" | ";
      k++;
      ArrayResize(array,k,0);
      array[k-1]=s;
     };
   y=k;
   z=25+vd+width;
// --------------------------------- BMP -----------------------------------------
   if(toPic==true)
     {
      //--- отображение дат в виде YYYY/MM/DD
      for(j=0;j<=width-1;j++)
        {
         string s0=strDBC[j];
         StringReplace(s0,".","/");
         bmp.TypeTextV(RowVolWidth+startX+cs*j,yshift+cs*(height-1)+5,s0,clrDimGray);
        }
      //--- подложка с клетками для объемов
      for(i=height-1;i>=0;i--)
         for(j=0;j<vd;j++)
           {
            bmp.Bar(cs+startX+cs*(j-1),yshift+cs*i,cs,cs,0xF6F6F6);
            bmp.Rectangle(cs+startX+cs*(j-1),yshift+cs*i,cs,cs,clrLightGray);
           }
      for(i=0; i>-7;i--)
         for(j=0;j<=vd;j++)
           {
            bmp.Bar(cs+startX+cs*(j-1),yshift+cs*i,cs,cs,clrWhite);
            bmp.Rectangle(cs+startX+cs*(j-1),yshift+cs*i,cs,cs,clrLightGray);
           }
      //--- объемы точные
      for(i=height-1;i>=0;i--)
         bmp.Bar(startX,yshift+cs*i,int(10*cs*VolByPrice[i]/HVolumeMax),cs,0xB5ABAB);
      //--- отображение крестиков и ноликов
      for(i=height-1;i>=0;i--)
         for(j=0;j<=width-1;j++)
           {
            int xpos=RowVolWidth+startX+cs*j+1;
            int ypos=yshift+cs*i+1;
            if(CharToString(matrix[j*height+i])=="X") ShowCell(xpos,ypos,'X');
            else
               if(CharToString(matrix[j*height+i])=="O") ShowCell(xpos,ypos,'O');
           }
      //--- подложка для объемов внизу
      for(i=0;i<=60/cs;i++)
         for(j=0;j<=width-1;j++)
           {
            bmp.Bar(RowVolWidth+startX+cs*j,12+cs*i,cs,cs,0xF6F6F6);
            bmp.Rectangle(RowVolWidth+startX+cs*j,12+cs*i,cs,cs,clrLightGray);
           }
      //--- отображение объемов
      for(j=0;j<=width-1;j++) bmp.Bar(RowVolWidth+startX+cs*j,yshift-60,
                                     cs,int(60*VolByCol[j]/VVolumeMax),0xB5ABAB);
      //--- отображение рамки основного поля
      bmp.Rectangle(RowVolWidth+startX+cs*0,yshift+cs*0,cs*(width),cs*(height),clrSilver);
      //--- отображение цен и шкалы
      bmp.LineV(startX,yshift,cs*height,clrBlack);
      bmp.LineV(RowVolWidth+startX+cs*width,yshift,cs*height,clrBlack);
      price=GlobalMax*dBox;
      for(i=height-1;i>=0;i--)
        {
         //-- цены слева
         bmp.TypeText(cs,yshift+cs*i,DoubleToString(price,sd),clrBlack);
         bmp.LineH(0,yshift+cs*i,startX,clrLightGray);
         bmp.LineH(0+startX-3,yshift+cs*i,6,clrBlack);
         //-- цены справа     
         int dx=RowVolWidth+cs*width;
         bmp.TypeText(10+startX+dx,yshift+cs*i,DoubleToString(price,sd),clrBlack);
         bmp.LineH(startX+dx,yshift+cs*i,40,clrLightGray);
         bmp.LineH(startX+dx-3,yshift+cs*i,6,clrBlack);
         price=price-dBox;
        }
      //-- сохраняем полученную картинку в файл  
      bmp.Save(sName,true);
     }
// --------------------------------- BMP -----------------------------------------
  }
//+------------------------------------------------------------------+
//|Выводим в текстовый файл                                          |
//+------------------------------------------------------------------+
void pnf2file(string sName,        // инструмент для имени файла
              string& array[],    // массив строк, который записываем в файл
              int beg,            // с какой строки массива начинаем записывать в файл
              int end)            // и какой строкой заканчиваем
  {
   string fn;
   int    handle;
   fn=sName+"_b"+DoubleToString(box,0)+"_r"+DoubleToString(reverse,0)+".txt";
   handle=FileOpen(fn,FILE_WRITE|FILE_TXT|FILE_ANSI,';');
   for(int i=beg;i<end;i++) FileWrite(handle,array[i]);
   FileClose(handle);
  }
//+------------------------------------------------------------------+
//| Приводим цену к размеру бокса                                    |
//+------------------------------------------------------------------+
int MathNorm(double value,     // любое double-число преобразуем в long-число
             double prec,      // доводим его до точности
             bool vect)        // и если true - округляем вверх, false - округляем вниз
  {
   if(vect==true)
      return((int)(MathCeil(value/prec)));
   else
      return((int)(MathFloor(value/prec)));
  }
//+------------------------------------------------------------------+
//| Заполняем массив                                                 |
//| Символьный одномерный массив представляем в виде матрицы         |
//+------------------------------------------------------------------+
void SetMatrix(uchar& array[],      // передаем его по ссылке для замены в нем
               long pbeg,          // начиная с этого места
               long pend,          // по это место
               long pheight,       // в колонке такой высоты
               long pwidth,        // с таким номером из числа всех колонок массива
               uchar ppnf)         // вот этим символом
  {
   long offset=0;
   for(offset=pheight*pwidth+pbeg;offset<=pheight*pwidth+pend;offset++) array[(int)offset]=ppnf;
  }
//+------------------------------------------------------------------+
//| Получаем из массива единичное значение                           |
//| Символьный одномерный массив представляем в виде матрицы         |
//+------------------------------------------------------------------+
uchar GetMatrix(uchar& array[],      // передаем его по ссылке для получения из него символа...
                long pbeg,          // в этом месте
                long pheight,       // в колонке такой высоты
                long pwidth)        // с таким номером из числа всех колонок массива
  {
   return(array[(int)pheight*(int)pwidth+(int)pbeg]);
  }
//+------------------------------------------------------------------+
//|Заполняем вектор                                                  |
//+------------------------------------------------------------------+
void SetVector(long &array[],      // long-массив передаем по ссылке для замены в нем
               long pbeg,         // начиная с этого места
               long pend,         // по это место
               long pv)           // вот этим значением
  {
   long offset=0;
   for(offset=pbeg;offset<=pend;offset++) array[(int)offset]=array[(int)offset]+pv;
  }
//+------------------------------------------------------------------+
//| Отображение горизонтальной линии                                 |
//+------------------------------------------------------------------+
void cIntBMPEx::LineH(int aX1,int aY1,int aSizeX,int aColor)
  {
   DrawLine(aX1,aY1,aX1+aSizeX,aY1,aColor);
  }
//+------------------------------------------------------------------+
//| Отображение вертикальной линии                                   |
//+------------------------------------------------------------------+  
void cIntBMPEx::LineV(int aX1,int aY1,int aSizeY,int aColor)
  {
   DrawLine(aX1,aY1,aX1,aY1+aSizeY,aColor);
  }
//+------------------------------------------------------------------+
//| Рисует прямоугольник (заданного размера)                         |
//+------------------------------------------------------------------+
void cIntBMPEx::Rectangle(int aX1,int aY1,int aSizeX,int aSizeY,int aColor)
  {
   DrawRectangle(aX1,aY1,aX1+aSizeX,aY1+aSizeY,aColor);
  }
//+------------------------------------------------------------------+
//| Рисует закрашенный прямоугольник (заданного размера)             |
//+------------------------------------------------------------------+
void cIntBMPEx::Bar(int aX1,int aY1,int aSizeX,int aSizeY,int aColor)
  {
   DrawBar(aX1,aY1,aX1+aSizeX,aY1+aSizeY,aColor);
  }
//+------------------------------------------------------------------+
//| Рисует закрашенный прямоугольник                                 |
//+------------------------------------------------------------------+
void cIntBMPEx::DrawBar(int aX1,int aY1,int aX2,int aY2,int aColor)
  {
   for(int i=aX1; i<=aX2; i++)
      for(int j=aY1; j<=aY2; j++)
        {
         DrawDot(i,j,aColor);
        }
  }
//+------------------------------------------------------------------+
//| Вертикальное отображение текста                                  |
//+------------------------------------------------------------------+
void cIntBMPEx::TypeTextV(int aX,int aY,string aText,int aColor)
  {
   SetDrawWidth(1);
   for(int j=0;j<StringLen(aText);j++)
     {
      string TypeChar=StringSubstr(aText,j,1);
      if(TypeChar==" ")
        {
         aY+=5;
        }
      else
        {
         int Pointer=0;
         for(int i=0;i<ArraySize(CA);i++)
           {
            if(CA[i]==TypeChar)
              {
               Pointer=i;
              }
           }
         for(int i=PA[Pointer];i<PA[Pointer+1];i++)
           {
            DrawDot(aX+YA[i],aY+MaxHeight+XA[i],aColor);
           }
         aY+=WA[Pointer]+1;
        }
     }
  }
//+------------------------------------------------------------------+
//| Преобразует компоненты в цвет                                    |
//+------------------------------------------------------------------+
int RGB256(int aR,int aG,int aB)
  {
   return(aR+256*aG+65536*aB);
  }
//+------------------------------------------------------------------+
//| Рисует "X" или "0" в виде картинки                               |
//+------------------------------------------------------------------+
void ShowCell(int x,int y,uchar img)
  {
   uchar r,g,b;
   for(int i=0; i<8; i++)
     {
      for(int j=0; j<8; j++)
        {
         switch(img)
           {
            case 'X':
               r=Mask_X[3*(j*8+i)];
               g=Mask_X[3*(j*8+i)+1];
               b=Mask_X[3*(j*8+i)+2];
               break;
            case 'O':
               r=Mask_O[3*(j*8+i)];
               g=Mask_O[3*(j*8+i)+1];
               b=Mask_O[3*(j*8+i)+2];
               break;
           };
         int col=RGB256(r,g,b);
         bmp.DrawDot(x+i,y+j,col);
        }
     }
  }
//+------------------------------------------------------------------+

В зависимости от значения входного параметра pic результатом работы скрипта будут текстовые файлы с файлами картинок (каталог_данных_терминала\MQL5\Images) или только текстовые файлы (сохраняются в папке: каталог_данных_терминала\MQL5\Files).


Сравнение результатов

Для сравнения результатов построим график Light Crude Oil с параметрами: бокс - 1$, разворот - 3 бокса.

StockCharts.com:

Рис. 1. Результат построения графика крестики-нолики для Light Crude Oil программой StockCharts.com

Рис. 1. Результат построения графика "крестики-нолики" для Light Crude Oil программой StockCharts.com

Bull's-Eye Broker:

Рис. 2. Результат построения графика "крестики-нолики" для Light Crude Oil программой Bull's-Eye Broker

Рис. 2. Результат построения графика "крестики-нолики" для Light Crude Oil программой Bull's-Eye Broker


Результат работы нашего скрипта:

Рис. 3. Результат построения графика крестики-нолики для Light Crude Oil при помощи нашего скрипта

Рис. 3. Результат построения графика "крестики-нолики" для Light Crude Oil при помощи нашего скрипта

Все три графика идентичны, поздравим себя, мы освоили построение крестиков-ноликов.


Типичные паттерны графиков "крестики-нолики"

Как все это можно использовать?

Сначала рассмотрим типичные паттерны, благо, в крестиках-ноликах их все можно перечесть на пальцах.

Вот они:

Рис. 4. Ценовые паттерны Двойная вершина, Тройная вершина, Двойное основание и Тройное основание

Рис. 4. Ценовые паттерны "Двойная вершина", "Тройная вершина", "Двойное основание" и "Тройное основание"

далее:

Рис. 5. Ценовые паттерны Бычий треугольник и Медвежий треугольник

Рис. 5. Ценовые паттерны "Бычий треугольник" и "Медвежий треугольник"

и наконец:

Рис. 6. Ценовые паттерны Бычья катапульта и Медвежья катапульта

Рис. 6. Ценовые паттерны "Бычья катапульта" и "Медвежья катапульта"

Теперь несколько советов.

  1. Открываться только вверх, находясь над линией поддержки и только вниз, находясь под линией сопротивления. Например, начиная с середины декабря 2011 года после пробития ценой линии сопротивления, идущей с конца сентября 2011 года, открывать только длинные позиции по нефтяному фьючерсу.
  2. Линии поддержки-сопротивления использовать для трейлинга приказов стоп-лосс.
  3. Перед открытием позиции применить правило вертикального счета для оценки соотношения возможного профита к возможным потерям.

Остановлюсь подробнее на правиле вертикального счета на примере.

В декабре 2011 года колонка "Х", начавшаяся от цены 76$, пошла вверх, превысила предыдущую колонку "Х" на уровне 85$, пробила на 87$ сопротивление и дошла до 89$. Правило вертикального счета гласит, что при таких раскладах цена может пройти вверх до цены, равной 76$+(89$-75$)*3 (разворот 3 бокса)=118$.

Следующее ценовое движение было коррекционным до цены 85$. Спекулянты могут выставить защитный стоп по длинной сделке на 1$ ниже, т.е. 84$.

Вход в длинную позицию можно планировать после окончания коррекционного движения на один бокс выше предыдущей колонки "Х", т.е. по цене 90$.

Оценим возможные потери, они могут составить 90$-84$=6$ на один фьючерс. Возможная прибыль может составить 118$-90$=28$. Соотношение возможной прибыли к возможному убытку 28$/6$>4.5 раз. По-моему, удачный бизнес. Уже сейчас наша прибыль составляла бы 105$-90$=15$ на каждый фьючерс.


Лиценезии

Скрипт написан и распространяется на условиях BSD автором Roman Rich. Текст лицензии в файле Lic.txt. Библиотека cIntBMP написана Дмитрием aka Integer. Торговые марки StockCharts.com и Bull's-Eye Broker принадлежат соответствующим правообладателям.


Заключение

В статье предложен алгоритм построения пункто-цифровых графиков ("крестики-нолики") и скрипт, позволяющий производить построение данных графиков. Рассмотрены типичные ценовые паттерны графиков "крестики-нолики", даны рекомендации по их практическому использованию.


Прикрепленные файлы |
cintbmp.mqh (39.48 KB)
pnf.zip (659.49 KB)
lic.txt (3.06 KB)
pnf.mq5 (32.3 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (12)
Igor Makanu
Igor Makanu | 14 мар. 2012 в 17:00
Automated-Trading:

Возможно проблема связана с тем, что не загружена история. Ее можно загрузить автоматически по всем символам при помощи CDownLoadHistory

загрузил историю скриптом downloadhistoryvisualmode.mq5 с настройкой: Вариант загрузки истории = Все символы из обзора рынка

после исполнения скрипта перезагрузил терминал, затем еще раз запустил скрипт  downloadhistoryvisualmode  и следом запустил PnF.mq5 с настройками по умолчанию

в журнале:

2012.03.14 19:38:00 Scripts script PnF (EURUSD,H1) removed
2012.03.14 19:38:00 MemoryException 1048576 bytes not available
2012.03.14 19:27:36 Scripts script PnF (EURUSD,H1) loaded successfully
2012.03.14 19:27:28 Scripts script downloadhistoryvisualmode (EURUSD,H1) removed
2012.03.14 19:26:41 Scripts script downloadhistoryvisualmode (EURUSD,H1) loaded successfully

 во вкладке эксперты:

2012.03.14 19:38:00 PnF (EURUSD,H1) array out of range in 'cIntBMP.mqh' (348,21)
2012.03.14 19:27:28 downloadhistoryvisualmode (EURUSD,H1) Загрузка выполнена успешно

 запустил затем с настройками в соответсвии с Вашим скрином, в журнале:

2012.03.14 19:56:11 Scripts script PnF (EURUSD,H1) removed
2012.03.14 19:55:57 Scripts script PnF (EURUSD,H1) loaded successfully

 во вкладке эксперты:

2012.03.14 19:56:11 PnF (EURUSD,H1) Ok.

 в папке МТ5:

 

файлы с рисунками содержат изображения графиков ХО, но терминал ничего не нарисовал, 

 

Igor Makanu
Igor Makanu | 14 мар. 2012 в 17:23

нашел в чем была проблема: у меня файл подкачки Win задан max/min  = 2048/2048 при 2Га оперативки никогда ни на одном приложении (MATLAB, Statistica, MSOffice, Delphi, debuggerы...,включая игры ) до сих пор ни разу не испытывал проблем с нехваткой памяти. Выставил файл подкачки "авто", скрипт в журнале:

2012.03.14 20:13:02 Scripts script PnF (EURUSD,H1) removed
2012.03.14 20:12:40 Scripts script PnF (EURUSD,H1) loaded successfully

во вкладке эксперты:2012.03.14 20:13:02 PnF (EURUSD,H1) Ok.

хм..., даже комментировать нет желания, что я думаю по этому поводу....

насколько я понял скрипт лишь формирует картинки в папке МТ5? если да, то на кой они нужны? я могу с разных ресурсов в предлагаемых web-платформах делать аналогичные скрины, не говоря о терминалах которые предоставляют ТФ в виде ХО

ЗЫ: неужели разработчикам настолько затруднительно сделать возможность средствами МТ5 рисовать по канве окна ТФ? про пользовательские оффлайн графики просто промолчу.....

удачи!
 

Sceptic Philozoff
Sceptic Philozoff | 14 мар. 2012 в 18:42
IgorM: хм..., даже комментировать нет желания, что я думаю по этому поводу....
Действительно странно. Дело даже не в том, что памяти хватает. Просто я посмотрел на Task Manager и увидел, что расход памяти на этом скрипте совсем невелик - ну от силы 50 мегов.
Anatoli Kazharski
Anatoli Kazharski | 14 мар. 2012 в 18:50
IgorM:

...

ЗЫ: неужели разработчикам настолько затруднительно сделать возможность средствами МТ5 рисовать по канве окна ТФ? про пользовательские оффлайн графики просто промолчу.....

удачи!

Вроде бы Ренат, что-то такое объявлял уже на днях, если не ошибаюсь.
MetaQuotes
Renat Fatkhullin | 14 мар. 2012 в 19:09
tol64:
Вроде бы Ренат, что-то такое объявлял уже на днях, если не ошибаюсь.

Уже в работе.

Сначала сделаем легкий способ динамического создания битмапов и привязки их к графическим объектам, а уже затем штатные функции рисования к битмапе. Хотя уже и без штатных функций при желании можно будет самому рисовать в буфере.

AutoElliottWaveMaker - инструмент полуавтоматической разметки волн Эллиотта в MetaTrader 5 AutoElliottWaveMaker - инструмент полуавтоматической разметки волн Эллиотта в MetaTrader 5
В данной статье описывается программа AutoElliottWaveMaker - первая разработка по анализу волн Эллиотта в MetaTrader 5, которая сочетает в себе функции ручной и автоматической разметки волн. Инструмент анализа волн полностью написан на языке MQL5 и не включает сторонние библиотеки dll. Это еще раз подтверждает тот факт, что на MQL5 можно (и нужно) создавать сложные и интересные программы.
Золотое правило трейдера Золотое правило трейдера
Чтобы получать прибыль на основе высокого ожидания, надо уяснить три основных принципа хорошей торговли: 1) знай свой риск, когда входишь в рынок; 2) делай свою прибыль кратной первоначальному риску, давая расти прибыли; 3) знай, ожидание своей системы – периодически тестируй и вноси коррективы. В данной статье предлагается программный код отслеживания открытых позиций, который позволяет реализовать вторую часть золотого правила трейдинга – дает расти прибыли до максимально возможной.
Как опубликовать свой продукт в сервисе Маркет Как опубликовать свой продукт в сервисе Маркет
Предложите свои разработки миллионам пользователей MetaTrader по всему миру — опубликуйте их в Маркете. Сервис предлагает готовую инфраструктуру для продаж: доступ к аудитории, механизмы лицензирования, предоставления пробных версий, доставки обновлений и приема платежей. От вас требуется лишь пройти быструю процедуру регистрации и публикации продукта. Начинайте зарабатывать на своих разработках, все технические детали сервис возьмет на себя.
Защита MQL5-программ: пароли, ключи, ограничение по времени, удаленная проверка лицензий Защита MQL5-программ: пароли, ключи, ограничение по времени, удаленная проверка лицензий
Большинство разработчиков нуждаются в защите своих кодов. В этой статье представлены несколько различных способов защиты MQL5-программ - методы обеспечения лицензирования скриптов, советников и индикаторов. Рассмотрена парольная защита, генераторы ключей, привязка к торговым счетам, ограничение по времени и удаленная проверка лицензий при помощи MQL5-RPC.