2025-11-07 16:37:16 +08:00
|
|
|
|
{
|
|
|
|
|
|
"cells": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
|
"id": "782ec73f",
|
|
|
|
|
|
"metadata": {
|
|
|
|
|
|
"ExecuteTime": {
|
2025-11-20 16:10:16 +08:00
|
|
|
|
"end_time": "2025-11-09T15:22:17.269305Z",
|
|
|
|
|
|
"start_time": "2025-11-09T15:22:17.246198Z"
|
2025-11-07 16:37:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"import sys\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"if '/mnt/d/PyProject/NewQuant/' not in sys.path:\n",
|
|
|
|
|
|
" sys.path.append('/mnt/d/PyProject/NewQuant/')\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"%load_ext autoreload\n",
|
|
|
|
|
|
"%autoreload 2\n",
|
|
|
|
|
|
"\n"
|
|
|
|
|
|
],
|
|
|
|
|
|
"outputs": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"name": "stdout",
|
|
|
|
|
|
"output_type": "stream",
|
|
|
|
|
|
"text": [
|
|
|
|
|
|
"The autoreload extension is already loaded. To reload it, use:\n",
|
|
|
|
|
|
" %reload_ext autoreload\n"
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
"execution_count": 7
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
|
"id": "298b8b26",
|
|
|
|
|
|
"metadata": {
|
|
|
|
|
|
"ExecuteTime": {
|
2025-11-20 16:10:16 +08:00
|
|
|
|
"end_time": "2025-11-09T15:22:17.288543Z",
|
|
|
|
|
|
"start_time": "2025-11-09T15:22:17.273214Z"
|
2025-11-07 16:37:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"import pandas as pd\n",
|
|
|
|
|
|
"from datetime import datetime\n",
|
|
|
|
|
|
"import itertools\n",
|
|
|
|
|
|
"from typing import Dict, Any, List, Tuple, Optional\n",
|
|
|
|
|
|
"import multiprocessing # 导入 multiprocessing 模块\n",
|
|
|
|
|
|
"import math # 保留 math 导入,因为您的策略内部可能需要用到数学函数\n",
|
|
|
|
|
|
"\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",
|
|
|
|
|
|
"# 导入策略类\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"import builtins\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"origin_print = print\n",
|
|
|
|
|
|
"\n"
|
|
|
|
|
|
],
|
|
|
|
|
|
"outputs": [],
|
|
|
|
|
|
"execution_count": 8
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
|
"id": "76f9a2e9",
|
|
|
|
|
|
"metadata": {
|
|
|
|
|
|
"ExecuteTime": {
|
2025-11-20 16:10:16 +08:00
|
|
|
|
"end_time": "2025-11-09T15:22:17.305734Z",
|
|
|
|
|
|
"start_time": "2025-11-09T15:22:17.291525Z"
|
2025-11-07 16:37:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# --- 单个回测任务函数 ---\n",
|
|
|
|
|
|
"# 这个函数将在每个独立的进程中运行,因此它必须是自包含的\n"
|
|
|
|
|
|
],
|
|
|
|
|
|
"outputs": [],
|
|
|
|
|
|
"execution_count": 9
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
|
"id": "c0984689",
|
|
|
|
|
|
"metadata": {
|
|
|
|
|
|
"ExecuteTime": {
|
2025-11-20 16:10:16 +08:00
|
|
|
|
"end_time": "2025-11-09T15:22:17.322796Z",
|
|
|
|
|
|
"start_time": "2025-11-09T15:22:17.308739Z"
|
2025-11-07 16:37:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"def slient_print(*args):\n",
|
|
|
|
|
|
" pass\n"
|
|
|
|
|
|
],
|
|
|
|
|
|
"outputs": [],
|
|
|
|
|
|
"execution_count": 10
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"metadata": {
|
|
|
|
|
|
"ExecuteTime": {
|
2025-11-20 16:10:16 +08:00
|
|
|
|
"end_time": "2025-11-09T15:29:57.347468Z",
|
|
|
|
|
|
"start_time": "2025-11-09T15:22:17.327802Z"
|
2025-11-07 16:37:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"from src.strategies.KalmanStrategy.utils import run_single_backtest\n",
|
2025-11-20 16:10:16 +08:00
|
|
|
|
"from src.strategies.KalmanStrategy.KalmanStrategy3 import DualModeKalmanStrategy\n",
|
2025-11-07 16:37:16 +08:00
|
|
|
|
"# --- 主执行块 ---\n",
|
|
|
|
|
|
"# 这是多进程代码的入口点,必须在 'if __name__ == \"__main__\":' 保护块中\n",
|
|
|
|
|
|
"# 确保 autoreload 启用 (在Jupyter Notebook中使用,纯Python脚本运行时可移除)\n",
|
|
|
|
|
|
"# %load_ext autoreload\n",
|
|
|
|
|
|
"# %autoreload 2\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"from src.strategies.ValueMigrationStrategy.ValueMigrationStrategy import ValueMigrationStrategy\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# --- 全局配置 ---\n",
|
2025-11-20 16:10:16 +08:00
|
|
|
|
"data_file_path = \"D:/PyProject/NewQuant/data/data/KQ_m@CZCE_SA/KQ_m@CZCE_SA_min15.csv\"\n",
|
2025-11-07 16:37:16 +08:00
|
|
|
|
"\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"initial_capital = 100000.0\n",
|
|
|
|
|
|
"slippage_rate = 0.0000\n",
|
|
|
|
|
|
"commission_rate = 0.0001\n",
|
|
|
|
|
|
"global_config = {\n",
|
2025-11-20 16:10:16 +08:00
|
|
|
|
" 'symbol': 'SA',\n",
|
2025-11-07 16:37:16 +08:00
|
|
|
|
"}\n",
|
|
|
|
|
|
"# 确保每个合约的tick_size在这里定义或获取\n",
|
|
|
|
|
|
"RB_TICK_SIZE = 1.0 # 螺纹钢的最小变动单位\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# --- 定义参数网格 ---\n",
|
|
|
|
|
|
"param1_name = \"kalman_measurement_noise\"\n",
|
|
|
|
|
|
"param1_values = generate_parameter_range(start=0.01, end=5.01, step=0.5)\n",
|
|
|
|
|
|
"param2_name = \"entry_threshold_atr\"\n",
|
|
|
|
|
|
"param2_values = generate_parameter_range(start=0.1, end=3.1, step=0.3)\n",
|
|
|
|
|
|
"optimization_metric = 'total_return'\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# 生成所有参数组合\n",
|
|
|
|
|
|
"param_combinations = list(itertools.product(param1_values, param2_values))\n",
|
|
|
|
|
|
"total_combinations = len(param_combinations)\n",
|
|
|
|
|
|
"print(f\"总计 {total_combinations} 种参数组合需要回测。\")\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"all_results: List[Dict[str, Any]] = []\n",
|
|
|
|
|
|
"grid_results: List[Dict[str, Any]] = []\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# 准备传递给每个子进程的公共配置字典\n",
|
|
|
|
|
|
"common_config_for_processes = {\n",
|
|
|
|
|
|
" 'main_symbol': global_config['symbol'],\n",
|
|
|
|
|
|
" 'symbol': global_config['symbol'],\n",
|
|
|
|
|
|
" 'data_path': data_file_path,\n",
|
|
|
|
|
|
" 'initial_capital': initial_capital,\n",
|
|
|
|
|
|
" 'slippage_rate': slippage_rate,\n",
|
|
|
|
|
|
" 'commission_rate': commission_rate,\n",
|
2025-11-20 16:10:16 +08:00
|
|
|
|
" 'start_time': datetime(2021, 1, 1), # 回测起始时间\n",
|
2025-11-07 16:37:16 +08:00
|
|
|
|
" 'end_time': datetime(2024, 1, 1), # 回测结束时间\n",
|
|
|
|
|
|
" 'roll_over_mode': True, # 保持换月模式\n",
|
|
|
|
|
|
" 'param1_name': param1_name,\n",
|
|
|
|
|
|
" 'param2_name': param2_name,\n",
|
|
|
|
|
|
" 'optimization_metric': optimization_metric,\n",
|
|
|
|
|
|
" 'strategy': DualModeKalmanStrategy,\n",
|
|
|
|
|
|
" 'order_direction': ['BUY', 'SELL'],\n",
|
|
|
|
|
|
" 'stop_loss_tick': 5,\n",
|
2025-11-20 16:10:16 +08:00
|
|
|
|
" 'strategy_mode': 'TREND'\n",
|
2025-11-07 16:37:16 +08:00
|
|
|
|
"}\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# 确定要使用的进程数量 (通常是CPU核心数)\n",
|
|
|
|
|
|
"num_processes = int(multiprocessing.cpu_count() * 0.6)\n",
|
|
|
|
|
|
"if num_processes < 1:\n",
|
|
|
|
|
|
" num_processes = 1\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"print(f\"--- 启动多进程网格搜索,使用 {num_processes} 个进程 ---\")\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# builtins.print = slient_print\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# 创建一个进程池\n",
|
|
|
|
|
|
"with multiprocessing.Pool(processes=num_processes) as pool:\n",
|
|
|
|
|
|
" # 准备 run_single_backtest 函数的参数列表\n",
|
|
|
|
|
|
" # starmap 需要一个可迭代对象,其中每个元素是传递给目标函数的参数元组\n",
|
|
|
|
|
|
" args_for_starmap = [\n",
|
|
|
|
|
|
" (combo, common_config_for_processes) for combo in param_combinations\n",
|
|
|
|
|
|
" ]\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
" # 使用 starmap() 来并行执行 run_single_backtest 函数\n",
|
|
|
|
|
|
" # starmap 是阻塞的,会等待所有任务完成并返回结果列表\n",
|
|
|
|
|
|
" for i, result_entry in enumerate(pool.starmap(run_single_backtest, args_for_starmap)):\n",
|
|
|
|
|
|
" if result_entry: # 确保结果不为空\n",
|
|
|
|
|
|
" all_results.append(result_entry)\n",
|
|
|
|
|
|
" # 仅将成功的(无错误的)结果添加到用于网格分析的列表中\n",
|
|
|
|
|
|
" if 'error' not in result_entry:\n",
|
|
|
|
|
|
" grid_results.append(\n",
|
|
|
|
|
|
" {\n",
|
|
|
|
|
|
" param1_name: result_entry.get(param1_name),\n",
|
|
|
|
|
|
" param2_name: result_entry.get(param2_name),\n",
|
|
|
|
|
|
" optimization_metric: result_entry.get(optimization_metric, 0.0),\n",
|
|
|
|
|
|
" }\n",
|
|
|
|
|
|
" )\n",
|
|
|
|
|
|
" else:\n",
|
|
|
|
|
|
" # 对于失败的组合,将其优化指标设置为一个特殊值,便于识别\n",
|
|
|
|
|
|
" grid_results.append(\n",
|
|
|
|
|
|
" {\n",
|
|
|
|
|
|
" param1_name: result_entry.get(param1_name),\n",
|
|
|
|
|
|
" param2_name: result_entry.get(param2_name),\n",
|
|
|
|
|
|
" optimization_metric: float('-inf'), # 用负无穷表示失败\n",
|
|
|
|
|
|
" 'error_mesMAge': result_entry['error']\n",
|
|
|
|
|
|
" }\n",
|
|
|
|
|
|
" )\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"builtins.print = origin_print\n",
|
|
|
|
|
|
"print(\"\\n--- 网格搜索回测完毕 ---\")"
|
|
|
|
|
|
],
|
|
|
|
|
|
"id": "a5f8ff3d084c2349",
|
|
|
|
|
|
"outputs": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"name": "stdout",
|
|
|
|
|
|
"output_type": "stream",
|
|
|
|
|
|
"text": [
|
|
|
|
|
|
"总计 121 种参数组合需要回测。\n",
|
|
|
|
|
|
"--- 启动多进程网格搜索,使用 12 个进程 ---\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"--- 网格搜索回测完毕 ---\n"
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
"execution_count": 11
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"metadata": {
|
|
|
|
|
|
"ExecuteTime": {
|
2025-11-20 16:10:16 +08:00
|
|
|
|
"end_time": "2025-11-09T15:29:57.681195Z",
|
|
|
|
|
|
"start_time": "2025-11-09T15:29:57.378952Z"
|
2025-11-07 16:37:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# --- 5. 后处理和最佳结果选择 ---\n",
|
|
|
|
|
|
"if all_results:\n",
|
|
|
|
|
|
" results_df = pd.DataFrame(all_results)\n",
|
|
|
|
|
|
" # print(\"\\n--- 所有回测结果汇总 ---\")\n",
|
|
|
|
|
|
" # # 确保打印时浮点数格式化\n",
|
|
|
|
|
|
" # pd.set_option('display.float_format', lambda x: '%.4f' % x)\n",
|
|
|
|
|
|
" # print(results_df.to_string())\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
" # 找到最佳组合 (排除有错误的)\n",
|
|
|
|
|
|
" # 过滤掉包含 'error' 键的行,或者 'error' 键的值不为空的行\n",
|
|
|
|
|
|
" # 同时确保优化指标是数值,并且不为无穷大\n",
|
|
|
|
|
|
" print(results_df.info())\n",
|
|
|
|
|
|
" successful_results_df = results_df[(pd.to_numeric(results_df[optimization_metric], errors='coerce').notna()) &\n",
|
|
|
|
|
|
" (pd.to_numeric(results_df[optimization_metric], errors='coerce') != float(\n",
|
|
|
|
|
|
" '-inf'))\n",
|
|
|
|
|
|
" ].copy() # 使用 .copy() 避免 SettingWithCopyWarning\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
" if not successful_results_df.empty and optimization_metric in successful_results_df.columns:\n",
|
|
|
|
|
|
" # 确保优化指标列是数值类型\n",
|
|
|
|
|
|
" successful_results_df[optimization_metric] = pd.to_numeric(successful_results_df[optimization_metric],\n",
|
|
|
|
|
|
" errors='coerce')\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
" if not successful_results_df.empty and optimization_metric in successful_results_df.columns:\n",
|
|
|
|
|
|
" # 过滤掉NaN值,如果所有夏普比率都是NaN,则可能没有有效结果\n",
|
|
|
|
|
|
" normal_results = successful_results_df[\n",
|
|
|
|
|
|
" (results_df['total_trades'] > 100)\n",
|
|
|
|
|
|
" # &\n",
|
|
|
|
|
|
" # (results_df['profit_factor'] < 3.)\n",
|
|
|
|
|
|
" ]\n",
|
|
|
|
|
|
" if len(normal_results) > 0:\n",
|
|
|
|
|
|
" best_result = normal_results.loc[(normal_results[optimization_metric].idxmax())]\n",
|
|
|
|
|
|
" print(f\"\\n--- 最优参数组合 (按{optimization_metric}) ---\")\n",
|
|
|
|
|
|
" print(best_result)\n",
|
|
|
|
|
|
" else:\n",
|
|
|
|
|
|
" print('ERROR!!!!!!!!!!!!!!!!!!!!')\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
" # 找到最大值的索引\n",
|
|
|
|
|
|
" # best_result = successful_results_df.loc[successful_results_df[optimization_metric].idxmax()]\n",
|
|
|
|
|
|
" # print(f\"\\n--- 最优参数组合 (按 {optimization_metric}) ---\")\n",
|
|
|
|
|
|
" # print(best_result)\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
" # 导出到CSV\n",
|
|
|
|
|
|
" output_filename = f\"grid_search_results_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv\"\n",
|
|
|
|
|
|
" # results_df.to_csv(output_filename, index=False, encoding='utf-8')\n",
|
|
|
|
|
|
" # print(f\"\\n所有结果已导出到: {output_filename}\")\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
" # 打印枢轴表\n",
|
|
|
|
|
|
" grid_df = pd.DataFrame(grid_results)\n",
|
|
|
|
|
|
" # 确保优化指标列是数值类型,非数值的(如 -inf)在pandas中可能被正确处理\n",
|
|
|
|
|
|
" grid_df[optimization_metric] = pd.to_numeric(grid_df[optimization_metric], errors='coerce')\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
" pivot_table = grid_df.pivot_table(\n",
|
|
|
|
|
|
" index=param1_name, columns=param2_name, values=optimization_metric\n",
|
|
|
|
|
|
" )\n",
|
|
|
|
|
|
" # print(f\"\\n{optimization_metric} 网格结果 (Pivoted):\")\n",
|
|
|
|
|
|
" # print(pivot_table.to_string())\n",
|
|
|
|
|
|
" else:\n",
|
|
|
|
|
|
" print(f\"\\n没有成功的组合结果可供分析,或优化指标 '{optimization_metric}' 不在结果中,或所有组合均失败。\")\n",
|
|
|
|
|
|
"else:\n",
|
|
|
|
|
|
" print(\"没有可用的回测结果。\")\n",
|
|
|
|
|
|
"print(\"\\n--- 动态网格搜索完成 ---\")\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# --- 6. 可视化 (依赖 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": "b6838275ff519227",
|
|
|
|
|
|
"outputs": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"name": "stdout",
|
|
|
|
|
|
"output_type": "stream",
|
|
|
|
|
|
"text": [
|
|
|
|
|
|
"<class 'pandas.core.frame.DataFrame'>\n",
|
|
|
|
|
|
"RangeIndex: 121 entries, 0 to 120\n",
|
|
|
|
|
|
"Data columns (total 40 columns):\n",
|
|
|
|
|
|
" # Column Non-Null Count Dtype \n",
|
|
|
|
|
|
"--- ------ -------------- ----- \n",
|
|
|
|
|
|
" 0 main_symbol 121 non-null object \n",
|
|
|
|
|
|
" 1 trade_volume 121 non-null int64 \n",
|
|
|
|
|
|
" 2 kalman_measurement_noise 121 non-null float64\n",
|
|
|
|
|
|
" 3 entry_threshold_atr 121 non-null float64\n",
|
|
|
|
|
|
" 4 order_direction 121 non-null object \n",
|
|
|
|
|
|
" 5 enable_log 121 non-null bool \n",
|
|
|
|
|
|
" 6 strategy_mode 121 non-null object \n",
|
|
|
|
|
|
" 7 初始资金 121 non-null float64\n",
|
|
|
|
|
|
" 8 最终资金 121 non-null float64\n",
|
|
|
|
|
|
" 9 总收益率 121 non-null float64\n",
|
|
|
|
|
|
" 10 年化收益率 121 non-null float64\n",
|
|
|
|
|
|
" 11 最大回撤 121 non-null float64\n",
|
|
|
|
|
|
" 12 夏普比率 121 non-null float64\n",
|
|
|
|
|
|
" 13 卡玛比率 121 non-null float64\n",
|
|
|
|
|
|
" 14 总交易次数 121 non-null int64 \n",
|
|
|
|
|
|
" 15 交易成本 121 non-null float64\n",
|
|
|
|
|
|
" 16 总实现盈亏 121 non-null float64\n",
|
|
|
|
|
|
" 17 胜率 121 non-null float64\n",
|
|
|
|
|
|
" 18 盈亏比 121 non-null float64\n",
|
|
|
|
|
|
" 19 盈利交易次数 121 non-null int64 \n",
|
|
|
|
|
|
" 20 亏损交易次数 121 non-null int64 \n",
|
|
|
|
|
|
" 21 平均每次盈利 121 non-null float64\n",
|
|
|
|
|
|
" 22 平均每次亏损 121 non-null float64\n",
|
|
|
|
|
|
" 23 initial_capital 121 non-null float64\n",
|
|
|
|
|
|
" 24 final_capital 121 non-null float64\n",
|
|
|
|
|
|
" 25 total_return 121 non-null float64\n",
|
|
|
|
|
|
" 26 annualized_return 121 non-null float64\n",
|
|
|
|
|
|
" 27 max_drawdown 121 non-null float64\n",
|
|
|
|
|
|
" 28 sharpe_ratio 121 non-null float64\n",
|
|
|
|
|
|
" 29 calmar_ratio 121 non-null float64\n",
|
|
|
|
|
|
" 30 sortino_ratio 121 non-null float64\n",
|
|
|
|
|
|
" 31 total_trades 121 non-null int64 \n",
|
|
|
|
|
|
" 32 transaction_costs 121 non-null float64\n",
|
|
|
|
|
|
" 33 total_realized_pnl 121 non-null float64\n",
|
|
|
|
|
|
" 34 win_rate 121 non-null float64\n",
|
|
|
|
|
|
" 35 profit_loss_ratio 121 non-null float64\n",
|
|
|
|
|
|
" 36 winning_trades_count 121 non-null int64 \n",
|
|
|
|
|
|
" 37 losing_trades_count 121 non-null int64 \n",
|
|
|
|
|
|
" 38 avg_profit_per_trade 121 non-null float64\n",
|
|
|
|
|
|
" 39 avg_loss_per_trade 121 non-null float64\n",
|
|
|
|
|
|
"dtypes: bool(1), float64(29), int64(7), object(3)\n",
|
|
|
|
|
|
"memory usage: 37.1+ KB\n",
|
|
|
|
|
|
"None\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"--- 最优参数组合 (按total_return) ---\n",
|
2025-11-20 16:10:16 +08:00
|
|
|
|
"main_symbol SA\n",
|
2025-11-07 16:37:16 +08:00
|
|
|
|
"trade_volume 1\n",
|
2025-11-20 16:10:16 +08:00
|
|
|
|
"kalman_measurement_noise 0.01\n",
|
2025-11-07 16:37:16 +08:00
|
|
|
|
"entry_threshold_atr 0.7\n",
|
|
|
|
|
|
"order_direction [BUY, SELL]\n",
|
|
|
|
|
|
"enable_log False\n",
|
2025-11-20 16:10:16 +08:00
|
|
|
|
"strategy_mode TREND\n",
|
2025-11-07 16:37:16 +08:00
|
|
|
|
"初始资金 100000.0\n",
|
2025-11-20 16:10:16 +08:00
|
|
|
|
"最终资金 102764.3367\n",
|
|
|
|
|
|
"总收益率 0.027643\n",
|
|
|
|
|
|
"年化收益率 0.00633\n",
|
|
|
|
|
|
"最大回撤 0.007762\n",
|
|
|
|
|
|
"夏普比率 0.261089\n",
|
|
|
|
|
|
"卡玛比率 0.815491\n",
|
|
|
|
|
|
"总交易次数 124\n",
|
|
|
|
|
|
"交易成本 28.6633\n",
|
|
|
|
|
|
"总实现盈亏 2793.0\n",
|
|
|
|
|
|
"胜率 0.193548\n",
|
|
|
|
|
|
"盈亏比 11.262703\n",
|
|
|
|
|
|
"盈利交易次数 12\n",
|
|
|
|
|
|
"亏损交易次数 50\n",
|
|
|
|
|
|
"平均每次盈利 369.416667\n",
|
|
|
|
|
|
"平均每次亏损 -32.8\n",
|
2025-11-07 16:37:16 +08:00
|
|
|
|
"initial_capital 100000.0\n",
|
2025-11-20 16:10:16 +08:00
|
|
|
|
"final_capital 102764.3367\n",
|
|
|
|
|
|
"total_return 0.027643\n",
|
|
|
|
|
|
"annualized_return 0.00633\n",
|
|
|
|
|
|
"max_drawdown 0.007762\n",
|
|
|
|
|
|
"sharpe_ratio 0.261089\n",
|
|
|
|
|
|
"calmar_ratio 0.815491\n",
|
|
|
|
|
|
"sortino_ratio 0.299849\n",
|
|
|
|
|
|
"total_trades 124\n",
|
|
|
|
|
|
"transaction_costs 28.6633\n",
|
|
|
|
|
|
"total_realized_pnl 2793.0\n",
|
|
|
|
|
|
"win_rate 0.193548\n",
|
|
|
|
|
|
"profit_loss_ratio 11.262703\n",
|
|
|
|
|
|
"winning_trades_count 12\n",
|
|
|
|
|
|
"losing_trades_count 50\n",
|
|
|
|
|
|
"avg_profit_per_trade 369.416667\n",
|
|
|
|
|
|
"avg_loss_per_trade -32.8\n",
|
|
|
|
|
|
"Name: 2, dtype: object\n",
|
2025-11-07 16:37:16 +08:00
|
|
|
|
"\n",
|
|
|
|
|
|
"--- 动态网格搜索完成 ---\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"--- 最佳参数组合 ---\n",
|
2025-11-20 16:10:16 +08:00
|
|
|
|
" kalman_measurement_noise: 0.01\n",
|
2025-11-07 16:37:16 +08:00
|
|
|
|
" entry_threshold_atr: 0.7\n",
|
2025-11-20 16:10:16 +08:00
|
|
|
|
" total_return: 0.0276\n",
|
2025-11-07 16:37:16 +08:00
|
|
|
|
"[0.01, 5.01, 0.1, 3.1]\n"
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"data": {
|
|
|
|
|
|
"text/plain": [
|
|
|
|
|
|
"<Figure size 1000x800 with 2 Axes>"
|
|
|
|
|
|
],
|
2025-11-20 16:10:16 +08:00
|
|
|
|
"image/png": "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
|
2025-11-07 16:37:16 +08:00
|
|
|
|
},
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
"output_type": "display_data",
|
|
|
|
|
|
"jetTransient": {
|
|
|
|
|
|
"display_id": null
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
"execution_count": 12
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
"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
|
|
|
|
|
|
}
|