この度、ナンピン幅および利確幅をATRに連動させて、破綻リスクを確率的に制御するナンピンマーチン型のFX自動売買ツール(EAまたはBOT)の開発を行いました。
この記事は、前回の記事の続きです。
MQL5で開発しMT5で稼働させるEA、MQL4で開発しMT4で稼働させるEA、Pythonで開発しMT5のPython APIを利用して稼働させるBOT、とそれぞれ用意しているのですが、この記事ではそのEAまたはBOTの開発における思考過程を少しずつ具体的に記事にしていきたいと思います。
なお、作成したMT5用EAとMT4用EAについては、以下からダウンロード可能です。
前回まで
talibで複数のテクニカル指標を計算
以下のように、1分足の各種テクニカル指標を計算しました。
この記事では、勝率計算は1分足で行いますが、テクニカル指標は1時間足を使うことにして、話を進めます。
1時間足にtalibでDMIフラグを追加
以下の通り、1分足と同様の手順でテクニカル指標を追加したdf(データフレーム)を用意します。
ここで、DMI_flgというフラグを追加しています。
#DMI_flg
df['DMI_flg'] = 0
df.loc[(df['pDI'] > df['mDI']), 'DMI_flg'] = 1
df.loc[(df['pDI'] < df['mDI']), 'DMI_flg'] = -1
+DIと-DIを比較して、+DIが大きければ+1、-DIが大きければ-1、というフラグです。
DMI(Directional Movement Index 、方向性指数)は、
-DI:下降トレンドである可能性を判断
ADX:トレンドの強弱を判断
1分足に1時間足のフラグを追加
ここでの勝率シミュレーションでは、価格変動は1分足を用いて、売買判断は1時間足を用いるので、二つのデータを結合します。
bar_timeを追加
ここは少しテクニカル(技術的)な話になりますが、まずは、df_H1にbar_timeを追加します。
start_time = datetime(2017, 1, 1, 0, 0, 0, 0)
df = df_H1
df = df.dropna()
df = df.reset_index()
df['start_time'] = start_time
delta = (df['time'] - df['start_time']).dt
df['bar_time'] = (df['time'] - df['start_time'])//timedelta(minutes=60)
df = df.set_index('time')
df_H1 = df
処理の流れを簡単に解説します。
まず、start_timeとして、起点となる時間を設定します。ここでは、2017年1月1日の0時を起点としています。
そして、そのstart_timeと、それぞれのレコードの時間(time)の差を取って、1時間(minutes=60)単位の整数にします。
出来上がったdf_H1は以下の通りです。
一つ目のレコードの2017-01-06 09:00:00は、2017-01-01 00:00:00から129時間後なので、bar_timeには129が入っています。以下、1時間(1レコード)毎に1ずつ増えていくような形です。
1分足に、1時間足のテクニカル指標を結合
pandasのdfのまま追加するロジックの方がわかりやすかったりしますが、それだと処理が遅くなるので、numbaを用いて処理が速くなるようなロジックにしています。少しわかりにくいかもしれませんが、載せておきます。
@numba.njit
def calc_bar_i(
df_len_bar,
df_Open,
df_bar_time,
len_bar,
bar_time,
bar_DMI_flg,
bar_ATR,
):
DMI_flg = df_bar_time.copy()
DMI_flg[:] = np.nan
ATR = df_Open.copy()
ATR[:] = np.nan
for j in range(len_bar):
if bar_time[j] == df_bar_time[0]:
bar_j = j
break
for i in range(df_len_bar):
for j in range(bar_j,len_bar):
if bar_time[j] == df_bar_time[i]:
bar_j = j
DMI_flg[i] = bar_DMI_flg[j-1]
ATR[i] = bar_ATR[j-1]
break
return DMI_flg, ATR
そして、このcalc_bar_i関数を用いて、以下の処理を行います。
df = df_M1
df = df.reset_index()
df['start_time'] = start_time
delta = (df['time'] - df['start_time']).dt
df['bar_time_H1'] = (df['time'] - df['start_time'])//timedelta(minutes=60)
df = df.set_index('time')
df['DMI_flg'],df['ATR']= calc_bar_i(
df_len_bar=len(df),
df_Open=df['Open'].values,
df_bar_time=df['bar_time_H1'].values,
len_bar=len(df_H1),
bar_time=df_H1['bar_time'].values,
bar_DMI_flg=df_H1['DMI_flg'].values,
bar_ATR=df_H1['ATR'].values,
)
df_ATR = df.dropna()
結果、以下のようなデータフレーム(df_ATR)が出来上がります。
処理の流れを簡単に解説しておくと、1分足のtimeから、2017年1月1日の0時を起点とした1時間単位の整数(bar_time_H1)を作成して、df_H1のbar_timeとマッチング、マッチングしたレコードの1つ前のレコードのDMI_flgとATRを取得しています。
例えば2017年1月4日の3:00であれば、2017年1月4日の2:00の1時間足で作成したDMI_flgとATRを取得することになります。
これはつまり、3:00の時点で確定している時間足は2:00のものなので、その情報(指標)を基に取引を行うという状態をイメージしてデータを作成していることになります。
勝率の変化を確認
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% |
この結果からわかる考察を少しまとめます。
- 何も考慮せずにbuyの勝率が50%を超えていて、sellの勝率が50%を下回っているので、全体的に上昇トレンドの方が多かったということが推測できます。
- sellの勝率が、ATRとDMIを考慮するとわかりやすく50%を超えるまで上昇しており、それなりに効果がありそうに見えます。
次の記事では、この勝率を試算するコードと、もう少し深く考察していく方向に進みます。