CGraphicのテスト - 質問と提案 - ページ 3

 

ロマン・コノペルコ

2つ目の問題、あるいはヒントを教えてください。

Closeの価格でラインを作ろうとしています。Xではそれに応じて、時間の配列を渡しています。しかし、問題はカーブを作成する際に、勝手に間隔を追加してしまうことです。つまり、時間を均一にして、データのない場所を追加するのです。

つまり、CURVE_TIMESERIESという別のタイプのカーブを作成する必要があることは理解できましたが、それは自動的にステップを見つけ、 Xポイント間にギャップを追加してはいけません。

これは、Xを渡さずにカーブを作成した方法と似ています - そして、すべての値は均等に行く、すべては純粋に配列Xのサイズに縛られています(m_xmax = m_size-1; m_xmin = 0.0; )。

 
o_O:

ロマン・コノペルコ

2つ目の問題、あるいはヒントを教えてください。

Closeの価格でラインを作成しようとしています。Xではそれに応じて、時間の配列を渡しています。しかし、問題はカーブを作成する際に、間隔を追加してしまうことです。つまり、時間を均一にして、データのない場所を追加するのです。

つまり、CURVE_TIMESERIESという別のタイプのカーブを作成する必要があることは理解できましたが、それは自動的にステップを見つけ、 Xポイント間にギャップを追加してはいけません。

これは、Xを渡さずに曲線作成を行った方法と類似しています - そして、すべての値が均等になり、すべてが純粋に配列Xのサイズに拘束されます (m_xmax = m_size-1; m_xmin = 0.0; ).

両軸のステップを内蔵アルゴリズムで自動計算します。私の理解では、最大、最小、ステップを自分で設定したいのですね。そのためには、軸のスケーリングをマニュアルモードに切り替えるとよいでしょう。

   CAxis *xAxis = graphic.XAxis();  // получаем ось X
   xAxis.AutoScale(false);          // отключаем автомасштабирование
   xAxis.Min(0);                    // указываем минимальное значение по X
   xAxis.Max(10);                   // указываем максимальное значение по X
   xAxis.DefaultStep(1);            // указываем шаг по X

もう一つ考慮すべきことは、MaxLabels 軸の値の最大許容数で、これは (Max-Min)/DefaultStep よりも大きくなければならず、さもなければステップが変更されます。

 
Roman Konopelko:

両軸のステップを内蔵アルゴリズムで自動計算します。私が理解する限り、最大、最小、ステップを自分で設定したいのですね。そのために、軸のスケーリングをマニュアルモードに切り替えることができます

maxLabels軸も考慮する必要があり、(Max-Min)/DefaultStepより大きくなければなりません、さもなければステップが変更されます。


そう、それは何かというと。

しかし、説明したように、あなたのスケールは均一です。

どう転んでも、Xスケールで、ピクセル単位で座標を狙ってるんでしょ。

まあ、時系列では無理なんですけどね。

取得するものを見る






#include <Graphics/Graphic.mqh>

//+------------------------------------------------------------------+
void OnStart()
{
        MqlRates rates[];
        CopyRates(Symbol(), Period(), 0, 100, rates);
        ArraySetAsSeries(rates, true);
        int size=ArraySize(rates);
        double arrY[], arrX[];
        ArrayResize(arrX, size); ArrayResize(arrY, size);
        for(int i=0; i<size; ++i) { arrX[i]=(double)rates[i].time; arrY[i]=rates[i].close; }
        
        CGraphic graphic;
        graphic.Create(0, "Rates", 0, 30, 30, 1600, 300);
        CCurve* curve=NULL;
        
        //curve=graphic.CurveAdd(arrY, CURVE_LINES, "Close");
        
        curve=graphic.CurveAdd(arrX, arrY, CURVE_LINES, "Close");
        CAxis *xAxis = graphic.XAxis();  // получаем ось X
        xAxis.AutoScale(false);          // отключаем автомасштабирование
        xAxis.Min(arrX[size-1]);                    // указываем минимальное значение по X
        xAxis.Max(arrX[0]);                 // указываем максимальное значение по X
        xAxis.DefaultStep(10*(arrX[0]-arrX[size-1])/size);            // указываем шаг по X
        xAxis.MaxLabels((arrX[0]-arrX[size-1])/xAxis.DefaultStep()+1);                          // число значений по оси MaxLabels должно быть больше чем (Max-Min)/DefaultStep
        
        curve.Visible(true);
        graphic.Redraw();
        graphic.Update();
}
 

