English
中文
日本語
ID
Vietnam
한국어
Filipino
 
   学院导航

外汇MQL4 智能交易系统示例

MQL4 Expert Advisor Example

在这篇完整的 MQL4 智能交易系统示例文章中学习如何编写功能齐全的 MA 智能交易系统,以帮助您对您的交易 EA 进行编程。


少数讨论智能交易系统构建的手册和指南倾向于使用移动平均线交叉 (MACross) 作为示例。 这样做的原因是它是目前最流行的基于指标的策略,而且使用大多数人已经熟悉的交易概念来教授新的编码概念要容易得多。


按照这条熟悉的路径,我提交了一个基于简单移动交叉 (20-200) 的基本专家顾问:


// 第 1 节:

// 预处理器指令、外部和内部变量

#property copyright “Copyright © 2008-2010, Excel Markets”
#property link “/article/”

extern string EAName = “MACross”;
extern double MagicNumber = 59483;

extern double Lots =0.1;
extern double LotDigits =2;
extern int Slippage = 5;

extern double StopLoss = 80;
extern double TakeProfit =0;

extern bool OppositeClose = true;
extern bool EnterOpenBar = true;

extern int FastMATime = 0;
extern int FastMAPeriod = 2;
extern int FastMAType = 0; //0:SMA 1:EMA 2:SMMA 3:LWMA
extern int FastMAPrice = 0;
extern int FastMAShift = 0;
extern int SlowMATime = 0;
extern int SlowMAPeriod = 30;
extern int SlowMAType = 1; //0:SMA 1:EMA 2:SMMA 3:LWMA
extern int SlowMAPrice = 0;
extern int SlowMAShift = 0;

// Global Variables

int Counter, vSlippage;
double ticket, number, vPoint;

double
FastMACurrent,
FastMAPrevious,
SlowMACurrent,
SlowMAPrevious;

// Section 2: Initialization

int init(){

if(Digits==3 || Digits==5)
{ vPoint=Point*10; vSlippage=Slippage*10; }
else{ vPoint=Point; vSlippage=Slippage; }

return(0); }

//——————————————————-
// Section 3: Start

int start()
{

if(Bars<100) { Print(“Bars less than 100”);
return(0); }

//——————————————————–
// Section 3A: Define ShortCuts to Common Functions

int Total, OType=-1, Ticket;
double Price, SL, TP, Lot;
bool CloseBuy=false, CloseSell=false, OpenBuy=false, OpenSell=false;

for(int Counter=1; Counter<=OrdersTotal(); Counter++)
{
if (OrderSelect(Counter-1,SELECT_BY_POS)==true)
if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)

{
Ticket=OrderTicket();
OType =OrderType();
Price =OrderOpenPrice();
SL =OrderStopLoss();
TP =OrderTakeProfit();
Lot =OrderLots();
}
}
//—————————————————-
// Section 3B: Indicator Calling

int Current = 0;

FastMACurrent = iMA(NULL, FastMATime, FastMAPeriod, FastMAShift, FastMAType, FastMAPrice, Current + 0);

FastMAPrevious = iMA(NULL, FastMATime, FastMAPeriod, FastMAShift, FastMAType, FastMAPrice, Current + 1);

SlowMACurrent = iMA(NULL, SlowMATime, SlowMAPeriod, SlowMAShift, SlowMAType, SlowMAPrice, Current + 0);

SlowMAPrevious = iMA(NULL, SlowMATime, SlowMAPeriod, SlowMAShift, SlowMAType, SlowMAPrice, Current + 1);

//————————————————
// Section 3C: Entry Conditions

bool OpenBar=true;
if(EnterOpenBar) if(iVolume(NULL,0,0)>1) OpenBar=false;

if (FastMACurrent > SlowMACurrent&& FastMAPrevious < SlowMAPrevious
&& OpenBar){
OpenBuy=true;
if (OppositeClose) CloseSell=true;
}

