散户如何实现自动化交易下单——篇1:体系介绍与获取同花顺资金账户和持仓信息
一、为什么要实现自动化交易
在瞬息万变的金融市场中,越来越多的散户投资者开始尝试构建自己的交易策略:有人通过技术指标捕捉趋势突破,有人利用基本面分析挖掘低估标的,还有人设计出复杂的网格交易或均值回归模型。然而,一个残酷的现实是——90%以上的个人策略最终因“执行脱节”而失效。
也许你会说我可以手动下单进行交易,作者本人亲自实验表明手动交易会有很多意想不到的情况出现。
-
1.时间与精力冲突
许多短线策略需要全天候盯盘(如分时均线突破、盘口挂单监测),但散户难以像职业交易员一样保持高强度专注。一位投资者曾自嘲:“凌晨三点起床盯外盘,结果白天上班时错过A股最佳卖点,策略再好也成了纸上谈兵。” -
2.人性的弱点:情绪化操作
即使策略逻辑清晰,手动执行时仍可能因恐惧(过早止损)、贪婪(延迟止盈)或从众心理(跟风追涨)而偏离计划。数据显示,超过70%的投资者承认曾在关键节点因情绪干扰做出错误决策。 -
3.复杂策略的“执行悖论”
高频调仓、多品种联动、动态止盈止损等操作对人工执行近乎苛刻。例如,一个简单的“股债动态平衡策略”需每月按比例调整持仓,但手动计算并下单极易出错;又如网格交易需在数百个价格档位挂单,人力根本无法完成。
而目前市面上并没有特别成熟且门槛低的工具可以帮我们实现各种复杂的自动化交易需求。尽管部分券商提供“条件单”功能,但其仅支持价格触发、定时交易等基础场景,无法适配个性化策略(如结合量价背离与新闻情绪分析的综合模型);而专业量化平台(如QMT)的高资金门槛和编程要求,又将普通投资者拒之门外。
对于散户而言,找到一种低门槛、高适配性、稳定可靠的自动化工具,意味着真正从“纸上谈兵”迈入“实战盈利”的质变——这不仅是效率的提升,更是投资认知的升维。
二、现有实现方法介绍
1.界面自动化工具(如pywinauto操作同花顺) 本系列教程将实现!
实现逻辑:通过模拟人工操作(点击、输入)控制交易软件界面。例如,用Python的pywinauto
库识别同花顺窗口控件,自动填写价格、数量并触发下单。
优势有,
-
低门槛:无需券商特殊权限,依赖现有交易软件即可实现。
-
灵活性:可适配多种交易软件(如同花顺、通达信、东方财富)
劣势有,
-
延迟风险:依赖本地软件运行,网络或硬件故障可能中断交易。
-
功能受限:无法实现高频交易或复杂策略的动态调整。
2.券商量化终端(如QMT、Ptrade) 本系列教程将实现!
实现逻辑:使用券商提供的专业量化平台(如中金QMT),通过内置API或策略编辑器编写交易逻辑,直接对接交易所系统执行订单。
优势有,
-
极速交易:支持高频操作,延迟低至毫秒级。
-
策略多样性:内置网格交易、算法拆单等模板,支持Python/Lua编程扩展。
-
风控完善:提供持仓监控、异常熔断等机制。
劣势有,
-
学习成本:需掌握量化框架及编程语言。
-
准入门槛高:通常需满足资金量要求(如QMT面向机构或高净值客户)。开通指南→
3. 同花顺内置条件单/策略交易 很简单也不实用,就不实现了~
实现逻辑:在同花顺软件中预设触发条件(如价格突破、定时交易),由本地或云端服务器监控并执行。
优势有,
-
无需编程:图形化界面操作,适合非技术用户。
-
基础功能免费:支持止盈止损、网格交易等常见策略。
劣势有,
-
功能局限:仅支持简单条件触发,无法自定义复杂逻辑。
三、进入本篇正题:如何通过pywinauto操作同花顺
首先是,前期准备工作:
环境搭建
-
1.安装Python环境(推荐Python 3.8+),配置好pip包管理工具。安装
pywinauto
库。 -
同花顺客户端配置
-
Inspect.exe(Windows SDK自带):用于查看窗口控件的属性(如类名、自动化ID)。
-
Spy++(Visual Studio工具):分析窗口层级结构。
-
2.安装辅助工具:
-
-
确保同花顺客户端为最新版本,避免因界面更新导致脚本失效。
-
登录账户并熟悉手动下单流程,明确需要自动化的操作步骤(如买入、卖出、撤单)。
-
关闭不必要的弹窗或提示(如风险提示),减少自动化干扰。
测试账户准备
-
强烈建议使用模拟账户,避免因脚本错误造成真实资金损失。
接着,明确需要学习的核心知识(如果你真想学会下面的每一个步骤都要亲自去学习尝试,遇到问题请问ai或查资料):
第一部分 pywinauto基础操作
-
连接应用程序
可以通过进程ID或窗口标题或者软件安装地址绑定同花顺客户端:
from pywinauto import Application
app = Application().connect(r'C:\APPS\同花顺软件\同花顺\xiadan.exe') # 根据实际窗口标题修改
注意这个界面才是下单界面,不是行情展示的界面窗口。
-
窗口与控件识别
-
使用
Inspect.exe(点击查看这是什么东西)
定位目标控件属性(如class_name
、automation_id
、name
)。 -
通过层级结构定位控件:
main_window = app.window(title="同花顺")
buy_button = main_window.child_window(title="买入", control_type="Button")
-
模拟操作
输入文本:edit_box.set_text("100")
点击按钮:button.click()
快捷键操作:type_keys("%s")
第二部分 同花顺界面结构分析
-
关键窗口与控件
登录窗口:账号输入框、密码输入框、验证码区域、登录按钮。
交易界面:股票代码输入框、买入/卖出选项卡、价格/数量输入框、下单按钮。
弹窗处理:确认对话框、错误提示框(如“价格超出涨跌幅限制”)。
动态控件应对
部分控件(如持仓列表)可能随数据变化刷新,需通过
wait
方法等待控件就绪:
buy_button.wait("exists", timeout=10).click() # 等待10秒直至控件出现
第三部分 同花顺界面中需要输入二维码情况的解决
-
Tesseract工具的使用(点击查看安装教程)
在操作账户的时候有时候会跳出输入“图形验证码”窗口,上面显示一些不规则(字符稍加扭曲变换得到的)的字符。tesseract-ocr(Optical Character Recognition)能够扫描字符,根据字符形状将其翻译成电子文本的过程。因此需要安装tesseract-ocr自动识别验证码。在Python中的额使用大概是这样:
def captcha_recognize(img_path):
import pytesseract
from PIL import Image
im = Image.open(img_path).convert("L")
# 1. threshold the image
threshold = 200
table = []
for i in range(256):
if i < threshold:
table.append(0)
else:
table.append(1)
out = im.point(table, "1")
# 2. recognize with tesseract
num = pytesseract.image_to_string(out)
return num
第四部分 异常处理与稳定性优化
-
网络延迟容错
添加重试机制,应对因网络卡顿导致的控件加载失败:
from pywinauto.timings import TimeoutError
try:
buy_button.click()
except TimeoutError:
print("控件未找到,尝试重新定位...")
-
日志记录
记录操作过程和错误信息,便于后期排查:
import logging
logging.basicConfig(filename="trade.log", level=logging.INFO)
-
防重复点击
通过状态标记避免因脚本卡顿导致的重复下单:
if not is_order_submitted:
submit_button.click()
is_order_submitted = True
接着,我们以获取当前账户的资金状况和持仓状况为例(在交易中实时获取这个两个信息是十分必要的),来进行一个实践。
注:代码逻辑参考于easytrader,下面的函数都是从相关的类中抽取出来的,所以会带有self.
首先我们看到,资金账户信息需要再在左边菜单栏切换到【查询F4】【资金股票】栏目后的右边展示,因此我们要先进行栏目的选择切换并获取右边的信息。
@property
def balance(self):
self._switch_left_menus(["查询[F4]", "资金股票"])
return self._get_balance_from_statics()
@perf_clock
def _switch_left_menus(self, path, sleep=0.2):
self.close_pop_dialog()
self._get_left_menus_handle().get_item(path).select()
self._app.top_window().type_keys('{F5}')
self.wait(sleep)
@perf_clock
def close_pop_dialog(self):
try:
if self._main.wrapper_object() != self._app.top_window().wrapper_object():
w = self._app.top_window()
if w is not None:
w.close()
self.wait(0.2)
except (
findwindows.ElementNotFoundError,
timings.TimeoutError,
RuntimeError,
) as ex:
pass
@functools.lru_cache()
def _get_left_menus_handle(self):
count = 2
while True:
try:
handle = self._main.child_window(
control_id=129, class_name="SysTreeView32"
)
if count <= 0:
return handle
# sometime can't find handle ready, must retry
handle.wait("ready", 2)
return handle
# pylint: disable=broad-except
except Exception as ex:
logger.exception("error occurred when trying to get left menus")
count = count - 1
随后我们要从右边保存信息,由上面第五行的_get_balance_from_statics()函数实现,_config中的信息是对应所需元素的contro_id.
def _get_balance_from_statics(self):
result = {}
for key, control_id in self._config.BALANCE_CONTROL_ID_GROUP.items():
result[key] = float(
self._main.child_window(
control_id=control_id, class_name="Static"
).window_text()
)
return result
BALANCE_CONTROL_ID_GROUP = {
"资金余额": 1012,
"可用金额": 1016,
"可取金额": 1017,
"总资产": 1015,
}
具体应用方式:
import easytrader
user = easytrader.use('universal_client')
user.enable_type_keys_for_editor()
user.connect(r'C:\APPS\同花顺软件\同花顺\xiadan.exe')
user.enable_type_keys_for_editor()
user.balance#获取资金账户信息
结果:
以上就获取到了balance信息,接下来获取position持仓信息,由于同花顺在这部分设置了验证码机制,所以这里我们要加上验证码截图、验证码识别和验证码输入的部分。方法是通过pytesseract
调用Tesseract引擎进行识别。
不同于上面的获取资金账户的信息,上面的账户信息直接就显示在控件中,因此获取到控件后可以直接得到想要的信息,但资金账户这个界面的信息是放在了一个grid中,获取的方式有两种,一是直接复制并从剪切板中获取信息,一种是邮件保存为文件再从文件中读取,第二种方式的稳定性更高,并且可以实现多次读取,因此讲解第二种方式的获取方法。请逐层函数的去看就
@property
def position(self):
self._switch_left_menus(["查询[F4]", "资金股票"])
return self._get_grid_data(self._config.COMMON_GRID_CONTROL_ID)
@perf_clock
def _switch_left_menus(self, path, sleep=0.2):
self.close_pop_dialog()
self._get_left_menus_handle().get_item(path).select()
self._app.top_window().type_keys('{F5}')
self.wait(sleep)
def _get_grid_data(self, control_id):
return self.grid_strategy_instance.get(control_id)
def get(self, control_id: int) -> List[Dict]:
grid = self._get_grid(control_id)
# ctrl+s 保存 grid 内容为 xls 文件
self._set_foreground(grid) # setFocus buggy, instead of SetForegroundWindow
grid.type_keys("^s", set_foreground=False)
if self._trader.is_exist_pop_dialog():
count = 5
while count > 0:
if (
self._trader.app.top_window().child_window(class_name="Static", title='提示').exists(timeout=1)
):
file_path = "tmp.png"
found = False
self._trader.app.top_window().child_window(class_name='Static',title ='')\
.capture_as_image().save(
file_path
) # 保存验证码
captcha_num = captcha_recognize(file_path).strip() # 识别验证码
captcha_num = "".join(captcha_num.split())
logger.info("captcha result-->" + captcha_num)
self._trader.app.top_window().child_window(
class_name="Edit",control_id=2404
).set_text(
""
)#删除原有的值
self._trader.app.top_window().child_window(
class_name="Edit",control_id=2404
).type_keys(
captcha_num
) # 模拟输入验证码
self._trader.app.top_window()\
.child_window(class_name="Button", title='确定').click()
# pywinauto.keyboard.send_keys("{ENTER}") # 模拟发送enter,点击确定
if self._trader.app.window(class_name="#32770", title='另存为').exists(timeout=2):
logger.info("验证码正确:" + captcha_num)
found = True
count = -1
else:
count = count - 1
if not found and count==0:
break
else:
Copy._need_captcha_reg = False
break
self._trader.wait(0.2)
if(count<=0 and (not found)):
self._trader.app.top_window()\
.child_window(class_name="Button", title='取消').click()
return self.get(control_id)
self._trader.wait(0.5)
temp_path = tempfile.mktemp(suffix=".xls", dir=self.tmp_folder)
self._set_foreground(self._trader.app.top_window())
# alt+s保存,alt+y替换已存在的文件
self._trader.app.top_window()['Edit1'].set_text(temp_path)
self._trader.wait(0.1)
self._trader.app.top_window().type_keys("%{s}%{y}", set_foreground=False)
# Wait until file save complete otherwise pandas can not find file
self._trader.wait(0.2)
if self._trader.is_exist_pop_dialog():
self._trader.app.top_window().Button2.click()
self._trader.wait(0.2)
return self._format_grid_data(temp_path)
def _format_grid_data(self, data: str) -> List[Dict]:
with open(data, encoding="gbk", errors="replace") as f:
content = f.read()
df = pd.read_csv(
StringIO(content),
delimiter="\t",
dtype=self._trader.config.GRID_DTYPE,
na_filter=False,
)
return df.to_dict("records")
具体应用:
import easytrader
user = easytrader.use('universal_client')
user.enable_type_keys_for_editor()
user.connect(r'C:\APPS\同花顺软件\同花顺\xiadan.exe')
user.enable_type_keys_for_editor()
user.position#获取持仓信息
结果:
代码自动识别窗口并识别验证码后填入保存信息
相关文章:

