3、项目初始化与环境搭建:FastAPI框架选型、项目目录结构、依赖管理、配置文件设计
好,咱们正式开始动手了。
这一章,说白了就是搭架子。架子搭得稳,后面写代码才不慌。我在多个量化项目里踩过不少坑,比如目录乱成一锅粥、依赖冲突到崩溃、配置写死在代码里导致部署时手忙脚乱……嗯,这些教训让我对项目初始化这件事格外重视。
今天咱们就用 FastAPI 来搭一个因子工厂的架子。为什么选它?我后面会细说。
3.1 为什么选 FastAPI?
选框架这事儿,我个人的习惯是:不追新,但要够用且好用。
FastAPI 有几个点特别打动我:
- 性能好:基于 Starlette 和 Pydantic,异步原生支持。做量化因子计算,经常要并行拉数据、算指标,异步 IO 能省下大把时间。
- 自动生成文档:Swagger 和 ReDoc 开箱即用。你想想看,团队协作时,接口文档自动生成,省了多少沟通成本。
- 类型校验强:Pydantic 做数据模型,请求参数、响应数据都能自动校验。我在项目中遇到过因为因子参数传错类型导致计算崩溃的惨案,有了类型校验,这类问题基本绝迹。
- 社区活跃:遇到问题,Stack Overflow 上一搜一大把。生态也成熟,ORM、缓存、消息队列都有现成方案。
核心观点:FastAPI 不是万能的,但在量化因子工厂这个场景下,它几乎是完美的选择。轻量、高效、易维护。
3.2 项目目录结构
目录结构这事儿,我建议一开始就定好规矩。别等到项目大了再重构,那滋味可不好受。
下面是我在多个项目中沉淀下来的结构,你可以直接拿来用:
factor_factory/
├── app/ # 主应用目录
│ ├── __init__.py
│ ├── main.py # 应用入口
│ ├── api/ # API 路由层
│ │ ├── __init__.py
│ │ ├── v1/ # API 版本控制
│ │ │ ├── __init__.py
│ │ │ ├── factors.py # 因子相关接口
│ │ │ └── health.py # 健康检查
│ ├── core/ # 核心配置
│ │ ├── __init__.py
│ │ ├── config.py # 配置管理
│ │ └── security.py # 安全相关
│ ├── models/ # 数据模型
│ │ ├── __init__.py
│ │ ├── factor.py # 因子模型
│ │ └── response.py # 通用响应模型
│ ├── services/ # 业务逻辑层
│ │ ├── __init__.py
│ │ ├── factor_calc.py # 因子计算服务
│ │ └── data_feed.py # 数据接入服务
│ ├── db/ # 数据库相关
│ │ ├── __init__.py
│ │ ├── session.py # 数据库会话
│ │ └── base.py # 基类模型
│ └── utils/ # 工具函数
│ ├── __init__.py
│ ├── logger.py # 日志工具
│ └── helpers.py # 辅助函数
├── tests/ # 测试目录
│ ├── __init__.py
│ ├── test_factors.py
│ └── conftest.py
├── logs/ # 日志文件
├── data/ # 数据文件(本地开发用)
├── .env # 环境变量(不提交到 Git)
├── .env.example # 环境变量示例
├── .gitignore
├── requirements.txt # 依赖清单
├── pyproject.toml # 项目元数据
└── README.md
这个结构有几个好处:
- 分层清晰:API、业务逻辑、数据模型各司其职,互不干扰。
- 版本控制:api/v1 目录方便后续接口升级,不会影响老版本。
- 测试独立:tests 目录和主代码分离,跑测试时不会污染业务代码。
小提示:我个人习惯把 .env 文件放在项目根目录,但绝不提交到 Git。你可以在 .env.example 里写个模板,方便新同事快速上手。
3.3 依赖管理
依赖管理这事儿,说大不大,说小不小。我曾经在一个项目里因为依赖版本冲突,排查了整整两天。从那以后,我对依赖管理就格外上心。
我推荐用 pip + requirements.txt 的组合,简单直接。如果你喜欢更现代的方案,Poetry 或 PDM 也可以,但咱们这个课程里,我选择最通用的方式。
下面是我们因子工厂的核心依赖:
# requirements.txt
fastapi==0.104.1
uvicorn[standard]==0.24.0
pydantic==2.5.2
pydantic-settings==2.1.0
sqlalchemy==2.0.23
asyncpg==0.29.0
redis==5.0.1
pandas==2.1.4
numpy==1.26.2
python-dotenv==1.0.0
loguru==0.7.2
httpx==0.25.2
pytest==7.4.3
pytest-asyncio==0.23.2
安装命令很简单:
pip install -r requirements.txt
注意:我建议你使用虚拟环境。不管是 venv 还是 conda,都行。千万别把项目依赖装到全局 Python 里,否则后面有你哭的。
3.4 配置文件设计
配置文件,说白了就是项目的「开关面板」。环境变了,改配置就行,不用改代码。
我习惯用 pydantic-settings 来管理配置。为什么?因为它能自动从环境变量读取值,还能做类型校验。你想想看,如果配置里有个端口号写成了字符串,程序启动时直接报错,总比运行时莫名其妙出问题强。
来看一个完整的配置示例:
# app/core/config.py
from pydantic_settings import BaseSettings
from typing import Optional
class Settings(BaseSettings):
# 应用基础配置
APP_NAME: str = "Factor Factory API"
APP_VERSION: str = "1.0.0"
DEBUG: bool = False
# 服务端口
HOST: str = "0.0.0.0"
PORT: int = 8000
# 数据库配置
DATABASE_URL: str = "postgresql+asyncpg://user:pass@localhost:5432/factor_db"
DB_POOL_SIZE: int = 10
DB_MAX_OVERFLOW: int = 20
# Redis 配置
REDIS_URL: str = "redis://localhost:6379/0"
REDIS_TIMEOUT: int = 5
# 因子计算配置
FACTOR_CACHE_TTL: int = 3600 # 因子缓存时间,单位秒
MAX_CONCURRENT_CALC: int = 4 # 最大并发计算数
# 日志配置
LOG_LEVEL: str = "INFO"
LOG_FILE: str = "logs/factor_factory.log"
class Config:
env_file = ".env"
env_file_encoding = "utf-8"
settings = Settings()
对应的 .env 文件:
# .env
APP_NAME=Factor Factory API
DEBUG=true
PORT=8000
DATABASE_URL=postgresql+asyncpg://dev_user:dev_pass@localhost:5432/factor_dev
REDIS_URL=redis://localhost:6379/0
LOG_LEVEL=DEBUG
使用方式也很简单:
from app.core.config import settings
print(settings.APP_NAME) # 输出:Factor Factory API
print(settings.DATABASE_URL) # 输出:postgresql+asyncpg://dev_user:dev_pass@localhost:5432/factor_dev
关键点:配置文件和代码分离,这是 12-Factor App 方法论的核心原则之一。你的代码应该能在任何环境中运行,只需要换一套配置就行。
3.5 知识体系结构图
下面这张图,是我用 SVG 画的,展示了本章的知识脉络。你可以把它当作一张地图,随时回来看看自己走到哪了。
3.6 启动你的第一个 FastAPI 应用
架子搭好了,咱们跑起来看看。
在 app/main.py 里写个最简单的入口:
# app/main.py
from fastapi import FastAPI
from app.core.config import settings
app = FastAPI(
title=settings.APP_NAME,
version=settings.APP_VERSION,
debug=settings.DEBUG
)
@app.get("/")
async def root():
return {"message": "Factor Factory API is running!"}
@app.get("/health")
async def health_check():
return {"status": "healthy"}
启动命令:
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
打开浏览器,访问 http://localhost:8000/docs,你会看到 FastAPI 自动生成的 Swagger 文档页面。嗯,这个感觉就对了。
小技巧:加上 --reload 参数,代码改了会自动重启。开发时特别方便,省得你每次改完代码还要手动重启服务。
好了,项目初始化这块就聊到这儿。架子搭好了,后面咱们就可以往里面填东西了。记住,好的开始是成功的一半,别嫌这一步麻烦。
公众号:蓝海资料掘金营,微信deep3321