プライスヒストグラム(マーケット特性)とMQL5への導入

Dmitry Voronkov | 2 10月, 2015

「マーケットプロファイルはマーケットの概念にこの内部ロジックを提供しようとする。
それは以下を理解することから始まる分析方法である。価格だけでは
マーケット参加者に情報を伝えない。それは
文脈のない
ただの言葉のようだ。また、文脈は何の意味も持ちえないかもしれない。出来高がマーケットの直接表現に不可欠の部分である。
このことを理解すれば、マーケット言語を理解できるようになる。」
ロビン・メッシュ


はじめに

ずいぶん以前になりますが、定期購読していた雑誌を読んでいて"Valutny Spekulant"(現在名"Active Trader")というロシアのジャーナルに "Market Profile and understanding the market language"(2002年10月号)という記事を見つけました。原文は"New Thinking in Technical Analysis: Trading Models from the Masters"に掲載されていました。

「マーケットプロファイル」は非常に優秀な思索家、 ピーター・スタイドルマイヤー氏によって展開されました。氏はマーケット(ボリューム)の自然な表現を発見し、それを判読可能な方法(釣鐘曲線)にまとめました。それによりマーケットによって生成された客観的な情報がマーケット参加者からアクセス可能となったのです。スタイドルマイヤー氏は全く異なるモデルセットに導く『水平的な』また『垂直的な』マーケットの動きに関する情報の別の解釈の仕方を提案しました。潜在するマーケットの拍動、または均衡と不均衡の周期と呼ばれる基本パターンがある、と仮定したのです。

「マーケットプロファイル」は、垂直なマーケットの動きを通じて水平な動きを計測します。それを、『不均衡』を通じた『均衡』と呼びましょう。この関係は基礎的なマーケットの組織化原理です。トレーダーの総括的なトレードスタイルは、マーケットが均衡/不均衡のどの部分にあるかによって変わる可能性があります。「マーケットプロファイル」は、マーケットが均衡から不均衡へ移動する時期と、その動きの大きさを決定しうるものです。

以下はマーケットプロファイルの二大概念です。

  1. マーケットはオークションであり、供給と需要がある程度一致している価格帯の方向に移動する。
  2. マーケットには二つの局面がある。すなわち、水平活動と垂直活動である。マーケットは、供給と需要が等しくないまたは不均衡のとき垂直に動きます。そして、供給と需要の均衡がとれているまたは安定していると水平に動きます。

下記の表にある「マーケットプロファイル」を使って表される平衡マーケットは、グラフの方向により90°回転した形になっていますが、完璧と言ってよいほどの釣鐘曲線を描く傾向にあります。

図1 平衡マーケットの「マーケットプロファイル」

傾向として、不均衡マーケットも釣鐘曲線を描きますが、中心が上か下にずれています。その他価格の動きとマーケット参加者の確実性により、鐘のてっぺんを二つ描く構成もあり得ます。

図2 不均衡(傾向)マーケットのマーケットプロファイル

マーケットの均衡/不均衡の程度を決定するのに日々のプロファイルの型を使うのも有用です。というのも、多くのマーケット参加者の間で起こる変化を理解する出発点を与えてくれるからです。

最大利益のチャンスはバランスが取れているところからバランスが崩れかけるところに起こります。それ以上に、取引チャンスをとらえ、変化の潜在的大きさを正確に推定できるなら、その取引の質とそれに必要な合計時間を判断することができます。

本記事では、「マーケットプロファイル」のシンプル版、すなわち価格と時間の関連に基づいた「プライスヒストグラム」と呼ばれるものを描くコードについて考察していきます。

このツールを用いて作業をする方法論の例はhttp://www.enthios.com/にてご覧いただけます。これはトレーダーのグループが1998年から「プライスヒストグラム」を学習している場です。Enthios Universal戦略と使用例もここで見ることができます。


1. プライスヒストグラム

「プライスヒストグラム」はたいへん信頼性の高いツールです。やや直感的ですが、極端に効果的です。プライスヒストグラムは、マーケットにおける「もっとも都合のよい」トレーディングポイントをわかりやすく示してくれます。どの時点でマーケットの方向性が変わるかを前もって示してくれる先行指標です。移動平均やオシレーター指標は、レジスタンスやサポートの正確なポイントを示すことはできません。ただ、マーケットが買い過ぎか売り過ぎか、事実を示せるにすぎません。

通常プライスヒストグラム(または マーケットプロファイル )は30分の価格グラフに適用し、1日のマーケットの動向を観察します。私は株式相場には5分グラフを、FOREXグラフには15~30分を使うのが好ましいと思っています。


