
スペクトラム分析の構築
はじめに
本稿は、MQL5言語のグラフィカルオブジェクト使用が可能なバリアントを知っていただくのが目的です。グラフィカルオブジェクトを使用し、シンプルなスペクトラム分析のコントロールパネルの実装を行うインディケータを分析します。
本稿にはファイルが3つ添付されています。
- SpecAnalyzer.mq5 – 本稿で述べられているインディケータ
- SpecAnalyzer.mqh – SpecAnalyzer.mq5へのインクルードファイル
- SAInpData.mq5 – 外部データへのアクセス作成に使用するインディケータ
インディケータSpecAnalyzerを普通にロードするには、すべてのファイルをクライアント端末のフォルダ \MQL5\Indicatorsに入れます。そしてファイルSpecAnalyzer.mq5とSAInpData.mq5をコンパイルします。インディケータはメインチャートウィンドウでロードするようになっています。インディケータがロードされたら、それはウィンドウの表示パラメータを変更し、それが消去されたらすべてのグラフィカルオブジェクトがウィンドウから削除されます。端末の既存のウィンドウの表示モードを思わず変更してしまうのをさけるため、インディケータを特別にそのために作成したウィンドウに個別にロードします。
本稿にはインディケータのソースコードを網羅していないことを考慮し、本稿を読む間、添付ファイルを開いておき、そのコードを参照されることをお薦めします。
本稿で述べるインディケータはすぐに使えるアプリケーションのように見せかけていません。それは言語のグラフィカルオブジェクト使用例に過ぎません。ご興味のある方はご自身で本稿に示すコードをグレードアップし最適化することが可能です。
座標
MQL5では、グラフを描くときに2とおりの方法があります。オブジェクトによっては、座標がウィンドウの特定のポイントからピクセルで指定されていることもあります。また、ウィンドウに表示されるチャートの価格と時刻の値として指定される場合もあります。
たとえば、そのようなオブジェクトを『ラベル』または 『ボタン』としてチャートに配置するには、 チャートウィンドウの隅の一つからの距離をピクセルで指定する必要があります。オブジェクトのアドレスを指定するこの方法で、現在のウィンドウプロパティがなんであれ、オブジェクトはポジションを保持しチャートスケールがそこに表示されます。ウィンドウサイズが変わったとしても、そのオブジェクトはポジションを保持し、お互いバインディングします。マウスの左ボタンを使ってウィンドウ内のチャートを移動させると、それらオブジェクトはウィンドウで選択されたアンカーポイントに対して相対的なポジションを保持します。
その他のオブジェクトグループはウィンドウの座標の代わりにウィンドウ内のチャートにバインディングすることを意味します。これらオブジェクトは『トレンドライン』、『長方形』などです。そのようはオブジェクトを作成し、配置するときは、座標はウィンドウに表示されたチャートの時刻と価格値として指定されます。この座標指定モードにより、チャートスケールが変更されたりスクロールされるとき、オブジェクトはチャートウィンドウに対してまたお互いに相対的にポジションを変えます。チャートに新規バーが作成されると、オブジェクトもポジションを変えます。それは時間軸が時間枠サイズで左に移動するからです。
インディケータSpecAnalyzerでは、スペクトラム分析のコントロールパネルを作成するのに両タイプのグラフィカルオブジェクトが同時に使用されます。チャートに縛られウィンドウに相対的に移動しないオブジェクトには、縦軸に沿ってチャート表示をする固定モードと水平スケールに従いできる限りの最小スケールに応じて表示するモードを設定します。それに加え、縦方向の最小スケールは0.0に設定されており、水平軸に右端からゼロバーの移動がなくチャートの右端へ自動スクロールがないモードを設定します。ゼロバーとチャートの0.0値に一する座標ポイントは右下に表示され、固定スケールを伴い、『トレンドライン』や『長方形』などのオブジェクトのアンカーポイントとして使用することが可能です。そこで、アンカーポイント と同じオブジェクトの右下隅に『ラベル』または『ボタン』を設定したら、両タイプのオブジェクトは確実にお互いを縛りあいます。
必要なチャートのプロパティはすべて、SpecAnalyzer.mqhファイルの関数SetOwnProperty() に設定されます。
void GRaphChart::SetOwnProperty(void) { ChartSetInteger(m_chart_id,CHART_FOREGROUND,1); ChartSetInteger(m_chart_id,CHART_SHIFT,0); ChartSetInteger(m_chart_id,CHART_AUTOSCROLL,0); ChartSetInteger(m_chart_id,CHART_AUTOSCROLL,1); ChartSetInteger(m_chart_id,CHART_SCALE,0); ChartSetInteger(m_chart_id,CHART_SCALEFIX_11,1); ChartSetInteger(m_chart_id,CHART_SHOW_OHLC,0); ChartSetInteger(m_chart_id,CHART_SHOW_BID_LINE,0); ChartSetInteger(m_chart_id,CHART_SHOW_ASK_LINE,0); ChartSetInteger(m_chart_id,CHART_SHOW_LAST_LINE,0); ChartSetInteger(m_chart_id,CHART_SHOW_PERIOD_SEP,0); ChartSetInteger(m_chart_id,CHART_SHOW_GRID,0); ChartSetInteger(m_chart_id,CHART_SHOW_VOLUMES,CHART_VOLUME_HIDE); ChartSetInteger(m_chart_id,CHART_SHOW_OBJECT_DESCR,0); ChartSetInteger(m_chart_id,CHART_SHOW_TRADE_LEVELS,0); ChartSetInteger(m_chart_id,CHART_COLOR_BACKGROUND,Black); ChartSetInteger(m_chart_id,CHART_COLOR_FOREGROUND,Black); ChartSetDouble(m_chart_id,CHART_FIXED_MIN,0.0); }
グラフィカルオブジェクトのバインディングを行うため必要なチャートのプロパティ設定に加え、この関数は色の割当てとチャート上のエレメント表示を制約するプロパティを設定します。
インディケータSpecAnalyzerが動作中チャートのプロパティを変更するので、インディケータのロード中チャートの設定を保存し、アンロード中設定を復元する必要があります。MQL5の標準ライブラリにはその目的のための特別なバーチャル関数が含まれています。 - CChartクラスのSave()関数およびLoad()関数です。これら関数はCChartクラスのオブジェクトプロパティを保存し、作成されたファイルからそれらを復元します。保存されたプロパティの設定を変更、チャートのプロパティ保存時にファイル処理を避けるために、新規クラスGRaphChart作成時、CChartクラスのバーチャル関数Save()およびLoad()がオーバーライドされます。(ファイル SpecAnalyzer.mqh参照)
class GRaphChart : public CChart { protected: struct ChartPropertyes { double shift_size; double fixed_max; double fixed_min; double points_per_bar; long mode; bool foreground; bool shift; bool autoscroll; long scale; bool scalefix; bool scalefix_11; bool scale_pt_per_bar; bool show_ohls; bool show_bid_line; bool show_ask_line; bool show_last_line; bool show_period_sep; bool show_grid; long show_volumes; bool show_object_descr; bool show_trade_levels; long color_background; long color_foreground; long color_grid; long color_volume; long color_chart_up; long color_chart_down; long color_chart_line; long color_candle_bull; long color_candle_bear; long color_bid; long color_ask; long color_last; long color_stop_level; string ch_comment; }; ChartPropertyes ChProp; public: GRaphChart(); ~GRaphChart(); void SetOwnProperty(); virtual void Save(); virtual void Load(); };
GRaphChart の基本クラスはMQL5標準ライブラリのCChartです。クラスGRaphChartはChartPropertyesストラクチャの記述を含み、ChPropオブジェクトの作成により、基本クラスに実装されているとおりファイルの代わりにメモリにチャートプロパティを格納します。Save() 関数はチャートの現在のプロパティに応じたデータでストラクチャChPropを埋め、Load()関数がそこから以前に保存されたプロパティを復元します。
関数Save() はGRaphChart クラスのコンストラクタに呼ばれ、関数 Load() がそのデストラクタに呼ばれます。それがGRaphChartクラスのオブジェクトを作成し削除するとき、前のチャート状態を自動的に保存し復元する理由です。上述のSetOwnProperty() はまたクラスコンストラクタ内でも呼ばれます。
//---------------------------------------------------- Constructor GRaphChart -- GRaphChart::GRaphChart() { m_chart_id=ChartID(); Save(); // Keep a original chart settings SetOwnProperty(); // Set own chart settings } //----------------------------------------------------- Destructor GRaphChart -- GRaphChart::~GRaphChart() { Load(); // Restore a previous chart settings m_chart_id=-1; }
簡単な例を使ってクラスGRaphChart を見ていきます。そのために、MetaEditorに新しいカスタムインディケータを作成し、それを『テスト』と名づけます。ヘッダファイルSpecAnalyzer.mqhをインディケータコードにインクルードし、2行追加することでGRaphChart クラスのオブジェクトを作成します。
//+------------------------------------------------------------------+ //| Test.mq5 | //| Copyright 2010, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "2010, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" #property indicator_chart_window #include "SpecAnalyzer.mqh" // <----- Including header file GRaphChart MainChart; // <----- Creating object of the class GRaphChart //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping //--- return(0); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[], const double& open[], const double& high[], const double& low[], const double& close[], const long& tick_volume[], const long& volume[], const int& spread[]) { //--- //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+
上記コードを問題なくコンパイルするために、SpecAnalyzer.mqh ファイルをクライアント端末のフォルダ \MQL5\Indicatorsに配置する必要があります。
クライアント端末にチャートを作成し、われわれの検証サンプルをこそにロードしようとしたら、チャートプロパティは変更されてしまい。グラフィカルオブジェクトを表示するための空のウィンドウしか出ません。テストインディケータをチャートから消去したら、新規ティックの到着とともに最初の姿が復元されるのです。
インディケータSpecAnalyzerに話を戻します。インディケータの最初では(ファイルSpecAnalyzer.mq5を参照ください。)、クラスGRaphChartのオブジェクトMainChart が作成されました。それによりインディケータのロードとチャートプロパティの保存ができるようになります。
button. button. button.
GRaphChart MainChart; // Create MainChart object
button. button. button.
インディケータをアンロードするときは、オブジェクトMainChartは自動的に終了され、チャートの最初のプロパティがクラスデストラクタに復元されます。
コントロールパネル
インディケータSpecAnalyzer内のコントロールパネルの外観はウィンドウに配置されたグラフィカルオブジェクトによって決定されます。AllGrObject クラスが作成とそれらとの連携に必要なすべての関数をまとめます。ファイルSpecAnalyzer.mqhを参照ください。
class AllGrObject : public CChart { protected: long m_chart_id; // chart identifier public: AllGrObject(); ~AllGrObject(); void AddLabel(string name,int fsize,string font, color col,int x,int y,string text=""); void AddButton(string name,int xsize,int ysize,color bgcol, int fsize,string font,color col,int x,int y, string text="",int state=0); void AddEdit(string name,int xsize,int ysize,color bgcol,int fsize, string font,color col,int x,int y,string text=""); void AddTrendLine(string name,color col,int style=0,int width=1); void AddArrowline(string name,color col,int style=0,int width=1); void AddRectangle(string name,color col,int style=0,int width=1); void MoveGrObject(string name,int x1,int y1,int x2,int y2); void SetButtonProp(string name,bool state,color col); long GetRowNumber(string name); void LabelTxt(string name,string str); };
名前が 'Add' から始まるクラス関数、はグラフィカルオブジェクト作成をします。たとえばAddButton() はオブジェクト『ボタン』を作成します。
アプリケーションでは、すべてのグラフィカルオブジェクトの座標はチャートの右下隅からの距離をピクセルで設定されています。オブジェクト『トレンドライン』、『矢印線』、 『長方形』には、そのような座標を時刻と価格の値に変換する必要があります。そのような変換はオブジェクトに座標を割り当てる前にMoveGrObject() 関数で行われます。一つの水平ピクセルが一つのバーに対応し、一つの垂直ピクセルが一つのポイントに対応します。
void AllGrObject::MoveGrObject(string name,int x1,int y1,int x2,int y2) { datetime t1[1],t2[1]; long typ; typ=ObjectGetInteger(m_chart_id,name,OBJPROP_TYPE); if(typ==OBJ_TREND||typ==OBJ_ARROWED_LINE||typ==OBJ_RECTANGLE) { CopyTime(_Symbol,_Period,x1,1,t1); CopyTime(_Symbol,_Period,x2,1,t2); ObjectSetInteger(m_chart_id,name,OBJPROP_TIME,0,t1[0]); ObjectSetDouble(m_chart_id,name,OBJPROP_PRICE,0,_Point*y1); ObjectSetInteger(m_chart_id,name,OBJPROP_TIME,1,t2[0]); ObjectSetDouble(m_chart_id,name,OBJPROP_PRICE,1,_Point*y2); } }
すべてのグラフィカルオブジェクトはインディケータ内で一度だけ作成され、インディケータの関数OnInit()からgr_object_create() を呼ぶときにそれは行われます。ファイルSpecAnalyzer.mq5を参照ください。オブジェクト『トレンドライン』、『矢印線』、 『長方形』以外のすべてのオブジェクトについて、座標はすぐに設定されます。『トレンドライン』、『矢印線』、 『長方形』のようなオブジェクトについては、座標は上述のMoveGrObject()関数を使うgr_object_coordinate() 関数を呼ぶことで設定されますそれによりアドレス設定モードが変換します。
void gr_object_coordinate() { GObj.MoveGrObject("Trdline1",48,150,48,360); GObj.MoveGrObject("Trdline2",176,150,176,360); GObj.MoveGrObject("Trdline3",304,150,304,360); GObj.MoveGrObject("Trdline4",432,150,432,360); GObj.MoveGrObject("Trdline5",42,350,560,350); GObj.MoveGrObject("Trdline6",42,300,560,300); GObj.MoveGrObject("Trdline7",42,250,560,250); GObj.MoveGrObject("Trdline8",42,200,560,200); GObj.MoveGrObject("Arrline1",560,150,28,150); GObj.MoveGrObject("Arrline2",560,150,560,370); GObj.MoveGrObject("Rect1",0,1,208,110); GObj.MoveGrObject("Rect2",208,1,416,110); GObj.MoveGrObject("Rect3",416,1,624,110); GObj.MoveGrObject("Rect4",0,1,624,400); GObj.MoveGrObject("Rect5",20,10,195,80); }
関数gr_object_coordinate() の呼び出しはインディケータの関数OnCalculate()にインクルードされています。それはチャート上に新規バーが作成されると座標の再計算を行います。これは、関数が新規ティックの到来のたびに呼ばれるためです。
インディケータパネルのボタンは3つのグループに分けられます。最初のグループは左にある4つのボタンを構成します。それらによりインディケータによる入力シーケンスのスペクトラム見積結果表示モードを選択することができます。4つの表示モードがサポートされています(ボタンの番号に従い)。
- Amplitude/Line - Y 軸に沿った均等メモリにおけるフーリエ変換モジュールを表示します。
- Amplitude/Line - Y 軸に沿った対数尺度におけるフーリエ変換モジュールを表示します。
- Amplitude/Line - Y 軸に沿った均等メモリにおけるフーリエ変換モジュールの二乗を表示します。
- Amplitude/Line - Y 軸に沿った対数尺度におけるフーリエ変換モジュールの二乗を表示します。
このグループのボタンのクリック処理をおこなうには、以下のコードがインディケータのOnChartEvent()関数にインクルードされます。
if(id==CHARTEVENT_OBJECT_CLICK) // Click on the gr. object { if(sparam=="Butt1") // Click on the button { GObj.SetButtonProp("Butt1",1,Chocolate); GObj.SetButtonProp("Butt2",0,SlateGray); GObj.SetButtonProp("Butt3",0,SlateGray); GObj.SetButtonProp("Butt4",0,SlateGray); YPowerFlag=0;YdBFlag=0; } if(sparam=="Butt2") // Click on the button { GObj.SetButtonProp("Butt1",0,SlateGray); GObj.SetButtonProp("Butt2",1,Chocolate); GObj.SetButtonProp("Butt3",0,SlateGray); GObj.SetButtonProp("Butt4",0,SlateGray); YPowerFlag=0;YdBFlag=1; } if(sparam=="Butt3") // Click on the button { GObj.SetButtonProp("Butt1",0,SlateGray); GObj.SetButtonProp("Butt2",0,SlateGray); GObj.SetButtonProp("Butt3",1,Chocolate); GObj.SetButtonProp("Butt4",0,SlateGray); YPowerFlag=1;YdBFlag=0; } if(sparam=="Butt4") // Click on the button { GObj.SetButtonProp("Butt1",0,SlateGray); GObj.SetButtonProp("Butt2",0,SlateGray); GObj.SetButtonProp("Butt3",0,SlateGray); GObj.SetButtonProp("Butt4",1,Chocolate); YPowerFlag=1;YdBFlag=1; }
ボタンのひとつがクリックされたのを検出すると、他のボタンの状態が「押下なし」に変更されます。これにより同一グループ内で複数のボタンが同時に押されるのを防ぎます。同時に、対応する値が表示の現在モードを判断するフラグYPowerFlag および YdBFlag に設定されます。
4つのボタンを構成する二番目のグループには入力データのソースを選択する機能があります。それは外部データでSAInpData.mq5インディケータを呼ぶか、アプリケーションに自身によって生成される3回の検証手順によって取得されます。最後のボタングループは検証情報入力フィールドのリストをスクロールするおに使う2つのボタンをインクルードします。これらボタンすべてのクリック操作はまた最初のグループのボタン操作と全く同じインディケータの関数OnChartEvent()内でお粉されます。ファイルSpecAnalyzer.mq5を参照ください。
前に作成したテストインディケータTest.mq5.を使用し、クラスAllGrObjectを使って例を示してみます。そのためには、ソースコードに数行追加し、ファイルSpecAnalyzer.mq5から以前に述べられた関数gr_object_create() およびgr_object_coordinate() をインクルードします。
//+------------------------------------------------------------------+ //| Test.mq5 | //| Copyright 2010, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "2010, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" #property indicator_chart_window #include "SpecAnalyzer.mqh" GRaphChart MainChart; AllGrObject GObj; // <----- Creating object of the class AllGrObject //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping //--- gr_object_create(); // <----- creating graphical objects return(0); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[], const double& open[], const double& high[], const double& low[], const double& close[], const long& tick_volume[], const long& volume[], const int& spread[]) { //--- MainChart.SetOwnProperty(); // <----- restoring current properties of the chart gr_object_coordinate(); // <----- setting coordinates for the graphical objects //--- return value of prev_calculated for next call return(rates_total); } //----------------------------------------------- Create all graphical objects -- void gr_object_create() { GObj.AddLabel("Title",10,"Arial",DarkGray,256,367,"Spectrum Analyzer"); GObj.AddLabel("Label1",9,"Arial",LightSteelBlue,557,128,"0"); GObj.AddLabel("Label2",9,"Arial",LightSteelBlue,422,128,"128"); GObj.AddLabel("Label3",9,"Arial",LightSteelBlue,294,128,"256"); GObj.AddLabel("Label4",9,"Arial",LightSteelBlue,166,128,"384"); GObj.AddLabel("Label5",9,"Arial",LightSteelBlue,40,128,"512"); GObj.AddLabel("Label6",9,"Arial",LightSteelBlue,28,156,"N"); GObj.AddLabel("Label7",9,"Arial",LightSteelBlue,569,141,"0.00"); GObj.AddLabel("Label8",9,"Arial",LightSteelBlue,569,191,"0.25"); GObj.AddLabel("Label9",9,"Arial",LightSteelBlue,569,241,"0.50"); GObj.AddLabel("Label10",9,"Arial",LightSteelBlue,569,291,"0.75"); GObj.AddLabel("Label11",9,"Arial",LightSteelBlue,569,341,"1.00"); GObj.AddLabel("Label12",9,"Arial",LightSteelBlue,569,358,"U"); GObj.AddLabel("Label13",9,"Arial",DarkGray,490,86,"Y-axis Mode"); GObj.AddLabel("Label14",9,"Arial",DarkGray,285,86,"Input Data"); GObj.AddLabel("Label15",9,"Arial",DarkGray,75,86,"Level"); GObj.AddLabel("Label16",9,"Arial",DarkGray,185,86,"N"); GObj.AddLabel("Label17",8,"Courier",DarkOliveGreen,64,64); GObj.AddLabel("Label18",8,"Courier",DarkOliveGreen,64,51); GObj.AddLabel("Label19",8,"Courier",DarkOliveGreen,64,38); GObj.AddLabel("Label20",8,"Courier",DarkOliveGreen,64,25); GObj.AddLabel("Label21",8,"Courier",DarkOliveGreen,64,12); GObj.AddButton("Butt1",185,18,C'32,32,32',8,"Arial",SlateGray,612,79,"Amplitude (line)",0); GObj.AddButton("Butt2",185,18,C'32,32,32',8,"Arial",Chocolate,612,61,"Amplitude (log)",1); GObj.AddButton("Butt3",185,18,C'32,32,32',8,"Arial",SlateGray,612,43,"Power (line)",0); GObj.AddButton("Butt4",185,18,C'32,32,32',8,"Arial",SlateGray,612,25,"Power (log)",0); GObj.AddButton("Butt5",185,18,C'32,32,32',8,"Arial",SlateGray,403,79,"External Data",0); GObj.AddButton("Butt6",185,18,C'32,32,32',8,"Arial",SlateGray,403,61,"Test 1. SMA(3)",0); GObj.AddButton("Butt7",185,18,C'32,32,32',8,"Arial",Chocolate,403,43,"Test 2. SMA(32)",1); GObj.AddButton("Butt8",185,18,C'32,32,32',8,"Arial",SlateGray,403,25,"Test 3. LWMA(12)",0); GObj.AddButton("Butt9",14,34,C'32,32,32',8,"Wingdings",SlateGray,36,78,"\x0431",0); GObj.AddButton("Butt10",14,34,C'32,32,32',8,"Wingdings",SlateGray,36,44,"\x0432",0); GObj.AddEdit("Edit1",35,18,Black,9,"Arial",SlateGray,180,102); GObj.AddTrendLine("Trdline1",C'32,32,32'); GObj.AddTrendLine("Trdline2",C'32,32,32'); GObj.AddTrendLine("Trdline3",C'32,32,32'); GObj.AddTrendLine("Trdline4",C'32,32,32'); GObj.AddTrendLine("Trdline5",C'32,32,32'); GObj.AddTrendLine("Trdline6",C'32,32,32'); GObj.AddTrendLine("Trdline7",C'32,32,32'); GObj.AddTrendLine("Trdline8",C'32,32,32'); GObj.AddArrowline("Arrline1",LightSteelBlue); GObj.AddArrowline("Arrline2",LightSteelBlue); GObj.AddRectangle("Rect1",C'72,72,72'); GObj.AddRectangle("Rect2",C'72,72,72'); GObj.AddRectangle("Rect3",C'72,72,72'); GObj.AddRectangle("Rect4",DarkGray); GObj.AddRectangle("Rect5",C'72,72,72'); } //---------- Set object coordinate for Trend Line, Arroved Line and Rectangle -- void gr_object_coordinate() { GObj.MoveGrObject("Trdline1",48,150,48,360); GObj.MoveGrObject("Trdline2",176,150,176,360); GObj.MoveGrObject("Trdline3",304,150,304,360); GObj.MoveGrObject("Trdline4",432,150,432,360); GObj.MoveGrObject("Trdline5",42,350,560,350); GObj.MoveGrObject("Trdline6",42,300,560,300); GObj.MoveGrObject("Trdline7",42,250,560,250); GObj.MoveGrObject("Trdline8",42,200,560,200); GObj.MoveGrObject("Arrline1",560,150,28,150); GObj.MoveGrObject("Arrline2",560,150,560,370); GObj.MoveGrObject("Rect1",0,1,208,110); GObj.MoveGrObject("Rect2",208,1,416,110); GObj.MoveGrObject("Rect3",416,1,624,110); GObj.MoveGrObject("Rect4",0,1,624,400); GObj.MoveGrObject("Rect5",20,10,195,80); } //+------------------------------------------------------------------+
AllGrObject クラスにアクセルするためには、このクラスのGObj オブジェクトを作成します。インディケータのOnInit() 関数はgr_object_create() 関数の呼び出しをインクルードします。これでインディケータコントロールパネルの外観と機能性を決定する必要なグラフィカルオブジェクをすべて作成します。
関数OnCalculateにおいて、関数 MainChart.SetOwnProperty() と gr_object_coordinate()の呼び出しを追加します。チャートプロパティとそこに描かれるオブジェクトの座標はティックの到来ごとに復元されることになります。そのような復元は、最初のチャートに新規バーが作成されるとき、マウスの左ボタンを使ってチャートが移動されるとき、またはユーザーがチャートプロパティを変更するとき要求されます。このテストレイをコンパイルロードしたら、コントロールパネルのインターフェースを確認します。図1を参照ください。
図1 コントロールパネルのインターフェース
視覚的に説明するために、コントロールパネルの位置はチャートにたいして相対位置とし、上図例ではチャートスケールが表示できるようになっています。図2を参照ください。
図2 チャートスケール
スペクトラム分析
インディケータのスペクトラム分析は入力シーケンスの1024 グラジュエ―ションによって行われます。スペクトラム分析は高速フーリエ変換 アルゴリズムを使って行われます。 FFT アルゴリズムを導入する関数は www.mql4.com ウェブサイトの公表文献から入手します。計算には入力リアルタイムシーケンスの FFT 関数を使用します。そのコードはファイルSpecAnalyzer.mqhにあります。スペクトラム分析に要求される処理はすべ fft_calc() 関数に実装されています。
void fft_calc() { int i,k; realfastfouriertransform(InpData,ArraySize(InpData),false); // FFT for(i=1;i<ArraySize(Spectrum);i++) { k=i*2; Spectrum[i]=InpData[k]*InpData[k]+InpData[k+1]*InpData[k+1]; } Spectrum[0]=0.0; // Clear constant component level }
fft_calc() 関数が呼ばれるとInpData[] 配列が分析をするための入力シーケンスを取り込みます。realfastfouriertransform() が実行されると、FFT の結果がその配列に入れられます。その後、スペクトラムの現実部分と仮想部分の概算から各調波についてモジュロの二乗が計算されます。結果は配列Spectrum[]に書かれます。Spectrum[] 配列のエレメント指数は調波ナンバーに対応しています。定数成分の計算値はインディケータでは使用されないので、ゼロ値が常に配列の Spectrum[0] エレメントに割り当てられます。
変数 InputSourceの値に応じて、配列InpData[] には検証手順または外部インディケータから取得したデータの書き込みが行われます。入力データは get_input_data() 関数によって作成されます。
void get_input_data() { int i; ArrayInitialize(InpData,0.0); switch(InputSource) { case 0: // External Data if(ExtHandle!=INVALID_HANDLE) CopyBuffer(ExtHandle,0,0,ArraySize(InpData),InpData); break; case 1: // Test 1. SMA(3) for(i=0;i<3;i++)InpData[i]=1; break; case 2: // Test 2. SMA(32) for(i=0;i<32;i++)InpData[i]=1; break; case 3: // Test 3. LWMA(12) for(i=0;i<12;i++)InpData[i]=12-i; break; } }
InputSourceの値がゼロであれば、1024 値は arraySAInpData.mq5インディケータのゼロバッファから入力配列 InpData[] にコピーされます。分析用データはインディケータ内部またはそこから他のインディケータを呼ぶことで作成できます。インディケータSAInpData.mq5にアクセスするには、OnInit() 関数に以下の行を追加します。それは ExtHandle 変数の値を決定します。
int OnInit() { button. button. button. ExtHandle=iCustom(NULL,0,"SAInpData"); // External indicator Handle return(0); }
インディケータ SAInpData.mq5はクライアント端末のディレクトリ \MQL5\Indicators に配置する必要があります。例として本稿に添付されているインディケータ SAInpData.mq5 はアナライザにランダムなシーケンスを渡します。SAInpData.mq5 を作成するには、アナライザに別のシーケンスを渡し、そのソースコードを変更します
関数 get_input_data()の検証シーケンスとして、移動平均 SMA(3)、 SMA(32)、 LWMA(12) のインパルス特性が生成されます。フィルターのインパルス特性のフーリエ変換はフィルターの振幅周波数特性に対応していることを考慮しながら、検証シーケンスとして選択した場合は、振幅周波数特性を見守ることができます。
Spectrum[] 配列に格納されたスペクトラム概算結果を正常化し、特定モードで表示することを準備するには、norm_and_draw()関数が使われます。ファイルSpecAnalyzer.mq5を参照ください。選択された表示モードによって、この関数は Y 軸にマークしているテキストを置き換えます。
入力シーケンスのスペクトラム概算結果はグラフ形式だけでなくテキスト形式でも表示されます。テキスト形式で表現するには、『ラベル』タイプの5つのグラフィカルオブジェクトが作成されます。それらは表示のテキスト行5行に対応しています。関数list_levels() performsがこれらの行に情報を書き込みます。
void list_levels() { int m; string str; if(YdBFlag==0) str="%3u %.5f"; // If Y-axis mode = Line else str="%3u %6.1f dB"; // If Y-axis mode = dB m=ArraySize(ListArray)-5; if(ListPointer<1)ListPointer=1; if(ListPointer>m)ListPointer=m; GObj.LabelTxt("Label17",StringFormat(str,ListPointer,ListArray[ListPointer])); GObj.LabelTxt("Label18",StringFormat(str,ListPointer+1,ListArray[ListPointer+1])); GObj.LabelTxt("Label19",StringFormat(str,ListPointer+2,ListArray[ListPointer+2])); GObj.LabelTxt("Label20",StringFormat(str,ListPointer+3,ListArray[ListPointer+3])); GObj.LabelTxt("Label21",StringFormat(str,ListPointer+4,ListArray[ListPointer+4])); }
その行は StringFormat()関数を用いてフォーマットされた配列ListArray[] からレベル値を表示します。表示の現在モードによって、この配列は norm_and_draw() 関数の内部に情報を書き込みます。ファイルSpecAnalyzer.mq5を参照ください。配列 ListArray[] の情報が表示されます。それは ListPointer 変数に格納される値に等しい配列インデックスから始まるものです。ListPointer 変数の値を変更することができます。それにより表示される行のインデックスの始まりも変更可能です。それはアウトプットフィールドの右側にあるボタンを押すか、インプットフィールドに必要なインデックスを指定することでできます。これらボタンを押すこととエントリーフィールド上での変更を終えることに関連したイベントはインディケータの OnChartEvent() 関数で行われます。これについてはファイルSpecAnalyzer.mq5を参照ください。
インディケータSpecAnalyzer は下記の図に表示されています。
図3 インディケータ SpecAnalyzerの外観
おわりに
すでに述べたとおり、インディケータSpecAnalyzer.mq5 は完全なスペクトラム分析のプロトタイプにしか過ぎません。本稿ではグラフィカルオブジェクトを使用する例として使っています。完全なインディケータを作成するには、もっと体裁を整え、関数インターフェースをもっと実装し、スペクトラム概算のアルゴリズムを改善する必要があります。
グラフィカルオブジェクト"Bitmap"を装飾に使用し、グラフィカルエディタのフロントコントロールパネルの画像を作成し、それを コントロールエレメントが表示されるアンダーレイヤーとして使ことでインディケータインターフェースを劇的に良くすることができます。そのようは方法は変更可能スキンを用いたインディケータを作成することで実現可能です。
文献
- 佐藤幸夫 シグナル処理入門
- L. Rabiner, B. Gold Theory and Application of Digital Signal Processing.
- S.L. Marple, Jr. Digital Spectral Analysis with Applications.
ファイル
- SpecAnalyzer.mq5 – 本稿で述べられているインディケータ
- SpecAnalyzer.mqh – SpecAnalyzer.mq5へのインクルードファイル
- SAInpData.mq5 – 外部データへのアクセス作成に使用するインディケータ
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/185





- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索