tinytrader 0.2.0__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tinytrader/3.10/_tinytrader.pyd +0 -0
- tinytrader/3.11/_tinytrader.pyd +0 -0
- tinytrader/3.12/_tinytrader.pyd +0 -0
- tinytrader/3.13/_tinytrader.pyd +0 -0
- tinytrader/3.9/_tinytrader.pyd +0 -0
- tinytrader/__init__.py +267 -0
- tinytrader/thostmduserapi_se.dll +0 -0
- tinytrader/thosttraderapi_se.dll +0 -0
- tinytrader-0.2.0.dist-info/METADATA +407 -0
- tinytrader-0.2.0.dist-info/RECORD +13 -0
- tinytrader-0.2.0.dist-info/WHEEL +5 -0
- tinytrader-0.2.0.dist-info/licenses/LICENSE +22 -0
- tinytrader-0.2.0.dist-info/top_level.txt +1 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
tinytrader/__init__.py
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TinyTrader - Lightweight C++ trading engine with Python bindings
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
import importlib.util
|
|
7
|
+
import os
|
|
8
|
+
from datetime import datetime, timedelta, timezone
|
|
9
|
+
import time
|
|
10
|
+
from importlib.metadata import version
|
|
11
|
+
|
|
12
|
+
__version__ = version("tinytrader")
|
|
13
|
+
|
|
14
|
+
# 1. 添加 DLL 搜索路径
|
|
15
|
+
_pkg_dir = os.path.dirname(__file__)
|
|
16
|
+
if hasattr(os, "add_dll_directory"):
|
|
17
|
+
os.add_dll_directory(_pkg_dir)
|
|
18
|
+
|
|
19
|
+
# 2. 选择正确的 pyd 路径
|
|
20
|
+
_ext = '.pyd' if sys.platform == 'win32' else '.so'
|
|
21
|
+
_module_name = "_tinytrader" + _ext
|
|
22
|
+
_module_path = os.path.join(_pkg_dir, _module_name)
|
|
23
|
+
if not os.path.exists(_module_path):
|
|
24
|
+
_sub_dir = f"{sys.version_info.major}.{sys.version_info.minor}"
|
|
25
|
+
_module_path = os.path.join(_pkg_dir, _sub_dir, _module_name)
|
|
26
|
+
if not os.path.exists(_module_path):
|
|
27
|
+
raise ImportError(_module_name + " not found")
|
|
28
|
+
|
|
29
|
+
# 3. 如果模块已经加载,先清理(防止重复加载)
|
|
30
|
+
if "_tinytrader" in sys.modules:
|
|
31
|
+
del sys.modules["_tinytrader"]
|
|
32
|
+
|
|
33
|
+
# 4. 动态加载
|
|
34
|
+
spec = importlib.util.spec_from_file_location("_tinytrader", _module_path)
|
|
35
|
+
_tinytrader = importlib.util.module_from_spec(spec)
|
|
36
|
+
spec.loader.exec_module(_tinytrader)
|
|
37
|
+
|
|
38
|
+
# 5. 注册到 sys.modules(让后续导入使用缓存)
|
|
39
|
+
sys.modules["_tinytrader"] = _tinytrader
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
_current_module = sys.modules[__name__]
|
|
43
|
+
for name in dir(_tinytrader):
|
|
44
|
+
if not name.startswith("_"):
|
|
45
|
+
setattr(_current_module, name, getattr(_tinytrader, name))
|
|
46
|
+
|
|
47
|
+
# 设置 __all__
|
|
48
|
+
__all__ = [name for name in dir(_tinytrader) if not name.startswith("_")]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# ========== __repr__ ==========
|
|
54
|
+
|
|
55
|
+
def _contract_repr(self):
|
|
56
|
+
return f"{self.Code()}"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _enum_repr(self):
|
|
60
|
+
return f"{self.name}"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _order_repr(self):
|
|
64
|
+
return (f"Order(Instrument={self.Instrument}, Ref={self.Ref}, "
|
|
65
|
+
f"Size={self.Size:+d}, Price={self.Price}, Type={self.Type}, "
|
|
66
|
+
f"Flag={self.Flag}, Status={self.Status}, Error={self.Error}, "
|
|
67
|
+
f"FilledSize={self.FilledSize:+d}, TradedSize={self.TradedSize:+d}, "
|
|
68
|
+
f"TradedValue={self.TradedValue}, Canceling={self.Canceling})")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _trade_repr(self):
|
|
72
|
+
return (f"Trade(Instrument={self.Instrument}, Size={self.Size:+d}, "
|
|
73
|
+
f"Price={self.Price}, Flag={self.Flag}, OrderRef={self.OrderRef})")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _position_repr(self):
|
|
77
|
+
return (f"Position(Long={self.Long}, LongToday={self.LongToday}, "
|
|
78
|
+
f"Short={self.Short}, ShortToday={self.ShortToday})")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _position_entry_repr(self):
|
|
82
|
+
return (f"PositionEntry(Code={self.Code}, Long={self.Long}, "
|
|
83
|
+
f"LongToday={self.LongToday}, Short={self.Short}, "
|
|
84
|
+
f"ShortToday={self.ShortToday})")
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# 注入 __repr__
|
|
88
|
+
Contract.__repr__ = _contract_repr
|
|
89
|
+
|
|
90
|
+
for enum_cls in [Market, OrderType, TradeFlag, OrderStatus]:
|
|
91
|
+
enum_cls.__repr__ = _enum_repr
|
|
92
|
+
|
|
93
|
+
Order.__repr__ = _order_repr
|
|
94
|
+
Trade.__repr__ = _trade_repr
|
|
95
|
+
Position.__repr__ = _position_repr
|
|
96
|
+
PositionEntry.__repr__ = _position_entry_repr
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _order_eq(self, other):
|
|
102
|
+
if not isinstance(other, Order):
|
|
103
|
+
return False
|
|
104
|
+
return self.Ref == other.Ref
|
|
105
|
+
|
|
106
|
+
Order.__eq__ = _order_eq
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def AutoRun(config, strategy_class, *args, **kwargs):
|
|
110
|
+
"""初始化引擎、创建策略并运行"""
|
|
111
|
+
InitEngine(config)
|
|
112
|
+
strategy = strategy_class(*args, **kwargs)
|
|
113
|
+
Run(strategy)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def TodayAt(time_str: str):
|
|
118
|
+
"""获取当日指定时间点。
|
|
119
|
+
Args:
|
|
120
|
+
time (str): 时间字符串,格式 "HH:MM:SS"
|
|
121
|
+
Returns:
|
|
122
|
+
datetime.datetime: 当日指定时间点
|
|
123
|
+
"""
|
|
124
|
+
h, m, s = map(int, time_str.split(':'))
|
|
125
|
+
return Now().replace(hour=h, minute=m, second=s, microsecond=0)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _make_time_property(original_prop):
|
|
130
|
+
def getter(self):
|
|
131
|
+
offset = time.timezone if time.daylight == 0 else time.altzone
|
|
132
|
+
dt = original_prop.fget(self) + timedelta(seconds=offset)
|
|
133
|
+
return dt
|
|
134
|
+
return property(getter)
|
|
135
|
+
|
|
136
|
+
# nonobind 自动使用 local_time,需进行修正
|
|
137
|
+
Quote.MarketTime = _make_time_property(Quote.MarketTime)
|
|
138
|
+
Quote.ReceiveTime = _make_time_property(Quote.ReceiveTime)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
# ========== 类文档 ==========
|
|
145
|
+
|
|
146
|
+
Contract.__doc__ = """
|
|
147
|
+
合约对象。
|
|
148
|
+
|
|
149
|
+
用法:
|
|
150
|
+
c = Contract("rb2610")
|
|
151
|
+
|
|
152
|
+
方法:
|
|
153
|
+
Code() -> str: 合约代码
|
|
154
|
+
Exchange() -> Market: 所属交易所
|
|
155
|
+
TickSize() -> float: 最小变动价位
|
|
156
|
+
Multiplier() -> int: 合约乘数
|
|
157
|
+
ToTicks(price: float) -> int: 将价格转换为跳数
|
|
158
|
+
|
|
159
|
+
示例:
|
|
160
|
+
c = Contract("rb2610")
|
|
161
|
+
print(c.Code()) # "rb2610"
|
|
162
|
+
print(c.Exchange()) # SHFE
|
|
163
|
+
print(c.TickSize()) # 1.0
|
|
164
|
+
"""
|
|
165
|
+
|
|
166
|
+
Quote.__doc__ = """
|
|
167
|
+
行情数据。
|
|
168
|
+
|
|
169
|
+
字段说明:
|
|
170
|
+
Instrument (Contract): 合约
|
|
171
|
+
Price (float): 最新价
|
|
172
|
+
Volume (int): 成交量
|
|
173
|
+
BidPrice1 (float): 买一价
|
|
174
|
+
BidSize1 (int): 买一量
|
|
175
|
+
AskPrice1 (float): 卖一价
|
|
176
|
+
AskSize1 (int): 卖一量
|
|
177
|
+
Turnover (float): 成交金额
|
|
178
|
+
OpenInterest (float): 持仓量
|
|
179
|
+
MarketTime (datetime.datetime): 交易所时间
|
|
180
|
+
ReceiveTime (datetime.datetime): 本地接收时间
|
|
181
|
+
UpperLimitPrice (float): 涨停价
|
|
182
|
+
LowerLimitPrice (float): 跌停价
|
|
183
|
+
"""
|
|
184
|
+
|
|
185
|
+
NewOrder.__doc__ = """
|
|
186
|
+
下单请求结构。
|
|
187
|
+
|
|
188
|
+
字段说明:
|
|
189
|
+
Instrument (Contract): 合约
|
|
190
|
+
Size (int): 委托量,正=买,负=卖
|
|
191
|
+
Price (float): 委托价格
|
|
192
|
+
Type (OrderType): 订单类型
|
|
193
|
+
Flag (TradeFlag): 开平标志
|
|
194
|
+
|
|
195
|
+
示例:
|
|
196
|
+
order = NewOrder()
|
|
197
|
+
order.Instrument = Contract("rb2610")
|
|
198
|
+
order.Size = -2
|
|
199
|
+
order.Price = 4100
|
|
200
|
+
"""
|
|
201
|
+
|
|
202
|
+
Order.__doc__ = """
|
|
203
|
+
订单对象(继承自 NewOrder)。
|
|
204
|
+
|
|
205
|
+
额外字段:
|
|
206
|
+
Status (OrderStatus): 订单状态
|
|
207
|
+
Canceling (bool): 是否有撤单指令在途
|
|
208
|
+
Ref (int): 订单索引
|
|
209
|
+
Error (OrderError): 错误码,0 表示无错误
|
|
210
|
+
FilledSize (int): 已成交数量(带方向)
|
|
211
|
+
TradedSize (int): 累计成交量(带方向)
|
|
212
|
+
TradedValue (float): 累计成交金额
|
|
213
|
+
|
|
214
|
+
方法:
|
|
215
|
+
Terminated() -> bool: 订单是否已结束(Filled / Canceled / Rejected)
|
|
216
|
+
Cancelable() -> bool: 订单是否可撤(Queuing 且无撤单在途)
|
|
217
|
+
AveragePrice() -> float: 成交均价
|
|
218
|
+
"""
|
|
219
|
+
|
|
220
|
+
Trade.__doc__ = """
|
|
221
|
+
成交回报。
|
|
222
|
+
|
|
223
|
+
字段说明:
|
|
224
|
+
Instrument (Contract): 合约
|
|
225
|
+
Size (int): 成交量,正=买,负=卖
|
|
226
|
+
Price (float): 成交价
|
|
227
|
+
Flag (TradeFlag): 开平标志
|
|
228
|
+
OrderRef (int): 对应的订单索引
|
|
229
|
+
|
|
230
|
+
方法:
|
|
231
|
+
Value() -> float: 成交金额 = abs(Size) * Multiplier * Price
|
|
232
|
+
"""
|
|
233
|
+
|
|
234
|
+
Position.__doc__ = """
|
|
235
|
+
持仓汇总。
|
|
236
|
+
|
|
237
|
+
字段说明:
|
|
238
|
+
Long (int): 多头总持仓
|
|
239
|
+
LongToday (int): 多头今仓
|
|
240
|
+
Short (int): 空头总持仓
|
|
241
|
+
ShortToday (int): 空头今仓
|
|
242
|
+
"""
|
|
243
|
+
|
|
244
|
+
PositionEntry.__doc__ = """
|
|
245
|
+
单个合约的持仓(继承自 Position)。
|
|
246
|
+
|
|
247
|
+
额外字段:
|
|
248
|
+
Code (str): 合约代码
|
|
249
|
+
"""
|
|
250
|
+
|
|
251
|
+
Config.__doc__ = """
|
|
252
|
+
引擎配置。
|
|
253
|
+
|
|
254
|
+
字段说明:
|
|
255
|
+
UserID (str): 资金账号
|
|
256
|
+
Password (str): 密码
|
|
257
|
+
AppID (str): AppID
|
|
258
|
+
AuthCode (str): 授权码
|
|
259
|
+
BrokerID (str): 经纪公司代码
|
|
260
|
+
TradeFront (str): 交易前置地址
|
|
261
|
+
MarketFront (str): 行情前置地址
|
|
262
|
+
LogPath (str): 日志文件路径
|
|
263
|
+
CachePath (str): 合约信息缓存路径
|
|
264
|
+
MaxOrderCount (int): 订单笔数上限,默认 10000
|
|
265
|
+
TimerInterval (int): 定时器间隔(毫秒),默认 100
|
|
266
|
+
BusyLoop (bool): 是否占满 CPU 核,默认 True
|
|
267
|
+
"""
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tinytrader
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Light Weight C++ Trading Engine with Python Binding
|
|
5
|
+
Author-email: tinytrader <tinytrader@163.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
14
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
15
|
+
Requires-Python: <3.14,>=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# TinyTrader —— Strategy to Live Trading in One Line
|
|
21
|
+
|
|
22
|
+
**极简轻量,一行实盘。**
|
|
23
|
+
|
|
24
|
+
TinyTrader 是一个基于 CTP 的 C++ 交易引擎,同时提供 Python 接口。支持单账户、单策略的期货与期权交易。
|
|
25
|
+
|
|
26
|
+
主要特点:
|
|
27
|
+
|
|
28
|
+
- **极简**————无抽象概念、无配置文件,写好策略、填上账号,一行代码启动实盘。
|
|
29
|
+
|
|
30
|
+
- **轻量**————核心代码不到 1000 行。
|
|
31
|
+
|
|
32
|
+
- **快速**————单线程事件模型,全程无锁,微秒级响应。
|
|
33
|
+
|
|
34
|
+
## 📦 快速开始
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install tinytrader
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**零依赖。** 不安装任何第三方包。支持 Python 3.9 至 3.13 版本。
|
|
41
|
+
|
|
42
|
+
一个完整的交易程序(`examples/minimal.py`):启动后立即下单。
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
import tinytrader as tt
|
|
46
|
+
|
|
47
|
+
class MyStrategy(tt.Strategy):
|
|
48
|
+
def OnStart(self):
|
|
49
|
+
order = tt.NewOrder()
|
|
50
|
+
order.Instrument = tt.Contract("rb2610")
|
|
51
|
+
order.Size = -2
|
|
52
|
+
order.Price = 4100
|
|
53
|
+
self.Insert(order)
|
|
54
|
+
|
|
55
|
+
if __name__ == "__main__":
|
|
56
|
+
config = tt.Config()
|
|
57
|
+
config.UserID = "12345678"
|
|
58
|
+
config.Password = "my_password"
|
|
59
|
+
config.AppID = "simnow_client_test"
|
|
60
|
+
config.AuthCode = "0000000000000000"
|
|
61
|
+
config.BrokerID = "9999"
|
|
62
|
+
config.TradeFront = "tcp://182.254.243.31:30002"
|
|
63
|
+
config.MarketFront = "tcp://182.254.243.31:30012"
|
|
64
|
+
# 以上为 CTP 账号及地址
|
|
65
|
+
|
|
66
|
+
tt.AutoRun(config, MyStrategy) # 一行启动
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
策略启动后立即以 4100 的价格卖出 2 手 rb2610。`Size` 大于 0 为买单,小于 0 为卖单。开平标志默认自动(平仓优先)。
|
|
70
|
+
|
|
71
|
+
同样的功能,C++ 版 (`examples/minimal.cpp`):
|
|
72
|
+
|
|
73
|
+
```cpp
|
|
74
|
+
#include "tinytrader.h"
|
|
75
|
+
|
|
76
|
+
using namespace tinytrader;
|
|
77
|
+
|
|
78
|
+
class MyStrategy : public Strategy
|
|
79
|
+
{
|
|
80
|
+
void OnStart() override
|
|
81
|
+
{
|
|
82
|
+
NewOrder order;
|
|
83
|
+
order.Instrument = "rb2610";
|
|
84
|
+
order.Size = -2;
|
|
85
|
+
order.Price = 4100;
|
|
86
|
+
Insert(order);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
int main()
|
|
91
|
+
{
|
|
92
|
+
Config config;
|
|
93
|
+
config.UserID = "12345678";
|
|
94
|
+
config.Password = "my_password";
|
|
95
|
+
config.AppID = "simnow_client_test";
|
|
96
|
+
config.AuthCode = "0000000000000000";
|
|
97
|
+
config.BrokerID = "9999";
|
|
98
|
+
config.TradeFront = "tcp://182.254.243.31:30002";
|
|
99
|
+
config.MarketFront = "tcp://182.254.243.31:30012";
|
|
100
|
+
// 以上为 CTP 账号及地址
|
|
101
|
+
|
|
102
|
+
return AutoRun<MyStrategy>(config); // 一行启动
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
和 Python 版一样简单!C++ 不仅速度更快,编译成二进制后可以更好地保护策略逻辑。
|
|
107
|
+
|
|
108
|
+
更多示例见 `examples` 目录,同时有 C++ 和 Python 版本。
|
|
109
|
+
|
|
110
|
+
## ⚠️ 安全警告
|
|
111
|
+
|
|
112
|
+
示例程序为保持简洁,直接将账号密码写在代码中。**此举可能导致密码泄露**,实盘应尽量手动输入密码。
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
## 📦 C++ 编译
|
|
116
|
+
|
|
117
|
+
依赖项 CTP API 、fmtlib、fmtlog、magic_enum 均已包含在 third_party 目录中。
|
|
118
|
+
|
|
119
|
+
编译器需支持 C++17 标准 (GCC 11.5 和 MSVC 2022 已测试)。
|
|
120
|
+
|
|
121
|
+
进入 TinyTrader 代码目录,执行以下命令,即可生成所有示例程序。
|
|
122
|
+
```bash
|
|
123
|
+
mkdir build
|
|
124
|
+
cd build
|
|
125
|
+
cmake ..
|
|
126
|
+
cmake --build . --config Release
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
如需调试版,将最后一行的 `Release` 改成 `Debug` 即可。
|
|
130
|
+
|
|
131
|
+
如果使用 Visual Studio,还可以直接用 VS 打开文件夹,然后在菜单栏选择 "生成"->"全部生成"。
|
|
132
|
+
|
|
133
|
+
如需从源码编译 Python 接口,可参考 `docs/build_python.md`。
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
## 📦 下单参数
|
|
137
|
+
|
|
138
|
+
`NewOrder` 包含全部下单参数:
|
|
139
|
+
|
|
140
|
+
| 字段 | 类型 | 说明 |
|
|
141
|
+
| :--- | :--- | :--- |
|
|
142
|
+
| `Instrument` | `Contract` | 合约,如 `"rb2610"` |
|
|
143
|
+
| `Size` | `int` | 委托量,**正=买,负=卖** |
|
|
144
|
+
| `Price` | 浮点数 | 价格 |
|
|
145
|
+
| `Type` | `OrderType` | 订单类型,默认 `GFD`(单日有效) |
|
|
146
|
+
| `Flag` | `TradeFlag` | 开平标志,默认 `Auto`(自动开平) |
|
|
147
|
+
|
|
148
|
+
**订单类型:**
|
|
149
|
+
|
|
150
|
+
| 类型 | 说明 |
|
|
151
|
+
| :--- | :--- |
|
|
152
|
+
| `GFD` | 单日有效 |
|
|
153
|
+
| `FAK` | 立即成交剩余撤销 |
|
|
154
|
+
| `FOK` | 立即全部成交否则撤销 |
|
|
155
|
+
|
|
156
|
+
**开平标志:**
|
|
157
|
+
|
|
158
|
+
| 标志 | 说明 |
|
|
159
|
+
| :--- | :--- |
|
|
160
|
+
| `Auto` | 自动开平(平仓优先) |
|
|
161
|
+
| `Open` | 开仓 |
|
|
162
|
+
| `Close` | 平仓 |
|
|
163
|
+
| `CloseToday` | 平今 |
|
|
164
|
+
| `CloseYesterday` | 平昨 |
|
|
165
|
+
|
|
166
|
+
上期所和能源中心明确区分平今平昨,如果使用 `Auto`,会根据现有仓位按照平今、平昨、开仓的优先级进行设置。
|
|
167
|
+
|
|
168
|
+
**Python:**
|
|
169
|
+
```python
|
|
170
|
+
order = tt.NewOrder()
|
|
171
|
+
order.Instrument = tt.Contract("rb2610")
|
|
172
|
+
order.Size = -2 # 卖 2 手
|
|
173
|
+
order.Price = 4100
|
|
174
|
+
order.Type = tt.OrderType.FAK
|
|
175
|
+
order.Flag = tt.TradeFlag.Auto
|
|
176
|
+
self.Insert(order)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**C++:**
|
|
180
|
+
```c++
|
|
181
|
+
NewOrder order;
|
|
182
|
+
order.Instrument = "rb2610";
|
|
183
|
+
order.Size = -2;
|
|
184
|
+
order.Price = 4100;
|
|
185
|
+
order.Type = OrderType::FAK;
|
|
186
|
+
order.Flag = TradeFlag::Auto;
|
|
187
|
+
Insert(order);
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## 📦 订单生命周期
|
|
191
|
+
|
|
192
|
+
订单主要有以下几种状态,由枚举类型 `OrderStatus` 表示:
|
|
193
|
+
|
|
194
|
+
| 状态 | 说明 |
|
|
195
|
+
| :--- | :--- |
|
|
196
|
+
| `Sent` | 已向柜台发送 |
|
|
197
|
+
| `Queuing` | 处于交易所队列中(含部分成交) |
|
|
198
|
+
| `Filled` | 全部成交 |
|
|
199
|
+
| `Canceled`| 已撤单 |
|
|
200
|
+
| `Rejected`| 被柜台或交易所拒绝 |
|
|
201
|
+
|
|
202
|
+
`Insert` 函数调用成功,即产生新的订单,其状态为初始值 `Sent`。
|
|
203
|
+
|
|
204
|
+
如果下单成功,订单状态会变成 `Queuing`,直到全部成交(变成 `Filled`)或撤单成功(变成 `Canceled`)。部分成交并不改变订单的状态,仍为 `Queuing`。
|
|
205
|
+
|
|
206
|
+
如果下单失败,订单状态会从 `Sent` 直接变成 `Rejected`。
|
|
207
|
+
|
|
208
|
+
```mermaid
|
|
209
|
+
stateDiagram-v2
|
|
210
|
+
[*] --> Sent: Insert()
|
|
211
|
+
Sent --> Queuing: 柜台和交易所均接受
|
|
212
|
+
Sent --> Rejected: 柜台或交易所拒绝
|
|
213
|
+
Queuing --> Filled: 全部成交
|
|
214
|
+
Queuing --> Canceled: 撤单成功
|
|
215
|
+
Filled --> [*]
|
|
216
|
+
Canceled --> [*]
|
|
217
|
+
Rejected --> [*]
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## 📦 订单字段
|
|
221
|
+
|
|
222
|
+
`Order` 对象由引擎自动创建和维护,策略中只能查看,不能修改。
|
|
223
|
+
|
|
224
|
+
| 字段 | 类型 | 说明 |
|
|
225
|
+
| :--- | :--- | :--- |
|
|
226
|
+
| `Instrument` | `Contract` | 合约 |
|
|
227
|
+
| `Size` | `int` | 委托量(正=买,负=卖) |
|
|
228
|
+
| `Price` | 浮点数 | 价格 |
|
|
229
|
+
| `Type` | `OrderType` | 订单类型 |
|
|
230
|
+
| `Flag` | `TradeFlag` | 开平标志 |
|
|
231
|
+
| `Status` | `OrderStatus` | 订单状态(见下方) |
|
|
232
|
+
| `Canceling` | `bool` | 是否有撤单指令在途 |
|
|
233
|
+
| `Error` | `int` | 错误码,0 表示正常 |
|
|
234
|
+
| `FilledSize` | `int` | 已成交数量(带方向) |
|
|
235
|
+
| `TradedSize` | `int` | 已成交数量(成交回报累计,带方向) |
|
|
236
|
+
| `TradedValue` | 浮点数 | 成交金额(累计) |
|
|
237
|
+
|
|
238
|
+
卖单的 `Size`、`FilledSize` 和 `TradedSize` 都是负值,买单都是正值。
|
|
239
|
+
|
|
240
|
+
订单不同状态对应的字段值:
|
|
241
|
+
|
|
242
|
+
| 状态描述 | `Status` | `FilledSize` | `Error` |
|
|
243
|
+
| :--- | :--- | :--- | :--- |
|
|
244
|
+
| 已发送 | `Sent` | 0 | 0 |
|
|
245
|
+
| 下单成功 | `Queuing` | 0 | 0 |
|
|
246
|
+
| 部分成交 | `Queuing` | 非 0 且不等于 `Size` | 0 |
|
|
247
|
+
| 全部成交 | `Filled` | 等于 `Size ` | 0 |
|
|
248
|
+
| 撤单成功 | `Canceled` | 可能为 0,一定不等于 `Size` | 0 |
|
|
249
|
+
| 下单失败 | `Rejected` | 0 | 非 0 |
|
|
250
|
+
|
|
251
|
+
**`FilledSize` 与 `TradedSize` 的区别:**
|
|
252
|
+
|
|
253
|
+
- `FilledSize`:来自订单状态回报,反映当前成交数量
|
|
254
|
+
- `TradedSize`:来自成交回报,逐笔累计
|
|
255
|
+
|
|
256
|
+
两者来自不同的回报消息,可能出现短暂不一致,最终会收敛于同一个值。
|
|
257
|
+
|
|
258
|
+
**Python:**
|
|
259
|
+
```python
|
|
260
|
+
def OnOrder(self, o: tt.Order):
|
|
261
|
+
# 防止重复撤单
|
|
262
|
+
if o.Status == tt.OrderStatus.Queuing and not o.Canceling:
|
|
263
|
+
self.Cancel(o)
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**C++:**
|
|
267
|
+
```c++
|
|
268
|
+
void OnOrder(const Order& o) override
|
|
269
|
+
{
|
|
270
|
+
// 防止重复撤单
|
|
271
|
+
if (o.Status == OrderStatus::Queuing && !o.Canceling)
|
|
272
|
+
Cancel(&o);
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## 📦 策略接口
|
|
277
|
+
|
|
278
|
+
策略类必须继承自 `Strategy`,并按需覆写回调函数:
|
|
279
|
+
|
|
280
|
+
| 回调函数 | 参数 | 触发时机 |
|
|
281
|
+
| :--- | :--- | :--- |
|
|
282
|
+
| `SubscribeList()` | — | 返回合约列表,引擎自动订阅行情 |
|
|
283
|
+
| `OnStart()` | — | 策略启动时触发一次 |
|
|
284
|
+
| `OnTimer()` | — | 定时触发,间隔可配置 |
|
|
285
|
+
| `OnQuote(quote)` | `quote`: 行情数据 | 每笔行情到达时 |
|
|
286
|
+
| `OnOrder(order)` | `order`: 订单数据 | 订单状态变化时 |
|
|
287
|
+
| `OnTrade(trade, order)` | `trade`: 成交数据,`order`: 关联订单 | 产生成交时 |
|
|
288
|
+
|
|
289
|
+
### 订阅行情
|
|
290
|
+
|
|
291
|
+
**Python:**
|
|
292
|
+
```python
|
|
293
|
+
def SubscribeList(self):
|
|
294
|
+
return [tt.Contract("rb2610"), tt.Contract("hc2610")]
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
**C++:**
|
|
298
|
+
```cpp
|
|
299
|
+
std::vector<Contract> SubscribeList() const override
|
|
300
|
+
{
|
|
301
|
+
return {"rb2610", "hc2610"};
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
订阅后,每收到一笔新行情,引擎就会自动调用 `OnQuote` 函数。
|
|
306
|
+
|
|
307
|
+
### 下单
|
|
308
|
+
|
|
309
|
+
**Python:**
|
|
310
|
+
```python
|
|
311
|
+
# 发送成功返回 Order 失败 None,开平标志若为 Auto 会被重设
|
|
312
|
+
def Insert(self, order: NewOrder):
|
|
313
|
+
pass
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
**C++:**
|
|
317
|
+
```c++
|
|
318
|
+
// 发送失败返回空指针,开平标志若为 Auto 会被重设
|
|
319
|
+
const Order* Insert(NewOrder& order);
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### 撤单
|
|
323
|
+
**Python:**
|
|
324
|
+
```python
|
|
325
|
+
# 发送成功返回 True 失败 False
|
|
326
|
+
def Cancel(self, order: Order):
|
|
327
|
+
pass
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**C++:**
|
|
331
|
+
```c++
|
|
332
|
+
// 发送成功返回 true 失败 false
|
|
333
|
+
bool Cancel(const Order& order);
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## 📦 自由函数
|
|
337
|
+
|
|
338
|
+
| 函数 | 功能 | 说明 |
|
|
339
|
+
| :--- | :--- | :--- |
|
|
340
|
+
| `Now` | 获取当前时间 | 北京时间 |
|
|
341
|
+
| `TodayAt` | 获取当日指定时间 | 入参应为 HH:MM:SS 格式,不检查 |
|
|
342
|
+
| `TradingDay` | 获取交易日 | 18 点前返回当日否则次日,周末顺延至周一 |
|
|
343
|
+
| `GetPosition` | 获取单个合约的持仓 | 无需柜台查询 |
|
|
344
|
+
| `GetPositions` | 获取所有持仓 | 无需柜台查询 |
|
|
345
|
+
| `GetQuote` | 获取最新行情 | 无需柜台查询 |
|
|
346
|
+
| `InitEngine` | 初始化交易引擎 | 完成后才可创建策略对象 |
|
|
347
|
+
| `Run` | 订阅行情并启动策略 | 不返回 |
|
|
348
|
+
| `AutoRun` | 一行启动策略 | |
|
|
349
|
+
| `MakeCache` | 创建合约信息缓存 | 路径由配置项 `CachePath` 指定 |
|
|
350
|
+
| `logd/logi/logw/loge` | 写日志 | fmtlog 提供 |
|
|
351
|
+
|
|
352
|
+
如果不使用 `AutoRun`,选择分开调用 `InitEngine` 和 `Run`,应当在 `InitEngine` 之后才创建策略对象,因为初始化之前 `Contract` 不可用,而策略类又必然需要合约。
|
|
353
|
+
|
|
354
|
+
对于 C++ 版,还应规范使用 `try catch`,以防异常导致日志缺失。
|
|
355
|
+
Python 版不易缺失,因为 Python 解释器会捕获 C++ 的异常再转换成脚本层面的异常。Python 脚本抛异常退出,在操作系统看来仍然是进程正常结束。
|
|
356
|
+
|
|
357
|
+
## 📦 配置项
|
|
358
|
+
|
|
359
|
+
除了 CTP 账号及地址信息,`Config` 还有以下字段:
|
|
360
|
+
|
|
361
|
+
| 参数 | 含义 | 默认值 | 说明 |
|
|
362
|
+
| :--- | :--- | :--- | :--- |
|
|
363
|
+
| `LogPath` | 日志路径 | 空 | 默认打印到屏幕 |
|
|
364
|
+
| `CachePath` | 合约信息缓存路径 | 空 | 读取成功则不向柜台查询合约信息 |
|
|
365
|
+
| `MaxOrderCount` | 订单笔数上限 | 1000 | 设小可防止 bug 导致疯狂下单 |
|
|
366
|
+
| `TimerInterval` | 定时器时间间隔 | 100 | 单位为 ms,实际时间会受操作系统影响 |
|
|
367
|
+
| `SleepOnIdle` | 空闲时短暂休眠 | false | 延迟不敏感场景可设为 true 以免占满一个 CPU 核 |
|
|
368
|
+
|
|
369
|
+
## 📦 FAQ
|
|
370
|
+
|
|
371
|
+
### Q: 成交发生时,策略类的 `OnOrder` 和 `OnTrade` 都会被触发,先后顺序是确定的吗?
|
|
372
|
+
|
|
373
|
+
A: 成交发生时,引擎既会收到订单回报(立即触发 `OnOrder`),也会收到成交回报(立即触发 `OnTrade`)。
|
|
374
|
+
一般来说,订单回报会排在前面,即 `OnOrder` 会先触发,据此操作会更快。但是消息的先后顺序取决于交易所的消息机制,并不是确定不变的。
|
|
375
|
+
|
|
376
|
+
### Q: 如何查看 `TimePoint` 的值?
|
|
377
|
+
|
|
378
|
+
A: `TimePoint` 是 `std::chrono::system_clock::time_point` 的别名,可以使用 fmtlib 打印或转换成字符串。
|
|
379
|
+
fmtlib 根据 `time_point` 的精度来确定秒以下的位数,默认精度与平台有关,需要时可先进行精度转换。
|
|
380
|
+
```cpp
|
|
381
|
+
TimePoint tp = Now();
|
|
382
|
+
fmt::print("{:%Y%m%d}", tp); // yyyymmdd
|
|
383
|
+
fmt::print("{:%T}", floor<seconds>(tp)); // HH:MM:SS
|
|
384
|
+
fmt::print("{:%T}", floor<milliseconds>(tp)); // HH:MM:SS.xxx
|
|
385
|
+
fmt::print("{:%T}", floor<nanoseconds>(tp)); // HH:MM:SS.xxxxxxxxx
|
|
386
|
+
```
|
|
387
|
+
更多示例可参考 `examples/format_time.cpp` 及 fmtlib 文档。
|
|
388
|
+
|
|
389
|
+
Python 版本用 `datetime` 表示时间,精度为微秒,可使用 `strftime` 进行格式化。
|
|
390
|
+
|
|
391
|
+
### Q: 在快期等客户端进行操作,是否会影响 TinyTrader 正在运行的策略?
|
|
392
|
+
|
|
393
|
+
A: 正常情况 TinyTrader 不会被客户端操作所干扰,具体反应如下:
|
|
394
|
+
|
|
395
|
+
| 客户端操作 | TinyTrader 的反应 |
|
|
396
|
+
|:--- |:--- |
|
|
397
|
+
| 撤销 TinyTrader 的订单 | 继续执行策略撤单后的逻辑(如追单) |
|
|
398
|
+
| 客户端手动下单 | 忽略该订单,不触发 `OnOrder` |
|
|
399
|
+
| 客户端订单成交 | 仅更新持仓数据,不触发 `OnTrade` |
|
|
400
|
+
|
|
401
|
+
### Q: 每次启动都要查询合约信息,有时侯特别慢,能否加速?
|
|
402
|
+
|
|
403
|
+
A: 查询合约信息的数据量较大,柜台可能限流,导致查询异常缓慢。可以创建一个工具程序,在每个交易日首次启动 TinyTrader 之前,进行一次合约信息查询,并将结果写入缓存文件。
|
|
404
|
+
缓存路径由配置项 `CachePath` 指定。示例见 `examples/make_cache.cpp` 或 `examples/make_cache.py`。
|
|
405
|
+
交易引擎初始化时将优先从 `CachePath` 指定的文件读取合约信息,读取失败才向柜台查询。这样就可以加速启动,同时减轻柜台的查询压力。
|
|
406
|
+
|
|
407
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
tinytrader/__init__.py,sha256=VnRcp6NdsHa5JmAhzHiWWO3gup7efS5_jzBsArb4hP4,7066
|
|
2
|
+
tinytrader/thostmduserapi_se.dll,sha256=K_TRySVjtqxGVK7RI2TEVSnZXKsZEAHlbiGcp4gobqo,3122176
|
|
3
|
+
tinytrader/thosttraderapi_se.dll,sha256=6NwxH_Ltgy-JuDJTeOwEPPPGvlrvJ31594p7fngL9qk,3521024
|
|
4
|
+
tinytrader/3.10/_tinytrader.pyd,sha256=lTYzzFdRTgk__KOjB2e8FanKMA24WGyA38e9oWDlqbE,343040
|
|
5
|
+
tinytrader/3.11/_tinytrader.pyd,sha256=lY6W_nYmIrxWCwevh1RlDv8lXgQscsqPV9lViV08DUk,342528
|
|
6
|
+
tinytrader/3.12/_tinytrader.pyd,sha256=M-RN7tw5MpWQXmlEDmZYebo0kckZ7T6xi2PzbotiS_o,339968
|
|
7
|
+
tinytrader/3.13/_tinytrader.pyd,sha256=BWjYT4963JNRGGvmhAf9Ygv8WZDgMbV8lgCDF-fQD1M,339968
|
|
8
|
+
tinytrader/3.9/_tinytrader.pyd,sha256=MIFKel7RVcQjl-BtetaxgvsMIgngQbFTtwW3B_oOd6s,344064
|
|
9
|
+
tinytrader-0.2.0.dist-info/licenses/LICENSE,sha256=0b4SeVLPtusk61qSITcFBfwW9tnCzmbleyfjSSGQE90,1090
|
|
10
|
+
tinytrader-0.2.0.dist-info/METADATA,sha256=DiNxU4MHl12YoYgUQlO7r6h0yqbOUy19-zq0_CL4RPk,14563
|
|
11
|
+
tinytrader-0.2.0.dist-info/WHEEL,sha256=3I5VVWZdsFlU417aCS2bMRuerS8wsfvBq99MyatBV3A,97
|
|
12
|
+
tinytrader-0.2.0.dist-info/top_level.txt,sha256=QVk7axpl-jBVtJ6K1OiOzixgh8gySHebgWkxLY0V-9Y,11
|
|
13
|
+
tinytrader-0.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 tinytrader
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
tinytrader
|