if (FastMACurrent<slowmacurrent&&amp> < SlowMACurrent&& FastMAPrevious > SlowMAPrevious
&& OpenBar){
OpenSell=true;
if (OppositeClose) CloseBuy=true;
}
//————————————————-
// Section 3D: Close Conditions

while(true)
{
if (OType==0 && CloseBuy==true)
{
close (OP_BUY); // Close Buy
return;
}

if (OType==1 && CloseSell==true)
{
close (OP_SELL); // Close Sell
return;
}
break;
}
//————————————————–
// Section 3E: Order Placement

while(true)

{
if (OrdersTotalMagicOpen()==0 && OpenBuy==true)
{

if(StopLoss>0){SL=Bid – StopLoss*vPoint;}else{SL=0;} if(TakeProfit>0){TP=Bid+TakeProfit*vPoint;}else{TP=0;}
ticket=0;number=0;
while(ticket<=0 && number<100){
RefreshRates();
ticket = OrderSend(Symbol(),OP_BUY,NormalizeDouble(Lots,LotDigits), Ask,vSlippage,SL,TP,EAName, MagicNumber, 0, Green);
return (ticket);
}}

if (OrdersTotalMagicOpen()==0 && OpenSell==true)
{
if(StopLoss>0){SL=Ask + StopLoss*vPoint;}else{SL=0;} if(TakeProfit>0){TP=Ask-TakeProfit*vPoint;}else{TP=0;}
ticket=0;number=0;
while(ticket<=0 && number<100){
RefreshRates();
ticket= OrderSend(Symbol(),OP_SELL, NormalizeDouble(Lots,LotDigits), Bid,vSlippage,SL,TP, EAName, MagicNumber, 0, Red);
return (ticket);
}}
break;
}
//———————————————————
return; // End of start()
}

// Section 4A: Close Function

void close(int type){
if(OrdersTotal()>0){
for(Counter=OrdersTotal()-1;Counter>=0;Counter–){
OrderSelect(Counter,SELECT_BY_POS,MODE_TRADES);

if(type==OP_BUY && OrderType()==OP_BUY){
if(OrderSymbol()==Symbol() && OrderMagicNumber()==MagicNumber) {
RefreshRates();
OrderClose(OrderTicket(),OrderLots(),NormalizeDouble(Bid,Digits), vSlippage);
} }

if(type==OP_SELL && OrderType()==OP_SELL){
if(OrderSymbol()==Symbol() && OrderMagicNumber()==MagicNumber) {
RefreshRates(); OrderClose(OrderTicket(),OrderLots(),NormalizeDouble(Ask,Digits),vSlippage);
}}
}}}

// Section 4B: OrdersTotalMagicOpen Function

int OrdersTotalMagicOpen() {
int l_count_0 = 0;
for (int l_pos_4 = OrdersTotal() – 1; l_pos_4 >= 0; l_pos_4–) {
OrderSelect(l_pos_4, SELECT_BY_POS, MODE_TRADES);
if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue;
if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
if (OrderType() == OP_SELL || OrderType() == OP_BUY) l_count_0++;
}
return (l_count_0);
}
</slowmacurrent&&amp>

如果您以前没有编程经验,上面的代码可能看起来有点神秘和令人生畏。 克服恐吓因素的一种方法是少担心小细节,关注大局。


尽量不要弄清楚语言的每一部分是如何工作的,也不要想知道在处理器级别幕后发生了什么,而只是接受它正在工作。 您无需纠结于语言及其格式的细节。 您无需关注具体细节即可理解和构建 EA。 在这个时间点,您只需要知道拼图的各个部分是如何组合在一起的,以及可以操纵哪些最重要的部分以制定新策略。


我将协助您拼好拼图,并为您指出最重要部分的方向。 我在 EA 中对每个部分进行了编号和标记,以便在我引导您理解每个部分时更容易进行交叉引用。

