
この完全な MQL4 Expert Advisor 記事でフル機能の MA Expert Advisor を作成する方法を学び、トレーディング 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&&> < 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&&>
これまでにプログラミングの経験がない場合、上記のコードは少し難解で怖く感じるかもしれません。 威圧的な要素を克服する 1 つの方法は、細かいことは気にせず、全体像に集中することです。
言語の各部分がどのように動作するか、またはプロセッサ レベルで舞台裏で何が起こっているかを理解しようとせず、言語が動作していることだけを受け入れてください。 言語とその形式の詳細にこだわる必要はありません。 EA を理解して構築するために、特定の詳細に焦点を当てる必要はありません。 この時点で必要なのは、パズルのピースがどのように組み合わされるのか、そして最も重要なピースのどれを操作して新しい戦略を立てることができるのかを知ることだけです。
パズルを組み立てて、最も重要なピースの方向を示すのをお手伝いします。 各セクションを説明する際に相互参照しやすいように、EA の各セクションに番号とラベルを付けました。
セクション 1: プリプロセッサ ディレクティブ、外部変数と内部変数
まず、コメントについて説明します。 // の後にいくつかのコメントを追加したことに気づくかもしれません。
// で始まる行はフリー テキストであり、プログラムによって無視されます。
コンピューターが無視する場合でも、プログラミング ステートメントの意味をわかりやすい英語で説明するのに役立つコメントが含まれています。 はい、プログラミング言語は一見すると理解するのが難しい場合がありますが、コードを作成するときにコメントを追加すると便利で、作業が楽になります。
次に、プリプロセッサ ディレクティブについて説明します。 各ディレクティブはポンド記号 (#) で始まります。 #import や #include など、高レベルの形式のディレクティブが多数ありますが、コードを自分のものとして識別する最も単純な #property 著作権プリプロセッサ ディレクティブのみを使用します。 それ以外はそれほど重要ではありませんし、特別なことでもありません。
次は外部変数です。これは非常に重要です。 前回の記事で、変数が後で使用するために内容を保存できる小さな箱のようなものであることを説明しました。 外部変数 (extern という単語が前に付く) は、その引数がプログラムの外側のエキスパート ダイアログに表示され、ユーザーが簡単に操作できるようにするため、重要です。
上記の基本的な EA で見られる外部変数の多くは、一目瞭然です。 EAName、MagicNumber、Lotsize、TakeProfit、Stoploss については、後で OrderSend 関数の構文を学習するときに説明します。セクション 3E「OrderPlacement」を参照してください。 これらの変数は主にその関数を参照します。
このセクションの興味深い外部変数は次のとおりです: 移動平均パラメータ変数 (特に MAPeriod)、OppositeClose、EnterOpenBar。
移動平均パラメータ変数。
すべての移動平均パラメータ値を外部変数として配置したことに注意してください。 これをする必要はありません。 セクション 3B「インジケーター呼び出し」でこれらを呼び出したとき、最も重要な変数 MAPeriod のみを外部変数にして、残りのパラメーターをインジケーター内のデフォルト値のままにすることもできました。 後でパラメータを最適化したい場合に備えて、ほぼすべてのパラメータを外部変数として宣言しました。 現時点ではおそらく MAPeriod のみを最適化しますが、将来的には他のいくつかを最適化すると役立つ可能性があります。 これらのパラメータについては、セクション 3B「インジケーターコール」を扱うときに詳しく説明します。
私の True/False Bool 変数: OppositeClose と EnterOpenBar
変数に bool がある場合、それは真理値に使用される型です。 bool 型は、論理微積分の発明者の姓である boolean に由来しています。 bool OppositeClose を確認してみましょう。
外部ブール値 OpositeClose=true
この変数の外部ブール値を使用すると、次のことが可能になります。 open と close の反対側の close 条件。 コード内でoppositecloseが参照されると、デフォルトでtrueになります。これは、オープンすることを意味します。 false に設定するとオフになります。 あるいは、true または false を使用する代わりに、false の場合は 0、true の場合は 1 を使用することもできます。
OppositeClose ブール値は、反対のシグナルで注文をクローズできるというアイデアを指します。 どういう意味ですか? true に設定すると、現在ロング ポジションにあり、ショート エントリー注文がトリガーされると、ショート トレードを行う前にショート エントリー注文によって現在のロング ポジションがクローズされます。 ショートエントリーシグナルは、現在のロングポジションを決済するための反対のシグナルです(逆も同様です)。 絶対にアクティブ化したいので、oppositeclose をデフォルトで true に設定しています。 false を選択した場合、つまり反対のクローズを無効にした場合、ショートエントリーシグナルは以前のロングトレードをクローズせず、ストップロスまたはテイクプロフィットを押してクローズするまでロングトレードはオープンしたままになります。 一般に、oppositeclose を true に設定してアクティブ化することをお勧めします。 セクション 3D「クローズ条件」で、oppositeclose のエンコードについて説明し、セクション 4A「クローズ関数」で関連する関数について説明します。
EnterOpenBar bool は、バーの間や終値ではなく、新しいバーの開始時にのみエントリーするというアイデアを指します。 インジケーターに基づいて新しい戦略を作成するときは、戦略がどのようにバックテストされるかを簡単に確認できるように、EnterOpenBar をデフォルトで true に設定することを好みます。 Strategytester のドロップダウン メニューには、すべてのティック ポイント、コントロール ポイント、始値のみの 3 種類のバックテスト モードがあります。 各スケールはより正確ですが、他のスケールよりも遅くなります。 始値の精度はそれほど高くありませんが、他のものよりも高速です。 Control Point は、精度と速度の点で 2 つの中間に位置します。 ただし、EnterOpenBar が true に設定されている場合は、オープン専用モードで安全にバックテストを行うことができ、バックテストが大幅に高速化され、同時に、everytick モードとほぼ同様の精度と結果が得られます。 バックテストの速度に加えて、enteronopenbar を true に設定すると、特に一般的なメトリクスに基づいている場合、システムの全体的なパフォーマンスと信頼性が向上することにも気付きました。 enteronopenbar を true と false に設定して、結果の違いを確認することをお勧めします。 EnterOpenBar の背後にあるコーディングについては、セクション 3C「エントリ ロジック」を参照してください。
最後に、このセクションでは、次のようないくつかの内部変数 (グローバル変数と呼ばれることもあります) を宣言します。
p>
Double ticket、number、vPoint;
各識別子の特定の値を宣言していないことに注意してください。 値が宣言されていない場合、各識別子のデフォルトは 0 ですが、後で決定されます。 OKが完了すると0に戻ります。 また、ステートメントがセミコロンで終わるまで、double の後に識別子をコンマで区切って順番にリストしていることにも注意してください。 これが可能なのは、どれもグローバルに異なる値を持たないためです。 これらをここではなく start() 関数で宣言することもできましたが、このセクションに置くことで、コード内の任意の関数からグローバルに参照できるようになります。 これは非常に便利で、不必要な繰り返しを避けることができます。
パート 2: 初期化
ご覧のとおり、このセクションには多くの内容はありません。
このセクションに含まれているコードは、ブローカーの通貨番号に相対的なピップ値を設定するためのものです (ブローカーは 4 桁または 5 桁の相場システムで設定されています)。
if(桁==3 || 桁==5)
{ vPoint=ポイント*10; vSlippage=Slippage*10; }
else{ vPoint= ポイント; vSlippage=スリッページ; }
簡単な英語訳: 通貨ペアが 3 または 5 の数字でクオートされている場合、pip 値はポイントと等しくなります*10、そうでない場合(例: 2 または 4)、ポイント値は乗数なしのポイント値のままになります。
小数点以下 3 桁または 5 桁のブローカーを自動的に検出して調整するコードを挿入することは、独自の記事「スリッページの自動検出と」で説明した便利なアイテムです。ポイント価値の詳細」。
構文、言語、構造を学びます。 if 条件がどのように括弧 () で囲まれているか、およびステートメントがどのように中括弧 {} で囲まれているかに注意してください。 これは、if 条件の後にそのステートメントが続く一般的な構造です。 この場合、if 条件は if(Digits==3 || Digits==5) です。二重等号 (==) は等しいを意味し、二重縦棒 (||) は「または」を意味することに注意してください。自分の言葉がどのように機械語に翻訳されるかを知る必要があります。単に「および」または「または」と言えば便利ですが、これらの言葉を使用するとプログラムは理解できません。 「または」には二重縦棒 (||) を使用し、「および」には二重記号 (&&) を使用します。