MT5のEAの学習メモ

なぜMT4ではなくMT5なのか?

デイトレするときにポジションをまとめてクローズすることができていいよ。と知人におしえてもらったからです。詳しいことはこれから勉強します。

MT5ダウンロード

以下の証券会社から無料でダウンロードできます。いまのところ日本の証券会社はMT4だけの場合が多い印象です。

EXNESSはオーストラリアの会社?だそうです。間違ってたらすいません。

https://exn.fxsignup.com/trading-tool/

住所の証明がちょっと大変でした。免許書と公共料金の支払いの紙が証明で必要でした。

移動平均を使った売買

はじめてMQT5でEAを作ってみました。

移動平均のクロスでエントリーして、ストップロスと、テークプロフィットを決めるロジックです。

いろいろ、間違っています。はい。

パラメータは、日足でUSD/JPYでよさげになるように調節してあります。

#property copyright "Copyright 2023, Hayashi Kuniyuki"
#property link      "https://java.boy.jp/pukiwiki/index.php?MT5%20EA"
#property version   "1.00"
#property strict
//+------------------------------------------------------------------+
//| Include                                                          |
//+------------------------------------------------------------------+
#include <Trade\trade.mqh>

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+

// グローバル変数の宣言
input double inpLotSize = 0.1;       // 注文のロットサイズ
input int inpMagicnumber = 20231006; // マジックナンバー
input double inpStopLoss = 100; // ストップロスのpips
input double inpTakeProfit = 700; // 利確のpips

input int inpShortSmaPeriod = 3; // 移動平均の短い期間
input int inpLongSmaPeriod = 5; // 移動平均の長い期間


// ポジションについての情報
struct Posi {
   datetime openTime; // 二重登録防止用
   double price; // 注文価格
   double stopLoss; // ストップロス
   double takeProfit; // 利確
   bool needRetry; // 取引失敗時のリトライ管理
   int sign; // 計算用 1 or -1
   ENUM_POSITION_TYPE posi_type;
   ENUM_SYMBOL_INFO_DOUBLE symbol_type;
   ENUM_ORDER_TYPE order_type;
};
Posi posiBuy = {0, 0, 0, 0, false, 1, POSITION_TYPE_BUY, SYMBOL_ASK, ORDER_TYPE_BUY}; // 買いポジション管理
Posi posiSell = {0, 0, 0, 0, false, -1, POSITION_TYPE_SELL, SYMBOL_BID, ORDER_TYPE_SELL}; // 売りポジション管理

// 移動平均の構造体
struct Sma {
   int period; // 期間
   int handle; // ハンドル
   double prices[]; // 直近とその前の値
};
Sma smaShort; // 短い期間の移動平均
Sma smaLong; // 長いほうの期間の移動平均

CTrade trade; // 取引実行インスタンス

int OnInit() {
   // ユーザ入力チェック
   if (inpLotSize <= 0 || inpLotSize >= 1) {
      Alert("inpLotSize <=0 || inpLotSize >= 1 ");
      return INIT_PARAMETERS_INCORRECT;
   }
   
   if (inpStopLoss <= 0 || inpStopLoss >= 1000) {
      Alert("inpStopLoss <= 0 || inpStopLoss >= 1000");
      return INIT_PARAMETERS_INCORRECT;
   }
   
   if (inpTakeProfit <= 0) {
      Alert("inpTakeProfit <= 0");
      return INIT_PARAMETERS_INCORRECT;
   }
   
   if (inpShortSmaPeriod <= 0) {
      Alert("inpShortSmaPeriod <= 0");
      return INIT_PARAMETERS_INCORRECT;
   }
   
   if (inpLongSmaPeriod <= 0) {
      Alert("inpLongSmaPeriod <= 0");
      return INIT_PARAMETERS_INCORRECT;
   }  
   
   if (inpLongSmaPeriod <= inpShortSmaPeriod) {
      Alert("inpLongSmaPeriod <= inpShortSmaPeriod");
      return INIT_PARAMETERS_INCORRECT;
   }         
   
   // Sma設定
   setSma(smaShort,inpShortSmaPeriod);
   setSma(smaLong,inpLongSmaPeriod);
    
   return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason){
   // メモリ解放
   releaseSma(smaShort);
   releaseSma(smaLong);
}

