From 0dbee5be479dc8e4cc81237a88894154a3891e55 Mon Sep 17 00:00:00 2001 From: shinny-hongyan Date: Fri, 12 Dec 2025 05:31:02 +0000 Subject: [PATCH] Update Version 3.8.8 --- PKG-INFO | 8 +- README.md | 4 +- doc/advanced/emergency_stop.rst | 53 ++++++++++ doc/advanced/index.rst | 1 + doc/conf.py | 4 +- doc/index.rst | 1 + doc/quickstart.rst | 2 +- doc/tq_trading_unit.rst | 10 ++ doc/tqsdk_trae.rst | 181 ++++++++++++++++++++++++++++++++ doc/usage/kqd_symbol.rst | 4 +- doc/version.rst | 11 ++ setup.py | 4 +- tqsdk/__version__.py | 2 +- tqsdk/api.py | 34 +++--- tqsdk/baseApi.py | 7 +- tqsdk/changelog_notification.py | 22 ++++ tqsdk/objs_not_entity.py | 12 +-- 17 files changed, 321 insertions(+), 39 deletions(-) create mode 100644 doc/advanced/emergency_stop.rst create mode 100644 doc/tqsdk_trae.rst create mode 100644 tqsdk/changelog_notification.py diff --git a/PKG-INFO b/PKG-INFO index b631f32b..b503cd22 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: tqsdk -Version: 3.8.7 +Version: 3.8.8 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.7 +Requires-Python: >=3.8 Description-Content-Type: text/markdown License-File: LICENSE @@ -20,7 +20,7 @@ License-File: LICENSE

- +

@@ -87,7 +87,7 @@ TqSdk提供的功能可以支持从简单到复杂的各类策略程序: ## 安装方法 -TqSdk 仅支持 Python 3.7 及更高版本。要安装 TqSdk,可使用 pip: +TqSdk 仅支持 Python 3.8 及更高版本。要安装 TqSdk,可使用 pip: ```bash pip install tqsdk diff --git a/README.md b/README.md index 25a83262..bb607ef4 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@

- +

