加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

你问我答:MQL4编程【持续更新】

(2012-12-31 02:34:53)
标签:

mql4

mt4

外汇

常见问题

分类: MT4产品
如果您遇到任何MQL4编程的问题,可以跟帖提问,我会酌情回答,并将常见问题的应对方法编入此贴当中。
你问我答,共同积累,互帮互助,提升水平

41、  
历史数据质量好坏真的很重要吗?
不要过于追求历史数据的所谓质量问题。我们能拿到的最小周期的数据是1分钟的,你想想,一个历史上的1分钟的大阳线,当时到底经历了多少个来回,根本无法考证。即使,你有所谓的tick数据,但如果你没有当时的点差数据,也是没用的。历史无法从通常的数据复盘。

40、 
把"csv"文件中的内容读到二维数组
handle=FileOpen(CtrlFileName,FILE_CSV|FILE_COMMON|FILE_READ|FILE_SHARE_READ,',');
string  ctrl_rule_text[100]; //二维数组
int str_size=FileReadInteger(handle,INT_VALUE); //字符大小
int myLncnt=0; //记录行计数器变量
int myColcnt=0; //记录列计数器变量
while(!FileIsEnding(handle) && myLncnt<17) //不是文件结尾
{
  myColcnt=0;
  ctrl_rule_text[myLncnt][myColcnt]=FileReadString(handle,str_size); //每行第一个元素
  while (!FileIsLineEnding(handle)) //读取一行每个元素
  {
    myColcnt++;
    ctrl_rule_text[myLncnt][myColcnt]=FileReadString(handle,str_size); //每行第二个以后的元素
  }
  myLncnt++;
}


39、
把逗号","分隔的字符串中的关键字分别摘出来
int temp_pos=0; //符号","位置
int temp_prv_pos=0; //前一个符号","位置
string temp_name="EURUSD,USDJPY,GOLD"; //测试字符串
string ouputstr=""; //输出字符串
for (int i=0;i<100;++i)
{
    temp_pos=StringFind(temp_name,",",temp_prv_pos);
    ouputstr+=StringSubstr(temp_name,temp_prv_pos,temp_pos-temp_prv_pos)+"\n"; //没有逗号,带换行的字符串
    temp_prv_pos=temp_pos+1;
    if (temp_pos==-1) break;
}
Comment(ouputstr); //查看结果字符串:

38、历史数据文件的新建与追加
MT4的历史数据文件后缀名为.hst。如果新建一个历史数据文件,用这条命令:
FileOpenHistory("***.hst",FILE_BIN|FILE_WRITE|FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_ANSI);
如果在历史数据后面追加,用这条命令:
FileOpenHistory("***.hst",FILE_BIN|FILE_WRITE|FILE_READ|FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_ANSI);
上面的用法在MQL4手册里没有说明,我是通过不断尝试找到的。

37、计算SMMA函数
int     rates_total, //MA数量
int     ma_Period, //MA采样数量
double  &src_array[], //源数据,需要计算的数列
double  &dst_array[] //目标数据,算好SMMA的数列


36、贴一段去重代码,备忘