2. コントロールポイント

上図では、マーケットが最大の時間で取引されたレベルを見ることができます。このヒストグラムでは、最も長い線で表されています。それはコントロールポイントまたはPOCと呼ばれます。上図に見られるように、ヒストグラムが2点最高点を示すことがあり、片方はやや低くなっています。その場合、インディケーターがPOCを1つだけ示していますが、実はPOCは2つあるのです。その点を考慮する必要があります。

また、ヒストグラム領域のパーセントレベルも追加のレベルを作成します。これはPOC 第二レベルと呼ばれるものです。

図3 コントロールポイント

POCが示すものは?トレーダーの多くが覚えている価格です。ロンガーマーケットがこの価格で取引されます。ロンガーマーケットはそれを記憶します。

心理的にPOCは引力の中心のようなふるまいをします。

次の図が示すのは、数日前に起こった事柄です。「プライスヒストグラム」の力をよく示しています。

コントロールポイントは絶対ではなく、トレードの範囲を示しているにすぎません。

図4 コントロールポイントは絶対ではなく、トレードの範囲を示しているにすぎません。

コントロールポイントは絶対ではなく、トレードの範囲を示しているにすぎません。そのためトレーダーはマーケットがPOCに近づくとき、行動をおこせるよう備える必要があります。これまでの経過を観察することは、注文を最適化するのに役立ちます。

図4について考察してみましょう。2009年12月29日の POC は価格68.87に位置しています。ヒストグラムやPOCラインがなくても、マーケットは一日中68.82~68.96の範囲にあったということは明らかです。その日の終わり、マーケットはPOCから5ポイント低いところでクローズしました。翌日、差分下がったところでマーケットがオープンしています。

マーケットが上がるか下がるか予言することはできない、ということを理解しておくのは重要です。マーケットは POCラインまたヒストグラムラインの最大集積まで戻ってくる、ということが予想できるだけです。しかし、価格が POCに接触すると何がおこるのでしょうか?ゴム状の物体が地面に落下したときと同じことが起こります。跳ね返って戻るのです。それはすばやく起こります。ラケットで打ち返されたテニスボールのような感じです。価格はすぐに最初のレベルにもどるのです。

2009年12月30日にマーケットがオープンした後には差異が見られます。そして、マーケットは前日のPOCに接触し、その後迅速に始値に戻し、最低値を更新します。

Note that POCは絶対的に正確なものではありません。(経験あるトレーダーなら価格が最高値、最低値、集中域に達するきに明確なレジスタンスレベルなどないことを承知しています。)この時点で何が起こるかということは、マーケット参加者によるのです。包括的な買い要望(新銘柄が出たなど)が同時期に起これば、マーケットはPOCを越えますが、そういうことは滅多になく、そういう事例はトレーディングシステム開発に使われることはありえます。

マーケットの動きは2009年12月31日と同じだということに注目しましょう。価格が POCに接触すると、買い手は売り手に譲ります。


3. バージンコントロールポイント

バージンPOC(バージンコントロールポイント)とは、その後の数日間、価格が到達していないレベルです。

ロジックは単純です。上述のようにPOCはマーケットを引きつけるポイントです。価格がPOCから遠ざかると、引き付ける力は増します。価格がバージンPOCから遠ざかるほど、このレベルに戻る際に起こるリバウンドは大きい可能性があり、価格の逆行も起こる可能性があります。

図5 以前のバージンPOCと現在のバージンPOC

図5において、サポートレベルとレジスタンスレベルだった過去のバージンPOCは丸で囲われています。今も有効なバージンPOCには価格値が入っています。

価格がバージン POCに到達すると、もはや『バージン』ではなくなります。心理的には、マーケットはもはやそれをサポートやレジスタンスレベルの代用とはみなしません。トレーダーはまだ価格レベルを見ることができますが、それはそもそもPOCを形

成したもので、単純な価格の集積にしかすぎません。価格レベルに関してはEric Naiman著"Master-trading: The X-Files"(第4章"Price Level is a base line")で詳しく知ることができます。


4. MQL5へのプライスヒストグラム導入

最初のプライスヒストグラムは2006に登場しました。MetaTrader4のMQL4に個人的使用のために書かれたものでした。このインディケーター開発中、いつくつの問題に遭遇しました。その中から数件をここに挙げます。

  1. M5の履歴バー数がひじょうに短い。M1は言うにおよばず。
  2. 休日を考慮して1日戻る、金曜日のマーケットクローズ時刻を確認する、CFDマーケットのオープンとクローズを確認するなど、履歴を使った作業のための特別な関数を開発する必要性
  3. 時間枠を変更する際のインディケーターの再計算。結果としてターミナルの遅延

