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.
- frytrader-0.1.0/LICENSE +22 -0
- frytrader-0.1.0/MANIFEST.in +3 -0
- frytrader-0.1.0/PKG-INFO +237 -0
- frytrader-0.1.0/README.md +171 -0
- frytrader-0.1.0/easytrader/__init__.py +11 -0
- frytrader-0.1.0/easytrader/api.py +128 -0
- frytrader-0.1.0/easytrader/background_focus.py +147 -0
- frytrader-0.1.0/easytrader/background_runtime.py +133 -0
- frytrader-0.1.0/easytrader/background_trader.py +542 -0
- frytrader-0.1.0/easytrader/background_windows.py +1115 -0
- frytrader-0.1.0/easytrader/clienttrader.py +684 -0
- frytrader-0.1.0/easytrader/config/__init__.py +0 -0
- frytrader-0.1.0/easytrader/config/background_controls.ahk +52 -0
- frytrader-0.1.0/easytrader/config/client.py +193 -0
- frytrader-0.1.0/easytrader/config/global.json +52 -0
- frytrader-0.1.0/easytrader/config/xq.json +11 -0
- frytrader-0.1.0/easytrader/exceptions.py +11 -0
- frytrader-0.1.0/easytrader/follower.py +408 -0
- frytrader-0.1.0/easytrader/gf_clienttrader.py +84 -0
- frytrader-0.1.0/easytrader/gj_clienttrader.py +80 -0
- frytrader-0.1.0/easytrader/grid_strategies.py +845 -0
- frytrader-0.1.0/easytrader/ht_clienttrader.py +76 -0
- frytrader-0.1.0/easytrader/htzq_clienttrader.py +61 -0
- frytrader-0.1.0/easytrader/joinquant_follower.py +140 -0
- frytrader-0.1.0/easytrader/log.py +14 -0
- frytrader-0.1.0/easytrader/miniqmt/__init__.py +1 -0
- frytrader-0.1.0/easytrader/miniqmt/miniqmt_trader.py +653 -0
- frytrader-0.1.0/easytrader/native/bin/focus_guard32.dll +0 -0
- frytrader-0.1.0/easytrader/native/bin/focus_host32.exe +0 -0
- frytrader-0.1.0/easytrader/native/build.ps1 +38 -0
- frytrader-0.1.0/easytrader/native/focus_guard.c +23 -0
- frytrader-0.1.0/easytrader/native/focus_host.c +92 -0
- frytrader-0.1.0/easytrader/native/kernel32.def +18 -0
- frytrader-0.1.0/easytrader/native/user32.def +9 -0
- frytrader-0.1.0/easytrader/pop_dialog_handler.py +112 -0
- frytrader-0.1.0/easytrader/refresh_strategies.py +59 -0
- frytrader-0.1.0/easytrader/remoteclient.py +135 -0
- frytrader-0.1.0/easytrader/ricequant_follower.py +119 -0
- frytrader-0.1.0/easytrader/screenshot.py +409 -0
- frytrader-0.1.0/easytrader/server.py +135 -0
- frytrader-0.1.0/easytrader/universal_clienttrader.py +60 -0
- frytrader-0.1.0/easytrader/utils/__init__.py +1 -0
- frytrader-0.1.0/easytrader/utils/captcha.py +250 -0
- frytrader-0.1.0/easytrader/utils/misc.py +31 -0
- frytrader-0.1.0/easytrader/utils/perf.py +48 -0
- frytrader-0.1.0/easytrader/utils/stock.py +86 -0
- frytrader-0.1.0/easytrader/utils/win_gui.py +3 -0
- frytrader-0.1.0/easytrader/webtrader.py +245 -0
- frytrader-0.1.0/easytrader/wk_clienttrader.py +56 -0
- frytrader-0.1.0/easytrader/xq_follower.py +249 -0
- frytrader-0.1.0/easytrader/xqtrader.py +644 -0
- frytrader-0.1.0/easytrader/yh_clienttrader.py +129 -0
- frytrader-0.1.0/frytrader.egg-info/PKG-INFO +237 -0
- frytrader-0.1.0/frytrader.egg-info/SOURCES.txt +67 -0
- frytrader-0.1.0/frytrader.egg-info/dependency_links.txt +1 -0
- frytrader-0.1.0/frytrader.egg-info/requires.txt +37 -0
- frytrader-0.1.0/frytrader.egg-info/top_level.txt +1 -0
- frytrader-0.1.0/setup.cfg +4 -0
- frytrader-0.1.0/setup.py +70 -0
- frytrader-0.1.0/tests/test_background_focus.py +134 -0
- frytrader-0.1.0/tests/test_background_trader.py +357 -0
- frytrader-0.1.0/tests/test_background_windows.py +223 -0
- frytrader-0.1.0/tests/test_desktop_control.py +183 -0
- frytrader-0.1.0/tests/test_easytrader.py +182 -0
- frytrader-0.1.0/tests/test_grid_parsing.py +334 -0
- frytrader-0.1.0/tests/test_screenshot.py +677 -0
- frytrader-0.1.0/tests/test_trade_result.py +178 -0
- frytrader-0.1.0/tests/test_xq_follower.py +240 -0
- frytrader-0.1.0/tests/test_xqtrader.py +38 -0
frytrader-0.1.0/LICENSE
ADDED
|
@@ -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.
|
frytrader-0.1.0/PKG-INFO
ADDED
|
@@ -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
|
+
[](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
|
+
[](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
|