株・FX, 自動売買を探究するエンジニアブログ

【ソースコードあり】FX自動売買ツール(EA)の作り方

FX 自動売買

本記事の手順を最後まで実行すると、自分の環境で自動売買ツール(EA)を動作させることができます。

EA開発を始めるには、まずスクリプトを書く→実行して動作確認するという手順を踏んでみるのが一番だと思います。
本記事はサンプルとして移動平均線(MA)のゴールデンクロス・デッドクロスに応じて売買するスクリプトのソースコードを載せています。

事前準備

FX口座の開設、MetaTrader5の導入が前提になるので、完了していない方は以下の記事を参考にやってみてください。

FX口座開設方法
MetaTrader5の導入方法

スクリプトを作成する

MetaEditorを起動し、新しいファイルを作成します。
MetaEditorの起動方法はこちら

ファイルの中身を全て削除して、下記の内容をコピペしてください。

#include <Trade\AccountInfo.mqh>

#include<Trade\SymbolInfo.mqh>

#include<Trade\Trade.mqh>



input int SL_pips; // 損切りするpips

input int TP_pips; // 利確するpips

input double risk_rate = 10; // 数量(残高のパーセンテージ)



// MA

input int ma_period_long = 25;

input int ma_period_short = 5;

input int ma_shift = 1;

input ENUM_MA_METHOD ma_method=MODE_SMA; 

input ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE; 

input double slippage;

double lot_size=SymbolInfoDouble(_Symbol,SYMBOL_TRADE_CONTRACT_SIZE);

int leverage=(int)AccountInfoInteger(ACCOUNT_LEVERAGE); 

int   MA_long_handle;

int   MA_short_handle;

double MA_long_buffer[];

double MA_short_buffer[];  

double pre_ma_long = 0.0;

double pre_ma_short = 0.0;

CTrade  trade;



int OnInit() {

   // MAの初期化

   MA_long_handle = iMA(_Symbol, PERIOD_CURRENT, ma_period_long, ma_shift, ma_method, applied_price);

   MA_short_handle = iMA(_Symbol, PERIOD_CURRENT, ma_period_short, ma_shift, ma_method, applied_price);

   ChartIndicatorAdd ( 0 , 0 ,MA_long_handle);

   ChartIndicatorAdd ( 0 , 1 ,MA_short_handle);

   return ( INIT_SUCCEEDED );

  }



void OnDeinit ( const int reason) {

   IndicatorRelease (MA_long_handle);

   IndicatorRelease (MA_short_handle);

   ChartIndicatorDelete ( 0 , 1 , "MA_long_handle" );

   ChartIndicatorDelete ( 0 , 2 , "MA_short_handle" );

   Comment ( "End" );

  }



