日経平均予測ツイートBOT

## はじめに
### 背景
未来を知りたい。。。
そんな思いに駆られて、日経平均予測ツイートBOTをPython+GCPで作りました。
日経平均は日本の株式市場の動きを象徴する指標で、多くの人が注目しています。これを予測することで、未来の動きを少しでも読み解けたら面白いと思ったのが、このプロジェクトを始めたきっかけです。
### BOTの概要と機能
日経平均を予測してツイートするBOTです。
## 必要な準備
### APIキーの取得
Twitter APIキーを取得する必要があります。
詳しい手順は[こちらのQiita記事](https://qiita.com/neru-dev/items/857cc27fd69411496388)をご覧ください。
### クラウド環境のセットアップ
#### Google Cloud Functionsのセットアップ
GCPでCloud Functionsを使うには、以下の手順が必要です：
1. プロジェクトの作成とCloud Functionsの有効化
2. Pythonコードのデプロイ
3. 必要なライブラリの設定

詳しい手順は、[Google公式ドキュメント](https://cloud.google.com/functions/docs?hl=ja)をご参照ください。

#### Cloud Schedulerでの定期トリガー設定
Cloud Schedulerを使って定期的にBOTを実行します。スケジュール設定の方法については、[Cloud Schedulerの公式ガイド](https://cloud.google.com/scheduler/docs?hl=ja)をご覧ください。

## コードの解説
### 全コード
```NIKKEI-Tweet-Bot-Function.py
import os
import tweepy
from yahoo_fin import stock_info as si
import pandas as pd
from datetime import datetime
from scipy.optimize import minimize
from scipy.stats import pearsonr
from sklearn.model_selection import train_test_split
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.metrics import mean_absolute_error
import numpy as np

# 環境変数からTwitter認証情報を取得
API_KEY = os.getenv('API_KEY')
API_SECRET = os.getenv('API_SECRET')
ACCESS_TOKEN = os.getenv('ACCESS_TOKEN')
ACCESS_SECRET = os.getenv('ACCESS_SECRET')

# データ取得開始日と終了日、データの目標
data_start_date = "2022-03-01"
today = datetime.today()
formatted_date = today.strftime("%Y-%m-%d")
data_end_date = formatted_date
target = "Close" #Low, High, Closeから選択
filtering_limit_low = 30000
filtering_limit_high = 43000

corn_target = f"corn_{target}"
gold_target = f"Gold_{target}"
nikkei_target = f"Nikkei_{target}"

# データ取得のためのクラス
class Data:
    def __init__(self, symbol, start_date, end_date):
        self.symbol = symbol
        self.start_date = start_date
        self.end_date = end_date
    
    def get_data(self):
        data = si.get_data(self.symbol, start_date=self.start_date, end_date=self.end_date, interval="1d")
        return data

def get_prediction():
    # データの取得と処理
    corn_instance = Data("ZC=F", data_start_date, data_end_date)
    corn_data = corn_instance.get_data()
    today_corn = corn_data["close"].iloc[-1]

    gold_instance = Data("GC=F", data_start_date, data_end_date)
    gold_data = gold_instance.get_data()
    today_gold = gold_data["close"].iloc[-1]

    nikkei_instance = Data("^N225", data_start_date, data_end_date)
    nikkei_data = nikkei_instance.get_data()

    merged_data = pd.concat([
        corn_data["close"].rename("corn_Close"),
        corn_data["high"].rename("corn_High"),
        corn_data["low"].rename("corn_Low"),
        gold_data["close"].rename("Gold_Close"),
        gold_data["high"].rename("Gold_High"),
        gold_data["low"].rename("Gold_Low"),
        nikkei_data["close"].rename("Nikkei_Close"),
        nikkei_data["high"].rename("Nikkei_High"),
        nikkei_data["low"].rename("Nikkei_Low"),
    ], axis=1).dropna()

    # 相関計算とモデルの訓練
    def objective(params):
        p_a, p_b = params
        mixed_close = -merged_data[corn_target] ** p_a + merged_data[gold_target] ** p_b
        corr, _ = pearsonr(mixed_close, merged_data[nikkei_target])
        return -corr

    result = minimize(objective, [1, 1], method='BFGS')
    optimized_params = result.x
    today_optimized_mixed_target = -today_corn ** optimized_params[0] + today_gold ** optimized_params[1]
    
    X = np.array(-merged_data[corn_target] ** optimized_params[0] + merged_data[gold_target] ** optimized_params[1]).reshape(-1,1)
    y = merged_data[nikkei_target]
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

    model = GradientBoostingRegressor(n_estimators=1000, learning_rate=0.01, max_depth=3, min_samples_split=2, subsample=1.0)
    model.fit(X_train, y_train)

    next_day_pred = model.predict(np.array([today_optimized_mixed_target]).reshape(-1, 1))
    rounded_next_day_pred = round(next_day_pred[0])
    
    return f"予測された次の日経平均株価の終値は、{rounded_next_day_pred}円です！\nこの予測は、{formatted_date}時点のデータに基づいています！\n#予測\n#日経平均株価"

def twitter_bot(data, context):
    tweet_word = get_prediction()
    
    # Twitter APIの認証と投稿
    auth = tweepy.OAuthHandler(API_KEY, API_SECRET)
    auth.set_access_token(ACCESS_TOKEN, ACCESS_SECRET)
    api = tweepy.API(auth)
    client = tweepy.Client(consumer_key=API_KEY, consumer_secret=API_SECRET, access_token=ACCESS_TOKEN, access_token_secret=ACCESS_SECRET)
    
    client.create_tweet(text=tweet_word)
    return "Tweet sent successfully!"

print(get_prediction())
```

```requirements.txt
tweepy
configparser
yahoo_fin
pandas
scipy
scikit-learn
```
### 必要なモジュールと役割
#### tweepy
Twitter APIを操作するためのライブラリ
#### yahoo_fin
Yahoo Financeから株価データを取得するためのライブラリ
#### scikit-learn
機械学習モデルの構築と評価

### データ取得と加工
Yahoo Finance APIを使い、日経平均、コーン、ゴールドの価格データを取得し、データフレームとして整形します。データの欠損値を削除し、分析の基礎を作ります。
### 相関係数計算とモデル訓練
コーンとゴールドの価格を適切に組み合わせて日経平均との相関を最適化します。その後、GradientBoostingRegressorを使い、翌日の予測値を計算します。
### Twitter投稿
tweepyライブラリを使って、予測結果をTwitterに自動投稿します。認証情報は環境変数で管理しています。
## 実行例
### BOTが生成したツイートの例
```
予測された次の日経平均株価の終値は、39060円です！
この予測は、2024-12-05時点のデータに基づいています！
#予測 #日経平均株価
```
## 改善ポイントと次のステップ
### 現時点での課題
・予測精度：より多くの指標を取り入れることで、予測精度を向上させたい。
・エラー処理：APIのデータ取得失敗や、Twitterの投稿エラーへの対策が必要。
### 今後追加したい機能
・通知機能：メールやSlackへの通知機能を追加する。
・可視化：予測結果と実際の値の推移をグラフ化して、予測精度を視覚的に確認できるようにする。
## 終わりに
### 実装してみた感想
ChatGPTさんに手伝ってもらいながら、コードと本記事を書きました。。。
ChatGPTさんや支えてくれた友人に感謝ですわ〜。
今後も、このBOTを改善していきたいと思います！この記事が誰かの参考になれば幸いです。