From 573ad2254e2650ab4bc5fd4b93aab5c17cdeacf5 Mon Sep 17 00:00:00 2001 From: shinny-hongyan Date: Wed, 30 Oct 2024 08:38:16 +0000 Subject: [PATCH] Update Version 3.7.4 --- PKG-INFO | 14 +- README.md | 10 +- doc/advanced/tqsdk2ctptest.rst | 2 +- doc/advanced/unanttended.rst | 2 +- doc/conf.py | 4 +- doc/profession.rst | 39 +--- doc/quickstart.rst | 31 ++- doc/tqsdk_llm.rst | 2 +- doc/usage/backtest.rst | 4 +- doc/usage/mddatas.rst | 2 +- doc/usage/option_trade.rst | 2 +- doc/usage/shinny_account.rst | 2 +- doc/usage/trade.rst | 2 +- doc/version.rst | 9 +- setup.py | 6 +- tqsdk/__version__.py | 2 +- tqsdk/api.py | 117 ++++++++-- tqsdk/auth.py | 48 +++- tqsdk/connect.py | 6 +- tqsdk/ins_schema.py | 398 +++++++++++++++++++++++++++++---- tqsdk/objs.py | 2 + tqsdk/objs_not_entity.py | 91 ++++++++ tqsdk/risk_rule.py | 6 +- tqsdk/tafunc.py | 2 +- tqsdk/tools/downloader.py | 4 +- tqsdk/tradeable/otg/tqkq.py | 2 +- 26 files changed, 667 insertions(+), 142 deletions(-) diff --git a/PKG-INFO b/PKG-INFO index 00437a36..e26e315e 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: tqsdk -Version: 3.7.3 +Version: 3.7.4 Summary: TianQin SDK Home-page: https://www.shinnytech.com/tqsdk Author: TianQin @@ -10,7 +10,7 @@ Platform: UNKNOWN Classifier: Programming Language :: Python :: 3 Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: OS Independent -Requires-Python: >=3.6.4 +Requires-Python: >=3.7 Description-Content-Type: text/markdown License-File: LICENSE @@ -20,7 +20,7 @@ License-File: LICENSE

- +

