Open15

仮想通貨MLbot探求のしおり

tomihei_tomihei_

機械学習 大事なこと

使用ツールは lightGBM

サンプル数

データはできるだけ長期間。
約定しやすい執行戦略にしてサンプル数を上げる。サンプルが少なければまず間違いなく過学習が起きる。

機械学習を通す前段階で、執行戦略とそのリターンがかなり重要なイメージがある。

richman方式の場合、マイナス手数料の取引所では生のリターンの状態でとんでもないマイナスになる。せめてフラットなとこまで持ってく執行戦略が必要。


学習具合

cvの区間別に学習具合を確認する。

1区間でも学習が進まない場合、
  • オーバーフィッティング
  • 特徴量が弱すぎ
    • yとの相関が低い?yの設計も考えなおす
  • 目的変数のばらつきを見る
  • サンプルウェイトやクラスウェイトの設定を見直す
 def training_model(trn_data=None, val_data=None,params=None index=None, plot=None):
        verbose_eval = 0
        records = {}
        clf = lgb.train(
                params, 
                trn_data,
                num_boost_round=10000,
                valid_sets=val_data,
                feval=self.evaluation.func if self.evaluation is not None else None,
                callbacks=[lgb.early_stopping(stopping_rounds=100, verbose=True),
                           lgb.log_evaluation(verbose_eval),
                           lgb.record_evaluation(records)]
        )
        # 学習具合を返す
        progress = records["valid_0"][metric]
        return clf,progress

サンプル・クラスウェイト設定

共通

richmanさんのノートにもあった
np.abs(リターン)

ファイナンス機械学習の

  • 平均独自性
  • 時間減衰
分類

is_umbalance : true 必要か?
scale_pos_weight: sqrt(負例数/正例数) 強い偏り補正
scale_pos_weight: 負例数/正例数

ラベルに極端な偏りがあると学習が進まない。
分類なら、CV期間ごとの予測値のばらつきも確認した方がいい。


特徴量重要度

木ごとの特徴量利用割合を下げていった時、極端に高い・低い重要度の特徴量は除外した方がいい。

ランダムなデータを加えてその他の特徴量と比較する。

df["RANDOM"] = np.random.normal(0, 1.0, df.shape[0] )

特徴量間の相関が高いものは正しく重要度が測れない。
ファイナンス機械学習にあるように、特徴量でクラスタリングして重要度を見てみたり、PCAで次元圧縮すると正確な数値がわかるって話。やれてない。


学習器

金融時系列はS/N比が低く価格やリターン推定はほぼ無理、分類や分位点回帰を使う。

目的変数のノイズと推論分布の関係について

https://zenn.dev/richwomanbtc/articles/1c4b71e74df0eb

lightGBMで分布予測

https://github.com/StatMixedML/LightGBMLSS


目的変数 y

正規分布に近づけた方がいいのかな。
sqrtやlog、boxcox変換して良さそうなのを使う。


特徴量

分数次差分をとる。

金融時系列は基本的に非定常なデータです。
非定常データをそのまま用いても機械学習の予測は難しい。
非定常データを定常データに変換するためには、差分を取る必要があります。

https://ai-trend.jp/basic-study/time-series-analysis/transformation/

ただ、こちらの記事にあるような1期、2期前といった整数次での差分は平均の推移の情報(メモリー)が抜け落ちてしまいます。
分数次差分では、1/2期,2/3期前といった差分の取り方が可能となり、メモリーを保持したまま定常なデータに変換できます。

機械学習で決定木を使うなら必須

詳細情報

https://qiita.com/takahashi-ry/items/17a101f10a54831cd324

高速な実装

https://github.com/fracdiff/fracdiff


メタラベリング

リターンの符号を予測するようなモデル(A)があった時、そのモデルに対してベッドサイズを決定するモデル(B)を作成する手法。

