18.外部入力パラメータを設定する
EAを稼働させる際に、そのEAに使わせるデータを外部入力できるようにしておくことで、EAの挙動に幅を持たせることができます。
外部入力パラメータとして用意されるものとしては、EAのマジックナンバー、ロット数や許容スリッページの値、ストップロスやテイクプロフィットの値幅などが挙げられます。
前回までで作成したsimple.mq4のソースコードに外部入力パラメータ用の記述を追加すると以下のようになります。
(追加記述をハイライトしています。)
#property copyright "" #property link "" #property version "1.00" #property strict input double Lots = 0.1; //ロット input int StopLoss = 200; //ストップロス(ポイント指定) int OnInit() { return(INIT_SUCCEEDED); } void OnDeinit(const int reason) { } void OnTick() { if(OrdersTotal() == 0) { //ポジションを持っていない時は、ここに処理が入る double sma200 = iMA(Symbol(), Period(), 200, 0, MODE_SMA, PRICE_CLOSE, 0); //現在時点での200SMA double sma200_prev = iMA(Symbol(), Period(), 200, 0, MODE_SMA, PRICE_CLOSE, 1); //1本前のバー時点での200SMA double sma20 = iMA(Symbol(), Period(), 20, 0, MODE_SMA, PRICE_CLOSE, 0); //現在時点での20SMA double sma20_prev = iMA(Symbol(), Period(), 20, 0, MODE_SMA, PRICE_CLOSE, 1); //1本前のバー時点での20SMA double bb_upper = iBands(Symbol(), Period(), 20, 2.0, 0, PRICE_CLOSE, MODE_UPPER, 0); //ボリンジャーバンド+2σ double bb_lower = iBands(Symbol(), Period(), 20, 2.0, 0, PRICE_CLOSE, MODE_LOWER, 0); //ボリンジャーバンド-2σ if(sma200 > sma200_prev) { //200SMAが上昇なら、ここに処理が入る if(sma20 > sma200) { //20SMAが200SMAより上に位置するなら、ここに処理が入る if(Open[1] < sma20_prev && Close[1] >= sma20_prev && Bid > sma20) { //バーが20SMAを上抜けたら、ここに処理が入る if(bb_lower > sma200) { //200SMAがボリンジャーバンドの外側(下)にある場合のみエントリー OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, Bid-200*Point(), 0, NULL, 12345); //買い注文・マジックナンバー12345 } } } } else if(sma200 < sma200_prev) { //200SMAが下降なら、ここに処理が入る if(sma20 < sma200) { //20SMAが200SMAより下に位置するなら、ここに処理が入る if(Open[1] > sma20_prev && Close[1] <= sma20_prev && Bid < sma20) { //バーが20SMAを下抜けたら、ここに処理が入る if(bb_upper < sma200) { //200SMAがボリンジャーバンドの外側(上)にある場合のみエントリー OrderSend(Symbol(), OP_SELL, 0.1, Bid, 3, Bid+200*Point(), 0, NULL, 12345); //売り注文・マジックナンバー12345 } } } } else { //200SMAが水平移動しているなら、ここに処理が入る } } else { //ポジションを持っている時は、ここに処理が入る double sma200 = iMA(Symbol(), Period(), 200, 0, MODE_SMA, PRICE_CLOSE, 0); //現在時点での200SMA for(int i=OrdersTotal()-1; i>=0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { if(OrderMagicNumber() == 12345) { //このEAによるポジションがあればここに処理が入る if(OrderType() == OP_BUY && Bid <= sma200) { //200SMAタッチで決済 OrderClose(OrderTicket(), OrderLots(), Bid, 3); } else if(OrderType() == OP_SELL && Bid >= sma200) { //200SMAタッチで決済 OrderClose(OrderTicket(), OrderLots(), Ask, 3); } } } } } }
ロットとストップロスを指定できるように設定しました。
通常の変数定義の先頭に、”input”と書くだけです。後ろに何のデータなのかを表すコメントを書いておきます。
input データ型 定数名 = 初期値; //何のデータかコメント
プログラム内で使用できるようになりますが、変更することはできないので定数と同じ扱いです。
inputは、EAの上の方に記述するのが一般的です。
また、OnInitやOnTickのブロックの外側に宣言されていますので、EAのプログラム全体から使用可能です(グローバルスコープ)。
これをコンパイルして、ストラテジーテスターから「エキスパート設定」を開きます。
記述追加前は無かった「パラメーターの入力」タブが表示され、ロットとストップロスをここから入力できるようになりました。
入力された値は、そのまま上記で宣言された定数に代入されます。
プログラム内の然るべき箇所をこの定数に書き換えます(OrderSendのロットとストップロス部分)。
#property copyright "" #property link "" #property version "1.00" #property strict input double Lots = 0.1; //ロット input int StopLoss = 200; //ストップロス(ポイント指定) int OnInit() { return(INIT_SUCCEEDED); } void OnDeinit(const int reason) { } void OnTick() { if(OrdersTotal() == 0) { //ポジションを持っていない時は、ここに処理が入る double sma200 = iMA(Symbol(), Period(), 200, 0, MODE_SMA, PRICE_CLOSE, 0); //現在時点での200SMA double sma200_prev = iMA(Symbol(), Period(), 200, 0, MODE_SMA, PRICE_CLOSE, 1); //1本前のバー時点での200SMA double sma20 = iMA(Symbol(), Period(), 20, 0, MODE_SMA, PRICE_CLOSE, 0); //現在時点での20SMA double sma20_prev = iMA(Symbol(), Period(), 20, 0, MODE_SMA, PRICE_CLOSE, 1); //1本前のバー時点での20SMA double bb_upper = iBands(Symbol(), Period(), 20, 2.0, 0, PRICE_CLOSE, MODE_UPPER, 0); //ボリンジャーバンド+2σ double bb_lower = iBands(Symbol(), Period(), 20, 2.0, 0, PRICE_CLOSE, MODE_LOWER, 0); //ボリンジャーバンド-2σ if(sma200 > sma200_prev) { //200SMAが上昇なら、ここに処理が入る if(sma20 > sma200) { //20SMAが200SMAより上に位置するなら、ここに処理が入る if(Open[1] < sma20_prev && Close[1] >= sma20_prev && Bid > sma20) { //バーが20SMAを上抜けたら、ここに処理が入る if(bb_lower > sma200) { //200SMAがボリンジャーバンドの外側(下)にある場合のみエントリー OrderSend(Symbol(), OP_BUY, Lots, Ask, 3, Bid-StopLoss*Point(), 0, NULL, 12345); //買い注文・マジックナンバー12345 } } } } else if(sma200 < sma200_prev) { //200SMAが下降なら、ここに処理が入る if(sma20 < sma200) { //20SMAが200SMAより下に位置するなら、ここに処理が入る if(Open[1] > sma20_prev && Close[1] <= sma20_prev && Bid < sma20) { //バーが20SMAを下抜けたら、ここに処理が入る if(bb_upper < sma200) { //200SMAがボリンジャーバンドの外側(上)にある場合のみエントリー OrderSend(Symbol(), OP_SELL, Lots, Bid, 3, Bid+StopLoss*Point(), 0, NULL, 12345); //売り注文・マジックナンバー12345 } } } } else { //200SMAが水平移動しているなら、ここに処理が入る } } else { //ポジションを持っている時は、ここに処理が入る double sma200 = iMA(Symbol(), Period(), 200, 0, MODE_SMA, PRICE_CLOSE, 0); //現在時点での200SMA for(int i=OrdersTotal()-1; i>=0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { if(OrderMagicNumber() == 12345) { //このEAによるポジションがあればここに処理が入る if(OrderType() == OP_BUY && Bid <= sma200) { //200SMAタッチで決済 OrderClose(OrderTicket(), OrderLots(), Bid, 3); } else if(OrderType() == OP_SELL && Bid >= sma200) { //200SMAタッチで決済 OrderClose(OrderTicket(), OrderLots(), Ask, 3); } } } } } }
外部入力ができるようになると、MAの期間やボリンジャーバンドの偏差など具体的な値をソースコードから取り除くことができます。
もっと言えば、SMAを使うかEMAを使うか、どういったときに売るのか買うのか、あらゆるものを全て外部入力に任せることも可能になりますが、普通のEAであれば、核となるロジック部分は変更できないように設定しましょう。
次回は、この外部入力パラメータを使った最適化について解説します。