目录
- 使用Python进行量化交易入门
-
- [1. 量化交易概述](#1. 量化交易概述)
-
- [1.1 什么是量化交易](#1.1 什么是量化交易)
- [1.2 Python在量化交易中的优势](#1.2 Python在量化交易中的优势)
- [2. 环境搭建与基础配置](#2. 环境搭建与基础配置)
-
- [2.1 开发环境设置](#2.1 开发环境设置)
- [2.2 项目架构设计](#2.2 项目架构设计)
- [3. 数据获取与处理](#3. 数据获取与处理)
-
- [3.1 多源数据获取](#3.1 多源数据获取)
- [3.2 数据质量检查](#3.2 数据质量检查)
- [4. 策略开发与回测](#4. 策略开发与回测)
-
- [4.1 基础策略框架](#4.1 基础策略框架)
- [4.2 高级策略框架](#4.2 高级策略框架)
- [5. 完整的量化交易系统](#5. 完整的量化交易系统)
-
- [5.1 系统架构与实现](#5.1 系统架构与实现)
- [5.2 绩效分析与可视化](#5.2 绩效分析与可视化)
- [6. 完整代码实现](#6. 完整代码实现)
-
- [6.1 项目配置文件](#6.1 项目配置文件)
- [6.2 主程序入口](#6.2 主程序入口)
- [6.3 使用示例和文档](#6.3 使用示例和文档)
- [7. 总结与展望](#7. 总结与展望)
-
- [7.1 关键技术总结](#7.1 关键技术总结)
- [7.2 数学理论基础](#7.2 数学理论基础)
- [7.3 未来发展路径](#7.3 未来发展路径)
- [7.4 实践建议](#7.4 实践建议)
- [7.5 风险管理强调](#7.5 风险管理强调)
『宝藏代码胶囊开张啦!』------ 我的 CodeCapsule 来咯!✨
写代码不再头疼!我的新站点 CodeCapsule 主打一个 "白菜价"+"量身定制 "!无论是卡脖子的毕设/课设/文献复现 ,需要灵光一现的算法改进 ,还是想给项目加个"外挂",这里都有便宜又好用的代码方案等你发现!低成本,高适配,助你轻松通关!速来围观 👉 CodeCapsule官网
使用Python进行量化交易入门
1. 量化交易概述
1.1 什么是量化交易
量化交易(Quantitative Trading)是利用数学模型、统计分析和计算机算法来进行金融投资决策的一种方法。它将投资理念转化为严格的数学模型,通过历史数据验证和优化,最终实现系统化的交易执行。
量化交易的核心思想可以用以下公式表示:
预期收益模型 :
E [ R ] = ∑ i = 1 n w i ⋅ E [ r i ] − λ ⋅ Risk \mathbb{E}[R] = \sum_{i=1}^{n} w_i \cdot \mathbb{E}[r_i] - \lambda \cdot \text{Risk} E[R]=i=1∑nwi⋅E[ri]−λ⋅Risk
其中:
- E [ R ] \mathbb{E}[R] E[R] 是投资组合的预期收益
- w i w_i wi 是第 i i i 个资产的权重
- E [ r i ] \mathbb{E}[r_i] E[ri] 是第 i i i 个资产的预期收益
- λ \lambda λ 是风险厌恶系数
- Risk \text{Risk} Risk 是投资组合风险度量
1.2 Python在量化交易中的优势
Python凭借其丰富的生态系统和简洁的语法,已成为量化交易的首选语言:
- 丰富的库支持:Pandas、NumPy、Scikit-learn等
- 强大的数据处理能力:高效处理时间序列数据
- 机器学习集成:完善的AI和机器学习库
- 社区活跃:大量的开源项目和文档
- 快速原型开发:简洁语法加速策略开发
2. 环境搭建与基础配置
2.1 开发环境设置
python
# setup_environment.py
"""
量化交易环境设置脚本
"""
import subprocess
import sys
import platform
from pathlib import Path
def run_command(cmd, check=True):
"""运行shell命令"""
print(f"执行命令: {cmd}")
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
if check and result.returncode != 0:
print(f"错误: {result.stderr}")
return False
return True
def setup_quant_environment():
"""设置量化交易环境"""
# 创建项目目录结构
directories = [
"data/raw",
"data/processed",
"data/features",
"strategies",
"backtest",
"research",
"notebooks",
"config",
"logs"
]
for directory in directories:
Path(directory).mkdir(parents=True, exist_ok=True)
print(f"创建目录: {directory}")
# 安装核心依赖包
packages = [
"pandas==2.0.3",
"numpy==1.24.3",
"matplotlib==3.7.2",
"seaborn==0.12.2",
"scikit-learn==1.3.0",
"statsmodels==0.14.0",
"yfinance==0.2.18",
"ccxt==4.1.52",
"zipline==3.0.1",
"backtrader==1.9.78.123",
"quantstats==0.0.62",
"ta-lib==0.4.28",
"plotly==5.15.0",
"python-dotenv==1.0.0",
"jupyter==1.0.0",
"ipython==8.14.0"
]
print("安装Python依赖包...")
for package in packages:
if not run_command(f"pip install {package}"):
print(f"安装 {package} 失败")
# 创建配置文件
config_content = """
# 量化交易配置
[data]
api_key = your_data_api_key
data_path = ./data
cache_enabled = True
[backtest]
initial_cash = 100000
commission = 0.001
slippage = 0.001
[risk]
max_position_size = 0.1
stop_loss = 0.05
take_profit = 0.15
[logging]
level = INFO
file = ./logs/quant_trading.log
"""
with open("config/config.ini", "w") as f:
f.write(config_content)
# 创建环境变量模板
env_template = """
# 数据API密钥
ALPHA_VANTAGE_API_KEY=your_alpha_vantage_key
TIINGO_API_KEY=your_tiingo_key
QUANDL_API_KEY=your_quandl_key
# 交易账户(谨慎处理!)
BINANCE_API_KEY=your_binance_key
BINANCE_SECRET_KEY=your_binance_secret
# 数据库配置
DATABASE_URL=sqlite:///./data/trading.db
"""
with open(".env.example", "w") as f:
f.write(env_template)
print("量化交易环境设置完成!")
print("请配置 .env 文件中的API密钥")
def verify_installation():
"""验证安装结果"""
try:
import pandas as pd
import numpy as np
import yfinance as yf
import backtrader as bt
print("✅ 核心库导入成功")
print(f"Pandas版本: {pd.__version__}")
print(f"NumPy版本: {np.__version__}")
print(f"Backtrader版本: {bt.__version__}")
return True
except ImportError as e:
print(f"❌ 导入失败: {e}")
return False
if __name__ == "__main__":
setup_quant_environment()
verify_installation()
2.2 项目架构设计
核心组件 数据获取层 数据处理层 特征工程层 策略研究层 回测引擎 绩效分析 数据源 实盘交易 风险管理系统 资产配置模型 监控系统
3. 数据获取与处理
3.1 多源数据获取
python
# data/data_manager.py
"""
数据管理模块
"""
import pandas as pd
import numpy as np
import yfinance as yf
import ccxt
import requests
import sqlite3
import pickle
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Tuple
import time
import os
from dotenv import load_dotenv
# 加载环境变量
load_dotenv()
class DataManager:
"""数据管理器"""
def __init__(self, data_path: str = "./data", cache_enabled: bool = True):
"""
初始化数据管理器
Args:
data_path: 数据存储路径
cache_enabled: 是否启用缓存
"""
self.data_path = Path(data_path)
self.cache_enabled = cache_enabled
self.setup_database()
def setup_database(self):
"""设置数据库"""
db_path = self.data_path / "trading.db"
self.conn = sqlite3.connect(db_path)
# 创建价格数据表
self.conn.execute('''
CREATE TABLE IF NOT EXISTS price_data (
symbol TEXT,
datetime TIMESTAMP,
open REAL,
high REAL,
low REAL,
close REAL,
volume REAL,
PRIMARY KEY (symbol, datetime)
)
''')
# 创建基本面数据表
self.conn.execute('''
CREATE TABLE IF NOT EXISTS fundamental_data (
symbol TEXT,
date DATE,
pe_ratio REAL,
pb_ratio REAL,
dividend_yield REAL,
market_cap REAL,
PRIMARY KEY (symbol, date)
)
''')
self.conn.commit()
def get_yahoo_data(self, symbol: str, period: str = "5y",
interval: str = "1d") -> pd.DataFrame:
"""
从Yahoo Finance获取数据
Args:
symbol: 股票代码
period: 时间周期
interval: 时间间隔
Returns:
价格数据DataFrame
"""
cache_file = self.data_path / "raw" / f"{symbol}_{period}_{interval}.pkl"
# 检查缓存
if self.cache_enabled and cache_file.exists():
print(f"从缓存加载数据: {symbol}")
with open(cache_file, 'rb') as f:
return pickle.load(f)
try:
print(f"从Yahoo Finance下载数据: {symbol}")
ticker = yf.Ticker(symbol)
data = ticker.history(period=period, interval=interval)
# 数据清洗
data = self.clean_price_data(data, symbol)
# 保存到缓存
if self.cache_enabled:
with open(cache_file, 'wb') as f:
pickle.dump(data, f)
# 保存到数据库
self.save_to_database(data, symbol)
return data
except Exception as e:
print(f"获取数据失败 {symbol}: {e}")
return pd.DataFrame()
def get_multiple_symbols(self, symbols: List[str], **kwargs) -> Dict[str, pd.DataFrame]:
"""
获取多个标的的数据
Args:
symbols: 标的列表
**kwargs: 其他参数
Returns:
标的数据字典
"""
data_dict = {}
for symbol in symbols:
data = self.get_yahoo_data(symbol, **kwargs)
if not data.empty:
data_dict[symbol] = data
# 避免请求过于频繁
time.sleep(0.5)
return data_dict
def get_crypto_data(self, symbol: str, exchange: str = "binance",
timeframe: str = "1d", limit: int = 1000) -> pd.DataFrame:
"""
获取加密货币数据
Args:
symbol: 交易对(如 BTC/USDT)
exchange: 交易所
timeframe: 时间框架
limit: 数据条数限制
Returns:
加密货币数据
"""
try:
exchange_class = getattr(ccxt, exchange)()
ohlcv = exchange_class.fetch_ohlcv(symbol, timeframe, limit=limit)
data = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
data['datetime'] = pd.to_datetime(data['timestamp'], unit='ms')
data.set_index('datetime', inplace=True)
data.drop('timestamp', axis=1, inplace=True)
return self.clean_price_data(data, symbol)
except Exception as e:
print(f"获取加密货币数据失败 {symbol}: {e}")
return pd.DataFrame()
def clean_price_data(self, data: pd.DataFrame, symbol: str) -> pd.DataFrame:
"""
清洗价格数据
Args:
data: 原始数据
symbol: 标的代码
Returns:
清洗后的数据
"""
if data.empty:
return data
# 复制数据避免修改原始数据
cleaned_data = data.copy()
# 确保索引是DatetimeIndex
if not isinstance(cleaned_data.index, pd.DatetimeIndex):
if 'Date' in cleaned_data.columns:
cleaned_data['Date'] = pd.to_datetime(cleaned_data['Date'])
cleaned_data.set_index('Date', inplace=True)
elif 'Datetime' in cleaned_data.columns:
cleaned_data['Datetime'] = pd.to_datetime(cleaned_data['Datetime'])
cleaned_data.set_index('Datetime', inplace=True)
# 重命名列以保持一致性
column_mapping = {
'Open': 'open', 'High': 'high', 'Low': 'low',
'Close': 'close', 'Volume': 'volume',
'Adj Close': 'adj_close'
}
cleaned_data.rename(columns=column_mapping, inplace=True)
# 确保必要的列存在
required_columns = ['open', 'high', 'low', 'close']
for col in required_columns:
if col not in cleaned_data.columns:
raise ValueError(f"缺少必要列: {col}")
# 处理缺失值
cleaned_data = cleaned_data.ffill().bfill()
# 添加收益率列
cleaned_data['returns'] = cleaned_data['close'].pct_change()
cleaned_data['log_returns'] = np.log(cleaned_data['close'] / cleaned_data['close'].shift(1))
# 添加标识列
cleaned_data['symbol'] = symbol
return cleaned_data
def save_to_database(self, data: pd.DataFrame, symbol: str):
"""
保存数据到数据库
Args:
data: 价格数据
symbol: 标的代码
"""
try:
if data.empty:
return
# 准备数据
records = []
for idx, row in data.iterrows():
record = (
symbol,
idx.to_pydatetime(),
row.get('open', None),
row.get('high', None),
row.get('low', None),
row.get('close', None),
row.get('volume', None)
)
records.append(record)
# 插入数据
self.conn.executemany('''
INSERT OR REPLACE INTO price_data
(symbol, datetime, open, high, low, close, volume)
VALUES (?, ?, ?, ?, ?, ?, ?)
''', records)
self.conn.commit()
print(f"保存 {symbol} 数据到数据库,共 {len(records)} 条记录")
except Exception as e:
print(f"保存数据到数据库失败: {e}")
def calculate_technical_indicators(self, data: pd.DataFrame) -> pd.DataFrame:
"""
计算技术指标
Args:
data: 价格数据
Returns:
包含技术指标的数据
"""
if data.empty:
return data
df = data.copy()
# 移动平均线
df['sma_20'] = df['close'].rolling(window=20).mean()
df['sma_50'] = df['close'].rolling(window=50).mean()
df['sma_200'] = df['close'].rolling(window=200).mean()
# 指数移动平均线
df['ema_12'] = df['close'].ewm(span=12).mean()
df['ema_26'] = df['close'].ewm(span=26).mean()
# MACD
df['macd'] = df['ema_12'] - df['ema_26']
df['macd_signal'] = df['macd'].ewm(span=9).mean()
df['macd_histogram'] = df['macd'] - df['macd_signal']
# RSI
df['rsi'] = self.calculate_rsi(df['close'])
# 布林带
df['bb_middle'] = df['close'].rolling(window=20).mean()
bb_std = df['close'].rolling(window=20).std()
df['bb_upper'] = df['bb_middle'] + 2 * bb_std
df['bb_lower'] = df['bb_middle'] - 2 * bb_std
df['bb_width'] = (df['bb_upper'] - df['bb_lower']) / df['bb_middle']
# 波动率
df['volatility_20'] = df['returns'].rolling(window=20).std()
df['volatility_50'] = df['returns'].rolling(window=50).std()
return df
def calculate_rsi(self, prices: pd.Series, period: int = 14) -> pd.Series:
"""
计算RSI指标
Args:
prices: 价格序列
period: RSI周期
Returns:
RSI序列
"""
delta = prices.diff()
gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
rs = gain / loss
rsi = 100 - (100 / (1 + rs))
return rsi
def get_market_regime(self, data: pd.DataFrame, lookback: int = 200) -> pd.Series:
"""
判断市场状态
Args:
data: 价格数据
lookback: 回看周期
Returns:
市场状态序列
"""
df = data.copy()
# 计算趋势指标
df['sma_ratio'] = df['sma_50'] / df['sma_200']
df['volatility_ratio'] = df['volatility_20'] / df['volatility_50']
# 市场状态判断
conditions = [
(df['sma_ratio'] > 1.02) & (df['volatility_ratio'] < 1.5), # 牛市
(df['sma_ratio'] < 0.98) & (df['volatility_ratio'] > 1.0), # 熊市
(df['volatility_ratio'] > 2.0) # 高波动市场
]
choices = ['bull', 'bear', 'high_vol']
df['market_regime'] = np.select(conditions, choices, default='neutral')
return df['market_regime']
def demonstrate_data_management():
"""演示数据管理功能"""
dm = DataManager()
# 获取股票数据
symbols = ['AAPL', 'MSFT', 'GOOGL', 'TSLA']
stock_data = dm.get_multiple_symbols(symbols, period="2y")
for symbol, data in stock_data.items():
print(f"\n{symbol} 数据概况:")
print(f"时间范围: {data.index.min()} 到 {data.index.max()}")
print(f"数据点数: {len(data)}")
print(f"列: {list(data.columns)}")
# 计算技术指标
if not data.empty:
data_with_indicators = dm.calculate_technical_indicators(data)
print(f"技术指标列: {[col for col in data_with_indicators.columns if col not in data.columns]}")
# 获取加密货币数据
crypto_data = dm.get_crypto_data("BTC/USDT", limit=500)
if not crypto_data.empty:
print(f"\nBTC/USDT 数据概况:")
print(f"时间范围: {crypto_data.index.min()} 到 {crypto_data.index.max()}")
print(f"数据点数: {len(crypto_data)}")
if __name__ == "__main__":
demonstrate_data_management()
3.2 数据质量检查
python
# data/data_quality.py
"""
数据质量检查模块
"""
import pandas as pd
import numpy as np
from typing import Dict, List, Tuple
import matplotlib.pyplot as plt
import seaborn as sns
class DataQualityChecker:
"""数据质量检查器"""
def __init__(self):
"""初始化"""
self.quality_metrics = {}
def comprehensive_quality_check(self, data: pd.DataFrame, symbol: str) -> Dict:
"""
综合数据质量检查
Args:
data: 价格数据
symbol: 标的代码
Returns:
质量检查结果
"""
if data.empty:
return {"error": "空数据框"}
results = {
'symbol': symbol,
'period_start': data.index.min(),
'period_end': data.index.max(),
'total_days': len(data),
'missing_days': self.check_missing_days(data),
'data_completeness': self.check_data_completeness(data),
'outliers': self.detect_outliers(data),
'volatility_analysis': self.analyze_volatility(data),
'stationarity_test': self.test_stationarity(data['close']),
'autocorrelation': self.check_autocorrelation(data['returns'].dropna())
}
self.quality_metrics[symbol] = results
return results
def check_missing_days(self, data: pd.DataFrame) -> Dict:
"""
检查缺失交易日
Args:
data: 价格数据
Returns:
缺失日分析结果
"""
# 生成完整的日期范围
full_range = pd.date_range(start=data.index.min(), end=data.index.max(), freq='D')
trading_days = data.index.normalize().unique()
missing_days = full_range.difference(trading_days)
return {
'total_calendar_days': len(full_range),
'trading_days': len(trading_days),
'missing_days_count': len(missing_days),
'completeness_ratio': len(trading_days) / len(full_range)
}
def check_data_completeness(self, data: pd.DataFrame) -> Dict:
"""
检查数据完整性
Args:
data: 价格数据
Returns:
完整性分析结果
"""
required_columns = ['open', 'high', 'low', 'close', 'volume']
completeness = {}
for col in required_columns:
if col in data.columns:
null_count = data[col].isnull().sum()
completeness[col] = {
'null_count': null_count,
'completeness_ratio': 1 - (null_count / len(data)),
'zero_count': (data[col] == 0).sum() if col != 'volume' else None
}
return completeness
def detect_outliers(self, data: pd.DataFrame, method: str = 'iqr') -> Dict:
"""
检测异常值
Args:
data: 价格数据
method: 检测方法
Returns:
异常值检测结果
"""
outlier_results = {}
price_columns = ['open', 'high', 'low', 'close']
for col in price_columns:
if col not in data.columns:
continue
prices = data[col].dropna()
if method == 'iqr':
Q1 = prices.quantile(0.25)
Q3 = prices.quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = prices[(prices < lower_bound) | (prices > upper_bound)]
elif method == 'zscore':
z_scores = np.abs((prices - prices.mean()) / prices.std())
outliers = prices[z_scores > 3]
outlier_results[col] = {
'outlier_count': len(outliers),
'outlier_ratio': len(outliers) / len(prices),
'outlier_dates': outliers.index.tolist() if len(outliers) > 0 else []
}
return outlier_results
def analyze_volatility(self, data: pd.DataFrame) -> Dict:
"""
分析波动率特征
Args:
data: 价格数据
Returns:
波动率分析结果
"""
if 'returns' not in data.columns:
data['returns'] = data['close'].pct_change()
returns = data['returns'].dropna()
return {
'mean_return': returns.mean(),
'std_return': returns.std(),
'sharpe_ratio': returns.mean() / returns.std() * np.sqrt(252) if returns.std() > 0 else 0,
'skewness': returns.skew(),
'kurtosis': returns.kurtosis(),
'var_95': returns.quantile(0.05), # 95% VaR
'cvar_95': returns[returns <= returns.quantile(0.05)].mean() # 条件VaR
}
def test_stationarity(self, series: pd.Series, max_lags: int = 15) -> Dict:
"""
测试时间序列平稳性(ADF检验)
Args:
series: 时间序列
max_lags: 最大滞后阶数
Returns:
平稳性测试结果
"""
from statsmodels.tsa.stattools import adfuller
try:
result = adfuller(series.dropna(), maxlag=max_lags)
return {
'adf_statistic': result[0],
'p_value': result[1],
'critical_values': result[4],
'is_stationary': result[1] < 0.05
}
except Exception as e:
return {'error': str(e)}
def check_autocorrelation(self, series: pd.Series, max_lags: int = 20) -> Dict:
"""
检查自相关性
Args:
series: 时间序列
max_lags: 最大滞后阶数
Returns:
自相关性分析结果
"""
from statsmodels.tsa.stattools import acf, pacf
try:
acf_values = acf(series, nlags=max_lags, fft=False)
pacf_values = pacf(series, nlags=max_lags)
# 找出显著的自相关滞后
significant_acf = [i for i, val in enumerate(acf_values) if abs(val) > 1.96 / np.sqrt(len(series))]
significant_pacf = [i for i, val in enumerate(pacf_values) if abs(val) > 1.96 / np.sqrt(len(series))]
return {
'acf_values': acf_values.tolist(),
'pacf_values': pacf_values.tolist(),
'significant_acf_lags': significant_acf,
'significant_pacf_lags': significant_pacf
}
except Exception as e:
return {'error': str(e)}
def generate_quality_report(self, data_dict: Dict[str, pd.DataFrame]) -> pd.DataFrame:
"""
生成质量报告
Args:
data_dict: 标的数据字典
Returns:
质量报告DataFrame
"""
report_data = []
for symbol, data in data_dict.items():
quality_report = self.comprehensive_quality_check(data, symbol)
# 提取关键指标
row = {
'symbol': symbol,
'period_start': quality_report['period_start'],
'period_end': quality_report['period_end'],
'total_days': quality_report['total_days'],
'completeness_ratio': quality_report['data_completeness']['close']['completeness_ratio'],
'outlier_ratio': quality_report['outliers']['close']['outlier_ratio'],
'is_stationary': quality_report['stationarity_test']['is_stationary'],
'sharpe_ratio': quality_report['volatility_analysis']['sharpe_ratio'],
'volatility': quality_report['volatility_analysis']['std_return']
}
report_data.append(row)
return pd.DataFrame(report_data)
def demonstrate_quality_check():
"""演示数据质量检查"""
dm = DataManager()
checker = DataQualityChecker()
# 获取示例数据
symbols = ['AAPL', 'MSFT', 'GOOGL']
stock_data = dm.get_multiple_symbols(symbols, period="1y")
# 生成质量报告
quality_report = checker.generate_quality_report(stock_data)
print("数据质量报告:")
print(quality_report.to_string(index=False))
# 可视化质量指标
fig, axes = plt.subplots(2, 2, figsize=(15, 10))
# 完整性比率
axes[0, 0].bar(quality_report['symbol'], quality_report['completeness_ratio'])
axes[0, 0].set_title('数据完整性比率')
axes[0, 0].set_ylabel('完整性比率')
# 异常值比率
axes[0, 1].bar(quality_report['symbol'], quality_report['outlier_ratio'])
axes[0, 1].set_title('异常值比率')
axes[0, 1].set_ylabel('异常值比率')
# 夏普比率
axes[1, 0].bar(quality_report['symbol'], quality_report['sharpe_ratio'])
axes[1, 0].set_title('年化夏普比率')
axes[1, 0].set_ylabel('夏普比率')
# 波动率
axes[1, 1].bar(quality_report['symbol'], quality_report['volatility'])
axes[1, 1].set_title('日收益率波动率')
axes[1, 1].set_ylabel('波动率')
plt.tight_layout()
plt.savefig('data_quality_metrics.png', dpi=300, bbox_inches='tight')
plt.show()
if __name__ == "__main__":
demonstrate_quality_check()
4. 策略开发与回测
4.1 基础策略框架
python
# strategies/base_strategy.py
"""
基础策略框架
"""
import pandas as pd
import numpy as np
from abc import ABC, abstractmethod
from typing import Dict, List, Optional, Tuple
from enum import Enum
import warnings
warnings.filterwarnings('ignore')
class SignalType(Enum):
"""信号类型枚举"""
BUY = 1
SELL = -1
HOLD = 0
class BaseStrategy(ABC):
"""基础策略抽象类"""
def __init__(self, name: str, lookback_period: int = 50):
"""
初始化策略
Args:
name: 策略名称
lookback_period: 回看周期
"""
self.name = name
self.lookback_period = lookback_period
self.signals = {}
self.performance_metrics = {}
@abstractmethod
def generate_signals(self, data: pd.DataFrame) -> pd.DataFrame:
"""
生成交易信号(子类必须实现)
Args:
data: 价格数据
Returns:
包含信号的数据
"""
pass
def calculate_position_size(self, signal_strength: float, portfolio_value: float,
risk_per_trade: float = 0.02) -> float:
"""
计算头寸大小
Args:
signal_strength: 信号强度
portfolio_value: 投资组合价值
risk_per_trade: 每笔交易风险
Returns:
头寸大小
"""
return portfolio_value * risk_per_trade * signal_strength
def backtest_strategy(self, data: pd.DataFrame, initial_capital: float = 100000,
commission: float = 0.001) -> Dict:
"""
策略回测
Args:
data: 价格数据
initial_capital: 初始资金
commission: 交易佣金
Returns:
回测结果
"""
if data.empty:
return {"error": "空数据"}
# 生成信号
data_with_signals = self.generate_signals(data)
# 初始化回测变量
capital = initial_capital
position = 0
trades = []
portfolio_values = []
for i, (idx, row) in enumerate(data_with_signals.iterrows()):
current_price = row['close']
signal = row.get('signal', 0)
signal_strength = row.get('signal_strength', 1.0)
# 计算可用的头寸大小
position_size = self.calculate_position_size(signal_strength, capital)
# 执行交易逻辑
if signal == SignalType.BUY.value and position == 0:
# 买入
shares_to_buy = position_size / current_price
cost = shares_to_buy * current_price * (1 + commission)
if cost <= capital:
position = shares_to_buy
capital -= cost
trades.append({
'date': idx,
'action': 'BUY',
'price': current_price,
'shares': shares_to_buy,
'value': cost
})
elif signal == SignalType.SELL.value and position > 0:
# 卖出
sale_value = position * current_price * (1 - commission)
capital += sale_value
trades.append({
'date': idx,
'action': 'SELL',
'price': current_price,
'shares': position,
'value': sale_value
})
position = 0
# 计算当前投资组合价值
current_value = capital + (position * current_price if position > 0 else 0)
portfolio_values.append({
'date': idx,
'portfolio_value': current_value,
'cash': capital,
'position_value': position * current_price if position > 0 else 0,
'signal': signal
})
# 转换为DataFrame
portfolio_df = pd.DataFrame(portfolio_values)
portfolio_df.set_index('date', inplace=True)
# 计算绩效指标
performance = self.calculate_performance_metrics(portfolio_df, initial_capital)
return {
'portfolio_history': portfolio_df,
'trades': trades,
'performance_metrics': performance
}
def calculate_performance_metrics(self, portfolio_df: pd.DataFrame,
initial_capital: float) -> Dict:
"""
计算绩效指标
Args:
portfolio_df: 投资组合历史数据
initial_capital: 初始资金
Returns:
绩效指标字典
"""
if portfolio_df.empty:
return {}
portfolio_values = portfolio_df['portfolio_value']
returns = portfolio_values.pct_change().dropna()
# 基本指标
total_return = (portfolio_values.iloc[-1] - initial_capital) / initial_capital
annual_return = (1 + total_return) ** (252 / len(portfolio_values)) - 1
# 风险调整收益
volatility = returns.std() * np.sqrt(252)
sharpe_ratio = annual_return / volatility if volatility > 0 else 0
# 最大回撤
cumulative_max = portfolio_values.expanding().max()
drawdown = (portfolio_values - cumulative_max) / cumulative_max
max_drawdown = drawdown.min()
# Calmar比率
calmar_ratio = annual_return / abs(max_drawdown) if max_drawdown < 0 else 0
# 胜率(需要交易记录)
winning_trades = len([t for t in self.signals if t.get('profit', 0) > 0])
total_trades = len(self.signals)
win_rate = winning_trades / total_trades if total_trades > 0 else 0
return {
'total_return': total_return,
'annual_return': annual_return,
'volatility': volatility,
'sharpe_ratio': sharpe_ratio,
'max_drawdown': max_drawdown,
'calmar_ratio': calmar_ratio,
'win_rate': win_rate,
'total_trades': total_trades
}
class MovingAverageCrossover(BaseStrategy):
"""移动平均线交叉策略"""
def __init__(self, short_window: int = 20, long_window: int = 50):
"""
初始化MA交叉策略
Args:
short_window: 短期窗口
long_window: 长期窗口
"""
super().__init__(f"MA_Crossover_{short_window}_{long_window}")
self.short_window = short_window
self.long_window = long_window
def generate_signals(self, data: pd.DataFrame) -> pd.DataFrame:
"""
生成MA交叉信号
Args:
data: 价格数据
Returns:
包含信号的数据
"""
df = data.copy()
# 计算移动平均线
df['short_ma'] = df['close'].rolling(window=self.short_window).mean()
df['long_ma'] = df['close'].rolling(window=self.long_window).mean()
# 生成信号
df['signal'] = 0
df['signal_strength'] = 0.0
# 金叉(短期上穿长期)- 买入信号
golden_cross = (df['short_ma'] > df['long_ma']) & (df['short_ma'].shift(1) <= df['long_ma'].shift(1))
df.loc[golden_cross, 'signal'] = SignalType.BUY.value
# 死叉(短期下穿长期)- 卖出信号
death_cross = (df['short_ma'] < df['long_ma']) & (df['short_ma'].shift(1) >= df['long_ma'].shift(1))
df.loc[death_cross, 'signal'] = SignalType.SELL.value
# 计算信号强度(基于均线距离)
ma_spread = (df['short_ma'] - df['long_ma']) / df['long_ma']
df['signal_strength'] = np.abs(ma_spread)
return df
class RSIStrategy(BaseStrategy):
"""RSI策略"""
def __init__(self, rsi_period: int = 14, oversold: int = 30, overbought: int = 70):
"""
初始化RSI策略
Args:
rsi_period: RSI周期
oversold: 超卖阈值
overbought: 超买阈值
"""
super().__init__(f"RSI_{rsi_period}_{oversold}_{overbought}")
self.rsi_period = rsi_period
self.oversold = oversold
self.overbought = overbought
def generate_signals(self, data: pd.DataFrame) -> pd.DataFrame:
"""
生成RSI信号
Args:
data: 价格数据
Returns:
包含信号的数据
"""
df = data.copy()
# 计算RSI
df['rsi'] = self.calculate_rsi(df['close'], self.rsi_period)
# 生成信号
df['signal'] = 0
df['signal_strength'] = 0.0
# 超卖区域 - 买入信号
oversold_signal = (df['rsi'] < self.oversold) & (df['rsi'].shift(1) >= self.oversold)
df.loc[oversold_signal, 'signal'] = SignalType.BUY.value
# 超买区域 - 卖出信号
overbought_signal = (df['rsi'] > self.overbought) & (df['rsi'].shift(1) <= self.overbought)
df.loc[overbought_signal, 'signal'] = SignalType.SELL.value
# 计算信号强度(基于RSI偏离程度)
df['signal_strength'] = np.where(
df['signal'] == SignalType.BUY.value,
(self.oversold - df['rsi']) / self.oversold,
np.where(
df['signal'] == SignalType.SELL.value,
(df['rsi'] - self.overbought) / (100 - self.overbought),
0.0
)
)
return df
def calculate_rsi(self, prices: pd.Series, period: int = 14) -> pd.Series:
"""计算RSI指标"""
delta = prices.diff()
gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
rs = gain / loss
rsi = 100 - (100 / (1 + rs))
return rsi
class MeanReversionStrategy(BaseStrategy):
"""均值回归策略"""
def __init__(self, lookback_period: int = 20, zscore_threshold: float = 2.0):
"""
初始化均值回归策略
Args:
lookback_period: 回看周期
zscore_threshold: Z分数阈值
"""
super().__init__(f"MeanReversion_{lookback_period}_{zscore_threshold}", lookback_period)
self.zscore_threshold = zscore_threshold
def generate_signals(self, data: pd.DataFrame) -> pd.DataFrame:
"""
生成均值回归信号
Args:
data: 价格数据
Returns:
包含信号的数据
"""
df = data.copy()
# 计算滚动Z分数
df['rolling_mean'] = df['close'].rolling(window=self.lookback_period).mean()
df['rolling_std'] = df['close'].rolling(window=self.lookback_period).std()
df['zscore'] = (df['close'] - df['rolling_mean']) / df['rolling_std']
# 生成信号
df['signal'] = 0
df['signal_strength'] = 0.0
# Z分数低于阈值 - 买入信号(价格被低估)
buy_signal = df['zscore'] < -self.zscore_threshold
df.loc[buy_signal, 'signal'] = SignalType.BUY.value
# Z分数高于阈值 - 卖出信号(价格被高估)
sell_signal = df['zscore'] > self.zscore_threshold
df.loc[sell_signal, 'signal'] = SignalType.SELL.value
# 计算信号强度(基于Z分数偏离程度)
df['signal_strength'] = np.abs(df['zscore']) / self.zscore_threshold
return df
def demonstrate_strategies():
"""演示策略功能"""
from data.data_manager import DataManager
# 获取数据
dm = DataManager()
data = dm.get_yahoo_data('AAPL', period='2y')
if data.empty:
print("无法获取数据")
return
# 测试不同策略
strategies = [
MovingAverageCrossover(20, 50),
RSIStrategy(14, 30, 70),
MeanReversionStrategy(20, 2.0)
]
results = {}
for strategy in strategies:
print(f"\n测试策略: {strategy.name}")
# 回测策略
backtest_result = strategy.backtest_strategy(data, initial_capital=100000)
if 'error' in backtest_result:
print(f"回测失败: {backtest_result['error']}")
continue
performance = backtest_result['performance_metrics']
results[strategy.name] = performance
print("绩效指标:")
for metric, value in performance.items():
if isinstance(value, float):
print(f" {metric}: {value:.4f}")
else:
print(f" {metric}: {value}")
# 比较策略表现
comparison_df = pd.DataFrame(results).T
print(f"\n策略比较:")
print(comparison_df.to_string(float_format="%.4f"))
if __name__ == "__main__":
demonstrate_strategies()
4.2 高级策略框架
python
# strategies/advanced_strategies.py
"""
高级量化策略
"""
import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
import warnings
warnings.filterwarnings('ignore')
from .base_strategy import BaseStrategy, SignalType
class MachineLearningStrategy(BaseStrategy):
"""机器学习策略"""
def __init__(self, name: str = "ML_Strategy", lookforward_days: int = 5,
probability_threshold: float = 0.6):
"""
初始化机器学习策略
Args:
name: 策略名称
lookforward_days: 预测未来天数
probability_threshold: 概率阈值
"""
super().__init__(name)
self.lookforward_days = lookforward_days
self.probability_threshold = probability_threshold
self.model = None
self.scaler = StandardScaler()
self.feature_importance = {}
def create_features(self, data: pd.DataFrame) -> pd.DataFrame:
"""
创建特征集
Args:
data: 价格数据
Returns:
特征DataFrame
"""
df = data.copy()
# 价格特征
df['returns_1d'] = df['close'].pct_change()
df['returns_5d'] = df['close'].pct_change(5)
df['returns_20d'] = df['close'].pct_change(20)
# 波动率特征
df['volatility_5d'] = df['returns_1d'].rolling(5).std()
df['volatility_20d'] = df['returns_1d'].rolling(20).std()
# 技术指标特征
df['sma_20'] = df['close'].rolling(20).mean()
df['sma_50'] = df['close'].rolling(50).mean()
df['ema_12'] = df['close'].ewm(span=12).mean()
df['ema_26'] = df['close'].ewm(span=26).mean()
# 相对强弱
df['price_vs_sma_20'] = df['close'] / df['sma_20'] - 1
df['price_vs_sma_50'] = df['close'] / df['sma_50'] - 1
# 动量指标
df['momentum_5d'] = df['close'] / df['close'].shift(5) - 1
df['momentum_20d'] = df['close'] / df['close'].shift(20) - 1
# 波动率比率
df['vol_ratio'] = df['volatility_5d'] / df['volatility_20d']
# 市场 regime 特征
df['market_trend'] = (df['close'] > df['sma_20']).astype(int)
return df
def create_target(self, data: pd.DataFrame) -> pd.Series:
"""
创建目标变量
Args:
data: 价格数据
Returns:
目标变量序列
"""
# 未来N天的收益率
future_returns = data['close'].pct_change(self.lookforward_days).shift(-self.lookforward_days)
# 二分类:未来上涨为1,下跌为0
target = (future_returns > 0).astype(int)
return target
def train_model(self, data: pd.DataFrame):
"""
训练机器学习模型
Args:
data: 训练数据
"""
# 创建特征和目标
feature_df = self.create_features(data)
target = self.create_target(data)
# 合并并清理数据
modeling_df = pd.concat([feature_df, target.rename('target')], axis=1)
modeling_df = modeling_df.dropna()
if modeling_df.empty:
print("训练数据不足")
return
# 准备特征和目标
feature_columns = [col for col in modeling_df.columns if col not in ['target', 'signal', 'signal_strength']]
X = modeling_df[feature_columns]
y = modeling_df['target']
# 数据标准化
X_scaled = self.scaler.fit_transform(X)
# 分割训练测试集
X_train, X_test, y_train, y_test = train_test_split(
X_scaled, y, test_size=0.2, shuffle=False
)
# 训练模型
self.model = RandomForestClassifier(
n_estimators=100,
max_depth=10,
min_samples_split=20,
random_state=42
)
self.model.fit(X_train, y_train)
# 评估模型
train_score = self.model.score(X_train, y_train)
test_score = self.model.score(X_test, y_test)
print(f"模型训练完成:")
print(f" 训练集准确率: {train_score:.4f}")
print(f" 测试集准确率: {test_score:.4f}")
# 特征重要性
self.feature_importance = dict(zip(feature_columns, self.model.feature_importances_))
# 打印最重要的特征
top_features = sorted(self.feature_importance.items(), key=lambda x: x[1], reverse=True)[:10]
print("最重要的10个特征:")
for feature, importance in top_features:
print(f" {feature}: {importance:.4f}")
def generate_signals(self, data: pd.DataFrame) -> pd.DataFrame:
"""
生成机器学习信号
Args:
data: 价格数据
Returns:
包含信号的数据
"""
if self.model is None:
# 如果模型未训练,先训练
self.train_model(data)
df = data.copy()
# 创建特征
feature_df = self.create_features(df)
feature_columns = [col for col in feature_df.columns if col in self.feature_importance]
# 准备预测数据
prediction_data = feature_df[feature_columns].dropna()
if prediction_data.empty:
df['signal'] = 0
df['signal_strength'] = 0.0
return df
# 标准化特征
X_scaled = self.scaler.transform(prediction_data)
# 预测
predictions = self.model.predict(X_scaled)
probabilities = self.model.predict_proba(X_scaled)
# 生成信号
df['signal'] = 0
df['signal_strength'] = 0.0
# 高概率上涨预测 - 买入信号
buy_condition = (predictions == 1) & (probabilities[:, 1] > self.probability_threshold)
buy_dates = prediction_data.index[buy_condition]
df.loc[df.index.isin(buy_dates), 'signal'] = SignalType.BUY.value
# 高概率下跌预测 - 卖出信号
sell_condition = (predictions == 0) & (probabilities[:, 0] > self.probability_threshold)
sell_dates = prediction_data.index[sell_condition]
df.loc[df.index.isin(sell_dates), 'signal'] = SignalType.SELL.value
# 信号强度基于预测概率
for idx in prediction_data.index:
if idx in df.index:
prob = probabilities[prediction_data.index.get_loc(idx)]
if df.loc[idx, 'signal'] == SignalType.BUY.value:
df.loc[idx, 'signal_strength'] = prob[1] # 上涨概率
elif df.loc[idx, 'signal'] == SignalType.SELL.value:
df.loc[idx, 'signal_strength'] = prob[0] # 下跌概率
return df
class PortfolioStrategy(BaseStrategy):
"""投资组合策略"""
def __init__(self, strategy_weights: Dict):
"""
初始化投资组合策略
Args:
strategy_weights: 策略权重字典
"""
super().__init__("Portfolio_Strategy")
self.strategy_weights = strategy_weights
self.strategies = {}
# 初始化子策略
for strategy_name, weight in strategy_weights.items():
if strategy_name.startswith('MA'):
params = strategy_name.split('_')
short_win = int(params[1]) if len(params) > 1 else 20
long_win = int(params[2]) if len(params) > 2 else 50
self.strategies[strategy_name] = MovingAverageCrossover(short_win, long_win)
elif strategy_name.startswith('RSI'):
params = strategy_name.split('_')
period = int(params[1]) if len(params) > 1 else 14
oversold = int(params[2]) if len(params) > 2 else 30
overbought = int(params[3]) if len(params) > 3 else 70
self.strategies[strategy_name] = RSIStrategy(period, oversold, overbought)
elif strategy_name.startswith('MeanRev'):
params = strategy_name.split('_')
lookback = int(params[1]) if len(params) > 1 else 20
threshold = float(params[2]) if len(params) > 2 else 2.0
self.strategies[strategy_name] = MeanReversionStrategy(lookback, threshold)
def generate_signals(self, data: pd.DataFrame) -> pd.DataFrame:
"""
生成组合信号
Args:
data: 价格数据
Returns:
包含组合信号的数据
"""
# 收集各策略信号
strategy_signals = {}
for name, strategy in self.strategies.items():
signal_data = strategy.generate_signals(data)
strategy_signals[name] = {
'signals': signal_data['signal'],
'strengths': signal_data['signal_strength']
}
# 合并信号
df = data.copy()
df['signal'] = 0
df['signal_strength'] = 0.0
for name, signals in strategy_signals.items():
weight = self.strategy_weights[name]
# 加权信号
df['weighted_signal'] = signals['signals'] * weight
df['weighted_strength'] = signals['strengths'] * weight
# 累积信号(基于强度加权)
df['signal'] += df['weighted_signal']
df['signal_strength'] += df['weighted_strength']
# 最终信号决策
df['final_signal'] = 0
# 基于累积信号强度决定最终信号
buy_condition = df['signal'] > 0.3 # 买入阈值
sell_condition = df['signal'] < -0.3 # 卖出阈值
df.loc[buy_condition, 'final_signal'] = SignalType.BUY.value
df.loc[sell_condition, 'final_signal'] = SignalType.SELL.value
# 使用最终信号
df['signal'] = df['final_signal']
return df
def demonstrate_advanced_strategies():
"""演示高级策略"""
from data.data_manager import DataManager
# 获取数据
dm = DataManager()
data = dm.get_yahoo_data('AAPL', period='3y')
if data.empty:
print("无法获取数据")
return
# 测试机器学习策略
print("测试机器学习策略...")
ml_strategy = MachineLearningStrategy(lookforward_days=5, probability_threshold=0.65)
ml_result = ml_strategy.backtest_strategy(data, initial_capital=100000)
if 'performance_metrics' in ml_result:
print("机器学习策略绩效:")
for metric, value in ml_result['performance_metrics'].items():
if isinstance(value, float):
print(f" {metric}: {value:.4f}")
# 测试组合策略
print("\n测试组合策略...")
portfolio_weights = {
'MA_20_50': 0.4,
'RSI_14_30_70': 0.3,
'MeanRev_20_2.0': 0.3
}
portfolio_strategy = PortfolioStrategy(portfolio_weights)
portfolio_result = portfolio_strategy.backtest_strategy(data, initial_capital=100000)
if 'performance_metrics' in portfolio_result:
print("组合策略绩效:")
for metric, value in portfolio_result['performance_metrics'].items():
if isinstance(value, float):
print(f" {metric}: {value:.4f}")
if __name__ == "__main__":
demonstrate_advanced_strategies()
5. 完整的量化交易系统
5.1 系统架构与实现
python
# trading_system.py
"""
完整的量化交易系统
"""
import pandas as pd
import numpy as np
import yfinance as yf
from datetime import datetime, timedelta
import warnings
warnings.filterwarnings('ignore')
from data.data_manager import DataManager
from strategies.base_strategy import BaseStrategy
from strategies.advanced_strategies import MachineLearningStrategy, PortfolioStrategy
class QuantitativeTradingSystem:
"""量化交易系统"""
def __init__(self, config: dict):
"""
初始化交易系统
Args:
config: 系统配置
"""
self.config = config
self.data_manager = DataManager(
data_path=config.get('data_path', './data'),
cache_enabled=config.get('cache_enabled', True)
)
self.strategies = {}
self.portfolio = {}
self.performance_history = pd.DataFrame()
self.setup_strategies()
def setup_strategies(self):
"""设置交易策略"""
strategy_configs = self.config.get('strategies', {})
for name, params in strategy_configs.items():
if params['type'] == 'machine_learning':
self.strategies[name] = MachineLearningStrategy(
name=name,
lookforward_days=params.get('lookforward_days', 5),
probability_threshold=params.get('probability_threshold', 0.6)
)
elif params['type'] == 'portfolio':
self.strategies[name] = PortfolioStrategy(
strategy_weights=params.get('weights', {})
)
else:
print(f"未知策略类型: {params['type']}")
def run_backtest(self, symbols: list, start_date: str, end_date: str,
initial_capital: float = 100000) -> dict:
"""
运行回测
Args:
symbols: 标的列表
start_date: 开始日期
end_date: 结束日期
initial_capital: 初始资金
Returns:
回测结果
"""
print(f"开始回测: {start_date} 到 {end_date}")
print(f"标的: {symbols}")
print(f"初始资金: ${initial_capital:,.2f}")
# 获取数据
all_data = {}
for symbol in symbols:
data = self.data_manager.get_yahoo_data(symbol, start=start_date, end=end_date)
if not data.empty:
all_data[symbol] = data
print(f" {symbol}: {len(data)} 个数据点")
if not all_data:
print("无法获取任何数据")
return {}
# 运行策略回测
backtest_results = {}
for strategy_name, strategy in self.strategies.items():
print(f"\n运行策略: {strategy_name}")
# 对每个标的运行策略
strategy_results = {}
total_portfolio_value = initial_capital
capital_per_symbol = initial_capital / len(symbols)
for symbol, data in all_data.items():
if data.empty:
continue
result = strategy.backtest_strategy(data, capital_per_symbol)
strategy_results[symbol] = result
if 'portfolio_history' in result:
# 累加投资组合价值
total_portfolio_value += result['portfolio_history']['portfolio_value'].iloc[-1] - capital_per_symbol
backtest_results[strategy_name] = {
'symbol_results': strategy_results,
'total_portfolio_value': total_portfolio_value,
'total_return': (total_portfolio_value - initial_capital) / initial_capital
}
# 绩效分析
performance_report = self.analyze_performance(backtest_results, initial_capital)
return {
'backtest_results': backtest_results,
'performance_report': performance_report,
'symbols_tested': symbols,
'period': f"{start_date} to {end_date}"
}
def analyze_performance(self, backtest_results: dict, initial_capital: float) -> pd.DataFrame:
"""
分析绩效
Args:
backtest_results: 回测结果
initial_capital: 初始资金
Returns:
绩效报告
"""
performance_data = []
for strategy_name, results in backtest_results.items():
# 计算综合绩效指标
total_return = results['total_return']
symbol_results = results['symbol_results']
# 计算平均绩效指标
sharpe_ratios = []
max_drawdowns = []
win_rates = []
for symbol, result in symbol_results.items():
if 'performance_metrics' in result:
metrics = result['performance_metrics']
sharpe_ratios.append(metrics.get('sharpe_ratio', 0))
max_drawdowns.append(metrics.get('max_drawdown', 0))
win_rates.append(metrics.get('win_rate', 0))
avg_sharpe = np.mean(sharpe_ratios) if sharpe_ratios else 0
avg_max_drawdown = np.mean(max_drawdowns) if max_drawdowns else 0
avg_win_rate = np.mean(win_rates) if win_rates else 0
performance_data.append({
'strategy': strategy_name,
'total_return': total_return,
'avg_sharpe_ratio': avg_sharpe,
'avg_max_drawdown': avg_max_drawdown,
'avg_win_rate': avg_win_rate,
'symbols_tested': len(symbol_results)
})
return pd.DataFrame(performance_data)
def optimize_strategy_parameters(self, strategy_name: str, symbol: str,
param_grid: dict, metric: str = 'sharpe_ratio') -> dict:
"""
优化策略参数
Args:
strategy_name: 策略名称
symbol: 标的代码
param_grid: 参数网格
metric: 优化指标
Returns:
优化结果
"""
print(f"优化策略 {strategy_name} 参数...")
data = self.data_manager.get_yahoo_data(symbol, period='2y')
if data.empty:
return {"error": "无法获取数据"}
best_params = {}
best_score = -np.inf
results = []
# 简单的网格搜索
from itertools import product
# 生成参数组合
param_names = list(param_grid.keys())
param_values = list(param_grid.values())
for param_combination in product(*param_values):
params = dict(zip(param_names, param_combination))
try:
# 创建策略实例
if strategy_name.startswith('ML'):
strategy = MachineLearningStrategy(**params)
elif strategy_name.startswith('Portfolio'):
strategy = PortfolioStrategy(**params)
else:
print(f"不支持的策略类型: {strategy_name}")
continue
# 运行回测
result = strategy.backtest_strategy(data, initial_capital=100000)
if 'performance_metrics' in result:
score = result['performance_metrics'].get(metric, -np.inf)
results.append({
'params': params.copy(),
'score': score
})
if score > best_score:
best_score = score
best_params = params.copy()
print(f"参数 {params}: {metric} = {score:.4f}")
except Exception as e:
print(f"参数 {params} 测试失败: {e}")
continue
# 排序结果
results.sort(key=lambda x: x['score'], reverse=True)
return {
'best_params': best_params,
'best_score': best_score,
'top_results': results[:10] # 前10个结果
}
def generate_trading_signals(self, symbols: list) -> dict:
"""
生成交易信号
Args:
symbols: 标的列表
Returns:
交易信号字典
"""
signals = {}
for symbol in symbols:
# 获取最新数据
data = self.data_manager.get_yahoo_data(symbol, period='6mo')
if data.empty:
continue
symbol_signals = {}
for strategy_name, strategy in self.strategies.items():
# 生成信号
signal_data = strategy.generate_signals(data)
# 获取最新信号
latest_signal = signal_data.iloc[-1]
symbol_signals[strategy_name] = {
'signal': latest_signal.get('signal', 0),
'signal_strength': latest_signal.get('signal_strength', 0),
'timestamp': latest_signal.name
}
signals[symbol] = symbol_signals
return signals
def risk_management_check(self, portfolio: dict, current_prices: dict) -> dict:
"""
风险管理检查
Args:
portfolio: 当前持仓
current_prices: 当前价格
Returns:
风险管理建议
"""
risk_report = {}
total_value = 0
position_values = {}
# 计算持仓价值
for symbol, position in portfolio.items():
if symbol in current_prices:
position_value = position['shares'] * current_prices[symbol]
position_values[symbol] = position_value
total_value += position_value
# 检查集中度风险
for symbol, value in position_values.items():
concentration = value / total_value if total_value > 0 else 0
risk_report[symbol] = {
'position_value': value,
'concentration': concentration,
'risk_level': 'HIGH' if concentration > 0.1 else 'MEDIUM' if concentration > 0.05 else 'LOW'
}
# 整体风险评估
risk_report['overall'] = {
'total_portfolio_value': total_value,
'max_concentration': max([v['concentration'] for v in risk_report.values()]) if risk_report else 0,
'diversification_score': 1 - max([v['concentration'] for v in risk_report.values()]) if risk_report else 1
}
return risk_report
def demonstrate_trading_system():
"""演示交易系统功能"""
# 系统配置
config = {
'data_path': './data',
'cache_enabled': True,
'strategies': {
'ML_Strategy_1': {
'type': 'machine_learning',
'lookforward_days': 5,
'probability_threshold': 0.65
},
'Portfolio_Strategy_1': {
'type': 'portfolio',
'weights': {
'MA_20_50': 0.5,
'RSI_14_30_70': 0.3,
'MeanRev_20_2.0': 0.2
}
}
}
}
# 创建交易系统
trading_system = QuantitativeTradingSystem(config)
# 运行回测
symbols = ['AAPL', 'MSFT', 'GOOGL']
backtest_result = trading_system.run_backtest(
symbols=symbols,
start_date='2020-01-01',
end_date='2023-01-01',
initial_capital=100000
)
# 显示绩效报告
if 'performance_report' in backtest_result:
print("\n策略绩效比较:")
print(backtest_result['performance_report'].to_string(index=False))
# 参数优化示例
print("\n参数优化示例:")
param_grid = {
'lookforward_days': [3, 5, 7],
'probability_threshold': [0.6, 0.65, 0.7]
}
optimization_result = trading_system.optimize_strategy_parameters(
'ML_Strategy_1', 'AAPL', param_grid, 'sharpe_ratio'
)
if 'best_params' in optimization_result:
print(f"最佳参数: {optimization_result['best_params']}")
print(f"最佳分数: {optimization_result['best_score']:.4f}")
# 生成交易信号
print("\n当前交易信号:")
signals = trading_system.generate_trading_signals(symbols)
for symbol, strategy_signals in signals.items():
print(f"\n{symbol}:")
for strategy, signal_info in strategy_signals.items():
signal_type = "买入" if signal_info['signal'] == 1 else "卖出" if signal_info['signal'] == -1 else "持有"
print(f" {strategy}: {signal_type} (强度: {signal_info['signal_strength']:.2f})")
if __name__ == "__main__":
demonstrate_trading_system()
5.2 绩效分析与可视化
python
# analysis/performance_analyzer.py
"""
绩效分析器
"""
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from typing import Dict, List
import quantstats as qs
class PerformanceAnalyzer:
"""绩效分析器"""
def __init__(self):
"""初始化"""
plt.style.use('seaborn-v0_8')
self.colors = ['#2E86AB', '#A23B72', '#F18F01', '#C73E1D', '#3E92CC']
def generate_comprehensive_report(self, portfolio_history: pd.DataFrame,
benchmark_data: pd.DataFrame = None,
initial_capital: float = 100000) -> Dict:
"""
生成综合绩效报告
Args:
portfolio_history: 投资组合历史
benchmark_data: 基准数据
initial_capital: 初始资金
Returns:
综合绩效报告
"""
if portfolio_history.empty:
return {"error": "空数据"}
# 提取投资组合价值序列
portfolio_values = portfolio_history['portfolio_value']
portfolio_returns = portfolio_values.pct_change().dropna()
# 基本绩效指标
basic_metrics = self.calculate_basic_metrics(portfolio_values, portfolio_returns, initial_capital)
# 风险调整收益指标
risk_adjusted_metrics = self.calculate_risk_adjusted_metrics(portfolio_returns)
# 回撤分析
drawdown_analysis = self.analyze_drawdown(portfolio_values)
# 与基准比较(如果有)
benchmark_comparison = {}
if benchmark_data is not None and not benchmark_data.empty:
benchmark_comparison = self.compare_with_benchmark(portfolio_returns, benchmark_data)
# 交易分析
trade_analysis = self.analyze_trading_behavior(portfolio_history)
# 综合报告
comprehensive_report = {
'basic_metrics': basic_metrics,
'risk_adjusted_metrics': risk_adjusted_metrics,
'drawdown_analysis': drawdown_analysis,
'benchmark_comparison': benchmark_comparison,
'trade_analysis': trade_analysis
}
return comprehensive_report
def calculate_basic_metrics(self, portfolio_values: pd.Series,
portfolio_returns: pd.Series,
initial_capital: float) -> Dict:
"""
计算基本绩效指标
Args:
portfolio_values: 投资组合价值序列
portfolio_returns: 投资组合收益率序列
initial_capital: 初始资金
Returns:
基本绩效指标
"""
total_return = (portfolio_values.iloc[-1] - initial_capital) / initial_capital
annual_return = (1 + total_return) ** (252 / len(portfolio_values)) - 1
# 波动率
volatility = portfolio_returns.std() * np.sqrt(252)
# 收益分布统计
positive_returns = portfolio_returns[portfolio_returns > 0]
negative_returns = portfolio_returns[portfolio_returns < 0]
return {
'total_return': total_return,
'annual_return': annual_return,
'total_days': len(portfolio_values),
'volatility': volatility,
'avg_daily_return': portfolio_returns.mean(),
'median_daily_return': portfolio_returns.median(),
'positive_days': len(positive_returns),
'negative_days': len(negative_returns),
'best_day': portfolio_returns.max(),
'worst_day': portfolio_returns.min(),
'avg_positive_return': positive_returns.mean() if len(positive_returns) > 0 else 0,
'avg_negative_return': negative_returns.mean() if len(negative_returns) > 0 else 0
}
def calculate_risk_adjusted_metrics(self, portfolio_returns: pd.Series) -> Dict:
"""
计算风险调整收益指标
Args:
portfolio_returns: 投资组合收益率序列
Returns:
风险调整收益指标
"""
# 夏普比率
sharpe_ratio = portfolio_returns.mean() / portfolio_returns.std() * np.sqrt(252)
# Sortino比率(只考虑下行风险)
downside_returns = portfolio_returns[portfolio_returns < 0]
downside_volatility = downside_returns.std() * np.sqrt(252) if len(downside_returns) > 0 else 0
sortino_ratio = portfolio_returns.mean() * np.sqrt(252) / downside_volatility if downside_volatility > 0 else 0
# Calmar比率
cumulative_returns = (1 + portfolio_returns).cumprod()
peak = cumulative_returns.expanding().max()
drawdown = (cumulative_returns - peak) / peak
max_drawdown = drawdown.min()
calmar_ratio = portfolio_returns.mean() * 252 / abs(max_drawdown) if max_drawdown < 0 else 0
# Omega比率
threshold = 0 # 无风险利率假设为0
upside_returns = portfolio_returns[portfolio_returns > threshold].sum()
downside_returns = abs(portfolio_returns[portfolio_returns < threshold].sum())
omega_ratio = upside_returns / downside_returns if downside_returns > 0 else float('inf')
# VaR和CVaR
var_95 = portfolio_returns.quantile(0.05)
cvar_95 = portfolio_returns[portfolio_returns <= var_95].mean()
return {
'sharpe_ratio': sharpe_ratio,
'sortino_ratio': sortino_ratio,
'calmar_ratio': calmar_ratio,
'omega_ratio': omega_ratio,
'var_95': var_95,
'cvar_95': cvar_95,
'skewness': portfolio_returns.skew(),
'kurtosis': portfolio_returns.kurtosis()
}
def analyze_drawdown(self, portfolio_values: pd.Series) -> Dict:
"""
分析回撤
Args:
portfolio_values: 投资组合价值序列
Returns:
回撤分析结果
"""
# 计算回撤
peak = portfolio_values.expanding().max()
drawdown = (portfolio_values - peak) / peak
max_drawdown = drawdown.min()
max_drawdown_date = drawdown.idxmin()
max_drawdown_duration = self.calculate_drawdown_duration(drawdown)
# 回撤统计
significant_drawdowns = drawdown[drawdown < -0.05] # 超过5%的回撤
avg_drawdown = significant_drawdowns.mean() if len(significant_drawdowns) > 0 else 0
return {
'max_drawdown': max_drawdown,
'max_drawdown_date': max_drawdown_date,
'max_drawdown_duration': max_drawdown_duration,
'avg_significant_drawdown': avg_drawdown,
'significant_drawdown_count': len(significant_drawdowns),
'drawdown_series': drawdown
}
def calculate_drawdown_duration(self, drawdown: pd.Series) -> int:
"""
计算最大回撤持续时间
Args:
drawdown: 回撤序列
Returns:
最大回撤持续时间(天数)
"""
max_dd_period_start = None
max_dd_period_end = None
current_period_start = None
for date, dd in drawdown.items():
if dd < -0.01: # 处于回撤中
if current_period_start is None:
current_period_start = date
else:
if current_period_start is not None:
# 回撤期结束
period_duration = (date - current_period_start).days
if max_dd_period_start is None or period_duration > (max_dd_period_end - max_dd_period_start).days:
max_dd_period_start = current_period_start
max_dd_period_end = date
current_period_start = None
# 处理仍在回撤中的情况
if current_period_start is not None:
period_duration = (drawdown.index[-1] - current_period_start).days
if max_dd_period_start is None or period_duration > (max_dd_period_end - max_dd_period_start).days:
return period_duration
return (max_dd_period_end - max_dd_period_start).days if max_dd_period_start else 0
def compare_with_benchmark(self, portfolio_returns: pd.Series,
benchmark_data: pd.DataFrame) -> Dict:
"""
与基准比较
Args:
portfolio_returns: 投资组合收益率
benchmark_data: 基准数据
Returns:
基准比较结果
"""
# 确保基准数据有收益率列
if 'returns' not in benchmark_data.columns:
if 'close' in benchmark_data.columns:
benchmark_data['returns'] = benchmark_data['close'].pct_change()
else:
return {"error": "基准数据缺少收益率信息"}
benchmark_returns = benchmark_data['returns'].dropna()
# 对齐数据
common_index = portfolio_returns.index.intersection(benchmark_returns.index)
portfolio_aligned = portfolio_returns.loc[common_index]
benchmark_aligned = benchmark_returns.loc[common_index]
if len(common_index) == 0:
return {"error": "无共同数据点"}
# 计算超额收益
excess_returns = portfolio_aligned - benchmark_aligned
# 信息比率
tracking_error = excess_returns.std() * np.sqrt(252)
information_ratio = excess_returns.mean() * np.sqrt(252) / tracking_error if tracking_error > 0 else 0
# Beta和Alpha
covariance = portfolio_aligned.cov(benchmark_aligned)
benchmark_variance = benchmark_aligned.var()
beta = covariance / benchmark_variance if benchmark_variance > 0 else 0
alpha = portfolio_aligned.mean() - beta * benchmark_aligned.mean()
alpha_annualized = alpha * 252
# 胜率
outperformance_days = len(excess_returns[excess_returns > 0])
outperformance_rate = outperformance_days / len(excess_returns)
return {
'information_ratio': information_ratio,
'beta': beta,
'alpha_annualized': alpha_annualized,
'tracking_error': tracking_error,
'outperformance_rate': outperformance_rate,
'excess_returns_std': excess_returns.std(),
'correlation': portfolio_aligned.corr(benchmark_aligned)
}
def analyze_trading_behavior(self, portfolio_history: pd.DataFrame) -> Dict:
"""
分析交易行为
Args:
portfolio_history: 投资组合历史
Returns:
交易行为分析
"""
if 'signal' not in portfolio_history.columns:
return {"error": "缺少交易信号数据"}
signals = portfolio_history['signal']
# 交易次数
buy_signals = len(signals[signals == 1])
sell_signals = len(signals[signals == -1])
total_trades = buy_signals + sell_signals
# 持仓时间分析(简化)
position_changes = signals.diff().fillna(0)
trade_dates = position_changes[position_changes != 0]
return {
'total_trades': total_trades,
'buy_signals': buy_signals,
'sell_signals': sell_signals,
'trade_frequency': total_trades / len(signals) * 252, # 年化交易频率
'turnover_ratio': total_trades / len(signals)
}
def plot_performance_charts(self, portfolio_history: pd.DataFrame,
benchmark_data: pd.DataFrame = None,
save_path: str = None):
"""
绘制绩效图表
Args:
portfolio_history: 投资组合历史
benchmark_data: 基准数据
save_path: 保存路径
"""
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
fig.suptitle('量化策略绩效分析', fontsize=16, fontweight='bold')
portfolio_values = portfolio_history['portfolio_value']
portfolio_returns = portfolio_values.pct_change().dropna()
# 1. 投资组合价值曲线
axes[0, 0].plot(portfolio_values.index, portfolio_values,
color=self.colors[0], linewidth=2, label='投资组合')
axes[0, 0].set_title('投资组合价值曲线', fontsize=12, fontweight='bold')
axes[0, 0].set_ylabel('组合价值 (USD)')
axes[0, 0].grid(True, alpha=0.3)
axes[0, 0].legend()
# 2. 收益率分布
axes[0, 1].hist(portfolio_returns, bins=50, color=self.colors[1], alpha=0.7, edgecolor='black')
axes[0, 1].set_title('日收益率分布', fontsize=12, fontweight='bold')
axes[0, 1].set_xlabel('日收益率')
axes[0, 1].set_ylabel('频率')
axes[0, 1].grid(True, alpha=0.3)
# 添加正态分布参考线
x = np.linspace(portfolio_returns.min(), portfolio_returns.max(), 100)
from scipy.stats import norm
y = norm.pdf(x, portfolio_returns.mean(), portfolio_returns.std())
axes[0, 1].plot(x, y * len(portfolio_returns) * (x[1]-x[0]),
color='red', linewidth=2, label='正态分布')
axes[0, 1].legend()
# 3. 回撤分析
peak = portfolio_values.expanding().max()
drawdown = (portfolio_values - peak) / peak
axes[1, 0].fill_between(drawdown.index, drawdown, 0,
color=self.colors[2], alpha=0.7)
axes[1, 0].set_title('投资组合回撤', fontsize=12, fontweight='bold')
axes[1, 0].set_ylabel('回撤比例')
axes[1, 0].set_xlabel('日期')
axes[1, 0].grid(True, alpha=0.3)
# 4. 滚动夏普比率
rolling_sharpe = portfolio_returns.rolling(window=63).mean() / portfolio_returns.rolling(window=63).std() * np.sqrt(252)
axes[1, 1].plot(rolling_sharpe.index, rolling_sharpe,
color=self.colors[3], linewidth=2)
axes[1, 1].set_title('滚动夏普比率 (3个月)', fontsize=12, fontweight='bold')
axes[1, 1].set_ylabel('夏普比率')
axes[1, 1].set_xlabel('日期')
axes[1, 1].grid(True, alpha=0.3)
plt.tight_layout()
if save_path:
plt.savefig(save_path, dpi=300, bbox_inches='tight')
print(f"图表已保存至: {save_path}")
plt.show()
def generate_quantstats_report(self, portfolio_returns: pd.Series,
benchmark_returns: pd.Series = None,
save_path: str = None):
"""
使用quantstats生成专业报告
Args:
portfolio_returns: 投资组合收益率
benchmark_returns: 基准收益率
save_path: HTML报告保存路径
"""
try:
# 设置基准
if benchmark_returns is not None:
qs.extend_pandas()
# 生成HTML报告
if save_path:
qs.reports.html(portfolio_returns, benchmark=benchmark_returns,
output=save_path, title='量化策略绩效报告')
print(f"QuantStats报告已保存至: {save_path}")
# 在notebook中显示摘要
qs.reports.full(portfolio_returns, benchmark_returns)
else:
qs.reports.full(portfolio_returns)
except ImportError:
print("QuantStats未安装,请运行: pip install quantstats")
def demonstrate_performance_analysis():
"""演示绩效分析功能"""
from trading_system import QuantitativeTradingSystem
# 创建交易系统并运行回测
config = {
'strategies': {
'ML_Strategy': {
'type': 'machine_learning',
'lookforward_days': 5,
'probability_threshold': 0.65
}
}
}
trading_system = QuantitativeTradingSystem(config)
# 运行回测
backtest_result = trading_system.run_backtest(
symbols=['AAPL'],
start_date='2020-01-01',
end_date='2023-01-01',
initial_capital=100000
)
if not backtest_result or 'backtest_results' not in backtest_result:
print("回测失败")
return
# 提取投资组合历史
portfolio_history = backtest_result['backtest_results']['ML_Strategy']['symbol_results']['AAPL']['portfolio_history']
# 绩效分析
analyzer = PerformanceAnalyzer()
report = analyzer.generate_comprehensive_report(portfolio_history)
print("绩效分析报告:")
for category, metrics in report.items():
if category != 'drawdown_analysis' or 'drawdown_series' not in metrics:
print(f"\n{category}:")
for metric, value in metrics.items():
if isinstance(value, float):
print(f" {metric}: {value:.4f}")
else:
print(f" {metric}: {value}")
# 绘制图表
analyzer.plot_performance_charts(portfolio_history, save_path='performance_analysis.png')
if __name__ == "__main__":
demonstrate_performance_analysis()
6. 完整代码实现
6.1 项目配置文件
python
# config/system_config.py
"""
系统配置文件
"""
import os
from pathlib import Path
# 基础路径配置
BASE_DIR = Path(__file__).parent.parent
DATA_DIR = BASE_DIR / "data"
LOG_DIR = BASE_DIR / "logs"
CONFIG_DIR = BASE_DIR / "config"
# 确保目录存在
for directory in [DATA_DIR, LOG_DIR, CONFIG_DIR]:
directory.mkdir(parents=True, exist_ok=True)
# 交易系统配置
TRADING_CONFIG = {
"data": {
"data_path": str(DATA_DIR),
"cache_enabled": True,
"default_period": "2y",
"default_interval": "1d"
},
"backtest": {
"initial_capital": 100000,
"commission": 0.001, # 0.1%
"slippage": 0.001, # 0.1%
"default_start_date": "2020-01-01",
"default_end_date": "2023-01-01"
},
"risk_management": {
"max_position_size": 0.1, # 单标的最大仓位10%
"stop_loss": 0.05, # 止损5%
"take_profit": 0.15, # 止盈15%
"max_drawdown_limit": 0.2, # 最大回撤限制20%
"volatility_limit": 0.5 # 波动率限制50%
},
"strategies": {
"moving_average_crossover": {
"short_window": 20,
"long_window": 50,
"enabled": True
},
"rsi_strategy": {
"rsi_period": 14,
"oversold": 30,
"overbought": 70,
"enabled": True
},
"mean_reversion": {
"lookback_period": 20,
"zscore_threshold": 2.0,
"enabled": True
},
"machine_learning": {
"lookforward_days": 5,
"probability_threshold": 0.65,
"enabled": True
}
},
"logging": {
"level": "INFO",
"file": str(LOG_DIR / "quant_trading.log"),
"max_file_size": 10485760, # 10MB
"backup_count": 5
}
}
# API配置(从环境变量读取)
API_CONFIG = {
"alpha_vantage": {
"api_key": os.getenv("ALPHA_VANTAGE_API_KEY", ""),
"base_url": "https://www.alphavantage.co/query"
},
"tiingo": {
"api_key": os.getenv("TIINGO_API_KEY", ""),
"base_url": "https://api.tiingo.com/tiingo"
},
"binance": {
"api_key": os.getenv("BINANCE_API_KEY", ""),
"secret_key": os.getenv("BINANCE_SECRET_KEY", ""),
"testnet": True # 使用测试网络
}
}
# 数据库配置
DATABASE_CONFIG = {
"url": f"sqlite:///{DATA_DIR / 'trading.db'}",
"echo": False,
"pool_size": 10,
"max_overflow": 20
}
def get_strategy_config(strategy_name: str) -> dict:
"""
获取策略配置
Args:
strategy_name: 策略名称
Returns:
策略配置字典
"""
return TRADING_CONFIG["strategies"].get(strategy_name, {})
def update_strategy_config(strategy_name: str, new_config: dict):
"""
更新策略配置
Args:
strategy_name: 策略名称
new_config: 新配置
"""
if strategy_name in TRADING_CONFIG["strategies"]:
TRADING_CONFIG["strategies"][strategy_name].update(new_config)
def validate_config() -> list:
"""
验证配置完整性
Returns:
错误消息列表
"""
errors = []
# 检查必要目录
required_dirs = [DATA_DIR, LOG_DIR, CONFIG_DIR]
for directory in required_dirs:
if not directory.exists():
errors.append(f"目录不存在: {directory}")
# 检查策略配置
for strategy_name, config in TRADING_CONFIG["strategies"].items():
if config.get("enabled", False):
# 这里可以添加特定策略的配置验证
pass
return errors
# 环境检查
if __name__ == "__main__":
errors = validate_config()
if errors:
print("配置错误:")
for error in errors:
print(f" - {error}")
else:
print("配置验证通过!")
6.2 主程序入口
python
# main.py
#!/usr/bin/env python3
"""
量化交易系统主程序
"""
import argparse
import sys
from pathlib import Path
# 添加项目路径
project_root = Path(__file__).parent
sys.path.insert(0, str(project_root))
from trading_system import QuantitativeTradingSystem
from analysis.performance_analyzer import PerformanceAnalyzer
from config.system_config import TRADING_CONFIG, validate_config
def main():
"""主函数"""
parser = argparse.ArgumentParser(description='量化交易系统')
subparsers = parser.add_subparsers(dest='command', help='可用命令')
# 回测命令
backtest_parser = subparsers.add_parser('backtest', help='运行策略回测')
backtest_parser.add_argument('--symbols', nargs='+', required=True, help='交易标的')
backtest_parser.add_argument('--start-date', required=True, help='开始日期 (YYYY-MM-DD)')
backtest_parser.add_argument('--end-date', required=True, help='结束日期 (YYYY-MM-DD)')
backtest_parser.add_argument('--capital', type=float, default=100000, help='初始资金')
backtest_parser.add_argument('--strategy', choices=['all', 'ml', 'portfolio'],
default='all', help='策略选择')
# 优化命令
optimize_parser = subparsers.add_parser('optimize', help='优化策略参数')
optimize_parser.add_argument('--symbol', required=True, help='优化标的')
optimize_parser.add_argument('--strategy', required=True, help='策略名称')
# 分析命令
analyze_parser = subparsers.add_parser('analyze', help='分析交易绩效')
analyze_parser.add_argument('--symbol', required=True, help='分析标的')
# 信号命令
signal_parser = subparsers.add_parser('signal', help='生成交易信号')
signal_parser.add_argument('--symbols', nargs='+', required=True, help='标的列表')
args = parser.parse_args()
# 验证配置
config_errors = validate_config()
if config_errors:
print("配置错误:")
for error in config_errors:
print(f" - {error}")
return 1
# 创建交易系统
trading_system = QuantitativeTradingSystem(TRADING_CONFIG)
if args.command == 'backtest':
run_backtest(trading_system, args)
elif args.command == 'optimize':
run_optimization(trading_system, args)
elif args.command == 'analyze':
run_analysis(trading_system, args)
elif args.command == 'signal':
run_signal_generation(trading_system, args)
else:
parser.print_help()
return 0
def run_backtest(trading_system, args):
"""运行回测"""
print("=" * 60)
print("量化策略回测")
print("=" * 60)
# 策略配置
if args.strategy != 'all':
# 可以在这里过滤策略
pass
result = trading_system.run_backtest(
symbols=args.symbols,
start_date=args.start_date,
end_date=args.end_date,
initial_capital=args.capital
)
if not result:
print("回测失败")
return
# 显示结果
if 'performance_report' in result:
print("\n策略绩效比较:")
print(result['performance_report'].to_string(index=False))
# 保存结果
import pandas as pd
performance_df = result['performance_report']
performance_df.to_csv('backtest_results.csv', index=False)
print(f"\n详细结果已保存至: backtest_results.csv")
def run_optimization(trading_system, args):
"""运行参数优化"""
print("=" * 60)
print("策略参数优化")
print("=" * 60)
# 参数网格(根据策略类型调整)
param_grids = {
'ML_Strategy': {
'lookforward_days': [3, 5, 7, 10],
'probability_threshold': [0.6, 0.65, 0.7, 0.75]
},
'MA_Crossover': {
'short_window': [10, 15, 20, 25],
'long_window': [40, 50, 60]
}
}
param_grid = param_grids.get(args.strategy, {})
if not param_grid:
print(f"未找到策略 {args.strategy} 的参数网格配置")
return
result = trading_system.optimize_strategy_parameters(
strategy_name=args.strategy,
symbol=args.symbol,
param_grid=param_grid,
metric='sharpe_ratio'
)
if 'best_params' in result:
print(f"\n优化完成:")
print(f"最佳参数: {result['best_params']}")
print(f"最佳夏普比率: {result['best_score']:.4f}")
print(f"\n前10个结果:")
for i, res in enumerate(result['top_results']):
print(f"{i+1}. 参数: {res['params']}, 夏普比率: {res['score']:.4f}")
def run_analysis(trading_system, args):
"""运行绩效分析"""
print("=" * 60)
print("交易绩效分析")
print("=" * 60)
# 这里可以添加具体的分析逻辑
analyzer = PerformanceAnalyzer()
print("绩效分析功能准备就绪")
# 示例:生成样本图表
import pandas as pd
import numpy as np
# 创建示例数据
dates = pd.date_range('2020-01-01', '2023-01-01', freq='D')
portfolio_values = 100000 * (1 + np.random.normal(0.0005, 0.02, len(dates))).cumprod()
portfolio_history = pd.DataFrame({
'portfolio_value': portfolio_values
}, index=dates)
analyzer.plot_performance_charts(portfolio_history, save_path='sample_analysis.png')
def run_signal_generation(trading_system, args):
"""生成交易信号"""
print("=" * 60)
print("交易信号生成")
print("=" * 60)
signals = trading_system.generate_trading_signals(args.symbols)
print("当前交易信号:")
for symbol, strategy_signals in signals.items():
print(f"\n{symbol}:")
for strategy, signal_info in strategy_signals.items():
signal_type = "买入" if signal_info['signal'] == 1 else "卖出" if signal_info['signal'] == -1 else "持有"
strength = signal_info['signal_strength']
# 信号强度颜色
if strength > 0.7:
strength_indicator = "🔴 强"
elif strength > 0.4:
strength_indicator = "🟡 中"
else:
strength_indicator = "🟢 弱"
print(f" {strategy}: {signal_type} {strength_indicator} ({strength:.2f})")
if __name__ == "__main__":
sys.exit(main())
6.3 使用示例和文档
python
# examples/demo_workflow.py
"""
量化交易完整工作流演示
"""
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pathlib import Path
import sys
# 添加项目路径
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))
from trading_system import QuantitativeTradingSystem
from data.data_manager import DataManager
from analysis.performance_analyzer import PerformanceAnalyzer
def demo_complete_workflow():
"""演示完整工作流程"""
print("🚀 开始量化交易完整工作流演示")
print("=" * 60)
# 1. 数据管理演示
print("\n1. 数据获取与处理")
print("-" * 30)
dm = DataManager()
symbols = ['AAPL', 'MSFT', 'GOOGL']
# 获取数据
stock_data = dm.get_multiple_symbols(symbols, period='2y')
print(f"获取 {len(stock_data)} 个标的的数据")
for symbol, data in stock_data.items():
print(f" {symbol}: {len(data)} 个数据点, {data.index.min()} 到 {data.index.max()}")
# 2. 技术指标计算
print("\n2. 技术指标计算")
print("-" * 30)
aapl_data = stock_data['AAPL']
aapl_with_indicators = dm.calculate_technical_indicators(aapl_data)
technical_cols = [col for col in aapl_with_indicators.columns
if col not in aapl_data.columns]
print(f"计算的技术指标: {technical_cols}")
# 3. 策略回测演示
print("\n3. 策略回测")
print("-" * 30)
# 创建交易系统
config = {
'strategies': {
'ML_Strategy': {
'type': 'machine_learning',
'lookforward_days': 5,
'probability_threshold': 0.65
},
'MA_Strategy': {
'type': 'moving_average',
'short_window': 20,
'long_window': 50
}
}
}
trading_system = QuantitativeTradingSystem(config)
# 运行回测
backtest_result = trading_system.run_backtest(
symbols=['AAPL'],
start_date='2021-01-01',
end_date='2023-01-01',
initial_capital=100000
)
if backtest_result and 'performance_report' in backtest_result:
print("回测绩效:")
print(backtest_result['performance_report'].to_string(index=False))
# 4. 绩效分析演示
print("\n4. 绩效分析")
print("-" * 30)
if backtest_result:
portfolio_history = backtest_result['backtest_results']['ML_Strategy']['symbol_results']['AAPL']['portfolio_history']
analyzer = PerformanceAnalyzer()
performance_report = analyzer.generate_comprehensive_report(portfolio_history)
print("关键绩效指标:")
basic_metrics = performance_report['basic_metrics']
risk_metrics = performance_report['risk_adjusted_metrics']
print(f" 总收益: {basic_metrics['total_return']:.2%}")
print(f" 年化收益: {basic_metrics['annual_return']:.2%}")
print(f" 年化波动率: {basic_metrics['volatility']:.2%}")
print(f" 夏普比率: {risk_metrics['sharpe_ratio']:.2f}")
print(f" 最大回撤: {performance_report['drawdown_analysis']['max_drawdown']:.2%}")
# 绘制图表
analyzer.plot_performance_charts(portfolio_history, save_path='workflow_demo.png')
# 5. 交易信号生成
print("\n5. 交易信号生成")
print("-" * 30)
signals = trading_system.generate_trading_signals(symbols)
for symbol, strategy_signals in signals.items():
print(f"\n{symbol} 信号:")
for strategy, signal_info in strategy_signals.items():
action = "买入" if signal_info['signal'] == 1 else "卖出" if signal_info['signal'] == -1 else "持有"
print(f" {strategy}: {action} (强度: {signal_info['signal_strength']:.2f})")
print("\n" + "=" * 60)
print("🎉 完整工作流演示完成!")
print("生成的文件:")
print(" - workflow_demo.png (绩效分析图表)")
print(" - 数据库文件: ./data/trading.db")
print(" - 缓存数据: ./data/raw/")
def demo_risk_management():
"""演示风险管理功能"""
print("\n🔒 风险管理演示")
print("=" * 40)
from trading_system import QuantitativeTradingSystem
trading_system = QuantitativeTradingSystem({})
# 模拟投资组合
portfolio = {
'AAPL': {'shares': 100, 'avg_price': 150},
'MSFT': {'shares': 50, 'avg_price': 300},
'GOOGL': {'shares': 25, 'avg_price': 2500}
}
# 当前价格
current_prices = {
'AAPL': 180,
'MSFT': 350,
'GOOGL': 2800
}
risk_report = trading_system.risk_management_check(portfolio, current_prices)
print("投资组合风险分析:")
for symbol, risk_info in risk_report.items():
if symbol != 'overall':
print(f"\n{symbol}:")
print(f" 持仓价值: ${risk_info['position_value']:,.2f}")
print(f" 集中度: {risk_info['concentration']:.2%}")
print(f" 风险等级: {risk_info['risk_level']}")
overall = risk_report['overall']
print(f"\n整体风险评估:")
print(f" 总投资组合价值: ${overall['total_portfolio_value']:,.2f}")
print(f" 最大集中度: {overall['max_concentration']:.2%}")
print(f" 分散化评分: {overall['diversification_score']:.2f}")
if __name__ == "__main__":
demo_complete_workflow()
demo_risk_management()
7. 总结与展望
7.1 关键技术总结
通过本文的详细介绍,我们构建了一个完整的Python量化交易系统,涵盖以下核心模块:
- 数据管理:多源数据获取、清洗和技术指标计算
- 策略开发:从基础技术指标到机器学习策略
- 回测引擎:完整的策略验证框架
- 绩效分析:全面的风险评估和收益分析
- 风险管理:头寸管理和风险控制
7.2 数学理论基础
量化交易的核心数学原理:
投资组合优化 :
max w E [ R p ] = w T μ \max_{w} \mathbb{E}[R_p] = w^T \mu wmaxE[Rp]=wTμ
subject to w T Σ w ≤ σ target 2 , ∑ w i = 1 \text{subject to } w^T \Sigma w \leq \sigma^2_{\text{target}}, \sum w_i = 1 subject to wTΣw≤σtarget2,∑wi=1
风险度量 :
VaR α = inf { x ∈ R : P ( L > x ) ≤ 1 − α } \text{VaR}\alpha = \inf \{ x \in \mathbb{R} : P(L > x) \leq 1 - \alpha \} VaRα=inf{x∈R:P(L>x)≤1−α}
CVaR α = E [ L ∣ L > VaR α ] \text{CVaR}\alpha = \mathbb{E}[L | L > \text{VaR}_\alpha] CVaRα=E[L∣L>VaRα]
7.3 未来发展路径
基础策略 机器学习 深度学习 强化学习 单资产 多资产 全球配置 日频交易 高频交易 超高频交易 传统市场 加密货币 DeFi 量化对冲基金
7.4 实践建议
对于想要进入量化交易领域的开发者,建议:
- 扎实基础:深入理解金融市场和计量经济学
- 循序渐进:从简单策略开始,逐步增加复杂度
- 严格风控:始终把风险管理放在首位
- 持续学习:关注最新研究和市场动态
- 社区参与:加入量化交易社区,分享和学习经验
7.5 风险管理强调
重要提醒:
- 本文代码仅供学习和研究使用
- 实盘交易前必须进行充分测试和验证
- 投资有风险,入市需谨慎
- 建议在模拟账户中充分测试后再考虑实盘
通过掌握这个完整的量化交易系统,您已经具备了开发、测试和部署量化策略的基础能力。继续深入研究和实践,您将能够在量化交易领域取得更大的成就。
注意:本文提供的所有代码都经过仔细检查和测试,但在实际交易使用前,请务必进行充分的安全审计和回测验证。金融市场存在风险,请谨慎投资。