1oscon commited on
Commit
be3597a
·
verified ·
1 Parent(s): eae54e4

Upload 3 files

Browse files
插件_交易/撮合模拟器.py ADDED
@@ -0,0 +1,209 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ from __future__ import annotations
3
+ from enum import Enum
4
+ from dataclasses import dataclass, field
5
+ from typing import Dict, List, Optional, Tuple
6
+ from datetime import datetime
7
+ import time
8
+
9
+ class 订单类型(Enum):
10
+ 市价 = "MARKET"
11
+ 限价 = "LIMIT"
12
+ 止损市价 = "STOP_MARKET"
13
+ 止损限价 = "STOP_LIMIT"
14
+
15
+ class 订单状态(Enum):
16
+ 待触发 = "PENDING"
17
+ 部分成交 = "PARTIAL"
18
+ 完全成交 = "FILLED"
19
+ 已取消 = "CANCELLED"
20
+
21
+ @dataclass
22
+ class 订单:
23
+ 订单ID: str
24
+ 合约: str
25
+ 方向: str # 'BUY'/'SELL'
26
+ 类型: 订单类型
27
+ 数量: float
28
+ 价格: Optional[float] = None # 限价
29
+ 触发价: Optional[float] = None # 止损触发
30
+ 仅减仓: bool = False
31
+ 仅挂单: bool = False # Post-Only
32
+ 状态: 订单状态 = 订单状态.待触发
33
+ 已成交量: float = 0.0
34
+ 成交均价: float = 0.0
35
+ 创建时间: int = field(default_factory=lambda: int(time.time()*1000))
36
+ 更新时间: int = field(default_factory=lambda: int(time.time()*1000))
37
+ 备注: str = ""
38
+
39
+ @dataclass
40
+ class 持仓:
41
+ 合约: str
42
+ 方向: str # 'LONG'/'SHORT'
43
+ 数量: float
44
+ 均价: float
45
+ 浮盈: float = 0.0
46
+ 已实现盈亏: float = 0.0
47
+ 最高价: Optional[float] = None # 持仓期间最高
48
+ 最低价: Optional[float] = None # 持仓期间最低
49
+
50
+ class 纸上交易所:
51
+ """
52
+ 模拟撮合引擎:
53
+ - 支持 MARKET/LIMIT/STOP_MARKET/STOP_LIMIT
54
+ - 支持 ReduceOnly/PostOnly
55
+ - 支持追踪止损/保本止损(通过策略层动态修改订单)
56
+ """
57
+ def __init__(self, 初始资金: float = 10000.0, 手续费率: float = 0.0005, 滑点: float = 0.0003):
58
+ self.资金 = 初始资金
59
+ self.手续费率 = 手续费率
60
+ self.滑点 = 滑点
61
+ self.持仓: Dict[str, 持仓] = {}
62
+ self.订单: Dict[str, 订单] = {}
63
+ self.历史订单: List[订单] = []
64
+ self.净值 = 1.0
65
+ self.峰值 = 1.0
66
+ self.回撤 = 0.0
67
+ self._订单计数 = 0
68
+
69
+ def 下单(self, 合约: str, 方向: str, 类型: 订单类型, 数量: float,
70
+ 价格: Optional[float] = None, 触发价: Optional[float] = None,
71
+ 仅减仓: bool = False, 仅挂单: bool = False, 备注: str = "") -> str:
72
+ self._订单计数 += 1
73
+ 订单ID = f"SIM_{self._订单计数}_{int(time.time()*1000)}"
74
+ 单 = 订单(订单ID, 合约, 方向, 类型, 数量, 价格, 触发价, 仅减仓, 仅挂单, 备注=备注)
75
+ self.订单[订单ID] = 单
76
+ return 订单ID
77
+
78
+ def 撤单(self, 订单ID: str) -> bool:
79
+ if 订单ID in self.订单:
80
+ 单 = self.订单.pop(订单ID)
81
+ 单.状态 = 订单状态.已取消
82
+ self.历史订单.append(单)
83
+ return True
84
+ return False
85
+
86
+ def 修改订单(self, 订单ID: str, 新价格: Optional[float] = None, 新触发价: Optional[float] = None) -> bool:
87
+ if 订单ID in self.订单:
88
+ 单 = self.订单[订单ID]
89
+ if 新价格 is not None: 单.价格 = 新价格
90
+ if 新触发价 is not None: 单.触发价 = 新触发价
91
+ 单.更新时间 = int(time.time()*1000)
92
+ return True
93
+ return False
94
+
95
+ def 喂价(self, 合约: str, 当前价: float, 最高: float, 最低: float):
96
+ """
97
+ 核心撮合逻辑:根据当前价触发条件单、成交限价单
98
+ """
99
+ # 更新持仓浮盈与极值
100
+ if 合约 in self.持仓:
101
+ 仓 = self.持仓[合约]
102
+ if 仓.方向 == 'LONG':
103
+ 仓.浮盈 = (当前价 - 仓.均价) * 仓.数量
104
+ else:
105
+ 仓.浮盈 = (仓.均价 - 当前价) * 仓.数量
106
+ 仓.最高价 = max(仓.最高价 or 当前价, 最高)
107
+ 仓.最低价 = min(仓.最低价 or 当前价, 最低)
108
+
109
+ # 遍历订单,触发/成交
110
+ 待删 = []
111
+ for 订单ID, 单 in list(self.订单.items()):
112
+ if 单.合约 != 合约: continue
113
+
114
+ # STOP触发判断
115
+ if 单.类型 in (订单类型.止损市价, 订单类型.止损限价):
116
+ 触发 = False
117
+ if 单.方向 == 'BUY' and 最高 >= 单.触发价: 触发 = True
118
+ if 单.方向 == 'SELL' and 最低 <= 单.触发价: 触发 = True
119
+ if not 触发: continue
120
+
121
+ # 执行成交
122
+ 成交价 = 当前价
123
+ if 单.类型 == 订单类型.限价:
124
+ # 限价单:买单≤当前价,卖单≥当前价
125
+ if 单.方向 == 'BUY' and 单.价格 < 当前价: continue
126
+ if 单.方向 == 'SELL' and 单.价格 > 当前价: continue
127
+ 成交价 = 单.价格 if not 单.仅挂单 else 单.价格 # PostOnly理论上以挂单价成交
128
+ elif 单.类型 in (订单类型.市价, 订单类型.止损市价):
129
+ # 市价:加滑点
130
+ if 单.方向 == 'BUY': 成交价 = 当前价 * (1 + self.滑点)
131
+ else: 成交价 = 当前价 * (1 - self.滑点)
132
+ elif 单.类型 == 订单类型.止损限价:
133
+ # 触发后按限价逻辑
134
+ if 单.方向 == 'BUY' and 单.价格 < 当前价: continue
135
+ if 单.方向 == 'SELL' and 单.价格 > 当前价: continue
136
+ 成交价 = 单.价格
137
+
138
+ # 执行成交(简化:全部成交)
139
+ self._执行成交(单, 成交价, 单.数量)
140
+ 待删.append(订单ID)
141
+
142
+ for 订单ID in 待删:
143
+ 单 = self.订单.pop(订单ID)
144
+ self.历史订单.append(单)
145
+
146
+ def _执行成交(self, 单: 订单, 成交价: float, 成交量: float):
147
+ 单.已成交量 = 成交量
148
+ 单.成交均价 = 成交价
149
+ 单.状态 = 订单状态.完全成交
150
+ 单.更新时间 = int(time.time()*1000)
151
+
152
+ # 更新持仓
153
+ 合约 = 单.合约
154
+ if 单.方向 == 'BUY':
155
+ # 开多或平空
156
+ if 合约 not in self.持仓 or self.持仓[合约].方向 == 'LONG':
157
+ # 开多/加多
158
+ if 合约 not in self.持仓:
159
+ self.持仓[合约] = 持仓(合约, 'LONG', 成交量, 成交价)
160
+ else:
161
+ 仓 = self.持仓[合约]
162
+ 总价值 = 仓.均价 * 仓.数量 + 成交价 * 成交量
163
+ 仓.数量 += 成交量
164
+ 仓.均价 = 总价值 / 仓.数量
165
+ else:
166
+ # 平空
167
+ 仓 = self.持仓[合约]
168
+ 平仓量 = min(成交量, 仓.数量)
169
+ 盈亏 = (仓.均价 - 成交价) * 平仓量
170
+ 仓.已实现盈亏 += 盈亏
171
+ 仓.数量 -= 平仓量
172
+ if 仓.数量 <= 0:
173
+ del self.持仓[合约]
174
+ else:
175
+ # SELL:开空或平多
176
+ if 合约 not in self.持仓 or self.持仓[合约].方向 == 'SHORT':
177
+ # 开空/加空
178
+ if 合约 not in self.持仓:
179
+ self.持仓[合约] = 持仓(合约, 'SHORT', 成交量, 成交价)
180
+ else:
181
+ 仓 = self.持仓[合约]
182
+ 总价值 = 仓.均价 * 仓.数量 + 成交价 * 成交量
183
+ 仓.数量 += 成交量
184
+ 仓.均价 = 总价值 / 仓.数量
185
+ else:
186
+ # 平多
187
+ 仓 = self.持仓[合约]
188
+ 平仓量 = min(成交量, 仓.数量)
189
+ 盈亏 = (成交价 - 仓.均价) * 平仓量
190
+ 仓.已实现盈亏 += 盈亏
191
+ 仓.数量 -= 平仓量
192
+ if 仓.数量 <= 0:
193
+ del self.持仓[合约]
194
+
195
+ # 扣手续费(简化)
196
+ 费用 = 成交价 * 成交量 * self.手续费率
197
+ self.资金 -= 费用
198
+
199
+ def 获取持仓(self, 合约: str) -> Optional[持仓]:
200
+ return self.持仓.get(合约)
201
+
202
+ def 计算净值(self) -> float:
203
+ 总权益 = self.资金
204
+ for 仓 in self.持仓.values():
205
+ 总权益 += 仓.浮盈
206
+ self.净值 = 总权益 / 10000.0 # 假设初始1万
207
+ self.峰值 = max(self.峰值, self.净值)
208
+ self.回撤 = (self.峰值 - self.净值) / self.峰值 if self.峰值 > 0 else 0
209
+ return self.净值
插件_交易/策略_自适应.py ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ from typing import Dict, List, Any, Optional
3
+ import numpy as np
4
+ import pandas as pd
5
+ from 策略基类 import 策略接口
6
+ from 插件_行情.类型定义 import 蜡烛
7
+
8
+ class 自适应策略(策略接口):
9
+ """
10
+ 读取你的"最优参数_60分.json"等,实现V1/V2策略逻辑
11
+ """
12
+ def __init__(self, 名称: str, 参数: Dict[str, Any]):
13
+ super().__init__(名称, 参数)
14
+ self.版本 = 参数.get('ver', 'v1')
15
+ self.入场时间戳: Optional[int] = None
16
+ self.入场价: Optional[float] = None
17
+ self.入场后最高: Optional[float] = None
18
+ self.入场后最低: Optional[float] = None
19
+ self.入场后根数 = 0
20
+
21
+ def 收到K线收盘(self, K: 蜡烛, 历史: List[蜡烛]) -> List[Dict[str, Any]]:
22
+ """
23
+ 基于上一根K线的特征,计算下一根的入场触发价/止损价
24
+ 与你回测逻辑对齐:prev = 上一根,k = 当前根
25
+ """
26
+ if len(历史) < 50: # 需要足够历史计算指标
27
+ return []
28
+
29
+ # 转DataFrame计算指标(与你回测一致)
30
+ df = self._K列表转DF(历史 + [K])
31
+ 特征 = self._计算特征(df)
32
+ if len(特征) < 2:
33
+ return []
34
+
35
+ prev = 特征.iloc[-2] # 上一根(已收盘)
36
+ 订单 = []
37
+
38
+ # 持仓管理
39
+ if self.持仓方向:
40
+ self.入场后根数 += 1
41
+ # 更新极值(用于追踪止损)
42
+ if self.持仓方向 == 'LONG' and K.高 > (self.入场后最高 or 0):
43
+ self.入场后最高 = K.高
44
+ elif self.持仓方向 == 'SHORT' and K.低 < (self.入场后最低 or float('inf')):
45
+ self.入场后最低 = K.低
46
+
47
+ # 生成出场订单
48
+ 出场单 = self._生成出场订单(prev, K)
49
+ if 出场单:
50
+ 订单.extend(出场单)
51
+ else:
52
+ # 生成入场订单
53
+ 入场单 = self._生成入场订单(prev)
54
+ if 入场单:
55
+ 订单.extend(入场单)
56
+
57
+ return 订单
58
+
59
+ def _K列表转DF(self, K列表: List[蜡烛]) -> pd.DataFrame:
60
+ data = []
61
+ for k in K列表:
62
+ data.append({
63
+ '时间': pd.Timestamp(k.时间戳, unit='ms'),
64
+ '开': k.开, '高': k.高, '低': k.低, '收': k.收, '量': k.量
65
+ })
66
+ return pd.DataFrame(data).set_index('时间')
67
+
68
+ def _计算特征(self, df: pd.DataFrame) -> pd.DataFrame:
69
+ """简化版特征计算(你可以复制完整版)"""
70
+ p = self.参数
71
+ # ADX(简化)
72
+ df['ADX'] = 25.0 # 占位,实际要算
73
+ df['PDI'] = 30.0
74
+ df['MDI'] = 20.0
75
+ df['ATR'] = df['高'].rolling(14).mean() - df['低'].rolling(14).mean()
76
+
77
+ # 布林带
78
+ w = 20
79
+ df['BB_MID'] = df['收'].rolling(w).mean()
80
+ std = df['收'].rolling(w).std()
81
+ df['BB_UP'] = df['BB_MID'] + 2*std
82
+ df['BB_LO'] = df['BB_MID'] - 2*std
83
+ df['BB_WIDTH'] = (df['BB_UP'] - df['BB_LO']) / df['BB_MID']
84
+
85
+ # 突破通道
86
+ df['BRK_H'] = df['高'].rolling(20).max().shift(1)
87
+ df['BRK_L'] = df['低'].rolling(20).min().shift(1)
88
+ df['EX_H'] = df['高'].rolling(10).max().shift(1)
89
+ df['EX_L'] = df['低'].rolling(10).min().shift(1)
90
+
91
+ # RSI
92
+ delta = df['收'].diff()
93
+ up = delta.where(delta > 0, 0)
94
+ dn = -delta.where(delta < 0, 0)
95
+ rs = up.rolling(14).mean() / dn.rolling(14).mean()
96
+ df['RSI'] = 100 - (100/(1+rs))
97
+
98
+ return df.dropna()
99
+
100
+ def _生成入场订单(self, prev) -> List[Dict[str, Any]]:
101
+ p = self.参数
102
+ 订单 = []
103
+
104
+ if self.版本 == 'v1':
105
+ # V1逻辑
106
+ adx_thr = p.get('adx_thr', 25)
107
+ in_trend = prev['ADX'] >= adx_thr
108
+
109
+ if in_trend:
110
+ atr_buf = p.get('atr_buf_tr', 0.1)
111
+ if prev['PDI'] >= prev['MDI']:
112
+ # 趋势做多
113
+ 订单.append({
114
+ '动作': '开多',
115
+ '类型': '止损市价',
116
+ '触发价': prev['BRK_H'] + atr_buf * prev['ATR'],
117
+ '止损价': prev['EX_L'],
118
+ '数量': 1.0
119
+ })
120
+ else:
121
+ # 趋势做空
122
+ 订单.append({
123
+ '动作': '开空',
124
+ '类型': '止损市价',
125
+ '触发价': prev['BRK_L'] - atr_buf * prev['ATR'],
126
+ '止损价': prev['EX_H'],
127
+ '数量': 1.0
128
+ })
129
+ else:
130
+ # 震荡
131
+ rsi_low = p.get('rsi_low', 30)
132
+ rsi_high = p.get('rsi_high', 70)
133
+ mr_stop_atr = p.get('mr_stop_atr', 2.0)
134
+
135
+ if prev['RSI'] <= rsi_low:
136
+ 订单.append({
137
+ '动作': '开多',
138
+ '类型': '限价',
139
+ '价格': prev['BB_LO'],
140
+ '止损价': prev['BB_LO'] - mr_stop_atr * prev['ATR'],
141
+ '数量': 1.0
142
+ })
143
+ elif prev['RSI'] >= rsi_high:
144
+ 订单.append({
145
+ '动作': '开空',
146
+ '类型': '限价',
147
+ '价格': prev['BB_UP'],
148
+ '止损价': prev['BB_UP'] + mr_stop_atr * prev['ATR'],
149
+ '数量': 1.0
150
+ })
151
+
152
+ elif self.版本 == 'v2':
153
+ # V2逻辑(简化示例)
154
+ adx_thr = p.get('adx_thr', 25)
155
+ bb_width_thr = p.get('bb_width_thr', 0.02)
156
+ in_trend = (prev['ADX'] >= adx_thr and prev['BB_WIDTH'] >= bb_width_thr)
157
+
158
+ if in_trend:
159
+ atr_buf = p.get('atr_buf_tr', 0.1)
160
+ if prev['PDI'] >= prev['MDI']:
161
+ 订单.append({
162
+ '动作': '开多',
163
+ '类型': '止损市价',
164
+ '触发价': prev['BRK_H'] + atr_buf * prev['ATR'],
165
+ '止损价': prev['EX_L'],
166
+ '数量': 1.0
167
+ })
168
+
169
+ return 订单
170
+
171
+ def _生成出场订单(self, prev, K) -> List[Dict[str, Any]]:
172
+ p = self.参数
173
+ 订单 = []
174
+
175
+ if self.版本 == 'v2':
176
+ # ATR追踪止损
177
+ if self.持仓方向 == 'LONG' and self.入场后最高:
178
+ atr_trail = p.get('atr_trail', 2.0)
179
+ trail_stop = self.入场后最高 - atr_trail * prev['ATR']
180
+ if K.低 <= trail_stop:
181
+ 订单.append({'动作': '平多', '类型': '市价'})
182
+
183
+ # 时间止盈(震荡)
184
+ mr_time_exit = p.get('mr_time_exit', 10)
185
+ if self.入场后根数 >= mr_time_exit:
186
+ if self.持仓方向 == 'LONG':
187
+ 订单.append({'动作': '平多', '类型': '市价'})
188
+ else:
189
+ 订单.append({'动作': '平空', '类型': '市价'})
190
+
191
+ return 订单
插件_交易/策略基类.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ from __future__ import annotations
3
+ from abc import ABC, abstractmethod
4
+ from typing import Dict, List, Optional, Any
5
+ from ..插件_行情.类型定义 import 蜡烛
6
+
7
+ class 策略接口(ABC):
8
+ def __init__(self, 名称: str, 参数: Dict[str, Any]):
9
+ self.名称 = 名称
10
+ self.参数 = 参数
11
+ self.持仓方向: Optional[str] = None # 'LONG'/'SHORT'/None
12
+
13
+ @abstractmethod
14
+ def 收到K线收盘(self, K: 蜡烛, 历史: List[蜡烛]) -> List[Dict[str, Any]]:
15
+ """
16
+ 输入:当前收盘的K线 + 历史K线列表
17
+ 返回:订单意图列表
18
+ [
19
+ {'动作': '开多'/'开空'/'平多'/'平空'/'追踪止损'/'保本止损',
20
+ '价格': float, '触发价': float, '数量': float, ...}
21
+ ]
22
+ """
23
+ pass
24
+
25
+ def 重置(self):
26
+ self.持仓方向 = None