FX手法をプログラム化してみた(EA検証)ロジック1

手法EA化
スポンサーリンク

検証ロジック

どうも潤奈です( ・Д・)

今回は以下のロジックをプログラム化して検証してみたいと思います。

まず日足と4時間足を見て大きなトレンドが上かどうかを判断し、強めの上昇トレンドであれば15分足を確認する。ポイントとしては、前日に上へ大きく動いており、かつ直近の高値を更新した場合はさらに高値を更新する可能性が高い。エントリータイミングは15分足で移動平均線(MA20、50、100)を設定し、ローソク足がMA20にタッチして下ヒゲ陽線になった時にロングエントリーする。MA50とMA100も同じように上昇している事が条件である。ロスカットは-20pipsで、利確は80~100pipsを狙う。

プログラム化していく流れについて

まずそのロジックを条件毎にリストアップしようと思います。

そのリストアップした条件毎にプログラム化して、最後にその条件に当てはまっているか確認する流れとなります。

簡単なロジックだと複数の条件をまとめる事は出来ますが、分かりやすいように(説明しやすい)都度分けて記述して行きたいと思いますので、

この条件とこの条件はまとめて記述して短縮出来るのでは?と判断出来る方はそうして頂いても結構です。

ではまずはロジックをリストアップして行きましょう( ・Д・)

検証ロジックをリストアップ

リストアップする前に説明しますが、以下の条件は「買い方向」の場合としていますので、「売り方向」へはその逆となり条件文からは省略していますので、その様な理解で読み進めて頂けたらと思います。

条件1)日足で上昇トレンドになっているか

この上昇トレンドになっているかの判断は3本の移動平均線のパーフェクトオーダーで判断したいと思います。

条件2)4時間足で上昇トレンドになっているか

こちらも同様に3本の移動平均線のパーフェクトオーダーが成立しているかで判断したいと思います。

条件3)前日に上へ大きく動き、かつ直近の高値を更新

まず「前日に上へ大きく動き」の部分ですが、具体的にどれぐらい動いたら大きくなのかがここでは判断出来ませんでしたので、とりあえず前日の始値より終値が大きい場合。で判断したいと思います。

条件4)ローソク足がMA20にタッチし下ヒゲ陽線を確認

「タッチ」という条件がプログラムにする際に難しいですよね。今回は細かく指定し過ぎるとあれなので、MA20を下へ抜けた後に上昇し下ヒゲ陽線が出来た場合で作成したいと思います。

条件5)MA50とMA100が同じように上昇しているか

こちらはそれぞれ、2本前より1本前の移動平均線の方が上であり、MA100よりMA50の方が上である場合という条件で上昇していると判断したいと思います。

条件6)条件1~5がすべて整った場合にエントリー

最後に条件1~5がすべて整った場合にエントリー出来るような条件式を作成します。

ロジックをプログラム化

プログラム化した時のEAから見た位置付けについて

このロジック化はオリジナル関数として作成する予定で説明して行きますので、オリジナル関数についてはよく分からない方は以下の記事で説明しています。

潤奈流EA講座④(オリジナル関数とは,AdjustPoint関数,AdjustSlippage関数)
...

全くEAが出来るまでの流れが分からない方は、一度この「潤奈流EA講座」を読み込んで頂くと頭の中に入りやすいと思います。

手順① パラメーターを作成する

こちらは手順①としていますが、一から考えながら作成する時は大体後から追加していく事が多いです。

ロジックを作成していく中で、「あ、ここに入れる値はパラメーターで変更出来た方が良いな」とか思ったら追加していく感じですね。

ですがここでそれをすると工程が前後に移動して訳がわからなくなるので先に必要なパラメーターを説明します。

それぞれのパラメーターついては、以降の手順でまとめて説明します。

手順② オリジナル関数の箱を用意する

ロジックを記述して行く為の箱を用意します。

int型(整数)のLogic1()関数を作成し、その{ }内に今回のロジックを記述して行きます。

手順③ 各ロジックをプログラム化する

ではリストアップした検証ロジックをプログラム化して行きます。

条件1)日足で上昇トレンドになっているか

上昇トレンドになっているかの判断は今回は3本の移動平均線のパーフェクトオーダーで行いますので、まず3本の日足移動平均線の値を取得して変数に代入します。

現在の日足の移動平均線がどうなっているかを見たいので、式の最後の数字は0(現在の日足)を取得するようにしています。

次に取得した値からパーフェクトオーダーになっているかを確認します。

最初にjyouken1変数に0を代入します。買いのパーフェクトオーダーの場合は1を、売りの場合は-1を代入し、どちらでもない場合は0のままとして条件の結果判断に使用します。

