news 2026/10/5 1:32:22

Python + EasyTrader + 同花顺:5分钟搭建个人自动化交易机器人

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python + EasyTrader + 同花顺:5分钟搭建个人自动化交易机器人

做个自动化交易机器人,听起来是个大工程,但如果你的下单入口是Python + EasyTrader + 同花顺,那第一个能用的版本,完全可能在5分钟内跑起来。这个“5分钟”指的是把最基本的连接、查询、下单这条路走通,不包括你之后为了适配客户端版本折腾掉的两小时,但至少方向对了,后面所有的坑都是可以逐个填平的。

我最早是被手动下单搞烦的。盯盘时手里正开着会、回着消息,价格到了预设位置,手一点慢,单子就滑出去了;有时候是涨到目标价舍不得卖,等回撤了又拍大腿。说实话,我的执行纪律并不可靠,所以我决定让程序来执行——不是让它替我思考买卖逻辑,而是把我已经定好的规则变成自动动作。这篇文章就记录我怎么做通这件事,涉及环境准备、核心代码、实跑会遇到的坑,以及我后来补上的工程化改造。适合有基础Python语法知识、想把手动操作自动化的朋友;如果你完全零基础,建议先跑一遍Python入门教程再回来,不然遇到环境问题会有点挫败。

先说清楚一点:这里说的“同花顺编程”和你在网上看到的“同花顺公式系统”“资金博弈指标源码”完全是两回事。公式系统是在同花顺内置环境里写指标,而本文是用Python在外部操控同花顺客户端去下单,逻辑层级完全不同,别混淆。

1. 为什么我用EasyTrader+同花顺做第一版机器人

1.1 手动交易真正的成本

手动下单看起来只是“点几下鼠标”,实际成本远不止时间。盘中打开交易软件,输入代码、看现价、填价格、填数量、点买入,再确认一次弹窗,顺利的话十秒钟,但这十秒钟恰恰是最容易出问题的:价格触发时你正在其他软件里切不过来;手一抖把100股填成1000股;看着分时图犹豫三秒,价格已经飘走。

这些其实都能用提前挂单解决一部分,但挂单只能挂固定价,没法做条件单、没法做网格、没法在你临时要开会时继续按纪律执行。自动化机器人的第一价值不是“快”,而是“不带情绪、不犯低级错误、能盯住你盯不住的盘”。

1.2 为什么不直接接券商API或者上量化平台

很多人的第一反应是:既然要自动化,为什么不直接找券商开量化接口?这个想法没错,但现实阻力不小。券商量化接口通常有资金门槛、开户时长要求、策略审核流程,个人小资金用户很难快速获批;第三方量化平台也类似,策略部署、数据许可以及订阅费用都是成本。我只想把自己的几个固定规则跑起来,为了这个去走一套企业级流程,太重了。

EasyTrader这类方案的本质是“操控现有客户端”:你已经有同花顺,有券商的网上交易功能,程序做的只是代替你操作那些按钮、输入框和确认键。它没有黑进交易所,也没有破解什么协议,就像是给软件请了一个不知疲倦的“隐形操作员”。好处是门槛低、实现快、账户逻辑和券商通道完全由官方客户端兜底;代价是它依赖界面元素的稳定,客户端一升级可能就识别失效,这是后面最大的维护成本。

1.3 EasyTrader的价值和局限

EasyTrader是GitHub上的开源Python库,它封装了同花顺客户端、部分券商客户端的底层自动化操作,屏蔽了窗口句柄查找、控件点击、输入框定位这些枯燥细节,对外暴露的是一套接近交易语义的API,比如查询资金、查询持仓、买入、卖出、撤单。我第一次看到它的README时,第一反应是“这么简单?”,但实际跑起来之后才发现,简单的是API,不简单的是环境匹配。

做个表格对比一下市面上几条技术路径,方便你判断自己的场景:

方案接入门槛资金成本稳定性适合场景
券商官方量化API高,需开户审核、资历门槛通常免费但条件严高中高频、策略复杂、资金量较大
第三方量化平台中,需注册认证订阅或数据费用高想专注策略研究不想管运维
EasyTrader操控同花顺低,会Python就行免费中,依赖客户端升级个人低频自动化、学习验证、小资金