int TicketIndex[1320]; //定义订单号索引变量
int tempTicketIndex[]; //定义订单号索引变量 最大120000,MT4的限制
ArrayResize(tempTicketIndex,(RecordNum+1)*66); //每条记录有66列
ArrayInitialize(TicketIndex,0.0); //初始化订单号索引数组
ArrayInitialize(tempTicketIndex,0.0);
int j=0,cnt=0,k=0;
//准备临时数组  将持仓单数据库记录导入到
tempTicketIndex,持仓单记录有很多重复订单号
for (cnt=0;cnt
{
 for (k=0;k<66;k++) //记录中订单号TO_Ticket中循环
 {
   if (TO_Ticket[cnt][k]>0)
   {
     tempTicketIndex[j]=TO_Ticket[cnt][k];
     j++;
   }
 }
}
ArrayResize(tempTicketIndex,j);
//去重tempTicketIndex,重组数组TicketIndex,该数组保存无重复的订单号
bool DataRepeat=false;
j=0;
for (cnt=0;cnt
{
 for (k=0;k0;k++) //循环TicketIndex,检查是否有重复
 {
    DataRepeat=false;
    if (tempTicketIndex[cnt]==TicketIndex[k]) //有重复,退出TicketIndex循环
    {
      DataRepeat=true;
      break;
    }
 }
 if (DataRepeat==false)
 {
   TicketIndex[j]=tempTicketIndex[cnt];
   j++;
 }
}
ArrayResize(TicketIndex,j);


35、停止水平位StopLevel规则是什么?

执行挂单交易以及持仓单设置止盈止损是受停止水平位规则制约的,即在当前报价一定范围内不允许挂单或者设置止盈止损,这个范围就是StopLevel,通常以“点”为单位。如果搞错了,就会报130错误。详细规则如下:

BuyLimit挂单价<=Ask-StopLevel BuyStop挂单价>=Ask+StopLevel 
SellLimit挂单价>=Bid+StopLevel SellStop挂单价<=Bid-StopLevel
Buy单止损价<=Bid-StopLevel Buy单止盈价>=Bid+StopLevel
Sell单止损价>=Ask+StopLevel Sell单止盈价<=Ask-StopLevel


34、如何加快EA测试速度?

在EA做历史数据回测的时候常常感觉速度很慢,测试过程中有卡顿,这是因为MT4终端要读取来自服务器的数据,故意输错密码登录一次,保持无帐号登录状态,速度明显提升。

33、执行EA的时候为什么会重复操作的情况?

有时候,运行了MT4却没有显示,以为没启动,于是反复双击MT4,就导致后台启动了多个活动的MT4进程,这是MT4的一个bug。通过以下方法检查并处理。

1、在桌面下方菜单条点击鼠标右键,打开任务管理器

http://s15/mw690/001WpylDgy6LX79Ih6C6e&690

2、在“进程”中查看是否有多个terminal.exe:

http://s4/mw690/001WpylDgy6LX7j6frJ53&690

3、如果有,右键点击该进程,逐一结束

http://s3/mw690/001WpylDgy6LX7p2I7g52&690

4、重启MT4

32、一个类定义、调用类的范例

类(Class)是C++的概念,定义一个新型的数据类型,其中的元素可以是单一的变量、结构体,也可以是一个自定义函数。通常结构体中的元素不定义为函数。

创建一个名称为“myClass.mqh”的类文件:

#property copyright "Copyright 2014, Laoyee"

#property link      "http://blog.sina.com.cn/yiwence"

#property version   "1.00"

#property strict

 

class myClass //

{

    private:    //私有

 

    public:     //公共

                            myClass();

                            ~myClass();

        virtual int         iAdd(int a,int b);      //整数加减法

        virtual string      iHello(string mystr);   //提示信息

};

 

//构建两个类库

myClass::myClass() {}

myClass::~myClass() {}

  

int myClass::iAdd(int a,int b)

{

    return(a+b);

}

 

string myClass::iHello(string mystr)

{

    return("迎:"+mystr+"!");

}

 

在相同文件夹中创建一个名称为“类编写范例.mq4”的EA程序文件:

#property copyright "Copyright 2014, Laoyee"

#property link      "http://blog.sina.com.cn/yiwence"

#property version   "1.00"

#property strict

#include "myClass.mqh"

myClass myTest1; //义类变

//--- 初始化模

int OnInit()

{

    int a=5,b=2;

    Print(a,"+",b,"=",myTest1.iAdd(a,b));

    Print(myTest1.iHello("laoyee"));

//--- 计时器事件

    EventSetTimer(60);

    return(INIT_SUCCEEDED);

}

 

//--- EA退出模

void OnDeinit(const int reason)

{

//--- 销毁计时器事件

    EventKillTimer();

    return;

}

 

//--- 价事件模

void OnTick()

{

    return;

}

 

//--- 时间事件模

void OnTimer()

{

    return;

}

 

//--- 测试事件模

double OnTester()

{

    double ret=0.0;

    return(ret);

}

 

//--- 表事件模

void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)

{

    return;

}

MT4主图中加载后显示如下:

http://s16/mw690/001WpylDgy6LFoW7gl17f&690

结构体(Struct)是一种自定义数据结构类型,用于将一组相关的信息变量组织为一个单一的变量实体

(Class)完整沿袭了C++面向对象编程的概念,是一种自定义数据结构类型,通常包含字段、属性、方法、构造函数、索引器、操作符等。

结构体中的元素由数据类型构成,类中的元素可以是函数。结构体的元素可以定义为另一个结构体或者另一个类,类的元素也可以定义为另一个类或者另一个结构体,这种表现形式就叫做“继承”,从这里不难得出一个结论:除非必须,否则最好不要做类方法。

31、向自定义函数的数组参数传递数据
int myarray[3]; //预定义数组
int OnInit()
{
    //给预定义数组赋值
    myarray[0]=1;
    myarray[1]=2;
    myarray[2]=3;
    Print("数据:",myarray[1]); //显示结果为2
    arraytest(myarray); //调用数组参数的自定义函数
    return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
    return;
}
//自定义函数
int arraytest(int& ma[])
{
    Print("函数数据:",ma[2]); //显示结果为3
    return(0);
}
void OnTick()
{
    return;
}

Q30:MQL4中利用input制作漂亮的参数下拉选项
http://s4/mw690/001WpylDgy6J2RdeRxha3&690
第一步,在程序头定义下拉选项元素,CT为自定义名称,我用非int数值报错,就不纠结原因了,方法重要。
enum CT{双向=9,买入=0,卖出=1};
第二步,在程序头定义输入参数,建仓类型中的CreatType定义为CT类型
input CT CreatType=9; //建仓类型
input double Lots=0.01; //开仓量
input int GirdPoint=300; //格子间距
input int TrallingStop=50; //移动止损
第三步,在int OnInit()中输出参数值
Print("建仓类型为:",CreatType);
加载后,如上图显示,在“终端”的智能交易窗口中显示不同选项的结果9、0、1
29、关于EA加载时预设参数
先定义一个预设参数如下:
input bool TestMonitor=true;                //启动测试监视
加载EA如图:
http://s9/mw690/001WpylDgy6Ii5xaM0868&690
新特性:输入参数变量部分显示源码中的注释内容,而不是让人费解的变量名。

28、关于最完整的历史数据
在demo.metaquotes.net:443注册账户,就可获得MT4所有商品较为完整历史数据。每个商品只需下载M1数据,在图表中点击其他时间周期,就会自动生成相应的k线。不过早期的M1数据只有D1。

27、PrintFormat()用法
PrintFormat()命令参数分为两大部分,第一部分规定格式,第二部分变量列表。例如:
PrintFormat("开仓价:%e 开仓量:%e",myOpenPrice,myLots);
双引号里面就是格式,空格在显示有效,%e表示变量是数字类型,如果是字符型,就用%s,显示出来的效果:
开仓价:1.38601 开仓量:0.1

26、GetLastError()的特点
GetLastError()用来获取错误代码,需要注意的是发生错误的语句下一条如果正确,就会返回0,而不会带到start中。

25、类型转换后作为比较条件特别注意的地方
string类型转换为double后,做两数相等比较,必须这样处理,否则,他们总是不会相等。
if (NormalizeDouble(StringToDouble("1234.56"),Digits)==NormalizeDouble(1234.56,Digits))

24、订单操作命令中哪些不需要事先选中订单,即用OrderSelect命令
OrderModify,OrderDelete, OrderClose

23、制作漂亮的EA封面
在MQL4程序头写入以下内容
#property copyright     "点击查看本软件最新信息"
#property link          "http://blog.sina.com.cn/s/blog_6a0d357d01017t36.html"
#property version       "628.1"
#property description   "软件有效截止日为2015年1月1日0点,到期之前不会有任何提示"
#property description   "请提前与作者联系,免费获取授权"
#property icon          "\Images\laoyeeico.ico"
EA加载时就会有一个漂亮的封面,鼠标点击还可以自动打开浏览器访问目标网站:

22、MQL4结构体
MQL4新增了“结构体”变量,这是一个非常有用的功能。我用来做持仓单管理。具体实现如下。
首先,在程序头部位定义结构体:
struct  OrderTradesRecord           //持仓单信息结构体
        {
         int        myTicket;       //订单号
         datetime   myOpenTime;     //开仓时间
         int        myType;         //订单类型
         double     myLots;         //开仓量
         string     mySymbol;       //商品名称
         double     myOpenPrice;    //建仓价
         double     myStopLoss;     //止损价
         double     myTakeProfit;   //止盈价
         double     myCommission;   //佣金
         double     mySwap;         //利息
         double     myProfit;       //利润
         string     myComment;      //注释
         int        myMagicNumber;  //程序识别码
         double     myAsk;          //买入报价
         double     myBid;          //卖出报价
        };
以上包含了一个持仓单全部有用的信息(还有一些例如“税金”我找不到相关命令,反正也用不着)。
OrderTradesRecord定义了持仓单的属性,接下来在程序中就需要定义变量了,结构体本身不能用,变量才能用。
OrderTradesRecord mytest[200]; //定义持仓单变量
考虑到持仓单有很多,在这里使用了数组,预定义200条记录,如果你有更多持仓单,就修改这个200参数,例如20000,表示能够容纳2万张订单。
最后,给mytest数组赋值:
for (int i=0;i
{
    if (OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
    {
        mytest[i].myTicket=OrderTicket();               //订单号
        mytest[i].myOpenTime=OrderOpenTime();           //开仓时间
        mytest[i].myType=OrderType();                   //订单类型
        mytest[i].myLots=OrderLots();                   //开仓量
        mytest[i].mySymbol=OrderSymbol();               //商品名称
        mytest[i].myOpenPrice=OrderOpenPrice();         //建仓价
        mytest[i].myStopLoss=OrderStopLoss();           //止损价
        mytest[i].myTakeProfit=OrderTakeProfit();       //止盈价
        mytest[i].myCommission=OrderCommission();       //佣金
        mytest[i].mySwap=OrderSwap();                   //利息
        mytest[i].myProfit=OrderProfit();               //利润
        mytest[i].myComment=OrderComment();             //注释
        mytest[i].myMagicNumber=OrderMagicNumber();     //程序识别码
        Print(i+" "+mytest[i].myTicket+" "+mytest[i].myOpenTime+" "+mytest[i].myType+" "+mytest[i].myLots+" "+mytest[i].mySymbol+
        " "+mytest[i].myOpenPrice+" "+mytest[i].myStopLoss+" "+mytest[i].myTakeProfit+" "+mytest[i].myCommission+" "+mytest[i].mySwap+
        " "+mytest[i].myProfit+" "+mytest[i].myComment+" "+mytest[i].myMagicNumber);
    }
}
完成这些,一个有效的持仓单变量就形成了,例如你要使用第三张单的开仓时间,就用mytest[2].myOpenTime,我们日常计数从1开始,计算机计数从0开始,这是你必须认可的规则。
我做这个的目的是要对持仓单排序,找到特定条件的订单,例如亏损最小的订单、最早建仓的订单、开仓量最大的订单等等,有了这个索引模块,肯定能大大提高编程质量和编程效率。
这个功能将打包到新版的编程模版程序中。
把代码封装到OnInit()中,加载EA,如图:
http://s12/mw690/001WpylDgy6HOp711wv2b&690
这与MT4终端的交易窗口显示信息、顺序一致。
用同样的方法,你还可以定义历史订单结构体或者其他你需要的结构体。

21、double转int
预定义两个变量
int a=0;
double b=1.23;
如果你直接用a=b;编译会出现类型不匹配警告,应该这样:
a=(int)b;做一个类型转换
同理,(string)a,或者(string)b就把两个变量转换成字符类型了。

========以下是mql4旧版的内容,以上是mql4新版的内容========

Q1:错误编号“4051”描述为“无效参量值函数”,怎么处理?
这实际上是指开仓量错误,检测程序中订单操作命令的开仓量变量是否为0,或者不符合交易平台规定的开仓量格式,例如平台规定XAUUSD最小开仓量为0.1,而变量计算结果为0.12,或者0.36,就会该类报错信息。以下提供一个“开仓量整形”的函数,直接调用就不会出现问题了,0.12被规范为0.1,0.36被规范为0.4:
//函    数:开仓量整形
//输入参数:myLots:开仓量
//输出参数:按照平台规则计算开仓量
//算    法:调整不规范的开仓量数据,按照四舍五入原则及平台开仓量格式规范数据
double iLotsFormat(double myLots)
   {
      myLots=MathRound(myLots/MarketInfo(Symbol(), MODE_MINLOT))*MarketInfo(Symbol(), MODE_MINLOT);//开仓量整形
      return(myLots);
   }

Q2:错误编号“1”描述为“没有错误返回但结果不明”,是什么原因?
这类问题通常出在修改止盈、止损价位的程序段中。例如开仓价为1.2222,止损价为1.2202,由于种种原因,比如程序计算止损价位时可能会出现4位小数之后更多的数字,如1.220234,那么就会出现该类报错信息。处理办法是使用NormalizeDouble函数将止损价变量数据规范成了平台能够识别的标准格式。因此建议大家编程时养成对价格变量随时整形的习惯。范例:
myStopLoss=NormalizeDouble(myStopLoss,Digits);

Q3:Sleep()函数在历史回测中为什么不能起到延时作用?
这个函数的功能是为实时交易延时提供的,只有在通讯或者服务器繁忙时才起作用,所以在历史回测中无效,而且在自定义指标程序中也无效。如果您需要在一个k线只开仓一单,一定不能用这个命令,只能采用程序模块办法来解决。

Q4:怎样控制持仓单数量?
我在《外汇交易MT4程序化方法》中第一章提供了《控单模版》,这里面预定义了22个常规变量,只要加载就会按照每个tick实时更新。变量分为买入组、卖出组,例如您已经有一张买入持仓单,那么变量BuyGroupOrders=1,此时如果买入信号再次到达,就可以用if语句进行开仓数量的控制。范例:
if (BuyGroupOrders>1 && BuyGroupOrders<2)
  {
     //新建买入持仓单
  }
我们需要注意的是,一个买入信号可能会持续一段时间,如果不增加限制条件,就会连续开出2张不同价位的买入持仓单。

Q5:成交持仓单中的Comment和MagicNumber有什么区别?
Comment是指订单注释,属于字符串类型。当您手工开单建仓的时候就可以预先输入,当然MQL4程序也可以做到。一旦订单成交,这个注释就不能手工修改了,但是如果订单止盈、止损出场,注释会被系统增加[tp]、[sl]标识,如果是部分减仓,例如开仓量1手,平掉0.4手,那么新的留在场内的0.6手订单将出现一个新的订单号,且注释部分会被系统自动添加一个[from xxxxxxxx]标识。
MagicNumber是指订单特征码,属于整数类型。这个字段只在自动交易中使用,一旦定义始终不会更改。这就给程序鉴别是否出自自己建仓提供了有效的区分依据。只要您的程序预定义了MagicNumber,那么对场内的订单就能实现精确统计。我在控单模版》中就是采用了这个特性进行与本EA相关订单的统计的。

Q6:系统的成交持仓单列表会按照时间顺序自动排序,为什么《控单模版》中还要重新排序?
在实盘操作中,可能是由于瞬间tick数量特别多,需要频繁进行建仓、平仓等操作的原因,我发现,系统的持仓单列表并不是按照时间顺序及时排序,这就导致不能精准控制类似“买入组最后一单”的操作,因此,我特意打造了这样一个控单模版。而在历史数据测试中,您是不可能发现系统这一不足之处的,大多数MQL4程序员都忽略了这一情况。

Q7:历史数据回测中出现“unmatched data error”是怎么回事
我们在进行历史数据回测时常常会看到“unmached data error”的提示,这说明历史数据不完整或者有错误。据我的经验,这类错误不影响历史数据测试效果,当然,如果能够确保数据完整就最好了。完整的历史数据可以参见《【MT4平台】一口气拿下10年数据》也可以参见《历史数据下载与服务中心》。

Q8:一个在历史数据回测中表现良好的EA能否直接实战
答案是否定的。MT4历史数据回测最好的用途是快速检验EA的逻辑符合性,即验证EA是否能够严格按照预定的策略执行。鉴于历史数据不完整和人工编造等原因,一个表现良好的EA并不意味着就可以直接实战,因此网上发表的众多的测试图都可能是一个噱头,极有可能是商家的推广手段。我的建议是您必须将EA放置到模拟盘中运行3个月进一步加以策略执行验证,但这还不够,因为模拟盘允许任意下单量成交,例如开仓量为1手,在实盘中可能就无法成交,另外大多数经纪商平台的模拟盘通讯质量与实盘有区别,这就导致了模拟盘的结果不可靠不真实。当您完成了模拟盘测试之后,建议在实盘中测试6个月,重点关注调试开仓量的执行情况、行情跳水的应对策略、检验平台通讯质量等等。因此,一个成功的EA不可能一蹴而就,有太多的细节需要关注。

Q9:为什么EA在历史数据回测能执行在模拟实盘中不行
主要从以下3点找原因:
1、测试的交易品种可能禁止EA。
2、可能没有符合条件的交易信号。
3、建仓指令包含了止盈止损价位。因为许多平台是不允许建仓同时设置止盈或者止损。
快速测试方法:编写一个开仓EA,运行验证。

Q10:MT4历史订单和持仓单是怎么排序的
MT4历史订单按照平仓时间顺序排序,最后平仓的订单序号最大,序号为OrdersHistoryTotal()-1,第一张平仓单序号为0。选取最新平仓单的命令:
OrderSelect(OrdersHistoryTotal()-1,SELECT_BY_POS,MODE_HISTORY);
MT4成交持仓单按照建仓时间顺序排序,最后建仓的订单顺序号最大,序号为OrdersTotal()-1,最先建仓的持仓单序号为0。选取最新平仓单的命令:
OrderSelect(OrdersTotal()-1,SELECT_BY_POS,MODE_TRADES);
但是,请注意这个“但是”很重要!在实际应用中,发现订单数量大于2张,系统排序就有问题了,所以,按序号检索第一单和最后一单的方法不可靠。

Q11:MT4历史数据导入文件是什么格式
MT4历史数据导入之前需要准备一个.csv文件,这是一个“逗号”格式的文件,可以用Excel打开编辑。每条记录有7个字段,分别是日期、时间、开盘价、最高价、最低价、收盘价、成交量。如下表(EURUSD月线数据所示:
2012.11.01 0:00 1.29564 1.30277 1.26613 1.29844 1384424
2012.12.01 0:00 1.29824 1.3308 1.28769 1.31964 1474901
2013.01.01 0:00 1.31978 1.34788 1.29969 1.34623 1936130

Q12:MT4历史数据无法导入,怎么办
已经编制好的MT4历史数据.csv文件会出现无法导入的情况,可按照以下步骤反复执行:
1、删除\history文件夹中的数据文件,例如现在需要导入XAUUSD M1数据,那就删除XAUUSD1.hst文件。
2、启动MT4平台,打开XAUUSD M1图表,等待平台自动更新1分钟数据,能获取到最新的一批数据。
3、按F2打开“历史数据”窗口,点击“导入”,打开指定的.csv文件,如果导入窗口下半部分显示了数据就说明正常,点击“确定”。
4、如果导入窗口下半部分没有任何显示,则关闭MT4终端,从第2步重新操作一遍,直到第3步完成。
5、浏览历史数据图形,查看错误并在“历史数据”窗口中加以修改。任何历史数据都有瑕疵,因此这一步是必须要执行的。

Q13:MQL4错误代码4008(ERR_NOT_INITIALIZED_STRING 没有初始字行)
预定义字符类型的变量没有赋初始值。这样就行了:
string mystring="";

Q14:MQL4历史数据测试出现stopped because of Stop Out是什么原因
账户资金不够,浮动亏损超过了账户余额。将起始资金调大即可。

Q15:MQL4历史数据测试出现ERR_OBJECT_ALREADY_EXISTS 4200 定单已经存在是什么原因
首先要更正中文翻译“订单已存在”应翻译成“对象已存在”,这是指在屏幕上采用Object模式显示信息时,需要先创建一个文字对象,如果屏幕中已经有这个对象,就不需要创建了,在我的自定义函数中做了如下修正:
void iDisplayInfo(string LableName,string LableDoc,int Corner,int LableX,int LableY,int DocSize,string DocStyle,color DocColor)
{
    if (Corner == -1) return(0);
    for (cnt=0;cnt
    {
        if (ObjectName(cnt)==LableName) //如果有对象名称,退出循环
        {
            break;
        }
    }
    if (cnt==ObjectsTotal())  ObjectCreate(LableName, OBJ_LABEL, 0, 0, 0);//新建对象
    ObjectSetText(LableName, LableDoc, DocSize, DocStyle,DocColor);
    ObjectSet(LableName, OBJPROP_CORNER, Corner);
    ObjectSet(LableName, OBJPROP_XDISTANCE, LableX);
    ObjectSet(LableName, OBJPROP_YDISTANCE, LableY);
}

Q16:MQL4历史数据测试出现ERR_ARRAY_INDEX_OUT_OF_RANGE 4002 数组索引超出范围是什么原因
简单讲就是数组超出边界。在使用数组前首先要定义数组的边界,比如定义数组为6,意味着数组有6个元素,在程序中采用for命令进行遍历计算的时候,那个上限变量是6-1=5,而不是6。

Q17:MT4智能交易中出现了“Off Quotes是什么原因
中文意思是“关闭行情”,EA发出的交易指令不被平台接受,通常是您的MT4软件需要升级更新了,取消EA关闭软件重启试试看?如果报价在服务器无法成交,被称为“价格过期”也是这种提示,那就等呗,直到成交为止。

Q18:Dll程序加载到MT4后容易崩溃,MT4终端自动关闭是什么原因
1、编写DLL代码工具还是有讲究的,我最先使用了Visuol Studio 2010,发现用这么大的程序写dll太夸张了,就改为VC++ 6.0,写出的DLL程序任然经常崩溃,现在使用的是DEV C++ 5.0。编译后的DLL程序只有VS、VC的十分之一大小,MT4终端程序不易崩溃。这是因为MT4软件只兼容标准C或者C++编译的DLL。
2、含有DLL调用的EA加载后还是会偶尔崩溃,多加载几次就行了。
3、历史数据回测时不要在交易图表中加载这类EA,容易崩溃,可能是DLL被重复调用的原因。我没有测试过多货币对同时加载这类EA是否会崩溃。
4、涉及到订单排序检索等算法,如果不用数据库模式,最好不用DLL实现。
5、除非算法加密、通讯等原因,否则强烈建议采用纯粹的MQL4语言编写,因为EA是生产工具,稳定性永远是排在第一位的。
6、用C语言编写的函数,因数据结构与MQL4之间的差异,会导致类型不匹配、内部死循环等非逻辑错误,加上MT4传送的市场数据不够规范,这些都是导致加载DLL后MT4软件崩溃的重要因素。

Q19:MQL4中的IndicatorCounted()干什么用的
当一个新的时间周期开始的时候,新来的报价可能不属于该k线的数据,那么当前k线就没有真正形成,此时只能计算“有效k线”数值,如果用Bars计算就可能会出现错误,IndicatorCounted()是MQL4中专门为编写指标提供的一个函数,返回有效k线数量以避免错误运算。
在时间周期没有更新的时候,Bars等于IndicatorCounted()。编写指标时,为了避免重复计算历史数据,通常会用以下代码只计算当前k线数据:
int limit; //预定义需要计算k线的数量
int counted_bars=IndicatorCounted(); //获取有效的k线总数量
if(counted_bars>0) counted_bars--; //如果有效k线大于0,有效k线数量减1
limit=Bars-counted_bars; //计算需要计算k线的数量,而不是全部
指标第一次加载的时候IndicatorCounted()返回0,那么就会将历史数据统统计算一遍,之后就不需要每次重复计算历史指标数据了。

Q20:MQL4中同一EA如何区别不同的订单
1.如果是不同的货币对,你加上&&symbol,不会乱。但是你要保证所有相关的逻辑判断都加上。比如订单总量,持仓情况,移动止损判断,清仓等等函数。
2.如果是相同的货币对,你需要在两个图表做不同周期的呢?那么你还要加上时间周期判断等控制。
3.Magic是唯一标识,还是用它吧。如果你想精确控制到同一Magic下的每一单,Magic+注释吧。

(等待提问...)

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有