//+------------------------------------------------------------------+ //| EA显示包含进一步工作请求的MessageBox窗口 | //| 当一系列未盈利交易达到指定数量时 | //| 等待指定的柱形图数量并显示MessageBox | //| 请求继续工作。 | //| 为了进行检查,我们需要手动打开和关闭多个持仓 | //| 亏损,因为EA无法控制 | //| 它自己的“持仓”(通过幻数)。 | //+------------------------------------------------------------------+ //--- 输入参数 input uint InpMaxLossDeals = 3; // 最大亏损交易 input uint InpInactivityNumBars = 5; // 不活动的柱形图数 //--- 全局变量 bool ExtFirstStart=true; // 第一启动标识 bool ExtFlag=true; // 允许EA工作的标识 uint ExtNumLoss; // 连续未盈利交易数 datetime ExtTimeLastLoss; // 最后一笔亏损平仓的时间 //+------------------------------------------------------------------+ //| EA交易初始化函数 | //+------------------------------------------------------------------+ int OnInit() { //--- 获得连续亏损交易的数量和最后一笔亏损平仓的时间 ExtNumLoss=GetNumLosingTradesInRow(ExtTimeLastLoss); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| EA交易去初始化函数 | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { Comment(""); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- 确定自该系列中最后一个收盘亏损持仓以来已经过多少柱形图 int bars_remaining=iBarShift(Symbol(),PERIOD_CURRENT,ExtTimeLastLoss); //--- 如果这是第一次启动 if(ExtFirstStart) { //--- 如果在一系列未盈利持仓之后已经通过指定数量的柱形图,则设置EA操作标识 if(bars_remaining>(int)InpInactivityNumBars) ExtFlag=true; ExtFirstStart=false; } //--- 如果EA操作标识被禁用 if(!ExtFlag) { Comment(StringFormat("The advisor is stopped for %d bars. Num Loss positions: %u, Time last loss: %s", (InpInactivityNumBars-bars_remaining),ExtNumLoss,TimeToString(ExtTimeLastLoss,TIME_DATE|TIME_MINUTES|TIME_SECONDS))); //--- 如果在一系列未盈利持仓之后已经通过指定数量的柱形图 if(bars_remaining>(int)InpInactivityNumBars) { //--- 显示带有指定文本和窗口标题的MessageBox窗口 //--- 请求窗口有两个“是(Yes)”/“否(No)”按键和一个带问号的图标。 //--- 默认选择“是(Yes)”按键。 string mb_text="The specified number of bars of EA inactivity have passed.\n Continue its work?"; string mb_caption="Please note"; int mb_id=MessageBox(mb_text,mb_caption,MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON1); //--- 如果来自MessageBox的返回代码是按下的“Yes”按键,则设置EA操作标识 if(mb_id==IDYES) { ExtFlag=true; return; } } //--- EA操作标识被禁用,退出OnTick() return; } //--- 设置EA操作标识 - EA按照下面代码提供的方式工作 Comment(StringFormat("The advisor is working. Num Loss positions: %u, Time last loss: %s, Elapsed Bars: %d", ExtNumLoss,TimeToString(ExtTimeLastLoss,TIME_DATE|TIME_MINUTES|TIME_SECONDS),bars_remaining)); } //+------------------------------------------------------------------+ //| TradeTransaction函数 | //+------------------------------------------------------------------+ void OnTradeTransaction(const MqlTradeTransaction& trans, const MqlTradeRequest& request, const MqlTradeResult& result) { //--- 如果交易事务类型是向历史记录添加交易 if(trans.type==TRADE_TRANSACTION_DEAL_ADD) { //--- 获得一个交易工单,并按工单从列表中选择一笔交易 ulong deal_ticket=trans.deal; if(HistoryDealSelect(deal_ticket)) { //--- 如果这是一个市场退出交易,得到连续亏损交易的数量和最后一次交易的时间 ENUM_DEAL_ENTRY entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(deal_ticket,DEAL_ENTRY); if(entry==DEAL_ENTRY_OUT || entry==DEAL_ENTRY_INOUT || entry==DEAL_ENTRY_OUT_BY) ExtNumLoss=GetNumLosingTradesInRow(ExtTimeLastLoss); } } //--- 如果连续亏损的交易数量大于指定的值,则启用EA操作标识 if(ExtNumLoss>=InpMaxLossDeals && ExtFlag) { //--- 显示包含指定文本和窗口标题的MessageBox窗口 //--- 请求窗口有两个“是(Yes)”/“否(No)”按键和一个带感叹号的图标。 //--- 默认情况下选择“否(No)”按键。 string mb_text="The number of losing trades has reached the specified maximum. The advisor is stopped.\n Continue its work?"; string mb_caption="Attention!"; int mb_id=MessageBox(mb_text,mb_caption,MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2); //--- 如果来自MessageBox的返回代码是按下的“No”按键,,则禁用EA操作标识 if(mb_id==IDNO) ExtFlag=false; } } //+------------------------------------------------------------------+ //| 返回连续未盈利交易的数量 | //| 以及最后一笔亏损平仓的时间 | //+------------------------------------------------------------------+ uint GetNumLosingTradesInRow(datetime &time_last_deal) { //--- 选择整个历史 if(!HistorySelect(0,TimeCurrent())) return(0); //--- 通过循环中的历史交易列表获得下一个交易工单 uint res=0; uint total=HistoryDealsTotal(); for(int i=(int)total-1; i>=0; i--) { ulong deal_ticket=HistoryDealGetTicket(i); if(deal_ticket>0) { //--- 如果交易不是为了退出持仓,那么继续下一笔交易 ENUM_DEAL_ENTRY entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(deal_ticket,DEAL_ENTRY); if(entry!=DEAL_ENTRY_OUT && entry!=DEAL_ENTRY_OUT_BY && entry!=DEAL_ENTRY_INOUT) continue; //--- 如果平仓的结果是获利,则中断循环 if(!IsClosePositionWithLoss(deal_ticket)) break; //--- 增加连续亏损交易的计数器 res++; //--- 将最大交易时间写入变量(查找最后一个) datetime deal_time=(datetime)HistoryDealGetInteger(deal_ticket,DEAL_TIME); if(deal_time>time_last_deal) time_last_deal=deal_time; } } //--- 返回连续亏损的数量 return(res); } //+------------------------------------------------------------------+ //| 返回亏损平仓标识 | //+------------------------------------------------------------------+ bool IsClosePositionWithLoss(const ulong deal_ticket) { //--- 获取影响交易利润的属性值 double profit=HistoryDealGetDouble(deal_ticket,DEAL_PROFIT); double comission=HistoryDealGetDouble(deal_ticket,DEAL_COMMISSION); double swap=HistoryDealGetDouble(deal_ticket,DEAL_SWAP); double fee=HistoryDealGetDouble(deal_ticket,DEAL_FEE); //--- 返回标识,表示接收到的属性总价值为负值 return(profit+comission+swap+fee<0); } |