所以这个方案的定位很明确:低门槛、能落地的个人交易自动化工具,而不是机构级交易系统。别指望用它去做毫秒级高频交易,那个场景下客户端UI自动化本身就不可行。

2. 环境准备:Python、同花顺、依赖这三件套

2.1 Python版本和操作系统的选择

EasyTrader依赖pywinauto、pywin32这类Windows下的GUI自动化库,所以强烈建议在Windows环境跑,我在Linux下用Wine试过,窗口句柄识别和控件映射一团糟,纯属给自己找麻烦。Python版本我建议用3.8或3.9,这个库本身维护节奏不快,太新的Python版本容易出现依赖编译问题。

如果习惯用VSCode,配置好Python环境之后记得用虚拟环境隔离项目,不要一股脑装进全局。我个人的习惯是:

conda create -n trader python=3.9 -y conda activate trader pip install easytrader pywinauto pywin32 pandas

这里有个特别容易踩的坑:PyPI上的easytrader版本可能很老,甚至不兼容你现在下载的同花顺客户端。如果pip安装后import正常但connect失败,去GitHub把最新源码clone下来,用pip install -e .装到本地,或者直接看仓库里最新的示例代码。我用的是社区维护的一个修复分支,不同发行版的API细节有差异,下面的代码示例是基于常见用法,实际操作时以你clone到的仓库README为准。

2.2 同花顺客户端怎么准备

不要直接双击图标就完事,有几个地方要提前处理:

  • 登录方式:建议先手动打开同花顺客户端,把交易账户登录一遍,确认能正常看到资金和持仓。同时把“保存账号密码”和“自动登录”选项看情况打开。自动登录确实方便程序启动,但也会降低一点账户安全性,需要在便利和安全之间做取舍。
  • 关闭弹窗:客户端经常有“系统升级”“资讯推荐”“风险评估”这类弹出窗口,如果不提前关掉,程序操作时主窗口后面突然跳出一个弹窗,可能把焦点抢走,导致后续点击全部错位。在设置里尽量关掉消息推送、自动更新提醒。
  • 固定安装路径:自动化程序需要定位客户端进程和窗口,安装路径不要有中文和空格最好(虽然技术上能处理,但没必要给自己加难度)。
  • 验证码和动态口令:新版同花顺经常有短信验证码或者动态口令登录,这类安全机制不要试图去绕过。不要找什么“自动输入验证码”的歪门邪道——安全验证存在是有原因的。正确做法是程序不负责登录,而是你先手动登录好客户端,再让脚本附加已登录的窗口。

2.3 一个常被忽视的环节:先验证窗口识别

环境准备阶段别急着写业务逻辑,先跑一个最简单的测试脚本,确认EasyTrader能不能看到你的同花顺窗口:

import easytrader user = easytrader.use('ths') # 方式A:连接已经打开并登录好的客户端窗口 user.connect() print(user.balance)

如果连接成功并能打印出账户资金信息,恭喜,最难的环境问题已经过了一半。如果报错说找不到窗口,先确认客户端是否已经登录到交易界面,再确认你没有同时开着多窗口——我见过有人开了主窗口和迷你窗口,程序连到了错误的那一个,结果所有操作都作用在看不见的窗口上,特别诡异。

3. 写一个能跑起来的最小交易脚本

3.1 连接客户端:两种方式都有前提条件

连接这块,EasyTrader常见用法有几种形式。一种是指定客户端的可执行文件路径,让库自己启动程序;另一种是附加到已经打开的客户端上。我强烈建议用“附加已登录窗口”这种方式,因为登录流程交给人工处理最稳,验证码、动态口令、滑块这些问题全部绕开了。

我自己用的连接模式大致是这样:

import easytrader user = easytrader.use('ths') user.connect()

如果是需要指定路径的版本,大概是:

user.connect(r'C:\同花顺软件\xiadan.exe')