第 1 节:预处理器指令、外部和内部变量

首先,谈谈评论。 您可能会注意到我在 // 之后包含的一些注释。


任何以 // 开头的行都是自由文本,会被程序忽略。


即使计算机忽略它们,我们也会包含注释,以帮助用简单的英语解释我们的编程语句的含义。 是的,编程语言乍一看可能很难理解,在编写代码时添加注释会很有用,可以让您的生活更轻松。


接下来,谈谈预处理器指令。 每个指令都以井号 (#) 开头。 有许多高级形式的指令,例如#import 和#include,但我们只使用其中最简单的一种,即#property 版权预处理器指令,它可以将代码标识为我们的代码。 除此之外,它并不那么重要,也没什么特别的。


接下来是外部变量,它们很重要。 在上一篇文章中,我已经解释了变量如何像一个小盒子,可以存放东西以备后用。 外部变量(前面有 extern 一词)很重要,因为它将其参数显示在专家对话框中的程序外部,以便用户轻松操作。


您在上面的基本 EA 中看到的许多外部变量都是不言自明的。 当您稍后学习 OrderSend 函数的语法时,我们将讨论 EAName、MagicNumber、Lotsize、TakeProfit 和 Stoploss,参见第 3E 节,OrderPlacement。 这些变量主要指的是那个函数。


本节中有趣的外部变量是:移动平均参数变量(特别是 MAPeriod)、OppositeClose 和 EnterOpenBar。

移动平均参数变量。

请注意,我已将所有移动平均参数值放置为外部变量。 我不必这样做。 当我在第 3B 节“指标调用”中调用它们时,我本可以只将最重要的变量 MAPeriod 设为外部变量,而将其余参数保留在指标内的默认值中。 我已将几乎所有参数声明为外部变量,以防我以后想优化任何参数。 现在我可能只会优化 MAPeriod,但在未来优化其他一些可能会有用。 我们将在处理第 3B 节“指标调用”时详细讨论这些参数。

我的 True/False Bool(布尔)变量:OppositeClose 和 EnterOpenBar

当您在变量中看到 bool 时,它是一种用于真值的类型。 bool 类型来自布尔,逻辑演算发明者的姓氏。 让我们检查一下 bool OppositeClose。


外部布尔 OpositeClose=真


这个变量的外部 bool 允许我打开和关闭 oppositeclose 条件。 每当在代码中引用 oppositeclose 时,它将默认为 true,这意味着我希望它被打开。 如果设置为 false,它将被关闭。 或者,您可以不使用 true 或 false,而是使用 0 表示 false,1 表示 true。


OppositeClose bool 指的是能够在相反信号上关闭订单的想法。 这是什么意思? 如果设置为 true,并且我目前处于多头头寸,并且触发空头入场订单,空头入场订单会在进行空头交易之前关闭我当前的多头头寸。 空头进场信号是关闭当前多头的相反信号(反之亦然)。 我默认 oppositeclose 为真,因为我肯定希望它被激活。 如果我选择了 false,即取消激活相反的收盘价,空头进场信号将不会关闭我之前的多头交易,并且我的多头交易将保持打开状态,直到它通过触及止损或获利而关闭。 通常,将 oppositeclose 设置为 true 并激活是个好主意。 我们将在第 3D 节“关闭条件”中讨论 oppositeclose 的编码,以及在第 4A 节“关闭函数”中找到的相关函数。


EnterOpenBar bool 指的是仅在每个新柱的开盘时进场的想法,而不是柱间或收盘时。 当基于指标制定新策略时,我更喜欢将 EnterOpenBar 默认为 true,以便快速查看策略回测情况。 strategytester 在其下拉菜单中有三种类型的回测模式:每个报价点、控制点和仅开盘价。 每个刻度都比其他刻度更准确但更慢。 开盘价不太准确,但比其他价格更快。 控制点在准确性和速度上都位于两者的中间。 但是,如果 EnterOpenBar 设置为 true,那么您可以在仅开盘价模式下安全地进行回测,从而大大提高回测速度,同时具有与 everytick 模式非常相似的准确性和结果。 除了回测速度之外,我还注意到,当 enteronopenbar 设置为 true 时,它提高了系统的整体性能和可靠性,特别是如果它基于通用指标。 我鼓励您尝试将 enteronopenbar 设置为 true 和 false,以查看结果的差异。 EnterOpenBar 背后的编码可以在第 3C 节“入口逻辑”中找到。


最后,在本节中我声明了一些内部变量(有时称为全局变量),例如


双人票、号码、vPoint;


请注意我没有为每个标识符声明一个特定的值。 如果没有声明值,每个标识符默认为 0,等待稍后确定。 完成确定后,它会恢复为 0。另请注意,我在双精度后列出标识符,一个接一个,用逗号分隔,直到我用分号结束语句。 这是可以做到的,因为没有一个具有全局不同的值。 我本可以在 start() 函数中而不是在此处声明这些,但是在本节中将它们放在此处允许我从代码的任何函数中全局引用它们。 这非常方便,可以避免不必要的重复。

Tip!

请记住,每当您遇到特定的标识符并且很难看出它们指的是代码的哪一部分时,有一种快速的方法可以找到它们的匹配项。 只需将标识符(例如:ExpertName)复制并粘贴到查找字段 (Cnt+F) 中,以便快速跳转到位于代码其他部分的匹配标识符。 除非您喜欢用文字玩 ISPY,否则您可能会发现自己经常这样做以匹配代码的不同部分。

第 2 部分:初始化

如您所见,本节内容不多。


我在本节中包含的代码用于设置相对于您的经纪人货币数字的点值(经纪人设置有 4 位或 5 位报价系统):

if(Digits==3 || Digits==5)
{ vPoint=Point*10; vSlippage=Slippage*10; }
else{ vPoint=Point; vSlippage=Slippage; }

简单的英文翻译:如果您的货币对以 3 或 5 的数字报价,则点值将等于 Point*10 ,如果不是(例如 2 或 4),点值将保持为没有倍数的点值。


插入代码以自动检测和调整小数 3 或 5 位经纪商是一个有用的项目,我在其自己的文章“自动检测滑点和点值”中对其进行了更多解释。


学习句法、语言和结构。 请注意 if 条件是如何放在圆括号 () 中以及语句是如何放在大括号 {} 中的。 这是 if 条件后跟其语句的常见结构。 在这种情况下,if 条件是 if(Digits==3 || Digits==5),请记住双等号 (==) 代表等于,双竖线 (||) 代表“或” ”。 是的,你必须知道你的用词是如何被翻译成机器语言的:虽然如果我们只说“和”或“或”会很方便,但如果你使用这些词,程序将无法理解你。 相反,您必须使用双竖线 (||) 表示“或”,使用双符号 (&&) 表示“和”。

Note

虽然很容易输入“和”的双符号 (&&),但很难输入“或”的双竖线 (||),因此快速的捷径就是复制并粘贴它。

Lastly, the first statement that falls in brackets{ vPoint=Point*10; vSlippage=Slippage*10; } has actually two statements separated by a semicolon: one statement defining what vPoint means and another statement defining what vSlippage means. When the condition is not met, there is the interlocking else function that points to an alternative compound statement in brackets { vPoint=Point; vSlippage=Slippage; }.
最后,括号中的第一个语句{ vPoint=Point*10; vSlippage=滑点*10; } 实际上有两个用分号分隔的语句:一个语句定义 vPoint 的含义,另一个语句定义 vSlippage 的含义。 当条件不满足时,有环环相扣的 else 函数指向括号中的替代复合语句 { vPoint=Point; vSlippage=滑点; }.

第 3 节:Start () 函数

这部分是最重要和最长的,最好将这部分分成单独的块,我用字母表示为 3A、3B 等。


在此 start() 函数的开头,我包含了以下几行:


if(Bars<100) { Print(“Bars less than 100”);

返回(0); }


翻译:如果 Bar 小于 100,则不要交易,并在屏幕上打印 bar 小于 100。包含此代码很有用,可防止在图表上加载的 bar 不足的情况下发生交易。


学习句法、语言和结构。 这是在“if”后的括号内设置的另一个 if 条件 (Bars < 100)。 现在请注意,if 条件后面的表达式如果包含两个或多个复合语句,则必须设置在大括号 {} 内,并且大括号内的每个语句必须用分号分隔。 在这个例子中,我们有两个语句跟在 if 条件之后。 在第一个语句中,Print 是一个常驻函数,需要在引号内并用圆括号括起来进行描述。 当条件满足时,它将在屏幕上打印该描述。 分号完成该表达式。 在第二个语句中,return (0) 表示如果少于 100 个柱,则不会发生任何交易。

Note

每个左大括号必须有一个匹配的右大括号,否则将无法编译,所以我们用右大括号关闭这两个语句。

第 3A 节:为常用交易功能定义短标签

在这里,我定义了一些代表常见交易功能的短标签,并配备了这些标签以与 MagicNumbers 一起使用。


为什么我希望我的交易功能与 MagicNumbers 一起使用?


MagicNumber 是您 EA 的指纹,允许程序将此 EA 与在相同货币和时间范围内运行的其他 EA(或交易)区分开来。 例如,如果我希望程序只跟踪我为此 EA 的未平仓买入头寸,而不是平台本身的未平仓买入仓位。 因此,当我引用我的任何交易信息函数时,我希望它们与 MagicNumber 相关联。

有关这些交易信息函数的完整列表和定义,请单击此处:http://docs.mql4.com/trading


我通过将它们放在 OrderSelect() 函数下使我的交易函数与 magicnumbers 一起工作:

for(int Counter=1; Counter<=OrdersTotal(); Counter++)
{ if (OrderSelect(Counter-1,SELECT_BY_POS, MODE_TRADES)==true)
if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
tag names = common trading functions;
}
}}

