//+------------------------------------------------------------------+
//| 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);
}
|