如何不通过翻找历史交易记录直接在图表上查看交易情况·进阶篇
📈

如何不通过翻找历史交易记录直接在图表上查看交易情况·进阶篇

(2/3)·图表被历史标签糊满看不清?本篇教你用光标键逐一调出平仓单并居中显示

案例拆解新手友好 第 2/3 篇
勾了“显示交易历史”后图表秒变标签海,鼠标悬停提示却只有开平价格,这种无效信息密度反而拖慢复盘。其实终端能在启动后只亮最后一笔平仓,用方向键逐步往前翻,比翻账户历史快得多。

成交对象里的字段与赋值入口

在 MT5 自建交易类里,一笔 deal 的基础属性通常拆成数值、字符串和行情三类成员。下面这段声明把止盈价、品种名、外部系统 ID、点值、买卖盘口都塞进同一个结构,方便后续在图表上还原当时上下文。 double m_tp; // 止盈价位 double m_bid; // 成交时的买价 double m_ask; // 成交时的卖价 int m_spread; // 成交时的点差(以整数点计) string m_symbol; // 成交品种名称 string m_external_id; // 交易所/外部系统里的成交编号 这些字段不是摆设。m_point 和 m_digits 决定了挂单偏移要不要按品种精度四舍五入;m_bid/m_ask 留痕后,你回看箭头标记就能算出当时真实滑点可能偏向哪边。 公开区的 Set 方法是一对一写字段,例如 SetTicket(long) 直接改 m_ticket,SetTypeDeal(ENUM_DEAL_TYPE) 定买卖类别。复制进 EA 头文件,把 DrawArrow() 留作虚函数,子类重写就能换箭头样式,不用碰核心数据层。 外汇与贵金属杠杆高,m_spread 在消息行情里可能瞬间扩到日常 5~10 倍,用这类结构做复盘时别把样本期的点差当常态。

MQL5 / C++
  class="type">class="kw">double                m_tp;                                          class=class="str">"cmt">// Take Profit level
class=class="str">"cmt">//--- String properties
  class="type">class="kw">string                m_symbol;                                      class=class="str">"cmt">// Name of the symbol for which the deal is executed
  class="type">class="kw">string                m_comment;                                     class=class="str">"cmt">// Deal comment
  class="type">class="kw">string                m_external_id;                                 class=class="str">"cmt">// Deal ID in an external trading system(on the exchange)

class=class="str">"cmt">//--- Additional properties
  class="type">int                   m_digits;                                      class=class="str">"cmt">// Symbol digits
  class="type">class="kw">double                m_point;                                       class=class="str">"cmt">// Symbol point
  class="type">class="kw">double                m_bid;                                         class=class="str">"cmt">// Bid when performing a deal
  class="type">class="kw">double                m_ask;                                         class=class="str">"cmt">// Ask when performing a deal
  class="type">int                   m_spread;                                      class=class="str">"cmt">// Spread when performing a deal
  class="type">class="kw">color                 m_color_arrow;                                 class=class="str">"cmt">// Deal label class="type">class="kw">color

class=class="str">"cmt">//--- Draws an arrow corresponding to the deal type. It can be redefined in the inherited classes
  class="kw">virtual class="type">void          DrawArrow(class="type">void);
class="kw">public:
class=class="str">"cmt">//--- Set the properties
class=class="str">"cmt">//--- Integer properties
  class="type">void                  SetTicket(const class="type">long ticket)                   { this.m_ticket=ticket;     }   class=class="str">"cmt">// Ticket
  class="type">void                  SetOrder(const class="type">long order)                     { this.m_order=order;       }   class=class="str">"cmt">// Order
  class="type">void                  SetTime(const class="type">class="kw">datetime time)                   { this.m_time=time;         }   class=class="str">"cmt">// Time
  class="type">void                  SetTimeMsc(const class="type">long value)                   { this.m_time_msc=value;    }   class=class="str">"cmt">// Time in milliseconds
  class="type">void                  SetTypeDeal(const ENUM_DEAL_TYPE type)         { this.m_type=type;         }   class=class="str">"cmt">// Type
  class="type">void                  SetEntry(const ENUM_DEAL_ENTRY entry)          { this.m_entry=entry;       }   class=class="str">"cmt">// Direction

◍ 订单结构里的字段写入接口