翻译:如果有任何打开或挂起的交易有我的 MagicNumber,以下标签名称将代表常用交易功能


精益语法、语言和结构。 您会在不同的 EA 中经常看到 OrderSelect 函数的一些变体,通常在任何自定义函数的第一行中(我在我自己的两个函数 4A 和 4B 中使用过它)。 OrderSelect 函数选择一个订单进行进一步处理,如果函数成功则返回 true,如果失败则返回 false。


因为 OrderSelect() 函数非常重要,所以我创建了自己的文章,您可以参考名为 Retrieving Order Information with OrderSelect


出于我的目的,我使用 OrderSelect 函数按交易、MODE_TRADES(表示未结订单和挂单)和 MagicNumber 选择。 换句话说,我希望我在此函数下包含的交易函数能够处理属于我的幻数的未结订单和挂单。 第三行,特别是说 OrderMagicNumber() == MagicNumber 的部分,表示将交易函数包含在 MagicNumber 中的条件。 在我归入该函数的所有交易函数中,我稍后在代码中使用的函数是 OType=OrderType(),我在第 3D 节“关闭函数”中使用了它。


我还应该提到该代码块中第一行的相关性:


for(int Counter=1; Counter<=OrdersTotal(); Counter++)


这称为 for 运算符,它用于按预定次数循环代码块。 第一个表达式,int = Counter =1,用值 1 初始化我们的 Counter 变量。第二个表达式,Counter <=OrdersTotal(),是条件,如果为真,将执行大括号内的代码(如果有 3 个打开 命令,它将执行循环三次)。 第三个表达式,Counter++,意思是“将 Counter 的值加一”。 每次循环完成时,本例中的计数器都会加 1,直到最终所有未结订单都被计算在内。