@@ -83,7 +83,7 @@ TqSdk 提供的功能可以支持从简单到复杂的各类策略程序. Installation ------------------------------------------------- -TqSdk 仅支持 Python 3.6 及更高版本. 要安装 TqSdk, 可使用 pip: +TqSdk 仅支持 Python 3.7 及更高版本. 要安装 TqSdk, 可使用 pip: ``` {.sourceCode .bash} $ pip install tqsdk @@ -94,11 +94,11 @@ Documentation ------------------------------------------------- 在线阅读HTML版本文档: https://doc.shinnytech.com/tqsdk/latest -在线问答社区: https://www.shinnytech.com/qa - 知乎账户【天勤量化】:https://www.zhihu.com/org/tian-qin-liang-hua/activities -用户交流QQ群: **619870862** (目前只允许给我们点过STAR的同学加入, 加群时请提供github用户名) +天勤AI助手:https://udify.app/chat/im02prcHNEOVbPAx 解释函数,编写demo策略,分析报错原因,它都可以做到! + +用户交流QQ群: **611806823** (目前只允许给我们点过STAR的同学加入, 加群时请提供github用户名) Gui diff --git a/README.md b/README.md index a8c261ad..fc32324d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@

- +

@@ -67,7 +67,7 @@ TqSdk 提供的功能可以支持从简单到复杂的各类策略程序. Installation ------------------------------------------------- -TqSdk 仅支持 Python 3.6 及更高版本. 要安装 TqSdk, 可使用 pip: +TqSdk 仅支持 Python 3.7 及更高版本. 要安装 TqSdk, 可使用 pip: ``` {.sourceCode .bash} $ pip install tqsdk @@ -78,11 +78,11 @@ Documentation ------------------------------------------------- 在线阅读HTML版本文档: https://doc.shinnytech.com/tqsdk/latest -在线问答社区: https://www.shinnytech.com/qa - 知乎账户【天勤量化】:https://www.zhihu.com/org/tian-qin-liang-hua/activities -用户交流QQ群: **619870862** (目前只允许给我们点过STAR的同学加入, 加群时请提供github用户名) +天勤AI助手:https://udify.app/chat/im02prcHNEOVbPAx 解释函数,编写demo策略,分析报错原因,它都可以做到! + +用户交流QQ群: **611806823** (目前只允许给我们点过STAR的同学加入, 加群时请提供github用户名) Gui diff --git a/doc/advanced/tqsdk2ctptest.rst b/doc/advanced/tqsdk2ctptest.rst index 0e1ca355..496d1d08 100644 --- a/doc/advanced/tqsdk2ctptest.rst +++ b/doc/advanced/tqsdk2ctptest.rst @@ -22,5 +22,5 @@ TqSdk 没有直接提供查询保证金的接口,但是你可以通过使用 T # 正常和tqsdk一样执行策略 -TqSdk2 的直连功能需要企业版权限,有关企业版的具体费用和功能,请参考 `天勤官方网站 `_ +TqSdk2 的直连功能需要企业版权限,有关企业版的具体费用和功能,请参考 `天勤官方网站 `_ 如果想了解更多关于 TqSdk2 的直连功能TqCtp,请参考 `tqsdk2官方文档 `_ diff --git a/doc/advanced/unanttended.rst b/doc/advanced/unanttended.rst index b577a456..a4583f86 100644 --- a/doc/advanced/unanttended.rst +++ b/doc/advanced/unanttended.rst @@ -8,7 +8,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TqSdk可以在windows/linux或macosx环境下运行. 无论您选择使用windows或linux系统, 请确保 -* 已经装有 Python 3.6+ +* 已经装有 Python 3.7+ * 安装 :ref:`TqSdk ` 创建一个目录, 放置你所有的策略文件. diff --git a/doc/conf.py b/doc/conf.py index 618e3046..4e2396f4 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -48,9 +48,9 @@ # built documents. # # The short X.Y version. -version = u'3.7.3' +version = u'3.7.4' # The full version, including alpha/beta/rc tags. -release = u'3.7.3' +release = u'3.7.4' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/profession.rst b/doc/profession.rst index 5a19c058..4b1e8de0 100644 --- a/doc/profession.rst +++ b/doc/profession.rst @@ -14,7 +14,7 @@ TqSdk 中大部分功能是供用户免费使用的, 同时我们也提供了专 此外还提供了丰富的交易手段与监控功能,帮助用户在程序化交易的同时能有一个PC端进行辅助监控与交易 -其中的持仓账户监控功能,内置了一基于grafana实时的监控手段,每5s存储一次用户的账户和持仓数据在本地,供用户对这些数据进行可视化分析 +其中的持仓账户监控功能,内置了一基于 grafana 实时的监控手段,每10s存储一次用户的账户和持仓数据在本地,供用户对这些数据进行可视化分析 例如回答用户今天的客户权益变动情况,和今天的最大权益和最小权益的发生时间等 @@ -30,11 +30,13 @@ TqSdk 中大部分功能是供用户免费使用的, 同时我们也提供了专 专业版的行情服务器会在免费版全部升级成功且没有问题之后再进行升级,因此对于 TqSdk 的专业版用户来说,会有更稳定行情服务器连接 -更多的实盘交易账户数 +更多的期货公司支持 ------------------------------------------------- -对于 TqSdk 免费版,每个快期账户支持最多绑定一个实盘账户,而天勤量化专业版支持最多一个快期账户绑定3个实盘账户 +对于 TqSdk 免费版,用户只能选择指定的期货公司进行免费实盘交易,专业版支持用户选择其他的期货公司来进行交易 -快期账户会在用户使用实盘账户时自动进行绑定,直到该快期账户没有能绑定实盘账户的名额(自动绑定功能需要 TqSdk 版本> 1.8.3) +支持免费实盘交易的期货公司,和 `全部期货公司的名单列表 `_ + +TqSdk 免费版和专业版均支持用户绑定3个账户,如需一个快期账户支持更多的实盘账户,请联系工作人员进行批量购买 QQ:532428198 如果需要注册快期账户或者修改您的快期账户绑定的实盘账户,请点击 `登录用户管理中心 `_ @@ -42,15 +44,6 @@ TqSdk 中大部分功能是供用户免费使用的, 同时我们也提供了专 .. figure:: images/user_web_management.png -如需一个快期账户支持更多的实盘账户,请联系工作人员进行批量购买 `个人中心 `_ - -策略回测功能 -------------------------------------------------- -:ref:`backtest` 是 TqSdk 专业版中的功能,能让用户在不改变代码的情况下去回测自己的策略在历史行情的表现,并且提供对应的web界面来统计用户的回测表现 - -.. figure:: images/web_gui_backtest.png - -对于 TqSdk 免费版本的用户,每天可以进行3次回测,同时也可以申请模拟账户后模拟运行来检验策略 :ref:`sim_trading` 股票行情 ------------------------------------------------- @@ -112,29 +105,9 @@ TqSdk 提供了 :py:class:`~tqsdk.TqKqStock` 方法供用户来进行股票的 其他相关函数 ------------------------------------------------- - :py:meth:`~tqsdk.TqApi.query_symbol_ranking` 交易所每日成交持仓排名 :py:meth:`~tqsdk.TqApi.get_kline_data_series` 以起始日期获取 Dataframe 格式的 kline 数据 - :py:meth:`~tqsdk.TqApi.get_trading_status` 获取指定合约的交易状态,帮助用户实现开盘/跨小节抢单 - -期权交易 & 交易所组合 -------------------------------------------------- -TqSdk 中期权交易(商品期权、金融期权)和交易所官方组合也是 TqSdk 专业版中提供的功能 - -详细期权说明请点击 :ref:`option_trade` - -TqSdk 中期权和交易所组合合约代码参考如下:: - - DCE.m1807-C-2450 - 大商所豆粕期权 - CZCE.CF003C11000 - 郑商所棉花期权 - SHFE.au2004C308 - 上期所黄金期权 - CFFEX.IO2002-C-3550 - 中金所沪深300股指期权 - SSE.10002513 - 上交所上证50etf期权 - SSE.10002504 - 上交所沪深300etf期权 - SZSE.90000097 - 深交所沪深300etf期权 - CZCE.SPD SR901&SR903 - 郑商所 SR901&SR903 跨期合约 - DCE.SP a1709&a1801 - 大商所 a1709&a1801 跨期合约 工作时间内的天勤客服支持 ------------------------------------------------- diff --git a/doc/quickstart.rst b/doc/quickstart.rst index 8cd65369..d0c600da 100644 --- a/doc/quickstart.rst +++ b/doc/quickstart.rst @@ -253,25 +253,23 @@ klines是一个pandas.DataFrame对象. 跟 api.get_quote() 一样, api.get_kline from tqsdk import TqApi, TqAuth, TqAccount - api = TqApi(TqAccount("H海通期货", "412432343", "123456"), auth=TqAuth("快期账户", "账户密码")) +# 如果要更换为徽商期货,只需要改为 H徽商期货 + api = TqApi(TqAccount("H宏源期货", "412432343", "123456"), auth=TqAuth("快期账户", "账户密码")) 更多关于实盘交易细节,请点击 :ref:`trade` -目前支持的期货公司列表, 请点击查看: `TqSdk支持的期货公司列表 `_ +其中实盘交易是属于 TqSdk 的专业版功能,用户需要购买 TqSdk 专业版才可以进行实盘交易, `点击申请试用或者购买 `_ + +于此同时,TqSdk 支持在部分的期货公司开户来进行免费的实盘交易,详细期货公司介绍请点击查看 `TqSdk支持的期货公司列表 `_ -注册快期账户,请点击 `登录用户管理中心 `_ .. _sim_trading: 模拟交易和论坛 ------------------------------------------------- -如果您需要使用能保存账户资金及持仓信息的模拟交易功能, 请点击 `注册信易账号 `_ ,填写完对应信息之后,并验证成功即可进入 `用户论坛 `_ . - -.. figure:: images/tq_register.png +如果您需要使用能保存账户资金及持仓信息的模拟交易功能,通过 :py:class:`~tqsdk.TqKq` 对 auth 传入参数进行登录,可以得到一个长期有效的快期模拟账户,快期模拟账户在快期APP、快期专业版、快期v2、快期v3 和天勤量化上是互通的 -刚刚注册完成的快期账户的【手机号】/【邮箱地址】/【用户名】和【密码】可以作为 快期模拟 账号,通过 :py:class:`~tqsdk.TqKq` 对 auth 传入参数进行登录,这个 快期模拟 账户在快期APP、快期V3 pro 和天勤量化上是互通的 - -快期模拟的资金可以通过快期APP、快期专业版的模拟银行进行出入金:: +快期模拟的资金可以通过快期APP、快期专业版的模拟银行进行出入金,也可以通过快期专业版对该账户进行重置:: from tqsdk import TqApi, TqAuth, TqKq @@ -285,6 +283,21 @@ klines是一个pandas.DataFrame对象. 跟 api.get_quote() 一样, api.get_kline +TqSdk AI 助手 +------------------------------------------------- +TqSdk 基于先进的大语言模型和常见天勤问题资料库,提供了新一代的 AI 助手 + +解释函数,编写demo策略,分析代码报错原因,它都有不错的表现 `点击使用 `_ + +.. figure:: images/llm_pic1.png +.. figure:: images/llm_pic2.png +.. figure:: images/llm_pic3.png +.. figure:: images/llm_pic4.png +.. figure:: images/llm_pic5.png +.. figure:: images/llm_pic6.png +.. figure:: images/llm_pic7.png + + TqSdk 学习视频 ------------------------------------------------- TqSdk 提供简单易懂的十分钟上手视频 `供用户学习 `_ diff --git a/doc/tqsdk_llm.rst b/doc/tqsdk_llm.rst index 3030a6e5..9ee95c80 100644 --- a/doc/tqsdk_llm.rst +++ b/doc/tqsdk_llm.rst @@ -1,6 +1,6 @@ .. _tqsdk_llm: -天勤量化机器人助手 +天勤量化 AI 助手 ----------------------------------------------- 在使用天勤的过程中,用户往往会遇到各种问题,尤其是初学者,他们可能会关心以下几点: diff --git a/doc/usage/backtest.rst b/doc/usage/backtest.rst index 7466f703..24153c48 100644 --- a/doc/usage/backtest.rst +++ b/doc/usage/backtest.rst @@ -4,9 +4,9 @@ ================================================= 策略程序回测是 TqSdk 专业版中的功能,能让用户在不改变代码的情况下去回测自己的策略在历史行情的表现 -如果想使用策略回测该功能,可以点击 `天勤量化专业版 `_ 申请使用或购买 +如果想使用策略回测该功能,可以点击 `天勤量化专业版 `_ 申请使用或购买 -对于 TqSdk 免费版本的用户,每天可以进行3次回测,同时也可以申请模拟账户后模拟运行来检验策略 :ref:`sim_trading` +用户也可以申请模拟账户后模拟运行来检验策略 :ref:`sim_trading` 执行策略回测 ------------------------------------------------- diff --git a/doc/usage/mddatas.rst b/doc/usage/mddatas.rst index 6887901b..2c9927a3 100644 --- a/doc/usage/mddatas.rst +++ b/doc/usage/mddatas.rst @@ -9,7 +9,7 @@ TqSdk中的合约代码, 统一采用 交易所代码.交易所内品种代码 其中 TqSdk 免费版本提供全部的期货、商品/金融期权和上证50、沪深300、中证500和中证1000的实时行情 -购买或申请 TqSdk 专业版试用后可提供A股股票的实时和历史行情,具体免费版和专业版的区别,请点击 `天勤量化专业版 `_ +购买或申请 TqSdk 专业版试用后可提供A股股票的实时和历史行情,具体免费版和专业版的区别,请点击 `天勤量化专业版 `_ 目前 TqSdk 支持的交易所包括: diff --git a/doc/usage/option_trade.rst b/doc/usage/option_trade.rst index 122614f9..152a3cf7 100644 --- a/doc/usage/option_trade.rst +++ b/doc/usage/option_trade.rst @@ -4,7 +4,7 @@ ==================================================== TqSdk 中期权交易(商品期权、金融期权和 ETF 期权)和交易所官方组合交易,均是 TqSdk 专业版中的功能 -用户如果想在 TqSdk 中进行上述操作,可以点击 `天勤量化专业版 `_ 申请使用或购买 +用户如果想在 TqSdk 中进行上述操作,可以点击 `天勤量化专业版 `_ 申请使用或购买 TqSdk 中期权合和交易所官方组合的约代码格式参考如下:: diff --git a/doc/usage/shinny_account.rst b/doc/usage/shinny_account.rst index 9670c5fd..567cc0a6 100644 --- a/doc/usage/shinny_account.rst +++ b/doc/usage/shinny_account.rst @@ -39,7 +39,7 @@ .. figure:: ../images/user_web_management.png -如需一个快期账户支持更多的实盘账户,请联系工作人员进行批量购买 `天勤量化专业版 `_ +如需一个快期账户支持更多的实盘账户,请联系工作人员进行批量购买 `天勤量化专业版 `_ diff --git a/doc/usage/trade.rst b/doc/usage/trade.rst index d990c19f..bd10d472 100644 --- a/doc/usage/trade.rst +++ b/doc/usage/trade.rst @@ -23,7 +23,7 @@ .. figure:: ../images/user_web_management.png -如果需要让您的快期账户支持更多的实盘账户,可以购买或申请试用我们的 `天勤量化专业版 `_ +如果需要让您的快期账户支持更多的实盘账户,可以购买或申请试用我们的 `天勤量化专业版 `_ 设定实盘交易账户 ---------------------------------------------------- diff --git a/doc/version.rst b/doc/version.rst index ef978df8..f1a448eb 100644 --- a/doc/version.rst +++ b/doc/version.rst @@ -2,6 +2,13 @@ 版本变更 ============================= +3.7.4 (2024/10/28) + +* 新增::py:class:`~tqsdk.objs.Quote` 增加属性 :py:meth:`~tqsdk.objs.Quote.position_limit` +* 增加: TqApi 增加 :py:meth:`~tqsdk.TqApi.query_symbol_settlement` 接口,支持查询合约每日结算价 +* 增加: TqAuth 增加 :py:meth:`~tqsdk.TqAuth.expire_datetime` 接口,支持查询快期账户授权到期时间 +* 自该版本起仅支持 Python >=3.7 + 3.7.3 (2024/09/20) * 新增::py:class:`~tqsdk.TqJees` 账户类型,支持杰宜斯资管柜台 @@ -739,7 +746,7 @@ 2.0.2 (2020/09/18) -* 2020/10/01 以后,免费版用户不再支持回测,下载数据等功能,`点击了解专业版和免费版区别 `_ +* 2020/10/01 以后,免费版用户不再支持回测,下载数据等功能,`点击了解专业版和免费版区别 `_ * 修改中证 500 的合约名称为 SSE.000905 * 修改 TqAccount 检查参数类型并提示用户 diff --git a/setup.py b/setup.py index eb38e041..b8cfeb8c 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setuptools.setup( name='tqsdk', - version="3.7.3", + version="3.7.4", description='TianQin SDK', author='TianQin', author_email='tianqincn@gmail.com', @@ -16,9 +16,9 @@ long_description_content_type="text/markdown", url='https://www.shinnytech.com/tqsdk', packages=setuptools.find_packages(exclude=["tqsdk.test", "tqsdk.test.*"]), - python_requires='>=3.6.4', + python_requires='>=3.7', install_requires=["websockets>=8.1", "requests", "numpy", "pandas>=1.1.0", "scipy", "simplejson", "aiohttp", - "certifi", "pyjwt", "psutil", "shinny_structlog", "sgqlc", "filelock", "tqsdk_ctpse", "tqsdk_sm"], + "certifi", "pyjwt", "psutil>=5.9.6", "shinny_structlog", "sgqlc", "filelock", "tqsdk_ctpse", "tqsdk_sm"], classifiers=[ "Programming Language :: Python :: 3", "License :: OSI Approved :: Apache Software License", diff --git a/tqsdk/__version__.py b/tqsdk/__version__.py index 87c08592..e604a8e1 100644 --- a/tqsdk/__version__.py +++ b/tqsdk/__version__.py @@ -1 +1 @@ -__version__ = '3.7.3' +__version__ = '3.7.4' diff --git a/tqsdk/api.py b/tqsdk/api.py index 5795e8d6..e20b8139 100644 --- a/tqsdk/api.py +++ b/tqsdk/api.py @@ -67,7 +67,7 @@ from tqsdk.objs import Quote, TradingStatus, Kline, Tick, Account, Position, Order, Trade, QuotesEntity, RiskManagementRule, RiskManagementData from tqsdk.objs import SecurityAccount, SecurityOrder, SecurityTrade, SecurityPosition from tqsdk.objs_not_entity import QuoteList, TqDataFrame, TqSymbolDataFrame, SymbolList, SymbolLevelList, \ - TqSymbolRankingDataFrame, TqOptionGreeksDataFrame + TqSymbolRankingDataFrame, TqOptionGreeksDataFrame, TqMdSettlementDataFrame from tqsdk.risk_manager import TqRiskManager from tqsdk.risk_rule import TqRiskRule from tqsdk.ins_schema import ins_schema, basic, derivative, future, option @@ -159,6 +159,13 @@ def __init__(self, account: Optional[Union[TqMultiAccount, UnionTradeable]] = No * False: 不输出调试信息。 * str: 指定一个日志文件名, 调试信息输出到指定文件。 + + disable_print(bool): [可选] 是否隐藏提示信息,默认值为 False + * False [默认]: 打印提示信息。 + + * True: 隐藏提示信息。 + + + 提示信息会输出到标准输出流,即 sys.stdout,标准输出流默认指向控制台。 loop(asyncio.AbstractEventLoop): [可选] 使用指定的 IOLoop, 默认创建一个新的. @@ -547,7 +554,7 @@ def get_trading_status(self, symbol: str) -> TradingStatus: """ 获取指定合约的交易状态. 此接口为 TqSdk 专业版提供,便于实现开盘抢单功能。 - 如果想使用此功能,可以点击 `天勤量化专业版 `_ 申请试用或购买 + 如果想使用此功能,可以点击 `天勤量化专业版 `_ 申请试用或购买 Args: symbol (str): 合约代码 @@ -575,7 +582,7 @@ def get_trading_status(self, symbol: str) -> TradingStatus: if symbol == "": raise Exception(f"get_trading_status 中合约代码不能为空字符串") if not self._auth._has_feature('tq_trading_status'): - raise Exception(f"您的账户不支持查看交易状态信息,需要购买后才能使用。升级网址:https://www.shinnytech.com/tqsdk_professional/") + raise Exception(f"您的账户不支持查看交易状态信息,需要购买后才能使用。升级网址:https://www.shinnytech.com/tqsdk-buy/") if self._backtest: raise Exception('回测/复盘不支持查看交易状态信息') ts = _get_obj(self._data, ['trading_status', symbol], self._prototype["trading_status"]["#"]) @@ -850,7 +857,7 @@ def get_kline_data_series(self, symbol: Union[str, List[str]], duration_seconds: """ 获取指定时间段内的 K 线序列,TqSdk 会缓存已经下载过的合约,提升代码执行效率、节约请求流量。 - 本接口仅限专业版用户使用,如需购买专业版或者申请试用,请访问 https://www.shinnytech.com/tqsdk_professional/。 + 本接口仅限专业版用户使用,如需购买专业版或者申请试用,请访问 https://www.shinnytech.com/tqsdk-buy/。 该函数返回的对象不会更新,不建议在循环内调用该方法。 @@ -919,7 +926,7 @@ def get_tick_data_series(self, symbol: Union[str, List[str]], start_dt: Union[da """ 获取指定时间段内的 tick 序列,TqSdk 会缓存已经下载过的合约,提升代码执行效率、节约请求流量。 - 本接口仅限专业版用户使用,如需购买专业版或者申请试用,请访问 https://www.shinnytech.com/tqsdk_professional/。 + 本接口仅限专业版用户使用,如需购买专业版或者申请试用,请访问 https://www.shinnytech.com/tqsdk-buy/。 该函数返回的对象不会更新,不建议在循环内调用该方法。 @@ -982,7 +989,7 @@ def _get_data_series(self, call_func: str, symbol_list: Union[str, List[str]], d raise Exception(f"不支持在协程中调用 {call_func} 接口") if not self._auth._has_feature("tq_dl"): raise Exception( - f"{call_func} 数据获取方式仅限专业版用户使用,如需购买专业版或者申请试用,请访问 https://www.shinnytech.com/tqsdk_professional/") + f"{call_func} 数据获取方式仅限专业版用户使用,如需购买专业版或者申请试用,请访问 https://www.shinnytech.com/tqsdk-buy/") if self._backtest: raise Exception(f"不支持在回测/复盘中调用 {call_func} 接口") dur_nano = duration_seconds * 1000000000 @@ -1121,14 +1128,14 @@ def add_risk_rule(self, rule: TqRiskRule) -> None: """ 添加一项风控规则实例,此接口为 TqSdk 专业版提供。 - 如需使用此功能,可以点击 `天勤量化专业版 `_ 申请试用或购买 + 如需使用此功能,可以点击 `天勤量化专业版 `_ 申请试用或购买 Args: rule (TqRiskRule): 风控规则实例,必须是 TqRiskRule 的子类型 """ if not self._auth._has_feature("tq_lc_rk"): - raise Exception("本地风控功能仅限专业版用户使用,如需购买专业版或者申请试用,请访问 https://www.shinnytech.com/tqsdk_professional/") + raise Exception("本地风控功能仅限专业版用户使用,如需购买专业版或者申请试用,请访问 https://www.shinnytech.com/tqsdk-buy/") if not isinstance(rule, TqRiskRule): raise Exception("传入参数对象必须是 TqRiskRule 的类型") self._risk_manager.append(rule) @@ -1137,7 +1144,7 @@ def delete_risk_rule(self, rule: TqRiskRule) -> None: """ 删除一项风控规则实例,此接口为 TqSdk 专业版提供。 - 如需使用此功能,可以点击 `天勤量化专业版 `_ 申请试用或购买 + 如需使用此功能,可以点击 `天勤量化专业版 `_ 申请试用或购买 Args: rule (TqRiskRule): 风控规则实例,必须是 TqRiskRule 的子类型 @@ -2299,13 +2306,86 @@ def query_graphql(self, query: str, variables: dict, query_id: Optional[str] = N "variables": {} }) return _get_obj(self._data, ["symbols", query_id]) + + def query_symbol_settlement(self, symbol: Union[str, List[str]], days: int = 1, start_dt: date = None)\ + -> TqMdSettlementDataFrame: + """ + 查询交易所合约每日结算价 + + 本接口仅限专业版用户使用,如需购买专业版或者申请试用,请访问 https://www.shinnytech.com/tqsdk_professional/。 + + 该函数返回的对象不会更新,不建议在循环内调用该方法。 + + Args: + + symbol (str / list of str): [必填] 合约代码 + + days (int): [可选] 交易日数,默认为 1 + + start_dt (date): [可选] 开始日期,默认为 None + + Returns: + pandas.DataFrame: 本函数返回 pandas.DataFrame 实例。行数为 days * 合约数,每行是一条合约结算价信息。包含以下列: + + * datetime (查询日期) + * symbol (交易所内合约代码) + * settlement (结算价) + + 注意: + 1. 每日结算价产生时间: 每天的 18:30 ~ 19:00: + * 如果想查询交易日 20241011 的结算价,需要在 20241011 的 19:00 之后查询,否则无法获取 20241011 的数据 + + 2. 如果没有指定 start_dt 参数,则返回当前日期前,已经产生的 days 个交易日的结算价数据: + * 此处的 days 指的是交易日数,会自动跳过节假日、周末等非交易日 + * 假设当前日期是 20241011,days=7: + * 在 19:00 前查询,返回 20240925 20240926 20240927 20240930 20241008 20241009 20241010 的结算价信息 + * 在 19:00 后查询,返回 20240926 20240927 20240930 20241008 20241009 20241010 20241011 的结算价信息 + + 3. 如果指定了 start_dt 参数,则返回从 start_dt 日期起,已经产生的 days 个交易日的结算价数据: + * 假设开始日期为 20241008,当前日期是 20241011: + * 假设 days=3,返回 20241008 20241009 20241010 三天的结算价信息 + * 假设 days=4,如果在 19:00 之前查询,返回 20241008 20241009 20241010 三天的结算价信息 + * 假设 days=4,如果在 19:00 之后查询,返回 20241008 20241009 20241010 20241011 四天的结算价信息 + + 4. 数据支持范围: + * 期货数据: + * 中金所、上期所、上能所、大商所、郑商所:20200102 起 + * 广期所:20221226 起 + * 期权数据: + * 中金所、上期所、大商所、郑商所:20200102 起 + * 上能所:20210621 起 + * 广期所:20221226 起 + + + Example:: + + from tqsdk import TqApi, TqAuth + api = TqApi(auth=TqAuth("快期账户", "账户密码")) + + df = api.query_symbol_settlement("INE.nr2408", days=3) + print(df.to_string()) # 最近 3 天结算价信息 + api.close() + + """ + if not (isinstance(symbol, (str, list))): + raise Exception(f"symbol 参数类型 {type(symbol)} 错误。") + if not (start_dt is None or isinstance(start_dt, date)): + raise Exception(f"start_dt 参数类型 {type(start_dt)} 错误。") + if not isinstance(days, int) or days < 1: + raise Exception(f"days 参数 {days} 错误。") + df = TqMdSettlementDataFrame(self, symbol=symbol, days=days, start_dt=start_dt) + deadline = time.time() + 30 + while not self._loop.is_running() and not df.__dict__["_task"].done(): + if not self.wait_update(deadline=deadline, _task=df.__dict__["_task"]): + raise TqTimeoutError("获取每日结算价信息超时,请检查客户端及网络是否正常") + return df def query_symbol_ranking(self, symbol: str, ranking_type: str, days: int = 1, start_dt: date = None, broker: str = None)\ -> TqSymbolRankingDataFrame: """ 查询合约成交排名/持仓排名 - 本接口仅限专业版用户使用,如需购买专业版或者申请试用,请访问 https://www.shinnytech.com/tqsdk_professional/。 + 本接口仅限专业版用户使用,如需购买专业版或者申请试用,请访问 https://www.shinnytech.com/tqsdk-buy/。 该函数返回的对象不会更新,不建议在循环内调用该方法。 @@ -3215,13 +3295,24 @@ def _setup_connection(self): else: self._auth.init(mode="bt" if isinstance(self._backtest, TqBacktest) else "real") self._auth.login() # tqwebhelper 有可能会设置 self._auth + + # tqsdk 内部捕获异常如果需要打印日志,则需要自定义异常 + # 对于第三方代码产生的异常需要逐个捕获,可以参考 connect.py TqConnect._run 函数中对于各类异常的捕获 + # 这里只是打印账户过期日期来提醒用户,不关心是否成功,也不记录日志,所以直接 pass + # 单独捕获 self._auth.expire_datetime 是为了语义清晰,表明异常的来源 + try: + self._auth.expire_datetime + except Exception: + pass + if self._auth._expire_days_left is not None and self._auth._product_type is not None and self._auth._expire_days_left < 30: + self._print(f"TqSdk {self._auth._product_type} 版剩余 {self._auth._expire_days_left} 天到期,如需续费或升级请访问 https://account.shinnytech.com/ 或联系相关工作人员。") # 在快期账户登录之后,对于账户的基本信息校验及更新 for acc in self._account._account_list: if isinstance(acc, BaseOtg): acc._update_otg_info(self) # 获取交易地址;更新模拟账户 _account_id if not self._check_account_auth(acc): - raise Exception(f"您的账户不支持 {type(acc)},需要购买后才能使用。升级网址:https://www.shinnytech.com/tqsdk_professional/") + raise Exception(f"您的账户不支持 {type(acc)},需要购买后才能使用。升级网址:https://www.shinnytech.com/tqsdk-buy/") # 等待复盘服务器启动 if isinstance(self._backtest, TqReplay): @@ -4048,8 +4139,8 @@ def _get_current_datetime(self): print("在使用天勤量化之前,默认您已经知晓并同意以下免责条款,如果不同意请立即停止使用:https://www.shinnytech.com/blog/disclaimer/", file=sys.stderr) -if platform.python_version().startswith('3.6'): - warnings.warn("TqSdk 计划在 20220601 之后放弃支持 Python 3.6 版本,请尽快升级 Python 版本。", FutureWarning, stacklevel=1) +if platform.python_version().startswith('3.7.'): + warnings.warn("TqSdk 计划在 20250601 之后放弃支持 Python 3.7 版本,请尽快升级 Python 版本。", FutureWarning, stacklevel=1) try: diff --git a/tqsdk/auth.py b/tqsdk/auth.py index cd8c4681..c909f2df 100644 --- a/tqsdk/auth.py +++ b/tqsdk/auth.py @@ -12,6 +12,7 @@ from tqsdk.constants import FUTURE_EXCHANGES, SPOT_EXCHANGES, KQ_EXCHANGES, KQD_EXCHANGES, STOCK_EXCHANGES from tqsdk.__version__ import __version__ +from tqsdk.datetime import _cst_tz, datetime class TqAuth(object): @@ -45,6 +46,9 @@ def __init__(self, user_name: str = "", password: str = ""): "features": [], "accounts": [] } + self._expire_datetime = None + self._expire_days_left = None + self._product_type = None self._logger = ShinnyLoggerAdapter(logging.getLogger("TqApi.TqAuth"), headers=self._base_headers, grants=self._grants) @property @@ -55,6 +59,46 @@ def _base_headers(self): "Authorization": "Bearer %s" % self._access_token } + @property + def expire_datetime(self): + """ + 返回快期账户授权到期时间 + + Returns: + datetime.datetime : datetime 模块中的 datetime 类型时间 + * 返回授权到期时间,如果查询失败则抛出异常。 + * 时区是东八区。 + + 注意: + 1. 对于免费用户,将返回到期时间:"2099-12-31 23:59:59+08:00",代表权限永不到期。 + + 2. 当用户升级版本或者续费后,将在下一次使用时获取最新到期时间。 + + + Example:: + + from tqsdk import TqApi, TqAuth + + auth = TqAuth("快期账户", "账户密码") + api = TqApi(auth=auth) + print(auth.expire_datetime) # 快期账户授权到期时间 + api.close() + + """ + if self._expire_datetime is None or self._expire_days_left is None or self._product_type is None: + url = f"{self._auth_url}/auth/realms/shinnytech/rest/get-grant/tq" + self._logger.debug("get auth expire datetime", url=url, method="GET") + response = requests.get(url=url, headers=self._base_headers, timeout=30) + self._logger.debug("get auth expire datetime result", url=response.url, status_code=response.status_code, headers=response.headers, reason=response.reason, text=response.text) + try: + content = json.loads(response.content) + self._expire_datetime = datetime.datetime.fromtimestamp(content["exp"], tz=_cst_tz) + self._expire_days_left = content["daysleft"] + self._product_type = content["account_type"] + except Exception: + raise Exception("查询快期账户授权到期日期失败") from None + return self._expire_datetime + def init(self, mode="real"): self._mode = mode @@ -156,7 +200,7 @@ def _has_md_grants(self, symbol): elif symbol in ["SSE.000016", "SSE.000300", "SSE.000905", "SSE.000852"] and self._has_feature("lmt_idx"): continue else: - raise Exception(f"您的账户不支持查看 {symbol} 的行情数据,需要购买后才能使用。升级网址:https://www.shinnytech.com/tqsdk_professional/") + raise Exception(f"您的账户不支持查看 {symbol} 的行情数据,需要购买后才能使用。升级网址:https://www.shinnytech.com/tqsdk-buy/") return True def _has_td_grants(self, symbol): @@ -165,4 +209,4 @@ def _has_td_grants(self, symbol): return True if symbol.split('.', 1)[0] in (FUTURE_EXCHANGES + KQ_EXCHANGES) and self._has_feature("futr"): return True - raise Exception(f"您的账户不支持交易 {symbol},需要购买后才能使用。升级网址:https://www.shinnytech.com/tqsdk_professional/") + raise Exception(f"您的账户不支持交易 {symbol},需要购买后才能使用。升级网址:https://www.shinnytech.com/tqsdk-buy/") diff --git a/tqsdk/connect.py b/tqsdk/connect.py index fefe89e3..6d67e139 100644 --- a/tqsdk/connect.py +++ b/tqsdk/connect.py @@ -82,7 +82,7 @@ async def handshake(self, *args, **kwargs) -> None: for h_key, h_value in self.response_headers.items(): if h_key == 'x-shinny-auth-check' and h_value == 'Backtest Permission Denied': raise TqBacktestPermissionError( - "免费账户每日可以回测3次,今日暂无回测权限,需要购买后才能使用。升级网址:https://www.shinnytech.com/tqsdk_professional/") from None + "免费账户每日可以回测3次,今日暂无回测权限,需要购买后才能使用。升级网址:https://www.shinnytech.com/tqsdk-buy/") from None raise async def read_message(self): @@ -112,6 +112,7 @@ async def _run(self, api, url, send_chan, recv_chan): """启动websocket客户端""" self._api = api # 调整代码位置,方便 monkey patch + self._query_max_length = 50000 # ins_query 最大长度 self._ins_list_max_length = 100000 # subscribe_quote 最大长度 self._subscribed_per_seconds = 100 # 每秒 subscribe_quote 请求次数限制 self._subscribed_queue = Queue(self._subscribed_per_seconds) @@ -255,6 +256,9 @@ async def _send_handler(self, send_chan, client): if time.time() - first_time < 1: warnings.warn(f"1s 内订阅请求次数超过 {self._subscribed_per_seconds} 次,订阅多合约时推荐使用 api.get_quote_list 方法。", stacklevel=3) self._subscribed_queue.put(time.time()) + if pack.get("aid") == "ins_query": + if len(pack.get("query", "")) > self._query_max_length: + warnings.warn(f"订阅合约信息字段总长度大于 {self._query_max_length},可能会引起服务器限制。", stacklevel=3) msg = json.dumps(pack) await client.send(msg) self._logger.debug("websocket send data", pack=msg) diff --git a/tqsdk/ins_schema.py b/tqsdk/ins_schema.py index 891e44c0..db889bbf 100644 --- a/tqsdk/ins_schema.py +++ b/tqsdk/ins_schema.py @@ -32,11 +32,43 @@ def _tqsdk__to_graphql_input__(self, value, *args, **kwargs): class Category(sgqlc.types.Enum): + '''全部板块 + + Enumeration Choices: + + * `AGRICULTURAL`: 农副 + * `CHEMICAL`: 化工 + * `COAL`: 煤炭 + * `EQUITY_INDEX`: 股指期货 + * `FERROUS`: 黑色金属 + * `GRAIN`: 谷物 + * `GREASE`: 油脂油料 + * `LIGHT_INDUSTRY`: 轻工 + * `NONFERROUS_METALS`: 有色金属 + * `OIL`: 石油 + * `PRECIOUS_METALS`: 贵金属 + * `SOFT_COMMODITY`: 软商 + * `TREASURY_BOND`: 国债期货 + ''' __schema__ = ins_schema __choices__ = ('AGRICULTURAL', 'CHEMICAL', 'COAL', 'EQUITY_INDEX', 'FERROUS', 'GRAIN', 'GREASE', 'LIGHT_INDUSTRY', 'NONFERROUS_METALS', 'OIL', 'PRECIOUS_METALS', 'SOFT_COMMODITY', 'TREASURY_BOND') class Class(sgqlc.types.Enum): + '''全部类别 + + Enumeration Choices: + + * `BOND`: 债券 + * `COMBINE`: 组合 + * `CONT`: 连续 + * `FUND`: 基金 + * `FUTURE`: 期货 + * `INDEX`: 指数 + * `OPTION`: 期权 + * `SPOT`: 现货 + * `STOCK`: 股票 + ''' __schema__ = ins_schema __choices__ = ('BOND', 'COMBINE', 'CONT', 'FUND', 'FUTURE', 'INDEX', 'OPTION', 'SPOT', 'STOCK') @@ -45,6 +77,7 @@ class Class(sgqlc.types.Enum): Int = sgqlc.types.Int + class Int64(sgqlc.types.Scalar): __schema__ = ins_schema @@ -60,60 +93,171 @@ class Int64(sgqlc.types.Scalar): # Output Objects and Interfaces ######################################################################## class basic(sgqlc.types.Interface): + '''基础信息''' __schema__ = ins_schema - __field_names__ = ('trading_time', 'instrument_name', 'instrument_id', 'derivative', 'ins_id', 'derivatives', 'exchange_id', 'instrument_name_wh', 'trading_day', 'english_name', 'price_decs', 'class_', 'py_wh', 'price_tick') + __field_names__ = ('instrument_name_wh', 'price_decs', 'price_tick', 'ins_id', 'instrument_id', 'derivatives', 'exchange_id', + 'instrument_name', 'trading_time', 'class_', 'py_wh', 'english_name', 'derivative', 'trading_day') + instrument_name_wh = sgqlc.types.Field(String, graphql_name='instrument_name_wh') + '''合约名称(文华风格)''' + + price_decs = sgqlc.types.Field(Int, graphql_name='price_decs') + '''价格小数位数''' + price_tick = sgqlc.types.Field(Float, graphql_name='price_tick') + '''最小变动价位''' + + ins_id = sgqlc.types.Field(String, graphql_name='ins_id') + '''合约代码(不含交易所)''' + + instrument_id = sgqlc.types.Field(String, graphql_name='instrument_id') + '''合约代码''' + derivatives = sgqlc.types.Field('derivativeConnection', graphql_name='derivatives', args=sgqlc.types.ArgDict(( ('class_', sgqlc.types.Arg(sgqlc.types.list_of(Class), graphql_name='class', default=None)), ('exchange_id', sgqlc.types.Arg(sgqlc.types.list_of(String), graphql_name='exchange_id', default=None)), ('expired', sgqlc.types.Arg(Boolean, graphql_name='expired', default=None)), ('timestamp', sgqlc.types.Arg(Int64, graphql_name='timestamp', default=None)), -)) + )) ) - trading_time = sgqlc.types.Field('tradingTime', graphql_name='trading_time') - trading_day = sgqlc.types.Field(String, graphql_name='trading_day') + '''衍生品 + + Arguments: + + * `class_` (`[Class]`): placeholder + * `exchange_id` (`[String]`): placeholder + * `expired` (`Boolean`) + * `timestamp` (`Int64`) + ''' + + exchange_id = sgqlc.types.Field(String, graphql_name='exchange_id') + '''交易所代码''' + instrument_name = sgqlc.types.Field(String, graphql_name='instrument_name') - english_name = sgqlc.types.Field(String, graphql_name='english_name') - price_decs = sgqlc.types.Field(Int, graphql_name='price_decs') + '''合约名称''' + + trading_time = sgqlc.types.Field('tradingTime', graphql_name='trading_time') + '''交易时间''' + class_ = sgqlc.types.Field(String, graphql_name='class') - instrument_id = sgqlc.types.Field(String, graphql_name='instrument_id') - exchange_id = sgqlc.types.Field(String, graphql_name='exchange_id') - ins_id = sgqlc.types.Field(String, graphql_name='ins_id') - instrument_name_wh = sgqlc.types.Field(String, graphql_name='instrument_name_wh') + '''类别''' + py_wh = sgqlc.types.Field(String, graphql_name='py_wh') - price_tick = sgqlc.types.Field(Float, graphql_name='price_tick') + '''拼音(文华风格)''' + + english_name = sgqlc.types.Field(String, graphql_name='english_name') + '''英文名称''' + derivative = sgqlc.types.Field('derivativeConnection', graphql_name='derivative', args=sgqlc.types.ArgDict(( ('class_', sgqlc.types.Arg(Class, graphql_name='class', default=None)), ('exchange_id', sgqlc.types.Arg(String, graphql_name='exchange_id', default=None)), ('expired', sgqlc.types.Arg(Boolean, graphql_name='expired', default=None)), -)) + )) ) + '''衍生品(旧) + + Arguments: + + * `class_` (`Class`): placeholder + * `exchange_id` (`String`): placeholder + * `expired` (`Boolean`) + ''' + + trading_day = sgqlc.types.Field(String, graphql_name='trading_day') + '''交易日''' + class derivative(sgqlc.types.Interface): + '''衍生品信息''' __schema__ = ins_schema __field_names__ = ('underlying',) underlying = sgqlc.types.Field('derivativeConnection', graphql_name='underlying') + '''标的合约''' + + +class securities(sgqlc.types.Interface): + '''证券信息''' + __schema__ = ins_schema + __field_names__ = ('first_trading_datetime', 'buy_volume_unit', 'sell_volume_unit', 'status', 'public_float_share_quantity', 'currency', 'face_value', 'first_trading_day') + first_trading_datetime = sgqlc.types.Field(Int64, graphql_name='first_trading_datetime') + '''起始交易时间''' + + buy_volume_unit = sgqlc.types.Field(Float, graphql_name='buy_volume_unit') + '''买入单位''' + + sell_volume_unit = sgqlc.types.Field(Float, graphql_name='sell_volume_unit') + '''卖出单位''' + + status = sgqlc.types.Field(String, graphql_name='status') + '''状态''' + + public_float_share_quantity = sgqlc.types.Field(Int64, graphql_name='public_float_share_quantity') + '''流通股本''' + + currency = sgqlc.types.Field(String, graphql_name='currency') + '''币种''' + + face_value = sgqlc.types.Field(Float, graphql_name='face_value') + '''面值''' + + first_trading_day = sgqlc.types.Field(Int64, graphql_name='first_trading_day') + '''首个交易日''' + + +class tradeable(sgqlc.types.Interface): + '''交易信息''' + __schema__ = ins_schema + __field_names__ = ('upper_limit', 'lower_limit', 'volume_multiple', 'quote_multiple', 'pre_close') + upper_limit = sgqlc.types.Field(Float, graphql_name='upper_limit') + '''涨停板价''' + + lower_limit = sgqlc.types.Field(Float, graphql_name='lower_limit') + '''跌停板价''' + + volume_multiple = sgqlc.types.Field(Float, graphql_name='volume_multiple') + '''合约乘数(交易单位 / 报价单位)''' + + quote_multiple = sgqlc.types.Field(Float, graphql_name='quote_multiple') + '''报价乘数(成交量单位 / 报价单位)''' + + pre_close = sgqlc.types.Field(Float, graphql_name='pre_close') + '''昨收盘价''' + + +class categoryInfo(sgqlc.types.Type): + '''板块信息''' + __schema__ = ins_schema + __field_names__ = ('id', 'name') + id = sgqlc.types.Field(String, graphql_name='id') + '''板块ID''' + + name = sgqlc.types.Field(String, graphql_name='name') + '''板块中文名称''' class derivativeConnection(sgqlc.types.Type): + '''衍生品关系''' __schema__ = ins_schema __field_names__ = ('count', 'edges') count = sgqlc.types.Field(Int, graphql_name='count') + edges = sgqlc.types.Field(sgqlc.types.list_of('derivativeEdges'), graphql_name='edges') class derivativeEdges(sgqlc.types.Type): + '''衍生品''' __schema__ = ins_schema __field_names__ = ('node', 'underlying_multiple') node = sgqlc.types.Field('allClassUnion', graphql_name='node') + '''衍生品''' + underlying_multiple = sgqlc.types.Field(Float, graphql_name='underlying_multiple') class rootQuery(sgqlc.types.Type): + '''symbol_info 为旧版单查询接口,multi_symbol_info 为新版多查询接口,即前者的兼容升级版本''' __schema__ = ins_schema __field_names__ = ('multi_symbol_info', 'symbol_info') multi_symbol_info = sgqlc.types.Field(sgqlc.types.list_of('allClassUnion'), graphql_name='multi_symbol_info', args=sgqlc.types.ArgDict(( - ('timestamp', sgqlc.types.Arg(Int64, graphql_name='timestamp', default=None)), ('instrument_id', sgqlc.types.Arg(sgqlc.types.list_of(String), graphql_name='instrument_id', default=None)), ('class_', sgqlc.types.Arg(sgqlc.types.list_of(Class), graphql_name='class', default=None)), ('exchange_id', sgqlc.types.Arg(sgqlc.types.list_of(String), graphql_name='exchange_id', default=None)), @@ -122,8 +266,22 @@ class rootQuery(sgqlc.types.Type): ('has_night', sgqlc.types.Arg(Boolean, graphql_name='has_night', default=None)), ('has_derivatives', sgqlc.types.Arg(Boolean, graphql_name='has_derivatives', default=None)), ('categories', sgqlc.types.Arg(sgqlc.types.list_of(Category), graphql_name='categories', default=None)), -)) + ('timestamp', sgqlc.types.Arg(Int64, graphql_name='timestamp', default=None)), + )) ) + '''Arguments: + + * `instrument_id` (`[String]`): 合约代码 + * `class_` (`[Class]`): 类别 + * `exchange_id` (`[String]`): 交易所代码 + * `product_id` (`[String]`): 品种代码 + * `expired` (`Boolean`): 是否已到期 + * `has_night` (`Boolean`): 是否有夜盘 + * `has_derivatives` (`Boolean`): 是否有衍生品 + * `categories` (`[Category]`): 所属板块 + * `timestamp` (`Int64`): 回测时间点 + ''' + symbol_info = sgqlc.types.Field(sgqlc.types.list_of('allClassUnion'), graphql_name='symbol_info', args=sgqlc.types.ArgDict(( ('instrument_id', sgqlc.types.Arg(String, graphql_name='instrument_id', default=None)), ('class_', sgqlc.types.Arg(Class, graphql_name='class', default=None)), @@ -132,172 +290,312 @@ class rootQuery(sgqlc.types.Type): ('expired', sgqlc.types.Arg(Boolean, graphql_name='expired', default=None)), ('has_night', sgqlc.types.Arg(Boolean, graphql_name='has_night', default=None)), ('has_derivatives', sgqlc.types.Arg(Boolean, graphql_name='has_derivatives', default=None)), -)) + )) ) + '''Arguments: - -class securities(sgqlc.types.Interface): - __schema__ = ins_schema - __field_names__ = ('currency', 'face_value', 'first_trading_day', 'first_trading_datetime', 'buy_volume_unit', 'sell_volume_unit', 'status', 'public_float_share_quantity') - status = sgqlc.types.Field(String, graphql_name='status') - public_float_share_quantity = sgqlc.types.Field(Int64, graphql_name='public_float_share_quantity') - currency = sgqlc.types.Field(String, graphql_name='currency') - face_value = sgqlc.types.Field(Float, graphql_name='face_value') - first_trading_day = sgqlc.types.Field(Int64, graphql_name='first_trading_day') - first_trading_datetime = sgqlc.types.Field(Int64, graphql_name='first_trading_datetime') - buy_volume_unit = sgqlc.types.Field(Float, graphql_name='buy_volume_unit') - sell_volume_unit = sgqlc.types.Field(Float, graphql_name='sell_volume_unit') - - -class tradeable(sgqlc.types.Interface): - __schema__ = ins_schema - __field_names__ = ('volume_multiple', 'quote_multiple', 'pre_close', 'upper_limit', 'lower_limit') - quote_multiple = sgqlc.types.Field(Float, graphql_name='quote_multiple') - pre_close = sgqlc.types.Field(Float, graphql_name='pre_close') - upper_limit = sgqlc.types.Field(Float, graphql_name='upper_limit') - lower_limit = sgqlc.types.Field(Float, graphql_name='lower_limit') - volume_multiple = sgqlc.types.Field(Float, graphql_name='volume_multiple') - - -class categoryInfo(sgqlc.types.Type): - __schema__ = ins_schema - __field_names__ = ('id', 'name') - id = sgqlc.types.Field(String, graphql_name='id') - name = sgqlc.types.Field(String, graphql_name='name') + * `instrument_id` (`String`) + * `class_` (`Class`) + * `exchange_id` (`String`) + * `product_id` (`String`) + * `expired` (`Boolean`) + * `has_night` (`Boolean`) + * `has_derivatives` (`Boolean`) + ''' class tradingTime(sgqlc.types.Type): + '''交易时间''' __schema__ = ins_schema __field_names__ = ('day', 'night') day = sgqlc.types.Field(sgqlc.types.list_of(sgqlc.types.list_of(String)), graphql_name='day') + '''白盘交易时间''' + night = sgqlc.types.Field(sgqlc.types.list_of(sgqlc.types.list_of(String)), graphql_name='night') + '''夜盘交易时间''' class bond(sgqlc.types.Type, basic, tradeable, securities): + '''债券''' __schema__ = ins_schema __field_names__ = ('maturity_date', 'maturity_datetime') maturity_date = sgqlc.types.Field(Int64, graphql_name='maturity_date') + '''到期日''' + maturity_datetime = sgqlc.types.Field(Int64, graphql_name='maturity_datetime') + '''到期时间''' class combine(sgqlc.types.Type, basic): + '''组合''' __schema__ = ins_schema - __field_names__ = ('close_max_limit_order_volume', 'close_max_market_order_volume', 'close_min_limit_order_volume', 'close_min_market_order_volume', 'expire_datetime', 'expired', 'leg1', 'leg2', 'max_limit_order_volume', 'max_market_order_volume', 'min_limit_order_volume', 'min_market_order_volume', 'open_max_limit_order_volume', 'open_max_market_order_volume', 'open_min_limit_order_volume', 'open_min_market_order_volume', 'product_id') + __field_names__ = ('close_max_limit_order_volume', 'close_max_market_order_volume', 'close_min_limit_order_volume', 'close_min_market_order_volume', 'expire_datetime', 'expired', 'leg1', 'leg2', 'max_limit_order_volume', + 'max_market_order_volume', 'min_limit_order_volume', 'min_market_order_volume', 'open_max_limit_order_volume', 'open_max_market_order_volume', 'open_min_limit_order_volume', 'open_min_market_order_volume', 'product_id') close_max_limit_order_volume = sgqlc.types.Field(Int, graphql_name='close_max_limit_order_volume') + '''平仓限价单最大下单量''' + close_max_market_order_volume = sgqlc.types.Field(Int, graphql_name='close_max_market_order_volume') + '''平仓市价单最大下单量''' + close_min_limit_order_volume = sgqlc.types.Field(Int, graphql_name='close_min_limit_order_volume') + '''平仓限价单最小下单量''' + close_min_market_order_volume = sgqlc.types.Field(Int, graphql_name='close_min_market_order_volume') + '''平仓市价单最小下单量''' + expire_datetime = sgqlc.types.Field(Int64, graphql_name='expire_datetime') + '''到期时间''' + expired = sgqlc.types.Field(Boolean, graphql_name='expired') + '''是否到期''' + leg1 = sgqlc.types.Field('allClassUnion', graphql_name='leg1') + '''组合单腿1''' + leg2 = sgqlc.types.Field('allClassUnion', graphql_name='leg2') + '''组合单腿2''' + max_limit_order_volume = sgqlc.types.Field(Int, graphql_name='max_limit_order_volume') + '''限价单最大下单量''' + max_market_order_volume = sgqlc.types.Field(Int, graphql_name='max_market_order_volume') + '''市价单最大下单量''' + min_limit_order_volume = sgqlc.types.Field(Int, graphql_name='min_limit_order_volume') + '''限价单最小下单量''' + min_market_order_volume = sgqlc.types.Field(Int, graphql_name='min_market_order_volume') + '''市价单最小下单量''' + open_max_limit_order_volume = sgqlc.types.Field(Int, graphql_name='open_max_limit_order_volume') + '''开仓限价单最大下单量''' + open_max_market_order_volume = sgqlc.types.Field(Int, graphql_name='open_max_market_order_volume') + '''开仓市价单最大下单量''' + open_min_limit_order_volume = sgqlc.types.Field(Int, graphql_name='open_min_limit_order_volume') + '''开仓限价单最小下单量''' + open_min_market_order_volume = sgqlc.types.Field(Int, graphql_name='open_min_market_order_volume') + '''开仓市价单最小下单量''' + product_id = sgqlc.types.Field(String, graphql_name='product_id') + '''品种代码''' class cont(sgqlc.types.Type, basic, tradeable, derivative): + '''连续''' __schema__ = ins_schema __field_names__ = () class fund(sgqlc.types.Type, basic, tradeable, securities): + '''基金''' __schema__ = ins_schema __field_names__ = ('cash_dividend_ratio',) cash_dividend_ratio = sgqlc.types.Field(sgqlc.types.list_of(String), graphql_name='cash_dividend_ratio') + '''现金分红''' class future(sgqlc.types.Type, basic, tradeable): + '''期货''' __schema__ = ins_schema - __field_names__ = ('categories', 'close_max_limit_order_volume', 'close_max_market_order_volume', 'close_min_limit_order_volume', 'close_min_market_order_volume', 'commission', 'delivery_month', 'delivery_year', 'expire_datetime', 'expired', 'margin', 'max_limit_order_volume', 'max_market_order_volume', 'min_limit_order_volume', 'min_market_order_volume', 'mmsa', 'open_max_limit_order_volume', 'open_max_market_order_volume', 'open_min_limit_order_volume', 'open_min_market_order_volume', 'pre_open_interest', 'product_id', 'product_short_name', 'product_short_name_wh', 'settlement_price') + __field_names__ = ('categories', 'close_max_limit_order_volume', 'close_max_market_order_volume', 'close_min_limit_order_volume', 'close_min_market_order_volume', 'commission', 'delivery_month', 'delivery_year', 'expire_datetime', 'expired', 'margin', 'max_limit_order_volume', 'max_market_order_volume', 'min_limit_order_volume', + 'min_market_order_volume', 'mmsa', 'open_max_limit_order_volume', 'open_max_market_order_volume', 'open_min_limit_order_volume', 'open_min_market_order_volume', 'position_limit', 'pre_open_interest', 'pre_open_interest2', 'product_id', 'product_short_name', 'product_short_name_wh', 'settlement_price') categories = sgqlc.types.Field(sgqlc.types.list_of(categoryInfo), graphql_name='categories') + '''所属板块''' + close_max_limit_order_volume = sgqlc.types.Field(Int, graphql_name='close_max_limit_order_volume') + '''平仓限价单最大下单量''' + close_max_market_order_volume = sgqlc.types.Field(Int, graphql_name='close_max_market_order_volume') + '''平仓市价单最大下单量''' + close_min_limit_order_volume = sgqlc.types.Field(Int, graphql_name='close_min_limit_order_volume') + '''平仓限价单最小下单量''' + close_min_market_order_volume = sgqlc.types.Field(Int, graphql_name='close_min_market_order_volume') + '''平仓市价单最小下单量''' + commission = sgqlc.types.Field(Float, graphql_name='commission') + '''手续费''' + delivery_month = sgqlc.types.Field(Int, graphql_name='delivery_month') + '''交割月份''' + delivery_year = sgqlc.types.Field(Int, graphql_name='delivery_year') + '''交割年份''' + expire_datetime = sgqlc.types.Field(Int64, graphql_name='expire_datetime') + '''到期时间''' + expired = sgqlc.types.Field(Boolean, graphql_name='expired') + '''是否到期''' + margin = sgqlc.types.Field(Float, graphql_name='margin') + '''保证金''' + max_limit_order_volume = sgqlc.types.Field(Int, graphql_name='max_limit_order_volume') + '''限价单最大下单量''' + max_market_order_volume = sgqlc.types.Field(Int, graphql_name='max_market_order_volume') + '''市价单最大下单量''' + min_limit_order_volume = sgqlc.types.Field(Int, graphql_name='min_limit_order_volume') + '''限价单最小下单量''' + min_market_order_volume = sgqlc.types.Field(Int, graphql_name='min_market_order_volume') + '''市价单最小下单量''' + mmsa = sgqlc.types.Field(Boolean, graphql_name='mmsa') + '''单向大边''' + open_max_limit_order_volume = sgqlc.types.Field(Int, graphql_name='open_max_limit_order_volume') + '''开仓限价单最大下单量''' + open_max_market_order_volume = sgqlc.types.Field(Int, graphql_name='open_max_market_order_volume') + '''开仓市价单最大下单量''' + open_min_limit_order_volume = sgqlc.types.Field(Int, graphql_name='open_min_limit_order_volume') + '''开仓限价单最小下单量''' + open_min_market_order_volume = sgqlc.types.Field(Int, graphql_name='open_min_market_order_volume') + '''开仓市价单最小下单量''' + + position_limit = sgqlc.types.Field(Int, graphql_name='position_limit') + '''持仓限额手数,为 null 时表示无该信息,为 0 则不允许持仓''' + pre_open_interest = sgqlc.types.Field(Int64, graphql_name='pre_open_interest') + '''昨持仓量(SHFE/INE/CZCE/DCE 为双边计量,其余为单边计量)''' + + pre_open_interest2 = sgqlc.types.Field(Int64, graphql_name='pre_open_interest2') + '''昨持仓量(单边计量)''' + product_id = sgqlc.types.Field(String, graphql_name='product_id') + '''品种代码''' + product_short_name = sgqlc.types.Field(String, graphql_name='product_short_name') + '''品种简称''' + product_short_name_wh = sgqlc.types.Field(String, graphql_name='product_short_name_wh') + '''品种简称(文华风格)''' + settlement_price = sgqlc.types.Field(Float, graphql_name='settlement_price') + '''结算价''' class index(sgqlc.types.Type, basic): + '''指数''' __schema__ = ins_schema __field_names__ = ('index_multiple',) index_multiple = sgqlc.types.Field(Float, graphql_name='index_multiple') + '''指数乘数(指数成交量单位 / 成份股报价单位)''' class option(sgqlc.types.Type, basic, tradeable, derivative): + '''期权''' __schema__ = ins_schema - __field_names__ = ('call_or_put', 'close_max_limit_order_volume', 'close_max_market_order_volume', 'close_min_limit_order_volume', 'close_min_market_order_volume', 'exercise_type', 'expire_datetime', 'expired', 'last_exercise_datetime', 'last_exercise_day', 'max_limit_order_volume', 'max_market_order_volume', 'min_limit_order_volume', 'min_market_order_volume', 'open_max_limit_order_volume', 'open_max_market_order_volume', 'open_min_limit_order_volume', 'open_min_market_order_volume', 'pre_open_interest', 'product_short_name', 'settlement_price', 'strike_price') + __field_names__ = ('call_or_put', 'close_max_limit_order_volume', 'close_max_market_order_volume', 'close_min_limit_order_volume', 'close_min_market_order_volume', 'exercise_type', 'expire_datetime', 'expired', 'last_exercise_datetime', 'last_exercise_day', 'max_limit_order_volume', 'max_market_order_volume', + 'min_limit_order_volume', 'min_market_order_volume', 'open_max_limit_order_volume', 'open_max_market_order_volume', 'open_min_limit_order_volume', 'open_min_market_order_volume', 'position_limit', 'pre_open_interest', 'pre_open_interest2', 'product_short_name', 'settlement_price', 'strike_price') call_or_put = sgqlc.types.Field(String, graphql_name='call_or_put') + '''认购/认沽''' + close_max_limit_order_volume = sgqlc.types.Field(Int, graphql_name='close_max_limit_order_volume') + '''平仓限价单最大下单量''' + close_max_market_order_volume = sgqlc.types.Field(Int, graphql_name='close_max_market_order_volume') + '''平仓市价单最大下单量''' + close_min_limit_order_volume = sgqlc.types.Field(Int, graphql_name='close_min_limit_order_volume') + '''平仓限价单最小下单量''' + close_min_market_order_volume = sgqlc.types.Field(Int, graphql_name='close_min_market_order_volume') + '''平仓市价单最小下单量''' + exercise_type = sgqlc.types.Field(String, graphql_name='exercise_type') + '''行权方式''' + expire_datetime = sgqlc.types.Field(Int64, graphql_name='expire_datetime') + '''到期时间''' + expired = sgqlc.types.Field(Boolean, graphql_name='expired') + '''是否到期''' + last_exercise_datetime = sgqlc.types.Field(Int64, graphql_name='last_exercise_datetime') + '''最后行权时间''' + last_exercise_day = sgqlc.types.Field(Int64, graphql_name='last_exercise_day') + '''最后行权日''' + max_limit_order_volume = sgqlc.types.Field(Int, graphql_name='max_limit_order_volume') + '''限价单最大下单量''' + max_market_order_volume = sgqlc.types.Field(Int, graphql_name='max_market_order_volume') + '''市价单最大下单量''' + min_limit_order_volume = sgqlc.types.Field(Int, graphql_name='min_limit_order_volume') + '''限价单最小下单量''' + min_market_order_volume = sgqlc.types.Field(Int, graphql_name='min_market_order_volume') + '''市价单最小下单量''' + open_max_limit_order_volume = sgqlc.types.Field(Int, graphql_name='open_max_limit_order_volume') + '''开仓限价单最大下单量''' + open_max_market_order_volume = sgqlc.types.Field(Int, graphql_name='open_max_market_order_volume') + '''开仓市价单最大下单量''' + open_min_limit_order_volume = sgqlc.types.Field(Int, graphql_name='open_min_limit_order_volume') + '''开仓限价单最小下单量''' + open_min_market_order_volume = sgqlc.types.Field(Int, graphql_name='open_min_market_order_volume') + '''开仓市价单最小下单量''' + + position_limit = sgqlc.types.Field(Int, graphql_name='position_limit') + '''持仓限额手数,为 null 时表示无该信息,为 0 则不允许持仓''' + pre_open_interest = sgqlc.types.Field(Int64, graphql_name='pre_open_interest') + '''昨持仓量(SHFE/INE/CZCE/DCE 为双边计量,其余为单边计量)''' + + pre_open_interest2 = sgqlc.types.Field(Int64, graphql_name='pre_open_interest2') + '''昨持仓量(单边计量)''' + product_short_name = sgqlc.types.Field(String, graphql_name='product_short_name') + '''品种简称''' + settlement_price = sgqlc.types.Field(Float, graphql_name='settlement_price') + '''结算价''' + strike_price = sgqlc.types.Field(Float, graphql_name='strike_price') + '''行权价''' class spot(sgqlc.types.Type, basic, tradeable): + '''现货''' __schema__ = ins_schema __field_names__ = () class stock(sgqlc.types.Type, basic, tradeable, securities): + '''股票''' __schema__ = ins_schema __field_names__ = ('cash_dividend_ratio', 'stock_dividend_ratio') cash_dividend_ratio = sgqlc.types.Field(sgqlc.types.list_of(String), graphql_name='cash_dividend_ratio') - stock_dividend_ratio = sgqlc.types.Field(sgqlc.types.list_of(String), graphql_name='stock_dividend_ratio') + '''现金分红''' + stock_dividend_ratio = sgqlc.types.Field(sgqlc.types.list_of(String), graphql_name='stock_dividend_ratio') + '''股票分红''' ######################################################################## # Unions ######################################################################## class allClassUnion(sgqlc.types.Union): + '''分类型结果集''' __schema__ = ins_schema __types__ = (future, index, option, combine, spot, cont, stock, bond, fund) - ######################################################################## # Schema Entry Points ######################################################################## @@ -371,6 +669,7 @@ class allClassUnion(sgqlc.types.Union): future_frag.commission() future_frag.mmsa() future_frag.categories() +future_frag.position_limit() option_frag = Fragment(option, 'option') option_frag.pre_open_interest() @@ -390,6 +689,7 @@ class allClassUnion(sgqlc.types.Union): option_frag.strike_price() option_frag.call_or_put() option_frag.exercise_type() +option_frag.position_limit() combine_frag = Fragment(combine, 'combine') combine_frag.expired() diff --git a/tqsdk/objs.py b/tqsdk/objs.py index 11297021..3c972e0b 100644 --- a/tqsdk/objs.py +++ b/tqsdk/objs.py @@ -183,6 +183,8 @@ def __init__(self, api): self.expire_rest_days: int = float('nan') #: 板块信息 self.categories: List[CategoryInfo] = [] + #: 持仓限额 + self.position_limit: int = 0 def _instance_entity(self, path): super(Quote, self)._instance_entity(path) diff --git a/tqsdk/objs_not_entity.py b/tqsdk/objs_not_entity.py index f75cdcf6..3f42277d 100644 --- a/tqsdk/objs_not_entity.py +++ b/tqsdk/objs_not_entity.py @@ -62,6 +62,9 @@ async def _ensure_symbols(self): self._api._send_pack(query_pack) async with self._api.register_update_notify(self) as update_chan: async for _ in update_chan: + # 这里用 price_tick 判断是否已经收到了合约信息,是为了兼容 2020年9月份之前上市的合约 + # 合约服务没有提供这些合约,tqsdk 是通过预先加载本地缓存文件的方式提供这些合约的信息 + # 理想的判断标准是 basktest 模块中的 _ensure_query 函数 if all([q.price_tick > 0 for q in self]): return @@ -310,6 +313,94 @@ def __await__(self): return self.__dict__["_task"].__await__() +class TqMdSettlementDataFrame(DataFrame): + + def __init__(self, api, symbol, days, start_dt): + self.__dict__["_api"] = api + params = {'days': days, 'symbols': symbol if isinstance(symbol, str) else ",".join(symbol)} + if start_dt is not None: + params['start_date'] = start_dt.strftime("%Y%m%d") + else: + params['days'] += 1 + self.__dict__["_params"] = params + self.__dict__["_days"] = days + self.__dict__["_symbol"] = symbol + self.__dict__["_columns"] = [ + "datetime", + "symbol", + "settlement" + ] + super(TqMdSettlementDataFrame, self).__init__(data=[], columns=self.__dict__["_columns"]) + self.__dict__["_task"] = api.create_task(self.async_update(), _caller_api=True) + + async def _get_settlement_data(self, settlement_id): + # 下载结算价数据,并将数据发回到 api.recv_chan + async with aiohttp.ClientSession(headers=self.__dict__["_api"]._base_headers) as session: + url = "https://md-settlement-system-fc-api.shinnytech.com/mss" + async with session.get(url, params=self.__dict__["_params"]) as response: + response.raise_for_status() + content = await response.json() + await self.__dict__["_api"]._ws_md_recv_chan.send({ + "aid": "rtn_data", + "data": [{ + "_settlement": { + settlement_id: content + }, + "_settlement_finished": { + settlement_id: True + } + }] + }) + + async def async_update(self): + await self.__dict__["_api"]._ensure_symbol_async(self.__dict__["_symbol"]) + settlement_id = _generate_uuid("PYSDK_settlement") + self.__dict__["_api"].create_task(self._get_settlement_data(settlement_id), _caller_api=True) # 错误会抛给 api 处理 + settlement_finished = _get_obj(self.__dict__["_api"]._data, ["_settlement_finished"]) + async with self.__dict__["_api"].register_update_notify(settlement_finished) as update_chan: + async for _ in update_chan: + if not settlement_finished.get(settlement_id, False): + continue + content = self.__dict__["_api"]._data.get("_settlement", {}).get(settlement_id, {}) + data = self._content_to_list(content) + for i, d in enumerate(data): + self.loc[i] = d + self.sort_values(by=['datetime', 'symbol'], inplace=True, ignore_index=True) + # 读完数据,清空数据 + await self.__dict__["_api"]._ws_md_recv_chan.send({ + "aid": "rtn_data", + "data": [{ + "_settlement": { + settlement_id: None + }, + "_settlement_finished": { + settlement_id: None + } + }] + }) + return self + + + def _content_to_list(self, content): + sorted_content = sorted( + content.items(), + key=lambda item: item[0], + reverse=True + ) + # 取最近的 N 天数据 + days = self.__dict__["_days"] + recent_content = sorted_content[:days] + return [ + {"datetime": dt, "symbol": symbol, "settlement": settlement} + for dt, symbols in recent_content + for symbol, settlement in symbols.items() + if settlement is not None + ] + + def __await__(self): + return self.__dict__["_task"].__await__() + + class TqSymbolRankingDataFrame(DataFrame): def __init__(self, api, symbol, ranking_type, days, start_dt, broker): diff --git a/tqsdk/risk_rule.py b/tqsdk/risk_rule.py index 226ecb21..c6666553 100644 --- a/tqsdk/risk_rule.py +++ b/tqsdk/risk_rule.py @@ -35,7 +35,7 @@ class TqRuleOpenCountsLimit(TqRiskRule): """ 风控规则类 - 交易日内开仓次数限制。 - 此功能为 TqSdk 专业版提供,如需使用此功能,可以点击 `天勤量化专业版 `_ 申请试用或购买 + 此功能为 TqSdk 专业版提供,如需使用此功能,可以点击 `天勤量化专业版 `_ 申请试用或购买 """ def __init__(self, api, open_counts_limit, symbol, account=None): @@ -110,7 +110,7 @@ class TqRuleOpenVolumesLimit(TqRiskRule): """ 风控规则类 - 交易日内开仓手数限制 - 此功能为 TqSdk 专业版提供,如需使用此功能,可以点击 `天勤量化专业版 `_ 申请试用或购买 + 此功能为 TqSdk 专业版提供,如需使用此功能,可以点击 `天勤量化专业版 `_ 申请试用或购买 """ def __init__(self, api, open_volumes_limit, symbol, account=None): @@ -207,7 +207,7 @@ class TqRuleAccOpenVolumesLimit(TqRiskRule): 限制合约开仓手数之和。 - 此功能为 TqSdk 专业版提供,如需使用此功能,可以点击 `天勤量化专业版 `_ 申请试用或购买 + 此功能为 TqSdk 专业版提供,如需使用此功能,可以点击 `天勤量化专业版 `_ 申请试用或购买 """ diff --git a/tqsdk/tafunc.py b/tqsdk/tafunc.py index 6cd4ecc1..cc44d70a 100644 --- a/tqsdk/tafunc.py +++ b/tqsdk/tafunc.py @@ -1468,7 +1468,7 @@ def get_dividend_factor(dividend_df, last_item, item): def _tq_pstdev(data: Series, mu: float): """ 计算标准差 - 标准库提供的方法 statistics.pstdev 在 py3.6,py3.7 版本下参数 mean 不能设定为指定值,所以这里另外计算。 + 标准库提供的方法 statistics.pstdev 在 py3.7 版本下参数 mean 不能设定为指定值,所以这里另外计算。 """ n = data.shape[0] assert n >= 1 diff --git a/tqsdk/tools/downloader.py b/tqsdk/tools/downloader.py index effa9ed2..bc0e7554 100644 --- a/tqsdk/tools/downloader.py +++ b/tqsdk/tools/downloader.py @@ -33,7 +33,7 @@ class DataDownloader: """ 数据下载工具是 TqSdk 专业版中的功能,能让用户下载目前 TqSdk 提供的全部期货、期权和股票类的历史数据,下载数据支持 tick 级别精度和任意 kline 周期 - 如果想使用数据下载工具,可以点击 `天勤量化专业版 `_ 申请使用或购买 + 如果想使用数据下载工具,可以点击 `天勤量化专业版 `_ 申请使用或购买 历史数据下载器, 输出到csv文件 @@ -103,7 +103,7 @@ def __init__(self, api: TqApi, symbol_list: Union[str, List[str]], dur_sec: int, """ self._api = api if not self._api._auth._has_feature("tq_dl"): - raise Exception("您的账户不支持下载历史数据功能,需要购买后才能使用。升级网址:https://www.shinnytech.com/tqsdk_professional/") + raise Exception("您的账户不支持下载历史数据功能,需要购买后才能使用。升级网址:https://www.shinnytech.com/tqsdk-buy/") self._start_dt_nano, self._end_dt_nano = _convert_user_input_to_nano(start_dt, end_dt) self._current_dt_nano = self._start_dt_nano self._symbol_list = symbol_list if isinstance(symbol_list, list) else [symbol_list] diff --git a/tqsdk/tradeable/otg/tqkq.py b/tqsdk/tradeable/otg/tqkq.py index 8f140eba..523cdbc5 100644 --- a/tqsdk/tradeable/otg/tqkq.py +++ b/tqsdk/tradeable/otg/tqkq.py @@ -103,7 +103,7 @@ def __init__(self, td_url: Optional[str] = None, number: Optional[int] = None): """ 创建快期股票模拟账户实例 - 快期股票模拟为专业版功能,可以点击 `天勤量化专业版 `_ 申请试用或购买 + 快期股票模拟为专业版功能,可以点击 `天勤量化专业版 `_ 申请试用或购买 Args: td_url (str): [可选]指定交易服务器的地址, 默认使用快期账户对应的交易服务地址