在 MT5 的自定义交易类里,这组 Set 方法负责把外部计算好的参数写进私有成员,相当于给一笔挂单或成交对象逐字段赋值。 从代码看,标识类字段(magic、reason、position_id)与真实数值字段(volume、price、commission、swap、profit、fee、sl、tp)是分开声明的,字符串类还有 symbol 与 comment。这种分层在回测日志排查时很有用:比如同一 magic 下若 swap 累计异常,可直接定位 SetSwap 的调用链。 [CODE] 逐行拆解: void SetMagic(const long magic) { this.m_magic=magic; } // 写入魔数,区分 EA 交易批次 void SetReason(const ENUM_DEAL_REASON reason) { this.m_reason=reason; } // 写入成交来源(脚本/EA/手动) void SetPositionID(const long id) { this.m_position_id=id; } // 绑定持仓 ID void SetVolume(const double volume) { this.m_volume=volume; } // 手数 void SetPrice(const double price) { this.m_price=price; } // 挂单或成交价 void SetCommission(const double value) { this.m_commission=value; } // 佣金 void SetSwap(const double value) { this.m_swap=value; } // 平仓时累计掉期 void SetProfit(const double value) { this.m_profit=value; } // 财务结果 void SetFee(const double value) { this.m_fee=value; } // 交易费 void SetSL(const double value) { this.m_sl=value; } // 止损位 void SetTP(const double value) { this.m_tp=value; } // 止盈位 void SetSymbol(const string symbol) { this.m_symbol=symbol; } // 品种名 void SetComment(const string comment) { this.m_comment=comment; } // 备注 实盘或复盘时,外汇与贵金属波动受杠杆与消息面影响大,高风险特征明显;建议你在 MT5 里新建一个 test script,依次调用这组 Set 方法后打印结构体,确认每字段写入无误再接入下单逻辑。

MQL5 / C++
  class="type">void                SetMagic(const class="type">long magic)                  { this.m_magic=magic;          }  class=class="str">"cmt">// Magic number
  class="type">void                SetReason(const ENUM_DEAL_REASON reason)  { this.m_reason=reason;        }  class=class="str">"cmt">// Deal execution reason or source
  class="type">void                SetPositionID(const class="type">long id)              { this.m_position_id=id;       }  class=class="str">"cmt">// Position ID

class=class="str">"cmt">//--- Real properties
  class="type">void                SetVolume(const class="type">class="kw">double volume)            { this.m_volume=volume;        }  class=class="str">"cmt">// Volume
  class="type">void                SetPrice(const class="type">class="kw">double price)              { this.m_price=price;          }  class=class="str">"cmt">// Price
  class="type">void                SetCommission(const class="type">class="kw">double value)         { this.m_commission=value;     }  class=class="str">"cmt">// Commission
  class="type">void                SetSwap(const class="type">class="kw">double value)               { this.m_swap=value;           }  class=class="str">"cmt">// Accumulated swap when closing
  class="type">void                SetProfit(const class="type">class="kw">double value)             { this.m_profit=value;         }  class=class="str">"cmt">// Financial result
  class="type">void                SetFee(const class="type">class="kw">double value)                { this.m_fee=value;            }  class=class="str">"cmt">// Deal fee
  class="type">void                SetSL(const class="type">class="kw">double value)                 { this.m_sl=value;             }  class=class="str">"cmt">// Stop Loss level
  class="type">void                SetTP(const class="type">class="kw">double value)                 { this.m_tp=value;             }  class=class="str">"cmt">// Take Profit level
class=class="str">"cmt">//--- String properties
  class="type">void                SetSymbol(const class="type">class="kw">string symbol)            { this.m_symbol=symbol;        }  class=class="str">"cmt">// Symbol name
  class="type">void                SetComment(const class="type">class="kw">string comment)          { this.m_comment=comment;      }  class=class="str">"cmt">// Comment

「从成交对象里直接抠出 Ticket 和毫秒时间」