第 3B 部分:指标调用

在这里我声明四种不同的移动平均线:


FastMACurrent = iMA(NULL, FastMATime, FastMAPeriod, FastMAShift, FastMAType, FastMAPrice, Current + 0);

FastMAPrevious = iMA(NULL, FastMATime, FastMAPeriod, FastMAShift, FastMAType, FastMAPrice, Current + 1);

SlowMACurrent = iMA(NULL, SlowMATime, SlowMAPeriod, SlowMAShift, SlowMAType, SlowMAPrice, Current + 0);

SlowMAPrevious = iMA(NULL, SlowMATime, SlowMAPeriod, SlowMAShift, SlowMAType, SlowMAPrice, Current + 1);


每一个都指的是 MT4 原生的移动平均线指标,它有自己特定的语法:


double iMA(字符串 Symbo)、int Timeframe、int MAPeriod、int MAShift、int MAMethod、int MAPrice、int Shift)


我喜欢将 iMA 标识符后面括号中的结构想象成一辆有多个指定座位的公共汽车。 公交车上的每个座位都用逗号隔开,称为参数。 iMA 指标有七个参数。 每个参数依次拥有一个默认值,可以自定义(或个性化,以保持总线隐喻)。 了解每个参数的功能、每个参数的默认值、如何自定义它们以及哪些参数真正驱动总线是很有用的。


