AIでFXのトレード判定実装したらゼニの匂いがしてきた

  • 28 December 2021
Post image

 前回の記事でFX(為替)のレートと速報ニュースの関係についてデータを調査してみたが、今回は速報ニュースを受けたらすぐに機械学習(AI)のNLPモデルで分類して、ポジションの命令を出せるようなシステムを考えてみる。基本の考え方は前回の記事に詳細を載せている。
 今回は機械学習の実装や詳細は書かないことにする。かなり良い成果が出ているのだが、トレードの責任は持てないのでモデルの配布もしない。まぁ気楽に読んでいって~な。

BERTで為替のニュースを識別

 ここ数年、NLPの分野でBERTとその派生形が天下をとっているように見える。なのでその中でも学習メソッドが効率的なElectraを使用してみる。また、こういうのは英語を対象とする方が簡単なんだが、後述するが、私の場合日本取引時間に出る日本語ニュースがメインになると思われるため、言語対象は日本語とする。
 Electra Baseモデルを使用。事前学習は以下の学習を行ったモデルを独自に用意した。

  • 90GBの日本語テキストデータ
  • 250万stepの学習
  • batchサイズ512

 16GBメモリGPUを8枚使用して25日程度で完成した。ちなみにLargeモデルは45日程度で完成。(ただし今回はなぜかBaseモデルの方が高い精度をだすのでLargeは無視)

対象の通貨ペアと学習データの用意

 ポジションをL、Sするべきと判断されるデータは、ドル円、ユーロ円だとかなり少なくなってしまう。そしてある程度、L、S、何もしないのデータが均等に存在しないと機械学習の精度が高まらないことが分かった。そのため通貨ペアはボラティリティが高いポンド円を採用。
 また、学習データは前回の記事で書いたロ○ターニュースの2016年~2021年のもので以下の条件でフィルタリングした。

  • ポンドや円に明らかに関連しなさそうなものを排除
  • サマリー情報や市況情報は排除
  • 2016年~2020年のものを学習データ、2021年のものをテストデータとして振り分けた
  • その他テキスト前処理

 そしてラベリングは以下のもので行った。

ラベル0: レートが0.35%以上変動しない
ラベル1: レートが0.35%超上がる
ラベル2: レートが0.35%超下がる
ラベル3: レートが0.35%超上下する

そしてラベル1とラベル2の学習データをすべて1回複製して(×2して)データをかさましした。

# 学習データ数
{'0': 3625, '1': 2898, '2': 3050, '3': 126}
# テストデータ数
{'0': 579, '1': 132, '2': 167, '3': 2}

 やはり学習データが少ない。あと10倍くらいは欲しいところだが、今回は用意できないのでこれで。

ファインチューニング

 普通のGPU(Tesla T4)で2epoch学習。約30分くらいで完了する。またpytorchのフレームワークで学習を行った。正直丸1日いろいろチューニングを試したけどさほど結果は変わらず。

# 正しく分類できた2021年のニュース
749/880(0.8511)

 まずまずな結果だ。つまり、2016~2020年のニュースデータで学習したAIで2021年のニュースを解析した結果約85%の確率で正しいポジションを当てられたってこと。

Pythonで売買シミュレーション

 一応シミュレーションしてみよう。2021/1/1~2021/11/30の実際の相場で今回作成したモデル(AI)を利用してやってみる。すでに現時点から過去の期間なので、AIによるクラスタリングはすべて行って以下のようなCSV形式で出力している。

label, date
0,20210104010100
2,20210104062600
2,20210104063600
2,20210104100700
0,20210105002200
:

 このデータは私が作った機械学習モデルによって出力された売買の命令みたいなものを表す。例えば、2021/01/04/06:26(標準時)に出たニュースで"label=2"、つまりポンド円のSポジションをもちなさいってこと。そしてトレードのルールは以下のように規定する。多分この以下の7は、実際のトレードではかなり難しいのではないかな。