不同分支写法有差异,我这里不把话说死,但整体的流程是:先有客户端实例,再连接,然后查询账户。连接成功后不要急着下单,先打印一下持仓和资金,确认程序看到的账目和你手动看到的一致,这一步能排除“连到了错误账户”这种低级但后果严重的问题。

3.2 查询资金和持仓

查询接口是检查自动化状态最常用的手段。运行成功后会得到类似结构的数据:

balance = user.balance position = user.position print(balance) # 资金、可用、冻结等 print(position) # 持仓列表:代码、名称、股份、成本价等

这里有一个非常重要的习惯:每次下单前先查一次可用资金和持仓,程序里要做校验。比如你想买1000股,但可用资金只有一半,直接下单会触发券商端报错,或者导致部分成交,处理起来特别麻烦。更安全的做法是下单前检查“可用资金 > 预计买入金额”,不满足就跳过这一轮并记录日志。这不算复杂逻辑,但能避免大量事故。

3.3 买入、卖出、撤单的基本用法

核心交易操作长这样:

# 买入:证券代码、价格、数量(股) user.buy('162411', price=0.535, amount=100) # 卖出 user.sell('162411', price=0.550, amount=100) # 查询当日委托,拿到委托编号后用编号撤单 # user.cancel_entrust('委托编号')

几个细节我吃过亏,这里展开说:

  • 价格是元单位,不是分单位;数量是股数,不是手数。A股交易是100股起,但场内基金有些是100份起,具体以券商规则为准。
  • 买入价格填的是你愿意接受的委托价,不是市价。如果直接填现价,可能因为行情跳动导致委托失败,所以在策略里要设定好“买一价”“卖一价”或者你自己算出来的目标价。
  • 撤单前一定要先查委托,拿到正确的委托编号再去撤。程序不是人,不会在界面上用眼睛找到那笔单再点击撤单,一切都要靠数据交互。

3.4 一个最小但完整的“机器人”骨架

我把第一版机器人核心逻辑拆成三部分:轮询、条件判断、下单护盾。轮询负责按固定间隔获取行情;条件判断决定要不要下单;下单护盾负责限制每日委托次数和金额上限,防止程序处于异常循环时把自己账户搞穿。

下面是一份示意代码,注意行情获取部分我留了接口,你需要根据自己可用的行情源来填充:

import time import easytrader user = easytrader.use('ths') user.connect() TICK_INTERVAL = 5 # 轮询间隔,单位秒 MAX_ORDER_PER_DAY = 3 # 每日最大委托次数 MAX_AMOUNT_PER_ORDER = 5000 # 单笔最大金额,就是一层保护 ordered_today = 0 def get_price(code): # 这里用你能拿到的行情源数据 # 可以是免费行情接口、数据文件、甚至是同花顺界面OCR抓取 # 示意返回值,真实场景需要替换 return 1.235 def main(): global ordered_today while ordered_today < MAX_ORDER_PER_DAY: try: price = get_price('162411') if price <= 1.200: amount = 100 if price * amount > MAX_AMOUNT_PER_ORDER: print('超过单笔金额上限,跳过') else: user.buy('162411', price=1.200, amount=amount) ordered_today += 1 print(f'已委托第 {ordered_today} 笔') except Exception as e: # 异常要记录,不能静默吞掉 print(f'执行异常: {e}') time.sleep(TICK_INTERVAL) if __name__ == '__main__': main()

这份代码很简单,但它把最重要的几个原则体现出来了:有轮询节奏、有策略条件、有防护上限、有异常打印。真实跑之前先把get_price换成可用行情源,再在模拟环境跑几天,不要直接上实盘。

4. 实跑中真正会遇到的几个坑

4.1 客户端窗口找不到,程序卡在connect

这个坑几乎每个人都会撞上。常见原因有三个:客户端没打开到交易界面、打开了多个同花顺窗口、客户端窗口最小化到了系统托盘但主窗口被隐藏。排查链路我建议这样做:先手动把客户端恢复到正常窗口状态,再在脚本里打印一下当前窗口列表,确认程序能看到哪个窗口;如果还找不到,检查客户端版本和EasyTrader分支是否兼容。我一度以为是代码问题,折腾了半小时,最后发现是客户端在托盘里,窗口是隐藏的,程序根本捕捉不到。