で時間を渡さないと、このような動作になります。

作図が正しい



#include <Graphics/Graphic.mqh>

//+------------------------------------------------------------------+
void OnStart()
{
        MqlRates rates[];
        CopyRates(Symbol(), Period(), 0, 100, rates);
        ArraySetAsSeries(rates, true);
        int size=ArraySize(rates);
        double arrY[];
        ArrayResize(arrY, size); ArraySetAsSeries(arrY, size);
        for(int i=0; i<size; ++i) arrY[i]=rates[i].close;
        
        CGraphic graphic;
        graphic.Create(0, "Rates", 0, 30, 30, 1600, 300);
        CCurve* curve=NULL;
        
        curve=graphic.CurveAdd(arrY, CURVE_LINES, "Close");
        curve.Visible(true);
        graphic.Redraw();
        graphic.Update();
}
 
o_O:


そう、何かを得たのです。

でも、説明したように、あなたのスケールはフラットなんです。

どのように回しても、Xで拡大縮小し、ピクセル単位で座標を目指します。

まあー時系列でプロットする場合は無理でしょうけど。

取得するものを見る

軸の出力形式を変更する機能は、ほとんどの場合、実装されると思いますが、具体的にどのような形になるかは、まだはっきり言えません。

例の「土日」ですが、これは直線を形成していますね。あなたの例を検証するために、私はそれを修正し、配列のファイルへの書き込みを追加しました。

#include <Graphics/Graphic.mqh>
//+------------------------------------------------------------------+
void OnStart()
  {
   MqlRates rates[];
   CopyRates(Symbol(),Period(),0,100,rates);
   ArraySetAsSeries(rates,true);
   int size=ArraySize(rates);
   double arrY[],arrX[];
   datetime arrTime[];
   ArrayResize(arrX,size);
   ArrayResize(arrY,size);
   ArrayResize(arrTime,size);
   int handle=FileOpen("result.txt",FILE_WRITE|FILE_TXT);
   for(int i=0; i<size;++i)
     {
      arrTime[i]=rates[i].time;
      arrX[i]=(double)rates[i].time;
      arrY[i]=rates[i].close;
      string str=TimeToString(arrTime[i])+"\t"+DoubleToString(arrY[i],3)+"\n";
      FileWriteString(handle,str);

     }
   FileClose(handle);
   CGraphic graphic;
   graphic.Create(0,"Rates",0,30,30,1080,380);
   CCurve *curve=graphic.CurveAdd(arrX,arrY,CURVE_LINES,"Close");
   double min = arrX[ArrayMinimum(arrX)];
   double max = arrX[ArrayMaximum(arrX)];
   double step=(max-min)/10;
   CAxis *xAxis = graphic.XAxis();           // получаем ось X
   xAxis.AutoScale(false);                   // отключаем автомасштабирование
   xAxis.Min(min);                           // указываем минимальное значение по X
   xAxis.Max(max);                           // указываем максимальное значение по X
   xAxis.DefaultStep(step);                  // указываем шаг по X
   curve.Visible(true);
   graphic.Redraw();
   graphic.Update();
  }

そしてOpenOfficeでプロットした。

このグラフも直線を含んでいるので、データ(配列X、Y)に埋め込まれている。コメント あるようなグラフを作るには、入力データを手動で編集する必要があります(例えば、週末を削除する)。

 
Roman Konopelko:

軸の出力形式を変更する機能は実装されそうですが、具体的にどのような形で実装されるかは、はっきり言えません。

