期末專題 (二):建構 FastAPI 股市資料服務 (第 46 章)

站主自己的課程,請大家支持
揭秘站長的架站心法:如何利用 Hugo × AI 打造高質感個人品牌網站? 揭秘站長的架站心法:如何利用 Hugo × AI 打造高質感個人品牌網站?
  • Post by
  • Jan 29, 2024
post-thumb

在這一章,我們要實作 Backend。它的唯一職責就是:「前端跟我要什麼股票資料,我就去 Yahoo Finance 抓回來給它。」

1. 資料服務層 (Service Layer)

我們先寫一個 service.py 專門處理 yfinance 的邏輯。這樣 main.py (API 層) 就不會跟資料邏輯混在一起,這叫做 關注點分離 (Separation of Concerns)

# backend/service.py
import yfinance as yf
import pandas as pd

def get_stock_info(ticker: str) -> dict:
    """取得股票基本資訊 (現價, 本益比...)"""
    stock = yf.Ticker(ticker)
    info = stock.info
    return {
        "symbol": info.get("symbol"),
        "name": info.get("longName"),
        "price": info.get("currentPrice", info.get("regularMarketPrice")),
        "currency": info.get("currency"),
        "pe_ratio": info.get("trailingPE"),
        "eps": info.get("trailingEps")
    }

def get_stock_history(ticker: str, period: str = "1mo") -> str:
    """取得歷史股價 (回傳 JSON 字串)"""
    stock = yf.Ticker(ticker)
    # 抓取歷史資料
    df = stock.history(period=period)
    
    # 整理資料:重設索引,讓 Date 變成欄位
    df.reset_index(inplace=True)
    
    # 轉換日期格式
    df['Date'] = df['Date'].dt.strftime('%Y-%m-%d')
    
    # 轉成 JSON 格式回傳 (使用 records 格式較易讀)
    return df.to_dict(orient="records")

2. API 介面層 (Controller Layer)

接著修改 backend/main.py,建立 API 端點。

# backend/main.py
from fastapi import FastAPI, HTTPException
from service import get_stock_info, get_stock_history

app = FastAPI(title="Stock API", version="1.0.0")

@app.get("/")
def read_root():
    return {"message": "Welcome to Stock API"}

@app.get("/stock/{ticker}")
def read_stock_info(ticker: str):
    """取得單檔股票即時資訊"""
    try:
        data = get_stock_info(ticker)
        if not data["price"]: # 簡單檢查
            raise HTTPException(status_code=404, detail="Stock not found")
        return data
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/history/{ticker}")
def read_stock_history(ticker: str, period: str = "1mo"):
    """
    取得歷史股價 K 線資料
    period: 1d, 5d, 1mo, 3mo, 6mo, 1y, 2y, 5y, 10y, ytd, max
    """
    try:
        data = get_stock_history(ticker, period)
        return data
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

3. 測試 API

打開終端機,啟動服務:

cd backend
uvicorn main:app --reload

用瀏覽器或 Postman 測試:

  • 基本面: http://localhost:8000/stock/AAPL -> 應回傳 Apple 的股價資訊。
  • 台股測試: http://localhost:8000/stock/2330.TW -> 應回傳台積電資訊。
  • K 線資料: http://localhost:8000/history/NVDA?period=1y -> 應回傳 NVIDIA 一年走勢。

4. 總結

我們成功建立了一個微服務 (Microservice)! 它不關心誰來呼叫它 (可能是網頁、可能是手機 App),它只負責吐出標準的 JSON 資料。

下一章,我們將切換到 Frontend,使用 Streamlit 來把這些冰冷的 JSON 數據變成漂亮的互動儀表板!


除錯小撇步: 如果 yfinance 報錯,通常是因為網路連線問題或股票代碼錯誤。可以嘗試更新套件:pip install --upgrade yfinance

LATEST POST
TAG