Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion PKG-INFO
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: tqsdk
Version: 3.9.3
Version: 3.9.4
Summary: TianQin SDK
Home-page: https://www.shinnytech.com/tqsdk
Author: TianQin
Expand Down
4 changes: 2 additions & 2 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@
# built documents.
#
# The short X.Y version.
version = u'3.9.3'
version = u'3.9.4'
# The full version, including alpha/beta/rc tags.
release = u'3.9.3'
release = u'3.9.4'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
21 changes: 21 additions & 0 deletions doc/enterprise.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,24 @@ front_broker="RohonDemo"
融航实盘情况下将对应信息换成实盘信息即可

融航资管平台连接模式的详细介绍,请点击 :py:class:`~tqsdk.TqRohon`


恒生 O32 柜台连接功能
-------------------------------------------------
TqSdk 提供了恒生 O32 柜台的连接支持,支持用户通过直连模式接入恒生 O32 柜台,详情可以点击 :py:class:`~tqsdk.TqO32` ::

from tqsdk import TqApi, TqAuth, TqO32, O32Account

account = TqO32(
account_id=O32Account(user="用户", fund="基金", asset_unit="资产单元", portfolio="组合"),
password="O32 密码",
td_front_url="trade_front_host:trade_front_port",
mc_front_url="query_front_host:query_front_port",
license_file="/path/to/license.dat",
auth_code="O32 授权码",
)
api = TqApi(account, auth=TqAuth("快期账户", "账户密码"))

其中 `account_id` 通过 :py:class:`~tqsdk.O32Account` 传入,内部会拼接成 ``用户.基金.资产单元.组合``

`td_front_url` / `mc_front_url` 为柜台方提供的前置地址,`license_file` 为本地许可证文件位置
1 change: 1 addition & 0 deletions doc/reference/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ TqSdk 模块参考
tqsdk.tqrohon.rst
tqsdk.tqjees.rst
tqsdk.tqyida.rst
tqsdk.tqo32.rst
tqsdk.sim.rst

.. toctree::
Expand Down
10 changes: 10 additions & 0 deletions doc/reference/tqsdk.tqo32.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.. _tqsdk.tqo32:

tqsdk.TqO32 - 恒生 O32 交易类
------------------------------------------------------------------
.. autoclass:: tqsdk.TqO32
:members:
:inherited-members:

.. autoclass:: tqsdk.O32Account
:members:
6 changes: 6 additions & 0 deletions doc/version.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

版本变更
=============================
3.9.4 (2026/04/17)

* 新增: 支持恒生 O32 柜台,详情参考 :py:class:`~tqsdk.TqO32`
* docs: 优化文档


3.9.3 (2026/04/14)

* 新增: :py:class:`~tqsdk.objs.Quote` 增加 :py:class:`~tqsdk.objs.Quote.open_limit` 属性,返回合约日内开仓限额,目前只支持期货合约
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

