vnpy_okx 2025.12.28__py3-none-any.whl → 2026.1.11__py3-none-any.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.
vnpy_okx/__init__.py CHANGED
@@ -23,7 +23,7 @@
23
23
  from .okx_gateway import OkxGateway
24
24
 
25
25
 
26
- __version__ = "2025.12.28"
26
+ __version__ = "2026.01.11"
27
27
 
28
28
 
29
29
  __all__ = ["OkxGateway"]
vnpy_okx/okx_gateway.py CHANGED
@@ -10,6 +10,7 @@ from types import TracebackType
10
10
  from collections.abc import Callable
11
11
  from time import sleep
12
12
  from decimal import Decimal
13
+ from typing import cast
13
14
 
14
15
  from vnpy.event import EventEngine, Event, EVENT_TIMER
15
16
  from vnpy.trader.constant import (
@@ -116,7 +117,7 @@ class OkxGateway(BaseGateway):
116
117
  "Margin Currency": ""
117
118
  }
118
119
 
119
- exchanges: Exchange = [Exchange.GLOBAL]
120
+ exchanges: list[Exchange] = [Exchange.GLOBAL]
120
121
 
121
122
  def __init__(self, event_engine: EventEngine, gateway_name: str) -> None:
122
123
  """
@@ -339,7 +340,7 @@ class OkxGateway(BaseGateway):
339
340
  self.orders[order.orderid] = order
340
341
  super().on_order(order)
341
342
 
342
- def get_order(self, orderid: str) -> OrderData:
343
+ def get_order(self, orderid: str) -> OrderData | None:
343
344
  """
344
345
  Get previously saved order by order id.
345
346
 
@@ -401,7 +402,7 @@ class OkxGateway(BaseGateway):
401
402
  Returns:
402
403
  OrderData: VeighNa order object
403
404
  """
404
- contract: ContractData = self.get_contract_by_name(data["instId"])
405
+ contract: ContractData = cast(ContractData, self.get_contract_by_name(data["instId"]))
405
406
 
406
407
  order_id: str = data["clOrdId"]
407
408
  if order_id:
@@ -439,7 +440,7 @@ class OkxGateway(BaseGateway):
439
440
  Returns:
440
441
  OrderData: VeighNa order object
441
442
  """
442
- contract: ContractData = self.get_contract_by_name(data["sprdId"])
443
+ contract: ContractData = cast(ContractData, self.get_contract_by_name(data["sprdId"]))
443
444
 
444
445
  order_id: str = data["clOrdId"]
445
446
  if order_id:
@@ -764,6 +765,7 @@ class RestApi(RestClient):
764
765
  net_position=net_position,
765
766
  gateway_name=self.gateway_name,
766
767
  )
768
+ contract.extra = d
767
769
 
768
770
  self.gateway.on_contract(contract)
769
771
 
@@ -795,7 +797,7 @@ class RestApi(RestClient):
795
797
  leg_symbols: list[str] = []
796
798
  for leg in d["legs"]:
797
799
  leg_name: str = leg["instId"]
798
- leg_contract: ContractData = self.gateway.get_contract_by_name(leg_name)
800
+ leg_contract: ContractData = cast(ContractData, self.gateway.get_contract_by_name(leg_name))
799
801
  leg_symbols.append(leg_contract.symbol)
800
802
 
