プログラム
MetaTrader 4に付属しているサンプル
言語・バージョン
MQL4
トレードの概要
- 買い条件:移動平均線が上向きのときに、MACDがマイナスの低い位置でゴールデンクロスを満たしたら買い注文をだす
- 売り条件:移動平均線が下向きのときに、MACDがプラスの高い位置でデッドクロスを満たしたら売り注文をだす
- 買いポジションの決済:MACDがプラスの高い位置でデッドクロスしたとき、またはトレーリングストップにひっかかったとき
- 売りポジションの決済:MACDがマイナスの低い位置でゴールデンクロスしたとき、またはトレーリングストップにひっかかったとき
ソース全体
//+------------------------------------------------------------------+
//| Moving Average.mq4 |
//| Copyright 2005-2014, MetaQuotes Software Corp. |
//| http://www.mql4.com |
//+------------------------------------------------------------------+
#property copyright "2005-2014, MetaQuotes Software Corp."
#property link "http://www.mql4.com"
#property description "Moving Average sample expert advisor"
#define MAGICMA 20131111
//--- Inputs
input double Lots =0.1;
input double MaximumRisk =0.02;
input double DecreaseFactor=3;
input int MovingPeriod =12;
input int MovingShift =6;
//+------------------------------------------------------------------+
//| 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()==MAGICMA)
{
if(OrderType()==OP_BUY) buys++;
if(OrderType()==OP_SELL) sells++;
}
}
//--- return orders volume
if(buys>0) return(buys);
else return(-sells);
}
//+------------------------------------------------------------------+
//| Calculate optimal lot size |
//+------------------------------------------------------------------+
double LotsOptimized()
{
double lot=Lots;
int orders=HistoryTotal(); // history orders total
int losses=0; // number of losses orders without a break
//--- select lot size
lot=NormalizeDouble(AccountFreeMargin()*MaximumRisk/1000.0,1);
//--- calcuulate number of losses orders without 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);
}
//+------------------------------------------------------------------+
//| Check for open order conditions |
//+------------------------------------------------------------------+
void CheckForOpen()
{
double ma;
int res;
//--- go trading only for first tiks of new bar
if(Volume[0]>1) return;
//--- get Moving Average
ma=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);
//--- sell conditions
if(Open[1]>ma && Close[1]<ma)
{
res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,0,"",MAGICMA,0,Red);
return;
}
//--- buy conditions
if(Open[1]<ma && Close[1]>ma)
{
res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,0,"",MAGICMA,0,Blue);
return;
}
//---
}
//+------------------------------------------------------------------+
//| Check for close order conditions |
//+------------------------------------------------------------------+
void CheckForClose()
{
double ma;
//--- go trading only for first tiks of new bar
if(Volume[0]>1) return;
//--- get Moving Average
ma=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);
//---
for(int i=0;i<OrdersTotal();i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
if(OrderMagicNumber()!=MAGICMA || OrderSymbol()!=Symbol()) continue;
//--- check order type
if(OrderType()==OP_BUY)
{
if(Open[1]>ma && Close[1]<ma)
{
if(!OrderClose(OrderTicket(),OrderLots(),Bid,3,White))
Print("OrderClose error ",GetLastError());
}
break;
}
if(OrderType()==OP_SELL)
{
if(Open[1]<ma && Close[1]>ma)
{
if(!OrderClose(OrderTicket(),OrderLots(),Ask,3,White))
Print("OrderClose error ",GetLastError());
}
break;
}
}
//---
}
//+------------------------------------------------------------------+
//| OnTick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- check for history and trading
if(Bars<100 || IsTradeAllowed()==false)
return;
//--- calculate open orders by current symbol
if(CalculateCurrentOrders(Symbol())==0) CheckForOpen();
else CheckForClose();
//---
}
//+------------------------------------------------------------------+
解説
9行目から14行目 グローバル変数の設定
| 変数名 | 説明 | 設定値(単位) |
|---|---|---|
| Lots | ロット数 | 0.1 |
| MaximumRisk | ロット数を最適化するために使用されている 。取引口座の余剰証拠金額の2%を1000で除算した数字をロット数としている。 lot=NormalizeDouble(AccountFreeMargin()*MaximumRisk/1000.0,1) | 0.02 |
| DecreaseFactor | 減少要因 | 3 |
| MovingPeriod | 12 | |
| MovingShift | 6 |
24行目から41行目 変数の初期値のチェック
//---
// initial data checks
// it is important to make sure that the expert works with a normal
// chart and the user did not make any mistakes setting external
// variables (Lots, StopLoss, TakeProfit,
// TrailingStop) in our case, we check TakeProfit
// on a chart of less than 100 bars
//---
if(Bars<100)
{
Print("bars less than 100");
return;
}
if(TakeProfit<10)
{
Print("TakeProfit less than 10");
return;
}
ここではコード中のコメントにあるように変数の初期値のチェックをしています。
外部変数(Lots、StopLoss、TakeProfit、TrailingStop)の値に間違えがないことを確認しています。
変数Bars は、現在のチャートの中にあるバーの数です。
バーとは、ロウソク足の一本一本のことです。
バーの数 が少ない場合(100未満の場合)は、処理をせずに終了します。
42行目から48行目 MACDとEMAの取得
//--- to simplify the coding and speed up access data are put into internal variables MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0); MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1); SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,0); SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,1); MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0); MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);
43行目から46行目でMACDを計算しています。各変数に格納している値の意味は下表のとおりです。 短期EMAは期間12、長期EMAは期間26で計算しています(終値を使用)。シグナルは期間9で計算しています。 それぞれの期間の時間単位は現在のチャートの時間単位になります(日足ならそれぞれ12日・26日・9日、時間足なら12時間・26時間・9時間)。
| 変数 | 説明 |
| MacdCurrent | 現在のMACD |
| MacdPrevious | 1つ前のMACD |
| SignalCurrent | 現在のシグナル |
| SignalPrevious | 1つ前のシグナル |
MACDについては用語解説を参照してください。
47行目から48行目はEMA (指数移動平均)の計算です。
各変数に格納している値の意味は下表のとおりです。
| 変数 | 説明 |
| MaCurrent | 現在の指数移動平均 |
| MaPrevious | 1つ前の 指数移動平均 |
50行目から51行目 ポジションの有無を確認
現在のポジション数を取得して変数totalに格納します。この後の処理では、ポジションの有無によって処理が大きく変わります。
51行目から88行目までがポジションがない場合(変数total が1未満の場合)の処理、90行目以降が ポジションがある場合(変数total が1以上の場合)の処理になります。
total=OrdersTotal();
if(total<1)
{
//--- no opened orders identified
51行目から88行目 ポジションがない場合の処理
total=OrdersTotal();
if(total<1)
{
//--- no opened orders identified
if(AccountFreeMargin()<(1000*Lots))
{
Print("We have no money. Free Margin = ",AccountFreeMargin());
return;
}
//--- check for long position (BUY) possibility
if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious &&
MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent>MaPrevious)
{
ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point,"macd sample",16384,0,Green);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
Print("BUY order opened : ",OrderOpenPrice());
}
else
Print("Error opening BUY order : ",GetLastError());
return;
}
//--- check for short position (SELL) possibility
if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious &&
MacdCurrent>(MACDOpenLevel*Point) && MaCurrent<MaPrevious)
{
ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,Bid-TakeProfit*Point,"macd sample",16384,0,Red);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
Print("SELL order opened : ",OrderOpenPrice());
}
else
Print("Error opening SELL order : ",GetLastError());
}
//--- exit from the "no opened orders" block
return;
}
//--- it is important to enter the market correctly, but it is more important to exit it correctly...
53行目から58行目 証拠金の残高確認
余剰証拠金の確認をして余力があるかを確認しています。
余剰証拠金 はAccountFreeMargin()で取得します。
total=OrdersTotal();
if(total<1)
{
//--- no opened orders identified
if(AccountFreeMargin()<(1000*Lots))
{
Print("We have no money. Free Margin = ",AccountFreeMargin());
return;
}
//--- check for long position (BUY) possibility
if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious &&
MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent>MaPrevious)
{
ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point,"macd sample",16384,0,Green);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
Print("BUY order opened : ",OrderOpenPrice());
}
else
Print("Error opening BUY order : ",GetLastError());
return;
}
59行目から72行目 ロングポジションの確認
total=OrdersTotal();
if(total<1)
{
//--- no opened orders identified
if(AccountFreeMargin()<(1000*Lots))
{
Print("We have no money. Free Margin = ",AccountFreeMargin());
return;
}
//--- check for long position (BUY) possibility
if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious &&
MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent>MaPrevious)
{
ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point,"macd sample",16384,0,Green);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
Print("BUY order opened : ",OrderOpenPrice());
}
else
Print("Error opening BUY order : ",GetLastError());
return;
}
以下の条件が同時に成立するときに買い注文を出します。
- 現在のMACD(MacdCurrent)が0より小さい
- 現在のMACD(MacdCurrent)がシグナルより大きい
- 1つ前のMACD(MacdPrevious)が一つ前のシグナルより小さい
- 現在のMACDの絶対値がMACDOpenLevelにPointを掛けた値より大きい
- 現在の指数移動平均(MaCurrent)が1つ前の 指数移動平均(MaPrevious)より大きい