【メモ】MQL4をMQL5に移植する。（その2：注文）

MQL4をMQL5に移植するので、備忘録としてメモを作成。
[MQL4をMQL5に移植する。（その１：レートの受信）](https://qiita.com/shin_urashima/items/8f6366c72d3f58170a4a)の続き。

移植の基本情報は前回の記事を参照。

今回は取引を実行するEAをMQL5に移植する。前回の記事に記載した、アカウント情報とレートをMQL5に移植してコンパイルすると、エラーが多数出たので順に修正する。

##ライブラリの移植
MQL4で利用していた標準ライブラリ<stdlib.mqh>、<stderror.mqh>がエラーになっているのでコメントして先に進む。
[MQL5で利用できる標準ライブラリ](https://www.mql5.com/ja/docs/standardlibrary)は以下。

| セクション                   | ディレクトリ       | 
|:----------------------------|:------------------| 
| 数学                         | Include\Math\    | 
| OpenCL                      | Include\OpenCL\   | 
| 基本クラスCObject            | Include           | 
| データ収集                   | Include\Arrays\   | 
| ジェネリックデータコレクション | Include\Generic\  | 
| ファイル                     | Include\Files\   | 
| 文字列                       | Include\Strings\ | 
| グラフィックオブジェクト      | Include\Objects\ | 
| カスタムグラフィックス        | Include\Canvas\  | 
| 価格チャート                 | Include\Charts\  | 
| 科学的チャート               | Include\Graphics\ | 
| 指標                        | Include\Indicators\ | 
| トレードクラス               | Include\Trade\ | 
| ストラテジーモジュール        | Include\Expert\ | 
| パネルとダイアログ           | Include\Controls\ | 
今回の移植に関係しそうな、[基本クラスのCObject](https://www.mql5.com/ja/docs/standardlibrary/cobject)、[文字列](https://www.mql5.com/ja/docs/standardlibrary/stringoperations)、[トレードクラス](https://www.mql5.com/ja/docs/standardlibrary/tradeclasses)、ストラテジーモジュールに目を通す。科学的チャートのディレクトリ名が「Graphics」になっているのが気になるが今回はスルー。

##エラー処理の移植： ErrorDescription()
ErrorDescription(GetLastError()) がエラーになっていたので調べると、ErrorDescription用のMT5ライブラリが用意されていた。MQL5ドキュメントに提供されている ErrorDescription.mqh を \MetaTrader 5\MQL5\Include フォルダにコピーしたところ、エラーは解消した。参照：[ErrorDescription - MetaTrader 5のためのライブラリ](https://www.mql5.com/ja/code/79)

MQL5のドキュメントに掲載されているサンプルより。

```mt5:ErrorDescTest.mq5
#include <ErrorDescription.mqh>
//+------------------------------------------------------------------+
//| Example of use of the ErrorDescription.mqh library               |
//+------------------------------------------------------------------+
void OnStart()
  {
   Print("----- Description of trade server return codes -----");
   for(int i=10004;i<=10034;i++)
     {
      Print("Trade server return code:",i,TradeServerReturnCodeDescription(i));
     }
   Print("-------- Description of runtime error codes ---------");
   for(int i=4001;i<=4014;i++)
     {
      Print("Runtime error code:",i,ErrorDescription(i));
     }
  }
//+------------------------------------------------------------------+
```
参照：[ErrorDescription - MetaTrader 5のためのライブラリ](https://www.mql5.com/ja/code/79)

##注文処理の移植： OrderSend()
OrderSend() 関数を、MT5に移植する。MT5ドキュメントの OrderSend()に記載されたサンプルプログラムで、注文は以下のように実行されている。参照：[OrderSend](https://www.mql5.com/ja/docs/trading/ordersend)

MTL5では、注文に必要な情報を MqlTradeRequest 構造体に設定、OrderSend(request, result) に引数として渡し、注文の結果は、MQLTradeResult 構造体で受け取る仕様となっている。

```mt5:sample.mq5
//--- リクエストを準備する
  MqlTradeRequest request={0};
  request.action=TRADE_ACTION_PENDING;         // 未決注文を設定する
  request.magic=magic_number;                 // ORDER_MAGIC
  request.symbol=_Symbol;                     // シンボル
  request.volume=0.1;                         // 0.1 ロットのボリューム
  request.sl=0;                               // 決済逆指の指定なし
  request.tp=0;                               // 決済指値の指定なし    
//--- 注文の種類を形成する
  request.type=GetRandomType();               // 注文の種類
//--- 未決注文の価格を形成する
  request.price=GetRandomPrice(request.type); // 始値
//--- 取引リクエストを送る
  MqlTradeResult result={0};
  OrderSend(request,result);
//--- サーバ返答をログに書く  
  Print(__FUNCTION__,":",result.comment);
  if(result.retcode==10016) Print(result.bid,result.ask,result.price);
//--- 取引サーバの返答のコードを返す
  return result.retcode;
```

今回移植するEAは成行き注文のみ使用しているので、成行き注文に必要なフィールドを以下のように設定し注文する。

```mt5:MqlTradeRequest
//--- リクエストを準備する
  MqlTradeRequest request = {0};
  request.action = TRADE_ACTION_DEAL; // 成行注文
  request.magic = magic_number;       // マジックナンバーを指定
  request.symbol = _Symbol;　　  　　　// 通貨ペアを指定
  request.volume = lot;               // 取引数量
  request.type=ORDER_TYPE_BUY;        // 買い注文の場合
//--- 取引リクエストを送付
  MqlTradeResult result = {0};
  OrderSend(request,result);
```

MqlTradeRequest, MQLTradeResult構造体はそれぞれ以下の通り。

```mt5:MqlTradeRequest
struct MqlTradeRequest
 {
  ENUM_TRADE_REQUEST_ACTIONS   action;           // 取引の種類
  ulong                         magic;           // エキスパートアドバイザー ID（マジックナンバー）
  ulong                         order;           // 注文チケット
  string                       symbol;           // 取引シンボル
  double                       volume;           // 約定のための要求されたボリューム（ロット単位）
  double                       price;           // 価格
  double                       stoplimit;       // 注文のストップリミットレベル
  double                       sl;               // 注文の決済逆指値レベル
  double                       tp;               // 注文の決済指値レベル
  ulong                         deviation;       // リクエストされた価格からの可能な最大偏差
  ENUM_ORDER_TYPE               type;             // 注文の種類
  ENUM_ORDER_TYPE_FILLING       type_filling;     // 注文実行の種類
  ENUM_ORDER_TYPE_TIME       type_time;       // 注文期限切れの種類
  datetime                     expiration;       // 注文期限切れの時刻 （ORDER_TIME_SPECIFIED 型の注文）
  string                       comment;         // 注文コメント
  ulong                         position;         // Position ticket
  ulong                         position_by;     // The ticket of an opposite position
 };
```
参照：[取引リクエスト構造体 (MqlTradeRequest)](https://www.mql5.com/ja/docs/constants/structures/mqltraderequest)

```mt5:MqlTradeResult
struct MqlTradeResult
 {
  uint   retcode;         // 操作のリターンコード
  ulong   deal;             // 実行された場合の 約定チケット
  ulong   order;           // 注文された場合のチケット
  double   volume;           // ブローカーによって確認された約定ボリューム
  double   price;           // ブローカーによって確認された約定価格
  double   bid;             // 現在の売値
  double   ask;             // 現在の買値
  string   comment;         // 操作に対するブローカーコメント（デフォルトは取引サーバの返したコードの記述）
  uint   request_id;       // ディスパッチの際に、端末によって設定されたリクエストID
  uint   retcode_external; // 外部取引システムのリターンコード
 };
```
参照：[取引リクエスト結果の構造体 (MqlTradeResult)](https://www.mql5.com/ja/docs/constants/structures/mqltraderesult)

##注文処理の移植： OrderSelect() => PositionSelectByTicket()
OrderSelect() 関数を、MT5に移植する。MT5では、PositionSelectByTicket() を利用する。
Order(注文)、Position（ポジション）、History（履歴）のそれぞれに対してアクセス用の関数が用意されている。対象データにより異なる関数を利用する必要があるため注意が必要。参照：[取引関数](https://www.mql5.com/ja/docs/trading)


```mt5:PositionSelectByTicket
bool PositionSelectByTicket(
  ulong  ticket     // ポジションチケット
  );
```

##注文処理の移植： OrderOpenPrice() => PositionGetDouble()
OrderOpenPrice() 関数を、MT5に移植する。MT5では、PositionGetDouble(POSITION_PRICE_OPEN) を利用する。

```mt5:PositionGetDouble
double  PositionGetDouble(
  ENUM_POSITION_PROPERTY_DOUBLE  property_id      // プロパティ識別子
  );
```
###ENUM_POSITION_PROPERTY_DOUBLE
| 識別子                  | 説明                          | Type    |
|:-----------------------|:------------------------------|:--------|  
| POSITION_VOLUME        | ポジションボリューム            | Double  |
| POSITION_PRICE_OPEN    | ポジションの始値                | Double  |
| POSITION_SL            | 未決済ポジションの決済逆指レベル | Double  |
| POSITION_TP            | 未決済ポジションの決済指値      | Double  |
| POSITION_PRICE_CURRENT | ポジションシンボルの現在価格     | Double  |
| POSITION_SWAP          | 累積スワップ                   | Double  |
| POSITION_PROFIT        | 現在の利益                     | Double  |



##注文処理の移植： OrderLots() => PositionGetDouble()
OrderLots() 関数を、MT5に移植する。MT5では、PositionGetDouble(POSITION_VOLUME) を利用する。関数の概要については「注文処理の移植： OrderOpenPrice() => PositionGetDouble()」の説明参照。


ここまでの修正でコンパイラのエラーは解消した。