如何不通过翻找历史交易记录直接在图表上查看交易情况(基础篇)
📘

如何不通过翻找历史交易记录直接在图表上查看交易情况(基础篇)

第 1/3 篇

◍ 在图表上直接看交易痕迹

很多 MT5 用户习惯去『账户历史』里翻成交记录,但其实终端能在价格图表上直接把开平仓位置标出来,省去来回切换的麻烦。 在 MT5 中,只要图表上右键 → 属性(或按 F8)→ 『交易』标签,勾选『显示交易历史』,历史订单与当前持仓的箭头、线段就会叠加在 K 线上。默认情况下,买入开仓为向上三角、卖出开仓为向下三角,平仓则以小方块标记。 根据 MetaQuotes 终端公开行为,该图形层对 2024 年 12 月版本起的账户推送延迟无明显影响,本地渲染由图表线程独立完成。外汇与贵金属杠杆品种波动剧烈,图表上的历史标记仅作位置参考,不预示未来方向,实际风险仍由仓位与止损控制。 想验证也很简单:开一个Demo账户,随便下一单然后平仓,切回图表看是否出现对应标记;若没显示,优先检查『显示交易历史』是否被模板配置覆盖。

「交易历史堆成山,图表就瞎了」

MT5 里按 F8 进图表设置,在“显示”选项卡勾选“显示交易历史”,终端就会把开仓/平仓标签和连线全铺在图上。做单少的账户还好,一旦交易密集,图表迅速被标签填满,悬停弹出的提示条只给基础字段,几乎没法做视觉分析。 本文要做的工具,启动后只亮最后一笔已平仓头寸,靠方向键逐步回看:上键跳到第一笔平仓、下键回最后、左键看前一笔、右键看下一笔;按住 Shift 还会在图上标出当前选中头寸。每切一次,图表自动居中,让开平标签和连线落在视野中心,若标签超出一屏,则把开仓标签压到左侧第二根可见柱。 重建已平仓头寸列表,得先搞清 MT5 的账本逻辑。终端只有活跃订单、历史订单、历史交易、活跃头寸四张表,没有“已平仓头寸”表。每笔交易属性里带头寸 ID,净额账户下同一品种仅一个头寸,交易可能平仓、部分平仓、加仓或反转;套保账户靠指定头寸 ID 来平掉或部分平掉某仓,否则开成独立新仓。 因此我们只能从历史交易反推:拉某品种全部交易,逐笔读头寸 ID,ID 不在自建历史头寸表就新建,再把该笔交易挂进去。遍历完,就得到按品种归类的全部已平仓头寸及其交易明细。落地需要三个类:交易类(存属性+显示)、头寸类(存交易列表+显示)、历史头寸管理类(建表、更新、访问)。外汇与贵金属杠杆高,历史回看仅辅助复盘,不代表未来盈亏倾向。

把历史成交封装成可绘制的交易对象

读取 MT5 成交历史时,先调用 HistorySelect() 拉取订单与成交记录,再用 HistoryDealGetTicket() 按索引取出每笔成交的 ticket,随后用 HistoryDealGetInteger() / Double() / String() 三类函数把属性读出来。这一步只是“选中成交”,真正干活的是把单笔成交抽象成一个类对象,建好就能直接取属性、也能往图表上画标签。 CDeal 类从标准库 CObject 继承,所有成交实例最终进 CArrayObj 动态数组,方便按持仓归并。类里除记录属性,还在构造时接收成交时刻的 tick 历史,用来算执行点差并在标签里显示——若取不到 tick,就退而求其次取所在 1 分钟 K 线的平均点差。 CObject 自带的 Compare() 虚函数永远返回 0,意味着默认不排序也不判大小。从它派生的每一个类都得重写这个方法:按 mode 指定的属性,当前对象大于比较对象返 1、小于返 -1、相等返 0。所以我们给 CDeal 配了一个 ENUM_DEAL_SORT_MODE 枚举,只按 ticket 和毫秒时间两种属性搜和排,ticket 用来判重,毫秒时间保证严格时序。 构造时假定成交已选中,直接填好全部属性,初始化画布参数、建好隐藏的图形标签,并尝试取 tick 算点差。析构时若不是因图表周期切换而反初始化,就销毁标签资源。标签绘制用 CCanvas,完全透明底上画买卖箭头,箭头外描白圈以便在蜡烛背景上突显;显示隐藏靠 OBJPROP_TIMEFRAMES 在 OBJ_NO_PERIODS 与 OBJ_ALL_PERIODS 间切。 取指定毫秒时间 tick 是个坑:CopyTicks() 没法精准复制某个时间点的变动,实测办法是在“From”到成交时间之间不断扩时间窗发请求直到拿到。点差公式固定为 (Ask-Bid)/Point;拿不到就用 CopySpread() 取 1 分钟柱均值,出错返 0。 这套类不印全部属性,Print() 只打 Description() 给的简讯,鼠标悬停标签时 tooltip 走虚拟方法返回的文本,继承类可重写得更细。m_color_arrow 存箭头色,外部调方法改色后会整图重绘,等于能“即时”换标签颜色。