801
803
  contract: ContractData = ContractData(
@@ -877,6 +879,11 @@ class RestApi(RestClient):
877
879
  self.gateway.write_log(f"Query kline history failed, symbol not found: {req.symbol}")
878
880
  return []
879
881
 
882
+ # Validate interval is not None
883
+ if not req.interval:
884
+ self.gateway.write_log(f"Query kline history failed, interval not found: {req.symbol}")
885
+ return []
886
+
880
887
  # Initialize buffer for storing bars
881
888
  buf: dict[datetime, BarData] = {}
882
889
  limit: str = "100"
@@ -913,7 +920,7 @@ class RestApi(RestClient):
913
920
  break
914
921
  else:
915
922
  data: dict = resp.json()
916
- bar_data: list = data.get("data", None)
923
+ bar_data: list | None = data.get("data", None)
917
924
 
918
925
  if not bar_data:
919
926
  msg: str = data.get("msg", "No data returned.")
@@ -1395,7 +1402,7 @@ class PrivateApi(WebsocketApi):
1395
1402
  # Process trade data for filled or partially filled orders
1396
1403
  # Round trade volume number to meet minimum volume precision
1397
1404
  trade_volume: float = float(d["fillSz"])
1398
- contract: ContractData = self.gateway.get_contract_by_symbol(order.symbol)
1405
+ contract: ContractData | None = self.gateway.get_contract_by_symbol(order.symbol)
1399
1406
  if contract:
1400
1407
  trade_volume = round_to(trade_volume, contract.min_volume)
1401
1408
 
@@ -1451,7 +1458,7 @@ class PrivateApi(WebsocketApi):
1451
1458
  data: list = packet["data"]
1452
1459
  for d in data:
1453
1460
  name: str = d["instId"]
1454
- contract: ContractData = self.gateway.get_contract_by_name(name)
1461
+ contract: ContractData = cast(ContractData, self.gateway.get_contract_by_name(name))
1455
1462
 
1456
1463
  pos: float = float(d["pos"])
1457
1464
  price: float = get_float_value(d, "avgPx")
@@ -1483,9 +1490,11 @@ class PrivateApi(WebsocketApi):
1483
1490
  # Wrong parameters
1484
1491
  if packet["code"] != "0":
1485
1492
  if not data:
1486
- order: OrderData = self.reqid_order_map[packet["id"]]
1487
- order.status = Status.REJECTED
1488
- self.gateway.on_order(order)
1493
+ order: OrderData | None = self.reqid_order_map.get(packet["id"], None)
1494
+ if order:
1495
+ order.status = Status.REJECTED
1496
+ self.gateway.on_order(order)
1497
+
1489
1498
  return
1490
1499
 
1491
1500
  # Failed to process
@@ -1625,9 +1634,15 @@ class PrivateApi(WebsocketApi):
1625
1634
  "tdMode": "cross" # Only support cross margin mode
1626
1635
  }
1627
1636
 
1637
+ # Add extra field for portfolio margin
1628
1638
  if self.margin_currency:
1629
1639
  arg["ccy"] = self.margin_currency
1630
1640
 
1641
+ # Add extra field for spot
1642
+ if "SPOT" in req.symbol:
1643
+ quote_ccy_list: list[str] = contract.extra["tradeQuoteCcyList"] # type: ignore
1644
+ arg["tradeQuoteCcy"] = quote_ccy_list[0]
1645
+
1631
1646
  # Create websocket request with unique request ID
1632
1647
  self.reqid += 1
1633
1648
  packet: dict = {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vnpy_okx
3
- Version: 2025.12.28
3
+ Version: 2026.1.11
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
@@ -0,0 +1,7 @@
1
+ vnpy_okx/__init__.py,sha256=f6oPlp_8EDCCpyWTT16niwdAtKE3BmP3CkntE6NITGc,1248
2
+ vnpy_okx/okx_gateway.py,sha256=9jRt6r5ReRAy15CnuF0cxR3d6f7jrtbHxxmAX5ofwNE,73037
3
+ vnpy_okx/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ vnpy_okx-2026.1.11.dist-info/METADATA,sha256=i6iIE4Sb-jNBO3t5YmY5dF4RQsZbFgE917kOkHtxY6I,2840
5
+ vnpy_okx-2026.1.11.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
6
+ vnpy_okx-2026.1.11.dist-info/licenses/LICENSE,sha256=vKkW-EmD7w-5lDDjg15L8feZ1nkQeNpEHfyO2v9tprs,1099
7
+ vnpy_okx-2026.1.11.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- vnpy_okx/__init__.py,sha256=q5WNRYb_KdEzXSfonARFuNujBAS4jL-z77Lu2pm8beY,1248
2
- vnpy_okx/okx_gateway.py,sha256=eqKESbdBr5Av4TJ7HhQgp6jJjmZjgtgP6ivICOIeozI,72352
3
- vnpy_okx/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- vnpy_okx-2025.12.28.dist-info/METADATA,sha256=gGPXJ52UM7FZ8oW0EkNWu3NU4k4rJZsS8iSOHay2sJk,2841
5
- vnpy_okx-2025.12.28.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
6
- vnpy_okx-2025.12.28.dist-info/licenses/LICENSE,sha256=vKkW-EmD7w-5lDDjg15L8feZ1nkQeNpEHfyO2v9tprs,1099
7
- vnpy_okx-2025.12.28.dist-info/RECORD,,