マーチンゲールの任意リセット

EAつくーる
オートリバース
2024/09/11 16:45
45

連敗時のマーチンゲールを相場状況や収支状況を勘案して任意のタイミングでリセットしたい場面があるのですが、
どのようにすればよいでしょうか。よろしくお願いします。

コメント

GogoJungle
2024/09/13 12:50

EAつくーるの機能のみでは実現できないためコードの修正が必要ですが、検証作業には非常に多くのステップと時間が必要となるため、考え方のヒントのみ提供させていただきます。
なお、ポジション1のみで動作する(Magic1しか使用しない)ものとして説明します。

リセット用のフラグを用意する

マーチンゲールをリセットするためのフラグを用意します。
OnTick関数が呼び出される度に0にリセットされ、条件を満たした場合のみ1になるようにします。

例えば、 OnTick関数内の

   Trade = true;

という行の下に1行追加し

   Trade = true;
   int is_martingale_reset = 0; // マーチンゲールリセットフラグ

とするとよいでしょう。

フラグを立てる

何らかの条件でリセットフラグを1にします。
下記コードが記述してある行を探し、その直前で実施します。

   if(signal != 0 && getOpenLots(Magic1) == 0) {
      if(isMartingale) lots = Martingale(lots, MartingaleCustom, MartingaleLots, MartingaleMult, MartingaleAdd, MartingaleMax, Magic1);
…

例えば、「ロングにおけるデッドクロス(短期MAが長期MAを上から下に抜ける)が発生したらリセットする」場合は次のようにします。

   if(iMA(Symbol(), 0, 25, 0, MODE_SMA, PRICE_CLOSE, 2)+PipsToPrice(0)  >  iMA(Symbol(), 0, 75, 0, MODE_SMA, PRICE_CLOSE, 2)+PipsToPrice(0)
    && iMA(Symbol(), 0, 25, 0, MODE_SMA, PRICE_CLOSE, 1)+PipsToPrice(0)  <  iMA(Symbol(), 0, 75, 0, MODE_SMA, PRICE_CLOSE, 1)+PipsToPrice(0)) is_martingale_reset = 1;

因みに今回の例は、EAつくーるの「取引条件」で生成されたコードのsignalという変数をis_martingale_resetに置き換えて作成しました。
このように、EAつくーるの機能を応用して、目的となる部分的なコードを簡単に作成できる場合があります。

変数「連敗無視数」の準備

通常、マーチンゲールは連敗数に応じてlot数を変化させますが、今回は勝ちトレードが生じていないにもかかわらずそこまでの連敗を無視することになるため、少し工夫が必要です。

(実際の連敗数) - (リセットまでの連敗数)

を元にlotの計算を行うために、リセットまでの連敗数、lose_ignore(「連敗無視数」と呼ぶことにします)を用意しておきます。
マジックナンバーの定義の下あたりに書いておくとよいでしょう。

修正前

input int Magic1 = 1;

修正後

input int Magic1 = 1;
int lose_ignore = 0; // 連敗無視数

連敗数を取得する関数の準備

任意のタイミングで連敗数を取得可能な関数を準備します。
コードの一番最後に追加しましょう。

//+--------------------------------------------------------------------------------------------------------+
//| 現在までの連敗数を取得する関数
//|  処理:現在までの連敗数を取得する
//|  引数:マジックナンバー
//|  戻り値:現在までの連敗数
//+--------------------------------------------------------------------------------------------------------+
int getLoseCount(int magic)
{
    int lose = 0;
    double profit = 0.0;

    for(int i = OrdersHistoryTotal() - 1; i >= 0; i--) {
        if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) == false) continue;
        if(OrderSymbol() != Symbol() || OrderMagicNumber() != magic) continue;

        profit = OrderProfit();

        if(profit < 0) {
            lose++;
        } else if(profit == 0) {
            continue;
        } else {
            break;
        }
    }

    return(lose);
}

連敗無視数のセットとリセット

