playbook/docs/tsl/modules/pytsl_api.md

948 lines
60 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 天软 pyTSL 接口使用说明
文档类型:模块 API 事实页
是否可直接用于生成代码:是,但真实账号、密码、服务地址、配置文件路径和权限范围必须来自项目上下文
遇到不确定时:[index.md](index.md)、项目自身部署文档、官方 pyTSL 接口文档
本页整理 pyTSL 官方 Python SDK 的可调用接口。它负责告诉智能体“pyTSL 有哪些类、函数、参数和返回结构”,不负责提供真实凭证、项目账号来源、服务权限或业务数据口径。
## 智能体 pyTSL 决策规则
- 用户要“用 Python 调 TSL / 执行 TSL 代码 / 调天软函数 / 查行情 / 并发或异步取数”时,优先使用本页。
- 用户只是要执行一段 TSL 并马上拿结果,默认使用 `pyTSL.Client.exec()`
- 用户要调用服务器上已有 TSL 函数,默认使用 `pyTSL.Client.call()`
- 用户要按证券、周期、开始时间、结束时间取标准行情字段,默认使用 `pyTSL.Client.query()`
- 用户要一次性提交很多独立任务,先考虑 `pyTSL.Batch`;不要把大量循环直接写成频繁登录、退出。
- 用户明确要求 asyncio才使用 `pyTSL.AsyncClient``pyTSL.async_util`
- 不要发明真实账号、密码、服务地址、代理、配置文件路径、服务节点、字段名或业务函数名。
- 不要把登录脚本、临时验证脚本或私有凭证写进生成代码;示例只能使用占位值或从项目配置读取。
## 安装与支持范围
### 包与导入
| 项目 | 事实 |
| ---------- | ------------------------------------------------------------------------- |
| 安装包名 | `tspytsl` |
| 导入模块名 | `pyTSL` |
| 在线安装 | `pip install tspytsl` |
| 升级 | `pip install tspytsl -U` |
| 离线安装 | 下载对应 `.whl` 后执行 `pip install 文件名.whl` |
| 手动安装 | 解压对应平台的 `.pyd``.so`,放入 Python 的 `site-packages` 或项目目录 |
### Python 与平台
- pyTSL 支持 Python 3.6+。
- 官方文档截至 2025-10-13 列出 Python 3.6 到 3.14 的 Windows、Linux x86_64、Linux arm64、MacOS x86_64 支持。
- MacOS arm64 从 Python 3.8 到 3.14 支持Python 3.6 和 3.7 不支持。
- Windows 需要确认已安装 VS2019 C++ 运行时库;其他系统不需要这一步。
## 最小同步链路
优先写成“一次登录,多次交互,最后退出”。`logout()` 后再次调用 `Client` 方法可能触发自动重新登录,频繁登录退出可能占用多个登录数。
```python
import pyTSL
from datetime import datetime
c = pyTSL.Client("user", "password", "tsl.tinysoft.com.cn", 443)
try:
if c.login() == 0:
raise RuntimeError(c.last_error())
r = c.exec("return close();", stock="SZ000002", time=datetime(2024, 7, 30))
if r.error():
raise RuntimeError(r.message())
value = r.value()
finally:
c.logout()
```
## `pyTSL.Client`
同步客户端。构造一个 `Client` 会占用一个登录数。
### 构造函数:账号参数方式
签名:
```python
pyTSL.Client(user, password, ip, port, proxy_ip=None, proxy_port=None, proxy_user=None, proxy_password=None)
```
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | ---------------- | ---- | -------- | -------------------------------------------------- |
| 1 | `user` | 是 | `str` | 天软账号 |
| 2 | `password` | 是 | `str` | 天软账号密码;支持用客户端工具生成的加密密码字符串 |
| 3 | `ip` | 是 | `str` | 天软服务器机群地址 |
| 4 | `port` | 是 | `int` | 天软服务器访问端口 |
| 5 | `proxy_ip` | 否 | `str` | 代理服务器地址 |
| 6 | `proxy_port` | 否 | `int` | 代理服务器端口 |
| 7 | `proxy_user` | 否 | `str` | 代理服务器验证账号 |
| 8 | `proxy_password` | 否 | `str` | 代理服务器验证密码 |
常见服务器:
| 服务器 | `ip` | `port` | 默认服务节点 |
| ---------------- | ------------------------- | -------------- | ------------------- |
| 深圳服务器 | `"tsl.tinysoft.com.cn"` | `443``444` | `"正式版"` |
| 武汉服务器 | `"wh.tinysoft.com.cn"` | `443``444` | `"Default Service"` |
| 深圳新节点服务器 | `"sznew.tinysoft.com.cn"` | `4433` | `"Default Service"` |
### 构造函数ini 文件方式
签名:
```python
pyTSL.Client(ini_file)
```
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | ---------- | ---- | -------- | ------------------------------------ |
| 1 | `ini_file` | 是 | `str` | 连接服务器信息 `.ini` 文件的绝对路径 |
ini 文件字段:
```ini
user=
password=
ip=
port=
proxy_user=
proxy_password=
proxy_ip=
proxy_port=
```
路径含中文并报找不到文件时,可把路径按 GBK 编码后传入。
### Client 方法总表
| 方法 | 签名 | 返回 | 用途 |
| ----------------- | --------------------------------------- | --------------- | ------------------------------------------- |
| `login` | `login()` | `bool` | 登录天软服务器;成功 `1`,失败 `0` |
| `last_error` | `last_error()` | `list` | 最近一次错误,结构为 `[错误代码, 错误信息]` |
| `logout` | `logout()` | `int` | 断开连接;成功 `0` |
| `exec` | `exec(code, **kwargs)` | `TSResultValue` | 执行 TSL 代码串 |
| `call` | `call(funcname, *args, **kwargs)` | `TSResultValue` | 调用 TSL 函数 |
| `query` | `query(**kwargs)` | `TSResultValue` | 提取行情数据 |
| `list_bgrun` | `list_bgrun()` | `list` | 列出委托执行任务 |
| `stop_bgrun` | `stop_bgrun(handle)` | `int` | 停止指定委托执行任务;成功 `1` |
| `admin` | `admin(**kwargs)` | `str` | 执行天软客户端任务管理命令 |
| `set_callback` | `set_callback(function)` | 未说明 | 设置 `rdo2` 回调函数 |
| `default_service` | `default_service(service)` | `str` | 设置或返回默认服务节点 |
| `server_list` | `server_list()` | `list` | 返回服务节点列表 |
| `download_list` | `download_list(type, timeout=0)` | `list` | 下载指定类型列表 |
| `download` | `download(type, key, ver=0, timeout=0)` | `list` | 下载指定关键字内容 |
| `upload` | `upload(type, key, data, timeout=0)` | `list` | 上传数据至指定关键字 |
| `remove` | `remove(type, key, timeout=0)` | `list` | 删除指定关键字内容 |
| `is_logined` | `is_logined()` | `bool` | 已登录返回 `1`,未登录返回 `0` |
| `is_closed` | `is_closed()` | `bool` | 已断开返回 `1`,未断开返回 `0` |
### `exec(code, **kwargs)`
执行 TSL 代码串。结果通过 `TSResultValue` 读取。
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | ---------- | ---- | -------- | ------------------- |
| 1 | `code` | 是 | `str` | 要执行的 TSL 代码串 |
| 2 | `**kwargs` | 否 | 见下表 | 执行上下文属性 |
### `call(funcname, *args, **kwargs)`
调用 TSL 函数。`*args` 会自动转换常见 Python 类型到 TSL 类型。
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | ---------- | ---- | ---------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- |
| 1 | `funcname` | 是 | `str` | 函数名 |
| 2 | `*args` | 否 | `float` / `int` / `bool` / `str` / `bytes` / `list` / `dict` / `tuple` / `pandas.DataFrame` / `numpy.ndarray` / 日期时间类型 | 传给 TSL 函数的位置参数 |
| 3 | `**kwargs` | 否 | 见下表 | 执行上下文属性,可通过 `code` 传入临时函数定义 |
Python 到 TSL 的自动转换:
| Python 类型 | TSL 类型 |
| ----------------------------------------------------------------------------- | -------------------- |
| `float` / `numpy.float32` / `numpy.float64` / `datetime` / `numpy.datetime64` | `real` / `tdatetime` |
| `bool` / `int` / `numpy.int32` / `numpy.int64` | `int` |
| `str` / `bytes` | `str` |
| `list` / `dict` / `tuple` / `pandas.DataFrame` / `numpy.ndarray` | `array` |
### `exec` / `call` 共享 `kwargs`
| 参数名 | 必填 | 接收类型 | 默认值 | 说明 |
| ------------ | ---- | ------------------------------------ | ---------------- | ------------------------------------------------------------------------------------ |
| `stock` | 否 | `str` | `None` | 当前股票代码,如 `"SZ000002"` |
| `cycle` | 否 | `str` | `"日线"` | 当前周期 |
| `time` | 否 | `datetime` / `int` / `float` / `str` | 今天 | 当前时间,如 `datetime(2019, 10, 1)`、`43739.0`、`20191001`、`"2019-10-01 14:03:01"` |
| `rate` | 否 | `int` | `0` | 复权方式:`0` 不复权,`1` 比例复权,`2` 复杂复权 |
| `rateday` | 否 | `datetime` / `int` / `float` / `str` | `0` | 复权基准日:`0` 最后交易日,`-1` 上市日,其他值为指定基准日 |
| `precision` | 否 | `int` | `-1` | 浮点数精度 |
| `viewpoint` | 否 | `datetime` / `int` / `float` / `str` | `0` | 仿真时点 |
| `code` | 否 | `str` | `None` | 临时定义函数代码段,不必先保存到服务器 |
| `service` | 否 | `str` | 由登录服务器决定 | 指定执行服务节点 |
| `timeout` | 否 | `int` | `None` | 超时,单位毫秒;`None` 表示无超时时限 |
| `bgrun` | 否 | `int` | `0` | 委托执行;`1` 表示委托执行 |
| `resultname` | 否 | `str` | `None` | 仅 `exec` 支持;`bgrun=1` 时用于指定委托保存的结果集名称 |
| `reportmode` | 否 | `int` | `-1` | 报表数据规则 |
| `emptymode` | 否 | `int` | `0` | 空记录模式 |
### `query(**kwargs)`
提取行情数据。适合标准证券、周期、时间区间、字段查询。
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | ---------- | ---- | -------- | ------------------------------------------------------------- |
| 1 | `**kwargs` | 是 | 见下表 | 查询属性,必须包含 `stock`、`cycle`、`begin_time`、`end_time` |
| 参数名 | 必填 | 接收类型 | 默认值 | 说明 |
| ------------- | ---- | ------------------------------------ | ---------------- | ------------------------------------------------ |
| `stock` | 是 | `str` / 一维数组 | `None` | 当前股票代码;可指定多只股票 |
| `cycle` | 是 | `str` | `"日线"` | 当前周期 |
| `begin_time` | 是 | `datetime` / `int` / `float` / `str` | `None` | 数据开始时间 |
| `end_time` | 是 | `datetime` / `int` / `float` / `str` | `None` | 数据结束时间 |
| `fields` | 否 | `str` / `tuple` / `list` | 所有字段 | 查询字段;字符串用逗号分隔 |
| `rate` | 否 | `int` | `0` | 复权方式:`0` 不复权,`1` 比例复权,`2` 复杂复权 |
| `rateday` | 否 | `datetime` / `int` / `float` / `str` | `0` | 复权基准日 |
| `precision` | 否 | `int` | `-1` | 浮点数精度 |
| `viewpoint` | 否 | `datetime` / `int` / `float` / `str` | `0` | 仿真时点 |
| `service` | 否 | `str` | 由登录服务器决定 | 指定执行服务节点 |
| `timeout` | 否 | `int` | `None` | 超时,单位毫秒 |
| `cyclefilter` | 否 | `int` | `0` | 周期过滤器以及集合竞价分离器 |
### 委托、任务管理和服务节点方法
#### `list_bgrun()`
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | ------ | ---- | -------- | ---------- |
| 无 | 无 | 否 | 无 | 不接收参数 |
返回 `["+OK", [委托任务1], ...]`。委托任务结构为 `[handle, 执行的函数名, 开始执行时间, 已运行时间]`
#### `stop_bgrun(handle)`
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | -------- | ---- | -------- | ------------ |
| 1 | `handle` | 是 | `float` | 委托任务编号 |
返回整数,成功为 `1`
#### `admin(**kwargs)`
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | ---------- | ---- | -------- | ----------------------------------------- |
| 1 | `**kwargs` | 是 | `str` | 天软客户端任务管理命令,如 `"oa"`、`"ou"` |
返回对应指令的查询信息。
#### `set_callback(function)`
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | ---------- | ---- | ----------------- | -------------------- |
| 1 | `function` | 是 | Python 可调用对象 | 设置 `rdo2` 回调函数 |
`rdo2 callback(...)` 调用时会回到 Python 函数;不要把已经通过 `register_proc` 注册过的函数再当作该回调。
#### `default_service(service)`
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | --------- | ---- | -------- | ---------------------------------------------- |
| 1 | `service` | 否 | `str` | 为空时返回当前服务节点;非空时设置当前服务节点 |
返回字符串,内容为服务节点。
#### `server_list()`
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | ------ | ---- | -------- | ---------- |
| 无 | 无 | 否 | 无 | 不接收参数 |
返回服务节点列表。
### 下载、上传和删除
#### 类型取值
| 类型值 | 可用于 | 说明 |
| -------- | -------------------------------------------------- | ---------------- |
| `0x2001` | `download_list` / `download` | 系统板块 |
| `0x2002` | `download_list` / `download` / `upload` / `remove` | 用户板块 |
| `0x5001` | `download_list` / `download` | 系统基本面表描述 |
| `0x6001` | `download_list` / `download` / `upload` / `remove` | 用户函数 |
| `0x6002` | `download_list` / `download` | 共享函数 |
| `0x6003` | `download_list` / `download` | 系统公用函数 |
| `0x6004` | `download_list` / `download` | 系统函数 |
| `0x8001` | `download_list` / `download` / `upload` / `remove` | 用户数据表 |
#### `download_list(type, timeout=0)`
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | --------- | ---- | -------- | --------------------------------------- |
| 1 | `type` | 是 | `int` | 指定类型 |
| 2 | `timeout` | 否 | `int` | 超时,单位毫秒;默认 `0` 表示无超时限制 |
返回长度为 2 的列表。无错误返回 `[0, 结果列表]`,有错误返回 `[错误代码, 错误信息]`。结果列表中的单项结构为 `[关键字, 版本, 修改时间]`
#### `download(type, key, ver=0, timeout=0)`
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | --------- | ---- | -------- | --------------------------------------- |
| 1 | `type` | 是 | `int` | 指定类型 |
| 2 | `key` | 是 | `str` | 关键字,如函数名、板块名 |
| 3 | `ver` | 否 | `int` | 关键字版本;默认 `0` 表示最新版本 |
| 4 | `timeout` | 否 | `int` | 超时,单位毫秒;默认 `0` 表示无超时限制 |
无错误返回 `[0, 结果]`,有错误返回 `[错误代码, 错误信息]`。结果结构包含:
| 键 | 说明 |
| ---------------- | -------------------------------------------------------- |
| `"data"` | 关键字内容TSL 流格式,可用 `pyTSL.DecodeStream()` 转换 |
| `"LastModified"` | 版本 |
| `"LastTime"` | 修改时间 |
#### `upload(type, key, data, timeout=0)`
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | --------- | ---- | -------- | --------------------------------------- |
| 1 | `type` | 是 | `int` | 只支持 `0x2002`、`0x6001`、`0x8001` |
| 2 | `key` | 是 | `str` | 关键字,如函数名、板块名、用户数据名 |
| 3 | `data` | 是 | `Any` | 上传至关键字的数据 |
| 4 | `timeout` | 否 | `int` | 超时,单位毫秒;默认 `0` 表示无超时限制 |
无错误返回 `[0, 结果]`,有错误返回 `[错误代码, 错误信息]`
#### `remove(type, key, timeout=0)`
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | --------- | ---- | -------- | --------------------------------------- |
| 1 | `type` | 是 | `int` | 只支持 `0x2002`、`0x6001`、`0x8001` |
| 2 | `key` | 是 | `str` | 关键字,如函数名、用户数据名 |
| 3 | `timeout` | 否 | `int` | 超时,单位毫秒;默认 `0` 表示无超时限制 |
无错误返回 `[0, 结果]`,有错误返回 `[错误代码, 错误信息]`
## `pyTSL.AsyncClient`
异步客户端,适用于 Python `asyncio`。与 `Client` 一样会占用登录数;异步任务数量受账号并发数限制,普通账号常见并发数为 5应保留资源。
构造方式同 `Client`
```python
pyTSL.AsyncClient("user", "password", "tsl.tinysoft.com.cn", 443)
pyTSL.AsyncClient("E:\\my.ini")
```
也支持空构造后复用已有 `Client`
```python
c = pyTSL.Client("user", "password", "tsl.tinysoft.com.cn", 443)
ac = pyTSL.AsyncClient()
ac.c = c
```
| 方法 | 签名 | 返回 | 参数来源 |
| --------------- | --------------------------------------- | --------------- | -------------------------------- |
| `login` | `login()` | `bool` | 无参数;成功 `1`,失败 `0` |
| `logout` | `logout()` | `int` | 无参数;成功 `0` |
| `exec` | `exec(code, **kwargs)` | `TSResultValue` | 同 `Client.exec` |
| `call` | `call(funcname, *args, **kwargs)` | `TSResultValue` | 同 `Client.call` |
| `query` | `query(**kwargs)` | `TSResultValue` | 同 `Client.query` |
| `admin` | `admin(**kwargs)` | `str` | 同 `Client.admin` |
| `download_list` | `download_list(type, timeout=0)` | `list` | 同 `Client.download_list` |
| `download` | `download(type, key, ver=0, timeout=0)` | `list` | 同 `Client.download` |
| `upload` | `upload(type, key, data, timeout=0)` | `list` | 同 `Client.upload` |
| `remove` | `remove(type, key, timeout=0)` | `list` | 同 `Client.remove` |
| `task_list` | `task_list()` | `list` | 返回异步任务列表 |
| `task_cancel` | `task_cancel(task)` | `int` | 取消异步任务;成功 `1`,失败 `0` |
最小异步示例:
```python
import asyncio
import pyTSL
from datetime import datetime
async def main():
c = pyTSL.AsyncClient("user", "password", "tsl.tinysoft.com.cn", 443)
try:
if await c.login() == 0:
raise RuntimeError("login failed")
r = await c.exec("return close();", stock="SZ000002", time=datetime(2024, 7, 30))
if r.error():
raise RuntimeError(r.message())
return r.value()
finally:
await c.logout()
value = asyncio.run(main())
```
## `pyTSL.async_util`
`async_util` 把普通 `Client` 的操作包装为可 `await` 的函数。所有函数第一个参数都是 `pyTSL.Client` 实例。
| 函数 | 签名 | 返回 | 对应同步方法 |
| --------------------- | ------------------------------------------------ | --------------- | ---------------------- |
| `async_login` | `async_login(c)` | `bool` | `c.login()` |
| `async_logout` | `async_logout(c)` | `int` | `c.logout()` |
| `async_exec` | `async_exec(c, code, **kwargs)` | `TSResultValue` | `c.exec(...)` |
| `async_call` | `async_call(c, funcname, *args, **kwargs)` | `TSResultValue` | `c.call(...)` |
| `async_query` | `async_query(c, **kwargs)` | `TSResultValue` | `c.query(...)` |
| `async_admin` | `async_admin(c, **kwargs)` | `str` | `c.admin(...)` |
| `async_download_list` | `async_download_list(c, type, timeout=0)` | `list` | `c.download_list(...)` |
| `async_download` | `async_download(c, type, key, ver=0, timeout=0)` | `list` | `c.download(...)` |
| `async_upload` | `async_upload(c, type, key, data, timeout=0)` | `list` | `c.upload(...)` |
| `async_remove` | `async_remove(c, type, key, timeout=0)` | `list` | `c.remove(...)` |
## pyTSL 全局方法
### `DatetimeToDouble(datetime, timezone=8)`
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | ---------- | ---- | ------------------------------------- | -------------------------- |
| 1 | `datetime` | 是 | `datetime.date` / `datetime.datetime` | Python 日期或日期时间 |
| 2 | `timezone` | 否 | `int` | 时区,默认 `8`,即北京时间 |
返回 TSL 的时间类型 `TDateTime`,精度到毫秒。
### `DoubleToDatetime(t)`
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | ------ | ---- | --------------------- | ------------ |
| 1 | `t` | 是 | `TDateTime` / `float` | TSL 时间类型 |
返回 Python `datetime`,精度到毫秒。
### `DataFrameDiff(df1, df2)`
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | ------ | ---- | ------------------ | ------------------------------------- |
| 1 | `df1` | 是 | `pandas.DataFrame` | 第一个 DataFrame结构需与 `df2` 一致 |
| 2 | `df2` | 是 | `pandas.DataFrame` | 第二个 DataFrame结构需与 `df1` 一致 |
返回两个 DataFrame 的不同数据以及行列位置。
### `EncodeStream(obj)`
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | ------ | ---- | ----------- | -------------------- |
| 1 | `obj` | 是 | Python 变量 | 要转换的 Python 对象 |
返回 TSL 流格式。
### `DecodeStream(bytes, parse_date=False)`
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | ------------ | ---- | ------------------------- | ------------------------------------ |
| 1 | `bytes` | 是 | TSL 流格式 | 要解码的 TSL 流 |
| 2 | `parse_date` | 否 | `bool` / `list` / `tuple` | 是否把日期字段转成 Python `datetime` |
`parse_date` 取值:
| 取值 | 说明 |
| ------------------------ | ------------------------------------------------------- |
| `False` | 默认值不转换TSL `TDateTime` 保持实数 |
| `True` | 将 TSL `TDateTime` 或日期字符串转换为 Python `datetime` |
| `["date"]` / `("date",)` | 只转换指定字段 |
返回 Python 变量。
### `register_proc(funcname1, funcname2)`
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | ----------- | ---- | ----------------- | ------------------------ |
| 1 | `funcname1` | 是 | `str` | TSL 本地调用时使用的名称 |
| 2 | `funcname2` | 是 | Python 可调用对象 | Python 中定义的函数 |
将 Python 函数注册为天软函数,可在交互语句中用 `rdo2` 调用。`importfile` 和 `exportfile` 已有默认实现,不要注册同名函数。
### `DataFrameToTSArray(DataFrame)`
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | ----------- | ---- | ------------------ | ------------------ |
| 1 | `DataFrame` | 是 | `pandas.DataFrame` | 要转换的 DataFrame |
返回 TSL 的 `array` 数据结构。`Client.call()` 传入 DataFrame 时也会自动转换。
### `start_network_threads(n)`
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | ------ | ---- | -------- | ---------------------------- |
| 1 | `n` | 是 | `int` | 额外启动的网络 IO 处理线程数 |
返回 `None`。pyTSL 默认有 1 个线程处理网络 IO多连接场景可以增加线程。
## `pyTSL.Batch`
用于并发执行多个天软任务,只占用一个登录数。并发数受账号资源限制,不是越大越好;普通账号常见并发数为 5建议保守设置。
### 构造函数
签名:
```python
pyTSL.Batch(parallel=5, reconnect=0)
```
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | ----------- | ---- | -------- | ---------------------------------------------------- |
| 1 | `parallel` | 否 | `int` | 并行任务数,默认 `5` |
| 2 | `reconnect` | 否 | `int` | 是否重新连接;`0` 不重新连接,`1` 重新连接,默认 `0` |
### Batch 方法
| 方法 | 签名 | 返回 | 说明 |
| --------- | --------------------------------------------- | ------ | ------------------------------------------------ |
| `exec` | `exec(client, code, **kwargs)` | `list` | 并发执行 TSL 代码串 |
| `call` | `call(client, functionname, *args, **kwargs)` | `list` | 并发调用 TSL 函数 |
| `query` | `query(client, **kwargs)` | `list` | 并发查询行情数据 |
| `__len__` | `__len__()` | `int` | 通过 `len(iter(batch))` 返回迭代器中剩余元素个数 |
`Batch.exec()` 参数:
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | ---------- | ---- | ---------------- | ------------------------------ |
| 1 | `client` | 是 | `pyTSL.Client` | 已构造的客户端实例 |
| 2 | `code` | 是 | `str` | TSL 代码串 |
| 3 | `**kwargs` | 否 | 见 `Client.exec` | 不支持委托执行;额外支持 `key` |
`Batch.call()` 参数:
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | -------------- | ---- | ---------------- | ------------------------------ |
| 1 | `client` | 是 | `pyTSL.Client` | 已构造的客户端实例 |
| 2 | `functionname` | 是 | `str` | TSL 函数名 |
| 3 | `*args` | 否 | 见 `Client.call` | 传给 TSL 函数的位置参数 |
| 4 | `**kwargs` | 否 | 见 `Client.call` | 不支持委托执行;额外支持 `key` |
`Batch.query()` 参数:
| 参数位置 | 参数名 | 必填 | 接收类型 | 说明 |
| -------- | ---------- | ---- | ----------------- | ------------------------------ |
| 1 | `client` | 是 | `pyTSL.Client` | 已构造的客户端实例 |
| 2 | `**kwargs` | 是 | 见 `Client.query` | 不支持委托执行;额外支持 `key` |
`key` 参数:
| 参数名 | 必填 | 接收类型 | 默认值 | 说明 |
| ------ | ---- | -------- | ------ | ------------------------------------------------- |
| `key` | 否 | `str` | `""` | 标识每个任务;也可通过返回的 `Task.key(str)` 设置 |
返回结构:
| 情况 | 返回 |
| -------- | --------------------- |
| 提交成功 | `[1, Task对象]` |
| 提交失败 | `[0, 错误信息字符串]` |
结果读取:
```python
for r in iter(batch):
print(r.key(), r.value())
```
遍历时每个 `r``TSResultValue`
## `pyTSL.Task`
`Batch` 执行任务的标识。
| 方法 | 签名 | 返回 | 说明 |
| ----- | --------------- | ----- | ------------------------------------------ |
| `id` | `id()` | `int` | 返回任务 ID |
| `key` | `key(str=None)` | `str` | 有参数时设置关键字;无参数时返回当前关键字 |
## `TSResultValue`
`Client.exec()`、`Client.call()`、`Client.query()`、异步方法和 `Batch` 迭代结果都会返回或产出 `TSResultValue`
| 方法 | 签名 | 返回 | 说明 |
| ----------- | ------------------------- | -------------------- | --------------------------------------- |
| `error` | `error()` | `int` | `0` 表示无错误,非 `0` 表示出错 |
| `message` | `message()` | `str` | 有错误时返回错误信息,无错误时为空 |
| `value` | `value(parse_date=False)` | `list` / 标量 / 对象 | 返回结果值 |
| `dataframe` | `dataframe()` | `pandas.DataFrame` | 输出 DataFrame相当于把 `value()` 转表 |
| `stream` | `stream()` | TSL 流格式 | 返回 TSL 流格式结果 |
| `stn` | `stn()` | `str` | 返回 TSL STN 格式结果 |
| `key` | `key()` | `str` | 返回任务关键字,配合 `Batch` 使用 |
| `cancelled` | `cancelled()` | `bool` | 返回任务是否被取消 |
`value(parse_date=...)`
| 取值 | 说明 |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `False` | 默认值不转换日期TSL `TDateTime` 保持实数 |
| `True` | 将一维数组或单个值中的 TSL 日期时间、日期字符串转换为 Python `datetime``query()` 的默认行为是转换日期 |
| `["date1", "date2"]` / `("date1", "date2")` | 对二维数组或表格中的指定日期字段做转换 |
推荐错误处理:
```python
r = c.exec("return 1 + 1;")
if r.error():
raise RuntimeError(r.message())
value = r.value()
```
## `pyTSL.Const`
常量模块包含周期、行情字段、文件导入导出类型和文件读写类型。导入方式:
```python
from pyTSL.Const import *
```
### 周期常量
| 常量 | 对应值 |
| ------------- | ---------------- |
| `cy_month` | `"月线"` |
| `cy_day` | `"日线"` |
| `cy_week` | `"周线"` |
| `cy_quarter` | `"季线"` |
| `cy_halfyear` | `"半年线"` |
| `cy_1m` | `"1分钟线"` |
| `cy_2m` | `"2分钟线"` |
| `cy_3m` | `"3分钟线"` |
| `cy_5m` | `"5分钟线"` |
| `cy_10m` | `"10分钟线"` |
| `cy_15m` | `"15分钟线"` |
| `cy_20m` | `"20分钟线"` |
| `cy_30m` | `"30分钟线"` |
| `cy_40m` | `"40分钟线"` |
| `cy_60m` | `"60分钟线"` |
| `cy_120m` | `"120分钟线"` |
| `cy_detail` | `"成交明细"` |
| `cy_halfs` | `"半秒线"` |
| `cy_1s` | `"1秒线"` |
| `cy_2s` | `"2秒线"` |
| `cy_3s` | `"3秒线"` |
| `cy_4s` | `"4秒线"` |
| `cy_5s` | `"5秒线"` |
| `cy_6s` | `"6秒线"` |
| `cy_10s` | `"10秒线"` |
| `cy_12s` | `"12秒线"` |
| `cy_15s` | `"15秒线"` |
| `cy_20s` | `"20秒线"` |
| `cy_30s` | `"30秒线"` |
| `cy_f30m` | `"期货30分钟线"` |
| `cy_f60m` | `"期货60分钟线"` |
### 行情字段常量
| 常量 | 字段值 | 说明 |
| ----------------------- | ------------------------- | -------------------- |
| `STOCKID` | `"StockID"` | 股票代码 |
| `STOCKNAME` | `"StockName"` | 股票名称 |
| `DATE` | `"date"` | 当前时间 |
| `PRICE` | `"price"` | 价格 |
| `CLOSE` | `"close"` | 收盘价 |
| `OPEN` | `"open"` | 开盘价 |
| `HIGH` | `"high"` | 最高价 |
| `LOW` | `"low"` | 最低价 |
| `VOL` | `"vol"` | 成交量 |
| `AMOUNT` | `"amount"` | 成交金额 |
| `CJBS` | `"cjbs"` | 成交笔数 |
| `YCLOSE` | `"yclose"` | 上次价 |
| `SYL1` | `"syl1"` | 市盈率 1 |
| `SYL2` | `"syl2"` | 市盈率 2 |
| `BUY1` | `"buy1"` | 买一价 |
| `BUY2` | `"buy2"` | 买二价 |
| `BUY3` | `"buy3"` | 买三价 |
| `BUY4` | `"buy4"` | 买四价 |
| `BUY5` | `"buy5"` | 买五价 |
| `SALE1` | `"sale1"` | 卖一价 |
| `SALE2` | `"sale2"` | 卖二价 |
| `SALE3` | `"sale3"` | 卖三价 |
| `SALE4` | `"sale4"` | 卖四价 |
| `SALE5` | `"sale5"` | 卖五价 |
| `BC1` | `"bc1"` | 买一量 |
| `BC2` | `"bc2"` | 买二量 |
| `BC3` | `"bc3"` | 买三量 |
| `BC4` | `"bc4"` | 买四量 |
| `BC5` | `"bc5"` | 买五量 |
| `SC1` | `"sc1"` | 卖一量 |
| `SC2` | `"sc2"` | 卖二量 |
| `SC3` | `"sc3"` | 卖三量 |
| `SC4` | `"sc4"` | 卖四量 |
| `SC5` | `"sc5"` | 卖五量 |
| `WB` | `"wb"` | 委比 |
| `LB` | `"lb"` | 量比 |
| `ZMM` | `"zmm"` | 买卖标识 |
| `BUY_VOL` | `"buy_vol"` | 主买量 |
| `BUY_AMOUNT` | `"buy_amount"` | 主买金额 |
| `SALE_VOL` | `"sale_vol"` | 主卖量 |
| `SALE_AMOUNT` | `"sale_amount"` | 主卖金额 |
| `W_BUY` | `"w_buy"` | 委买 |
| `W_SALE` | `"w_sale"` | 委卖 |
| `SECTIONAL_BUY_VOL` | `"sectional_buy_vol"` | 时点当日累计主买量 |
| `SECTIONAL_BUY_AMOUNT` | `"sectional_buy_amount"` | 时点当日累计主买金额 |
| `SECTIONAL_SALE_VOL` | `"sectional_sale_vol"` | 时点当日累计主卖量 |
| `SECTIONAL_SALE_AMOUNT` | `"sectional_sale_amount"` | 时点当日累计主卖金额 |
| `SECTIONAL_W_BUY` | `"sectional_w_buy"` | 时点当日累计委买 |
| `SECTIONAL_W_SALE` | `"sectional_w_sale"` | 时点当日累计委卖 |
| `SECTIONAL_YCLOSE` | `"sectional_yclose"` | 前日收盘 |
| `SECTIONAL_OPEN` | `"sectional_open"` | 时点当日开盘 |
| `SECTIONAL_HIGH` | `"sectional_high"` | 时点当日最高 |
| `SECTIONAL_LOW` | `"sectional_low"` | 时点当日最低 |
| `SECTIONAL_VOL` | `"sectional_vol"` | 时点当日累计成交量 |
| `SECTIONAL_AMOUNT` | `"sectional_amount"` | 时点当日累计成交金额 |
| `SECTIONAL_CJBS` | `"sectional_cjbs"` | 时点当日累计成交笔数 |
| `SECTIONAL_WB` | `"sectional_wb"` | 时点当日累计委比 |
### 文件导入导出类型常量
| 常量 | 值 | 说明 |
| ---------- | --- | --------------------------- |
| `ftCSV` | `0` | 逗号分割文件类型 |
| `ftXLS` | `1` | Excel 文件类型 |
| `ftStream` | `2` | 天软对象流文件类型 |
| `ftString` | `3` | 天软对象字符串文件类型 |
| `ftADO` | `4` | ADO 文件类型 |
| `ftXML` | `5` | XML 文件类型 |
| `ftXLS2` | `6` | 支持多表头的 Excel 文件类型 |
| `ftXLS3` | `7` | Excel 文件类型 |
| `ftDBF` | `8` | DBF 文件类型 |
### 文件读写类型常量
| 常量 | 值 | 说明 |
| ---------- | --- | ---------------- |
| `rwByte` | `0` | 字节流读写类型 |
| `rwInt` | `1` | 整数流读写类型 |
| `rwReal` | `2` | 实数流读写类型 |
| `rwStr` | `3` | 字符串流读写类型 |
| `rwObj` | `4` | 对象流读写类型 |
| `rwRaw` | `5` | 原始读写类型 |
| `rwBinary` | `6` | 二进制读写类型 |
## `query` 周期与字段
### 周期字符串
| 分类 | 可用值 |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 低频 | `"日线"`、`"周线"`、`"月线"`、`"季线"`、`"半年线"`、`"年线"` |
| 高频 | `"1分钟线"`、`"2分钟线"`、`"3分钟线"`、`"5分钟线"`、`"10分钟线"`、`"15分钟线"`、`"20分钟线"`、`"30分钟线"`、`"40分钟线"`、`"60分钟线"`、`"120分钟线"` |
| 超高频 | `"成交明细"`、`"半秒线"`、`"1秒线"`、`"2秒线"`、`"3秒线"`、`"4秒线"`、`"5秒线"`、`"6秒线"`、`"10秒线"`、`"12秒线"`、`"15秒线"`、`"20秒线"`、`"30秒线"` |
| 其他 | `"任意周期"`、`"期货30分钟线"`、`"期货60分钟线"` |
### 低频字段
| 字段 | 数据类型 | 名称 | 说明 |
| ----------- | ---------- | -------- | ------------------------------------------------------------------ |
| `StockID` | `string` | 代码 | 股票 ID |
| `StockName` | `string` | 名称 | 股票名称 |
| `date` | `datetime` | 日期 | 当前时间 |
| `price` | `real` | 最新价 | 该周期内最后一笔成交价 |
| `open` | `real` | 开盘价 | 交易所公布的开盘价 |
| `close` | `real` | 收盘价 | 交易所公布的收盘价 |
| `high` | `real` | 最高价 | 周期内最高价 |
| `low` | `real` | 最低价 | 周期内最低价 |
| `vol` | `real` | 成交量 | 周期内成交量;股票单位为股,基金单位为份,期货和期权单位为合约数量 |
| `amount` | `real` | 成交金额 | 周期内成交金额 |
| `cjbs` | `real` | 成交笔数 | 股票为成交笔数;期货/期权可表示持仓变动量,日线表示当日持仓量 |
| `yclose` | `real` | 系统昨收 | 交易所发布的考虑分红送股后的价格 |
| `syl1` | `real` | 市盈率 1 | 期货/期权日线表示当日结算价;其他通常为 `0` |
| `syl2` | `real` | 市盈率 2 | 期货/期权表示昨日结算价ETF/LOF 表示时点净值;其他通常为 `0` |
### 高频与 Level1 字段
| 字段 | 数据类型 | 名称 | 说明 |
| ----------------------- | ---------- | -------------------- | --------------------------------------------------------------------------------------------------- |
| `StockID` | `string` | 代码 | 股票 ID |
| `StockName` | `string` | 名称 | 股票名称 |
| `date` | `datetime` | 时间 | 当前时间 |
| `price` | `real` | 价格 | 交易明细为该时间点最后一笔成交价;其他为该周期最后一笔成交价 |
| `vol` | `real` | 成交量 | 周期内成交量;分钟周期表示该分钟成交量,不是开盘累计 |
| `amount` | `real` | 成交金额 | 周期内成交金额;分钟周期表示该分钟成交金额 |
| `cjbs` | `real` | 成交笔数 | 股票为成交笔数;期货/期权为周期内持仓变动量 |
| `yclose` | `real` | 上次价 | 上一周期的收盘价 |
| `syl1` | `real` | 市盈率 1 | 期货/期权分钟线或秒线中,当日结算价存储在当日最后成交记录中;其他通常为 `0` |
| `syl2` | `real` | 市盈率 2 | 期货/期权为昨日结算价ETF/LOF 为时点净值;其他通常为 `0` |
| `buy1``buy5` | `real` | 买一价至买五价 | 期货没有 `buy2``buy5` |
| `sale1``sale5` | `real` | 卖一价至卖五价 | 期货没有 `sale2``sale5` |
| `bc1``bc5` | `int` | 买一量至买五量 | 对应价位的委买量 |
| `sc1``sc5` | `int` | 卖一量至卖五量 | 对应价位的委卖量 |
| `wb` | `real` | 委比 | 公式为委买/委卖 |
| `lb` | `int` | 量比 | 秒线取交易明细最后一笔1 分钟线按过去 5 日均量和当日累计开市时间计算;其他分钟线取周期内最后一分钟 |
| `zmm` | `int` | 买卖标识 | 交易明细中 `1` 主买,`2` 主卖,`3` 集合竞价/涨停/跌停等;非交易明细无意义 |
| `buy_vol` | `real` | 主买量 | 主买成交量加买卖标识为 `3` 的成交量一半 |
| `buy_amount` | `real` | 主买金额 | 主买成交金额加买卖标识为 `3` 的成交金额一半 |
| `sale_vol` | `real` | 主卖量 | 主卖成交量加买卖标识为 `3` 的成交量一半 |
| `sale_amount` | `real` | 主卖金额 | 主卖成交金额加买卖标识为 `3` 的成交金额一半 |
| `w_buy` | `real` | 委买 | 一个周期内的委买量 |
| `w_sale` | `real` | 委卖 | 一个周期内的委卖量 |
| `sectional_buy_vol` | `real` | 时点当日累计主买量 | 从开盘到当前时间的主买量之和 |
| `sectional_buy_amount` | `real` | 时点当日累计主买金额 | 从开盘到当前时间的主买金额之和 |
| `sectional_sale_vol` | `real` | 时点当日累计主卖量 | 从开盘到当前时间的主卖量之和 |
| `sectional_sale_amount` | `real` | 时点当日累计主卖金额 | 从开盘到当前时间的主卖金额之和 |
| `sectional_w_buy` | `real` | 时点当日累计委买 | 从开盘到当前时间的委买量之和 |
| `sectional_w_sale` | `real` | 时点当日累计委卖 | 从开盘到当前时间的委卖量之和 |
| `sectional_yclose` | `real` | 前日收盘 | 上一交易日收盘价,与 `yclose` 的“上一周期收盘价”不同 |
| `sectional_open` | `real` | 时点当日开盘 | 今天开盘价 |
| `sectional_high` | `real` | 时点当日最高 | 从开盘到当前时间的最高价 |
| `sectional_low` | `real` | 时点当日最低 | 从开盘到当前时间的最低价 |
| `sectional_vol` | `real` | 时点当日累计成交量 | 从开盘到当前时间成交量之和 |
| `sectional_amount` | `real` | 时点当日累计成交金额 | 从开盘到当前时间成交金额之和 |
| `sectional_cjbs` | `int` | 时点当日累计成交笔数 | 股票为成交笔数;股指期货/期权可表示市场现有持仓量 |
| `sectional_wb` | `real` | 时点当日累计委比 | 当日累计委买/当日累计委卖 |
## 数据类型转换规则
| TSL | Python | TSL 转 Python | Python 转 TSL |
| ------------ | ------------------ | --------------------------- | ---------------------------- |
| 数值型 | `float` / `int` | 自动转换 | 自动转换 |
| 字符串 | `str` | 自动转换 | 自动转换 |
| 布尔型 | `bool` / `int` | 自动转换 | 自动转换为整数语义 |
| 日期时间实数 | `datetime` | `pyTSL.DoubleToDatetime()` | `pyTSL.DatetimeToDouble()` |
| `array` | `pandas.DataFrame` | `TSResultValue.dataframe()` | `pyTSL.DataFrameToTSArray()` |
| TSL 流 | Python 变量 | `pyTSL.DecodeStream()` | `pyTSL.EncodeStream()` |
TSL 日期时间是一个实数,例如 `20240730.145533T` 对应日期和时间;`Client.call()` 中的日期时间参数可直接传 Python `datetime`pyTSL 会自动转换。
## `pyTSLPy` 兼容模块
`pyTSLPy` 是用 `pyTSL` 实现旧版 `TSLPy3.pyd` 功能的兼容模块。安装命令:
```bash
pip install pyTSLPy
```
迁移入口:
```python
import pyTSLPy as ts
```
支持情况:
| 旧接口 | 支持情况 | 说明 |
| ----------------------------------------------- | ---------- | --------------------------------------------- |
| `DefaultConnectAndLogin` | 支持 | 通过配置文件登录 |
| `ConnectServer` | 支持 | 连接服务器 |
| `LoginServer` | 支持 | 登录用户 |
| `Disconnect` | 支持 | 断开连接 |
| `Logined` | 支持 | 判断是否连接 |
| `SetService` | 支持 | 设置服务器类型 |
| `GetService` | 支持 | 获得服务器类型 |
| `RemoteExecute` | 不完全支持 | 不支持本地交互 |
| `RemoteCallFunc` | 不完全支持 | 不支持本地交互 |
| `EncodeDate` / `EncodeTime` / `EncodeDateTime` | 支持 | 在 Python 中构造 TSL 日期、时间、日期时间 |
| `DecodeDate` / `DecodeTime` / `DecodeDateTime` | 支持 | 将 TSL 日期、时间、日期时间转换到 Python 数组 |
| `SetComputeBitsOption` / `GetComputeBitsOption` | 暂不支持 | 计算服务器位数相关 |
| `SetSysParam` / `GetSysParam` | 暂不支持 | 系统参数相关 |
如果旧代码使用本地交互函数,`pyTSLPy` 只直接支持 `ExportFile``ImportFile`;其他本地交互函数应通过 `pyTSL.register_proc()` 注册。
## 常见风险
- `import pyTSL` 失败并提示找不到模块时Windows 先确认 VC 运行库。
- 旧版本出现字符串对象分配错误时,先升级 pyTSL。
- MacOS 导入报签名或权限问题时,需要按系统权限策略放开对应模块。
- `Client(ini_file)` 路径含中文时,可传入 GBK 编码后的路径。
- `logout()` 后再次执行 `Client` 方法可能自动重新登录;生成长期任务时遵循一次登录、多次交互。
- pyTSL 返回值编码为 UTF-8不需要再手动从 GBK 转码。
- 使用代理时,代理需要支持 HTTP CONNECT只支持应用层代理的环境需要使用官方协议网关方案。
- Linux 旧版本在子进程场景可能出现网络线程初始化问题;应使用较新 pyTSL。
- 非中国时区下日期时间转换有偏差时,使用 `DatetimeToDouble(datetime, timezone)` 显式指定时区。
## 常用示例
### 执行 TSL 代码串
```python
import pyTSL
c = pyTSL.Client("user", "password", "tsl.tinysoft.com.cn", 443)
try:
if c.login() == 0:
raise RuntimeError(c.last_error())
r = c.exec("return 1 + 1;")
if r.error():
raise RuntimeError(r.message())
print(r.value())
finally:
c.logout()
```
### 查询行情并转 DataFrame
```python
import pyTSL
from datetime import datetime
c = pyTSL.Client("user", "password", "tsl.tinysoft.com.cn", 443)
try:
if c.login() == 0:
raise RuntimeError(c.last_error())
r = c.query(
stock=["SZ000001", "SZ000002"],
cycle="日线",
begin_time=datetime(2020, 1, 1),
end_time=datetime(2020, 3, 20),
fields="StockID,StockName,date,close",
)
if r.error():
raise RuntimeError(r.message())
df = r.dataframe()
finally:
c.logout()
```
### 通过 `code` 临时定义并调用 TSL 函数
```python
import pyTSL
from datetime import date
tsl_code = """
function getValue(begt, endt);
begin
n := tradeDays(begt, endt);
return nday(n, "date", dateToStr(spTime()), "close", close(), "vol", vol(), "amount", amount());
end;
"""
c = pyTSL.Client("user", "password", "tsl.tinysoft.com.cn", 443)
try:
if c.login() == 0:
raise RuntimeError(c.last_error())
r = c.call("getValue", date(2019, 4, 10), date(2019, 4, 18), code=tsl_code, stock="SH000001", cycle="日线")
if r.error():
raise RuntimeError(r.message())
df = r.dataframe()
finally:
c.logout()
```
### 并发任务
```python
import pyTSL
c = pyTSL.Client("user", "password", "tsl.tinysoft.com.cn", 443)
try:
if c.login() == 0:
raise RuntimeError(c.last_error())
batch = pyTSL.Batch(3, 0)
for stock in ["SH600028", "SH600030", "SH600036"]:
ok, task = batch.exec(c, "return stockMarketValue(20240410T);", stock=stock, key=stock)
if ok == 0:
print(task)
for r in iter(batch):
if r.error():
print(r.key(), r.message())
else:
print(r.key(), r.value())
finally:
c.logout()
```