条件2)4時間足で上昇トレンドになっているか

日日足と同様に3本の移動平均線のパーフェクトオーダーで判断しますので、3本の4時間足移動平均線の値を取得して変数に代入します。

こちらも同様に式の最後の数字は0(現在の4時間足)を取得するようにしています。

jyouken2変数に0を代入し、買いのパーフェクトオーダーの場合は1を、売りの場合は-1を代入し、どちらでもない場合は0のままとして条件の結果判断に使用します。

条件3)前日に上へ大きく動き、かつ直近の高値を更新

まずは直近の高値と安値を取得して変数に代入します。

ここで高値を取得するのにiHigh関数とiHighest関数を組合わせて使用しています。

ちょっと分かりずらいので分解して説明します。

まず先に後ろ側にあるiHighest関数についての引数(質問)は以下が必要になります。

そしてこれは最高値を持つバーの位置を返してくれます。

なので今回は、「今の通貨ペアの日足で、2本前から10本分までの間で最高値を持つバーの位置は?」と質問して、「例)3本前だよ」と答えを返してくれます。

では次に前側にあるiHigh関数の引数(質問)は以下が必要になります。

そしてこれはそのバー位置の高値を返してくれます。

よってiHighest関数で最高値のローソク足の位置を特定して、iHigh関数でそのローソク足の高値を取得しH変数に代入するという流れになります。

安値も同様の仕組みですのでここでは割愛させて頂きますね。

【ポイント】iHighest関数で検索開始位置を2本前からにしているのは、高値を更新したかのタイミングは1本前の終値と比較するからです。検索開始位置を1本前からしてしまうと、もし上昇中で1本前の高値が最高値の場合は1本前の終値が高値を更新する事がない為です。そりゃそうだ( ゚Д゚)

これは意外に盲点だったりしますので注意して下さい。あれ?なんでエントリーしないの?状態になります( ゚Д゚)

次で2つの条件をまとめて記述します。

jyouken3変数に0を代入しておきます。

iOpen関数とiClose関数はiHigh関数と同様の仕組みで、指定の始値と終値を取得出来ます。

if文で2つの買い条件をクリアしていれば1を代入し、売り条件の場合は-1を代入します。

条件4)ローソク足がMA20にタッチし下ヒゲ陽線を確認

まずMA20の移動平均線の値を取得して変数に代入し、この条件式を組む際の見た目を分かりやすくする為にローソク足の4本値を変数に代入しておきます。

ヒゲの長さを価格単位で比較する為にAdjustPoint関数(オリジナル関数)で調節しています。こちらに関しては以下の記事で説明していますのでご覧下さい。

ではこの条件式を記述します。

jyouken4変数に0を代入しておきます。

条件は「MA20にタッチする」という部分は「MA20より一度価格が下回った」とします。

ヒゲはある程度の長さが必要だと思いましたので、パラメーターで設定した長さがあるか確認するようにして、陽線かどうかの確認も入れています。

言葉で説明するよりは図と式で見比べた方が分かりやすいと思いましたので以下の図をご覧ください。

「タッチ」という意味が何pips移動平均線にヒゲが触れているか、まで指定すると条件が絞られ過ぎてしまうと感じたので今回はこのようなプログラムにしています。

if文でこれらの買い条件をクリアしていれば1を代入し、売り条件の場合は-1を代入します。

条件5)MA50とMA100が同じように上昇しているか

「同じように上昇している」とありますので、MA50と100の位置関係と、単体での方向性を確認する為に1本前と2本前の移動平均線の値を取得して変数に代入します。

これらを使って条件式を組んで行きます。

jyouken5変数に0を代入しておきます。

if文で3つの買い条件をクリアしていれば1を代入し、売り条件の場合は-1を代入します。

条件6)条件1~5がすべて整った場合にエントリー

最後にそれぞれの条件がすべて整っているかを確認する条件式を作成します。

entry変数に0を代入しておきます。

if文でそれぞれの条件すべてが買い(1)の場合は1を代入し、売り(-1)の場合は-1を代入します。

それを最後にreturnでこのLogic関数の戻り値として値を返します。

この戻り値を利用して、1の場合は買いエントリー、-1の場合は売りエントリーを行うようにプログラムを組めば利用が出来ます。

検証結果

ではこのロジックを使用したEAでバックテストした結果が以下になります。

最高値のチェック期間とヒゲ判定長さのみ軽く最適化しています。

USDJPY

GBPJPY

EURUSD

まとめ

全体ソースコード

感想

上位足のトレンドを確認してから下位足の移動平均線での反発を狙ったトレード手法になりますね。

バックテストでは過剰にパラメーターを最適化しなかった為、エントリー数が少なかったですが、日足と4時間足をもっと下位に下げたらもっとエントリーチャンスが増えてどうなるかですね。