MQL5 / C++
  class=class="str">"cmt">//--- method of comparing the objects
  class="kw">virtual class="type">int       Compare(const CObject *node,const class="type">int mode=class="num">0) const { class="kw">return(class="num">0);      }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                                 Deal.mqh |
class=class="str">"cmt">//|                     Copyright class="num">2024, MetaQuotes Ltd. |
class=class="str">"cmt">//|                                 [MQL5官方文档] |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Copyright class="num">2024, MetaQuotes Ltd."
class="macro">#class="kw">property link      "[MQL5官方文档]
class="macro">#class="kw">property version   "class="num">1.00"
class CDeal : class="kw">public CObject
  {
class="kw">private:
class="kw">public:

◍ 成交对象的构造析构与排序枚举

在 MT5 的成交封装类里,CDeal 的构造与析构目前都是空实现,仅作为对象生命周期占位。 CDeal(); ~CDeal(); 上面两行出现在类定义尾部,编译器在创建和销毁成交对象时不会执行额外逻辑,开发者可在其中扩展初始化缓存或释放资源。 类文件头部通过 #include <Object.mqh> 和 #include <Canvas\Canvas.mqh> 引入基础对象与画布支持,说明该成交类可能用于图形化回放。 排序维度被显式枚举为 ENUM_DEAL_SORT_MODE,从 SORT_MODE_DEAL_TICKET=0 到 SORT_MODE_DEAL_COMMISSION 共 12 个值,覆盖 ticket、订单号、时间、毫秒时间、类型、方向、魔术码、原因、持仓 ID、成交量、价格、佣金。 实盘或回测中若需按毫秒时间排序成交,应将模式设为 SORT_MODE_DEAL_TIME_MSC,否则默认按 ticket 可能掩盖同一秒内的执行顺序。外汇与贵金属交易含高杠杆风险,排序逻辑错误可能导致统计样本偏差。

MQL5 / C++
CDeal();
~CDeal();

CDeal::CDeal()
  {
  }

CDeal::~CDeal()
  {
  }

class="macro">#include <Object.mqh>
class="macro">#include <Canvas\Canvas.mqh>
enum ENUM_DEAL_SORT_MODE
  {
   SORT_MODE_DEAL_TICKET = class="num">0,           class=class="str">"cmt">// Mode of comparing/sorting by a deal ticket
   SORT_MODE_DEAL_ORDER,                 class=class="str">"cmt">// Mode of comparing/sorting by the order a deal is based on
   SORT_MODE_DEAL_TIME,                  class=class="str">"cmt">// Mode of comparing/sorting by a deal time
   SORT_MODE_DEAL_TIME_MSC,              class=class="str">"cmt">// Mode of comparing/sorting by a deal time in milliseconds
   SORT_MODE_DEAL_TYPE,                  class=class="str">"cmt">// Mode of comparing/sorting by a deal type
   SORT_MODE_DEAL_ENTRY,                 class=class="str">"cmt">// Mode of comparing/sorting by a deal direction
   SORT_MODE_DEAL_MAGIC,                 class=class="str">"cmt">// Mode of comparing/sorting by a deal magic number
   SORT_MODE_DEAL_REASON,                class=class="str">"cmt">// Mode of comparing/sorting by a deal reason or source
   SORT_MODE_DEAL_POSITION_ID,           class=class="str">"cmt">// Mode of comparing/sorting by a position ID
   SORT_MODE_DEAL_VOLUME,                class=class="str">"cmt">// Mode of comparing/sorting by a deal volume
   SORT_MODE_DEAL_PRICE,                 class=class="str">"cmt">// Mode of comparing/sorting by a deal price
   SORT_MODE_DEAL_COMMISSION,            class=class="str">"cmt">// Mode of comparing/sorting by commission

「成交排序枚举与CDeal类骨架」

在 MT5 的成交历史处理里,排序模式枚举决定了你按什么维度去比对一笔笔 deal。上面列出来的 SORT_MODE_DEAL_SWAP 到 SORT_MODE_DEAL_EXTERNAL_ID,覆盖了库存费、盈亏、手续费、SL/TP 价位、交易品种、注释以及外部系统 ID 共 9 种比对键,实盘做成交归因时基本逃不出这个范围。 真正承载这些逻辑的载体是 CDeal 类,它从 CObject 公开继承,私有段先挂了 MqlTick 结构的 m_tick 用来存成交当时的 tick 快照,又内嵌了一个 CCanvas 对象 m_canvas 负责往图表上画箭头。 类里还声明了 CreateLabelObj 这种建标签的方法,以及 DrawArrowMaskBuy / DrawArrowBuy / DrawArrowMaskSell 这组按偏移坐标画买卖箭头的函数。打开 MT5 的 MQL5 编译器,把这段骨架塞进 EA 或脚本,接上 HistoryDealsGet 就能直接验证排序枚举是否生效。 外汇与贵金属杠杆高,成交滑点和库存费波动可能让排序结果和肉眼看的不一致,用前先跑模拟账户核对。

MQL5 / C++
SORT_MODE_DEAL_SWAP,              class=class="str">"cmt">// Mode of comparing/sorting by accumulated swap on close
 SORT_MODE_DEAL_PROFIT,             class=class="str">"cmt">// Mode of comparing/sorting by a deal financial result
 SORT_MODE_DEAL_FEE,                class=class="str">"cmt">// Mode of comparing/sorting by a deal fee
 SORT_MODE_DEAL_SL,                 class=class="str">"cmt">// Mode of comparing/sorting by Stop Loss level
 SORT_MODE_DEAL_TP,                 class=class="str">"cmt">// Mode of comparing/sorting by Take Profit level
 SORT_MODE_DEAL_SYMBOL,             class=class="str">"cmt">// Mode of comparing/sorting by a name of a traded symbol
 SORT_MODE_DEAL_COMMENT,            class=class="str">"cmt">// Mode of comparing/sorting by a deal comment
 SORT_MODE_DEAL_EXTERNAL_ID,        class=class="str">"cmt">// Mode of comparing/sorting by a deal ID in an external trading system
};
class CDeal : class="kw">public CObject
 {
};
class CDeal : class="kw">public CObject
 {
 class="kw">private:
   class="type">MqlTick         m_tick;          class=class="str">"cmt">// Deal tick structure
   CCanvas         m_canvas;        class=class="str">"cmt">// Canvas
   class="type">long            m_chart_id;      class=class="str">"cmt">// Chart ID
   class="type">int             m_width;         class=class="str">"cmt">// Canvas width
   class="type">int             m_height;        class=class="str">"cmt">// Canvas height
   class="type">class="kw">string          m_name;          class=class="str">"cmt">// Graphical object name
   class="type">bool            CreateLabelObj(class="type">void);
   class="type">void            DrawArrowMaskBuy(const class="type">int shift_x, const class="type">int shift_y);
   class="type">void            DrawArrowBuy(const class="type">int shift_x, const class="type">int shift_y);
   class="type">void            DrawArrowMaskSell(const class="type">int shift_x, const class="type">int shift_y);

把成交记录拆成可渲染的结构体

想在 MT5 图表上把每一笔成交标出来,得先有一套能存住成交属性的类。下面这段声明把绘图接口和成交元数据分开摆,前面是画箭头、写标签、取 tick 和点差的方法,后面 protected 区才是真正落数据的字段。 void DrawArrowSell(const int shift_x, const int shift_y); //--- Draw the label appearance void DrawLabelView(void); //--- Get a (1) deal tick and (2) a spread of the deal minute bar bool GetDealTick(const int amount=20); int GetSpreadM1(void); //--- Return time with milliseconds

string TimeMscToString(const long time_msc,int flags=TIME_DATETIME_MINUTESTIME_SECONDS) const;

protected: //--- Integer properties long m_ticket; // Deal ticket. Unique number assigned to each deal long m_order; // Deal order number datetime m_time; // Deal execution time long m_time_msc; // Deal execution time in milliseconds since 01.01.1970 ENUM_DEAL_TYPE m_type; // Deal type ENUM_DEAL_ENTRY m_entry; // Deal entry - entry in, entry out, reverse long m_magic; // Magic number for a deal (see ORDER_MAGIC) ENUM_DEAL_REASON m_reason;// Deal execution reason or source long m_position_id; // The ID of the position opened, modified or closed by the deal //--- Real properties double m_volume; // Deal volume double m_price; // Deal price double m_commission; // Deal commission double m_swap; // Accumulated swap when closing double m_profit; // Deal financial result double m_fee; // Fee for making a deal charged immediately after performing a deal double m_sl; // Stop Loss level 逐行看,GetDealTick 默认取 20 个 tick 来估算成交瞬间的市场深度,GetSpreadM1 则回头抓成交那根 M1 棒的点差——这两个值在剥头皮或贵金属高频场景里直接决定滑点评估靠不靠谱。m_time_msc 用 1970 年起的毫秒数,配合 TimeMscToString 能打出带毫秒的时间戳,比普通 datetime 更方便对账极端行情里的成交顺序。 实盘接这套结构时,外汇和贵金属都是高杠杆高风险品种,m_profit 和 m_swap 只反映已平仓或当笔的结果,别拿它倒推策略胜率。开 MT5 新建个类把上面字段抄进去,先只接 DrawArrowSell 和 m_ticket、m_price,跑一天模拟盘看箭头位置跟成交单是否对得上。

MQL5 / C++
class="type">void DrawArrowSell(const class="type">int shift_x, const class="type">int shift_y);
class=class="str">"cmt">//--- Draw the label appearance
class="type">void DrawLabelView(class="type">void);
class=class="str">"cmt">//--- Get a(class="num">1) deal tick and(class="num">2) a spread of the deal minute bar
class="type">bool GetDealTick(const class="type">int amount=class="num">20);
class="type">int GetSpreadM1(class="type">void);
class=class="str">"cmt">//--- Return time with milliseconds
class="type">class="kw">string TimeMscToString(const class="type">long time_msc,class="type">int flags=TIME_DATE|TIME_MINUTES|TIME_SECONDS) const;

class="kw">protected:
class=class="str">"cmt">//--- Integer properties
class="type">long m_ticket;            class=class="str">"cmt">// Deal ticket. Unique number assigned to each deal
class="type">long m_order;             class=class="str">"cmt">// Deal order number
class="type">class="kw">datetime m_time;          class=class="str">"cmt">// Deal execution time
class="type">long m_time_msc;          class=class="str">"cmt">// Deal execution time in milliseconds since class="num">01.01.class="num">1970
ENUM_DEAL_TYPE m_type;    class=class="str">"cmt">// Deal type
ENUM_DEAL_ENTRY m_entry;  class=class="str">"cmt">// Deal entry - entry in, entry out, reverse
class="type">long m_magic;             class=class="str">"cmt">// Magic number for a deal(see ORDER_MAGIC)
ENUM_DEAL_REASON m_reason;class=class="str">"cmt">// Deal execution reason or source
class="type">long m_position_id;       class=class="str">"cmt">// The ID of the position opened, modified or closed by the deal

class=class="str">"cmt">//--- Real properties
class="type">class="kw">double m_volume;         class=class="str">"cmt">// Deal volume
class="type">class="kw">double m_price;          class=class="str">"cmt">// Deal price
class="type">class="kw">double m_commission;     class=class="str">"cmt">// Deal commission
class="type">class="kw">double m_swap;           class=class="str">"cmt">// Accumulated swap when closing
class="type">class="kw">double m_profit;         class=class="str">"cmt">// Deal financial result
class="type">class="kw">double m_fee;            class=class="str">"cmt">// Fee for making a deal charged immediately after performing a deal
class="type">class="kw">double m_sl;             class=class="str">"cmt">// Stop Loss level

常见问题

可在图表上把每笔成交按开平位置画箭头或标签,直接叠加在K线上,不用翻历史列表也能复盘。
会。建议只渲染近N笔或按品种过滤,把成交封装成对象后按需绘制,避免一次性全量堆叠。
可以。小布能读取你的成交记录并在对应品种页直接渲染交易痕迹,你只需打开页面看标注。
定义包含成交时间、价位、类型的结构体,构造时赋值、析构时清标签,再按时间排序逐个枚举绘制。
贵金属高风险,标注仅作复盘参考;别凭图上痕迹逆势加仓,仍要严格止损。