# 编程规范文档
本文档定义了IBKR-MCP项目的编程规范,包括文件命名、代码风格、注释规范等,确保代码的一致性和可维护性。
## 目录
- [1. 文件命名规范](#1-文件命名规范)
- [2. 代码格式规范](#2-代码格式规范)
- [3. 变量命名规范](#3-变量命名规范)
- [4. 函数命名规范](#4-函数命名规范)
- [5. 类命名规范](#5-类命名规范)
- [6. 注释编写规范](#6-注释编写规范)
- [7. 导入规范](#7-导入规范)
- [8. 代码结构规范](#8-代码结构规范)
---
## 1. 文件命名规范
### 1.1 Python文件
- **模块文件名**:使用小写字母,单词间用下划线分隔
- ✅ 正确:`option_data_service.py`, `market_analyzer.py`
- ❌ 错误:`OptionDataService.py`, `marketAnalyzer.py`
- **测试文件**:以`test_`开头,后跟被测试的模块名
- ✅ 正确:`test_option_data_service.py`, `test_market_analyzer.py`
- ❌ 错误:`option_data_service_test.py`
- **配置文件**:使用描述性的名称
- ✅ 正确:`config.yaml`, `settings.json`, `alembic.ini`
### 1.2 文档文件
- **Markdown文档**:使用小写字母和连字符
- ✅ 正确:`user-guide.md`, `api-reference.md`, `development-plan.md`
- ❌ 错误:`UserGuide.md`, `API_Reference.md`
### 1.3 目录命名
- **包目录**:使用小写字母,单词间用下划线分隔
- ✅ 正确:`src/ibkr_mcp/services/`
- ❌ 错误:`src/ibkr_mcp/Services/`
---
## 2. 代码格式规范
### 2.1 缩进
- 使用**4个空格**进行缩进
- 不要使用制表符(Tab)
- 推荐配置编辑器自动将Tab转换为4个空格
### 2.2 行长度
- 每行代码最长不超过**88个字符**
- 使用圆括号进行隐式换行
- 长的导入语句可以分行书写
```python
# 正确示例
from ibkr_mcp.services.option_data import (
OptionDataService,
OptionChainAnalyzer,
GreeksCalculator
)
# 正确示例
long_variable_name = (
some_long_function_call()
+ another_function_call()
)
```
### 2.3 空行
- 函数和类之间用**两个空行**分隔
- 方法之间用一个空行分隔
- 在逻辑相关的代码块之间可以添加空行(一个)
```python
class OptionDataService:
"""期权数据服务类"""
def fetch_option_chain(self):
"""获取期权链数据"""
pass
def analyze_greeks(self):
"""分析希腊字母"""
pass
class RiskAnalyzer:
"""风险分析器类"""
def calculate_var(self):
"""计算VaR"""
pass
```
---
## 3. 变量命名规范
### 3.1 命名约定
- 使用**小写字母和下划线**(snake_case)
- 变量名应该具有描述性,能清楚表达其用途
### 3.2 局部变量
```python
# 正确示例
option_chain_data = fetch_option_chain()
current_market_price = 150.25
risk_threshold = 0.05
max_position_size = 1000
# 循环变量
for index in range(len(option_list)):
pass
for option_item in option_chain:
pass
```
### 3.3 全局变量
- 尽量避免使用全局变量
- 如果必须使用,使用全大写和下划线
```python
# 正确示例
MAX_RETRY_COUNT = 3
DEFAULT_TIMEOUT = 30
API_BASE_URL = "https://api.ibkr.com"
# 错误示例
retry_count = 3
```
### 3.4 常量命名
- 使用全大写字母,单词间用下划线分隔
- 在模块顶部定义
```python
# 正确示例
SUPPORTED_EXPIRY_DATES = ["2024-01", "2024-02", "2024-03"]
MIN_LIQUIDITY_RATIO = 0.1
COMISSION_RATE = 0.001
```
---
## 4. 函数命名规范
### 4.1 命名规则
- 使用**小写字母和下划线**(snake_case)
- 函数名应该是动词或动词短语,能清楚表达函数的功能
### 4.2 常用前缀
- `get_`:获取数据
- `fetch_`:从外部源获取数据
- `calculate_`:计算
- `validate_`:验证
- `process_`:处理
- `convert_`:转换
### 4.3 示例
```python
# 正确示例
def get_account_balance():
"""获取账户余额"""
pass
def fetch_option_chain_data(symbol):
"""获取期权链数据"""
pass
def calculate_implied_volatility(option_price, underlying_price):
"""计算隐含波动率"""
pass
def validate_position_size(size):
"""验证仓位大小"""
pass
# 错误示例
def AccountBalance():
pass
def optionData():
pass
```
---
## 5. 类命名规范
### 5.1 命名规则
- 使用**大驼峰命名法**(PascalCase)
- 类名应该是名词或名词短语
### 5.2 常见类后缀
- `Service`:服务类
- `Manager`:管理器类
- `Handler`:处理器类
- `Analyzer`:分析器类
- `Calculator`:计算器类
### 5.3 示例
```python
# 正确示例
class OptionDataService:
"""期权数据服务"""
pass
class RiskAnalyzer:
"""风险分析器"""
pass
class GreeksCalculator:
"""希腊字母计算器"""
pass
class PortfolioManager:
"""投资组合管理器"""
pass
# 错误示例
class option_data_service:
pass
class risk_analyzer:
pass
```
---
## 6. 注释编写规范
### 6.1 文档字符串(Docstring)
所有公共模块、类、函数都必须有文档字符串。
#### 6.1.1 函数文档字符串
```python
def calculate_implied_volatility(
option_price: float,
underlying_price: float,
strike_price: float,
time_to_expiry: float,
risk_free_rate: float
) -> float:
"""
使用Black-Scholes模型计算期权的隐含波动率。
该函数通过Newton-Raphson迭代法求解隐含波动率,
是期权定价模型中的核心计算函数。
Args:
option_price: 期权当前市场价格
underlying_price: 标的资产当前价格
strike_price: 期权行权价
time_to_expiry: 期权到期时间(年)
risk_free_rate: 无风险利率
Returns:
float: 隐含波动率(以小数形式,如0.25表示25%)
Raises:
ValueError: 当期权价格或参数无效时抛出
Example:
>>> iv = calculate_implied_volatility(
... option_price=5.0,
... underlying_price=100.0,
... strike_price=105.0,
... time_to_expiry=0.5,
... risk_free_rate=0.03
... )
>>> print(f"隐含波动率: {iv:.2%}")
"""
if option_price <= 0:
raise ValueError("期权价格必须大于0")
# 计算过程...
return implied_volatility
```
#### 6.1.2 类文档字符串
```python
class GreeksCalculator:
"""
期权希腊字母计算器。
该类提供计算期权各种希腊字母(Delta、Gamma、Theta、Vega、Rho)
的功能,基于Black-Scholes期权定价模型。
Attributes:
risk_free_rate: 无风险利率
volatility: 波动率
Example:
>>> calculator = GreeksCalculator(risk_free_rate=0.03)
>>> delta = calculator.delta(option_type="call", S=100, K=105, T=0.5)
"""
def __init__(self, risk_free_rate: float = 0.03):
"""
初始化希腊字母计算器。
Args:
risk_free_rate: 无风险利率(年化)
"""
self.risk_free_rate = risk_free_rate
```
### 6.2 行内注释
- 谨慎使用行内注释
- 只在代码复杂难懂时使用
- 与代码保持至少2个空格的距离
```python
# 正确示例
# 使用二分查找法提高查找效率
left, right = 0, len(sorted_list) - 1
# 计算期权内在价值(对于看涨期权)
intrinsic_value = max(0, underlying_price - strike_price)
# 错误示例
# 赋值
option_price = 5.0
# 调用函数
result = calculate()
```
### 6.3 块注释
用于解释复杂的代码块或算法。
```python
# 牛顿迭代法计算隐含波动率
# 初始猜测使用ATM期权的波动率作为起点
# 迭代直到收敛或达到最大迭代次数
initial_guess = 0.2
tolerance = 1e-6
max_iterations = 100
for i in range(max_iterations):
# 计算当前波动率对应的期权价格
price = black_scholes_price(S, K, T, initial_guess, r, option_type)
# 计算价格差异
price_diff = price - market_price
# 检查收敛性
if abs(price_diff) < tolerance:
break
# 使用Vega计算波动率的梯度
vega = calculate_vega(S, K, T, initial_guess, r)
if abs(vega) < 1e-10:
break
# 更新波动率估计
initial_guess = initial_guess - price_diff / vega
```
---
## 7. 导入规范
### 7.1 导入顺序
1. 标准库导入
2. 第三方库导入
3. 本地应用导入
各部分之间用**一个空行**分隔。
```python
# 标准库
import logging
import asyncio
from datetime import datetime
from typing import Dict, List, Optional
# 第三方库
import pandas as pd
import numpy as np
from ib_insync import IBClient
# 本地应用
from ibkr_mcp.models import OptionContract
from ibkr_mcp.services.option_data import OptionDataService
from ibkr_mcp.common.greeks import GreeksCalculator
```
### 7.2 导入方式
- **推荐使用**:模块级导入(`from module import class`)
- **避免使用**:星号导入(`from module import *`)
```python
# 正确示例
from ibkr_mcp.services import OptionDataService
from ibkr_mcp.common import GreeksCalculator
# 错误示例
from ibkr_mcp.services import *
```
### 7.3 导入排序和分组
- 按字母顺序排列导入
- 使用工具(如`isort`)自动排序
---
## 8. 代码结构规范
### 8.1 模块结构
```python
"""
模块描述
这里应该有一个简洁的模块描述,说明模块的用途。
"""
# 标准库导入
import logging
# 第三方库导入
import pandas as pd
# 本地应用导入
from ibkr_mcp.models import OptionContract
# 常量定义
SUPPORTED_EXPIRY_DATES = ["2024-01", "2024-02"]
# 工具函数(可选)
def validate_option_symbol(symbol: str) -> bool:
"""验证期权代码格式"""
pass
# 类定义
class OptionDataService:
"""期权数据服务类"""
def __init__(self):
"""初始化"""
pass
def fetch_data(self):
"""获取数据"""
pass
```
### 8.2 类结构
```python
class OptionAnalyzer:
"""期权分析器
该类负责分析期权数据,计算各种指标和风险参数。
Attributes:
market_data: 市场数据源
risk_free_rate: 无风险利率
"""
def __init__(self, market_data, risk_free_rate=0.03):
"""初始化分析器
Args:
market_data: 市场数据源
risk_free_rate: 无风险利率
"""
self.market_data = market_data
self.risk_free_rate = risk_free_rate
# 公共方法
def analyze_option_chain(self, symbol: str) -> Dict:
"""分析期权链
Args:
symbol: 标的股票代码
Returns:
分析结果字典
Raises:
ValueError: 当symbol无效时
"""
pass
# 私有方法
def _calculate_metrics(self, option_data: Dict) -> Dict:
"""计算内部指标(私有方法)"""
pass
```
### 8.3 函数结构
```python
def process_option_data(
raw_data: Dict,
validate: bool = True,
calculate_greeks: bool = True
) -> Optional[Dict]:
"""
处理原始期权数据。
该函数对原始期权数据进行清洗、验证和增强,
可选择计算希腊字母指标。
Args:
raw_data: 原始期权数据字典
validate: 是否进行数据验证
calculate_greeks: 是否计算希腊字母
Returns:
处理后的数据字典,如果处理失败返回None
Example:
>>> data = {
... "symbol": "AAPL",
... "strike": 150.0,
... "expiry": "2024-06-21"
... }
>>> processed = process_option_data(data)
>>> if processed:
... print(f"Delta: {processed['delta']}")
"""
if not raw_data:
return None
if validate:
if not _validate_input(raw_data):
logging.error("数据验证失败")
return None
processed = _clean_data(raw_data)
if calculate_greeks:
processed = _add_greeks(processed)
return processed
```
---
## 9. 类型注解
### 9.1 函数类型注解
```python
from typing import Dict, List, Optional, Union
from ibkr_mcp.models import OptionContract
def get_option_chain(
symbol: str,
expiry_date: str,
option_type: str = "call"
) -> List[OptionContract]:
"""获取期权链"""
pass
def calculate_portfolio_var(
positions: List[Dict],
confidence_level: float = 0.95
) -> Optional[float]:
"""计算投资组合VaR"""
pass
def process_data(
data: Union[Dict, List],
filters: Optional[Dict] = None
) -> Dict:
"""处理数据"""
pass
```
### 9.2 变量类型注解
```python
# 简单类型
option_price: float = 5.0
is_expired: bool = False
position_size: int = 100
# 复杂类型
option_chain: List[Dict] = []
option_map: Dict[str, OptionContract] = {}
greeks_data: Dict[str, float] = {
"delta": 0.5,
"gamma": 0.1,
"theta": -0.05
}
# 可选类型
def get_option(
symbol: str,
expiry: Optional[str] = None
) -> Optional[OptionContract]:
"""获取期权合约"""
pass
```
---
## 10. 错误处理
### 10.1 异常处理
```python
def fetch_option_data(symbol: str) -> Dict:
"""
获取期权数据
Args:
symbol: 标的股票代码
Returns:
期权数据字典
Raises:
ValueError: 当symbol格式无效时
ConnectionError: 当无法连接数据源时
TimeoutError: 当请求超时时
"""
if not symbol or not isinstance(symbol, str):
raise ValueError(f"无效的股票代码: {symbol}")
try:
data = ibkr_client.get_option_data(symbol)
if not data:
raise ValueError(f"未找到{symbol}的期权数据")
return data
except ConnectionError as e:
logging.error(f"连接错误: {e}")
raise ConnectionError(f"无法获取{symbol}的期权数据") from e
except TimeoutError as e:
logging.error(f"请求超时: {e}")
raise
except Exception as e:
logging.error(f"未知错误: {e}")
raise
```
### 10.2 日志记录
```python
import logging
logger = logging.getLogger(__name__)
def analyze_portfolio(positions: List[Dict]) -> Dict:
"""分析投资组合"""
logger.info(f"开始分析投资组合,共{len(positions)}个仓位")
try:
total_value = sum(pos['value'] for pos in positions)
logger.debug(f"投资组合总价值: {total_value}")
risk_metrics = calculate_risk_metrics(positions)
logger.info("风险指标计算完成")
return {
"total_value": total_value,
"risk_metrics": risk_metrics
}
except Exception as e:
logger.error(f"分析投资组合时发生错误: {e}", exc_info=True)
raise
```
---
## 11. 测试代码规范
### 11.1 测试文件命名
```python
# test_option_data_service.py
import pytest
from ibkr_mcp.services.option_data import OptionDataService
class TestOptionDataService:
"""期权数据服务测试类"""
def test_fetch_option_chain_success(self):
"""测试成功获取期权链"""
# Arrange
service = OptionDataService()
symbol = "AAPL"
# Act
result = service.fetch_option_chain(symbol)
# Assert
assert result is not None
assert "call_options" in result
assert "put_options" in result
def test_fetch_option_chain_invalid_symbol(self):
"""测试无效股票代码"""
# Arrange
service = OptionDataService()
invalid_symbol = "INVALID"
# Act & Assert
with pytest.raises(ValueError):
service.fetch_option_chain(invalid_symbol)
@pytest.mark.parametrize("symbol,expiry", [
("AAPL", "2024-01"),
("MSFT", "2024-02"),
("TSLA", "2024-03"),
])
def test_multiple_expiries(self, symbol, expiry):
"""测试多个到期日期"""
service = OptionDataService()
result = service.fetch_option_chain(symbol, expiry=expiry)
assert result is not None
```
### 11.2 测试注释规范
```python
def test_calculate_implied_volatility():
"""
测试隐含波动率计算。
测试场景:
1. ATM期权(波动率应该接近输入波动率)
2. OTM期权(波动率应该合理)
3. ITM期权(波动率应该合理)
4. 无效参数(应该抛出异常)
"""
# Arrange
calculator = GreeksCalculator()
# Act
# ATM期权:内在价值为0,期权价格等于时间价值
atm_option = create_option(
option_type="call",
S=100, K=100, T=0.5,
market_price=5.0, # 假设时间价值为5.0
implied_vol=0.2
)
# Assert
calculated_iv = calculator.calculate_implied_volatility(atm_option)
assert abs(calculated_iv - 0.2) < 0.01, \
f"ATM期权波动率计算错误: 期望0.2,实际{calculated_iv}"
```
---
## 12. 代码审查清单
### 12.1 命名检查
- [ ] 变量名是否清晰且具有描述性
- [ ] 函数名是否使用了动词且表达了功能
- [ ] 类名是否使用了名词且遵循大驼峰命名法
- [ ] 常量是否使用了全大写和下划线
### 12.2 代码风格检查
- [ ] 是否遵循PEP 8规范
- [ ] 缩进是否使用4个空格
- [ ] 行长度是否不超过88个字符
- [ ] 空行使用是否合理
### 12.3 注释检查
- [ ] 所有公共API是否有文档字符串
- [ ] 文档字符串是否符合规范
- [ ] 复杂的算法是否有块注释解释
- [ ] 行内注释是否必要且不重复代码含义
### 12.4 代码质量检查
- [ ] 函数长度是否合理(建议不超过50行)
- [ ] 类是否职责单一
- [ ] 是否有重复代码可以提取
- [ ] 错误处理是否完善
- [ ] 类型注解是否完整
---
## 13. 工具推荐
### 13.1 代码格式化
- **black**:自动格式化Python代码
- **isort**:自动排序和组织导入语句
### 13.2 代码检查
- **flake8**:检查代码风格和错误
- **pylint**:更全面的代码分析
- **mypy**:类型检查
### 13.3 预提交钩子
在 `.pre-commit-config.yaml` 中配置:
```yaml
repos:
- repo: https://github.com/psf/black
rev: 23.3.0
hooks:
- id: black
language_version: python3
- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: isort
- repo: https://github.com/pycqa/flake8
rev: 6.0.0
hooks:
- id: flake8
args: [--max-line-length=88]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.3.0
hooks:
- id: mypy
```
---
## 14. 参考资料
- [PEP 8 - Python代码风格指南](https://peps.python.org/pep-0008/)
- [PEP 257 - 文档字符串约定](https://peps.python.org/pep-0257/)
- [Google Python风格指南](https://google.github.io/styleguide/pyguide.html)
- [NumPy文档字符串风格](https://numpydoc.readthedocs.io/)
---
## 版本历史
| 版本 | 日期 | 修改内容 |
|------|------|----------|
| 1.0 | 2024-12-18 | 初始版本,包含文件命名、变量命名和注释规范 |