下表描述了移动平均线的每个参数:

MA
Parameters
Description
Symbol交易符号,例如 EURUSD。 Symbol() 代表货币图表的对
TimeFrame应用移动平均线的图表时间段,通常设置为 0,表示 EA 附加到图表的符号。
MAPeriod移动平均线的回顾期。 这是最重要的变量。
MAShift移动平均线的前移,以柱为单位,通常设置为 0。
MAMethod移动平均线的计算方法,可选择简单、指数、平滑或线性加权。 第二个最重要的变量。
MAPrice计算移动平均线时使用的价格数组,可以是收盘价、开盘价、最高价、最低价或某种类型的平均线。 通常使用默认值 0 或关闭。
Shift返回计算的柱的后移。 值 0 返回当前柱的指标值,值 3 将返回 3 柱前的指标值。 正如我们将要看到的,这是第三个最重要的变量。

可以在此处找到对 MA 参数(以及所有 20 个本机指标的参数)的便捷快速参考:http://docs.mql4.com/indicators/iMA 出于我们的直接目的,我们将使用默认参数值,对于我们的目的最重要的参数是 MAPeriod,即移动平均线的长度,对于 FastMAPeriod,我默认为 2,对于 SlowMAPeriod,我默认为 30。 驱动总线的是 MAPeriod,因为它区分了快移动平均线和慢移动平均线。 MAMethod 也很重要,尤其是 Simple (Integer=0) 和 Exponential (Integer=1)。 对于快速移动平均线,我默认为 0 或 Simple,对于慢速移动平均线,我默认为 1 或 Exponential。 因此,我希望 30 周期指数移动平均线穿过 2 周期简单移动平均线以触发买入信号。 MAShift 和 MAPrice 通常保留为 0,更改这些参数影响不大。 最后一个参数 Shift 与第四个参数 MAShift 没有关系,所以不要混淆两者。 实际上,最后一个参数是及时定位移动平均线的重要参数。 它对于区分前一个柱和当前柱尤为重要,这是我们进入和退出逻辑的组成部分。 请记住,所有这些参数都已作为外部变量放置,以便在稍后阶段轻松修改或优化它们。 快速提问:如果我只为双 MA 交叉使用快速和慢速移动平均线,为什么我必须声明四个移动平均线? 当我想做双 MA 交叉时,有必要指出交叉前后发生的事情。 正如我们将要看到的,买入交叉的实例是当前快速 MA 高于当前慢速 MA,而先前的快速 MA 低于先前的慢速 MA。 这使得必须定义四个移动平均线:FastMACurrent、FastMAPrevious、SlowMACurrent、SlowMAPrevious。 当前移动平均线与先前移动平均线有什么区别? Current 与 Previous 移动平均线的唯一区别是最后一个参数,即 Shift 参数:当前的 Shift 为 0,之前的为 1。

