从规则到学习:拆解一个会思考的外汇交易AI机器人
发布时间:2026/10/20 15:11:23 锦皓数字建站

“会思考的外汇交易AI机器人”这句话我见过太多人把它当成营销噱头了。下载一个几十行代码的EA写死几个if-else就叫“智能交易系统”。但真正的思考至少得包含三个能力感知当前市场状态、根据状态做决策、从结果中修正自身行为。这篇文章我会把我自己搭的一个原型机器人完整拆开讲从数据怎么拿、特征怎么算、决策引擎怎么写、回测怎么避坑到模拟盘怎么对接全程给源码思路和踩坑记录。项目叫 fxbrain_demo技术栈就是纯Python没有复杂分布式单机就能跑。适合有一定Python基础、想认真做量化交易机器人而不是买神器的朋友。先说清楚外汇交易是高风险杠杆交易本文所有内容仅供技术研究不构成任何投资建议请只在模拟账户里测试亏钱别找我。1. 会“思考”的三个层级从定时器到学习型机器人1.1 大部分EA只是定时器不是机器人市面上很多EA的核心逻辑就三行如果均线金叉就买如果死叉就卖如果亏损超过100点就平仓。这套东西在震荡行情里偶尔能赚但遇到趋势反转就是连续止损。为什么因为它没有“状态”概念它不知道当前是趋势市还是震荡市不知道波动率是不是突然放大了更不会因为前几天亏了钱而改变自己的行为方式。我见过某开发者把一个几百行的EA吹成“自适应智能系统”打开源码一看所谓的自适应就是if atr 20换一套参数。这充其量算“多套定时器轮换”离智能差得很远。真正做这个项目时我给自己定了个标准不能只按当前K线的一个信号触发而是要把一段时间的市场信息压缩成“状态”让机器人基于状态做概率判断同时保留一套人工规则兜底。1.2 三个层级的具体定义我把“思考”拆成三个层级这样才知道自己做到哪一步了。第一层是规则反射。就是最传统的技术指标组合比如RSI超卖价格突破N日高点就做多。这一层的特点是快、可解释、但僵化。第二层是状态感知。机器人除了看单一指标还会维护一组“市场状态变量”当前趋势方向、波动率水平、最近一段时间的盈亏状态、持仓时长等。决策不再是单点触发而是基于当前状态向量查一张“应对表”。我第一版就在做这层效果已经比纯规则稳定不少。第三层是学习迭代。决策表不是人写死的而是通过历史数据训练出来的。模型根据奖励信号不断更新自己对“什么状态下该做什么”的判断。fxbrain_demo 目前做到了第二层和第三层的混合一条规则基线负责极端风控模型负责常规开仓平仓决策。1.3 能力边界和适用人群我这个机器人不预测涨跌它只做一件事在一个明确定义的场景下用最大概率的正期望动作应对市场。它不适合指望“一夜暴富”的人也不适合完全不懂交易就上来抄代码的人。你要懂一点K线、懂一点Python、懂一点统计学否则后面遇到过拟合、数据漂移这些问题根本不是改两行代码能解决的。适用人群我总结一下已经手工交易一段时间、想把自己的交易规则自动化的人学机器学习、想找一个小而完整的强化学习练手项目的人对数据工程感兴趣想看看行情数据怎么变成特征、又怎么变成动作的人。fxbrain_demo 整个项目从零到跑通模拟盘大概花了我两个完整的周末大部分人照着做会慢一点但不会卡死。2. 架构选型单机也能跑的四模块智能系统2.1 四个模块的职责边界很多第一次做交易机器人的朋友一上来就想写一个大脚本里面有行情获取又有下单逻辑结果后面牵一发动全身。我把项目拆成了四个独立的模块模块之间只通过接口通信互相不引内部实现。数据采集模块负责从经纪商接口拉取K线行情落成本地数据文件同时做基础清洗。决策引擎是核心它接收当前市场状态向量输出动作开多、开空、持有、平仓内部由规则基线和模型组成。执行模块负责把决策信号翻译成真实下单指令包含防重复下单、超时重试、仓位计算。风控模块是一个独立进程随时盯着持仓、亏损和网络状态一旦触发熔断条件直接接管。这个拆分的好处是我可以单独把回测系统接在“决策引擎”上而不影响其他模块也可以在模拟盘运行时单独升级数据采集的频率不用重启整个机器人。后面我会给每个模块的接口代码照着写不会走偏。2.2 技术栈选择与理由技术栈我全部选了Python生态理由很简单模型开发和数据处理最顺手而且单机性能对一小时级别的交易频率完全够用。通知和告警用系统邮件接口就够了不用引入消息队列。存储直接落 CSV 文件加一个简单的 JSON 状态文件前期根本不需要数据库。为什么不用MySQL因为机器人只是一天运行几次决策进程又没有高并发写入引入数据库只是增加部署复杂度。我见过有人为了一个日频策略上 Kafka 和 ClickHouse那是给自己找麻烦。依赖库精简到五个pandas 做数据处理numpy 做数值计算scikit-learn 的 GradientBoosting 做策略模型轻量且不容易过拟合requests 做API调用schedule 做本地调度。深度学习框架我特意没上因为外汇分钟级数据上的小样本问题用复杂神经网络反而容易学偏。如果你后面想把模型升级成 Transformer这一个模块替换并不影响整体架构。2.3 部署形态单机循环加模拟盘先行部署我只跑在一台普通Linux服务器或者本地电脑上。main.py是一个死循环按预设节奏调用四个模块。python main.py --mode paper --pair EURUSD --interval H1--mode参数我设计了历史回测、模拟盘、只监控不交易三种。在没跑完三个月模拟盘之前不要碰真实小账户这是铁律。为什么因为即使回测表现很好真实环境里还有点差变化、滑点、断线重连、服务器时钟漂移这些问题模拟盘会全部暴露给你。3. 数据与特征行情进模型之前必须做的两步3.1 数据源接入与坐标对齐第一个要解决的是数据从哪来。我在 fxbrain_demo 里抽象了一个DataProvider接口模拟盘对接经纪商提供的 REST 行情接口回测则直接读本地 CSV 历史数据。这里我踩的第一个坑就是时间坐标对齐经纪商返回的是服务器时间本地时间是UTC或东八区如果不统一机器人会以为K线还没收盘结果把未完成的K线当成了已完成K线来算特征。解决方式很简单数据清洗时强制把所有时间戳转为 UTC 并去重同时额外记录每根K线的“状态字段”0表示收盘完整1表示正在形成中。决策引擎只允许使用状态为0的K线这样就从根上杜绝了“用未来数据”的隐患。3.2 特征设计从裸K线到状态向量行情原始数据是四列开盘、最高、最低、收盘。机器人在这些裸数据上是思考不起来的需要压缩成特征。我第一版只用了两个指标RSI 和 ATR后来发现趋势市和震荡市里机器人的行为完全不对又加了趋势强度特征。最终我用五类特征组合成状态向量动量特征最近N根K线的累计涨跌幅、当前K线相对N周期均线的偏离度波动特征ATR的近期分位数用来区分“今天波动大不大”反转特征RSI、布林带位置价格在通道中的百分比位置时间特征当前时段亚盘/欧盘/美盘、一周的第几天、非农之类的日历事件在真实系统里要单独考虑资金状态当前持仓方向、持仓时长、最近20笔交易的盈亏比率这五类特征合起来就是一个向量。机器人的“思考”就是在这个向量空间上做决策而不是看单一指标。特征全部用滚动窗口在历史数据上无未来地计算窗口设得越大状态越平滑但对突变反应越慢。我最终取的是 12 和 24 双窗口兼顾短趋势和日间趋势。3.3 时间感与波动感知机器人不能“失忆”有一个容易被忽略的点机器人必须有时间感。同样一根阳线出现在亚盘早盘和纽约尾盘含义完全不同。亚盘流动性差突破信号经常是假突破欧盘和美盘的重叠时段才是外汇市场波动最真实的时候。所以我把本地时间转换成 UTC 后再映射成交易时段特征0代表亚盘1代表欧盘2代表美盘3代表重叠时段。实测下来加入这个特征后决策引擎在假突破上的止损次数减少了大约两成。波动感知则通过 ATR 分位数实现。我会在每一天收盘后把过去30天的 ATR 从小到大排序算出当天 ATR 处于什么分位。高于80分位说明市场在放大波动低于20分位说明市场极度收敛这两种状态下机器人都会自动降低仓位因为极端行情里方向最难猜。状态向量最后经过标准化后喂给模型标准化参数只在训练集上拟合防止信息泄漏。4. 决策引擎从规则基线的确定性到可训练模型的概率判断4.1 规则基线所有模型都先有一个“保底策略”直接上模型不是好主意。我先写了一套全人工规则的基线策略当对照组后续模型必须跑赢它才有保留价值。规则基线是这样设计的趋势过滤只有当 EMA50 和 EMA200 方向一致时才允许顺趋势开仓入场触发顺趋势方向的价格突破 20 根K线的新高/新低仓位固定为每笔 2% 风险ATR 倒数计算止损距离止盈2.5 倍止损距离用移动止损追踪这套规则非常朴素但它是可解释的“底线”。我跑下来胜率在四成左右盈亏比能做到 2 左右长期就是微赚的状态。后面模型做出来如果连这个都跑不赢说明特征或奖励函数有严重问题应当回去查而不是强行上模型。4.2 用轻量模型替换固定阈值规则基线的问题在于“20根K线新高”“4成胜率”都是拍脑袋定的市场切换状态后这些固定阈值就成了枷锁。模型版本做的事情不是让你完全甩掉规则而是把“阈值判断”换成“概率预测”。还是那些特征但决策变成两步。第一步用一个随机森林分类器根据状态向量输出三档概率涨、跌、盘整。第二步由人工逻辑把关只有“涨”概率超过 0.62 且 ATR 分位数没有进入极端区时才开多反过来“跌”概率超过阈值才开空。这里的模型用 scikit-learn 的GradientBoostingClassifier理由上文说过了轻量、非线性足够、对小样本更稳。我训练的时候只用了最近 180 天的 H1 数据没有把三年数据全部灌进去因为市场结构会漂移太久远的数据对当前决策反而是噪音。4.3 训练流程与奖励函数模型“思考”的反馈回路如果只用历史涨跌来给模型输出做监督那机器人学的其实是“预测”不是“交易”。预测准不代表赚钱因为交易要考核赔率和风险。所以我在训练样本里对标签做了收益加权不是简单地“这根K线之后涨了就算正确”而是用“未来N根K线的收益按持仓成本折算后的利润”作为标签强度。具体做法分三步第一步把历史K线切成一个个片段计算每个片段之后 12 根K线的真实收益第二步把收益按 ATR 归一化变成“风险调整后的收益”这样波动大的时段和波动小的时段可以公平比较第三步高于正一个标准差的片段标记为“做多样本”低于负一个标准差的标记为“做空样本”中间标记为“持有样本”这个流程本质是给机器人构建了一个行驶反馈回路它学到的不是“涨还是跌”而是“在这种状态下冒险进场值不值得”。我建议所有做类似机器人的朋友把精力重点放在这里因为特征工程和模型算法有大量现成资料而奖励函数设计才是机器人能不能“思考”的灵魂。5. 回测系统最容易让机器人“作弊”的地方5.1 回测的三件事撮合价、点差、费用回测就是把历史的每一天重放一遍看机器人会做出什么决策、赚多少钱。但很多人的回测结果是假的因为撮合逻辑太理想了。fxbrain_demo 的回测引擎强制模拟三项成本点差、手续费、滑点。点差我直接取数据源里真实K线的spread字段而不是固定一个值。手续费按经纪商常见标准来每手 7 美元这种量级。滑点设置成 0.2 个点市价单必然会有。如果你发现自己的回测报告在扣掉这三项成本之后仍然赚钱那才算勉强合格。我见过不少策略没扣点差时看着胜率很高扣掉之后直接亏损这就是典型的“自欺欺人”。5.2 三个重坑未来函数、过拟合、滑点乐观未来函数是回测里最常见的作弊方式。比如用全天最高最低价去算“突破”但机器人决策时这根K线还没收盘。我自己的解决办法是上面提过的“状态字段”所有特征计算都强制用已收盘K线K线进行中产生的临时高低点一律不进历史窗口。这个规则必须在回测引擎和实时引擎里保持完全一致否则回测能赚模拟盘亏问题往往就出在这里。过拟合则是调参调出来的病。有些人跑了一百组参数选最好的一组拿来宣传。真实世界的指标不是这样用的一百组里总有一组在特定历史段表现好。我为了避免这个问题把最近 60 天的数据完全隔离不做任何调参只有全部开发完成后才允许跑一次这段数据做“期末考试”。过拟合检测还有一个朴素办法把回测区间切成前半年和后半年如果两个半年的收益形态差异巨大大概率是你把参数拟合到了某一段特殊行情里。滑点乐观是指回测里假设成交价总是对自己有利。我的回测引擎里开仓固定按K线收盘价加一个不利方向的滑点平仓同理。这样机器人永远不会在回测里“恰好买在最低点”那是不可能发生的事。回测结果宁可难看真实也不要漂亮虚假。5.3 一个完整回测案例fxbrain_demo 在欧系主流货币对上的表现我挑了一组欧系主流货币对最近一年的 H1 数据做完整回测。先跑规则基线再跑模型版本所有结果都扣掉了点差、手续费和不利滑点。模型版本年化收益比基线高出约8个百分点最大回撤从 14% 降到 9%但注意胜率其实没有显著提高。为什么因为模型的主要贡献不在“预测变准”而在“回避不利波动”——它在高波动时段自动降低了仓位所以回撤幅度变小资金曲线更平滑。这里我必须泼一盆冷水一年回测代表不了任何未来。我紧跟着又做了一个压力测试把回测区间换成某段持续三年的数据包含了几次大的单边行情模型版本的收益就掉了一半。这很正常没有哪种固定策略能在所有行情里通吃。回测的真正价值不是证明“机器人很厉害”而是帮你发现它在哪些行情下会亏钱然后针对性地加风控规则。6. 从策略信号到真实下单模拟盘接入的最后一公里6.1 模拟盘API对接防重复与重试机制策略引擎输出的是一个信号对象里面包含方向、目标仓位和止损距离。执行模块拿到信号后不能立即下单要经过三个校验才走API。第一校验当前是否有未完成的同方向订单有就不重复提交。第二校验信号方向和当前持仓方向相反时先平仓再开新仓不能直接对敲。第三校验下单时间是否在允许交易时段内周末和重大数据发布前五分钟禁止交易。API 调用我封装成一个类底层用 requests 轮询订单状态而不是调完接口就不管了。模拟盘接口同样可能超时所以我把“提交订单”和“确认订单”分开提交后每隔 2 秒查一次状态最多查 10 次如果超时就标记为未知状态转入人工处理清单。这个机制在第一周模拟盘里救了我三次其中两次接口确实抽疯了如果代码没有重试机制机器人会以为已经开仓成功实际上订单压根没发出去。代码层面最关键的一个函数是计算仓位def calc_position_size(account_equity, risk_pct2.0, entry_price1.10, stop_distance50): risk_amount account_equity * (risk_pct / 100.0) pip_value 0.0001 * 100000 # 标准手每点价值 lots risk_amount / (stop_distance * pip_value) return round(lots, 2)这个公式的逻辑很简单先确定这一笔最多亏多少钱权益的2%再用止损距离反推手数。止损距离越大手数就越小这样单笔风险恒定。我用它替代了很多新手“固定0.5手开仓”的做法后者一旦遇到大止损一笔就能亏掉账户的10%。6.2 风控模块仓位、止损、熔断三层防线风控模块我做成一个独立线程每秒检查一次账户状态。它不管“这单会不会赚”只管“这单会不会让我们死”。三件事是强制的。任何单笔持仓亏损超过 2% 权益无条件入场平仓不管策略信号说什么。当日累计亏损超过 5% 权益当天停止所有新开仓。连续止损三笔后机器人自动把风险参数减半进入“冷静期”。第三点不是资金上的硬风控而是行为上的纪律因为连续止损往往意味着市场状态已经变了策略暂时失效这时候继续按原参数开仓等于送钱。熔断逻辑我写进独立的RiskManager类里和策略引擎彻底隔离。某个同学一开始把风控判断写进了策略主循环后来策略崩溃导致风控也没触发那一次直接在模拟盘亏了4个百分点。后来我改成双进程模式策略进程和数据进程 die 了风控进程还在盯着账户必要时候强制平仓并把所有状态写入日志。6.3 运行监控与告警机器人不能是黑箱机器人运行期间我每天会在固定时间点收到一份运行摘要包含当日盈亏、当前持仓、信号数量、API调用失败次数、模型输出的概率分布。为什么关心概率分布因为我发现如果模型长期输出的概率都集中在0.5附近说明它已经失去判断力了这时候就要检查是不是市场状态太新、训练集覆盖不到。告警级别我分三档信息级是每天摘要普通告警是策略异常或API失败重试超过三次严重告警是风控触发强制平仓。普通告警通过邮件发给自己严重告警额外发一条手机推送。我自己吃亏的教训是别只监控“赚不赚钱”还要监控“系统还活着吗”。有一次服务器上证书过期API连接静默失败机器人以为一直没信号其实已经断线一整天了。7. 源码结构与踩坑实录7.1 核心模块文件结构与关键代码fxbrain_demo 的源码结构大致如下你可以照着建fxbrain_demo/ ├── main.py # 入口调度循环 ├── config.yaml # 所有配置项 ├── provider/ │ ├── base.py # 数据接口抽象类 │ └── broker_sim.py # 模拟盘实现 ├── features/ │ ├── calculator.py # 特征计算 │ └── normalizer.py # 标准化 ├── strategy/ │ ├── rule_base.py # 规则基线 │ ├── model_base.py # 模型决策 │ └── reward.py # 训练标签生成 ├── execution/ │ ├── executor.py # 下单执行与重试 │ └── position.py # 仓位计算 ├── risk/ │ ├── manager.py # 风控与熔断 │ └── alerts.py # 告警 └── backtest/ ├── engine.py # 回测引擎 └── metrics.py # 绩效指标决策引擎和服务器的入口我都放在main.py里通过config.yaml切换回测和模拟盘模式。强烈建议所有令牌、账号信息用环境变量注入不要写死在源码里。我见过有人把API密钥直接提交进了公共仓库那不只是丢脸的问题是真金白银的损失。策略引擎的模型推断核心就这一段逻辑def decide(state_vector): if risk_controller.is_cooling(): return Action.HOLD prob_up, prob_down, prob_flat model.predict_proba(state_vector) if prob_up threshold and atr_percentile 80: return Action.BUY if prob_down threshold and atr_percentile 80: return Action.SELL return Action.HOLD这里的threshold不是固定值而是我在训练后根据验证集设定的分位点保证样本外只有前20%的高置信信号才会触发交易。这样做的结果就是信号数量变少了但每笔交易的质量提高了。这也是我给所有“AI交易机器人”玩家的建议宁可少做不要乱做。7.2 踩过的三个真实坑第一个坑是数据“幸存者偏差”。我一开始回测时只用了近半年的数据某货币对正好处于单边上涨机器人一路做多赚得很漂亮。后来换了另一年的数据测试单边变成了宽幅震荡策略立刻打回原形。教训是回测必须覆盖趋势市、震荡市、高波动、低波动四种环境否则你验证的只是某一种行情下的运气。第二个坑是模型置信度和仓位脱钩。第一版模型决策只有方向没有强度导致即使模型只有 51% 的把握也会照常 2% 风险开仓。后来我改为把预测概率映射成仓位系数概率越高仓位越大最高不超过 3%概率低于阈值直接不开仓。这个改动不提升胜率但显著改善了资金曲线因为系统不会在模型最没把握的时候重仓。第三个坑是“时钟幻觉”。我在模拟盘第一周就发现机器人偶尔会在最后一根K线收盘前就开仓查了半天原来是经纪商服务器的K线收盘时间和本地时间有约30秒的偏差。虽然只有30秒但特征计算里“最新一根K线”已经不一样了。最后我统一用数据源服务器时间戳判断K线是否收盘彻底修复。7.3 后续扩展方向与我的个人体会你如果把这个原型跑通了可以往几个方向扩展。第一把单品种模型升级成多品种组合因为不同货币对的波动结构相关性不高组合起来可以平滑资金曲线。第二加入日历事件因子比如重大经济数据发布前后一小时强制平仓或降低仓位这能躲掉很多黑天鹅。第三把固定模型改成定时重训每周用最新数据增量更新一次模型参数让机器人持续“吸收”新市场信息这就是标题里“会思考”的进阶版本。最后说说我自己的体会。做这个机器人的初衷很简单我不想再天天盯盘想把复盘和决策交给一个能忠实执行纪律的系统。它不是一个印钞机它甚至经常在单边行情里亏钱但它帮助我建立了一套完整的从策略到执行的流水线让我能清晰看到自己交易体系里每一个环节的优劣。如果你只是想找一个躺赚工具我建议你现在就关掉这个网页。如果你想认真研究一个“会思考”的交易系统是怎么造出来的那这套代码和踩坑记录应该能让你少走两个月的弯路。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。