在 MT5 的 CDeal 类封装里,成交记录不是靠 HistoryDealGetXXX 一个个字段去查,而是把属性做成成员函数直接返回。下面这段是类里取属性的一段典型实现,开 MT5 新建个 include 文件就能原样编译。 代码里分了整数属性和实数属性两块。整数块里 Ticket() 返回 m_ticket,这是成交在交易历史里的唯一编号;TimeMsc() 返回 m_time_msc,精度到毫秒,比 Time() 的秒级 datetime 更适合做高频去重。 实数块目前只露出 Volume() 返回 m_volume,即成交手数。注意所有 getter 都带 const 修饰,说明它们不改动对象内部状态,可以放心在回测或实盘事件里反复调用。 外汇和贵金属杠杆高,用 PositionID() 和 Magic() 交叉过滤自己的 EA 成交,能避免把手动单误判成策略单,从而降低统计偏差的概率。

MQL5 / C++
class="type">void SetExternalID(const class="type">class="kw">string ext_id) { this.m_external_id=ext_id; } class=class="str">"cmt">// Deal ID in an external trading system
class=class="str">"cmt">//--- Get the properties
class=class="str">"cmt">//--- Integer properties
  class="type">long Ticket(class="type">void) const { class="kw">return(this.m_ticket); } class=class="str">"cmt">// Ticket
  class="type">long Order(class="type">void) const { class="kw">return(this.m_order); } class=class="str">"cmt">// Order
  class="type">class="kw">datetime Time(class="type">void) const { class="kw">return(this.m_time); } class=class="str">"cmt">// Time
  class="type">long TimeMsc(class="type">void) const { class="kw">return(this.m_time_msc); } class=class="str">"cmt">// Time in milliseconds
  ENUM_DEAL_TYPE TypeDeal(class="type">void) const { class="kw">return(this.m_type); } class=class="str">"cmt">// Type
  ENUM_DEAL_ENTRY Entry(class="type">void) const { class="kw">return(this.m_entry); } class=class="str">"cmt">// Direction
  class="type">long Magic(class="type">void) const { class="kw">return(this.m_magic); } class=class="str">"cmt">// Magic number
  ENUM_DEAL_REASON Reason(class="type">void) const { class="kw">return(this.m_reason); } class=class="str">"cmt">// Deal execution reason or source
  class="type">long PositionID(class="type">void) const { class="kw">return(this.m_position_id); } class=class="str">"cmt">// Position ID

class=class="str">"cmt">//--- Real properties
  class="type">class="kw">double Volume(class="type">void) const { class="kw">return(this.m_volume); } class=class="str">"cmt">// Volume

持仓对象的只读取值接口

在自定义持仓类里,这一组方法全部声明为 const,意味着调用时不会改动对象内部状态,只把私有成员吐出来供外部读取。 Price() 返回 m_price,即开仓或标记价格;Commission() 与 Fee() 分别给出佣金和单笔成交手续费,两者在 MT5 真实账户中常不同步计入浮盈。Swap() 返回平仓时累计的库存费,隔夜持仓超过 24 小时才可能显著。 Profit() 是财务结果,未扣除 fee 前它可能为正但净值仍亏,验证时要把 Profit() 减 Fee() 再减 Commission()。SL() / TP() 直接给止损止盈价位,若返回 0 表示该侧未挂。 Bid() / Ask() / Spread() 保留成交瞬间的市场快照:Spread() 为 int 类型,通常是点差点数,比如 EURUSD 在流动性正常时可能为 8~12 点。Symbol() 返回品种名字符串,便于在多品种回测里区分持仓来源。 把这些方法直接贴进你的 .mqh 结构体,编译后可在 EA 里写 double net = pos.Profit() - pos.Fee() - pos.Commission(); 做净收益判断,比只看 Profit() 更接近实盘。

MQL5 / C++
class="type">class="kw">double Price(class="type">void) const { class="kw">return(this.m_price); } class=class="str">"cmt">// Price
class="type">class="kw">double Commission(class="type">void) const { class="kw">return(this.m_commission); } class=class="str">"cmt">// Commission
class="type">class="kw">double Swap(class="type">void) const { class="kw">return(this.m_swap); } class=class="str">"cmt">// Accumulated swap when closing
class="type">class="kw">double Profit(class="type">void) const { class="kw">return(this.m_profit); } class=class="str">"cmt">// Financial result
class="type">class="kw">double Fee(class="type">void) const { class="kw">return(this.m_fee); } class=class="str">"cmt">// Deal fee
class="type">class="kw">double SL(class="type">void) const { class="kw">return(this.m_sl); } class=class="str">"cmt">// Stop Loss level
class="type">class="kw">double TP(class="type">void) const { class="kw">return(this.m_tp); } class=class="str">"cmt">// Take Profit level