1. 初期投資額は100万円
2. ポジションは毎回レバレッジ10倍でとれる最大枚数をもつ(ポンド円は10000通貨で1枚)
3. AIがラベル1(Lポジ)またはラベル2(Sポジ)を出したときのみポジションをもつ
4. ニュース公表から1分後のレートでポジションをもつ
5. レートの0.25%で損切り
6. レートの0.35%利益方向に変動してはじめて約0.15%アゲインストの利確逆指値
7. 含み益が増加していけば、約0.15%アゲインストの利確逆指値を釣りあげていく
8. ポジションをもっている状態で次のポジション保有通知がきても無視(先に出た命令を優先)

 これらの条件を反映したシミュレーションは以下のコードで用意した。めちゃくちゃ汚いコードだが、今回はどうでもいい!ゼニ儲けの方が重要やろ!

import math
import csv
def get_csv_data():
    with open(f'GBPJPY.txt') as f:
        reader = csv.reader(f)
        ret = []
        for row in reader: ret.append(row)
        return ret

def get_result():
    with open(f'NLPの結果CSV') as f:
        reader = csv.reader(f)
        dic = {}
        for row in reader:
          if row[0] == 0 or row[0] == 3: continue
          dic[row[2]] = row[0]
        return dic

def get_profit(csv, i, type_num):
  l_or_s = 1
  if type_num == 2: l_or_s = -1
  if i >= len(csv): return 0
  spread = 0
  start = float(csv[i][3]) # 1分後のレート
  fix_profit_per = 1 + (0.0035 * l_or_s) # 利確逆指値を入れるポイント
  fix_profit_border_per = 0.0015 * l_or_s # fix_profit_perの0.15%againstで逆指値
  fix_profit_border = 0
  is_set_profit = False
  loss_cut_per = 1 - (0.0025 * l_or_s) # 損切り逆指値
  end = i
  for plus in range(99999):
    end += plus
    rate = float(csv[end][3])
    if end >= (len(csv) - 1): # 最新のレートの場合
      spread = (rate - start) * l_or_s
      break
    if rate < start * loss_cut_per and l_or_s == 1: # 損切り
      spread = (rate - start) * l_or_s
      break
    elif rate > start * loss_cut_per and l_or_s == -1: # 損切り
      spread = (rate - start) * l_or_s
      break
    if is_set_profit is False: # 利確ルールの設定
      if rate > start * fix_profit_per and l_or_s == 1:
        fix_profit_border = start * (fix_profit_per - fix_profit_border_per)
        is_set_profit = True
      elif rate < start * fix_profit_per and l_or_s == -1:
        fix_profit_border = start * (fix_profit_per - fix_profit_border_per)
        is_set_profit = True
    else: 
      if rate < fix_profit_border and l_or_s == 1: #利確処理
        spread = (rate - start) * l_or_s
        break
      elif rate > fix_profit_border and l_or_s == -1:
        spread = (rate - start) * l_or_s
        break
      if rate > (fix_profit_border + start * fix_profit_border_per) and l_or_s == 1: #利確ポイントを1分ごとに再設定
        fix_profit_border = rate - start * fix_profit_border_per
      elif rate < (fix_profit_border + start * fix_profit_border_per) and l_or_s == -1:
        fix_profit_border = rate - start * fix_profit_border_per
  return spread, end

if __name__ == '__main__':
    csv_data = get_csv_data()
    result_dic = get_result()
    asset_sum = 1000000 # 初期投資100万円
    leverage = 10 # レバは常に10倍
    unit = 10000 # 10,000通貨で1枚とする
    i = -1
    end = 0 # ポジションが被らないように終了時点のindexをもつ
    for c in csv_data:
      i += 1
      if i < end: continue
      result_data = result_dic.get(c[1] + c[2])
      if result_data is None: continue
      rate = float(csv_data[i + 1][3]) # 1分後のレート
      position_unit = math.floor((asset_sum * leverage) / (unit * rate)) # n枚のポジションを持つ
      spread, end = get_prof(csv_data, i + 1, result_data)
      asset_sum += position_unit * unit * spread
      print(math.floor(asset_sum))