setuptools.setup(
name='tqsdk',
version="3.9.3",
version="3.9.4",
description='TianQin SDK',
author='TianQin',
author_email='tianqincn@gmail.com',
Expand Down
2 changes: 1 addition & 1 deletion tqsdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
name = "tqsdk"

from tqsdk.api import TqApi
from tqsdk.tradeable import TqAccount, TqZq, TqKq, TqKqStock, TqSim, TqSimStock, TqCtp, TqRohon, TqJees, TqYida, TqTradingUnit
from tqsdk.tradeable import TqAccount, TqZq, TqKq, TqKqStock, TqSim, TqSimStock, TqCtp, TqRohon, TqJees, TqYida, TqO32, O32Account, TqTradingUnit
from tqsdk.auth import TqAuth
from tqsdk.channel import TqChan
from tqsdk.backtest import TqBacktest, TqReplay
Expand Down
2 changes: 1 addition & 1 deletion tqsdk/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '3.9.3'
__version__ = '3.9.4'
9 changes: 6 additions & 3 deletions tqsdk/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
from tqsdk.risk_rule import TqRiskRule
from tqsdk.ins_schema import ins_schema, basic, derivative, future, option
from tqsdk.symbols import TqSymbols
from tqsdk.tradeable import TqAccount, TqZq, TqKq, TqKqStock, TqSim, TqSimStock, BaseSim, BaseOtg, TqCtp, TqRohon, TqJees, TqYida, TqTradingUnit
from tqsdk.tradeable import TqAccount, TqZq, TqKq, TqKqStock, TqSim, TqSimStock, BaseSim, BaseOtg, TqCtp, TqRohon, TqJees, TqYida, TqO32, TqTradingUnit
from tqsdk.trading_status import TqTradingStatus
from tqsdk.tqwebhelper import TqWebHelper
from tqsdk.utils import _generate_uuid, _query_for_quote, BlockManagerUnconsolidated, _quotes_add_night, _bisect_value, \
Expand All @@ -86,7 +86,7 @@
# 在 python 文档中对 type alias 的定义有多种:TypeAliasType, TypeAlias 以及 simple assignment https://docs.python.org/3.13/library/typing.html#type-aliases
# Union 类型支持嵌套 Union 类型,但是不支持嵌套 Union TypeAliasType 类型:https://docs.python.org/3.13/library/typing.html#typing.Union
# 但是 Union 文档没有明说是否支持嵌套 Union simple assignment 类型,从实现上看,目前所有版本都支持(最新 3.13)
UnionTradeable = Union[TqAccount, TqKq, TqZq, TqKqStock, TqSim, TqSimStock, TqCtp, TqRohon, TqJees, TqYida, TqTradingUnit]
UnionTradeable = Union[TqAccount, TqKq, TqZq, TqKqStock, TqSim, TqSimStock, TqCtp, TqRohon, TqJees, TqYida, TqO32, TqTradingUnit]


class TqApi(TqBaseApi):
Expand All @@ -106,7 +106,7 @@ def __init__(self, account: Optional[Union[TqMultiAccount, UnionTradeable]] = No
创建天勤接口实例

Args:
account (None/TqAccount/TqKq/TqKqStock/TqSim/TqSimStock/TqZq/TqMultiAccount): [可选]交易账号:
account (None/TqAccount/TqKq/TqKqStock/TqSim/TqSimStock/TqZq/TqCtp/TqRohon/TqJees/TqYida/TqO32/TqTradingUnit/TqMultiAccount): [可选]交易账号:
* None: 账号将根据环境变量决定, 默认为 :py:class:`~tqsdk.TqSim`

* :py:class:`~tqsdk.TqAccount` : 使用实盘账号, 直连行情和交易服务器, 需提供期货公司/帐号/密码
Expand All @@ -129,12 +129,15 @@ def __init__(self, account: Optional[Union[TqMultiAccount, UnionTradeable]] = No

* :py:class:`~tqsdk.TqYida` : 使用易达账号

* :py:class:`~tqsdk.TqO32` : 使用恒生 O32 账号

* :py:class:`~tqsdk.TqTradingUnit` : 使用交易单元账号

* :py:class:`~tqsdk.TqMultiAccount` : 多账户列表,列表中支持
:py:class:`~tqsdk.TqAccount`、:py:class:`~tqsdk.TqKq`、:py:class:`~tqsdk.TqKqStock`、
:py:class:`~tqsdk.TqSim`、:py:class:`~tqsdk.TqSimStock`、:py:class:`~tqsdk.TqZq`、
:py:class:`~tqsdk.TqRohon`、:py:class:`~tqsdk.TqJees`、:py:class:`~tqsdk.TqYida`、
:py:class:`~tqsdk.TqO32`、
:py:class:`~tqsdk.TqTradingUnit` 和 :py:class:`~tqsdk.TqCtp` 中的 0 至 N 个或者组合

auth (TqAuth/str): [必填]用户快期账户:
Expand Down
2 changes: 1 addition & 1 deletion tqsdk/multiaccount.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def __init__(self, accounts: Optional[List['UnionTradeable']] = None):
创建 TqMultiAccount 实例

Args:
accounts (List[Union[TqAccount, TqKq, TqKqStock, TqSim, TqSimStock, TqZq, TqCtp, TqRohon, TqJees, TqYida, TqTradingUnit]]): [可选] 多账户列表, 若未指定任何账户, 则为 [TqSim()]
accounts (List[Union[TqAccount, TqKq, TqKqStock, TqSim, TqSimStock, TqZq, TqCtp, TqRohon, TqJees, TqYida, TqO32, TqTradingUnit]]): [可选] 多账户列表, 若未指定任何账户, 则为 [TqSim()]

Example1::

Expand Down
8 changes: 4 additions & 4 deletions tqsdk/risk_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def __init__(self, api: 'TqApi', open_counts_limit: int, symbol: Union[str, List
* str: 一个合约代码
* list of str: 合约代码列表

account (TqAccount/TqKq/TqZq/TqKqStock/TqSim/TqSimStock/TqCtp/TqRohon/TqJees/TqYida/TqTradingUnit): [可选] 指定发送下单指令的账户实例, 多账户模式下,该参数必须指定
account (TqAccount/TqKq/TqZq/TqKqStock/TqSim/TqSimStock/TqCtp/TqRohon/TqJees/TqYida/TqO32/TqTradingUnit): [可选] 指定发送下单指令的账户实例, 多账户模式下,该参数必须指定

Example1::

Expand Down Expand Up @@ -151,7 +151,7 @@ def __init__(self, api: 'TqApi', open_volumes_limit: int, symbol: Union[str, Lis
* str: 一个合约代码
* list of str: 合约代码列表

account (TqAccount/TqKq/TqZq/TqKqStock/TqSim/TqSimStock/TqCtp/TqRohon/TqJees/TqYida/TqTradingUnit): [可选] 指定发送下单指令的账户实例, 多账户模式下,该参数必须指定
account (TqAccount/TqKq/TqZq/TqKqStock/TqSim/TqSimStock/TqCtp/TqRohon/TqJees/TqYida/TqO32/TqTradingUnit): [可选] 指定发送下单指令的账户实例, 多账户模式下,该参数必须指定

Example1::

Expand Down Expand Up @@ -248,7 +248,7 @@ def __init__(self, api: 'TqApi', open_volumes_limit: int, symbol: Union[str, Lis
* str: 一个合约代码
* list of str: 合约代码列表

account (TqAccount/TqKq/TqZq/TqKqStock/TqSim/TqSimStock/TqCtp/TqRohon/TqJees/TqYida/TqTradingUnit): [可选] 指定发送下单指令的账户实例, 多账户模式下,该参数必须指定
account (TqAccount/TqKq/TqZq/TqKqStock/TqSim/TqSimStock/TqCtp/TqRohon/TqJees/TqYida/TqO32/TqTradingUnit): [可选] 指定发送下单指令的账户实例, 多账户模式下,该参数必须指定

Example::

Expand Down Expand Up @@ -328,7 +328,7 @@ def __init__(self, api: 'TqApi', limit_per_second: int, exchange_id: Union[str,
* str: 指定交易所代码,如 "SHFE", "DCE", "CZCE", "CFFEX" 等
* list of str: 交易所代码列表,如 ["DCE", "SHFE"],每个交易所分别限制

account (TqAccount/TqKq/TqZq/TqKqStock/TqSim/TqSimStock/TqCtp/TqRohon/TqJees/TqYida/TqTradingUnit): [可选] 指定发送下单指令的账户实例, 多账户模式下,该参数必须指定
account (TqAccount/TqKq/TqZq/TqKqStock/TqSim/TqSimStock/TqCtp/TqRohon/TqJees/TqYida/TqO32/TqTradingUnit): [可选] 指定发送下单指令的账户实例, 多账户模式下,该参数必须指定

Example1::

Expand Down
2 changes: 1 addition & 1 deletion tqsdk/tradeable/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@


from tqsdk.tradeable.otg.base_otg import BaseOtg
from tqsdk.tradeable.otg import TqAccount, TqZq, TqKq, TqKqStock, TqCtp, TqRohon, TqJees, TqYida, TqTradingUnit
from tqsdk.tradeable.otg import TqAccount, TqZq, TqKq, TqKqStock, TqCtp, TqRohon, TqJees, TqYida, TqO32, O32Account, TqTradingUnit
from tqsdk.tradeable.sim.basesim import BaseSim
from tqsdk.tradeable.sim import TqSim, TqSimStock
1 change: 1 addition & 0 deletions tqsdk/tradeable/otg/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
from tqsdk.tradeable.otg.tqrohon import TqRohon
from tqsdk.tradeable.otg.tqjees import TqJees
from tqsdk.tradeable.otg.tqyida import TqYida
from tqsdk.tradeable.otg.tqo32 import TqO32, O32Account
from tqsdk.tradeable.otg.tqtradingunit import TqTradingUnit
124 changes: 124 additions & 0 deletions tqsdk/tradeable/otg/tqo32.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# -*- coding:utf-8 -*-
__author__ = 'chenli'

import hashlib
from dataclasses import dataclass

from tqsdk.tradeable.otg.base_otg import BaseOtg
from tqsdk.tradeable.mixin import FutureMixin


@dataclass
class O32Account:
user: str # 用户
fund: str # 基金
asset_unit: str # 资产单元
portfolio: str # 组合

def __post_init__(self) -> None:
if not isinstance(self.user, str):
raise Exception("user 参数类型应该是 str")
if not isinstance(self.fund, str):
raise Exception("fund 参数类型应该是 str")
if not isinstance(self.asset_unit, str):
raise Exception("asset_unit 参数类型应该是 str")
if not isinstance(self.portfolio, str):
raise Exception("portfolio 参数类型应该是 str")

@property
def user_name(self) -> str:
return ".".join([self.user, self.fund, self.asset_unit, self.portfolio])


class TqO32(BaseOtg, FutureMixin):
"""恒生 O32 账户类"""

def __init__(self, account_id: O32Account, password: str, td_front_url: str, mc_front_url: str,
license_file: str, auth_code: str) -> None:
"""
创建恒生 O32 账户实例

Args:
account_id (O32Account): O32 组合账户

password (str): O32 用户密码

td_front_url (str): O32 交易前置地址,格式如 112.54.165.180:9003

mc_front_url (str): O32 查询前置地址,格式如 110.54.163.160:8003

license_file (str): O32 许可证文件绝对路径

auth_code (str): O32 授权码

Example1::

from tqsdk import TqApi, TqAuth, TqO32, O32Account

def create_account():
return TqO32(
account_id=O32Account(user="用户", fund="基金", asset_unit="资产单元", portfolio="组合"),
password="password",
td_front_url="trade_front_host:trade_front_port",
mc_front_url="query_front_host:query_front_port",
license_file="/path/to/license.dat",
auth_code="auth_code",
)

with TqApi(account=create_account(), auth=TqAuth("快期账户", "账户密码")) as api:
account_info = api.get_account()
positions = api.get_position()

print("当前账户信息:", account_info)
print("当前持仓信息:", positions)

注意:
1. 使用 TqO32 账户需要安装 tqsdk_zq_otg 包: pip install -U tqsdk_zq_otg
2. td_front_url、mc_front_url、license_file 和 auth_code 信息需要向柜台方获取

"""
if not isinstance(account_id, O32Account):
raise Exception("account_id 参数类型应该是 O32Account")
if not isinstance(td_front_url, str):
raise Exception("td_front_url 参数类型应该是 str")
if not isinstance(mc_front_url, str):
raise Exception("mc_front_url 参数类型应该是 str")
if not isinstance(license_file, str):
raise Exception("license_file 参数类型应该是 str")
if not isinstance(auth_code, str):
raise Exception("auth_code 参数类型应该是 str")
self._td_front_url = td_front_url
self._mc_front_url = mc_front_url
self._license_file = license_file
self._auth_code = auth_code
if not self._license_file:
raise Exception("license_file 参数不能为空字符串")
super(TqO32, self).__init__(broker_id="", account_id=account_id.user_name, password=password, td_url="zqotg://127.0.0.1:0/trade")

@property
def _account_auth(self):
return {
"feature": "tq_direct",
"account_id": self._account_id,
"auto_add": True,
}

def _get_account_key(self):
s = self._broker_id + self._account_id
s += self._td_front_url if self._td_front_url else ""
s += self._mc_front_url if self._mc_front_url else ""
s += self._license_file if self._license_file else ""
return hashlib.md5(s.encode('utf-8')).hexdigest()

async def _send_login_pack(self):
req = {
"aid": "req_login",
"backend": "o32",
"user_name": self._account_id,
"password": self._password,
"trading_fronts": [self._td_front_url, self._mc_front_url],
"license_file_addr": self._license_file,
"auth_code": self._auth_code,
"app_id": "tqsdk_o32",
}
await self._td_send_chan.send(req)