MQL5 Cookbook: 交易历史和取得仓位信息的函数库(基础篇)
📘

MQL5 Cookbook: 交易历史和取得仓位信息的函数库(基础篇)

第 1/3 篇

用 MQL5 把持仓和 history 拉出来

在 MT5 里做复盘或写 EA,第一步往往是把当前持仓和历史订单读准。官方客户端自带的交易类接口分散在 CTrade、HistorySelect 等对象里,自己拼容易漏掉魔术码(magic number)过滤,导致统计错位。 一个实用的做法是用函数库封装两类查询:一是当前仓位枚举(PositionGetTicket + PositionGetInteger),二是历史订单与成交的批量选取(HistorySelect + HistoryDealGetTicket)。下面这段就是最小可用的查询骨架,跑通后你可以直接套进自己的指标里。 根据社区示例页的公开数据,该文发布于 2013-10-29,累计浏览 4 869 次、评论 14 条,说明这类底层封装长期有需求。外汇与贵金属杠杆高,用历史数据回测时务必区分模拟与实盘点差。

MQL5 / C++
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策略测试器用真实点差跑一遍。

MQL5 / C++
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,就能自己写函数遍历持仓算每仓成本。

MQL5 / C++
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">// 初始仓位交易量
  };

常见问题

用持仓函数读 live 仓位,再用 history 相关函数按时间区间遍历已平仓位,分别存结构体数组就能同时拿到。
加仓或复盘类逻辑需要看开平均价、最大回撤等历史数据,只查当前仓会漏掉已平部分的盈亏与信号。
可以,小布能按你设定的品种和周期持续读取历史与持仓结构,出现异常加仓密度或回撤时直接推送提醒。
把品种名、查询天数、最大记录数做成输入参数,初始化时填进仓位结构体,循环里按参数过滤即可。
至少留 ticket、品种、方向、开平时间、开平价、手数、手续费和净盈亏,复盘时才能算出完整权益曲线。