{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "782ec73f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "初始化数据管理器...\n",
      "数据加载成功: /mnt/d/PyProject/NewQuant/data/data/KQ_m@SHFE_rb/KQ_m@SHFE_rb_min60.csv\n",
      "数据范围从 2021-12-31 14:00:00 到 2025-06-20 21:00:00\n",
      "总计 5811 条记录。\n",
      "\n",
      "--- 开始网格搜索回测 ---\n",
      "总计 1 种参数组合需要回测。\n"
     ]
    }
   ],
   "source": [
    "from datetime import datetime\n",
    "import itertools\n",
    "import pandas as pd # 导入pandas用于结果存储和展示\n",
    "\n",
    "# 导入所有必要的模块\n",
    "from src.analysis.grid_search_analyzer import GridSearchAnalyzer\n",
    "from src.analysis.result_analyzer import ResultAnalyzer\n",
    "from src.common_utils import generate_parameter_range\n",
    "from src.data_manager import DataManager\n",
    "from src.backtest_engine import BacktestEngine\n",
    "from src.strategies.SimpleLimitBuyStrategy import SimpleLimitBuyStrategyShort, SimpleLimitBuyStrategyLong\n",
    "\n",
    "# 确保 autoreload 启用\n",
    "%load_ext autoreload\n",
    "%autoreload 2\n",
    "\n",
    "# --- 全局配置 ---\n",
    "data_file_path = \"/mnt/d/PyProject/NewQuant/data/data/KQ_m@SHFE_rb/KQ_m@SHFE_rb_min60.csv\"\n",
    "initial_capital = 100000.0\n",
    "slippage_rate = 0.0001\n",
    "commission_rate = 0.0002\n",
    "global_config = {\n",
    "    'symbol': 'KQ_m@SHFE_rb',\n",
    "}\n",
    "# --- 定义参数网格 ---\n",
    "# 为策略参数定义一个字典，每个键对应一个参数，值是一个列表，包含所有要尝试的可能值\n",
    "# 这些参数名必须与 SimpleLimitBuyStrategyShort 的 __init__ 方法中接收的参数名一致\n",
    "param1_name = \"open_range_factor_1_ago\"\n",
    "param1_values = generate_parameter_range(start=-2, end=-2, step=0.1)\n",
    "param2_name = \"open_range_factor_7_ago\"\n",
    "param2_values = generate_parameter_range(start=-2, end=-2, step=0.1)\n",
    "optimization_metric = 'sharpe_ratio'\n",
    "# 存储所有回测的结果\n",
    "all_results = []\n",
    "grid_results = []\n",
    "\n",
    "# --- 1. 初始化数据管理器 (只需要一次) ---\n",
    "print(\"初始化数据管理器...\")\n",
    "data_manager = DataManager(file_path=data_file_path, symbol=global_config['symbol'])\n",
    "# --- 2. 遍历参数组合并运行回测 ---\n",
    "\n",
    "print(\"\\n--- 开始网格搜索回测 ---\")\n",
    "\n",
    "current_combination_idx = 0\n",
    "param_combinations = list(itertools.product(param1_values, param2_values))\n",
    "total_combinations = len(param_combinations)\n",
    "print(f\"总计 {total_combinations} 种参数组合需要回测。\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "db55a49d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "--- 正在运行组合 1/1: {'trade_volume': 1, 'open_range_factor_1_ago': -2, 'open_range_factor_7_ago': -2, 'max_position': 10, 'enable_log': False} ---\n",
      "DataManager 已重置。\n",
      "模拟器初始化：初始资金=100000.00, 滑点率=0.0001, 佣金率=0.0002\n",
      "\n",
      "--- 回测引擎初始化完成 ---\n",
      "  策略: SimpleLimitBuyStrategyShort\n",
      "  初始资金: 100000.00\n",
      "  换月模式: 启用\n",
      "\n",
      "--- 回测开始 ---\n",
      "SimpleLimitBuyStrategyShort 策略初始化回调被调用。\n",
      "开始将 DataFrame 转换为 Bar 对象流...\n",
      "到达结束时间 2025-01-01 00:00:00，回测终止。\n",
      "\n",
      "--- 回测结束，检查并平仓所有剩余持仓 ---\n",
      "--- 回测结束 ---\n",
      "总计处理了 5044 根K线。\n",
      "总计发生了 586 笔交易。\n",
      "最终总净值: -79.78\n",
      "总收益率: -100.08%\n",
      "\n",
      "--- 结果分析器初始化完成 ---\n",
      "正在计算绩效指标...\n",
      "total_return: -1.000797761896799, annualized_return:-9999999, 252 / total_days:0.23076923076923078\n",
      "绩效指标计算完成。\n",
      "{'初始资金': 100000.0, '最终资金': np.float64(-79.77618967989383), '总收益率': np.float64(-1.000797761896799), '年化收益率': -9999999, '最大回撤': np.float64(1.000797761896799), '夏普比率': -10, '卡玛比率': np.float64(-9992027.740996474), '总交易次数': 586, '交易成本': 555.88858968, '总实现盈亏': -49761.943799999965, '胜率': 0.0, '盈亏比': 0.0, '盈利交易次数': 0, '亏损交易次数': 293, '平均每次盈利': 0.0, '平均每次亏损': -169.83598566552888, 'initial_capital': 100000.0, 'final_capital': np.float64(-79.77618967989383), 'total_return': np.float64(-1.000797761896799), 'annualized_return': -9999999, 'max_drawdown': np.float64(1.000797761896799), 'sharpe_ratio': -10, 'calmar_ratio': np.float64(-9992027.740996474), 'total_trades': 586, 'transaction_costs': 555.88858968, 'total_realized_pnl': -49761.943799999965, 'win_rate': 0.0, 'profit_loss_ratio': 0.0, 'winning_trades_count': 0, 'losing_trades_count': 293, 'avg_profit_per_trade': 0.0, 'avg_loss_per_trade': -169.83598566552888}\n",
      "\n",
      "--- 网格搜索回测完毕 ---\n"
     ]
    }
   ],
   "source": [
    "\n",
    "# --- 4. 执行网格搜索循环 ---\n",
    "for idx, (p1_value, p2_value) in enumerate(param_combinations):\n",
    "    current_combination_idx += 1\n",
    "    \n",
    "    # 在网格搜索时通常关闭策略内部的详细日志，只保留关键信息\n",
    "    strategy_parameters = {\n",
    "        # 'symbol': \"SHFE_rb2501\",  # 根据您的数据文件中的品种名称调整\n",
    "        'trade_volume': 1,\n",
    "        'open_range_factor_1_ago': p1_value,  # 示例值，需要通过网格搜索优化\n",
    "        'open_range_factor_7_ago': p2_value,  # 示例值\n",
    "        'max_position': 10,\n",
    "        'enable_log': False\n",
    "    }\n",
    "    \n",
    "    print(f\"\\n--- 正在运行组合 {current_combination_idx}/{total_combinations}: {strategy_parameters} ---\")\n",
    "    # 每次回测前，需要重置数据管理器和模拟器状态\n",
    "    data_manager.reset() # 确保每次回测都从数据的起点开始\n",
    "    # 注意：BacktestEngine 的 __init__ 会创建新的 ExecutionSimulator 实例，所以不用单独重置 simulator\n",
    "    # 初始化回测引擎\n",
    "    engine = BacktestEngine(\n",
    "        data_manager=data_manager,\n",
    "        strategy_class=SimpleLimitBuyStrategyShort,\n",
    "        strategy_params=strategy_parameters,\n",
    "        initial_capital=initial_capital,\n",
    "        slippage_rate=slippage_rate,\n",
    "        commission_rate=commission_rate,\n",
    "        roll_over_mode=True, # 保持换月模式\n",
    "        start_time=datetime(2022, 1, 1),\n",
    "        end_time=datetime(2025, 1, 1)\n",
    "    )\n",
    "    # 运行回测\n",
    "    engine.run_backtest()\n",
    "    # --- 3. 获取回测结果并分析 ---\n",
    "    results = engine.get_backtest_results()\n",
    "    portfolio_snapshots = results[\"portfolio_snapshots\"]\n",
    "    trade_history = results[\"trade_history\"]\n",
    "    initial_capital_result = results[\"initial_capital\"]\n",
    "    bars = results[\"all_bars\"]\n",
    "    if portfolio_snapshots:\n",
    "        analyzer = ResultAnalyzer(portfolio_snapshots, trade_history, bars, initial_capital_result)\n",
    "        metrics = analyzer.calculate_all_metrics()\n",
    "\n",
    "        print(metrics)\n",
    "        \n",
    "        # 将当前组合的参数和性能指标存储起来\n",
    "        result_entry = {**strategy_parameters, **metrics}\n",
    "        all_results.append(result_entry)\n",
    "        grid_results.append(\n",
    "            {\n",
    "                param1_name: p1_value,\n",
    "                param2_name: p2_value,\n",
    "                optimization_metric: metrics.get(optimization_metric, 0.0),\n",
    "            }\n",
    "        )\n",
    "        \n",
    "    #     # 可以选择性地打印每个组合的关键指标\n",
    "    #     print(f\"  组合 {current_combination_idx} 结果:\")\n",
    "    #     print(f\"    总收益率: {metrics.get('total_return', 0):.2f}%\")\n",
    "    #     # print(f\"    年化收益率: {metrics.get('annualized_return', 0):.2f}%\")\n",
    "    #     print(f\"    夏普比率: {metrics.get('sharpe_ratio', 0):.2f}\")\n",
    "    #     print(f\"    最大回撤: {metrics.get('max_drawdown', 0):.2f}%\")\n",
    "    # else:\n",
    "    #     print(f\"  组合 {strategy_parameters} 没有生成投资组合快照，无法进行结果分析。\")\n",
    "    #     result_entry = {**strategy_parameters, \"total_return_percentage\": 0, \"annualized_return\": 0, \"sharpe_ratio\": 0, \"max_drawdown\": 0} # 记录失败组合\n",
    "    #     all_results.append(result_entry) # 依然加入结果列表，以便追踪\n",
    "print(\"\\n--- 网格搜索回测完毕 ---\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "f1d9c77a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "--- 所有回测结果汇总 ---\n",
      "   trade_volume  open_range_factor_1_ago  open_range_factor_7_ago  \\\n",
      "0             1                       -2                       -2   \n",
      "\n",
      "   max_position  enable_log      初始资金   最终资金  总收益率    年化收益率  最大回撤  ...  \\\n",
      "0            10       False  100000.0 -79.78  -1.0 -9999999   1.0  ...   \n",
      "\n",
      "   calmar_ratio  total_trades  transaction_costs  total_realized_pnl  \\\n",
      "0   -9992027.74           586             555.89           -49761.94   \n",
      "\n",
      "   win_rate  profit_loss_ratio  winning_trades_count  losing_trades_count  \\\n",
      "0       0.0                0.0                     0                  293   \n",
      "\n",
      "   avg_profit_per_trade  avg_loss_per_trade  \n",
      "0                   0.0             -169.84  \n",
      "\n",
      "[1 rows x 37 columns]\n",
      "\n",
      "--- 动态网格搜索完成 ---\n",
      "[{'open_range_factor_1_ago': -2, 'open_range_factor_7_ago': -2, 'sharpe_ratio': -10}]\n",
      "\n",
      "--- 最佳参数组合 ---\n",
      "  open_range_factor_1_ago: -2\n",
      "  open_range_factor_7_ago: -2\n",
      "  sharpe_ratio: -10.0000\n",
      "[-2, -2, -2, -2]\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/mnt/d/PyProject/NewQuant/src/analysis/grid_search_analyzer.py:70: UserWarning: Attempting to set identical low and high xlims makes transformation singular; automatically expanding.\n",
      "  im = ax.imshow(heatmap_matrix, cmap='viridis', origin='lower',\n",
      "/mnt/d/PyProject/NewQuant/src/analysis/grid_search_analyzer.py:70: UserWarning: Attempting to set identical low and high ylims makes transformation singular; automatically expanding.\n",
      "  im = ax.imshow(heatmap_matrix, cmap='viridis', origin='lower',\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 46720 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "# --- 4. 汇总并报告最优结果 ---\n",
    "if all_results:\n",
    "    results_df = pd.DataFrame(all_results)\n",
    "    print(\"\\n--- 所有回测结果汇总 ---\")\n",
    "    print(results_df.round(2)) # 打印所有组合的结果，保留两位小数\n",
    "\n",
    "    # 根据某个指标（例如夏普比率）找到最优参数组合\n",
    "    # 确保 DataFrame 不为空且有 sharpe_ratio 列\n",
    "    if not results_df.empty and 'sharpe_ratio' in results_df.columns:\n",
    "        # 过滤掉NaN值，如果所有夏普比率都是NaN，则可能没有有效结果\n",
    "        normal_results = results_df[(results_df['total_trades'] > 200) & (results_df['total_return'] > 0)]\n",
    "        if len(normal_results) > 0:\n",
    "            best_result = normal_results.loc[(normal_results['sharpe_ratio'].idxmax())]\n",
    "            print(\"\\n--- 最优参数组合 (按夏普比率) ---\")\n",
    "            print(best_result)\n",
    "    else:\n",
    "        print(\"\\n没有有效的回测结果可用于找出最优参数。\")\n",
    "else:\n",
    "    print(\"\\n没有执行任何回测。\")\n",
    "print(\"\\n--- 动态网格搜索完成 ---\")\n",
    "# --- 5. 使用新的 GridSearchAnalyzer 分析和可视化结果 ---\n",
    "print(grid_results)\n",
    "if grid_results:\n",
    "    grid_analyzer = GridSearchAnalyzer(grid_results, optimization_metric)\n",
    "    grid_analyzer.find_best_parameters()\n",
    "    grid_analyzer.plot_heatmap()\n",
    "else:\n",
    "    print(\"\\n没有生成任何网格搜索结果，无法进行分析。\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "quant",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