朗報です、ありがとうございます。

先ほども言いましたが、正式なビルドを待つ必要はなく、ここにテスト用のクラスを投稿してください。
 
o_O:

朗報です、ありがとうございます。

先ほども言いましたが、ビルドオフィスを待たずに、ここにテスト用のクラスを置くことができます。
これまでは、3つのフォーマットで軸のフォーマットを設定する機能を実装する予定でした。
enum ENUM_AXIS_TYPE
  {
   AXIS_TYPE_DOUBLE,
   AXIS_TYPE_DATETIME,
   AXIS_TYPE_CUSTOM,
  };
  1. AXIS_TYPE_DOUBLE - 現在使われているもので、デフォルトの設定となります。
  2. AXIS_TYPE_DATETIME - ご質問の内容は、TimeToString に基づいて行われます。
  3. AXIS_TYPE_CUSTOM -DoubleToStringFunction へのポインタに基づいた任意の出力を可能にします。
    typedef string(*DoubleToStringFunction)(double);

念のため、添付ファイルにはライブラリの全ファイルを入れておきました。

servicedeskへのメッセージについてですが、確かにX配列には土日がありません。だから、データを修正する必要があるとは正しく言っていないのです。

しかし、AXIS_TYPE_CUSTOMを使用することで、問題を解決することができます。

#include <Graphics/Graphic.mqh>
double arrX[];
double arrY[];
//---
string TimeFirmat(double x)
  {
   return(TimeToString((datetime)arrX[ArraySize(arrX)-(int)x-1]));
  }
//+------------------------------------------------------------------+
void OnStart()
  {
   MqlRates rates[];
   CopyRates(Symbol(),Period(),0,100,rates);
   ArraySetAsSeries(rates,true);
   int size=ArraySize(rates);
   ArrayResize(arrX,size);
   ArrayResize(arrY,size);
   for(int i=0; i<size;++i)
     {
      arrX[i]=(double)rates[i].time;
      arrY[i]=rates[i].close;
     }
   CGraphic graphic;
   graphic.Create(0,"Rates",0,30,30,780,380);
   CCurve *curve=graphic.CurveAdd(arrY,CURVE_LINES,"Close");
   CAxis *xAxis=graphic.XAxis();           // получаем ось X
   xAxis.AutoScale(false);
   xAxis.Type(AXIS_TYPE_CUSTOM);
   xAxis.ValuesFunctionFormat(TimeFirmat);
   xAxis.DefaultStep(20.0);
   curve.Visible(true);
   graphic.Redraw();
   graphic.Update();
  }
//+------------------------------------------------------------------+

結果


ファイル:
Graphic.mqh  86 kb
Curve.mqh  21 kb
Axis.mqh  12 kb
 
Roman Konopelko:

しかし、AXIS_TYPE_CUSTOMを使用するだけで問題を解決することができます。

超、似合ってる!
 

Graphic.mqhのファイルをざっと見てみました。

すべての機能を仮想化 しないままにしておくことにしたのでしょうか?

OKです。

せめて ***Plot 関数 (HistogramPlot, LinesPlot, etc.) を仮想 にできないでしょうか?

その「デザイン」能力が十分でないため(塗りつぶし時のグラデーションやレンダリング時の多色化)。

 
o_O:

Graphic.mqhのファイルをざっと見てみました。

すべての機能を仮想化 しないままにしておくことにしたのでしょうか?

OKです。

せめて ***Plot 関数 (HistogramPlot, LinesPlot, etc.) を仮想 にできないでしょうか?

その「デザイン」能力が十分でないため(塗りつぶし時のグラデーションやレンダリング時の多色化)。

仮想 化しても、CGraphicsクラスのメンバに 完全にアクセスできなければ、通常のオーバーロードはできないので、すべて(ほとんど)protectedとして 宣言する必要があります。また、はっきりとは言いませんが、ほとんどの場合、両方の側面が実装されるでしょう。