| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- 深入诊断 - 检查卖出逻辑和移动止损问题
- """
- import pandas as pd
- import numpy as np
- import sys
- sys.path.insert(0, '/root/.openclaw/workspace/quant')
- # 加载数据
- df = pd.read_csv('/root/.openclaw/workspace/quant/cyb50_baostock.csv')
- df['date'] = pd.to_datetime(df['date'])
- df = df.set_index('date').sort_index()
- for col in ['open', 'high', 'low', 'close', 'volume']:
- df[col] = pd.to_numeric(df[col], errors='coerce')
- # 计算指标
- df['ma10'] = df['close'].rolling(window=10).mean()
- df['ma30'] = df['close'].rolling(window=30).mean()
- df['high_20'] = df['high'].rolling(window=20).max()
- df['low_20'] = df['low'].rolling(window=20).min()
- df['ret_10'] = df['close'].pct_change(periods=10)
- # 买入条件
- buy_cond = (
- (df['close'] > df['ma10']) &
- (df['ma10'] > df['ma30']) &
- (df['close'] >= df['high_20'] * 0.995) &
- (df['ret_10'] > 0.02)
- )
- # 卖出条件1: 跌破MA30
- sell_cond1 = df['close'] < df['ma30']
- # 卖出条件2: 创20日新低
- sell_cond2 = df['close'] <= df['low_20'] * 1.005
- print("="*60)
- print("🔍 卖出条件分析")
- print("="*60)
- print(f"\n卖出条件1 (跌破MA30): {sell_cond1.sum()} 天")
- print(f"卖出条件2 (创20日新低): {sell_cond2.sum()} 天")
- print(f"任一条件触发: {(sell_cond1 | sell_cond2).sum()} 天")
- # 检查卖出条件1和2的重叠
- both_sell = sell_cond1 & sell_cond2
- print(f"两个条件同时触发: {both_sell.sum()} 天")
- # 模拟交易,详细检查每次卖出原因
- print("\n📈 详细交易分析:")
- df['signal'] = 0
- df.loc[buy_cond, 'signal'] = 1
- df.loc[sell_cond1 | sell_cond2, 'signal'] = -1
- position = 0
- entry_price = 0
- peak_price = 0
- capital = 1000000
- trades = []
- for i in range(30, len(df)):
- date = df.index[i]
- price = df['close'].iloc[i]
- signal = df['signal'].iloc[i]
-
- # 检查各种卖出原因
- sell_ma30 = price < df['ma30'].iloc[i]
- sell_low20 = price <= df['low_20'].iloc[i] * 1.005
-
- # 移动止损检查
- stop_loss_triggered = False
- stop_loss_price = None
- if position > 0:
- if price > peak_price:
- peak_price = price
- stop_loss_price = peak_price * 0.90
- if price < stop_loss_price:
- signal = -1
- stop_loss_triggered = True
-
- # 买入
- if signal == 1 and position == 0:
- position = 1
- entry_price = price
- peak_price = price
- trades.append({
- 'date': date,
- 'action': 'BUY',
- 'price': price,
- 'capital': capital
- })
-
- # 卖出
- elif signal == -1 and position == 1:
- pnl = (price / entry_price - 1) * capital
- capital += pnl
-
- hold_days = (date - trades[-1]['date']).days
-
- exit_reasons = []
- if stop_loss_triggered:
- exit_reasons.append(f"移动止损({peak_price:.2f}→{stop_loss_price:.2f})")
- if sell_ma30:
- exit_reasons.append("跌破MA30")
- if sell_low20:
- exit_reasons.append("创20日新低")
-
- trades.append({
- 'date': date,
- 'action': 'SELL',
- 'price': price,
- 'capital': capital,
- 'pnl': pnl,
- 'return_pct': (price / entry_price - 1) * 100,
- 'reasons': ' + '.join(exit_reasons),
- 'hold_days': hold_days
- })
-
- position = 0
- # 显示最近10次卖出的详细原因
- print("\n最近10次卖出详情:")
- sell_trades = [t for t in trades if t['action'] == 'SELL']
- for t in sell_trades[-10:]:
- print(f" {t['date'].strftime('%Y-%m-%d')}: {t['return_pct']:+.2f}% ({t['hold_days']}天)")
- print(f" 原因: {t['reasons']}")
- # 统计各卖出原因的占比
- print("\n📊 卖出原因统计:")
- reasons_count = {}
- for t in sell_trades:
- for reason in t['reasons'].split(' + '):
- reasons_count[reason] = reasons_count.get(reason, 0) + 1
- for reason, count in sorted(reasons_count.items(), key=lambda x: x[1], reverse=True):
- print(f" {reason}: {count}次 ({count/len(sell_trades)*100:.1f}%)")
- print("\n" + "="*60)
- # 检查移动止损的触发情况
- print("\n📉 移动止损检查:")
- stop_loss_trades = [t for t in sell_trades if '移动止损' in t['reasons']]
- print(f" 移动止损触发次数: {len(stop_loss_trades)}")
- if stop_loss_trades:
- avg_return = np.mean([t['return_pct'] for t in stop_loss_trades])
- print(f" 移动止损平均收益: {avg_return:.2f}%")
-
- print("\n 最近5次移动止损:")
- for t in stop_loss_trades[-5:]:
- print(f" {t['date'].strftime('%Y-%m-%d')}: {t['return_pct']:+.2f}%")
|