具体的には一段目の予測モデルAの推論結果と、実際のリターン符号が正しい場合は1をそれ以外は0を割り当てた目的変数(y')を学習したモデルBを作成する。

目的変数 y' =
Aが + と予測する。 => 実際のリターン符号 + => 1
Aが - と予測する。 => 実際のリターン符号 - => 1
Aが + と予測する。 => 実際のリターン符号 - => 0
Aが - と予測する。 => 実際のリターン符号 + => 0

Bはy'を学習し、Aの推論の正答率を予測する。

出力した正答率から適切なベッドサイズを決めるには、ファイナンス機械学習10章を参照。


逐次ブートストラップ

ラベルの平均独自性をもとに時系列全体の独自性を高める抽出方法
使えてない。

ファイナンス機械学習では、ランダムフォレストのブートストラップを置き換えるためのものだった。
GBDTで使う場合、bagging設定をオフにして逐次ブートストラップで抽出したデータ毎にモデルを作成して予測の平均を出すのがいいのかな。すごい過学習しそう。

本のやつよりは速い実装(間違ってるかも


@numba.jit(nopython=True)
def rand_choice_nb(arr, prob):
    return arr[np.searchsorted(np.cumsum(prob), np.random.random(), side="right")]

@numba.jit(nopython=True, parallel=True)
def seq_bootstrap(num, index, probs):
    '''
    num : 何個の時系列を生成するか
    index : ラベルのインデックス
    probs: ラベルの平均独自性
    '''
    seq_bootstrap_arr = []
    for v in numba.prange(num):
        phi = np.zeros(index.size)
        cal = np.ones(index.size)
        master = probs
        for i in range(index.size):
            prob = (probs / np.sum(probs))
            pick_data = rand_choice_nb(arr=index, prob=prob)
            phi[i] = pick_data
            pick_index = np.where(index == pick_data)[0][0]
            cal[pick_index] += 1
            probs = master / cal
        phi = np.sort(phi)
        seq_bootstrap_arr.append(phi)
    return seq_bootstrap_arr

特徴量のbinning

binning : 値を代表値に分割集約する処理
過学習防止

from sklearn.preprocessing import KBinsDiscretizer

def binning(n_bins=10,df)
    df = df.dropna()
    for feat in x_feats:
            bins[feat] = KBinsDiscretizer(n_bins=10, encode="ordinal")
            bins[feat].fit(df[[feat]])
            df[feat] = bins[feat].transform(df[[feat]])
            #pickle_dump(bins[feat], f"../input/gresearch/bins_model/bins_{feat}.pickle")
参考コード

https://www.kaggle.com/code/yukieleventyone/g-research-final

n_bins数は5分位がおすすめ?

https://zenn.dev/ageonsen/articles/7723d5d1f7dc8f#データ作成


ハイパーパラメータチューニング

あんまりよくわかってない。
CPCVとoptunaで組み合わせて寝てる間にベストなパラメータが出てる。
良いものをより良くできるという認識、よくないものをよくすることはできない。

CPCV

https://qiita.com/persimmon-persimmon/items/f52c37dca943ee58fd8e

optuna

https://zenn.dev/megane_otoko/articles/2021ad_09_optuna_optimization

オススメハイパラ

https://note.com/j26/n/n64d9c37167a6

重要だなって思うハイパラ簡単解説

n_estimators

決定木の数、earlystopping設定で勝手に学習止めるなら10000とか大きい数にする。

"learning_rate"

学習率、大きいと大雑把に学習する(スピードが速い)本番では0.01とかにする

"extra_tree" True,

上の記事に説明があるやつ、過学習防止

"max_depth"

決定木の階層数、大きすぎると過学習する

"feature_fraction"

一本の決定木に使う特徴量の割合、numeraiのサンプルでは0.1、できるだけ低くして汎化性能をあげる。

"bagging_fraction"

利用するサンプルの割合、低くして汎化性能上げる

"bagging_freq"

決定木何本に一回バギングするかの設定、

具体的な解説はこちらがわかりやすい。

https://knknkn.hatenablog.com/entry/2021/06/29/125226#bagging_fractionsubsample


本番モデルの作成法

  1. パージ済みCVでモデルを作成する。この時アーリーストッピングで各期間の木の本数を確定
  2. 各期間の木の本数の平均をとる
  3. 2で出した値にcvの期間数に応じて係数をかける cv数5なら1.2とか
  4. n_estimatorsに3の値を入れて全データで学習する。

twitterで見た感じいろんなやり方があるっぽい
直近のデータをvalidデータとして、アーリーストッピングかけるとか

正解はわからないけど、良い特徴量とyを与えてやれば決定木の本数が大きすぎても精度は下がらない。

下記記事参照

https://zenn.dev/ageonsen/articles/7723d5d1f7dc8f#特徴量の吟味

とりあえず各CVの学習進捗は確認する!


バックテストしすぎない

損益曲線を見てもいいけど、あまり意味は考えない方がいい。

tomihei_tomihei_

bot開発

ライブラリ

今から開発するならこれ!
pybotters
https://github.com/MtkN1/pybotters/tree/main/pybotters

pybotters-wrapper
https://github.com/ko0hi/pybotters-wrapper

有料だけど
ccxt
https://github.com/ccxt/ccxt

MLBotに必要な機能

  • データ取得
  • データ整形
  • 特徴量作成
  • 推論

どんな時間軸・発注方式で戦うにせよスピードは早くした方がいいんでしょうね。

止まらないbot

止まっても再起動させる
https://note.com/btcml/n/nfb226649686f

複雑なプログラムを書きたくないなら、エントリーとイグジットで難しいことをしすぎない。
複雑になりすぎたと思ったら寝る!

23/01/27

ローソク足の更新が止まってる
lambdaで動かしてるローソク足保存機能が原因?
rate limitに引っかかってる?

tomihei_tomihei_

bot最速化計画

現状

発注まで1.5秒程度かかってる。
ごく稀に指値が成行に変わってしまう。

データ受信 0.01秒
データ前処理 0.6秒
推論 0.8秒
発注 0.1秒

推論非同期処理・並列化?
データ前処理部分を最適化する。

データ前処理部分

  • 話題のpolars導入する

推論

tomihei_tomihei_

執行コストを考える。

執行コスト例

https://www.tac.biz/wp-content/uploads/2022/09/2023年2次証券分析_基本テキスト_第1章_株式:取引コストとその分析_p52-.pdf

執行戦略と取引コストに関する研究の進展(難しい)

https://www.imes.boj.or.jp/research/papers/japanese/kk31-1-8.pdf

  • 数式が多くて難しい。
  • 取引の遅延等は、指値注文の場合あまり気にしなくて良いか。。。
  • マーケットインパクトは小口の場合考えない
    • 指値位置分散させるのが良い?
  • botでは、収益が最大になる参入価格と、実際に参入した価格の差をコストとして考えても良いかも
tomihei_tomihei_

特徴量を考える

自動生成する?

特徴量のスクリーニング
https://note.com/btcml/n/n3cb3324d0eb1

OHLCV以外の特徴量

  • oi
  • liquidation
  • taker makerに関する情報

強すぎる特徴量はよくない。
結局一個ずつ検証するしかない気がする

tomihei_tomihei_

CNNについて学ぶ

MNISTで学ぶCNN

https://qiita.com/mako0715/items/b6605a77467ac439955b

CNNわかりやすい動画解説

https://www.youtube.com/watch?v=xzzTYL90M8s&ab_channel=予備校のノリで学ぶ「大学の数学・物理」

構造化データを使ったCNN例

https://blog.shikoan.com/brest-cancer-cnn/

まず手を動かすことから始める。

ファイナンスへの応用については、マケデコの輪読会でつかってる参考書かって考える。(載ってるのはRNNだけど)
https://www.amazon.co.jp/データ駆動型ファイナンス-基礎理論からPython機械学習による応用-吉川-大介/dp/4320096525/ref=sr_1_39?__mk_ja_JP=カタカナ&crid=2IUO8OM96VQ3W&keywords=ファイナンス&qid=1675562928&sprefix=ファイナンス%2Caps%2C199&sr=8-39

CNN使って予測

既存の特徴量・目的変数で学習。
GBDTより学習が安定しない & 精度が低い。
中間層を適当に増やすと過学習しがち。

やり方が間違ってる?

CNNの特徴

畳み込みで特徴量間の関係を学んでいる。
パターン認識が得意

GBDTとCNNのいいとこ取りできないかな。

tomihei_tomihei_

あん

戦略のリターン符号(手数料なし)分類
戦略リターンが往復手数料より大きいか分類

ウェイト

エントリーからイグジットまでの日数に応じてウェイトを減少させる。
=> 時間経過で予測力を失っていく。

tomihei_tomihei_

現状分析

取引数が少ない。
=> ohlcv + a で作成した特徴量じゃ説明力がなくなっている。

ボラティリティが増える場面ではしっかりと稼いでる。
=> ノイジーなトレーダーはフォローできてる。

対策

より多くの非効率なトレードやミスプライスを発見するしかない。

具体的に

  • 市場間(フィアット・国債・株式・仮想通貨)の関係性を表現できる特徴量の追加
    => データソース増やす、特徴量いっぱいつくる
  • 既存の特徴量からより多くのデータを取り出す。
    => CNN?