卡尔曼策略新增md文件

This commit is contained in:
2025-11-07 16:37:16 +08:00
parent 2eec6452ee
commit 2ae9f2db9e
89 changed files with 39954 additions and 0 deletions

View File

@@ -0,0 +1,232 @@
import numpy as np
import pandas as pd
from typing import Optional, Dict, Any, List
# 假设这些是你项目中的模块
from src.core_data import Bar, Order
from src.strategies.base_strategy import Strategy
from src.algo.TrendLine import calculate_latest_trendline_values_v2
class DualModeVolumeIntensityStrategy(Strategy):
"""
双模式成交量强度策略 (V7 - 无状态高效版):
- 【核心命名】将 "霍克斯过程" 概念替换为更准确的 "成交量强度 (Volume Intensity)"
- 【核心优化】使用 NumPy 的卷积操作 (np.convolve) 代替循环,高效地计算滑动窗口的成交量强度,彻底消除路径依赖,同时保证高性能。
- 策略行为在任何时间点只与最近的固定窗口数据相关,保证了回测与实盘的绝对一致性。
- 完整保留了双模式(趋势/回归)和冲突解决机制。
"""
def __init__(
self,
context: Any,
main_symbol: str,
trade_volume: int = 1,
trend_params: Dict[str, Any] = None,
reversion_params: Dict[str, Any] = None,
enabled_modes: Optional[List[str]] = None,
conflict_resolution: str = 'TREND_PRIORITY',
enable_log: bool = True,
):
super().__init__(context, main_symbol, enable_log)
self.main_symbol = main_symbol
self.trade_volume = trade_volume
default_params = {
"order_direction": ["BUY", "SELL"],
"trendline_n": 50,
# 【命名修改】参数名也同步调整
"intensity_kappa": 0.1, # 衰减因子
"intensity_lookback": 50, # 回看窗口
"intensity_entry_percent": 0.95,
"intensity_exit_percent": 0.50,
}
self.trend_params = default_params.copy()
if trend_params:
self.trend_params.update(trend_params)
self.reversion_params = default_params.copy()
if reversion_params:
self.reversion_params.update(reversion_params)
self.enabled_modes = enabled_modes or ['TREND', 'REVERSION']
self.conflict_resolution = conflict_resolution
self.pos_meta: Dict[str, Dict[str, Any]] = {}
print("DualModeVolumeIntensityStrategy (V7) initialized.")
print(f"Enabled modes: {self.enabled_modes}")
print(f"Conflict resolution: {self.conflict_resolution}")
print("Volume Intensity calculation is STATELESS and EFFICIENT (using np.convolve).")
# --- 【核心修改】使用卷积实现无状态、高效的窗口计算 ---
def _calculate_volume_intensity_window(self, volumes: np.ndarray, kappa: float, lookback: int) -> np.ndarray:
"""
使用一维卷积高效计算成交量强度窗口。
这是一个纯函数,无任何副作用和路径依赖。
:param volumes: 历史成交量序列。长度应为 2*lookback - 1。
:param kappa: 强度衰减因子。
:param lookback: 强度计算的回看窗口,也是返回的强度窗口的长度。
:return: 一个长度为 `lookback` 的成交量强度值窗口。
"""
# 权重是指数衰减的,越近的成交量权重越高
# weights = [exp(-kappa*lookback), ..., exp(-kappa*1)]
weights = np.exp(-kappa * np.arange(lookback, 0, -1))
# 使用'valid'模式的卷积,本质上是一个滑动的点积运算
# 结果的长度将是 len(volumes) - len(weights) + 1 = (2*lookback-1) - lookback + 1 = lookback
intensity_unscaled = np.convolve(volumes, weights, mode='valid')
return intensity_unscaled * kappa
def on_init(self):
super().on_init()
self.pos_meta.clear()
def on_open_bar(self, open_price: float, symbol: str):
bar_history = self.get_bar_history()
# 确保有足够的数据来满足最长的回看需求
# 趋势线需要 trendline_n + 1 个价格
# 强度计算需要 2 * lookback - 1 个成交量
min_bars_required = max(
self.trend_params['trendline_n'] + 2, 2 * self.trend_params['intensity_lookback'],
self.reversion_params['trendline_n'] + 2, 2 * self.reversion_params['intensity_lookback']
)
if len(bar_history) < min_bars_required:
return
all_volumes = np.array([b.volume for b in bar_history], dtype=float)
# 为每个模式计算其独立的成交量强度窗口
trend_intensity_window = np.array([], dtype=np.float64)
if 'TREND' in self.enabled_modes:
lookback = self.trend_params['intensity_lookback']
# 截取计算所需的、正确长度的成交量数据
volumes_slice = all_volumes[-(2 * lookback - 1):]
trend_intensity_window = self._calculate_volume_intensity_window(
volumes_slice, self.trend_params['intensity_kappa'], lookback
)
reversion_intensity_window = np.array([], dtype=np.float64)
if 'REVERSION' in self.enabled_modes:
lookback = self.reversion_params['intensity_lookback']
volumes_slice = all_volumes[-(2 * lookback - 1):]
reversion_intensity_window = self._calculate_volume_intensity_window(
volumes_slice, self.reversion_params['intensity_kappa'], lookback
)
self.cancel_all_pending_orders(symbol)
pos = self.get_current_positions().get(symbol, 0)
# --- 1. 平仓逻辑 ---
meta = self.pos_meta.get(symbol)
if meta and pos != 0:
strategy_mode = meta.get('strategy_mode')
params_to_use = self.trend_params if strategy_mode == 'TREND' else self.reversion_params
window_to_use = trend_intensity_window if strategy_mode == 'TREND' else reversion_intensity_window
if window_to_use.size > 0:
latest_intensity_value = window_to_use[-1]
exit_threshold = np.quantile(window_to_use, params_to_use['intensity_exit_percent'])
if latest_intensity_value < exit_threshold:
self.log(f"[{strategy_mode}模式] 成交量强度平仓信号 (市场热度下降),平仓。")
self.send_market_order("CLOSE_LONG" if meta['direction'] == "BUY" else "CLOSE_SHORT", abs(pos))
del self.pos_meta[symbol]
return
# --- 2. 开仓逻辑 ---
if pos == 0:
trend_signal = self._calculate_entry_signal(
'TREND', bar_history, self.trend_params, trend_intensity_window
) if 'TREND' in self.enabled_modes else None
reversion_signal = self._calculate_entry_signal(
'REVERSION', bar_history, self.reversion_params, reversion_intensity_window
) if 'REVERSION' in self.enabled_modes else None
# ... 冲突解决和下单逻辑保持不变 ...
final_direction, winning_mode = self.resolve_signals(trend_signal, reversion_signal)
if final_direction and winning_mode:
params_to_use = self.trend_params if winning_mode == 'TREND' else self.reversion_params
if final_direction in params_to_use['order_direction']:
self.log(f"[{winning_mode}模式] 开仓信号确认: {final_direction}")
self.send_open_order(final_direction, open_price, self.trade_volume, winning_mode)
def _calculate_entry_signal(self, mode: str, bar_history: List[Bar], params: Dict, intensity_window: np.ndarray) -> \
Optional[str]:
if intensity_window.size == 0:
return None
# 1. 成交量强度确认
latest_intensity_value = intensity_window[-1]
entry_threshold = np.quantile(intensity_window, params['intensity_entry_percent'])
intensity_confirmation = latest_intensity_value > entry_threshold
if not intensity_confirmation:
return None
# 2. 趋势线突破事件
close_prices = np.array([b.close for b in bar_history])
prices_for_trendline = close_prices[-params['trendline_n'] - 1:-1]
trend_upper, trend_lower = calculate_latest_trendline_values_v2(prices_for_trendline)
if trend_upper is not None and trend_lower is not None:
prev_close = bar_history[-2].close
last_close = bar_history[-1].close
upper_break_event = last_close > trend_upper and prev_close < trend_upper
lower_break_event = last_close < trend_lower and prev_close > trend_lower
if upper_break_event: return "BUY" if mode == 'TREND' else "SELL"
if lower_break_event: return "SELL" if mode == 'TREND' else "BUY"
return None
def resolve_signals(self, trend_signal: Optional[str], reversion_signal: Optional[str]) -> (Optional[str],
Optional[str]):
if trend_signal and reversion_signal:
self.log(f"信号冲突:趋势模式 ({trend_signal}) vs 回归模式 ({reversion_signal})")
if self.conflict_resolution == 'TREND_PRIORITY':
return trend_signal, 'TREND'
elif self.conflict_resolution == 'REVERSION_PRIORITY':
return reversion_signal, 'REVERSION'
else:
self.log("冲突解决策略为'NONE',本次不开仓。")
return None, None
elif trend_signal:
return trend_signal, 'TREND'
elif reversion_signal:
return reversion_signal, 'REVERSION'
return None, None
# send_open_order, send_market_order, on_rollover 等辅助函数保持不变
# ... (代码与之前版本相同)
def send_open_order(self, direction: str, entry_price: float, volume: int, strategy_mode: str):
current_time = self.get_current_time()
order_id = f"{self.symbol}_{direction}_{current_time.strftime('%Y%m%d%H%M%S')}"
order_direction = "BUY" if direction == "BUY" else "SELL"
order = Order(id=order_id, symbol=self.symbol, direction=order_direction, volume=volume, price_type="MARKET",
submitted_time=current_time, offset="OPEN")
self.send_order(order)
self.pos_meta[self.symbol] = {
"direction": direction,
"volume": volume,
"entry_price": entry_price,
"strategy_mode": strategy_mode
}
self.log(f"发送开仓订单 ({strategy_mode}): {direction} {volume}手 @ Market Price (执行价约 {entry_price:.2f})")
def send_market_order(self, direction: str, volume: int):
current_time = self.get_current_time()
order_id = f"{self.symbol}_{direction}_{current_time.strftime('%Y%m%d%H%M%S')}"
order = Order(id=order_id, symbol=self.symbol, direction=direction, volume=volume, price_type="MARKET",
submitted_time=current_time, offset="CLOSE")
self.send_order(order)
self.log(f"发送平仓订单: {direction} {volume}手 @ Market Price")
def on_rollover(self, old_symbol: str, new_symbol: str):
super().on_rollover(old_symbol, new_symbol)
self.cancel_all_pending_orders(new_symbol)
self.pos_meta.clear()