第 3C 节:进入逻辑:

在入口逻辑的第一部分,我们将编写前面提到的 EnterOpenBar 逻辑。 有趣的是,这是一段简短但重要的代码,经常被许多专家顾问忽略。 代码如下所示:


布尔打开栏=真;

if(EnterOpenBar) if(iVolume(NULL,0,0)>1) openbar=false;


程序如何找到新柱的开盘价? 它必须找到出现在新柱上的第一个报价单。 因此,在上面的代码中,我正在检查交易量并延迟交易的进入,直到它检测到找到的新柱的第一个报价。 你可以看到我有两个 if 条件语句背靠背。


第一个“if (enteronopenbar)”指的是 bool 变量,我之前将其默认为 true。 当为真时,它会传递到下一个 if 条件语句,“if (iVolume(NULL,0,0)>1)”。 第二个 if 条件检查成交量是否为 1,在这种情况下 openbar 变为真(任何大于 1 的都为假),因为它找到了新柱的第一个订单号。 由于对 openbar 的这种检查对于任何新系统来说都是一个简单但至关重要的组件,因此我在其自己的文章 Enter on Open Bar 中对其进行了更详细的讨论。


接下来,我们继续讨论 EA 的大脑,进入和退出的策略条件。


以下是我打算编码的买卖条件:


购买条件一:

如果 3 周期移动平均线超过 30 周期移动平均线,则在市场上买入(也关闭未平仓的卖出头寸);


卖出条件1:

如果 3 周期移动平均线低于 30 周期移动平均线,则在市场上卖出(也关闭未平仓买入头寸)。


这两个条件如何转换为 MQL4 代码?


编写交叉条件的方法有很多种,但出于教学目的,我们将采用最简单的方法。 MT4 没有内置交叉功能,因此我们将构建一个通用的两步解决方法。 我们将通过观察前一根柱线的快速移动平均线之前是否低于慢速移动平均线以及当前柱线的移动平均线是否高于慢速移动平均线来指示买入交叉条件。 因此,它已经越界了。 也许您现在可以更好地理解以下代码。


如果 (

FastMACurrent > SlowMACurrent &&

FastMAPrevious < SlowMAPrevious

&& 开业的酒吧)


{

开买=真;

if (OppositeClose) CloseSell=true;

}

如果 (

FastMACurrent FastMAPrevious > SlowMAPrevious && openbar)

{

开卖=真;

if (OppositeClose) CloseBuy=true;

}


在语法方面,当你声明一个 if 条件时,你必须将逻辑放在大括号{}中,特别是如果包含两个或多个语句。 为了提示 FastMACurrent 必须大于 SlowMACurrent,我使用了 > 符号,这称为运算符。 我们基本上会说,如果前一个柱的 20 周期移动平均线低于 200 周期移动平均线,并且如果当前柱的 20 周期移动平均线现在高于当前柱的 200 周期移动平均线,则在市场上买入。 由于运算符对交易条件如此重要,我写了一篇关于它们的简短文章 简单逻辑运算符


在if条件之后,是用大括号{}括起来并用分号隔开的两条语句:如果移动平均线条件满足,一条语句将OpenBuy设置为true,这很简单易懂。 第二个陈述有点微妙。 如果满足前面的移动平均线条件,它将 CloseSell 设置为真,并且 extern bool OppositeClose 也为真。 请注意它如何请求自己的内部 if 条件,在本例中为 OppositeClose bool = true 或 false,然后才能激活其 CloseSell 或 CloseBuy bool。 我喜欢将这些内部 if bool 条件想象成钥匙和锁定机制,使最终用户能够从专家属性选项卡中轻松打开和关闭机制(在本例中为 OppositeClose)。


