使用ctpplus,然后增加回测模块

This commit is contained in:
2026-06-06 16:40:15 +08:00
parent abed7371b3
commit d7ba8a8344
21 changed files with 4197 additions and 52 deletions
+85 -37
View File
@@ -7,6 +7,7 @@ import threading # 线程模块
import os # 操作系统模块
import json # JSON模块
import re # 正则表达式模块
import csv # CSV模块
import time as time_module # 标准库时间模块
from datetime import datetime, time as datetime_time # datetime时间对象
from multiprocessing import Process, Queue # 多进程模块
@@ -167,12 +168,23 @@ class OrderFlowTrader(TraderApiBase):
# 数据存储
self._json_save_counter = {} # JSON保存计数器
self.md_queue = md_queue # 行情队列
self._tick_record_counter = {} # tick录制计数器 {symbol: count}
# ============ 行情数据处理 ============
def tickcome(self, md_queue):
"""接收并处理Tick行情数据"""
data = md_queue # 从队列获取行情数据
# === tick录制(实盘模式) ===
if SYSTEM_CONFIG.get("record_tick", False):
instrument_id_raw = data["InstrumentID"]
symbol = instrument_id_raw.decode() if isinstance(instrument_id_raw, bytes) else instrument_id_raw
self._tick_record_counter[symbol] = self._tick_record_counter.get(symbol, 0) + 1
interval = SYSTEM_CONFIG.get("tick_record_interval", 1)
if self._tick_record_counter[symbol] % interval == 0:
self._record_tick_to_csv(data, symbol)
instrument_id = data["InstrumentID"].decode() # 解码合约代码
action_day = data["ActionDay"].decode() # 解码交易日期
update_time = data["UpdateTime"].decode() # 解码更新时间
@@ -215,6 +227,36 @@ class OrderFlowTrader(TraderApiBase):
}
self.on_tick(tick) # 调用Tick处理回调
def _record_tick_to_csv(self, data: dict, symbol: str):
"""录制 tick 数据到 CSV"""
data_dir = SYSTEM_CONFIG["data_dir"]
os.makedirs(data_dir, exist_ok=True)
csv_path = f"{data_dir}/{symbol}_tick.csv"
# CSV 字段
fields = [
"InstrumentID", "ActionDay", "UpdateTime", "UpdateMillisec",
"LastPrice", "Volume", "BidPrice1", "BidVolume1",
"AskPrice1", "AskVolume1", "UpperLimitPrice", "LowerLimitPrice",
"TradingDay", "Turnover", "OpenInterest"
]
# 写入字段(bytes 解码)
row = {}
for field in fields:
val = data.get(field)
if isinstance(val, bytes):
row[field] = val.decode()
else:
row[field] = val
file_exists = os.path.exists(csv_path)
with open(csv_path, 'a', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=fields)
if not file_exists:
writer.writeheader()
writer.writerow(row)
def on_tick(self, tick):
"""处理单个Tick数据"""
if tick["last_volume"] == 0: # 无成交量则返回
@@ -330,6 +372,8 @@ class OrderFlowTrader(TraderApiBase):
of = DataStore.ofdata.pop(symbol, None)
if of is not None:
self.data_of(symbol, of) # 写入交易DataFrame
# 保存 ofdata.json(改善时间戳对齐:旧K线完成时即保存)
self.save_ofdata_json(symbol)
# 清空旧K线的报价数据
with self._quote_lock:
@@ -1033,9 +1077,6 @@ class OrderFlowTrader(TraderApiBase):
# 计算Delta累计(必须在保存之前)
self.calculate_delta_cumulative(trade_df, param)
# 保存 ofdata.json(计算 delta累计 之后)
self.save_ofdata_json(instrument_id)
# 计算交易信号
bull_signal, bear_signal, dj_last, delta_last = self.calculate_signals(trade_df, param)
@@ -1146,44 +1187,51 @@ if __name__ == "__main__":
for symbol, config in TRADING_PARAMS.items():
param_dict[symbol] = TradingParam.from_config(symbol, config)
# 连接SimNow模拟交易
future_account = get_simulate_account(
investor_id=SIMNOW_CONFIG["investor_id"],
password=SIMNOW_CONFIG["password"],
server_name=SIMNOW_CONFIG["server_name"],
subscribe_list=list(param_dict.keys()),
)
# ===模式切换:回测模式 ===
if SYSTEM_CONFIG.get("mode", "live") == "backtest":
from backtest import Backtester
backtester = Backtester(param_dict)
backtester.run()
else:
# === 实盘/模拟模式 ===
# 连接SimNow模拟交易
future_account = get_simulate_account(
investor_id=SIMNOW_CONFIG["investor_id"],
password=SIMNOW_CONFIG["password"],
server_name=SIMNOW_CONFIG["server_name"],
subscribe_list=list(param_dict.keys()),
)
# 连接实盘(备用)
# from CtpPlus.CTP.FutureAccount import FutureAccount
# future_account = FutureAccount(...)
# 连接实盘(备用)
# from CtpPlus.CTP.FutureAccount import FutureAccount
# future_account = FutureAccount(...)
print("开始", len(future_account.subscribe_list))
print("开始", len(future_account.subscribe_list))
# 创建共享队列
share_queue = Queue(maxsize=SYSTEM_CONFIG["queue_share_size"])
# 创建共享队列
share_queue = Queue(maxsize=SYSTEM_CONFIG["queue_share_size"])
# 启动行情进程
md_process = Process(target=run_tick_engine, args=(future_account, [share_queue]))
# 启动行情进程
md_process = Process(target=run_tick_engine, args=(future_account, [share_queue]))
# 启动交易进程
trader_process = Process(
target=run_trader,
args=(
param_dict,
future_account.broker_id,
future_account.server_dict["TDServer"],
future_account.investor_id,
future_account.password,
future_account.app_id,
future_account.auth_code,
share_queue,
future_account.td_flow_path,
),
)
# 启动交易进程
trader_process = Process(
target=run_trader,
args=(
param_dict,
future_account.broker_id,
future_account.server_dict["TDServer"],
future_account.investor_id,
future_account.password,
future_account.app_id,
future_account.auth_code,
share_queue,
future_account.td_flow_path,
),
)
md_process.start() # 启动行情进程
trader_process.start() # 启动交易进程
md_process.start() # 启动行情进程
trader_process.start() # 启动交易进程
md_process.join() # 等待行情进程结束
trader_process.join() # 等待交易进程结束
md_process.join() # 等待行情进程结束
trader_process.join() # 等待交易进程结束