💹

richmanbtcさんチュートリアル 正解データ作成までの流れ

2022/03/08に公開

注意 Force Entry Priceまで飛ばします。

特徴量や学習モデルの作成は扱いません。
この記事ではひたすら正解データについて扱います。

botter必読書

  • 日給300万円のSS級トレーダーが明かすbotterのリアル

https://amzn.to/3hUFlfm
いわずと知れたリッチマンさんの著書です。
ぼんやりと仮想通貨のトレードで儲けたいと考えていた僕を、
botterの道へ明確に導くキッカケになった本。

botterになろうと考えている人は、botterのメリット、
狙い目などの概略的な部分が知れて良いと思います。

  • Kaggleで勝つ技術

https://amzn.to/3MD6iCf
リッチマンさん推奨の本。分からなくなったら読めと書いてあった。
僕はデータの前処理や学習モデルを作っているとき、「???」となることがあった。
そのとき読んでクリアできた。

過去の僕の記事

文系で機械学習未経験の僕が、richmanBTCさんのチュートリアルをやってbotterになるまでの流れ

https://zenn.dev/flutternyumon/articles/4fa5f97b0c4ba3

richmanbtcさんのForce Entry Priceがよく分からなかったので、自分なりにまとめてみた

https://zenn.dev/flutternyumon/articles/17fffff306fd79

本題

正解データ作成までの流れ

  1. 終値 - ATR*0.5で、エントリー価格を出す。

  2. ['buy_executed']とかで、一本後の足でエントリーできるか調べる。
    また、calc_force_entry_priceメソッドを走らせて、
    いくらで約定できたか、いつまでに約定できたかを出す。

  3. ②で一本後の足でエントリーできた場合、
    [y_buy]などで正解データを計算。
    できなかった場合は0を入れる。

  4. ②で一本後の足でエントリーできた場合、
    手数料を計算。できなかった場合は0を入れる。

1.終値 - ATR*0.5で、エントリー価格を出す。

# ATRで指値距離を計算します
limit_price_dist = df['ATR'] * 0.5
limit_price_dist = np.maximum(1, (limit_price_dist / pips).round().fillna(1)) * pips
# 終値から両側にlimit_price_distだけ離れたところに、買い指値と売り指値を出します
df['buy_price'] = df['cl'] - limit_price_dist
df['sell_price'] = df['cl'] + limit_price_dist

[buy_price]の場合、cl(終値) - ATR*0.5 をする。
ここで求めた値を使って、1,約定できたかどうか、|約定できた場合2,約定した価格、3,約定した時間を求める。

指値が約定したかどうかを0,1で表示する

# 指値が約定したかどうか (0, 1)
df['buy_executed'] = ((df['buy_price'] / pips).round() > (df['lo'].shift(-1) / pips).round()).astype('float64')
df['sell_executed'] = ((df['sell_price'] / pips).round() < (df['hi'].shift(-1) / pips).round()).astype('float64')

ここでは、一本後の足で指値が約定したかどうかを調べている。
このチュートリアルでは一本後の足で約定できなかった場合はエントリーしないという仕組みなっている。

ここを変更して、例えば10本まで待つといったことをしても良いと思う。

2. ['buy_executed']とかで、一本後の足でエントリーできるか調べ、calc_force_entry_priceメソッドを走らせて、いくらで約定できたか、いつまでに約定できたかを出す。

Force Entry Priceでエントリーした価格、かかった時間を求める

# Force Entry Priceの計算
df['buy_fep'], df['buy_fet'] = calc_force_entry_price(
    entry_price=df['buy_price'].values,
    lo=df['lo'].values,
    pips=pips,
)
# calc_force_entry_priceは入力と出力をマイナスにすれば売りに使えます
df['sell_fep'], df['sell_fet'] = calc_force_entry_price(
    entry_price=-df['sell_price'].values,
    lo=-df['hi'].values, # 売りのときは高値
    pips=pips,
)
df['sell_fep'] *= -1

ここでは、一本後の足で約定できてなかった場合でも、約定した価格と時間を出す。

3.②で一本後の足でエントリーできた場合、[y_buy]などで正解データを計算。できなかった場合は0を入れる。

# yを計算
df['y_buy'] = np.where(
    df['buy_executed'],
    df['sell_fep'].shift(-horizon) / df['buy_price'] - 1 - 2 * fee,
    0
)
df['y_sell'] = np.where(
    df['sell_executed'],
    -(df['buy_fep'].shift(-horizon) / df['sell_price'] - 1) - 2 * fee,
    0
)

先ほど一本後の足で約定できるかどうかを代入したdf['buy_executed']を使う。
もし代入できていたら、[y_buy]に正解データを計算し、代入する。

約定できていなかったら、0を入れる。

4.②で一本後の足でエントリーできた場合、手数料を計算。できなかった場合は0を入れる。

# バックテストで利用する取引コストを計算
df['buy_cost'] = np.where(
    df['buy_executed'],
    df['buy_price'] / df['cl'] - 1 + fee,
    0
)
df['sell_cost'] = np.where(
    df['sell_executed'],
    -(df['sell_price'] / df['cl'] - 1) + fee,
    0
)

先ほど一本後の足で約定できるかどうかを代入したdf['buy_executed']を使う。
もし代入できていたら、[buy_cost]などに正解データを計算し、代入する。

約定できていなかったら、0を入れる。

出典

richmanbtcさんのgithub「https://github.com/richmanbtc/mlbot_tutorial」

Discussion