それに伴いМetaТrader5とMQL5のベータ版試用が始まるとき、 MQL5に変換することを決断しました。

「最初のパンケーキはいつも扱いにくい」と言いますが、それをインディケーターとして導入しようと努力しました。

良い面から始めましょう。全シンボルに対する分クオートのに長い履歴、履歴データをどんな時間範囲でも一定の期間に対して取得する可能性。

これからそれが判明した理由をご説明します。MQL5インディケータ機能については考えたことがありませんでした。

  1. インディケータのランタイムは重要なものです。
  2. 時間枠を変更した後のインディケータ動作の特徴

計算イベント ハンドラに対応するOnCalculate()関数の実行には重大なランタイムがあります。そのため、ミニッツバーヒストリーを用いて 260日間(年間)処理するのは数分までと長くかかります。インディケータがチャートに添付されたのち、一斉に計算が行われるのであれば、もちろんそれもできます。が、時間枠変更に関してはあてはまりません。インディケータが異なる時間枠に切り替わったら、インディケータの古いコピーは破棄され、新規コピーが作成されます。それが時間枠変更後同じレベルを再び計算しなければならない理由で、そのため時間がかかってしまうのです。

しかし、どうしてよいかわからなかったら、よく言われるように「まずドキュメンテーションを読むこと」です。この場合、それはMQL5のドキュメンテーションです。解決方法はひじょうに簡単です。このインディケータを取引しないExpert Advisorとして実装するのです。

Expert Advisorの利点は以下です。

  1. OnTick ()内のInitイベントハンドラにとって処理時間は重要ではない。
  2. ハンドラOnDeinit (const int reason)のパラメータを取得する可能性

Expert Advisorはインディケータとは以下の点で異なります。時間枠の更後、expert advisorはREASON_CHARTCHANGE理由パラメータを伴いDeInitイベントを生成するだけです。それはExpert Advisorをメモリからアンロードしません。またグローバル変数値を供給します。Expert Advisorがパラメータを貼り付け変更し、新規データが表示されたのちすべての計算を一度にできるようになります。新規データとはここでは、新規取引日を指します。

後に必要となる定義をいくつかご紹介しましょう。

オブジェクトに基づくプログラミング (OOP)は基本コンセプトがオブジェクトとクラスのコンセプトであるプログラムスタイルです。

オブジェクトとはバーチャル空間におけるエンティティで、指定された状態にあり、指定された動きをします。プロパティ値(属性と呼ばれる)を有し、それに伴う操作(メソッドと呼ばれます)を行います。

OOP では、クラスは特別な抽象データタイプで、コンストラクションの方法により特徴づけられています。クラスがOOPの重要なコンセプトです。クラスはその他の抽象データタイプとは異なっています。クラス内のデータ定義はそのデータ処理(インターフェース)のクラス メソッドを含んでいます。

プログラミングにおいては、ソフトウェア インターフェース コンセプトがあります。それは、アルゴリズム、引数の記述、処理するための入力パラメータ順序、返す値を含む、プログラムの数か所で行われる可能性のある計算のリストを意味します。抽象データ タイプのインターフェースはそういったリストの様式化された記述のために開発されてきました。アルゴリズムそのものやそういう計算のすべてをおこなうコードは指定されるものではなく、インターフェースの実装と呼ばれるものです。

クラス生成はフィールドとメソッドを伴うストラクチャの構築です。クラス全体はオブジェクト作成のためのテンプレートと考えられ、それはクラス インスタンスです。クラス インスタンスも同じテンプレートを使用して作成されます。そのため、同じフィールドとメソッドを有します。

では始めていきましょう。

ソースコードは4ファイルに配置されています。中心的なファイルはPriceHistogram.mq5で、その他のファイルはClassExpert.mqhClassPriceHistogram.mqhClassProgressBar.mqhです。.mqh拡張子を伴うファイルにはクラス記述とメソッドが含まれます。 ファイルはすべて同一ディレクトリに配置されなければなりません。私のディレクトリはこちらです。 My directory is: \MQL5\ Experts\PriceHistogram.

4.1. PriceHistogram.mq5

ソースコードの最初の記述は

#include "ClassExpert.mqh"

#includeコンパイラ指令は指定されたファイルからのテキストを含みます。ここでは、クラス記述CExpert(以下に説明があります)です。

次はinput variablesのブロックで、Expert Advisorのパラメータです。