@@ -71,7 +71,7 @@ TqSdk提供的功能可以支持从简单到复杂的各类策略程序: ## 安装方法 -TqSdk 仅支持 Python 3.7 及更高版本。要安装 TqSdk,可使用 pip: +TqSdk 仅支持 Python 3.8 及更高版本。要安装 TqSdk,可使用 pip: ```bash pip install tqsdk diff --git a/doc/advanced/emergency_stop.rst b/doc/advanced/emergency_stop.rst new file mode 100644 index 00000000..f547007c --- /dev/null +++ b/doc/advanced/emergency_stop.rst @@ -0,0 +1,53 @@ +.. _emergency_stop: + +在外出环境下的紧急停止方案 +================================================= + +在实际交易中, 难免会遇到人在外面、无法第一时间回到电脑前, 但又需要 **立刻阻止策略继续报单** 的情况。 +对于这类极端场景, 可以准备一套 **从物理链路上阻断报单** 的“最后一道防线”——使用远程遥控插座控制电脑或网络设备的供电。 + +.. note:: + + 如果可以正常远程登录到运行环境, 仍然 **优先通过程序自身的退出/风控逻辑** 来停止策略; + 本文介绍的方案只用于“网络中断、远程工具失效、程序卡死/死循环”等, 无法正常操作时的 **兜底紧急手段** 。 + + +适用场景 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +下面这些场景都可以考虑使用远程遥控插座作为补充手段: + +* 人不在机房/办公室, 无法直接操作运行策略的电脑 +* 远程桌面/VPN 无法连接, 不能登录服务器手动停止程序 +* 运行环境网络异常, 与远程服务器或交易终端的会话建立/恢复失败 +* 程序出现死循环、界面无响应, 无法通过常规方式优雅退出 +* 需要在数秒~数十秒内阻止程序继续发出新的报单 + + +推荐做法: 使用远程遥控插座 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +市面上有很多可以通过手机 App 控制的 **远程遥控插座/智能插座** , 一般具备以下能力: + +* 支持 4G/5G 或通过家庭/公司网络连接互联网 +* 在手机上安装 App 后, 可以远程开/关插座电源 +* 一键断电, 立刻切断下游设备的供电或网络 + +对于无人监控环境下运行的策略, 可以从物理链路上做如下配置: + +* 将 **运行策略的电脑/服务器电源** 接在远程遥控插座上, 需要紧急停机时, 在手机 App 中关断插座电源, 电脑随之断电, 程序立即停止, 不会再继续报单 +* 或者, 将 **用于联网的路由器/交换机等网络设备电源** 接在远程遥控插座上, 紧急情况下关闭插座, 网络被切断, 程序虽然暂时仍在运行, 但已无法向交易服务器发送新的报单 + + +重要提示 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. warning:: + + 通过远程遥控插座断电, 对电脑来说相当于“强制断电”, 可能造成未保存数据丢失, + 请只在 **确属紧急情况** 时使用。 + + 该方案的主要目的在于 **尽快阻止程序继续发送报单** , 而不是优雅关闭系统; + 日常风险控制仍应依赖合理的仓位管理、风控规则和监控告警, 远程插座仅作为极端情况下的补充。 + + diff --git a/doc/advanced/index.rst b/doc/advanced/index.rst index 4f2e0a4e..bfd67a7e 100644 --- a/doc/advanced/index.rst +++ b/doc/advanced/index.rst @@ -15,5 +15,6 @@ for_vnpy_user.rst for_ctp_user.rst unanttended.rst + emergency_stop.rst targetpostask2.rst scheduler.rst diff --git a/doc/conf.py b/doc/conf.py index 15defb47..5326ec2c 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -48,9 +48,9 @@ # built documents. # # The short X.Y version. -version = u'3.8.7' +version = u'3.8.8' # The full version, including alpha/beta/rc tags. -release = u'3.8.7' +release = u'3.8.8' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/index.rst b/doc/index.rst index 0ce76957..ea5b735d 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -22,6 +22,7 @@ TianQin Python Sdk User Guide tq_trading_unit.rst advanced/index.rst tqsdk_cursor.rst + tqsdk_trae.rst dev_general.rst dev_framework.rst profession.rst diff --git a/doc/quickstart.rst b/doc/quickstart.rst index 69633b1b..991ef876 100644 --- a/doc/quickstart.rst +++ b/doc/quickstart.rst @@ -24,7 +24,7 @@ ------------------------------------------------- 天勤量化的核心是TqSdk开发包, 在安装天勤量化 (TqSdk) 前, 你需要先准备适当的环境和Python包管理工具, 包括: -* Python >=3.7,3.8,3.9,3.10,3.11,3.12 版本 +* Python >= 3.8 版本 * Windows 7 以上版本, Mac Os, 或 Linux diff --git a/doc/tq_trading_unit.rst b/doc/tq_trading_unit.rst index b7a012dc..177eb48e 100644 --- a/doc/tq_trading_unit.rst +++ b/doc/tq_trading_unit.rst @@ -113,6 +113,16 @@ TqSdk 多策略使用手册 ========= 使用 `pip install -U --upgrade-strategy eager tqsdk-zq` 更新多策略功能所有依赖包 +.. line-block:: + **2025/12/10** + tqsdk-zq: 1.0.3 + tqsdk-zq-server: 1.0.6 + tqsdk-zq-history: 1.0.0 + tqsdk-zq-pgserver: 1.0.0 + tqsdk-zq-proxy: 1.0.0 + +* 修复: 撤单失败的问题 + .. line-block:: **2025/06/16** tqsdk-zq: 1.0.3 diff --git a/doc/tqsdk_trae.rst b/doc/tqsdk_trae.rst new file mode 100644 index 00000000..835e6baa --- /dev/null +++ b/doc/tqsdk_trae.rst @@ -0,0 +1,181 @@ +.. _tqsdk_trae: + +============================================ +在 Trae 中高效学习和使用 TqSdk +============================================ + + + +Trae:TqSdk 开发与学习的 AI 助手 +=================================== + +Trae 简介 +------------- + +Trae 是一款 AI 原生的智能开发环境,旨在将大模型的理解、生成与协作能力深度融入日常编码流程。它支持对话式编程(Chat/Agent)、代码补全与多处位点修改、项目级生成(Builder)、实时预览与调试等能力,帮助开发者在同一环境内完成从构思到实现与迭代的闭环。 + +在 TqSdk 开发中使用 Trae 的好处 +---------------------------------- + +对于 TqSdk 用户而言,使用 Trae 进行开发与学习具有以下优势: + +* **快速理解 TqSdk API 与概念**: + * 面向 TqSdk 的类(如 ``TqApi``, ``TqAccount``)、函数或交易概念(如 ``KLine``, ``Backtest``, ``target_pos``)提出问题,获得结构化解释与示例。 + * 在编辑器内就地查询函数参数、返回值及常见用法。 +* **高效编写与改造策略代码**: + * **对话生成**:用自然语言描述策略需求,如“订阅多个合约的 tick 并统计成交量阈值报警”,“基于布林带的简易开平仓框架”。 + * **智能补全与批量修改**:基于上下文提供更契合的补全,并可对多处代码进行一致性修改与重构建议。 +* **智能辅助调试**: + * **错误分析与定位**:粘贴错误堆栈和相关代码,获得原因分析与修复建议。 +* **深入学习与理解源码**: + * 将 TqSdk 源码加入工作区后,可让 AI 针对具体模块/函数解释实现思路和设计取舍。 +* **项目级上下文感知**:结合项目代码结构与依赖,回答更贴合当前工程语境。 + +开始使用 Trae +================ + +下载和安装 Trae +----------------- + +1. 访问 Trae 官方下载页面(请根据您组织/渠道提供的地址获取安装包)。 +2. 根据您的操作系统(Windows, macOS, Linux)下载对应安装包。 +3. 按向导完成安装并启动 Trae。 + +初次启动与界面要点 +------------------- + +1. **登录/账户**:根据产品要求完成登录或激活。 +2. **界面区域**:文件资源管理器、编辑器区、终端/调试区与 AI 对话/智能体入口。 +3. **AI 入口**:可通过侧边栏或工具栏打开 Chat/Agent 面板,进行上下文对话与代码指令。 + +在 Trae 中配置 TqSdk 开发环境 +=============================== + +创建或打开您的 TqSdk 项目 +---------------------------- + +1. 在 Trae 中创建新工程或通过“打开文件夹”导入现有的 TqSdk 项目根目录。 + +配置 Python 解释器 +-------------------- + +确保 Trae 使用您期望的 Python 解释器/环境来运行 TqSdk 代码。常用做法: + +1. 在 Trae 的设置或状态栏中选择目标 Python 解释器(如系统 Python、venv、Conda 环境等)。 +2. 或在 Trae 集成终端中激活虚拟环境(例如 ``venv/Scripts/activate`` 或 ``conda activate ``)。 + +安装 TqSdk 库 +-------------- + +在 Trae 的集成终端中(确保已选定正确解释器/已激活环境),执行::: + + pip install tqsdk + +可用以下命令验证安装: ``python -c "import tqsdk; print(tqsdk.__version__)"`` 。若提示 ``pip`` 未找到,请使用 ``python -m pip install tqsdk`` 或检查环境变量设置。 + +让 Trae 深度理解 TqSdk:打开源码 (推荐) +========================================= + +将 TqSdk 源码加入工作区,可显著提升 AI 对实现细节与 API 的理解质量。 + +操作步骤 +--------- + +1. **获取 TqSdk 源码**: + * **方式一(深入研究推荐)**:从官方仓库克隆::: + + git clone https://github.com/shinnytech/tqsdk-python.git + + 记下其中的 ``tqsdk`` 源码目录。 + * **方式二(快速查阅已安装版本)**:定位到当前 Python 环境的 ``site-packages`` 目录中的 ``tqsdk`` 包路径(如 Windows 的 ``.../Lib/site-packages/tqsdk``)。 +2. **添加到 Trae 工作区**: + * 在已打开的项目中,将上述 ``tqsdk`` 源码文件夹添加到工作区(使用“添加文件夹到工作区”或等效入口)。 +3. **效果**: + * 之后可直接在工作区浏览 TqSdk 源码,AI 对应答与代码生成将更贴近真实实现。 + +在 Trae 中提问和学习 TqSdk +============================= + +如何提问? +----------- + +打开 Trae 的 AI Chat/Agent 面板后,您可以: + +* **直接提问**:输入关于 TqSdk 的问题。 +* **选中代码后提问**:选中一段 TqSdk 代码并发起对话,让 AI 以上下文模式进行解释、优化或缺陷分析。 + +提问示例 +--------- + +**基础概念与用法:** + +* “TqSdk 中 ``TqApi`` 与 ``TqAccount`` 的关系与区别是什么?” +* “如何获取 ``SHFE.rb2410`` 的 1 分钟 K 线?请给完整示例。” +* “回测 ``TqBacktest`` 的 ``start_dt`` 和 ``end_dt`` 该如何设置?” +* “``insert_order`` 的 ``limit_price`` 与 ``offset`` 参数如何使用?” + +**结合源码提问(已将源码加入工作区):** + +* “``@tqsdk/trade.py`` 中 ``TdApi`` 的 ``_on_rsp_order_insert`` 做了什么?” +* “我在看 ``@tqsdk/tools/downloader.py``,该下载器支持哪些数据类型?” + +**错误排查:** + +* “运行以下代码时报错 ``...``(附完整堆栈),可能原因是什么?如何修复?” + +利用 AI 进行 TqSdk 代码生成与修改 +--------------------------------- + +* **生成代码片段**: + * “写个函数,输入合约列表,批量订阅这些合约的盘口行情 ``quote``。” + * “用 ``TqSim`` 做模拟交易,当资金变化超过 5% 时发送通知的框架。” +* **修改现有代码(选中后发起)**: + * “将这段 TqSdk 代码的 ``datetime`` 格式化为 ``YYYY-MM-DD HH:MM:SS``。” + * “为下单逻辑增加条件:只有当最新价大于过去 20 周期均线时才开多。” + * “重构策略:将行情处理与交易决策拆成独立函数。” + +调试 TqSdk 代码 +---------------- + +Trae 提供集成调试能力(具体入口与配置以实际版本为准)。 + +1. **设置断点**:在行号旁点击设置断点。 +2. **启动调试**:在运行/调试面板选择相应 Python 配置(如“Python File”或配置的调试任务)。 +3. **AI 辅助调试**:调试中若遇到异常或变量状态不明,可将相关片段与变量值粘贴到对话中,请求解释或给出下一步排查建议。 + +高效提问的技巧 +=============== + +为获得准确与可操作的回答,建议: + +* **问题明确具体**:避免过于笼统。 +* **提供上下文**: + * 涉及代码时,附上相关片段。 + * 发生错误时,附完整堆栈与复现步骤。 + * 若已加入 TqSdk 源码,指明相关模块或符号位置(例如 ``@tqsdk/...`` 风格的文件/符号提示)。 +* **逐步拆解**:复杂问题分步提问。 +* **说明版本**:如 Python 版本、TqSdk 版本、依赖(pandas/NumPy 等)版本。 +* **共享尝试**:说明已尝试方案与结果,便于更精准的建议。 +* **迭代追问**:基于首次回答继续澄清与收敛。 + + +使用建议 +-------- + +1. 在 AI 对话中说明您的需求与版本信息(如 Python 3.11、pandas 2.2、NumPy 2.x)。 +2. 在合适的平台(若支持)启用 Context7 后,配合工作区源码一起提问,获得“规范 + 实现”的双重校对。 +3. 在问题末尾添加“use context7”的提示仅在支持的平台/配置生效;在不支持的平台不会生效。 + +常见问题(FAQ) +--------------- + +* “环境已选但运行用错解释器?”——在设置与集成终端中同时确认:状态栏解释器与终端激活环境需一致。 +* “AI 回答不贴合代码?”——将 TqSdk 源码加入工作区;提问时引用具体模块或函数;粘贴最小可复现片段。 +* “网络/镜像问题导致安装失败?”——优先使用内网镜像或 ``python -m pip`` 方式;必要时手动下载离线包安装。 + +总结 +===== + +Trae 将 AI 深度融入开发流程,对 TqSdk 用户而言,既能加速理解与编写策略,也能在调试与源码学习上提供持续助力。我们建议您将 TqSdk 源码加入工作区,并充分利用对话生成、智能补全与调试能力,配合明确的问题与上下文描述,以获得更高质量、更高效率的开发体验。 + + diff --git a/doc/usage/kqd_symbol.rst b/doc/usage/kqd_symbol.rst index 0251fa3a..6b886bf9 100644 --- a/doc/usage/kqd_symbol.rst +++ b/doc/usage/kqd_symbol.rst @@ -4,9 +4,9 @@ ================================================== 板块介绍 -------------------------------------------------- -为了满足投资者对全球市场信息的需求,提供更全面、准确的投资决策支持,快期/天勤专业版上线了外盘行情(延时15分钟) +为了满足投资者对全球市场信息的需求,提供更全面、准确的投资决策支持,快期专业版 / 天勤量化 上线了外盘行情(延时15分钟) -在快期专业版总添加方式:【添加板块】 - 【系统报价表】 - 【外盘行情(延时)】 +在快期专业版中的添加方式:【添加板块】 - 【系统报价表】 - 【外盘行情(延时)】 .. figure:: /images/foreign01.png diff --git a/doc/version.rst b/doc/version.rst index 60dd6f13..ae7cec40 100644 --- a/doc/version.rst +++ b/doc/version.rst @@ -2,6 +2,17 @@ 版本变更 ============================= +3.8.8 (2025/12/11) + +* 修复: :py:meth:`~tqsdk.TqApi.ischanging` 接口无法正确判断 tick 中的字段更新 +* 优化: :py:meth:`~tqsdk.TqApi.query_symbol_settlement` 和 :py:meth:`~tqsdk.TqApi.query_symbol_settlement` 接口复用 tcp 连接 +* 优化: 版本变更信息的通知时机 +* docs: 多策略依赖包升级 +* docs: 修改外盘行情描述 +* docs: 提供 trae IDE 配置方式 +* 自该版本起仅支持 Python >=3.8 + + 3.8.7 (2025/10/27) * 修复: 多进程回测触发的超时报错 diff --git a/setup.py b/setup.py index 6586bcf6..9b5b58c7 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setuptools.setup( name='tqsdk', - version="3.8.7", + version="3.8.8", description='TianQin SDK', author='TianQin', author_email='tianqincn@gmail.com', @@ -16,7 +16,7 @@ long_description_content_type="text/markdown", url='https://www.shinnytech.com/tqsdk', packages=setuptools.find_packages(exclude=["tqsdk.test", "tqsdk.test.*"]), - python_requires='>=3.7', + python_requires='>=3.8', install_requires=["websockets>=10.1", "requests", "numpy", "pandas>=1.1.0", "scipy", "simplejson", "aiohttp", "certifi", "pyjwt", "psutil>=5.9.6", "shinny_structlog", "sgqlc", "filelock", "tqsdk_ctpse", "tqsdk_sm", "packaging"], diff --git a/tqsdk/__version__.py b/tqsdk/__version__.py index bd03e733..eb4c7bae 100644 --- a/tqsdk/__version__.py +++ b/tqsdk/__version__.py @@ -1 +1 @@ -__version__ = '3.8.7' +__version__ = '3.8.8' diff --git a/tqsdk/api.py b/tqsdk/api.py index f8ae64a1..1c4b1829 100644 --- a/tqsdk/api.py +++ b/tqsdk/api.py @@ -14,6 +14,7 @@ """ __author__ = 'chengzhi' +import aiohttp import asyncio import copy import logging @@ -201,6 +202,8 @@ def __init__(self, account: Optional[Union[TqMultiAccount, UnionTradeable]] = No api = TqApi(TqKq(), auth=TqAuth("快期账户", "账户密码")) # 根据填写的快期账户参数连接指定的快期模拟账户 """ + # 保证在初始化 TqApi 时打印版本变更与广播信息,并且一个进程内只会打印一次 + from tqsdk import changelog_notification # 初始化 logger self._logger = logging.getLogger("TqApi") @@ -265,6 +268,7 @@ def __init__(self, account: Optional[Union[TqMultiAccount, UnionTradeable]] = No self._send_chan, self._recv_chan = TqChan(self), TqChan(self) # 消息收发队列 self._ws_md_recv_chan = None # 记录 ws_md_recv_chan 引用 self._pre20_ins_info = {} # 20年9月份之前的合约信息 + self._http_session_internal = None # 记录 http 会话 # slave模式的api不需要完整初始化流程 self._is_slave = isinstance(account, TqApi) @@ -312,6 +316,12 @@ def _print(self, msg: str = "", level: str = "INFO"): def _base_headers(self): return self._auth._base_headers + @property + def _http_session(self): + if self._http_session_internal is None or self._http_session_internal.closed: + self._http_session_internal = aiohttp.ClientSession(headers=self._base_headers) + return self._http_session_internal + # ---------------------------------------------------------------------- def copy(self) -> 'TqApi': """ @@ -354,7 +364,10 @@ def close(self) -> None: # 总会发送 serial_extra_array 数据,由 TqWebHelper 处理 for _, serial in self._serials.items(): self._process_serial_extra_array(serial) - super(TqApi, self)._close() + super(TqApi, self)._close_tasks() + if self._http_session_internal: + self._loop.run_until_complete(self._http_session_internal.close()) + super(TqApi, self)._close_loop() mem = psutil.virtual_memory() self._logger.debug("process end", mem_total=mem.total, mem_free=mem.free) finally: @@ -2090,6 +2103,8 @@ def _is_obj_changing(self, obj: Any, diffs: List[Dict[str, Any]], key: List[str] elif int(m.group(2)) < len(paths): m_k = int(m.group(2)) k_dict.setdefault(m_k, []).append(m.group(1)) + else: # 数字 >= len(paths),说明是字段本身的数字(如 tick 盘口字段) + k_dict.setdefault(0, []).append(k) # 保留完整字段名 for k_id, v in k_dict.items(): if _is_key_exist(diff, paths[k_id], v): return True @@ -4120,18 +4135,5 @@ def _get_current_datetime(self): print("在使用天勤量化之前,默认您已经知晓并同意以下免责条款,如果不同意请立即停止使用:https://www.shinnytech.com/blog/disclaimer/", file=sys.stderr) -if platform.python_version().startswith('3.7.'): - warnings.warn("TqSdk 计划在 20250601 之后放弃支持 Python 3.7 版本,请尽快升级 Python 版本。", FutureWarning, stacklevel=1) - - -try: - res = requests.get("https://shinny-tqsdk.oss-cn-shanghai.aliyuncs.com/tqsdk_metadata.json", timeout=10) - tq_metadata = res.json() - current_version = version.parse(__version__) - change_version = version.parse(tq_metadata.get('tqsdk_version', '0.0.0')) - if tq_metadata.get('tqsdk_changelog') and current_version < change_version: - print(tq_metadata['tqsdk_changelog'], file=sys.stderr) - if tq_metadata.get('tqsdk_notify'): - print(tq_metadata['tqsdk_notify'], file=sys.stderr) -except: - pass +if platform.python_version().startswith('3.8.'): + warnings.warn("TqSdk 计划在 20260601 之后放弃支持 Python 3.8 版本,请尽快升级 Python 版本。", FutureWarning, stacklevel=1) \ No newline at end of file diff --git a/tqsdk/baseApi.py b/tqsdk/baseApi.py index e51f46d4..7e50109a 100644 --- a/tqsdk/baseApi.py +++ b/tqsdk/baseApi.py @@ -37,8 +37,7 @@ def __init__(self, loop: Optional[asyncio.AbstractEventLoop] = None) -> None: def _create_task(self, coro: Coroutine, _caller_api: bool = False) -> asyncio.Task: task = self._loop.create_task(coro) - py_ver = sys.version_info - current_task = asyncio.Task.current_task(loop=self._loop) if (py_ver.major == 3 and py_ver.minor < 7) else asyncio.current_task(loop=self._loop) + current_task = asyncio.current_task(loop=self._loop) if current_task is None or _caller_api: # 由 api 创建的 task,需要 api 主动管理 self._tasks.add(task) task.add_done_callback(self._on_task_done) @@ -145,11 +144,13 @@ async def _windows_patch(self): while True: await asyncio.sleep(1) - def _close(self) -> None: + def _close_tasks(self) -> None: self._run_until_idle(async_run=False) # 由于有的处于 ready 状态 task 可能需要报撤单, 因此一直运行到没有 ready 状态的 task for task in self._tasks: task.cancel() while self._tasks: # 等待 task 执行完成 self._run_once() + + def _close_loop(self) -> None: self._loop.run_until_complete(self._loop.shutdown_asyncgens()) self._loop.close() diff --git a/tqsdk/changelog_notification.py b/tqsdk/changelog_notification.py new file mode 100644 index 00000000..5178bb7a --- /dev/null +++ b/tqsdk/changelog_notification.py @@ -0,0 +1,22 @@ +# !usr/bin/env python3 +# -*- coding:utf-8 -*- +__author__ = 'chenli' + +import sys +from packaging import version + +import requests + +from tqsdk.__version__ import __version__ + +try: + res = requests.get("https://shinny-tqsdk.oss-cn-shanghai.aliyuncs.com/tqsdk_metadata.json", timeout=10) + tq_metadata = res.json() + current_version = version.parse(__version__) + change_version = version.parse(tq_metadata.get('tqsdk_version', '0.0.0')) + if tq_metadata.get('tqsdk_changelog') and current_version < change_version: + print(tq_metadata['tqsdk_changelog'], file=sys.stderr) + if tq_metadata.get('tqsdk_notify'): + print(tq_metadata['tqsdk_notify'], file=sys.stderr) +except: + pass diff --git a/tqsdk/objs_not_entity.py b/tqsdk/objs_not_entity.py index 07a7d3a3..0de994e7 100644 --- a/tqsdk/objs_not_entity.py +++ b/tqsdk/objs_not_entity.py @@ -321,9 +321,9 @@ def __init__(self, api, symbol, days, start_dt): 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: + session = self.__dict__["_api"]._http_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({ @@ -422,9 +422,9 @@ def __init__(self, api, symbol, ranking_type, days, start_dt, broker): async def _get_ranking_data(self, ranking_id): # 下载持仓排名数据,并将数据发回到 api.recv_chan - async with aiohttp.ClientSession(headers=self.__dict__["_api"]._base_headers) as session: - url = "https://symbol-ranking-system-fc-api.shinnytech.com/srs" - async with session.get(url, params=self.__dict__["_params"]) as response: + session = self.__dict__["_api"]._http_session + url = "https://symbol-ranking-system-fc-api.shinnytech.com/srs" + 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({