Python全栈开发-第9章 量化金融回测系统

📅 2026/7/18 10:59:52
Python全栈开发-第9章 量化金融回测系统
第三篇 · 科学计算与AI💹 第9章 量化金融回测系统用代码验证你的交易策略9.1 量化交易基础让Python帮你炒股的第一步量化交易就是用数学模型代替感觉来做交易决策。人类交易员会受情绪影响——恐惧时割肉,贪婪时追高。量化策略则严格执行规则,不受情绪干扰。量化交易的核心流程:获取数据:历史行情、财务报表、新闻舆情构建策略:用数学规则定义买卖时机回测验证:用历史数据模拟交易,检验策略表现风险评估:最大亏损多少?夏普比率如何?实盘交易:接入交易所API自动执行本课聚焦前两步:用Python获取金融数据,为后续策略开发打好基础。importnumpyasnpimportpandasaspd# ===== 用模拟数据演示(无需联网) =====# 实际项目中用 yfinance 获取真实数据:# pip install yfinance# import yfinance as yf# df = yf.download('AAPL', start='2023-01-01', end='2024-01-01')# 生成模拟股票数据(类似真实行情)np.random.seed(42)dates=pd.bdate_range('2023-01-01',periods=252)# 一年交易日n=len(dates)# 使用几何布朗运动模拟股价mu=0.10# 年化收益率10%sigma=0.25# 年化波动率25%dt=1/252returns=(mu-0.5*sigma**2)*dt+sigma*np.sqrt(dt)*np.random.randn(n)close=150*np.exp(np.cumsum(returns))# 起始价150# 生成OHLCV数据high=close*(1+np.abs(np.random.randn(n))*0.01)low=close*(1-np.abs(np.random.randn(n))*0.01)open_price=close*(1+np.random.randn(n)*0.005)volume=np.random.randint(1_000_000,10_000_000,n)df=pd.DataFrame({'Open':open_price,'High':high,'Low':low,'Close':close,'Volume':volume},index=dates)print('股票数据预览:')print(df.head(10).round(2))print(f'\n数据形状:{df.shape}')print(f'时间范围:{df.index[0].date()}至{df.index[-1].date()}')print(f'价格范围:{df["Close"].min():.2f}~{df["Close"].max():.2f}')print(f'总收益率:{(df["Close"].iloc[-1]/df["Close"].iloc[0]-1)*100:.1f}%')🔑 核心要点金融数据的核心结构是OHLCV:-Open(开盘价):当天第一笔成交价-High(最高价):当天最高成交价-Low(最低价):当天最低成交价-Close(收盘价):当天最后一笔成交价(最常用)-Volume(成交量):当天交易的股票数量importnumpyasnpimportpandasaspd# ===== 收益率计算 =====np.random.seed(42)dates=pd.bdate_range('2023-01-01',periods=252)n=len(dates)returns_series=(0.10/252)+(0.25/np.sqrt(252))*np.random.randn(n)close=150*np.exp(np.cumsum(returns_series))df=pd.DataFrame({'Close':close},index=dates)# 日收益率(简单收益率)df['Daily_Return']=df['Close'].pct_change()# 对数收益率(更适合数学处理,可加性好)df['Log_Return']=np.log(df['Close']/df['Close'].shift(1))# 累计收益率df['Cumulative_Return']=(1+df['Daily_Return']).cumprod()-1print('收益率计算:')print(df[['Close','Daily_Return','Log_Return','Cumulative_Return']].head(10).round(4))# 统计摘要print(f'\n日收益率统计:')print(f' 均值:{df["Daily_Return"].mean():.6f}')print(f' 标准差:{df["Daily_Return"].std():.6f}')print(f' 偏度:{df["Daily_Return"].skew():.4f}')print(f' 峰度:{df["Daily_Return"].kurtosis():.4f}')print(f' 最大单日涨幅:{df["Daily_Return"].max():.4f}')print(f' 最大单日跌幅:{df["Daily_Return"].min():.4f}')# 年化收益与年化波动率annual_return=df['Daily_Return'].mean()*252annual_vol=df['Daily_Return'].std()*np.sqrt(252)print(f'\n年化收益率:{annual_return*100:.2f}%')print(f'年化波动率:{annual_vol*100:.2f}%')💡 技巧对数收益率比简单收益率更适合量化分析:它具有时间可加性——多日对数收益率直接相加就等于总对数收益率,而简单收益率需要连乘。在收益率较小(小于5%)时,两者近似相等。⚠️ 注意回测中常见的前视偏差(Look-ahead Bias):在计算今天的信号时不小心用到了明天的数据。比如用今天的收盘价做决策,但实际中你只能在收盘后才知道收盘价,今天盘中无法使用。务必确保信号计算只用历史数据!🧪 随堂测验某股票今天收盘价100元,昨天收盘价95元,今天的对数收益率约为?A. 5.26%B. 5.00%C. 4.88%D. 5.13%答案解析:对数收益率 = ln(100/95) = ln(1.05263) 约等于 0.05129 约等于 5.13%。简单收益率 = (100-95)/95 = 5.26%。对数收益率总是略小于简单收益率(当收益为正时)。9.2 技术指标计算MA、RSI、MACD、布林带的Python实现技术指标是量化交易的信息面板——它们把杂乱的价格数据提炼成可读的信号。四大常用指标:-MA/EMA(移动平均线):趋势的方向盘,判断涨跌趋势-RSI(相对强弱指标):超买超卖的体温计,70过热,30过冷-MACD(指数平滑异同移动平均线):趋势+动量的双料指示器-布林带(Bollinger Bands):价格波动的安全边界打个比方:MA是大方向,RSI是温度计,MACD是加速器,布林带是围栏。老练的交易员会综合多个指标做决策。importnumpyasnpimportpandasaspd# ===== 生成模拟股价数据 =====np.random.seed(42)dates=pd.bdate_range('2023-01-01',periods=252)n=len(dates)returns=0.0004+0.016*np.random.randn(n)close=100*np.exp(np.cumsum(returns))df=pd.DataFrame({'Close':close},index=dates)# ===== 移动平均线 =====# 简单移动平均(SMA):等权重平均df['SMA_5']=df['Close'].rolling(window=5).mean()df['SMA_20']=df['Close'].rolling(window=20).mean()df['SMA_60']=df['Close'].rolling(window=60).mean()# 指数移动平均(EMA):近期数据权重更大df['EMA_12']=df['Close'].ewm(span=12,adjust=False).mean()df['EMA_26']=df['Close'].ewm(span=26,adjust=False).mean()print('移动平均线(最后5天):')cols=['Close','SMA_5','SMA_20','SMA_60','EMA_12','EMA_26']print(df[cols].tail(5).round(2))# 金叉/死叉判断df['Golden_Cross']=(df['SMA_5']df['SMA_20'])(df['SMA_5'].shift(1)=df['SMA_20'].shift(1))df['Death_Cross']=(df[