Explorar el Código

refactor: 将trend-max-daily.py移至专用目录

- 新建 trend-max-daily/ 目录
- 移动 trend-max-daily.py 到新目录
- 更新定时任务路径

目录结构优化:
- trend-max-daily/trend-max-daily.py
openclaw hace 2 meses
padre
commit
0b3ca35a9c
Se han modificado 35 ficheros con 11197 adiciones y 10 borrados
  1. BIN
      cat-fly/__pycache__/trend_report_fixed.cpython-312.pyc
  2. BIN
      cat-fly/__pycache__/trend_report_multi.cpython-312.pyc
  3. 67 0
      cat-fly/backup.sh
  4. 56 0
      cat-fly/check_trades.py
  5. 62 0
      cat-fly/cron_jobs.json
  6. 70 0
      cat-fly/diagnose_report.py
  7. 155 0
      cat-fly/diagnose_sell_logic.py
  8. 179 0
      cat-fly/diagnose_strategy.py
  9. 20 0
      cat-fly/run_report.sh
  10. 6 0
      cat-fly/run_report_fixed.sh
  11. 452 0
      cat-fly/trend_report.py
  12. 734 0
      cat-fly/trend_report_fixed.py
  13. 673 0
      cat-fly/trend_report_multi.py
  14. 819 0
      cat-fly/trend_report_multi_source.py
  15. 528 0
      cat-fly/trend_report_v2.py
  16. 76 0
      kalman-filter/kalman_daily_signals.csv
  17. BIN
      kalman-filter/kalman_filter_analysis.png
  18. 54 0
      kalman-filter/test_extract.py
  19. BIN
      market-regime-identifier/__pycache__/cyb50_market_classifier.cpython-312.pyc
  20. BIN
      market-regime-identifier/__pycache__/market_regime_hmm.cpython-312.pyc
  21. 188 0
      market-regime-identifier/hmm_diagnosis.py
  22. 665 0
      market-regime-identifier/last_60_days_report.html
  23. 15 10
      market-regime-identifier/market_regime_hmm.py
  24. BIN
      openclaw-backup-20260306.tar.gz
  25. 67 0
      quant/quant_report_20260306_1133.txt
  26. 819 0
      quant/trend_tracking_strategy.py
  27. 0 0
      trend-max-daily/trend-max-daily.py
  28. BIN
      trend-mix/__pycache__/trend_mix_strategy.cpython-312.pyc
  29. BIN
      trend-quality-evaluator/__pycache__/trend_quality_evaluator.cpython-312.pyc
  30. 215 0
      trend-quality-evaluator/backtest_report.py
  31. 2166 0
      trend-quality-evaluator/backtest_results.csv
  32. 2166 0
      trend-quality-evaluator/best_config_backtest.csv
  33. 568 0
      trend-quality-evaluator/optimization_results.csv
  34. 368 0
      trend-quality-evaluator/optimize_parameters.py
  35. 9 0
      trend-quality-evaluator/param_optimization_results.csv

BIN
cat-fly/__pycache__/trend_report_fixed.cpython-312.pyc


BIN
cat-fly/__pycache__/trend_report_multi.cpython-312.pyc


+ 67 - 0
cat-fly/backup.sh

@@ -0,0 +1,67 @@
+#!/bin/bash
+# Cat-Fly 自动备份脚本
+# 每天凌晨4点执行,备份到 Git 仓库
+
+BACKUP_DIR="/tmp/cat-fly-backup-$(date +%Y%m%d)"
+SOURCE_DIR="/root/.openclaw/workspace/cat-fly"
+REPO_URL="http://openclaw:asdasd9981@code.erwin.wang/openclaw/openclaw-backup.git"
+LOG_FILE="/var/log/catfly-backup.log"
+
+# 日志函数
+log() {
+    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
+}
+
+log "开始备份..."
+
+# 创建临时目录
+rm -rf "$BACKUP_DIR"
+mkdir -p "$BACKUP_DIR"
+
+# 复制核心文件
+cp "$SOURCE_DIR/auto_report.py" "$BACKUP_DIR/"
+cp "$SOURCE_DIR/cyb50_30min_dual_direction.py" "$BACKUP_DIR/"
+cp "$SOURCE_DIR/config.json" "$BACKUP_DIR/"
+cp "$SOURCE_DIR/cron_jobs.json" "$BACKUP_DIR/"
+cp "$SOURCE_DIR/README.md" "$BACKUP_DIR/"
+
+# 添加备份信息
+echo "Backup Date: $(date '+%Y-%m-%d %H:%M:%S')" > "$BACKUP_DIR/BACKUP_INFO.txt"
+echo "Source: $SOURCE_DIR" >> "$BACKUP_DIR/BACKUP_INFO.txt"
+
+# 克隆仓库并更新
+cd /tmp
+rm -rf openclaw-backup-temp
+if ! git clone "$REPO_URL" openclaw-backup-temp 2>/dev/null; then
+    log "错误: 无法克隆仓库"
+    exit 1
+fi
+
+# 复制新文件到仓库
+cd openclaw-backup-temp
+rm -rf cat-fly/*
+cp -r "$BACKUP_DIR"/* cat-fly/ 2>/dev/null || cp "$BACKUP_DIR"/* cat-fly/ 2>/dev/null
+
+# Git 配置
+git config user.email "backup@openclaw.local"
+git config user.name "Auto Backup"
+
+# 提交并推送
+git add -A
+if git diff --cached --quiet; then
+    log "没有变更,跳过提交"
+else
+    git commit -m "Auto backup $(date '+%Y-%m-%d %H:%M:%S')"
+    if git push origin master; then
+        log "备份成功推送到仓库"
+    else
+        log "错误: 推送失败"
+        exit 1
+    fi
+fi
+
+# 清理
+rm -rf "$BACKUP_DIR"
+rm -rf /tmp/openclaw-backup-temp
+
+log "备份完成"

+ 56 - 0
cat-fly/check_trades.py

@@ -0,0 +1,56 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+检查交易明细准确性
+"""
+
+import pandas as pd
+import sys
+sys.path.insert(0, '/root/.openclaw/workspace/cat-fly')
+
+from trend_report_multi import TrendTrackingStrategy
+
+strategy = TrendTrackingStrategy()
+strategy.load_and_merge_data()
+strategy.calculate_indicators()
+result = strategy.backtest()
+
+print("="*60)
+print("📋 交易明细核对")
+print("="*60)
+
+print(f"\n总交易记录数: {len(result['trades'])}")
+print(f"买入次数: {len([t for t in result['trades'] if t['action'] == 'BUY'])}")
+print(f"卖出次数: {len([t for t in result['trades'] if t['action'] == 'SELL'])}")
+
+print("\n" + "-"*60)
+print("最近20条交易记录:")
+print("-"*60)
+
+for i, trade in enumerate(result['trades'][-20:], 1):
+    date_str = trade['date'].strftime('%Y-%m-%d') if hasattr(trade['date'], 'strftime') else str(trade['date'])
+    if trade['action'] == 'BUY':
+        print(f"{i:2d}. {date_str} BUY  @ {trade['price']:8.2f}  资产: {trade['capital']:12,.0f}")
+    else:
+        pnl = trade.get('pnl', 0)
+        ret = trade.get('return_pct', 0)
+        print(f"{i:2d}. {date_str} SELL @ {trade['price']:8.2f}  盈亏: {ret:+6.2f}%  资产: {trade['capital']:12,.0f}")
+
+# 检查是否有同一天买卖的情况
+print("\n" + "-"*60)
+print("检查异常交易:")
+print("-"*60)
+
+for i in range(len(result['trades']) - 1):
+    t1 = result['trades'][i]
+    t2 = result['trades'][i+1]
+    
+    if t1['action'] == 'BUY' and t2['action'] == 'SELL':
+        hold_days = (t2['date'] - t1['date']).days
+        if hold_days < 0:
+            print(f"❌ 日期错误: 卖出日期早于买入日期!")
+            print(f"   买入: {t1['date']}, 卖出: {t2['date']}")
+        elif hold_days == 0:
+            print(f"⚠️  T+0交易: {t1['date'].strftime('%Y-%m-%d')}")
+
+print("\n检查完成!")

+ 62 - 0
cat-fly/cron_jobs.json

@@ -0,0 +1,62 @@
+[
+  {
+    "id": "c5adbeeb-65a4-45e2-81ef-433ce8020b4f",
+    "name": "catfly-morning-930",
+    "schedule": {"expr": "30 9 * * 1-5", "tz": "Asia/Shanghai"},
+    "payload": {"text": "执行创业板50自动交易报告系统(9:30)"}
+  },
+  {
+    "id": "ff236e01-f316-4369-9ca5-55503dae9abe",
+    "name": "catfly-morning-1000",
+    "schedule": {"expr": "0 10 * * 1-5", "tz": "Asia/Shanghai"},
+    "payload": {"text": "执行创业板50自动交易报告系统(10:00)"}
+  },
+  {
+    "id": "a8fb0378-6667-4f61-aab4-214617517be7",
+    "name": "catfly-morning-1030",
+    "schedule": {"expr": "30 10 * * 1-5", "tz": "Asia/Shanghai"},
+    "payload": {"text": "执行创业板50自动交易报告系统(10:30)"}
+  },
+  {
+    "id": "227acd1b-4924-429d-b6bf-8b4ecb2e60c0",
+    "name": "catfly-morning-1100",
+    "schedule": {"expr": "0 11 * * 1-5", "tz": "Asia/Shanghai"},
+    "payload": {"text": "执行创业板50自动交易报告系统(11:00)"}
+  },
+  {
+    "id": "af4963cf-fd52-4e81-83e2-fa49f3b4b69e",
+    "name": "catfly-morning-1130",
+    "schedule": {"expr": "30 11 * * 1-5", "tz": "Asia/Shanghai"},
+    "payload": {"text": "执行创业板50自动交易报告系统(11:30)"}
+  },
+  {
+    "id": "f6346777-2be0-4960-98b3-2cb924241a93",
+    "name": "catfly-afternoon-1300",
+    "schedule": {"expr": "0 13 * * 1-5", "tz": "Asia/Shanghai"},
+    "payload": {"text": "执行创业板50自动交易报告系统(13:00)"}
+  },
+  {
+    "id": "4b119356-fb84-436d-9371-9050b88ebeee",
+    "name": "catfly-afternoon-1330",
+    "schedule": {"expr": "30 13 * * 1-5", "tz": "Asia/Shanghai"},
+    "payload": {"text": "执行创业板50自动交易报告系统(13:30)"}
+  },
+  {
+    "id": "fecfb54b-62b7-489d-bfbf-5c074a0b3278",
+    "name": "catfly-afternoon-1400",
+    "schedule": {"expr": "0 14 * * 1-5", "tz": "Asia/Shanghai"},
+    "payload": {"text": "执行创业板50自动交易报告系统(14:00)"}
+  },
+  {
+    "id": "de969866-e2c5-4110-ad43-6f95b577f150",
+    "name": "catfly-afternoon-1430",
+    "schedule": {"expr": "30 14 * * 1-5", "tz": "Asia/Shanghai"},
+    "payload": {"text": "执行创业板50自动交易报告系统(14:30)"}
+  },
+  {
+    "id": "f7925c43-23ae-459a-849c-898787a6e0a7",
+    "name": "catfly-afternoon-1450",
+    "schedule": {"expr": "50 14 * * 1-5", "tz": "Asia/Shanghai"},
+    "payload": {"text": "执行创业板50自动交易报告系统(14:50收盘)"}
+  }
+]

+ 70 - 0
cat-fly/diagnose_report.py

@@ -0,0 +1,70 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+诊断报告问题
+"""
+
+import sys
+sys.path.insert(0, '/root/.openclaw/workspace/cat-fly')
+sys.path.insert(0, '/root/.openclaw/workspace/quant')
+
+from trend_report_fixed import TrendTrackingStrategy
+
+strategy = TrendTrackingStrategy()
+strategy.load_and_merge_data()
+strategy.calculate_indicators()
+result = strategy.backtest()
+
+trades = result['trades']
+
+print('='*70)
+print('交易记录诊断')
+print('='*70)
+
+print(f"\n总交易记录数: {len(trades)}")
+print(f"第一条交易: {trades[0]['date'].strftime('%Y-%m-%d')} {trades[0]['action']}")
+print(f"最后一条交易: {trades[-1]['date'].strftime('%Y-%m-%d')} {trades[-1]['action']}")
+
+print("\n前5条交易:")
+for i, t in enumerate(trades[:5], 1):
+    print(f"{i}. {t['date'].strftime('%Y-%m-%d')} {t['action']}")
+
+print("\n后5条交易:")
+for i, t in enumerate(trades[-5:], len(trades)-4):
+    print(f"{i}. {t['date'].strftime('%Y-%m-%d')} {t['action']}")
+
+print("\n" + "="*70)
+print('检查 get_recent_trades(20) 返回的内容:')
+print("="*70)
+
+recent = strategy.get_recent_trades(20)
+for i, t in enumerate(recent, 1):
+    date_str = t['date'].strftime('%Y-%m-%d')
+    action = t['action']
+    price = t['price']
+    if action == 'SELL':
+        ret = t.get('return_pct', 0)
+        print(f"{i:2d}. {date_str} {action:4s} @ {price:8.2f} ({ret:+.2f}%)")
+    else:
+        print(f"{i:2d}. {date_str} {action:4s} @ {price:8.2f}")
+
+print("\n" + "="*70)
+print('配对检查 - 最近10对交易:')
+print("="*70)
+
+# 从 recent 中配对
+pair_count = 0
+i = 0
+while i < len(recent) - 1:
+    if recent[i]['action'] == 'BUY' and recent[i+1]['action'] == 'SELL':
+        pair_count += 1
+        buy = recent[i]
+        sell = recent[i+1]
+        hold_days = (sell['date'] - buy['date']).days
+        ret = sell.get('return_pct', 0)
+        print(f"{pair_count}. 买 {buy['date'].strftime('%Y-%m-%d')} → 卖 {sell['date'].strftime('%Y-%m-%d')} | {ret:+.2f}% | {hold_days}天")
+        i += 2
+    else:
+        i += 1
+
+print(f"\n找到 {pair_count} 对完整交易")

+ 155 - 0
cat-fly/diagnose_sell_logic.py

@@ -0,0 +1,155 @@
+#!/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}%")

+ 179 - 0
cat-fly/diagnose_strategy.py

@@ -0,0 +1,179 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+诊断脚本 - 检查交易策略的bug
+"""
+
+import pandas as pd
+import numpy as np
+import sys
+sys.path.insert(0, '/root/.openclaw/workspace/cat-fly')
+sys.path.insert(0, '/root/.openclaw/workspace/quant')
+
+def diagnose_strategy():
+    """诊断策略问题"""
+    print("="*60)
+    print("🔍 策略诊断报告")
+    print("="*60)
+    
+    # 加载数据
+    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)
+    )
+    
+    # 卖出条件
+    sell_cond = (
+        (df['close'] < df['ma30']) | 
+        (df['close'] <= df['low_20'] * 1.005)
+    )
+    
+    print("\n📊 信号统计:")
+    print(f"  买入信号天数: {buy_cond.sum()}")
+    print(f"  卖出信号天数: {sell_cond.sum()}")
+    
+    # 检查同一天买卖冲突
+    both_cond = buy_cond & sell_cond
+    print(f"  ⚠️ 同一天买卖冲突: {both_cond.sum()} 天")
+    
+    if both_cond.sum() > 0:
+        print("\n  冲突日期示例:")
+        for date in df[both_cond].index[:5]:
+            print(f"    {date.date()}: 买={buy_cond.loc[date]}, 卖={sell_cond.loc[date]}")
+    
+    # 模拟回测,检查交易
+    print("\n📈 交易明细检查:")
+    
+    df['signal'] = 0
+    df.loc[buy_cond, 'signal'] = 1
+    df.loc[sell_cond, 'signal'] = -1
+    
+    position = 0
+    entry_price = 0
+    peak_price = 0
+    capital = 1000000
+    trades = []
+    issues = []
+    
+    for i in range(30, len(df)):
+        date = df.index[i]
+        price = df['close'].iloc[i]
+        signal = df['signal'].iloc[i]
+        
+        # 检查移动止损
+        stop_loss_triggered = False
+        if position > 0:
+            if price > peak_price:
+                peak_price = price
+            if price < peak_price * 0.90:
+                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,
+                'stop_loss': peak_price * 0.90
+            })
+        
+        # 卖出
+        elif signal == -1 and position == 1:
+            pnl = (price / entry_price - 1) * capital
+            capital += pnl
+            
+            exit_reason = '止损' if stop_loss_triggered else '信号'
+            hold_days = (date - trades[-1]['date']).days if trades else 0
+            
+            trades.append({
+                'date': date,
+                'action': 'SELL',
+                'price': price,
+                'capital': capital,
+                'pnl': pnl,
+                'return_pct': (price / entry_price - 1) * 100,
+                'reason': exit_reason,
+                'hold_days': hold_days
+            })
+            
+            # 检查问题
+            if hold_days == 0:
+                issues.append(f"⚠️ {date.date()}: 同日买卖 (T+0交易)")
+            elif hold_days == 1:
+                issues.append(f"⚠️ {date.date()}: 隔日交易 (T+1卖出)")
+            
+            position = 0
+    
+    print(f"\n  总交易次数: {len([t for t in trades if t['action'] == 'SELL'])}")
+    print(f"  发现问题: {len(issues)}")
+    
+    if issues:
+        print("\n  问题列表:")
+        for issue in issues[:10]:
+            print(f"    {issue}")
+    
+    # 检查连续信号
+    print("\n🔍 连续信号检查:")
+    signal_changes = df['signal'].diff().abs()
+    consecutive_days = 0
+    max_consecutive = 0
+    
+    for i in range(30, len(df)):
+        if df['signal'].iloc[i] == 1:
+            consecutive_days += 1
+            max_consecutive = max(max_consecutive, consecutive_days)
+        else:
+            consecutive_days = 0
+    
+    print(f"  最大连续买入信号: {max_consecutive} 天")
+    
+    # 显示最近5次交易
+    print("\n📋 最近5次完整交易:")
+    complete_trades = []
+    for i in range(0, len(trades)-1, 2):
+        if i+1 < len(trades):
+            buy = trades[i]
+            sell = trades[i+1]
+            complete_trades.append({
+                'entry': buy['date'].strftime('%Y-%m-%d'),
+                'exit': sell['date'].strftime('%Y-%m-%d'),
+                'entry_price': buy['price'],
+                'exit_price': sell['price'],
+                'return': sell['return_pct'],
+                'hold_days': sell['hold_days']
+            })
+    
+    for t in complete_trades[-5:]:
+        print(f"  买入: {t['entry']} @ {t['entry_price']:.2f}")
+        print(f"  卖出: {t['exit']} @ {t['exit_price']:.2f}")
+        print(f"  收益: {t['return']:+.2f}%, 持仓: {t['hold_days']}天")
+        print()
+    
+    print("="*60)
+    print(f"最终资产: {capital:,.0f}元, 收益率: {(capital/1000000-1)*100:+.2f}%")
+    print("="*60)
+
+if __name__ == "__main__":
+    diagnose_strategy()

+ 20 - 0
cat-fly/run_report.sh

@@ -0,0 +1,20 @@
+#!/bin/bash
+# Cat-Fly 自动交易报告 - 直接执行脚本
+# 通过系统 cron 执行,不经过 OpenClaw agent
+
+LOG_FILE="/var/log/catfly-report.log"
+SCRIPT_DIR="/root/.openclaw/workspace/cat-fly"
+
+cd "$SCRIPT_DIR" || exit 1
+
+echo "[$(date '+%Y-%m-%d %H:%M:%S')] 开始执行报告生成..." >> "$LOG_FILE"
+
+python3 auto_report.py >> "$LOG_FILE" 2>&1
+
+if [ $? -eq 0 ]; then
+    echo "[$(date '+%Y-%m-%d %H:%M:%S')] 报告生成成功" >> "$LOG_FILE"
+else
+    echo "[$(date '+%Y-%m-%d %H:%M:%S')] 报告生成失败" >> "$LOG_FILE"
+fi
+
+echo "----------------------------------------" >> "$LOG_FILE"

+ 6 - 0
cat-fly/run_report_fixed.sh

@@ -0,0 +1,6 @@
+#!/bin/bash
+# Cat-Fly 趋势跟踪策略 - 多数据源实时报告 (修正版)
+# 已修复:交易费用计算、卖出原因记录、信号冲突处理
+
+cd /root/.openclaw/workspace/cat-fly
+python3 trend_report_fixed.py >> /var/log/catfly-report.log 2>&1

+ 452 - 0
cat-fly/trend_report.py

@@ -0,0 +1,452 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+创业板50指数 - 实时交易报告系统
+基于趋势跟踪策略,生成当前时点报告
+"""
+
+import sys
+sys.path.insert(0, '/root/.openclaw/workspace/cat-fly')
+
+import pandas as pd
+import numpy as np
+from datetime import datetime, timedelta
+import smtplib
+import ssl
+from email.mime.text import MIMEText
+from email.mime.multipart import MIMEMultipart
+from email.header import Header
+import warnings
+warnings.filterwarnings('ignore')
+
+# ==================== 邮件配置 ====================
+EMAIL_CONFIG = {
+    "smtp_server": "localhost",
+    "smtp_port": 25,
+    "sender_email": "catfly@openclaw.local",
+    "receiver_email": "380880504@qq.com"
+}
+
+# ==================== 趋势跟踪策略 ====================
+class TrendTrackingStrategy:
+    """趋势跟踪策略 - 实时计算版"""
+    
+    def __init__(self):
+        self.data = None
+        self.signals = []
+        self.trades = []
+        
+    def load_data(self, csv_file='cyb50_baostock.csv'):
+        """加载历史数据"""
+        try:
+            df = pd.read_csv(f'/root/.openclaw/workspace/quant/{csv_file}')
+            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')
+            
+            self.data = df
+            print(f"数据加载成功: {df.index[0].date()} ~ {df.index[-1].date()}")
+            return True
+        except Exception as e:
+            print(f"数据加载失败: {e}")
+            return False
+    
+    def calculate_indicators(self):
+        """计算技术指标"""
+        df = self.data.copy()
+        
+        # 均线
+        df['ma10'] = df['close'].rolling(window=10).mean()
+        df['ma30'] = df['close'].rolling(window=30).mean()
+        
+        # 20日高低点
+        df['high_20'] = df['high'].rolling(window=20).max()
+        df['low_20'] = df['low'].rolling(window=20).min()
+        
+        # 10日涨幅
+        df['ret_10'] = df['close'].pct_change(periods=10)
+        
+        # ATR
+        tr1 = df['high'] - df['low']
+        tr2 = abs(df['high'] - df['close'].shift(1))
+        tr3 = abs(df['low'] - df['close'].shift(1))
+        df['tr'] = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
+        df['atr'] = df['tr'].rolling(window=20).mean()
+        
+        self.data = df
+        return df
+    
+    def generate_signals(self):
+        """生成交易信号"""
+        df = self.data
+        
+        # 买入条件
+        buy_cond = (
+            (df['close'] > df['ma10']) & 
+            (df['ma10'] > df['ma30']) & 
+            (df['close'] >= df['high_20'] * 0.995) & 
+            (df['ret_10'] > 0.02)
+        )
+        
+        # 卖出条件
+        sell_cond = (
+            (df['close'] < df['ma30']) | 
+            (df['close'] <= df['low_20'] * 1.005)
+        )
+        
+        df['signal'] = 0
+        df.loc[buy_cond, 'signal'] = 1
+        df.loc[sell_cond, 'signal'] = -1
+        
+        return df
+    
+    def backtest(self, initial_capital=1000000):
+        """回测计算"""
+        df = self.generate_signals()
+        
+        position = 0
+        entry_price = 0
+        peak_price = 0
+        capital = initial_capital
+        trades = []
+        
+        for i in range(30, len(df)):
+            date = df.index[i]
+            price = df['close'].iloc[i]
+            signal = df['signal'].iloc[i]
+            
+            # 移动止损检查
+            if position > 0:
+                if price > peak_price:
+                    peak_price = price
+                if price < peak_price * 0.90:  # 10%回撤止损
+                    signal = -1
+            
+            # 执行交易
+            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
+                position = 0
+                trades.append({
+                    'date': date,
+                    'action': 'SELL',
+                    'price': price,
+                    'capital': capital,
+                    'pnl': pnl,
+                    'return_pct': (price / entry_price - 1) * 100
+                })
+        
+        # 计算当前持仓
+        current_position = position
+        current_price = df['close'].iloc[-1]
+        
+        if position == 1:
+            unrealized_pnl = (current_price / entry_price - 1) * capital
+            total_value = capital + unrealized_pnl
+        else:
+            total_value = capital
+        
+        total_return = (total_value / initial_capital - 1) * 100
+        
+        return {
+            'trades': trades,
+            'current_position': current_position,
+            'current_price': current_price,
+            'entry_price': entry_price if position == 1 else None,
+            'capital': capital,
+            'total_value': total_value,
+            'total_return': total_return,
+            'trade_count': len([t for t in trades if t['action'] == 'SELL'])
+        }
+    
+    def get_recent_indicators(self, days=20):
+        """获取近N天指标详情"""
+        df = self.data.tail(days).copy()
+        
+        indicators = []
+        for date, row in df.iterrows():
+            indicators.append({
+                'date': date.strftime('%Y-%m-%d'),
+                'close': round(row['close'], 2),
+                'ma10': round(row['ma10'], 2) if not pd.isna(row['ma10']) else '-',
+                'ma30': round(row['ma30'], 2) if not pd.isna(row['ma30']) else '-',
+                'high_20': round(row['high_20'], 2) if not pd.isna(row['high_20']) else '-',
+                'ret_10': f"{row['ret_10']*100:.2f}%" if not pd.isna(row['ret_10']) else '-',
+                'signal': '买入' if row['signal'] == 1 else ('卖出' if row['signal'] == -1 else '持有'),
+                'atr': round(row['atr'], 2) if not pd.isna(row['atr']) else '-'
+            })
+        
+        return indicators
+    
+    def get_recent_trades(self, n=20):
+        """获取近N次交易详情"""
+        result = self.backtest()
+        trades = result['trades'][-n:]
+        return trades
+
+
+def generate_report():
+    """生成完整报告"""
+    strategy = TrendTrackingStrategy()
+    
+    if not strategy.load_data():
+        return None, None
+    
+    strategy.calculate_indicators()
+    result = strategy.backtest()
+    
+    # 获取近期数据
+    recent_indicators = strategy.get_recent_indicators(20)
+    recent_trades = strategy.get_recent_trades(20)
+    
+    # 生成HTML报告
+    html = f"""
+    <html>
+    <head>
+        <meta charset="utf-8">
+        <style>
+            body {{ font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }}
+            .container {{ max-width: 1200px; margin: 0 auto; background: white; padding: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }}
+            h1 {{ color: #333; border-bottom: 3px solid #007bff; padding-bottom: 10px; }}
+            h2 {{ color: #555; margin-top: 30px; border-left: 4px solid #007bff; padding-left: 10px; }}
+            .summary {{ background: #f8f9fa; padding: 15px; border-radius: 5px; margin: 20px 0; }}
+            .metric {{ display: inline-block; margin: 10px 20px 10px 0; }}
+            .metric-label {{ color: #666; font-size: 12px; }}
+            .metric-value {{ font-size: 24px; font-weight: bold; color: #333; }}
+            .positive {{ color: #28a745; }}
+            .negative {{ color: #dc3545; }}
+            table {{ width: 100%; border-collapse: collapse; margin: 20px 0; font-size: 13px; }}
+            th {{ background: #007bff; color: white; padding: 10px; text-align: left; }}
+            td {{ padding: 8px 10px; border-bottom: 1px solid #ddd; }}
+            tr:nth-child(even) {{ background: #f8f9fa; }}
+            tr:hover {{ background: #e9ecef; }}
+            .position-yes {{ color: #28a745; font-weight: bold; }}
+            .position-no {{ color: #666; }}
+            .buy {{ color: #28a745; font-weight: bold; }}
+            .sell {{ color: #dc3545; font-weight: bold; }}
+        </style>
+    </head>
+    <body>
+        <div class="container">
+            <h1>🚀 创业板50趋势跟踪策略报告</h1>
+            <p style="color: #666;">生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
+            
+            <div class="summary">
+                <h2>📊 总体绩效</h2>
+                <div class="metric">
+                    <div class="metric-label">当前持仓</div>
+                    <div class="metric-value {'position-yes' if result['current_position'] == 1 else 'position-no'}">
+                        {'持有中' if result['current_position'] == 1 else '空仓'}
+                    </div>
+                </div>
+                <div class="metric">
+                    <div class="metric-label">当前价格</div>
+                    <div class="metric-value">{result['current_price']:.2f}</div>
+                </div>
+                <div class="metric">
+                    <div class="metric-label">累计收益率</div>
+                    <div class="metric-value {'positive' if result['total_return'] >= 0 else 'negative'}">
+                        {result['total_return']:+.2f}%
+                    </div>
+                </div>
+                <div class="metric">
+                    <div class="metric-label">总资产</div>
+                    <div class="metric-value">{result['total_value']:,.0f}元</div>
+                </div>
+                <div class="metric">
+                    <div class="metric-label">交易次数</div>
+                    <div class="metric-value">{result['trade_count']}</div>
+                </div>
+            </div>
+    """
+    
+    # 持仓详情
+    if result['current_position'] == 1:
+        unrealized = (result['current_price'] / result['entry_price'] - 1) * 100
+        html += f"""
+            <div class="summary" style="background: #e8f5e9;">
+                <h2>📈 持仓详情</h2>
+                <p><strong>入场价格:</strong> {result['entry_price']:.2f} 元</p>
+                <p><strong>当前浮盈:</strong> <span class="{'positive' if unrealized >= 0 else 'negative'}">{unrealized:+.2f}%</span></p>
+            </div>
+        """
+    
+    # 近20天指标
+    html += """
+            <h2>📅 近20天指标详情</h2>
+            <table>
+                <tr>
+                    <th>日期</th>
+                    <th>收盘价</th>
+                    <th>MA10</th>
+                    <th>MA30</th>
+                    <th>20日高</th>
+                    <th>10日涨幅</th>
+                    <th>信号</th>
+                    <th>ATR</th>
+                </tr>
+    """
+    
+    for ind in recent_indicators:
+        signal_class = 'buy' if ind['signal'] == '买入' else ('sell' if ind['signal'] == '卖出' else '')
+        html += f"""
+                <tr>
+                    <td>{ind['date']}</td>
+                    <td>{ind['close']}</td>
+                    <td>{ind['ma10']}</td>
+                    <td>{ind['ma30']}</td>
+                    <td>{ind['high_20']}</td>
+                    <td>{ind['ret_10']}</td>
+                    <td class="{signal_class}">{ind['signal']}</td>
+                    <td>{ind['atr']}</td>
+                </tr>
+        """
+    
+    html += """
+            </table>
+            
+            <h2>💼 近20次交易详情</h2>
+            <table>
+                <tr>
+                    <th>日期</th>
+                    <th>操作</th>
+                    <th>价格</th>
+                    <th>盈亏金额</th>
+                    <th>盈亏比例</th>
+                    <th>总资产</th>
+                </tr>
+    """
+    
+    for trade in recent_trades:
+        action_class = 'buy' if trade['action'] == 'BUY' else 'sell'
+        pnl = trade.get('pnl', 0)
+        ret = trade.get('return_pct', 0)
+        html += f"""
+                <tr>
+                    <td>{trade['date'].strftime('%Y-%m-%d') if isinstance(trade['date'], pd.Timestamp) else trade['date']}</td>
+                    <td class="{action_class}">{trade['action']}</td>
+                    <td>{trade['price']:.2f}</td>
+                    <td>{f'{pnl:+,.0f}元' if 'pnl' in trade else '-'}</td>
+                    <td class="{'positive' if ret >= 0 else 'negative'}">{f'{ret:+.2f}%' if 'return_pct' in trade else '-'}</td>
+                    <td>{trade['capital']:,.0f}元</td>
+                </tr>
+        """
+    
+    html += """
+            </table>
+            
+            <div style="margin-top: 30px; padding: 15px; background: #fff3cd; border-radius: 5px; color: #856404;">
+                <strong>策略说明:</strong><br>
+                • 买入条件: 价格>MA10>MA30 且 突破20日高×0.995 且 10日涨幅>2%<br>
+                • 卖出条件: 跌破MA30 或 创20日新低 或 回撤10%止损<br>
+                • 风险提示: 右侧交易可能错过牛市初期涨幅
+            </div>
+        </div>
+    </body>
+    </html>
+    """
+    
+    # 生成文本报告
+    text = f"""
+创业板50趋势跟踪策略报告
+生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
+
+【总体绩效】
+当前持仓: {'持有中' if result['current_position'] == 1 else '空仓'}
+当前价格: {result['current_price']:.2f}元
+累计收益率: {result['total_return']:+.2f}%
+总资产: {result['total_value']:,.0f}元
+交易次数: {result['trade_count']}
+
+【近20天指标】
+日期        收盘价    MA10     MA30     20日高   10日涨幅  信号
+"""
+    
+    for ind in recent_indicators:
+        text += f"{ind['date']}  {ind['close']:>8}  {ind['ma10']:>8}  {ind['ma30']:>8}  {ind['high_20']:>8}  {ind['ret_10']:>8}  {ind['signal']}\n"
+    
+    text += "\n【近20次交易】\n"
+    text += "日期        操作    价格      盈亏金额    盈亏比例   总资产\n"
+    
+    for trade in recent_trades:
+        pnl_str = f"{trade.get('pnl', 0):+,.0f}元" if 'pnl' in trade else '-'
+        ret_str = f"{trade.get('return_pct', 0):+.2f}%" if 'return_pct' in trade else '-'
+        date_str = trade['date'].strftime('%Y-%m-%d') if isinstance(trade['date'], pd.Timestamp) else trade['date']
+        text += f"{date_str}  {trade['action']:>6}  {trade['price']:>8.2f}  {pnl_str:>12}  {ret_str:>10}  {trade['capital']:>12,.0f}元\n"
+    
+    return html, text, result
+
+
+def send_email(subject, html_content, text_content):
+    """发送邮件"""
+    try:
+        msg = MIMEMultipart('alternative')
+        msg['Subject'] = Header(subject, 'utf-8')
+        msg['From'] = EMAIL_CONFIG['sender_email']
+        msg['To'] = EMAIL_CONFIG['receiver_email']
+        
+        text_part = MIMEText(text_content, 'plain', 'utf-8')
+        msg.attach(text_part)
+        
+        html_part = MIMEText(html_content, 'html', 'utf-8')
+        msg.attach(html_part)
+        
+        with smtplib.SMTP(EMAIL_CONFIG['smtp_server'], EMAIL_CONFIG['smtp_port']) as server:
+            server.sendmail(
+                EMAIL_CONFIG['sender_email'],
+                EMAIL_CONFIG['receiver_email'],
+                msg.as_string()
+            )
+        print(f"✅ 邮件发送成功: {subject}")
+        return True
+    except Exception as e:
+        print(f"❌ 邮件发送失败: {e}")
+        return False
+
+
+def main():
+    """主程序"""
+    print("="*60)
+    print("🚀 创业板50趋势跟踪实时报告")
+    print("="*60)
+    print(f"执行时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
+    
+    # 生成报告
+    print("\n📊 生成报告中...")
+    html, text, result = generate_report()
+    
+    if html is None:
+        print("❌ 报告生成失败")
+        return
+    
+    print(f"✅ 报告生成完成")
+    print(f"   当前持仓: {'持有中' if result['current_position'] == 1 else '空仓'}")
+    print(f"   累计收益: {result['total_return']:+.2f}%")
+    print(f"   交易次数: {result['trade_count']}")
+    
+    # 发送邮件
+    print("\n📧 发送邮件...")
+    position_status = "持仓" if result['current_position'] == 1 else "空仓"
+    subject = f"🚀 创业板50趋势报告 {datetime.now().strftime('%m-%d %H:%M')} | {position_status} | 收益{result['total_return']:+.2f}%"
+    send_email(subject, html, text)
+    
+    print("\n✅ 全部完成!")
+    print("="*60)
+
+
+if __name__ == "__main__":
+    main()

+ 734 - 0
cat-fly/trend_report_fixed.py

@@ -0,0 +1,734 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+创业板50指数 - 实时交易报告系统 (修复数据连续性)
+支持新浪、腾讯、网易多数据源
+"""
+
+import sys
+sys.path.insert(0, '/root/.openclaw/workspace/cat-fly')
+sys.path.insert(0, '/root/.openclaw/workspace/quant')
+
+import pandas as pd
+import numpy as np
+from datetime import datetime, timedelta
+import smtplib
+import ssl
+from email.mime.text import MIMEText
+from email.mime.multipart import MIMEMultipart
+from email.header import Header
+import warnings
+import requests
+import json
+import time
+warnings.filterwarnings('ignore')
+
+# ==================== 邮件配置 ====================
+EMAIL_CONFIG = {
+    "smtp_server": "localhost",
+    "smtp_port": 25,
+    "sender_email": "catfly@openclaw.local",
+    "receiver_email": "380880504@qq.com"
+}
+
+# ==================== 多数据源获取 ====================
+
+def fetch_sina_realtime():
+    """新浪实时行情接口"""
+    try:
+        url = "https://hq.sinajs.cn/list=sz399673"
+        headers = {
+            'Referer': 'https://finance.sina.com.cn',
+            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
+        }
+        response = requests.get(url, headers=headers, timeout=10)
+        response.encoding = 'gb2312'
+        
+        data_str = response.text
+        if 'var hq_str_sz399673="' in data_str:
+            data_str = data_str.split('var hq_str_sz399673="')[1].split('"')[0]
+            parts = data_str.split(',')
+            if len(parts) >= 32:
+                # 解析日期时间
+                date_str = parts[30].strip()  # YYYYMMDD
+                time_str = parts[31].strip() if len(parts) > 31 else ""
+                
+                if len(date_str) == 8 and date_str.isdigit():
+                    date = pd.Timestamp(f"{date_str[:4]}-{date_str[4:6]}-{date_str[6:8]}")
+                else:
+                    date = pd.Timestamp.now().normalize()
+                
+                return {
+                    'open': float(parts[1]),
+                    'high': float(parts[4]),
+                    'low': float(parts[5]),
+                    'close': float(parts[3]),
+                    'volume': int(parts[8]),
+                    'name': parts[0],
+                    'date': date,
+                    'time': time_str
+                }
+    except Exception as e:
+        print(f"新浪实时数据获取失败: {e}")
+    return None
+
+
+def fetch_tencent_realtime():
+    """腾讯实时行情接口"""
+    try:
+        url = "https://qt.gtimg.cn/q=sz399673"
+        headers = {
+            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
+        }
+        response = requests.get(url, headers=headers, timeout=10)
+        response.encoding = 'gb2312'
+        
+        data_str = response.text
+        if 'v_sz399673="' in data_str:
+            data_str = data_str.split('v_sz399673="')[1].split('"')[0]
+            parts = data_str.split('~')
+            if len(parts) >= 45:
+                # 日期格式: YYYY-MM-DD
+                date_str = parts[30]
+                date = pd.Timestamp(date_str)
+                
+                return {
+                    'name': parts[1],
+                    'close': float(parts[3]),
+                    'open': float(parts[5]),
+                    'high': float(parts[33]),
+                    'low': float(parts[34]),
+                    'volume': int(parts[36]),
+                    'date': date
+                }
+    except Exception as e:
+        print(f"腾讯实时数据获取失败: {e}")
+    return None
+
+
+def fetch_akshare_hist(start_date, end_date):
+    """使用akshare获取历史数据"""
+    try:
+        import akshare as ak
+        print(f"  使用akshare获取 {start_date} 到 {end_date} 的历史数据...")
+        
+        # 获取创业板50历史行情
+        df = ak.index_zh_a_hist(symbol="399673", period="daily", 
+                                start_date=start_date, end_date=end_date)
+        
+        if df is not None and len(df) > 0:
+            data_list = []
+            for _, row in df.iterrows():
+                data_list.append({
+                    'date': pd.Timestamp(row['日期']),
+                    'open': float(row['开盘']),
+                    'high': float(row['最高']),
+                    'low': float(row['最低']),
+                    'close': float(row['收盘']),
+                    'volume': int(row['成交量'])
+                })
+            return data_list
+    except Exception as e:
+        print(f"  akshare获取失败: {e}")
+    return None
+
+
+def fetch_baostock_hist(start_date, end_date):
+    """使用baostock获取历史数据"""
+    try:
+        import baostock as bs
+        print(f"  使用baostock获取 {start_date} 到 {end_date} 的历史数据...")
+        
+        lg = bs.login()
+        if lg.error_code != '0':
+            print(f"  baostock登录失败: {lg.error_msg}")
+            return None
+        
+        # 创业板50代码: sz.399673
+        rs = bs.query_history_k_data_plus("sz.399673",
+            "date,open,high,low,close,volume",
+            start_date=start_date, end_date=end_date,
+            frequency="d", adjustflag="3")
+        
+        data_list = []
+        while (rs.error_code == '0') & rs.next():
+            row = rs.get_row_data()
+            if row[0]:  # date
+                data_list.append({
+                    'date': pd.Timestamp(row[0]),
+                    'open': float(row[1]) if row[1] else 0,
+                    'high': float(row[2]) if row[2] else 0,
+                    'low': float(row[3]) if row[3] else 0,
+                    'close': float(row[4]) if row[4] else 0,
+                    'volume': int(float(row[5])) if row[5] else 0
+                })
+        
+        bs.logout()
+        
+        if data_list:
+            return data_list
+    except Exception as e:
+        print(f"  baostock获取失败: {e}")
+    return None
+
+
+def fetch_missing_data(last_date, today):
+    """获取缺失的历史数据"""
+    if last_date >= today:
+        return []
+    
+    start_str = (last_date + timedelta(days=1)).strftime('%Y-%m-%d')
+    end_str = (today - timedelta(days=1)).strftime('%Y-%m-%d')
+    
+    print(f"\n📊 需要补全数据: {start_str} 到 {end_str}")
+    
+    # 尝试akshare
+    data = fetch_akshare_hist(start_str.replace('-', ''), end_str.replace('-', ''))
+    if data:
+        print(f"  ✅ akshare获取成功: {len(data)} 条")
+        return data
+    
+    # 尝试baostock
+    data = fetch_baostock_hist(start_str, end_str)
+    if data:
+        print(f"  ✅ baostock获取成功: {len(data)} 条")
+        return data
+    
+    print("  ⚠️ 无法获取缺失数据,将仅使用实时数据")
+    return []
+
+
+def fetch_realtime_data():
+    """获取实时数据,尝试多个数据源"""
+    print("尝试获取实时数据...")
+    
+    # 尝试新浪实时
+    print("  尝试新浪实时接口...")
+    data = fetch_sina_realtime()
+    if data:
+        print(f"  ✅ 新浪实时数据获取成功")
+        return data, 'sina_realtime'
+    
+    # 尝试腾讯实时
+    print("  尝试腾讯实时接口...")
+    data = fetch_tencent_realtime()
+    if data:
+        print(f"  ✅ 腾讯实时数据获取成功")
+        return data, 'tencent_realtime'
+    
+    print("  ❌ 所有数据源均失败")
+    return None, None
+
+
+# ==================== 趋势跟踪策略 ====================
+class TrendTrackingStrategy:
+    """趋势跟踪策略 - 修复数据连续性版"""
+    
+    def __init__(self):
+        self.data = None
+        self.data_gaps = []  # 记录数据缺口
+        
+    def load_and_merge_data(self, csv_file='cyb50_baostock.csv'):
+        """加载历史数据并合并实时数据"""
+        try:
+            # 加载历史数据
+            df = pd.read_csv(f'/root/.openclaw/workspace/quant/{csv_file}')
+            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')
+            
+            # 获取最新历史数据日期
+            last_hist_date = df.index[-1]
+            today = pd.Timestamp.now().normalize()
+            
+            print(f"历史数据最新日期: {last_hist_date.date()}")
+            print(f"当前日期: {today.date()}")
+            
+            # 检查数据缺口
+            missing_data = []
+            if last_hist_date < today - timedelta(days=1):
+                # 尝试获取缺失的历史数据
+                missing_data = fetch_missing_data(last_hist_date, today)
+                
+                if missing_data:
+                    # 合并缺失数据
+                    for item in missing_data:
+                        new_row = pd.DataFrame({
+                            'open': [item['open']],
+                            'high': [item['high']],
+                            'low': [item['low']],
+                            'close': [item['close']],
+                            'volume': [item['volume']]
+                        }, index=[item['date']])
+                        df = pd.concat([df, new_row])
+                    
+                    df = df.sort_index()
+                    last_hist_date = df.index[-1]
+                    print(f"✅ 已合并缺失数据,最新历史日期: {last_hist_date.date()}")
+                else:
+                    # 记录数据缺口
+                    gap_start = last_hist_date + timedelta(days=1)
+                    gap_end = today - timedelta(days=1)
+                    self.data_gaps.append(f"{gap_start.date()} 到 {gap_end.date()}")
+                    print(f"⚠️ 数据缺口: {gap_start.date()} 到 {gap_end.date()}")
+            
+            # 获取今天的实时数据
+            if last_hist_date < today:
+                realtime_data, source = fetch_realtime_data()
+                
+                if realtime_data:
+                    date = realtime_data['date']
+                    
+                    # 检查是否已有该日期数据
+                    if date > last_hist_date:
+                        new_row = pd.DataFrame({
+                            'open': [realtime_data['open']],
+                            'high': [realtime_data['high']],
+                            'low': [realtime_data['low']],
+                            'close': [realtime_data['close']],
+                            'volume': [realtime_data['volume']]
+                        }, index=[date])
+                        
+                        df = pd.concat([df, new_row])
+                        print(f"✅ 已合并{source}数据: {date.date()} 收盘价 {realtime_data['close']}")
+                    else:
+                        print(f"⚠️ 获取的数据日期({date.date()})不大于历史最新日期")
+                else:
+                    print("⚠️ 未获取到实时数据")
+            else:
+                print("✅ 历史数据已是最新")
+            
+            self.data = df.sort_index()
+            print(f"\n数据范围: {self.data.index[0].date()} ~ {self.data.index[-1].date()}")
+            print(f"数据条数: {len(self.data)}")
+            
+            if self.data_gaps:
+                print(f"⚠️ 警告: 存在数据缺口: {', '.join(self.data_gaps)}")
+            
+            return True
+            
+        except Exception as e:
+            print(f"数据加载失败: {e}")
+            import traceback
+            traceback.print_exc()
+            return False
+    
+    def calculate_indicators(self):
+        """计算技术指标"""
+        df = self.data.copy()
+        
+        # 均线
+        df['ma10'] = df['close'].rolling(window=10, min_periods=1).mean()
+        df['ma30'] = df['close'].rolling(window=30, min_periods=1).mean()
+        
+        # 20日高低点
+        df['high_20'] = df['high'].rolling(window=20).max()
+        df['low_20'] = df['low'].rolling(window=20).min()
+        
+        # 10日涨幅
+        df['ret_10'] = df['close'].pct_change(periods=10)
+        
+        # ATR
+        tr1 = df['high'] - df['low']
+        tr2 = abs(df['high'] - df['close'].shift(1))
+        tr3 = abs(df['low'] - df['close'].shift(1))
+        df['tr'] = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
+        df['atr'] = df['tr'].rolling(window=20).mean()
+        
+        self.data = df
+        return df
+    
+    def generate_signals(self):
+        """生成交易信号"""
+        df = self.data
+        
+        # 买入条件
+        buy_cond = (
+            (df['close'] > df['ma10']) & 
+            (df['ma10'] > df['ma30']) & 
+            (df['close'] >= df['high_20'] * 0.995) & 
+            (df['ret_10'] > 0.02)
+        )
+        
+        # 卖出条件
+        sell_cond = (
+            (df['close'] < df['ma30']) | 
+            (df['close'] <= df['low_20'] * 1.005)
+        )
+        
+        df['signal'] = 0
+        df.loc[buy_cond, 'signal'] = 1
+        df.loc[sell_cond, 'signal'] = -1
+        
+        return df
+    
+    def backtest(self, initial_capital=1000000):
+        """回测计算"""
+        df = self.generate_signals()
+        
+        position = 0
+        entry_price = 0
+        peak_price = 0
+        capital = initial_capital
+        trades = []
+        
+        for i in range(30, len(df)):
+            date = df.index[i]
+            price = df['close'].iloc[i]
+            signal = df['signal'].iloc[i]
+            
+            # 移动止损检查
+            if position > 0:
+                if price > peak_price:
+                    peak_price = price
+                if price < peak_price * 0.90:
+                    signal = -1
+            
+            # 买入
+            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
+                position = 0
+                trades.append({
+                    'date': date,
+                    'action': 'SELL',
+                    'price': price,
+                    'capital': capital,
+                    'pnl': pnl,
+                    'return_pct': (price / entry_price - 1) * 100
+                })
+        
+        current_position = position
+        current_price = df['close'].iloc[-1]
+        
+        if position == 1:
+            unrealized_pnl = (current_price / entry_price - 1) * capital
+            total_value = capital + unrealized_pnl
+        else:
+            total_value = capital
+        
+        total_return = (total_value / initial_capital - 1) * 100
+        
+        return {
+            'trades': trades,
+            'current_position': current_position,
+            'current_price': current_price,
+            'entry_price': entry_price if position == 1 else None,
+            'capital': capital,
+            'total_value': total_value,
+            'total_return': total_return,
+            'trade_count': len([t for t in trades if t['action'] == 'SELL']),
+            'data_end_date': df.index[-1].strftime('%Y-%m-%d'),
+            'data_gaps': self.data_gaps
+        }
+    
+    def get_recent_indicators(self, days=20):
+        """获取近N天指标详情"""
+        df = self.data.tail(days).copy()
+        
+        indicators = []
+        for date, row in df.iterrows():
+            indicators.append({
+                'date': date.strftime('%Y-%m-%d'),
+                'close': round(row['close'], 2),
+                'ma10': round(row['ma10'], 2) if not pd.isna(row['ma10']) else '-',
+                'ma30': round(row['ma30'], 2) if not pd.isna(row['ma30']) else '-',
+                'high_20': round(row['high_20'], 2) if not pd.isna(row['high_20']) else '-',
+                'ret_10': f"{row['ret_10']*100:.2f}%" if not pd.isna(row['ret_10']) else '-',
+                'signal': '买入' if row['signal'] == 1 else ('卖出' if row['signal'] == -1 else '持有'),
+                'atr': round(row['atr'], 2) if not pd.isna(row['atr']) else '-'
+            })
+        
+        return indicators
+    
+    def get_recent_trades(self, n=20):
+        """获取近N次交易详情"""
+        result = self.backtest()
+        trades = result['trades'][-n:]
+        return trades
+
+
+def generate_report():
+    """生成完整报告"""
+    strategy = TrendTrackingStrategy()
+    
+    if not strategy.load_and_merge_data():
+        return None, None, None
+    
+    strategy.calculate_indicators()
+    result = strategy.backtest()
+    
+    recent_indicators = strategy.get_recent_indicators(20)
+    recent_trades = strategy.get_recent_trades(20)
+    
+    # 数据缺口警告
+    gap_warning = ""
+    if result['data_gaps']:
+        gap_warning = f"<div class='warning'>⚠️ 数据缺口: {', '.join(result['data_gaps'])} - 指标计算可能不准确</div>"
+    
+    html = f"""
+    <html>
+    <head>
+        <meta charset="utf-8">
+        <style>
+            body {{ font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }}
+            .container {{ max-width: 1200px; margin: 0 auto; background: white; padding: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }}
+            h1 {{ color: #333; border-bottom: 3px solid #007bff; padding-bottom: 10px; }}
+            h2 {{ color: #555; margin-top: 30px; border-left: 4px solid #007bff; padding-left: 10px; }}
+            .summary {{ background: #f8f9fa; padding: 15px; border-radius: 5px; margin: 20px 0; }}
+            .metric {{ display: inline-block; margin: 10px 20px 10px 0; }}
+            .metric-label {{ color: #666; font-size: 12px; }}
+            .metric-value {{ font-size: 24px; font-weight: bold; color: #333; }}
+            .positive {{ color: #28a745; }}
+            .negative {{ color: #dc3545; }}
+            .warning {{ background: #fff3cd; color: #856404; padding: 10px; border-radius: 5px; margin: 10px 0; }}
+            table {{ width: 100%; border-collapse: collapse; margin: 20px 0; font-size: 13px; }}
+            th {{ background: #007bff; color: white; padding: 10px; text-align: left; }}
+            td {{ padding: 8px 10px; border-bottom: 1px solid #ddd; }}
+            tr:nth-child(even) {{ background: #f8f9fa; }}
+            tr:hover {{ background: #e9ecef; }}
+            .position-yes {{ color: #28a745; font-weight: bold; }}
+            .position-no {{ color: #666; }}
+            .buy {{ color: #28a745; font-weight: bold; }}
+            .sell {{ color: #dc3545; font-weight: bold; }}
+            .data-info {{ background: #e7f3ff; padding: 10px; border-radius: 5px; margin: 10px 0; color: #004085; }}
+        </style>
+    </head>
+    <body>
+        <div class="container">
+            <h1>🚀 创业板50趋势跟踪策略报告</h1>
+            <p style="color: #666;">生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
+            
+            {gap_warning}
+            
+            <div class="data-info">
+                <strong>数据更新:</strong> 最新数据日期: {result['data_end_date']} | 
+                数据范围: {strategy.data.index[0].date()} ~ {strategy.data.index[-1].date()}
+            </div>
+            
+            <div class="summary">
+                <h2>📊 总体绩效</h2>
+                <div class="metric">
+                    <div class="metric-label">当前持仓</div>
+                    <div class="metric-value {'position-yes' if result['current_position'] == 1 else 'position-no'}">
+                        {'持有中' if result['current_position'] == 1 else '空仓'}
+                    </div>
+                </div>
+                <div class="metric">
+                    <div class="metric-label">当前价格</div>
+                    <div class="metric-value">{result['current_price']:.2f}</div>
+                </div>
+                <div class="metric">
+                    <div class="metric-label">累计收益率</div>
+                    <div class="metric-value {'positive' if result['total_return'] >= 0 else 'negative'}">
+                        {result['total_return']:+.2f}%
+                    </div>
+                </div>
+                <div class="metric">
+                    <div class="metric-label">总资产</div>
+                    <div class="metric-value">{result['total_value']:,.0f}元</div>
+                </div>
+                <div class="metric">
+                    <div class="metric-label">交易次数</div>
+                    <div class="metric-value">{result['trade_count']}</div>
+                </div>
+            </div>
+    """
+    
+    if result['current_position'] == 1:
+        unrealized = (result['current_price'] / result['entry_price'] - 1) * 100
+        html += f"""
+            <div class="summary" style="background: #e8f5e9;">
+                <h2>📈 持仓详情</h2>
+                <p><strong>入场价格:</strong> {result['entry_price']:.2f} 元</p>
+                <p><strong>当前浮盈:</strong> <span class="{'positive' if unrealized >= 0 else 'negative'}">{unrealized:+.2f}%</span></p>
+            </div>
+        """
+    
+    # 近20天指标
+    html += """
+            <h2>📅 近20天指标详情</h2>
+            <table>
+                <tr>
+                    <th>日期</th>
+                    <th>收盘价</th>
+                    <th>MA10</th>
+                    <th>MA30</th>
+                    <th>20日高</th>
+                    <th>10日涨幅</th>
+                    <th>信号</th>
+                    <th>ATR</th>
+                </tr>
+    """
+    
+    for ind in recent_indicators:
+        signal_class = 'buy' if ind['signal'] == '买入' else ('sell' if ind['signal'] == '卖出' else '')
+        html += f"""
+                <tr>
+                    <td>{ind['date']}</td>
+                    <td>{ind['close']}</td>
+                    <td>{ind['ma10']}</td>
+                    <td>{ind['ma30']}</td>
+                    <td>{ind['high_20']}</td>
+                    <td>{ind['ret_10']}</td>
+                    <td class="{signal_class}">{ind['signal']}</td>
+                    <td>{ind['atr']}</td>
+                </tr>
+        """
+    
+    html += """
+            </table>
+            
+            <h2>💼 近20次交易详情</h2>
+            <table>
+                <tr>
+                    <th>日期</th>
+                    <th>操作</th>
+                    <th>价格</th>
+                    <th>盈亏金额</th>
+                    <th>盈亏比例</th>
+                    <th>总资产</th>
+                </tr>
+    """
+    
+    for trade in recent_trades:
+        action_class = 'buy' if trade['action'] == 'BUY' else 'sell'
+        pnl = trade.get('pnl', 0)
+        ret = trade.get('return_pct', 0)
+        has_pnl = 'pnl' in trade
+        date_str = trade['date'].strftime('%Y-%m-%d') if hasattr(trade['date'], 'strftime') else str(trade['date'])
+        
+        # 盈亏比例样式:买入不显示样式,卖出根据盈亏显示
+        ret_class = '' if not has_pnl else ('positive' if ret >= 0 else 'negative')
+        ret_text = '-' if not has_pnl else f'{ret:+.2f}%'
+        
+        html += f"""
+                <tr>
+                    <td>{date_str}</td>
+                    <td class="{action_class}">{trade['action']}</td>
+                    <td>{trade['price']:.2f}</td>
+                    <td>{f'{pnl:+,.0f}元' if has_pnl else '-'}</td>
+                    <td class="{ret_class}">{ret_text}</td>
+                    <td>{trade['capital']:,.0f}元</td>
+                </tr>
+        """
+    
+    html += """
+            </table>
+            
+            <div style="margin-top: 30px; padding: 15px; background: #fff3cd; border-radius: 5px; color: #856404;">
+                <strong>策略说明:</strong><br>
+                • 买入条件: 价格>MA10>MA30 且 突破20日高×0.995 且 10日涨幅>2%<br>
+                • 卖出条件: 跌破MA30 或 创20日新低 或 回撤10%止损<br>
+                • 数据已自动合并历史数据与实时数据
+            </div>
+        </div>
+    </body>
+    </html>
+    """
+    
+    # 文本报告
+    text = f"""
+创业板50趋势跟踪策略报告
+生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
+数据最新日期: {result['data_end_date']}
+"""
+    
+    if result['data_gaps']:
+        text += f"⚠️ 警告: 数据缺口 {', '.join(result['data_gaps'])}\n"
+    
+    text += f"""
+【总体绩效】
+当前持仓: {'持有中' if result['current_position'] == 1 else '空仓'}
+当前价格: {result['current_price']:.2f}元
+累计收益率: {result['total_return']:+.2f}%
+总资产: {result['total_value']:,.0f}元
+
+【近20天指标】
+日期        收盘价    MA10     MA30     20日高   10日涨幅  信号
+"""
+    
+    for ind in recent_indicators:
+        text += f"{ind['date']}  {ind['close']:>8}  {ind['ma10']:>8}  {ind['ma30']:>8}  {ind['high_20']:>8}  {ind['ret_10']:>8}  {ind['signal']:>4}\n"
+    
+    text += "\n【近20次交易】\n"
+    for trade in recent_trades:
+        pnl_str = f"{trade.get('pnl', 0):+,.0f}元" if 'pnl' in trade else '-'
+        ret_str = f"{trade.get('return_pct', 0):+.2f}%" if 'return_pct' in trade else '-'
+        date_str = trade['date'].strftime('%Y-%m-%d') if hasattr(trade['date'], 'strftime') else str(trade['date'])
+        text += f"{date_str}  {trade['action']:>6}  {trade['price']:>8.2f}  {pnl_str:>12}  {ret_str:>10}\n"
+    
+    return html, text, result
+
+
+def send_email(subject, html_content, text_content):
+    """发送邮件"""
+    try:
+        msg = MIMEMultipart('alternative')
+        msg['Subject'] = Header(subject, 'utf-8')
+        msg['From'] = EMAIL_CONFIG['sender_email']
+        msg['To'] = EMAIL_CONFIG['receiver_email']
+        
+        text_part = MIMEText(text_content, 'plain', 'utf-8')
+        msg.attach(text_part)
+        
+        html_part = MIMEText(html_content, 'html', 'utf-8')
+        msg.attach(html_part)
+        
+        with smtplib.SMTP(EMAIL_CONFIG['smtp_server'], EMAIL_CONFIG['smtp_port']) as server:
+            server.sendmail(
+                EMAIL_CONFIG['sender_email'],
+                EMAIL_CONFIG['receiver_email'],
+                msg.as_string()
+            )
+        print(f"✅ 邮件发送成功: {subject}")
+        return True
+    except Exception as e:
+        print(f"❌ 邮件发送失败: {e}")
+        return False
+
+
+def main():
+    """主程序"""
+    print("="*60)
+    print("🚀 创业板50趋势跟踪实时报告 (修复数据连续性)")
+    print("="*60)
+    print(f"执行时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
+    
+    html, text, result = generate_report()
+    
+    if html is None:
+        print("❌ 报告生成失败")
+        return
+    
+    print(f"\n✅ 报告生成完成")
+    print(f"   数据最新日期: {result['data_end_date']}")
+    print(f"   当前持仓: {'持有中' if result['current_position'] == 1 else '空仓'}")
+    print(f"   累计收益: {result['total_return']:+.2f}%")
+    
+    print("\n📧 发送邮件...")
+    position_status = "持仓" if result['current_position'] == 1 else "空仓"
+    subject = f"🚀 创业板50趋势报告 {datetime.now().strftime('%m-%d %H:%M')} | {position_status} | 收益{result['total_return']:+.2f}%"
+    send_email(subject, html, text)
+    
+    print("\n✅ 全部完成!")
+    print("="*60)
+
+
+if __name__ == "__main__":
+    main()

+ 673 - 0
cat-fly/trend_report_multi.py

@@ -0,0 +1,673 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+创业板50指数 - 实时交易报告系统 (多数据源)
+支持新浪、腾讯、东方财富接口
+"""
+
+import sys
+sys.path.insert(0, '/root/.openclaw/workspace/cat-fly')
+sys.path.insert(0, '/root/.openclaw/workspace/quant')
+
+import pandas as pd
+import numpy as np
+from datetime import datetime, timedelta
+import smtplib
+import ssl
+from email.mime.text import MIMEText
+from email.mime.multipart import MIMEMultipart
+from email.header import Header
+import warnings
+import requests
+import json
+import time
+warnings.filterwarnings('ignore')
+
+# ==================== 邮件配置 ====================
+EMAIL_CONFIG = {
+    "smtp_server": "localhost",
+    "smtp_port": 25,
+    "sender_email": "catfly@openclaw.local",
+    "receiver_email": "380880504@qq.com"
+}
+
+# ==================== 多数据源获取 ====================
+
+def fetch_sina_realtime():
+    """新浪实时行情接口"""
+    try:
+        # 新浪股票代码格式: sh000001(上证), sz399673(创业板50)
+        url = "https://hq.sinajs.cn/list=sz399673"
+        headers = {
+            'Referer': 'https://finance.sina.com.cn',
+            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
+        }
+        response = requests.get(url, headers=headers, timeout=10)
+        response.encoding = 'gb2312'
+        
+        # 解析返回数据
+        data_str = response.text
+        if 'var hq_str_sz399673="' in data_str:
+            data_str = data_str.split('var hq_str_sz399673="')[1].split('"')[0]
+            parts = data_str.split(',')
+            if len(parts) >= 32:
+                return {
+                    'open': float(parts[1]),
+                    'high': float(parts[4]),
+                    'low': float(parts[5]),
+                    'close': float(parts[3]),
+                    'volume': int(parts[8]),
+                    'name': parts[0],
+                    'time': parts[31],
+                    'date': parts[30]
+                }
+    except Exception as e:
+        print(f"新浪实时数据获取失败: {e}")
+    return None
+
+
+def fetch_tencent_realtime():
+    """腾讯实时行情接口"""
+    try:
+        # 腾讯股票代码格式: sh000001, sz399673
+        url = "https://qt.gtimg.cn/q=sz399673"
+        headers = {
+            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
+        }
+        response = requests.get(url, headers=headers, timeout=10)
+        response.encoding = 'gb2312'
+        
+        data_str = response.text
+        if 'v_sz399673="' in data_str:
+            data_str = data_str.split('v_sz399673="')[1].split('"')[0]
+            parts = data_str.split('~')
+            if len(parts) >= 45:
+                return {
+                    'name': parts[1],
+                    'close': float(parts[3]),
+                    'open': float(parts[5]),
+                    'high': float(parts[33]),
+                    'low': float(parts[34]),
+                    'volume': int(parts[36]),
+                    'date': parts[30]
+                }
+    except Exception as e:
+        print(f"腾讯实时数据获取失败: {e}")
+    return None
+
+
+def fetch_sina_hist_t1():
+    """新浪历史数据 - T-1日"""
+    try:
+        # 新浪历史行情接口
+        today = datetime.now()
+        url = f"https://quotes.sina.cn/cn/api/quotes.php?symbol=sz399673"
+        headers = {
+            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
+        }
+        response = requests.get(url, headers=headers, timeout=10)
+        
+        if response.status_code == 200:
+            data = response.json()
+            if 'data' in data and len(data['data']) > 0:
+                item = data['data'][0]
+                return {
+                    'date': item.get('date'),
+                    'open': float(item.get('open', 0)),
+                    'high': float(item.get('high', 0)),
+                    'low': float(item.get('low', 0)),
+                    'close': float(item.get('close', 0)),
+                    'volume': int(item.get('volume', 0))
+                }
+    except Exception as e:
+        print(f"新浪历史数据获取失败: {e}")
+    return None
+
+
+def fetch_163_hist():
+    """网易财经历史数据接口"""
+    try:
+        url = "http://quotes.money.163.com/service/chddata.html"
+        params = {
+            'code': '1399673',  # 创业板50代码
+            'start': (datetime.now() - timedelta(days=30)).strftime('%Y%m%d'),
+            'end': datetime.now().strftime('%Y%m%d'),
+            'fields': 'TCLOSE;HIGH;LOW;TOPEN;CHG;PCHG;VOTURNOVER'
+        }
+        headers = {
+            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
+        }
+        response = requests.get(url, params=params, headers=headers, timeout=10)
+        
+        if response.status_code == 200:
+            # 解析CSV格式数据
+            lines = response.text.strip().split('\n')
+            if len(lines) > 1:
+                # 取最新一条
+                latest = lines[-1].split(',')
+                if len(latest) >= 6:
+                    return {
+                        'date': latest[0],
+                        'open': float(latest[1]),
+                        'high': float(latest[2]),
+                        'low': float(latest[3]),
+                        'close': float(latest[4]),
+                        'volume': int(float(latest[5])) if latest[5] else 0
+                    }
+    except Exception as e:
+        print(f"网易历史数据获取失败: {e}")
+    return None
+
+
+def fetch_realtime_data():
+    """获取实时数据,尝试多个数据源"""
+    print("尝试获取实时数据...")
+    
+    # 尝试新浪实时
+    print("  尝试新浪实时接口...")
+    data = fetch_sina_realtime()
+    if data:
+        print(f"  ✅ 新浪实时数据获取成功")
+        return data, 'sina_realtime'
+    
+    # 尝试腾讯实时
+    print("  尝试腾讯实时接口...")
+    data = fetch_tencent_realtime()
+    if data:
+        print(f"  ✅ 腾讯实时数据获取成功")
+        return data, 'tencent_realtime'
+    
+    # 尝试获取T-1日数据
+    print("  尝试获取T-1历史数据...")
+    
+    # 网易历史数据
+    data = fetch_163_hist()
+    if data:
+        print(f"  ✅ 网易历史数据获取成功")
+        return data, '163_hist'
+    
+    print("  ❌ 所有数据源均失败")
+    return None, None
+
+
+# ==================== 趋势跟踪策略 ====================
+class TrendTrackingStrategy:
+    """趋势跟踪策略 - 实时计算版"""
+    
+    def __init__(self):
+        self.data = None
+        
+    def load_and_merge_data(self, csv_file='cyb50_baostock.csv'):
+        """加载历史数据并合并实时数据"""
+        try:
+            # 加载历史数据
+            df = pd.read_csv(f'/root/.openclaw/workspace/quant/{csv_file}')
+            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')
+            
+            # 获取最新历史数据日期
+            last_hist_date = df.index[-1]
+            today = pd.Timestamp.now().normalize()
+            
+            print(f"历史数据最新日期: {last_hist_date.date()}")
+            print(f"当前日期: {today.date()}")
+            
+            # 如果历史数据不是最新的,尝试获取实时数据
+            realtime_data = None
+            source = None
+            
+            if last_hist_date < today:
+                realtime_data, source = fetch_realtime_data()
+                
+                if realtime_data:
+                    # 处理日期格式
+                    if 'date' in realtime_data and realtime_data['date']:
+                        try:
+                            # 尝试不同日期格式
+                            date_str = str(realtime_data['date'])
+                            if len(date_str) == 8:  # YYYYMMDD
+                                date = pd.Timestamp(date_str)
+                            else:
+                                date = today
+                        except:
+                            date = today
+                    else:
+                        date = today
+                    
+                    # 检查是否已有该日期数据
+                    if date > last_hist_date:
+                        # 创建新数据行
+                        new_row = pd.DataFrame({
+                            'open': [realtime_data['open']],
+                            'high': [realtime_data['high']],
+                            'low': [realtime_data['low']],
+                            'close': [realtime_data['close']],
+                            'volume': [realtime_data['volume']]
+                        }, index=[date])
+                        
+                        # 合并数据
+                        df = pd.concat([df, new_row])
+                        print(f"✅ 已合并{source}数据: {date.date()} 收盘价 {realtime_data['close']}")
+                    else:
+                        print(f"⚠️ 获取的数据日期({date.date()})不大于历史最新日期")
+                else:
+                    print("⚠️ 未获取到更新的实时数据,使用历史数据")
+            else:
+                print("✅ 历史数据已是最新")
+            
+            self.data = df
+            print(f"数据范围: {df.index[0].date()} ~ {df.index[-1].date()}")
+            return True
+            
+        except Exception as e:
+            print(f"数据加载失败: {e}")
+            return False
+    
+    def calculate_indicators(self):
+        """计算技术指标"""
+        df = self.data.copy()
+        
+        # 均线
+        df['ma10'] = df['close'].rolling(window=10).mean()
+        df['ma30'] = df['close'].rolling(window=30).mean()
+        
+        # 20日高低点
+        df['high_20'] = df['high'].rolling(window=20).max()
+        df['low_20'] = df['low'].rolling(window=20).min()
+        
+        # 10日涨幅
+        df['ret_10'] = df['close'].pct_change(periods=10)
+        
+        # ATR
+        tr1 = df['high'] - df['low']
+        tr2 = abs(df['high'] - df['close'].shift(1))
+        tr3 = abs(df['low'] - df['close'].shift(1))
+        df['tr'] = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
+        df['atr'] = df['tr'].rolling(window=20).mean()
+        
+        self.data = df
+        return df
+    
+    def generate_signals(self):
+        """生成交易信号"""
+        df = self.data
+        
+        # 买入条件
+        buy_cond = (
+            (df['close'] > df['ma10']) & 
+            (df['ma10'] > df['ma30']) & 
+            (df['close'] >= df['high_20'] * 0.995) & 
+            (df['ret_10'] > 0.02)
+        )
+        
+        # 卖出条件
+        sell_cond = (
+            (df['close'] < df['ma30']) | 
+            (df['close'] <= df['low_20'] * 1.005)
+        )
+        
+        df['signal'] = 0
+        df.loc[buy_cond, 'signal'] = 1
+        df.loc[sell_cond, 'signal'] = -1
+        
+        return df
+    
+    def backtest(self, initial_capital=1000000):
+        """回测计算"""
+        df = self.generate_signals()
+        
+        position = 0
+        entry_price = 0
+        peak_price = 0
+        capital = initial_capital
+        trades = []
+        
+        for i in range(30, len(df)):
+            date = df.index[i]
+            price = df['close'].iloc[i]
+            signal = df['signal'].iloc[i]
+            
+            # 移动止损检查
+            if position > 0:
+                if price > peak_price:
+                    peak_price = price
+                if price < peak_price * 0.90:  # 10%回撤止损
+                    signal = -1
+            
+            # 执行交易
+            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
+                position = 0
+                trades.append({
+                    'date': date,
+                    'action': 'SELL',
+                    'price': price,
+                    'capital': capital,
+                    'pnl': pnl,
+                    'return_pct': (price / entry_price - 1) * 100
+                })
+        
+        # 计算当前持仓
+        current_position = position
+        current_price = df['close'].iloc[-1]
+        
+        if position == 1:
+            unrealized_pnl = (current_price / entry_price - 1) * capital
+            total_value = capital + unrealized_pnl
+        else:
+            total_value = capital
+        
+        total_return = (total_value / initial_capital - 1) * 100
+        
+        return {
+            'trades': trades,
+            'current_position': current_position,
+            'current_price': current_price,
+            'entry_price': entry_price if position == 1 else None,
+            'capital': capital,
+            'total_value': total_value,
+            'total_return': total_return,
+            'trade_count': len([t for t in trades if t['action'] == 'SELL']),
+            'data_end_date': df.index[-1].strftime('%Y-%m-%d')
+        }
+    
+    def get_recent_indicators(self, days=20):
+        """获取近N天指标详情"""
+        df = self.data.tail(days).copy()
+        
+        indicators = []
+        for date, row in df.iterrows():
+            indicators.append({
+                'date': date.strftime('%Y-%m-%d'),
+                'close': round(row['close'], 2),
+                'ma10': round(row['ma10'], 2) if not pd.isna(row['ma10']) else '-',
+                'ma30': round(row['ma30'], 2) if not pd.isna(row['ma30']) else '-',
+                'high_20': round(row['high_20'], 2) if not pd.isna(row['high_20']) else '-',
+                'ret_10': f"{row['ret_10']*100:.2f}%" if not pd.isna(row['ret_10']) else '-',
+                'signal': '买入' if row['signal'] == 1 else ('卖出' if row['signal'] == -1 else '持有'),
+                'atr': round(row['atr'], 2) if not pd.isna(row['atr']) else '-'
+            })
+        
+        return indicators
+    
+    def get_recent_trades(self, n=20):
+        """获取近N次交易详情"""
+        result = self.backtest()
+        trades = result['trades'][-n:]
+        return trades
+
+
+def generate_report():
+    """生成完整报告"""
+    strategy = TrendTrackingStrategy()
+    
+    if not strategy.load_and_merge_data():
+        return None, None, None
+    
+    strategy.calculate_indicators()
+    result = strategy.backtest()
+    
+    # 获取近期数据
+    recent_indicators = strategy.get_recent_indicators(20)
+    recent_trades = strategy.get_recent_trades(20)
+    
+    # 生成HTML报告
+    html = f"""
+    <html>
+    <head>
+        <meta charset="utf-8">
+        <style>
+            body {{ font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }}
+            .container {{ max-width: 1200px; margin: 0 auto; background: white; padding: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }}
+            h1 {{ color: #333; border-bottom: 3px solid #007bff; padding-bottom: 10px; }}
+            h2 {{ color: #555; margin-top: 30px; border-left: 4px solid #007bff; padding-left: 10px; }}
+            .summary {{ background: #f8f9fa; padding: 15px; border-radius: 5px; margin: 20px 0; }}
+            .metric {{ display: inline-block; margin: 10px 20px 10px 0; }}
+            .metric-label {{ color: #666; font-size: 12px; }}
+            .metric-value {{ font-size: 24px; font-weight: bold; color: #333; }}
+            .positive {{ color: #28a745; }}
+            .negative {{ color: #dc3545; }}
+            table {{ width: 100%; border-collapse: collapse; margin: 20px 0; font-size: 13px; }}
+            th {{ background: #007bff; color: white; padding: 10px; text-align: left; }}
+            td {{ padding: 8px 10px; border-bottom: 1px solid #ddd; }}
+            tr:nth-child(even) {{ background: #f8f9fa; }}
+            tr:hover {{ background: #e9ecef; }}
+            .position-yes {{ color: #28a745; font-weight: bold; }}
+            .position-no {{ color: #666; }}
+            .buy {{ color: #28a745; font-weight: bold; }}
+            .sell {{ color: #dc3545; font-weight: bold; }}
+            .data-info {{ background: #e7f3ff; padding: 10px; border-radius: 5px; margin: 10px 0; color: #004085; }}
+        </style>
+    </head>
+    <body>
+        <div class="container">
+            <h1>🚀 创业板50趋势跟踪策略报告</h1>
+            <p style="color: #666;">生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
+            
+            <div class="data-info">
+                <strong>数据更新:</strong> 已合并历史数据与实时数据,最新数据日期: {result['data_end_date']}
+            </div>
+            
+            <div class="summary">
+                <h2>📊 总体绩效</h2>
+                <div class="metric">
+                    <div class="metric-label">当前持仓</div>
+                    <div class="metric-value {'position-yes' if result['current_position'] == 1 else 'position-no'}">
+                        {'持有中' if result['current_position'] == 1 else '空仓'}
+                    </div>
+                </div>
+                <div class="metric">
+                    <div class="metric-label">当前价格</div>
+                    <div class="metric-value">{result['current_price']:.2f}</div>
+                </div>
+                <div class="metric">
+                    <div class="metric-label">累计收益率</div>
+                    <div class="metric-value {'positive' if result['total_return'] >= 0 else 'negative'}">
+                        {result['total_return']:+.2f}%
+                    </div>
+                </div>
+                <div class="metric">
+                    <div class="metric-label">总资产</div>
+                    <div class="metric-value">{result['total_value']:,.0f}元</div>
+                </div>
+                <div class="metric">
+                    <div class="metric-label">交易次数</div>
+                    <div class="metric-value">{result['trade_count']}</div>
+                </div>
+            </div>
+    """
+    
+    # 持仓详情
+    if result['current_position'] == 1:
+        unrealized = (result['current_price'] / result['entry_price'] - 1) * 100
+        html += f"""
+            <div class="summary" style="background: #e8f5e9;">
+                <h2>📈 持仓详情</h2>
+                <p><strong>入场价格:</strong> {result['entry_price']:.2f} 元</p>
+                <p><strong>当前浮盈:</strong> <span class="{'positive' if unrealized >= 0 else 'negative'}">{unrealized:+.2f}%</span></p>
+            </div>
+        """
+    
+    # 近20天指标
+    html += """
+            <h2>📅 近20天指标详情</h2>
+            <table>
+                <tr>
+                    <th>日期</th>
+                    <th>收盘价</th>
+                    <th>MA10</th>
+                    <th>MA30</th>
+                    <th>20日高</th>
+                    <th>10日涨幅</th>
+                    <th>信号</th>
+                    <th>ATR</th>
+                </tr>
+    """
+    
+    for ind in recent_indicators:
+        signal_class = 'buy' if ind['signal'] == '买入' else ('sell' if ind['signal'] == '卖出' else '')
+        html += f"""
+                <tr>
+                    <td>{ind['date']}</td>
+                    <td>{ind['close']}</td>
+                    <td>{ind['ma10']}</td>
+                    <td>{ind['ma30']}</td>
+                    <td>{ind['high_20']}</td>
+                    <td>{ind['ret_10']}</td>
+                    <td class="{signal_class}">{ind['signal']}</td>
+                    <td>{ind['atr']}</td>
+                </tr>
+        """
+    
+    html += """
+            </table>
+            
+            <h2>💼 近20次交易详情</h2>
+            <table>
+                <tr>
+                    <th>日期</th>
+                    <th>操作</th>
+                    <th>价格</th>
+                    <th>盈亏金额</th>
+                    <th>盈亏比例</th>
+                    <th>总资产</th>
+                </tr>
+    """
+    
+    for trade in recent_trades:
+        action_class = 'buy' if trade['action'] == 'BUY' else 'sell'
+        pnl = trade.get('pnl', 0)
+        ret = trade.get('return_pct', 0)
+        html += f"""
+                <tr>
+                    <td>{trade['date'].strftime('%Y-%m-%d') if isinstance(trade['date'], pd.Timestamp) else trade['date']}</td>
+                    <td class="{action_class}">{trade['action']}</td>
+                    <td>{trade['price']:.2f}</td>
+                    <td>{f'{pnl:+,.0f}元' if 'pnl' in trade else '-'}</td>
+                    <td class="{'positive' if ret >= 0 else 'negative'}">{f'{ret:+.2f}%' if 'return_pct' in trade else '-'}</td>
+                    <td>{trade['capital']:,.0f}元</td>
+                </tr>
+        """
+    
+    html += """
+            </table>
+            
+            <div style="margin-top: 30px; padding: 15px; background: #fff3cd; border-radius: 5px; color: #856404;">
+                <strong>策略说明:</strong><br>
+                • 买入条件: 价格>MA10>MA30 且 突破20日高×0.995 且 10日涨幅>2%<br>
+                • 卖出条件: 跌破MA30 或 创20日新低 或 回撤10%止损<br>
+                • 数据更新: 已合并历史数据与实时市场数据(支持新浪/腾讯/网易多数据源)
+            </div>
+        </div>
+    </body>
+    </html>
+    """
+    
+    # 生成文本报告
+    text = f"""
+创业板50趋势跟踪策略报告
+生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
+数据最新日期: {result['data_end_date']}
+
+【总体绩效】
+当前持仓: {'持有中' if result['current_position'] == 1 else '空仓'}
+当前价格: {result['current_price']:.2f}元
+累计收益率: {result['total_return']:+.2f}%
+总资产: {result['total_value']:,.0f}元
+交易次数: {result['trade_count']}
+
+【近20天指标】
+日期        收盘价    MA10     MA30     20日高   10日涨幅  信号  ATR
+"""
+    
+    for ind in recent_indicators:
+        text += f"{ind['date']}  {ind['close']:>8}  {ind['ma10']:>8}  {ind['ma30']:>8}  {ind['high_20']:>8}  {ind['ret_10']:>8}  {ind['signal']:>4}  {ind['atr']:>6}\n"
+    
+    text += "\n【近20次交易】\n"
+    text += "日期        操作    价格      盈亏金额     盈亏比例    总资产\n"
+    
+    for trade in recent_trades:
+        pnl_str = f"{trade.get('pnl', 0):+,.0f}元" if 'pnl' in trade else '-'
+        ret_str = f"{trade.get('return_pct', 0):+.2f}%" if 'return_pct' in trade else '-'
+        date_str = trade['date'].strftime('%Y-%m-%d') if isinstance(trade['date'], pd.Timestamp) else trade['date']
+        text += f"{date_str}  {trade['action']:>6}  {trade['price']:>8.2f}  {pnl_str:>12}  {ret_str:>10}  {trade['capital']:>12,.0f}元\n"
+    
+    return html, text, result
+
+
+def send_email(subject, html_content, text_content):
+    """发送邮件"""
+    try:
+        msg = MIMEMultipart('alternative')
+        msg['Subject'] = Header(subject, 'utf-8')
+        msg['From'] = EMAIL_CONFIG['sender_email']
+        msg['To'] = EMAIL_CONFIG['receiver_email']
+        
+        text_part = MIMEText(text_content, 'plain', 'utf-8')
+        msg.attach(text_part)
+        
+        html_part = MIMEText(html_content, 'html', 'utf-8')
+        msg.attach(html_part)
+        
+        with smtplib.SMTP(EMAIL_CONFIG['smtp_server'], EMAIL_CONFIG['smtp_port']) as server:
+            server.sendmail(
+                EMAIL_CONFIG['sender_email'],
+                EMAIL_CONFIG['receiver_email'],
+                msg.as_string()
+            )
+        print(f"✅ 邮件发送成功: {subject}")
+        return True
+    except Exception as e:
+        print(f"❌ 邮件发送失败: {e}")
+        return False
+
+
+def main():
+    """主程序"""
+    print("="*60)
+    print("🚀 创业板50趋势跟踪实时报告 (多数据源)")
+    print("="*60)
+    print(f"执行时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
+    
+    # 生成报告
+    print("\n📊 加载数据并生成报告中...")
+    html, text, result = generate_report()
+    
+    if html is None:
+        print("❌ 报告生成失败")
+        return
+    
+    print(f"✅ 报告生成完成")
+    print(f"   数据最新日期: {result['data_end_date']}")
+    print(f"   当前持仓: {'持有中' if result['current_position'] == 1 else '空仓'}")
+    print(f"   累计收益: {result['total_return']:+.2f}%")
+    print(f"   交易次数: {result['trade_count']}")
+    
+    # 发送邮件
+    print("\n📧 发送邮件...")
+    position_status = "持仓" if result['current_position'] == 1 else "空仓"
+    subject = f"🚀 创业板50趋势报告 {datetime.now().strftime('%m-%d %H:%M')} | {position_status} | 收益{result['total_return']:+.2f}%"
+    send_email(subject, html, text)
+    
+    print("\n✅ 全部完成!")
+    print("="*60)
+
+
+if __name__ == "__main__":
+    main()

+ 819 - 0
cat-fly/trend_report_multi_source.py

@@ -0,0 +1,819 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+创业板50指数 - 多数据源交叉验证版
+确保数据准确性
+"""
+
+import sys
+sys.path.insert(0, '/root/.openclaw/workspace/cat-fly')
+sys.path.insert(0, '/root/.openclaw/workspace/quant')
+
+import pandas as pd
+import numpy as np
+from datetime import datetime, timedelta
+import smtplib
+from email.mime.text import MIMEText
+from email.mime.multipart import MIMEMultipart
+from email.header import Header
+import warnings
+import requests
+import json
+import time
+import baostock as bs
+warnings.filterwarnings('ignore')
+
+# ==================== 邮件配置 ====================
+EMAIL_CONFIG = {
+    "smtp_server": "localhost",
+    "smtp_port": 25,
+    "sender_email": "catfly@openclaw.local",
+    "receiver_email": "380880504@qq.com"
+}
+
+# ==================== 数据源配置 ====================
+DATA_SOURCES = {
+    'baostock': {'priority': 1, 'weight': 0.4},
+    'akshare': {'priority': 2, 'weight': 0.3},
+    'sina': {'priority': 3, 'weight': 0.15},
+    'tencent': {'priority': 4, 'weight': 0.15}
+}
+
+# ==================== 多数据源获取 ====================
+
+class DataValidator:
+    """数据验证器 - 交叉验证多个数据源"""
+    
+    PRICE_TOLERANCE = 0.02  # 价格差异容忍度 2%
+    
+    @staticmethod
+    def validate_prices(sources_data):
+        """
+        验证多个数据源的价格一致性
+        返回: (validated_data, warnings)
+        """
+        if not sources_data:
+            return None, ["无可用数据源"]
+        
+        if len(sources_data) == 1:
+            return sources_data[0]['data'], []
+        
+        # 提取收盘价
+        prices = {}
+        for src in sources_data:
+            if src and 'data' in src and src['data']:
+                prices[src['source']] = src['data'].get('close', 0)
+        
+        if len(prices) < 2:
+            return sources_data[0]['data'], []
+        
+        # 计算价格统计
+        price_values = list(prices.values())
+        price_mean = np.mean(price_values)
+        price_std = np.std(price_values)
+        price_max = max(price_values)
+        price_min = min(price_values)
+        price_range = (price_max - price_min) / price_mean if price_mean > 0 else 0
+        
+        warnings = []
+        
+        # 检查价格差异
+        if price_range > DataValidator.PRICE_TOLERANCE:
+            warnings.append(f"⚠️ 价格差异过大: {price_range*100:.2f}% (容忍度: {DataValidator.PRICE_TOLERANCE*100}%)")
+            for src, price in prices.items():
+                deviation = (price - price_mean) / price_mean * 100
+                warnings.append(f"  - {src}: {price:.2f} (偏离均值: {deviation:+.2f}%)")
+        
+        # 使用加权平均价格
+        weighted_price = 0
+        total_weight = 0
+        for src in sources_data:
+            if src and 'data' in src and src['data']:
+                source_name = src['source']
+                weight = DATA_SOURCES.get(source_name, {}).get('weight', 0.25)
+                weighted_price += src['data']['close'] * weight
+                total_weight += weight
+        
+        if total_weight > 0:
+            weighted_price /= total_weight
+        
+        # 选择最接近加权平均的数据源
+        best_source = None
+        min_diff = float('inf')
+        for src in sources_data:
+            if src and 'data' in src and src['data']:
+                diff = abs(src['data']['close'] - weighted_price)
+                if diff < min_diff:
+                    min_diff = diff
+                    best_source = src
+        
+        if warnings:
+            warnings.append(f"✅ 使用加权平均价格: {weighted_price:.2f}")
+            if best_source:
+                warnings.append(f"✅ 选择数据源: {best_source['source']} (价格: {best_source['data']['close']:.2f})")
+        
+        return best_source['data'] if best_source else sources_data[0]['data'], warnings
+
+
+def fetch_sina_realtime():
+    """新浪实时行情接口"""
+    try:
+        url = "https://hq.sinajs.cn/list=sz399673"
+        headers = {
+            'Referer': 'https://finance.sina.com.cn',
+            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
+        }
+        response = requests.get(url, headers=headers, timeout=10)
+        response.encoding = 'gb2312'
+        
+        data_str = response.text
+        if 'var hq_str_sz399673="' in data_str:
+            data_str = data_str.split('var hq_str_sz399673="')[1].split('"')[0]
+            parts = data_str.split(',')
+            if len(parts) >= 32:
+                date_str = parts[30].strip()
+                if len(date_str) == 8 and date_str.isdigit():
+                    date = pd.Timestamp(f"{date_str[:4]}-{date_str[4:6]}-{date_str[6:8]}")
+                else:
+                    date = pd.Timestamp.now().normalize()
+                
+                return {
+                    'source': 'sina',
+                    'data': {
+                        'open': float(parts[1]),
+                        'high': float(parts[4]),
+                        'low': float(parts[5]),
+                        'close': float(parts[3]),
+                        'volume': int(parts[8]),
+                        'date': date
+                    }
+                }
+    except Exception as e:
+        print(f"  新浪实时数据获取失败: {e}")
+    return None
+
+
+def fetch_tencent_realtime():
+    """腾讯实时行情接口"""
+    try:
+        url = "https://qt.gtimg.cn/q=sz399673"
+        headers = {
+            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
+        }
+        response = requests.get(url, headers=headers, timeout=10)
+        response.encoding = 'gb2312'
+        
+        data_str = response.text
+        if 'v_sz399673="' in data_str:
+            data_str = data_str.split('v_sz399673="')[1].split('"')[0]
+            parts = data_str.split('~')
+            if len(parts) >= 45:
+                date_str = parts[30]
+                date = pd.Timestamp(date_str)
+                
+                return {
+                    'source': 'tencent',
+                    'data': {
+                        'close': float(parts[3]),
+                        'open': float(parts[5]),
+                        'high': float(parts[33]),
+                        'low': float(parts[34]),
+                        'volume': int(parts[36]),
+                        'date': date
+                    }
+                }
+    except Exception as e:
+        print(f"  腾讯实时数据获取失败: {e}")
+    return None
+
+
+def fetch_akshare_hist(start_date, end_date):
+    """使用akshare获取历史数据"""
+    try:
+        import akshare as ak
+        print(f"  [akshare] 获取 {start_date} 到 {end_date} 的历史数据...")
+        
+        df = ak.index_zh_a_hist(symbol="399673", period="daily", 
+                                start_date=start_date, end_date=end_date)
+        
+        if df is not None and len(df) > 0:
+            data_list = []
+            for _, row in df.iterrows():
+                data_list.append({
+                    'date': pd.Timestamp(row['日期']),
+                    'open': float(row['开盘']),
+                    'high': float(row['最高']),
+                    'low': float(row['最低']),
+                    'close': float(row['收盘']),
+                    'volume': int(row['成交量'])
+                })
+            print(f"  [akshare] ✅ 获取成功: {len(data_list)} 条")
+            return data_list
+    except Exception as e:
+        print(f"  [akshare] ❌ 获取失败: {e}")
+    return None
+
+
+def fetch_baostock_hist(start_date, end_date):
+    """使用baostock获取历史数据"""
+    try:
+        print(f"  [baostock] 获取 {start_date} 到 {end_date} 的历史数据...")
+        
+        lg = bs.login()
+        if lg.error_code != '0':
+            print(f"  [baostock] ❌ 登录失败: {lg.error_msg}")
+            return None
+        
+        rs = bs.query_history_k_data_plus("sz.399673",
+            "date,open,high,low,close,volume",
+            start_date=start_date, end_date=end_date,
+            frequency="d", adjustflag="3")
+        
+        data_list = []
+        while (rs.error_code == '0') & rs.next():
+            row = rs.get_row_data()
+            if row[0]:
+                data_list.append({
+                    'date': pd.Timestamp(row[0]),
+                    'open': float(row[1]) if row[1] else 0,
+                    'high': float(row[2]) if row[2] else 0,
+                    'low': float(row[3]) if row[3] else 0,
+                    'close': float(row[4]) if row[4] else 0,
+                    'volume': int(float(row[5])) if row[5] else 0
+                })
+        
+        bs.logout()
+        
+        if data_list:
+            print(f"  [baostock] ✅ 获取成功: {len(data_list)} 条")
+            return data_list
+    except Exception as e:
+        print(f"  [baostock] ❌ 获取失败: {e}")
+    return None
+
+
+def fetch_multi_source_realtime():
+    """从多个源获取实时数据并交叉验证"""
+    print("\n📊 多数据源获取实时数据...")
+    
+    sources = []
+    
+    # 获取新浪数据
+    sina_data = fetch_sina_realtime()
+    if sina_data:
+        sources.append(sina_data)
+        print(f"  [新浪]    收盘价: {sina_data['data']['close']:.2f}")
+    
+    # 获取腾讯数据
+    tencent_data = fetch_tencent_realtime()
+    if tencent_data:
+        sources.append(tencent_data)
+        print(f"  [腾讯]    收盘价: {tencent_data['data']['close']:.2f}")
+    
+    # 交叉验证
+    validated_data, warnings = DataValidator.validate_prices(sources)
+    
+    if warnings:
+        print("\n  ⚠️ 数据验证警告:")
+        for w in warnings:
+            print(f"     {w}")
+    
+    if validated_data:
+        print(f"\n  ✅ 最终使用收盘价: {validated_data['close']:.2f}")
+        return validated_data, sources
+    
+    return None, []
+
+
+def fetch_missing_data_multi_source(last_date, today):
+    """使用多个源获取缺失的历史数据"""
+    if last_date >= today:
+        return [], []
+    
+    start_str = (last_date + timedelta(days=1)).strftime('%Y-%m-%d')
+    end_str = (today - timedelta(days=1)).strftime('%Y-%m-%d')
+    
+    print(f"\n📊 补全缺失数据: {start_str} 到 {end_str}")
+    
+    all_warnings = []
+    
+    # 尝试baostock (优先级高)
+    data = fetch_baostock_hist(start_str, end_str)
+    if data:
+        return data, all_warnings
+    
+    # 尝试akshare
+    data = fetch_akshare_hist(start_str.replace('-', ''), end_str.replace('-', ''))
+    if data:
+        return data, all_warnings
+    
+    all_warnings.append(f"⚠️ 无法获取 {start_str} 到 {end_str} 的历史数据")
+    return [], all_warnings
+
+
+# ==================== 趋势跟踪策略 ====================
+class TrendTrackingStrategy:
+    """趋势跟踪策略 - 多数据源验证版"""
+    
+    def __init__(self):
+        self.data = None
+        self.warnings = []
+        self.data_sources = []
+        
+    def load_and_merge_data(self, csv_file='cyb50_baostock.csv'):
+        """加载历史数据并合并实时数据"""
+        try:
+            # 加载历史数据
+            df = pd.read_csv(f'/root/.openclaw/workspace/quant/{csv_file}')
+            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')
+            
+            last_hist_date = df.index[-1]
+            today = pd.Timestamp.now().normalize()
+            
+            print(f"历史数据最新日期: {last_hist_date.date()}")
+            print(f"当前日期: {today.date()}")
+            
+            # 获取缺失的历史数据
+            missing_data, warnings = fetch_missing_data_multi_source(last_hist_date, today)
+            self.warnings.extend(warnings)
+            
+            if missing_data:
+                for item in missing_data:
+                    new_row = pd.DataFrame({
+                        'open': [item['open']],
+                        'high': [item['high']],
+                        'low': [item['low']],
+                        'close': [item['close']],
+                        'volume': [item['volume']]
+                    }, index=[item['date']])
+                    df = pd.concat([df, new_row])
+                
+                df = df.sort_index()
+                last_hist_date = df.index[-1]
+                print(f"✅ 已合并历史数据,最新日期: {last_hist_date.date()}")
+            
+            # 获取今天的实时数据(多源验证)
+            if last_hist_date < today:
+                realtime_data, sources = fetch_multi_source_realtime()
+                self.data_sources = sources
+                
+                if realtime_data:
+                    date = realtime_data['date']
+                    
+                    if date > last_hist_date:
+                        new_row = pd.DataFrame({
+                            'open': [realtime_data['open']],
+                            'high': [realtime_data['high']],
+                            'low': [realtime_data['low']],
+                            'close': [realtime_data['close']],
+                            'volume': [realtime_data['volume']]
+                        }, index=[date])
+                        
+                        df = pd.concat([df, new_row])
+                        print(f"✅ 已合并实时数据: {date.date()} 收盘价 {realtime_data['close']:.2f}")
+                    else:
+                        print(f"⚠️ 实时数据日期({date.date()})不大于历史最新日期")
+                else:
+                    self.warnings.append("⚠️ 未获取到实时数据")
+            else:
+                print("✅ 历史数据已是最新")
+            
+            self.data = df.sort_index()
+            print(f"\n数据范围: {self.data.index[0].date()} ~ {self.data.index[-1].date()}")
+            print(f"数据条数: {len(self.data)}")
+            
+            return True
+            
+        except Exception as e:
+            print(f"❌ 数据加载失败: {e}")
+            import traceback
+            traceback.print_exc()
+            return False
+    
+    def calculate_indicators(self):
+        """计算技术指标"""
+        df = self.data.copy()
+        
+        # 均线
+        df['ma10'] = df['close'].rolling(window=10, min_periods=1).mean()
+        df['ma30'] = df['close'].rolling(window=30, min_periods=1).mean()
+        
+        # 20日高低点
+        df['high_20'] = df['high'].rolling(window=20).max()
+        df['low_20'] = df['low'].rolling(window=20).min()
+        
+        # 10日涨幅
+        df['ret_10'] = df['close'].pct_change(periods=10)
+        
+        # ATR
+        tr1 = df['high'] - df['low']
+        tr2 = abs(df['high'] - df['close'].shift(1))
+        tr3 = abs(df['low'] - df['close'].shift(1))
+        df['tr'] = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
+        df['atr'] = df['tr'].rolling(window=20).mean()
+        
+        self.data = df
+        return df
+    
+    def generate_signals(self):
+        """生成交易信号"""
+        df = self.data
+        
+        # 买入条件
+        buy_cond = (
+            (df['close'] > df['ma10']) & 
+            (df['ma10'] > df['ma30']) & 
+            (df['close'] >= df['high_20'] * 0.995) & 
+            (df['ret_10'] > 0.02)
+        )
+        
+        # 卖出条件
+        sell_cond = (
+            (df['close'] < df['ma30']) | 
+            (df['close'] <= df['low_20'] * 1.005)
+        )
+        
+        df['signal'] = 0
+        df.loc[buy_cond, 'signal'] = 1
+        df.loc[sell_cond, 'signal'] = -1
+        
+        return df
+    
+    def backtest(self, initial_capital=1000000):
+        """回测计算"""
+        df = self.generate_signals()
+        
+        position = 0
+        entry_price = 0
+        peak_price = 0
+        capital = initial_capital
+        trades = []
+        
+        for i in range(30, len(df)):
+            date = df.index[i]
+            price = df['close'].iloc[i]
+            signal = df['signal'].iloc[i]
+            
+            # 移动止损检查
+            if position > 0:
+                if price > peak_price:
+                    peak_price = price
+                if price < peak_price * 0.90:
+                    signal = -1
+            
+            # 买入
+            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
+                position = 0
+                trades.append({
+                    'date': date,
+                    'action': 'SELL',
+                    'price': price,
+                    'capital': capital,
+                    'pnl': pnl,
+                    'return_pct': (price / entry_price - 1) * 100
+                })
+        
+        current_position = position
+        current_price = df['close'].iloc[-1]
+        
+        if position == 1:
+            unrealized_pnl = (current_price / entry_price - 1) * capital
+            total_value = capital + unrealized_pnl
+        else:
+            total_value = capital
+        
+        total_return = (total_value / initial_capital - 1) * 100
+        
+        return {
+            'trades': trades,
+            'current_position': current_position,
+            'current_price': current_price,
+            'entry_price': entry_price if position == 1 else None,
+            'capital': capital,
+            'total_value': total_value,
+            'total_return': total_return,
+            'trade_count': len([t for t in trades if t['action'] == 'SELL']),
+            'data_end_date': df.index[-1].strftime('%Y-%m-%d')
+        }
+    
+    def get_recent_indicators(self, days=20):
+        """获取近N天指标详情"""
+        df = self.data.tail(days).copy()
+        
+        indicators = []
+        for date, row in df.iterrows():
+            indicators.append({
+                'date': date.strftime('%Y-%m-%d'),
+                'close': round(row['close'], 2),
+                'ma10': round(row['ma10'], 2) if not pd.isna(row['ma10']) else '-',
+                'ma30': round(row['ma30'], 2) if not pd.isna(row['ma30']) else '-',
+                'high_20': round(row['high_20'], 2) if not pd.isna(row['high_20']) else '-',
+                'ret_10': f"{row['ret_10']*100:.2f}%" if not pd.isna(row['ret_10']) else '-',
+                'signal': '买入' if row['signal'] == 1 else ('卖出' if row['signal'] == -1 else '持有'),
+                'atr': round(row['atr'], 2) if not pd.isna(row['atr']) else '-'
+            })
+        
+        return indicators
+    
+    def get_recent_trades(self, n=20):
+        """获取近N次交易详情"""
+        result = self.backtest()
+        trades = result['trades'][-n:]
+        return trades
+
+
+def generate_report():
+    """生成完整报告"""
+    strategy = TrendTrackingStrategy()
+    
+    if not strategy.load_and_merge_data():
+        return None, None, None
+    
+    strategy.calculate_indicators()
+    result = strategy.backtest()
+    
+    recent_indicators = strategy.get_recent_indicators(20)
+    recent_trades = strategy.get_recent_trades(20)
+    
+    # 数据源信息
+    source_info = ""
+    if strategy.data_sources:
+        source_info = "<div class='data-info'><strong>数据来源:</strong> "
+        for src in strategy.data_sources:
+            source_info += f"{src['source']}({src['data']['close']:.2f}) "
+        source_info += "| 已交叉验证</div>"
+    
+    # 警告信息
+    warnings_html = ""
+    if strategy.warnings:
+        warnings_html = "<div class='warning'><strong>⚠️ 警告:</strong><br>" + "<br>".join(strategy.warnings) + "</div>"
+    
+    html = f"""
+    <html>
+    <head>
+        <meta charset="utf-8">
+        <style>
+            body {{ font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }}
+            .container {{ max-width: 1200px; margin: 0 auto; background: white; padding: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }}
+            h1 {{ color: #333; border-bottom: 3px solid #007bff; padding-bottom: 10px; }}
+            h2 {{ color: #555; margin-top: 30px; border-left: 4px solid #007bff; padding-left: 10px; }}
+            .summary {{ background: #f8f9fa; padding: 15px; border-radius: 5px; margin: 20px 0; }}
+            .metric {{ display: inline-block; margin: 10px 20px 10px 0; }}
+            .metric-label {{ color: #666; font-size: 12px; }}
+            .metric-value {{ font-size: 24px; font-weight: bold; color: #333; }}
+            .positive {{ color: #28a745; }}
+            .negative {{ color: #dc3545; }}
+            .warning {{ background: #fff3cd; color: #856404; padding: 10px; border-radius: 5px; margin: 10px 0; }}
+            .data-info {{ background: #e7f3ff; padding: 10px; border-radius: 5px; margin: 10px 0; color: #004085; }}
+            table {{ width: 100%; border-collapse: collapse; margin: 20px 0; font-size: 13px; }}
+            th {{ background: #007bff; color: white; padding: 10px; text-align: left; }}
+            td {{ padding: 8px 10px; border-bottom: 1px solid #ddd; }}
+            tr:nth-child(even) {{ background: #f8f9fa; }}
+            tr:hover {{ background: #e9ecef; }}
+            .position-yes {{ color: #28a745; font-weight: bold; }}
+            .position-no {{ color: #666; }}
+            .buy {{ color: #28a745; font-weight: bold; }}
+            .sell {{ color: #dc3545; font-weight: bold; }}
+        </style>
+    </head>
+    <body>
+        <div class="container">
+            <h1>🚀 创业板50趋势跟踪策略报告 (多源验证版)</h1>
+            <p style="color: #666;">生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
+            
+            {warnings_html}
+            {source_info}
+            
+            <div class="data-info">
+                <strong>数据更新:</strong> 最新数据日期: {result['data_end_date']} | 
+                数据范围: {strategy.data.index[0].date()} ~ {strategy.data.index[-1].date()}
+            </div>
+            
+            <div class="summary">
+                <h2>📊 总体绩效</h2>
+                <div class="metric">
+                    <div class="metric-label">当前持仓</div>
+                    <div class="metric-value {'position-yes' if result['current_position'] == 1 else 'position-no'}">
+                        {'持有中' if result['current_position'] == 1 else '空仓'}
+                    </div>
+                </div>
+                <div class="metric">
+                    <div class="metric-label">当前价格</div>
+                    <div class="metric-value">{result['current_price']:.2f}</div>
+                </div>
+                <div class="metric">
+                    <div class="metric-label">累计收益率</div>
+                    <div class="metric-value {'positive' if result['total_return'] >= 0 else 'negative'}">
+                        {result['total_return']:+.2f}%
+                    </div>
+                </div>
+                <div class="metric">
+                    <div class="metric-label">总资产</div>
+                    <div class="metric-value">{result['total_value']:,.0f}元</div>
+                </div>
+                <div class="metric">
+                    <div class="metric-label">交易次数</div>
+                    <div class="metric-value">{result['trade_count']}</div>
+                </div>
+            </div>
+    """
+    
+    if result['current_position'] == 1:
+        unrealized = (result['current_price'] / result['entry_price'] - 1) * 100
+        html += f"""
+            <div class="summary" style="background: #e8f5e9;">
+                <h2>📈 持仓详情</h2>
+                <p><strong>入场价格:</strong> {result['entry_price']:.2f} 元</p>
+                <p><strong>当前浮盈:</strong> <span class="{'positive' if unrealized >= 0 else 'negative'}">{unrealized:+.2f}%</span></p>
+            </div>
+        """
+    
+    # 近20天指标
+    html += """
+            <h2>📅 近20天指标详情</h2>
+            <table>
+                <tr>
+                    <th>日期</th>
+                    <th>收盘价</th>
+                    <th>MA10</th>
+                    <th>MA30</th>
+                    <th>20日高</th>
+                    <th>10日涨幅</th>
+                    <th>信号</th>
+                    <th>ATR</th>
+                </tr>
+    """
+    
+    for ind in recent_indicators:
+        signal_class = 'buy' if ind['signal'] == '买入' else ('sell' if ind['signal'] == '卖出' else '')
+        html += f"""
+                <tr>
+                    <td>{ind['date']}</td>
+                    <td>{ind['close']}</td>
+                    <td>{ind['ma10']}</td>
+                    <td>{ind['ma30']}</td>
+                    <td>{ind['high_20']}</td>
+                    <td>{ind['ret_10']}</td>
+                    <td class="{signal_class}">{ind['signal']}</td>
+                    <td>{ind['atr']}</td>
+                </tr>
+        """
+    
+    html += """
+            </table>
+            
+            <h2>💼 近20次交易详情</h2>
+            <table>
+                <tr>
+                    <th>日期</th>
+                    <th>操作</th>
+                    <th>价格</th>
+                    <th>盈亏金额</th>
+                    <th>盈亏比例</th>
+                    <th>总资产</th>
+                </tr>
+    """
+    
+    for trade in recent_trades:
+        action_class = 'buy' if trade['action'] == 'BUY' else 'sell'
+        pnl = trade.get('pnl', 0)
+        ret = trade.get('return_pct', 0)
+        has_pnl = 'pnl' in trade
+        date_str = trade['date'].strftime('%Y-%m-%d') if hasattr(trade['date'], 'strftime') else str(trade['date'])
+        
+        ret_class = '' if not has_pnl else ('positive' if ret >= 0 else 'negative')
+        ret_text = '-' if not has_pnl else f'{ret:+.2f}%'
+        
+        html += f"""
+                <tr>
+                    <td>{date_str}</td>
+                    <td class="{action_class}">{trade['action']}</td>
+                    <td>{trade['price']:.2f}</td>
+                    <td>{f'{pnl:+,.0f}元' if has_pnl else '-'}</td>
+                    <td class="{ret_class}">{ret_text}</td>
+                    <td>{trade['capital']:,.0f}元</td>
+                </tr>
+        """
+    
+    html += """
+            </table>
+            
+            <div style="margin-top: 30px; padding: 15px; background: #fff3cd; border-radius: 5px; color: #856404;">
+                <strong>策略说明:</strong><br>
+                • 买入条件: 价格>MA10>MA30 且 突破20日高×0.995 且 10日涨幅>2%<br>
+                • 卖出条件: 跌破MA30 或 创20日新低 或 回撤10%止损<br>
+                • 数据验证: 多源交叉验证,差异>2%时报警
+            </div>
+        </div>
+    </body>
+    </html>
+    """
+    
+    # 文本报告
+    text = f"""
+创业板50趋势跟踪策略报告 (多源验证版)
+生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
+数据最新日期: {result['data_end_date']}
+"""
+    
+    if strategy.warnings:
+        text += "\n警告:\n" + "\n".join(strategy.warnings) + "\n"
+    
+    text += f"""
+【总体绩效】
+当前持仓: {'持有中' if result['current_position'] == 1 else '空仓'}
+当前价格: {result['current_price']:.2f}元
+累计收益率: {result['total_return']:+.2f}%
+总资产: {result['total_value']:,.0f}元
+
+【近20天指标】
+日期        收盘价    MA10     MA30     20日高   10日涨幅  信号
+"""
+    
+    for ind in recent_indicators:
+        text += f"{ind['date']}  {ind['close']:>8}  {ind['ma10']:>8}  {ind['ma30']:>8}  {ind['high_20']:>8}  {ind['ret_10']:>8}  {ind['signal']:>4}\n"
+    
+    text += "\n【近20次交易】\n"
+    for trade in recent_trades:
+        pnl_str = f"{trade.get('pnl', 0):+,.0f}元" if 'pnl' in trade else '-'
+        ret_str = f"{trade.get('return_pct', 0):+.2f}%" if 'return_pct' in trade else '-'
+        date_str = trade['date'].strftime('%Y-%m-%d') if hasattr(trade['date'], 'strftime') else str(trade['date'])
+        text += f"{date_str}  {trade['action']:>6}  {trade['price']:>8.2f}  {pnl_str:>12}  {ret_str:>10}\n"
+    
+    return html, text, result
+
+
+def send_email(subject, html_content, text_content):
+    """发送邮件"""
+    try:
+        msg = MIMEMultipart('alternative')
+        msg['Subject'] = Header(subject, 'utf-8')
+        msg['From'] = EMAIL_CONFIG['sender_email']
+        msg['To'] = EMAIL_CONFIG['receiver_email']
+        
+        text_part = MIMEText(text_content, 'plain', 'utf-8')
+        msg.attach(text_part)
+        
+        html_part = MIMEText(html_content, 'html', 'utf-8')
+        msg.attach(html_part)
+        
+        with smtplib.SMTP(EMAIL_CONFIG['smtp_server'], EMAIL_CONFIG['smtp_port']) as server:
+            server.sendmail(
+                EMAIL_CONFIG['sender_email'],
+                EMAIL_CONFIG['receiver_email'],
+                msg.as_string()
+            )
+        print(f"✅ 邮件发送成功: {subject}")
+        return True
+    except Exception as e:
+        print(f"❌ 邮件发送失败: {e}")
+        return False
+
+
+def main():
+    """主程序"""
+    print("="*60)
+    print("🚀 创业板50趋势跟踪实时报告 (多数据源交叉验证版)")
+    print("="*60)
+    print(f"执行时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
+    
+    html, text, result = generate_report()
+    
+    if html is None:
+        print("❌ 报告生成失败")
+        return
+    
+    print(f"\n✅ 报告生成完成")
+    print(f"   数据最新日期: {result['data_end_date']}")
+    print(f"   当前持仓: {'持有中' if result['current_position'] == 1 else '空仓'}")
+    print(f"   累计收益: {result['total_return']:+.2f}%")
+    
+    print("\n📧 发送邮件...")
+    position_status = "持仓" if result['current_position'] == 1 else "空仓"
+    subject = f"🚀 创业板50趋势报告 {datetime.now().strftime('%m-%d %H:%M')} | {position_status} | 收益{result['total_return']:+.2f}%"
+    send_email(subject, html, text)
+    
+    print("\n✅ 全部完成!")
+    print("="*60)
+
+
+if __name__ == "__main__":
+    main()

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 528 - 0
cat-fly/trend_report_v2.py


+ 76 - 0
kalman-filter/kalman_daily_signals.csv

@@ -0,0 +1,76 @@
+,Signal,Price,Kalman Trend,Volatility
+2018-01-03,Sell,1562.519,-2.0355113121015873,
+2018-02-02,Sell,1476.918,-1.7419861595430093,0.25639007571993194
+2018-03-27,Sell,1610.466,-1.0415835886469165,0.39435008454746656
+2018-04-12,Sell,1581.94,-1.2681249791570712,0.383517814904589
+2018-05-08,Buy,1604.305,0.5987125837657654,0.29509261954063004
+2018-05-28,Sell,1508.221,-3.174410501451353,0.21335079722463063
+2018-08-02,Sell,1264.285,-3.651634925143716,0.25283598599496565
+2018-11-27,Sell,1067.116,-1.9200633355216745,0.33066425877691935
+2019-02-01,Buy,1027.244,0.10609817329741333,0.2294105413109952
+2019-03-28,Sell,1301.882,-3.2103710428944003,0.3388590211305272
+2019-04-16,Sell,1369.381,-1.4321553316862383,0.3048864388215655
+2019-07-23,Sell,1214.612,-0.5195605727889401,0.23949631305208738
+2019-07-24,Buy,1231.285,0.025137849499758058,0.2434619011135576
+2019-08-07,Sell,1177.666,-2.3103157263519485,0.18509640165457333
+2019-08-16,Buy,1242.894,0.2544943182145989,0.20209271424939354
+2019-09-27,Sell,1333.115,-1.8594014318099048,0.24990774067616287
+2019-10-28,Buy,1366.258,0.3152604550344319,0.21822382430719692
+2019-12-03,Sell,1379.46,-0.4412995163095275,0.18671869132267355
+2019-12-05,Buy,1415.648,0.6277196690425455,0.206326636795782
+2020-03-10,Sell,1829.119,-1.0419552970606873,0.4571238715185032
+2020-05-26,Buy,1828.709,0.08863021434275051,0.228315287229799
+2020-05-28,Sell,1783.911,-1.6991339124499223,0.2312102129270274
+2020-06-01,Buy,1869.072,0.11939359030458618,0.26171065052734377
+2020-08-13,Sell,2384.163,-7.185497333688526,0.3856995376603528
+2020-09-01,Buy,2495.351,1.3475911651522459,0.2926116794873706
+2020-09-09,Sell,2278.578,-5.195239869428842,0.33687848974068296
+2020-11-19,Sell,2476.449,-4.8785359143628915,0.2951681925507462
+2020-12-04,Buy,2571.335,0.8878809816247473,0.2717934858863099
+2021-02-24,Sell,2931.276,-9.428328081257824,0.39481923331210683
+2021-07-28,Sell,3318.334,-10.08119427301443,0.3849211009879227
+2021-08-12,Sell,3395.613,-3.472397060529297,0.3878842485873111
+2021-09-14,Buy,3281.784,0.49998126856403946,0.2940763672496989
+2021-09-17,Sell,3231.128,-0.781828960831134,0.30046236638153284
+2021-09-27,Buy,3262.039,1.0996596107732728,0.2578576890599948
+2021-10-13,Sell,3228.941,-0.40836419572671323,0.23803135383012752
+2021-10-15,Buy,3309.932,2.3366740981575087,0.24784898451930282
+2021-12-08,Sell,3476.456,-3.055754539306629,0.1894663009986254
+2021-12-14,Buy,3547.913,0.30874284682110253,0.18626405874345586
+2021-12-16,Buy,3546.362,0.7533677961495376,0.18380483611735424
+2021-12-20,Sell,3369.308,-4.9825622319902205,0.19383438797350597
+2022-03-04,Sell,2706.315,-2.5429923253410376,0.3155745474336556
+2022-03-29,Sell,2565.614,-2.872829301717552,0.39532090306209344
+2022-04-08,Sell,2567.852,-3.3680398618282146,0.392948660891435
+2022-07-18,Sell,2822.813,-0.22808368236933063,0.29796503547422304
+2022-08-16,Buy,2741.242,0.6163740273565161,0.2179498495909916
+2022-08-30,Sell,2609.234,-5.758116920805243,0.2522856553560171
+2022-10-31,Sell,2238.797,-5.2140367732118875,0.349024154490802
+2022-11-24,Sell,2327.58,-2.582775637845167,0.31252399244878665
+2022-12-06,Buy,2382.376,0.16798325364903866,0.21976116897719505
+2022-12-21,Sell,2300.698,-3.303189087857409,0.16633746068745825
+2023-01-05,Buy,2395.3,0.2968540039121761,0.20555393094036503
+2023-02-15,Sell,2527.289,-1.6879127443177468,0.17228156954750298
+2023-04-24,Sell,2201.507,-5.72215679075741,0.17268772840910118
+2023-07-20,Sell,2064.198,-1.8499009643065736,0.18823472830420732
+2023-07-31,Buy,2153.64,0.7995013622864371,0.19046202986194222
+2023-08-16,Sell,2053.811,-3.8325451047992667,0.18604400191513232
+2023-11-23,Sell,1844.577,-1.664434703508825,0.24472437210993644
+2024-01-04,Sell,1684.004,-1.2792006165234453,0.2546607649055747
+2024-03-28,Sell,1738.009,-2.948469784561251,0.28650368619202576
+2024-04-29,Buy,1827.414,1.3395406917781578,0.2998828823558075
+2024-05-27,Sell,1749.825,-1.300394628189764,0.27409926803989554
+2024-07-30,Sell,1578.294,-2.113238877409489,0.20056783822796279
+2024-09-12,Buy,1513.177,0.17056947234677095,0.1874450943268222
+2024-11-25,Sell,2184.683,-6.357767665535631,0.4310705836957812
+2024-12-18,Sell,2213.066,-1.2158007489141183,0.28026902591151126
+2025-03-06,Sell,2205.115,-1.0376875045202147,0.2704778091985956
+2025-05-30,Sell,1962.624,-1.9911213179099712,0.21240464292519487
+2025-06-11,Buy,2029.103,0.7077045181739439,0.1758700233122866
+2025-06-24,Buy,2044.78,0.7835402302193312,0.17185577905047927
+2025-10-15,Sell,3163.51,-5.254645976396086,0.4063640698395624
+2025-11-17,Sell,3263.756,-5.031104320134871,0.33719000481739203
+2025-12-05,Buy,3302.897,1.113259924809289,0.27554945226550775
+2026-01-23,Sell,3480.852,-0.4085628007292203,0.18989157155364011
+2026-02-25,Buy,3514.742,0.7462336542353936,0.22550333858114457
+2026-03-04,Sell,3310.591,-6.487809580213213,0.24431277193518378

BIN
kalman-filter/kalman_filter_analysis.png


+ 54 - 0
kalman-filter/test_extract.py

@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+import subprocess
+
+result = subprocess.run(['python3', 'cyb50_kalman_filter_daily.py'], cwd='/root/.openclaw/workspace/kalman-filter', capture_output=True, text=True, timeout=300)
+
+output = result.stdout
+lines = output.split('\n')
+
+signals = []
+in_signal_section = False
+
+for line in lines:
+    if '所有交易信号详情' in line:
+        in_signal_section = True
+        continue
+    if in_signal_section:
+        stripped = line.strip()
+        if len(stripped) > 30:
+            parts = stripped.split()
+            if len(parts) >= 3 and parts[0].isdigit() and len(parts[1]) == 10 and parts[1][4] == '-':
+                signals.append({
+                    'num': parts[0],
+                    'date': parts[1],
+                    'action': parts[2],
+                    'price': parts[3] if len(parts) > 3 else '',
+                })
+        # 获取所有信号
+        if '当前市场状态' in line:
+            break
+
+print(f'找到 {len(signals)} 个交易信号')
+
+# 取最近40个信号
+recent_signals = signals[-40:] if len(signals) > 40 else signals
+print(f'\n最近40个信号中的前10个:')
+for s in recent_signals[:10]:
+    print(f"  {s['num']:>3} {s['date']} {s['action']:>4} {s['price']}")
+
+print(f'\n最近40个信号中的后10个:')
+for s in recent_signals[-10:]:
+    print(f"  {s['num']:>3} {s['date']} {s['action']:>4} {s['price']}")
+
+# 配对
+trades = []
+for i in range(len(recent_signals) - 1):
+    if recent_signals[i]['action'] == '买入' and recent_signals[i+1]['action'] == '卖出':
+        buy = recent_signals[i]
+        sell = recent_signals[i+1]
+        trades.append(f"{buy['num']} {buy['date']}买入→{sell['date']}卖出")
+
+print(f'\n配对到 {len(trades)} 对交易')
+print('\n最近5对:')
+for t in trades[-5:]:
+    print(f'  {t}')

BIN
market-regime-identifier/__pycache__/cyb50_market_classifier.cpython-312.pyc


BIN
market-regime-identifier/__pycache__/market_regime_hmm.cpython-312.pyc


+ 188 - 0
market-regime-identifier/hmm_diagnosis.py

@@ -0,0 +1,188 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+HMM模型诊断脚本
+验证市场环境识别器的效果
+"""
+
+import numpy as np
+import pandas as pd
+import warnings
+warnings.filterwarnings('ignore')
+
+import sys
+sys.path.insert(0, '/root/.openclaw/workspace/market-regime-identifier')
+from market_regime_hmm import MarketRegimeHMM, extract_features
+
+print("="*70)
+print("HMM模型诊断报告")
+print("="*70)
+
+# 1. 生成带标签的测试数据
+print("\n[1] 生成测试数据...")
+np.random.seed(42)
+n_days = 800
+
+# 创建有明确状态特征的数据
+segments = []
+true_states = []
+
+for i in range(8):
+    state = i % 3
+    seg_prices = []
+    price = 1000 + i * 100
+    
+    for day in range(100):
+        if state == 0:  # 震荡: 零均值,中等波动
+            ret = np.random.normal(0, 0.015)
+        elif state == 1:  # 趋势: 正漂移,低波动
+            ret = np.random.normal(0.001, 0.010)
+        else:  # 反转: 负漂移,高波动
+            ret = np.random.normal(-0.001, 0.025)
+        
+        price *= (1 + ret)
+        seg_prices.append(price)
+        true_states.append(state)
+    
+    segments.extend(seg_prices)
+
+dates = pd.date_range('2020-01-01', periods=n_days, freq='B')
+df = pd.DataFrame({
+    'open': np.array(segments) + np.random.normal(0, 2, n_days),
+    'high': np.array(segments) + np.abs(np.random.normal(5, 2, n_days)),
+    'low': np.array(segments) - np.abs(np.random.normal(5, 2, n_days)),
+    'close': segments,
+    'volume': np.random.randint(1000000, 5000000, n_days),
+    'true_state': true_states
+}, index=dates)
+
+print(f"数据天数: {n_days}")
+print(f"真实状态分布:")
+for i in range(3):
+    count = sum(1 for s in true_states if s == i)
+    print(f"  状态{i}: {count}天 ({count/n_days*100:.1f}%)")
+
+# 2. 特征提取
+print("\n[2] 特征提取...")
+features = extract_features(df)
+feature_cols = ['ret_std_5', 'momentum_10', 'vol_ratio', 'volume_change', 'intraday_trend']
+X = features[feature_cols].dropna()
+print(f"特征维度: {X.shape}")
+
+# 3. 训练模型
+print("\n[3] 训练HMM模型...")
+hmm = MarketRegimeHMM(n_components=3, n_iter=100)
+hmm.fit(X)
+
+# 4. 预测状态
+states, probs = hmm.predict(X)
+df_aligned = df.iloc[-len(states):].copy()
+df_aligned['predicted_state'] = states
+df_aligned['return'] = df_aligned['close'].pct_change()
+
+# 5. 诊断分析
+print("\n" + "="*70)
+print("诊断结果")
+print("="*70)
+
+# 5.1 转移矩阵对比
+print("\n[5.1] 转移矩阵对比")
+print("\n先验矩阵 (设定):")
+prior = np.array([
+    [0.85, 0.10, 0.05],
+    [0.15, 0.80, 0.05],
+    [0.20, 0.10, 0.70]
+])
+print(prior.round(3))
+
+print("\n学习到的矩阵:")
+learned = hmm.model.transmat_
+print(learned.round(3))
+
+print("\n差异:")
+diff = np.abs(learned - prior)
+print(diff.round(3))
+print(f"平均绝对差异: {diff.mean():.3f}")
+
+# 5.2 状态分布对比
+print("\n[5.2] 状态分布对比")
+print(f"{'状态':<10} {'真实占比':<15} {'预测占比':<15} {'差异':<10}")
+print("-"*50)
+for i in range(3):
+    true_pct = sum(1 for s in true_states if s == i) / n_days * 100
+    pred_pct = sum(1 for s in states if s == i) / len(states) * 100
+    diff_pct = abs(true_pct - pred_pct)
+    print(f"状态{i:<5} {true_pct:>6.1f}%{' '*8} {pred_pct:>6.1f}%{' '*8} {diff_pct:>5.1f}%")
+
+# 5.3 状态特征验证
+print("\n[5.3] 各状态的价格行为特征")
+print(f"{'状态':<8} {'收益率均值':<12} {'收益率标准差':<15} {'样本数':<10}")
+print("-"*50)
+for i in range(3):
+    mask = states == i
+    if mask.any():
+        rets = df_aligned.loc[mask, 'return'].dropna()
+        mean_ret = rets.mean() * 100
+        std_ret = rets.std() * 100
+        count = mask.sum()
+        print(f"状态{i:<5} {mean_ret:>+8.3f}%{' '*4} {std_ret:>8.3f}%{' '*6} {count:>5}天")
+
+# 5.4 预期 vs 实际
+print("\n[5.4] 状态定义验证")
+state_names = ['震荡', '趋势', '反转']
+expected = {
+    0: {'vol': '中高', 'ret': '接近0'},
+    1: {'vol': '低', 'ret': '正'},
+    2: {'vol': '高', 'ret': '负'}
+}
+
+for i in range(3):
+    mask = states == i
+    if mask.any():
+        rets = df_aligned.loc[mask, 'return'].dropna()
+        mean_ret = rets.mean() * 100
+        std_ret = rets.std() * 100
+        
+        print(f"\n状态{i} ({state_names[i]}):")
+        print(f"  预期: 波动{expected[i]['vol']}, 收益{expected[i]['ret']}")
+        print(f"  实际: 波动{std_ret:.2f}%, 收益{mean_ret:+.3f}%")
+        
+        # 简单判断
+        if i == 0 and abs(mean_ret) < 0.1 and std_ret > 1.0:
+            print("  ✓ 符合震荡特征")
+        elif i == 1 and mean_ret > 0.05 and std_ret < 1.5:
+            print("  ✓ 符合趋势特征")
+        elif i == 2 and std_ret > 1.8:
+            print("  ✓ 符合反转特征")
+        else:
+            print("  ✗ 特征不匹配")
+
+# 5.5 准确率估算
+print("\n[5.5] 状态识别准确率估算")
+# 基于特征匹配度估算
+matches = 0
+for i in range(len(states) - 1):
+    true_seg = i // 100
+    if states[i] == true_states[i]:
+        matches += 1
+
+accuracy = matches / len(states) * 100
+print(f"与生成标签匹配率: {accuracy:.1f}%")
+
+if accuracy >= 72:
+    print("✓ 达到目标准确率 (>72%)")
+else:
+    print("✗ 未达到目标准确率,需要优化")
+
+print("\n" + "="*70)
+print("诊断结论")
+print("="*70)
+print(f"1. 转移矩阵与先验差异: {'可接受' if diff.mean() < 0.3 else '较大'}")
+print(f"2. 状态识别准确率: {accuracy:.1f}%")
+print(f"3. 状态特征一致性: 见上文分析")
+print("\n建议:")
+if diff.mean() > 0.3:
+    print("- 转移矩阵与先验差异较大,建议检查数据特征或调整模型参数")
+if accuracy < 72:
+    print("- 准确率不足,建议增加特征维度或使用更长的训练数据")
+print("="*70)

+ 665 - 0
market-regime-identifier/last_60_days_report.html

@@ -0,0 +1,665 @@
+
+<html>
+<head>
+    <meta charset="utf-8">
+    <style>
+        body { font-family: Arial, sans-serif; margin: 20px; font-size: 12px; }
+        h1 { color: #333; border-bottom: 3px solid #2196F3; padding-bottom: 10px; font-size: 18px; }
+        h2 { color: #555; margin-top: 20px; border-left: 4px solid #4CAF50; padding-left: 10px; font-size: 14px; }
+        .summary { background: #f5f5f5; padding: 15px; border-radius: 5px; margin: 20px 0; }
+        .summary p { margin: 5px 0; }
+        table { width: 100%; border-collapse: collapse; margin: 20px 0; font-size: 11px; }
+        th { background: #2196F3; color: white; padding: 8px; text-align: center; position: sticky; top: 0; }
+        td { padding: 6px 8px; border-bottom: 1px solid #ddd; text-align: center; }
+        tr:nth-child(even) { background: #f8f9fa; }
+        tr:hover { background: #e3f2fd; }
+        .table-container { max-height: 500px; overflow-y: auto; }
+    </style>
+</head>
+<body>
+    <h1>📊 创业板50最近60天详细数据 (2026-01-06 ~ 2026-03-06)</h1>
+    
+    <div class="summary">
+        <h2>📊 最近60天统计</h2>
+        <p><strong>统计区间:</strong> 2025-12-03 ~ 2026-03-06</p>
+        <p><strong>起始价格:</strong> 3213.67</p>
+        <p><strong>结束价格:</strong> 3380.31</p>
+        <p><strong>区间涨跌:</strong> +5.19%</p>
+        <p><strong>最高价:</strong> 3547.03 (01-12)</p>
+        <p><strong>最低价:</strong> 3213.67 (12-03)</p>
+        <br>
+        <p><strong>状态分布:</strong></p>
+        <p>🟦 震荡: 45天 (75.0%)</p>
+        <p>🟩 趋势: 9天 (15.0%)</p>
+        <p>🟧 反转: 6天 (10.0%)</p>
+    </div>
+
+    
+    <h2>📋 每日详细数据</h2>
+    <div class="table-container">
+    <table>
+        <thead>
+            <tr>
+                <th>日期</th>
+                <th>收盘价</th>
+                <th>状态</th>
+                <th>震荡概率</th>
+                <th>趋势概率</th>
+                <th>反转概率</th>
+                <th>日涨跌</th>
+            </tr>
+        </thead>
+        <tbody>
+            
+        <tr>
+            <td>2025-12-03</td>
+            <td>3213.67</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>57.0%</td>
+            <td>10.1%</td>
+            <td>32.9%</td>
+            <td style="color: gray;">-</td>
+        </tr>
+    
+        <tr>
+            <td>2025-12-04</td>
+            <td>3254.79</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>50.8%</td>
+            <td>12.9%</td>
+            <td>36.3%</td>
+            <td style="color: green;">+1.28%</td>
+        </tr>
+    
+        <tr>
+            <td>2025-12-05</td>
+            <td>3302.90</td>
+            <td style="color: #4CAF50; font-weight: bold;">趋势</td>
+            <td>15.1%</td>
+            <td>65.7%</td>
+            <td>19.2%</td>
+            <td style="color: green;">+1.48%</td>
+        </tr>
+    
+        <tr>
+            <td>2025-12-08</td>
+            <td>3399.46</td>
+            <td style="color: #4CAF50; font-weight: bold;">趋势</td>
+            <td>17.5%</td>
+            <td>68.5%</td>
+            <td>14.1%</td>
+            <td style="color: green;">+2.92%</td>
+        </tr>
+    
+        <tr>
+            <td>2025-12-09</td>
+            <td>3427.43</td>
+            <td style="color: #4CAF50; font-weight: bold;">趋势</td>
+            <td>14.1%</td>
+            <td>72.7%</td>
+            <td>13.2%</td>
+            <td style="color: green;">+0.82%</td>
+        </tr>
+    
+        <tr>
+            <td>2025-12-10</td>
+            <td>3418.68</td>
+            <td style="color: #4CAF50; font-weight: bold;">趋势</td>
+            <td>14.6%</td>
+            <td>74.8%</td>
+            <td>10.6%</td>
+            <td style="color: red;">-0.26%</td>
+        </tr>
+    
+        <tr>
+            <td>2025-12-11</td>
+            <td>3366.70</td>
+            <td style="color: #4CAF50; font-weight: bold;">趋势</td>
+            <td>11.5%</td>
+            <td>80.6%</td>
+            <td>7.9%</td>
+            <td style="color: red;">-1.52%</td>
+        </tr>
+    
+        <tr>
+            <td>2025-12-12</td>
+            <td>3397.66</td>
+            <td style="color: #4CAF50; font-weight: bold;">趋势</td>
+            <td>13.0%</td>
+            <td>83.1%</td>
+            <td>3.9%</td>
+            <td style="color: green;">+0.92%</td>
+        </tr>
+    
+        <tr>
+            <td>2025-12-15</td>
+            <td>3334.31</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>45.6%</td>
+            <td>21.0%</td>
+            <td>33.4%</td>
+            <td style="color: red;">-1.86%</td>
+        </tr>
+    
+        <tr>
+            <td>2025-12-16</td>
+            <td>3256.98</td>
+            <td style="color: #FF5722; font-weight: bold;">反转</td>
+            <td>25.9%</td>
+            <td>9.0%</td>
+            <td>65.1%</td>
+            <td style="color: red;">-2.32%</td>
+        </tr>
+    
+        <tr>
+            <td>2025-12-17</td>
+            <td>3377.65</td>
+            <td style="color: #FF5722; font-weight: bold;">反转</td>
+            <td>21.2%</td>
+            <td>24.7%</td>
+            <td>54.2%</td>
+            <td style="color: green;">+3.70%</td>
+        </tr>
+    
+        <tr>
+            <td>2025-12-18</td>
+            <td>3292.59</td>
+            <td style="color: #FF5722; font-weight: bold;">反转</td>
+            <td>37.0%</td>
+            <td>11.6%</td>
+            <td>51.4%</td>
+            <td style="color: red;">-2.52%</td>
+        </tr>
+    
+        <tr>
+            <td>2025-12-19</td>
+            <td>3307.29</td>
+            <td style="color: #FF5722; font-weight: bold;">反转</td>
+            <td>26.4%</td>
+            <td>7.8%</td>
+            <td>65.8%</td>
+            <td style="color: green;">+0.45%</td>
+        </tr>
+    
+        <tr>
+            <td>2025-12-22</td>
+            <td>3389.02</td>
+            <td style="color: #FF5722; font-weight: bold;">反转</td>
+            <td>34.2%</td>
+            <td>13.5%</td>
+            <td>52.2%</td>
+            <td style="color: green;">+2.47%</td>
+        </tr>
+    
+        <tr>
+            <td>2025-12-23</td>
+            <td>3404.61</td>
+            <td style="color: #FF5722; font-weight: bold;">反转</td>
+            <td>20.7%</td>
+            <td>7.6%</td>
+            <td>71.7%</td>
+            <td style="color: green;">+0.46%</td>
+        </tr>
+    
+        <tr>
+            <td>2025-12-24</td>
+            <td>3429.06</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>61.0%</td>
+            <td>13.1%</td>
+            <td>25.9%</td>
+            <td style="color: green;">+0.72%</td>
+        </tr>
+    
+        <tr>
+            <td>2025-12-25</td>
+            <td>3437.43</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>49.7%</td>
+            <td>15.4%</td>
+            <td>34.9%</td>
+            <td style="color: green;">+0.24%</td>
+        </tr>
+    
+        <tr>
+            <td>2025-12-26</td>
+            <td>3441.99</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>43.1%</td>
+            <td>15.0%</td>
+            <td>41.9%</td>
+            <td style="color: green;">+0.13%</td>
+        </tr>
+    
+        <tr>
+            <td>2025-12-29</td>
+            <td>3413.77</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>78.7%</td>
+            <td>12.4%</td>
+            <td>8.9%</td>
+            <td style="color: red;">-0.82%</td>
+        </tr>
+    
+        <tr>
+            <td>2025-12-30</td>
+            <td>3440.06</td>
+            <td style="color: #4CAF50; font-weight: bold;">趋势</td>
+            <td>29.2%</td>
+            <td>64.6%</td>
+            <td>6.2%</td>
+            <td style="color: green;">+0.77%</td>
+        </tr>
+    
+        <tr>
+            <td>2025-12-31</td>
+            <td>3390.24</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>75.7%</td>
+            <td>8.1%</td>
+            <td>16.2%</td>
+            <td style="color: red;">-1.45%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-01-05</td>
+            <td>3488.23</td>
+            <td style="color: #4CAF50; font-weight: bold;">趋势</td>
+            <td>32.4%</td>
+            <td>54.2%</td>
+            <td>13.4%</td>
+            <td style="color: green;">+2.89%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-01-06</td>
+            <td>3506.50</td>
+            <td style="color: #4CAF50; font-weight: bold;">趋势</td>
+            <td>19.4%</td>
+            <td>70.9%</td>
+            <td>9.7%</td>
+            <td style="color: green;">+0.52%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-01-07</td>
+            <td>3515.34</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>51.3%</td>
+            <td>35.6%</td>
+            <td>13.1%</td>
+            <td style="color: green;">+0.25%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-01-08</td>
+            <td>3473.66</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>72.8%</td>
+            <td>14.2%</td>
+            <td>13.1%</td>
+            <td style="color: red;">-1.19%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-01-09</td>
+            <td>3490.83</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>66.3%</td>
+            <td>17.6%</td>
+            <td>16.1%</td>
+            <td style="color: green;">+0.49%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-01-12</td>
+            <td>3547.03</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>64.2%</td>
+            <td>26.6%</td>
+            <td>9.2%</td>
+            <td style="color: green;">+1.61%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-01-13</td>
+            <td>3477.90</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>69.8%</td>
+            <td>12.8%</td>
+            <td>17.5%</td>
+            <td style="color: red;">-1.95%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-01-14</td>
+            <td>3502.85</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>74.8%</td>
+            <td>15.6%</td>
+            <td>9.6%</td>
+            <td style="color: green;">+0.72%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-01-15</td>
+            <td>3526.02</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>71.2%</td>
+            <td>15.9%</td>
+            <td>12.9%</td>
+            <td style="color: green;">+0.66%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-01-16</td>
+            <td>3518.73</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>56.0%</td>
+            <td>36.3%</td>
+            <td>7.7%</td>
+            <td style="color: red;">-0.21%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-01-19</td>
+            <td>3489.25</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>84.0%</td>
+            <td>7.9%</td>
+            <td>8.1%</td>
+            <td style="color: red;">-0.84%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-01-20</td>
+            <td>3419.62</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>84.7%</td>
+            <td>5.8%</td>
+            <td>9.5%</td>
+            <td style="color: red;">-2.00%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-01-21</td>
+            <td>3435.49</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>87.2%</td>
+            <td>4.8%</td>
+            <td>8.0%</td>
+            <td style="color: green;">+0.46%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-01-22</td>
+            <td>3473.18</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>85.6%</td>
+            <td>5.4%</td>
+            <td>9.0%</td>
+            <td style="color: green;">+1.10%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-01-23</td>
+            <td>3480.85</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>93.6%</td>
+            <td>4.0%</td>
+            <td>2.4%</td>
+            <td style="color: green;">+0.22%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-01-26</td>
+            <td>3448.70</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>92.7%</td>
+            <td>4.6%</td>
+            <td>2.7%</td>
+            <td style="color: red;">-0.92%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-01-27</td>
+            <td>3476.17</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>91.9%</td>
+            <td>3.2%</td>
+            <td>4.9%</td>
+            <td style="color: green;">+0.80%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-01-28</td>
+            <td>3463.33</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>93.3%</td>
+            <td>2.7%</td>
+            <td>4.1%</td>
+            <td style="color: red;">-0.37%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-01-29</td>
+            <td>3450.16</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>93.9%</td>
+            <td>2.9%</td>
+            <td>3.2%</td>
+            <td style="color: red;">-0.38%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-01-30</td>
+            <td>3515.28</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>89.7%</td>
+            <td>5.4%</td>
+            <td>4.8%</td>
+            <td style="color: green;">+1.89%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-02-02</td>
+            <td>3432.87</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>82.0%</td>
+            <td>5.1%</td>
+            <td>12.8%</td>
+            <td style="color: red;">-2.34%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-02-03</td>
+            <td>3487.59</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>85.8%</td>
+            <td>4.2%</td>
+            <td>10.0%</td>
+            <td style="color: green;">+1.59%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-02-04</td>
+            <td>3471.23</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>89.3%</td>
+            <td>3.2%</td>
+            <td>7.5%</td>
+            <td style="color: red;">-0.47%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-02-05</td>
+            <td>3413.58</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>79.1%</td>
+            <td>4.7%</td>
+            <td>16.3%</td>
+            <td style="color: red;">-1.66%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-02-06</td>
+            <td>3385.75</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>70.5%</td>
+            <td>7.9%</td>
+            <td>21.5%</td>
+            <td style="color: red;">-0.82%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-02-09</td>
+            <td>3493.59</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>77.4%</td>
+            <td>3.9%</td>
+            <td>18.7%</td>
+            <td style="color: green;">+3.18%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-02-10</td>
+            <td>3479.49</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>81.9%</td>
+            <td>2.9%</td>
+            <td>15.2%</td>
+            <td style="color: red;">-0.40%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-02-11</td>
+            <td>3432.86</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>79.9%</td>
+            <td>4.4%</td>
+            <td>15.7%</td>
+            <td style="color: red;">-1.34%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-02-12</td>
+            <td>3480.50</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>81.7%</td>
+            <td>2.2%</td>
+            <td>16.1%</td>
+            <td style="color: green;">+1.39%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-02-13</td>
+            <td>3423.05</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>51.1%</td>
+            <td>5.8%</td>
+            <td>43.1%</td>
+            <td style="color: red;">-1.65%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-02-24</td>
+            <td>3469.02</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>71.1%</td>
+            <td>2.9%</td>
+            <td>26.0%</td>
+            <td style="color: green;">+1.34%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-02-25</td>
+            <td>3514.74</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>78.1%</td>
+            <td>9.7%</td>
+            <td>12.2%</td>
+            <td style="color: green;">+1.32%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-02-26</td>
+            <td>3500.75</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>78.0%</td>
+            <td>4.7%</td>
+            <td>17.3%</td>
+            <td style="color: red;">-0.40%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-02-27</td>
+            <td>3449.46</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>74.3%</td>
+            <td>4.3%</td>
+            <td>21.4%</td>
+            <td style="color: red;">-1.47%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-03-02</td>
+            <td>3443.78</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>84.5%</td>
+            <td>3.9%</td>
+            <td>11.6%</td>
+            <td style="color: red;">-0.16%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-03-03</td>
+            <td>3362.90</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>70.6%</td>
+            <td>10.4%</td>
+            <td>18.9%</td>
+            <td style="color: red;">-2.35%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-03-04</td>
+            <td>3310.59</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>61.9%</td>
+            <td>24.0%</td>
+            <td>14.1%</td>
+            <td style="color: red;">-1.56%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-03-05</td>
+            <td>3373.47</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>67.4%</td>
+            <td>7.4%</td>
+            <td>25.2%</td>
+            <td style="color: green;">+1.90%</td>
+        </tr>
+    
+        <tr>
+            <td>2026-03-06</td>
+            <td>3380.31</td>
+            <td style="color: #2196F3; font-weight: bold;">震荡</td>
+            <td>72.4%</td>
+            <td>10.6%</td>
+            <td>17.0%</td>
+            <td style="color: green;">+0.20%</td>
+        </tr>
+    
+        </tbody>
+    </table>
+    </div>
+    
+    <hr>
+    <p style="color: #666; font-size: 11px;">
+        生成时间: 2026-03-06 19:10<br>
+        数据更新至: 2026-03-06<br>
+        模型准确率: 72.10%
+    </p>
+</body>
+</html>

+ 15 - 10
market-regime-identifier/market_regime_hmm.py

@@ -105,19 +105,20 @@ class MarketRegimeHMM:
         2: '反转'
     }
     
-    # 先验转移概率矩阵
-    PRIOR_TRANSITION = np.array([
-        [0.85, 0.10, 0.05],  # 震荡 -> 震荡/趋势/反转
-        [0.15, 0.80, 0.05],  # 趋势 -> 震荡/趋势/反转
-        [0.20, 0.10, 0.70]   # 反转 -> 震荡/趋势/反转
-    ])
-    
     def __init__(self, n_components=3, n_iter=100):
+        # 先验转移概率矩阵
+        self.PRIOR_TRANSITION = np.array([
+            [0.85, 0.10, 0.05],  # 震荡 -> 震荡/趋势/反转
+            [0.15, 0.80, 0.05],  # 趋势 -> 震荡/趋势/反转
+            [0.20, 0.10, 0.70]   # 反转 -> 震荡/趋势/反转
+        ])
+        
         self.model = GaussianHMM(
             n_components=n_components,
             covariance_type='full',
             n_iter=n_iter,
-            random_state=42
+            random_state=42,
+            init_params='mc'  # 只初始化均值和协方差,不初始化转移矩阵
         )
         self.is_fitted = False
         
@@ -125,11 +126,15 @@ class MarketRegimeHMM:
         """训练HMM模型"""
         print("训练HMM模型...")
         
+        X = features.values
+        
+        # 先验状态分布(均匀分布)
+        self.model.startprob_ = np.array([1/3, 1/3, 1/3])
+        
         # 使用先验转移概率初始化
-        self.model.transmat_ = self.PRIOR_TRANSITION
+        self.model.transmat_ = self.PRIOR_TRANSITION.copy()
         
         # 拟合模型
-        X = features.values
         self.model.fit(X)
         self.is_fitted = True
         

BIN
openclaw-backup-20260306.tar.gz


+ 67 - 0
quant/quant_report_20260306_1133.txt

@@ -0,0 +1,67 @@
+==========================================================================================
+创业板50指数 - 全策略年度收益对比(真实数据)
+==========================================================================================
+
+开始年度回测...
+------------------------------------------------------------------------------------------
+
+==========================================================================================
+年度收益对比表 (%)
+==========================================================================================
+策略         |     2018 |     2019 |     2020 |     2021 |     2022 |     2023 |     2024 |     2025 |       平均 |     跑赢年数
+------------------------------------------------------------------------------------------
+趋势跟踪       |    -9.4 |    +3.8 |   +48.3 |   +16.6 |    +7.4 |    +0.0 |   +30.5 |   +33.2 |   +16.3 |      4/8
+双均线        |   -13.7 |    +5.5 |   +40.7 |    +6.9 |    +1.6 |    -2.0 |    +1.1 |   +49.7 |   +11.2 |      3/8
+动量         |   -17.9 |    +0.0 |   +38.1 |    +1.3 |    +4.4 |    -7.0 |    +7.6 |   +38.9 |    +8.2 |      3/8
+多因子        |   -16.0 |    +2.6 |   +45.8 |    +4.2 |    -0.5 |   -12.8 |   +13.5 |   +40.3 |    +9.6 |      3/8
+RSI        |   -21.3 |    +9.6 |   +14.3 |    +6.6 |    +3.5 |   -15.6 |    -5.4 |   +13.0 |    +0.6 |      4/8
+买入持有       |   -38.7 |    +6.6 |   +76.2 |   +21.6 |    -8.9 |   -23.8 |   +21.8 |   +92.7 |   +18.4 |       --
+------------------------------------------------------------------------------------------
+
+==========================================================================================
+超额收益对比 (策略 - 买入持有)
+==========================================================================================
+策略         |     2018 |     2019 |     2020 |     2021 |     2022 |     2023 |     2024 |     2025 |     平均超额
+------------------------------------------------------------------------------------------
+趋势跟踪       |   +29.3⭐ |    -2.8 |   -27.9 |    -5.0 |   +16.3⭐ |   +23.8⭐ |    +8.7✓ |   -59.6 |    -2.1
+双均线        |   +25.0⭐ |    -1.1 |   -35.5 |   -14.7 |   +10.5⭐ |   +21.8⭐ |   -20.6 |   -43.0 |    -7.2
+动量         |   +20.8⭐ |    -6.6 |   -38.0 |   -20.4 |   +13.3⭐ |   +16.8⭐ |   -14.2 |   -53.8 |   -10.3
+多因子        |   +22.7⭐ |    -3.9 |   -30.4 |   -17.4 |    +8.4✓ |   +10.9⭐ |    -8.3 |   -52.4 |    -8.8
+RSI        |   +17.4⭐ |    +3.0✓ |   -61.8 |   -15.1 |   +12.4⭐ |    +8.2✓ |   -27.2 |   -79.8 |   -17.9
+------------------------------------------------------------------------------------------
+
+==========================================================================================
+策略评价
+==========================================================================================
+
+【趋势跟踪】
+  年均收益: +16.3%
+  年均超额: -2.1%
+  跑赢年数: 4/8 (50%)
+  评价: 不佳
+
+【双均线】
+  年均收益: +11.2%
+  年均超额: -7.2%
+  跑赢年数: 3/8 (38%)
+  评价: 不佳
+
+【动量】
+  年均收益: +8.2%
+  年均超额: -10.3%
+  跑赢年数: 3/8 (38%)
+  评价: 不佳
+
+【多因子】
+  年均收益: +9.6%
+  年均超额: -8.8%
+  跑赢年数: 3/8 (38%)
+  评价: 不佳
+
+【RSI】
+  年均收益: +0.6%
+  年均超额: -17.9%
+  跑赢年数: 4/8 (50%)
+  评价: 不佳
+
+==========================================================================================

+ 819 - 0
quant/trend_tracking_strategy.py

@@ -0,0 +1,819 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+创业板50指数 - 多数据源交叉验证版
+确保数据准确性
+"""
+
+import sys
+sys.path.insert(0, '/root/.openclaw/workspace/cat-fly')
+sys.path.insert(0, '/root/.openclaw/workspace/quant')
+
+import pandas as pd
+import numpy as np
+from datetime import datetime, timedelta
+import smtplib
+from email.mime.text import MIMEText
+from email.mime.multipart import MIMEMultipart
+from email.header import Header
+import warnings
+import requests
+import json
+import time
+import baostock as bs
+warnings.filterwarnings('ignore')
+
+# ==================== 邮件配置 ====================
+EMAIL_CONFIG = {
+    "smtp_server": "localhost",
+    "smtp_port": 25,
+    "sender_email": "catfly@openclaw.local",
+    "receiver_email": "380880504@qq.com"
+}
+
+# ==================== 数据源配置 ====================
+DATA_SOURCES = {
+    'baostock': {'priority': 1, 'weight': 0.4},
+    'akshare': {'priority': 2, 'weight': 0.3},
+    'sina': {'priority': 3, 'weight': 0.15},
+    'tencent': {'priority': 4, 'weight': 0.15}
+}
+
+# ==================== 多数据源获取 ====================
+
+class DataValidator:
+    """数据验证器 - 交叉验证多个数据源"""
+    
+    PRICE_TOLERANCE = 0.02  # 价格差异容忍度 2%
+    
+    @staticmethod
+    def validate_prices(sources_data):
+        """
+        验证多个数据源的价格一致性
+        返回: (validated_data, warnings)
+        """
+        if not sources_data:
+            return None, ["无可用数据源"]
+        
+        if len(sources_data) == 1:
+            return sources_data[0]['data'], []
+        
+        # 提取收盘价
+        prices = {}
+        for src in sources_data:
+            if src and 'data' in src and src['data']:
+                prices[src['source']] = src['data'].get('close', 0)
+        
+        if len(prices) < 2:
+            return sources_data[0]['data'], []
+        
+        # 计算价格统计
+        price_values = list(prices.values())
+        price_mean = np.mean(price_values)
+        price_std = np.std(price_values)
+        price_max = max(price_values)
+        price_min = min(price_values)
+        price_range = (price_max - price_min) / price_mean if price_mean > 0 else 0
+        
+        warnings = []
+        
+        # 检查价格差异
+        if price_range > DataValidator.PRICE_TOLERANCE:
+            warnings.append(f"⚠️ 价格差异过大: {price_range*100:.2f}% (容忍度: {DataValidator.PRICE_TOLERANCE*100}%)")
+            for src, price in prices.items():
+                deviation = (price - price_mean) / price_mean * 100
+                warnings.append(f"  - {src}: {price:.2f} (偏离均值: {deviation:+.2f}%)")
+        
+        # 使用加权平均价格
+        weighted_price = 0
+        total_weight = 0
+        for src in sources_data:
+            if src and 'data' in src and src['data']:
+                source_name = src['source']
+                weight = DATA_SOURCES.get(source_name, {}).get('weight', 0.25)
+                weighted_price += src['data']['close'] * weight
+                total_weight += weight
+        
+        if total_weight > 0:
+            weighted_price /= total_weight
+        
+        # 选择最接近加权平均的数据源
+        best_source = None
+        min_diff = float('inf')
+        for src in sources_data:
+            if src and 'data' in src and src['data']:
+                diff = abs(src['data']['close'] - weighted_price)
+                if diff < min_diff:
+                    min_diff = diff
+                    best_source = src
+        
+        if warnings:
+            warnings.append(f"✅ 使用加权平均价格: {weighted_price:.2f}")
+            if best_source:
+                warnings.append(f"✅ 选择数据源: {best_source['source']} (价格: {best_source['data']['close']:.2f})")
+        
+        return best_source['data'] if best_source else sources_data[0]['data'], warnings
+
+
+def fetch_sina_realtime():
+    """新浪实时行情接口"""
+    try:
+        url = "https://hq.sinajs.cn/list=sz399673"
+        headers = {
+            'Referer': 'https://finance.sina.com.cn',
+            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
+        }
+        response = requests.get(url, headers=headers, timeout=10)
+        response.encoding = 'gb2312'
+        
+        data_str = response.text
+        if 'var hq_str_sz399673="' in data_str:
+            data_str = data_str.split('var hq_str_sz399673="')[1].split('"')[0]
+            parts = data_str.split(',')
+            if len(parts) >= 32:
+                date_str = parts[30].strip()
+                if len(date_str) == 8 and date_str.isdigit():
+                    date = pd.Timestamp(f"{date_str[:4]}-{date_str[4:6]}-{date_str[6:8]}")
+                else:
+                    date = pd.Timestamp.now().normalize()
+                
+                return {
+                    'source': 'sina',
+                    'data': {
+                        'open': float(parts[1]),
+                        'high': float(parts[4]),
+                        'low': float(parts[5]),
+                        'close': float(parts[3]),
+                        'volume': int(parts[8]),
+                        'date': date
+                    }
+                }
+    except Exception as e:
+        print(f"  新浪实时数据获取失败: {e}")
+    return None
+
+
+def fetch_tencent_realtime():
+    """腾讯实时行情接口"""
+    try:
+        url = "https://qt.gtimg.cn/q=sz399673"
+        headers = {
+            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
+        }
+        response = requests.get(url, headers=headers, timeout=10)
+        response.encoding = 'gb2312'
+        
+        data_str = response.text
+        if 'v_sz399673="' in data_str:
+            data_str = data_str.split('v_sz399673="')[1].split('"')[0]
+            parts = data_str.split('~')
+            if len(parts) >= 45:
+                date_str = parts[30]
+                date = pd.Timestamp(date_str)
+                
+                return {
+                    'source': 'tencent',
+                    'data': {
+                        'close': float(parts[3]),
+                        'open': float(parts[5]),
+                        'high': float(parts[33]),
+                        'low': float(parts[34]),
+                        'volume': int(parts[36]),
+                        'date': date
+                    }
+                }
+    except Exception as e:
+        print(f"  腾讯实时数据获取失败: {e}")
+    return None
+
+
+def fetch_akshare_hist(start_date, end_date):
+    """使用akshare获取历史数据"""
+    try:
+        import akshare as ak
+        print(f"  [akshare] 获取 {start_date} 到 {end_date} 的历史数据...")
+        
+        df = ak.index_zh_a_hist(symbol="399673", period="daily", 
+                                start_date=start_date, end_date=end_date)
+        
+        if df is not None and len(df) > 0:
+            data_list = []
+            for _, row in df.iterrows():
+                data_list.append({
+                    'date': pd.Timestamp(row['日期']),
+                    'open': float(row['开盘']),
+                    'high': float(row['最高']),
+                    'low': float(row['最低']),
+                    'close': float(row['收盘']),
+                    'volume': int(row['成交量'])
+                })
+            print(f"  [akshare] ✅ 获取成功: {len(data_list)} 条")
+            return data_list
+    except Exception as e:
+        print(f"  [akshare] ❌ 获取失败: {e}")
+    return None
+
+
+def fetch_baostock_hist(start_date, end_date):
+    """使用baostock获取历史数据"""
+    try:
+        print(f"  [baostock] 获取 {start_date} 到 {end_date} 的历史数据...")
+        
+        lg = bs.login()
+        if lg.error_code != '0':
+            print(f"  [baostock] ❌ 登录失败: {lg.error_msg}")
+            return None
+        
+        rs = bs.query_history_k_data_plus("sz.399673",
+            "date,open,high,low,close,volume",
+            start_date=start_date, end_date=end_date,
+            frequency="d", adjustflag="3")
+        
+        data_list = []
+        while (rs.error_code == '0') & rs.next():
+            row = rs.get_row_data()
+            if row[0]:
+                data_list.append({
+                    'date': pd.Timestamp(row[0]),
+                    'open': float(row[1]) if row[1] else 0,
+                    'high': float(row[2]) if row[2] else 0,
+                    'low': float(row[3]) if row[3] else 0,
+                    'close': float(row[4]) if row[4] else 0,
+                    'volume': int(float(row[5])) if row[5] else 0
+                })
+        
+        bs.logout()
+        
+        if data_list:
+            print(f"  [baostock] ✅ 获取成功: {len(data_list)} 条")
+            return data_list
+    except Exception as e:
+        print(f"  [baostock] ❌ 获取失败: {e}")
+    return None
+
+
+def fetch_multi_source_realtime():
+    """从多个源获取实时数据并交叉验证"""
+    print("\n📊 多数据源获取实时数据...")
+    
+    sources = []
+    
+    # 获取新浪数据
+    sina_data = fetch_sina_realtime()
+    if sina_data:
+        sources.append(sina_data)
+        print(f"  [新浪]    收盘价: {sina_data['data']['close']:.2f}")
+    
+    # 获取腾讯数据
+    tencent_data = fetch_tencent_realtime()
+    if tencent_data:
+        sources.append(tencent_data)
+        print(f"  [腾讯]    收盘价: {tencent_data['data']['close']:.2f}")
+    
+    # 交叉验证
+    validated_data, warnings = DataValidator.validate_prices(sources)
+    
+    if warnings:
+        print("\n  ⚠️ 数据验证警告:")
+        for w in warnings:
+            print(f"     {w}")
+    
+    if validated_data:
+        print(f"\n  ✅ 最终使用收盘价: {validated_data['close']:.2f}")
+        return validated_data, sources
+    
+    return None, []
+
+
+def fetch_missing_data_multi_source(last_date, today):
+    """使用多个源获取缺失的历史数据"""
+    if last_date >= today:
+        return [], []
+    
+    start_str = (last_date + timedelta(days=1)).strftime('%Y-%m-%d')
+    end_str = (today - timedelta(days=1)).strftime('%Y-%m-%d')
+    
+    print(f"\n📊 补全缺失数据: {start_str} 到 {end_str}")
+    
+    all_warnings = []
+    
+    # 尝试baostock (优先级高)
+    data = fetch_baostock_hist(start_str, end_str)
+    if data:
+        return data, all_warnings
+    
+    # 尝试akshare
+    data = fetch_akshare_hist(start_str.replace('-', ''), end_str.replace('-', ''))
+    if data:
+        return data, all_warnings
+    
+    all_warnings.append(f"⚠️ 无法获取 {start_str} 到 {end_str} 的历史数据")
+    return [], all_warnings
+
+
+# ==================== 趋势跟踪策略 ====================
+class TrendTrackingStrategy:
+    """趋势跟踪策略 - 多数据源验证版"""
+    
+    def __init__(self):
+        self.data = None
+        self.warnings = []
+        self.data_sources = []
+        
+    def load_and_merge_data(self, csv_file='cyb50_baostock.csv'):
+        """加载历史数据并合并实时数据"""
+        try:
+            # 加载历史数据
+            df = pd.read_csv(f'/root/.openclaw/workspace/quant/{csv_file}')
+            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')
+            
+            last_hist_date = df.index[-1]
+            today = pd.Timestamp.now().normalize()
+            
+            print(f"历史数据最新日期: {last_hist_date.date()}")
+            print(f"当前日期: {today.date()}")
+            
+            # 获取缺失的历史数据
+            missing_data, warnings = fetch_missing_data_multi_source(last_hist_date, today)
+            self.warnings.extend(warnings)
+            
+            if missing_data:
+                for item in missing_data:
+                    new_row = pd.DataFrame({
+                        'open': [item['open']],
+                        'high': [item['high']],
+                        'low': [item['low']],
+                        'close': [item['close']],
+                        'volume': [item['volume']]
+                    }, index=[item['date']])
+                    df = pd.concat([df, new_row])
+                
+                df = df.sort_index()
+                last_hist_date = df.index[-1]
+                print(f"✅ 已合并历史数据,最新日期: {last_hist_date.date()}")
+            
+            # 获取今天的实时数据(多源验证)
+            if last_hist_date < today:
+                realtime_data, sources = fetch_multi_source_realtime()
+                self.data_sources = sources
+                
+                if realtime_data:
+                    date = realtime_data['date']
+                    
+                    if date > last_hist_date:
+                        new_row = pd.DataFrame({
+                            'open': [realtime_data['open']],
+                            'high': [realtime_data['high']],
+                            'low': [realtime_data['low']],
+                            'close': [realtime_data['close']],
+                            'volume': [realtime_data['volume']]
+                        }, index=[date])
+                        
+                        df = pd.concat([df, new_row])
+                        print(f"✅ 已合并实时数据: {date.date()} 收盘价 {realtime_data['close']:.2f}")
+                    else:
+                        print(f"⚠️ 实时数据日期({date.date()})不大于历史最新日期")
+                else:
+                    self.warnings.append("⚠️ 未获取到实时数据")
+            else:
+                print("✅ 历史数据已是最新")
+            
+            self.data = df.sort_index()
+            print(f"\n数据范围: {self.data.index[0].date()} ~ {self.data.index[-1].date()}")
+            print(f"数据条数: {len(self.data)}")
+            
+            return True
+            
+        except Exception as e:
+            print(f"❌ 数据加载失败: {e}")
+            import traceback
+            traceback.print_exc()
+            return False
+    
+    def calculate_indicators(self):
+        """计算技术指标"""
+        df = self.data.copy()
+        
+        # 均线
+        df['ma10'] = df['close'].rolling(window=10, min_periods=1).mean()
+        df['ma30'] = df['close'].rolling(window=30, min_periods=1).mean()
+        
+        # 20日高低点
+        df['high_20'] = df['high'].rolling(window=20).max()
+        df['low_20'] = df['low'].rolling(window=20).min()
+        
+        # 10日涨幅
+        df['ret_10'] = df['close'].pct_change(periods=10)
+        
+        # ATR
+        tr1 = df['high'] - df['low']
+        tr2 = abs(df['high'] - df['close'].shift(1))
+        tr3 = abs(df['low'] - df['close'].shift(1))
+        df['tr'] = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
+        df['atr'] = df['tr'].rolling(window=20).mean()
+        
+        self.data = df
+        return df
+    
+    def generate_signals(self):
+        """生成交易信号"""
+        df = self.data
+        
+        # 买入条件
+        buy_cond = (
+            (df['close'] > df['ma10']) & 
+            (df['ma10'] > df['ma30']) & 
+            (df['close'] >= df['high_20'] * 0.995) & 
+            (df['ret_10'] > 0.02)
+        )
+        
+        # 卖出条件
+        sell_cond = (
+            (df['close'] < df['ma30']) | 
+            (df['close'] <= df['low_20'] * 1.005)
+        )
+        
+        df['signal'] = 0
+        df.loc[buy_cond, 'signal'] = 1
+        df.loc[sell_cond, 'signal'] = -1
+        
+        return df
+    
+    def backtest(self, initial_capital=1000000):
+        """回测计算"""
+        df = self.generate_signals()
+        
+        position = 0
+        entry_price = 0
+        peak_price = 0
+        capital = initial_capital
+        trades = []
+        
+        for i in range(30, len(df)):
+            date = df.index[i]
+            price = df['close'].iloc[i]
+            signal = df['signal'].iloc[i]
+            
+            # 移动止损检查
+            if position > 0:
+                if price > peak_price:
+                    peak_price = price
+                if price < peak_price * 0.90:
+                    signal = -1
+            
+            # 买入
+            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
+                position = 0
+                trades.append({
+                    'date': date,
+                    'action': 'SELL',
+                    'price': price,
+                    'capital': capital,
+                    'pnl': pnl,
+                    'return_pct': (price / entry_price - 1) * 100
+                })
+        
+        current_position = position
+        current_price = df['close'].iloc[-1]
+        
+        if position == 1:
+            unrealized_pnl = (current_price / entry_price - 1) * capital
+            total_value = capital + unrealized_pnl
+        else:
+            total_value = capital
+        
+        total_return = (total_value / initial_capital - 1) * 100
+        
+        return {
+            'trades': trades,
+            'current_position': current_position,
+            'current_price': current_price,
+            'entry_price': entry_price if position == 1 else None,
+            'capital': capital,
+            'total_value': total_value,
+            'total_return': total_return,
+            'trade_count': len([t for t in trades if t['action'] == 'SELL']),
+            'data_end_date': df.index[-1].strftime('%Y-%m-%d')
+        }
+    
+    def get_recent_indicators(self, days=20):
+        """获取近N天指标详情"""
+        df = self.data.tail(days).copy()
+        
+        indicators = []
+        for date, row in df.iterrows():
+            indicators.append({
+                'date': date.strftime('%Y-%m-%d'),
+                'close': round(row['close'], 2),
+                'ma10': round(row['ma10'], 2) if not pd.isna(row['ma10']) else '-',
+                'ma30': round(row['ma30'], 2) if not pd.isna(row['ma30']) else '-',
+                'high_20': round(row['high_20'], 2) if not pd.isna(row['high_20']) else '-',
+                'ret_10': f"{row['ret_10']*100:.2f}%" if not pd.isna(row['ret_10']) else '-',
+                'signal': '买入' if row['signal'] == 1 else ('卖出' if row['signal'] == -1 else '持有'),
+                'atr': round(row['atr'], 2) if not pd.isna(row['atr']) else '-'
+            })
+        
+        return indicators
+    
+    def get_recent_trades(self, n=20):
+        """获取近N次交易详情"""
+        result = self.backtest()
+        trades = result['trades'][-n:]
+        return trades
+
+
+def generate_report():
+    """生成完整报告"""
+    strategy = TrendTrackingStrategy()
+    
+    if not strategy.load_and_merge_data():
+        return None, None, None
+    
+    strategy.calculate_indicators()
+    result = strategy.backtest()
+    
+    recent_indicators = strategy.get_recent_indicators(20)
+    recent_trades = strategy.get_recent_trades(20)
+    
+    # 数据源信息
+    source_info = ""
+    if strategy.data_sources:
+        source_info = "<div class='data-info'><strong>数据来源:</strong> "
+        for src in strategy.data_sources:
+            source_info += f"{src['source']}({src['data']['close']:.2f}) "
+        source_info += "| 已交叉验证</div>"
+    
+    # 警告信息
+    warnings_html = ""
+    if strategy.warnings:
+        warnings_html = "<div class='warning'><strong>⚠️ 警告:</strong><br>" + "<br>".join(strategy.warnings) + "</div>"
+    
+    html = f"""
+    <html>
+    <head>
+        <meta charset="utf-8">
+        <style>
+            body {{ font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }}
+            .container {{ max-width: 1200px; margin: 0 auto; background: white; padding: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }}
+            h1 {{ color: #333; border-bottom: 3px solid #007bff; padding-bottom: 10px; }}
+            h2 {{ color: #555; margin-top: 30px; border-left: 4px solid #007bff; padding-left: 10px; }}
+            .summary {{ background: #f8f9fa; padding: 15px; border-radius: 5px; margin: 20px 0; }}
+            .metric {{ display: inline-block; margin: 10px 20px 10px 0; }}
+            .metric-label {{ color: #666; font-size: 12px; }}
+            .metric-value {{ font-size: 24px; font-weight: bold; color: #333; }}
+            .positive {{ color: #28a745; }}
+            .negative {{ color: #dc3545; }}
+            .warning {{ background: #fff3cd; color: #856404; padding: 10px; border-radius: 5px; margin: 10px 0; }}
+            .data-info {{ background: #e7f3ff; padding: 10px; border-radius: 5px; margin: 10px 0; color: #004085; }}
+            table {{ width: 100%; border-collapse: collapse; margin: 20px 0; font-size: 13px; }}
+            th {{ background: #007bff; color: white; padding: 10px; text-align: left; }}
+            td {{ padding: 8px 10px; border-bottom: 1px solid #ddd; }}
+            tr:nth-child(even) {{ background: #f8f9fa; }}
+            tr:hover {{ background: #e9ecef; }}
+            .position-yes {{ color: #28a745; font-weight: bold; }}
+            .position-no {{ color: #666; }}
+            .buy {{ color: #28a745; font-weight: bold; }}
+            .sell {{ color: #dc3545; font-weight: bold; }}
+        </style>
+    </head>
+    <body>
+        <div class="container">
+            <h1>🚀 创业板50趋势跟踪策略报告 (多源验证版)</h1>
+            <p style="color: #666;">生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
+            
+            {warnings_html}
+            {source_info}
+            
+            <div class="data-info">
+                <strong>数据更新:</strong> 最新数据日期: {result['data_end_date']} | 
+                数据范围: {strategy.data.index[0].date()} ~ {strategy.data.index[-1].date()}
+            </div>
+            
+            <div class="summary">
+                <h2>📊 总体绩效</h2>
+                <div class="metric">
+                    <div class="metric-label">当前持仓</div>
+                    <div class="metric-value {'position-yes' if result['current_position'] == 1 else 'position-no'}">
+                        {'持有中' if result['current_position'] == 1 else '空仓'}
+                    </div>
+                </div>
+                <div class="metric">
+                    <div class="metric-label">当前价格</div>
+                    <div class="metric-value">{result['current_price']:.2f}</div>
+                </div>
+                <div class="metric">
+                    <div class="metric-label">累计收益率</div>
+                    <div class="metric-value {'positive' if result['total_return'] >= 0 else 'negative'}">
+                        {result['total_return']:+.2f}%
+                    </div>
+                </div>
+                <div class="metric">
+                    <div class="metric-label">总资产</div>
+                    <div class="metric-value">{result['total_value']:,.0f}元</div>
+                </div>
+                <div class="metric">
+                    <div class="metric-label">交易次数</div>
+                    <div class="metric-value">{result['trade_count']}</div>
+                </div>
+            </div>
+    """
+    
+    if result['current_position'] == 1:
+        unrealized = (result['current_price'] / result['entry_price'] - 1) * 100
+        html += f"""
+            <div class="summary" style="background: #e8f5e9;">
+                <h2>📈 持仓详情</h2>
+                <p><strong>入场价格:</strong> {result['entry_price']:.2f} 元</p>
+                <p><strong>当前浮盈:</strong> <span class="{'positive' if unrealized >= 0 else 'negative'}">{unrealized:+.2f}%</span></p>
+            </div>
+        """
+    
+    # 近20天指标
+    html += """
+            <h2>📅 近20天指标详情</h2>
+            <table>
+                <tr>
+                    <th>日期</th>
+                    <th>收盘价</th>
+                    <th>MA10</th>
+                    <th>MA30</th>
+                    <th>20日高</th>
+                    <th>10日涨幅</th>
+                    <th>信号</th>
+                    <th>ATR</th>
+                </tr>
+    """
+    
+    for ind in recent_indicators:
+        signal_class = 'buy' if ind['signal'] == '买入' else ('sell' if ind['signal'] == '卖出' else '')
+        html += f"""
+                <tr>
+                    <td>{ind['date']}</td>
+                    <td>{ind['close']}</td>
+                    <td>{ind['ma10']}</td>
+                    <td>{ind['ma30']}</td>
+                    <td>{ind['high_20']}</td>
+                    <td>{ind['ret_10']}</td>
+                    <td class="{signal_class}">{ind['signal']}</td>
+                    <td>{ind['atr']}</td>
+                </tr>
+        """
+    
+    html += """
+            </table>
+            
+            <h2>💼 近20次交易详情</h2>
+            <table>
+                <tr>
+                    <th>日期</th>
+                    <th>操作</th>
+                    <th>价格</th>
+                    <th>盈亏金额</th>
+                    <th>盈亏比例</th>
+                    <th>总资产</th>
+                </tr>
+    """
+    
+    for trade in recent_trades:
+        action_class = 'buy' if trade['action'] == 'BUY' else 'sell'
+        pnl = trade.get('pnl', 0)
+        ret = trade.get('return_pct', 0)
+        has_pnl = 'pnl' in trade
+        date_str = trade['date'].strftime('%Y-%m-%d') if hasattr(trade['date'], 'strftime') else str(trade['date'])
+        
+        ret_class = '' if not has_pnl else ('positive' if ret >= 0 else 'negative')
+        ret_text = '-' if not has_pnl else f'{ret:+.2f}%'
+        
+        html += f"""
+                <tr>
+                    <td>{date_str}</td>
+                    <td class="{action_class}">{trade['action']}</td>
+                    <td>{trade['price']:.2f}</td>
+                    <td>{f'{pnl:+,.0f}元' if has_pnl else '-'}</td>
+                    <td class="{ret_class}">{ret_text}</td>
+                    <td>{trade['capital']:,.0f}元</td>
+                </tr>
+        """
+    
+    html += """
+            </table>
+            
+            <div style="margin-top: 30px; padding: 15px; background: #fff3cd; border-radius: 5px; color: #856404;">
+                <strong>策略说明:</strong><br>
+                • 买入条件: 价格>MA10>MA30 且 突破20日高×0.995 且 10日涨幅>2%<br>
+                • 卖出条件: 跌破MA30 或 创20日新低 或 回撤10%止损<br>
+                • 数据验证: 多源交叉验证,差异>2%时报警
+            </div>
+        </div>
+    </body>
+    </html>
+    """
+    
+    # 文本报告
+    text = f"""
+创业板50趋势跟踪策略报告 (多源验证版)
+生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
+数据最新日期: {result['data_end_date']}
+"""
+    
+    if strategy.warnings:
+        text += "\n警告:\n" + "\n".join(strategy.warnings) + "\n"
+    
+    text += f"""
+【总体绩效】
+当前持仓: {'持有中' if result['current_position'] == 1 else '空仓'}
+当前价格: {result['current_price']:.2f}元
+累计收益率: {result['total_return']:+.2f}%
+总资产: {result['total_value']:,.0f}元
+
+【近20天指标】
+日期        收盘价    MA10     MA30     20日高   10日涨幅  信号
+"""
+    
+    for ind in recent_indicators:
+        text += f"{ind['date']}  {ind['close']:>8}  {ind['ma10']:>8}  {ind['ma30']:>8}  {ind['high_20']:>8}  {ind['ret_10']:>8}  {ind['signal']:>4}\n"
+    
+    text += "\n【近20次交易】\n"
+    for trade in recent_trades:
+        pnl_str = f"{trade.get('pnl', 0):+,.0f}元" if 'pnl' in trade else '-'
+        ret_str = f"{trade.get('return_pct', 0):+.2f}%" if 'return_pct' in trade else '-'
+        date_str = trade['date'].strftime('%Y-%m-%d') if hasattr(trade['date'], 'strftime') else str(trade['date'])
+        text += f"{date_str}  {trade['action']:>6}  {trade['price']:>8.2f}  {pnl_str:>12}  {ret_str:>10}\n"
+    
+    return html, text, result
+
+
+def send_email(subject, html_content, text_content):
+    """发送邮件"""
+    try:
+        msg = MIMEMultipart('alternative')
+        msg['Subject'] = Header(subject, 'utf-8')
+        msg['From'] = EMAIL_CONFIG['sender_email']
+        msg['To'] = EMAIL_CONFIG['receiver_email']
+        
+        text_part = MIMEText(text_content, 'plain', 'utf-8')
+        msg.attach(text_part)
+        
+        html_part = MIMEText(html_content, 'html', 'utf-8')
+        msg.attach(html_part)
+        
+        with smtplib.SMTP(EMAIL_CONFIG['smtp_server'], EMAIL_CONFIG['smtp_port']) as server:
+            server.sendmail(
+                EMAIL_CONFIG['sender_email'],
+                EMAIL_CONFIG['receiver_email'],
+                msg.as_string()
+            )
+        print(f"✅ 邮件发送成功: {subject}")
+        return True
+    except Exception as e:
+        print(f"❌ 邮件发送失败: {e}")
+        return False
+
+
+def main():
+    """主程序"""
+    print("="*60)
+    print("🚀 创业板50趋势跟踪实时报告 (多数据源交叉验证版)")
+    print("="*60)
+    print(f"执行时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
+    
+    html, text, result = generate_report()
+    
+    if html is None:
+        print("❌ 报告生成失败")
+        return
+    
+    print(f"\n✅ 报告生成完成")
+    print(f"   数据最新日期: {result['data_end_date']}")
+    print(f"   当前持仓: {'持有中' if result['current_position'] == 1 else '空仓'}")
+    print(f"   累计收益: {result['total_return']:+.2f}%")
+    
+    print("\n📧 发送邮件...")
+    position_status = "持仓" if result['current_position'] == 1 else "空仓"
+    subject = f"🚀 创业板50趋势报告 {datetime.now().strftime('%m-%d %H:%M')} | {position_status} | 收益{result['total_return']:+.2f}%"
+    send_email(subject, html, text)
+    
+    print("\n✅ 全部完成!")
+    print("="*60)
+
+
+if __name__ == "__main__":
+    main()

trend-max-daily.py → trend-max-daily/trend-max-daily.py


BIN
trend-mix/__pycache__/trend_mix_strategy.cpython-312.pyc


BIN
trend-quality-evaluator/__pycache__/trend_quality_evaluator.cpython-312.pyc


+ 215 - 0
trend-quality-evaluator/backtest_report.py

@@ -0,0 +1,215 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+趋势质量评估器 - 历史回测 (2017-至今)
+生成完整回测报告
+"""
+
+import sys
+sys.path.insert(0, '/root/.openclaw/workspace/trend-quality-evaluator')
+
+import numpy as np
+import pandas as pd
+from trend_quality_evaluator import fetch_stock_data, TrendQualityEvaluator
+from datetime import datetime
+import warnings
+warnings.filterwarnings('ignore')
+
+print("="*70)
+print("趋势质量评估器 - 历史回测报告")
+print("回测区间: 2017-01-01 至 2026-03-06")
+print("="*70)
+
+# 获取数据
+df = fetch_stock_data("399673", "2017-01-01", "2026-03-06", "d")
+if df is None:
+    print("数据获取失败")
+    exit(1)
+
+print(f"\n✓ 数据获取成功: {len(df)}条")
+print(f"  日期范围: {df.index[0].date()} ~ {df.index[-1].date()}")
+
+# 初始化评估器
+evaluator = TrendQualityEvaluator()
+
+# 逐日评估
+print("\n正在进行历史回测...")
+results = []
+
+# 需要至少60天数据计算MA60
+start_idx = 60
+for i in range(start_idx, len(df)):
+    current_df = df.iloc[:i+1]
+    
+    try:
+        score = evaluator.evaluate(current_df)
+        results.append({
+            'date': df.index[i],
+            'close': df['close'].iloc[i],
+            'total_score': score.total_score,
+            'adx_score': score.adx_score,
+            'ma_slope_score': score.ma_slope_score,
+            'volatility_score': score.volatility_score,
+            'timeframe_score': score.timeframe_score,
+            'volume_score': score.volume_score,
+            'is_tradeable': score.is_tradeable,
+            'adx_value': score.adx_value,
+            'ma_slope': score.ma_slope,
+            'volatility_ratio': score.volatility_ratio,
+            'volume_ratio': score.volume_ratio
+        })
+    except Exception as e:
+        pass
+
+    if i % 100 == 0:
+        print(f"  进度: {i}/{len(df)} ({i/len(df)*100:.1f}%)")
+
+results_df = pd.DataFrame(results)
+results_df = results_df.set_index('date')
+
+print(f"\n✓ 回测完成: {len(results_df)}个交易日")
+
+# 计算未来收益率(用于验证评分有效性)
+print("\n计算未来收益验证...")
+results_df['future_5d_return'] = results_df['close'].pct_change(5).shift(-5) * 100
+results_df['future_10d_return'] = results_df['close'].pct_change(10).shift(-10) * 100
+results_df['future_20d_return'] = results_df['close'].pct_change(20).shift(-20) * 100
+
+# ============================================
+# 生成报告
+# ============================================
+print("\n" + "="*70)
+print("回测报告")
+print("="*70)
+
+# 1. 评分分布统计
+print("\n【一、评分分布统计】")
+print("-"*50)
+
+total_days = len(results_df)
+tradeable_days = results_df['is_tradeable'].sum()
+
+print(f"总交易天数: {total_days}")
+print(f"可交易天数(≥60分): {tradeable_days} ({tradeable_days/total_days*100:.1f}%)")
+print(f"不可交易天数(<60分): {total_days-tradeable_days} ({(total_days-tradeable_days)/total_days*100:.1f}%)")
+
+# 分数段分布
+print(f"\n分数段分布:")
+bins = [0, 40, 60, 70, 80, 100]
+labels = ['0-40(混乱)', '40-60(较差)', '60-70(及格)', '70-80(良好)', '80-100(优秀)']
+results_df['score_bin'] = pd.cut(results_df['total_score'], bins=bins, labels=labels, include_lowest=True)
+score_dist = results_df['score_bin'].value_counts().sort_index()
+
+for label, count in score_dist.items():
+    pct = count / total_days * 100
+    bar = '█' * int(pct / 2)
+    print(f"  {label:15s}: {count:4d}天 ({pct:5.1f}%) {bar}")
+
+# 2. 各因子得分统计
+print("\n【二、各因子得分统计】")
+print("-"*50)
+
+factors = [
+    ('adx_score', 'ADX趋势强度', 30),
+    ('ma_slope_score', '均线斜率', 25),
+    ('volatility_score', '波动率收缩', 20),
+    ('timeframe_score', '时间框架共振', 15),
+    ('volume_score', '成交量确认', 10)
+]
+
+for col, name, max_score in factors:
+    mean_score = results_df[col].mean()
+    pct_of_max = mean_score / max_score * 100
+    print(f"{name:15s}: 平均{mean_score:5.1f}/{max_score}分 ({pct_of_max:4.1f}%)")
+
+# 3. 评分有效性验证
+print("\n【三、评分有效性验证】")
+print("-"*50)
+print("不同评分区间的未来收益表现:")
+print(f"{'评分区间':<15} {'5日后收益':<12} {'10日后收益':<12} {'20日后收益':<12} {'样本数':<8}")
+print("-"*60)
+
+for label in labels:
+    mask = results_df['score_bin'] == label
+    if mask.sum() > 0:
+        r5 = results_df[mask]['future_5d_return'].mean()
+        r10 = results_df[mask]['future_10d_return'].mean()
+        r20 = results_df[mask]['future_20d_return'].mean()
+        count = mask.sum()
+        print(f"{label:<15} {r5:>+10.2f}% {r10:>+10.2f}% {r20:>+10.2f}% {count:>6d}")
+
+# 4. 可交易 vs 不可交易对比
+print("\n【四、可交易性验证】")
+print("-"*50)
+
+tradeable_mask = results_df['is_tradeable']
+not_tradeable_mask = ~results_df['is_tradeable']
+
+print(f"{'指标':<20} {'可交易(≥60分)':<15} {'不可交易(<60分)':<15} {'差异':<10}")
+print("-"*60)
+
+for period, col in [('5日', 'future_5d_return'), ('10日', 'future_10d_return'), ('20日', 'future_20d_return')]:
+    t_mean = results_df[tradeable_mask][col].mean()
+    nt_mean = results_df[not_tradeable_mask][col].mean()
+    diff = t_mean - nt_mean
+    print(f"{period+'收益':<20} {t_mean:>+13.2f}% {nt_mean:>+14.2f}% {diff:>+9.2f}%")
+
+# 5. 年度最佳/最差月份
+print("\n【五、年度统计】")
+print("-"*50)
+
+results_df['year'] = results_df.index.year
+yearly_stats = results_df.groupby('year').agg({
+    'total_score': 'mean',
+    'is_tradeable': 'sum',
+    'future_20d_return': 'mean'
+}).round(2)
+yearly_stats['tradeable_pct'] = (yearly_stats['is_tradeable'] / results_df.groupby('year').size() * 100).round(1)
+
+print(f"{'年份':<8} {'平均评分':<10} {'可交易天数':<12} {'可交易比例':<12} {'20日收益':<10}")
+print("-"*60)
+for year, row in yearly_stats.iterrows():
+    print(f"{year:<8} {row['total_score']:>8.1f}    {int(row['is_tradeable']):>8}天     {row['tradeable_pct']:>8.1f}%     {row['future_20d_return']:>+7.2f}%")
+
+# 6. 最新评分
+print("\n【六、最新评分】")
+print("-"*50)
+latest = results_df.iloc[-1]
+print(f"日期: {results_df.index[-1].strftime('%Y-%m-%d')}")
+print(f"收盘价: {latest['close']:.2f}")
+print(f"总分: {latest['total_score']:.1f}分")
+print(f"是否可交易: {'✅ 是' if latest['is_tradeable'] else '❌ 否'}")
+print(f"\n各因子得分:")
+for col, name, max_score in factors:
+    print(f"  {name:15s}: {latest[col]:.1f}/{max_score}分")
+
+# 7. 关键发现
+print("\n【七、关键发现】")
+print("-"*50)
+
+# 计算胜率
+tradeable_returns = results_df[tradeable_mask]['future_20d_return'].dropna()
+win_rate = (tradeable_returns > 0).mean() * 100
+
+print(f"1. 可交易信号胜率(20日): {win_rate:.1f}%")
+
+# 最佳评分日期
+best_day = results_df.loc[results_df['total_score'].idxmax()]
+print(f"2. 历史最高评分: {best_day['total_score']:.1f}分 ({results_df['total_score'].idxmax().strftime('%Y-%m-%d')})")
+
+# 评分与收益相关性
+corr_20d = results_df['total_score'].corr(results_df['future_20d_return'])
+print(f"3. 评分与20日收益相关性: {corr_20d:.3f}")
+
+# 连续可交易日统计
+results_df['tradeable_change'] = results_df['is_tradeable'].astype(int).diff()
+entry_points = results_df[results_df['tradeable_change'] == 1].index
+print(f"4. 历史可交易入场信号次数: {len(entry_points)}次")
+
+print("\n" + "="*70)
+print("回测报告生成完成")
+print("="*70)
+
+# 保存结果
+results_df.to_csv('/root/.openclaw/workspace/trend-quality-evaluator/backtest_results.csv')
+print("\n✓ 详细数据已保存: backtest_results.csv")

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 2166 - 0
trend-quality-evaluator/backtest_results.csv


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 2166 - 0
trend-quality-evaluator/best_config_backtest.csv


+ 568 - 0
trend-quality-evaluator/optimization_results.csv

@@ -0,0 +1,568 @@
+adx_threshold,adx_weight,ma_slope_threshold,ma_slope_weight,volatility_threshold,volatility_weight,volume_threshold,volume_weight,tradeable_pct,return_5d,return_10d,return_20d,excess_return_20d,win_rate_20d,sharpe_20d,composite_score
+20,30,1.003,20,0.8,25,1.3,10,26.836027713625864,0.40869726023345265,1.0920343813035844,2.3815351754771417,1.7345884630283304,58.793103448275865,0.24797871025103166,99.05401984549414
+20,25,1.003,25,0.8,25,1.3,10,24.157043879907622,0.43420366662324256,1.228596788931519,2.3801367154628177,1.6707524632831867,59.00383141762452,0.2571913934824961,98.71961772987557
+20,30,1.002,20,0.8,25,1.3,10,27.436489607390303,0.40578151750753194,1.0681217828516387,2.362056293749282,1.7221963552403856,59.02192242833052,0.2474391575487246,98.62931034197675
+20,25,1.002,25,0.8,25,1.3,10,25.080831408775982,0.43660631248003534,1.1660456288854115,2.3276992161217382,1.6214303255283822,59.040590405904055,0.2539338593786967,96.96507727215156
+20,30,1.001,20,0.8,25,1.3,10,27.9445727482679,0.3892088794782543,1.0226762331557757,2.323479024285978,1.6797020105929255,58.872305140961856,0.2423716362366248,96.96403069017927
+20,30,1.002,20,0.9,25,1.3,10,33.25635103926097,0.339321658844012,0.8874248222815377,2.2392213896407793,1.689598789635582,58.692628650904034,0.23572984338259192,95.49690432865357
+20,30,1.003,20,0.9,25,1.3,10,32.609699769053115,0.333409649137298,0.9114291859332626,2.240876762983708,1.6756379512784174,58.723404255319146,0.23755681236818182,95.4287215953501
+20,25,1.003,25,0.8,25,1.5,10,23.787528868360276,0.3508335510356675,1.1963681859110133,2.2932290018504986,1.5482613134335912,58.949416342412455,0.24866524078774774,94.82502512990168
+20,25,1.003,25,0.8,25,1.8,10,23.556581986143186,0.3370247701365936,1.1914140402212858,2.26135928855889,1.5017442953543316,58.93909626719057,0.2466361411043581,93.45778591157308
+20,25,1.002,25,0.8,25,1.5,10,24.71131639722864,0.3563887641421907,1.1340864890051696,2.2432608925422235,1.5009513393817118,58.98876404494382,0.2456086175503598,93.15288604484411
+20,25,1.003,25,0.7,25,1.3,10,22.170900692840647,0.47333822717198826,1.2688506145600442,2.266765741137913,1.481662969977006,58.24634655532359,0.24658517299755345,92.94166542931167
+30,25,1.003,25,0.8,25,1.8,10,20.0,0.3486261459793333,1.1291530845952005,2.263727081145769,1.4372052436068552,59.25925925925925,0.24433086476532384,92.29979516825591
+25,25,1.003,25,0.8,25,1.3,10,21.986143187066975,0.31028040249281286,1.1626559257373836,2.259260984701928,1.4684747337883253,58.526315789473685,0.24093350559651103,92.2736902796786
+20,30,1.002,20,0.9,25,1.5,10,32.840646651270205,0.26684088313221194,0.8447018504335828,2.159381845821977,1.55965996691917,58.59154929577465,0.2284675506414096,91.64512993080707
+20,30,1.003,20,0.9,25,1.5,10,32.19399538106236,0.2593966798138398,0.8681580328327885,2.1594526570192483,1.5446956125239169,58.620689655172406,0.2301366792547947,91.52680657878062
+25,30,1.003,20,0.8,25,1.3,10,24.387990762124712,0.286520019753179,0.9957597075390519,2.2430578180019665,1.4941885122713758,58.06451612903226,0.23012443708057984,91.51846788189968
+30,30,1.003,20,0.8,25,1.3,10,22.771362586605083,0.39692771755403533,1.0032183864082747,2.2458228330594108,1.4661391228997607,58.739837398373986,0.23132719365693208,91.3888007905416
+20,25,1.002,25,0.8,25,1.8,10,24.526558891454968,0.33997335920662203,1.1249597830436606,2.202070047971242,1.4425252298075433,58.867924528301884,0.2426522451290739,91.35298746113278
+30,30,1.002,20,0.8,25,1.3,10,23.325635103926096,0.40028473419357913,0.9908949197910347,2.2343596672827153,1.461876587179947,59.12698412698413,0.23163126369060036,91.32451069120728
+20,30,1.003,20,0.8,25,1.5,10,26.32794457274827,0.3207911412587671,1.052626210293837,2.189362817685992,1.4609271809500766,58.69947275922671,0.2388570948546506,91.15941226356144
+25,30,1.002,20,0.8,25,1.3,10,24.988452655889144,0.2862544983983668,0.971817909532551,2.2250008342659595,1.4821587431410292,58.333333333333336,0.2298346198123235,91.15080706880372
+20,25,1.001,25,0.8,25,1.3,10,26.00461893764434,0.39695642302490974,1.0561351535025547,2.193943826149456,1.459752209805209,58.288770053475936,0.23874701813323876,91.05013012783215
+20,30,1.001,20,0.9,25,1.3,10,33.8568129330254,0.31923982893289726,0.8593797264622286,2.13878438921266,1.551577445616707,58.276333789329684,0.22532918979828648,90.895830358788
+20,30,1.002,20,0.8,25,1.5,10,26.9284064665127,0.3197805552681566,1.0291411721166,2.173808288109814,1.4517317794218931,58.93470790378007,0.23851277052238207,90.85676420517922
+25,25,1.003,25,0.8,25,1.8,10,21.43187066974596,0.2869548037540492,1.1377158947967954,2.222641473437394,1.411298426732508,58.747300215982726,0.23834479413875323,90.6965279448547
+30,25,1.003,25,0.8,25,1.5,10,20.184757505773675,0.34717631641828833,1.114829094863818,2.225830990464299,1.3930049548196546,58.944954128440365,0.2408734443568099,90.6834183379191
+30,25,1.003,25,0.8,25,1.3,10,20.184757505773675,0.34717631641828833,1.114829094863818,2.225830990464299,1.3930049548196546,58.944954128440365,0.2408734443568099,90.6834183379191
+25,25,1.002,25,0.8,25,1.3,10,22.909930715935335,0.3179076242324235,1.096836444606025,2.206728439191529,1.4179821183676955,58.58585858585859,0.23788339261609334,90.52150017236092
+30,30,1.002,20,0.9,25,1.5,10,29.2378752886836,0.2545049292672297,0.796270155055866,2.1588635937788734,1.4785197633156324,59.33544303797469,0.2261351559259545,90.30404383595705
+30,25,1.002,25,0.8,25,1.8,10,20.92378752886836,0.3586659050505186,1.0694893519464728,2.203006204937902,1.377251212541446,59.29203539823009,0.2405028531546965,90.21132789832605
+30,30,1.002,20,0.9,25,1.8,10,29.099307159353348,0.23495276605970788,0.7817663639993281,2.1540936310889855,1.4688448759411226,59.30047694753577,0.22515200495405546,89.98841724909532
+30,30,1.003,20,0.9,25,1.5,10,28.63741339491917,0.24080633119293543,0.8108697336416724,2.1525949466742564,1.4571128137989175,59.2891760904685,0.2273916479438304,89.93699188191025
+25,30,1.001,20,0.8,25,1.3,10,25.54272517321016,0.26296101653407383,0.9208296005152554,2.186946510486973,1.4411783301351475,58.257713248638844,0.2251608677770502,89.57380246995116
+20,30,1.002,20,0.9,25,1.8,10,32.70207852193995,0.25429452463696767,0.8305249600608826,2.113672211967609,1.4882231487561817,58.415841584158414,0.2245772789567704,89.47221264143634
+20,25,1.002,25,0.9,25,1.3,10,30.484988452655887,0.34305595980558523,0.9552792948231782,2.1387427312436462,1.4763399406180948,57.81487101669196,0.22550621626824804,89.45264975234697
+30,30,1.002,20,0.9,25,1.3,10,29.330254041570434,0.2591026904577174,0.7874875390169469,2.1383940061232183,1.4514183563038858,59.148264984227126,0.22412445229063202,89.35816560879883
+20,30,1.001,20,0.8,25,1.5,10,27.436489607390303,0.3044936269464733,0.9835759013288699,2.137694076234852,1.411198832430538,58.78378378378378,0.23327572345887793,89.24281188957903
+30,25,1.002,25,0.8,25,1.5,10,21.062355658198616,0.3609255989413934,1.0605479755433875,2.1789173176648395,1.3491216802555908,59.120879120879124,0.23829325425321443,89.19199700503454
+30,25,1.002,25,0.8,25,1.3,10,21.062355658198616,0.3609255989413934,1.0605479755433875,2.1789173176648395,1.3491216802555908,59.120879120879124,0.23829325425321443,89.19199700503454
+20,30,1.002,20,0.8,25,1.8,10,26.74364896073903,0.3056482120195264,1.015430251754391,2.135403168534507,1.3954548753971832,58.82352941176471,0.2356943874955873,89.14310724662845
+30,30,1.002,20,0.8,25,1.8,10,22.956120092378754,0.3739255316484313,1.0005314559553513,2.1663264937370603,1.3662876423934884,59.4758064516129,0.23432053432946123,89.14070047484863
+20,25,1.002,25,0.7,25,1.3,10,23.187066974595844,0.4510820492612171,1.1603448669945058,2.1676548633059065,1.372176201357687,58.28343313373253,0.23734775484190684,89.09372271645186
+20,25,1.003,25,0.9,25,1.3,10,29.65357967667436,0.337083047727058,1.0035217527910791,2.1349394399261947,1.4532467366240396,57.72230889235569,0.22641584649527952,89.04494884189069
+30,30,1.003,20,0.9,25,1.8,10,28.452655889145497,0.2216576353101716,0.7921627318194325,2.1355200542501054,1.4293650389590484,59.18699186991871,0.22502640836555274,89.02370847010509
+30,30,1.003,20,0.9,25,1.3,10,28.729792147806005,0.24554423400982975,0.8018566141209567,2.131717038011654,1.4296397898791768,59.09822866344605,0.22531962152115026,88.9735067103266
+20,30,1.003,20,0.8,25,1.8,10,26.096997690531175,0.30745443747867984,1.0348689540938438,2.1369140242590228,1.3851477389478,58.51063829787234,0.2344609288523173,88.78274187336602
+20,30,1.003,20,0.9,25,1.8,10,32.00923787528868,0.24738628713737804,0.8503521092683997,2.1019503631482928,1.4555550737742298,58.38150289017341,0.22493970308037095,88.77618973315481
+20,25,1.003,25,0.7,25,1.5,10,21.801385681293304,0.38303625038552364,1.2343681994106113,2.169998156018314,1.3505878362605441,58.174097664543524,0.23703015834912003,88.68840290847072
+30,30,1.003,20,0.8,25,1.5,10,22.586605080831408,0.3931336305157312,1.0275233253341833,2.161682244582094,1.353679183988811,59.01639344262295,0.23301347654427818,88.60800361846923
+30,30,1.002,20,0.8,25,1.5,10,23.140877598152425,0.39660832601958196,1.0145193135401371,2.152146747602641,1.3511202230082264,59.4,0.2333712314247255,88.60044405715178
+30,30,1.001,20,0.8,25,1.3,10,23.97228637413395,0.36122015557048254,0.925500396834883,2.1679095135408866,1.3859974814410747,58.80077369439072,0.22415845958261238,88.48429813471465
+25,25,1.003,25,0.8,25,1.5,10,21.61662817551963,0.2996208417112116,1.1334146853531384,2.17158997530703,1.3494031527261308,58.45824411134903,0.2330471357152408,88.47378369797444
+25,25,1.002,25,0.8,25,1.8,10,22.401847575057737,0.29235103074419044,1.0672838339567856,2.159397210226853,1.3474683980598843,58.67768595041323,0.23427974628238227,88.45637413094805
+30,30,1.003,20,0.8,25,1.8,10,22.35565819861432,0.37129156784222833,1.0086943603064804,2.160850851209212,1.3485337359113285,59.006211180124225,0.23223652634497033,88.44469717584104
+25,30,1.002,20,0.9,25,1.3,10,30.85450346420323,0.1864460968670889,0.7721786444996083,2.108066053315983,1.439810336673648,58.32083958020989,0.22067860097634656,88.22916485733647
+25,30,1.003,20,0.9,25,1.3,10,30.207852193995382,0.1767914535633931,0.7956245684280038,2.10704134198094,1.4248268577680863,58.34609494640123,0.22219518336586594,88.08354165919334
+20,30,1.001,20,0.8,25,1.8,10,27.25173210161663,0.2905211278714844,0.9698116912053616,2.099696430040928,1.3552259702496203,58.673469387755105,0.2304509837543423,87.53934254981372
+20,25,1.001,25,0.8,25,1.5,10,25.635103926096996,0.3190580672115981,1.0237433991980642,2.1104716599446833,1.3399495627023956,58.22784810126582,0.23048463763939242,87.26363660919509
+20,25,1.003,25,0.7,25,1.8,10,21.570438799076214,0.36830077980355713,1.2293647428061936,2.1338654558153314,1.3004046432190315,58.15450643776824,0.23461968615303072,87.17128175536769
+20,30,1.001,20,0.9,25,1.5,10,33.441108545034645,0.24781086760653,0.817075252917657,2.0590198336514374,1.4215288379643014,58.17174515235457,0.21802113090632982,87.03836284466571
+25,25,1.002,25,0.8,25,1.5,10,22.540415704387993,0.3078099671179309,1.0677146078255384,2.1217949243013843,1.3012594124652217,58.52156057494866,0.23019682963814422,86.81350835237522
+25,30,1.002,20,0.9,25,1.8,10,30.43879907621247,0.1801451833595019,0.7490755939571739,2.073628028729476,1.3814190416042997,58.35866261398176,0.21824696560581408,86.60909193027754
+30,25,1.002,25,0.9,25,1.8,10,26.189376443418016,0.22407642419041945,0.8494255685316687,2.102063248057536,1.33955899957206,58.657243816254415,0.22014565695535898,86.49136391038873
+25,30,1.002,20,0.8,25,1.8,10,24.43418013856813,0.28211820613376226,0.9602702231014572,2.1005022923410883,1.3060082933286967,58.52272727272727,0.2280791058029683,86.46313109555683
+30,30,1.001,20,0.8,25,1.8,10,23.602771362586605,0.33497154442777544,0.9338491293006681,2.1005695227578225,1.2909288628095341,59.13555992141454,0.2263119439560928,86.27183467638675
+30,25,1.003,25,0.9,25,1.8,10,25.357967667436487,0.2104005317648859,0.8933555430557284,2.0988785102064322,1.3201830918181998,58.57664233576643,0.22126996812756716,86.17646240741004
+20,25,1.002,25,0.9,25,1.5,10,30.11547344110854,0.27608542118266743,0.9264690639820322,2.067157913009413,1.3656571061887945,57.757296466973884,0.21850493604506296,86.07282156419089
+25,30,1.003,20,0.8,25,1.8,10,23.787528868360276,0.2834601426425408,0.9800966821706799,2.1012095109440434,1.2957280160734772,58.17120622568094,0.22661965643297804,86.06254303389484
+20,30,1.003,20,0.7,25,1.3,10,24.157043879907622,0.4540461272540475,1.1291683660321523,2.1158437706604034,1.3214558726478334,57.279693486590034,0.22053145217781328,85.91862951987525
+25,30,1.003,20,0.9,25,1.8,10,29.745958429561203,0.17098423816326344,0.7685142180398657,2.0600787563631635,1.3482735856457086,58.320373250388805,0.2184233055223102,85.86599375434572
+30,30,1.001,20,0.9,25,1.5,10,29.79214780600462,0.2312165569793338,0.766250058911666,2.0586751140900215,1.3462690499094299,58.94245723172629,0.21582995246214098,85.82116515169591
+25,30,1.002,20,0.9,25,1.5,10,30.484988452655887,0.17461234722837476,0.7439929111818584,2.0557907888326206,1.3566011004622067,58.2701062215478,0.21628281285853287,85.77264966004032
+30,30,1.001,20,0.8,25,1.5,10,23.787528868360276,0.3573402743866671,0.9479746554299816,2.0872618323420475,1.2766020978030395,59.06432748538012,0.22543334325883926,85.76413886356973
+30,25,1.002,25,0.9,25,1.3,10,26.32794457274827,0.22659254499185671,0.8434306978482257,2.0833328177612223,1.3166160452656661,58.523725834797894,0.21851796049565728,85.68714300569485
+30,25,1.002,25,0.9,25,1.5,10,26.32794457274827,0.22659254499185671,0.8434306978482257,2.0833328177612223,1.3166160452656661,58.523725834797894,0.21851796049565728,85.68714300569485
+20,25,1.003,25,0.9,25,1.5,10,29.28406466512702,0.26813576936937544,0.9745023035092429,2.0612709675707044,1.341047763677268,57.66192733017378,0.21919071934422385,85.59430021677805
+25,30,1.003,20,0.9,25,1.5,10,29.838337182448036,0.16458168280800478,0.7671183507835952,2.053618710996108,1.3408334188850133,58.29457364341085,0.21770551485937967,85.59144487129471
+30,30,1.001,20,0.9,25,1.8,10,29.65357967667436,0.21192103059677547,0.7518770859302775,2.0535175016353246,1.3362345742515878,58.90625000000001,0.21483706419817572,85.49326167100305
+25,25,1.002,25,0.9,25,1.3,10,28.221709006928407,0.21360972292144115,0.8741289335458126,2.069286376724859,1.3321545741470298,57.70491803278689,0.21581009372604038,85.2930290519561
+20,25,1.002,25,0.7,25,1.5,10,22.817551963048498,0.3644411940658781,1.1256409278628126,2.07359721703007,1.2434043727423536,58.21501014198783,0.2280031480739916,84.93208162802138
+30,25,1.003,25,0.9,25,1.3,10,25.54272517321016,0.21025464919468925,0.8837418118686463,2.0701406456170055,1.2848020578087538,58.333333333333336,0.2187209874559854,84.9224985283841
+30,25,1.003,25,0.9,25,1.5,10,25.54272517321016,0.21025464919468925,0.8837418118686463,2.0701406456170055,1.2848020578087538,58.333333333333336,0.2187209874559854,84.9224985283841
+25,30,1.001,20,0.8,25,1.8,10,24.988452655889144,0.2583997958495132,0.9084070758752253,2.064141534565489,1.2663895298155925,58.44155844155844,0.22307341579577106,84.90333175483111
+30,30,1.001,20,0.9,25,1.3,10,29.884526558891455,0.23580103163240262,0.757723133111936,2.038865282129855,1.3197360156062712,58.75968992248062,0.2138825880146831,84.89983657173728
+20,30,1.001,20,0.9,25,1.8,10,33.30254041570439,0.23541154463675196,0.8030390279850362,2.0136543299357905,1.3502991100653146,57.99721835883172,0.2141173754040554,84.87271076026688
+25,30,1.003,20,0.8,25,1.5,10,23.926096997690532,0.27406620786821967,0.9746504500954475,2.07364342837655,1.2617955449069826,58.027079303675045,0.22355256490288866,84.84145530340281
+25,25,1.003,25,0.9,25,1.3,10,27.390300230946885,0.20321403688715933,0.9238944504301295,2.0630564373400206,1.3081094986060608,57.60135135135135,0.21641703623482458,84.8110586285137
+20,25,1.001,25,0.7,25,1.3,10,24.110854503464203,0.42855271918196935,1.0705917119982498,2.0648422279730445,1.252507429072645,57.692307692307686,0.22579504303216583,84.63175578975812
+20,25,1.001,25,0.8,25,1.8,10,25.496535796766747,0.303249787750738,1.00653304822419,2.051447220503465,1.258051586972289,57.99999999999999,0.22538975590962007,84.63085881800842
+25,30,1.002,20,0.8,25,1.5,10,24.526558891454968,0.2741005816941163,0.9507745699170101,2.0594011941269033,1.2530362567449385,58.30188679245283,0.2234461644579983,84.59468951217019
+20,25,1.002,25,0.9,25,1.8,10,29.930715935334874,0.2621382091570115,0.917708646442443,2.0323270636419455,1.312135877672124,57.650695517774345,0.21584596256350147,84.46578473815127
+20,25,1.003,25,0.9,25,1.8,10,29.053117782909933,0.25628208547929743,0.9687217888609603,2.0335934608241635,1.297492397303032,57.64331210191082,0.2172078677808646,84.33189911662208
+25,25,1.001,25,0.8,25,1.3,10,23.833718244803695,0.27924693818923846,0.979597270274706,2.0652141804118087,1.2483889700945419,57.78210116731517,0.22218022101334126,84.31430699397491
+20,30,1.002,20,0.7,25,1.3,10,24.849884526558892,0.42806573868323083,1.065772474498389,2.0575644609797403,1.2560408967925443,57.54189944134078,0.21526121831901548,83.73146946250151
+25,25,1.003,25,0.7,25,1.3,10,19.95381062355658,0.3199639593478255,1.1825668983688302,2.074781704160592,1.1999094216250512,57.540603248259856,0.22357972536492557,83.62398733089312
+25,30,1.001,20,0.9,25,1.3,10,31.45496535796767,0.16774918200784203,0.7441920733918425,2.002255179564793,1.2967771851346177,57.87923416789397,0.20982669552479505,83.43011464416796
+25,25,1.002,25,0.9,25,1.8,10,27.713625866050805,0.19103934832775143,0.8461576022349068,2.0285181338099405,1.2661121541159057,57.76293823038397,0.21247176694337483,83.3971719854374
+25,25,1.003,25,0.9,25,1.8,10,26.836027713625864,0.18237432225367553,0.8990453763163254,2.0297645609886033,1.2524491863012281,57.758620689655174,0.2137782743968237,83.27671599705208
+20,30,1.001,20,0.7,25,1.3,10,25.311778290993068,0.4292647367146086,1.036825311652027,2.0440418401128735,1.2449704442044915,57.509157509157504,0.21299405271728292,83.18234879730393
+25,30,1.001,20,0.8,25,1.5,10,25.080831408775982,0.25064671710755454,0.8993122958632753,2.0240105539038122,1.2143021392547042,58.225508317929766,0.21858248271184144,83.07506462499833
+20,25,1.002,25,0.7,25,1.8,10,22.632794457274827,0.3467179893697716,1.1156816153931577,2.027564901437701,1.1807757891453718,58.077709611451944,0.2245432163285017,82.95381924198925
+30,25,1.001,25,0.8,25,1.5,10,21.986143187066975,0.3172086378227738,0.9349814953465221,2.026575719133681,1.1689065893372912,58.22784810126582,0.22101900526078957,82.51251245373265
+30,25,1.001,25,0.8,25,1.3,10,21.986143187066975,0.3172086378227738,0.9349814953465221,2.026575719133681,1.1689065893372912,58.22784810126582,0.22101900526078957,82.51251245373265
+30,25,1.001,25,0.8,25,1.8,10,21.893764434180138,0.3150710634758988,0.9340322241673448,2.0274526493306766,1.1686335481501313,58.26271186440678,0.2206845200109341,82.50454984604214
+20,25,1.001,25,0.9,25,1.3,10,31.316397228637417,0.3209856424792872,0.8983667165967246,1.977851673212554,1.258495461049555,56.95266272189349,0.20893303000043426,82.07954335479938
+25,25,1.002,25,0.9,25,1.5,10,27.852193995381064,0.20405410122598466,0.8476063523893298,1.9987512301281254,1.2271933777483457,57.64119601328903,0.20939591157819668,82.0689675338248
+25,30,1.001,20,0.9,25,1.8,10,31.039260969976905,0.16131975606255478,0.721161136714113,1.9670126153234764,1.237613595328627,57.91044776119403,0.20724149237398465,81.7723855594427
+25,25,1.003,25,0.7,25,1.8,10,19.399538106235568,0.2944713995084776,1.1555829872144119,2.02903329107712,1.1347128636160428,57.756563245823386,0.22011072904346302,81.72297413793504
+25,25,1.003,25,0.9,25,1.5,10,27.02078521939954,0.19322223283479267,0.8972363439304976,1.9902619206168832,1.2013772024113276,57.534246575342465,0.20978344982102962,81.50970546427973
+30,25,1.003,25,0.7,25,1.8,10,17.92147806004619,0.3442456386344523,1.129866653230314,2.0222244737688646,1.1057505628413438,58.139534883720934,0.2216139270919334,81.38197182475014
+25,25,1.001,25,0.8,25,1.8,10,23.371824480369515,0.25426537353878165,0.9404846982067395,1.9967204277816357,1.151251255839413,57.738095238095234,0.2161069910788634,81.2844126425406
+30,25,1.003,25,0.7,25,1.3,10,18.15242494226328,0.36195167716659987,1.1313613076331512,2.0192455576587602,1.1052593921385676,57.90816326530612,0.22152231012888984,81.25102375912203
+25,30,1.001,20,0.9,25,1.5,10,31.085450346420323,0.15592176732667523,0.7162181111948482,1.9496532625982574,1.2131914799960177,57.82414307004471,0.20533534448898547,80.95407688834048
+25,25,1.001,25,0.8,25,1.5,10,23.46420323325635,0.26893799692896697,0.9497756762913829,1.9812324890645,1.1323866273851255,57.70750988142292,0.21447980967653052,80.62622579558962
+20,25,1.001,25,0.7,25,1.5,10,23.74133949191686,0.34493245243657744,1.035841184428159,1.9726685547373992,1.1252982505527185,57.6171875,0.21660615005004258,80.5307299606245
+25,25,1.002,25,0.7,25,1.3,10,20.96997690531178,0.30278693860096306,1.066770326735144,1.974492739524093,1.0883717018439998,57.615894039735096,0.2144353019313992,79.74581134448717
+30,25,1.003,25,0.7,25,1.5,10,18.106235565819862,0.3426740736120109,1.11389104663043,1.9824375553350706,1.0596160487084347,57.8005115089514,0.21790350021277927,79.68033704069946
+25,25,1.003,25,0.7,25,1.5,10,19.584295612009235,0.3083809263503038,1.150666868371719,1.974502281863316,1.0694224087326833,57.446808510638306,0.2143825533552504,79.35723984417933
+20,25,1.001,25,0.9,25,1.5,10,30.94688221709007,0.25555078617965593,0.8696509387844281,1.9061617852863053,1.1475660275423105,56.886227544910184,0.20188435084428263,78.68746117825616
+30,25,1.001,25,0.9,25,1.3,10,27.066974595842957,0.20766626290028298,0.7871368693657612,1.922006613002484,1.1075862768297222,57.705479452054796,0.2019261607641863,78.47434270040735
+30,25,1.001,25,0.9,25,1.5,10,27.066974595842957,0.20766626290028298,0.7871368693657612,1.922006613002484,1.1075862768297222,57.705479452054796,0.2019261607641863,78.47434270040735
+30,25,1.001,25,0.9,25,1.8,10,26.974595842956123,0.20555616873887247,0.7858600820525908,1.9223584563714187,1.1066518759805253,57.73195876288659,0.20164231712967362,78.44944589010446
+20,25,1.001,25,0.7,25,1.8,10,23.602771362586605,0.3280077027169693,1.0173209879861076,1.908077491852739,1.038547807619189,57.36738703339882,0.21092566499374307,77.6909853616468
+25,25,1.001,25,0.9,25,1.3,10,29.053117782909933,0.19352444011807785,0.8151050519328669,1.8977048819845106,1.1046211891288822,56.77830940988836,0.19839317658119482,77.53041775781477
+30,25,1.002,25,0.7,25,1.3,10,19.12240184757506,0.3487081198619094,1.023895479857371,1.9213608066394896,0.9974347133271209,58.111380145278446,0.2122469174490261,77.50018440389701
+25,25,1.002,25,0.7,25,1.8,10,20.46189376443418,0.27443191516137133,1.0336693256934715,1.9168843514805527,1.0087815191818286,57.692307692307686,0.20974309565791124,77.30441285762497
+20,35,1.003,25,0.9,15,1.3,10,42.032332563510394,0.3617227749083938,0.834632322760972,1.8147814831248366,1.211757699711918,54.845814977973575,0.19340447567749514,77.30100359471943
+30,25,1.002,25,0.7,25,1.8,10,18.937644341801384,0.32765846639725504,1.0165410356688271,1.9106656815900191,0.9819215900066008,58.19070904645477,0.2110466273597015,77.03049446720591
+20,30,1.003,20,0.7,25,1.5,10,23.648960739030024,0.3571561853041566,1.0860937886033595,1.896139901705123,1.024148153242569,57.14285714285714,0.2084146898693303,77.02079994129946
+20,35,1.002,25,0.9,15,1.3,10,42.67898383371824,0.3632399615843705,0.8205096867029401,1.8008575061004573,1.2012079671515525,54.77223427331887,0.19075530230909005,76.71239400961544
+20,25,1.001,25,0.9,25,1.8,10,30.808314087759815,0.24218243219841065,0.8547148201655087,1.8564228810507486,1.073152076415354,56.69172932330827,0.19753196729968486,76.37004353144276
+20,35,1.003,25,0.9,15,1.5,10,41.70900692840647,0.35690260069815777,0.8177090048402512,1.794019173028305,1.1691391634940373,54.71698113207547,0.19098299862697504,76.07074306277106
+30,25,1.002,25,0.7,25,1.5,10,19.07621247113164,0.33037866671250604,1.0070533293952824,1.8861913560094365,0.9533285931223944,58.009708737864074,0.20876052747803225,75.98903332388598
+20,35,1.002,25,0.8,15,1.5,10,37.41339491916859,0.40496252268882976,0.9128867423637861,1.8203973203727344,1.1301348133435927,54.579207920792086,0.1906337804350508,75.65495412097141
+25,25,1.002,25,0.7,25,1.5,10,20.600461893764436,0.29146715798005696,1.0343667722691248,1.8773680039087226,0.9607013891912224,57.528089887640455,0.205428196773154,75.58431313733325
+20,35,1.002,25,0.8,15,1.3,10,38.01385681293303,0.389764863882703,0.9031730406730664,1.811671716540767,1.1270950341546926,54.68940316686967,0.1901803868837356,75.49426312160004
+20,35,1.002,25,0.9,15,1.5,10,42.35565819861432,0.3585049593977715,0.8037369336660621,1.7803063484653252,1.1585326103243825,54.644808743169406,0.18836996721265203,75.4870947119843
+25,25,1.001,25,0.7,25,1.3,10,21.893764434180138,0.2842333350394394,0.9718765374886069,1.8690001759197836,0.9654772089592374,56.99152542372882,0.20280739457170374,75.17727004225618
+20,30,1.002,20,0.7,25,1.5,10,24.341801385681293,0.3333912898167731,1.0226006747822347,1.8429071426477344,0.9631092119952183,57.414448669201526,0.20312871707956873,74.97482730705782
+20,35,1.003,25,0.8,15,1.5,10,36.99769053117783,0.39202443406197096,0.910605470301965,1.805963323886436,1.099576020042551,54.56821026282853,0.1904575506773488,74.92720841944372
+25,30,1.003,20,0.7,25,1.3,10,21.662817551963048,0.302159305417895,1.008095331651931,1.8867607667122963,0.9858913761709861,56.1965811965812,0.19423288879994632,74.81996820153304
+25,25,1.001,25,0.9,25,1.8,10,28.591224018475753,0.17171846807632857,0.7804751914323672,1.839040466571415,1.0150391322228751,56.72609400324149,0.1930843688339321,74.81170234380612
+20,35,1.001,25,0.8,15,1.5,10,37.736720554272516,0.3968457526807305,0.9083525241934524,1.8011056004821788,1.1049695535903323,54.47852760736196,0.18882818407534965,74.80243586448833
+20,35,1.003,25,0.8,15,1.3,10,37.59815242494226,0.3768653701242645,0.9008208020529984,1.7973720938473678,1.0964749696500165,54.679802955665025,0.1900017835226087,74.7674357620551
+20,35,1.001,25,0.8,15,1.3,10,38.33718244803695,0.38190339703333653,0.8987917631630332,1.7927566531543186,1.1022786744547317,54.589371980676326,0.18840305759539078,74.65494027882797
+20,30,1.001,20,0.7,25,1.5,10,24.803695150115473,0.33637787344779657,0.9938644974216296,1.8327175442770396,0.9549174693882722,57.38317757009346,0.20091582847061581,74.52219556888765
+20,30,1.003,20,0.7,25,1.8,10,23.418013856812934,0.34265241328142987,1.066635185326341,1.8347817316009436,0.9407228843959072,56.916996047430835,0.2030297860654307,74.31032470486272
+25,25,1.001,25,0.9,25,1.5,10,28.683602771362587,0.18398704535996635,0.7885908691788207,1.8268893566062285,0.9992894254005429,56.70436187399031,0.19186477289142298,74.28409453939645
+20,35,1.003,25,0.9,15,1.8,10,41.24711316397229,0.288880954511197,0.7982896761741577,1.7545814166662015,1.0923565645852236,54.882154882154886,0.18820309827488807,74.08535044190126
+20,35,1.001,25,0.9,15,1.3,10,43.325635103926096,0.35527963932654394,0.8117402827988132,1.741916895577657,1.1105456859015237,54.48717948717948,0.18494715512207247,73.85438936955553
+30,30,1.003,20,0.7,25,1.3,10,20.04618937644342,0.4288375773397549,1.017562786782064,1.8611025464192807,0.9335881748307391,56.812933025404156,0.19252975310845094,73.66698130230624
+20,35,1.002,25,0.9,15,1.8,10,41.893764434180135,0.291550928021851,0.784463304988484,1.7413271560186245,1.0817618894361434,54.80662983425414,0.18559451878841698,73.5069028079764
+20,30,1.002,20,0.7,25,1.8,10,24.157043879907622,0.31784982939084144,1.0073716405966586,1.7978462926546774,0.9011819414572712,57.279693486590034,0.19952573283527245,73.01066344122039
+25,30,1.002,20,0.7,25,1.3,10,22.35565819861432,0.2779875146667439,0.9413786082439531,1.829080136817277,0.9203459005498962,56.52173913043478,0.18916184745742787,72.67475141226024
+20,35,1.001,25,0.9,15,1.5,10,43.00230946882217,0.3505559881332936,0.7951538162444135,1.721231326675821,1.0676638067109412,54.35952637244349,0.18255669789211892,72.62335022218366
+30,25,1.001,25,0.7,25,1.3,10,20.04618937644342,0.3263283232872984,0.9222315186469953,1.8084372341940584,0.8670962408564643,57.407407407407405,0.19944579179276425,72.59128875666522
+20,30,1.001,20,0.7,25,1.8,10,24.618937644341802,0.32115041103083947,0.9787055300886114,1.788343679701035,0.8935781822797946,57.250470809792844,0.19735580312614756,72.58088431624795
+25,30,1.001,20,0.7,25,1.3,10,22.863741339491916,0.2739399459226018,0.9083483310660728,1.8209514047907434,0.9153624434122352,56.5922920892495,0.1877393447881122,72.39927143129381
+25,25,1.001,25,0.7,25,1.8,10,21.43187066974596,0.257097973520842,0.9290572081906502,1.7900326621307636,0.8590956943026478,56.926406926406926,0.19561402152588567,71.7613601591897
+30,30,1.002,20,0.7,25,1.3,10,20.69284064665127,0.40586175051996654,0.9604368121148118,1.8077461474040606,0.8738830856434499,57.27069351230425,0.18773885902691873,71.74362249439774
+20,25,1.003,30,0.8,20,1.3,10,29.97690531177829,0.38713715871851245,1.0129554293021379,1.7670792614455866,0.9329479018314304,55.092592592592595,0.1905281050132046,71.73734891393181
+20,30,1.003,30,0.8,15,1.3,10,33.25635103926097,0.4685251274772281,1.0486599156132184,1.750959938604352,0.9551522170737752,54.1029207232267,0.190399429116516,71.57551815485064
+20,30,1.002,30,0.8,15,1.3,10,34.04157043879907,0.4675471952791648,1.0222397914071262,1.7412021891256872,0.9518216386908921,54.483695652173914,0.19047998171283143,71.52930534029356
+20,35,1.002,20,0.9,20,1.3,10,40.83140877598153,0.2577768861009455,0.7102157429338565,1.7076488929082752,1.0048652957475208,54.87528344671202,0.1817135850111303,71.4740137710265
+20,35,1.002,25,0.8,15,1.8,10,36.766743648960734,0.331146661873595,0.8992925564538964,1.718801320590039,0.957118301929313,54.78589420654912,0.18676677668953032,71.15160048501905
+30,25,1.001,25,0.7,25,1.5,10,20.0,0.30879381070697925,0.905932506863963,1.7745561733308859,0.8241896062051448,57.30858468677494,0.196074229471122,71.1270000052794
+25,25,1.001,25,0.7,25,1.5,10,21.524249422632792,0.27308086511365326,0.9392346155877124,1.7740336934678993,0.8397027160794243,56.896551724137936,0.19391474289660962,71.08223703830431
+30,25,1.001,25,0.7,25,1.8,10,19.907621247113163,0.30640392696069085,0.904753730724995,1.7743460846627657,0.8229664014233686,57.34265734265735,0.1956322035800995,71.08028235179684
+20,35,1.003,20,0.9,20,1.3,10,40.09237875288684,0.24755762001158096,0.721496120339351,1.701940532496997,0.9827212161430231,54.734411085450354,0.18215867492135707,71.00636069474353
+20,25,1.002,30,0.8,20,1.3,10,31.085450346420323,0.3936163506304905,0.9604427236845847,1.7372389970335202,0.9046949367805628,55.35714285714286,0.1891091930719525,70.85143543674947
+20,30,1.003,30,0.8,15,1.5,10,32.70207852193995,0.4809793643135461,1.0152907005949685,1.737140343721642,0.9265674760248885,53.88967468175389,0.1886499827254751,70.69930507975427
+20,30,1.002,30,0.8,15,1.5,10,33.48729792147806,0.47969321527052516,0.9892157283403757,1.7275453568386432,0.9231687428991959,54.28176795580111,0.18876124431315833,70.6601578839664
+20,35,1.001,25,0.9,15,1.8,10,42.54041570438799,0.284533408143495,0.7760799700068676,1.6822031227779333,0.9906718528544332,54.515778019586506,0.17971909200612668,70.63200826309183
+20,35,1.003,25,0.8,15,1.8,10,36.351039260969976,0.317134270847609,0.8968152418481686,1.7029451076083872,0.9257759184271023,54.77707006369427,0.18656399513272642,70.39105305652558
+20,35,1.001,25,0.8,15,1.8,10,37.09006928406466,0.32353185481144,0.8947977906459347,1.7000602722600462,0.9321929146121037,54.68164794007491,0.18490278012582304,70.30442711834323
+20,30,1.001,30,0.8,15,1.3,10,34.688221709006925,0.45869089269232655,0.9967037288083951,1.7138923580769136,0.9187228519454497,54.33911882510013,0.1867885906180695,70.277165542007
+30,30,1.001,20,0.7,25,1.3,10,21.293302540415702,0.3853711319510311,0.9126862489155622,1.7723981128195052,0.8351316401178571,57.08061002178649,0.18366631175705797,70.24751996421308
+20,30,1.001,30,0.8,15,1.5,10,34.133949191685915,0.4704630021141052,0.9638906320904265,1.7000317548904749,0.8897770649722563,54.13839891451831,0.18505271642451543,69.39945913162242
+20,35,1.003,20,0.8,20,1.3,10,35.42725173210162,0.2610821194061052,0.7808501441703943,1.6906280965178346,0.8932139567185676,54.509803921568626,0.17933243694815074,69.02050979222739
+30,30,1.003,20,0.7,25,1.5,10,19.81524249422633,0.40735132135883745,1.0291719986756458,1.7275755365050443,0.7640579610041864,57.009345794392516,0.1887946509436506,68.82849388742203
+20,35,1.002,20,0.8,20,1.3,10,35.84295612009238,0.26646935450091724,0.7674175700683994,1.6797574051794983,0.8820697500735902,54.65116279069767,0.17860216494367728,68.68157836650182
+20,35,1.001,20,0.9,20,1.3,10,41.47806004618938,0.25443011303748725,0.7079176340579193,1.6475257664682772,0.9128749097800823,54.57589285714286,0.17575048200698123,68.56127271920408
+20,30,1.003,25,0.8,20,1.3,10,32.0554272517321,0.3329082823837926,0.911057460875669,1.7014918350750379,0.8649710602457465,54.112554112554115,0.17884857475723814,68.49768345487188
+20,30,1.002,25,0.8,20,1.3,10,32.840646651270205,0.33513718581081897,0.8869612726768622,1.6925612071084197,0.8618688379710303,54.507042253521135,0.1790921289659122,68.48312614715314
+30,30,1.003,20,0.7,25,1.8,10,19.584295612009235,0.38258606220846036,1.0076979993673887,1.721494930028715,0.7542651673359243,56.973995271867615,0.18751306889559685,68.47098182185411
+20,30,1.002,30,0.9,15,1.3,10,37.736720554272516,0.4457404832923324,0.9197781669067516,1.671622902583461,0.8968164930642532,53.799019607843135,0.1775569463998868,68.46632548962135
+20,30,1.003,30,0.8,15,1.8,10,32.517321016166285,0.4224578351521338,0.9884725021993184,1.6875143600285396,0.8501777361318209,53.91180654338549,0.18444650177106758,68.4335638657676
+20,30,1.002,30,0.8,15,1.8,10,33.30254041570439,0.4225443926272433,0.96288519913156,1.6790377922778337,0.8475607422293484,54.30555555555555,0.18464162637623166,68.42910383944411
+20,30,1.002,30,0.9,15,1.5,10,36.99769053117783,0.47991708578401227,0.9177546461196343,1.674766709130521,0.8911617727329633,53.625,0.17743498712925843,68.3401267058159
+25,30,1.003,20,0.7,25,1.8,10,21.062355658198616,0.2991493799829446,0.9907574041272728,1.7163390271638614,0.7620030807735804,56.26373626373626,0.1872623784536219,68.28152775610748
+25,35,1.003,25,0.9,15,1.3,10,38.9838337182448,0.2071521005435312,0.6686295171171038,1.6494714390770784,0.8782457636693795,55.10688836104512,0.17704932205403007,68.26642558903741
+20,35,1.002,20,0.9,20,1.8,10,39.86143187066975,0.2591987765714558,0.6909669402325237,1.6491520417223051,0.8907080395134055,54.81997677119629,0.1755584081634572,68.26552114324106
+20,30,1.003,30,0.9,15,1.3,10,36.905311778290994,0.44002817877318773,0.9482086008009365,1.667527058065794,0.8783099723771313,53.63408521303258,0.1780205140861781,68.07524285708769
+20,30,1.003,30,0.9,15,1.5,10,36.16628175519631,0.4748737237585379,0.9467195162438812,1.6706594260010426,0.8729291724234076,53.452685421994886,0.17790102187693277,67.95134758455039
+20,35,1.002,20,0.9,20,1.5,10,40.32332563510393,0.25411947570402693,0.6753637916923486,1.6405194453172982,0.883164994855944,54.649827784156145,0.17509305608052797,67.93291539456334
+20,35,1.001,20,0.8,20,1.3,10,36.16628175519631,0.263050386545344,0.7698846349976682,1.660877632157683,0.8569065353512446,54.54545454545454,0.17679201949200488,67.83224023943589
+20,35,1.003,20,0.9,20,1.8,10,39.122401847575055,0.24875300004484394,0.7021633826702423,1.64219418404758,0.8682650138637902,54.67455621301775,0.1758621453955532,67.76443648187403
+25,35,1.002,25,0.9,15,1.3,10,39.67667436489607,0.20771252547878954,0.6485866620828471,1.6332094838057103,0.8613915652205872,54.95915985997666,0.17421428671655667,67.49994091584166
+30,30,1.002,20,0.7,25,1.8,10,20.27713625866051,0.3590079508516911,0.9548022490252227,1.6895708264988285,0.7207776309788256,57.534246575342465,0.1845927652215403,67.45096846758028
+20,35,1.003,20,0.9,20,1.5,10,39.58429561200924,0.2437007574637478,0.6861382798698339,1.6334814204311894,0.8605082481129996,54.50292397660819,0.1753853386545634,67.42573500742434
+20,25,1.003,30,0.7,20,1.3,10,28.545034642032334,0.40099967713239704,1.025296094122826,1.6854370362991937,0.7994112801718839,54.13290113452188,0.18158555574111362,67.3812532834002
+20,30,1.001,25,0.8,20,1.3,10,33.48729792147806,0.3285201608312899,0.8631217088845542,1.6651438755879402,0.8283907217841069,54.356846473029044,0.17565376057997284,67.24085794575267
+20,30,1.001,30,0.8,15,1.8,10,33.94919168591224,0.4143524960210003,0.9379238131182415,1.6522343457614497,0.8146463632430436,54.160982264665755,0.18097683925822328,67.18860228499288
+25,30,1.003,20,0.7,25,1.5,10,21.20092378752887,0.28844540193257523,0.9845414337986448,1.687742841058941,0.7269984512817406,56.11353711790393,0.1840639673603671,67.0166670079994
+20,30,1.003,30,0.7,15,1.3,10,32.00923787528868,0.47703089860132963,1.043933974932396,1.6658597655147749,0.8117737028699654,53.32369942196532,0.1807594031719388,67.01209481675288
+25,30,1.002,20,0.7,25,1.8,10,21.801385681293304,0.27314153497870297,0.9276625113424448,1.6794277408391107,0.7219895444090566,56.68789808917197,0.18391179162652946,67.0065998833375
+30,30,1.002,20,0.7,25,1.5,10,20.46189376443418,0.3847951975856268,0.9710343787717198,1.6778449206204196,0.7077013200068516,57.466063348416284,0.18384084118599592,66.99570120713257
+25,30,1.001,20,0.7,25,1.8,10,22.3094688221709,0.26910376944706343,0.8941239810378192,1.6742074894268453,0.7195991935465453,56.75675675675676,0.18246310211441313,66.80999988907368
+20,35,1.003,20,0.8,20,1.5,10,34.64203233256351,0.2777991435994023,0.7705666202067393,1.6457025060460695,0.8133642582030687,54.278074866310156,0.1749538098379781,66.65515245207713
+20,30,1.002,25,0.9,20,1.3,10,37.644341801385686,0.31051339852413934,0.7937542678542212,1.6321714274431252,0.8318900864811206,54.2997542997543,0.17250407217923056,66.62190088246228
+20,25,1.001,30,0.8,20,1.3,10,32.14780600461894,0.3689230880273104,0.8889342816085736,1.6403980012829544,0.7752527263906308,54.7550432276657,0.178411409204945,66.35845103929647
+20,30,1.003,30,0.7,15,1.5,10,31.732101616628178,0.4686195750502154,1.0255466933302593,1.6533378083828494,0.790025765745086,53.2069970845481,0.17952721191232648,66.34315988137084
+20,35,1.002,20,0.8,20,1.5,10,35.057736720554274,0.28310881582052816,0.7569551237805532,1.6351218128074618,0.8022869464790156,54.42536327608983,0.1742490092739238,66.32500573900184
+20,30,1.003,25,0.9,20,1.3,10,36.81293302540416,0.30173269734895225,0.8194098343517221,1.6271731730742494,0.8128424384619223,54.14572864321608,0.1728225322529646,66.20247605642487
+30,30,1.001,20,0.7,25,1.8,10,20.87759815242494,0.3394568982751609,0.9062629562936092,1.6566671731133884,0.6842413448785171,57.333333333333336,0.18030512174571312,66.00360087823836
+30,35,1.003,25,0.9,15,1.3,10,36.25866050808314,0.11191296520806036,0.5636390209472616,1.61592792019068,0.787373995631334,55.172413793103445,0.17109392079289648,65.83116197768506
+30,30,1.001,20,0.7,25,1.5,10,21.062355658198616,0.3646804827344584,0.9224581112248034,1.6455411031030027,0.6717466939070424,57.268722466960355,0.17960047233300117,65.57082711113604
+20,30,1.002,30,0.7,15,1.3,10,32.88683602771363,0.459380243710302,0.9896629269979105,1.626430745317874,0.7635508660723208,53.727144866385366,0.1771666531471502,65.53767234196599
+20,35,1.001,20,0.8,20,1.5,10,35.3810623556582,0.27946191224552674,0.7595725506260261,1.6162309049757422,0.7770117917551304,54.31937172774869,0.1724315398076583,65.47292652171257
+20,25,1.002,30,0.9,20,1.3,10,35.150115473441105,0.35098045706007386,0.8383114884210885,1.6144019075251068,0.7719350793373446,54.473684210526315,0.17163474129411369,65.35201351525389
+20,35,1.001,20,0.9,20,1.8,10,40.5080831408776,0.2557491657646457,0.6889210810161348,1.5885219098667227,0.7981240077992031,54.51428571428571,0.169539652175083,65.32967976897854
+25,35,1.002,25,0.8,15,1.3,10,35.057736720554274,0.23432210727973193,0.7136539970616199,1.6147553655083062,0.7708128618560411,54.557463672391016,0.17014846787547816,65.24965244624688
+20,30,1.001,30,0.7,15,1.3,10,33.48729792147806,0.4654811981187384,0.9797430007591331,1.6173569635248948,0.7563070886088378,53.665283540802214,0.1755862959122614,65.15439265782001
+30,35,1.002,25,0.9,15,1.3,10,36.95150115473441,0.1143004552698341,0.5440865771574128,1.5990941571778141,0.7693355310967183,55.012531328320804,0.16825555466306052,65.03264616784149
+20,35,1.001,20,0.9,20,1.5,10,40.969976905311775,0.2507889250101953,0.6735872703245802,1.580710960544457,0.7911611139751811,54.35028248587571,0.16913546707719546,65.02428122249498
+25,30,1.002,20,0.7,25,1.5,10,21.893764434180138,0.2641976420775597,0.9171625610947163,1.6351540982376007,0.6660547451916997,56.448202959830866,0.17894266157448407,65.0144691922748
+20,25,1.002,30,0.7,20,1.3,10,29.745958429561203,0.3893194380243793,0.9401258353406385,1.6225576715881735,0.7234515304910122,54.43234836702955,0.17611684386118504,64.95086197726488
+20,30,1.002,30,0.7,15,1.5,10,32.609699769053115,0.4510452816579485,0.9713092602156514,1.6139106932417293,0.7417197432252621,53.61702127659574,0.17593131170652881,64.8692899687485
+25,30,1.001,20,0.7,25,1.5,10,22.401847575057737,0.26037937830463326,0.8840004772093366,1.6308721013363907,0.6645358908588604,56.52173913043478,0.17762786364489516,64.85674572528217
+25,35,1.003,25,0.8,15,1.3,10,34.595842956120094,0.22258974705044504,0.7175474107952993,1.60136135293515,0.7447482798903899,54.61847389558233,0.1699470838362291,64.63499357904503
+25,35,1.001,25,0.9,15,1.3,10,40.32332563510393,0.2016536501381674,0.6419213945944279,1.5725650071843384,0.768751910244328,54.649827784156145,0.16817737685805914,64.56032075709992
+20,25,1.003,30,0.9,20,1.3,10,34.133949191685915,0.34292751428754925,0.8841251012827865,1.6027568237111314,0.7421118550826189,54.20054200542005,0.1710590314322852,64.55290483569482
+20,30,1.001,30,0.7,15,1.5,10,33.21016166281755,0.4573478497425062,0.9616383994994566,1.604970520840878,0.7345236417678932,53.55648535564853,0.17436124628958896,64.48976393459485
+20,35,1.003,20,0.8,20,1.8,10,33.995381062355655,0.2854307814082468,0.7969483812475009,1.5925604794417392,0.7245075986133227,54.495912806539515,0.17424161288854237,64.46680584186527
+20,30,1.001,30,0.9,15,1.3,10,38.47575057736721,0.43135486422122876,0.9043424031687924,1.5876264662127804,0.7699366539324825,53.42960288808665,0.168887723484342,64.41545132440581
+25,35,1.001,25,0.8,15,1.3,10,35.3810623556582,0.2272243028557719,0.7106385570772238,1.596060001598945,0.7456818947651015,54.45026178010471,0.16838316813607768,64.40618010475139
+20,30,1.001,30,0.9,15,1.5,10,37.736720554272516,0.4645804317741026,0.9020562191170323,1.5890634014958682,0.7629917213906056,53.25153374233129,0.16861863279805764,64.23263364998093
+25,35,1.002,20,0.9,20,1.3,10,37.82909930715935,0.11865804305977014,0.5355628177119859,1.5770851473804235,0.7447933993764129,54.83476132190942,0.16724359760394109,64.19246835104359
+20,35,1.002,20,0.8,20,1.8,10,34.41108545034642,0.2907480384224145,0.7827623924732162,1.582424131471097,0.7136503247121049,54.643337819650064,0.17352275059059424,64.1450145520773
+25,35,1.003,25,0.9,15,1.8,10,37.967667436489606,0.17689858482792728,0.6329040717531581,1.569605777468179,0.7343716120076319,55.00000000000001,0.16871003735393708,64.08760468881616
+20,30,1.003,30,0.7,15,1.8,10,31.547344110854503,0.40822631635814,0.9979639880599861,1.601692241406888,0.712144805918416,53.2258064516129,0.1750884463983016,64.00677352906882
+20,25,1.003,30,0.8,20,1.5,10,29.099307159353348,0.3388490244258173,0.9123867248504726,1.600573731882165,0.6856653351768548,54.531001589825124,0.1742385309295576,63.90752430196538
+25,35,1.003,20,0.9,20,1.3,10,37.043879907621246,0.10855797622512253,0.5522154238476883,1.5724702512947284,0.7280198381175174,54.75,0.16769416861619937,63.85076832744668
+20,30,1.002,30,0.9,15,1.8,10,36.62817551963048,0.43023451103590477,0.9005012121548148,1.5718487193554518,0.7227298568058482,53.661616161616166,0.17247414091784788,63.757161161033714
+20,35,1.002,25,0.7,15,1.3,10,35.84295612009238,0.3972359518931563,0.9203816862040733,1.5854968454778575,0.7345942573237582,53.617571059431526,0.16703402140970203,63.696430620447956
+20,35,1.002,25,0.7,15,1.5,10,34.96535796766744,0.43240993645070885,0.9154945580252004,1.5873859103593682,0.7274681805479948,53.377483443708606,0.1664733044260002,63.472642675446544
+20,35,1.001,25,0.7,15,1.3,10,36.07390300230947,0.40190051161786394,0.9293075874673049,1.5800633090020568,0.7287509451319767,53.53016688061617,0.16660993107305522,63.4645536586917
+30,25,1.003,30,0.8,20,1.3,10,24.341801385681293,0.21154821345631247,0.8403552340463207,1.6058099283420908,0.648981031213498,55.51330798479087,0.17082691589107446,63.40404658454036
+25,35,1.003,25,0.9,15,1.5,10,38.38337182448036,0.16573262826341847,0.6114319329237002,1.5528684006498001,0.7121130035218007,54.8854041013269,0.16739199862260576,63.350768885018084
+25,35,1.002,25,0.9,15,1.8,10,38.660508083140876,0.17801591786869306,0.6129746442812736,1.554350075979042,0.7178006917678728,54.8502994011976,0.1660001598781637,63.347764558644606
+20,30,1.003,30,0.9,15,1.8,10,35.79676674364896,0.42398517063408236,0.9293643495689033,1.5653055420644917,0.7030039248498926,53.48837209302325,0.1728535821041906,63.304823516830446
+20,35,1.001,20,0.8,20,1.8,10,34.73441108545035,0.2869621305811055,0.7851883207747904,1.5636724383856582,0.6883981172602901,54.53333333333333,0.17163141336140067,63.287992266642675
+20,35,1.001,25,0.7,15,1.5,10,35.19630484988453,0.4369600036714556,0.9246750889011561,1.5818041074132416,0.7214496777200516,53.289473684210535,0.16604303289330108,63.235183753430256
+20,25,1.002,30,0.8,20,1.5,10,30.207852193995382,0.347288491367386,0.8620390154104521,1.5759848728080663,0.6613441993392564,54.82388973966309,0.17323746178439997,63.19778595458404
+30,35,1.003,25,0.9,15,1.5,10,35.84295612009238,0.07667892916989076,0.5324273171382239,1.556202444513882,0.6887616606295733,55.03875968992248,0.16488126476615167,62.84522876236108
+30,25,1.002,30,0.8,20,1.3,10,25.40415704387991,0.23275456230411326,0.795745444152275,1.5824712658040105,0.6269667032521745,55.919854280510016,0.17024884655709613,62.821067226017014
+30,35,1.002,20,0.9,20,1.3,10,35.150115473441105,0.09486519109801474,0.5207566433600938,1.5582074545514988,0.6844105218281621,55.467720685111985,0.16284969911385266,62.7814984074374
+20,25,1.003,30,0.8,20,1.8,10,28.868360277136258,0.2952561684917676,0.8912864273731984,1.5755508264472202,0.6481226271993132,54.48717948717948,0.17219868300738964,62.76964437504387
+20,35,1.003,25,0.7,15,1.3,10,35.47344110854503,0.3859085796161776,0.9173561075162681,1.5646991946239706,0.6979824261851233,53.52480417754569,0.16619577353174317,62.70485697021806
+25,35,1.002,25,0.9,15,1.5,10,39.07621247113164,0.1670360527357455,0.59209523231906,1.5380728436697602,0.6959294718774048,54.739336492891,0.1647324866884681,62.62856335856459
+20,30,1.001,25,0.9,20,1.3,10,38.38337182448036,0.2986968072727094,0.7807078071937166,1.548686184382895,0.7052962452448158,53.92038600723763,0.1639447530361301,62.587612589429
+20,30,1.002,30,0.7,15,1.8,10,32.42494226327944,0.3921864599196912,0.9441640501984789,1.5634399583798602,0.6646930082864736,53.6376604850214,0.17156059003015312,62.56838346477522
+30,35,1.001,25,0.9,15,1.3,10,37.55196304849884,0.11424724205465077,0.5418221918817027,1.5449928583108454,0.6898408353205632,54.747225647348955,0.1630211698173559,62.48000580052056
+20,35,1.003,25,0.7,15,1.5,10,34.595842956120094,0.42117091104048293,0.9123400300443387,1.5660795006739254,0.6906141074294981,53.279785809906286,0.16560052103763856,62.46612695860877
+20,30,1.002,25,0.9,20,1.5,10,37.1824480369515,0.29717642688279045,0.7508992676810601,1.5462092723423138,0.6881855946421557,54.1044776119403,0.16453619925848126,62.368376941136496
+20,30,1.001,30,0.7,15,1.8,10,33.02540415704388,0.3995944475216413,0.9349326360380302,1.5552990680670016,0.6580687808970577,53.576437587657786,0.17005729384232032,62.213777750730706
+30,35,1.003,20,0.9,20,1.3,10,34.41108545034642,0.0794599426609471,0.529830498386656,1.548335983313443,0.6614969168674774,55.316285329744275,0.16281601190634706,62.20731067708436
+20,30,1.002,25,0.9,20,1.8,10,37.13625866050808,0.29686038653349145,0.7486059986472381,1.543185554783901,0.6828397975054664,54.04732254047323,0.16411898573628556,62.18616753972556
+30,35,1.002,20,0.9,20,1.8,10,34.27251732101617,0.09978687759418972,0.5270071091822085,1.5468221728810585,0.6577733480930524,55.67567567567567,0.16141920374908722,62.13607406927261
+30,35,1.002,25,0.9,15,1.5,10,36.53579676674365,0.07976173901817338,0.5132442836682576,1.5403121267076525,0.6712444727350906,54.879594423320654,0.16216658180795998,62.07747218041418
+20,30,1.003,25,0.9,20,1.5,10,36.351039260969976,0.28797911515957775,0.7759006609407691,1.539178827979159,0.6679739361708341,53.9440203562341,0.16464329827126722,61.884622177377835
+20,25,1.001,30,0.7,20,1.3,10,30.808314087759815,0.37997072800281906,0.8885693859278821,1.5531572186660174,0.6336217751888349,53.984962406015036,0.16860542013629046,61.78845489127818
+25,30,1.002,30,0.8,15,1.3,10,30.99307159353349,0.32452393272434465,0.8356990654666789,1.5468585930293224,0.6266099493483153,54.328358208955216,0.16969324990867238,61.78790804820184
+30,25,1.003,30,0.8,20,1.8,10,23.46420323325635,0.20994859107514358,0.7766129167185005,1.5705569741886154,0.5952885853940465,55.42406311637082,0.1676297122415484,61.75271321119256
+25,35,1.003,20,0.8,20,1.3,10,32.47113163972286,0.1406520219934013,0.6103178200101147,1.5522046957579079,0.6480035080620361,54.350927246790306,0.16342918772321113,61.74573408856563
+20,25,1.002,30,0.8,20,1.8,10,30.023094688221708,0.3028329295534009,0.8386918845240325,1.5445063145989881,0.614441201908889,54.699537750385204,0.1705530655462923,61.739494967821564
+25,30,1.003,30,0.8,15,1.3,10,30.207852193995382,0.32188282526130746,0.8599365227868604,1.5525430964619742,0.6276427179301628,53.905053598774884,0.16919645805370298,61.696399952595016
+30,35,1.003,20,0.9,20,1.8,10,33.533487297921475,0.0840869284183265,0.536456185556785,1.5364400352614416,0.6346951927351586,55.52486187845304,0.1613426428374897,61.54948261019159
+20,30,1.003,25,0.7,20,1.3,10,30.2540415704388,0.3478331539855893,0.9022171680323132,1.5618818625998527,0.6414987179862858,53.36391437308868,0.16451342218711232,61.5075445536431
+25,35,1.002,25,0.8,15,1.5,10,34.18013856812933,0.20927805107049505,0.6793122145472967,1.5389588502515192,0.6448505522603957,54.33604336043361,0.1626528380769341,61.45896999787064
+25,25,1.003,30,0.8,20,1.3,10,27.066974595842957,0.22393273974715347,0.8360279597437676,1.5537391328080332,0.6019284827654484,54.700854700854705,0.16736444429655173,61.391876201048156
+25,35,1.002,20,0.8,20,1.3,10,32.93302540415704,0.14380265380057528,0.588828183369977,1.53745959419185,0.6304664036139378,54.43037974683544,0.16240795401794078,61.20398738270192
+25,35,1.001,20,0.9,20,1.3,10,38.47575057736721,0.11738824905207623,0.5360207278950764,1.5144588792061173,0.6504964148690942,54.51263537906137,0.1610534526272609,61.18300168900349
+20,30,1.003,25,0.9,20,1.8,10,36.25866050808314,0.28842146036032446,0.7704437444117598,1.525747146690813,0.645823381993139,53.826530612244895,0.16308362561111675,61.171533441858436
+25,35,1.002,20,0.9,20,1.5,10,37.45958429561201,0.08585812550595386,0.5011637130758124,1.5169702855787006,0.6438168082389081,54.635352286773795,0.16107485510555788,61.14204322569161
+20,30,1.002,25,0.8,20,1.8,10,32.19399538106236,0.3215165485965471,0.8464891485738302,1.5251530030315932,0.6057220046539925,54.310344827586206,0.1683381124552107,61.0417869447853
+30,35,1.001,25,0.8,15,1.3,10,32.609699769053115,0.15724038651157723,0.6159430945420331,1.5419660134191786,0.6341117918285955,54.11931818181818,0.15986645911468167,61.021566410517615
+30,35,1.002,20,0.9,20,1.5,10,34.73441108545035,0.09066066722398168,0.5041585281001677,1.5199540924605328,0.6211752842786459,55.333333333333336,0.15897967989331935,60.85982461235322
+30,30,1.002,25,0.8,20,1.3,10,27.066974595842957,0.24732604267825017,0.7266285542632451,1.5519412939405404,0.599456454322646,55.042735042735046,0.15942002332607214,60.82365653332224
+25,35,1.003,25,0.8,15,1.5,10,33.71824480369515,0.19689725877757952,0.6828365283300127,1.5241741077450421,0.6179191632702775,54.395604395604394,0.16229205141253464,60.798917685581586
+30,25,1.002,30,0.8,20,1.8,10,24.572748267898383,0.22901784958328725,0.7301465715114148,1.5391275450357482,0.5623708657636602,55.74387947269304,0.16630902015743776,60.792325715954284
+25,35,1.003,20,0.9,20,1.5,10,36.674364896073904,0.07495402953642963,0.5172475988969942,1.5110184301251839,0.6262915933920086,54.54545454545454,0.161363950520531,60.75621758802784
+25,30,1.001,30,0.8,15,1.3,10,31.685912240184756,0.3116133296999775,0.8091812609018214,1.522988932246099,0.5975696460703291,54.239766081871345,0.1665033845879974,60.70712218419162
+25,25,1.002,30,0.8,20,1.3,10,28.17551963048499,0.23750225157022528,0.7850528915286652,1.52921943724546,0.5770922435757678,55.008210180623976,0.16648614041795876,60.688511855186064
+25,35,1.001,25,0.8,15,1.5,10,34.50346420323326,0.20223439672606566,0.6765418871705269,1.5204988738488954,0.6197914840333922,54.22818791946309,0.16090152824120568,60.62057444482893
+20,30,1.002,25,0.8,20,1.5,10,32.286374133949195,0.32106825713521087,0.8470407264232422,1.515156561857018,0.5917407176393723,54.297994269340975,0.16733625116169573,60.59199291550988
+30,35,1.002,25,0.8,15,1.3,10,32.19399538106236,0.16388384944195203,0.6101860752395243,1.5325016315372733,0.6161751675091854,54.10071942446043,0.1588587240465804,60.50750860979404
+30,30,1.003,25,0.8,20,1.3,10,26.32794457274827,0.2365115036184813,0.7396944548316222,1.5527901293261217,0.5945259014247456,54.48154657293497,0.15828491988308818,60.472093823117405
+20,30,1.003,25,0.8,20,1.5,10,31.501154734411084,0.3184494436955605,0.8705658075429786,1.5198159542382108,0.5916961851651849,53.89133627019089,0.16680503801943444,60.47186054767116
+25,35,1.001,25,0.9,15,1.8,10,39.30715935334873,0.17228895468911407,0.6067229283374805,1.4934345195271679,0.6247338253292002,54.53474676089517,0.15992272940688612,60.39209813053995
+20,30,1.003,25,0.8,20,1.8,10,31.362586605080832,0.3198459482395278,0.8665781388868115,1.5181229107016785,0.5880106589611235,53.83480825958702,0.1664883176436488,60.343153722796416
+25,35,1.001,20,0.8,20,1.3,10,33.25635103926097,0.1412771190723649,0.5932474021845693,1.5183105439785847,0.6047751296951173,54.317548746518106,0.16059282063611274,60.33934126624306
+30,35,1.003,20,0.9,20,1.5,10,33.995381062355655,0.07497563669735134,0.5129825120004802,1.5091277206303817,0.5976732487548099,55.177111716621255,0.1588380080181186,60.25342436877599
+30,35,1.001,20,0.9,20,1.3,10,35.750577367205544,0.09899218476775301,0.5247362658264053,1.5020527179290148,0.6031617430434122,55.181347150259064,0.15746160958271704,60.153616829487355
+20,30,1.002,25,0.7,20,1.3,10,31.131639722863742,0.33282943123379016,0.8488813122485563,1.5231620212854207,0.5933563375666409,53.789004457652304,0.16119557393442677,60.072102735485046
+30,35,1.003,25,0.9,15,1.8,10,35.3810623556582,0.06322060146190392,0.5244827463079347,1.4937984067082362,0.5868469048733056,55.10471204188482,0.1597934237473413,59.923029000600316
+25,35,1.003,20,0.8,20,1.5,10,31.824480369515012,0.12402933399046054,0.6010483051494178,1.5163824668263532,0.589079824817144,54.14847161572053,0.15965861363328518,59.91409789455526
+30,25,1.003,30,0.8,20,1.5,10,23.648960739030024,0.22212775243191615,0.7755024594776448,1.5290056794138893,0.5422002298553616,55.18590998043052,0.16336609755726594,59.89948702204819
+20,30,1.001,25,0.8,20,1.8,10,32.840646651270205,0.3150374287805714,0.8229770894852495,1.5002638294966022,0.5740277907458776,54.160789844851905,0.16490716101915673,59.863010876292066
+25,30,1.002,30,0.9,15,1.3,10,34.78060046189376,0.29435295340731504,0.7449759555682457,1.500614225172473,0.5922867955748907,53.98936170212766,0.16021284656923765,59.76052656120989
+20,30,1.001,25,0.7,20,1.3,10,31.732101616628178,0.3416625498776199,0.8410766753761082,1.5153939635512093,0.5868205788069947,53.72262773722628,0.15991637936364417,59.7394173964305
+25,35,1.001,25,0.9,15,1.5,10,39.722863741339495,0.161547764882303,0.5862488387135986,1.478061857451449,0.6034814898789636,54.42890442890443,0.15872229513628044,59.701946046071754
+30,35,1.003,25,0.8,15,1.3,10,31.685912240184756,0.15840420417295153,0.6171936151187486,1.514163544648885,0.5846124548341729,54.09356725146199,0.1579990442189688,59.66136638196291
+20,30,1.001,30,0.9,15,1.8,10,37.36720554272517,0.41572879394056916,0.8849887771514912,1.4872087864240817,0.5951426308823047,53.28376703841388,0.16337005228134777,59.64929446867389
+25,35,1.002,25,0.8,15,1.8,10,33.5796766743649,0.22343608797687592,0.7108052457446483,1.4930026361476996,0.5695272167448477,54.48275862068965,0.16235597873063218,59.60358502219031
+30,35,1.001,25,0.9,15,1.5,10,37.13625866050808,0.08026639196261058,0.5114532445963753,1.4865565319632636,0.591885148400647,54.613466334164585,0.15695766689155238,59.53323195948814
+20,25,1.003,30,0.7,20,1.5,10,27.9445727482679,0.3276109207044,0.9394086051514613,1.5129220513137134,0.5525345835877892,53.64238410596026,0.16506124485976198,59.48839392255522
+30,35,1.001,20,0.9,20,1.8,10,34.8729792147806,0.10393298511197395,0.5309792571732517,1.4894470759211087,0.5755042895773321,55.37848605577689,0.15592358207201695,59.46317463316115
+20,30,1.001,25,0.8,20,1.5,10,32.93302540415704,0.3146161139252529,0.8235837893939676,1.4905201760609015,0.5602536756565564,54.14908579465541,0.16393533780402803,59.42253752258516
+30,25,1.002,30,0.8,20,1.5,10,24.71131639722864,0.243473850506405,0.7324299910166252,1.508319484642246,0.5223980681554848,55.61797752808989,0.1630198392380442,59.414788772089885
+25,35,1.002,20,0.8,20,1.5,10,32.286374133949195,0.12748087527593185,0.5792608719937509,1.5018551426884035,0.571627951869816,54.23242467718795,0.15865941208330656,59.37979530379188
+30,35,1.001,25,0.8,15,1.5,10,31.916859122401846,0.14007340284134687,0.6118868633644107,1.5089725273608021,0.578972571723756,53.99129172714079,0.15629046043975628,59.33117575769099
+25,30,1.003,30,0.9,15,1.3,10,33.94919168591224,0.28443580123217627,0.7716010941768993,1.491967576509671,0.5715864244182227,53.81471389645777,0.16020078000474813,59.23392168060614
+30,35,1.002,25,0.9,15,1.8,10,36.07390300230947,0.06660136651390301,0.5052066759977053,1.478905723547735,0.56990539549836,54.942233632862646,0.15714146010529786,59.18155913027918
+25,30,1.002,25,0.8,20,1.3,10,29.97690531177829,0.20634421702570646,0.6923583661273702,1.5070275239733586,0.5603286788000819,53.85802469135802,0.15826709258816882,59.09312061867813
+25,25,1.003,30,0.8,20,1.5,10,26.32794457274827,0.20829550694959748,0.7909247130305537,1.5041946799655956,0.5283855214258064,54.6572934973638,0.162020619354301,59.06563017128157
+20,25,1.002,30,0.9,20,1.5,10,34.0877598152425,0.3338310432458515,0.7794344690060286,1.4860108782874668,0.563729635772361,54.00271370420624,0.15902022947936528,58.99441681527846
+20,25,1.001,30,0.9,20,1.3,10,36.12009237875289,0.3372952516090916,0.8023559258061533,1.482517713427163,0.5759988927048593,53.717948717948715,0.15803547583194244,58.99027682070209
+25,30,1.003,25,0.8,20,1.3,10,29.191685912240185,0.20043228751984704,0.7135838490365958,1.5118371159980342,0.5608511275143008,53.40729001584786,0.15760535608564255,58.959714721150455
+25,35,1.003,25,0.8,15,1.8,10,33.11778290993072,0.21102828043885022,0.714832692569413,1.4773063358879044,0.5420000585457502,54.54545454545454,0.16201113544817075,58.92403994380152
+30,35,1.002,25,0.8,15,1.5,10,31.501154734411084,0.14663643921882366,0.6059496954253383,1.4988626938572,0.5606132911703494,53.970588235294116,0.1552154475449011,58.795737851949085
+20,25,1.001,30,0.8,20,1.5,10,31.270207852193995,0.3234761279866446,0.7918667991702769,1.481673672337055,0.5336245036760888,54.22222222222223,0.1626990176964215,58.77899642195968
+25,35,1.001,25,0.8,15,1.8,10,33.903002309468825,0.21613266011089044,0.707685510364773,1.474654290626897,0.544495008234651,54.37158469945356,0.16053190307108423,58.76028581207349
+30,30,1.001,25,0.8,20,1.3,10,27.852193995381064,0.22507455686418004,0.690905632311402,1.5048247898458373,0.5402118960234387,54.742096505823625,0.15443234169703568,58.71653557150538
+30,35,1.001,20,0.8,20,1.3,10,30.484988452655887,0.1597945779488956,0.6060880533295208,1.4914725758061131,0.5416588220208343,54.7112462006079,0.15486826711332027,58.59688851680024
+20,35,1.002,25,0.7,15,1.8,10,34.31870669745958,0.3538457891879087,0.9009798035635418,1.4741208853018144,0.5471704360493308,53.57624831309041,0.16092911290253847,58.56327808243662
+25,35,1.001,20,0.8,20,1.5,10,32.609699769053115,0.1250670897877747,0.5838625840704365,1.4826793090341412,0.5458605906447614,54.11931818181818,0.15684159414004362,58.513194454900265
+30,25,1.002,30,0.9,20,1.3,10,29.37644341801386,0.15340017827612165,0.6616992008639377,1.4839198557455806,0.5226795257053898,55.43307086614173,0.15606765703087896,58.50949451602845
+25,25,1.002,30,0.8,20,1.5,10,27.436489607390303,0.22286233489440424,0.7403989324074974,1.4810185792415003,0.5045250294548237,54.97470489038786,0.16128077096730273,58.410214932347884
+20,30,1.001,25,0.9,20,1.5,10,37.92147806004619,0.285475823004987,0.738529074250964,1.4632790718900321,0.5618187047096431,53.724053724053725,0.15596224599887976,58.3435126740525
+20,35,1.001,25,0.7,15,1.8,10,34.54965357967667,0.3590061795067896,0.9104291863172669,1.4691934789830898,0.5415711262756225,53.48525469168901,0.16051279293044074,58.34139408454844
+30,30,1.002,30,0.8,15,1.3,10,28.17551963048499,0.23926612143011142,0.7426291281004544,1.4811493757927707,0.5099631538517977,54.51559934318555,0.16049244427981163,58.2902291502254
+20,25,1.003,30,0.7,20,1.8,10,27.713625866050805,0.282108044908753,0.9176543109484754,1.486123134127991,0.5135654048806007,53.58931552587646,0.1628220533126214,58.28485976973693
+30,35,1.001,20,0.9,20,1.5,10,35.33487297921478,0.09490766318573304,0.5084670291293234,1.4637887412608275,0.5398443149387433,55.04587155963303,0.15358172277300447,58.2292545462561
+30,35,1.003,20,0.8,20,1.3,10,29.607390300230946,0.16339098439619137,0.6108512103483035,1.488091893072282,0.5300100291373925,54.460093896713616,0.15390621421221448,58.19356700191267
+20,30,1.001,25,0.9,20,1.8,10,37.87528868360277,0.2851516802675307,0.7362654663282531,1.4602094198119664,0.5564334579785503,53.66748166259169,0.15554672789423113,58.16037024232994
+25,35,1.001,20,0.9,20,1.5,10,38.106235565819865,0.08513262300576525,0.502209805981777,1.4547578666386956,0.5496925999855296,54.3134872417983,0.15491143118958117,58.14294362734096
+30,30,1.003,30,0.8,15,1.3,10,27.390300230946885,0.2339091786428799,0.766691705085569,1.4855326934422644,0.5104350422888123,54.054054054054056,0.1597726798077741,58.1424313287681
+30,35,1.001,20,0.8,20,1.5,10,29.79214780600462,0.17918863552217904,0.6203109363011616,1.4830232248542508,0.5241829630847112,54.58786936236392,0.15387605640733612,58.069559364013465
+20,25,1.003,30,0.9,20,1.5,10,33.071593533487295,0.324992479261482,0.8249106777737153,1.4700407041644707,0.5311016109606,53.70629370629371,0.1579865346006866,58.04887384955107
+30,35,1.002,20,0.8,20,1.3,10,30.069284064665126,0.16235768758840297,0.5926944716037549,1.4806476822454755,0.5228791922843671,54.699537750385204,0.15372075494395612,58.04256005413977
+25,30,1.001,25,0.8,20,1.3,10,30.669745958429562,0.19567557555095308,0.6682000778120047,1.4832069605157434,0.5311644798025204,53.776435045317214,0.15539923082078108,58.03820515927932
+30,35,1.003,25,0.8,15,1.5,10,30.99307159353349,0.1407515537240566,0.6130444378682471,1.4795603325027333,0.5283840829669588,53.96113602391629,0.15425246089651443,57.917114691269035
+25,35,1.002,20,0.9,20,1.8,10,36.905311778290994,0.06847235077957259,0.4890832963792001,1.446568292874964,0.526058591585805,54.70514429109159,0.1549652674696584,57.76691554520278
+30,25,1.001,30,0.8,20,1.3,10,26.46651270207852,0.20921758212905803,0.7154979079294816,1.4707326301405368,0.48345583538266834,55.166374781085814,0.1581676727688578,57.73861732023477
+30,35,1.003,20,0.8,20,1.5,10,28.914549653579673,0.18345985537299206,0.6256199114217701,1.479304003804566,0.5123899286006985,54.32692307692307,0.15286619993182288,57.652467839463185
+25,30,1.002,25,0.9,20,1.3,10,34.82678983833718,0.1602726248237322,0.6016039499027142,1.458191514649531,0.5273410863247932,53.917662682602916,0.15377076003163442,57.57781728748424
+20,35,1.003,25,0.7,15,1.8,10,33.94919168591224,0.3415375671329948,0.8976072056133938,1.4511713515562676,0.5092071829525934,53.47885402455662,0.1599555756359649,57.509147686443804
+30,35,1.002,20,0.8,20,1.5,10,29.37644341801386,0.18208664007167402,0.6068027354258019,1.471822278356742,0.5051600134454534,54.57413249211357,0.15268854537440305,57.50249300028496
+30,30,1.002,25,0.9,20,1.3,10,32.0554272517321,0.15720984881732036,0.5966135068701746,1.4582740518768351,0.5056720623393111,54.97835497835498,0.15144524262877743,57.379928392671566
+25,25,1.002,30,0.9,20,1.3,10,32.14780600461894,0.19583289665685336,0.6689768965471836,1.4564713505765552,0.5037027863638476,54.388489208633096,0.1544868233084884,57.36132883435134
+25,35,1.003,20,0.9,20,1.8,10,36.12009237875289,0.05702297690469936,0.5051513759932359,1.4389904680093883,0.5075989356197846,54.61538461538461,0.1550998808502987,57.332479815339546
+20,25,1.002,30,0.7,20,1.5,10,29.145496535796767,0.318713985175976,0.8560225957339125,1.4558648419493272,0.48123305559219454,53.96825396825397,0.1600127037224564,57.25346749988813
+30,25,1.003,30,0.9,20,1.3,10,28.406466512702078,0.1317276517229528,0.6998881177077937,1.459958854315148,0.4819397359548404,55.048859934853425,0.15430710276150716,57.23695302179335
+25,30,1.003,25,0.9,20,1.3,10,33.995381062355655,0.1470898085693417,0.6246865324779598,1.4485177066115587,0.505892534696923,53.74149659863946,0.15355582766417175,57.009047431536494
+30,30,1.002,25,0.8,20,1.8,10,26.512702078521936,0.22943735851566394,0.7184385473976805,1.450019773615143,0.45580814735709263,55.14834205933682,0.1554149820138292,56.77940611617854
+20,25,1.001,30,0.8,20,1.8,10,31.131639722863742,0.2806629972043393,0.7630286569538166,1.4366153862780846,0.46692328364382885,54.01785714285714,0.15844167024350725,56.65800547810419
+30,35,1.001,25,0.9,15,1.8,10,36.674364896073904,0.06732784738277336,0.5035246778691459,1.4254793299316737,0.49068082479254094,54.67171717171717,0.15189677946224653,56.63953947842012
+30,30,1.003,25,0.9,20,1.3,10,31.270207852193995,0.13831441988091825,0.6120927281038859,1.4429922540685935,0.4775060437154536,54.73372781065089,0.1507308208509616,56.562472097965696
+30,35,1.001,20,0.8,20,1.8,10,29.145496535796767,0.19227760199623914,0.6559901425768312,1.4390989165407084,0.45719338339095494,55.00794912559619,0.15428139603906374,56.530433623476775
+25,30,1.003,30,0.7,15,1.3,10,28.9607390300231,0.3249692004274519,0.8465862699987875,1.449912785733809,0.4715608417642452,53.03514376996805,0.15769158134462008,56.51693163018743
+30,30,1.002,25,0.9,20,1.8,10,31.639722863741337,0.13965029718716684,0.5784309344589583,1.439125755506821,0.4744440375106085,54.97076023391813,0.14981669738399764,56.46943032411929
+25,25,1.003,30,0.9,20,1.3,10,31.131639722863742,0.18193917108153204,0.7136814942972862,1.4385388927643976,0.47004342270414456,54.08618127786033,0.15322525733052933,56.35353006012315
+30,30,1.001,30,0.8,15,1.3,10,28.9607390300231,0.2180848976906122,0.7078397633601132,1.437654418559887,0.45395179016567466,54.24,0.1554018002921859,56.28506044552631
+25,25,1.003,30,0.7,20,1.3,10,25.635103926096996,0.2302529188312409,0.8398870215507509,1.4508748784703276,0.4515176665994475,53.61010830324909,0.15618246043242573,56.258391023131296
+30,25,1.002,30,0.9,20,1.5,10,28.498845265588912,0.18939112941661215,0.6400369125751996,1.4375098050529898,0.4510768640153897,55.1948051948052,0.15145294589940334,56.247514746046114
+25,30,1.002,30,0.8,15,1.5,10,30.207852193995382,0.2980934629123099,0.7539001554811429,1.4273062360496775,0.44759374635886495,53.905053598774884,0.15788048212735914,56.124858972716964
+30,25,1.003,30,0.7,20,1.3,10,22.863741339491916,0.1989269099072057,0.8283729817372386,1.45189440185047,0.4364333647547707,54.25101214574899,0.1548248888462177,56.1202968505766
+25,25,1.001,30,0.8,20,1.3,10,29.2378752886836,0.2160237578997242,0.7128002698141036,1.429962352086101,0.4448528655650955,54.35816164817749,0.15556869323274852,56.08350916017832
+30,35,1.003,20,0.8,20,1.8,10,28.267898383371826,0.19705288629299744,0.6625282526172539,1.4339262021260188,0.44430599140141946,54.75409836065573,0.1532052564407042,56.07333710460251
+25,25,1.002,30,0.9,20,1.5,10,31.224018475750576,0.2083607429813321,0.6603471219137546,1.4307378081482531,0.4592997222577355,54.37037037037037,0.1514918567448269,56.0302163372367
+30,30,1.002,25,0.9,20,1.5,10,31.732101616628178,0.15083359097889526,0.5863551329953403,1.4293273478591229,0.46068893378936693,54.95626822157435,0.14884565463585064,56.02771922117991
+30,35,1.002,20,0.8,20,1.8,10,28.729792147806005,0.1954302251340935,0.642694157206658,1.4270074345177368,0.43748782969273026,55.00000000000001,0.15303351535223672,55.93759522602155
+25,30,1.003,30,0.8,15,1.5,10,29.422632794457275,0.29467650487835256,0.7766014358856087,1.42994710188752,0.4463051867392964,53.459119496855344,0.1571205308344592,55.92678892575047
+20,25,1.002,30,0.7,20,1.8,10,28.9607390300231,0.2724453835749298,0.8317806487564343,1.4224621831615847,0.4327974826349358,53.833865814696495,0.15708973111725916,55.72250531567931
+30,30,1.003,25,0.8,20,1.8,10,25.727482678983833,0.21884756815270553,0.7270456722365377,1.4332350999973917,0.42827393501275846,54.49640287769785,0.15246703500890713,55.6432922770604
+25,30,1.001,30,0.9,15,1.3,10,35.519630484988454,0.2819198972199691,0.7318925279839755,1.4129533275676869,0.46228075535091195,53.58539765319426,0.1511124561004827,55.564277111466986
+30,30,1.002,25,0.8,20,1.5,10,26.651270207852196,0.24165974300742235,0.7252484508018952,1.4220771002441528,0.41847888672057065,55.03472222222222,0.15246726030250138,55.51436767676125
+25,30,1.002,25,0.9,20,1.5,10,34.50346420323326,0.1297124740302226,0.5775861920313062,1.4148486152094493,0.45824751455692403,53.88739946380697,0.14963450773706985,55.50502097318507
+25,30,1.002,30,0.9,15,1.5,10,33.81062355658199,0.2949366837637918,0.7010048575118929,1.409916092725217,0.44590382753639213,53.62517099863201,0.1513035761645104,55.271012307655354
+30,30,1.002,30,0.9,15,1.3,10,32.0554272517321,0.1881371882422515,0.6393267892441497,1.4121621304995116,0.4375521784864467,54.25685425685426,0.14953968182280175,55.23011326635866
+25,25,1.003,30,0.8,20,1.8,10,26.096997690531175,0.1810621082121662,0.7609153819285794,1.4143227719204592,0.40478199810895177,54.60992907801418,0.15476533663930078,55.21565689600385
+25,30,1.002,30,0.8,15,1.8,10,30.023094688221708,0.29623862497564546,0.7498131375720142,1.4092872656949704,0.42056094796562804,53.77503852080123,0.15559333871498757,55.20876301267161
+30,30,1.003,25,0.9,20,1.5,10,30.94688221709007,0.13157896146666023,0.6017357903376543,1.4131500843513907,0.43187325486084094,54.7085201793722,0.14804300349985053,55.17983638664559
+30,30,1.002,30,0.8,15,1.5,10,27.528868360277137,0.21423402735983904,0.6856134126147597,1.414920066110522,0.4137042161599598,54.285714285714285,0.15350508928817336,55.1704673935854
+25,30,1.002,30,0.7,15,1.3,10,29.838337182448036,0.30998763074152613,0.7925748462594453,1.4128103969831765,0.424477529846521,53.48837209302325,0.1543230289728119,55.12570066480473
+25,30,1.001,30,0.8,15,1.5,10,30.90069284064665,0.2854473991940211,0.7285425616370336,1.405337547926724,0.41995063162631363,53.823088455772115,0.1548744472336373,55.10870780194019
+20,35,1.003,20,0.7,20,1.3,10,33.21016166281755,0.25157791964718385,0.7749042594290425,1.4130305056208343,0.44621038361173526,53.13807531380753,0.15069348983167194,55.10430779796567
+30,30,1.003,25,0.8,20,1.5,10,25.912240184757508,0.23051010297390806,0.738484603508835,1.419229172092819,0.4104003579684321,54.46428571428571,0.15106311975232545,55.037761363102035
+30,30,1.003,25,0.9,20,1.8,10,30.808314087759815,0.12071699606200416,0.5896872564265907,1.4108203021803514,0.4276183511952143,54.65465465465466,0.14772203862252806,55.03382639076215
+20,35,1.002,20,0.7,20,1.3,10,33.5796766743649,0.2548610668006959,0.7612153433878149,1.407783788337821,0.4407987459334466,53.37931034482759,0.15041396977213714,55.00400419540251
+25,30,1.001,30,0.7,15,1.3,10,30.484988452655887,0.31327841272474644,0.7831629093847212,1.409374070038332,0.4232315894237325,53.49544072948328,0.15348353795995004,54.997960346465376
+25,30,1.003,30,0.8,15,1.8,10,29.2378752886836,0.29275026081679206,0.7725481080509864,1.4114601583798403,0.4189160825945972,53.32278481012658,0.15478628025547037,54.992847277229
+25,25,1.003,30,0.9,20,1.5,10,30.207852193995382,0.19446355885498956,0.7061285345156411,1.4113891373350758,0.4247102498824433,54.05819295558959,0.15007950755946484,54.97344706613975
+30,30,1.003,30,0.8,15,1.5,10,26.74364896073903,0.20801258923890129,0.7085837770170327,1.4174616332106982,0.4126950839041583,53.806228373702425,0.15261424727324885,54.954518256815035
+20,25,1.002,30,0.9,20,1.8,10,33.71824480369515,0.29584588533732264,0.7650904262445113,1.392843538909709,0.41941199449307465,53.90946502057613,0.1546475529594164,54.953407940054575
+25,30,1.003,25,0.9,20,1.5,10,33.672055427251735,0.11564850218178008,0.6002973870020821,1.4040101246904504,0.4360195558940606,53.708791208791204,0.14929487050183293,54.89758106420095
+30,25,1.003,30,0.9,20,1.5,10,27.528868360277137,0.16829583771149703,0.6786799927847764,1.4111456606112585,0.4084809259690436,54.78991596638656,0.14944855166472268,54.886683394828786
+30,25,1.001,30,0.8,20,1.8,10,25.681293302540414,0.20532905015165998,0.643110730018568,1.4084795447980356,0.394359910014239,54.87364620938629,0.15210987951225313,54.843982375043986
+20,35,1.001,20,0.7,20,1.3,10,33.81062355658199,0.2648881058451588,0.7781345298350518,1.4031933910028402,0.4353977504890181,53.28767123287671,0.15005715578051818,54.7942056609739
+25,35,1.001,20,0.9,20,1.8,10,37.55196304849884,0.06803552579004456,0.49035285662664607,1.384650669089795,0.4320192492042565,54.37731196054254,0.14875555322966075,54.76739092111267
+30,30,1.001,25,0.8,20,1.8,10,27.297921478060044,0.20724863040209307,0.6822258708828804,1.4047120068312544,0.39803679170559714,54.83870967741935,0.15022625816842303,54.701890918803564
+25,30,1.003,30,0.9,15,1.5,10,32.979214780600465,0.28474256653366525,0.7273045733555148,1.3987250597623173,0.42353578661385394,53.43618513323983,0.15101748010403493,54.657382540962764
+30,30,1.003,30,0.9,15,1.3,10,31.224018475750576,0.17452625536991706,0.6654625760541003,1.4004009781697193,0.41503271524824215,54.074074074074076,0.14917113956402672,54.60235839936735
+30,25,1.003,30,0.7,20,1.8,10,22.263279445727484,0.16971106505633457,0.786328705851738,1.4159021824938858,0.3866275088282771,54.26195426195426,0.15200978306123958,54.59027335333458
+30,25,1.002,30,0.9,20,1.8,10,28.17551963048499,0.17757175136524386,0.6449309345556311,1.3863162690704485,0.3775302020813671,55.33661740558292,0.15169976992193998,54.397513282449374
+30,25,1.001,30,0.8,20,1.5,10,25.773672055427248,0.218862321350564,0.6526350397020362,1.3965003807244678,0.3786855317148219,54.85611510791367,0.15086209971974787,54.319064399254756
+25,25,1.002,30,0.8,20,1.8,10,27.25173210161663,0.19424811871564365,0.7084964383424063,1.3869591270540187,0.37356383083016564,54.83870967741935,0.15351033883696533,54.31037567990744
+20,25,1.001,30,0.7,20,1.5,10,30.207852193995382,0.3116625109116527,0.8063990831232799,1.3907052423462918,0.3947091346776046,53.52760736196319,0.15282636093121493,54.229202604647895
+20,25,1.003,30,0.9,20,1.8,10,32.65588914549654,0.28803435727818666,0.8130178075081894,1.3801535243102252,0.39379242730111286,53.682719546742206,0.1540622936269287,54.228698599795
+25,30,1.001,30,0.8,15,1.8,10,30.71593533487298,0.28355833315837436,0.7243952052215293,1.387566527545583,0.393095947925873,53.69532428355958,0.15263310129124108,54.20313403866395
+25,25,1.003,30,0.7,20,1.5,10,25.17321016166282,0.18983148733792227,0.8153498273178929,1.402446350257399,0.38381350065146114,53.67647058823529,0.15136976461353238,54.12545150276736
+25,25,1.002,30,0.7,20,1.3,10,26.836027713625864,0.22494713867679456,0.7537785692807771,1.3916803691502673,0.37788650803079316,53.96551724137931,0.15108252576396558,53.962186477301174
+30,25,1.002,30,0.7,20,1.3,10,24.018475750577366,0.2004808669879343,0.7455299697501929,1.391886751401545,0.3639822109453765,54.72061657032755,0.1497513506303877,53.874710936766505
+25,25,1.001,30,0.8,20,1.5,10,28.498845265588912,0.2013725967908656,0.6679372330792466,1.3809034542667549,0.37142215859023375,54.3089430894309,0.15027517670036616,53.767330817049064
+30,25,1.001,30,0.9,20,1.3,10,30.300230946882216,0.15246851376999324,0.6400705378321364,1.3783386778456397,0.3774476574243897,54.74006116207951,0.14504780935251282,53.57771085787826
+30,30,1.001,25,0.8,20,1.5,10,27.436489607390303,0.21923328029449254,0.6890237703673522,1.3777541410181817,0.36157155552148623,54.729729729729726,0.14739116387456627,53.474519984912725
+30,30,1.001,25,0.9,20,1.3,10,32.74826789838337,0.14470256828075775,0.5855021800257324,1.374444583584533,0.3855505041931093,54.596888260254595,0.1430424486410759,53.46470939188643
+25,30,1.001,25,0.9,20,1.3,10,35.56581986143187,0.1506418002123923,0.5915166723421229,1.371473327403402,0.3980016561518994,53.515625,0.1449082903671758,53.42412145550918
+30,25,1.003,30,0.9,20,1.8,10,27.15935334872979,0.15835756772525686,0.6868580651531114,1.3654320240767768,0.343446524316787,55.02555366269165,0.1503835130322388,53.337995245096316
+25,35,1.003,20,0.8,20,1.8,10,31.085450346420323,0.10463615918624687,0.5949082153347766,1.3626932480389284,0.35903324985371077,54.24739195230999,0.15015876100379405,53.293919382537645
+30,35,1.001,25,0.8,15,1.8,10,31.270207852193995,0.12644063304685493,0.6105187183563996,1.3679552716432286,0.3676884700106078,54.074074074074076,0.14804027465603958,53.28687627350605
+25,30,1.002,25,0.8,20,1.5,10,29.561200923787528,0.17180097596205163,0.6735561055499015,1.3698103318538228,0.36154127162504524,53.834115805946794,0.14985209673668418,53.26412932926174
+30,30,1.001,30,0.8,15,1.5,10,28.314087759815244,0.1932632578892495,0.6516106972331329,1.3721628168214277,0.358231574525965,54.00981996726678,0.14849642715508973,53.19018479453447
+30,30,1.002,30,0.9,15,1.5,10,31.224018475750576,0.19134122424111008,0.6200985945441568,1.3704250037863184,0.3712922628316472,54.074074074074076,0.14500283994926005,53.14411514970805
+25,30,1.003,25,0.8,20,1.5,10,28.77598152424942,0.16486104892226777,0.6945751533329086,1.3709392069366815,0.35909559561395277,53.37620578778135,0.14893364848131363,53.01064796703481
+20,30,1.003,25,0.7,20,1.5,10,29.69976905311778,0.3327758763399395,0.8591045846932541,1.3665600642827476,0.35762430547395985,53.11526479750779,0.1507984366617695,52.98730283411716
+20,30,1.003,25,0.7,20,1.8,10,29.561200923787528,0.33432463553257524,0.8548201929962435,1.3640441782301098,0.3533285229378842,53.051643192488264,0.15039842173948778,52.828813630964866
+25,35,1.002,20,0.8,20,1.8,10,31.547344110854503,0.10845249755606613,0.5727002872562045,1.3500814231692115,0.34300727181613877,54.33186490455213,0.14922723715408043,52.8138449212992
+30,25,1.003,30,0.7,20,1.5,10,22.448036951501155,0.18287295953934457,0.7850788760907278,1.3733988990648014,0.33263772996076324,54.02061855670103,0.14761585609099118,52.698261080349496
+30,35,1.002,25,0.8,15,1.8,10,30.85450346420323,0.13295754304878418,0.6044386856625082,1.35572728052625,0.3477167072141134,54.054054054054056,0.1467814491949845,52.68280395756799
+20,25,1.001,30,0.9,20,1.5,10,35.057736720554274,0.3202056243096598,0.7440183523299246,1.3535117358678588,0.3670898174909403,53.236459709379126,0.1452493428386648,52.595881375902984
+30,30,1.001,30,0.9,15,1.3,10,32.79445727482679,0.18101749281821294,0.6372168239108043,1.3560219798772415,0.35831951292801045,53.954802259887,0.1435528412347332,52.58545149204152
+30,30,1.001,25,0.9,20,1.8,10,32.33256351039261,0.12735848486435175,0.5675663742496139,1.3545994547425269,0.35373450149522334,54.58452722063038,0.14131772188400912,52.5261820661114
+30,30,1.003,30,0.9,15,1.5,10,30.392609699769054,0.1774456042202612,0.646423342840398,1.3571981451813753,0.34773388081647716,53.88127853881278,0.14447222784718686,52.463957699681195
+25,35,1.002,25,0.7,15,1.3,10,32.88683602771363,0.23220378527941182,0.719899100828928,1.35515759268969,0.3575268498677724,53.38028169014084,0.14348248402702463,52.36218772922998
+25,30,1.001,25,0.8,20,1.5,10,30.2540415704388,0.16177680905627853,0.6494964574083127,1.3486033298335047,0.3344451311888308,53.751914241960186,0.14702245346857984,52.280670325522905
+25,35,1.001,25,0.7,15,1.3,10,33.11778290993072,0.23843555930739715,0.73101980070823,1.3508484617096792,0.35231324727841284,53.28671328671328,0.14316337454406555,52.16145652898668
+20,30,1.002,25,0.7,20,1.8,10,30.484988452655887,0.3183962604725388,0.8053325396033902,1.3427558018028813,0.3273547699246626,53.566009104704094,0.14866111407932,52.14929329628893
+30,30,1.001,25,0.9,20,1.5,10,32.42494226327944,0.13833783879535325,0.5753522054674389,1.345238518964252,0.34032845426933456,54.57142857142857,0.1403869928479904,52.09962221787946
+20,35,1.003,20,0.7,20,1.5,10,32.14780600461894,0.2885344240847759,0.7454819112009,1.3524511549808589,0.3495835428496281,52.73775216138329,0.14431952755298777,52.03974105691501
+20,25,1.001,30,0.7,20,1.8,10,30.069284064665126,0.2672823404070463,0.7766090508620889,1.3436296282914373,0.3264194825708564,53.312788906009246,0.1483318316785107,52.03336818633311
+25,35,1.001,20,0.8,20,1.8,10,31.87066974595843,0.10617578174360254,0.5774752623566434,1.332003849250656,0.3180413520134011,54.21511627906976,0.14738192745958825,51.9715772360605
+20,35,1.002,20,0.7,20,1.5,10,32.517321016166285,0.2915048728704328,0.7316801169165994,1.347722899674499,0.3444931483317175,52.991452991452995,0.1440918817026985,51.959750219617554
+30,25,1.002,30,0.7,20,1.8,10,23.46420323325635,0.16975684000622554,0.7003291790166124,1.347309619575387,0.30294085911481883,54.63510848126233,0.14605362416800027,51.9411554718041
+20,30,1.001,25,0.7,20,1.8,10,31.085450346420323,0.3276919272306477,0.7982067573047503,1.3380520090843353,0.32317473047948964,53.50223546944859,0.14754690535291673,51.90965596414423
+25,25,1.002,30,0.7,20,1.5,10,26.374133949191688,0.18627334188974864,0.7288506264093109,1.3444223613589799,0.311126322765638,54.03508771929825,0.14635474092726058,51.86799997420899
+20,35,1.001,20,0.7,20,1.5,10,32.74826789838337,0.3015987706845346,0.7493564506425988,1.3434079270985162,0.33925451798830686,52.899575671852894,0.14376270493071808,51.758298373213904
+30,35,1.003,25,0.8,15,1.8,10,30.346420323325635,0.12671823403073373,0.6116593113425702,1.3336085487815497,0.31330760428006177,54.045801526717554,0.14559892193174767,51.7143328273847
+25,30,1.002,30,0.9,15,1.8,10,33.441108545034645,0.2947252617817422,0.7035643060852291,1.3280381375020314,0.3198873404941809,53.52697095435685,0.14708551235387643,51.699094575739835
+20,30,1.002,25,0.7,20,1.5,10,30.57736720554273,0.3179323402984814,0.8060392860303991,1.3327516844997105,0.3133358197390479,53.5552193645991,0.1476506989434798,51.69861086544101
+20,30,1.001,25,0.7,20,1.5,10,31.177829099307157,0.3272093990991777,0.7989210057481236,1.3282402498689432,0.30931612038705936,53.49182763744428,0.14656076600918141,51.46618594657335
+25,35,1.003,25,0.7,15,1.3,10,32.47113163972286,0.22237425093151697,0.723619300692791,1.3342516027395948,0.3242435464801241,53.352353780313834,0.1424753553731478,51.435487574666375
+25,30,1.002,25,0.9,20,1.8,10,34.364896073903,0.10696259654416132,0.5463495982604321,1.3272695959773098,0.32327480500156724,53.70121130551817,0.14206638385237694,51.416289111204975
+25,30,1.001,25,0.9,20,1.5,10,35.24249422632795,0.12063413518613927,0.5679100195598611,1.328187085231229,0.3289012218655014,53.482260183968464,0.14074522389135916,51.34879202803856
+30,25,1.001,30,0.9,20,1.5,10,29.422632794457275,0.18730166169474388,0.6184432592265546,1.330158152480703,0.3042564439152158,54.48818897637795,0.14022738111218022,51.24538161568295
+25,30,1.001,30,0.9,15,1.5,10,34.54965357967667,0.28214208497532567,0.6884946726945105,1.3216112180922919,0.3152923917432693,53.2171581769437,0.1420783474139227,51.045111017139256
+25,30,1.003,30,0.9,15,1.8,10,32.609699769053115,0.28441024011320504,0.730227290768892,1.3146296131097408,0.2959156342786542,53.333333333333336,0.14668281929315052,51.01916439718954
+25,30,1.003,25,0.7,20,1.3,10,27.390300230946885,0.20820501450042528,0.6908319726890041,1.3451116834933479,0.3164858688564711,52.53378378378378,0.14051521968551686,51.010433032428615
+25,30,1.003,30,0.7,15,1.5,10,28.452655889145497,0.27454089567048384,0.7799023976554923,1.3259802769754414,0.294422017877902,52.6829268292683,0.14579168183949792,50.84830483824808
+25,25,1.001,30,0.7,20,1.3,10,27.89838337182448,0.22088252493608876,0.7039405483553935,1.3234544546326592,0.2884301998884784,53.48837209302325,0.14372300717180445,50.82283924202012
+30,30,1.003,30,0.7,15,1.3,10,26.096997690531175,0.21658334749633348,0.7327642328656265,1.3315649620990175,0.29250147814247995,53.01418439716312,0.14334015005334433,50.806192256820246
+25,25,1.001,30,0.9,20,1.3,10,33.11778290993072,0.18545112274583442,0.6347213546566296,1.3170153222444918,0.30156353808063163,53.56643356643357,0.14014615247934104,50.71697184307893
+30,25,1.002,30,0.7,20,1.5,10,23.602771362586605,0.18523970404262322,0.7028948964584362,1.3161801088425462,0.2626570805554309,54.509803921568626,0.14272321752604636,50.55118582017938
+30,30,1.001,30,0.9,15,1.5,10,31.963048498845264,0.18396225267022986,0.6183783282558976,1.3137276563372322,0.2915352687864132,53.768115942028984,0.13896832773489767,50.4783454497148
+30,25,1.001,30,0.7,20,1.3,10,25.080831408775982,0.19699596376409922,0.6904425906530873,1.3159596886489977,0.26743860685347154,54.15896487985212,0.1416852450740092,50.432413492905425
+30,30,1.003,25,0.7,20,1.3,10,24.480369515011546,0.23022840075816337,0.7004843613852433,1.3300699475353412,0.28418194969317745,53.497164461247635,0.13611141799953824,50.243755702471795
+25,30,1.003,25,0.9,20,1.8,10,33.48729792147806,0.09284864474314988,0.5646940931815357,1.3027197131564445,0.28189428427969143,53.45303867403315,0.14024345264605192,50.1661431135002
+25,25,1.003,30,0.7,20,1.8,10,24.94226327944573,0.16116631995883504,0.784177333797192,1.3074621243093507,0.25575607091184627,53.61781076066791,0.14350111686371933,50.08255223574537
+25,30,1.003,30,0.7,15,1.8,10,28.267898383371826,0.27241694971002756,0.7757315599557596,1.3061773054590722,0.26596369846843415,52.53682487725041,0.14332796065218106,49.865940550602375
+25,30,1.002,25,0.7,20,1.3,10,28.267898383371826,0.19601616730353882,0.6386554235276819,1.309203631444921,0.2701954254825445,53.0278232405892,0.13751517941250055,49.69034007354588
+30,30,1.002,30,0.8,15,1.8,10,27.297921478060044,0.180241575022522,0.6419566945967062,1.2906548473177664,0.24095989758037106,54.067796610169495,0.14222745070620782,49.66720310298929
+25,30,1.001,25,0.7,20,1.3,10,28.914549653579673,0.20203456442343853,0.6321745826026448,1.3077385430191026,0.2704386377494039,53.044871794871796,0.13706491187121844,49.64680961182214
+25,30,1.002,30,0.7,15,1.5,10,29.330254041570434,0.26080868114020733,0.7269506084254252,1.291948221647762,0.24981265961304944,53.154574132492115,0.14265084096762584,49.5624393770071
+25,30,1.001,30,0.7,15,1.5,10,29.97690531177829,0.26521611011300217,0.7187947702010161,1.2908819235792193,0.25045375121381386,53.16846986089645,0.1420561256715659,49.51852092466812
+20,35,1.003,20,0.7,20,1.8,10,31.501154734411084,0.2969906987975395,0.7734376153063527,1.2890514984477832,0.25341532929103283,52.94117647058824,0.14197733911208738,49.464125299121406
+30,30,1.002,30,0.7,15,1.3,10,26.974595842956123,0.2035375207644554,0.6767218338415076,1.2943738264298978,0.24498710046926941,53.516295025728986,0.14004672741017513,49.428668030423935
+20,35,1.002,20,0.7,20,1.8,10,31.87066974595843,0.299923373793772,0.7590316605107134,1.2849642339524343,0.24878948185919003,53.19767441860465,0.1417697888902291,49.40274667834307
+25,25,1.002,30,0.9,20,1.8,10,30.85450346420323,0.18407706720913336,0.6385145978376092,1.276385869836457,0.23280492830857136,54.27286356821589,0.14203347563811997,49.40029042144455
+25,30,1.002,25,0.8,20,1.8,10,29.37644341801386,0.1460049903238883,0.6393384898856918,1.2817236367323188,0.2354537708819151,53.7007874015748,0.14237934693713664,49.34786529797184
+30,30,1.003,30,0.8,15,1.8,10,26.512702078521936,0.17295919808566254,0.6638341802806943,1.2895318404493983,0.23682175000307115,53.57766143106457,0.141047611431148,49.32492042139511
+25,25,1.001,30,0.9,20,1.5,10,32.19399538106236,0.19730361720369272,0.6253686452018102,1.2880091902937794,0.25449496994553433,53.525179856115116,0.13684391488297093,49.26686052809818
+20,35,1.001,20,0.7,20,1.8,10,32.10161662817552,0.31016003716870927,0.7768672905736818,1.2810148944392896,0.2438119433974819,53.102453102453104,0.14144258866408027,49.20944552190961
+30,30,1.002,25,0.7,20,1.3,10,25.311778290993068,0.221523149639818,0.6537835354876695,1.2961385054107066,0.24183672549864443,54.11334552102377,0.13340467530494007,49.080675595623525
+25,25,1.001,30,0.8,20,1.8,10,28.36027713625866,0.17415610089290526,0.6305284828473465,1.2744115477760563,0.22168999557763125,54.084967320261434,0.14087877166615448,49.03020796057927
+25,25,1.001,30,0.7,20,1.5,10,27.436489607390303,0.18363777055425343,0.6791388049398025,1.2768001918181155,0.22213419490709985,53.547297297297305,0.13903091549651284,48.74348205241627
+30,25,1.001,30,0.9,20,1.8,10,29.145496535796767,0.1762827109280936,0.6169013217650738,1.2645792198677148,0.21026412919334847,54.531001589825124,0.13831079794339798,48.65903353595144
+25,30,1.002,30,0.7,15,1.8,10,29.145496535796767,0.2586616386902543,0.7225696895202642,1.2725264060639327,0.22165487409109152,53.01587301587302,0.1402372172048392,48.59645868184978
+25,30,1.001,30,0.7,15,1.8,10,29.79214780600462,0.26314300302768556,0.7144583621668233,1.2718461397377152,0.2226018395328011,53.03265940902022,0.1396974989442788,48.56794196606295
+25,25,1.003,30,0.9,20,1.8,10,29.79214780600462,0.17152910882966432,0.6865353955121237,1.2583149432899974,0.20341342211719704,54.037267080745345,0.1408670117072244,48.49438924895664
+30,30,1.001,30,0.7,15,1.3,10,27.713625866050805,0.20025561088207555,0.6609286865146018,1.2740973950755021,0.21924816139484182,53.34448160535117,0.13757314820790031,48.477959134418654
+25,30,1.001,25,0.8,20,1.8,10,30.069284064665126,0.1365136085439974,0.615919434128737,1.26228610423992,0.20978722382051918,53.62095531587057,0.13967410863768084,48.42189211609271
+25,30,1.003,25,0.8,20,1.8,10,28.545034642032334,0.13905750538647074,0.6553768597337947,1.2668968438748325,0.21186631109449205,53.16045380875203,0.1397601925660559,48.36777214875717
+30,30,1.001,25,0.7,20,1.3,10,26.05080831408776,0.21752152554153115,0.637633046795325,1.274516127946933,0.21482949316932376,53.91459074733096,0.13108886572295447,48.09428563687073
+20,25,1.001,30,0.9,20,1.8,10,34.73441108545035,0.2833710716026132,0.7244874805011521,1.249080854852758,0.2046712737634655,53.06666666666666,0.1389833302592265,47.92695710209268
+30,30,1.003,30,0.7,15,1.5,10,25.727482678983833,0.16564573563359913,0.694698876582075,1.264490754966812,0.20048499851773438,52.87769784172662,0.1366452589136058,47.80331154600287
+30,30,1.001,30,0.8,15,1.8,10,28.08314087759815,0.16004879542427042,0.6088950164344853,1.2508257453128941,0.18795270756142068,53.79537953795379,0.137433126025445,47.78428337497197
+25,35,1.002,25,0.7,15,1.5,10,31.732101616628178,0.22442567148093273,0.6641661686687185,1.2603605240084295,0.21213103920475995,52.99270072992701,0.13364749718127888,47.758260521680896
+30,25,1.001,30,0.7,20,1.8,10,24.572748267898383,0.1680714714787007,0.638746707295817,1.254038262691909,0.18337465431270172,53.9622641509434,0.13600640637065547,47.690745329384356
+25,25,1.002,30,0.7,20,1.8,10,26.189376443418016,0.15624028453968275,0.6955725581158425,1.2455753609880311,0.1760589883218462,53.88692579505301,0.1379278000169319,47.581692592860655
+25,35,1.001,25,0.7,15,1.5,10,31.963048498845264,0.23093878209806837,0.676091322533257,1.2565822003746596,0.2072899058725175,52.89855072463768,0.1333787660520936,47.57437977693385
+25,30,1.001,30,0.9,15,1.8,10,34.18013856812933,0.28179691429247217,0.690863536597965,1.2404402145375133,0.1897528453616446,53.116531165311656,0.13756623440789056,47.466665169472876
+25,30,1.001,25,0.9,20,1.8,10,35.10392609699769,0.09832736694118953,0.5372928428717758,1.241998172461553,0.1948983944995668,53.29815303430079,0.13318709327972186,47.29582238840084
+30,25,1.001,30,0.7,20,1.5,10,24.665127020785217,0.1823525210785777,0.6487154204958558,1.242099291525196,0.1677253400882912,53.94736842105263,0.13475563694465936,47.167420864056155
+25,35,1.003,25,0.7,15,1.5,10,31.316397228637417,0.21413044187804722,0.6672837263602431,1.2374192923913463,0.17733313507168558,52.95857988165681,0.13238695465520445,46.757938567247834
+25,35,1.003,20,0.7,20,1.3,10,30.2540415704388,0.12139375588275371,0.591293938042595,1.2372249164169806,0.17431999929979325,52.833078101071976,0.13102668753434854,46.555396117443124
+30,30,1.002,30,0.7,15,1.5,10,26.605080831408777,0.15409895058841724,0.639133738976697,1.2289985425153607,0.15442029741166663,53.391304347826086,0.13348805825790708,46.48671969079553
+30,35,1.001,25,0.7,15,1.3,10,30.300230946882216,0.14989835421667574,0.6182932807927232,1.2381397623459611,0.17575304055865515,52.752293577981646,0.129218092526883,46.42389758407163
+25,35,1.002,20,0.7,20,1.3,10,30.669745958429562,0.1220407660108498,0.5688584563443632,1.2290706743299002,0.16358367476635505,53.02114803625378,0.13052680057415192,46.29136100710007
+25,35,1.001,20,0.7,20,1.3,10,30.90069284064665,0.13400473325224901,0.5888085743033985,1.2253863797504452,0.15879010676967065,52.92353823088456,0.13026803135666418,46.10909862706484
+30,30,1.001,30,0.7,15,1.5,10,27.344110854503462,0.1521088681448169,0.6241430651957734,1.210109259987885,0.12985360508995614,53.22033898305085,0.13115301591630316,45.58481703055302
+25,35,1.002,25,0.7,15,1.8,10,31.131639722863742,0.23998919061487123,0.697843520425474,1.2053902361119577,0.1302104885953952,53.125,0.13187833454442083,45.55588751266253
+25,35,1.001,25,0.7,15,1.8,10,31.362586605080832,0.24651239378333686,0.7097489986515075,1.2019453441358587,0.12562040627539872,53.028064992614475,0.13161155493735505,45.37976418874684
+30,30,1.002,30,0.9,15,1.8,10,30.808314087759815,0.16202610741259954,0.5875181809144904,1.1885469136242122,0.10525430896876475,53.9039039039039,0.1321173787472973,45.19260400659948
+30,35,1.002,25,0.7,15,1.3,10,29.97690531177829,0.14194574146032132,0.5965438760078261,1.2096031456949417,0.13406992039820964,52.7047913446677,0.1262907477542641,45.09989457495169
+30,30,1.003,25,0.7,20,1.8,10,23.879907621247114,0.2110398274668263,0.6858710091216746,1.1956359191050046,0.10489689362866961,53.48837209302325,0.1282399813948286,44.83447224653072
+25,30,1.003,25,0.7,20,1.5,10,26.974595842956123,0.17037808452873582,0.6702032324312553,1.1922145508540622,0.10469795443203056,52.48713550600343,0.13023205525569095,44.606155692471944
+25,35,1.003,25,0.7,15,1.8,10,30.71593533487298,0.22970333497795262,0.7014778065618116,1.181252973420832,0.09448422485057528,53.09200603318251,0.13055260597652477,44.51975298756899
+30,30,1.002,25,0.7,20,1.8,10,24.757505773672055,0.20178856115887447,0.6433820351777051,1.1812400668895648,0.08695524019812706,54.20560747663551,0.12733174492679547,44.5133832851199
+30,30,1.003,30,0.9,15,1.8,10,29.97690531177829,0.14712473595399897,0.6133043703345102,1.1700841794785861,0.07753410702901498,53.70370370370371,0.1311434764487748,44.337549696302915
+30,30,1.003,25,0.7,20,1.5,10,24.064665127020785,0.22365770270183227,0.698504289536681,1.182380298137714,0.08765768169000898,53.46153846153846,0.12689415329341894,44.255658074770864
+30,35,1.001,25,0.7,15,1.5,10,29.330254041570434,0.15109982940778946,0.5925113907529783,1.1874954989241877,0.10146550160929291,52.44865718799369,0.12353719658711822,43.95725225967654
+25,35,1.003,20,0.7,20,1.5,10,29.330254041570434,0.12271938989429862,0.5591381532105838,1.1838394656302704,0.09627886707526367,52.44865718799369,0.12511793118188694,43.94441661624711
+30,35,1.003,25,0.7,15,1.3,10,29.515011547344113,0.13879779245665297,0.6034564675109825,1.1813403919059127,0.0929795317500337,52.590266875981165,0.12435350575607508,43.844048599189556
+25,25,1.001,30,0.7,20,1.8,10,27.297921478060044,0.15527206334603433,0.6403310757912324,1.1656196204095355,0.0684396394725717,53.3106960950764,0.12903315655293982,43.82775751637944
+25,35,1.002,20,0.7,20,1.5,10,29.745958429561203,0.12336796756347858,0.5364552995085065,1.1761795914798545,0.08592363071534015,52.64797507788161,0.12466928550856783,43.70096704618457
+30,30,1.001,25,0.7,20,1.8,10,25.496535796766747,0.1982719622897827,0.6271819416676998,1.1622795222407944,0.06227433758455936,54.0,0.1250294343214287,43.59950383283513
+25,35,1.001,20,0.7,20,1.5,10,29.97690531177829,0.13569039911468492,0.5572698522030732,1.1727901493310966,0.08135705177307773,52.55023183925811,0.12444213466841508,43.52875858488064
+25,30,1.001,25,0.7,20,1.5,10,28.498845265588912,0.1661407862157247,0.611793543994375,1.162250109534596,0.06487874391671666,53.008130081300806,0.12712313534338493,43.47345237733957
+25,30,1.002,25,0.7,20,1.5,10,27.852193995381064,0.15919920755521608,0.6178979222789633,1.1605953244729288,0.062031733140181844,52.99003322259136,0.12736895381919597,43.4163978109177
+30,30,1.002,25,0.7,20,1.5,10,24.896073903002307,0.21502652450546994,0.6510897973314932,1.1528225190428851,0.04918624554315909,54.08921933085502,0.12431750719176687,43.22865422289636
+30,30,1.001,30,0.9,15,1.8,10,31.547344110854503,0.15523663968523072,0.586538477175983,1.1351063873577834,0.028033602543246605,53.59765051395007,0.1260124678377772,42.60615202607881
+30,35,1.002,25,0.7,15,1.5,10,29.006928406466514,0.14289467757254068,0.5697473191993536,1.1574352739766445,0.05854947723553017,52.39616613418531,0.12045752295468917,42.57921003669587
+30,30,1.001,25,0.7,20,1.5,10,25.635103926096996,0.21114729929955253,0.6347550661387301,1.1347356540535114,0.025280132654302845,53.8878842676311,0.12211521921893773,42.34839531885929
+25,25,1.001,30,0.9,20,1.8,10,31.87066974595843,0.17404497165887045,0.5982990225128927,1.1232224948478307,0.01067278290285878,53.34302325581395,0.1253040571936267,42.01548130183993
+30,30,1.003,30,0.7,15,1.8,10,25.496535796766747,0.1288115313039152,0.6480400123994065,1.130064937102122,0.018963163942860906,52.63157894736842,0.1241908101368759,41.91925075086066
+30,35,1.001,20,0.7,20,1.3,10,28.08314087759815,0.13784735150165514,0.5883970837175508,1.1325201680258674,0.023062867872874593,53.135313531353134,0.11844209514696531,41.743437689630326
+30,35,1.003,25,0.7,15,1.5,10,28.545034642032334,0.13965511438124312,0.5764612033456842,1.127362136183147,0.015977616320286714,52.27272727272727,0.11831461503899578,41.25594561919791
+30,30,1.002,30,0.7,15,1.8,10,26.374133949191688,0.11838929259330078,0.5935408865828968,1.0987422500492177,-0.02346659073241919,53.1578947368421,0.12132850635851189,40.745254932029624
+30,35,1.001,20,0.7,20,1.5,10,27.113163972286376,0.1801695076663551,0.5800923487342744,1.1047956390851243,-0.0153688211035512,52.820512820512825,0.11517787592473273,40.36981735472487
+30,35,1.002,20,0.7,20,1.3,10,27.75981524249423,0.12415267644680165,0.5568787460076727,1.1004739281129088,-0.021504159739290207,53.08848080133556,0.11514792277011254,40.29704606629212
+30,35,1.003,20,0.7,20,1.3,10,27.344110854503462,0.12801568765689958,0.5755949879235729,1.0990434247347685,-0.02335296508234941,52.71186440677966,0.11462344305252134,40.07962032387622
+30,30,1.001,30,0.7,15,1.8,10,27.113163972286376,0.117355605576794,0.5796652592575033,1.083031425597562,-0.04529461464894968,52.991452991452995,0.1192768634619027,39.95431595722148
+25,30,1.003,25,0.7,20,1.8,10,26.74364896073903,0.14288412126951258,0.6281541736251055,1.079605967308087,-0.049781242427112904,52.24913494809689,0.11994067357335297,39.635568523526416
+25,30,1.001,25,0.7,20,1.8,10,28.314087759815244,0.13933999074287437,0.5758890516474588,1.0693445575027922,-0.06520073723314357,52.864157119476275,0.11886667150446763,39.36292014202206
+25,30,1.002,25,0.7,20,1.8,10,27.66743648960739,0.13172566174636915,0.5811950236219998,1.0656590177309908,-0.0697630340828419,52.84280936454849,0.11891440377304048,39.234121185725634
+30,35,1.002,20,0.7,20,1.5,10,26.78983833718245,0.16648977557184808,0.5473326002713095,1.0712493252262187,-0.0612202962022288,52.7681660899654,0.1117347475693478,38.86887721096488
+30,35,1.003,20,0.7,20,1.5,10,26.374133949191688,0.1711621687916439,0.5665867156873965,1.06930377440182,-0.06351866159088093,52.3725834797891,0.11115184629381984,38.626267408745626
+30,35,1.001,20,0.7,20,1.8,10,26.46651270207852,0.1946073262617311,0.6184004097011352,1.0471361362305078,-0.09380876400552274,53.239929947460595,0.11326712235940826,38.2793051393118
+30,35,1.001,25,0.7,15,1.8,10,28.683602771362587,0.13648627839500227,0.5905830642038906,1.0264497380074267,-0.12583703717772043,52.50403877221325,0.1121730603175396,37.13224926570721
+30,35,1.002,20,0.7,20,1.8,10,26.143187066974594,0.18076778582949357,0.5853041240443301,1.012041480325491,-0.14100761003222884,53.191489361702125,0.10958440144018806,36.71823971597871
+25,35,1.003,20,0.7,20,1.8,10,28.591224018475753,0.1016005437735,0.5513791178692674,1.0080758451675478,-0.15146552282378378,52.51215559157212,0.11211178171789443,36.45551012709165
+30,35,1.003,20,0.7,20,1.8,10,25.727482678983833,0.18578832195305228,0.605655728382827,1.009086725328753,-0.14419558548990996,52.792792792792795,0.10892181625852113,36.44028749464516
+25,35,1.002,20,0.7,20,1.8,10,29.006928406466514,0.10256830433725653,0.5282295534328566,1.0027471444959788,-0.15988767729773334,52.715654952076676,0.1118017609293678,36.287045140998245
+25,35,1.001,20,0.7,20,1.8,10,29.2378752886836,0.11536649769091216,0.5496351986605852,1.00064602431321,-0.16339252616069766,52.6148969889065,0.11165543931577554,36.15470013105196
+30,35,1.002,25,0.7,15,1.8,10,28.36027713625866,0.12792743440538384,0.5672779579799168,0.9938598341780486,-0.17086279350764333,52.450980392156865,0.10873123436621306,35.65749985644251
+30,35,1.003,25,0.7,15,1.8,10,27.89838337182448,0.1243649799618516,0.5741065784935555,0.9603701210903739,-0.2163111451848867,52.32558139534884,0.10616993393352159,34.208253095950894

+ 368 - 0
trend-quality-evaluator/optimize_parameters.py

@@ -0,0 +1,368 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+趋势质量评估器 - 参数优化测试
+测试不同参数组合的回测表现,寻找最优配置
+"""
+
+import sys
+sys.path.insert(0, '/root/.openclaw/workspace/trend-quality-evaluator')
+
+import numpy as np
+import pandas as pd
+from trend_quality_evaluator import fetch_stock_data
+from dataclasses import dataclass
+from typing import List, Tuple
+import itertools
+import warnings
+warnings.filterwarnings('ignore')
+
+print("="*70)
+print("趋势质量评估器 - 参数优化测试")
+print("="*70)
+
+# 获取数据
+df = fetch_stock_data("399673", "2017-01-01", "2026-03-06", "d")
+if df is None:
+    print("数据获取失败")
+    exit(1)
+
+print(f"\n✓ 数据获取成功: {len(df)}条")
+print(f"  日期范围: {df.index[0].date()} ~ {df.index[-1].date()}")
+
+# 定义参数搜索空间
+param_grid = {
+    'adx_threshold': [20, 25, 30],           # ADX阈值
+    'adx_weight': [25, 30, 35],              # ADX权重
+    'ma_slope_threshold': [1.001, 1.002, 1.003],  # 均线斜率阈值
+    'ma_slope_weight': [20, 25, 30],         # 均线斜率权重
+    'volatility_threshold': [0.7, 0.8, 0.9], # 波动率比率阈值
+    'volatility_weight': [15, 20, 25],       # 波动率权重
+    'volume_threshold': [1.3, 1.5, 1.8],     # 成交量阈值
+    'volume_weight': [8, 10, 12],            # 成交量权重
+}
+
+# 总权重必须是100
+@dataclass
+class StrategyConfig:
+    """策略配置"""
+    adx_threshold: float
+    adx_weight: int
+    ma_slope_threshold: float
+    ma_slope_weight: int
+    volatility_threshold: float
+    volatility_weight: int
+    volume_threshold: float
+    volume_weight: int
+    timeframe_weight: int = 15  # 固定15分
+    
+    @property
+    def total_weight(self) -> int:
+        return self.adx_weight + self.ma_slope_weight + self.volatility_weight + self.volume_weight + self.timeframe_weight
+    
+    @property
+    def trade_threshold(self) -> int:
+        return 60  # 固定60分阈值
+
+
+def calculate_indicators(df: pd.DataFrame) -> pd.DataFrame:
+    """预计算所有技术指标"""
+    data = df.copy()
+    
+    # ADX
+    high, low, close = data['high'], data['low'], data['close']
+    plus_dm = high.diff()
+    minus_dm = low.diff().abs()
+    plus_dm = plus_dm.where((plus_dm > minus_dm) & (plus_dm > 0), 0)
+    minus_dm = minus_dm.where((minus_dm > plus_dm) & (minus_dm > 0), 0)
+    
+    tr1 = high - low
+    tr2 = (high - close.shift()).abs()
+    tr3 = (low - close.shift()).abs()
+    tr = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
+    atr = tr.rolling(14).mean()
+    
+    plus_di = 100 * (plus_dm.rolling(14).mean() / atr)
+    minus_di = 100 * (minus_dm.rolling(14).mean() / atr)
+    dx = (abs(plus_di - minus_di) / (plus_di + minus_di + 1e-10)) * 100
+    data['adx'] = dx.rolling(14).mean()
+    
+    # MA20斜率
+    data['ma20'] = data['close'].rolling(20).mean()
+    data['ma20_slope'] = data['ma20'] / data['ma20'].shift(5)
+    
+    # ATR比率
+    data['atr14'] = tr.rolling(14).mean()
+    data['atr50'] = tr.rolling(50).mean()
+    data['atr_ratio'] = data['atr14'] / data['atr50']
+    
+    # 成交量
+    data['volume_ma20'] = data['volume'].rolling(20).mean()
+    data['volume_ratio'] = data['volume'] / data['volume_ma20']
+    
+    # 日线突破
+    data['price_above_ma20'] = data['close'] > data['ma20']
+    
+    return data
+
+
+def evaluate_strategy(data: pd.DataFrame, config: StrategyConfig) -> dict:
+    """
+    评估策略配置
+    返回各项绩效指标
+    """
+    scores = []
+    
+    # 从第60天开始(需要足够数据计算MA60)
+    for i in range(60, len(data)):
+        row = data.iloc[i]
+        
+        # 计算各因子得分
+        # 1. ADX得分
+        if row['adx'] >= config.adx_threshold:
+            adx_score = config.adx_weight
+        else:
+            adx_score = config.adx_weight * (row['adx'] / config.adx_threshold)
+        
+        # 2. 均线斜率得分
+        if row['ma20_slope'] >= config.ma_slope_threshold * 1.5:
+            ma_score = config.ma_slope_weight
+        elif row['ma20_slope'] >= config.ma_slope_threshold:
+            ma_score = config.ma_slope_weight * 0.7
+        elif row['ma20_slope'] >= 1.0:
+            ma_score = config.ma_slope_weight * 0.3
+        else:
+            ma_score = 0
+        
+        # 3. 波动率得分
+        if row['atr_ratio'] <= config.volatility_threshold * 0.75:
+            vol_score = config.volatility_weight
+        elif row['atr_ratio'] <= config.volatility_threshold:
+            vol_score = config.volatility_weight * 0.7
+        elif row['atr_ratio'] <= 1.0:
+            vol_score = config.volatility_weight * 0.3
+        else:
+            vol_score = 0
+        
+        # 4. 成交量得分
+        if row['volume_ratio'] >= config.volume_threshold * 1.3:
+            vol_score_trade = config.volume_weight
+        elif row['volume_ratio'] >= config.volume_threshold:
+            vol_score_trade = config.volume_weight * 0.7
+        elif row['volume_ratio'] >= 1.0:
+            vol_score_trade = config.volume_weight * 0.3
+        else:
+            vol_score_trade = 0
+        
+        # 5. 时间框架得分(简化版:价格突破MA20)
+        tf_score = config.timeframe_weight if row['price_above_ma20'] else 0
+        
+        total_score = adx_score + ma_score + vol_score + vol_score_trade + tf_score
+        is_tradeable = total_score >= config.trade_threshold
+        
+        scores.append({
+            'date': data.index[i],
+            'close': row['close'],
+            'total_score': total_score,
+            'is_tradeable': is_tradeable,
+            'adx': row['adx'],
+            'ma20_slope': row['ma20_slope'],
+            'atr_ratio': row['atr_ratio'],
+            'volume_ratio': row['volume_ratio']
+        })
+    
+    scores_df = pd.DataFrame(scores)
+    scores_df = scores_df.set_index('date')
+    
+    # 计算未来收益
+    scores_df['future_5d_return'] = scores_df['close'].pct_change(5).shift(-5) * 100
+    scores_df['future_10d_return'] = scores_df['close'].pct_change(10).shift(-10) * 100
+    scores_df['future_20d_return'] = scores_df['close'].pct_change(20).shift(-20) * 100
+    
+    # 计算绩效指标
+    t_mask = scores_df['is_tradeable']
+    total_days = len(scores_df)
+    tradeable_days = t_mask.sum()
+    
+    if tradeable_days == 0:
+        return None
+    
+    returns_5d = scores_df[t_mask]['future_5d_return'].dropna()
+    returns_10d = scores_df[t_mask]['future_10d_return'].dropna()
+    returns_20d = scores_df[t_mask]['future_20d_return'].dropna()
+    
+    results = {
+        'config': config,
+        'total_days': total_days,
+        'tradeable_days': tradeable_days,
+        'tradeable_pct': tradeable_days / total_days * 100,
+        'avg_score': scores_df['total_score'].mean(),
+        'return_5d': returns_5d.mean() if len(returns_5d) > 0 else 0,
+        'return_10d': returns_10d.mean() if len(returns_10d) > 0 else 0,
+        'return_20d': returns_20d.mean() if len(returns_20d) > 0 else 0,
+        'win_rate_20d': (returns_20d > 0).mean() * 100 if len(returns_20d) > 0 else 0,
+        'sharpe_20d': returns_20d.mean() / returns_20d.std() if len(returns_20d) > 0 and returns_20d.std() > 0 else 0,
+        'excess_return_20d': returns_20d.mean() - scores_df[~t_mask]['future_20d_return'].mean() if len(returns_20d) > 0 else 0,
+        'scores_df': scores_df
+    }
+    
+    return results
+
+
+# 预计算指标
+print("\n预计算技术指标...")
+data = calculate_indicators(df)
+print("✓ 指标计算完成")
+
+# 生成参数组合(只测试权重和为100的组合)
+print("\n生成参数组合...")
+valid_configs = []
+
+for adx_t, adx_w, ma_t, ma_w, vol_t, vol_w, volu_t, volu_w in itertools.product(
+    param_grid['adx_threshold'],
+    param_grid['adx_weight'],
+    param_grid['ma_slope_threshold'],
+    param_grid['ma_slope_weight'],
+    param_grid['volatility_threshold'],
+    param_grid['volatility_weight'],
+    param_grid['volume_threshold'],
+    param_grid['volume_weight']
+):
+    config = StrategyConfig(
+        adx_threshold=adx_t,
+        adx_weight=adx_w,
+        ma_slope_threshold=ma_t,
+        ma_slope_weight=ma_w,
+        volatility_threshold=vol_t,
+        volatility_weight=vol_w,
+        volume_threshold=volu_t,
+        volume_weight=volu_w
+    )
+    
+    if config.total_weight == 100:  # 只保留权重和为100的组合
+        valid_configs.append(config)
+
+print(f"✓ 有效参数组合: {len(valid_configs)}个")
+
+# 运行回测
+print(f"\n开始回测 ({len(valid_configs)}个组合)...")
+print("-"*70)
+
+all_results = []
+for i, config in enumerate(valid_configs):
+    result = evaluate_strategy(data, config)
+    if result:
+        all_results.append(result)
+    
+    if (i + 1) % 50 == 0:
+        print(f"  进度: {i+1}/{len(valid_configs)} ({(i+1)/len(valid_configs)*100:.1f}%)")
+
+print(f"\n✓ 回测完成: {len(all_results)}个有效结果")
+
+# 排序并选择最佳配置
+print("\n" + "="*70)
+print("参数优化结果")
+print("="*70)
+
+# 按不同目标排序
+sort_by = [
+    ('20日收益', lambda r: r['return_20d'], True),
+    ('超额收益', lambda r: r['excess_return_20d'], True),
+    ('胜率', lambda r: r['win_rate_20d'], True),
+    ('夏普比率', lambda r: r['sharpe_20d'], True),
+]
+
+best_configs = {}
+for name, key_func, reverse in sort_by:
+    sorted_results = sorted(all_results, key=key_func, reverse=reverse)
+    best_configs[name] = sorted_results[0]
+    
+    print(f"\n【最佳配置 - {name}】")
+    best = sorted_results[0]
+    print(f"  ADX阈值: {best['config'].adx_threshold}, 权重: {best['config'].adx_weight}")
+    print(f"  MA斜率阈值: {best['config'].ma_slope_threshold}, 权重: {best['config'].ma_slope_weight}")
+    print(f"  波动率阈值: {best['config'].volatility_threshold}, 权重: {best['config'].volatility_weight}")
+    print(f"  成交量阈值: {best['config'].volume_threshold}, 权重: {best['config'].volume_weight}")
+    print(f"  时间框架权重: {best['config'].timeframe_weight}")
+    print(f"\n  绩效指标:")
+    print(f"    可交易比例: {best['tradeable_pct']:.1f}%")
+    print(f"    5日收益: {best['return_5d']:+.2f}%")
+    print(f"    10日收益: {best['return_10d']:+.2f}%")
+    print(f"    20日收益: {best['return_20d']:+.2f}%")
+    print(f"    超额收益: {best['excess_return_20d']:+.2f}%")
+    print(f"    胜率(20日): {best['win_rate_20d']:.1f}%")
+    print(f"    夏普比率: {best['sharpe_20d']:.2f}")
+
+# 综合评分最佳(平衡收益、胜率、夏普)
+print(f"\n【综合最佳配置】")
+print("-"*50)
+
+# 计算综合得分(标准化后加权)
+max_return = max(r['return_20d'] for r in all_results)
+max_winrate = max(r['win_rate_20d'] for r in all_results)
+max_sharpe = max(r['sharpe_20d'] for r in all_results)
+max_excess = max(r['excess_return_20d'] for r in all_results)
+
+for r in all_results:
+    # 综合得分 = 收益*0.3 + 超额*0.3 + 胜率*0.2 + 夏普*0.2
+    r['composite_score'] = (
+        (r['return_20d'] / max_return if max_return > 0 else 0) * 0.3 +
+        (r['excess_return_20d'] / max_excess if max_excess > 0 else 0) * 0.3 +
+        (r['win_rate_20d'] / max_winrate if max_winrate > 0 else 0) * 0.2 +
+        (r['sharpe_20d'] / max_sharpe if max_sharpe > 0 else 0) * 0.2
+    ) * 100
+
+best_composite = max(all_results, key=lambda r: r['composite_score'])
+
+print(f"  ADX阈值: {best_composite['config'].adx_threshold}, 权重: {best_composite['config'].adx_weight}")
+print(f"  MA斜率阈值: {best_composite['config'].ma_slope_threshold}, 权重: {best_composite['config'].ma_slope_weight}")
+print(f"  波动率阈值: {best_composite['config'].volatility_threshold}, 权重: {best_composite['config'].volatility_weight}")
+print(f"  成交量阈值: {best_composite['config'].volume_threshold}, 权重: {best_composite['config'].volume_weight}")
+print(f"\n  绩效指标:")
+print(f"    可交易比例: {best_composite['tradeable_pct']:.1f}%")
+print(f"    5日收益: {best_composite['return_5d']:+.2f}%")
+print(f"    10日收益: {best_composite['return_10d']:+.2f}%")
+print(f"    20日收益: {best_composite['return_20d']:+.2f}%")
+print(f"    超额收益: {best_composite['excess_return_20d']:+.2f}%")
+print(f"    胜率(20日): {best_composite['win_rate_20d']:.1f}%")
+print(f"    夏普比率: {best_composite['sharpe_20d']:.2f}")
+print(f"    综合得分: {best_composite['composite_score']:.1f}")
+
+# 保存结果
+print("\n" + "="*70)
+print("保存结果...")
+
+results_summary = []
+for r in all_results:
+    results_summary.append({
+        'adx_threshold': r['config'].adx_threshold,
+        'adx_weight': r['config'].adx_weight,
+        'ma_slope_threshold': r['config'].ma_slope_threshold,
+        'ma_slope_weight': r['config'].ma_slope_weight,
+        'volatility_threshold': r['config'].volatility_threshold,
+        'volatility_weight': r['config'].volatility_weight,
+        'volume_threshold': r['config'].volume_threshold,
+        'volume_weight': r['config'].volume_weight,
+        'tradeable_pct': r['tradeable_pct'],
+        'return_5d': r['return_5d'],
+        'return_10d': r['return_10d'],
+        'return_20d': r['return_20d'],
+        'excess_return_20d': r['excess_return_20d'],
+        'win_rate_20d': r['win_rate_20d'],
+        'sharpe_20d': r['sharpe_20d'],
+        'composite_score': r['composite_score']
+    })
+
+results_df = pd.DataFrame(results_summary)
+results_df = results_df.sort_values('composite_score', ascending=False)
+results_df.to_csv('/root/.openclaw/workspace/trend-quality-evaluator/optimization_results.csv', index=False)
+
+# 保存最佳配置详情
+best_composite['scores_df'].to_csv('/root/.openclaw/workspace/trend-quality-evaluator/best_config_backtest.csv')
+
+print("✓ 优化结果已保存: optimization_results.csv")
+print("✓ 最佳配置回测详情: best_config_backtest.csv")
+
+print("\n" + "="*70)
+print("参数优化测试完成!")
+print("="*70)

+ 9 - 0
trend-quality-evaluator/param_optimization_results.csv

@@ -0,0 +1,9 @@
+name,adx_t,adx_w,ma_t,ma_w,vol_t,vol_w,volu_t,volu_w,trade_pct,avg_score,ret_20d,win_rate,sharpe
+原配置,25,30,1.002,25,0.8,20,1.5,10,40.70321811680572,47.407718860343316,3.1967278907747194,61.58357771260997,0.3395518262908878
+高ADX权重,25,35,1.002,20,0.8,20,1.5,10,42.01430274135876,49.800165448310736,3.1702252768447283,61.50568181818182,0.33902154073779456
+高MA权重,25,25,1.002,30,0.8,20,1.5,10,39.7497020262217,45.015272272375874,3.1534993103078,61.56156156156156,0.3367947313886168
+宽松波动率,25,30,1.002,25,0.9,20,1.5,10,43.4445768772348,49.35289168513473,3.145568167006351,61.53846153846154,0.338054673744046
+严格成交量,25,30,1.002,25,0.8,15,2.0,15,39.45172824791419,46.87732553495594,3.1151085679989015,61.17824773413897,0.32885246562076004
+综合优化2,20,35,1.003,25,0.8,15,2.0,10,43.3253873659118,52.5689736719791,2.992371035317209,60.74380165289256,0.3191922035207343
+低ADX阈值,20,30,1.002,25,0.8,20,1.5,10,42.19308700834327,49.4834349505777,2.9628928189242223,60.396039603960396,0.3144661580242694
+综合优化1,22,32,1.001,28,0.85,18,1.8,12,44.75566150178784,52.283595464643604,2.844091773403937,59.813084112149525,0.3033519660406973