// The block input parameters
input int         DayTheHistogram   = 10;          // Days for histogram
input int         DaysForCalculation= 500;         // Days for calculation(-1 all)
input uint        RangePercent      = 70;          // Percent range
input color       InnerRange        =Indigo;       // Inner range
input color       OuterRange        =Magenta;      // Outer range
input color       ControlPoint      =Orange;       // Point of Control
input bool        ShowValue         =true;         // Show Values

その後、変数ExtExpert(CExpert クラスタイプ)が宣言されます。

次はMQL5プログラムにある標準イベント ハンドラですイベントハンドラは対応するCExpertクラスのメソッドを必要とします。

CExpertの実行前に操作をおこなう唯一のメソッドがあります。OnInit()メソッドです。
int OnInit()
  {
//---
// We check for symbol synchronization before the start of calculations
   int err=0;
   while(!(bool)SeriesInfoInteger(Symbol(),0,SERIES_SYNCRONIZED) && err<AMOUNT_OF_ATTEMPTS)
     {
      Sleep(500);
      err++;
     }
// CExpert class initialization
   ExtExpert.RangePercent=RangePercent;
   ExtExpert.InnerRange=InnerRange;
   ExtExpert.OuterRange=OuterRange;
   ExtExpert.ControlPoint=ControlPoint;
   ExtExpert.ShowValue=ShowValue;
   ExtExpert.DaysForCalculation=DaysForCalculation;
   ExtExpert.DayTheHistogram=DayTheHistogram;
   ExtExpert.Init();
   return(0);
  }

Expert Advisorの初版を書いたとき、私はクライアント端末が再起動したときやシンボルに変更があったとき、なぜEAがエラーで停止してしまうのか理由が理解できず困ったことがありました。 それが起こるのはクライアント端末が接続されていなかったり、シンボルが長い間使われていなかった場合に起こるのでした。

MetaEditor5に開発者の手でデバッガが追加されたのはすばらしいことです。私はPrint()やComment()といったコマンドをたくさん覚えています。そういうコマンドはMetaEditor4で変数値をチェックするのに使われています。MetaEditor5開発者の皆様に感謝を申し上げます。

私の場合、事は簡単でした。エキスパートはサーバーに接続する前に起動し、履歴データも更新さてしまいました。この問題解決には、 SeriesInfoInteger(Symbol(),0,SERIES_SYNCRONIZED)を使わなければなりませんでした。これは、データが同期しているか否か()間のサイクルを報告します。接続されていない場合カウンター変数errを使用します。

データが同期するか、接続なしのカウンターのおかげでサイクルが完了すると、エキスパート クラスの入力パラメータであるCExpertを渡し、クラス初期化メソッド Init ()を呼びます。

ご覧のように、MQL5のクラスコンセプトのおかげで、われわれのファイル、PriceHistogram.mq5はシンプルなテンプレートに変換されました。今後の処理はすべてClassExpert.mqhで宣言されたCExpertクラスで行われます。

4.2. ClassExpert.mqh

この記述について考察していきます。

//+------------------------------------------------------------------+
//|   Class CExpert                                                  |
//|   Class description                                              |
//+------------------------------------------------------------------+
class CExpert
  {
public:
   int               DaysForCalculation; // Days to calculate (-1 for all)
   int               DayTheHistogram;    // Days for Histogram 
   int               RangePercent;       // Percent range
   color             InnerRange;         // Internal range color
   color             OuterRange;         // Outer range color
   color             ControlPoint;       // Point of Control (POC) Color
   bool              ShowValue;          // Show value

パブリック セクションはオープンで外部変数からアクセス可能です。変数名がPriceHistogram.mq5で宣言される入力パラメータ セクション名と一致しているのがわかります。入力パラメータはグローバルなのでそれは必要ではありません。今回の場合は、よい増殖ルールに敬意を表します。が、クラス内で外部変数を使用するのは避けたいところです。

private:
   CList             list_object;        // The dynamic list of CObject class instances
   string            name_symbol;        // Symbol name
   int               count_bars;         // Number of daily bars
   bool              event_on;           // Flag of events processing

プライベートセクションは外部から閉じられており、クラス内でのみアクセス可能です。変数list_object of CListタイプの概要を述べたいと思います。それはMQL5 ライブラリの標準クラスです。CList クラスは動的クラスでCObjectクラスインスタンスのリストと継承者を伴います。私はこのリストをCPriceHistogramCObject クラスの後継であるクラス要素の参照ストレージとして使用するつもりです。詳細は以下で考察します。CListクラス記述はList.mqhにあり、コンパイラ指令#include <Arrays\List.mqh>を使用することでインクルードします。

public:
   // Class constructor
                     CExpert();
   // Class destructor
                    ~CExpert(){Deinit(REASON_CHARTCLOSE);}
   // Initialization method
   bool              Init();
   // Deinitialization method
   void              Deinit(const int reason);
   // Method of OnTick processing
   void              OnTick();
   // Method of OnChartEvent() event processing
   void              OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
   // Method of OnTimer() event processing
   void              OnTimer();
};