あとは、利確と損切が固定の為その辺りの合う決済ロジックが見つかると面白いEAが出来るのではないでしょうか。

是非、プログラム化の参考にして下さい。各条件のロジックに関しては解釈が違えばロジックも変わり結果も変わって来ますので、あくまでこれは一例のロジックであり、この手法の有効性がこれで判断されるという物ではありません。

皆さんの何か気付きになればと思います( ・Д・)

【免責事項】

※当ソースコードにおける如何なる損失もご自身の自己責任となります。投資資産における運用の結果生じた損害の全部若しくは一部について一切の責任及び負担を負わないものとします。
※当ソースコードにつきましても、バグや不具合がないことを保証するものではありません。
※このブログで掲載されている情報は、投資等の勧誘又は推奨を目的としたものではありません。
※掲載されている内容は予告なしに変更することがあります。

EAの全ソースコード

以下の記事をご購入頂きましたらEAまでの全ソースコードを閲覧する事が出来ますので、すぐにバックテストで試す事が出来ます( ・Д・)

この続きを見るには

コメント

  1. FXおじさん より:

    いつも参考にさせていただいております。
    MT5で似たプログラムを作って強化していこうと目論んでいるのですが、なぜか取引が実行されません。
    何か分かりますでしょうか・・・?

    input int MAPeriod1 = 20; // 短期移動平均線
    input int MAPeriod2 = 50; // 中期移動平均線
    input int MAPeriod3 = 100; // 長期移動平均線
    input ENUM_MA_METHOD Method = MODE_SMA; // 方法
    input ENUM_APPLIED_PRICE Price = PRICE_CLOSE; // 価格
    input int HLPeriod = 10; // 高安値チェック期間
    input int Beard = 3; // ヒゲ条件(pips)
    input int TakeProfitPips = 10; // 利確ピップス

    // 50MAと100MAのトレンドを確認して15分足のヒゲでエントリーロジック
    int Logic1() {
    // 日足のトレンド判断→移動平均線のパーフェクトオーダー
    double MAS24 = iMA(_Symbol, PERIOD_D1, MAPeriod1, 0, Method, Price);
    double MAM24 = iMA(_Symbol, PERIOD_D1, MAPeriod2, 0, Method, Price);
    double MAL24 = iMA(_Symbol, PERIOD_D1, MAPeriod3, 0, Method, Price);

    // パーフェクトオーダー確認
    int jyouken1 = 0;
    if (MAL24 < MAM24 && MAM24 MAM24 && MAM24 > MAS24)
    jyouken1 = -1;

    // 4時間足のトレンド判断→移動平均線のパーフェクトオーダー
    double MAS4 = iMA(_Symbol, PERIOD_H4, MAPeriod1, 0, Method, Price);
    double MAM4 = iMA(_Symbol, PERIOD_H4, MAPeriod2, 0, Method, Price);
    double MAL4 = iMA(_Symbol, PERIOD_H4, MAPeriod3, 0, Method, Price);

    // パーフェクトオーダー確認
    int jyouken2 = 0;
    if (MAL4 < MAM4 && MAM4 MAM4 && MAM4 > MAS4)
    jyouken2 = -1;

    // 前日に上へ大きく動き、かつ直近の高値を更新
    // 直近高安値を取得
    double H = iHigh(_Symbol, PERIOD_D1, iHighest(_Symbol, PERIOD_D1, MODE_HIGH, HLPeriod, 2));
    double L = iLow(_Symbol, PERIOD_D1, iLowest(_Symbol, PERIOD_D1, MODE_LOW, HLPeriod, 2));

    // 前日に上へ動いていて、かつ直近の高値を更新しているか(買い条件。売りはその逆)
    int jyouken3 = 0;
    if (iOpen(_Symbol, PERIOD_D1, 1) < iClose(_Symbol, PERIOD_D1, 1) && H iClose(_Symbol, PERIOD_D1, 1) && L > iClose(_Symbol, PERIOD_D1, 1))
    jyouken3 = -1;

    // ローソク足が20MAにタッチし下ヒゲ陽線
    double MAS1 = iMA(_Symbol, PERIOD_M15, MAPeriod1, 0, Method, Price);
    double OP = iOpen(_Symbol, PERIOD_M15, 1);
    double CL = iClose(_Symbol, PERIOD_M15, 1);
    double HI = iHigh(_Symbol, PERIOD_M15, 1);
    double LO = iLow(_Symbol, PERIOD_M15, 1);
    double BPips = Beard * _Point;

    int jyouken4 = 0;
    if (MAS1 < OP && LO <= MAS1 && BPips < OP – LO && OP OP && HI >= MAS1 && BPips CL)
    jyouken4 = -1;

    // 50MAと100MAが同じように上昇している
    double MAM1 = iMA(_Symbol, PERIOD_M15, MAPeriod2, 0, Method, Price);
    double MAL1 = iMA(_Symbol, PERIOD_M15, MAPeriod3, 0, Method, Price);
    double MAM2 = iMA(_Symbol, PERIOD_M15, MAPeriod2, 0, Method, Price);
    double MAL2 = iMA(_Symbol, PERIOD_M15, MAPeriod3, 0, Method, Price);

    int jyouken5 = 0;
    if (MAM2 < MAM1 && MAL2 < MAL1 && MAL1 MAM1 && MAL2 > MAL1 && MAL1 > MAM1)
    jyouken5 = -1;

    // すべての条件が整っているか
    int entry = 0;
    if (jyouken1 == 1 && jyouken2 == 1 && jyouken3 == 1 && jyouken4 == 1 && jyouken5 == 1)
    entry = 1;
    else if (jyouken1 == -1 && jyouken2 == -1 && jyouken3 == -1 && jyouken4 == -1 && jyouken5 == -1)
    entry = -1;

    return entry;
    }

    //+——————————————————————+
    //| Expert initialization function |
    //+——————————————————————+
    int OnInit()
    {
    return INIT_SUCCEEDED;
    }

    //+——————————————————————+
    //| Expert deinitialization function |
    //+——————————————————————+
    void OnDeinit(const int reason)
    {
    // 他の解放処理をここに追加する
    }

    //+——————————————————————+
    //| Expert tick function |
    //+——————————————————————+
    void OnTick()
    {
    // トレードロジックをここに追加する
    int entry = Logic1();

    // entryの値に応じたトレード処理をここに追加する
    if (entry == 1) {
    double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
    double stopLoss = NormalizeDouble(ask – TakeProfitPips * _Point, _Digits);
    double takeProfit = NormalizeDouble(ask + TakeProfitPips * _Point, _Digits);

    MqlTradeRequest request = {};
    MqlTradeResult result = {0};

    request.action = TRADE_ACTION_DEAL;
    request.symbol = _Symbol;
    request.volume = 0.1; // トレードしたいロットサイズを指定してください
    request.type = ORDER_TYPE_BUY;
    request.price = ask;
    request.sl = stopLoss;
    request.tp = takeProfit;

    // OrderSendの戻り値を確認する
    if(OrderSend(request, result) == false){
    Print(“OrderSend error: “, GetLastError());
    }
    } else if (entry == -1) {
    double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    double stopLoss = NormalizeDouble(bid + TakeProfitPips * _Point, _Digits);
    double takeProfit = NormalizeDouble(bid – TakeProfitPips * _Point, _Digits);

    MqlTradeRequest request = {};
    MqlTradeResult result = {0};

    request.action = TRADE_ACTION_DEAL;
    request.symbol = _Symbol;
    request.volume = 0.1; // トレードしたいロットサイズを指定してください
    request.type = ORDER_TYPE_SELL;
    request.price = bid;
    request.sl = stopLoss;
    request.tp = takeProfit;

    // OrderSendの戻り値を確認する
    if(OrderSend(request, result) == false){
    Print(“OrderSend error: “, GetLastError());
    }
    }
    }

    • 潤奈FX より:

      FXおじさん様

      コメントありがとうございます。
      MT5については私がまだ着手出来ていませんので、的確なアドバイスが出来ないのですが、自己解決能力は必要なのでその点でのアドバイスをさせて頂きます。

      取引が実行されない原因がどこにあるのか探さなければいけません。
      地道ですが一つづつ確認が必要です。

      例えば、Print関数でentryの値を確認する。
      entryの値がずっと0の場合はLogic1()関数の中に原因があります。
      int entry = Logic1();
      Print(entry);

      この関数の中に原因があるのであれば、パーフェクトオーダーの符号の向きに間違いがないか?そもそも移動平均線の値が正しく取得出来ているか?高安値を取得出来ているか?をPrint関数で確認して行きます。

      そして、ここに問題がないのであればOrderSendでのエラーを確認します。
      エラーが出ていればそのエラーを検索して調べる。

      他にはスプレッドや、証拠金の設定が足りてなくてなど、MT5の設定がおかしい場合もあるかと思います。
      MT4のコードをMT5にする時には、かなり仕様が変わっているという話は聞きますので、そのまま使い方として転用出来ない部分が他にあるかもしれません。

      すでに調べている事ばかりかもしれませんが、現状ではこちらの回答となりますが、頑張ってみて下さい!( ゚Д゚)

タイトルとURLをコピーしました