4.2 验证码和二次验证:不要试图自动化

新版同花顺在交易登录时经常要求短信验证码或者动态口令,这里我要说重点:不要尝试自动识别验证码,也不要尝试绕过二次验证。一方面这涉及账户安全问题,另一方面这种对抗纯属无用功——券商的验证机制会不断升级,你花时间写出来的识别逻辑过几天就失效。我的方案是让脚本只负责“登录之后”的操作,登录这一步保留人工。等到下单的时候,程序操作的是已经登录好的界面,自然就不会碰到验证码问题。先登录,再连接,这个顺序不要打乱。

4.3 客户端一升级,控件识别全部失灵

这是EasyTrader方案最大的长期成本。同花顺发布新版本后,按钮的位置、大小、控件类型都可能变化,程序找不到原来的控件,下单就失败。我遇到过最典型的情况:一次客户端自动更新后,buy函数调用没有任何报错,但委托并没有真的提交——程序以为是点了买入按钮,实际那个按钮已经改名为别的控件名了。解决思路有三种:回退客户端到旧版本;等社区发布适配补丁;定期手动检查控件树,把变化映射更新到脚本里。没有一劳永逸的办法,只能把它当作定期维护项写进自己的运维清单。

4.4 下单确认弹窗和风险揭示弹窗

很多券商端在委托后会弹确认框,有些还会在首次交易时弹风险揭示。程序如果没识别到弹窗就去点下一个按钮,整个操作序列就错乱了。我的处理办法是在客户端设置里关闭可关闭的二次确认;对于不可关闭的风控弹窗,只能让脚本增加弹窗检测逻辑,先截屏识别弹窗再决定是否点击确认按钮。这一步没什么捷径,得对着自己客户端的具体情况调试。

4.5 重复下单比漏单更可怕

脚本崩溃后重启,或者网络超时导致程序以为上次下单失败,于是重新下单,这些场景都会产生重复委托。手动操作用眼睛能看出来,程序可不知道。我的防护手段是记录“已提交委托”的日志文件,每次下单前先检查这次要下的单是否已经提交过。更保险的做法是每天开盘前生成一个唯一标识的批次号,同一批次同一标的同一价格只允许下一笔。

4.6 长时间运行会越来越不稳定

GUI自动化本质上是反复操作窗口控件,窗口对象、内存句柄、临时文件都会慢慢累积。我跑过一个连续运行三天的脚本,到第三天下单响应时间明显变长,最后直接卡死。后来养成的习惯是:每天收盘后自动重启脚本和客户端,开盘前再做一次连通性自检。简单的定时计划任务就能搞定,不需要引入太复杂的守护进程。

5. 从“能跑的脚本”到“能用的机器人”

5.1 日志是你唯一的现场记录

脚本跑起来之后,你不可能每时每刻盯着屏幕,出问题时的排查完全靠日志。我第一版只用了print,等真正出问题时悔得肠子都青了——程序崩了,控制台也关了,什么都查不到。后来把核心操作全部落日志文件,至少记录这几类:每次轮询的行情快照、每次下单的价格数量金额、委托编号、异常堆栈、每次连接和断开客户端的动作。日志不用复杂格式,一行一条,能追溯到时间、操作、结果就够了。

5.2 参数别写死在代码里

第一版脚本我把价格阈值写死在代码里,每次想调整都要改源码再重启,非常麻烦。后来抽出来一个配置文件,用JSON存账户代码、策略阈值、买卖标的、单笔金额上限、每日次数上限,程序启动时读一次。这个改动很小,但收益巨大——你可以在收盘后修改配置,第二天自动生效,完全不用碰代码。

5.3 行情数据源:整个方案里最需要你自己解决的部分

