FX自動売買(EA)の作り方MQL4MQL5Python

【Python】ナンピン幅をATRに連動させるFX自動売買ツールの開発④【MQL5/MQL4】

※アフィリエイト広告を利用しています

広告

この度、ナンピン幅および利確幅をATRに連動させて、破綻リスクを確率的に制御するナンピンマーチン型のFX自動売買ツール(EAまたはBOT)の開発を行いました。

この記事は、前回の記事の続きです。

MQL5で開発しMT5で稼働させるEA、MQL4で開発しMT4で稼働させるEA、Pythonで開発しMT5のPython APIを利用して稼働させるBOT、とそれぞれ用意しているのですが、この記事ではそのEAまたはBOTの開発における思考過程を少しずつ具体的に記事にしていきたいと思います。

なお、作成したMT5用EAとMT4用EAについては、以下からダウンロード可能です。

広告

前回まで

以下のようなデータフレーム(df_ATR)を作成しました。

これを用いて、1分足で簡易的に勝率を試算する関数を作成します。

勝率を試算する関数

buyポジションの勝率計算

@numba.njit
def calc_buy_result(op=None, lo=None, hi=None, lc_range=None, tp_range=None, spread=None):
    y = op.copy()
    y[:] = np.nan
    for i in range(op.size):
        lc_price = op[i] - lc_range[i] + spread
        tp_price = op[i] + tp_range[i] + spread
        for j in range(i + 1, op.size):
            if lo[j] < lc_price:
                y[i] = -1
                break
            if hi[j] > tp_price:
                y[i] = 1
                break
    return y

以下、各コードの説明をしていきます。

@numba.njit

これは、処理を高速化するおまじないのようなものです。

ChatGPTに説明してもらったので載せておきます。

@numba.njitは、PythonのパッケージであるNumbaを使って、関数を高速化するための装飾子(デコレータ)です。これにより、Pythonのコードを最適化して、C言語やFortranのような高速な言語と同等の速度を得ることができます。
つまり、これを入れるだけで計算処理が速くなるのですが、一つポイントとして、Pandasのdf(データフレーム)のまま処理するコードを書いても扱えないことがあります。
Numbaは、一部のpandasのメソッドや演算子に対応しています。特に、数値計算に関連する処理を高速化することができます。ただし、すべてのpandasのメソッドや演算子に対応しているわけではないので、実際に使ってみて、高速化されるかどうかを確認する必要があります。

したがって、ここでは基本的にPandasのdfは、配列に変換してから引数にするという前提で書いています。

引数

以下のような引数を想定した関数になります。

  • op:始値(Open)
  • lo:安値(Low)
  • hi:高値(High)
  • lc_range:ロスカット幅
  • tp_range:利確幅
  • spread:想定スプレッド

return y

この関数は、yを返します。最初の処理でyを初期化しています。

y = op.copy()
y[:] = np.nan

ループ処理

以下の通り、Openのレコード数(op.size)だけループさせます。1分足であれば、毎分処理するイメージです。

for i in range(op.size):

利確価格とロスカット価格

始値から、利確幅だけ上を利確価格、ロスカット幅だけ下をロスカット価格に設定します。その際、スプレッド幅も考慮して、利確がスプレッド分だけ不利に(ロスカットが有利に)なるようにしておきます。

lc_price = op[i] - lc_range[i] + spread
tp_price = op[i] + tp_range[i] + spread

ポジションクローズ

時刻iにおける始値でポジションを取るので、その後のi+1以降の時刻における安値と高値を見にいきます。

for j in range(i + 1, op.size):
    if lo[j] < lc_price:
        y[i] = -1
        break
    if hi[j] > tp_price:
        y[i] = 1
        break

先に安値がロスカット価格を下回ったら負けとしてy=-1、高値が利確価格を上回ったら勝ちとしてy=1、というアウトプットを出力して終了します。

sellポジションの勝率計算

同様に、sellポジションの勝率を計算する関数も用意しておきます。ロジックはほぼ同様です。

@numba.njit
def calc_sell_result(op=None, lo=None, hi=None, lc_range=None, tp_range=None, spread=None):
    y = op.copy()
    y[:] = np.nan
    for i in range(op.size):
        lc_price = op[i] + lc_range[i] - spread
        tp_price = op[i] - tp_range[i] - spread
        for j in range(i + 1, op.size):
            if hi[j] > lc_price:
                y[i] = -1
                break
            if lo[j] < tp_price:
                y[i] = 1
                break
    return y

四本値(バー)をインプットに勝率計算

df[‘y’]の追加

用意したdf_ATRとcalc_buy_result関数を使って、以下のようにdf[‘y’]を追加します。

df = df_ATR
df = df.dropna()
df['ATR'] = 12.00
spread = 0.15
tp_factor = 1.0
lc_factor = 1.0

df['y']= calc_buy_result(
    op=df['Open'].values,
    lo=df['Low'].values,
    hi=df['High'].values,
    lc_range=lc_factor*df['ATR'].values,
    tp_range=tp_factor*df['ATR'].values,
    spread = spread,
)

df[‘ATR’] = 12.00とすることによって、df_ATRに入っていたATRを上書きして固定幅にすることが可能です。これを削除すれば、ATRに連動した利確幅とナンピン幅を設定できます。

また、tp_factorとlc_factorはATRの何倍を利確幅・ナンピン幅にするかを設定する係数です。

DMI_flgの反映

こちらは以下のように既に出力されたdf[‘y’]を書き換えるだけで可能です。

df.loc[(df['DMI_flg'] != 1), 'y'] = 0

これは何をしているかと言いますと、フラグを反映させる前は、df[‘y’]には勝ち(+1)または負け(-1)のどちらかの値が入っています。これを、DMI_flgが0の場合は引き分け(0)とします。

つまり、フラグが0であればエントリーしないということを表現しています。

勝率計算

書き方は様々ですが、例えば以下のようにします。

buy_wins = len(df[df['y']==1])
buy_trials = len(df[df['y']!=0])
buy_win_rate = round( buy_wins / buy_trials * 100, 2)
print('buy勝ち:',buy_wins,'buy試行回数:', buy_trials, 'buy勝率:',buy_win_rate,'%')
出力結果は、以下です。
buy勝ち: 1076024 buy試行回数: 2117811 buy勝率: 50.81 %

勝率の変化を確認

以上の流れで勝率を計算し、ATRとDMIを考慮せずに勝率を計算した場合と、考慮して勝率を計算した場合で、どのように変化するかを確認した結果が以下の通りです。

利確幅 DMI buy 勝率 sell 勝率 buy+sell 勝率
12.00固定 なし 52.9% 45.7% 49.3%
ATR×3.2 なし 50.8% 47.2% 49.0%
12.00固定 あり 54.8% 47.6% 51.1%
ATR×3.2 あり 54.1% 50.4% 52.2%

検証期間としては、2017年〜2022年の4年間です。勝率50%をやや超えているというのは最低水準クリアですので、なかなか良い感じです。これを応用すれば実装してもそこまで悪くない結果が得られるかもしれません。

まとめ

さて、以上の通り、1分足を使ったEAの簡単なバックテスト方法をご紹介しました。

ベースロジックが思い浮かんだら、このように1分足で勝率を試算してみるというのは有用です。これが良かったら実装しても必ず良い結果が得られるとは限りませんが、少なくともこの結果が悪ければそれ以上ブラッシュアップしてもあまり良いEAにはならなそうということは言えるかと思います。

次回からは、ティックデータを使ってより詳細なバックテストを行う方法をご紹介します。

同じように、Google ColabとPythonを使って進めていく予定です。

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