この記事では、PythonのFastAPIを使用してYahoo Financeから株価データを取得し、そのデータをNext.jsを使って表示する方法について解説します。また、実装における工夫点についても詳しく説明します。
プロジェクトの概要
FastAPIを用いてYahoo Financeから株価データを取得し、Next.jsを使ってそのデータを表示するウェブアプリケーションを作成します。以下が今回の実装における主なステップです。
- FastAPIサーバーのセットアップ
- Next.jsアプリケーションのセットアップ
- FastAPIとNext.jsの統合
- データのグラフ化
ディレクトリ構成
まず、プロジェクト全体のディレクトリ構成を以下のように整理します。
my-app/
├── back-end/
│ ├── app/
│ │ ├── __init__.py
│ │ ├── main.py
│ └── requirements.txt
├── my-next-app/
│ ├── pages/
│ │ ├── index.js
│ ├── public/
│ ├── styles/
│ ├── .gitignore
│ ├── package.json
│ ├── README.md
│ ├── next.config.js
└── README.md
各ディレクトリとファイルの説明
-
back-end/: FastAPIプロジェクトを含むディレクトリ。
-
app/: FastAPIアプリケーションのコードを格納するディレクトリ。
- init.py: パッケージとして認識させるための空ファイル。
- main.py: FastAPIのメインアプリケーションコード。
- requirements.txt: 必要なPythonパッケージを記載したファイル。
-
app/: FastAPIアプリケーションのコードを格納するディレクトリ。
fastapi
uvicorn
yahoo_fin
-
/: Next.jsプロジェクトを含むディレクトリ。
-
pages/: Next.jsのページコンポーネントを格納するディレクトリ。
- index.js: メインページのコンポーネント。
- public/: 静的ファイルを配置するディレクトリ。
- styles/: CSSファイルを配置するディレクトリ。
- .gitignore: Gitが無視するファイルやディレクトリを記述したファイル。
- package.json: Next.jsプロジェクトの設定ファイル。
- README.md: プロジェクトの説明ファイル。
- next.config.js: Next.jsの設定ファイル(必要に応じて)。
-
pages/: Next.jsのページコンポーネントを格納するディレクトリ。
1. FastAPIサーバーのセットアップ
インストールと初期設定
まず、必要なパッケージをインストールします。
pip install fastapi uvicorn yahoo_fin
次に、FastAPIサーバーのコードを以下のように作成します。
# app/main.py
from fastapi import FastAPI, HTTPException
from yahoo_fin import stock_info as si
from fastapi.middleware.cors import CORSMiddleware
import pandas as pd
import logging
app = FastAPI()
origins = [
"http://localhost:3000", # Next.jsのデフォルトのポート
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
@app.get("/stocks/{symbol}")
async def get_stock_data(symbol: str, start: str, end: str):
try:
logger.info(f"Fetching data for {symbol} from {start} to {end}")
data = si.get_data(symbol, start_date=start, end_date=end)
data = data.reset_index()
data['date'] = data['index'].astype(str)
return data.to_dict(orient='records')
except Exception as e:
logger.error(f"Error fetching data: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=str(e))
工夫した点
- エラーハンドリング:適切なエラーハンドリングを追加し、エラーが発生した場合に詳細なログを記録するようにしました。
-
データ形式の整形:
pandas
データフレームのインデックスをリセットし、date
列を作成することで、データが正しい形式で返されるようにしました。
2. Next.jsアプリケーションのセットアップ
インストールと初期設定
Next.jsプロジェクトを作成し、必要なパッケージをインストールします。
npx create-next-app my-next-app
cd my-next-app
npm install chart.js react-chartjs-2
次に、Next.jsアプリケーションのコードを以下のように作成します。
import { useState } from 'react';
import { Line } from 'react-chartjs-2';
import { Chart, registerables } from 'chart.js';
Chart.register(...registerables);
export default function Home() {
const [data, setData] = useState(null);
const [symbol, setSymbol] = useState('');
const [start, setStart] = useState('');
const [end, setEnd] = useState('');
const fetchData = async () => {
try {
const response = await fetch(`http://localhost:8000/stocks/${symbol}?start=${start}&end=${end}`);
const result = await response.json();
// データのコンソール出力
console.log('Fetched data:', result);
if (Array.isArray(result)) {
setData(result);
} else {
console.error('Unexpected data format:', result);
setData([]);
}
} catch (error) {
console.error('Error fetching data:', error);
setData([]);
}
};
const chartData = {
labels: data ? data.map(item => item.date) : [],
datasets: [
{
label: `${symbol} Stock Price`,
data: data ? data.map(item => item.close) : [],
fill: false,
backgroundColor: 'rgba(75,192,192,0.4)',
borderColor: 'rgba(75,192,192,1)',
},
],
};
return (
<div>
<h1>Stock Data</h1>
<input placeholder="Symbol" value={symbol} onChange={(e) => setSymbol(e.target.value)} />
<input type="date" value={start} onChange={(e) => setStart(e.target.value)} />
<input type="date" value={end} onChange={(e) => setEnd(e.target.value)} />
<button onClick={fetchData}>Fetch Data</button>
{data && (
<Line data={chartData} />
)}
</div>
);
}
工夫した点
- データの形式確認:データを取得した際に、データが配列形式であることを確認し、想定外のデータ形式が返された場合のエラーハンドリングを追加しました。
-
グラフの表示:
chart.js
とreact-chartjs-2
を使用して、取得したデータをグラフ化しました。
3. FastAPIとNext.jsの統合
FastAPIサーバーを起動し、Next.jsアプリケーションからデータを取得して表示します。
実行
-
FastAPIサーバーを起動:
uvicorn app.main:app --reload
-
Next.jsアプリケーションを起動:
npm run dev
ブラウザで http://localhost:3000
にアクセスすると、Yahoo Financeから取得したデータがグラフとして表示されます。
シンプルな構成が難しかった理由
最初はシンプルな構成で実装を試みましたが、以下の点で難しさがありました。
-
クランブトークンとクッキーの問題: JavaScriptのライブラリを用いる際に、Yahoo Financeのクランブトークンとクッキーの取得や管理が必要でした。一方、Pythonの
yahoo_fin
ライブラリではこれらの管理が自動化されており、設定が簡単でした。 - エラーハンドリングの複雑さ: JavaScript側で発生するエラーのハンドリングが複雑で、エラーの原因を特定しにくかったため、PythonのFastAPIを使用してバックエンドを構築することにしました。
まとめ
この記事では、FastAPIとNext.jsを使ってYahoo Financeから株価データを取得し、そのデータをグラフとして表示する方法を紹介しました。エラーハンドリングやデータの形式確認など、いくつかの工夫点を中心に解説しました。このアプローチを活用して、他のデータソースやグラフ表示にも応用できるでしょう。