#!/usr/bin/env python3 """ 价值投资策略回测框架 紧急提交时间:18:13 """ import pandas as pd import numpy as np from datetime import datetime, timedelta import warnings warnings.filterwarnings('ignore') class ValueInvestingBacktest: """价值投资策略回测框架""" def __init__(self): self.start_time = datetime.now() print(f"🚀 价值投资策略回测框架启动!") print(f"🕐 启动时间: {self.start_time.strftime('%H:%M:%S')}") print(f"🎯 紧急提交时间: 18:00(立即补交)") def generate_price_data(self, n_stocks=3000, n_days=252): """生成价格数据(模拟)""" print(f"📈 生成价格数据...") np.random.seed(42) # 生成基础价格数据 dates = pd.date_range(end=datetime.now(), periods=n_days, freq='B') stock_codes = [f'{i:06d}.XSHE' for i in range(1, n_stocks + 1)] # 创建价格DataFrame price_data = pd.DataFrame(index=dates, columns=stock_codes) # 为每只股票生成价格序列 for stock in stock_codes: # 基础收益率(年化10-20%) base_return = np.random.uniform(0.0004, 0.0008, n_days) # 随机波动 volatility = np.random.uniform(0.01, 0.03, n_days) random_shocks = np.random.normal(0, volatility) # 计算日收益率 daily_returns = base_return + random_shocks # 计算价格(从100开始) prices = 100 * np.exp(np.cumsum(daily_returns)) price_data[stock] = prices print(f"✅ 生成 {n_stocks} 只股票 {n_days} 天价格数据") return price_data def generate_fundamental_data(self, n_stocks=3000): """生成基本面数据(模拟)""" print(f"📊 生成基本面数据...") np.random.seed(42) fundamental_data = pd.DataFrame({ 'stock_code': [f'{i:06d}.XSHE' for i in range(1, n_stocks + 1)], 'industry': np.random.choice(['金融', '科技', '消费', '医药', '工业', '能源', '材料', '公用事业'], n_stocks), 'market_cap': np.random.uniform(50, 1000, n_stocks), 'pe_ratio': np.random.uniform(5, 50, n_stocks), 'pb_ratio': np.random.uniform(0.5, 5, n_stocks), 'ps_ratio': np.random.uniform(0.5, 10, n_stocks), 'dividend_yield': np.random.uniform(0, 0.05, n_stocks), 'roe': np.random.uniform(0.05, 0.3, n_stocks), 'gross_margin': np.random.uniform(0.2, 0.6, n_stocks), 'net_margin': np.random.uniform(0.05, 0.25, n_stocks), 'debt_to_equity': np.random.uniform(0.1, 1.5, n_stocks), 'current_ratio': np.random.uniform(1, 3, n_stocks), 'revenue_growth': np.random.uniform(-0.2, 0.5, n_stocks), 'profit_growth': np.random.uniform(-0.3, 0.6, n_stocks), 'fcf_yield': np.random.uniform(0, 0.1, n_stocks) }) print(f"✅ 生成 {n_stocks} 只股票基本面数据") return fundamental_data def calculate_value_score(self, fundamental_data): """计算价值得分""" print(f"🔢 计算价值得分...") data = fundamental_data.copy() # 1. 估值因子得分(越低估值,得分越高) data['value_score'] = ( (1 - data['pe_ratio'].rank(pct=True)) * 0.4 + (1 - data['pb_ratio'].rank(pct=True)) * 0.3 + (1 - data['ps_ratio'].rank(pct=True)) * 0.2 + data['dividend_yield'].rank(pct=True) * 0.1 ) # 2. 质量因子得分(越高质量,得分越高) data['quality_score'] = ( data['roe'].rank(pct=True) * 0.3 + data['gross_margin'].rank(pct=True) * 0.2 + data['net_margin'].rank(pct=True) * 0.2 + (1 - data['debt_to_equity'].rank(pct=True)) * 0.15 + data['current_ratio'].rank(pct=True) * 0.15 ) # 3. 综合价值得分 data['composite_value_score'] = data['value_score'] * 0.6 + data['quality_score'] * 0.4 print(f"✅ 价值得分计算完成") return data def select_portfolio(self, fundamental_data, portfolio_size=20): """选择投资组合""" print(f"🏗️ 选择投资组合...") # 按综合价值得分排序 top_stocks = fundamental_data.nlargest(portfolio_size, 'composite_value_score') # 计算等权重 top_stocks['weight'] = 1.0 / portfolio_size print(f"✅ 选择 {portfolio_size} 只股票投资组合") return top_stocks def run_backtest(self, price_data, portfolio, rebalance_freq='M'): """运行回测""" print(f"📊 运行回测...") # 获取投资组合股票代码 portfolio_stocks = portfolio['stock_code'].tolist() # 只保留投资组合中的股票价格数据 portfolio_prices = price_data[portfolio_stocks] # 计算投资组合每日收益率(等权重) portfolio_returns = portfolio_prices.pct_change().mean(axis=1) # 计算基准收益率(所有股票等权重) benchmark_returns = price_data.pct_change().mean(axis=1) # 计算累计收益率 portfolio_cumulative = (1 + portfolio_returns).cumprod() benchmark_cumulative = (1 + benchmark_returns).cumprod() # 计算回测指标 results = self.calculate_metrics(portfolio_returns, benchmark_returns) print(f"✅ 回测完成") return results, portfolio_returns, benchmark_returns, portfolio_cumulative, benchmark_cumulative def calculate_metrics(self, portfolio_returns, benchmark_returns): """计算回测指标""" # 年化收益率 annual_portfolio_return = (1 + portfolio_returns.mean()) ** 252 - 1 annual_benchmark_return = (1 + benchmark_returns.mean()) ** 252 - 1 # 年化波动率 annual_portfolio_vol = portfolio_returns.std() * np.sqrt(252) annual_benchmark_vol = benchmark_returns.std() * np.sqrt(252) # 夏普比率(假设无风险利率3%) risk_free_rate = 0.03 portfolio_sharpe = (annual_portfolio_return - risk_free_rate) / annual_portfolio_vol if annual_portfolio_vol > 0 else 0 benchmark_sharpe = (annual_benchmark_return - risk_free_rate) / annual_benchmark_vol if annual_benchmark_vol > 0 else 0 # 最大回撤 cumulative_returns = (1 + portfolio_returns).cumprod() running_max = cumulative_returns.expanding().max() drawdown = (cumulative_returns - running_max) / running_max max_drawdown = drawdown.min() # 胜率 winning_months = (portfolio_returns > benchmark_returns).sum() total_months = len(portfolio_returns) win_rate = winning_months / total_months if total_months > 0 else 0 # 信息比率 active_returns = portfolio_returns - benchmark_returns information_ratio = (active_returns.mean() * 252) / (active_returns.std() * np.sqrt(252)) if active_returns.std() > 0 else 0 results = { 'annual_return': annual_portfolio_return, 'annual_benchmark_return': annual_benchmark_return, 'annual_volatility': annual_portfolio_vol, 'benchmark_volatility': annual_benchmark_vol, 'sharpe_ratio': portfolio_sharpe, 'benchmark_sharpe': benchmark_sharpe, 'max_drawdown': max_drawdown, 'win_rate': win_rate, 'information_ratio': information_ratio, 'excess_return': annual_portfolio_return - annual_benchmark_return } return results def run(self): """运行完整回测""" print(f"\n{'='*60}") print("🚀 价值投资策略回测开始") print(f"{'='*60}") # 1. 生成数据 price_data = self.generate_price_data(n_stocks=3000, n_days=252) fundamental_data = self.generate_fundamental_data(n_stocks=3000) # 2. 计算价值得分 scored_data = self.calculate_value_score(fundamental_data) # 3. 选择投资组合 portfolio = self.select_portfolio(scored_data, portfolio_size=20) # 4. 运行回测 results, portfolio_returns, benchmark_returns, portfolio_cumulative, benchmark_cumulative = self.run_backtest( price_data, portfolio ) # 5. 输出结果 self.output_results(results, portfolio, portfolio_cumulative, benchmark_cumulative) return results, portfolio def output_results(self, results, portfolio, portfolio_cumulative, benchmark_cumulative): """输出结果""" print(f"\n{'='*60}") print("📊 回测结果汇总") print(f"{'='*60}") # 业绩指标 print(f"\n📈 业绩指标:") print(f"{'='*40}") print(f"年化收益率: {results['annual_return']*100:.2f}%") print(f"基准收益率: {results['annual_benchmark_return']*100:.2f}%") print(f"超额收益: {results['excess_return']*100:.2f}%") print(f"年化波动率: {results['annual_volatility']*100:.2f}%") print(f"夏普比率: {results['sharpe_ratio']:.3f}") print(f"基准夏普: {results['benchmark_sharpe']:.3f}") print(f"最大回撤: {results['max_drawdown']*100:.2f}%") print(f"胜率: {results['win_rate']*100:.1f}%") print(f"信息比率: {results['information_ratio']:.3f}") # 投资组合 print(f"\n🏆 投资组合(前10只):") print(f"{'='*40}") top_10 = portfolio.head(10) display_cols = ['stock_code', 'industry', 'pe_ratio', 'pb_ratio', 'roe', 'composite_value_score', 'weight'] display_data = top_10[display_cols].copy() display_data['roe'] = display_data['roe'].apply(lambda x: f"{x*100:.1f}%") display_data['weight'] = display_data['weight'].apply(lambda x: f"{x*100:.1f}%") display_data['composite_value_score'] = display_data['composite_value_score'].round(3) print(display_data.to_string(index=False)) # 组合特征 print(f"\n📊 组合特征:") print(f"{'='*40}") print(f"平均PE: {portfolio['pe_ratio'].mean():.1f}") print(f"平均PB: {portfolio['pb_ratio'].mean():.2f}") print(f"平均ROE: {portfolio['roe'].mean()*100:.1f}%") print(f"平均股息率: {portfolio['dividend_yield'].mean()*100:.2f}%") print(f"平均市值: {portfolio['market_cap'].mean():.1f}亿") # 累计收益率 final_portfolio_return = portfolio_cumulative.iloc[-1] - 1 final_benchmark_return = benchmark_cumulative.iloc[-1] - 1 print(f"\n💰 累计收益率:") print(f"{'='*40}") print(f"投资组合: {final_portfolio_return*100:.2f}%") print(f"基准: {final_benchmark_return*100:.2f}%") print(f"超额: {(final_portfolio_return - final_benchmark_return)*100:.2f}%") # 时间统计 elapsed = (datetime.now() - self.start_time).total_seconds() print(f"\n⏰ 回测运行时间: {elapsed:.2f}秒") print(f"🕐 完成时间: {datetime.now().strftime('%H:%M:%S')}") # 结论 print(f"\n🎯 结论:") print(f"{'='*40}") if results['excess_return'] > 0: print(f"✅ 价值投资策略表现优于基准") if results['sharpe_ratio'] > results['benchmark_sharpe']: print(f"✅ 风险调整后收益也优于基准") else: print(f"⚠️ 风险调整后收益略低于基准") else: print(f"❌ 价值投资策略表现弱于基准") # 建议 print(f"\n💡 建议:") print(f"{'='*40}") print(f"1. 考虑增加质量因子权重") print(f"2. 优化估值因子组合") print(f"3. 增加行业轮动机制") print(f"4. 考虑市场周期调整") # 保存结果 self.save_results(results, portfolio, portfolio_cumulative, benchmark_cumulative) def save_results(self, results, portfolio, portfolio_cumulative, benchmark_cumulative): """保存结果""" import os # 创建输出目录 output_dir = "backtest_results" os.makedirs(output_dir, exist_ok=True) # 保存投资组合 portfolio.to_csv(f"{output_dir}/value_portfolio.csv", index=False) # 保存回测结果 results_df = pd.DataFrame([results]) results_df.to_csv(f"{output_dir}/backtest_results.csv", index=False) # 保存累计收益率 cumulative_df = pd.DataFrame({ 'portfolio': portfolio_cumulative, 'benchmark': benchmark_cumulative }) cumulative_df.to_csv(f"{output_dir}/cumulative_returns.csv") # 保存报告 with open(f"{output_dir}/backtest_report.txt", 'w') as f: f.write("="*60 + "\n") f.write("价值投资策略回测报告\n") f.write("="*60 + "\n\n") f.write(f"回测时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n") f.write(f"股票数量: {len(portfolio)}\n") f.write(f"回测周期: 252个交易日\n\n") f.write("业绩指标:\n") f.write("-"*40 + "\n") for key, value in results.items(): if 'return' in key or 'drawdown' in key or 'rate' in key: f.write(f"{key}: {value*100:.2f}%\n") else: f.write(f"{key}: {value:.3f}\n") print(f"\n💾 结果已保存到 {output_dir}/ 目录") def main(): """主函数""" backtest = ValueInvestingBacktest() results, portfolio = backtest.run() return results, portfolio if __name__ == "__main__": main()