散户如何实现自动化交易下单——篇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 Applicationapp = 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 pytesseractfrom PIL import Imageim = Image.open(img_path).convert("L")# 1. threshold the imagethreshold = 200table = []for i in range(256):if i < threshold:table.append(0)else:table.append(1)out = im.point(table, "1")# 2. recognize with tesseractnum = pytesseract.image_to_string(out)return num
第四部分 异常处理与稳定性优化
-
网络延迟容错
添加重试机制,应对因网络卡顿导致的控件加载失败:
from pywinauto.timings import TimeoutErrortry:buy_button.click()except TimeoutError:print("控件未找到,尝试重新定位...")
-
日志记录
记录操作过程和错误信息,便于后期排查:
import logginglogging.basicConfig(filename="trade.log", level=logging.INFO)
-
防重复点击
通过状态标记避免因脚本卡顿导致的重复下单:
if not is_order_submitted:submit_button.click()is_order_submitted = True
接着,我们以获取当前账户的资金状况和持仓状况为例(在交易中实时获取这个两个信息是十分必要的),来进行一个实践。
注:代码逻辑参考于easytrader,下面的函数都是从相关的类中抽取出来的,所以会带有self.
首先我们看到,资金账户信息需要再在左边菜单栏切换到【查询F4】【资金股票】栏目后的右边展示,因此我们要先进行栏目的选择切换并获取右边的信息。

@propertydef balance(self):self._switch_left_menus(["查询[F4]", "资金股票"])return self._get_balance_from_statics()@perf_clockdef _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_clockdef 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 = 2while 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 retryhandle.wait("ready", 2)return handle# pylint: disable=broad-exceptexcept 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 resultBALANCE_CONTROL_ID_GROUP = {"资金余额": 1012,"可用金额": 1016,"可取金额": 1017,"总资产": 1015,}
具体应用方式:
import easytraderuser = 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中,获取的方式有两种,一是直接复制并从剪切板中获取信息,一种是邮件保存为文件再从文件中读取,第二种方式的稳定性更高,并且可以实现多次读取,因此讲解第二种方式的获取方法。请逐层函数的去看就
@propertydef position(self):self._switch_left_menus(["查询[F4]", "资金股票"])return self._get_grid_data(self._config.COMMON_GRID_CONTROL_ID)@perf_clockdef _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 SetForegroundWindowgrid.type_keys("^s", set_foreground=False)if self._trader.is_exist_pop_dialog():count = 5while count > 0:if (self._trader.app.top_window().child_window(class_name="Static", title='提示').exists(timeout=1)):file_path = "tmp.png"found = Falseself._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 = Truecount = -1else:count = count - 1if not found and count==0:breakelse:Copy._need_captcha_reg = Falsebreakself._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 fileself._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 easytraderuser = 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...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
