开发指南
Fire 量化交易系统开发实践指南。
🚀 快速开始
启动服务
# 启动所有服务
./scripts/startup.sh
# 仅启动后端
./scripts/startup.sh --backend-only
# 仅启动前端
./scripts/startup.sh --frontend-only
访问地址:
- 前端: http://localhost:3000
- 后端 API: http://localhost:8000
- API 文档: http://localhost:8000/docs
环境要求
- Python 3.13+
- Node.js 18+
- Redis 6+
- Git
🔧 环境配置
初始化配置
# 复制配置模板
cp .env.example .env
# 编辑配置
vim .env
必需环境变量
# Redis
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_DB=0
# 环境类型
ENVIRONMENT=development # development/staging/production
开发环境配置
# 长桥 API(可选,用于开发测试)
LONGPORT_APP_KEY=your_app_key
LONGPORT_APP_SECRET=your_app_secret
LONGPORT_ACCESS_TOKEN=your_access_token
# 开发环境认证 Token(可选)
AUTHORIZATION=Bearer your-jwt-token-here
# 强制 Mock 模式(测试用)
FORCE_MOCK_MODE=true
默认测试账户
- 用户名:
test_for_dev - 密码:
test_only_for_dev - 注意: 生产环境必须删除此账户
📁 项目结构
fire/
├── backend/
│ ├── venv/ # Python虚拟环境
│ ├── api/ # API端点
│ ├── core/ # 核心业务逻辑
│ │ ├── trading/ # 交易核心模块
│ │ │ ├── strategies/ # 策略实现(⭐ 正确路径)
│ │ │ ├── engines/ # 交易引擎
│ │ │ ├── models/ # 交易数据模型
│ │ │ └── services/ # 交易服务
│ │ └── models/ # 通用数据模型
│ └── tests/ # 测试代码
├── frontend/
│ ├── src/
│ │ ├── pages/ # 页面组件
│ │ ├── services/ # API服务层
│ │ └── utils/ # 工具函数
│ └── node_modules/ # 依赖包
├── docs/ # 文档
├── scripts/ # 脚本工具
└── .specify/ # Spec-Kit配置
💻 开发规范
Python 开发
代码风格:
# 格式化代码
cd backend && source venv/bin/activate
black .
isort .
# 代码检查
flake8 .
mypy .
命名规范:
- 文件名:
snake_case.py - 类名:
PascalCase - 函数/变量:
snake_case - 常量:
UPPER_SNAKE_CASE
TypeScript 开发
API 调用规范:
// ✅ 正确:使用 API 服务层
import { tradingApi } from '@/services';
const session = await tradingApi.getSession(sessionId);
// ❌ 错误:直接使用 fetch
const response = await fetch('/api/v1/sessions/123');
命名规范:
- 组件:
PascalCase.tsx - 工具函数:
camelCase.ts - 样式文件:
ComponentName.module.scss
🎯 CSS 样式规范 - 必须使用 CSS Modules:
所有组件样式必须写在 .module.scss 文件中,禁止使用内联样式:
// ✅ 正确:使用 CSS Modules
import styles from './StrategyCard.module.scss';
export const StrategyCard: React.FC = () => {
return (
<div className={styles.card}>
<Text className={styles.title}>{title}</Text>
</div>
);
};
// ❌ 错误:内联样式
<div style=>
<Text style=>{title}</Text>
</div>
// ❌ 错误:内联 style 标签
<style>{`.my-class { padding: 12px; }`}</style>
CSS Modules 文件示例:
// StrategyCard.module.scss
.card {
padding: 12px;
border-radius: 6px;
border: 1px solid var(--semi-color-border);
background-color: var(--semi-color-bg-none);
transition: all 0.2s ease;
&:hover {
border-color: var(--semi-color-focus-border);
}
}
.title {
display: block;
margin-bottom: 4px;
}
.disabled {
opacity: 0.5;
cursor: not-allowed;
}
CSS Modules 命名规范:
- 使用 camelCase:
.strategyCard,.templateHeader - 状态类使用语义化命名:
.active,.disabled,.selected - 组合多个类:
className={\${styles.card} ${isActive ? styles.active : ‘’}`}`
为什么使用 CSS Modules:
- ✅ 样式隔离,避免全局污染
- ✅ 便于维护和重构
- ✅ 支持 SCSS 嵌套和变量
- ✅ 编译时检查类名是否存在
Toast 提示规范:
🎯 原则: 避免在 Hook 层显示 Toast,统一在组件层处理
// ❌ 错误:Hook 中显示成功 Toast(会导致双重提示)
export function useCustomTemplates() {
const saveTemplate = async (name: string) => {
const result = await api.save(name);
Toast.success('保存成功'); // ❌ Hook 层不应显示成功提示
return result;
};
}
// ✅ 正确:Hook 只处理错误,成功由组件层处理
export function useCustomTemplates() {
const saveTemplate = async (name: string) => {
try {
const result = await api.save(name);
return result; // ✅ 只返回结果
} catch (err) {
Toast.error('保存失败'); // ✅ 错误提示可以在 Hook 层
return null;
}
};
}
// ✅ 正确:组件层显示成功提示
function MyComponent() {
const { saveTemplate } = useCustomTemplates();
const handleSave = async () => {
const result = await saveTemplate(name);
if (result) {
Toast.success('模板保存成功'); // ✅ 组件层显示成功提示
}
};
}
原因:
- Hook 是可复用的,不同场景的提示文案可能不同
- 避免 Hook 和组件层都显示 Toast 导致双重提示
- 组件层更了解业务上下文,可以定制更准确的提示
规则总结:
- ✅ 组件层:显示成功提示、业务相关提示
- ✅ Hook 层:显示错误提示(通用错误)、验证失败提示
- ❌ Hook 层:不显示成功提示
数据处理规范
金融计算:
# ✅ 使用 Decimal 精确计算
from decimal import Decimal
price = Decimal("100.50")
quantity = Decimal("10")
total = price * quantity
# ❌ 避免使用 float
total = 100.50 * 10 # 精度问题
日期时间:
# ✅ 使用 total_seconds() 精确计算
duration = (end_time - start_time).total_seconds() / 86400
# ❌ 避免使用 .days(会向下取整)
duration = (end_time - start_time).days
🧪 测试
运行测试
# 使用测试脚本(推荐)
./scripts/test.sh unit # 单元测试
./scripts/test.sh integration # 集成测试
./scripts/test.sh coverage # 覆盖率报告
# 手动运行
cd backend && source venv/bin/activate
python -m pytest tests/unit/ -v
测试环境
- 测试使用独立的 Redis DB(15)
- 测试不需要启动开发服务器
- 测试不会影响开发环境数据
编写测试
# backend/tests/unit/test_example.py
import pytest
from backend.core.models import Order
def test_order_creation():
"""测试订单创建"""
order = Order(
symbol="AAPL.US",
quantity=100,
price=150.00,
side="buy"
)
assert order.symbol == "AAPL.US"
assert order.total_value == 15000.00
🎯 Spec-Kit 工作流
Fire 项目采用规范驱动开发(Specification-Driven Development)。
核心命令
| 命令 | 用途 | 说明 |
|---|---|---|
/specify |
创建功能规范 | 将需求转化为结构化文档 |
/plan |
生成实施计划 | 设计技术方案 |
/tasks |
生成任务清单 | 分解为可执行任务 |
/implement |
执行实施 | 按任务清单开发 |
/analyze |
分析一致性 | 检查文档冲突 |
使用示例
# 1. 创建新功能规范
/specify 添加 MACD 技术指标策略
# 2. 生成实施计划
/plan
# 3. 生成任务清单
/tasks
# 4. 开始实施
/implement
产出文件
.specify/specs/001-macd-strategy/
├── spec.md # 功能规范
├── plan.md # 实施计划
├── tasks.md # 任务清单
└── data-model.md # 数据模型
🐛 调试技巧
后端调试
# 添加调试日志
import logging
logger = logging.getLogger(__name__)
logger.debug("Debug info")
logger.info("Info message")
logger.error(f"Error: {e}")
# 查看日志
tail -f backend.log
Redis 调试
# 查看数据
redis-cli
> KEYS *session*
> HGETALL session:123
# 监控命令
> MONITOR
前端调试
// 浏览器控制台
console.log('Debug info:', data);
// React DevTools
// 安装浏览器扩展进行组件调试
⚠️ 常见问题
1. 测试失败
问题: ImportError: No module named 'backend'
解决:
cd backend && source venv/bin/activate
export PYTHONPATH=$PWD:$PYTHONPATH
python -m pytest tests/
2. Redis 连接错误
问题: redis.exceptions.ConnectionError
解决:
# 检查 Redis 状态
redis-cli ping
# 启动 Redis
redis-server
3. 端口占用
问题: Address already in use
解决:
# 查找占用端口的进程
lsof -i :8000
lsof -i :3000
# 终止进程
kill -9 <PID>
4. 虚拟环境问题
问题: python: command not found
解决:
# 确保激活虚拟环境
cd backend && source venv/bin/activate
# 重建虚拟环境
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
📚 最佳实践
命名规范
前后端字段命名统一原则:
- API 层统一使用 snake_case
// ✅ 正确: api.ts 中的接口定义 export interface SessionInfo { session_name: string; // snake_case trading_mode: string; asset_mode: string; } - 前端内部可使用 camelCase,但必须在 API 边界转换
// frontend/src/hooks/useCustomTemplates.ts // 转换函数:前端 → 后端 function convertToBackend(data: FrontendType): BackendType { return { channel_name: data.channelName, // camelCase → snake_case channel_type: data.channelType, capital_allocation: data.capitalAllocation, }; } // 转换函数:后端 → 前端 function convertToFrontend(data: BackendType): FrontendType { return { channelName: data.channel_name, // snake_case → camelCase channelType: data.channel_type, capitalAllocation: data.capital_allocation, }; } - 推荐方案:前端也使用 snake_case(与项目现有代码保持一致)
- 优点:无需转换,减少错误
- 缺点:违反 JavaScript 惯例
- 项目现状:多数 API 接口已使用 snake_case
- 转换层要求
- ✅ 所有转换必须在
api.ts或自定义 Hook 中完成 - ✅ 业务组件不应直接处理字段名转换
- ✅ 转换函数必须同时处理请求和响应
- ✅ 所有转换必须在
代码组织
- 单一职责: 每个模块/函数只做一件事
- 依赖注入: 通过参数传递依赖,便于测试
- 抽象接口: 业务逻辑不依赖具体实现
错误处理
# ✅ 明确的错误处理
try:
result = risky_operation()
except SpecificError as e:
logger.error(f"Operation failed: {e}")
return default_value
# ❌ 忽略错误
try:
result = risky_operation()
except:
pass
性能优化
- 使用缓存: Redis 缓存热点数据
- 批量操作: 减少数据库往返
- 异步处理: 非关键路径使用异步
安全实践
- 永不硬编码密钥: 使用环境变量
- 输入验证: 验证所有用户输入
- 最小权限: 仅授予必要的权限