第 3D 节:关闭条件

我们从 while 运算符开始本节。 它是 MQL4 中一种简单的循环方法,类似于上面讨论的 for 循环,但如果您不确定迭代次数则更合适。 我们的 while 循环基本上是这样的:

while (true) {
// loop code
}

Next we place our conditions to close our buy and sell orders:

if (OType==0 && CloseBuy==true)
{
close (OP_BUY); // Close Buy
return;
}

OType是一个变量,代表交易信息函数OderType(),每一种交易订单类型都有一个对应的整数。 OrderType == 0 指的是 OP_BUY,即买入仓位,而 OrderType = 1 指的是 OP_SELL,即卖出仓位。


以下是各种订单类型及其对应的整数值:

OrderTypeIntegerDescription
OP_BUY0Buy Position
OP_SELL1Sell Position
OP_BUYLIMIT3Buy Limit Pending
OP_BUYSTOP4Buy Stop Pending
OP_SELLLIMIT5Sell Limit Pending
OP_SELLSTOP6Sell Stop Pending

如果当前有买入头寸 (OType==1) 并且 bool CloseBuy 为 (==) true,则可以执行我的自定义平仓函数 close (OP_BUY)。 要了解我的自定义关闭功能,请单击此处。


我以中断运算符结束本节。 运算符“break”停止执行最近的“while”、“for”或“switch”类型的外部运算符。 运算符“break”的执行包括将“while”、“for”或“switch”类型的复合运算符之外的控制传递给最近的后续运算符。


第 3E 节:下单

在上一节的 break 运算符之后,我从另一个 while 运算符开始本节。 上一节的中断已将控制权或流程移交给了第二个 while 循环。


在本节中,程序将下达买卖订单。


它以以下条件开始:


如果 (OrdersTotalMagicOpen()==0 && OpenBuy==true)


OrdersTotalMagicOpen() 是一个自定义程序,我们很快就会访问它,它计算包含在 EA 幻数中的未结订单数量。 如果订单总数为 0(==0),那么我们可以继续。 并且 (&&) 如果 bool OpenBuy 为真,我们可以继续。


接下来是确定止损和利润目标值的代码:


if(StopLoss>0){SL=Bid – StopLoss*vPoint;}else{SL=0;} if(TakeProfit>0){TP=Bid+TakeProfit*vPoint;}else{TP=0;}


这里我们背靠背使用两个 if-else 顺序语句。 让我们稍微回顾一下。 请记住,如果前面的 if 语句为假,则 else 条件会评估替代条件。 我们正在结合 else 和 if 来创建只有在 true 时才会执行的替代条件。 在这种情况下,我们说如果 StopLoss > 0,那么我们可以确定 StopLoss 的值 (Bid-StopLoss *vPoint)。 如果它是我们的止损,而不是 0,我们不确定止损的值,并且这种替代方案是止损保持为 0。同样的逻辑对于止盈也是重复的。 根据这些 if-else 条件确定的值出现在 OrderSend() 函数的 StopLoss 和 TakeProfit 参数中。


接下来,我们希望继续刷新利率并推动我们的订单,直到它们被执行:


门票=0;号码=0;

while(票<=0 && 号码<100){

刷新率();


我们是说,如果 ticket 为 0(订单尚未填写),并且尝试填写的次数少于 100,那么我们将继续刷新率并尝试填写。 如果在快速变化的市场中有重新报价并且您无论如何都想成交,那么这是一个有用的代码。 同样,您会看到 while 运算符在运行,这次循环遍历票据和尝试下订单的次数。


接下来是 OrderSend() 函数。 它本身就是一个多方面的功能,我在这里写了一篇简短的文章 Market Orders with OrderSend