yfinance + fastapi = 股票历史 k 线 api

848 阅读3分钟

背景

无论是做量化交易还是行情分析,数据是少不了的。数据来源一般有三种

  1. 券商自己的数据源

这方面境外券商做的好一点,基本都开放了 api,申请很容易,只是有些限制,例如长桥的每月标的限制:

用户类型每月可查询的标的数量上限(只)
用户开户100
总资产达 1 万 HKD400
总资产达 8 万 HKD600
总资产达 40 万 HKD 或 月交易笔数大于 160 笔1000
总资产达 400 万 HKD 或 月交易笔数大于 1600 笔2000
总资产达 600 万 HKD 或 月交易笔数大于 2500 笔3000

而国内的券商一般需要单独开通量化功能,且数据接口的费用动辄要上万/年。

  1. 数据供应商

网上可以找到一些专门的数据供应商,可提供按月或者按量收费。下图为国内某公司提供的数据接口:

image.png

国外的则更贵一些:

image.png

  1. 开源数据仓库

一般是在公开网站上抓取所需要的信息,不保证稳定性,能提供的接口有限。同时需要自行搭建。如果你像笔者一样贫穷,这可能是唯一选项。

akshare,数据主要来源于国内各类财经网站,维护较为频繁,文档也比较丰富。他最大的好处是提供了 api 库,可以很方便的自行部署 api。

akfamily/akshare: AKShare is an elegant and simple financial data interface library for Python, built for human beings! 开源财经数据接口库

yfinance,数据来源于 Yahoo! Finance。算是国外最大的股票数据仓库了,目前 16k stars。可惜没有提供 api 库。没关系,本文会介绍如何封装成 api。

ranaroussi/yfinance: Download market data from Yahoo! Finance's API

安装 yfinance

创建 python 虚拟环境

python3 -m venv yfinance

安装 yfinance

./yfinance/bin/pip install yfinance

开启 python 命令行

./yfinance/bin/python3

测试输出股票历史数据

import yfinance as yf
dat = yf.Ticker("MSFT")
dat.history(period='1mo')

如果你能输出下图,那就成功了。

image.png

但如果有报错 yfinance.exceptions.YFRateLimitError: Too Many Requests. Rate limited. Try after a while.,那大概率是 ip 被封了,需要尝试更换服务器或者 ip。

安装 fastapi

安装 fastapi

./yfinance/bin/pip install "fastapi[standard]"

创建文件 main.py

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}

开启服务

./yfinance/bin/fastapi dev ./yfinance/main.py

测试接口

curl http://localhost:8000

如果能显示 {"Hello":"World"} 就成功了。

用 fastapi 封装 yfinance

新增一个接口,提供参数 symbol, startdate, enddate, interval 分别表示股票代码,开始日期,结束日期,间隔。具体的格式要求请参考 yfinance 代码内注释。

@app.get("/history")
async def history(symbol: str, startdate: str, enddate: str, interval: str):

获取数据

dat = yf.Ticker(symbol)
df = dat.history(start=startdate, end=enddate, interval=interval)

这里获取的数据是 DateFrame 格式,时间为 index。为了后续的使用,我们需要将时间转为新的一列

df = df.reset_index()

再将表格转为 json 格式返回。这里的 orient="records" 代表输出方式,详见官方文档。epoch 表示时间格式为时间戳

json_str = df.to_json(orient="records", date_format='epoch')
return Response(content=json_str, media_type='application/json')

完整的代码如下

from fastapi import FastAPI, Response
import yfinance as yf

app = FastAPI()

@app.get("/history")
async def history(symbol: str, startdate: str, enddate: str, interval: str):
    dat = yf.Ticker(symbol)
    df = dat.history(start=startdate, end=enddate, interval=interval)
    df = df.reset_index()
    json_str = df.to_json(orient="records", date_format='epoch')
    return Response(content=json_str, media_type='application/json')