EasyTrader解决的是“下单”环节,它不提供行情数据。你需要自己找一个可靠的数据源来判断“该不该下单”。这里有几个选择:免费行情库的HTTP接口、券商App的推送数据、甚至从同花顺界面里截图识别价格。我的建议是优先用结构化接口,别用截图OCR,准确率虽然够但处理速度慢还不稳定。行情数据的延时也要有数,作为低频策略,几秒钟的延时问题不大;但如果你想做稍微快一点的策略,数据链路就要重新设计了。这一步不要贪快,先解决“有数据”,再考虑“数据准”。

5.4 应急停止能力必须提前做

无论你的策略逻辑多完美,都要假设最坏情况发生:程序在下单循环里疯狂提交委托、或者客户端连不上又重试。我的做法是:程序启动时创建一个“停止标志”文件,主循环每轮检查一次,如果文件存在就暂停所有下单动作,只记录日志不操作。这样遇到异常时,我只需要在机器上生成一个文件就能让机器人“收手”,比去改代码或者杀进程更安全。同时保留“手动撤单”的路径——程序出问题时你还能手动打开客户端一键全撤,这个兜底比任何自动化都可靠。

5.5 先回测,再用模拟盘验证,最后小资金实盘

自动化交易中最大的风险不是代码写得烂,而是策略本身不行。我见过太多人写了一个线上赚钱的策略就急着实盘,结果亏到怀疑人生。现在开源的回测框架很多,把你的策略逻辑先落地到历史数据上,跑出一段时间的结果,看最大回撤、胜率、盈亏比这些指标,有统计意义了再说下一步。实盘也用最小仓位跑,把它当成一次真实环境验收,而不是一上来就来大的。

6. 该做什么、不该做什么:自动化交易的安全边界与心理准备

聊完技术,说说边界。EasyTrader这套方案适合什么?适合个人低频自动化、适合学习量化交易流程、适合把你已经验证过的策略变成自动执行。不适合什么?不适合高频抢单、不适合无人值守的全自动滚仓、不适合把它当成一台没有监督的“赚钱机器”——本质是GUI自动化,性能和稳定性都够不着这些场景。

使用层面有两条底线要守住。第一,了解并遵守你的券商和第三方软件的服务条款,不要做明显违反账户使用规则的事情。低频合理使用通常不会有什么问题,但如果你的账户出现高频登录、频繁下单、异常操作等特征,券商风控系统可能会关注到,届时配合核实就好,别去想办法对抗。第二,验证码、动态口令这类安全机制不要尝试绕过,那是保护你资金不受损失的最后一道防线。自动化是为了解放你的手,不是为了让别人更容易盗走你的钱。

投资风险上也要说透:自动化不改变交易策略本身的质量,垃圾策略自动执行只会亏得更快。机器人做的事情是替你执行纪律,不是替你创造奇迹。我第一次让脚本自动下单时,盯着客户端里的买单状态,手心全是汗,比手动下单紧张多了——因为你知道这一次点击不是自己控制的,成不成交、什么价成交,全部交给了系统和行情。那笔单子最终成交在预期价格,但我从那次起意识到,自动化交易真正难的不是写代码,是敢不敢放手让程序执行,以及事后能不能冷静地接受结果。

如果你也想做,我的建议是从最小成本开始:先用模拟环境跑通流程,再用最小金额验证实盘,观察至少一两周,确认它不会在关键时刻掉链子,再逐渐加大投入。过程中始终保持手动干预的能力,记住它只是一把升级过的工具,使用工具的人仍然是你自己。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/5 1:31:39

霍尔传感器FOC角度估算:插值法与PLL锁相环对比解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/5 1:31:21

AI助手为何说“无法处理该请求“?解析模型拒绝机制与安全对齐

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/5 1:30:23

安卓直链APK安装被拦截?解析三层拦截机制及放行方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/5 1:30:23

OpenBMC开发环境构建实战:从Yocto到硬件移植的完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/5 1:30:08

WPF RichTextBox MVVM双向绑定实战:附加属性方案与序列化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/5 1:30:08

YOLOv11岩石裂隙检测与三维地质建模联合优化实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华