なんと投資額が約2.5倍に!

 全部で113回のトレードを行い、 100万円がおよそ250万円に増えています! うそやろ?何かすごくねこれ。。
 正直試行回数が少なすぎるのと、ハイレバレッジでたまたまうまくいっているだけかもしれない。しかし11か月にわたって113回トレードしてうまいこと増えているのは驚きだ。前述の通り、利確の逆指値をうまいことスライドさせるのは多分難しいと思うので実際にはこんなパフォーマンスはでないのかも。また、システムトレードのシミュレーションで上手くいって、実際のトレードでボロボロってあるあるだから信用ならないけどな。

やっぱゼニやゼニ。

 う~ん。こんなにうまくいくとは全く思っていなかったんですが。。実際のトレードでは以下のような感じで行う。日本のFXの会社でAPIで取引できるところがなさそうなので、取引自体は人間が手で行う必要がある。残念。

 最新のニュースを常に取得して、その都度機械学習のモデルに通して判定する。ポジションをとるべきと判断した場合LINEで私に通知する。その後すぐにFXのアプリを開いてLかSのポジションを持つ。あとは上記のルールで決済する。ちなみに今回作成したAIモデルの実行時間は1秒程度なので、私がLINEに気付くことができれば1分以内にポジることは全然可能だ。LINEはDeveloper登録したら以下のコードで簡単にAPI送信できる。

import requests

def send_line(text):
  response = requests.post(
      'https://api.line.me/v2/bot/message/push',
      json={
          "to": "toid",
          "messages":[
              {
                  "type":"text",
                  "text":text
              }
          ]
      },
      headers={
          "Authorization": "Bearer TOKEN"
      }
  )

 また1か月に一回、機械学習モデルの追加学習を行う。一か月で為替ニュースがどんどん増えていくので、AIをアップデートしていくことで最新の情報を判断できるように強化していくわけだ。

 ただ、ここまで書いておいて思うんだけど、 世の中そんな甘くないやろ。明らかに上手くいきすぎていないか? てかなんか上記の線グラフとか詐欺サイトで出てきそうなやつやん(笑)。
 私が懸念していたのは、経済ニュースって連続性があると思うが、今回のモデルでは1つのニュースのみで判断している。なので例えば「FRBが利上げを示唆」からの「FRB金利据え置き」ってニュースがあった場合、2つ目のニュースが強すぎてポジションを再考する必要があると思うけど、今回のモデルでは最初のニュースを優先するようなルールにしている。また、2つのニュースから”大きなギャップ”が合った時に大きくレートが変動するものなので、ニュースを1つずつ判断するなんて明らかにおかしいと思うんだよね。

 しかし今回のAIモデルは上手く行っちゃっているので試さざるを得ない。まぁこのサイトで今後のパフォーマンスは書かないと思うけど。(なんか技術ブログではなくなっている気がする。。)

You May Also Like

Pythonでニュース速報と為替レートの関係を調べてみる

Pythonでニュース速報と為替レートの関係を調べてみる

 FXのシステムトレードについて、私はほぼすべてを信用していない。おそらく巨大なファンドがお金をかけて開発したシステムやごくごく一部の個人トレーダーがひたすら時間をかけて作ったシステムはもしかしたら稼げるのかもわからないが、その他のネット上に転がっている「FX自動売買システム」は誰でも簡単に儲けられ …

情弱が運営するWordPressサイトを攻撃する

情弱が運営するWordPressサイトを攻撃する

 なんとなく悪いことってのは、魅力的だったりする。 おそらく1970年代~1990年前半に生まれた人で、学生時代にPCを触っていた人ってアングラな世界に1度や2度触れたことがあるのではないでしょうか?特にエロ系ね。私も若かりし頃は、なんとかしてずりネタを確保しようと、意味も分かってなかった通信プロト …