{
 "cells": [
  {
   "cell_type": "code",
   "id": "b385d20c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-22T15:51:22.842778Z",
     "start_time": "2025-06-22T15:51:22.809938Z"
    }
   },
   "source": [
    "# grid_search_dynamic_notebook.ipynb\n",
    "\n",
    "%load_ext autoreload\n",
    "%autoreload 2\n",
    "# 导入必要的库和模块\n",
    "import pandas as pd\n",
    "from datetime import datetime\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import itertools\n",
    "from typing import Dict, Any, List, Type\n",
    "\n",
    "# 导入 src 和 research 目录中的功能\n",
    "from src.backtest_runner import run_backtest_for_optimization  # 导入简化的回测入口\n",
    "from src.analysis.result_analyzer import (\n",
    "    ResultAnalyzer,\n",
    ")  # 仍然需要用于单个回测结果的详细分析\n",
    "from src.strategies.SimpleLimitBuyStrategy import SimpleLimitBuyStrategy\n",
    "from src.analysis.grid_search_analyzer import (\n",
    "    GridSearchAnalyzer,\n",
    ")  # 导入新的网格搜索分析器\n",
    "from src.common_utils import generate_parameter_range  # 导入参数范围生成器\n",
    "\n",
    "print(\"--- Jupyter Notebook: 动态参数网格搜索回测 ---\")\n",
    "\n",
    "# --- 1. 定义全局回测配置 ---\n",
    "GLOBAL_CONFIG = {\n",
    "    \"total_start_date\": datetime(2024, 5, 1, 0, 0, 0),\n",
    "    \"total_end_date\": datetime(2024, 12, 1, 0, 0, 0),\n",
    "    \"initial_capital\": 100000.0,\n",
    "    \"slippage_rate\": 0.000,\n",
    "    \"commission_rate\": 0.0000,\n",
    "    \"segment_configs\": {\n",
    "        \"rb2410\": {\n",
    "            \"file\": \"/mnt/d/PyProject/NewQuant/data/data/SHFE_rb2410/SHFE_rb2410_min60.csv\",\n",
    "            \"start\": datetime(2024, 5, 1),\n",
    "            \"end\": datetime(\n",
    "                2024, 9, 1, 0, 0, 0\n",
    "            ),  # 2024-09-15 切换到 rb2505，所以 rb2501 运行到 9-14 结束\n",
    "        },\n",
    "        \"rb2501\": {\n",
    "            \"file\": \"/mnt/d/PyProject/NewQuant/data/data/SHFE_rb2501/SHFE_rb2501_min60.csv\",\n",
    "            \"start\": datetime(2024, 9, 1),\n",
    "            \"end\": datetime(\n",
    "                2024, 12, 1, 0, 0, 0\n",
    "            ),  # 2024-09-15 切换到 rb2505，所以 rb2501 运行到 9-14 结束\n",
    "        },\n",
    "        # \"rb2505\": {\n",
    "        #     \"file\": \"/mnt/d/PyProject/NewQuant/data/data/SHFE_rb2505/SHFE_rb2505_min60.csv\",\n",
    "        #     \"start\": datetime(2024, 12, 1),\n",
    "        #     \"end\": datetime(2025, 4, 1, 0, 0, 0),  # rb2505 运行到总回测结束\n",
    "        # },\n",
    "    },\n",
    "}\n"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The autoreload extension is already loaded. To reload it, use:\n",
      "  %reload_ext autoreload\n",
      "--- Jupyter Notebook: 动态参数网格搜索回测 ---\n"
     ]
    }
   ],
   "execution_count": 44
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-22T15:51:23.021614Z",
     "start_time": "2025-06-22T15:51:22.865943Z"
    }
   },
   "cell_type": "code",
   "source": [
    "\n",
    "# --- 2. 定义策略基础参数 ---\n",
    "BASE_STRATEGY_PARAMS = {\n",
    "    \"trade_volume\": 1,\n",
    "    \"max_position\": 100,\n",
    "    \"enable_log\": False\n",
    "    # 'limit_price_factor': 会被动态生成并覆盖\n",
    "    # 'max_position': 会被动态生成并覆盖\n",
    "}\n",
    "\n",
    "# --- 3. 定义动态搜索空间 ---\n",
    "# 使用 generate_parameter_range 来定义参数的起始、结束和步长\n",
    "param1_name = \"open_range_factor_1_ago\"\n",
    "param1_values = generate_parameter_range(start=0, end=0, step=0.1)\n",
    "\n",
    "param2_name = \"open_range_factor_7_ago\"\n",
    "param2_values = generate_parameter_range(start=0, end=0, step=0.1)\n",
    "\n",
    "optimization_metric = \"SharpeRatio\"  # 优化目标指标\n",
    "\n",
    "print(f\"\\n--- 开始动态网格搜索 ---\")\n",
    "print(f\"参数1 '{param1_name}' 搜索范围: {param1_values}\")\n",
    "print(f\"参数2 '{param2_name}' 搜索范围: {param2_values}\")\n",
    "print(f\"优化目标: {optimization_metric}\")\n",
    "\n",
    "grid_results: List[Dict[str, Any]] = []\n",
    "param_combinations = list(itertools.product(param1_values, param2_values))\n",
    "total_combinations = len(param_combinations)\n",
    "print(f\"总计 {total_combinations} 种参数组合需要回测。\")\n",
    "\n",
    "# --- 4. 执行网格搜索循环 ---\n",
    "for idx, (p1_value, p2_value) in enumerate(param_combinations):\n",
    "    print(f\"\\n--- 运行回测：组合 {idx + 1}/{total_combinations} ---\")\n",
    "    print(f\"  {param1_name}: {p1_value}, {param2_name}: {p2_value}\")\n",
    "\n",
    "    current_strategy_params = BASE_STRATEGY_PARAMS.copy()\n",
    "    current_strategy_params[param1_name] = p1_value\n",
    "    current_strategy_params[param2_name] = p2_value\n",
    "\n",
    "    # 调用简化的回测入口\n",
    "    backtest_output = run_backtest_for_optimization(\n",
    "        global_config=GLOBAL_CONFIG,\n",
    "        strategy_class=SimpleLimitBuyStrategy,\n",
    "        current_strategy_params=current_strategy_params,\n",
    "    )\n",
    "\n",
    "    # 从回测结果中提取优化指标\n",
    "    metric_value = 0.0\n",
    "    if backtest_output[\"portfolio_snapshots\"]:\n",
    "        # 注意：这里我们仍然需要 ResultAnalyzer 来计算单个回测的指标\n",
    "        analyzer_for_this_run = ResultAnalyzer(\n",
    "            backtest_output[\"portfolio_snapshots\"],\n",
    "            backtest_output[\"trade_history\"],\n",
    "            backtest_output[\"all_bars\"],\n",
    "            backtest_output[\"initial_capital\"],\n",
    "        )\n",
    "        summary_metrics = analyzer_for_this_run.calculate_all_metrics()\n",
    "        metric_value = summary_metrics.get(optimization_metric, 0.0)\n",
    "\n",
    "    grid_results.append(\n",
    "        {\n",
    "            param1_name: p1_value,\n",
    "            param2_name: p2_value,\n",
    "            optimization_metric: metric_value,\n",
    "        }\n",
    "    )\n",
    "\n",
    "print(\"\\n--- 动态网格搜索完成 ---\")\n",
    "\n",
    "# --- 5. 使用新的 GridSearchAnalyzer 分析和可视化结果 ---\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没有生成任何网格搜索结果，无法进行分析。\")"
   ],
   "id": "d9fde4c77f3d8158",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "--- 开始动态网格搜索 ---\n",
      "参数1 'open_range_factor_1_ago' 搜索范围: [0]\n",
      "参数2 'open_range_factor_7_ago' 搜索范围: [0]\n",
      "优化目标: SharpeRatio\n",
      "总计 1 种参数组合需要回测。\n",
      "\n",
      "--- 运行回测：组合 1/1 ---\n",
      "  open_range_factor_1_ago: 0, open_range_factor_7_ago: 0\n",
      "\n",
      "--- 开始分段回测跨越多个合约 ---\n",
      "\n",
      "--- 回测片段: rb2410 从 2024-05-01 00:00 到 2024-09-01 00:00 ---\n",
      "数据加载成功: /mnt/d/PyProject/NewQuant/data/data/SHFE_rb2410/SHFE_rb2410_min60.csv\n",
      "数据范围从 2024-04-30 14:00:00 到 2024-08-30 21:00:00\n",
      "总计 586 条记录。\n",
      "模拟器初始化：初始资金=100000.00, 滑点率=0.0, 佣金率=0.0\n",
      "\n",
      "--- 回测引擎初始化完成 ---\n",
      "  策略: SimpleLimitBuyStrategy\n",
      "  初始资金: 100000.00\n",
      "ExecutionSimulator: 重置状态。\n",
      "\n",
      "--- 回测开始 ---\n",
      "SimpleLimitBuyStrategy 策略初始化回调被调用。\n",
      "开始将 DataFrame 转换为 Bar 对象流...\n",
      "Bar 对象流生成完毕。\n",
      "\n",
      "--- 回测片段结束，检查并平仓所有持仓 ---\n",
      "[2024-08-30 21:00:00] 回测结束平仓: 平仓 rb2410 (1 手) @ 3234.00。\n",
      "--- 回测结束 ---\n",
      "总计处理了 586 根K线。\n",
      "总计发生了 364 笔交易。\n",
      "最终总净值: 99776.00\n",
      "总收益率: -0.22%\n",
      "\n",
      "--- 回测片段: rb2501 从 2024-09-01 00:00 到 2024-12-01 00:00 ---\n",
      "数据加载成功: /mnt/d/PyProject/NewQuant/data/data/SHFE_rb2501/SHFE_rb2501_min60.csv\n",
      "数据范围从 2024-08-30 14:00:00 到 2024-11-29 21:00:00\n",
      "总计 404 条记录。\n",
      "模拟器初始化：初始资金=100000.00, 滑点率=0.0, 佣金率=0.0\n",
      "\n",
      "--- 回测引擎初始化完成 ---\n",
      "  策略: SimpleLimitBuyStrategy\n",
      "  初始资金: 100000.00\n",
      "ExecutionSimulator: 重置状态。\n",
      "\n",
      "--- 回测开始 ---\n",
      "SimpleLimitBuyStrategy 策略初始化回调被调用。\n",
      "开始将 DataFrame 转换为 Bar 对象流...\n",
      "Bar 对象流生成完毕。\n",
      "\n",
      "--- 回测片段结束，检查并平仓所有持仓 ---\n",
      "[2024-11-29 21:00:00] 回测结束平仓: 平仓 rb2501 (1 手) @ 3301.00。\n",
      "--- 回测结束 ---\n",
      "总计处理了 404 根K线。\n",
      "总计发生了 304 笔交易。\n",
      "最终总净值: 100023.00\n",
      "总收益率: 0.02%\n",
      "\n",
      "--- 总分段回测完成 ---\n",
      "\n",
      "--- 结果分析器初始化完成 ---\n",
      "正在计算绩效指标...\n",
      "绩效指标计算完成。\n",
      "\n",
      "--- 动态网格搜索完成 ---\n",
      "\n",
      "--- 最佳参数组合 ---\n",
      "  open_range_factor_1_ago: 0\n",
      "  open_range_factor_7_ago: 0\n",
      "  SharpeRatio: 0.0302\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/mnt/d/PyProject/NewQuant/src/analysis/grid_search_analyzer.py:69: 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:69: 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": {
      "text/plain": [
       "<Figure size 1000x800 with 2 Axes>"
      ],
      "image/png": "[encoded data, 45848 characters]"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 45
  }
 ],
 "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
}
