frytrader 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. frytrader-0.1.0/LICENSE +22 -0
  2. frytrader-0.1.0/MANIFEST.in +3 -0
  3. frytrader-0.1.0/PKG-INFO +237 -0
  4. frytrader-0.1.0/README.md +171 -0
  5. frytrader-0.1.0/easytrader/__init__.py +11 -0
  6. frytrader-0.1.0/easytrader/api.py +128 -0
  7. frytrader-0.1.0/easytrader/background_focus.py +147 -0
  8. frytrader-0.1.0/easytrader/background_runtime.py +133 -0
  9. frytrader-0.1.0/easytrader/background_trader.py +542 -0
  10. frytrader-0.1.0/easytrader/background_windows.py +1115 -0
  11. frytrader-0.1.0/easytrader/clienttrader.py +684 -0
  12. frytrader-0.1.0/easytrader/config/__init__.py +0 -0
  13. frytrader-0.1.0/easytrader/config/background_controls.ahk +52 -0
  14. frytrader-0.1.0/easytrader/config/client.py +193 -0
  15. frytrader-0.1.0/easytrader/config/global.json +52 -0
  16. frytrader-0.1.0/easytrader/config/xq.json +11 -0
  17. frytrader-0.1.0/easytrader/exceptions.py +11 -0
  18. frytrader-0.1.0/easytrader/follower.py +408 -0
  19. frytrader-0.1.0/easytrader/gf_clienttrader.py +84 -0
  20. frytrader-0.1.0/easytrader/gj_clienttrader.py +80 -0
  21. frytrader-0.1.0/easytrader/grid_strategies.py +845 -0
  22. frytrader-0.1.0/easytrader/ht_clienttrader.py +76 -0
  23. frytrader-0.1.0/easytrader/htzq_clienttrader.py +61 -0
  24. frytrader-0.1.0/easytrader/joinquant_follower.py +140 -0
  25. frytrader-0.1.0/easytrader/log.py +14 -0
  26. frytrader-0.1.0/easytrader/miniqmt/__init__.py +1 -0
  27. frytrader-0.1.0/easytrader/miniqmt/miniqmt_trader.py +653 -0
  28. frytrader-0.1.0/easytrader/native/bin/focus_guard32.dll +0 -0
  29. frytrader-0.1.0/easytrader/native/bin/focus_host32.exe +0 -0
  30. frytrader-0.1.0/easytrader/native/build.ps1 +38 -0
  31. frytrader-0.1.0/easytrader/native/focus_guard.c +23 -0
  32. frytrader-0.1.0/easytrader/native/focus_host.c +92 -0
  33. frytrader-0.1.0/easytrader/native/kernel32.def +18 -0
  34. frytrader-0.1.0/easytrader/native/user32.def +9 -0
  35. frytrader-0.1.0/easytrader/pop_dialog_handler.py +112 -0
  36. frytrader-0.1.0/easytrader/refresh_strategies.py +59 -0
  37. frytrader-0.1.0/easytrader/remoteclient.py +135 -0
  38. frytrader-0.1.0/easytrader/ricequant_follower.py +119 -0
  39. frytrader-0.1.0/easytrader/screenshot.py +409 -0
  40. frytrader-0.1.0/easytrader/server.py +135 -0
  41. frytrader-0.1.0/easytrader/universal_clienttrader.py +60 -0
  42. frytrader-0.1.0/easytrader/utils/__init__.py +1 -0
  43. frytrader-0.1.0/easytrader/utils/captcha.py +250 -0
  44. frytrader-0.1.0/easytrader/utils/misc.py +31 -0
  45. frytrader-0.1.0/easytrader/utils/perf.py +48 -0
  46. frytrader-0.1.0/easytrader/utils/stock.py +86 -0
  47. frytrader-0.1.0/easytrader/utils/win_gui.py +3 -0
  48. frytrader-0.1.0/easytrader/webtrader.py +245 -0
  49. frytrader-0.1.0/easytrader/wk_clienttrader.py +56 -0
  50. frytrader-0.1.0/easytrader/xq_follower.py +249 -0
  51. frytrader-0.1.0/easytrader/xqtrader.py +644 -0
  52. frytrader-0.1.0/easytrader/yh_clienttrader.py +129 -0
  53. frytrader-0.1.0/frytrader.egg-info/PKG-INFO +237 -0
  54. frytrader-0.1.0/frytrader.egg-info/SOURCES.txt +67 -0
  55. frytrader-0.1.0/frytrader.egg-info/dependency_links.txt +1 -0
  56. frytrader-0.1.0/frytrader.egg-info/requires.txt +37 -0
  57. frytrader-0.1.0/frytrader.egg-info/top_level.txt +1 -0
  58. frytrader-0.1.0/setup.cfg +4 -0
  59. frytrader-0.1.0/setup.py +70 -0
  60. frytrader-0.1.0/tests/test_background_focus.py +134 -0
  61. frytrader-0.1.0/tests/test_background_trader.py +357 -0
  62. frytrader-0.1.0/tests/test_background_windows.py +223 -0
  63. frytrader-0.1.0/tests/test_desktop_control.py +183 -0
  64. frytrader-0.1.0/tests/test_easytrader.py +182 -0
  65. frytrader-0.1.0/tests/test_grid_parsing.py +334 -0
  66. frytrader-0.1.0/tests/test_screenshot.py +677 -0
  67. frytrader-0.1.0/tests/test_trade_result.py +178 -0
  68. frytrader-0.1.0/tests/test_xq_follower.py +240 -0
  69. frytrader-0.1.0/tests/test_xqtrader.py +38 -0
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 shidenggui
4
+ Copyright (c) 2024-2026 Fryt1 (Frytrader fork)
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,3 @@
1
+ include README.md
2
+ recursive-include easytrader/config *.json *.ahk
3
+ recursive-include easytrader/native *.c *.def *.ps1 *.dll *.exe
@@ -0,0 +1,237 @@
1
+ Metadata-Version: 2.4
2
+ Name: frytrader
3
+ Version: 0.1.0
4
+ Summary: 中国券商 GUI 交易适配器,支持同花顺远航版后台只读模式。
5
+ Home-page: https://github.com/Fryt1/Frytrader
6
+ Author: Fryt1
7
+ License: MIT
8
+ Project-URL: Source, https://github.com/Fryt1/Frytrader
9
+ Project-URL: Tracker, https://github.com/Fryt1/Frytrader/issues
10
+ Project-URL: Upstream, https://github.com/shidenggui/easytrader
11
+ Keywords: china stock trade,easytrader,ths,同花顺
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Win32 (MS Windows)
14
+ Classifier: Intended Audience :: Financial and Insurance Industry
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: Microsoft :: Windows
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Topic :: Office/Business :: Financial :: Investment
19
+ Requires-Python: >=3.8
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: requests>=2.25.0
23
+ Requires-Dist: six>=1.15.0
24
+ Requires-Dist: easyutils>=0.1.7
25
+ Requires-Dist: flask>=1.1.0
26
+ Requires-Dist: pywinauto==0.6.6; sys_platform == "win32"
27
+ Requires-Dist: pillow>=8.0.0
28
+ Requires-Dist: pandas>=1.1.0
29
+ Requires-Dist: pytesseract>=0.3.7
30
+ Requires-Dist: beautifulsoup4>=4.9.0
31
+ Requires-Dist: bs4>=0.0.1
32
+ Requires-Dist: certifi>=2020.6.20
33
+ Requires-Dist: chardet>=3.0.4
34
+ Requires-Dist: click>=7.0
35
+ Requires-Dist: cssselect>=1.1.0
36
+ Requires-Dist: dill>=0.3.0
37
+ Requires-Dist: idna>=2.10
38
+ Requires-Dist: itsdangerous>=1.1.0
39
+ Requires-Dist: jinja2>=2.11.0
40
+ Requires-Dist: lxml>=4.6.0
41
+ Requires-Dist: markupsafe>=1.1.0
42
+ Requires-Dist: numpy>=1.19.0
43
+ Requires-Dist: pyperclip>=1.8.0
44
+ Requires-Dist: pyquery>=1.4.0
45
+ Requires-Dist: python-dateutil>=2.8.0
46
+ Requires-Dist: pytz>=2020.1
47
+ Requires-Dist: urllib3>=1.26.0
48
+ Requires-Dist: werkzeug>=1.0.0
49
+ Provides-Extra: miniqmt
50
+ Requires-Dist: xtquant; extra == "miniqmt"
51
+ Provides-Extra: background
52
+ Requires-Dist: pyvda<0.7,>=0.6.0; sys_platform == "win32" and extra == "background"
53
+ Dynamic: author
54
+ Dynamic: classifier
55
+ Dynamic: description
56
+ Dynamic: description-content-type
57
+ Dynamic: home-page
58
+ Dynamic: keywords
59
+ Dynamic: license
60
+ Dynamic: license-file
61
+ Dynamic: project-url
62
+ Dynamic: provides-extra
63
+ Dynamic: requires-dist
64
+ Dynamic: requires-python
65
+ Dynamic: summary
66
+
67
+ # Frytrader
68
+
69
+ [![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
70
+
71
+ 中国券商 GUI 交易适配器,支持同花顺远航版免打扰后台只读模式。
72
+
73
+ Frytrader 是 [EasyTrader](https://github.com/shidenggui/easytrader) 的 fork,在保留上游交易核心和 `import easytrader` 导入名的前提下,增强了验证码识别、表格导出和后台只读能力。发行包名为 `frytrader`,与 PyPI 上游的 `easytrader` 区分;Python 导入名仍为 `easytrader`,已有代码无需修改。
74
+
75
+ ## Table of Contents
76
+
77
+ - [安全](#安全)
78
+ - [背景](#背景)
79
+ - [安装](#安装)
80
+ - [用法](#用法)
81
+ - [API](#api)
82
+ - [配置](#配置)
83
+ - [测试](#测试)
84
+ - [维护者](#维护者)
85
+ - [致谢](#致谢)
86
+ - [贡献](#贡献)
87
+ - [许可证](#许可证)
88
+
89
+ ## 安全
90
+
91
+ **本库可以驱动真实券商客户端并提交真实委托。误用会造成资金损失。**
92
+
93
+ - 不要将账号、密码、验证码截图或其他凭证提交到 Git、Issue 或日志。
94
+ - 不要把交易服务暴露到公网。仓库内的 `easytrader/server.py` **无鉴权**且提供 `/buy`、`/sell`、`/cancel_entrust`,默认监听 `0.0.0.0`,不要直接对外运行。
95
+ - GUI 自动化会遇到弹窗、客户端升级、焦点丢失和结果不明。下单前必须自行验证委托状态,不能仅凭界面返回判断成功,**结果未知时不要盲目重试**。
96
+ - 本软件按 MIT 许可证「按原样」提供,不附带任何担保。交易决策和损失由使用者自行承担。
97
+
98
+ ## 背景
99
+
100
+ EasyTrader 提供多种券商 GUI、雪球和 MiniQMT 适配器。Frytrader 保留上游交易核心,并针对通用 Windows GUI 客户端做了三类增强:
101
+
102
+ 1. **验证码识别**:多图变体 OCR、按位投票,减少误识别。
103
+ 2. **表格导出**:修正空行丢弃、陈旧数据判断和失败诊断。
104
+ 3. **后台只读模式**:任务视图隔离 + 定向控件消息 + 线程激活保护,在不抢键盘、鼠标、前台和任务视图桌面的前提下读取资金、持仓、委托与成交。
105
+
106
+ 本项目不是券商原生 API。GUI 路线适合低频操作,不适合高频交易。MiniQMT 是可选的另一条路径,安装 Python 依赖不授予券商权限,也不会解除券商端限制。
107
+
108
+ ## 安装
109
+
110
+ 需要 Python 3.8 或更高。GUI 客户端自动化仅在 Windows 上可用。
111
+
112
+ 从 PyPI 安装:
113
+
114
+ ```console
115
+ $ pip install frytrader
116
+ ```
117
+
118
+ 从本仓库安装开发版:
119
+
120
+ ```console
121
+ $ git clone https://github.com/Fryt1/Frytrader.git
122
+ $ cd Frytrader
123
+ $ python -m venv .venv
124
+ $ .\.venv\Scripts\Activate.ps1
125
+ $ python -m pip install -e .
126
+ ```
127
+
128
+ 安装后台模式依赖:
129
+
130
+ ```console
131
+ $ python -m pip install -e ".[background]"
132
+ ```
133
+
134
+ 安装可选 MiniQMT 依赖:
135
+
136
+ ```console
137
+ $ python -m pip install -e ".[miniqmt]"
138
+ ```
139
+
140
+ 验证码识别需要另行安装 [Tesseract OCR](https://github.com/UB-Mannheim/tesseract/wiki),让 `tesseract.exe` 可从 `PATH` 访问,或在配置中指定路径。
141
+
142
+ 后台只读模式还需要 [AutoHotkey v2](https://www.autohotkey.com/)。程序按 `ahk_path` 参数 → `FRYTRADER_AHK` 环境变量 → `%LOCALAPPDATA%\Frytrader\runtime\AutoHotkey64.exe` → `PATH` → 常规安装目录依次查找,**不会在运行时自动下载或安装软件**。
143
+
144
+ ## 用法
145
+
146
+ 查询账户:
147
+
148
+ ```python
149
+ import easytrader
150
+
151
+ user = easytrader.use("universal_client")
152
+ user.prepare(config_path="config.json")
153
+
154
+ print(user.balance)
155
+ print(user.position)
156
+ ```
157
+
158
+ 同花顺远航版后台只读模式(不抢焦点):
159
+
160
+ ```python
161
+ import easytrader
162
+
163
+ user = easytrader.use("ths", background=True)
164
+ try:
165
+ user.connect() # 连接已登录的远航版,不启动新客户端
166
+ print(user.balance)
167
+ print(user.position)
168
+ print(user.today_entrusts)
169
+ print(user.today_trades)
170
+ finally:
171
+ user.close()
172
+ ```
173
+
174
+ 后台模式的用时数据来自本机登录态实测:公开接口连续两轮 8 次读取全部成功,零桌面和前台干扰。资金约 0.44 秒,三类表格 1.2–6.7 秒(取决于验证码重试次数)。详见 [`docs/background.md`](docs/background.md)。
175
+
176
+ **尚未验证**:非空持仓/委托/成交数据、长时间无人值守稳定性、非 x86 客户端、非 Windows 平台。
177
+
178
+ ## API
179
+
180
+ 入口为 `easytrader.use(broker)`。账户对象提供 `balance`、`position`、`today_entrusts`、`today_trades` 等查询属性,以及上游定义的 `buy`、`sell`、撤单等方法。
181
+
182
+ 支持的客户端类型和交易方法见 [`docs/usage.md`](docs/usage.md),MiniQMT 见 [`docs/miniqmt.md`](docs/miniqmt.md)。
183
+
184
+ 后台只读模式限制:
185
+
186
+ - `background=True` 仅支持 `ths`。传给其他适配器会抛 `NotImplementedError`,不会静默退回前台模式。
187
+ - 后台模式不继承下单能力,`buy`、`sell`、`cancel_entrust`、`prepare`、`login`、`auto_ipo` 等一律抛 `PermissionError`。
188
+ - 默认 `close()` 只停止后台执行器,不取消验证码、不搬回窗口。需要恢复窗口位置时显式调用 `user.restore_windows()`。
189
+
190
+ ## 配置
191
+
192
+ 复制 [`config.json.example`](config.json.example) 为 `config.json` 并填写账号、密码和客户端路径。`config.json` 已加入 `.gitignore`。
193
+
194
+ 验证码选项位于 `captcha` 对象:
195
+
196
+ - `mode`:`fast`、`balanced` 或 `accurate`
197
+ - `manual_input`:OCR 失败后是否等待手动输入;无人值守时应保持 `false`
198
+ - `save_debug_samples`:是否把样本保存到本地 `captcha_debug` 目录,默认关闭
199
+ - `tesseract_path`:Tesseract 可执行文件路径;`null` 表示使用系统 `PATH`
200
+
201
+ 这些选项只影响通用 GUI 客户端的 XLS 表格读取器,不改变券商端校验,也不赋予任何交易权限。
202
+
203
+ ## 测试
204
+
205
+ 运行离线测试(不连接真实账户):
206
+
207
+ ```console
208
+ $ python -m unittest discover -s tests -p "test_*.py"
209
+ ```
210
+
211
+ `tests/test_easytrader.py` 中的集成测试受 `EZ_TEST_CLIENTS` 环境变量控制,会连接真实账户。没有隔离测试账户时不要启用。不要把真实委托作为 CI 测试。
212
+
213
+ ## 维护者
214
+
215
+ [Fryt1](https://github.com/Fryt1)。问题请提交到 [Issues](https://github.com/Fryt1/Frytrader/issues)。
216
+
217
+ ## 致谢
218
+
219
+ 感谢 [shidenggui](https://github.com/shidenggui) 及 [EasyTrader](https://github.com/shidenggui/easytrader) 的所有贡献者提供上游项目和交易适配器。Frytrader 的发行基于其 MIT 许可证条款,原始版权声明保留在 [`LICENSE`](LICENSE) 中。
220
+
221
+ ## 贡献
222
+
223
+ 欢迎提交 Issue 和 Pull Request。提交前请:
224
+
225
+ 1. 说明使用的券商客户端版本和复现步骤。
226
+ 2. 移除日志、配置和截图中的账号、密码、资金等敏感信息。
227
+ 3. 涉及 GUI 或 OCR 的改动附带脱离真实账户的测试。
228
+
229
+ ### Contributors
230
+
231
+ <a href="https://github.com/Fryt1/Frytrader/graphs/contributors">
232
+ <img src="https://contrib.rocks/image?repo=Fryt1/Frytrader" alt="Contributors" />
233
+ </a>
234
+
235
+ ## 许可证
236
+
237
+ [MIT](LICENSE) © 2018 shidenggui, © 2024-2026 Fryt1。
@@ -0,0 +1,171 @@
1
+ # Frytrader
2
+
3
+ [![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
4
+
5
+ 中国券商 GUI 交易适配器,支持同花顺远航版免打扰后台只读模式。
6
+
7
+ Frytrader 是 [EasyTrader](https://github.com/shidenggui/easytrader) 的 fork,在保留上游交易核心和 `import easytrader` 导入名的前提下,增强了验证码识别、表格导出和后台只读能力。发行包名为 `frytrader`,与 PyPI 上游的 `easytrader` 区分;Python 导入名仍为 `easytrader`,已有代码无需修改。
8
+
9
+ ## Table of Contents
10
+
11
+ - [安全](#安全)
12
+ - [背景](#背景)
13
+ - [安装](#安装)
14
+ - [用法](#用法)
15
+ - [API](#api)
16
+ - [配置](#配置)
17
+ - [测试](#测试)
18
+ - [维护者](#维护者)
19
+ - [致谢](#致谢)
20
+ - [贡献](#贡献)
21
+ - [许可证](#许可证)
22
+
23
+ ## 安全
24
+
25
+ **本库可以驱动真实券商客户端并提交真实委托。误用会造成资金损失。**
26
+
27
+ - 不要将账号、密码、验证码截图或其他凭证提交到 Git、Issue 或日志。
28
+ - 不要把交易服务暴露到公网。仓库内的 `easytrader/server.py` **无鉴权**且提供 `/buy`、`/sell`、`/cancel_entrust`,默认监听 `0.0.0.0`,不要直接对外运行。
29
+ - GUI 自动化会遇到弹窗、客户端升级、焦点丢失和结果不明。下单前必须自行验证委托状态,不能仅凭界面返回判断成功,**结果未知时不要盲目重试**。
30
+ - 本软件按 MIT 许可证「按原样」提供,不附带任何担保。交易决策和损失由使用者自行承担。
31
+
32
+ ## 背景
33
+
34
+ EasyTrader 提供多种券商 GUI、雪球和 MiniQMT 适配器。Frytrader 保留上游交易核心,并针对通用 Windows GUI 客户端做了三类增强:
35
+
36
+ 1. **验证码识别**:多图变体 OCR、按位投票,减少误识别。
37
+ 2. **表格导出**:修正空行丢弃、陈旧数据判断和失败诊断。
38
+ 3. **后台只读模式**:任务视图隔离 + 定向控件消息 + 线程激活保护,在不抢键盘、鼠标、前台和任务视图桌面的前提下读取资金、持仓、委托与成交。
39
+
40
+ 本项目不是券商原生 API。GUI 路线适合低频操作,不适合高频交易。MiniQMT 是可选的另一条路径,安装 Python 依赖不授予券商权限,也不会解除券商端限制。
41
+
42
+ ## 安装
43
+
44
+ 需要 Python 3.8 或更高。GUI 客户端自动化仅在 Windows 上可用。
45
+
46
+ 从 PyPI 安装:
47
+
48
+ ```console
49
+ $ pip install frytrader
50
+ ```
51
+
52
+ 从本仓库安装开发版:
53
+
54
+ ```console
55
+ $ git clone https://github.com/Fryt1/Frytrader.git
56
+ $ cd Frytrader
57
+ $ python -m venv .venv
58
+ $ .\.venv\Scripts\Activate.ps1
59
+ $ python -m pip install -e .
60
+ ```
61
+
62
+ 安装后台模式依赖:
63
+
64
+ ```console
65
+ $ python -m pip install -e ".[background]"
66
+ ```
67
+
68
+ 安装可选 MiniQMT 依赖:
69
+
70
+ ```console
71
+ $ python -m pip install -e ".[miniqmt]"
72
+ ```
73
+
74
+ 验证码识别需要另行安装 [Tesseract OCR](https://github.com/UB-Mannheim/tesseract/wiki),让 `tesseract.exe` 可从 `PATH` 访问,或在配置中指定路径。
75
+
76
+ 后台只读模式还需要 [AutoHotkey v2](https://www.autohotkey.com/)。程序按 `ahk_path` 参数 → `FRYTRADER_AHK` 环境变量 → `%LOCALAPPDATA%\Frytrader\runtime\AutoHotkey64.exe` → `PATH` → 常规安装目录依次查找,**不会在运行时自动下载或安装软件**。
77
+
78
+ ## 用法
79
+
80
+ 查询账户:
81
+
82
+ ```python
83
+ import easytrader
84
+
85
+ user = easytrader.use("universal_client")
86
+ user.prepare(config_path="config.json")
87
+
88
+ print(user.balance)
89
+ print(user.position)
90
+ ```
91
+
92
+ 同花顺远航版后台只读模式(不抢焦点):
93
+
94
+ ```python
95
+ import easytrader
96
+
97
+ user = easytrader.use("ths", background=True)
98
+ try:
99
+ user.connect() # 连接已登录的远航版,不启动新客户端
100
+ print(user.balance)
101
+ print(user.position)
102
+ print(user.today_entrusts)
103
+ print(user.today_trades)
104
+ finally:
105
+ user.close()
106
+ ```
107
+
108
+ 后台模式的用时数据来自本机登录态实测:公开接口连续两轮 8 次读取全部成功,零桌面和前台干扰。资金约 0.44 秒,三类表格 1.2–6.7 秒(取决于验证码重试次数)。详见 [`docs/background.md`](docs/background.md)。
109
+
110
+ **尚未验证**:非空持仓/委托/成交数据、长时间无人值守稳定性、非 x86 客户端、非 Windows 平台。
111
+
112
+ ## API
113
+
114
+ 入口为 `easytrader.use(broker)`。账户对象提供 `balance`、`position`、`today_entrusts`、`today_trades` 等查询属性,以及上游定义的 `buy`、`sell`、撤单等方法。
115
+
116
+ 支持的客户端类型和交易方法见 [`docs/usage.md`](docs/usage.md),MiniQMT 见 [`docs/miniqmt.md`](docs/miniqmt.md)。
117
+
118
+ 后台只读模式限制:
119
+
120
+ - `background=True` 仅支持 `ths`。传给其他适配器会抛 `NotImplementedError`,不会静默退回前台模式。
121
+ - 后台模式不继承下单能力,`buy`、`sell`、`cancel_entrust`、`prepare`、`login`、`auto_ipo` 等一律抛 `PermissionError`。
122
+ - 默认 `close()` 只停止后台执行器,不取消验证码、不搬回窗口。需要恢复窗口位置时显式调用 `user.restore_windows()`。
123
+
124
+ ## 配置
125
+
126
+ 复制 [`config.json.example`](config.json.example) 为 `config.json` 并填写账号、密码和客户端路径。`config.json` 已加入 `.gitignore`。
127
+
128
+ 验证码选项位于 `captcha` 对象:
129
+
130
+ - `mode`:`fast`、`balanced` 或 `accurate`
131
+ - `manual_input`:OCR 失败后是否等待手动输入;无人值守时应保持 `false`
132
+ - `save_debug_samples`:是否把样本保存到本地 `captcha_debug` 目录,默认关闭
133
+ - `tesseract_path`:Tesseract 可执行文件路径;`null` 表示使用系统 `PATH`
134
+
135
+ 这些选项只影响通用 GUI 客户端的 XLS 表格读取器,不改变券商端校验,也不赋予任何交易权限。
136
+
137
+ ## 测试
138
+
139
+ 运行离线测试(不连接真实账户):
140
+
141
+ ```console
142
+ $ python -m unittest discover -s tests -p "test_*.py"
143
+ ```
144
+
145
+ `tests/test_easytrader.py` 中的集成测试受 `EZ_TEST_CLIENTS` 环境变量控制,会连接真实账户。没有隔离测试账户时不要启用。不要把真实委托作为 CI 测试。
146
+
147
+ ## 维护者
148
+
149
+ [Fryt1](https://github.com/Fryt1)。问题请提交到 [Issues](https://github.com/Fryt1/Frytrader/issues)。
150
+
151
+ ## 致谢
152
+
153
+ 感谢 [shidenggui](https://github.com/shidenggui) 及 [EasyTrader](https://github.com/shidenggui/easytrader) 的所有贡献者提供上游项目和交易适配器。Frytrader 的发行基于其 MIT 许可证条款,原始版权声明保留在 [`LICENSE`](LICENSE) 中。
154
+
155
+ ## 贡献
156
+
157
+ 欢迎提交 Issue 和 Pull Request。提交前请:
158
+
159
+ 1. 说明使用的券商客户端版本和复现步骤。
160
+ 2. 移除日志、配置和截图中的账号、密码、资金等敏感信息。
161
+ 3. 涉及 GUI 或 OCR 的改动附带脱离真实账户的测试。
162
+
163
+ ### Contributors
164
+
165
+ <a href="https://github.com/Fryt1/Frytrader/graphs/contributors">
166
+ <img src="https://contrib.rocks/image?repo=Fryt1/Frytrader" alt="Contributors" />
167
+ </a>
168
+
169
+ ## 许可证
170
+
171
+ [MIT](LICENSE) © 2018 shidenggui, © 2024-2026 Fryt1。
@@ -0,0 +1,11 @@
1
+ # -*- coding: utf-8 -*-
2
+ import urllib3
3
+
4
+ from easytrader import exceptions
5
+ from easytrader.api import use, follower
6
+ from easytrader.log import logger
7
+
8
+ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
9
+
10
+ __version__ = "0.1.0"
11
+ __author__ = "shidenggui, Fryt1"
@@ -0,0 +1,128 @@
1
+ # -*- coding: utf-8 -*-
2
+ import logging
3
+ import sys
4
+
5
+ import six
6
+
7
+ from easytrader.joinquant_follower import JoinQuantFollower
8
+ from easytrader.log import logger
9
+ from easytrader.ricequant_follower import RiceQuantFollower
10
+ from easytrader.xq_follower import XueQiuFollower
11
+ from easytrader.xqtrader import XueQiuTrader
12
+
13
+ if sys.version_info <= (3, 5):
14
+ raise TypeError("不支持 Python3.5 及以下版本,请升级")
15
+
16
+
17
+ def use(broker, debug=False, **kwargs):
18
+ """用于生成特定的券商对象
19
+ :param broker: 券商名支持
20
+ 例如 ['miniqmt', 'xq', '雪球', 'gj_client', '国金客户端', "universal_client", "通用同花顺客户端", "ths", "同花顺客户端"] 等
21
+ :param debug: 控制 debug 日志的显示, 默认为 False
22
+ :param initial_assets: [雪球参数] 控制雪球初始资金,默认为一百万
23
+ :return the class of trader
24
+
25
+ Usage::
26
+
27
+ >>> import easytrader
28
+ >>> user = easytrader.use('xq')
29
+ >>> user.prepare('xq.json')
30
+ """
31
+ if "background" in kwargs:
32
+ if not isinstance(kwargs["background"], bool):
33
+ raise TypeError("background 必须是布尔值")
34
+ if kwargs["background"] and broker.lower() not in (
35
+ "ths", "同花顺客户端"
36
+ ):
37
+ raise NotImplementedError("后台只读模式仅支持 ths 远航版")
38
+
39
+ if debug:
40
+ logger.setLevel(logging.DEBUG)
41
+
42
+ if broker.lower() in ["xq", "雪球"]:
43
+ return XueQiuTrader(**kwargs)
44
+
45
+ if broker.lower() in ["yh_client", "银河客户端"]:
46
+ from .yh_clienttrader import YHClientTrader
47
+
48
+ return YHClientTrader()
49
+
50
+ if broker.lower() in ["ht_client", "华泰客户端"]:
51
+ from .ht_clienttrader import HTClientTrader
52
+
53
+ return HTClientTrader()
54
+
55
+ if broker.lower() in ["wk_client", "五矿客户端"]:
56
+ from easytrader.wk_clienttrader import WKClientTrader
57
+
58
+ return WKClientTrader()
59
+
60
+ if broker.lower() in ["htzq_client", "海通证券客户端"]:
61
+ from easytrader.htzq_clienttrader import HTZQClientTrader
62
+
63
+ return HTZQClientTrader()
64
+
65
+ if broker.lower() in ["gj_client", "国金客户端"]:
66
+ from .gj_clienttrader import GJClientTrader
67
+
68
+ return GJClientTrader()
69
+
70
+ if broker.lower() in ["gf_client", "广发客户端"]:
71
+ from .gf_clienttrader import GFClientTrader
72
+
73
+ return GFClientTrader()
74
+
75
+ if broker.lower() in ["universal_client", "通用同花顺客户端"]:
76
+ from easytrader.universal_clienttrader import UniversalClientTrader
77
+
78
+ return UniversalClientTrader()
79
+
80
+ if broker.lower() in ["ths", "同花顺客户端"]:
81
+ background = kwargs.pop("background", False)
82
+ if not isinstance(background, bool):
83
+ raise TypeError("background 必须是布尔值")
84
+ if background:
85
+ from .background_trader import BackgroundThsTrader
86
+
87
+ return BackgroundThsTrader(**kwargs)
88
+ from .clienttrader import ClientTrader
89
+
90
+ return ClientTrader()
91
+
92
+ if broker.lower() in ["miniqmt"]:
93
+ try:
94
+ import xtquant
95
+ except:
96
+ logger.error("miniqmt 相关组件 xtqimt 未安装, 请执行 pip install easytrader[xtquant]安装")
97
+ from easytrader.miniqmt.miniqmt_trader import MiniqmtTrader
98
+
99
+ return MiniqmtTrader()
100
+
101
+ raise NotImplementedError
102
+
103
+
104
+ def follower(platform, **kwargs):
105
+ """用于生成特定的券商对象
106
+ :param platform:平台支持 ['jq', 'joinquant', '聚宽’]
107
+ :param initial_assets: [雪球参数] 控制雪球初始资金,默认为一万,
108
+ 总资金由 initial_assets * 组合当前净值 得出
109
+ :param total_assets: [雪球参数] 控制雪球总资金,无默认值,
110
+ 若设置则覆盖 initial_assets
111
+ :return the class of follower
112
+
113
+ Usage::
114
+
115
+ >>> import easytrader
116
+ >>> user = easytrader.use('xq')
117
+ >>> user.prepare('xq.json')
118
+ >>> jq = easytrader.follower('jq')
119
+ >>> jq.login(user='username', password='password')
120
+ >>> jq.follow(users=user, strategies=['strategies_link'])
121
+ """
122
+ if platform.lower() in ["rq", "ricequant", "米筐"]:
123
+ return RiceQuantFollower()
124
+ if platform.lower() in ["jq", "joinquant", "聚宽"]:
125
+ return JoinQuantFollower()
126
+ if platform.lower() in ["xq", "xueqiu", "雪球"]:
127
+ return XueQiuFollower(**kwargs)
128
+ raise NotImplementedError