optimize_params_simple.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. 趋势质量评估器 - 参数优化测试 (简化版)
  5. 测试不同参数组合的回测表现
  6. """
  7. import sys
  8. sys.path.insert(0, '/root/.openclaw/workspace/trend-quality-evaluator')
  9. import numpy as np
  10. import pandas as pd
  11. from trend_quality_evaluator import fetch_stock_data
  12. import warnings
  13. warnings.filterwarnings('ignore')
  14. print("="*70)
  15. print("趋势质量评估器 - 参数优化测试")
  16. print("="*70)
  17. # 获取数据
  18. df = fetch_stock_data("399673", "2019-01-01", "2026-03-06", "d")
  19. if df is None:
  20. print("数据获取失败")
  21. exit(1)
  22. print(f"\n✓ 数据获取成功: {len(df)}条")
  23. # 预计算指标
  24. def calc_indicators(data):
  25. d = data.copy()
  26. high, low, close = d['high'], d['low'], d['close']
  27. # ADX
  28. plus_dm = high.diff().where(high.diff() > 0, 0)
  29. minus_dm = low.diff().abs().where(low.diff().abs() > 0, 0)
  30. tr = pd.concat([high-low, (high-close.shift()).abs(), (low-close.shift()).abs()], axis=1).max(axis=1)
  31. atr = tr.rolling(14).mean()
  32. dx = (plus_dm.rolling(14).mean() / atr * 100).abs()
  33. d['adx'] = dx.rolling(14).mean()
  34. # MA斜率
  35. d['ma20'] = d['close'].rolling(20).mean()
  36. d['ma_slope'] = d['ma20'] / d['ma20'].shift(5)
  37. # ATR比率
  38. d['atr_ratio'] = tr.rolling(14).mean() / tr.rolling(50).mean()
  39. # 成交量
  40. d['vol_ratio'] = d['volume'] / d['volume'].rolling(20).mean()
  41. d['above_ma20'] = d['close'] > d['ma20']
  42. return d
  43. data = calc_indicators(df)
  44. # 测试的参数组合 (简化版)
  45. test_configs = [
  46. # 配置1: 原配置
  47. {'name': '原配置', 'adx_t': 25, 'adx_w': 30, 'ma_t': 1.002, 'ma_w': 25, 'vol_t': 0.8, 'vol_w': 20, 'volu_t': 1.5, 'volu_w': 10},
  48. # 配置2: 提高ADX权重
  49. {'name': '高ADX权重', 'adx_t': 25, 'adx_w': 35, 'ma_t': 1.002, 'ma_w': 20, 'vol_t': 0.8, 'vol_w': 20, 'volu_t': 1.5, 'volu_w': 10},
  50. # 配置3: 降低ADX阈值
  51. {'name': '低ADX阈值', 'adx_t': 20, 'adx_w': 30, 'ma_t': 1.002, 'ma_w': 25, 'vol_t': 0.8, 'vol_w': 20, 'volu_t': 1.5, 'volu_w': 10},
  52. # 配置4: 提高MA权重
  53. {'name': '高MA权重', 'adx_t': 25, 'adx_w': 25, 'ma_t': 1.002, 'ma_w': 30, 'vol_t': 0.8, 'vol_w': 20, 'volu_t': 1.5, 'volu_w': 10},
  54. # 配置5: 更严格成交量
  55. {'name': '严格成交量', 'adx_t': 25, 'adx_w': 30, 'ma_t': 1.002, 'ma_w': 25, 'vol_t': 0.8, 'vol_w': 15, 'volu_t': 2.0, 'volu_w': 15},
  56. # 配置6: 宽松波动率
  57. {'name': '宽松波动率', 'adx_t': 25, 'adx_w': 30, 'ma_t': 1.002, 'ma_w': 25, 'vol_t': 0.9, 'vol_w': 20, 'volu_t': 1.5, 'volu_w': 10},
  58. # 配置7: 综合优化1
  59. {'name': '综合优化1', 'adx_t': 22, 'adx_w': 32, 'ma_t': 1.001, 'ma_w': 28, 'vol_t': 0.85, 'vol_w': 18, 'volu_t': 1.8, 'volu_w': 12},
  60. # 配置8: 综合优化2
  61. {'name': '综合优化2', 'adx_t': 20, 'adx_w': 35, 'ma_t': 1.003, 'ma_w': 25, 'vol_t': 0.8, 'vol_w': 15, 'volu_t': 2.0, 'volu_w': 10},
  62. ]
  63. results = []
  64. for cfg in test_configs:
  65. print(f"\n测试: {cfg['name']}...")
  66. scores = []
  67. for i in range(60, len(data)):
  68. row = data.iloc[i]
  69. # 计算各因子得分
  70. adx_s = cfg['adx_w'] if row['adx'] >= cfg['adx_t'] else cfg['adx_w'] * (row['adx'] / cfg['adx_t'])
  71. if row['ma_slope'] >= cfg['ma_t'] * 1.5:
  72. ma_s = cfg['ma_w']
  73. elif row['ma_slope'] >= cfg['ma_t']:
  74. ma_s = cfg['ma_w'] * 0.7
  75. elif row['ma_slope'] >= 1.0:
  76. ma_s = cfg['ma_w'] * 0.3
  77. else:
  78. ma_s = 0
  79. if row['atr_ratio'] <= cfg['vol_t'] * 0.75:
  80. vol_s = cfg['vol_w']
  81. elif row['atr_ratio'] <= cfg['vol_t']:
  82. vol_s = cfg['vol_w'] * 0.7
  83. elif row['atr_ratio'] <= 1.0:
  84. vol_s = cfg['vol_w'] * 0.3
  85. else:
  86. vol_s = 0
  87. if row['vol_ratio'] >= cfg['volu_t'] * 1.3:
  88. volu_s = cfg['volu_w']
  89. elif row['vol_ratio'] >= cfg['volu_t']:
  90. volu_s = cfg['volu_w'] * 0.7
  91. elif row['vol_ratio'] >= 1.0:
  92. volu_s = cfg['volu_w'] * 0.3
  93. else:
  94. volu_s = 0
  95. tf_s = 15 if row['above_ma20'] else 0
  96. total = adx_s + ma_s + vol_s + volu_s + tf_s
  97. is_trade = total >= 60
  98. scores.append({
  99. 'date': data.index[i],
  100. 'close': row['close'],
  101. 'score': total,
  102. 'is_trade': is_trade,
  103. 'adx_s': adx_s, 'ma_s': ma_s, 'vol_s': vol_s, 'volu_s': volu_s, 'tf_s': tf_s
  104. })
  105. scores_df = pd.DataFrame(scores).set_index('date')
  106. scores_df['ret_20d'] = scores_df['close'].pct_change(20).shift(-20) * 100
  107. t_mask = scores_df['is_trade']
  108. trade_days = t_mask.sum()
  109. if trade_days > 0:
  110. ret_20d = scores_df[t_mask]['ret_20d'].dropna()
  111. result = {
  112. 'name': cfg['name'],
  113. 'adx_t': cfg['adx_t'], 'adx_w': cfg['adx_w'],
  114. 'ma_t': cfg['ma_t'], 'ma_w': cfg['ma_w'],
  115. 'vol_t': cfg['vol_t'], 'vol_w': cfg['vol_w'],
  116. 'volu_t': cfg['volu_t'], 'volu_w': cfg['volu_w'],
  117. 'trade_pct': trade_days / len(scores_df) * 100,
  118. 'avg_score': scores_df['score'].mean(),
  119. 'ret_20d': ret_20d.mean() if len(ret_20d) > 0 else 0,
  120. 'win_rate': (ret_20d > 0).mean() * 100 if len(ret_20d) > 0 else 0,
  121. 'sharpe': ret_20d.mean() / ret_20d.std() if len(ret_20d) > 0 and ret_20d.std() > 0 else 0,
  122. }
  123. results.append(result)
  124. print(f" 可交易: {result['trade_pct']:.1f}%, 20日收益: {result['ret_20d']:+.2f}%, 胜率: {result['win_rate']:.1f}%")
  125. # 排序结果
  126. print("\n" + "="*70)
  127. print("参数优化结果排名")
  128. print("="*70)
  129. # 按20日收益排序
  130. results_by_return = sorted(results, key=lambda x: x['ret_20d'], reverse=True)
  131. print("\n【按20日收益排序】")
  132. print(f"{'排名':<4} {'配置名称':<12} {'可交易%':<10} {'20日收益':<12} {'胜率':<10} {'夏普':<8}")
  133. print("-"*70)
  134. for i, r in enumerate(results_by_return[:5]):
  135. print(f"{i+1:<4} {r['name']:<12} {r['trade_pct']:>8.1f}% {r['ret_20d']:>+10.2f}% {r['win_rate']:>8.1f}% {r['sharpe']:>6.2f}")
  136. # 按胜率排序
  137. results_by_winrate = sorted(results, key=lambda x: x['win_rate'], reverse=True)
  138. print("\n【按胜率排序】")
  139. print(f"{'排名':<4} {'配置名称':<12} {'可交易%':<10} {'20日收益':<12} {'胜率':<10} {'夏普':<8}")
  140. print("-"*70)
  141. for i, r in enumerate(results_by_winrate[:5]):
  142. print(f"{i+1:<4} {r['name']:<12} {r['trade_pct']:>8.1f}% {r['ret_20d']:>+10.2f}% {r['win_rate']:>8.1f}% {r['sharpe']:>6.2f}")
  143. # 综合最佳
  144. print("\n【综合推荐配置】")
  145. best = results_by_return[0]
  146. print(f"配置名称: {best['name']}")
  147. print(f"ADX阈值: {best['adx_t']}, 权重: {best['adx_w']}")
  148. print(f"MA斜率阈值: {best['ma_t']}, 权重: {best['ma_w']}")
  149. print(f"波动率阈值: {best['vol_t']}, 权重: {best['vol_w']}")
  150. print(f"成交量阈值: {best['volu_t']}, 权重: {best['volu_w']}")
  151. print(f"\n绩效:")
  152. print(f" 可交易比例: {best['trade_pct']:.1f}%")
  153. print(f" 20日平均收益: {best['ret_20d']:+.2f}%")
  154. print(f" 胜率: {best['win_rate']:.1f}%")
  155. print(f" 夏普比率: {best['sharpe']:.2f}")
  156. # 保存结果
  157. results_df = pd.DataFrame(results)
  158. results_df = results_df.sort_values('ret_20d', ascending=False)
  159. results_df.to_csv('/root/.openclaw/workspace/trend-quality-evaluator/param_optimization_results.csv', index=False)
  160. print("\n✓ 结果已保存: param_optimization_results.csv")
  161. print("\n" + "="*70)
  162. print("参数优化测试完成!")
  163. print("="*70)