bool DailyTradeLimit(int limit) { ulong deal_ticket; // 历史成交编号 int pos_total = 0; // 初始化单子数量 HistorySelect(iTime(_Symbol, PERIOD_D1, 0), TimeCurrent()); // 搜索时间范围,从每天0时开始到当前时间 int deal_total = HistoryDealsTotal(); // 获取时间段内所有单子总数 if(deal_total > 0) // 如果单子单数大于0 for(int i = deal_total - 1; i >= 0; i--) // 历遍所有单子 if((deal_ticket = HistoryDealGetTicket(i)) > 0) // 获取历史单子的成交编号 if(HistoryDealGetString(deal_ticket, DEAL_SYMBOL) == _Symbol) // 只选择当前加载图表的货币对名称 if(HistoryDealGetInteger(deal_ticket, DEAL_ENTRY) == DEAL_ENTRY_IN) // 只选已经入场成交的单子 pos_total++; // 总数 /* 判断用户自行输入的参数 limit 总数若大于或者等于,返回false 表示不能继续交易,否则返回true 表示可以继续交易 */ return((pos_total >= limit) ? false : true); }
调用方法:
例如你每天只想开 3 单
input int DailyTotal = 3; void OnTimer() { if(DailyTradeLimit(DailyTotal)) { //--- 你的继续交易的代码 } else { //--- 停止交易的代码 } }
谢谢您的帮助,您写的代码真的是我想要的效果。
还想请教一个关于移动止损的问题,
就是移动止损时,要保持订单距离大于或者等于用户设定的移动止损点数.
以下的代码是当达到用户设置的移动止损点数时,代码就会执行,
但是平仓时移动止损点数并没有大于或者等于用户设置的移动止损点数.
请问如何解决?
void yidong(int yidongdian,string symbol,ENUM_POSITION_TYPE type,int magic) // yidongdian 就是要设置的移动止损的点数.
{
int t=PositionsTotal();
for(int i=t-1;i>=0;i--)
{
if(PositionGetTicket(i)>0)
{
if(PositionGetString(POSITION_SYMBOL)==symbol)
{
double bid=SymbolInfoDouble(symbol,SYMBOL_BID);
double ask=SymbolInfoDouble(symbol,SYMBOL_ASK);
double dig=SymbolInfoInteger(symbol,SYMBOL_DIGITS);
double pot=SymbolInfoDouble(symbol,SYMBOL_POINT);
double op=PositionGetDouble(POSITION_PRICE_OPEN);
double sl=PositionGetDouble(POSITION_SL);
double tp=PositionGetDouble(POSITION_TP);
if(type==POSITION_TYPE_BUY)
{
if((bid-op)>=pot*yidongdian && (sl<(bid-pot*yidongdian) || (sl==0)))
{
if(magic==0)
{
MqlTradeRequest request={};
MqlTradeResult result={};
request.action=TRADE_ACTION_SLTP;
request.position=PositionGetTicket(i);
request.symbol=symbol;
request.sl=bid-pot*yidongdian;
request.tp=tp;
if(!OrderSend(request,result))
PrintFormat("OrderSend error %d",GetLastError());
}
else
{
if(PositionGetInteger(POSITION_MAGIC)==magic)
{
MqlTradeRequest request={};
MqlTradeResult result={};
request.action=TRADE_ACTION_SLTP;
request.position=PositionGetTicket(i);
request.symbol=symbol;
request.sl=bid-pot*yidongdian;
request.tp=tp;
if(!OrderSend(request,result))
PrintFormat("OrderSend error %d",GetLastError());
}
}
}
}
if(type==POSITION_TYPE_SELL)
{
if((op-ask)>=pot*yidongdian && ((sl>(ask+pot*yidongdian)) || (sl==0)))
{
if(magic==0)
{
MqlTradeRequest request={};
MqlTradeResult result={};
request.action=TRADE_ACTION_SLTP;
request.position=PositionGetTicket(i);
request.symbol=symbol;
request.sl=ask+pot*yidongdian;
request.tp=tp;
if(!OrderSend(request,result))
PrintFormat("OrderSend error %d",GetLastError());
}
else
{
if(PositionGetInteger(POSITION_MAGIC)==magic)
{
MqlTradeRequest request={};
MqlTradeResult result={};
request.action=TRADE_ACTION_SLTP;
request.position=PositionGetTicket(i);
request.symbol=symbol;
request.sl=ask+pot*yidongdian;
request.tp=tp;
if(!OrderSend(request,result))
PrintFormat("OrderSend error %d",GetLastError());
}
}
}
}
}
}
}
}
谢谢您的帮助,您写的代码真的是我想要的效果。
还想请教一个关于移动止损的问题,
就是移动止损时,要保持订单距离大于或者等于用户设定的移动止损点数.
以下的代码是当达到用户设置的移动止损点数时,代码就会执行,
但是平仓时移动止损点数并没有大于或者等于用户设置的移动止损点数.
请问如何解决?
void yidong(int yidongdian,string symbol,ENUM_POSITION_TYPE type,int magic) // yidongdian 就是要设置的移动止损的点数.
{
int t=PositionsTotal();
for(int i=t-1;i>=0;i--)
{
if(PositionGetTicket(i)>0)
{
if(PositionGetString(POSITION_SYMBOL)==symbol)
{
double bid=SymbolInfoDouble(symbol,SYMBOL_BID);
double ask=SymbolInfoDouble(symbol,SYMBOL_ASK);
double dig=SymbolInfoInteger(symbol,SYMBOL_DIGITS);
double pot=SymbolInfoDouble(symbol,SYMBOL_POINT);
double op=PositionGetDouble(POSITION_PRICE_OPEN);
double sl=PositionGetDouble(POSITION_SL);
double tp=PositionGetDouble(POSITION_TP);
if(type==POSITION_TYPE_BUY)
{
if((bid-op)>=pot*yidongdian && (sl<(bid-pot*yidongdian) || (sl==0)))
{
if(magic==0)
{
MqlTradeRequest request={};
MqlTradeResult result={};
request.action=TRADE_ACTION_SLTP;
request.position=PositionGetTicket(i);
request.symbol=symbol;
request.sl=bid-pot*yidongdian;
request.tp=tp;
if(!OrderSend(request,result))
PrintFormat("OrderSend error %d",GetLastError());
}
else
{
if(PositionGetInteger(POSITION_MAGIC)==magic)
{
MqlTradeRequest request={};
MqlTradeResult result={};
request.action=TRADE_ACTION_SLTP;
request.position=PositionGetTicket(i);
request.symbol=symbol;
request.sl=bid-pot*yidongdian;
request.tp=tp;
if(!OrderSend(request,result))
PrintFormat("OrderSend error %d",GetLastError());
}
}
}
}
if(type==POSITION_TYPE_SELL)
{
if((op-ask)>=pot*yidongdian && ((sl>(ask+pot*yidongdian)) || (sl==0)))
{
if(magic==0)
{
MqlTradeRequest request={};
MqlTradeResult result={};
request.action=TRADE_ACTION_SLTP;
request.position=PositionGetTicket(i);
request.symbol=symbol;
request.sl=ask+pot*yidongdian;
request.tp=tp;
if(!OrderSend(request,result))
PrintFormat("OrderSend error %d",GetLastError());
}
else
{
if(PositionGetInteger(POSITION_MAGIC)==magic)
{
MqlTradeRequest request={};
MqlTradeResult result={};
request.action=TRADE_ACTION_SLTP;
request.position=PositionGetTicket(i);
request.symbol=symbol;
request.sl=ask+pot*yidongdian;
request.tp=tp;
if(!OrderSend(request,result))
PrintFormat("OrderSend error %d",GetLastError());
}
}
}
}
}
}
}
}
从你的写的代码,可以看出你对编程的思维还没有跳脱出mql4的写法,其实无论mql4还是mql5都有现成大量的库文件,方便我们编写代码时少了很多工作量,
下面的例子,调用一个库文件
<Trade\Trade.mqh>
即可方便我们编程,减少代码量,已经注释好了, 方便初学者学习, mql5不同于mql4是真正做到面向对象的编写
//+------------------------------------------------------------------+ //| 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; // 创建类对象 input ulong Magic = 1234; input int DailyTotal = 3; input bool AllowTrailingStop = true; input double StartTrailing = 200; //+------------------------------------------------------------------+ //| 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(); // 关闭计时器 } //+------------------------------------------------------------------+ //| 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); // 卖单移动止损 } } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- } //+------------------------------------------------------------------+ //| 每天限制交易的数量 | //+------------------------------------------------------------------+ bool DailyTradeLimit(int limit) { ulong deal_ticket; // 历史成交编号 int pos_total = 0; // 初始化单子数量 HistorySelect(iTime(_Symbol, PERIOD_D1, 0), TimeCurrent()); // 搜索时间范围,从每天0时开始到当前时间 int deal_total = HistoryDealsTotal(); // 获取时间段内所有单子总数 if(deal_total > 0) // 如果单子单数大于0 for(int i = deal_total - 1; i >= 0; i--) // 历遍所有单子 if((deal_ticket = HistoryDealGetTicket(i)) > 0) // 获取历史单子的成交编号 if(HistoryDealGetString(deal_ticket, DEAL_SYMBOL) == _Symbol) // 只选择当前加载图表的货币对名称 if(HistoryDealGetInteger(deal_ticket, 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(PositionGetSymbol(i) == _Symbol) // 取当前货币对 if(PositionGetInteger(POSITION_TYPE) == pos_type) // 获取单子成交类型 { ulong pos_ticket = PositionGetInteger(POSITION_TICKET); // 获取单子成交编号 double pos_open = PositionGetDouble(POSITION_PRICE_OPEN); // 获取单子成交价格 double pos_sl = PositionGetDouble(POSITION_SL); // 获取单子止损价格 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; // 退出 } } } //+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
CTrade m_trade;
1.上面的CTrade为什么不是Trade,因为它的名字是Trade,引用它的时候要用相同的名字才可以引用吧?
2.这个CTrade会不停的开单.
3.您写的移动止损应该跟我发的一样效果吧,就是有时候大于客户设置的移动止损点数,有时候小于。
而客户要求的是一直都要大于。
大家好,我刚自学编程,不知道每天限制指定货币对开单的数量怎么写。
比如说EURUSD不论盈亏一天内开单的数量都不超过3单,
然后GBPUSD 不论盈亏一天内开单的数量都不超过5单,
试过用HistoryDealsTotal();这个函数,但返回的是所有货币对的数量,而不是指定货币对的数量。
请问怎样解决?