ChatGPT先生に明日のBTC価格が上がるか下がるか聞いてみた

# 趣旨
最近のGPT先生はバージョンがアップが凄まじく、気づかないうちに新機能が続々と登場していたので、面白半分でGPT先生に価格予測してもらったら仕事が楽になるんじゃないかと思って聞いてみました。

GPT先生にAPIで接続して毎回直接予測を聞かせてもらおうと思って依頼してみたんですが、なぜかコードをまるまるくれたので言われるがままコードの中身も全く把握せず起動させてみました…。

そしたらなんか言い切る形でアップトレンドだとはっきり言ってもらったのでロングしようと思います(^^)

```json
{
  "prediction": "up"
}
```

# コード
必要なライブラリをインストールします。
結構多いですね。
なぜFlask採用なのかもよくわかりません。
とりあえずコードくれたので喜んで実行してみます。

```
pip install pandas numpy scikit-learn joblib flask yfinance
```

Gradient Boosting Machine (GBM) modelというモデルを使っているみたいですが、僕にはそれが何なのか、どうやって動かすのか皆目見当がつきません。

**詳しい方がいらしたら、コメントにてご説明をお願いします。**

以下のコードでモデルのトレーニングとデータの生成をするようです。

```python bitcoin_predictor.py
# Import libraries
import pandas as pd
import numpy as np
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import train_test_split
import joblib
import yfinance as yf
from flask import Flask, jsonify

# Fetch Bitcoin data
def fetch_data():
    data = yf.download("BTC-USD", period="2y", interval="1d")
    return data

# Preprocess data and generate features
def preprocess_data(data):
    data['MA10'] = data['Close'].rolling(window=10).mean()
    data['Price_Change'] = data['Close'].diff()
    data['Target'] = (data['Price_Change'] > 0).astype(int)
    data['RSI'] = rsi(data['Close'])
    data.dropna(inplace=True)
    return data

# Calculate RSI
def rsi(series, period=14):
    delta = series.diff(1)
    gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
    loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean().abs()
    RS = gain / loss
    return 100 - (100 / (1 + RS))

# Train and save the model
def train_and_save_model(data):
    features = data[['MA10', 'RSI']]
    target = data['Target']
    X_train, X_test, y_train, y_test = train_test_split(features, target, test_size=0.2, random_state=42)
    
    model = GradientBoostingClassifier()
    model.fit(X_train, y_train)
    joblib.dump(model, 'btc_model.pkl')

# Load the trained model
def load_model():
    model = joblib.load('btc_model.pkl')
    return model

# Make a prediction
def make_prediction(model, data):
    latest_data = data.iloc[-1:][['MA10', 'RSI']]
    prediction = model.predict(latest_data)
    return "up" if prediction[0] == 1 else "down"

# Main function to run the entire process
def main():
    btc_data = fetch_data()
    preprocessed_data = preprocess_data(btc_data)
    train_and_save_model(preprocessed_data)
    print("Model trained and saved.")

# Flask API
app = Flask(__name__)

@app.route('/predict', methods=['GET'])
def predict():
    try:
        model = load_model()
        btc_data = fetch_data()
        preprocessed_data = preprocess_data(btc_data)
        prediction = make_prediction(model, preprocessed_data)
        return jsonify({'prediction': prediction})
    except Exception as e:
        return jsonify({'error': str(e)})

if __name__ == '__main__':
    main()  # Comment this out if you're running Flask app
    app.run(debug=True)  # Uncomment this to run Flask API
```
実行してちょっと待っているとこんなメッセージが出ます。
```
(openai) (base) danieltanaka@Daniels-MacBook-Air ~ % python bitcoin_predictor.py
/Users/daniel/openai/lib/python3.10/site-packages/yfinance/utils.py:775: FutureWarning: The 'unit' keyword in TimedeltaIndex construction is deprecated and will be removed in a future version. Use pd.to_timedelta instead.
  df.index += _pd.TimedeltaIndex(dst_error_hours, 'h')
[*********************100%%**********************]  1 of 1 completed
Model trained and saved.
```
モデル生成がおわったようですね。

次に上のコードのモデルのトレーニングをオフにしてFlaskをオンにしたコードを実行します。
よくわからない人もいると思うので、さっきのコードと全く同じファイルの中を全部決して以下のコードをまるまる貼り付けて実行するだけでOKです。

```python bitcoin_predictor.py
# Import libraries
import pandas as pd
import numpy as np
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import train_test_split
import joblib
import yfinance as yf
from flask import Flask, jsonify

# Fetch Bitcoin data
def fetch_data():
    data = yf.download("BTC-USD", period="2y", interval="1d")
    return data

# Preprocess data and generate features
def preprocess_data(data):
    data['MA10'] = data['Close'].rolling(window=10).mean()
    data['Price_Change'] = data['Close'].diff()
    data['Target'] = (data['Price_Change'] > 0).astype(int)
    data['RSI'] = rsi(data['Close'])
    data.dropna(inplace=True)
    return data

# Calculate RSI
def rsi(series, period=14):
    delta = series.diff(1)
    gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
    loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean().abs()
    RS = gain / loss
    return 100 - (100 / (1 + RS))

# Train and save the model
def train_and_save_model(data):
    features = data[['MA10', 'RSI']]
    target = data['Target']
    X_train, X_test, y_train, y_test = train_test_split(features, target, test_size=0.2, random_state=42)
    
    model = GradientBoostingClassifier()
    model.fit(X_train, y_train)
    joblib.dump(model, 'btc_model.pkl')

# Load the trained model
def load_model():
    model = joblib.load('btc_model.pkl')
    return model

# Make a prediction
def make_prediction(model, data):
    latest_data = data.iloc[-1:][['MA10', 'RSI']]
    prediction = model.predict(latest_data)
    return "up" if prediction[0] == 1 else "down"

# Main function to run the entire process
def main():
    btc_data = fetch_data()
    preprocessed_data = preprocess_data(btc_data)
    train_and_save_model(preprocessed_data)
    print("Model trained and saved.")

# Flask API
app = Flask(__name__)

@app.route('/predict', methods=['GET'])
def predict():
    try:
        model = load_model()
        btc_data = fetch_data()
        preprocessed_data = preprocess_data(btc_data)
        prediction = make_prediction(model, preprocessed_data)
        return jsonify({'prediction': prediction})
    except Exception as e:
        return jsonify({'error': str(e)})

if __name__ == '__main__':
    # main()  # Comment this out if you're running Flask app
    app.run(debug=True)  # Uncomment this to run Flask API
```

Flaskが起動して以下のようなメッセージがでます

```
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 965-342-561
/Users/danieltanaka/openai/lib/python3.10/site-packages/yfinance/utils.py:775: FutureWarning: The 'unit' keyword in TimedeltaIndex construction is deprecated and will be removed in a future version. Use pd.to_timedelta instead.
  df.index += _pd.TimedeltaIndex(dst_error_hours, 'h')
[*********************100%%**********************]  1 of 1 completed
127.0.0.1 - - [09/Feb/2024 20:31:26] "GET /predict HTTP/1.1" 200 -
127.0.0.1 - - [09/Feb/2024 20:31:27] "GET /favicon.ico HTTP/1.1" 404 -
```

Flaskがローカルサーバーを立ち上げてる状態になるので、以下のURLに同一パソコン内のブラウザーでアクセスします。

http://127.0.0.1:5000


そうすると明日のBTC価格が上なのか下なのか予想が書かれています。

当たるわけがないと思うのですが、55％くらいの確率で当たっていたらと考えたらワクワクしますね。