スポンサーリンク
FastAPIPython

📘 〜株価分析アプリ開発の第5回:FastAPI × yfinanceで個別銘柄と主要指数をまとめて返す API を作る

FastAPI
この記事は約7分で読めます。

前回の記事では、個別銘柄の月末株価を取得する API を作りました。 今回はさらに一歩進めて、個別銘柄の月末データと、主要指数(日経平均・S&P500・ダウ平均)をまとめて取得し、同じ日付で横に結合して返す API を実装します。

株価分析や機械学習では、

  • 目的変数(個別銘柄の株価)
  • 説明変数(指数やテクニカル指標) を同じ日付で揃えることが非常に重要です。

今回の API は、まさにそのための「分析用データセット生成 API」です。

1. 今回のゴール

最終的に返したいデータは次のような形です。(例:トヨタ

Date7203_Close7203_MA25NikkeiSP500Dow
2024-01-313150308036000480038000
2024-02-293200310536500485038500

つまり、 個別銘柄の月末データ(Close + MA)と、主要指数の月末データを 1 行にまとめる ということです。

2. 処理の流れ

今回の API は次の流れで動きます。

  1. 個別銘柄の過去5年の日次データを取得
  2. 25日移動平均(MA25)を計算
  3. 月末だけ抽出
  4. 日経平均・S&P500・ダウ平均も同じ処理
  5. Date をキーに横結合
  6. JSON として返す

この仕組みにより、分析に必要な「日付で揃った特徴量セット」が自動で生成されます。

3. stock_service.py(ビジネスロジック)

まずは、株価データを取得し、月末データに加工する関数です。別記事でstock_service.pyを記述している場合は書き換えます。

# app/services/stock_service.py

import yfinance as yf
from datetime import datetime, timedelta


def fetch_monthly_features(code: str, window: int = 25):
    if code.isdigit() and len(code) == 4:
        symbol = f"{code}.T"
    elif code in ["^N225", "^DJI", "^GSPC"]:
        symbol = code
    else:
        raise ValueError("銘柄コードは4桁の数字、または ^N225 / ^DJI / ^GSPC を指定してください。")

    end = datetime.today()
    start = end - timedelta(days=365 * 5)

    df = yf.Ticker(symbol).history(start=start, end=end)
    if df.empty:
        raise RuntimeError(f"{symbol} の株価データが取得できませんでした。")

    df["MA"] = df["Close"].rolling(window=window).mean()
    monthly_df = df.resample("ME").last()
    monthly_df = monthly_df.dropna(subset=["MA"])

    monthly_df = monthly_df[["Close", "MA"]].copy()
    monthly_df.reset_index(inplace=True)
    monthly_df["Date"] = monthly_df["Date"].dt.strftime("%Y-%m-%d")

    return monthly_df


def fetch_merged_features(target_code: str, window: int = 25):
    """
    個別銘柄 + 日経平均 + S&P500 + ダウ を
    Date で横結合して1行にまとめて返す
    """

    # 個別銘柄
    target = fetch_monthly_features(target_code, window)
    target = target.rename(columns={
        "Close": f"{target_code}_Close",
        "MA": f"{target_code}_MA{window}"
    })

    # 指数3つ
    nikkei = fetch_monthly_features("^N225", window).rename(columns={"Close": "Nikkei"})
    sp500 = fetch_monthly_features("^GSPC", window).rename(columns={"Close": "SP500"})
    dow = fetch_monthly_features("^DJI", window).rename(columns={"Close": "Dow"})

    # Date で横結合
    merged = target.merge(nikkei[["Date", "Nikkei"]], on="Date", how="inner")
    merged = merged.merge(sp500[["Date", "SP500"]], on="Date", how="inner")
    merged = merged.merge(dow[["Date", "Dow"]], on="Date", how="inner")

    return merged.to_dict(orient="records")

4. routes.py(API エンドポイント)

次に、FastAPI のルーティングです。

from fastapi import APIRouter, HTTPException
from app.services.nikkei_service import fetch_nikkei225_stocks
from app.services.stock_service import fetch_merged_features

router = APIRouter()

@router.get("/hello")
def hello():
    return {"message": "Hello FastAPI!"}

@router.get("/nikkei225", tags=["Nikkei"])
def get_nikkei225():
    return fetch_nikkei225_stocks()

@router.get("/monthly-features")
def monthly_features(code: str, window: int = 25):
    try:
        data = fetch_merged_features(code, window)
        return data
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except RuntimeError as e:
        raise HTTPException(status_code=404, detail=str(e))

上記コードを記述したら、以下のコードでFastAPIを起動します。

uv run uvicorn app.main:app --reload

5. 実際のエンドポイント

✔ 個別銘柄(例:7203)+ 指数3つをまとめて取得

以下のURLを叩くとデータがJSON形式で返却されます。

http://localhost:8000/api/v1/monthly-features?code=7203&window=25

docsで確認すると

パラメータを入れてテストすることもできます。

6.返却される JSON(例)

[
  {
    "Date": "2024-01-31",
    "7203_Close": 3150,
    "7203_MA25": 3080,
    "Nikkei": 36000,
    "SP500": 4800,
    "Dow": 38000
  },
  {
    "Date": "2024-02-29",
    "7203_Close": 3200,
    "7203_MA25": 3105,
    "Nikkei": 36500,
    "SP500": 4850,
    "Dow": 38500
  }
]

7. まとめ

今回の記事では、次のことができるようになりました。

  • 個別銘柄の月末データ(Close + MA)を取得
  • 日経平均・S&P500・ダウ平均の月末データも取得
  • すべてを Date で横結合して 1 行にまとめる API を実装
  • 分析や機械学習にそのまま使えるデータセットを自動生成

これにより、株価分析の前処理が大幅に効率化されます。

次回は、株価を分析予測する機械学習モデルを作ろうかと思っています。

コメント

タイトルとURLをコピーしました