MQL5 Cookbook: 交易历史和取得仓位信息的函数库(基础篇)
用 MQL5 把持仓和 history 拉出来
在 MT5 里做复盘或写 EA,第一步往往是把当前持仓和历史订单读准。官方客户端自带的交易类接口分散在 CTrade、HistorySelect 等对象里,自己拼容易漏掉魔术码(magic number)过滤,导致统计错位。 一个实用的做法是用函数库封装两类查询:一是当前仓位枚举(PositionGetTicket + PositionGetInteger),二是历史订单与成交的批量选取(HistorySelect + HistoryDealGetTicket)。下面这段就是最小可用的查询骨架,跑通后你可以直接套进自己的指标里。 根据社区示例页的公开数据,该文发布于 2013-10-29,累计浏览 4 869 次、评论 14 条,说明这类底层封装长期有需求。外汇与贵金属杠杆高,用历史数据回测时务必区分模拟与实盘点差。
class="type">int total=PositionsTotal(); for(class="type">int i=class="num">0;i<total;i++) { class="type">ulong ticket=PositionGetTicket(i); class="type">long magic=(class="type">long)PositionGetInteger(POSITION_MAGIC); Print("Ticket:",ticket," Magic:",magic); }
「为什么需要单独取历史仓位的属性」
如果你的交易系统里,每个仓位从开到平都保持同一手数,那本文要写的几个函数基本用不上。 但凡是打算做资金管理的策略——比如运行中根据浮盈或回撤动态调仓、分批加減仓——就必须能读取只有交易历史里才有的仓位属性,而不是只看当前持仓快照。 MQL5 里当前仓位和已平仓位分属不同接口,想拿到历史成交的精确手数、入场偏离、平仓原因这些字段,得绕到 history 那边去查。新手若刚接触这套语言,建议先补系列前几篇再回来啃这段代码。
◍ 给加仓型EA补上历史仓位探针
已有持仓时若建仓信号再度出现,多数简易EA只会忽略,或凭POSITION_PRICE_OPEN这类标准标识符去读「当前」开仓价。但加仓后仓位均价必然漂移,想算「首笔进场价」「末笔加仓价」与现价的间距,标准标识符根本给不出,只能去账户交易历史里翻。 原文给出的仓位属性枚举里,新增了P_TOTAL_DEALS=0、P_PRICE_FIRST_DEAL=6、P_PRICE_LAST_DEAL=9、P_INITIAL_VOLUME=12、P_DURATION=16五个标识符,专门承载从交易历史回算的字段。配合HistorySelect(仓位开启时间, 当前时间)或HistorySelectByPosition(仓位编号)把历史拉进内存,再逐笔比对成交时间即可定位首笔与末笔。 用sinput修饰符声明MagicNumber、Deviation、VolumeIncrease、InfoPanel等外部参数,在策略测试器里它们会变灰、不可优化——你很清楚哪些参数是固定设置项,就别让它们占优化组合。把原来散落的全局变量收进struct,用Ctrl+H批量把pos_open之类替换成position_properties.exists,编译零报错才算改干净。 CurrentPositionFirstDealPrice()从开启时间起逐笔读,时间吻合即返回首价;CurrentPositionLastDealPrice()倒序遍历,遇交易品种匹配即停;CurrentPositionInitialVolume()要考虑反转等边界;CurrentPositionDuration()可按秒/分/时/天输出持仓时长。外汇与贵金属杠杆高,这类历史回算逻辑若写错,加仓手数可能偏离预期,实盘前务必在MT5策略测试器用真实点差跑一遍。
class=class="str">"cmt">//--- 仓位属性的枚举 enum ENUM_POSITION_PROPERTIES { P_TOTAL_DEALS = class="num">0, P_SYMBOL = class="num">1, P_MAGIC = class="num">2, P_COMMENT = class="num">3, P_SWAP = class="num">4, P_COMMISSION = class="num">5, P_PRICE_FIRST_DEAL = class="num">6, P_PRICE_OPEN = class="num">7, P_PRICE_CURRENT = class="num">8, P_PRICE_LAST_DEAL = class="num">9, P_PROFIT = class="num">10, P_VOLUME = class="num">11, P_INITIAL_VOLUME = class="num">12, P_SL = class="num">13, P_TP = class="num">14, P_TIME = class="num">15, P_DURATION = class="num">16, P_ID = class="num">17, P_TYPE = class="num">18, P_ALL = class="num">19 }; class=class="str">"cmt">//--- EA交易的外部参数
EA 参数与仓位结构体的落地写法
这套网格类 EA 把可调项分成了 sinput 和 input 两类:MagicNumber=777、Deviation=10、ShowInfoPanel=true 这类属于 sinput,在策略测试器里会被锁定不可实时改;Lot=0.1、StopLoss=50、TakeProfit=100、TrailingStop=10、Reverse=true 则是普通 input,实盘可随时手调。 NumberOfBars=2 表示用最近 2 根牛市或熊市柱作为触发条件,VolumeIncrease=0.1 代表每加一层网格就多开 0.1 手,属于典型的马丁加仓思路,外汇和贵金属杠杆品种里这么跑回撤可能迅速放大,属高风险玩法。 为了让面板和统计能直接读持仓,代码里定义了 position_properties 结构体,字段覆盖 total_deals(成交笔数)、exists(是否有仓)、swap(库存费)、commission(手续费)、first_deal_price 与 last_deal_price(首末笔成交价)、profit 和 volume(浮盈与当前手数)等。你在 MT5 里把这段结构体原样贴进 include,就能自己写函数遍历持仓算每仓成本。
sinput class="type">long MagicNumber=class="num">777; class=class="str">"cmt">// 幻数 sinput class="type">int Deviation=class="num">10; class=class="str">"cmt">// 滑点 input class="type">int NumberOfBars=class="num">2; class=class="str">"cmt">// 用于买/卖的牛市/熊市柱数 input class="type">class="kw">double Lot=class="num">0.1; class=class="str">"cmt">// 手数 input class="type">class="kw">double VolumeIncrease=class="num">0.1; class=class="str">"cmt">// 仓位交易量增加量 input class="type">class="kw">double StopLoss=class="num">50; class=class="str">"cmt">// 止损 input class="type">class="kw">double TakeProfit=class="num">100; class=class="str">"cmt">// 获利 input class="type">class="kw">double TrailingStop=class="num">10; class=class="str">"cmt">// 跟踪止损 input class="type">bool Reverse=true; class=class="str">"cmt">// 反向仓位 sinput class="type">bool ShowInfoPanel=true; class=class="str">"cmt">// 是否显示信息面板 class=class="str">"cmt">//--- 仓位属性 class="kw">struct position_properties { class="type">uint total_deals; class=class="str">"cmt">// 交易数量 class="type">bool exists; class=class="str">"cmt">// 有没有开启仓位的标志 class="type">class="kw">string symbol; class=class="str">"cmt">// 交易品种 class="type">long magic; class=class="str">"cmt">// 幻数 class="type">class="kw">string comment; class=class="str">"cmt">// 注释 class="type">class="kw">double swap; class=class="str">"cmt">// 库存费 class="type">class="kw">double commission; class=class="str">"cmt">// 手续费 class="type">class="kw">double first_deal_price; class=class="str">"cmt">// 仓位中第一笔交易的价格 class="type">class="kw">double price; class=class="str">"cmt">// 仓位当前价格 class="type">class="kw">double current_price; class=class="str">"cmt">// 仓位交易品种的当前价格 class="type">class="kw">double last_deal_price; class=class="str">"cmt">// 仓位最后一笔交易的价格 class="type">class="kw">double profit; class=class="str">"cmt">// 仓位的利润/亏损 class="type">class="kw">double volume; class=class="str">"cmt">// 当前仓位交易量 class="type">class="kw">double initial_volume; class=class="str">"cmt">// 初始仓位交易量 };