散户如何实现自动化交易下单——篇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…...
轻松实现语音生成:GPT-SoVITS V2整合包的远程访问操作详解
文章目录 前言1.GPT-SoVITS V2下载2.本地运行GPT-SoVITS V23.简单使用演示4.安装内网穿透工具4.1 创建远程连接公网地址 5. 固定远程访问公网地址 前言 今天要给大家安利一个绝对能让你大呼过瘾的声音黑科技——GPT-SoVITS!这款由花儿不哭大佬精心打造的语音克隆神…...
【微知】git 如何修改某个tag名字?如何根据某个commit创建一个tag?
背景 某些时候git tag名字搞错了,需要修改,如何处理? 删除某个tag git tag -d oldtagname修改某个tag名字 创建新的,删除老的 git tag newtagname git tag -d oldtagname基于某个老的commit创建一个tag git tag V0.1.0 xxxc…...
Java中使用for和Iterator遍历List集合的区别
在 Java 中,遍历 List 可以使用 for 循环 和 Iterator 两种方式。它们各有优缺点,适用于不同的场景。以下是它们的区别和适用场景: 1. 语法和使用方式 for 循环: 使用索引遍历列表。 示例: List<String> li…...
删除有序链表中重复的元素-II(C++)
目录 问题描述 示例1 示例2 解题思路 代码实现 代码解析 1. 初始化 2. 遍历链表 总结 问题描述 给出一个升序排序的链表,删除链表中的所有重复出现的元素,只保留原链表中只出现一次的元素。 例如: 给出的链表为1→2→3→3→4→4→51…...
SFP(Small Form-factor Pllugable)详解
1. SFP的定义 SFP(Small Form-factor Pluggable)是一种小型化热插拔光模块/电模块,广泛用于网络设备(如交换机、路由器、网卡等)中,作为物理层接口模块。其设计遵循由多源协议(MSA)…...
【0011】HTML其他文本格式化标签详解(em标签、strong标签、b标签、i标签、sup标签、sub标签......)
如果你觉得我的文章写的不错,请关注我哟,请点赞、评论,收藏此文章,谢谢! 本文内容体系结构如下: 本文旨在深入探讨HTML中其他的文本格式化标签,主要有<em> 标签、<strong> 标签、…...
在分布式系统中,解决因锁持有者故障导致锁无法释放的问题
分布式锁的自动释放与容错机制 在分布式系统中,如果锁的持有者因故障无法主动释放锁,可能会导致死锁或业务阻塞。为了提高系统的稳定性和可用性,需要结合自动释放机制和容错设计。以下是几种关键解决方案: 1. 设置锁的自动过期时…...
结构型模式--组合模式
概念 组合人模式是结构型设计模式的一种,主要是用于解决代码中出现类像树一样进行组合而出现的组合结构的相关操作问题。使其树中的任意一个节点(无论是子节点还是父节点)都可以使用同一套接口进行操作。 使用场景 1、如果希望我们对象组合…...
时间复杂度练习题(6道题,C语言)
// 第一道int x 90;int y 100;while (y>0)if(x>100){x x -10;y--;}else x; // 第二道for (int i 0;i<n;i){for (int j 0;j<m;j){a[i][j] 0;}}// 第三道s 0;for(int i 1;i<n;i){for(int j 1;j<n;j){s B[i][j];}}sum s; // 第四道i 1;while (i<…...
第十四届蓝桥杯大赛软件赛国赛C/C++大学C组
A 【跑步计划——日期问题】-CSDN博客 B 【残缺的数字】-CSDN博客 C 题目 代码 #include <bits/stdc.h> using namespace std;void change(int &x) {int sum 0, t x;while(t){sum t % 10;t / 10;}x - sum; } int main() {int n;cin >> n;int ans 0;…...
【WPF】绑定报错:双向绑定需要 Path 或 XPath
背景 最开始使用的是 TextBlock: <ItemsControl ItemsSource"{Binding CameraList}"><ItemsControl.ItemsPanel><ItemsPanelTemplate><StackPanel Orientation"Horizontal"/></ItemsPanelTemplate></ItemsControl.Item…...
谈谈 ES 6.8 到 7.10 的功能变迁(6)- 其他
这是 ES 7.10 相较于 ES 6.8 新增内容的最后一篇,主要涉及算分方法和同义词加载的部分。 自定义算分:script_score 2.0 Elasticsearch 7.0 引入了新一代的函数分数功能,称为 script_score 查询。这一新功能提供了一种更简单、更灵活的方式来…...
huggingface下载模型到本地缓存环境变量配置详解
1.安装huggingface-cli 命令行工具,进行模型文件下载 pip install -U huggingface_hub huggingface-cli --help 帮助命令 2.从huggingface下载模型方法 方法1: git clone 下载模型 方法2:huggingface-cli 工具下载模型 方法3&…...
u-boot的环境变量设置、保存、汇总与说明【同时对u-boot的环境变量`bootcmd`和网络启动(run netboot)方式进行了详细解释】
前言 在 U-Boot 中,环境变量用于配置系统的启动参数和行为。是否能正确理解和设置u-boot中的环境变量是启动Linux系统的关键,所以有必要认真学习了解下各环境变量的意思和作用。 最好的学习材料就是实际的例子,所以本篇博文把我遇到过的各个…...
【后端】Docker一本通
长期更新补充,建议关注收藏点赞 目录 Docker概述安装部署Docker基本操作使用docker部署tomcat使用docker部署mysql Docker概述 docker是⼀个应⽤级隔离的虚拟化技术docker三大核心概念 镜像:是具有源的所有特征的⼀个标记⽂件 仓库:存放镜像…...
基于Spring Boot和Vue的餐饮管理系统设计与实现
大家好,今天要和大家聊的是一款基于Spring Boot和Vue的餐饮管理系统的设计与实现。项目源码以及部署相关事宜请联系我,文末附上联系方式。 项目简介 基于Spring Boot和Vue的餐饮管理系统设计与实现的主要使用者分为管理员、员工和用户。没有授权的用户无…...
如何快速的解除oracle dataguard
有些时候,我们为了使oracle dg的standby库另做他用,需要解除oracle dataguard数据同步。我本地因为standby库存储出现故障,导致dg存在问题,故需要解除。今天,我们通过使用部分命令,实现dg的快速解除。 1&a…...
C语言【指针篇】(四)
前言:正文1. 字符指针变量2. 数组指针变量2.1 数组指针变量是什么?2.2 数组指针变量怎么初始化 3. 二维数组传参的本质4. 函数指针变量4.1 函数指针变量的创建4.2 函数指针变量的使用4.3 两段有趣的代码4.3.1 typedef关键字 5. 函数指针数组6. 转移表 总结 前言&am…...
Python基于Django的网络课程在线学习平台【附源码】
博主介绍:✌Java老徐、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇&…...
vscode集成DeepSeek
vscode 扩展 安装 Cline Meet Cline,一个可以使用你的CLI和编辑器的AI助手。 得益于 Claude 3.5 Sonnet的代理编码功能,Cline 可以逐步处理复杂的软件开发任务。借助让他创建和编辑文件、探索大型项目、使用浏览器和执行终端命令(在您授予权限后)的工具&…...
【TCAD】Sentaurus 中的“陷阱trap”仿真设置
13.1 陷阱类型 13.2 定义陷阱 13.3 陷阱态密度的类型 13.4 陷阱空间分布 13.5 陷阱占据 13.6 陷阱横截面 13.7 陷阱作为掺杂 13.8 陷阱填充控制 13.9 陷阱可视化 目标 演示如何使用 Sentaurus 设备在模拟中使用陷阱。13.1 陷阱类型...
Lucene硬核解析专题系列(三):查询解析与执行
Lucene的索引构建为高效搜索奠定了基础,而查询解析与执行则是将用户意图转化为实际结果的关键环节。本篇将从查询的解析开始,逐步深入到查询类型、评分模型和执行流程,揭示Lucene搜索能力的底层原理。 一、查询语法与QueryParser的工作原理 Lucene的查询过程始于用户输入的…...
Linux操作系统5-进程信号3(信号产生总结与核心转储)
上篇文章:Linux操作系统5-进程信号2(信号的4种产生方式,signal系统调用)-CSDN博客 本篇Gitee仓库:myLerningCode/l25 橘子真甜/Linux操作系统与网络编程学习 - 码云 - 开源中国 (gitee.com) 本篇重点:核心…...
家用可燃气体探测器——家庭燃气安全的坚实防线
随着社会的发展和变迁,天然气为我们的生活带来了诸多便利,无论是烹饪美食,还是温暖取暖,都离不开它的支持。然而,燃气安全隐患如影随形,一旦发生泄漏,可能引发爆炸、火灾等严重事故,…...
【学习笔记】网络设备(华为交换机)基础知识 9 —— 堆叠配置
提示:学习华为交换机堆叠配置,含堆叠的概念、功能、角色、ID和优先级;堆叠的建立过程以及注意事项;包含堆叠的配置命令,以及堆叠的配置案例 一、前期准备 1.已经可以正常访问交换机的命令行接口 Console口本地访问教…...
【Linux】Linux的进程控制
目录 1. 学习思维导图 2.进程创建(fork) 2.1 fork创建进程失败 3.进程终止 3.1 进程退出情况 3.1.1main函数 3.1.2 退出码 3.2 exit/_exit函数 1. exit() 函数 2. _exit() 函数 4.进程等待 4.1 实现进程等待的方法 wait/waitpid方法 区别&a…...
电子电气架构 --- 汽车行业技术变革
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…...
【告别双日期面板!一招实现el-date-picker智能联动日期选择】
告别双日期面板!一招实现el-date-picker智能联动日期选择 1.需求背景2.DateTimePicker 现状图3.日期选择器实现代码4.日期选择器实现效果图5.日期时间选择器实现代码6.日期时间选择器实现效果图 1.需求背景 在用户使用时间查询时,我们经常需要按月份筛选…...
利用 Python 爬虫进行跨境电商数据采集
1 引言2 代理IP的优势3 获取代理IP账号4 爬取实战案例---(某电商网站爬取)4.1 网站分析4.2 编写代码4.3 优化代码 5 总结 1 引言 在数字化时代,数据作为核心资源蕴含重要价值,网络爬虫成为企业洞察市场趋势、学术研究探索未知领域…...