void OnTick() {
   // 価格取得
   if (!fetchPrice(smaShort)) return;
   if (!fetchPrice(smaLong)) return;
   
   // 買いポジションを取る
   if (posiBuy.needRetry) {
      openPosi(posiBuy);
   }
   if (isCrossOver(smaShort.prices, smaLong.prices) && !hasPosition(posiBuy)) {
      Print("ゴールデンクロス");
      posiBuy.needRetry = true;
      openPosi(posiBuy);
      dump(smaShort);
      dump(smaLong);
   }

   // 売りポジションを取る
   if (posiSell.needRetry) {
      openPosi(posiSell);
   }   
   if (isCrossOver(smaLong.prices, smaShort.prices) && !hasPosition(posiSell)) {
      Print("デッドクロス");
      posiSell.needRetry = true;
      openPosi(posiSell);
      dump(smaShort);
      dump(smaLong);
   }  
}


//+------------------------------------------------------------------+
//| Utility                                                          |
//+------------------------------------------------------------------+
// 移動平均の初期化
void setSma(Sma &sma, int period) {
   sma.period = period;
   sma.handle = iMA(_Symbol, PERIOD_CURRENT, period, 0, MODE_SMA, PRICE_CLOSE);
   ArraySetAsSeries(sma.prices, true);
}

// インジケータをメモリから解放
void releaseSma(Sma &sma) {
   if (sma.handle != INVALID_HANDLE) {IndicatorRelease(sma.handle);} 
}

// 移動平均の現在値とひとつ前の値取得
bool fetchPrice(Sma &sma) {
   int arraySize= CopyBuffer(sma.handle, 0, 0, 2, sma.prices);
   if (arraySize != 2) {
      Print("移動平均のデータが十分ではない。");
      return false;
   }
   return true;
}

// 交わっているか判定
bool isCrossOver(double &prices1[], double &prices2[]) {
   return ((prices1[1] <= prices2[1]) && (prices1[0] > prices2[0]));
}

// Tickの現時間取得
datetime now() {
   return iTime(_Symbol,PERIOD_CURRENT,0);
}

// ポジション持っているか
bool hasPosition(Posi &posi) {
   return (posi.openTime == now());
}

// ポジションを持つ
void openPosi(Posi &posi) {
   double symbolPoint = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   posi.price = SymbolInfoDouble(_Symbol, posi.symbol_type);
   posi.stopLoss = posi.price - (posi.sign * inpStopLoss * symbolPoint );
   posi.takeProfit = posi.price + (posi.sign + inpTakeProfit * symbolPoint ); 
   
   Print("symbolPoint: ", symbolPoint, ", price: ", posi.price, ", st: ", posi.stopLoss, " tp: ", posi.takeProfit);
   
   // ポジションをもてなければリトライフラグを取り下げない
   if (trade.PositionOpen(_Symbol, posi.order_type,inpLotSize,posi.price, posi.stopLoss, posi.takeProfit,"cross EA")){
      posi.needRetry = false;
   }
   posi.openTime = now();
   
}

// 確認用
void dump(Sma &sma){
   Print("[0]: ", sma.prices[0], ", [1]: ", sma.prices[1]," :Sma" , sma.period);
}

クラスも作成できる

class CSomethingClass{
  public:
    int number;
};

インスタンスの生成例

CSomethingClass somethingClass;

クラスの配列の作成例

CSomethingClass somethingClass[];

要素を追加するには

ArrayResize(somethingClass, ArraySize(somethingClass) + 1);

Scriptの作成

ちょっとしたチャート上でよくやる操作は、Sciptとして作成し、ショートカットで呼び出すと便利です。

取引履歴のトグル表示

まだ、確認画面がでる点がスマートではないですが、チャートの表示状態の取得と変更のサンプルにはなるでしょう。

//+------------------------------------------------------------------+
//|                                       ToggleShowOrderHistory.mq5 |
//|                                 Copyright 2023, Hayashi Kuniyuki |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Hayashi Kuniyuki"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
#property script_show_inputs
#property strict
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart() {
   // Get the current chart ID
   long chartID = ChartID();

   // Check the current state of 'Show trade history' property
   bool showTradeHistory = ChartGetInteger(chartID, CHART_SHOW_TRADE_HISTORY);

   // Toggle the 'Show trade history' property
   showTradeHistory = !showTradeHistory;
   ChartSetInteger(chartID, CHART_SHOW_TRADE_HISTORY, showTradeHistory);

   // Notify the user of the change
   if(showTradeHistory)
      Print("Trade history is now displayed.");
   else
      Print("Trade history is now hidden.");
}

チャートテンプレートを適用するコード

チャートのテンプレートをショートカットで切り替えれるようになると便利です。

//+------------------------------------------------------------------+
//|                                 Copyright 2023, Hayashi Kuniyuki |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Hayashi Kuniyuki"
input string templateName = "xxx"; // 使用したいテンプレート名

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
   // インジケータのテンプレートを読み込む
   ChartApplyTemplate(0, templateName + ".tpl");
}
トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2023-12-24 (日) 00:36:57 (125d)