散户如何实现自动化交易下单——篇1:体系介绍与获取同花顺资金账户和持仓信息
一、为什么要实现自动化交易 在瞬息万变的金融市场中,越来越多的散户投资者开始尝试构建自己的交易策略:有人通过技术指标捕捉趋势突破,有人利用基本面分析挖掘低估标的,还有人设计出复杂的网格交易或均值回归模型。然而&a…...

基于Electron的应用程序安全测试基础 — 提取和分析.asar文件的案例研究
目录: 4.4. 案例研究 4.4.2. 情况描述 4.4.3. 信息收集 4.4.3.2. 检查隐藏目录(点目录)的可能性 4.4.3.3. 使用 DB Browser for SQLite 打开 .db 文件 4.4.3.4. 寻找加密算法 4.4.3.5. 找到加密算法 4.4.3.6. 理解加密流程 4.4.3.7. 找到“Ke…...
vue中computed方法使用;computed返回函数
文章目录 1.正常使用computed2.使用computed返回可传参的函数 1.正常使用computed 一般我们使用computed返回一个变量字段,这个字段会根据具体的某个变量计算得到 例如 <div>{{num}}--{{num10}}</div>let num ref(1) let num10 computed(()>{ret…...
大语言模型的评测
大语言模型评测是评估这些模型在各种任务和场景下的性能和能力的过程。 能力 1. 基准测试(Benchmarking) GLUE(General Language Understanding Evaluation):包含多个自然语言处理任务,如文本分类、情感分…...

【Vue3】浅谈setup语法糖
Vue3 的 setup 语法糖是通过 <script setup> 标签启用的特性,它是对 Composition API 的进一步封装,旨在简化组件的声明式写法,同时保留 Composition API 的逻辑组织能力。以下是其核心概念和原理分析: 一、<script setu…...

EasyRTC嵌入式WebRTC技术与AI大模型结合:从ICE框架优化到AI推理
实时通信技术在现代社会中扮演着越来越重要的角色,从视频会议到在线教育,再到远程医疗,其应用场景不断拓展。WebRTC作为一项开源项目,为浏览器和移动应用提供了便捷的实时通信能力。而EasyRTC作为基于WebRTC的嵌入式解决方案&…...
如何管理路由器
一、管理路由器的必要性 1、需要修改拨号上网的密码。 2、需要修改WIFI的SSID名字和密码。 3、设置DHCP协议信息。 4、设置IP地址的过滤规则。 5、给某个设备连接设置网络限速。 二、常见的方式 (一)web网页方式 1、计算机用双绞线或者WIFI的方式连接路由器。 2、在计算机中打开…...

【NTN 卫星通信】低轨卫星通信需要解决的关键问题
1 低轨卫星通信需要考虑的关键问题 3GPP在开始阶段对低轨卫星通信需要面对的关键问题对架构的影响进行了探讨,主要在协议23.737中,我们来看看有哪些内容吧。 2 关键问题讨论 2.1 大型卫星覆盖区域的移动性管理 PLMN的覆盖区域受到HPLMN母国监管机构的限…...
DOM HTML:深入理解与高效运用
DOM HTML:深入理解与高效运用 引言 随着互联网的飞速发展,前端技术逐渐成为软件开发中的关键部分。DOM(文档对象模型)和HTML(超文本标记语言)是前端开发中的基石。本文将深入探讨DOM和HTML的概念、特性以及在实际开发中的应用,帮助读者更好地理解和使用这两项技术。 …...
如何进行OceanBase 运维工具的部署和表性能优化
本文来自OceanBase 用户的实践分享 随着OceanBase数据库应用的日益深入,数据量不断攀升,单个表中存储数百万乃至数千万条数据的情况变得愈发普遍。因此,部署专门的运维工具、实施针对性的表性能优化策略,以及加强指标监测工作&…...

docker简介-学习与参考
docker Docker 是一个开源的应用容器引擎,基于 Go 语言并遵从 Apache2.0 协议开源。 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。 容器是完全使用沙箱…...
AcWing 蓝桥杯集训·每日一题2025·密接牛追踪2
密接牛追踪2 农夫约翰有 N 头奶牛排成一排,从左到右依次编号为 1∼N。 不幸的是,有一种传染病正在蔓延。 最开始时,只有一部分奶牛受到感染。 每经过一个晚上,受感染的牛就会将病毒传染给它左右两侧的牛(如果有的话…...
LeetCode 每日一题 2025/2/24-2025/3/2
记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步 目录 2/24 1656. 设计有序流2/25 2502. 设计内存分配器2/26 1472. 设计浏览器历史记录2/27 2296. 设计一个文本编辑器2/28 2353. 设计食物评分系统3/1 131. 分割回文串3/2 132. …...

TeX Live 2025 最新版安装与中文环境配置全教程(Windows/Mac/Linux)
一、软件定位与特性 TeX Live 是由国际TeX用户组(TUG)维护的跨平台专业排版系统,支持LaTeX、XeLaTeX等多种排版引擎,广泛应用于学术论文、书籍出版等领域。2025版核心升级: 智能编译:自动检测编码错误并提…...

Android实现漂亮的波纹动画
Android实现漂亮的波纹动画 本文章讲述如何使用二维画布canvas和camera、矩阵实现二、三维波纹动画效果(波纹大小变化、画笔透明度变化、画笔粗细变化) 一、UI界面 界面主要分为三部分 第一部分:输入框,根据输入x轴、Y轴、Z轴倾…...
JAVA学习笔记038——bean的概念和常见注解标注
什么是bean? Bean 就是 被 Spring 管理的对象,就像工厂流水线上生产的“标准产品”。这些对象不是你自己 new 出来的,而是由 Spring 容器(一个超级工厂)帮你创建、组装、管理。 由 Component、Service、Controller 等注解标记的…...
自然语言处理NLP入门 -- 第十节NLP 实战项目 2: 简单的聊天机器人
一、为什么要做聊天机器人? 在互联网时代,我们日常接触到的“在线客服”“自动问答”等,大多是以聊天机器人的形式出现。它能帮我们快速回复常见问题,让用户获得及时的帮助,并在一定程度上减少人工客服的压力。 同时&…...
【网络安全 | 渗透工具】小程序反编译分析源码 | 图文教程
未经许可,禁止转载。 本文仅供学习使用,严禁用于非法渗透测试,笔者不承担任何责任。 文章目录 1、下载Proxifier2、下载反编译工具unveilr3、寻找小程序文件包4、对文件包进行反编译5、对源码进行分析6、渗透思路6.1、查找敏感信息泄露6.2、解析加解密逻辑6.3、枚举 API 接口…...

uniapp 系统学习,从入门到实战(六)—— 样式与布局
全篇大概 4700 字(含代码),建议阅读时间 30min 📚 目录 Flex 布局在 UniApp 中的应用响应式设计与适配多端使用 SCSS 提升样式开发效率实战案例演示总结 1. Flex 布局在 UniApp 中的应用 1.1 基础布局实现 通过 display: flex 快速构建弹性容器&#…...

‘ts-node‘ 不是内部或外部命令,也不是可运行的程序
新建一个test.ts文件 let message: string = Hello World; console.log(message);如果没有任何配置的前提下,会报错’ts-node’ 不是内部或外部命令,也不是可运行的程序。 此时需要安装一下ts-node。 npm install...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...
深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏
一、引言 在深度学习中,我们训练出的神经网络往往非常庞大(比如像 ResNet、YOLOv8、Vision Transformer),虽然精度很高,但“太重”了,运行起来很慢,占用内存大,不适合部署到手机、摄…...