フラグが立っている場合は連敗無視数をセット、前回が勝ちトレードだった場合(= 連敗数が0の場合)はリセットします。
「フラグを立てる」の項目で記述したコードの直下に、下記コードを追加します。

   // マーチンゲールをリセットする場合は連敗無視数に現在までの連敗数をセット
   if(is_martingale_reset == 1) {
      lose_ignore = getLoseCount(Magic1);
   }

   // 前回が勝ちトレードだった場合は連敗無視数をリセット
   if(getLoseCount(Magic1) == 0) {
      lose_ignore = 0;
   }

マーチンゲール関数に連敗無視数を渡す

引数に連敗無視数を追加します。

修正前

if(isMartingale) lots = Martingale(lots, MartingaleCustom, MartingaleLots, MartingaleMult, MartingaleAdd, MartingaleMax, Magic1);

修正後

if(isMartingale) lots = Martingale(lots, MartingaleCustom, MartingaleLots, MartingaleMult, MartingaleAdd, MartingaleMax, Magic1, lose_ignore);

マーチンゲール関数を修正する

連敗無視数の分だけ連敗数を減らしてロットの計算が行われるように修正します。

修正前

double Martingale(
    double base_lots,
    int is_custom,
    string clots,
    double mult,
    double add,
    double limit,
    int magic)
{
    
(中略)


    if(is_custom) {
        if(lose < clots_cnt) {
            lots = custom_lots[lose];
        } else {
            lots = custom_lots[clots_cnt - 1];
        }
    } else {
        lots = lots * MathPow(mult, lose) + add * lose;
    }

    if(limit != 0 && lots > limit) lots = limit;

    return(lots);
}

修正後

double Martingale(
    double base_lots,
    int is_custom,
    string clots,
    double mult,
    double add,
    double limit,
    int magic
    int lose_ignore) // この変数を追加する
{
    
(中略)

    if(lose >= lose_ignore) lose -= lose_ignore; // 連敗数の調整(この行を追加する)

    if(is_custom) {
        if(lose < clots_cnt) {
            lots = custom_lots[lose];
        } else {
            lots = custom_lots[clots_cnt - 1];
        }
    } else {
        lots = lots * MathPow(mult, lose) + add * lose;
    }

    if(limit != 0 && lots > limit) lots = limit;

    return(lots);
}

最後に

前述のように、上記のコードあくまでヒントです。
細かい検証は行っておりませんので、修正される場合は十分な検証をお願いいたします。
参考になれば幸いでございます。

オートリバース
2024/09/13 18:38

ありがとうございます。
もしかしたら私の書き方が悪かったかもしれませんが、

今連敗中で、保有ポジションが無い状態で、
次のエントリーは一旦初期ロット(例えば0.01)からリスタートしたいので
それをパラメータをいじる等で手動で行うことは可能でしょうか。

という事ですが、それでも上記お答えいただいたようにプログラム的な事が必要になるでしょうか。

GogoJungle
2024/09/13 18:57

はい、仰る通りの挙動を実装するための修正方法が、先述のものでございます。

EAつくーるに搭載されているマーチンゲールのロジックは、前回のロット数を元に今回の数値を計算する漸化式的な方法ではなく、何連敗しているかをティック毎に取得して一般項の式から計算するため、仮に途中で初期エントリーのロットに戻しても、次のエントリーでは数列の元の項に戻ってしまうのです。

例えば、デフォルトが

0.01→0.02→0.04→0.08→0.16→0.32→0.64...

であり、0.04の後でリセットを行った場合、期待する挙動は

0.01→0.02→0.04→0.01→0.02→0.04→0.08...

ですが、単に0.04の後のロット数を0.01にしただけの場合は

0.01→0.02→0.04→0.01→0.16→0.32→0.64...

となります。

これを防ぐために、連敗数自体をシフトしてあげる必要があり、その方法が少々複雑なのです。

オートリバース
2024/09/15 05:10

わかりました。
ありがとうござます。

関連トピックス

検索結果がありません。

ノーコードで誰でも簡単EA開発!MQL言語学習にも使える! | GogoJungle

注目トピックス

検索結果がありません。