httptrading 1.0.0__tar.gz → 1.0.1__tar.gz
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.
- {httptrading-1.0.0 → httptrading-1.0.1}/PKG-INFO +34 -29
- {httptrading-1.0.0 → httptrading-1.0.1}/README.md +33 -28
- {httptrading-1.0.0 → httptrading-1.0.1}/httptrading/broker/base.py +7 -1
- {httptrading-1.0.0 → httptrading-1.0.1}/httptrading/broker/futu.py +3 -3
- {httptrading-1.0.0 → httptrading-1.0.1}/httptrading/broker/interactive_brokers.py +23 -3
- {httptrading-1.0.0 → httptrading-1.0.1}/httptrading/broker/tiger.py +3 -3
- {httptrading-1.0.0 → httptrading-1.0.1}/httptrading/http_server.py +3 -1
- {httptrading-1.0.0 → httptrading-1.0.1}/httptrading.egg-info/PKG-INFO +34 -29
- {httptrading-1.0.0 → httptrading-1.0.1}/pyproject.toml +1 -1
- {httptrading-1.0.0 → httptrading-1.0.1}/LICENSE +0 -0
- {httptrading-1.0.0 → httptrading-1.0.1}/httptrading/__init__.py +0 -0
- {httptrading-1.0.0 → httptrading-1.0.1}/httptrading/broker/__init__.py +0 -0
- {httptrading-1.0.0 → httptrading-1.0.1}/httptrading/broker/longbridge.py +0 -0
- {httptrading-1.0.0 → httptrading-1.0.1}/httptrading/model.py +0 -0
- {httptrading-1.0.0 → httptrading-1.0.1}/httptrading/tool/__init__.py +0 -0
- {httptrading-1.0.0 → httptrading-1.0.1}/httptrading/tool/leaky_bucket.py +0 -0
- {httptrading-1.0.0 → httptrading-1.0.1}/httptrading/tool/locate.py +0 -0
- {httptrading-1.0.0 → httptrading-1.0.1}/httptrading/tool/time.py +0 -0
- {httptrading-1.0.0 → httptrading-1.0.1}/httptrading.egg-info/SOURCES.txt +0 -0
- {httptrading-1.0.0 → httptrading-1.0.1}/httptrading.egg-info/dependency_links.txt +0 -0
- {httptrading-1.0.0 → httptrading-1.0.1}/httptrading.egg-info/requires.txt +0 -0
- {httptrading-1.0.0 → httptrading-1.0.1}/httptrading.egg-info/top_level.txt +0 -0
- {httptrading-1.0.0 → httptrading-1.0.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: httptrading
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.1
|
4
4
|
Summary: 统一交易通道的接口服务
|
5
5
|
Author-email: songwei <github@songwei.name>
|
6
6
|
License: MIT
|
@@ -14,6 +14,10 @@ Dynamic: license-file
|
|
14
14
|
|
15
15
|
# httptrading
|
16
16
|
|
17
|
+
```shell
|
18
|
+
pip install httptrading
|
19
|
+
```
|
20
|
+
|
17
21
|
项目的用途
|
18
22
|
--------
|
19
23
|
|
@@ -221,34 +225,35 @@ GET /httptrading/api/{instanceId}/market/state
|
|
221
225
|
|
222
226
|
```json lines
|
223
227
|
{
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
228
|
+
"type": "apiResponse",
|
229
|
+
"instanceId": "ggUqPZbSKuQ7Ewsk",
|
230
|
+
"broker": "futu",
|
231
|
+
"brokerDisplay": "富途证券",
|
232
|
+
"time": "2025-05-28T05:33:42.543109+00:00",
|
233
|
+
"ex": null,
|
234
|
+
"marketStatus": {
|
235
|
+
"type": "marketStatusMap",
|
236
|
+
"securities": { // 证券类市场状态, 以 region 为键的结构
|
237
|
+
"US": {
|
238
|
+
"type": "marketStatus",
|
239
|
+
"region": "US",
|
240
|
+
"originStatus": "AFTER_HOURS_END", // 交易通道原始市场状态
|
241
|
+
"unifiedStatus": "CLOSED" // 统一映射的定义
|
242
|
+
},
|
243
|
+
"CN": {
|
244
|
+
"type": "marketStatus",
|
245
|
+
"region": "CN",
|
246
|
+
"originStatus": "AFTERNOON",
|
247
|
+
"unifiedStatus": "RTH"
|
248
|
+
},
|
249
|
+
"HK": {
|
250
|
+
"type": "marketStatus",
|
251
|
+
"region": "HK",
|
252
|
+
"originStatus": "AFTERNOON",
|
253
|
+
"unifiedStatus": "RTH"
|
254
|
+
}
|
255
|
+
}
|
256
|
+
}
|
252
257
|
}
|
253
258
|
```
|
254
259
|
|
@@ -1,5 +1,9 @@
|
|
1
1
|
# httptrading
|
2
2
|
|
3
|
+
```shell
|
4
|
+
pip install httptrading
|
5
|
+
```
|
6
|
+
|
3
7
|
项目的用途
|
4
8
|
--------
|
5
9
|
|
@@ -207,34 +211,35 @@ GET /httptrading/api/{instanceId}/market/state
|
|
207
211
|
|
208
212
|
```json lines
|
209
213
|
{
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
214
|
+
"type": "apiResponse",
|
215
|
+
"instanceId": "ggUqPZbSKuQ7Ewsk",
|
216
|
+
"broker": "futu",
|
217
|
+
"brokerDisplay": "富途证券",
|
218
|
+
"time": "2025-05-28T05:33:42.543109+00:00",
|
219
|
+
"ex": null,
|
220
|
+
"marketStatus": {
|
221
|
+
"type": "marketStatusMap",
|
222
|
+
"securities": { // 证券类市场状态, 以 region 为键的结构
|
223
|
+
"US": {
|
224
|
+
"type": "marketStatus",
|
225
|
+
"region": "US",
|
226
|
+
"originStatus": "AFTER_HOURS_END", // 交易通道原始市场状态
|
227
|
+
"unifiedStatus": "CLOSED" // 统一映射的定义
|
228
|
+
},
|
229
|
+
"CN": {
|
230
|
+
"type": "marketStatus",
|
231
|
+
"region": "CN",
|
232
|
+
"originStatus": "AFTERNOON",
|
233
|
+
"unifiedStatus": "RTH"
|
234
|
+
},
|
235
|
+
"HK": {
|
236
|
+
"type": "marketStatus",
|
237
|
+
"region": "HK",
|
238
|
+
"originStatus": "AFTERNOON",
|
239
|
+
"unifiedStatus": "RTH"
|
240
|
+
}
|
241
|
+
}
|
242
|
+
}
|
238
243
|
}
|
239
244
|
```
|
240
245
|
|
@@ -81,7 +81,13 @@ class BaseBroker(ABC):
|
|
81
81
|
async def quote(self, contract: Contract) -> Quote:
|
82
82
|
raise NotImplementedError
|
83
83
|
|
84
|
-
async def market_status(self) -> dict[
|
84
|
+
async def market_status(self) -> dict[TradeType, dict[str, MarketStatus] | str]:
|
85
|
+
"""
|
86
|
+
报告交易通道提供的市场状态,
|
87
|
+
返回一个双层字典,
|
88
|
+
外层字典是以交易品种分类的结构, 比如 TradeType.Securities,
|
89
|
+
内层的字典是按国家代码区分的各个市场状态的结构, 比如 "US".
|
90
|
+
"""
|
85
91
|
raise NotImplementedError
|
86
92
|
|
87
93
|
|
@@ -166,7 +166,7 @@ class Futu(SecuritiesBroker):
|
|
166
166
|
async def cash(self) -> Cash:
|
167
167
|
return await self.call_sync(lambda : self._cash())
|
168
168
|
|
169
|
-
def _market_status(self) -> dict[
|
169
|
+
def _market_status(self) -> dict[TradeType, dict[str, MarketStatus] | str]:
|
170
170
|
# 各个市场的状态定义见:
|
171
171
|
# https://openapi.futunn.com/futu-api-doc/qa/quote.html#2090
|
172
172
|
from futu import RET_OK
|
@@ -204,10 +204,10 @@ class Futu(SecuritiesBroker):
|
|
204
204
|
unified_status=unified_status,
|
205
205
|
)
|
206
206
|
return {
|
207
|
-
TradeType.Securities
|
207
|
+
TradeType.Securities: sec_result,
|
208
208
|
}
|
209
209
|
|
210
|
-
async def market_status(self) -> dict[
|
210
|
+
async def market_status(self) -> dict[TradeType, dict[str, MarketStatus] | str]:
|
211
211
|
return await self.call_sync(lambda : self._market_status())
|
212
212
|
|
213
213
|
def _quote(self, contract: Contract):
|
@@ -5,6 +5,7 @@ https://ib-insync.readthedocs.io/readme.html
|
|
5
5
|
import re
|
6
6
|
import asyncio
|
7
7
|
from typing import Any
|
8
|
+
from collections import defaultdict
|
8
9
|
from httptrading.tool.leaky_bucket import *
|
9
10
|
from httptrading.tool.time import *
|
10
11
|
from httptrading.broker.base import *
|
@@ -74,7 +75,6 @@ class InteractiveBrokers(SecuritiesBroker):
|
|
74
75
|
async with self._lock:
|
75
76
|
if contract in self._ib_contracts:
|
76
77
|
return self._ib_contracts[contract]
|
77
|
-
print(f'{contract}未命中')
|
78
78
|
currency = self.contract_to_currency(contract)
|
79
79
|
ib_contract = ib_insync.Stock(contract.ticker, 'SMART', currency=currency)
|
80
80
|
client = self._client
|
@@ -82,6 +82,15 @@ class InteractiveBrokers(SecuritiesBroker):
|
|
82
82
|
self._ib_contracts[contract] = ib_contract
|
83
83
|
return ib_contract
|
84
84
|
|
85
|
+
def _when_create_client(self, client):
|
86
|
+
import ib_insync
|
87
|
+
client: ib_insync.IB = client
|
88
|
+
|
89
|
+
def _order_status_changed(trade: ib_insync.Trade):
|
90
|
+
pass
|
91
|
+
|
92
|
+
client.orderStatusEvent += _order_status_changed
|
93
|
+
|
85
94
|
async def _try_create_client(self):
|
86
95
|
import ib_insync
|
87
96
|
async with self._lock:
|
@@ -101,6 +110,7 @@ class InteractiveBrokers(SecuritiesBroker):
|
|
101
110
|
ib = ib_socket
|
102
111
|
else:
|
103
112
|
ib = ib_insync.IB()
|
113
|
+
self._when_create_client(ib)
|
104
114
|
host = self.broker_args.get('host', '127.0.0.1')
|
105
115
|
port = self.broker_args.get('port', 4000)
|
106
116
|
client_id = self.broker_args.get('client_id', self._client_id)
|
@@ -222,13 +232,23 @@ class InteractiveBrokers(SecuritiesBroker):
|
|
222
232
|
case _:
|
223
233
|
raise Exception(f'不支持的订单类型: {order_type}')
|
224
234
|
|
235
|
+
evt = asyncio.Event()
|
236
|
+
def _status_evnet(_trade: ib_insync.Trade):
|
237
|
+
evt.set()
|
238
|
+
|
225
239
|
ib_order = _map_order()
|
226
240
|
ib_order.tif = _map_time_in_force()
|
227
241
|
ib_order.outsideRth = _map_lifecycle()
|
228
242
|
trade: ib_insync.Trade = client.placeOrder(ib_contract, ib_order)
|
229
|
-
|
230
|
-
|
243
|
+
trade.statusEvent += _status_evnet
|
244
|
+
try:
|
245
|
+
await asyncio.wait_for(evt.wait(), timeout=2.0)
|
246
|
+
except asyncio.TimeoutError:
|
247
|
+
pass
|
248
|
+
finally:
|
249
|
+
order_id = str(trade.order.permId)
|
231
250
|
assert order_id
|
251
|
+
order_id = str(trade.order.permId)
|
232
252
|
return order_id
|
233
253
|
|
234
254
|
async def place_order(
|
@@ -142,7 +142,7 @@ class Tiger(SecuritiesBroker):
|
|
142
142
|
async def cash(self) -> Cash:
|
143
143
|
return await self.call_sync(lambda: self._cash())
|
144
144
|
|
145
|
-
def _market_status(self) -> dict[
|
145
|
+
def _market_status(self) -> dict[TradeType, dict[str, MarketStatus] | str]:
|
146
146
|
from tigeropen.common.consts import Market
|
147
147
|
from tigeropen.quote.domain.market_status import MarketStatus as TigerMarketStatus
|
148
148
|
client = self._quote_client
|
@@ -172,10 +172,10 @@ class Tiger(SecuritiesBroker):
|
|
172
172
|
unified_status=unified_status,
|
173
173
|
)
|
174
174
|
return {
|
175
|
-
TradeType.Securities
|
175
|
+
TradeType.Securities: sec_result,
|
176
176
|
}
|
177
177
|
|
178
|
-
async def market_status(self) -> dict[
|
178
|
+
async def market_status(self) -> dict[TradeType, dict[str, MarketStatus] | str]:
|
179
179
|
return await self.call_sync(lambda: self._market_status())
|
180
180
|
|
181
181
|
def _quote(self, contract: Contract):
|
@@ -19,7 +19,7 @@ class HttpTradingView(web.View):
|
|
19
19
|
def instance_id(self) -> str:
|
20
20
|
return self.request.match_info.get('instance_id', '')
|
21
21
|
|
22
|
-
def current_broker(self):
|
22
|
+
def current_broker(self) -> BaseBroker:
|
23
23
|
broker = getattr(self.request, '__current_broker__', None)
|
24
24
|
if broker is None:
|
25
25
|
raise web.HTTPNotFound()
|
@@ -212,6 +212,8 @@ class MarketStatusView(HttpTradingView):
|
|
212
212
|
async def get(self):
|
213
213
|
broker = self.current_broker()
|
214
214
|
ms_dict = await broker.market_status()
|
215
|
+
ms_dict = {t.name.lower(): d for t, d in ms_dict.items()}
|
216
|
+
ms_dict['type'] = 'marketStatusMap'
|
215
217
|
return self.response_api(broker, {
|
216
218
|
'marketStatus': ms_dict,
|
217
219
|
})
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: httptrading
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.1
|
4
4
|
Summary: 统一交易通道的接口服务
|
5
5
|
Author-email: songwei <github@songwei.name>
|
6
6
|
License: MIT
|
@@ -14,6 +14,10 @@ Dynamic: license-file
|
|
14
14
|
|
15
15
|
# httptrading
|
16
16
|
|
17
|
+
```shell
|
18
|
+
pip install httptrading
|
19
|
+
```
|
20
|
+
|
17
21
|
项目的用途
|
18
22
|
--------
|
19
23
|
|
@@ -221,34 +225,35 @@ GET /httptrading/api/{instanceId}/market/state
|
|
221
225
|
|
222
226
|
```json lines
|
223
227
|
{
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
228
|
+
"type": "apiResponse",
|
229
|
+
"instanceId": "ggUqPZbSKuQ7Ewsk",
|
230
|
+
"broker": "futu",
|
231
|
+
"brokerDisplay": "富途证券",
|
232
|
+
"time": "2025-05-28T05:33:42.543109+00:00",
|
233
|
+
"ex": null,
|
234
|
+
"marketStatus": {
|
235
|
+
"type": "marketStatusMap",
|
236
|
+
"securities": { // 证券类市场状态, 以 region 为键的结构
|
237
|
+
"US": {
|
238
|
+
"type": "marketStatus",
|
239
|
+
"region": "US",
|
240
|
+
"originStatus": "AFTER_HOURS_END", // 交易通道原始市场状态
|
241
|
+
"unifiedStatus": "CLOSED" // 统一映射的定义
|
242
|
+
},
|
243
|
+
"CN": {
|
244
|
+
"type": "marketStatus",
|
245
|
+
"region": "CN",
|
246
|
+
"originStatus": "AFTERNOON",
|
247
|
+
"unifiedStatus": "RTH"
|
248
|
+
},
|
249
|
+
"HK": {
|
250
|
+
"type": "marketStatus",
|
251
|
+
"region": "HK",
|
252
|
+
"originStatus": "AFTERNOON",
|
253
|
+
"unifiedStatus": "RTH"
|
254
|
+
}
|
255
|
+
}
|
256
|
+
}
|
252
257
|
}
|
253
258
|
```
|
254
259
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|