void OnTick () {

   CopyBuffer (MA_long_handle, 0 , 0 , 7 ,MA_long_buffer);

   CopyBuffer (MA_short_handle, 0 , 0 , 7 ,MA_short_buffer);



   ArraySetAsSeries (MA_long_buffer, true);

   ArraySetAsSeries (MA_short_buffer, true);



   double balance=AccountInfoDouble(ACCOUNT_BALANCE);

   string symbol="USDJPY";

   int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);

   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);

   double ask=SymbolInfoDouble(symbol,SYMBOL_ASK);  

   double bid=SymbolInfoDouble(symbol,SYMBOL_BID);  

   datetime expiration=TimeTradeServer()+PeriodSeconds(PERIOD_D1);



   // Comentar

   MqlDateTime nowtime_structure;

   TimeCurrent(nowtime_structure);

   Comment (

           "balance: " , DoubleToString (balance, 6 ), "\n" ,

           "bid: " , DoubleToString (bid, 6 ), "\n" ,

           "ask: " , DoubleToString (ask, 6 ), "\n" ,

           "MA_short_buffer: " , DoubleToString (MA_short_buffer[ 0 ], 6 ), "\n" ,

           "MA_long_buffer: " , DoubleToString (MA_long_buffer[ 0 ], 6 ), "\n" ,

           "day_of_week: " , nowtime_structure.day_of_week, "\n" ,

           "time: " , nowtime_structure.hour, ":", nowtime_structure.min

           ); 



   // BUY

   if (MA_long_buffer[0] < MA_short_buffer[0] && pre_ma_long > pre_ma_short) {

      if(PositionsTotal() > 0) {

         if(trade.RequestType() == ORDER_TYPE_SELL) trade.PositionClose(symbol, slippage);

      }else{

         double one_lot_price = bid*lot_size/leverage;

         double use_balance = balance*risk_rate/100;

         double volume= NormalizeDouble(use_balance/one_lot_price, 2);

         double SL=bid-SL_pips*point;

         SL=NormalizeDouble(SL,digits);    

         Print(DoubleToString (SL, 6 ) );

         double TP=bid+TP_pips*point;

         TP=NormalizeDouble(TP,digits);

         trade.Buy(volume, symbol, bid, SL,TP);

         Sleep(60*1000*PERIOD_CURRENT);

      }



   // SELL

   } else if (MA_short_buffer[0] < MA_long_buffer[0] &&  pre_ma_short > pre_ma_long) {

      if(PositionsTotal() > 0) {

         if(trade.RequestType() == ORDER_TYPE_BUY) trade.PositionClose(symbol, slippage);

      }else{

         double one_lot_price = ask*lot_size/leverage;

         double use_balance = balance*risk_rate/100;

         double volume= NormalizeDouble(use_balance/one_lot_price, 2);

         double SL=ask+SL_pips*point;

         SL=NormalizeDouble(SL,digits);

         double TP=ask-TP_pips*point;

         TP=NormalizeDouble(TP,digits);

         trade.Sell(volume, symbol, ask, SL,TP);

         Sleep(60*1000*PERIOD_CURRENT);

      }

   }

   pre_ma_long = MA_long_buffer[ 0 ];

   pre_ma_short = MA_short_buffer[ 0 ];

  }

コピペが完了したら、Ctrl + Sボタンを押して保存しましょう。

保存後、上部にあるメニューバーからコンパイルボタンを押します。
これで実行可能な状態になりました。

動かしてみよう

MetaTrader5に戻ると作成したファイルが画面左のナビゲータペインに表示されています。

右クリックするとテストの選択肢があるのでクリックします。

ストラテジーテスターのウィンドウが表示されるので、設定タブを選択します。

下記のように設定しましょう。

  • エキスパート:作成したファイル名.ex5が選択されていることを確認
  • 銘柄:USDJPY M15に変更
  • 日付:期間指定に変更し、好きな期間を1ヶ月分になるように設定
  • フォワードテスト:キャンセル
  • 延滞:そのまま
  • モデル:全ティック
  • 入金:50000 JPY レバレッジ 1:888
  • オプティマイズ:無効化
  • チャート、指標、取引を表示するビジュアルモード:チェックをいれる

設定が完了したら右下のスタートボタンを押します

うまく実行できました!
Strategy Tester Visualizationという画面が表示され、指定した期間の自動売買テストの結果が表示されます。

また、MetaTraderのストラテジーテスターウィンドウのバックテストタブをみるとテストのサマリが表示されています。

勝てるEAを開発するために

本記事ではスクリプトのコンパイル→実行までを行いました。

今後はパラメータの設定、チューニング、サーバをレンタルして常時起動する方法なども紹介します。

ここに記載したスクリプトは、短期の移動平均線が長期の移動平均線を上回ったら買い、逆なら売りという単純なスクリプトです。
これだけの条件では勝つことは難しいですが、これに移動平均線と現在価格との位置関係や、曜日・時間帯などの条件を加えるなど様々な工夫が考えられます。

MQL5の仕様やテクニカルの知識を増やし、EAに反映することでやがて勝てるEAが作れるようになると思います。
今後も僕が学んだ内容は随時、記事にしていきます。