optimization_compare.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. 创业板50 T+1 高级优化策略 - 简化版
  5. 聚焦: 移动止损、分批止盈效果验证
  6. """
  7. import pandas as pd
  8. import numpy as np
  9. from datetime import datetime
  10. import warnings
  11. warnings.filterwarnings('ignore')
  12. from cyb50_30min_dual_direction import ConfigManager, IntradayDataFetcher, DualDirectionSignalGenerator, DualDirectionExecutor
  13. from t1_converter import simulate_t1_trades
  14. def load_local_data(csv_file='cyb50_30min_2023_to_20260325.csv'):
  15. df = pd.read_csv(csv_file)
  16. df['DateTime'] = pd.to_datetime(df['DateTime'])
  17. df.set_index('DateTime', inplace=True)
  18. df.sort_index(inplace=True)
  19. if 'Open' not in df.columns and 'o' in df.columns:
  20. df.rename(columns={'o':'Open','h':'High','l':'Low','c':'Close','v':'Volume','a':'Amount'}, inplace=True)
  21. for col in ['Open', 'High', 'Low', 'Close', 'Volume']:
  22. if col in df.columns:
  23. df[col] = pd.to_numeric(df[col], errors='coerce')
  24. df['Returns'] = df['Close'].pct_change()
  25. df.ffill(inplace=True)
  26. df.dropna(inplace=True)
  27. return df
  28. def calculate_indicators(df):
  29. """计算指标"""
  30. # RSI
  31. delta = df['Close'].diff()
  32. gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
  33. loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
  34. rs = gain / loss
  35. df['RSI_14'] = 100 - (100 / (1 + rs))
  36. # 动量
  37. df['Momentum_5'] = (df['Close'] / df['Close'].shift(5) - 1) * 100
  38. # 均线
  39. df['EMA_5'] = df['Close'].ewm(span=5, adjust=False).mean()
  40. df['EMA_20'] = df['Close'].ewm(span=20, adjust=False).mean()
  41. df['Trend_Score'] = 0
  42. df.loc[df['Close'] > df['EMA_5'], 'Trend_Score'] += 1
  43. df.loc[df['Close'] > df['EMA_20'], 'Trend_Score'] += 1
  44. # 添加Close_Open_Pct(原策略需要)
  45. df['Close_Open_Pct'] = (df['Close'] - df['Open']) / df['Open']
  46. df.dropna(inplace=True)
  47. return df
  48. # 加载数据
  49. print("="*60)
  50. print("创业板50 T+1 高级优化策略 - 简化版")
  51. print("="*60)
  52. raw_data = load_local_data('cyb50_30min_2023_to_20260325.csv')
  53. data = calculate_indicators(raw_data)
  54. print(f"\n📊 数据: {len(data)}条K线")
  55. # 获取原策略交易
  56. config_manager = ConfigManager('config.json')
  57. fetcher = IntradayDataFetcher(config_manager)
  58. signal_generator = DualDirectionSignalGenerator()
  59. executor = DualDirectionExecutor(initial_capital=1000000)
  60. data_with_indicators = fetcher.calculate_intraday_indicators(data)
  61. signals_df = signal_generator.generate_dual_direction_signals(data_with_indicators)
  62. results_df, trades_df = executor.execute_dual_direction_trades(signals_df)
  63. long_trades = trades_df[trades_df['交易方向'] == '做多'].copy()
  64. t1_trades = simulate_t1_trades(data_with_indicators, long_trades, 1000000)
  65. print(f"\n📈 原策略交易: {len(t1_trades)}笔")
  66. # 准备数据
  67. t1_trades['开仓时间'] = pd.to_datetime(t1_trades['开仓时间'])
  68. t1_trades['平仓时间'] = pd.to_datetime(t1_trades['平仓时间'])
  69. t1_trades['是否盈利'] = t1_trades['盈亏金额'] > 0
  70. # 计算期间高低点(用于移动止损)
  71. for idx, row in t1_trades.iterrows():
  72. mask = (data.index >= row['开仓时间']) & (data.index <= row['平仓时间'])
  73. if mask.any():
  74. period_data = data.loc[mask]
  75. t1_trades.loc[idx, '期间最高'] = period_data['High'].max()
  76. t1_trades.loc[idx, '期间最低'] = period_data['Low'].min()
  77. else:
  78. t1_trades.loc[idx, '期间最高'] = row['平仓价格']
  79. t1_trades.loc[idx, '期间最低'] = row['平仓价格']
  80. # 策略对比
  81. print("\n" + "="*60)
  82. print("📊 策略对比分析")
  83. print("="*60)
  84. strategies = []
  85. # 策略1: 原策略
  86. original_pnl = t1_trades['盈亏金额'].sum()
  87. original_winrate = (t1_trades['盈亏金额'] > 0).mean() * 100
  88. strategies.append({
  89. '策略': '原策略(止损0.8%止盈2%)',
  90. '交易数': len(t1_trades),
  91. '胜率': f"{original_winrate:.1f}%",
  92. '总盈亏': f"{original_pnl:+.0f}",
  93. '改善': '-'
  94. })
  95. # 策略2: 固定止损0.8%止盈2.5%
  96. def simulate_fixed_sl_tp(trades, sl, tp, position=0.7):
  97. total = 0
  98. for _, row in trades.iterrows():
  99. entry = row['开仓价格']
  100. exit_p = row['平仓价格']
  101. pnl_pct = (exit_p - entry) / entry
  102. if pnl_pct <= -sl:
  103. actual = -sl
  104. elif pnl_pct >= tp:
  105. actual = tp
  106. else:
  107. actual = pnl_pct
  108. total += actual * 1000000 * position
  109. return total
  110. pnl_v1 = simulate_fixed_sl_tp(t1_trades, 0.008, 0.025)
  111. strategies.append({
  112. '策略': '优化V1(固定SL0.8% TP2.5%)',
  113. '交易数': len(t1_trades),
  114. '胜率': f"{original_winrate:.1f}%",
  115. '总盈亏': f"{pnl_v1:+.0f}",
  116. '改善': f"{pnl_v1 - original_pnl:+.0f}"
  117. })
  118. # 策略3: 移动止损
  119. def simulate_trailing_stop(trades, sl, tp, trail_activate, trail_dist, position=0.7):
  120. total = 0
  121. wins = 0
  122. losses = 0
  123. for _, row in trades.iterrows():
  124. entry = row['开仓价格']
  125. exit_p = row['平仓价格']
  126. high = row['期间最高']
  127. pnl_pct = (exit_p - entry) / entry
  128. max_profit_pct = (high - entry) / entry
  129. # 硬止损
  130. if pnl_pct <= -sl:
  131. actual = -sl
  132. losses += 1
  133. # 移动止损激活
  134. elif max_profit_pct >= trail_activate:
  135. trail_stop_price = high * (1 - trail_dist)
  136. trail_stop_pct = (trail_stop_price - entry) / entry
  137. if pnl_pct <= trail_stop_pct:
  138. actual = trail_stop_pct
  139. else:
  140. actual = pnl_pct
  141. if actual > 0:
  142. wins += 1
  143. else:
  144. losses += 1
  145. # 目标止盈
  146. elif pnl_pct >= tp:
  147. actual = tp
  148. wins += 1
  149. else:
  150. actual = pnl_pct
  151. if actual > 0:
  152. wins += 1
  153. else:
  154. losses += 1
  155. total += actual * 1000000 * position
  156. win_rate = wins / (wins + losses) * 100 if (wins + losses) > 0 else 0
  157. return total, win_rate
  158. pnl_v2, wr_v2 = simulate_trailing_stop(t1_trades, 0.008, 0.025, 0.01, 0.005)
  159. strategies.append({
  160. '策略': '优化V2(移动止损)',
  161. '交易数': len(t1_trades),
  162. '胜率': f"{wr_v2:.1f}%",
  163. '总盈亏': f"{pnl_v2:+.0f}",
  164. '改善': f"{pnl_v2 - original_pnl:+.0f}"
  165. })
  166. # 策略4: 分批止盈
  167. def simulate_partial_exit(trades, sl, tp1, tp2, ratio, position=0.7):
  168. total = 0
  169. for _, row in trades.iterrows():
  170. entry = row['开仓价格']
  171. exit_p = row['平仓价格']
  172. high = row['期间最高']
  173. max_profit_pct = (high - entry) / entry
  174. # 第一批止盈
  175. if max_profit_pct >= tp1:
  176. # 假设50%仓位在tp1止盈,剩余按实际或tp2
  177. if max_profit_pct >= tp2:
  178. actual = tp1 * ratio + tp2 * (1 - ratio)
  179. else:
  180. actual_pnl = (exit_p - entry) / entry
  181. actual = tp1 * ratio + actual_pnl * (1 - ratio)
  182. elif (exit_p - entry) / entry <= -sl:
  183. actual = -sl
  184. else:
  185. actual = (exit_p - entry) / entry
  186. total += actual * 1000000 * position
  187. return total
  188. pnl_v3 = simulate_partial_exit(t1_trades, 0.008, 0.015, 0.03, 0.5)
  189. strategies.append({
  190. '策略': '优化V3(分批止盈 1.5%+3%)',
  191. '交易数': len(t1_trades),
  192. '胜率': f"{original_winrate:.1f}%",
  193. '总盈亏': f"{pnl_v3:+.0f}",
  194. '改善': f"{pnl_v3 - original_pnl:+.0f}"
  195. })
  196. # 策略5: 最优组合
  197. def simulate_optimal(trades, position=0.7):
  198. total = 0
  199. for _, row in trades.iterrows():
  200. entry = row['开仓价格']
  201. exit_p = row['平仓价格']
  202. high = row['期间最高']
  203. rsi = 50
  204. # 获取RSI
  205. mask = data.index <= row['开仓时间']
  206. if mask.any():
  207. try:
  208. rsi = data.loc[data.index[mask][-1], 'RSI_14']
  209. except:
  210. pass
  211. # 只在RSI 35-55交易
  212. if not (35 <= rsi <= 55):
  213. continue
  214. pnl_pct = (exit_p - entry) / entry
  215. max_profit_pct = (high - entry) / entry
  216. # 移动止损 + 分批止盈组合
  217. if pnl_pct <= -0.008:
  218. actual = -0.008
  219. elif max_profit_pct >= 0.015:
  220. # 部分止盈
  221. trail_stop = max_profit_pct - 0.005
  222. if pnl_pct <= trail_stop and trail_stop > 0.01:
  223. actual = 0.015 * 0.5 + trail_stop * 0.5
  224. elif pnl_pct >= 0.03:
  225. actual = 0.015 * 0.5 + 0.03 * 0.5
  226. else:
  227. actual = pnl_pct
  228. elif pnl_pct >= 0.025:
  229. actual = 0.025
  230. else:
  231. actual = pnl_pct
  232. total += actual * 1000000 * position
  233. return total
  234. pnl_v4 = simulate_optimal(t1_trades)
  235. # 统计优化V4的交易数
  236. count_v4 = 0
  237. for _, row in t1_trades.iterrows():
  238. mask = data.index <= row['开仓时间']
  239. if mask.any():
  240. try:
  241. rsi = data.loc[data.index[mask][-1], 'RSI_14']
  242. if 35 <= rsi <= 55:
  243. count_v4 += 1
  244. except:
  245. pass
  246. strategies.append({
  247. '策略': '优化V4(RSI35-55+移动+分批)',
  248. '交易数': count_v4,
  249. '胜率': '-',
  250. '总盈亏': f"{pnl_v4:+.0f}",
  251. '改善': f"{pnl_v4 - original_pnl:+.0f}"
  252. })
  253. # 打印结果
  254. results_df = pd.DataFrame(strategies)
  255. print("\n" + results_df.to_string(index=False))
  256. # 最优参数推荐
  257. print("\n" + "="*60)
  258. print("🏆 最优策略推荐")
  259. print("="*60)
  260. best_pnl = max([original_pnl, pnl_v1, pnl_v2, pnl_v3, pnl_v4])
  261. if best_pnl == pnl_v2:
  262. print("【推荐】优化V2: 移动止损策略")
  263. print(" 参数: 止损0.8%, 止盈2.5%, 移动激活1%, 移动距离0.5%")
  264. print(f" 预期收益: {pnl_v2:+.0f}元")
  265. elif best_pnl == pnl_v4:
  266. print("【推荐】优化V4: 综合策略")
  267. print(" 参数: RSI35-55过滤 + 移动止损 + 分批止盈")
  268. print(f" 预期收益: {pnl_v4:+.0f}元")
  269. elif best_pnl == pnl_v3:
  270. print("【推荐】优化V3: 分批止盈策略")
  271. print(" 参数: 第一批1.5%止盈50%, 第二批3%止盈剩余")
  272. print(f" 预期收益: {pnl_v3:+.0f}元")
  273. else:
  274. print("【推荐】优化V1: 固定止盈2.5%")
  275. print(f" 预期收益: {pnl_v1:+.0f}元")
  276. print("\n" + "="*60)
  277. print("✅ 分析完成")
  278. print("="*60)