Meta Trader 4 における自動取引システム (Expert Advisor) 作成

# はじめに
[Meta Trader 4 の基本的な使い方](http://qiita.com/Salinger/items/4fe247f27418e4dc734e) では Meta Trader 4 (MT4) の基本的な使い方を説明しました。また MT4 のカスタム指標作成や自動取引の際に利用するプログラミング言語 MQL の開発環境は [Sublime Text 3 による MQL 開発環境の構築](http://qiita.com/Salinger/items/be5dcc6f686b9fe07d9e) で説明しました。そして前回 [Meta Trader 4 におけるカスタム指標の作成](http://qiita.com/Salinger/items/55b4299fba59026aa6a7) では MQL を用いてカスタム指標を作成しました。

今回はブレイクアウト戦略と呼ばれる手法を用いて自動取引を行うシステム (Expert Advisor: EA) を構築し、仮想口座で取引を行ってみます。

# MT4 の基本的な使い方 & 開発環境設定
環境構築から MQL で記述したプログラムの実行までは前回までの記事を参考にしてください。

# ブレイクアウト戦略

* 一定期間の最高値を超えたら上昇トレンドとみなし買い(ロングポジションをとる)。
   * この際ショートポジションは全て決済。
* 一定期間の最安値を下回ったら下降トレンドとみなし売り(ショートポジションをとる)。
   * この際ロングポジションは全て決済。
* 注文は成行注文で。

![breakout.tiff](https://qiita-image-store.s3.amazonaws.com/0/58390/8b939987-0d0e-80a0-307a-f5b324fadc85.tiff)

具体例として画像ような状況を考えます。ある期間（画像の赤のライン間）の最安値は青のラインとなります。次の単位時間（グレーの部分）に達した際、最安値が青いラインを割り込みます(break out)。このとき下降トレンドとみなし、持っていたロングポジションを全て決済し、新たにショートポジションをとります。

# プログラムの構造
## 起動 & 終了 に関する関数
MQL4 では `init()` 、 `start()` 、 `deinit()` という特殊な関数が存在します。

* init():
   * チャートにEAを追加した際に実行される。
* start():
   * init() 実行直後 & 価格が更新されるたびに実行される。
* deinit():
   * 以下の条件で実行される。この関数は 2.5 秒以内に実行終了しなければならない。
      * チャートが閉じられる時。
      * チャートの表示期間や通貨が変化する前。
      * プログラムの再コンパイルが成功した時。
      * 設定が変化した時。
      * アカウントが変化した時に実行。

基本的にはカスタム指標と同じです。

## 取引関係の関数

![取引関数.tiff](https://qiita-image-store.s3.amazonaws.com/0/58390/84be0186-a64b-b8d6-aa0c-78743918a296.tiff)

上記の画像は、取引に用いる基本的な関数と取引の状態遷移をまとめたものです。

* [OrderSend()](http://www.metasys-seeker.net/MQL4_Reference_ver1/20-18_OrderSend.html): オーダー送信
* [OrderModify()](http://www.metasys-seeker.net/MQL4_Reference_ver1/20-12_OrderModify.html): オーダー修正
* [OrderClose()](http://www.metasys-seeker.net/MQL4_Reference_ver1/20-02_OrderClose.html): ポジション決済
* [OrderDelete()](http://www.metasys-seeker.net/MQL4_Reference_ver1/20-08_OrderDelete.html): 注文キャンセル

## 必要なパラメータ
* Magic: EA 識別のため、固有のマジックナンバーを指定する。
* Lots: ロット数 (100,000 通貨単位)
* BreakPeriod: ブレイクアウト戦略でトレンド判定に使用する期間。チャートの足 N 本。
* Slippage: プログラムが計算したタイミングと決済価格の差の許容範囲。N pips。
* StopLoss: 安全のため損失がこの値に達した際ポジション決済。N pips。
* ClosePeriod: この期間が過ぎても決済されない場合はポジション決済する。 チャートの足 N 本。

# サンプルプログラム

以下のコードがブレイクアウト戦略のサンプルプログラムです。

`OrderSend()` で StopLoss や TakeProfit を直接設定せず、`OrderModifiy()` で後に設定したのは業者によっては `OrderSend()` で設定しようとした場合に `OrderSend error = 130` となってしまい、注文を受け付けないことがあるためです。

```breakout_ea.mq4
// パラメータ変数
extern int Magic = 1101;
extern double Lots = 0.1;
extern int BreakPeriod = 10;
extern int Slippage = 3;
extern double StopLoss = 30;
extern int ClosePeriod = 300;

// 変数
int BuyTicketId = 0;
int SellTicketId = 0;
int CurrentPeriod = 0;
datetime BarTime = 0;

int init(){
    return(0);
}

int start(){
	// 始値でなければ終了
  	if(BarTime == Time[0]){
   		return(0);
   	}
   	BarTime = Time[0];

    if(OrdersTotal() != 0){
        // 強制決済
        if(CurrentPeriod >= ClosePeriod){
            OrderSelect(0, SELECT_BY_POS, MODE_TRADES);
            OrderClose(
                OrderTicket(),
                OrderLots(),
                OrderClosePrice(),
                Slippage,
                Gray
            );    
            CurrentPeriod = 0;
        }

        // 決済処理
        close_position();
        CurrentPeriod += 1;
    } 

    if(OrdersTotal() == 0){
        // 注文処理
	    order_position();
    }

    return(0);
}

int close_position(){
	// 存在しているポジションを選択
    bool order = OrderSelect(0, SELECT_BY_POS, MODE_TRADES);
    bool is_not_closed = OrderCloseTime() == 0;

    if(OrderType() == OP_BUY){
        // ロングポジションに関する決済処理
        // 一定期間の最安値
        double min_price = Low[iLowest(Symbol(), 0, MODE_LOW, BreakPeriod, 1)];
        if(Close[0] < min_price && is_not_closed){
            OrderClose(
                OrderTicket(),
                OrderLots(),
                OrderClosePrice(),
                Slippage,
                Blue
                );
            BuyTicketId = 0;
        }
    } else {
        // ショートポジションに関する決済処理
        // 一定期間の最高値
        double max_price = High[iHighest(Symbol(), 0, MODE_HIGH, BreakPeriod, 1)];
        if(Close[0] > max_price && is_not_closed){
            OrderClose(
                OrderTicket(),
                OrderLots(),
                OrderClosePrice(),
                Slippage,
                Red
                );
            SellTicketId = 0;
        }

    }

    return(0);
}

int order_position(){
    // ロングポジションに関する注文処理
    //   一定期間の最高値
    double max_price = High[iHighest(Symbol(), 0, MODE_HIGH, BreakPeriod, 1)];

    if(max_price <= High[0]){
        BuyTicketId = OrderSend(
            Symbol(),         // 選択されている通貨
            OP_BUY,           // ポジション指定
            Lots,             // 取引量
            Ask,              // 現在の売値
            Slippage,         // Slippage
            NULL,             // StopLoss
            NULL,             // TakeProfit
            "BreakOut: Long", // コメント
            0,                // マジックナンバー
            0,                // 有効期限
            Blue              // チャート上に表示されるラインの色
            );
        OrderModify(
        	BuyTicketId,
        	Ask,
        	Ask - StopLoss * Point,
        	NULL,
        	0, 
        	Blue
        	);
        return(0);
    }

    // ショートポジションに関する注文処理
    //   一定期間の最安値
    double min_price = Low[iLowest(Symbol(), 0, MODE_LOW, BreakPeriod, 1)];
    if(min_price >= Low[0]){
        SellTicketId = OrderSend(
            Symbol(),          // 選択されている通貨
            OP_SELL,           // ポジション指定
            Lots,              // 取引量
            Bid,               // 現在の買値
            Slippage,          // Slippage
            NULL,              // StopLoss
            NULL,              // TakeProfit
            "BreakOut: Short", // コメント
            0,                 // マジックナンバー
            0,                 // 有効期限
            Red                // チャート上に表示されるラインの色
            );
        OrderModify(
        	SellTicketId,
        	Bid,
        	Bid - StopLoss * Point,
        	NULL,
        	0, 
        	Red
        	);
    }
    return(0);
}

int deinit(){
	// 終了時にはすべて決済。
    if(OrdersTotal() != 0){
        OrderSelect(0, SELECT_BY_POS, MODE_TRADES);
        bool is_not_closed = OrderCloseTime() == 0;
        if(is_not_closed == true){
            OrderClose(
                OrderTicket(),
                OrderLots(),
                OrderClosePrice(),
                Slippage,
                Yellow
            );
        }
    }
    return(0);
}
```

上記コードをコンパイルし、出力された ex4 ファイルを Experts 以下に格納します ([Meta Trader 4 におけるカスタム指標の作成](http://qiita.com/Salinger/items/55b4299fba59026aa6a7)では Indicators に格納しました)。その後、`Navigator` で右クリックし、`Refresh` を選択すると作成した EA が Navigator に現れます。

EA を適用したいチャートを選択後、EA を右クリックし、`Attach to a chart` をクリックするとパラメータ変数設定の画面が現れるので、必要ならパラメータを変更し、`OK` をクリック。これで対象の EA が起動し自動取引が始まります。


# おわりに
ここまでで、自動取引システムである EA を作成することが出来ました。次回はバックテストを行い、作成した EA の性能評価を行います。


# 参考文献
* [Meta Trader 4](http://www.metatrader4.com/)
* [Meta Trader 4 の基本的な使い方](http://qiita.com/Salinger/items/4fe247f27418e4dc734e)
* [Sublime Text 3 による MQL 開発環境の構築](http://qiita.com/Salinger/items/be5dcc6f686b9fe07d9e)
* [Meta Trader 4 におけるカスタム指標の作成](http://qiita.com/Salinger/items/55b4299fba59026aa6a7)
* [MQL4](https://www.mql4.com/)
* [メタトレーダー４ MQL言語リファレンス日本語翻訳マニュアル ver1.1](http://www.metasys-seeker.net/MQL4_Reference_ver1/MQL4_Reference_Contents.html)