以下はパブリックメソッド セクションです。ご推察のとおり、これらメソッド(関数)はクラス外で使用可能です。

最後にセミコロンと括弧でクラス記述は完成です。

それではクラスメソッドを詳しく見ていきましょう。

クラス構成は記述の特別なブロックで、オブジェクトが作成されるときに呼ばれます。コンストラクタはメソッドと似ていますが、必ずしもある種のデータを返さない点で異なります。

MQL5言語では、コンストラクタは入力パラメータを持ちえません。また、クラスはそれぞれただ一つのコンストラクタを有します。今回の場合は、コンストラクタは変数の最初の初期化です。

デストラクタは特別なクラスメソッドでオブジェクトの 最初期設定(いわゆるフリーメモリ)に使用されます。この場合、メソッドは『デイニット』と呼ばれます。(REASON_CHARTCLOSE)

Init()はクラス初期化メソッドです。これはCExpertクラスで最も重要なメソッドです。そこでヒストグラム オブジェクトが作成されるのです。詳細コメントに目を通してください。そこのポイントについて考えてみたいと思います。

まず、日時の『プライスヒストグラム』を作成するには、処理すべき日時のオープン時刻が必要です。ここでは脱線して、タイムシリーズと連動した機能に着目していただきたいと思います。 他の時間枠から要求されるデータに対しては時間が必要です。よって、最初のコールからはBars ()関数、またはCopyTime ()関数、タイムシリーズに連動するその他の関数は要求するデータを返すとは限りません。

そこで、この関数をdo (...) while () ループに入れる必要がありますがそれを限定するため、カウンター変数を使用します。

int err=0;
 do
   {
    // Calculate the number of days which available from the history
    count_bars=Bars(NULL,PERIOD_D1);
    if(DaysForCalculation+1<count_bars)
       count=DaysForCalculation+1;
    else
       count=count_bars;
    if(DaysForCalculation<=0) count=count_bars;
    rates_total=CopyTime(NULL,PERIOD_D1,0,count,day_time_open);
    Sleep(1);
    err++;
   }
 while(rates_total<=0 && err<AMOUNT_OF_ATTEMPTS);
 if(err>=AMOUNT_OF_ATTEMPTS)
   {
   Print("There is no accessible history PERIOD_D1");
   name_symbol=NULL;
   return(false);
   }

