
初心者のためのクイックスタート、あるいはショートガイド
はじめに
読者の皆さんこんにちは!この記事では、Expert Advisorsの作成やインディケーターの使い方などの基本的なコツを簡単に素早く掴めるように説明していきたいと思います。初心者対象で難しいサンプルの紹介は行いません。ですので、この記事はExpert Advisorのプログラムをすでに理解している人たちには退屈で有益ではないかもしれません。
Expert Advisorとその構造
Expert AdvisorMQL言語で書かれたプログラムで、トレードを行うか横に据え置くかを特定します。
基本的にはEAは多くのブロックで構成することができますが、簡単に理解できるよう、MetaEditorで作成されたとてもシンプルな例をお見せします。
EA全体はそれぞれ受け持つ動作がある4つのパートに分けることができます。
図 1. EAのメインブロック
- パラメータのブロックターミナルがEAを正しく処理するための情報を含むブロック。もっとも一般的なパラメータはEAのバージョン、開発者名、簡単な説明です。
- OnInit()ブロックはEAがターミナルにロードされるとコントロールできるようになります。EAの初期化に関する様々なデータを含みます - 変数の宣言や配列、インディケーターハンドルの取得など。これは、このブロックにはトレーディングに直接関係する関数は含まれていないということです。
- OnDeinit()ブロック OnInit()ブロックの逆の役割を果たします。EAがオペレーションを完了した時に呼びだされます(EA/ターミナルのシャットダウンやEAの初期化の失敗)。このブロックの主な役割の1つが必要のなくなったEAが占めるメモリスペースの解除です、言い換えると、変数、配列、インディケーターハンドル等の削除プロセスを記述します。
- OnTick() Blockはシンボルの新しい情報をサーバーから受信するたびに呼び出されます。トレードをするための状況とトレード自体の関数を指定します。
図 2. MetaEditorのデフォルトで生成されたドキュメントの例
上の例を用いて説明したいと思います。まず”空の”Expert Advisorがあります。後で埋めていくことになるExpert Advisorのテンプレートのようなものです。
次のことが分かります:
- 最初の5行(1行目から5行目)はEAの名前 (ファイル名)、EAの製作者名とそのWebサイトを含むコメントを表しています。ここには何を書いても良いです。このテキストはどこでも見られませんし、スキップすることも可能です。ここに含まれる情報は開発者のみを対象としています;
- 次の3行(6行目から8行目)はパラメータブロックになります。ここの情報はEAをターミナルで開始した時に見ることができます;
- 次に来るのがOnInit()関数です (12行目から19行目)。これはOnInit()ブロックです。この関数はパラメータを取得しませんが、初期化コードを返します(返さないかもしれませんが); the initialization code;
- OnDeinit(const int reason) 関数が次に来ます(22行目から26行目)。これがOnDeinit()ブロックです。EAのシャットダウンの理由を特定するパラメータです。
EAの初期化が失敗した場合、この関数が関連するコードを受け取ります; - 最後の関数はOnTick()(30行目から34行目)です。これはOnTick() ブロックの中に記述されいます。このブロックはEAの”頭脳”と呼ぶこともでき、トレードに関するすべての関数から成るブロックです。
前述のとおり、この構造は何倍も複雑になることもあり、今回のように簡単に全体を把握することができないものもあります。これが十分でないと感じるならば、自分のブロックを追加することができるのです。
インディケーターとその処理方法
インディケーターは MQLで書かれた小さなプログラムで、プライスチャートやその下の別のウインドウに表示され、マーケットのテクニカル分析を行うために使用されます。
すべてのインディケータは2つのタイプに分類できます:トレンドフォロー型のインディケーターとオシレーターです。
トレンドフォロー型のインディケーターは、ルールとして、プライスチャート内に描画され、トレンドの方向を特定するのに使われ、オシレーターはプライスチャートの下にあり、エントリーポイントを判断するのに役立ちます。
ほとんどのインディケーターは、最低1つのバッファ(インディケーターバッファ)を持ち、ある時点での自身の読み取りデータを格納しています。EAと同じように、インディケーターも計算するためのシンボルとタイムフレームを持っています。
インディケーターバッファは、最後の要素が現在値(running value)である列と考えることができます。
図 3. 移動平均インディケーターの例
インディケーターバッファは、最初の要素(インデックスが0)が右端の足のデータを持ち、次の要素が(インデックスが1) 右から2番目の足のデータを持ち・・・という配列です。このような要素の構成はタイムシリーズと呼ばれます。
次の例を見てみましょう:通貨ペアはEUR/USDでタイムフレームは1時間だとしましょう。
まず最初に、EAにインディケーターを追加してそのハンドルを取得します。
ハンドルは固有のポインタで、インディケーターがプログラムのどこにあっても処理することを可能にします。
int iMA_handle; iMA_handle=iMA("EURUSD",PERIOD_H1,10,0,MODE_SMA,PRICE_CLOSE);もう少し詳しく見てみましょう。
最初の行ではインディケーターハンドルを格納する変数を定義しています。2行目ではインディケーターを呼び出し(ここでは移動平均インディケーター)そのパラメータを指定し、後で使うためにハンドルを変数に保存しています。
図 4. 移動平均インディケーターのパラメータを表示するツールチップの例
左から順に以下のパラメータが表示されているのが分かるはずです:
- シンボル名(ツールチップでは太字で表示)はテキストパラメータで、通貨ペア(シンボル)です;
- タイムフレーム;
- インディケーターの期間(ここでは平均的な期間);
- チャートシフトN本進める/戻す。チャートシフトが正の数の場合は、N本進め、負の場合はN本戻します;
- 平均方法;
- 適用されたプライス あるいは異なるインディケーターのハンドル
それぞれのインディケーターには独自の変数と型があります;見たことのないインディケーターに出会った場合は、ビルトインのコンテキストヘルプで情報を得ることができます。例えば、iMAと入力しF1を押すと、その特定のインディケーターのヘルプウインドウが表れ、詳しいプロパティを見ることができます。
図 5. F1を押して詳しい説明を見るためのヘルプウインドウを呼び出す例
コードを書いてEAをターミナルで開始すると(プライスチャートの右上にEAが表れると)、そのインディケーターはチャート上から消えるのが分かると思います。これはエラーではありません - そうなるべきものです。それが表れるためには、もう1行必要になります:
ChartIndicatorAdd(ChartID(),0,iMA_handle);
これが何をしているのかを見てみましょう。ChartIndicatorAddコマンドの上にカーソルを置いて、F1を押しコマンドの目的に関するヘルプインフォメーションを読んでみましょう。そこにはこう書かれています:
特定のハンドルを持つインディケーターを特定のチャートウインドウに追加する。
2つ目の0に等しいパラメータはサブウインドウの数です。サブウインドウには大抵、プライスチャートの下にオシレーターがあります。覚えていますか?それは大量かもしれません。インディケーターをサブウインドウに表示するには、既に存在しているサブウインドウの数よりも1多い、サブウインドウの数を指定するだけで良いです。つまり最後のサブウインドウの数+1ということです。
次のようにコードを変更しました:
ChartIndicatorAdd(ChartID(),1,iMA_handle);
これで、インディケーターはプライスチャートの下のサブウインドウに表示されます。
それでは、インディケーターからデータを取り出してみましょう。そのためには、動的な配列を宣言し 、便宜的に配列のインデックスをタイムシリーズとして配置し、インディケーターの値をこの配列にコピーします。
double iMA_buf[]; ArraySetAsSeries(iMA_buf,true); CopyBuffer(iMA_handle,0,0,3,iMA_buf);
上記の例では、移動平均インディケーターとして宣言したダブル型の動的な配列 iMA_buf[]はプライスに基づいており、プライスは分数を持っていることが示されています。
次の行では配列のインデックス化の設定を行っています。インデックスの小さいほど古い値を、大きなインデックスは新しい値を格納しています。これは、すべてのインディケーターのインディケーターバッファはタイムシリーズとしてインデックスされているため、混乱を防ぐのに便利です。
最後の行はiMA_buf[]の配列にインディケーターの値をコピーするための行です。これで、これらのデータが使えるようになりました。
オーダー、トレードとポジション
オーダーから始めましょう。
-
オーダーはトレードサーバーによって受け取られるトレードのリクエストです。リクエストが無効な場合、拒否されます。
トレードリクエストを満たす難しさを避けるための、標準ライブラリを使用した簡単な方法を後ほど解説します。オーダーには2つのタイプがあります:マーケット(即座に実行されます)と指値です。
マーケットオーダーとは特定の投資対象を市場価格で、あるボリュームで売買するということです。指値注文は、投資対象がある条件を満たしたときに実行される命令を表します。指値注文にはそれを取り消される一定の期間があります。
-
トレードとは実行された注文(トレードを実行する命令)の結果を表します。すべてのトレードは、ある1つの注文に基づきますが、1つの注文は複数のトレードによって行うことができます。例えば、10ロットの買い注文は、連続する複数のトレードによって実行することができます。トレードはトレード履歴に保存され、変更することはできません。トレードはターミナルの”過去データ”タブに表示されます。
-
ポジション実行中の注文の結果を表します。1つの通貨ペアに対し、ロングかショート、いずれかのポジションを開くことができます。
分かりやすくするために、例を使って説明させてください:1ロットのロングのポジションを開きました、現在のマーケット価格で1ロットの注文を出したということです。リクエストが正しければ、サーバーに送られ処理されます。処理が終了次第、ポジションとオーダーパラメータがターミナルの”トレード”タブに表示されます。もう1つ、1ロットのロングポジションを取ることを決めたとします。注文の処理が終了しても”トレード”タブには2つのトレードは表れませんが、1つのポジションのサイズが2ロットになります。つまり、ポジションとは複数の注文の実行の結果であるということです。
それでは、実際にみてみましょう。リクエストをするためには、次のストラクチャフィールドを埋めていかなければいけません:
struct MqlTradeRequest { ENUM_TRADE_REQUEST_ACTIONS action; // Type of action ulong magic; // Expert Advisor ID (magic number) ulong order; // Order ticket string symbol; // Trade instrument double volume; // Requested trade size in lots double price; // Price double stoplimit; // StopLimit level of the order double sl; // Stop Loss level of the order double tp; // Take Profit level of the order ulong deviation; // Maximum allowed deviation from the requested price ENUM_ORDER_TYPE type; // Order type ENUM_ORDER_TYPE_FILLING type_filling; // Order type by execution ENUM_ORDER_TYPE_TIME type_time; // Order type by duration datetime expiration; // Order expiration time (for orders of the ORDER_TIME_SPECIFIED type) string comment; // Comment to the order };
様々なオーダーがあるため、それぞれのオーダーのタイプによって、必須パラメータがあります。これらのフィールドについては長く説明ません。この問題に関しては、Webサイトで多くの情報を提供しているからです。あるオーダーの必須のパラメータが、指定されていなかったり、不正だった場合、リクエストは失敗します。
上のストラクチャは、それを埋める段階になった時に生じる問題を見やすくするためのものです。
ストップロスとテイクプロフィット
ストップロスとテイクプロフィットは ”代替策”として出される特別注文です。つまり、ミスやvExpert Advisorによって開かれたポジションに損失がある場合、ストップロス注文は、そのロスを好みのレベルに設定できます。
テイクプロフィットも同じですが、限定するのは損失ではなく利益であるということです。ポジションと閉じる心配をしなくてすむようになるかもしれません。あるプライスレベルになると、ポジションは閉じられます。言い換えれば、これらの注文は”保険”だということです。マーケットで損失を出すか、利益をあげるか。
このタイプの注文はそれだけで出すことはできません -すでに持っているポジションに対して変更するだけです。
標準ライブラリの使用
ついに、標準ライブラリまできました。このライブラリはターミナルに付属していることから-標準ライブラリと呼ばれます。EAのプログラミングを容易にする関数と複雑な処理を請け負う関数で構成されています。
トレードライブラリ(トレードクラスをご参照ください)は次のパスに置かれています:Include\Trade\ #includeディレクティブを使用して追加することも可能です。
例:
#include <Trade\Trade.mqh> #include <Trade\PositionInfo.mqh>
上記のクラスは基本的なものと言えます。Expert Advisorの多数はこの2つのクラスを使ってプログラミングされるからです。それらをライブラリと呼びます:
- 1つ目はオーダーを出したり、変更したりするためのものです。
- 2つ目は、すでに存在するポジションの情報を取得するのに使われます。
他のライブラリが有用なこともあります:
#include <Trade\OrderInfo.mqh>
オーダーに関する関数を含みます。例えば、ストラテジーに指値注文の使用が必要な場合。正しく知識を利用しなければならない様々なパラメータを含むトレードリクエストストラクチャを覚えていますか?
ここでは、ライブラリを使ったトレードリクエストのサンプルを見ていきます:
CTrade m_Trade; m_Trade.Sell(lot,symbol_name,price,sl,tp,comment);
合計6つのパラメータがあります。そのうち1つが必須です(オーダーのサイズ-1つ目のパラメータです)。
1つずつ見てみましょう:
- lotオーダーのサイズ;
- symbol_nameオーダーを出すシンボル(通貨ペア)(指定が無ければ、EAを使用中の通貨ペア)
- price オープンプライス(アクティブなオーダーを出す関数であるため、そのプライスが特定できない場合はチャートから自動的に直接取得されます);
- slプライスが有利でなければ、オーダーを閉じるプライス(ストラテジーがストップロスを使用しない場合、省略可)
- slプライスが望む希方向へ動けばはオーダーを閉じるプライス。(ストラテジーがテイクプロフィットを使用しない場合、省略可)
- commentオーダーに関するコメント、オーダーを出した理由等。
ポジションを閉じる方法は多くあります:
-
ポジションをすべて閉じる
CPositionInfo m_Position; m_Position.Select(symbol_name); m_Trade.PositionClose(symbol_name);
-
反対に同じサイズの注文を出すことによって注文を閉じる
CTrade m_Trade; m_Trade.Buy(lot,symbol_name,price,sl,tp,comment);
-
より複雑な方法をを使い、すべてのポジションの中から、さらに閉じるための特定のパラメータ (通貨ペア、型、マジックナンバー、ポジション識別子など)を持つポジションを探し出す。上の例は初心者には難しすぎるので、ここでは出しません。
全てを1つに
新しく得た知識を1つのExpert Advisorに注ぎ込むには良いタイミングでしょう。
//+------------------------------------------------------------------+ //| fast-start-example.mq5 | //| Copyright 2012, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2012, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ #include <Trade\Trade.mqh> //include the library for execution of trades #include <Trade\PositionInfo.mqh> //include the library for obtaining information on positions int iMA_handle; //variable for storing the indicator handle double iMA_buf[]; //dynamic array for storing indicator values double Close_buf[]; //dynamic array for storing the closing price of each bar string my_symbol; //variable for storing the symbol ENUM_TIMEFRAMES my_timeframe; //variable for storing the time frame CTrade m_Trade; //structure for execution of trades CPositionInfo m_Position; //structure for obtaining information of positions //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int OnInit() { my_symbol=Symbol(); //save the current chart symbol for further operation of the EA on this very symbol my_timeframe=PERIOD_CURRENT; //save the current time frame of the chart for further operation of the EA on this very time frame iMA_handle=iMA(my_symbol,my_timeframe,40,0,MODE_SMA,PRICE_CLOSE); //apply the indicator and get its handle if(iMA_handle==INVALID_HANDLE) //check the availability of the indicator handle { Print("Failed to get the indicator handle"); //if the handle is not obtained, print the relevant error message into the log file return(-1); //complete handling the error } ChartIndicatorAdd(ChartID(),0,iMA_handle); //add the indicator to the price chart ArraySetAsSeries(iMA_buf,true); //set iMA_buf array indexing as time series ArraySetAsSeries(Close_buf,true); //set Close_buf array indexing as time series return(0); //return 0, initialization complete } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { IndicatorRelease(iMA_handle); //deletes the indicator handle and deallocates the memory space it occupies ArrayFree(iMA_buf); //free the dynamic array iMA_buf of data ArrayFree(Close_buf); //free the dynamic array Close_buf of data } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { int err1=0; //variable for storing the results of working with the indicator buffer int err2=0; //variable for storing the results of working with the price chart err1=CopyBuffer(iMA_handle,0,1,2,iMA_buf); //copy data from the indicator array into the dynamic array iMA_buf for further work with them err2=CopyClose(my_symbol,my_timeframe,1,2,Close_buf); //copy the price chart data into the dynamic array Close_buf for further work with them if(err1<0 || err2<0) //in case of errors { Print("Failed to copy data from the indicator buffer or price chart buffer"); //then print the relevant error message into the log file return; //and exit the function } if(iMA_buf[1]>Close_buf[1] && iMA_buf[0]<Close_buf[0]) //if the indicator values were greater than the closing price and became smaller { if(m_Position.Select(my_symbol)) //if the position for this symbol already exists { if(m_Position.PositionType()==POSITION_TYPE_SELL) m_Trade.PositionClose(my_symbol); //and this is a Sell position, then close it if(m_Position.PositionType()==POSITION_TYPE_BUY) return; //or else, if this is a Buy position, then exit } m_Trade.Buy(0.1,my_symbol); //if we got here, it means there is no position; then we open it } if(iMA_buf[1]<Close_buf[1] && iMA_buf[0]>Close_buf[0]) //if the indicator values were less than the closing price and became greater { if(m_Position.Select(my_symbol)) //if the position for this symbol already exists { if(m_Position.PositionType()==POSITION_TYPE_BUY) m_Trade.PositionClose(my_symbol); //and this is a Buy position, then close it if(m_Position.PositionType()==POSITION_TYPE_SELL) return; //or else, if this is a Sell position, then exit } m_Trade.Sell(0.1,my_symbol); //if we got here, it means there is no position; then we open it } } //+------------------------------------------------------------------+
このExpert Advisorを以下のパラメータでテストしましょう:
- 通貨ペア- EURUSD;
- タイムフレーム - H1;
- トレードモード”オープニングプライスオンリー”。
1つ目の足(0番目の足は現在アクティブな足)から、インディケーター値と閉じるプライスを使用するため、チャートは再描画されません。”オープニングプライスオンリー”のトレードモードを使用できるということです。これはテストの質には影響しませんが、テストを早く行うことができます。
過去のデータを使ったクイックテストの結果です。
図. 6. Expert Advisorのテスト結果
ドローダウンを見逃すことはできません。しかし、この記事の目的は、最少のドローダウンで大きな利益を上げる”スーパーなExpert Advisor”のプログラミングではありません。基本的な知識を持つだけでどれほど簡単にEA を作ることができるのかを示すことです。
100行未満のコードのExpert Advisorを作ることができました。
まとめ
この記事ではEAのプログラミングにおける重要な基本事項をカバーしています。MetaEditor 5のビルトインのヘルプメニューから様々な関数に関する情報や、注文やポジションに基本的な考え方、内蔵されている標準ライブラリの使用などの情報を得る方法を学びました。
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/496





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