11:57MetaQuotes Language 4 (MQL4) 是一种新的内置型程序用来编写交易策略。 这种语言可以创建你自己的智能交易,使自己的交易策略能够完全自动地执行。而且,MQL4 还能自定义客户指标,脚本和数据库。 内包含了大量可以分析当前及历史报价所必须的函数,以及一些基本的运算和逻辑操作。并内置了一些基本的指标和操作命令。 MetaEditor 4集合了编写 MQL4 程序代码的各种语句,它能帮助使用者方便地写出规范的代码。 MetaQuotes Language Dictionary 是 MQL4 语言的帮助工具,它包含了我们在使用工程中所有可能用到的函数。 MetaQuotes Language 4 可以编写不同作用的程序代码: 智能交易 是一种连接到特定图表的自动交易系统。它能够根据设置的节点自动启动,当它开始运行后,它不会同时去处理另一个新的指令(也就是说必须等到当前程序完成)。 这种交易系统能够在提醒用户可以交易的同时,将交易定单自动送到交易服务器。与大多数交易系统一样,它也能够用历史数据测试交易策略,并在图表上显示出来。 智能交易存储在terminal_directory\experts。 自定义指标 可用来编写新的技术指标,和内置的指标一样,它不能用来进行自动交易,只能作为分析数据的工具。 自定义指标储存在terminal_directory\experts\indicators。 脚本 是执行单一功能的一段程序,和智能交易不同,脚本不能单独执行,只能被调用。 脚本存储在terminal_dictionary\experts\scripts。 数据库 常被使用的自定义函数的集合。数据库不能单独运行。 数据库建议存储在terminal_directory\experts\libraries。 包含文件 包含文件常被使用的程序块源代码,这些文件能够被包含在智能交易,脚本,客户指标和数据库的源代码中。 使用包含文件比调用资料库更灵活快捷。 包含文件交易储存在terminal_directory\experts\include。
关于 MT 4 (MQL4)智能交易(EA)程序编辑简介-22009年04月10日 星期五 12:08 EA是什么?及他的工作原理 EA 即 ExpertAdvisors 的英文缩写,中文意思专家顾问,俗称智能交易系统,就是由电脑模拟交易员的下单操作进行机器自动交易的过程。 一、人工操盘过程 下面我们就以MT4外汇客户端为例,首先来分析一个外汇交易员手工进行外汇交易的操作过程:其步骤如下: 1.打开外汇交易客户端,选定一种货币对图表; 2.监视该货币对的K线趋势图,俗称盯盘,寻找开仓或者是平仓的时机,即开仓或者是平仓的条件 3.如果条件满足,进行下单开仓(做多或者做空)或者平仓 4.重复第二步,继续盯盘,假定第二步是开仓,就是寻找平仓的条件。 5.如果平仓的条件满足,进行平仓操作,计算盈亏核算。完成一次交易的循环。 6.若继续交易,重复2->3->4->5步 7.若不进行交易,退出外汇客户端。 二、机器操盘过程 基于以上的分析,我们已经知道一个完整的智能交易系统(俗称EA)在运行后必须要实现的基本功能,就是上述的人工操作的1-5步。 这也就是智能交易系统的基本工作过程,所以智能交易系统的工作原理就是由程序员借助一门计算机程序设计语言,通过编写程序交易 指令模拟人类交易员的行为进行下单操作,实现机器自动进行交易的过程。主要执行过程可分为:盯盘->开仓->再盯盘->平仓,如此循环执行的过程。 关于支持机器自动交易的平台,目前外汇市场上流行的就是MetaQuotes公司的MT4平台,由于这个平台中嵌入了一种MQL4语言,它提供了对服务器端的数据访问并可进行交易操作的接口,程序交易者可以根据自己的交易策略来编写自己的自动交易系统,从而实现让机器自动交易,既可以减轻人类的工作量,又可以克服人类交易中的一此性格弱点,但目前的EA开发,尚所早期起步阶段,有的还存在缺陷,但相信随着技术的发展,机器自动交易终将会逐步取代人类的手工操作。届时会给交易者一项新的选择。 三、 相关MQL语言知识: 为了实现机器操作,再来看看所需的MQL4语言的相关知识: 1.掌握MQL4语言的基本语法和程序的构成,及运行流程 有关语法部分,请读者参看相关的资料,这里略去。 关于程序的构成,对于一个智能交易系统EA程序来说:主要由三个函数构成分别是: init():初始化函数,负责程序变量及数据初始输入;只在程序调入时执行一次,一般不用重写内容。 deinit():反初始化函数,负责程序退出时,将数据从内存中清除;只在程序退出时,执行一次,一般不用重写内容。 start():开始函数,也即程序的主函数,负责EA程序 的全部交易执行过程,实际上他是一个EA的交易管理与执行函数。每隔一定时间,一般几秒之内,执行一次,就是循环执行,起到程序退出时终止 运行流程:启动EA后,程序的INTI()开始执行一次,-->然后 START()循环执行--->最后退出EA时deinit()执行一次 2.mql4中与交易相关的交易函数: 开仓函数: int OrderSend( string symbol, int cmd, doublevolume, double price, int slippage, double stoploss, double takeprofit, voidcomment, void magic, void expiration, void arrow_color) 这个功能主要应用于开仓位置和挂单交易. 参量: symbol - 交易货币对。 cmd - 购买方式。 volume - 购买手数。 price - 收盘价格。 slippage - 最大允许滑点数。 stoploss - 止损水平。 takeprofit - 赢利水平。 comment - 注解文本。 magic - 定单指定码。可以作为用户指定识别码使用。 expiration - 定单有效时间(只限挂单)。 arrow_color - 图表上箭头颜色。如果参量丢失或存在CLR_NONE价格值不会在图表中画出 平仓函数: bool OrderClose( int ticket, double lots,double price, int slippage, void Color) 对定单进行平仓操作。如果函数成功,返回的值是真实的。如果函数失败,返回的值是假的。获得详细错误信息,请查看GetLastError()函数。 参量: ticket - 定单编号。 lots - 手数。 price - 收盘价格。 slippage - 最高划点数。 Color - 图表中标记颜色。如果参量丢失,CLR_NONE值将不会在图表中画出。 定单修改函数: bool OrderModify( int ticket, double price,double stoploss, double takeprofit, datetime expiration, void arrow_color) 对于先前的开仓或挂单进行特性修改。如果函数成功,返回的值为 TRUE。如果函数失败,返回的值为FALSE。 获得详细的错误信息,查看GetLastError()函数。 参量: ticket - 定单编号。 price - 收盘价格 stoploss - 新止损水平。 takeprofit - 新赢利水平。 expiration - 挂单有效时间。 arrow_color - 在图表中允许对止损/赢利颜色进行修改。如果参量丢失或存在CLR_NONE 值,在图表中将不会显示。 四、源码的交易流程分析 下面的源码是一个基于KD指标的智能交易系统的代码,整个程序非常简洁但EA的功能又非常齐全,实现了完全由电脑自动下单和平仓,程序代码分析参看代码中的相关注释 //+------------------------------------------------------------------+ //| KD.mq4 | //| QQ: 412968847 | //+------------------------------------------------------------------+ #property copyright "毅丰汇业-教学使用EA" #property link "sy_yfhy@126.com" #define MAGICKDJ 20080220 //---- input parameters extern int whichmethod = 2;//1;//4; //1: no S/L,no T/P 不设止赢也不设止损 //2: noS/L,has T/P 设止损,但不设止赢 //3: hasS/L,no T/P 设止赢,不设止损 //4: hasT/P has S/L,设止赢也设止损 extern double Lots=0.1; //开仓量 extern double MaximumRisk=0.5; //开仓占可用资金比例 extern double DecreaseFactor=0.3; //开仓亏损减少下单手数 extern int tp=200; //最大赢利止赢点数 extern int sl=100; //最大损失止损点数 extern int Leverage=100; //交易倍数1:100 //+------------------------------------------------------------------+ //| expert start function | //+------------------------------------------------------------------+ int start() { //---- check for history and trading if(Bars<100 || IsTradeAllowed()==false) return; //---- calculate open orders by currentsymbol if(CalculateCurrentOrders(Symbol())==0) CheckForOpen(); else CheckForClose(); return(0); } //+------------------------------------------------------------------+ //| Calculate open positions | //+------------------------------------------------------------------+ int CalculateCurrentOrders(string symbol) { int buys=0,sells=0; //---- for(int i=0;i<OrdersTotal();i++) { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break; if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGICKDJ) { if(OrderType()==OP_BUY) buys++; if(OrderType()==OP_SELL) sells++; } } //---- return orders volume if(buys>0) return(buys); else return(-sells); } //+------------------------------------------------------------------+ //| Check for open order conditions | //+------------------------------------------------------------------+ void CheckForOpen() { //double ma; int res; double point =MarketInfo(Symbol(),MODE_POINT); Print("point=",point); //---- go trading only for first tiks ofnew bar if(Volume[0]>1) return; double valK=iStochastic(NULL,0,5,3,3,MODE_SMA,0,MODE_MAIN,0); //当周期的K值 double valD=iStochastic(NULL,0,5,3,3,MODE_SMA,0,MODE_SIGNAL,0); //当周期的D值 //---- sell conditions if(valD > 80 && valK < valD) //k下穿D K<d 开空仓 { switch (whichmethod) { case 1: res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,0,"开空仓",MAGICKDJ,0,Red); break; case 2: res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,Bid+sl*point,0,"开空仓",MAGICKDJ,0,Red);break; case 3: res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,Bid-tp*point,"开空仓",MAGICKDJ,0,Red); break; case 4: res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,0,Bid+sl*point,Bid-tp*point,"开空仓",MAGICKDJ,0,Red); break; default :res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,0,"",MAGICKDJ,0,Red);break; } if (res <=0) { int error=GetLastError(); if(error==134) Print("Received 134 Error after OrderSend() !!"); // not enough money if(error==135) RefreshRates(); // prices have changed if(error==131) Print("Received 131 Error after OrderSend() !!"); // not enough money } //Sleep(5000); return; } //---- buy conditions if(valD < 20 && valK > valD) //k上穿D k>d 开多仓 { switch (whichmethod) { case 1: res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,0,"开多仓",MAGICKDJ,0,Blue);break; case 2: res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,Ask-sl*point,0,"开多仓",MAGICKDJ,0,Blue);break; case 3: res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,Ask+tp*point,"开多仓",MAGICKDJ,0,Blue);break; case 4: res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,0,Ask-sl*point,Ask+tp*point,"开多仓",MAGICKDJ,0,Blue);break; default : res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,0,"开多仓",MAGICKDJ,0,Blue);break; } if (res <=0) { error=GetLastError(); if(error==134) Print("Received 134 Error after OrderSend() !!"); // not enough money if(error==135) RefreshRates(); // prices have changed } Sleep(5000); return; } //---- } //+------------------------------------------------------------------+ //| Check for close order conditions | //+------------------------------------------------------------------+ void CheckForClose() { double ma; //---- go trading only for first tiks ofnew bar if(Volume[0]>1) return; double valK=iStochastic(NULL,0,5,3,3,MODE_SMA,0,MODE_MAIN,0); //当周期的K值 double valD=iStochastic(NULL,0,5,3,3,MODE_SMA,0,MODE_SIGNAL,0); //当周期的D值 //---- for(int i=0;i<OrdersTotal();i++) { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break; if(OrderMagicNumber()!=MAGICKDJ || OrderSymbol()!=Symbol()) continue; //---- check order type if(OrderType()==OP_BUY) { if(valK >80 && valK < valD) //k下穿D K<d 多方盘平仓 OrderClose(OrderTicket(),OrderLots(),Bid,3,White); Sleep(5000); break; } if(OrderType()==OP_SELL) { if(valK <20 && valK > valD) //k上穿D or k>d 空方盘平仓 OrderClose(OrderTicket(),OrderLots(),Ask,3,White); Sleep(5000); break; } } //---- } //+------------------------------------------------------------------+ //| Calculate optimal lot size | //+------------------------------------------------------------------+ double LotsOptimized() { double lot=Lots; int orders=HistoryTotal(); // history orders total int losses=0; // number of losses orderswithout a break //---- select lot size lot=NormalizeDouble(AccountFreeMargin()*MaximumRisk*Leverage/1000000.0,1); //---- calcuulate number of losses orderswithout a break if(DecreaseFactor>0) { for(int i=orders-1;i>=0;i--) { if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false) { Print("Error in history!"); break; } if(OrderSymbol()!=Symbol() || OrderType()>OP_SELL) continue; //---- if(OrderProfit()>0) break; if(OrderProfit()<0) losses++; } if(losses>1) lot=NormalizeDouble(lot-lot*losses*DecreaseFactor,1); } //---- return lot size if(lot<0.1) lot=0.1; return(lot); } //+------------------------------------------------------------------+ //| 请勿用于真实帐户使用,并非稳定盈利交易系统,技术交流: 15840167522 | //+------------------------------------------------------------------+ 五、本文结论 从以上的分析,可以知道,所谓EA,就是由电脑模拟交易员的下单操作进行机器交易的过程, 具体步骤如下: 1.当用户打开外汇客户端程序后,由客户端程序调入用户在系统内已预置好的EA交易系统程序。 2.当EA程序启动后便开始对图表中货币对的K线趋势图,进行监视,寻找开仓的条件; 3.如果条件满足,进行下单开仓(做多或者做空); 4.重复第二步,继续盯盘,假定第二步是开仓,就是寻找平仓的条件。 5.如果平仓的条件满足,进行平仓操作,计算盈亏核算。完成一次交易的循环。 6.若继续交易,EA重复2->3->4->5步 7.用户若不想让EA进行交易,可通过相关菜单操作设置禁用EA,或者退出外汇客户端。
关于 MT 4 (MQL4)智能交易(EA)程序编辑简介-3 智能交易的特性 在MetaTrader4交易系统中创建并测试智能交易存在以下列举特性。
- 在开仓之前必须验证账户内是否存在自由保证金。如果账户内的自由保证金不足,开仓交易将失败。您可以测试检验"FreeMargin"值不能够少于1000,因为测试期间一个标准手的的价格为 1000。
if(AccountFreeMargin() < 1000) return(0); // 没有保证金 - 退出
- 您可以通过使用预设定数组Time, Open, Low, High, Close, Volume 获取历史数据。因为历史数据的原因,指数的增长是逐渐递减-指数的最后值为0。指数 1 表示倒数一个时间周期,指数2表示倒数两个时间周期,指数3 倒数三个时间周期以此类推。
· // 如果前一个蜡烛柱的Close少于 · // 前者的Close if(Close[1] < Close[2]) return(0);
- 使用其他的时间间隔甚至是其他货币对可以获得当前历史的数据。得到这些数据首先需要确定一维数组,并且在函数"ArrayCopySeries"的帮助下完成复制工作。对于函数的调用您可以发送较少数量的参量,并且不指明默认参量。
· doubleeur_close_m1[]; · int number_copied= ArrayCopySeries(eur_close_m1, MODE_CLOSE, "EURUSD", PERIOD_M1);
- 智能交易的编写与其他程序创建一样需要一些附加的调试信息。 MQL4 语言提供了几种获取信息的方法。
- 函数 "Alert" 会出现一个对话窗口显示用户指定数据。
Alert("FreeMargin grows to ",AccountFreeMargin(), "!");
- 函数 "Comment"将会在图表窗口的左上角显示用户指定的数据。符号"\n" 使用于字行的转接。
Comment("FreeMargin is ", AccountFreeMargin(),".");
- 函数"Print"在系统日志中打印用户指定的数据。
Print("FreeMargin is ", AccountFreeMargin(),".");
- 程序中错误的获取,函数"GetLastError"的功能非常有用。例如,交易订单经常返回替克数。如果这个替克数字等于 0 (在执行业务过程中出现了错误),获取这个错误的详细信息必须调用函数"GetLastError":
· int iTickNum = 0; · int iLastError =0; · ... · iTickNum =OrderSend(Symbol(), OP_BUY, g_Lots, Ask, 3, 0, · Ask + g_TakeProfit *g_Points); · if(iTickNum <=0) · { · iLastError = GetLastError(); · if(iLastError != ERR_NO_ERROR) Alert("Some Message"); } 调用"GetLastError"函数可以显示错误代码,并且重新设置改值。 因此连续调用这个函数返回的值将是0。
- 怎样确定开始柱? (必须找到先前柱结束的位置)存在以下几种方法。
第一种方法以检测柱的数量为基础: static int prevbars = 0; ... if(prevbars == Bars) return(0); prevbars = Bars; ... 这种方法在历史加载的情况下不能运行。在“先前”柱没有完成之间,柱的数量发生改变。这种情况下您可以检查这些值之间的差距等于1。
接下来这种方法是以 "Volume" 值为基础取决先前每个柱生成的替克的数量。第一个替克意味着形成柱的"Volume"值等于 1: if( Volume[0] > 1) return(0); ... 这种方法在大量价格替克输入时可能会运行失败。问题在于价格替克的输入时实行单独的作业。如果当下一个替克进入时这个作业处于繁忙状态,那么进入的这个替克则不能进入以避免超载的出现!这种情况下可以使用先前保存的 "Volume"执行检测。
第三种方法是以柱的打开时间为基础: static datetime prevtime=0; ... if(prevtime == Time[0]) return(0); prevtime = Time[0]; ... 这种方法是最保险的方法。它能够在任意条件下运行。 · int h1; · h1 =FileOpen("my_data.csv", MODE_CSV | MODE_WRITE, ";"); · if(h1 < 0) · { · Print("Unable to open filemy_data.csv"); · return(false); · } · FileWrite(h1,High[1], Low[1], Close[1], Volume[1]); FileClose(h1); 对于代码的一些描述。首先打开"CSV"格式文件。在打开文件时生成错误将会对出程序。在文件成功打开后,清除文件内容并复制数据到文件内,随后关闭文件。如果您需要保存文件原有的内容,可以使用 MODE_READ模式打开: int h1; h1 = FileOpen("my_data.csv", MODE_CSV |MODE_WRITE | MODE_READ, ";"); if(h1 < 0) { Print("Unable to open file my_data.csv"); return(false); } FileSeek(h1, 0, SEEK_END); FileWrite(h1, High[1], Low[1], Close[1], Volume[1]); FileClose(h1); 这个范例中数据被添加到文件的尾页。在文件打开后,我们可以使用函数 "FileSeek"。
MT4编程实例:箭头符号(2009-06-28 10:46:48)
符号是一种断断续续的指标线。在指标线有值区域,指标线显示;在指标线无值区域,指标线隐藏。例如下图:当价格上穿、下穿均线时,均线上出现一个标记符号。 原理也很简单:在上图中,存在二条指标线,一条是均线,另一条是笑脸符号线。 均线在任何位置都有值,所以均线是一条连续的曲线; 当价格上、下穿均线时,符号线被赋予了均线值;而在其他位置上,符号线被赋了空值。所以只是在价格上、下穿均线的位置上,符号线才有值,才能出现笑脸符号。因为符号线只是个别位置有值,所以符号线仅在个别位置显现。 符号也正好落在均线上,因为符号线值=均线值。如果符号线被赋了别的值,例如(符号线=均线+10点),那么符号水平坐标不变,垂直坐标将是均线上方的10点位置。
源码如下: //======================================================
#property indicator_chart_window
#property indicator_buffers1
#property indicator_color1 Yellow
extern int 均线=10;
double mk[];
double temp0,temp1;
int init()
{
IndicatorBuffers(1);
SetIndexBuffer(0,mk);
SetIndexStyle(0,DRAW_ARROW);
SetIndexArrow(0,204);
IndicatorDigits(Digits);
return(0);
}
int start()
{
int limit;
int counted_bars=IndicatorCounted();
if(counted_bars>0) counted_bars--;
limit=Bars-counted_bars-均线;
for(int i=0; i<limit; i++)
{
temp0=iMA(NULL,0,均线,0,0,0,i);
temp1=iMA(NULL,0,均线,0,0,0,i+1);
mk=EMPTY_VALUE;
if(Close>temp0 &&Close[i+1]<temp1) mk=temp0;
if(Close<temp0 &&Close[i+1]>temp1) mk=temp0;
}
return(0);
}
//源码到此已结束 =============================================
语句简要解释如下:
============================================= #property indicator_chart_window
指标放在主图 #property indicator_buffers1
设置指标线数为1条 #property indicator_color1 Yellow
设置第一条指标线颜色为黄色 extern int 均线=10;
设立一个自定义变量,允许外部值修改,整数形,变量名为"均线",默认值10 double mk[];
设立一个自定义数组,双精度型 double temp0,temp1;
设立二个自定义变量,双精度型,变量名为temp0、temp1 int init()
设立初始化函数init。init为系统规定函数名,函数内容自定义。该函数在指标被加载时仅运行一次 {
IndicatorBuffers(1);
指标线数量为1条
SetIndexBuffer(0,mk);
第一条指标线的数组为mk SetIndexStyle(0,DRAW_ARROW);
第一条指标线的线型为箭头符号 SetIndexArrow(0,204);
第一条指标线的箭头符号为第204种符号,如果换一个编号,那出现的就是另一种符号。箭头符号的编码详见《MT4编程参考》 IndicatorDigits(Digits);
设置指标线的小数位数
Digits=当前汇率的小数位数,如日元叉盘Digits=2,其他币对Digits==4 return(0);
函数结束,返回零值 }
int start()
设立触发函数start。start为系统规定函数名,函数内容自定义。当数据变动时,start函数被触发
{
int limit;
设立整数型自定义变量limit intcounted_bars=IndicatorCounted();
设立整数型自定义变量counted_bars,并将IndicatorCounted()的值赋给counted_bars
IndicatorCounted()为缓存数量,即已经计算过值的烛柱数 if(counted_bars>0)counted_bars--;
如果counted_bars大于零,则将counted_bars的值减掉1
这是为了配合下一句,以避免limit相差1而发生出错 limit=Bars-counted_bars-均线;
这是给limit赋值
Bars为图表中的柱数
counted_bars为已经赋值的柱数
这样limit的结果就是未赋值的烛柱数
再减去“均线”是因为图表最右边段均线无意义 for(int i=0; i<limit;i++)
循环语句,括号中有三个语句:
第一句int i=0; 表示循环从i=0开始
第二句i<limit; 这是循环的条件,如果条件满足则执行大括号中的循环体,如果条件不满足,则中止循环,跳到大括号下面的语句执行
第三句i++,这是循环步调控制语句,每循环一次后执行一次此语句。
i++相当于i=i+1,即i值在原有数值上增加1
{
temp0=iMA(NULL,0,均线,0,0,0,i);
把均线在i位置上的值赋给temp0
iMA:均线取值函数 temp1=iMA(NULL,0,均线,0,0,0,i+1);
把均线在(i+1)位置上的值赋给temp1 mk=EMPTY_VALUE;
给数组mk在i位置上赋空值
EMPTY_VALUE就是空值 if(Close>temp0 && Close[i+1]<temp1) mk=temp0;
条件判断语句。如果在i位置上价格大于均线,并且在(i+1)位置上价格小于均线(即价格上穿均线),则给数组mk在i位置上赋该位置的均线值
Close:在i位置上收盘价。
&&:逻辑运算符“并且” if(Close<temp0 && Close[i+1]>temp1) mk=temp0;
与上一句相似
}
return(0);
start函数结束语句
--------------------------------------------------------------------------------------------------- #property indicator_chart_window #property indicator_buffers 2 #property indicator_color1 Red #property indicator_color2 Green extern int 变色均线=18; double duo[]; double kong[]; int init() { SetIndexBuffer(0,duo); SetIndexBuffer(1,kong); SetIndexStyle(0,DRAW_LINE); SetIndexStyle(1,DRAW_LINE); SetIndexDrawBegin(0,变色均线); SetIndexDrawBegin(1,变色均线); IndicatorDigits(Digits); return(0); } int start() { double temp0,temp1; int limit; int counted_bars=IndicatorCounted(); if(counted_bars<0)return(-1); if(counted_bars>0)counted_bars--; limit=Bars-counted_bars; for(int i=limit; i>=0; i--) { duo=EMPTY_VALUE; kong=EMPTY_VALUE; temp0=iMA(NULL,0,变色均线,0,MODE_SMA,PRICE_CLOSE,i); temp1=iMA(NULL,0,变色均线,0,MODE_SMA,PRICE_CLOSE,i+1); if(iClose(NULL,0,i)>=iMA(NULL,0,变色均线,0,MODE_SMA,PRICE_CLOSE,i)) {duo=temp0; duo[i+1]=temp1;} else {kong=temp0; kong[i+1]=temp1;} } return(0); } ----------------------------------------------------------------------------------------------------------- 复制代码 当然,上面这个是以价格在均线上下方为条件的,我们也可以以MACD、KDJ、RSI等指标作为均线变色的条件。我们还可以更进一步,把双色线改为三色线等等
===================================================
语句简要解释如下:
===================================================
#property indicator_chart_window
指标放在主图
#property indicator_buffers 2
设置指标线数组为2个
#property indicator_color1 Red
#property indicator_color2 Green
设置第一条指标线颜色值为Red,第二条颜色值为Green
extern int 变色均线=18;
设立一个自定义变量,允许外部值修改,整数形,变量名为"变色均线",默认值18
double duo[];
设立一个自定义数组,双精度型,名称为duo
该数组在后面用于存储红线数据
double kong[];
设立一个自定义数组,双精度型,名称为kong
该数组在后面用于存储绿线数据
int init()
设立初始化函数init。init为系统规定函数名,函数内容自定义。该函数在指标被加载时运行一次
{
SetIndexBuffer(0,duo);
SetIndexBuffer(1,kong);
设置第一、二条指标线的数组为duo和kong
SetIndexStyle(0,DRAW_LINE);
SetIndexStyle(1,DRAW_LINE);
设置第一、二条指标线的样式,线型为连续曲线
SetIndexDrawBegin(0,变色均线);
SetIndexDrawBegin(1,变色均线);
设置第一、二条指标线的最左边的起始划线位置
IndicatorDigits(Digits);
设置指标精确到的小数位数
Digits是当前汇率小数位,日系Digits=2,其他币对Digits=4
return(0);
init函数结束,返回零值
}
int start()
设立触发函数start。start为系统规定函数名,函数内容自定义。当数据变动时,start函数被触发
{
double temp0,temp1;
设立双精度型自定义变量temp0、temp1
int limit;
设立自定义变量limit,整数型
int counted_bars=IndicatorCounted();
设立整数型自定义变量counted_bars,并将IndicatorCounted()的值赋给counted_bars
IndicatorCounted()为缓存数,即已经计算过值的烛柱数
if(counted_bars<0) return(-1);
如果counted_bars值小于零,start函数结束
if(counted_bars>0) counted_bars--;
如果counted_bars值大于零,则counted_bars值减掉1。这是为了配合下一句,以避免limit相差1而出错
limit=Bars-counted_bars;
给limit赋值
Bars为图表中的烛柱数
counted_bars为缓存数,即已经运算过的烛柱数
这样limit的值就是未经运算的烛柱数
这样做的目的是避免重复运算,优化程序
for(int i=limit; i>=0; i--)
循环语句,括号中有三个语句:
第一句inti=limit; 表示循环从i=limit开始
第二句i>=0; 这是循环的条件,如果条件满足则执行大括号中的循环体,如果条件不满足,则中止循环,跳到大括号下面的语句执行
第三句i--,这是循环步调控制语句,每循环一次后执行一次此语句。
i--相当于i=i-1,即i值在原有数值上减少1
{
duo=EMPTY_VALUE;
kong=EMPTY_VALUE;
给数组duo和kong在i位置上赋空值
EMPTY_VALUE:空值
temp0=iMA(NULL,0,变色均线,0,MODE_SMA,PRICE_CLOSE,i);
temp1=iMA(NULL,0,变色均线,0,MODE_SMA,PRICE_CLOSE,i+1);
把均线在i和i+1位置上均线值,分别赋给temp0和temp1
这是为了使后面的语句看起来简洁
if(iClose(NULL,0,i)>=iMA(NULL,0,变色均线,0,MODE_SMA,PRICE_CLOSE,i))
判断条件语句:如果价格高于均线
{duo=temp0;duo[i+1]=temp1;}
判断执行语句:给数组元素duo、duo[i+1]分别赋值
else {kong=temp0; kong[i+1]=temp1;}
如果判断条件不成立,即价格低于均线:则给数组元素kong、kong[i+1]分别赋值
}
return(0);
start函数结束,返回零值
}
|