ken138888:
历史订单有亏损的,有盈利的,请问一下如何判断是连续亏损的?
历史订单有亏损的,有盈利的,请问一下如何判断是连续亏损的?
呵呵,又遇到你了,
这个逻辑很简单
搜索全部历史,如果是亏损,就让一个计数变量+1,如果出现一次盈利就让这个计数变量清零
//+------------------------------------------------------------------+ //| Test4.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #define Ask SymbolInfoDouble(_Symbol, SYMBOL_ASK) // 定义当前货币对买入价 #define Bid SymbolInfoDouble(_Symbol, SYMBOL_BID) // 定义当前货币对卖出价 #include <Trade\Trade.mqh> // 调用MQL5交易库文件 CTrade m_trade; // 创建交易类对象 CPositionInfo m_pos; // 创建订单类对象 CDealInfo m_deal; // 创建成交类对象 input long Magic = 1234; input int DailyTotal = 3; input bool AllowTrailingStop = true; input double StartTrailing = 200; input int MaxLoss = 3; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetMillisecondTimer(100); // 设置计时器 1秒=1000 毫秒, 这里设置100毫秒, 即1秒运行10次 m_trade.SetExpertMagicNumber(Magic); // 设置魔术编号, 只管理此EA开设的单子 m_trade.SetAsyncMode(true); // 设置异步交易模式, 这样程序就不用等待每个交易操作的结果 m_trade.SetDeviationInPoints(INT_MAX);// 设置允许的最大滑点 //--- return(INIT_SUCCEEDED); // 返回初始化成功 } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); // 关闭计时器 Comment(""); // 清空显示 } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { if(DailyTradeLimit(DailyTotal)) { //--- 你的继续交易的代码 } else { //--- 停止交易的代码 } //--- if(AllowTrailingStop) // 如果允许使用移动止损 { PositionsTrailingStop(POSITION_TYPE_BUY, StartTrailing); // 买单移动止损 PositionsTrailingStop(POSITION_TYPE_SELL, StartTrailing); // 卖单移动止损 } //--- if(IsLoss(MaxLoss, Magic)) { Comment("出现连续亏损", MaxLoss, "次的单子"); //--- 如果出现连续亏损,你的代码 } else { Comment("没有出现连续亏损", MaxLoss, "次的单子"); //--- 没有出现连续亏损,继续交易的代码 } } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- } //+------------------------------------------------------------------+ //| 每天限制交易的数量 | //+------------------------------------------------------------------+ bool DailyTradeLimit(int limit) { int pos_total = 0; // 初始化单子数量 HistorySelect(iTime(_Symbol, PERIOD_D1, 0), TimeTradeServer()); // 搜索时间范围,从每天0时开始到当前时间 int total = HistoryDealsTotal(); // 获取时间段内所有单子总数 if(total > 0) for(int i = total - 1; i >= 0; i--) // 历遍所有单子 if(m_deal.SelectByIndex(i)) // 选中单子 if(m_deal.Symbol() == _Symbol && m_deal.Entry() == DEAL_ENTRY_IN) // 只选择当前加载图表的货币对名称和入场类型 pos_total++; /* 判断用户自行输入的参数 limit 总数若大于或者等于,返回false 表示不能继续交易,否则返回true 表示可以继续交易 */ return((pos_total >= limit) ? false : true); } //+------------------------------------------------------------------+ //| 移动止损方法 | //+------------------------------------------------------------------+ void PositionsTrailingStop(const ENUM_POSITION_TYPE pos_type, const double ts) { int pos_total = PositionsTotal(); // 取得成交单子总数 if(pos_total > 0) // 如果有单子 for(int i = 0; i < pos_total; i++) // 历遍所有单子 if(m_pos.SelectByIndex(i)) // 选中单子 if(m_pos.Symbol() == _Symbol && m_pos.PositionType() == pos_type) // 取当前货币对和单子成交类型 { ulong pos_ticket = m_pos.Ticket(); // 获取单子成交编号 double pos_open = m_pos.PriceOpen(); // 获取单子成交价格 double pos_sl = m_pos.StopLoss(); // 获取单子止损价格 switch(pos_type) // 分类单子类型 { case POSITION_TYPE_BUY: // 如果是买单 if(Bid >= pos_open + ts * _Point) // 如果大于设置的移动止损点数 if(Bid - ts * _Point > pos_sl) // 如果大于当前止损价 if(!m_trade.PositionModify(pos_ticket, Bid - ts * _Point, 0)) // 修改单子新的止损价 PrintFormat("%s, %s", __FUNCTION__, "设置买单止损失败!"); // 如果修改失败,打印日志 break; // 退出 case POSITION_TYPE_SELL: // 如果是卖单 if(Ask <= pos_open - ts * _Point) // 如果小于设置的移动止损点数 if(Ask + ts * _Point < pos_sl || pos_sl == 0) // 如果小于当前止损价,或者第一次设置止损价 if(!m_trade.PositionModify(pos_ticket, Ask + ts * _Point, 0)) // 修改单子新的止损价 PrintFormat("%s, %s", __FUNCTION__, "设置卖单止损失败!"); // 如果修改失败,打印日志 break; // 退出 } } } //+------------------------------------------------------------------+ //| 获取最后成交单平仓时间 | //+------------------------------------------------------------------+ datetime GetHistoryLastDealCloseTime(const ENUM_DEAL_TYPE type) // 输入类型 { datetime close_time = 0; // 初始化平仓时间 ENUM_DEAL_TYPE deal_type = (type == DEAL_TYPE_BUY) ? DEAL_TYPE_SELL : DEAL_TYPE_BUY; // 如果输入买单,那么out就是卖类型,反之亦然 HistorySelect(0, TimeTradeServer()); // 设置搜索时间段, 这里代表所有历史 int total = HistoryDealsTotal(); // 获取所有数量 if(total > 0) // 如果数量大于0 for(int i = 0; i < total; i++) // 历遍所有单子 if(m_deal.SelectByIndex(i)) // 选中单子 if(m_deal.Symbol() == _Symbol && // 只选择当前加载图表的货币对名称 m_deal.DealType() == deal_type && // 指定成交类型 m_deal.Entry() == DEAL_ENTRY_OUT) // 只取出场的成交单 close_time = m_deal.Time(); // 获取平仓时间 return(close_time); // 输出最后平仓时间 } //+------------------------------------------------------------------+ //| 判断是否连续亏损 | //+------------------------------------------------------------------+ bool IsLoss(const int count, const long magic = 0) { HistorySelect(iTime(_Symbol, PERIOD_D1, 0), TimeTradeServer()); // 只统计当天的交易历史 int total = HistoryDealsTotal(); // 获取当天交易的总单数 int loss = 0; // 初始化连续亏损的次数 if(total > 0) // 如果历史单数大于0 for(int i = 0; i < total; i++) // 历遍所有单子 if(m_deal.SelectByIndex(i)) // 获取单子索引 if(m_deal.Symbol() == _Symbol && // 只选当前货币品种 m_deal.Magic() == magic && // 如果magic 默认为 0 时视为手动单 m_deal.Entry() == DEAL_ENTRY_OUT) // 只选平仓属性的成交单 { if(m_deal.Profit() < 0) // 如果成交单获得小于0,说明是亏损单 loss++; // 连续亏损计数+1 else loss = 0; // 若中途有盈利单,重新计数(连续计数初始为0) if(loss >= count) // 若连续亏损大于或者等于自定义计数,返回true值 return(true); // 返回true值 } return(false); } //+------------------------------------------------------------------+
ken138888 #:
首先,非常感谢你,愿意花时间回答问题。
我们应该没有偶遇过吧,我是一个初学者。
你写的代码我要完全看明白可能要花很长的时间,有问题再来请教。
注释真的很有帮助,代码看起来很舒服。
//+------------------------------------------------------------------+ //| 判断是否连续亏损 | //+------------------------------------------------------------------+ bool IsLoss(const int count, const long magic = 0) { HistorySelect(iTime(_Symbol, PERIOD_D1, 0), TimeTradeServer()); // 只统计当天的交易历史 int total = HistoryDealsTotal(); // 获取当天交易的总单数 int loss = 0; // 初始化连续亏损的次数 if(total > 0) // 如果历史单数大于0 for(int i = 0; i < total; i++) // 历遍所有单子 if(m_deal.SelectByIndex(i)) // 获取单子索引 if(m_deal.Symbol() == _Symbol && // 只选当前货币品种 m_deal.Magic() == magic && // 如果magic 默认为 0 时视为手动单 m_deal.Entry() == DEAL_ENTRY_OUT) // 只选平仓属性的成交单 { if(m_deal.Profit() < 0) // 如果成交单获得小于0,说明是亏损单 loss++; // 连续亏损计数+1 else loss = 0; // 若中途有盈利单,重新计数(连续计数初始为0) if(loss >= count) // 若连续亏损大于或者等于自定义计数,返回true值 return(true); // 返回true值 } return(false); }
这里有点不严谨,例如如果你想在连续亏损3单后中止交易,那么我们就要判断最后3个单子的盈亏情况,如果把黄色部分放在循环体内的话,
在这过程中有超过3单亏损的话,它会直接返回true值,所以不能把这个判断放在循环体内,把它改在到循环体外做判断.
//+------------------------------------------------------------------+ //| 判断是否连续亏损 | //+------------------------------------------------------------------+ bool IsLoss(const int count, const long magic = 0) { HistorySelect(iTime(_Symbol, PERIOD_D1, 0), TimeTradeServer()); // 只统计当天的交易历史 int total = HistoryDealsTotal(); // 获取当天交易的总单数 int loss = 0; // 初始化连续亏损的次数 if(total > 0) // 如果历史单数大于0 for(int i = 0; i < total; i++) // 历遍所有单子 if(m_deal.SelectByIndex(i)) // 获取单子索引 if(m_deal.Symbol() == _Symbol && // 只选当前货币品种 m_deal.Magic() == magic && // 如果magic 默认为 0 时视为手动单 m_deal.Entry() == DEAL_ENTRY_OUT) // 只选平仓属性的成交单 { if(m_deal.Profit() < 0) // 如果成交单获得小于0,说明是亏损单 loss++; // 连续亏损计数+1 else loss = 0; // 若中途有盈利单,重新计数(连续计数初始为0) } return((loss >= count) ? true : false); // 如果在最后为count内有连续超过count次亏损,返回true值 }
历史订单有亏损的,有盈利的,请问一下如何判断是连续亏损的?