string str; ... if(str) // 将会导致"不能转换'string'类型到'bool'"编译错误(在之前版本不会出现错误) Print("str is true");应该使用明确的条件:
string str; ... //--- 检查字符串是否被初始化 if(str!=NULL) Print("str is true"); or //--- 检查字符串值是否为"true" if(StringCompare(str,"true",false)) Print("str is true"); or //--- 检查字符串是否为不等于零的整数 if((int)str!=0) Print("str is true");
修正崩溃日志中报告的错误。
void ArrayPrint( const void& array[], // 输出数组 uint digits=_Digits, // 小数位数 const string separator=NULL, // 结构字段值之间的分隔符 ulong start=0, // 最先显示元素的指数 ulong count=WHOLE_ARRAY, // 显示的元素数 ulong flags=ARRAYPRINT_HEADER|ARRAYPRINT_INDEX|ARRAYPRINT_LIMIT|ARRAYPRINT_ALIGN );ArrayPrint无法打印全部结构数组字段到日志 – 跳过对象的数组字段和指针字段。如果您想打印全部结构字段,您应该使用所需格式批量打印的定制功能。
//--- 显示最近的10个柱形图值 MqlRates rates[]; if(CopyRates(_Symbol,_Period,1,10,rates)) { ArrayPrint(rates); Print("Проверка\n[time]\t[open]\t[high]\t[low]\t[close]\t[tick_volume]\t[spread]\t[real_volume]"); for(int i=0;i<10;i++) { PrintFormat("[%d]\t%s\t%G\t%G\t%G\t%G\t%G\t%G\t%I64d\t",i, TimeToString(rates[i].time,TIME_DATE|TIME_MINUTES|TIME_SECONDS), rates[i].open,rates[i].high,rates[i].low,rates[i].close, rates[i].tick_volume,rates[i].spread,rates[i].real_volume); } } else PrintFormat("CopyRates failed, error code=%d",GetLastError()); //--- 日志示例 /* [time] [open] [high] [low] [close] [tick_volume] [spread] [real_volume] [0] 2016.11.09 04:00:00 1.11242 1.12314 1.11187 1.12295 18110 10 17300175000 [1] 2016.11.09 05:00:00 1.12296 1.12825 1.11930 1.12747 17829 9 15632176000 [2] 2016.11.09 06:00:00 1.12747 1.12991 1.12586 1.12744 13458 10 9593492000 [3] 2016.11.09 07:00:00 1.12743 1.12763 1.11988 1.12194 15362 9 12352245000 [4] 2016.11.09 08:00:00 1.12194 1.12262 1.11058 1.11172 16833 9 12961333000 [5] 2016.11.09 09:00:00 1.11173 1.11348 1.10803 1.11052 15933 8 10720384000 [6] 2016.11.09 10:00:00 1.11052 1.11065 1.10289 1.10528 11888 9 8084811000 [7] 2016.11.09 11:00:00 1.10512 1.11041 1.10472 1.10915 7284 10 5087113000 [8] 2016.11.09 12:00:00 1.10915 1.11079 1.10892 1.10904 8710 9 6769629000 [9] 2016.11.09 13:00:00 1.10904 1.10913 1.10223 1.10263 8956 7 7192138000 Check [time] [open] [high] [low] [close] [tick_volume] [spread] [real_volume] [0] 2016.11.09 04:00:00 1.11242 1.12314 1.11187 1.12295 18110 10 17300175000 [1] 2016.11.09 05:00:00 1.12296 1.12825 1.1193 1.12747 17829 9 15632176000 [2] 2016.11.09 06:00:00 1.12747 1.12991 1.12586 1.12744 13458 10 9593492000 [3] 2016.11.09 07:00:00 1.12743 1.12763 1.11988 1.12194 15362 9 12352245000 [4] 2016.11.09 08:00:00 1.12194 1.12262 1.11058 1.11172 16833 9 12961333000 [5] 2016.11.09 09:00:00 1.11173 1.11348 1.10803 1.11052 15933 8 10720384000 [6] 2016.11.09 10:00:00 1.11052 1.11065 1.10289 1.10528 11888 9 8084811000 [7] 2016.11.09 11:00:00 1.10512 1.11041 1.10472 1.10915 7284 10 5087113000 [8] 2016.11.09 12:00:00 1.10915 1.11079 1.10892 1.10904 8710 9 6769629000 [9] 2016.11.09 13:00:00 1.10904 1.10913 1.10223 1.10263 8956 7 7192138000 */
void OnStart() { int arr[]; //--- 最初使用的内存数量 Print("Array size:",ArraySize(arr)," Memory used:",MQLInfoInteger(MQL_MEMORY_USED)," MB"); //--- 用于数组大小1的内存数量,保留 ArrayResize(arr,1,1024*1024); Print("Array size:",ArraySize(arr)," Memory used:",MQLInfoInteger(MQL_MEMORY_USED)," MB"); //--- 增加数组以后,使用的内存数量因保留而无法更改 ArrayResize(arr,1024*512,1024*1024); Print("Array size:",ArraySize(arr)," Memory used:",MQLInfoInteger(MQL_MEMORY_USED)," MB"); //--- 减少数组以后,内存大小也不会改变 ArrayResize(arr,1); Print("Array size:",ArraySize(arr)," Memory used:",MQLInfoInteger(MQL_MEMORY_USED)," MB"); //--- 移除储备内存后将释放未使用的内存 ArrayResize(arr,1,-1); Print("Array size:",ArraySize(arr)," Memory used:",MQLInfoInteger(MQL_MEMORY_USED)," MB"); }
#include <Graphics/Graphic.mqh> double Func1(double x) { return MathPow(x,2); } double Func2(double x) { return MathPow(x,3); } double Func3(double x) { return MathPow(x,4); } void OnStart() { GraphPlot(Func1,Func2,Func3,-2,2,0.05,CURVE_LINES); }结果:
#include <Math/Stat/Binomial.mqh> #include <Graphics/Graphic.mqh> void OnStart(void) { double vars[101]; double results[101]; const int N=2000; //--- MathSequence(0,N,20,vars); MathProbabilityDensityBinomial(vars,N,M_PI/10,true,results); ArrayPrint(results,4); GraphPlot(results); //--- }结果:
更新文档。
在交易对话框添加买入,卖出和关闭按键的工具提示。工具提示包括操作期间买入或卖出安全性的信息,以帮助新手了解交易的过程。
标准程序库中加入了MQL5版的ALGLIB数值分析库 。
程序库特点
如何使用
ALGLIB 文件位于\MQL5\Include\Math\Alglib。若要使用这些函数,请将主程序文件添加到您的程序:
#include <Math\Alglib\alglib.mqh>
标准程序库包含了数理统计函数。MQL5 现在提供R语言的功能,这是最好的统计数据处理和分析工具之一。
程序库特点
统计程序库包含计算数据统计特征的函数以及统计分布操作的函数:
如何使用
统计程序库文件位于 \MQL5\Include\Math\Stat。若要使用该程序库,请将所需函数的文件添加到您的程序,例如:
#include <Math\Stat\Binomal.mqh> #include <Math\Stat\Cauchy.mqh>
程序库函数的详细描述可在文章MQL5统计分布 - 使用最好的R中得到。
标准程序库中加入了MQL5版的Fuzzy程序库。Fuzzy程序库实现了Mamdani和Sugeno模糊推理系统。
程序库特点
如何使用
Fuzzy程序库文件位于\MQL5\Include\Math\Fuzzy。若要使用该程序库,请将所需函数的文件添加到您的程序,例如:
#include <Math\Fuzzy\mamdanifuzzysystem.mqh> #include <Math\Fuzzy\sugenofuzzysystem.mqh>
程序库的详细描述可在代码库:Fuzzy - 开发模糊模型的程序库中得到
long FileLoad( const string filename, // [in] 文件名 void &buffer[], // [out] 阅读文件的数组 uint common_flag=0 // [in] 0 - 搜索程序端Files文件夹中的文件,FILE_COMMON - 在程序端普通目录中搜索 ); bool FileSave( const string filename, // [in] 文件名 const void &buffer[], // [in] 保存文件的数组 uint common_flag=0 // [in] 0 - 创建程序端Files文件夹中的文件,FILE_COMMON - 在程序端普通目录中创建 );如何将报价写入文件然后阅读的示例:
//--- 输入参数 input int ticks_to_save=1000; // 报价数 //+------------------------------------------------------------------+ //| 脚本程序起始函数 | //+------------------------------------------------------------------+ void OnStart() { string filename=_Symbol+"_ticks.bin"; MqlTick ticks[]; //--- int copied=CopyTicks(_Symbol,ticks,COPY_TICKS_ALL,0,ticks_to_save); if(copied!=-1) { PrintFormat(" CopyTicks(%s) copied %d ticks",_Symbol,copied); //--- 如果报价历史被同步,错误代码等于零 if(!GetLastError()==0) PrintFormat("%s: Ticks are not synchronized. Error=",_Symbol,copied,_LastError); //--- 写入报价到文件 if(!FileSave(filename,ticks,FILE_COMMON)) PrintFormat("FileSave() failed, error=%d",GetLastError()); } else PrintFormat("Failed CopyTicks(%s), Error=",_Symbol,GetLastError()); //--- 现在阅读返回到文件的报价 ArrayFree(ticks); long count=FileLoad(filename,ticks,FILE_COMMON); if(count!=-1) { Print("Time\tBid\tAsk\tLast\tVolume\tms\tflags"); for(int i=0;i<count;i++) { PrintFormat("%s.%03I64u:\t%G\t%G\t%G\t%I64u\t0x%04x", TimeToString(ticks[i].time,TIME_DATE|TIME_SECONDS),ticks[i].time_msc%1000, ticks[i].bid,ticks[i].ask,ticks[i].last,ticks[i].volume,ticks[i].flags); } } }
//--- 绘制相同颜色的蜡烛图 #property indicator_label1 "One color candles" #property indicator_type1 DRAW_CANDLES //--- 仅指定一种颜色,所以所有蜡烛图都是相同的颜色 #property indicator_color1 clrGreen如果指定两种颜色,一种颜色用于蜡烛图的边框,另一种用于主体。
//--- 蜡烛图的颜色不同于阴影颜色 #property indicator_label1 "Two color candles" #property indicator_type1 DRAW_CANDLES //--- 蜡烛图边框和阴影为绿色,主体为白色 #property indicator_color1 clrGreen,clrWhite如果指定三种颜色,一种颜色用于蜡烛图的边框,其他两种颜色用于牛市蜡烛图和熊市蜡烛图的主体。
//--- 蜡烛图的颜色不同于阴影颜色 #property indicator_label1 "One color candles" #property indicator_type1 DRAW_CANDLES //--- 蜡烛图边框和阴影为绿色,牛市蜡烛图主体为白色,熊市蜡烛图主体为红色 #property indicator_color1 clrGreen,clrWhite,clrRedDRAW_CANDLES 风格允许设置自定义颜色的蜡烛图。使用PlotIndexSetInteger函数运行指标期间还可以动态更改所有颜色(drawing_index_DRAW_CANDLES, PLOT_LINE_COLOR, modifier_number, color),在这里modifier_number 可能是以下的值:
//--- 设置边框和阴影的颜色 PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,clrBlue); //--- 设置牛市蜡烛图主体颜色 PlotIndexSetInteger(0,PLOT_LINE_COLOR,1,clrGreen); //--- 设置熊市蜡烛图主体颜色 PlotIndexSetInteger(0,PLOT_LINE_COLOR,2,clrRed);
更新文档。
class CFoo final { //--- 类主体 }; class CBar : public CFoo { //--- 类主体 };当如上面显示的一样试图以'final'修饰符从一个类继承时,编译器显示一个错误:
class CFoo { void virtual func(int x) const { } };类函数重写在继承类:
class CBar : public CFoo { void func(short x) { } };但是自变量类型错误的从'int' 变为'short'。实际上,替代重写的重载类函数在这种情况下执行。根据重载函数定义算法进行操作时,编译器在有些情况下可能会选择基本类中定义的类函数而不是重写的类函数。
class CBar : public CFoo { void func(short x) override { } };如果在重写过程中更改了类函数签名,编译器将无法在发布编译错误的父类中找到相同签名的类函数:
class CFoo { void virtual func(int x) final { } }; class CBar : public CFoo { void func(int) { } };当如上面显示的一样试图以'final'修饰符重写一个类函数,编译器显示一个错误:
更新文档。
class CFoo { }; class CBar { }; //+------------------------------------------------------------------+ //| 脚本程序起始函数 | //+------------------------------------------------------------------+ void OnStart() { void *vptr[2]; vptr[0]=new CFoo(); vptr[1]=new CBar(); //--- for(int i=0;i<ArraySize(vptr);i++) { if(dynamic_cast<CFoo *>(vptr[i])!=NULL) Print("CFoo * object at index ",i); if(dynamic_cast<CBar *>(vptr[i])!=NULL) Print("CBar * object at index ",i); } CFoo *fptr=vptr[1]; // 将返回类型转换指针错误,vptr[1] 并不是CFoo对象 } //+------------------------------------------------------------------+
string text="Hello"; ushort symb=text[0]; // 将返回符号'H'代码
更新文档。
修正测试期间每年按百分比计算手续费。
修正测试进行中生成的图表上的结余计算和展示。
公开测试两个月后,多元化MetaTrader 5 平台网页版 现已官方对外发布。它允许从任何浏览器和任何操作系统进行外汇和金融市场交易。仅需网络连接即可,无需安装任何软件。
该应用将桌面版的主要优势(高速,支持多元化市场和扩展的交易功能)与网页程序端的便利性和跨平台特性相结合。该发布版的主要功能在于测试版中所没有的市场深度。
网页平台允许交易者执行技术分析和交易操作,就像在桌面版一样。网页平台提供以下特性:
现在从桌面平台转移SSL证书到移动平台更加容易。您不再需要iTunes去完成它。
MetaTrader 5允许您通过使用证书为您的账户添加额外保护。没有证书,则无法连接。如果证书在桌面版创建,您应该能够通过移动设备进入您的账户转移它。
为此,请打开桌面平台,在导航窗口右击所需的账户,并选择转移。设置只有您知道的证书密码,打开移动平台,连接您的账户。您将被立即提供导入证书。
此外,最新版还具有从MetaTrader 4转移账户的迁移对话框。如果您的账户已经转移到第五代交易平台,我们热烈欢迎,并提供有关新特性的信息和要求更改您的密码。
之前 | 之后 | |
---|---|---|
起动 | 所有挂单类型和SL/TP的卖价/买价 | 限价订单卖价/买价 最终止损,止损限价和SL/TP订单 |
执行 | 所有挂单类型和SL/TP的订单指定价格 | 所有挂单类型和SL/TP的订单起动时的卖价/买价 |
让我们考虑Si-6.16 交易品种的示例。起动价格的新买入止损订单 = 设定72580 而当前价格是:Bid=72570,Ask=72572,Last=72552。在价格流新收到的当前价格:
起动交易工具止损订单的是最终价。所以价格流中收到的Last price=72580 激活买入止损订单。在早期版本中,相同价格将用于执行该订单。这个行为是错误的,因为市场中没有Ask=72580 执行买入交易。
2016.05.10 12:47:53 Core 1 5.10 Mb 已处理历史记录 0:00.842 2016.05.10 12:47:53 Core 1 GBPUSD:历史同步完成 [5225 Kb]
更新内容将通过LiveUpdate系统提供。
MetaTrader 5 网页平台测试版现已发布。新产品将网页程序端的便利性和跨平台的特性与MetaTrader 5桌面版的优势相结合 – 高速,支持多元化市场和扩展的交易功能。
MetaTrader 5 网页平台可在MQL5.community上使用,它允许交易者从任何浏览器和操作系统,包括Windows,Mac和Linux,执行金融市场的交易操作。您只需要一个网络连接。不需要额外的软件。
测试版拥有以下特性:
净额系统
通过这个系统,在同一时间,一个交易品种您只能有一个普通持仓:
这没关系,导致反向交易的是 — 已执行的市场订单或触发的挂单。
下面示例显示了执行两个每笔0.5手的EURUSD买入交易:
执行这两个交易即是1手的一个普通持仓。
锁仓系统
通过这个系统,您可以一个交易品种拥有多个持仓,包括反向持仓。
如果您有一个交易品种的持仓,执行一个新交易(或触发挂单),那么会另外建立一个新持仓。您当前持仓不会改变。
下面示例显示了执行两个每笔0.5手的EURUSD买入交易:
执行这些交易则会新建两个独立的持仓。
新交易操作类型 - Close By
新的交易类型已经被加入锁仓账户 — 通过反向持仓来平仓。这个操作允许在单一交易品种关闭两个反向的持仓。如果反向持仓手数不同,那么两个持仓中只有一个订单保留持仓。其交易量将等于平仓手数的差异值,而持仓方向和开盘价将匹配平仓的更大(交易量)。
相比单独关闭两个持仓,关闭反向持仓允许交易者保留一个点差:
在后面那种情况下,下单"close by" 订单。平仓信息在该评论指明。一组反向持仓通过两个"out by"交易关闭。关闭两个持仓得到的总利润/亏损只在一个交易中指明。
订单和持仓(包括历史订单)标签在导入过程中不会保留,因为从MetaTrader 4导入一个历史记录可能相当于MetaTrader 5中的4个历史操作。所有的交易记录都会分配新的标签。
根据交易商导入的方式可以保留或替代账号。
class CAnimal { public: CAnimal(); // 构造函数 virtual void Sound() = 0; // 纯虚拟函数 private: double m_legs_count; // 动物脚的数量 };这里Sound() 是一个纯虚拟函数,因为它声明为纯虚拟函数PURE (=0)的说明符。
class CAnimal { public: virtual void Sound()=NULL; // PURE 类函数,应被覆盖在派生类中,CAnimal 现在是抽象类,不能创建 }; //--- 派生自一个抽象类 class CCat : public CAnimal { public: virtual void Sound() { Print("Myau"); } // PURE被覆盖,CCat 不是抽象类,可以创建 }; //--- 错误使用的例子 new CAnimal; // 'CAnimal' 错误 - 编译器返回"不能实例化抽象类"的错误 CAnimal some_animal; // 'CAnimal' 错误 - 编译器返回"不能实例化抽象类"的错误 //--- 正确使用的示例 new CCat; // 没有错误 - CCat 类不是抽象类 CCat cat; // 没有错误 - CCat 类不是抽象类抽象类的限制
//+------------------------------------------------------------------+ //| 抽象基类 | //+------------------------------------------------------------------+ class CAnimal { public: //--- 纯虚拟函数 virtual void Sound(void)=NULL; //--- 函数 void CallSound(void) { Sound(); } //--- 构造函数 CAnimal() { //--- 虚拟类函数的显式调用 Sound(); //--- 隐式调用(使用第三个函数) CallSound(); //--- 构造函数或析构函数始终调用自己的函数, //--- 即使它们是虚拟函数并且已经被派生类中已调用的函数所覆盖 //--- 如果调用的函数是纯虚拟函数 //--- 调用会引起“纯虚拟函数调用”的关键的执行错误 } };然而,抽象类的构造函数和析构函数可以调用其他成员函数。
typedef int (*TFunc)(int,int);现在,TFunc是一种类型,可以声明函数的变量指针:
TFunc func_ptr;func_ptr 变量可以存储函数地址以便稍后声明:
int sub(int x,int y) { return(x-y); } int add(int x,int y) { return(x+y); } int neg(int x) { return(~x); } func_ptr=sub; Print(func_ptr(10,5)); func_ptr=add; Print(func_ptr(10,5)); func_ptr=neg; // 错误:neg 不是 int (int,int) 型 Print(func_ptr(10)); // 错误:应该有两个参数函数指针可以被存储并作为参数传递。您不能得到非静态类函数的指针。
ulong PositionGetTicket( int index // 持仓列表索引 );
bool PositionSelectByTicket(
ulong ticket // 持仓标签
);
净额系统
通过这个系统,在同一时间,一个交易品种您只能有一个普通持仓:
这没关系,导致反向交易的是 — 已执行的市场订单或触发的挂单。
下面示例显示了执行两个每笔0.5手的EURUSD买入交易:
执行这两个交易即是1手的一个普通持仓。
锁仓系统
通过这个系统,您可以一个交易品种拥有多个持仓,包括反向持仓。
如果您有一个交易品种的持仓,执行一个新交易(或触发挂单),那么会另外建立一个新持仓。您当前持仓不会改变。
下面示例显示了执行两个每笔0.5手的EURUSD买入交易:
执行这些交易则会新建两个独立的持仓。
新交易操作类型 - Close By
新的交易类型已经被加入锁仓账户 — 通过反向持仓来平仓。这个操作允许在单一交易品种关闭两个反向的持仓。如果反向持仓手数不同,那么两个持仓中只有一个订单保留持仓。其交易量将等于平仓手数的差异值,而持仓方向和开盘价将匹配平仓的更大(交易量)。
相比单独关闭两个持仓,关闭反向持仓允许交易者保留一个点差:
在后面那种情况下,下单"close by" 订单。平仓信息在该评论指明。一组反向持仓通过两个"out by"交易关闭。关闭两个持仓得到的总利润/亏损只在一个交易中指明。
class CAnimal { public: CAnimal(); // 构造函数 virtual void Sound() = 0; // 纯虚拟函数 private: double m_legs_count; // 动物腿的数量 };这里Sound() 是一个纯虚拟函数,因为它声明为纯虚拟函数PURE (=0)的说明符。
class CAnimal { public: virtual void Sound()=NULL; // PURE 类函数,应被覆盖在派生类中,CAnimal 现在是抽象类,不能创建 }; //--- 抽象类的后裔 class CCat : public CAnimal { public: virtual void Sound() { Print("Myau"); } // PURE被覆盖,CCat 不是抽象类,可以创建 }; //--- 错误使用的例子 new CAnimal; // 'CAnimal' 错误 - 编译器返回"不能实例化抽象类"的错误 CAnimal some_animal; // 'CAnimal' 错误 - 编译器返回"不能实例化抽象类"的错误 //--- 正确使用的示例 new CCat; // 没有错误 - CCat 类不是抽象类 CCat cat; // 没有错误 - CCat 类不是抽象类抽象类的限制
//+------------------------------------------------------------------+ //| 抽象基类 | //+------------------------------------------------------------------+ class CAnimal { public: //--- 纯虚拟函数 virtual void Sound(void)=NULL; //--- 函数 void CallSound(void) { Sound(); } //--- 构造函数 CAnimal() { //--- 虚拟类函数的显式调用 Sound(); //--- 隐式调用(使用第三个函数) CallSound(); //--- 构造函数或析构函数始终调用自己的函数, //--- 即使它们是虚拟函数并且已经被派生类中已调用的函数所覆盖 //--- 如果调用的函数是纯虚拟函数 //--- 调用会引起“纯虚拟函数调用”的关键的执行错误 } };然而,抽象类的构造函数和析构函数可以调用其他成员函数。
typedef int (*TFunc)(int,int);现在,TFunc是一种类型,可以声明函数的变量指针:
TFunc func_ptr;func_ptr 变量可以存储函数地址以便稍后声明:
int sub(int x,int y) { return(x-y); } int add(int x,int y) { return(x+y); } int neg(int x) { return(~x); } func_ptr=sub; Print(func_ptr(10,5)); func_ptr=add; Print(func_ptr(10,5)); func_ptr=neg; // 错误:neg 不是 int (int,int) 型 Print(func_ptr(10)); // 错误:应该有两个参数函数指针可以被存储并作为参数传递。您不能得到非静态类函数的指针。
ulong PositionGetTicket( int index // 持仓列表索引 );
bool PositionSelectByTicket(
ulong ticket // 持仓标签
);