View File

@@ -0,0 +1,381 @@
{
"cells": [
{
"cell_type": "code",
"id": "522f09ca7b3fe929",
"metadata": {
"ExecuteTime": {
"end_time": "2025-10-24T08:54:09.381083Z",
"start_time": "2025-10-24T08:54:09.363240Z"
}
},
"source": [
"from datetime import datetime\n",
"\n",
"from src.data_processing import load_raw_data\n",
"%load_ext autoreload\n",
"%autoreload 2\n",
"\n",
"import sys\n",
"\n",
"if '/mnt/d/PyProject/NewQuant/' not in sys.path:\n",
" sys.path.append('/mnt/d/PyProject/NewQuant/')"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The autoreload extension is already loaded. To reload it, use:\n",
" %reload_ext autoreload\n"
]
}
],
"execution_count": 9
},
{
"cell_type": "code",
"id": "4f7e4b438cea750e",
"metadata": {
"ExecuteTime": {
"end_time": "2025-10-24T08:54:09.402764Z",
"start_time": "2025-10-24T08:54:09.387096Z"
}
},
"source": [
"from turtle import down\n",
"from src.analysis.result_analyzer import ResultAnalyzer\n",
"# 导入所有必要的模块\n",
"from src.data_manager import DataManager\n",
"from src.backtest_engine import BacktestEngine\n",
"from src.indicators.indicator_list import INDICATOR_LIST\n",
"from src.indicators.indicators import *\n",
"\n",
"# 导入您自己的 SMC 策略\n",
"from futures_trading_strategies.FG.TrendlineBreakoutStrategy.DualModeTrendlineHawkesStrategy2 import DualModeTrendlineHawkesStrategy\n",
"\n",
"# --- 配置参数 ---\n",
"# 获取当前脚本所在目录,假设数据文件在项目根目录下的 data 文件夹内\n",
"data_file_path = 'D:/PyProject/NewQuant/data/data/KQ_m@CZCE_FG/KQ_m@CZCE_FG_min15.csv'\n"
],
"outputs": [],
"execution_count": 10
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-10-24T08:54:09.420838Z",
"start_time": "2025-10-24T08:54:09.404769Z"
}
},
"cell_type": "code",
"source": [
"\n",
"initial_capital = 100000.0\n",
"slippage_rate = 0.000 # 假设每笔交易0.1%的滑点\n",
"commission_rate = 0.0000 # 假设每笔交易0.02%的佣金\n",
"\n",
"global_config = {\n",
" 'symbol': 'KQ_m@CZCE_FG', # 确保与数据文件中的 symbol 匹配\n",
"}\n",
"\n",
"# 回测时间范围\n",
"start_time = datetime(2021, 1, 1)\n",
"end_time = datetime(2024, 6, 1)\n",
"\n",
"start_time = datetime(2025, 9, 1)\n",
"end_time = datetime(2025, 11, 1)\n",
"\n",
"\n",
"indicators = INDICATOR_LIST\n",
"indicators = []\n",
"\n",
"# 确保 DataManager 能够重置以进行多次回测\n",
"# data_manager.reset() # 首次运行不需要重置"
],
"id": "9ee53c41eaaefabb",
"outputs": [],
"execution_count": 11
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-10-24T08:54:30.631596Z",
"start_time": "2025-10-24T08:54:09.424852Z"
}
},
"cell_type": "code",
"source": [
"from src.tqsdk_engine import TqsdkEngine\n",
"from tqsdk import TqApi, TqBacktest, TqAuth\n",
"from src.indicators.indicators import ROC_MA\n",
"\n",
"# --- 1. 初始化数据管理器 ---\n",
"print(\"初始化数据管理器...\")\n",
"data_manager = DataManager(file_path=data_file_path, symbol=global_config['symbol'], start_time=start_time,\n",
" end_time=end_time)\n",
"\n",
"strategy_parameters = {\n",
" 'main_symbol': 'FG', # <-- 替换为你的交易品种代码,例如 'GC=F' (黄金期货), 'ZC=F' (玉米期货)\n",
" 'trade_volume': 1,\n",
" # 'indicators': [RateOfChange(10, -2.1, -0.5), ROC_MA(10, 10, -2.7, -0.4)],\n",
" 'enable_log': False,\n",
" 'trend_params': {\n",
" \"trendline_n\": 10,\n",
" \"hawkes_kappa\": 0.9,\n",
" },\n",
" 'reversion_params': {\n",
" \"trendline_n\": 70,\n",
" \"hawkes_kappa\": 0.1,\n",
" },\n",
" 'conflict_resolution': 'NONE'\n",
"}\n",
"\n",
"# --- 2. 初始化回测引擎并运行 ---\n",
"print(\"\\n初始化回测引擎...\")\n",
"api = TqApi(\n",
" backtest=TqBacktest(start_dt=start_time, end_dt=end_time),\n",
" auth=TqAuth(\"emanresu\", \"dfgvfgdfgg\"),\n",
")\n",
"# --- 1. 初始化回测引擎并运行 ---\n",
"print(\"\\n初始化 Tqsdk 回测引擎...\")\n",
"engine = TqsdkEngine(\n",
" strategy_class=DualModeTrendlineHawkesStrategy,\n",
" strategy_params=strategy_parameters,\n",
" api=api,\n",
" symbol=global_config['symbol'],\n",
" duration_seconds=60 * 15,\n",
" roll_over_mode=True, # 启用换月模式检测\n",
" start_time=start_time,\n",
" end_time=end_time,\n",
")\n",
"\n",
"print(\"\\n开始运行回测...\")\n",
"engine.run_backtest()\n",
"print(\"\\n回测运行完毕。\")\n",
"\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",
"\n",
"# --- 4. 结果分析与可视化 ---\n",
"if portfolio_snapshots:\n",
" analyzer = ResultAnalyzer(portfolio_snapshots, trade_history, bars, initial_capital_result, INDICATOR_LIST)\n",
"\n",
" analyzer.generate_report()\n",
" analyzer.plot_performance()\n",
" metrics = analyzer.calculate_all_metrics()\n",
" print(metrics)\n",
"\n",
" analyzer.analyze_indicators()\n",
"else:\n",
" print(\"\\n没有生成投资组合快照无法进行结果分析。\")"
],
"id": "f903fd2761d446cd",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"初始化数据管理器...\n",
"数据加载成功: D:/PyProject/NewQuant/data/data/KQ_m@CZCE_FG/KQ_m@CZCE_FG_min15.csv\n",
"数据范围从 2020-12-31 14:45:00 到 2025-10-24 14:30:00\n",
"总计 26508 条记录。\n",
"\n",
"初始化回测引擎...\n",
" INFO - TqSdk free 版剩余 0 天到期,如需续费或升级请访问 https://account.shinnytech.com/ 或联系相关工作人员。\n",
"\n",
"初始化 Tqsdk 回测引擎...\n",
"内存仓储已初始化管理ID: 'futures_trading_strategies.FG.TrendlineBreakoutStrategy.DualModeTrendlineHawkesStrategy2.DualModeTrendlineHawkesStrategy_ec6cb042fb4d776e22af01d6641dc528'\n",
"TqsdkContext: 初始化完成。\n",
"DualModeTrendlineHawkesStrategy initialized.\n",
"Enabled modes: ['TREND', 'REVERSION']\n",
"Conflict resolution: NONE\n",
"TqsdkContext: 已设置引擎引用。\n",
"TqsdkEngine: 初始化完成。\n",
"\n",
"开始运行回测...\n",
"TqsdkEngine: 开始运行回测,从 2025-09-01 00:00:00 到 2025-11-01 00:00:00\n",
"DualModeTrendlineHawkesStrategy 策略初始化回调被调用。\n",
"Initializing Hawkes state with lookback 50...\n",
"Initializing Hawkes state with lookback 50...\n",
"Context: 订单已加入队列: Order(symbol='CZCE.FG601', direction='BUY', volume=1, id='CZCE.FG601_BUY_20250904211500', price_type='LIMIT', limit_price=1148, stop_price=None, submitted_time=Timestamp('2025-09-04 21:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
"Engine: 处理订单请求: Order(symbol='CZCE.FG601', direction='BUY', volume=1, id='CZCE.FG601_BUY_20250904211500', price_type='LIMIT', limit_price=1148, stop_price=None, submitted_time=Timestamp('2025-09-04 21:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
" INFO - 模拟交易下单 TQSIM, PYSDK_insert_4aacb590c09871e5cfae4a8eb64c3c4d: 时间: 2025-09-04 21:15:00.000000, 合约: CZCE.FG601, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 1148.0\n",
" INFO - 模拟交易委托单 TQSIM, PYSDK_insert_4aacb590c09871e5cfae4a8eb64c3c4d: 全部成交\n",
"Context: 订单已加入队列: Order(symbol='CZCE.FG601', direction='CLOSE_LONG', volume=1, id='CZCE.FG601_CLOSE_LONG_20250904221500', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-09-04 22:15:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
"Engine: 处理订单请求: Order(symbol='CZCE.FG601', direction='CLOSE_LONG', volume=1, id='CZCE.FG601_CLOSE_LONG_20250904221500', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-09-04 22:15:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
" INFO - 模拟交易下单 TQSIM, PYSDK_target_0f909d3561fe7c107a1b19326fa53a17: 时间: 2025-09-04 22:15:00.000000, 合约: CZCE.FG601, 开平: CLOSE, 方向: SELL, 手数: 1, 价格: 1140.0\n",
" INFO - 模拟交易委托单 TQSIM, PYSDK_target_0f909d3561fe7c107a1b19326fa53a17: 全部成交\n",
"Context: 订单已加入队列: Order(symbol='CZCE.FG601', direction='SELL', volume=1, id='CZCE.FG601_SELL_20250909211500', price_type='LIMIT', limit_price=1171, stop_price=None, submitted_time=Timestamp('2025-09-09 21:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
"Engine: 处理订单请求: Order(symbol='CZCE.FG601', direction='SELL', volume=1, id='CZCE.FG601_SELL_20250909211500', price_type='LIMIT', limit_price=1171, stop_price=None, submitted_time=Timestamp('2025-09-09 21:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
" INFO - 模拟交易下单 TQSIM, PYSDK_insert_8db38b8aee8f78c3607d2d84cb4abb0b: 时间: 2025-09-09 21:15:00.000000, 合约: CZCE.FG601, 开平: OPEN, 方向: SELL, 手数: 1, 价格: 1171.0\n",
" INFO - 模拟交易委托单 TQSIM, PYSDK_insert_8db38b8aee8f78c3607d2d84cb4abb0b: 全部成交\n",
"Context: 订单已加入队列: Order(symbol='CZCE.FG601', direction='CLOSE_SHORT', volume=1, id='CZCE.FG601_CLOSE_SHORT_20250909223000', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-09-09 22:30:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
"Engine: 处理订单请求: Order(symbol='CZCE.FG601', direction='CLOSE_SHORT', volume=1, id='CZCE.FG601_CLOSE_SHORT_20250909223000', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-09-09 22:30:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
" INFO - 模拟交易下单 TQSIM, PYSDK_target_c462ad51e812c4f54117aa66ae1499e4: 时间: 2025-09-09 22:30:00.000000, 合约: CZCE.FG601, 开平: CLOSE, 方向: BUY, 手数: 1, 价格: 1171.0\n",
" INFO - 模拟交易委托单 TQSIM, PYSDK_target_c462ad51e812c4f54117aa66ae1499e4: 全部成交\n",
"Context: 订单已加入队列: Order(symbol='CZCE.FG601', direction='SELL', volume=1, id='CZCE.FG601_SELL_20250918091500', price_type='LIMIT', limit_price=1217, stop_price=None, submitted_time=Timestamp('2025-09-18 09:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
"Engine: 处理订单请求: Order(symbol='CZCE.FG601', direction='SELL', volume=1, id='CZCE.FG601_SELL_20250918091500', price_type='LIMIT', limit_price=1217, stop_price=None, submitted_time=Timestamp('2025-09-18 09:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
" INFO - 模拟交易下单 TQSIM, PYSDK_insert_487e402458d1b25fb8a7e687ae4c291c: 时间: 2025-09-18 09:15:00.000000, 合约: CZCE.FG601, 开平: OPEN, 方向: SELL, 手数: 1, 价格: 1217.0\n",
" INFO - 模拟交易委托单 TQSIM, PYSDK_insert_487e402458d1b25fb8a7e687ae4c291c: 全部成交\n",
"Context: 订单已加入队列: Order(symbol='CZCE.FG601', direction='CLOSE_SHORT', volume=1, id='CZCE.FG601_CLOSE_SHORT_20250918103000', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-09-18 10:30:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
"Engine: 处理订单请求: Order(symbol='CZCE.FG601', direction='CLOSE_SHORT', volume=1, id='CZCE.FG601_CLOSE_SHORT_20250918103000', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-09-18 10:30:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
" INFO - 模拟交易下单 TQSIM, PYSDK_target_b3b97d0e6d4fdc323ec344f7d89ce1f0: 时间: 2025-09-18 10:30:00.000000, 合约: CZCE.FG601, 开平: CLOSE, 方向: BUY, 手数: 1, 价格: 1225.0\n",
" INFO - 模拟交易委托单 TQSIM, PYSDK_target_b3b97d0e6d4fdc323ec344f7d89ce1f0: 全部成交\n",
"Context: 订单已加入队列: Order(symbol='CZCE.FG601', direction='SELL', volume=1, id='CZCE.FG601_SELL_20250918133000', price_type='LIMIT', limit_price=1207, stop_price=None, submitted_time=Timestamp('2025-09-18 13:30:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
"Engine: 处理订单请求: Order(symbol='CZCE.FG601', direction='SELL', volume=1, id='CZCE.FG601_SELL_20250918133000', price_type='LIMIT', limit_price=1207, stop_price=None, submitted_time=Timestamp('2025-09-18 13:30:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
" INFO - 模拟交易下单 TQSIM, PYSDK_insert_96c036710e7b53b554fc7c33b95b9c24: 时间: 2025-09-18 13:30:00.000000, 合约: CZCE.FG601, 开平: OPEN, 方向: SELL, 手数: 1, 价格: 1207.0\n",
" INFO - 模拟交易委托单 TQSIM, PYSDK_insert_96c036710e7b53b554fc7c33b95b9c24: 全部成交\n",
"Context: 订单已加入队列: Order(symbol='CZCE.FG601', direction='CLOSE_SHORT', volume=1, id='CZCE.FG601_CLOSE_SHORT_20250918214500', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-09-18 21:45:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
"Engine: 处理订单请求: Order(symbol='CZCE.FG601', direction='CLOSE_SHORT', volume=1, id='CZCE.FG601_CLOSE_SHORT_20250918214500', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-09-18 21:45:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
" INFO - 模拟交易下单 TQSIM, PYSDK_target_7865ded2b9c1bfa3442b1701742c4d58: 时间: 2025-09-18 21:45:00.000000, 合约: CZCE.FG601, 开平: CLOSE, 方向: BUY, 手数: 1, 价格: 1205.0\n",
" INFO - 模拟交易委托单 TQSIM, PYSDK_target_7865ded2b9c1bfa3442b1701742c4d58: 全部成交\n",
"Context: 订单已加入队列: Order(symbol='CZCE.FG601', direction='BUY', volume=1, id='CZCE.FG601_BUY_20250919211500', price_type='LIMIT', limit_price=1225, stop_price=None, submitted_time=Timestamp('2025-09-19 21:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
"Engine: 处理订单请求: Order(symbol='CZCE.FG601', direction='BUY', volume=1, id='CZCE.FG601_BUY_20250919211500', price_type='LIMIT', limit_price=1225, stop_price=None, submitted_time=Timestamp('2025-09-19 21:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
" INFO - 模拟交易下单 TQSIM, PYSDK_insert_8ecdd284ec65ec961067a00e1e03e315: 时间: 2025-09-19 21:15:00.000000, 合约: CZCE.FG601, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 1225.0\n",
" INFO - 模拟交易委托单 TQSIM, PYSDK_insert_8ecdd284ec65ec961067a00e1e03e315: 全部成交\n",
"Context: 订单已加入队列: Order(symbol='CZCE.FG601', direction='CLOSE_LONG', volume=1, id='CZCE.FG601_CLOSE_LONG_20250919220000', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-09-19 22:00:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
"Engine: 处理订单请求: Order(symbol='CZCE.FG601', direction='CLOSE_LONG', volume=1, id='CZCE.FG601_CLOSE_LONG_20250919220000', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-09-19 22:00:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
" INFO - 模拟交易下单 TQSIM, PYSDK_target_29eb0b749e58167aa45665d208253b36: 时间: 2025-09-19 22:00:00.000000, 合约: CZCE.FG601, 开平: CLOSE, 方向: SELL, 手数: 1, 价格: 1223.0\n",
" INFO - 模拟交易委托单 TQSIM, PYSDK_target_29eb0b749e58167aa45665d208253b36: 全部成交\n",
"Context: 订单已加入队列: Order(symbol='CZCE.FG601', direction='BUY', volume=1, id='CZCE.FG601_BUY_20250924091500', price_type='LIMIT', limit_price=1203, stop_price=None, submitted_time=Timestamp('2025-09-24 09:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
"Engine: 处理订单请求: Order(symbol='CZCE.FG601', direction='BUY', volume=1, id='CZCE.FG601_BUY_20250924091500', price_type='LIMIT', limit_price=1203, stop_price=None, submitted_time=Timestamp('2025-09-24 09:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
" INFO - 模拟交易下单 TQSIM, PYSDK_insert_32cf408c5635c11b831b98b2fd635a66: 时间: 2025-09-24 09:15:00.000000, 合约: CZCE.FG601, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 1203.0\n",
" INFO - 模拟交易委托单 TQSIM, PYSDK_insert_32cf408c5635c11b831b98b2fd635a66: 全部成交\n",
"Context: 订单已加入队列: Order(symbol='CZCE.FG601', direction='CLOSE_LONG', volume=1, id='CZCE.FG601_CLOSE_LONG_20250924100000', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-09-24 10:00:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
"Engine: 处理订单请求: Order(symbol='CZCE.FG601', direction='CLOSE_LONG', volume=1, id='CZCE.FG601_CLOSE_LONG_20250924100000', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-09-24 10:00:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
" INFO - 模拟交易下单 TQSIM, PYSDK_target_f046b95f5e3d13c223fa1f9c535d76bf: 时间: 2025-09-24 10:00:00.000000, 合约: CZCE.FG601, 开平: CLOSE, 方向: SELL, 手数: 1, 价格: 1196.0\n",
" INFO - 模拟交易委托单 TQSIM, PYSDK_target_f046b95f5e3d13c223fa1f9c535d76bf: 全部成交\n",
"Context: 订单已加入队列: Order(symbol='CZCE.FG601', direction='SELL', volume=1, id='CZCE.FG601_SELL_20251010211500', price_type='LIMIT', limit_price=1185, stop_price=None, submitted_time=Timestamp('2025-10-10 21:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
"Engine: 处理订单请求: Order(symbol='CZCE.FG601', direction='SELL', volume=1, id='CZCE.FG601_SELL_20251010211500', price_type='LIMIT', limit_price=1185, stop_price=None, submitted_time=Timestamp('2025-10-10 21:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
" INFO - 模拟交易下单 TQSIM, PYSDK_insert_9a63d90f357be3164b448d24e95ea66d: 时间: 2025-10-10 21:15:00.000000, 合约: CZCE.FG601, 开平: OPEN, 方向: SELL, 手数: 1, 价格: 1185.0\n",
" INFO - 模拟交易委托单 TQSIM, PYSDK_insert_9a63d90f357be3164b448d24e95ea66d: 全部成交\n",
"Context: 订单已加入队列: Order(symbol='CZCE.FG601', direction='CLOSE_SHORT', volume=1, id='CZCE.FG601_CLOSE_SHORT_20251010220000', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-10-10 22:00:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
"Engine: 处理订单请求: Order(symbol='CZCE.FG601', direction='CLOSE_SHORT', volume=1, id='CZCE.FG601_CLOSE_SHORT_20251010220000', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-10-10 22:00:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
" INFO - 模拟交易下单 TQSIM, PYSDK_target_6dfce0e150315f78983eda0bcb0e9a91: 时间: 2025-10-10 22:00:00.000000, 合约: CZCE.FG601, 开平: CLOSE, 方向: BUY, 手数: 1, 价格: 1184.0\n",
" INFO - 模拟交易委托单 TQSIM, PYSDK_target_6dfce0e150315f78983eda0bcb0e9a91: 全部成交\n",
"Context: 订单已加入队列: Order(symbol='CZCE.FG601', direction='SELL', volume=1, id='CZCE.FG601_SELL_20251016211500', price_type='LIMIT', limit_price=1129, stop_price=None, submitted_time=Timestamp('2025-10-16 21:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
"Engine: 处理订单请求: Order(symbol='CZCE.FG601', direction='SELL', volume=1, id='CZCE.FG601_SELL_20251016211500', price_type='LIMIT', limit_price=1129, stop_price=None, submitted_time=Timestamp('2025-10-16 21:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
" INFO - 模拟交易下单 TQSIM, PYSDK_insert_6cd2d65278d526385068e2106d70854c: 时间: 2025-10-16 21:15:00.000000, 合约: CZCE.FG601, 开平: OPEN, 方向: SELL, 手数: 1, 价格: 1129.0\n",
" INFO - 模拟交易委托单 TQSIM, PYSDK_insert_6cd2d65278d526385068e2106d70854c: 全部成交\n",
"Context: 订单已加入队列: Order(symbol='CZCE.FG601', direction='CLOSE_SHORT', volume=1, id='CZCE.FG601_CLOSE_SHORT_20251016221500', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-10-16 22:15:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
"Engine: 处理订单请求: Order(symbol='CZCE.FG601', direction='CLOSE_SHORT', volume=1, id='CZCE.FG601_CLOSE_SHORT_20251016221500', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-10-16 22:15:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
" INFO - 模拟交易下单 TQSIM, PYSDK_target_3299638e3209614bcfd7538e8fefa867: 时间: 2025-10-16 22:15:00.000000, 合约: CZCE.FG601, 开平: CLOSE, 方向: BUY, 手数: 1, 价格: 1130.0\n",
" INFO - 模拟交易委托单 TQSIM, PYSDK_target_3299638e3209614bcfd7538e8fefa867: 全部成交\n",
"Context: 订单已加入队列: Order(symbol='CZCE.FG601', direction='BUY', volume=1, id='CZCE.FG601_BUY_20251017211500', price_type='LIMIT', limit_price=1125, stop_price=None, submitted_time=Timestamp('2025-10-17 21:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
"Engine: 处理订单请求: Order(symbol='CZCE.FG601', direction='BUY', volume=1, id='CZCE.FG601_BUY_20251017211500', price_type='LIMIT', limit_price=1125, stop_price=None, submitted_time=Timestamp('2025-10-17 21:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
" INFO - 模拟交易下单 TQSIM, PYSDK_insert_eb18a1a9237778c79666acd207f76702: 时间: 2025-10-17 21:15:00.000000, 合约: CZCE.FG601, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 1125.0\n",
" INFO - 模拟交易委托单 TQSIM, PYSDK_insert_eb18a1a9237778c79666acd207f76702: 全部成交\n",
"Context: 订单已加入队列: Order(symbol='CZCE.FG601', direction='CLOSE_LONG', volume=1, id='CZCE.FG601_CLOSE_LONG_20251017223000', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-10-17 22:30:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
"Engine: 处理订单请求: Order(symbol='CZCE.FG601', direction='CLOSE_LONG', volume=1, id='CZCE.FG601_CLOSE_LONG_20251017223000', price_type='MARKET', limit_price=None, stop_price=None, submitted_time=Timestamp('2025-10-17 22:30:00+0800', tz='Asia/Shanghai'), offset='CLOSE')\n",
" INFO - 模拟交易下单 TQSIM, PYSDK_target_48e62f08faa15a6e629c20770e7fe2d0: 时间: 2025-10-17 22:30:00.000000, 合约: CZCE.FG601, 开平: CLOSE, 方向: SELL, 手数: 1, 价格: 1113.0\n",
" INFO - 模拟交易委托单 TQSIM, PYSDK_target_48e62f08faa15a6e629c20770e7fe2d0: 全部成交\n",
"Context: 订单已加入队列: Order(symbol='CZCE.FG601', direction='BUY', volume=1, id='CZCE.FG601_BUY_20251024111500', price_type='LIMIT', limit_price=1105, stop_price=None, submitted_time=Timestamp('2025-10-24 11:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
"Engine: 处理订单请求: Order(symbol='CZCE.FG601', direction='BUY', volume=1, id='CZCE.FG601_BUY_20251024111500', price_type='LIMIT', limit_price=1105, stop_price=None, submitted_time=Timestamp('2025-10-24 11:15:00+0800', tz='Asia/Shanghai'), offset='OPEN')\n",
" INFO - 模拟交易下单 TQSIM, PYSDK_insert_cbe9a4c43285732cf01979eded2c27af: 时间: 2025-10-24 11:15:00.000000, 合约: CZCE.FG601, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 1105.0\n",
" INFO - 模拟交易委托单 TQSIM, PYSDK_insert_cbe9a4c43285732cf01979eded2c27af: 全部成交\n",
" INFO - 回测结束\n",
" INFO - 模拟交易成交记录, 账户: TQSIM\n",
" INFO - 时间: 2025-09-04 21:15:00.000000, 合约: CZCE.FG601, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 1148.000,手续费: 3.00\n",
" INFO - 时间: 2025-09-04 22:15:00.000000, 合约: CZCE.FG601, 开平: CLOSE, 方向: SELL, 手数: 1, 价格: 1140.000,手续费: 3.00\n",
" INFO - 时间: 2025-09-09 21:15:00.000000, 合约: CZCE.FG601, 开平: OPEN, 方向: SELL, 手数: 1, 价格: 1171.000,手续费: 3.00\n",
" INFO - 时间: 2025-09-09 22:30:00.000000, 合约: CZCE.FG601, 开平: CLOSE, 方向: BUY, 手数: 1, 价格: 1171.000,手续费: 3.00\n",
" INFO - 时间: 2025-09-18 09:15:00.000000, 合约: CZCE.FG601, 开平: OPEN, 方向: SELL, 手数: 1, 价格: 1217.000,手续费: 3.00\n",
" INFO - 时间: 2025-09-18 10:30:00.000000, 合约: CZCE.FG601, 开平: CLOSE, 方向: BUY, 手数: 1, 价格: 1225.000,手续费: 3.00\n",
" INFO - 时间: 2025-09-18 13:30:00.000000, 合约: CZCE.FG601, 开平: OPEN, 方向: SELL, 手数: 1, 价格: 1207.000,手续费: 3.00\n",
" INFO - 时间: 2025-09-18 21:45:00.000000, 合约: CZCE.FG601, 开平: CLOSE, 方向: BUY, 手数: 1, 价格: 1205.000,手续费: 3.00\n",
" INFO - 时间: 2025-09-19 21:15:00.000000, 合约: CZCE.FG601, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 1225.000,手续费: 3.00\n",
" INFO - 时间: 2025-09-19 22:00:00.000000, 合约: CZCE.FG601, 开平: CLOSE, 方向: SELL, 手数: 1, 价格: 1223.000,手续费: 3.00\n",
" INFO - 时间: 2025-09-24 09:15:00.000000, 合约: CZCE.FG601, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 1203.000,手续费: 3.00\n",
" INFO - 时间: 2025-09-24 10:00:00.000000, 合约: CZCE.FG601, 开平: CLOSE, 方向: SELL, 手数: 1, 价格: 1196.000,手续费: 3.00\n",
" INFO - 时间: 2025-10-10 21:15:59.999999, 合约: CZCE.FG601, 开平: OPEN, 方向: SELL, 手数: 1, 价格: 1185.000,手续费: 3.00\n",
" INFO - 时间: 2025-10-10 22:00:00.000000, 合约: CZCE.FG601, 开平: CLOSE, 方向: BUY, 手数: 1, 价格: 1184.000,手续费: 3.00\n",
" INFO - 时间: 2025-10-16 21:15:00.000000, 合约: CZCE.FG601, 开平: OPEN, 方向: SELL, 手数: 1, 价格: 1129.000,手续费: 3.00\n",
" INFO - 时间: 2025-10-16 22:15:00.000000, 合约: CZCE.FG601, 开平: CLOSE, 方向: BUY, 手数: 1, 价格: 1130.000,手续费: 3.00\n",
" INFO - 时间: 2025-10-17 21:15:59.999999, 合约: CZCE.FG601, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 1125.000,手续费: 3.00\n",
" INFO - 时间: 2025-10-17 22:30:00.000000, 合约: CZCE.FG601, 开平: CLOSE, 方向: SELL, 手数: 1, 价格: 1113.000,手续费: 3.00\n",
" INFO - 时间: 2025-10-24 11:15:00.000000, 合约: CZCE.FG601, 开平: OPEN, 方向: BUY, 手数: 1, 价格: 1105.000,手续费: 3.00\n",
" INFO - 模拟交易账户资金, 账户: TQSIM\n",
" INFO - 日期: 2025-09-01, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-09-02, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-09-03, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-09-04, 账户权益: 10000000.00, 可用资金: 10000000.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-09-05, 账户权益: 9999834.00, 可用资金: 9999834.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: -160.00, 市值: 0.00, 保证金: 0.00, 手续费: 6.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-09-08, 账户权益: 9999834.00, 可用资金: 9999834.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-09-09, 账户权益: 9999834.00, 可用资金: 9999834.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-09-10, 账户权益: 9999828.00, 可用资金: 9999828.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 6.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-09-11, 账户权益: 9999828.00, 可用资金: 9999828.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-09-12, 账户权益: 9999828.00, 可用资金: 9999828.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-09-15, 账户权益: 9999828.00, 可用资金: 9999828.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-09-16, 账户权益: 9999828.00, 可用资金: 9999828.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-09-17, 账户权益: 9999828.00, 可用资金: 9999828.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-09-18, 账户权益: 9999639.00, 可用资金: 9998541.00, 浮动盈亏: -20.00, 持仓盈亏: -20.00, 平仓盈亏: -160.00, 市值: 0.00, 保证金: 1098.00, 手续费: 9.00, 风险度: 0.01%\n",
" INFO - 日期: 2025-09-19, 账户权益: 9999696.00, 可用资金: 9999696.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 60.00, 市值: 0.00, 保证金: 0.00, 手续费: 3.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-09-22, 账户权益: 9999650.00, 可用资金: 9999650.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: -40.00, 市值: 0.00, 保证金: 0.00, 手续费: 6.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-09-23, 账户权益: 9999650.00, 可用资金: 9999650.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-09-24, 账户权益: 9999504.00, 可用资金: 9999504.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: -140.00, 市值: 0.00, 保证金: 0.00, 手续费: 6.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-09-25, 账户权益: 9999504.00, 可用资金: 9999504.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-09-26, 账户权益: 9999504.00, 可用资金: 9999504.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-09-29, 账户权益: 9999504.00, 可用资金: 9999504.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-09-30, 账户权益: 9999504.00, 可用资金: 9999504.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-10-09, 账户权益: 9999504.00, 可用资金: 9999504.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-10-10, 账户权益: 9999504.00, 可用资金: 9999504.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-10-13, 账户权益: 9999518.00, 可用资金: 9999518.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 20.00, 市值: 0.00, 保证金: 0.00, 手续费: 6.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-10-14, 账户权益: 9999518.00, 可用资金: 9999518.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-10-15, 账户权益: 9999518.00, 可用资金: 9999518.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-10-16, 账户权益: 9999518.00, 可用资金: 9999518.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-10-17, 账户权益: 9999492.00, 可用资金: 9999492.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: -20.00, 市值: 0.00, 保证金: 0.00, 手续费: 6.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-10-20, 账户权益: 9999246.00, 可用资金: 9999246.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: -240.00, 市值: 0.00, 保证金: 0.00, 手续费: 6.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-10-21, 账户权益: 9999246.00, 可用资金: 9999246.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-10-22, 账户权益: 9999246.00, 可用资金: 9999246.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-10-23, 账户权益: 9999246.00, 可用资金: 9999246.00, 浮动盈亏: 0.00, 持仓盈亏: 0.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 0.00, 手续费: 0.00, 风险度: 0.00%\n",
" INFO - 日期: 2025-10-24, 账户权益: 9998983.00, 可用资金: 9997885.00, 浮动盈亏: -260.00, 持仓盈亏: -260.00, 平仓盈亏: 0.00, 市值: 0.00, 保证金: 1098.00, 手续费: 3.00, 风险度: 0.01%\n",
" INFO - 胜率: 33.33%, 盈亏额比例: 0.16, 收益率: -0.01%, 年化收益率: -0.07%, 最大回撤: 0.01%, 年化夏普率: -215.1636,年化索提诺比率: -15.7689\n",
"回测结束:开始平仓所有剩余持仓...\n",
"TqsdkEngine: 回测运行完毕。\n",
"TqsdkEngine: API 已关闭。\n",
"\n",
"回测运行完毕。\n"
]
},
{
"ename": "KeyError",
"evalue": "'initial_capital'",
"output_type": "error",
"traceback": [
"\u001B[31m---------------------------------------------------------------------------\u001B[39m",
"\u001B[31mKeyError\u001B[39m Traceback (most recent call last)",
"\u001B[36mCell\u001B[39m\u001B[36m \u001B[39m\u001B[32mIn[12]\u001B[39m\u001B[32m, line 53\u001B[39m\n\u001B[32m 51\u001B[39m portfolio_snapshots = results[\u001B[33m\"\u001B[39m\u001B[33mportfolio_snapshots\u001B[39m\u001B[33m\"\u001B[39m]\n\u001B[32m 52\u001B[39m trade_history = results[\u001B[33m\"\u001B[39m\u001B[33mtrade_history\u001B[39m\u001B[33m\"\u001B[39m]\n\u001B[32m---> \u001B[39m\u001B[32m53\u001B[39m initial_capital_result = \u001B[43mresults\u001B[49m\u001B[43m[\u001B[49m\u001B[33;43m\"\u001B[39;49m\u001B[33;43minitial_capital\u001B[39;49m\u001B[33;43m\"\u001B[39;49m\u001B[43m]\u001B[49m\n\u001B[32m 54\u001B[39m bars = results[\u001B[33m\"\u001B[39m\u001B[33mall_bars\u001B[39m\u001B[33m\"\u001B[39m]\n\u001B[32m 56\u001B[39m \u001B[38;5;66;03m# --- 4. 结果分析与可视化 ---\u001B[39;00m\n",
"\u001B[31mKeyError\u001B[39m: 'initial_capital'"
]
}
],
"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
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,171 @@
import numpy as np
import pandas as pd
from typing import Optional, Dict, Any, List
from collections import deque
# 假设这些是你项目中的模块
from src.core_data import Bar, Order
from src.strategies.base_strategy import Strategy
from src.algo.TrendLine import calculate_latest_trendline_values_v2
class PriceRangeVolumeIntensityStrategy(Strategy):
"""
价格区间成交量强度策略 (V11 - 市场冲击强度版):
- 【核心修改】策略的强度指标从单纯的 `volume` 升级为 `volume * (bar.high - bar.low)`。
- 这个新指标能更准确地衡量市场的“冲击力”或“有效动能”,过滤掉高换手但价格停滞的无效信号。
- 继承了 V10 版本的高效无状态 deque 实现,仅改变了指标的输入源。
"""
def __init__(
self,
context: Any,
main_symbol: str,
strategy_mode: str,
trade_volume: int = 1,
trendline_n: int = 50,
intensity_kappa: float = 0.1,
intensity_lookback: int = 24,
intensity_entry_percent: float = 0.95,
intensity_exit_percent: float = 0.50,
order_direction: Optional[List[str]] = None,
enable_log: bool = True,
):
super().__init__(context, main_symbol, enable_log)
self.main_symbol = main_symbol
self.trade_volume = trade_volume
if strategy_mode not in ['TREND', 'REVERSION']:
raise ValueError(f"strategy_mode 必须是 'TREND''REVERSION', 但收到了 '{strategy_mode}'")
self.strategy_mode = strategy_mode
self.params = {
"order_direction": order_direction if order_direction is not None else ["BUY", "SELL"],
"trendline_n": trendline_n,
"intensity_kappa": intensity_kappa,
"intensity_lookback": intensity_lookback,
"intensity_entry_percent": intensity_entry_percent,
"intensity_exit_percent": intensity_exit_percent,
}
self.weights = np.exp(-self.params['intensity_kappa'] * np.arange(self.params['intensity_lookback'], 0, -1))
self.intensity_window: Optional[deque] = None
self.pos_meta: Dict[str, Dict[str, Any]] = {}
print(f"PriceRangeVolumeIntensityStrategy (V11) initialized.")
print(f"--- Strategy Mode SET TO: {self.strategy_mode} ---")
print(f"Intensity metric: volume * (high - low)")
def _calculate_single_intensity(self, metric_slice: np.ndarray) -> float:
"""根据一段“市场冲击”指标切片,计算最新的一个强度值。"""
intensity_unscaled = np.dot(metric_slice, self.weights)
return intensity_unscaled * self.params['intensity_kappa']
def on_init(self):
super().on_init()
self.pos_meta.clear()
self.intensity_window = None
def on_open_bar(self, open_price: float, symbol: str):
bar_history = self.get_bar_history()
lookback = self.params['intensity_lookback']
min_bars_required = max(self.params['trendline_n'] + 2, 2 * lookback)
if len(bar_history) < min_bars_required:
return
# --- 【核心修改】计算新的“市场冲击”指标序列 ---
# 替代了之前的 all_volumes
market_impact_metric = np.array(
[(b.high - b.low) * 1 for b in bar_history],
dtype=float
)
# 简单的零值处理,防止 (high-low) 为 0 或负数(异常数据)导致的问题
market_impact_metric[market_impact_metric <= 0] = 1e-9
# --- 策略预热 (Warm-up) 与 增量更新 (逻辑不变,数据源已更新) ---
if self.intensity_window is None:
self.intensity_window = deque(maxlen=lookback)
print("Warming up the market impact intensity window...")
for i in range(len(market_impact_metric) - lookback, len(market_impact_metric)):
metric_slice = market_impact_metric[i - lookback : i]
intensity_value = self._calculate_single_intensity(metric_slice)
self.intensity_window.append(intensity_value)
print("Warm-up complete.")
else:
latest_metric_slice = market_impact_metric[-lookback:]
latest_intensity_value = self._calculate_single_intensity(latest_metric_slice)
self.intensity_window.append(latest_intensity_value)
self.cancel_all_pending_orders(symbol)
pos = self.get_current_positions().get(symbol, 0)
# --- 平仓与开仓逻辑 (完全不变,因为它们依赖于 intensity_window 的结果) ---
latest_intensity = self.intensity_window[-1]
# 1. 平仓逻辑
meta = self.pos_meta.get(symbol)
if meta and pos != 0:
exit_threshold = np.quantile(list(self.intensity_window), self.params['intensity_exit_percent'])
if latest_intensity < exit_threshold:
self.log(f"[{self.strategy_mode}模式] 市场冲击强度平仓信号,平仓。")
self.send_market_order("CLOSE_LONG" if meta['direction'] == "BUY" else "CLOSE_SHORT", abs(pos))
del self.pos_meta[symbol]
return
# 2. 开仓逻辑
if pos == 0:
signal = self._calculate_entry_signal(
self.strategy_mode, bar_history, self.params, self.intensity_window
)
if signal and signal in self.params['order_direction']:
self.log(f"[{self.strategy_mode}模式] 市场冲击强度开仓信号: {signal}")
self.send_open_order(signal, open_price, self.trade_volume)
# _calculate_entry_signal 函数完全不变,因为它只消费 intensity_window
def _calculate_entry_signal(self, mode: str, bar_history: List[Bar], params: Dict, intensity_window: deque) -> \
Optional[str]:
latest_intensity_value = intensity_window[-1]
entry_threshold = np.quantile(list(intensity_window), params['intensity_entry_percent'])
if not (latest_intensity_value > entry_threshold):
return None
close_prices = np.array([b.close for b in bar_history])
prices_for_trendline = close_prices[-params['trendline_n'] - 1:-1]
trend_upper, trend_lower = calculate_latest_trendline_values_v2(prices_for_trendline)
if trend_upper is not None and trend_lower is not None:
prev_close = bar_history[-2].close
last_close = bar_history[-1].close
upper_break_event = last_close > trend_upper and prev_close < trend_upper
lower_break_event = last_close < trend_lower and prev_close > trend_lower
if upper_break_event: return "BUY" if mode == 'TREND' else "SELL"
if lower_break_event: return "SELL" if mode == 'TREND' else "BUY"
return None
# 其他辅助函数 (send_order, on_rollover) 保持不变
def send_open_order(self, direction: str, entry_price: float, volume: int):
current_time = self.get_current_time()
order_id = f"{self.symbol}_{direction}_{current_time.strftime('%Y%m%d%H%M%S')}"
order_direction = "BUY" if direction == "BUY" else "SELL"
order = Order(id=order_id, symbol=self.symbol, direction=order_direction, volume=volume, price_type="MARKET",
submitted_time=current_time, offset="OPEN")
self.send_order(order)
self.pos_meta[self.symbol] = {
"direction": direction, "volume": volume, "entry_price": entry_price
}
self.log(
f"发送开仓订单 ({self.strategy_mode}): {direction} {volume}手 @ Market Price (执行价约 {entry_price:.2f})")
def send_market_order(self, direction: str, volume: int):
current_time = self.get_current_time()
order_id = f"{self.symbol}_{direction}_{current_time.strftime('%Y%m%d%H%M%S')}"
order = Order(id=order_id, symbol=self.symbol, direction=direction, volume=volume, price_type="MARKET",
submitted_time=current_time, offset="CLOSE")
self.send_order(order)
self.log(f"发送平仓订单: {direction} {volume}手 @ Market Price")
def on_rollover(self, old_symbol: str, new_symbol: str):
super().on_rollover(old_symbol, new_symbol)
self.cancel_all_pending_orders(new_symbol)
self.pos_meta.clear()
self.intensity_window = None

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
{
"pos_meta": {
"CZCE.FG405": {
"direction": "BUY",
"volume": 1,
"entry_price": 1908.0,
"strategy_mode": "TREND"
}
}
}