次に、MetaTrader 5のミニッツ ヒストリーは、利用可能な日と等しくなっています。そのため、処理を進めるにはたいへんな時間を要するので、計算過程を可視化する必要があります。クラスCProgressBar (#include "ClassProgressBar.mqh")はこの目的で開発されました。 チャート ウィンドウに進行状況を示すバーを設け、計算処理中に更新していくのです。

// We create the progress bar on the char to shot the loading process
 CProgressBar   *progress=new CProgressBar;
 progress.Create(0,"Loading",0,150,20);
 progress.Text("Calculation:");
 progress.Maximum=rates_total; 

三番目に、サイクル内で、『新規』記述を使用します。CPriceHistogramオブジェクトを作成し、メソッドを用いてそれをコンフィギュアし、 Init()をコールして初期化します。ここまでうまくいけば、list_objectリストにそれを追加し、そうでない場合は、削除記述を使用してhist_objを削除します。 The CPriceHistogramクラス記述がのちに表示されます。コメント内のコードを見ます。

// In this cycle there is creation of object CPriceHistogram
 // its initialization and addition to the list of objects
 for(int i=0;i<rates_total;i++)
   {
    CPriceHistogram  *hist_obj=new CPriceHistogram();
    //         hist_obj.StepHistigram(step);
    // We set the flag to show text labels
    hist_obj.ShowLevel(ShowValue);
    // We set POCs colour
    hist_obj.ColorPOCs(ControlPoint);
    // We set colour for inner range
    hist_obj.ColorInner(InnerRange);
    // We set colour for outer range
    hist_obj.ColorOuter(OuterRange);
    // We set the percent range
    hist_obj.RangePercent(RangePercent);
    //  hist_obj.ShowSecondaryPOCs((i>=rates_total-DayTheHistogram),PeriodSeconds(PERIOD_D1));
    if(hist_obj.Init(day_time_open[i],day_time_open[i]+PeriodSeconds(PERIOD_D1),(i>=rates_total-DayTheHistogram)))
       list_object.Add(hist_obj);
    else
       delete hist_obj; // Delete object if there was an error
    progress.Value(i);
   }; 

OnTick()はあるシンボルに対して新しいティックを入手したときに呼ばれるメソッドです。 count_bars変数に保存されている日ナンバー値をBars (Symbol (), PERIOD_D1)から返される日時ナンバーと比較し、両者が等しくなければ、クラス初期化のためにInit ()メソッドを呼びます。そうすることで、list_objectリストを消去し、値をNULL name_symbolに変更します。日ナンバーが変更されなければ、ループはCPriceHistogram list_objectクラスに保存された全オブジェクトをあたり、Virgin ( «virgin")であるデータに対してRedraw ()メソッドを実行します。

Deinit()はクラスの初期化解除メソッドです。 REASON_PARAMETERS(入力パラメータがユーザーによって変更された)の場合、list_objectリストを消去し、name_symbol変数をNULLに設定します。それ以外の場合、エキスパートはなにも行いませんが、追加したいことがあれば、コメントを読んでください。

OnEvent()クライアント端末のイベント処理を行うメソッドです。イベントは、ユーザーがチャートで作業をしているとき、クライアント端末で生成されます。詳細についてはMQL5言語ドキュメンテーションで参照可能です。本Expert Advisorでは、チャート イベントとして CHARTEVENT_OBJECT_CLICKが使用されています。ヒストグラム エレメントをクリックすると、第二のPOCレベルとヒストグラム色の逆数が表示されます。

OnTimer(void)はタイマー イベント処理メソッドです。私のプログラムでは使用していませんが、タイマー操作(時間表示など)を付け加えたい場合は、以下を参照してください。しかし、それを使用する前に、クラス コンストラクタに下記の行を追加する必要があります。

EventSetTimer(秒単位での時間)

デストラクタには下記の行を追加します。

EventKillTimer(); 

Deinit (REASON_CHARTCLOSE)メソッドを呼ぶ前に上記追加を行います。

CExpertクラスに関して。これはCPriceHistogramクラスメソッド表示のために作成されます。

4.3. ClassPriceHistogram.mqh
//+------------------------------------------------------------------+
//|   Class CPriceHistogram                                          |
//|   Class description                                              |
//+------------------------------------------------------------------+
class CPriceHistogram : public CObject
  {
private:
   // Class variables
   double            high_day,low_day;
   bool              Init_passed;      // Flag if the initialization has passed or not
   CChartObjectTrend *POCLine;
   CChartObjectTrend *SecondTopPOCLine,*SecondBottomPOCLine;
   CChartObjectText  *POCLable;
   CList             ListHistogramInner; // list for inner lines storage 
   CList             ListHistogramOuter; // list for outer lines storage
   bool              show_level;         // to show values of level
   bool              virgin;             // is it virgin
   bool              show_second_poc;    // show secondary POC levels
   double            second_poc_top;     // value of the top secondary POC level
   double            second_poc_bottom;  // value of the bottom secondary POC level
   double            poc_value;          // POC level value
   color             poc_color;          // color of POC level
   datetime          poc_start_time;
   datetime          poc_end_time;
   bool              show_histogram;     // show histogram  
   color             inner_color;        // inner color of the histogram
   color             outer_color;        // outer color of the histogram
   uint              range_percent;      // percent range
   datetime          time_start;         // start time for construction
   datetime          time_end;           // final time of construction
public:
   // Class constructor
                     CPriceHistogram();
   // Class destructor
                    ~CPriceHistogram(){Delete();}
   // Class initialization
   bool              Init(datetime time_open,datetime time_close,bool showhistogram);
   // To level value
   void              ShowLevel(bool show){show_level=show; if(Init_passed) RefreshPOCs();}
   bool              ShowLevel(){return(show_level);}
   // To show histogram
   void              ShowHistogram(bool show);
   bool              ShowHistogram(){return(show_histogram);}
   // To show Secondary POC levels
   void              ShowSecondaryPOCs(bool show){show_second_poc=show;if(Init_passed)RefreshPOCs();}
   bool              ShowSecondaryPOCs(){return(show_second_poc);}
   // To set color of POC levels
   void              ColorPOCs(color col){poc_color=col; if(Init_passed)RefreshPOCs();}
   color             ColorPOCs(){return(poc_color);}
   // To set internal colour of histogram
   void              ColorInner(color col);
   color             ColorInner(){return(inner_color);}
   // To set outer colour of histogram
   void              ColorOuter(color col);
   color             ColorOuter(){return(outer_color);}
   // To set percent range
   void              RangePercent(uint percent){range_percent=percent; if(Init_passed)calculationPOCs();}
   uint              RangePercent(){return(range_percent);}
   // Returns value of virginity of POC level
   bool              VirginPOCs(){return(virgin);}
   // Returns starting time of histogram construction
   datetime          GetStartDateTime(){return(time_start);}
   // Updating of POC levels
   bool              RefreshPOCs();
private:
   // Calculations of the histogram and POC levels
   bool              calculationPOCs();
   // Class delete
   void              Delete();
  }; 

クラス記述においては、クラス変数とクラスメソッドに対するコメントを提供しようと思います。そのいくつかを詳しく考察していきましょう。

//+------------------------------------------------------------------+
//|   Class initialization                                           |
//+------------------------------------------------------------------+
bool CPriceHistogram::Init(datetime time_open,datetime time_close,bool showhistogram) 

このメソッドは入力パラメータを3つ使用しています。構築開始、コンストラクションの終了時間、ヒストグラムの構築を指示するフラグ、またはただPOCレベルを指定するフラグです。

この例 (CExpertクラス)では、入力パラメータは開始日と翌日の開始時間day_time_open [i] + PeriodSeconds (PERIOD_D1)に渡されます。しかし、このクラスを使用するにあたり、ヨーロッパ時間、アメリカでのセッション、週や月のギャップサイズなどを求めるのを拒むものはありません。

//+---------------------------------------------------------------------------------------+
//|   Calculations of the histogram and POCs levels                                       |
//+---------------------------------------------------------------------------------------+
bool CPriceHistogram::calculationPOCs() 

このメソッドでは、コンストラクションの全レベルと計算の元は閉じられた個別のメソッドで外部からのアクセスは不可能です。

// We get the data from time_start to time_end
   int err=0;
   do
     {
      //--- for each bar we are copying the open time
      rates_time=CopyTime(NULL,PERIOD_M1,time_start,time_end,iTime);
      if(rates_time<0)
         PrintErrorOnCopyFunction("CopyTime",_Symbol,PERIOD_M1,GetLastError());

      //--- for each bar we are copying the High prices
      rates_high=CopyHigh(NULL,PERIOD_M1,time_start,time_end,iHigh);
      if(rates_high<0)
         PrintErrorOnCopyFunction("CopyHigh",_Symbol,PERIOD_M1,GetLastError());

      //--- for each bar we are copying the Low prices
      rates_total=CopyLow(NULL,PERIOD_M1,time_start,time_end,iLow);
      if(rates_total<0)
         PrintErrorOnCopyFunction("CopyLow",_Symbol,PERIOD_M1,GetLastError());

      err++;
     }
   while((rates_time<=0 || (rates_total!=rates_high && rates_total!=rates_time)) && err<AMOUNT_OF_ATTEMPTS&&!IsStopped());
   if(err>=AMOUNT_OF_ATTEMPTS)
     {
      return(false);
     }
   poc_start_time=iTime[0];
   high_day=iHigh[ArrayMaximum(iHigh,0,WHOLE_ARRAY)];
   low_day=iLow[ArrayMinimum(iLow,0,WHOLE_ARRAY)];
   int count=int((high_day-low_day)/_Point)+1;
// Count of duration of a finding of the price at each level
   int ThicknessOfLevel[];    // create an array for count of ticks
   ArrayResize(ThicknessOfLevel,count);
   ArrayInitialize(ThicknessOfLevel,0);
   for(int i=0;i<rates_total;i++)
     {
      double C=iLow[i];
      while(C<iHigh[i])
        {
         int Index=int((C-low_day)/_Point);
         ThicknessOfLevel[Index]++;
         C+=_Point;
        }
     }
   int MaxLevel=ArrayMaximum(ThicknessOfLevel,0,count);
   poc_value=low_day+_Point*MaxLevel;

まず、限られた時間範囲(iTime []、iHigh[]、iLow[])にたいするミニッツバーの履歴を取得します。そののち、iHigh[] iand Low[]の最大または最小エレメントを見つけますそして、最小から最大のポイント(件数)数を計算します。ThicknessOfLevel要素とともに、ThicknessOfLevel配列を保持します。サイクルでは、ローからハイまでの各分そうろく足を見ていき、現在の価格レベルに表示される時間範囲のデータを追加します。それにより ThicknessOfLevel配列の最大エレメントを取得すると、それがもっとも長い期間続いた価格のレベルということになります。今回のPOCレベルは以下です。

// Search for the secondary POCs
   int range_min=ThicknessOfLevel[MaxLevel]-ThicknessOfLevel[MaxLevel]*range_percent/100;
   int DownLine=0;
   int UpLine=0;
   for(int i=0;i<count;i++)
     {
      if(ThicknessOfLevel[i]>=range_min)
        {
         DownLine=i;
         break;
        }
     }
   for(int i=count-1;i>0;i--)
     {
      if(ThicknessOfLevel[i]>=range_min)
        {
         UpLine=i;
         break;
        }
     }
   if(DownLine==0)
      DownLine=MaxLevel;
   if(UpLine==0)
      UpLine=MaxLevel;
   second_poc_top=low_day+_Point*UpLine;
   second_poc_bottom=low_day+_Point*DownLine;

次のステップは二番目のPOCレベルを得ることです。ダイアグラムが分割されていることを思い出しましょう。ヒストグラムは、内部および外部(別の色で表示されています)の2つの範囲に分割され、サイズ範囲は現レベルにおける価格の時間パーセンテージで定義されています。内部境界の範囲が「二番目のPOC」レベルなのです。

「二番目の POC」すなわち境界パーセント範囲が入手できたところで、 ヒストグラムのコンストラクションに進みます。

// Histogram formation 
   if(show_histogram)
     {
      datetime Delta=(iTime[rates_total-1]-iTime[0]-PeriodSeconds(PERIOD_H1))/ThicknessOfLevel[MaxLevel];
      int step=1;
      
      if(count>100)
         step=count/100// Calculate the step of the histogram (100 lines as max)

      ListHistogramInner.Clear();
      ListHistogramOuter.Clear();
      for(int i=0;i<count;i+=step)
        {
         string name=TimeToString(time_start)+" "+IntegerToString(i);
         double StartY= low_day+_Point*i;
         datetime EndX= iTime[0]+(ThicknessOfLevel[i])*Delta;

         CChartObjectTrend *obj=new CChartObjectTrend();
         obj.Create(0,name,0,poc_start_time,StartY,EndX,StartY);
         obj.Background(true);
         if(i>=DownLine && i<=UpLine)
           {
            obj.Color(inner_color);
            ListHistogramInner.Add(obj);
           }
         else
           {
            obj.Color(outer_color);
            ListHistogramOuter.Add(obj);
           }
        }
     }

端末の負荷を減らすため、ヒストグラム1つに対して画面には100行しか表示しないことをお伝えしておきます。ヒストグラムの行は2つのリストに保存されます。ListHistogramInnerおよび ListHistogramOuterですが、両者はすでにCListクラスとして知っているオブジェクトです。ただし、これらポインタは標準クラスのオブジェクトCChartObjectTrendに保存されます。タイトルから、ヒストグラムの色を変更するのに、なぜリストが2つ必要なのかと疑問に思うでしょう。

// We receive data beginning from the final time of the histogram till current time
   err=0;
   do
     {
      rates_time=CopyTime(NULL,PERIOD_M1,time_end,last_tick.time,iTime);
      rates_high=CopyHigh(NULL,PERIOD_M1,time_end,last_tick.time,iHigh);
      rates_total=CopyLow(NULL,PERIOD_M1,time_end,last_tick.time,iLow);
      err++;
     }
   while((rates_time<=0 || (rates_total!=rates_high && rates_total!=rates_time)) && err<AMOUNT_OF_ATTEMPTS);
// If there isn't history, the present day, level is virgin, we hoist the colours
   if(rates_time==0)
     {
      virgin=true;
     }
   else
// Otherwise we check history
     {
      for(index=0;index<rates_total;index++)
         if(poc_value<iHigh[index] && poc_value>iLow[index]) break;

      if(index<rates_total)   // If level has crossed
         poc_end_time=iTime[index];
      else
         virgin=true;
     }
   if(POCLine==NULL)
     {     
      POCLine=new CChartObjectTrend();
      POCLine.Create(0,TimeToString(time_start)+" POC ",0,poc_start_time,poc_value,0,0);
     }
   POCLine.Color(poc_color);
   RefreshPOCs();

必要なメソッドは全て用いてCPriceHistogramを設計してみました。もしも不十分であるなら、ご自身でメソッドを追加することも可能です。そのときはお手伝いいたします。


要約

プライス ヒストグラムは信頼性が高いが、直感的なツールであるということを再度思い出したいと思います。そのため、使用には確認シグナルが必要です。

関心を持っていただいてありがとうございました。ご質問があればなんなりとお問い合わせください。