vnpy_okx 2025.11.1__tar.gz → 2025.11.8__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.
- {vnpy_okx-2025.11.1 → vnpy_okx-2025.11.8}/PKG-INFO +2 -2
- {vnpy_okx-2025.11.1 → vnpy_okx-2025.11.8}/README.md +1 -1
- {vnpy_okx-2025.11.1 → vnpy_okx-2025.11.8}/vnpy_okx/__init__.py +1 -1
- {vnpy_okx-2025.11.1 → vnpy_okx-2025.11.8}/vnpy_okx/okx_gateway.py +21 -15
- {vnpy_okx-2025.11.1 → vnpy_okx-2025.11.8}/.gitignore +0 -0
- {vnpy_okx-2025.11.1 → vnpy_okx-2025.11.8}/LICENSE +0 -0
- {vnpy_okx-2025.11.1 → vnpy_okx-2025.11.8}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vnpy_okx
|
|
3
|
-
Version: 2025.11.
|
|
3
|
+
Version: 2025.11.8
|
|
4
4
|
Summary: OKX trading gateway for VeighNa.
|
|
5
5
|
Project-URL: Homepage, https://www.github.com/veighna-global
|
|
6
6
|
Project-URL: Source, https://www.github.com/veighna-global
|
|
@@ -33,7 +33,7 @@ Description-Content-Type: text/markdown
|
|
|
33
33
|
</p>
|
|
34
34
|
|
|
35
35
|
<p align="center">
|
|
36
|
-
<img src ="https://img.shields.io/badge/version-2025.11.
|
|
36
|
+
<img src ="https://img.shields.io/badge/version-2025.11.08-blueviolet.svg"/>
|
|
37
37
|
<img src ="https://img.shields.io/badge/platform-windows|linux|macos-yellow.svg"/>
|
|
38
38
|
<img src ="https://img.shields.io/badge/python-3.10|3.11|3.12|3.13-blue.svg" />
|
|
39
39
|
<img src ="https://img.shields.io/github/license/veighna-global/vnpy_okx.svg?color=orange"/>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
<img src ="https://img.shields.io/badge/version-2025.11.
|
|
8
|
+
<img src ="https://img.shields.io/badge/version-2025.11.08-blueviolet.svg"/>
|
|
9
9
|
<img src ="https://img.shields.io/badge/platform-windows|linux|macos-yellow.svg"/>
|
|
10
10
|
<img src ="https://img.shields.io/badge/python-3.10|3.11|3.12|3.13-blue.svg" />
|
|
11
11
|
<img src ="https://img.shields.io/github/license/veighna-global/vnpy_okx.svg?color=orange"/>
|
|
@@ -8,6 +8,7 @@ from datetime import datetime
|
|
|
8
8
|
from urllib.parse import urlencode
|
|
9
9
|
from types import TracebackType
|
|
10
10
|
from collections.abc import Callable
|
|
11
|
+
from time import sleep
|
|
11
12
|
|
|
12
13
|
from vnpy.event import EventEngine, Event, EVENT_TIMER
|
|
13
14
|
from vnpy.trader.constant import (
|
|
@@ -47,12 +48,6 @@ REAL_PUBLIC_HOST: str = "wss://ws.okx.com:8443/ws/v5/public"
|
|
|
47
48
|
REAL_PRIVATE_HOST: str = "wss://ws.okx.com:8443/ws/v5/private"
|
|
48
49
|
REAL_BUSINESS_HOST: str = "wss://ws.okx.com:8443/ws/v5/business"
|
|
49
50
|
|
|
50
|
-
# AWS server hosts
|
|
51
|
-
AWS_REST_HOST: str = "https://aws.okx.com"
|
|
52
|
-
AWS_PUBLIC_HOST: str = "wss://wsaws.okx.com:8443/ws/v5/public"
|
|
53
|
-
AWS_PRIVATE_HOST: str = "wss://wsaws.okx.com:8443/ws/v5/private"
|
|
54
|
-
AWS_BUSINESS_HOST: str = "wss://wsaws.okx.com:8443/ws/v5/business"
|
|
55
|
-
|
|
56
51
|
# Demo server hosts
|
|
57
52
|
DEMO_REST_HOST: str = "https://www.okx.com"
|
|
58
53
|
DEMO_PUBLIC_HOST: str = "wss://wspap.okx.com:8443/ws/v5/public"
|
|
@@ -113,7 +108,7 @@ class OkxGateway(BaseGateway):
|
|
|
113
108
|
"API Key": "",
|
|
114
109
|
"Secret Key": "",
|
|
115
110
|
"Passphrase": "",
|
|
116
|
-
"Server": ["REAL", "
|
|
111
|
+
"Server": ["REAL", "DEMO"],
|
|
117
112
|
"Proxy Host": "",
|
|
118
113
|
"Proxy Port": 0,
|
|
119
114
|
"Spread Trading": ["False", "True"],
|
|
@@ -152,6 +147,8 @@ class OkxGateway(BaseGateway):
|
|
|
152
147
|
self.ping_count: int = 0
|
|
153
148
|
self.ping_interval: int = 20
|
|
154
149
|
|
|
150
|
+
self.subscribed_symbols: set[str] = set()
|
|
151
|
+
|
|
155
152
|
def connect(self, setting: dict) -> None:
|
|
156
153
|
"""
|
|
157
154
|
Start server connections.
|
|
@@ -218,11 +215,18 @@ class OkxGateway(BaseGateway):
|
|
|
218
215
|
Parameters:
|
|
219
216
|
req: Subscription request object containing symbol information
|
|
220
217
|
"""
|
|
218
|
+
# Check if symbol exists in contract map
|
|
221
219
|
contract: ContractData | None = self.symbol_contract_map.get(req.symbol, None)
|
|
222
220
|
if not contract:
|
|
223
221
|
self.write_log(f"Failed to subscribe data, symbol not found: {req.symbol}")
|
|
224
222
|
return
|
|
225
223
|
|
|
224
|
+
# Filter duplicate subscription
|
|
225
|
+
if req.vt_symbol in self.subscribed_symbols:
|
|
226
|
+
return
|
|
227
|
+
self.subscribed_symbols.add(req.vt_symbol)
|
|
228
|
+
|
|
229
|
+
# Send request to corresponding API
|
|
226
230
|
if contract.product == Product.SPREAD:
|
|
227
231
|
self.business_api.subscribe(req)
|
|
228
232
|
else:
|
|
@@ -557,7 +561,7 @@ class RestApi(RestClient):
|
|
|
557
561
|
key: API Key for authentication
|
|
558
562
|
secret: API Secret for request signing
|
|
559
563
|
passphrase: API Passphrase for authentication
|
|
560
|
-
server: Server type ("REAL"
|
|
564
|
+
server: Server type ("REAL" or "DEMO")
|
|
561
565
|
proxy_host: Proxy server hostname or IP
|
|
562
566
|
proxy_port: Proxy server port
|
|
563
567
|
spread_trading: Whether to enable spread trading
|
|
@@ -573,7 +577,6 @@ class RestApi(RestClient):
|
|
|
573
577
|
|
|
574
578
|
server_hosts: dict[str, str] = {
|
|
575
579
|
"REAL": REAL_REST_HOST,
|
|
576
|
-
"AWS": AWS_REST_HOST,
|
|
577
580
|
"DEMO": DEMO_REST_HOST,
|
|
578
581
|
}
|
|
579
582
|
|
|
@@ -880,6 +883,9 @@ class RestApi(RestClient):
|
|
|
880
883
|
|
|
881
884
|
# Loop until no more data or request fails
|
|
882
885
|
while True:
|
|
886
|
+
# Add small delay to avoid rate limit
|
|
887
|
+
sleep(0.1)
|
|
888
|
+
|
|
883
889
|
# Create query params
|
|
884
890
|
params: dict = {
|
|
885
891
|
id_key: contract.name,
|
|
@@ -1089,7 +1095,10 @@ class WebsocketApi(WebsocketClient):
|
|
|
1089
1095
|
def send_ping(self) -> None:
|
|
1090
1096
|
"""Send heartbeat ping to server"""
|
|
1091
1097
|
if self.connected:
|
|
1092
|
-
|
|
1098
|
+
try:
|
|
1099
|
+
self.wsapp.send("ping")
|
|
1100
|
+
except Exception:
|
|
1101
|
+
pass
|
|
1093
1102
|
|
|
1094
1103
|
|
|
1095
1104
|
class PublicApi(WebsocketApi):
|
|
@@ -1115,7 +1124,6 @@ class PublicApi(WebsocketApi):
|
|
|
1115
1124
|
|
|
1116
1125
|
self.server_hosts: dict[str, str] = {
|
|
1117
1126
|
"REAL": REAL_PUBLIC_HOST,
|
|
1118
|
-
"AWS": AWS_PUBLIC_HOST,
|
|
1119
1127
|
"DEMO": DEMO_PUBLIC_HOST,
|
|
1120
1128
|
}
|
|
1121
1129
|
|
|
@@ -1275,7 +1283,6 @@ class PrivateApi(WebsocketApi):
|
|
|
1275
1283
|
|
|
1276
1284
|
self.server_hosts: dict[str, str] = {
|
|
1277
1285
|
"REAL": REAL_PRIVATE_HOST,
|
|
1278
|
-
"AWS": AWS_PRIVATE_HOST,
|
|
1279
1286
|
"DEMO": DEMO_PRIVATE_HOST,
|
|
1280
1287
|
}
|
|
1281
1288
|
|
|
@@ -1299,7 +1306,7 @@ class PrivateApi(WebsocketApi):
|
|
|
1299
1306
|
key: API Key for authentication
|
|
1300
1307
|
secret: API Secret for request signing
|
|
1301
1308
|
passphrase: API Passphrase for authentication
|
|
1302
|
-
server: Server type ("REAL"
|
|
1309
|
+
server: Server type ("REAL" or "DEMO")
|
|
1303
1310
|
proxy_host: Proxy server hostname or IP
|
|
1304
1311
|
proxy_port: Proxy server port
|
|
1305
1312
|
"""
|
|
@@ -1701,7 +1708,6 @@ class BusinessApi(WebsocketApi):
|
|
|
1701
1708
|
|
|
1702
1709
|
self.server_hosts: dict[str, str] = {
|
|
1703
1710
|
"REAL": REAL_BUSINESS_HOST,
|
|
1704
|
-
"AWS": AWS_BUSINESS_HOST,
|
|
1705
1711
|
"DEMO": DEMO_BUSINESS_HOST,
|
|
1706
1712
|
}
|
|
1707
1713
|
|
|
@@ -1725,7 +1731,7 @@ class BusinessApi(WebsocketApi):
|
|
|
1725
1731
|
key: API Key for authentication
|
|
1726
1732
|
secret: API Secret for request signing
|
|
1727
1733
|
passphrase: API Passphrase for authentication
|
|
1728
|
-
server: Server type ("REAL"
|
|
1734
|
+
server: Server type ("REAL" or "DEMO")
|
|
1729
1735
|
proxy_host: Proxy server hostname or IP
|
|
1730
1736
|
proxy_port: Proxy server port
|
|
1731
1737
|
"""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|