View File

@@ -0,0 +1,105 @@
import multiprocessing
from typing import Tuple, Dict, Any, Optional
from src.analysis.result_analyzer import ResultAnalyzer
from src.backtest_engine import BacktestEngine
from src.data_manager import DataManager
# --- 单个回测任务函数 ---
# 这个函数将在每个独立的进程中运行,因此它必须是自包含的
def run_single_backtest(
combination: Tuple[float, float], # 传入当前参数组合
common_config: Dict[str, Any] # 传入公共配置 (如数据路径, 初始资金等)
) -> Optional[Dict[str, Any]]:
"""
运行单个参数组合的回测任务。
此函数将在一个独立的进程中执行。
"""
print(123)
p1_value, p2_value = combination
# 从 common_config 中获取必要的配置
symbol = common_config['symbol']
data_path = common_config['data_path']
initial_capital = common_config['initial_capital']
slippage_rate = common_config['slippage_rate']
commission_rate = common_config['commission_rate']
start_time = common_config['start_time']
end_time = common_config['end_time']
roll_over_mode = common_config['roll_over_mode']
# bar_duration_seconds = common_config['bar_duration_seconds'] # 如果DataManager需要可以再传
param1_name = common_config['param1_name']
param2_name = common_config['param2_name']
# 每个进程内部独立初始化 DataManager 和 BacktestEngine
# 确保每个进程有自己的数据副本和模拟状态
data_manager = DataManager(
file_path=data_path,
symbol=symbol,
# bar_duration_seconds=bar_duration_seconds, # 如果DataManager需要根据数据文件路径推断或者额外参数传入
# start_date=start_time.date(), # DataManager 现在通过 file_path 和 symbol 处理数据
# end_date=end_time.date(),
)
# data_manager.load_data() # DataManager 内部加载数据
strategy_parameters = {
'main_symbol': common_config['main_symbol'],
'trade_volume': 1,
param1_name: p1_value, # 15分钟扫荡K线下影线占其总范围的最小比例。
param2_name: p2_value, # 15分钟限价单的入场点位于扫荡K线低点到收盘价的斐波那契回撤比例。
'order_direction': common_config['order_direction'],
'strategy_mode': common_config['strategy_mode'],
'enable_log': False, # 建议在调试和测试时开启日志
}
# 打印当前进程正在处理的组合信息
# 注意:多进程打印会交错显示
print(f"--- 正在运行组合: {strategy_parameters} (PID: {multiprocessing.current_process().pid}) ---")
try:
# 初始化回测引擎
engine = BacktestEngine(
data_manager=data_manager,
strategy_class=common_config['strategy'],
strategy_params=strategy_parameters,
initial_capital=initial_capital,
slippage_rate=slippage_rate,
commission_rate=commission_rate,
roll_over_mode=True, # 保持换月模式
start_time=common_config['start_time'],
end_time=common_config['end_time']
)
# 运行回测,传入时间范围
engine.run_backtest()
# 获取回测结果并分析
results = engine.get_backtest_results()
portfolio_snapshots = results["portfolio_snapshots"]
trade_history = results["trade_history"]
bars = results["all_bars"]
initial_capital_result = results["initial_capital"]
if portfolio_snapshots:
analyzer = ResultAnalyzer(portfolio_snapshots, trade_history, bars, initial_capital_result)
# analyzer.generate_report()
# analyzer.plot_performance()
metrics = analyzer.calculate_all_metrics()
# 将当前组合的参数和性能指标存储起来
result_entry = {**strategy_parameters, **metrics}
return result_entry
else:
print(
f" 组合 {strategy_parameters} 没有生成投资组合快照,无法进行结果分析。(PID: {multiprocessing.current_process().pid})")
# 返回一个包含参数和默认0值的结果以便追踪失败组合
return {**strategy_parameters, "total_return": 0.0, "annualized_return": 0.0, "sharpe_ratio": 0.0,
"max_drawdown": 0.0, "error": "No portfolio snapshots"}
except Exception as e:
import traceback
error_trace = traceback.format_exc()
print(
f" 组合 {strategy_parameters} 运行失败: {e}\n{error_trace} (PID: {multiprocessing.current_process().pid})")
# 返回错误信息,以便后续处理
return {**strategy_parameters, "error": str(e), "traceback": error_trace}