
UML ツールを用いたExpert Advisorの開発方法
すでに存在するものを調査するのが科学者であり、まだ存在しないものを産み出すのがエンジニアである。
Albert Einstein
はじめに
拙著 Simulink: a Guide for the Developers of Expert Advisors で、私は動的システムを利用した Expert Advisor のモデル化を提案しました。ただこの方法はトレーディングシステムの設計の一側面しか表していません。すなわちシステムの動的振る舞いです。専門家はトレーディングシステム開発者の方法論を拡げる特殊なツールを持っています。本稿では汎用ツール - グラフィカル言語 UMLを用いたExpert Advisorの開発方法についてお話していきたいと思います。
一般的にグラフィカル言語としての UML はオブジェクト指向のソフトウェアシステムのビジュアルモデル化に使用されるものです。ですが、私の考えではトレーディングシステム開発にそのツールを利用することも可能なのです。それ以上にMQL5 はオブジェクト指向言語の一員であり、このことでわれわれのタスクはより簡単なものとなります。
モデル化にあたり非営利的な無料ソフトウェアSoftware Ideas Modelerを選びました。
1. UML の基本
UML は Expert Advisor作成にどのように役立つのでしょうか?まずグラフィックです。多面的モデル化の問題は言語で使用可能なグラフィックイメージを用いることで解決が可能です。次に可読性です。Expert Advisor が大容量で複雑であっても、UML の汎用性によりダイアグラムを使用してそのモデルを提示することができます。
UML の開発者がおっしゃるように、人間の知覚の特殊な性質は、ただのテキストよりイメージを伴うテキストがより簡単に理解できるということにあります。
UMLの基本について端的にお話します。このテーマにご興味があれば、ウェブサイトから無料で利用できる数多くの文献からUMLについて学習することができます。
UML のストラクチャを図示することができます(図1)。
図1 UML ストラクチャ
以下をインクルードしたブロック構築: エンティティ (モデルエレメント)、関係 (物をバインドします)、ダイアグラム (UML モデルを提示します)。
UML ダイアグラムは異なる観点から設計されるシステムの表現を可視化します。
共通メカニズム には以下が含まれます。:仕様(意味の記述)、 装飾(モデルの重要な特性をマーク)共通ディビジョン(抽象化とそのインスタンス、インターフェース、実装)、 拡張性メカニズム(制約、ステレオタイプ、タグされた値)
アーキテクチャはその環境におけるシステムのハイレベルな提示を行います。UML アーキテクチャは "4+1 アーキテクチャビュー" (図2)によってもっともよく示されます。
- ロジカルビュー
- プロセスビュー
- 開発ビュー
- フィジカルビュー
- シナリオ
図2 4+1 アーキテクチャビュー
UML にはそれ自身の標準的ダイアグラム の階層があることも注意が必要です(図3)。言語バージョン 2.2 は 14 タイプの UML ダイアグラムを使用します。
図3 標準的 UML ダイアグラム
またUML ダイアグラムの使用について特殊なケースを考察することを提案します。EA 開発のためのダイアグラムを使用した特殊なバリアントに対する抽象化から移動することができます。UML ダイアグラムの階層が提供するトレーディングシステムの多面的設計の基本は、TS 作成タスクの体系的な解りやすい解決に寄与しすることを繰り返しておきます。
2. UML ダイアグラム
2.1ユースケース図
ことわざのとおり、「出だしがよければ半分成功したも同じこと」です。通常、必要がなくても分析作業はユースケース図で始まります。それはユーザー視点からシステムを表現します。
その作成の際、できることは以下です。
- TS 使用のバリアントを指定する
- TSの境界を指定する
- TS のアクターを決定する
- アクターと TS バージョンの関係を定義する
ユースケース はステップのリストで、目標達成のため通常は役割(UML では『アクター』として知られています)とシステム関の相互連携を決めます。
アクター はユーザーまたはサブジェクトを伴い連携する他のシステムによる役割を指定します。アクターは人間のユーザー、外部ハードウェア、他のサブジェクトによる役割を表します。
関係 はモデルのi個別エレメント間の意味的関連を言います。
このタイプのダイアグラムはかなり一般的で、実装よりもむしろ TSの概念的性質を反映していることにお気づきかもしれません。しかし、それがポイントなのです。全体から細部へ、抽象から具体への移り変わりです。われわれはアーティストでないと誰が言いましたか?一般的アイデアとスケッチから出発してわれわれは絵を描くのです。まず、カンヴァスに線を描きます。それから色を塗ります。細部を描きます...
そんなわけで、トレーディングシステム用のユースケースを作成してみようではありませんか。
インプットアクターとして以下の役割を選びました。開発者、システムアナリスト、リスク管理者、アドミニストレータです。1人以上の人がこれら役割を担うことに注意が必要です。われわれのトレーディングシステムはどのようは処理を行い、それに関連してどのような処理が行われるのでしょうか?
そのため、開発者が作成され TSを実装するのです。また、その人は TSの最適化にも関与します。システムアナリストが TSの最適化を行います。リスク管理者はリスク管理に責任を持ちます。アドミニストレータはT TSの全体的動作を監視します。アウトプット側では、TSの機能の結果としてユーザーが収益をあげます。この役割は「トレーダー」および「投資家」といった役割を兼ねています。また、アドミニストレータ同様管理者も TSの動作を監視します。
ダイアグラムには『トレーディングシステム』ブロックがあります。それは TS 境界を表し、外界からそれを隔離します。
ここでアクターとユースケース、アクターと他のアクター、ユースケースと他のユースケースの関係について少しお話します。関係のほとんどは実線でマークされたつながりによって表現されます。これは特定のアクターはユースケースに参加することを意味します。リスク管理者はリスク管理プロセスを開始する、などです。ユースケースを開始するアクターは基本で行われる処理の結果を利用する者はその次です。たとえば、二番手のアクターはアウトプット側の管理者です。
アソシエーション はアクターが適切なユースケースを起動するよう指示します。
一般化は役割の妥当な一般性をモデル化します。
拡張は基本ユースケースとその特別ケースの依存関係の一種です。
インクルードは基本のユースケースの他のユースケースに対する関係を定義します。その機能的ふるまいは追加条件下のみで使用され、基本ケースによって使用されるとは限りません。
ただし、ケースに関しての二次的役割はこの役割の重要性が二番目だというわけではありません。また、ダイアグラムでは一般化関係によって「TS ユーザー」 は「トレーダー」の役割と「投資家」の役割で構成されているのがわかります。それは『色なし』の三角形の矢線で示されている部分です。
図4 TSのユースケースダイアグラム
同様にユースケースの『オープンポジション』と『クローズポジション』は『一般化によってトレーディング』に関連づけられます。後者はその他2つの基本ケースです。それは『リスク管理』も含みます。その振る舞いは個別ケース『プロフィット』を補完します。
Since the TS プロフィットは資本の「売り」価格がその「買い」価格より大きいという条件の上に形成されるので、これらのケースに対して拡張した関係を作りました。ダイアグラムはまた拡張ポイントも示しています。たとえば特定の条件下でケース『対プロフィット』が使用されるなどです。依存関係は対応するステレオタイプ『インクルード』と『拡張』を伴う破断矢線で表示されています。
それぞれのユースケースに対してシナリオを作成する必要があります。それは意図する目標に導くステップのシーケンスを表現するものです。ユースケースは複数の形式で表現することができます。一般的に受け入れられる形式は以下を含みます。:テキスト記述、疑似コード、アクティビティ図、相互作用図。
トレーダーは厳密な意味で図4に示されているものよりも TS に興味を持つことに注意が必要です。よってそれ以上に『対プロフィット』の拡張を伴う『トレーディング』のユースケースに注目することを提案します。
2.2クラスダイアグラム
クラスダイアグラム を用いて TS ストラクチャを記述します。すなわち、オブジェクト指向プログラ民のクラスに関してトレーディングシステムの統計的ストラクチャモデルを提示します。よってわれわれは TSのプログラムロジックを反映します。
UML ではクラスダイアグラム は統計ストラクチャダイアグラムの一種です。それはクラス、属性とオペレータを示すことでシステムストラクチャを提示します。クラスの関係も同様です。
このタイプのダイアグラムの利点は何でしょうか?オブジェクト指向プログラミング言語にほんの少しでも詳しい方はすぐに親しみのある『クラス』表記にお気づきでしょう。クラスは基本構築ブロックとして UML クラスダイアグラムにおける処理を行います。たとえば、C++ コードを一般化するとき、クラステンプレート形式で UML クラスブロックが自動で作成されます。よって各メソッドとプロパティの実装を終える必要があるだけです。
では例として何かをデザインしていきます。まずはじめに記事 "Prototype of a Trading Robot"に注目していただきたいと思います。そこにはストレートロジックを用いる利点が述べられています。私の意見ではひじょうに効果的で生産的なのはネスティングの原理です。すなわち「マクロ関数トレードモジュール」です。
たとえば、標準ライブラリのトレーディングクラス機能を使用する Expert Advisor が必要です。
クラスブロックを使用してクラスダイアグラムにクラスモデルを作成します。それを CTradeExpert と呼びます。新しいクラスにいくらかの属性(MQL5ではクラスのデータメンバです)を追加します。それらは: Magic_No, e_trade, e_account, e_deal, e_symbol, e_pnt です。またクラスのコンストラクタメソッド CTradeExpert を挿入します。グラフィック的には処理は図5のようになります。
図5 UML モデルクラス CTradeExpert
属性の前の符号 "-" は属性がモード «private»、«#» - «protected»、«+» - «public»においてアクセス権を持つことを示します。属性 Magic_No についてはアクセス指定子はプライベートとして設定され、e_pnt についてはパブリック、その他については保護と設定されることとなります。属性名に続くコロンは属性に対するデータタイプおよびメソッドに帰すデータタイプを示します。たとえば、属性 Magic_No はタイプ int、属性 e_trade はタイプ CTradeなどです。
ここではメンバや属性は追加していません。このクラス CTradeExpertが Standard Libraryのクラスと連携しているのをシンプルに示すだけです。このためにダイアグラムにクラスのブロックを6個追加し、それらを次のように呼びます。CTrade、CAccountInfo、CDealInfo、 CSymbolInfo、CObject。これで"use"のステレオタイプ(矢印付一点鎖線)の依存関係によってトレードクラスを4ブロック持つ CTradeExpertクラスのモデルと連携しました。
そしてこれらブロックを「色なし」矢印の線を使っている一般化関係によるブロックにリンクさせます。標準ライブラリクラスにコメントを追加します。これでわれわれの UML ダイアグラムは図6のようになりました。
図6 UML クラスダイアグラム
ここで必要なのはサイドバーの"Generate"タブ(図7)の『作成』関数を用いてコードを作成することだけです。
図7 作成されたコード
もっとも適しているのは С++ 言語です。Expert Advisor クラスのコード作成にC++ 言語を使用し、簡単にそれを MQL5に翻訳します。
このダイアグラムに対して作成されたコードは以下のようなものです。
// class CTradeExpert { private: int Magic_No; protected: CTrade e_trade; protected: CAccountInfo e_account; protected: CDealInfo e_deal; protected: CSymbolInfo e_symbol; public: double e_pnt; public: void CTradeExpert () { } }; // class CObject { }; // class CTrade : public CObject { }; // class CDealInfo : public CObject { }; // class CSymbolInfo : public CObject { }; // class CAccountInfo : public CObject { };
じつになじみのあるシンタックスではありませんか?そしてクラスの本文をあてはめるだけです。このためにMetaEditor において、新しいクラスTradeExpert.mqhのためのファイルを一つ作成します。そこに前に作成したコードをコピーします。可読性のためにCTradeExpertクラスのメンバに対して繰り返されているアクセス指定子保護 を削除します。
標準ライブラリクラスの宣言に関連している行を削除します。そののち、使用されている標準ライブラリの各クラスに対してインストラクション # Include をインクルードしているファイルを追加します。というのもこれらクラスはすでに開発者によって定義されているからです。そしてコメントを追加します。結果取得するのが以下のようなコードです。
//includes #include <Trade\Trade.mqh> #include <Trade\AccountInfo.mqh> #include <Trade\DealInfo.mqh> #include <Trade\SymbolInfo.mqh> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CTradeExpert { private: int Magic_No; // Expert Advisor magic protected: CTrade e_trade; // An object for executing trade orders CAccountInfo e_account; // An object for receiving account properties CDealInfo e_deal; // An object for receiving deal properties CSymbolInfo e_symbol; // An object for receiving symbol properties public: double e_pnt; // Value in points public: CTradeExpert() { } }; //+------------------------------------------------------------------+
ここからわれわれの Expert Advisor クラスにトレーディング関数をいくらか追加していきます。
その関数は次のようなものです。: CheckSignal、OpenPosition、 CheckPosition、ClosePosition など。すでにみなさんは「コンディションサービング」の原則をご存じのことと思います。この場合には、われわれのテストクラス CTradeExpert はみなさんにとって難しくはなさそうです。IUMLのメカニズムを理解しやすいようにするため、いくつかすでになじみのあるExpert Advisorの例に注目しています。
よってクラスのモデルは図8のようなものです。
図8 UML モデルクラス CTradeExpert
クラスのアップデートされたモデルについてもすでに述べた方法を使用してコードを作成することができます。
2.3アクティビティ図
このタイプのUMLダイアグラムを使用し、データフローおよびコントロールフローのモデルを用いたシステムの振る舞いを調査することができます。アクティビティ図は段階を踏んだアクティビティとアクションのワークフローをグラフィカルに表現するものです。
アクティビティ図はアルゴリズムのステップを示すだけのフローチャートとは異なります。アクティビティ図の表記はより幅広いものです。たとえば、その中でオブジェクト状態を指定することが可能です。
開発者は以下を表現するためにアクティビティ図を利用します。
- ビジネスルール
- 単独ユースケース
- 複数ユースケースの複合シリーズ
- ソリューションとオルタナティブ・ストリームを伴うプロセス
- 並列処理
- プログラムフローとロジックコントロールストラクチャ
作成されたエキスパートクラス CTradeExpert が Expert Advisorのファイル Test_TradeExpert.mq5内で使われるとします。記憶にあるように MetaEditor 5 でEAを作成する際、デフォルトのテンプレートはデフォルトのイベントハンドラ関数を3つ提供します。それらは OnInit、OnDeinit 、 OnTickです。それらについて詳しく述べます。
ファイルTest_TradeExpert.mq5を構成するわれわれのEA 処理によってダイアグラムを表示します。ここで Expert Advisorというよりもそのストラクチャはかなり原始的なものであることに注意が必要です。ここは単にトレーニングの場です。トレーニングにはシンプルな EA ストラクチャでだいじょうぶです。
Expert Advisor使用のダイアグラムをダイアグラムをデザインします。そのアルゴリズムはファイル Test_TradeExpert.mq5にあります。
よってすべて初期ノードから始まります(図9)。Sこのノードからアクション「Expert Advisorのインスタンス作成」を呼び、コントロールトークンはノードに移動します。このアクションはオブジェクトフロー(青矢印)を起動します。それはオブジェクトノード(myTE=created)および「Expert Advisorを初期化」を呼ぶノードへのコントロールフローの状態を変化させます。
コントロールフロー はアクティビティエッジの形式で表現されます。それはアクティビティの2つのノードに連携し、それを経てコントロールトークンのみが渡されます。
オブジェクトフロー はアクティビティエッジとして表現され、そのに対してはオブジェクトまたはデータトークンのみ渡されます。
アクティビティノードはエッジによってつながるアクティビティフロー内の個別ポイントに対する抽象クラスです。
デシジョンノード はコントロールノードで、出力フロー間で選択を行います。
オブジェクトノード はアクティビティで使用されるオブジェクトを表します。
アクティビティエッジ は2つのアクティビティノード間の直接連携に対する抽象クラスです。
初期ノードはアクティビティ開始箇所を示します。
アクティビティの最終ノードはすべてのアクティビティのフローを完了します。それは次にオブジェクト myTE (myTE=initialized) の状態を変更し、デシジョンノードにコントロールトークンを渡します。Expert Advisor が首尾よく初期化されたら、コントロールフローはノード「トレードイベントNewTick»を処理する」に進みます。初期化に失敗したらコントロールトークンはまず一般化ノードに入り、そののちアクションノード「Expert Advisorを再初期化する」に行きます。
トークンは統計的に定義されるアクティビティグラフの実行を動的に処理する記述における利便性のために導入される抽象コンストラクションです。 トークンにはその他情報は含まれません(空のトークン)。この場合はコントロールフロートークンと呼ばれます。またそれにはオブジェクトあるいはデータストラクチャが含まれ、その場合にはデータフロートークンと呼ばれます。
デシジョンノードから来る第一のコントロールフローを見ます。それは中断されたアクションを持つ領域を対象とし、赤の破線で引かれた角丸長方形によって示されているように『割り込み可能』のステレオタイプです。コントロールフローがこの領域にあるときは、予想外に停止する可能性があります。アクションノード(オレンジのフラグ)を起動すれば、それはイベント「Expert Advisorをアンロードする」を受け取り、すべてのフローを中断します。コントロールトークンは中断エッジ(オレンジのジグザグ矢印)に移動し、その後連携ノードに移ります。そののち EA は再初期化されます。そしてコントロールトークンはノード「グローバル変数を削除する」に行き、フローは最終アクティビティノードで完了します。
アクションノード「Expert Advisorを初期化」もまたオブジェクトフローによってオブジェクト myTE (myTE=deinitsialized) を変更します。次にノード「グローバル変数を削除する」はオブジェクト myTE (myTE=deleted)を消去します。
図9 Test_TradeExpert.mq5に対するアクティビティ図
コントロールフローが安定しているとすると、 EA はアンロードされません。フローはノード「トレードイベント NewTick» を処理する」から別のブロック - 拡張領域へ移動します。そのステレオタイプは『反復』(グリーンの破線で描かれた長方形)として定義されます。
私はこの領域を『トレーディングブロック』と呼びます。それは基本特性を反映しダイアグラムを見やすくします。ブロックの特性は受信オブジェクトに対する処理の循環的実行です。われわれが必要とするのは長短の指示を処理する2サイクルだけです。ブロック入口およびブロックからの出力ではトレード指示オブジェクト(長/短)をインクルードする拡張ノードがあります。
拡張ノードは拡張領域に入る、または拡張領域から出てくるオブジェクトの集合でそれは各オブジェクトに対して一度実行されます。
シグナルを送信するアクションノード(シグナル送信アクション)はシグナル送信を示します。
イベントを受け取るアクションノード(イベント受け取りアクション)は適切なタイプのイベント受け取りを待ちます。
各指示は次のようなノードによって処理されます。「シグナル確認」(シグナル送信ノード)、「シグナル受信」(シグナル受信ノード)、「オープンポジション」(シグナル送信ノード)、「ポジション確認」(シグナル送信ノード)、「ポジションクローズ」(シグナル送信ノード)。指示オブジェクト (dir) は紫の矢印で示されるようにアクションノード間のオブジェクトフロー内で渡されます。ブロック内処理は Expert Adviser がアンロードされる限り続きます。
2.4シーケンス図
オブジェクトの連携シーケンスを記述するためにシーケンス図 を利用します。このタイプのダイアグラムでひじょうに重要な面は時間です。
ダイアグラムには暗黙の形式でスケールが2つあります。横方向はオブジェクトの連携シーケンスに関与します。縦方向は時間軸です。時間間隔は図の上部から始まります。
図の一番上にはダイアグラムオブジェクトがあり、それぞれが連携しています。オブジェクトには縦向きの破線で示されるようにそれ自体のライフラインがあります。オブジェクトはメッセージを交換します。それは矢印で表されています。オブジェクトがアクティブであれば、制御フォーカスを受け取ります。グラフではこのフォーカスはライフライン上の細い長方形として描かれています。
オブジェクトは下線が引かれたオブジェクト名とコロンで区切られたクラス名(オプション)が書かれた長方形です。
オブジェクトライフラインはある期間に対してオブジェクトが存在することを示す線です。線が長いほどオブジェクトは長く存在します。
制御フォーカスは細い長方形として描かれています。その上側はオブジェクトによって制御フォーカスが受け取られる (アクティビティ開始)ことを示し、下側は制御フォーカスの終了(アクティビティ終了)を示しています
UMLではそれぞれの連携はメッセージセットとして記述されます。それはそこに関わるオブジェクトが交換するものです。
少し練習をします。
ターミナルがアクターです。それは Expert Advisorの処理を開始します。『イベント』ステレオタイプでマークされたその他のオブジェクトはクライアントターミナルのイベントです。それらは Init、Deinit、 NewTickです。もちろんお望みであればイベント範囲を拡張することは可能です。Expert Advisor起動時、myTE オブジェクトがグローバルレベルで作成されます。それは CTradeExpertクラスのインスタンスです。クラスオブジェクトは図の中で他のオブジェクトよりもやや下位にあります。それはコンストラクタ関数よりも後に作成されることを示しています。
作成コマンドは一点鎖線矢印でマークされておりメッセージ 1.1 CTradeExpert()を伴っています。一点鎖線矢印はデフォルトのコンストラクタCTradeExpert()の「作成」タイプを示します。CTradeExpertのインスタンスを作成したら、ステップ step 1.2 がアクティブになります。よって制御フォーカスはターミナルに返されます。読みやすくするために、私は 1.1のように同期メッセージを #.# の形式で、 非同期メッセージを #. の形式で表示しています。ターミナルはステップ 2.1でOnInit() 関数を使用してInit イベントを処理し、フォーカスはステップ 2.2で返されます。『呼び出し』タイプのメッセージは先が「黒塗り」の矢印で表示されています。
Init イベントがターミナルに非ゼロ値を返せば、初期化が失敗したことを意味します。ステップ 3.1 は Deinit イベントの作成および処理につながります。ステップ 3.2 において制御フォーカスはターミナルに返されます。それからCTradeExpertクラスオブジェクトが削除されます(ステップ 4.1)。ところで、クラス図を作成する際、クラス内にでストラクチャ関数CTradeExpert をインクルードしませんでした。これは後でもできます。これがダイアグラム構築のメリットの一つです。- 複数のダイアグラム構築プロセスは反復的なのです。最初のダイアグラムに対して行われたことはのちに別のものに対して行われ、またそののち最初のダイアグラムを変更することも可能です。
標準 EA テンプレートのMQL5コードには初期化失敗を処理するブロックが含まれていないことに注意が必要です。私はシーケンスのロジックを保存することを指定しました。UML シーケンス図はガード条件OnInit()!=0を持つ opt ブロックを使用します。それは MQL5 コンストラクションの if(OnInit()!= 0) {}に等しいものです。
ステップ 4.2では制御はターミナルに転送されます。
これでターミナルはイベント NewTick を処理する準備が整いました。
このイベントの処理は無限ループを意味するブロック loop 内で行われます。それは無効にするまで EA はこのイベントの処理を行うということです。ターミナルは OnTick 関数を用いてe NewTickイベントを処理します(ステップ5)。ステップ6では、制御フォーカスは Expert Advisor のmyTEに転送されます。4件の再帰メッセージを利用し、それは次の関数を実装します。 CheckSignal、OpenPosition、CheckPosition、ClosePositionです。再帰性は Expert Advisor オブジェクトがメッセージをそれ自体に送ることに起因します。
また、これら CTradeExpert クラスの関数は loop(2) ブロックに入っています。2というのはループが2つのパスを持つことを意味しています。なぜ2つなのでしょうか?それはトレードの二方向を処理するからです。- ロングとショートです(ステップ7~10)。第11番目のステップでフォーカスはターミナルに渡されます。
ステップ12~13ではそれぞれ再初期化と Expert Advisor オブジェクトの削除を行います。
図10 Test_TradeExpert.mq5に対するSD図
これで初歩のデザインスキルは身につきました。作成されたダイアグラムの助けを借りて、デベロッパーの動作が最適化されます。これでファイル Test_TradeExpert.mq5に対するコードを書き始めることができます。もちろんダイアグラムなしでもそれは可能です。ただ、複雑な Expert Advisorを持っている場合、ダイアグラムを利用することでエラーの可能性が減り、ご自身の TS開発を効果的に管理することができます。
Expert Advisor テンプレートを使用し、これからTest_TradeExpert.mq5を作成します。
グローバルレベルで CTradeExpert myTE クラスのインスタンスを作成します。
OnTick() 関数の本文を書きます。
クラス関数を以下のように記述します。
for(long dir=0;dir<2;dir++) { myTE.CheckSignal(dir); myTE.OpenPosition(dir); myTE.CheckPosition (dir); myTE.ClosePosition(dir); }
このようなものが NewTick イベントを処理していくのです。もちろんまだ、その他メンバの中でクラスデータメンバいによって使用される関数をそれぞれ指定する必要はあります。が、これは後の仕事として残しておきます。ここでの目標はUMLダイアグラムのロジックを MQL5コードに変換することなのですから。
3. UML ダイアグラムに基づくExpert Advisorの作成と提示
例として複雑な Expert Advisorに対するダイアグラムを作成します。MQL5に実装されている既定の戦略コンテキストにおける特性を定義します。一般的にわれわれの Expert Advisor はトレード処理を行います。特に、トレーディングシグナルを作成し、オープンポジションを保持し、資金管理を行うのです。それはどちらかというとテンプレートのトレーディング戦略です。ただしトレーニングのためにこれで作業をしてみます。
まずわれわれの EAに対するユースケースを作成します。ほんのいくらか前述のものとは異なるかもしれません。TSの内的環境に注意を払い、外部環境は無視します(図11)。ここでのコードにはトレーディングタスクのみ実装するからです。
図11 TSのユースケースダイアグラム
ここでExpert Advisorのストラクチャを定義します。標準ライブラリ作成を使用するとします。なぜならそれは述べられている TSの目的と一致しているからです。最近、それは大幅に拡張されました。そして何にもましてそれはトレーディング戦略のクラスに関連しています。よって目標はクラス図の作成です。それは簡単なものではありません。練習が必要です。
ここでいくつかの理由により標準ライブラリを考えることに注意したいと思います。まず、それを基に売買ロボットを作成しようとすることです。二番目に、これもまた重要ですが、UML ダイアグラムで作業する練習をいくらかすることです。三番目にライブラリ自体がひじょうに価値があるからです。ライブラリから多くの有用なことがらを学び、同時にそのあまりシンプルとは言えないストラクチャを理解しようとすることができます。
UML ダイアグラムのストラクチャにおけるコード変換はリバースエンジニアリングと呼ばれます。実際、われわれはこれを手動で行っています。これを自動で行えるようにする専用のソフトウェアがあります(IBM Rational RoseやVisual Paradigm for UMLなど)。ただ実用のためには「手動」で作業する必要があると思います。
『クラス』ブロックを使用してトレーディング戦略 CExpertを実装するための基本クラスのモデルを作成します。CExpertクラスの本文でその他どのクラスやコンストラクションが使用されるか見てみます。まず、CExpert クラスは基本クラスCExpertBaseから派生したものではないことに注意が必要です。それは今度は基本クラスCObjectから派生するものです。
ダイアグラムではこれらクラスに対してブロックを作成し、クラス間の関係を定義します。その際『白抜きの』矢線(一般化)を用います。CExpert クラス(角の折れ曲がった黄色の長方形)のモデルにコメントを追加します。仲介クラスストラクチャは図12のようになります。この図をExpertと呼びます。
図12 Expert 図初期表示
Expert.mqh ファイル内のコードを見ます。その他の事柄の中でクラス CExpertは列挙 ENUM_TRADE_EVENTS および 8個の定義済みストラクチャ MqlDateTimeの一つであるENUM_TIMEFRAMESを含みます。このクラスはまた他のクラスインスタンスを使用します。それは次のようなものです。CExpertTrade、CExpertSignal、 CExpertMoney、CExpertTrailing、 CIndicators、CPositiontInfo、 COrderInfo.
ここで図にいくらか変更を加える必要があります。まず、クラス CExpertSignal、CExpertMoney、 CExpertTrailing は基本クラス CExpertBaseから派生し、クラス CPositiontInfo、COrderInfo はCObject(これに対してはステレオタイプ"metaclass"を設定しました) から派生します。
CExpert クラスとその他クラスのブロック間の"use"ステレオタイプを持つ依存関係をマークします。MqlDateTime ストラクチャと列挙を忘れないようにします。ブロックの色を変更し、次のストラクチャ、図13を取得します。
図13 Expert 図初期表示
ただし、このストラクチャは全体像を反映していません。なぜならすでに述べたクラスによって間接的に使用されるクラスが数多くあるからです。それらはどのような類のクラスでしょうか?まず CTradeからCExpertTrade クラスが派生します。CTradeはCObject.のサブクラスです。
CExpertTrade クラスはENUM_ORDER_TYPE_TIME 列挙で、クラスCSymbolInfo および CAccountInfo もまたCObjectから派生するものです。CTrade クラスはまたCSymbolInfo クラスのインスタンスを使用します。図に変更を加えます。これでわれわれの図は次のようになりました- 図14。
図14 Expert 図初期表示
しかしまだ図は完成ではありません。たとえば、標準ライブラリファイルTrade.mqhを見る場合、CTrade は複数の異なるストラクチャ、列挙、CSymbolInfo クラスを取るのが解ります。それをすべて図いn表示すると負荷がかかりすぎます。そして理解しづらくなります。
この困難に対処するために、私はダイアグラム用のパッケージを使いました。そのパッケージは関連するクラス、列挙、その他パッケージなどをカプセル化します。インターフェースによって図エレメントを持つパッケージを関連づけたのです。たとえばパッケージ用ダイアグラム CTrade は次のように提示されます ( 図15)。
図15 CTrade パッケージ用クラス図
CTrade パッケージのダイアグラムは CTrade クラスの 列挙とストラクチャへの依存関係を示します。
基本クラス CObject と使用される CSymbolInfo クラスとの関係はインターフェースによって実装されます。
インターフェースの近くには単一エレメントとして CTrade パッケージを持つクラス図との関係のアイコンがあります。インターフェースをどれかクリックすると自動的に元の図に戻ります(図16)。
Fig. 16. インターフェースを伴う Expert 図
インターフェースの関係はオレンジで示しています。 CTrade パッケージの隣のクラス図アイコンはこの図を移動する機能を示しています。このようにカプセル化を使うとクラス図が格段に見やすくなるのです。
それでは先に進みます。CObject クラスは本文の同じクラスのインスタンスに対してポインターを取ります。これでCObject ブロックに対して、それ自体に関連するステレオタイプ "use" との依存関係を設定することができます。
CExpertBase クラスモデルのブロックを見ていきます。ヘッダファイルExpertBase.mqhの最初の行に基づき、このクラスは多様なクラスと列挙の複数インスタンスを使用すると言えます。よってクラスモデルとその関係についてはパッケージ CExpertBaseを作成するのが合理的です。
そこでまずパッケージ図内に CExpertBase クラスモデルを決めます。インターフェースによって基本クラス CObjectとの関係、クラス CSymbolInfo および CAccountInfoとの使用関係を示します。それからクラスのブロックと依存関係を利用し、 CExpertBase クラスが以下のクラスを使用するよう指定します。CiOpen、CiHigh、CiLow、 CiSpread、CiTime、 CiTickVolume、CiRealVolumeです。
最初の4つのクラスは CPriceSeriesから派生し、あとの4つはCSeriesから派生しています。その上、 CSeries クラスはそこからの派生クラス CPriceSeries を持ち、これ自体は CArrayObjから派生しています。継承関係を以前に利用したことは記憶にあるとおりです。それらをダイアグラム内の一般化関係として表示します。
クラス CExpertBase はその本文に次のような列挙を取ることを忘れないようにします。ENUM_TYPE_TREND、 ENUM_USED_SERIES、ENUM_INIT_PHASE、ENUM_TIMEFRAMESです。最後の列挙はクラスCPriceSeries および CSeriesの派生クラスでも使用されます。関係性を失わないため、また図を理解しやすくするために、図の各エレメントのスタイルを調整します。結果が以下の図です(図17)。
図17 CExpertBase パッケージのクラス図
しかしまだ完成ではありません。もうすこし手を加える必要があります。 CPriceSeries クラスを継承する4つのクラスもまた CDoubleBuffer クラスを利用します。その上、4つのクラスはそれぞれCDoubleBufferから派生するバッファクラスを使います。ということはCOpen はuses COpenBuffer を使用する、などです。CDoubleBufferは基本クラス (CArrayDouble) を持ち、ENUM_TIMEFRAMESを使用します。
CArrayDouble はCArrayを継承し、その同じクラスのインスタンスと ENUM_DATATYPE列挙 に対してポインターを使用します。COpenBuffer クラスとその他価格系列のバッファクラス(CHighBuffer、CLowBuffer、 CCloseBuffer)はENUM_TIMEFRAMES 列挙を使用します。
CSeries クラスを継承する4つのクラスは それら自体のバッファクラス(CSpreadBuffer、 CTimeBuffer、CTickVolumeBuffer、 CRealVolumeBuffer)のみ使用します。最初のクラスバッファ CSpreadBuffer はinherits CArrayIntを継承し その他は CArrayLongを継承します。最後の2つのクラスはそれ自体のクラス、ENUM_DATATYPE列挙のインスタンスに対してポインターを使用し CArrayから派生しています。それ自体ははクラスCObjectから派生しているものです。
CPriceSeriesクラスおよびその派生クラスは CDoubleBuffer クラスとENUM_TIMEFRAMES列挙を使用します。
CSeriesが使用するのは 列挙 ENUM_SERIES_INFO_INTEGER、 ENUM_TIMEFRAMESです。それはw CArrayObjを継承します。後者はCArrayを継承し、ENUM_POINTER_TYPE、それ自体のクラスのインスタンスにおけるポインター、CObject クラスを使用します。結果、図18に示されるダイアグラムを取得します。
図18 CExpertBase パッケージに対して拡張されたクラス図
And the original diagram クラスおよびインターフェースを持つパッケージCExpert、CExpertBase、CSymbolInfo、 CAccountInfo 、 CObject に対する元のダイアグラExpertは以下です(図19)。
図19 インターフェースを伴う Expert 図
CExpertTradeによって使用される列挙 ENUM_ORDER_TYPEも追加しました。読みやすくするため、関係のあるグループ別に色を変えてマークしました。
作業を続けます。ロジックをご理解いただけているとよいのですが。図にあるクラスモデルはその他のクラスやエンティティと多くの関連があります。よって基本図の中にパッケージセットをいくつか入れます。
そこでCSymbolInfoを調べます。SymbolInfo.mqhのコードを見たら、基本クラスCSymbolInfoがいくつかMQL5 の列挙とストラクチャを使用しているのが判ります。それとその関係に用のパッケージを使用するのがよいでしょう (図20)。
図20 CSymbolInfo パッケージ図
図の中の空スペースはコメント用に使用できます。また親クラス CObjectと関連するインターフェースはマークしました。パッケージおよびクラスの元ダイアグラム Expert にはやや変更を加えました。すべてのクラスとパッケージが図に反映されたら、のちにそのアップデートバージョンを提供します。
それでは先に進みます。AccountInfo.mqh内の MQL5コードを見ます。結局のところ CAccountInfo もまたいくつか列挙を使用します。それらをこのクラスと他のエンティティとの関連に対して作成するパッケージ図上に反映します(図21)。
図21 CAccountlInfo パッケージ図
ここからCExpertクラスに取り組みます。このクラスに対してもパッケージ CExpertを作成します。それは図22のようなものとなります。メインの図を読みやすくするように改善を続けます。CExpert クラスはその他複数クラスと連携しておりそれを示しているのはオレンジのインターフェースの矢線です。
図22 CExpert パッケージ図
残りのクラスも見ていきます。それらについてさらにパッケージを作成します。
CExpertSignal は CExpertBaseから派生しています。この関係はすでに元ダイアグラム Expertで示しました。またCExpertSignal クラスは CArrayObj、 COrderInfo、 CIndicators とそれ自体のクラスのインスタンスを使用します(図23)。特に、CArrayObj クラスとの関連のインターフェースはCExpertBase パッケージ図に連れて行きます。それはCArrayObj クラスの他のエンティティとの関係を示すものです。
図23 CExpertSignal パッケージ図
ここではすべての図を表示していません。 - すべては添付ファイル Expert.simpで利用可能です。ではアップデートしたパッケージおよびクラス図Expert を見ます(図24)。
ご覧のとおり、ほとんどすべてのダイアグラム内主要クラスはパッケージにカプセル化され、図が解りやすくなっています。一般化の線を茶色に変更し、依存関係の線と区別しました。
図24 パッケージおよびクラス図 Expert
ダイアグラム作成のために標準ライブラリ内で利用可能なコードから得られるものはすべて反映しました。Expert Advisorのトレーディング処理を指定するあといくつかブロックを追加するだけです。
一番最初のブロックは CmyExpert で、これは CExpertクラスのトレーディング『スキル』を継承しています。これはリバースエンジニアリングにおいて長らく取り組んできたブロックです。このブロックは指定のトレーディング戦略を実装するものです。また EAの基本クラスの仮想関数も指定する必要があります。
このためにクラス CmyExpertSignal、 CmyExpertMoney、 CmyExpertTrailing のブロックを作成し、適切なものから派生するよう指示します(図25)。
図25 拡張されたパケージおよびクラス図 Expert
各クラスがインクルードすべき関数やデータはデベロッパーによります。ここでは派生クラスの特殊な実装ではなく、より一般的なスキームを提示します。各派生クラスに対してインクルードされるメソッドおよびプロパティの詳細リストを持つ個別のダイアグラムを作成することができます。たとえば図8で見たようなものです。
それではわれわれの作業でシーケンス図を利用する方法を見ていきます。それは時間系列に関しての EA がどのように処理を行うか示していることを思い出していただきたいと思います。
というわけで、年代順で EA動作の詳細を書き出します(図26)。
図26 Expert Advisorのシーケンス図
ターミナルはアクターの役割をします。それはグローバルレベルで myTrader オブジェクト、CmyExpertのインスタンスを作成します(ステップ 1.1)。グリーンで示されているのはクライアント端末(Init、Deinit、 NewTick、Trade)の定義済みイベントです。シーケンス図のロジックは以前に述べられています。ここでいくつか特別な点を指摘したいと思います。When the body of the Expert Advisor の本体が大きくなり、コードがどんどん増えると、それを図示するのは難しくなります。
この問題を解決するにはブロック法を利用します。いくつか共通の関数セットをブロック形式で可視化します。結果、別のシーケンス図となります。それは相互使用と言われます。
今回の場合、個別のダイアグラムでターミナルイベントInitを処理するロジックを反映するため OnInit と呼ばれるシーケンス図を作成しました。構文的にはキーワードref (reference)で境界として定義され、制御トークンが OnInit(ステップ2.1) からInit オブジェクトのライフラインに渡すとき使用されます。
その上、OnInitに対してこのシーケンス図へのインターフェース移動を設定しました。これは、境界で2度クリックすると OnInit の詳細シーケンス図を開くことができるというものです(図27)。
図27 OnInitのシーケンス図
他のシーケンス図への移動いくつかのアクションの反復にはひじょうに好都合です 。
たとえば OnInit ダイアグラムには EA 再初期化に関連するアクションが含まれ、その処理は myTrader_Deinit で行われます(図28)。
図28 myTrader_Deinitのシーケンス図
通常 EA 設計のこの段階で、シーケンス図を4つ取得します。当然もっと本格的な開発中にはそれ以上のダイアグラムが必要になると思われます。たとえば、私はクライアント端末のその他イベント(NewTick、Trade)は処理しませんでした。
おわりに
本稿では 、オブジェクト指向のソフトウェアシステムのビジュアルモデル化に使用されるUML グラフィカル言語を用いたExpert Advisorの開発過程の多次元的特性を考慮することを提案しました。この方法のおもなメリットは設計者の可視化です。
複雑な現象はくらでもあるでしょうが、UML にはそれ自体の開発者が知っておくべきデメリットがあります(冗長性、精度の低い構文など)。
述べられている EA 開発の方法論がみなさんにとって興味をひくものであることを願っています。本稿に対するコメントおよび建設的批評をいただけるとうれしく思います。
ファイルの保存場所
# | ファイル | パス | 内容 |
---|---|---|---|
1 | TradeExpert.mqh | %MetaTrader%\MQL5\Include | Expert Advisor クラス |
2 | Test_TradeExpert.mq5 | %MetaTrader%\MQL5\Experts | Expert Advisor |
3 | Expert.simp | %Documents%\UML projects | UML ダイアグラムプロジェクト |
4 | SoftwareIdeasModeler.4.103.zip | %Program Files%\SoftwareIdeasModeler | Software Ideas Modeler 配布ファイル |
参考文献
- Free UML courses. The Internet University of Information Technology
- Jim Arlow, Ila Neutstadt. UML2 and the Unified Process Practical: Object-Oriented Analysis and Design
- Leonenkov A. Object-Oriented Analysis and Design Using UML and IBM Rational Rose.
- Martin Fowler UML Distilled: A Brief Guide to the Standard Object Modeling Language. - 192 стр.
- Paul Kimmel. UML Demystified. - 272 стр.
- F. A. Novikov, D. Y. Ivanov. Modeling in UML
- Mark Priestly. Practical Object-Oriented Design With Uml, Mcgraw Hill Higher Education; 2nd edition, 2007.
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/304





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