class="type">class="kw">double Bid(class="type">void) const { class="kw">return(this.m_bid); } class=class="str">"cmt">// Bid when performing a deal
class="type">class="kw">double Ask(class="type">void) const { class="kw">return(this.m_ask); } class=class="str">"cmt">// Ask when performing a deal
class="type">int Spread(class="type">void) const { class="kw">return(this.m_spread); } class=class="str">"cmt">// Spread when performing a deal

class=class="str">"cmt">//--- String properties
class="type">class="kw">string Symbol(class="type">void) const { class="kw">return(this.m_symbol); } class=class="str">"cmt">// Symbol name

◍ 扒开 CDeal 类的存取与绘制接口

在 MT5 标准库的交易历史封装里,CDeal 类把每笔成交的元数据拆成了可直接调用的成员函数。想在自己的 EA 里把某笔单的备注和外部系统 ID 捞出来,直接读 Comment() 与 ExternalID() 即可,两者都带 const 修饰,不会改动底层结构。 下面这段声明展示了标签颜色与图表显隐的控制入口:SetColorArrow 负责改箭头色,HideArrow / ShowArrow 的入参 chart_redraw 默认 false,意味着你批量隐藏十笔成交时若都走默认,可能只在最后一次手动 Refresh() 才整图重绘,CPU 占用倾向更低。 TypeDescription、EntryDescription、ReasonDescription 三个函数把枚举型的成交类型、开平方式和触发原因转成人类可读字符串,做日志或悬浮提示时比硬查 DEAL_TYPE 枚举省事。Description 与虚函数 Tooltip 则分别给出简描和鼠标悬停文本,Print 一键把属性喷到专家日志。 构造函数重载值得注意:无参版 CDeal(void) 仅把 m_ticket 置 0,带 ulong ticket 的版本才真正绑定某笔历史成交。若你传了不存在的 ticket,后续取属性大概率返回空或零值,开 MT5 用 HistoryDealGetTicket 先校验再 new 才稳。

MQL5 / C++
class="type">class="kw">string Comment(class="type">void) const { class="kw">return(this.m_comment); }  class=class="str">"cmt">// Comment
class="type">class="kw">string ExternalID(class="type">void) const { class="kw">return(this.m_external_id); } class=class="str">"cmt">// Deal ID in an external trading system

class=class="str">"cmt">//--- Set the class="type">class="kw">color of the deal label
class="type">void SetColorArrow(const class="type">class="kw">color clr);
class=class="str">"cmt">//--- (class="num">1) Hide, (class="num">2) display the deal label on a chart
class="type">void HideArrow(const class="type">bool chart_redraw=false);
class="type">void ShowArrow(const class="type">bool chart_redraw=false);
class=class="str">"cmt">//--- Return the description of a(class="num">1) deal type, (class="num">2) position change method and(class="num">3) deal reason
class="type">class="kw">string TypeDescription(class="type">void) const;
class="type">class="kw">string EntryDescription(class="type">void) const;
class="type">class="kw">string ReasonDescription(class="type">void) const;

class=class="str">"cmt">//--- Return(class="num">1) a class="type">short description and(class="num">2) a tooltip text of a deal
class="type">class="kw">string Description(class="type">void);
class="kw">virtual class="type">class="kw">string Tooltip(class="type">void);
class=class="str">"cmt">//--- Print deal properties in the journal
class="type">void Print(class="type">void);

class=class="str">"cmt">//--- Compare two objects by the class="kw">property specified in &class="macro">#x27;mode&class="macro">#x27;
class="kw">virtual class="type">int Compare(const CObject *node, const class="type">int mode=class="num">0) const;

class=class="str">"cmt">//--- Constructors/destructor
 CDeal(class="type">void) { this.m_ticket=class="num">0; }
 CDeal(const class="type">ulong ticket);
~CDeal();
};

CDeal::CDeal(const class="type">ulong ticket)
 {
 this.m_ticket = (class="type">long)ticket; class=class="str">"cmt">// Deal ticket

「从成交单号回填一笔历史交易的全字段」

在 EA 回测或实盘复盘里,拿到一个 deal ticket 后,第一件事就是把它对应的整数、双精度、字符串属性全部读出来塞进结构体。下面这段就是典型的回填逻辑,整数类用 HistoryDealGetInteger,双精度类用 HistoryDealGetDouble。 整数属性里最容易被忽略的是 DEAL_TIME_MSC,它给出毫秒级成交时间,在做高频出场归因时比 DEAL_TIME 的秒级精度更有用;DEAL_POSITION_ID 则用来把多笔平仓 deal 归并到同一个持仓上。 双精度属性中 DEAL_FEE 和 DEAL_SWAP 要分开看:前者是经纪商额外手续费,后者是隔夜利息,二者都会直接吃掉 DEAL_PROFIT 的净值。外汇与贵金属杠杆高,swap 在周三翻三倍时可能让隔夜仓成本陡增,复盘时务必单独拉出来核对。 代码只列到字符串属性之前,但读法一致:字符串类用 HistoryDealGetString 取品种名、comment 等。开 MT5 按 F4 把这段粘进你的 CDeal 类,改一下成员变量名就能直接跑。

MQL5 / C++
  this.m_order      =  ::HistoryDealGetInteger(ticket, DEAL_ORDER);             class=class="str">"cmt">// Order
  this.m_time       =  (class="type">class="kw">datetime)::HistoryDealGetInteger(ticket, DEAL_TIME);       class=class="str">"cmt">// Deal execution time
  this.m_time_msc   =  ::HistoryDealGetInteger(ticket, DEAL_TIME_MSC);             class=class="str">"cmt">// Deal execution time in milliseconds
  this.m_type       =  (ENUM_DEAL_TYPE)::HistoryDealGetInteger(ticket, DEAL_TYPE); class=class="str">"cmt">// Type
  this.m_entry      =  (ENUM_DEAL_ENTRY)::HistoryDealGetInteger(ticket, DEAL_ENTRY); class=class="str">"cmt">// Direction
  this.m_magic      =  ::HistoryDealGetInteger(ticket, DEAL_MAGIC);                class=class="str">"cmt">// Magic number
  this.m_reason     =  (ENUM_DEAL_REASON)::HistoryDealGetInteger(ticket, DEAL_REASON); class=class="str">"cmt">// Deal execution reason or source
  this.m_position_id=  ::HistoryDealGetInteger(ticket, DEAL_POSITION_ID);          class=class="str">"cmt">// Position ID

class=class="str">"cmt">//--- Real properties
  this.m_volume     =  ::HistoryDealGetDouble(ticket, DEAL_VOLUME);                class=class="str">"cmt">// Volume
  this.m_price      =  ::HistoryDealGetDouble(ticket, DEAL_PRICE);                 class=class="str">"cmt">// Price
  this.m_commission =  ::HistoryDealGetDouble(ticket, DEAL_COMMISSION);            class=class="str">"cmt">// Commission
  this.m_swap       =  ::HistoryDealGetDouble(ticket, DEAL_SWAP);                  class=class="str">"cmt">// Accumulated swap when closing
  this.m_profit     =  ::HistoryDealGetDouble(ticket, DEAL_PROFIT);                class=class="str">"cmt">// Financial result
  this.m_fee        =  ::HistoryDealGetDouble(ticket, DEAL_FEE);                   class=class="str">"cmt">// Deal fee
  this.m_sl         =  ::HistoryDealGetDouble(ticket, DEAL_SL);                    class=class="str">"cmt">// Stop Loss level
  this.m_tp         =  ::HistoryDealGetDouble(ticket, DEAL_TP);                    class=class="str">"cmt">// Take Profit level
class=class="str">"cmt">//--- String properties
把逐笔翻单交给小布盯盘
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到每笔平仓的居中高亮与提示条增强,你只需用方向键节奏把控自己的复盘路径。

常见问题

在图表设置关闭默认全量历史显示,改用本文的逐笔展示机制,启动后仅渲染最后一笔平仓,按上下左右键切换其余单。
向上键跳到第一笔平仓,向下键回到最后笔,左键看前一笔记,右箭头看下一笔,配合 Shift 可常显选中单信息。
净额核算只允许一个方向一个头寸,后到的交易会修改既有头寸而非新建,理解这点才能正确解析平仓单来源。
能,小布盯盘内置了居中逻辑与增强提示条,打开品种页即可让开平标签落在可视中心,不用手动拖图。
将图表置于中央并使开仓交易落在左侧第二根可见柱,保证开平标签与连线优先进入视野。