MQL5ソースコード解体新書とは、端的に言えば
巷にある、MQL5ソースコードを色々と解析・解説していこうというシリーズです。
今回は、MT5に標準実装されているエキスパートアドバイザー(EA)である、「MACD Sample」のソースコードを解説していきたいと思います。
当サイトでは「MQL5でEA作ろう講座」というプログラミング未経験者でもMQL5を使ってEAを自作できるよう、世界一わかりやすいMQL5講座の記事を完全無料で提供している訳ですが、講座記事を一通り学び終えて、次のステップに進もうとする際にMT5に実装されているエキスパートアドバイザーで、ソースコードが公開されているものを、解読していく作業は、大変有益であると考えています。
MT5に標準実装されているインジケータやエキスパートアドバイザーのソースコードは日々拡張と改良を続けるMQL5の技巧がふんだんに盛り込まれています。
これらのテクニックを自在に自身のEA開発に取り込めるようになれば、もうMQL5をマスターしたといっても過言ではないでしょう。
一見すると難しく感じるかもしれませんが、一つ一つを分解してみていけば、その殆どが「MQL5でEA作ろう講座」で学習した事になります。
丁寧な解説を心掛けましたので、順番に見て頂ければと思います。
- MT5に実装されている「MACD Sample」のソースコード確認方法
- サンプルコード解説1:define命令とinclude命令部分
- サンプルコード解説2:その他グローバル領域部分
- サンプルコード解説3:CSampleExpertクラスの定義部分
- サンプルコード解説4:コンストラクタCSampleExpertの処理記述部分
- サンプルコード解説5:デストラクタ~CSampleExpertの処理記述部分
- サンプルコード解説6:Initメソッドの処理記述部分
- サンプルコード解説7:InitCheckParametersメソッドの処理記述部分
- サンプルコード解説8:InitIndicatorsメソッドの処理記述部分
- サンプルコード解説9:LongClosedメソッドの処理記述部分
- サンプルコード解説10:ShortClosedメソッドの処理記述部分
- サンプルコード解説11:LongModifiedメソッドの処理記述部分
- サンプルコード解説12:ShortModifiedメソッドの処理記述部分
- サンプルコード解説13:LongOpenedメソッドの処理記述部分
- サンプルコード解説14:ShortOpenedメソッドの処理記述部分
- サンプルコード解説15:Processingメソッドの処理記述部分
- サンプルコード解説16:OnInit関数部分
- サンプルコード解説17:OnTick関数部分
- 「MACD Sample」EAの仕様まとめ
MT5に実装されている「MACD Sample」のソースコード確認方法
MT5に実装されている「MACD Sample」のソースコードを確認する方法をお伝えします。
MT5の「ナビゲーター」ウィンドウから
「エキスパートアドバイザー(EA)」→「Advisor」→「Examples」→「MACD」
とディレクトリーを展開していくと、その中に
「MACD Sample」
があるので、その部分を右クリックして表示メニューから
「変更」
を選択するとメタエディターが起動し、メタトレーダーに実装されている「MACD Sample」のソースコードが確認できます。
MT5に実装されている「MACD Sample」のソースコードは以下のようになっています。
//+------------------------------------------------------------------+
//| MACD Sample.mq5 |
//| Copyright 2000-2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2024, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "5.50"
#property description "正常なチャートでエキスパートが動作することを確認し、"
//+------------------------------------------------------------------+
//| 必要なライブラリをインクルード |
//+------------------------------------------------------------------+
#define MACD_MAGIC 1234502 // MACD専用のマジックナンバー(注文識別用)
#include <Trade\Trade.mqh> // 取引機能クラス(CTrade)
#include <Trade\SymbolInfo.mqh> // シンボル情報クラス(CSymbolInfo)
#include <Trade\PositionInfo.mqh> // ポジション情報クラス(CPositionInfo)
#include <Trade\AccountInfo.mqh> // 取引口座情報クラス(CAccountInfo)
//+------------------------------------------------------------------+
//| 入力パラメータ |
//+------------------------------------------------------------------+
input double InpLots =0.1; // ロット数の設定
input int InpTakeProfit =50; // テイクプロフィット
input int InpTrailingStop =30; // トレーリングストップレベル
input int InpMACDOpenLevel =3; // MACDのオープンレベル(pips単位)
input int InpMACDCloseLevel=2; // MACDのクローズレベル(pips単位)
input int InpMATrendPeriod =26; // 移動平均のトレンド期間
//---
int ExtTimeOut=10; // 取引操作のタイムアウト(秒単位)
//+------------------------------------------------------------------+
//| エキスパートクラス定義 |
//+------------------------------------------------------------------+
class CSampleExpert
{
protected:
double m_adjusted_point; // ポイント数調整後の値(小数点数対応)
CTrade m_trade; // 取引オブジェクト
CSymbolInfo m_symbol; // シンボル情報オブジェクト
CPositionInfo m_position; // ポジション情報オブジェクト
CAccountInfo m_account; // アカウント情報オブジェクト
//--- インジケータ
int m_handle_macd; // MACDインジケータのハンドル
int m_handle_ema; // 移動平均インジケータのハンドル
//--- インジケータバッファ
double m_buff_MACD_main[]; // MACDインジケータのメインバッファ
double m_buff_MACD_signal[]; // MACDインジケータのシグナルバッファ
double m_buff_EMA[]; // EMAインジケータのバッファ
//--- インジケータデータの格納
double m_macd_current; // 現在のMACD値
double m_macd_previous; // 前回のMACD値
double m_signal_current; // 現在のシグナル値
double m_signal_previous; // 前回のシグナル値
double m_ema_current; // 現在のEMA値
double m_ema_previous; // 前回のEMA値
//---
double m_macd_open_level; // MACDのオープンレベル
double m_macd_close_level; // MACDのクローズレベル
double m_traling_stop; // トレーリングストップ値
double m_take_profit; // テイクプロフィット値
public:
CSampleExpert(void); // コンストラクタ
~CSampleExpert(void); // デストラクタ
bool Init(void); // 初期化関数
void Deinit(void); // 終了処理関数
bool Processing(void); // メイン処理関数
protected:
bool InitCheckParameters(const int digits_adjust); // 初期パラメータチェック
bool InitIndicators(void); // インジケータの初期化
bool LongClosed(void); // ロングポジションのクローズ確認
bool ShortClosed(void); // ショートポジションのクローズ確認
bool LongModified(void); // ロングポジションの変更確認
bool ShortModified(void); // ショートポジションの変更確認
bool LongOpened(void); // ロングポジションのオープン確認
bool ShortOpened(void); // ショートポジションのオープン確認
};
//--- グローバルエキスパートオブジェクト
CSampleExpert ExtExpert;
//+------------------------------------------------------------------+
//| コンストラクタ |
//+------------------------------------------------------------------+
CSampleExpert::CSampleExpert(void) : m_adjusted_point(0), // ポイント値の初期化
m_handle_macd(INVALID_HANDLE), // MACDハンドル初期化
m_handle_ema(INVALID_HANDLE), // EMAハンドル初期化
m_macd_current(0), // MACDの初期値
m_macd_previous(0), // MACDの前回値
m_signal_current(0), // シグナルの初期値
m_signal_previous(0), // シグナルの前回値
m_ema_current(0), // EMAの初期値
m_ema_previous(0), // EMAの前回値
m_macd_open_level(0), // MACDのオープンレベル
m_macd_close_level(0), // MACDのクローズレベル
m_traling_stop(0), // トレーリングストップ値
m_take_profit(0) // テイクプロフィット値
{
ArraySetAsSeries(m_buff_MACD_main,true); // MACDメインバッファの配列順序設定
ArraySetAsSeries(m_buff_MACD_signal,true); // MACDシグナルバッファの配列順序設定
ArraySetAsSeries(m_buff_EMA,true); // EMAバッファの配列順序設定
}
//+------------------------------------------------------------------+
//| デストラクタ |
//+------------------------------------------------------------------+
CSampleExpert::~CSampleExpert(void)
{
//--- 必要なリソースの解放(デストラクタでは特に処理なし)
}
//+------------------------------------------------------------------+
//| 初期化と入力パラメータのチェック |
//+------------------------------------------------------------------+
bool CSampleExpert::Init(void)
{
//--- シンボル情報を初期化
m_symbol.Name(Symbol()); // 現在のシンボル名を設定
m_trade.SetExpertMagicNumber(MACD_MAGIC); // マジックナンバーの設定
m_trade.SetMarginMode(); // マージンモード設定
m_trade.SetTypeFillingBySymbol(Symbol()); // シンボルごとのフィリング設定
//--- 調整設定(小数点対応)
int digits_adjust=1;
if(m_symbol.Digits()==3 || m_symbol.Digits()==5)
digits_adjust=10;
m_adjusted_point=m_symbol.Point()*digits_adjust; // ポイント値を調整
//--- トレーリングストップ、テイクプロフィットの値を設定
m_macd_open_level =InpMACDOpenLevel*m_adjusted_point;
m_macd_close_level=InpMACDCloseLevel*m_adjusted_point;
m_traling_stop =InpTrailingStop*m_adjusted_point;
m_take_profit =InpTakeProfit*m_adjusted_point;
//--- 許容スリッページ設定
m_trade.SetDeviationInPoints(3*digits_adjust);
//--- 初期パラメータのチェック
if(!InitCheckParameters(digits_adjust))
return(false);
//--- インジケータの初期化
if(!InitIndicators())
return(false);
//--- 正常終了
return(true);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| 入力パラメータのチェック |
//+------------------------------------------------------------------+
bool CSampleExpert::InitCheckParameters(const int digits_adjust)
{
//--- 初期データチェック
if(InpTakeProfit * digits_adjust < m_symbol.StopsLevel()) // テイクプロフィットが停止レベルより小さい場合
{
printf("Take Profit must be greater than %d", m_symbol.StopsLevel()); // エラーメッセージ出力
return(false); // チェック失敗
}
if(InpTrailingStop * digits_adjust < m_symbol.StopsLevel()) // トレーリングストップが停止レベルより小さい場合
{
printf("Trailing Stop must be greater than %d", m_symbol.StopsLevel()); // エラーメッセージ出力
return(false); // チェック失敗
}
//--- ロット数の確認
if(InpLots < m_symbol.LotsMin() || InpLots > m_symbol.LotsMax()) // 許可されるロット範囲外の場合
{
printf("Lots amount must be in the range from %f to %f", m_symbol.LotsMin(), m_symbol.LotsMax());
return(false); // チェック失敗
}
if(MathAbs(InpLots / m_symbol.LotsStep() - MathRound(InpLots / m_symbol.LotsStep())) > 1.0E-10)
{
printf("Lots amount is not corresponding with lot step %f", m_symbol.LotsStep()); // ロット量が不正
return(false); // チェック失敗
}
//--- 警告メッセージ
if(InpTakeProfit <= InpTrailingStop) // トレーリングストップがテイクプロフィット以上の場合
printf("Warning: Trailing Stop must be less than Take Profit"); // 警告メッセージ出力
//--- チェック成功
return(true); // 全てのチェックが成功
}
//+------------------------------------------------------------------+
//| インジケータの初期化 |
//+------------------------------------------------------------------+
bool CSampleExpert::InitIndicators(void)
{
//--- MACDインジケータの作成
if(m_handle_macd == INVALID_HANDLE) // ハンドルが無効な場合に新規作成
if((m_handle_macd = iMACD(NULL, 0, 12, 26, 9, PRICE_CLOSE)) == INVALID_HANDLE)
{
printf("Error creating MACD indicator"); // エラーを出力
return(false); // 初期化失敗
}
//--- EMAインジケータの作成
if(m_handle_ema == INVALID_HANDLE) // ハンドルが無効な場合に新規作成
if((m_handle_ema = iMA(NULL, 0, InpMATrendPeriod, 0, MODE_EMA, PRICE_CLOSE)) == INVALID_HANDLE)
{
printf("Error creating EMA indicator"); // エラーを出力
return(false); // 初期化失敗
}
//--- 初期化成功
return(true);
}
//+------------------------------------------------------------------+
//| ロングポジションのクローズ確認 |
//+------------------------------------------------------------------+
bool CSampleExpert::LongClosed(void)
{
bool res = false;
//--- クローズ条件の確認
if(m_macd_current > 0)
if(m_macd_current < m_signal_current && m_macd_previous > m_signal_previous)
if(m_macd_current > m_macd_close_level)
{
//--- ポジションのクローズ
if(m_trade.PositionClose(Symbol()))
printf("Long position by %s to be closed", Symbol()); // クローズ成功メッセージ出力
else
printf("Error closing position by %s : '%s'", Symbol(), m_trade.ResultComment()); // エラーメッセージ出力
res = true; // クローズ処理完了
}
//--- 結果を返す
return(res);
}
//+------------------------------------------------------------------+
//| ショートポジションのクローズ確認 |
//+------------------------------------------------------------------+
bool CSampleExpert::ShortClosed(void)
{
bool res = false;
//--- クローズ条件の確認
if(m_macd_current < 0)
if(m_macd_current > m_signal_current && m_macd_previous < m_signal_previous)
if(MathAbs(m_macd_current) > m_macd_close_level)
{
//--- ポジションのクローズ
if(m_trade.PositionClose(Symbol()))
printf("Short position by %s to be closed", Symbol()); // クローズ成功メッセージ出力
else
printf("Error closing position by %s : '%s'", Symbol(), m_trade.ResultComment()); // エラーメッセージ出力
res = true; // クローズ処理完了
}
//--- 結果を返す
return(res);
}
//+------------------------------------------------------------------+
//| ロングポジションの変更確認 |
//+------------------------------------------------------------------+
bool CSampleExpert::LongModified(void)
{
bool res = false;
//--- トレーリングストップの確認
if(InpTrailingStop > 0)
{
if(m_symbol.Bid() - m_position.PriceOpen() > m_adjusted_point * InpTrailingStop)
{
double sl = NormalizeDouble(m_symbol.Bid() - m_traling_stop, m_symbol.Digits()); // ストップロス価格の計算
double tp = m_position.TakeProfit(); // テイクプロフィットを取得
if(m_position.StopLoss() < sl || m_position.StopLoss() == 0.0)
{
//--- ポジションの変更
if(m_trade.PositionModify(Symbol(), sl, tp))
printf("Long position by %s to be modified", Symbol()); // 変更成功メッセージ出力
else
{
printf("Error modifying position by %s : '%s'", Symbol(), m_trade.ResultComment()); // エラーメッセージ出力
printf("Modify parameters : SL=%f,TP=%f", sl, tp); // エラー詳細出力
}
res = true; // 変更処理完了
}
}
}
//--- 結果を返す
return(res);
}
//+------------------------------------------------------------------+
//| ショートポジションの変更確認 |
//+------------------------------------------------------------------+
bool CSampleExpert::ShortModified(void)
{
bool res = false;
//--- トレーリングストップの確認
if(InpTrailingStop > 0)
{
if((m_position.PriceOpen() - m_symbol.Ask()) > (m_adjusted_point * InpTrailingStop))
{
double sl = NormalizeDouble(m_symbol.Ask() + m_traling_stop, m_symbol.Digits()); // ストップロス価格の計算
double tp = m_position.TakeProfit(); // テイクプロフィットを取得
if(m_position.StopLoss() > sl || m_position.StopLoss() == 0.0)
{
//--- ポジションの変更
if(m_trade.PositionModify(Symbol(), sl, tp))
printf("Short position by %s to be modified", Symbol()); // 変更成功メッセージ出力
else
{
printf("Error modifying position by %s : '%s'", Symbol(), m_trade.ResultComment()); // エラーメッセージ出力
printf("Modify parameters : SL=%f,TP=%f", sl, tp); // エラー詳細出力
}
res = true; // 変更処理完了
}
}
}
//--- 結果を返す
return(res);
}
//+------------------------------------------------------------------+
//| ロングポジションのオープン確認 |
//+------------------------------------------------------------------+
bool CSampleExpert::LongOpened(void)
{
bool res = false;
//--- ロングポジション(買い)のオープン条件を確認
if(m_macd_current < 0)
if(m_macd_current > m_signal_current && m_macd_previous < m_signal_previous)
if(MathAbs(m_macd_current) > m_macd_open_level && m_ema_current > m_ema_previous)
{
double price = m_symbol.Ask(); // 現在の買い価格を取得
double tp = m_symbol.Bid() + m_take_profit; // テイクプロフィット価格を計算
//--- フリーマージンの確認
if(m_account.FreeMarginCheck(Symbol(), ORDER_TYPE_BUY, InpLots, price) < 0.0)
printf("We have no money. Free Margin = %f", m_account.FreeMargin()); // フリーマージンが不足している場合
else
{
//--- ポジションをオープン
if(m_trade.PositionOpen(Symbol(), ORDER_TYPE_BUY, InpLots, price, 0.0, tp))
printf("Position by %s to be opened", Symbol()); // オープン成功メッセージ出力
else
{
printf("Error opening BUY position by %s : '%s'", Symbol(), m_trade.ResultComment()); // エラーメッセージ出力
printf("Open parameters : price=%f,TP=%f", price, tp); // エラー詳細出力
}
}
res = true; // 処理完了
}
//--- 結果を返す
return(res);
}
//+------------------------------------------------------------------+
//| ショートポジションのオープン確認 |
//+------------------------------------------------------------------+
bool CSampleExpert::ShortOpened(void)
{
bool res = false;
//--- ショートポジション(売り)のオープン条件を確認
if(m_macd_current > 0)
if(m_macd_current < m_signal_current && m_macd_previous > m_signal_previous)
if(m_macd_current > m_macd_open_level && m_ema_current < m_ema_previous)
{
double price = m_symbol.Bid(); // 現在の売り価格を取得
double tp = m_symbol.Ask() - m_take_profit; // テイクプロフィット価格を計算
//--- フリーマージンの確認
if(m_account.FreeMarginCheck(Symbol(), ORDER_TYPE_SELL, InpLots, price) < 0.0)
printf("We have no money. Free Margin = %f", m_account.FreeMargin()); // フリーマージンが不足している場合
else
{
//--- ポジションをオープン
if(m_trade.PositionOpen(Symbol(), ORDER_TYPE_SELL, InpLots, price, 0.0, tp))
printf("Position by %s to be opened", Symbol()); // オープン成功メッセージ出力
else
{
printf("Error opening SELL position by %s : '%s'", Symbol(), m_trade.ResultComment()); // エラーメッセージ出力
printf("Open parameters : price=%f,TP=%f", price, tp); // エラー詳細出力
}
}
res = true; // 処理完了
}
//--- 結果を返す
return(res);
}
//+------------------------------------------------------------------+
//| メイン処理関数:ポジションが処理された場合にtrueを返す |
//+------------------------------------------------------------------+
bool CSampleExpert::Processing(void)
{
//--- レート情報の更新
if(!m_symbol.RefreshRates())
return(false);
//--- インジケータの更新確認
if(BarsCalculated(m_handle_macd) < 2 || BarsCalculated(m_handle_ema) < 2)
return(false);
if(CopyBuffer(m_handle_macd, 0, 0, 2, m_buff_MACD_main) != 2 ||
CopyBuffer(m_handle_macd, 1, 0, 2, m_buff_MACD_signal) != 2 ||
CopyBuffer(m_handle_ema, 0, 0, 2, m_buff_EMA) != 2)
return(false);
//--- データを内部変数に格納
m_macd_current = m_buff_MACD_main[0];
m_macd_previous = m_buff_MACD_main[1];
m_signal_current = m_buff_MACD_signal[0];
m_signal_previous = m_buff_MACD_signal[1];
m_ema_current = m_buff_EMA[0];
m_ema_previous = m_buff_EMA[1];
//--- 既存ポジションの有無を確認
if(m_position.Select(Symbol()))
{
if(m_position.PositionType() == POSITION_TYPE_BUY)
{
//--- ロングポジションのクローズまたは変更を確認
if(LongClosed())
return(true);
if(LongModified())
return(true);
}
else
{
//--- ショートポジションのクローズまたは変更を確認
if(ShortClosed())
return(true);
if(ShortModified())
return(true);
}
}
else
{
//--- ロングポジションのオープン確認
if(LongOpened())
return(true);
//--- ショートポジションのオープン確認
if(ShortOpened())
return(true);
}
//--- ポジションが処理されなかった場合
return(false);
}
//+------------------------------------------------------------------+
//| エキスパート初期化関数 |
//+------------------------------------------------------------------+
int OnInit(void)
{
//--- エキスパートオブジェクトの初期化
if(!ExtExpert.Init())
return(INIT_FAILED); // 初期化失敗時にエキスパートの開始をキャンセル
//--- 初期化成功
return(INIT_SUCCEEDED); // 正常に初期化が完了したことを示す
}
//+------------------------------------------------------------------+
//| エキスパートティック関数 |
//+------------------------------------------------------------------+
void OnTick(void)
{
static datetime limit_time = 0; // 最後の取引処理時間とタイムアウトを保持
//--- タイムアウトが経過しているか確認
if(TimeCurrent() >= limit_time)
{
//--- データが十分であることを確認
if(Bars(Symbol(), Period()) > 2 * InpMATrendPeriod)
{
//--- 処理が行われた場合は次のタイムアウト時間を設定
if(ExtExpert.Processing())
limit_time = TimeCurrent() + ExtTimeOut; // 次回の処理をタイムアウト設定に基づき遅延
}
}
}
//+------------------------------------------------------------------+
サンプルコード解説1:define命令とinclude命令部分
//+------------------------------------------------------------------+
//| 必要なライブラリをインクルード |
//+------------------------------------------------------------------+
#define MACD_MAGIC 1234502 // MACD専用のマジックナンバー(注文識別用)
#include <Trade\Trade.mqh> // 取引機能クラス(CTrade)
#include <Trade\SymbolInfo.mqh> // シンボル情報クラス(CSymbolInfo)
#include <Trade\PositionInfo.mqh> // ポジション情報クラス(CPositionInfo)
#include <Trade\AccountInfo.mqh> // 取引口座情報クラス(CAccountInfo)
このコード冒頭では、define命令とinclude命令を使ってエキスパートアドバイザー(EA)内で使用する定数やライブラリを設定しています。
まず、define命令では「MACD_MAGIC」という定数を設定しています。この値「1234502」はマジックナンバーと呼ばれ、取引の識別に使用されるユニーク(一意で他と重複しない)な番号です。特に、複数のEAが稼働している場合、このマジックナンバーによって取引がどのEAに関連しているかを判別できます。
次に、include命令によってMQL5標準ライブラリがインポートされています。これにより、取引や情報管理に役立つ各クラスが使えるようになります。具体的には、以下のライブラリがインポートされています。
- Trade.mqh: CTradeクラスを提供し、取引の発注、ポジションの変更やクローズなどの取引操作が可能になります。
- SymbolInfo.mqh: CSymbolInfoクラスを通して銘柄情報を取得し、現在の価格や取引単位、スプレッドなどの詳細なシンボル情報を取得します。
- PositionInfo.mqh: CPositionInfoクラスを使い、現在の保有ポジションの情報(建値、数量、未決済損益など)を取得・管理します。
- AccountInfo.mqh: CAccountInfoクラスにより、取引口座の残高、資本、証拠金などの情報を管理します。
これらのライブラリをインポートすることで、EA内での取引操作や口座情報の参照、シンボル情報の取得が容易になり、EAの処理を効率化することができます。
サンプルコード解説2:その他グローバル領域部分
//+------------------------------------------------------------------+
//| 入力パラメータ |
//+------------------------------------------------------------------+
input double InpLots =0.1; // ロット数の設定
input int InpTakeProfit =50; // テイクプロフィット(pips単位)
input int InpTrailingStop =30; // トレーリングストップレベル(pips単位)
input int InpMACDOpenLevel =3; // MACDのオープンレベル(pips単位)
input int InpMACDCloseLevel=2; // MACDのクローズレベル(pips単位)
input int InpMATrendPeriod =26; // 移動平均のトレンド期間
//---
int ExtTimeOut=10; // 取引操作のタイムアウト(秒単位)
このコードのグローバル領域では、input変数を用いてエキスパートアドバイザー(EA)の設定パラメータを定義し、ユーザーがEAを操作する際に簡単に設定を調整できるようにしています。また、取引操作のタイムアウト時間を設定するための変数も定義しています。それぞれのパラメータの詳細は以下の通りです。
入力パラメータ
- InpLots
取引のロット数を指定します。ロット数は取引の基本単位であり、数値が大きいほど取引のリスクやリターンも大きくなります。初期値は0.1に設定されています。 - InpTakeProfit
テイクプロフィット(利確)のポイント数を指定します。取引が利益目標に達した場合に自動的に決済するレベルで、初期値は50に設定されています。 - InpTrailingStop
トレーリングストップのレベルを設定します。トレーリングストップは、価格が有利に進んだ際にストップレベルを追従させ、利益の確保と損失の抑制を同時に行う仕組みです。初期値は30です。 - InpMACDOpenLevel
MACDのオープンレベルを設定します。MACDのシグナルがこのレベルに達した場合、ポジションをオープンする条件を満たすものと見なされます。初期値は3です。 - InpMACDCloseLevel
MACDのクローズレベルを設定します。MACDシグナルがこのレベルに達した場合、ポジションをクローズする条件を満たすものと見なされます。初期値は2です。 - InpMATrendPeriod
移動平均(MA)を使用する期間を設定します。移動平均のトレンド期間はトレンドの方向性や強さを把握するために使用され、初期値は26に設定されています。
その他の変数
- ExtTimeOut
取引操作のタイムアウト時間を秒単位で指定します。この時間は、連続する取引操作の間隔を調整するために使用され、連続的な操作によるサーバー負荷や誤動作を防ぎます。初期値は10秒に設定されています。
これらのパラメータにより、EAの運用方針やリスク管理が柔軟に調整できるようになり、トレード戦略に応じた最適な設定が可能となっています。
サンプルコード解説3:CSampleExpertクラスの定義部分
//+------------------------------------------------------------------+
//| エキスパートクラス定義 |
//+------------------------------------------------------------------+
class CSampleExpert
{
protected:
double m_adjusted_point; // ポイント数調整後の値(小数点数対応)
CTrade m_trade; // 取引オブジェクト
CSymbolInfo m_symbol; // シンボル情報オブジェクト
CPositionInfo m_position; // ポジション情報オブジェクト
CAccountInfo m_account; // アカウント情報オブジェクト
//--- インジケータ
int m_handle_macd; // MACDインジケータのハンドル
int m_handle_ema; // 移動平均インジケータのハンドル
//--- インジケータバッファ
double m_buff_MACD_main[]; // MACDインジケータのメインバッファ
double m_buff_MACD_signal[]; // MACDインジケータのシグナルバッファ
double m_buff_EMA[]; // EMAインジケータのバッファ
//--- インジケータデータの格納
double m_macd_current; // 現在のMACD値
double m_macd_previous; // 前回のMACD値
double m_signal_current; // 現在のシグナル値
double m_signal_previous; // 前回のシグナル値
double m_ema_current; // 現在のEMA値
double m_ema_previous; // 前回のEMA値
//---
double m_macd_open_level; // MACDのオープンレベル
double m_macd_close_level; // MACDのクローズレベル
double m_traling_stop; // トレーリングストップ値
double m_take_profit; // テイクプロフィット値
public:
CSampleExpert(void); // コンストラクタ
~CSampleExpert(void); // デストラクタ
bool Init(void); // 初期化関数
void Deinit(void); // 終了処理関数
bool Processing(void); // メイン処理関数
protected:
bool InitCheckParameters(const int digits_adjust); // 初期パラメータチェック
bool InitIndicators(void); // インジケータの初期化
bool LongClosed(void); // ロングポジションのクローズ確認
bool ShortClosed(void); // ショートポジションのクローズ確認
bool LongModified(void); // ロングポジションの変更確認
bool ShortModified(void); // ショートポジションの変更確認
bool LongOpened(void); // ロングポジションのオープン確認
bool ShortOpened(void); // ショートポジションのオープン確認
};
//--- グローバルエキスパートオブジェクト
CSampleExpert ExtExpert;
このセクションでは、CSampleExpertクラスの定義部分について説明します。このクラスは、エキスパートアドバイザー(EA)の中心的な機能を実装するために使用され、取引管理やインジケータの初期化といった一連の処理を行います。
クラスメンバ
CSampleExpertクラスは、保護された変数(protected)とメソッドによって、EAの動作に必要な内部データと処理ロジックを保持します。
- m_adjusted_point
ポイント数を調整した値を保持します。通常、価格の小数点桁数に応じた調整が必要な場合に使われます。 - m_trade, m_symbol, m_position, m_account
それぞれCTrade、CSymbolInfo、CPositionInfo、CAccountInfoクラスのインスタンスで、取引の操作、シンボル情報、ポジション情報、口座情報を管理するオブジェクトです。これらを使うことで、EA内で取引管理や情報取得が簡単に行えるようになっています。
インジケータ関連のメンバ
- m_handle_macd, m_handle_ema
MACDと移動平均(EMA)の各インジケータのハンドルを保持します。これらのハンドルはインジケータの値を参照するために使用します。 - m_buff_MACD_main, m_buff_MACD_signal, m_buff_EMA
MACDのメインバッファとシグナルバッファ、ならびにEMAのバッファをそれぞれ保持し、インジケータの計算結果を格納するための配列です。 - m_macd_current, m_macd_previous, m_signal_current, m_signal_previous, m_ema_current, m_ema_previous
各インジケータの現在値と前回値を格納するための変数で、トレードシグナルの発生やポジションの管理に使用されます。
その他の取引関連メンバ
- m_macd_open_level, m_macd_close_level
MACDに基づくポジションのオープンレベルとクローズレベルの閾値を保持します。 - m_traling_stop, m_take_profit
トレーリングストップとテイクプロフィットの値を保持し、取引の損益管理に利用します。
クラスメソッド
このクラスには、エキスパートアドバイザーの操作に必要なメソッドがいくつか定義されています。
- CSampleExpert()と~CSampleExpert()
コンストラクタとデストラクタです。クラスのインスタンス作成時と破棄時に自動的に呼ばれ、初期化やリソースの解放を行います。 - Init()とDeinit()
InitメソッドはEAの初期化処理を担当し、Deinitメソッドは終了処理を行います。EAを稼働させる前の準備や、終了後の後片付けに用いられます。 - Processing()
Processingメソッドはメイン処理を担うメソッドで、取引のタイミング判断やポジション管理といったエキスパートアドバイザーの主要なロジックを実行します。
アクセルレベル=protectedされたメソッド
- InitCheckParameters()
初期化時に入力パラメータが正しいかをチェックします。桁数の調整が必要な場合には、引数digits_adjustで対応します。 - InitIndicators()
MACDやEMAなどのインジケータを初期化します。成功すると、インジケータの値をEA内で利用できるようになります。 - LongClosed(), ShortClosed()
ロングポジションとショートポジションのクローズ条件を確認します。特定の条件が満たされるとポジションをクローズします。 - LongModified(), ShortModified()
トレーリングストップやテイクプロフィットのレベルを管理し、ロングまたはショートポジションのストップロス値を適宜更新します。 - LongOpened(), ShortOpened()
新規ポジションのオープン条件を確認します。特定のシグナルが発生した際に新しいロングまたはショートポジションをオープンします。
グローバルエキスパートオブジェクト「ExtExpert」
CSampleExpertクラスのインスタンスである「ExtExpert」は、EAの全体で使用されるグローバルオブジェクトです。これにより、コード内のさまざまな場所からエキスパートの主要な処理や設定にアクセスすることができます。
サンプルコード解説4:コンストラクタCSampleExpertの処理記述部分
//+------------------------------------------------------------------+
//| コンストラクタ |
//+------------------------------------------------------------------+
CSampleExpert::CSampleExpert(void) : m_adjusted_point(0), // ポイント値の初期化
m_handle_macd(INVALID_HANDLE), // MACDハンドル初期化
m_handle_ema(INVALID_HANDLE), // EMAハンドル初期化
m_macd_current(0), // MACDの初期値
m_macd_previous(0), // MACDの前回値
m_signal_current(0), // シグナルの初期値
m_signal_previous(0), // シグナルの前回値
m_ema_current(0), // EMAの初期値
m_ema_previous(0), // EMAの前回値
m_macd_open_level(0), // MACDのオープンレベル
m_macd_close_level(0), // MACDのクローズレベル
m_traling_stop(0), // トレーリングストップ値
m_take_profit(0) // テイクプロフィット値
{
ArraySetAsSeries(m_buff_MACD_main,true); // MACDメインバッファの配列順序設定
ArraySetAsSeries(m_buff_MACD_signal,true); // MACDシグナルバッファの配列順序設定
ArraySetAsSeries(m_buff_EMA,true); // EMAバッファの配列順序設定
}
コンストラクタCSampleExpertの役割は、オブジェクトが生成されたときに初期化すべき値を設定することです。特に、m_adjusted_pointやm_macd_currentなどのメンバ変数に対して初期値を指定しています。コンストラクタ内での初期化方法について、ここでは特に「メンバ初期化リスト」という規則に基づいた処理が行われています。
メンバ初期化リストの規則と理由
MQL5では、クラスのコンストラクタでメンバ変数を初期化する方法として、「メンバ初期化リスト」を使うことが推奨されています。このリストを使うと、メンバ変数の初期化がクラスオブジェクト生成時に一度に行われるため、パフォーマンスが向上し、また初期化が明確に記述されるという利点があります。
ここでは、メンバ初期化リストが「:」の後に続いて宣言されており、それぞれのメンバ変数に初期値が代入されています。
各メンバ変数の初期化設定
- m_adjusted_point(0)
ポイント値を保持する変数で、0に初期化されています。トレードの際に価格の調整に用いられます。 - m_handle_macd(INVALID_HANDLE), m_handle_ema(INVALID_HANDLE)
MACDとEMAのインジケータを指し示すハンドル(識別子)で、初期化時はINVALID_HANDLEという無効値で設定されています。インジケータがまだ設定されていないことを表します。 - m_macd_current(0), m_macd_previous(0)
現在のMACD値と前回のMACD値を保持する変数で、それぞれ0に初期化されています。これにより、MACDが生成された際にすぐにデータの更新が反映できるようになります。 - m_signal_current(0), m_signal_previous(0)
MACDシグナルの現在値と前回値を保持する変数で、同様に0に初期化されています。MACDと合わせて取引シグナルの判断に使用されます。 - m_ema_current(0), m_ema_previous(0)
現在のEMA値と前回のEMA値を保持する変数です。MACDと連携して相場のトレンドを把握するために使われます。 - m_macd_open_level(0), m_macd_close_level(0)
MACDのオープン・クローズレベルを保持する変数で、ポジションの開閉条件の設定に使われます。初期化は0ですが、設定値を受け取ることで、後に動的に変更されます。 - m_traling_stop(0), m_take_profit(0)
トレーリングストップとテイクプロフィットの値で、ポジションの損益管理に使用されます。0で初期化されますが、設定により実際の運用では異なる値に置き換えられます。
配列の初期設定
コンストラクタ内の最後の3行では、ArraySetAsSeries関数を使って、各インジケータのバッファ(データを保持する配列)を逆順にする設定を行っています。
配列順序を逆にすることで、最新のデータがインジケータバッファの最初の要素に格納され、アクセスが迅速に行えるようになります。
サンプルコード解説5:デストラクタ~CSampleExpertの処理記述部分
デストラクタ「~CSampleExpert」は、CSampleExpertクラスのオブジェクトが不要になったとき、またはスコープを抜けた際に自動的に呼び出されます。デストラクタは、オブジェクトがメモリから削除される前に最後の処理を行うための関数で、通常は必要なリソースやメモリの解放に用いられます。デストラクタはコンストラクタと対になる重要な関数です。
デストラクタの記述方法
デストラクタは次のように記述します。
// デストラクタの例
CSampleExpert::~CSampleExpert(void)
{
// 必要に応じてリソースの解放や後処理を記述
}
このサンプルコードでは、デストラクタ内に特別な処理はありません。クラス内で使用している変数やオブジェクト(例えばm_tradeやm_symbolなど)は、システムによって自動的に管理されるため、明示的に解放する必要がないからです。
しかし、動的に確保したメモリやファイル、ネットワーク接続などを含むクラスの場合、デストラクタ内でそれらを解放するコードを記述する必要があります。
サンプルコード解説6:Initメソッドの処理記述部分
//+------------------------------------------------------------------+
//| 初期化と入力パラメータのチェック |
//+------------------------------------------------------------------+
bool CSampleExpert::Init(void)
{
//--- シンボル情報を初期化
m_symbol.Name(Symbol()); // 現在のシンボル名を設定
m_trade.SetExpertMagicNumber(MACD_MAGIC); // マジックナンバーの設定
m_trade.SetMarginMode(); // マージンモード設定
m_trade.SetTypeFillingBySymbol(Symbol()); // シンボルごとのフィリング設定
//--- 調整設定(小数点対応)
int digits_adjust=1;
if(m_symbol.Digits()==3 || m_symbol.Digits()==5)
digits_adjust=10;
m_adjusted_point=m_symbol.Point()*digits_adjust; // ポイント値を調整
//--- トレーリングストップ、テイクプロフィットの値を設定
m_macd_open_level =InpMACDOpenLevel*m_adjusted_point;
m_macd_close_level=InpMACDCloseLevel*m_adjusted_point;
m_traling_stop =InpTrailingStop*m_adjusted_point;
m_take_profit =InpTakeProfit*m_adjusted_point;
//--- 許容スリッページ設定
m_trade.SetDeviationInPoints(3*digits_adjust);
//--- 初期パラメータのチェック
if(!InitCheckParameters(digits_adjust))
return(false);
//--- インジケータの初期化
if(!InitIndicators())
return(false);
//--- 正常終了
return(true);
}
//+------------------------------------------------------------------+
Initメソッドは、CSampleExpertクラスの初期設定を行うために使用されます。このメソッドは、エキスパートアドバイザー(EA)が正しく動作するための準備を整える役割を担っており、シンボルや取引の設定、調整、パラメータチェック、インジケータの初期化などを実施しています。
Initメソッドの処理内容
- シンボル情報の初期化
- m_symbol.Nameに現在のシンボル名(取引銘柄)を設定します。これにより、EAが対象とする銘柄が決まります。
- m_trade.SetExpertMagicNumberでマジックナンバーを設定します。これにより、EAが実行する取引を他のEAと区別するための識別番号が設定されます。
- m_trade.SetMarginModeで証拠金に関連するモードを設定し、m_trade.SetTypeFillingBySymbolでシンボルごとに適用されるフィルポリシーを指定します。
ポイント値の調整
- 通貨ペアや取引銘柄によって価格の小数点桁数が異なるため、ポイント値を調整する必要があります。ここでは、小数点が3桁または5桁の場合、digits_adjustを10に設定して、小数点対応を行います。
- m_adjusted_pointに調整されたポイント値を計算し、取引時に用います。
トレーリングストップとテイクプロフィットの設定
- トレーリングストップやテイクプロフィットの各レベルを、調整済みのポイント値を使って計算し、それぞれm_traling_stopやm_take_profitに設定します。
- InpMACDOpenLevelとInpMACDCloseLevelも調整済みのポイント値で計算し、MACDのエントリーレベルとクローズレベルを設定します。
スリッページの設定
- 許容スリッページ(価格の許容誤差)をm_trade.SetDeviationInPointsで設定します。ここでは、3ポイントのスリッページ許容範囲を設定しており、この範囲内での価格変動が発生した場合にのみ取引を実行します。
初期パラメータのチェック
- InitCheckParametersメソッドで、ユーザーが設定した入力パラメータ(ロット数、トレード範囲など)が適切であるか確認します。ここで不適切な設定があればfalseを返し、初期化に失敗します。
インジケータの初期化
正常終了
- 全ての初期化が成功した場合、trueを返してEAが正常に動作できる状態になったことを示します。
サンプルコード解説7:InitCheckParametersメソッドの処理記述部分
//+------------------------------------------------------------------+
//| 入力パラメータのチェック |
//+------------------------------------------------------------------+
bool CSampleExpert::InitCheckParameters(const int digits_adjust)
{
//--- 初期データチェック
if(InpTakeProfit * digits_adjust < m_symbol.StopsLevel()) // テイクプロフィットが停止レベルより小さい場合
{
printf("Take Profit must be greater than %d", m_symbol.StopsLevel()); // エラーメッセージ出力
return(false); // チェック失敗
}
if(InpTrailingStop * digits_adjust < m_symbol.StopsLevel()) // トレーリングストップが停止レベルより小さい場合
{
printf("Trailing Stop must be greater than %d", m_symbol.StopsLevel()); // エラーメッセージ出力
return(false); // チェック失敗
}
//--- ロット数の確認
if(InpLots < m_symbol.LotsMin() || InpLots > m_symbol.LotsMax()) // 許可されるロット範囲外の場合
{
printf("Lots amount must be in the range from %f to %f", m_symbol.LotsMin(), m_symbol.LotsMax());
return(false); // チェック失敗
}
if(MathAbs(InpLots / m_symbol.LotsStep() - MathRound(InpLots / m_symbol.LotsStep())) > 1.0E-10)
{
printf("Lots amount is not corresponding with lot step %f", m_symbol.LotsStep()); // ロット量が不正
return(false); // チェック失敗
}
//--- 警告メッセージ
if(InpTakeProfit <= InpTrailingStop) // トレーリングストップがテイクプロフィット以上の場合
printf("Warning: Trailing Stop must be less than Take Profit"); // 警告メッセージ出力
//--- チェック成功
return(true); // 全てのチェックが成功
}
InitCheckParametersメソッドは、CSampleExpertクラスの入力パラメータが適切であるかをチェックし、条件を満たしていない場合はエラーメッセージを表示します。チェック内容には、テイクプロフィットやトレーリングストップの設定、ロット数、ステップ量などが含まれ、いずれかの条件が不適切な場合はfalseを返して初期化を停止します。
処理内容
テイクプロフィットとトレーリングストップのレベル確認
- InpTakeProfitおよびInpTrailingStopが、m_symbol.StopsLevel(指定されたシンボルにおける最小停止レベル)よりも小さい場合、エラーメッセージを出力しfalseを返します。
- これにより、ユーザーが設定した利益確定(テイクプロフィット)およびトレーリングストップが、取引条件を満たしていることを確認します。
ロット数の確認
- InpLots(設定されたロット数)が、シンボルの最低許容ロット数m_symbol.LotsMinと最大許容ロット数m_symbol.LotsMaxの範囲外である場合、エラーメッセージを出力しfalseを返します。
- また、ロット数がLotStep(設定されたロット刻み)と一致しない場合も、エラーメッセージを表示してfalseを返します。これにより、ロット数の範囲と単位が適切であるかを検証します。
警告メッセージの表示
- InpTakeProfitがInpTrailingStop以下である場合、利益確定レベルがトレーリングストップと重複するため、ユーザーに警告を表示します。この場合、取引に影響を及ぼすため、注意を促しますがfalseは返しません。
チェック成功の確認
- 全てのチェック条件を通過した場合、trueを返して初期化が正常に進行できる状態であることを示します。
InitCheckParametersメソッドにより、EAが開始される前にパラメータが適切に設定されているかを確認し、不適切な設定によるエラーを未然に防ぎます。
サンプルコード解説8:InitIndicatorsメソッドの処理記述部分
//+------------------------------------------------------------------+
//| インジケータの初期化 |
//+------------------------------------------------------------------+
bool CSampleExpert::InitIndicators(void)
{
//--- MACDインジケータの作成
if(m_handle_macd == INVALID_HANDLE) // ハンドルが無効な場合に新規作成
if((m_handle_macd = iMACD(NULL, 0, 12, 26, 9, PRICE_CLOSE)) == INVALID_HANDLE)
{
printf("Error creating MACD indicator"); // エラーを出力
return(false); // 初期化失敗
}
//--- EMAインジケータの作成
if(m_handle_ema == INVALID_HANDLE) // ハンドルが無効な場合に新規作成
if((m_handle_ema = iMA(NULL, 0, InpMATrendPeriod, 0, MODE_EMA, PRICE_CLOSE)) == INVALID_HANDLE)
{
printf("Error creating EMA indicator"); // エラーを出力
return(false); // 初期化失敗
}
//--- 初期化成功
return(true);
}
InitIndicatorsメソッドは、MACDとEMA(移動平均)インジケータを初期化する役割を担っています。これにより、エキスパートアドバイザーがトレードシグナルの判断に必要なテクニカル指標を取得できるようになります。初期化に失敗した場合はエラーメッセージを表示し、falseを返してエキスパートアドバイザーの起動を停止します。
処理内容
- m_handle_macdが無効(INVALID_HANDLE)である場合に、新しいMACDインジケータを生成します。
- iMACD関数を使ってMACDインジケータのハンドルを作成し、初期化が成功するとm_handle_macdにそのハンドルが代入されます。
- 初期化に失敗した場合は、エラーメッセージを出力しfalseを返します。
- m_handle_emaが無効(INVALID_HANDLE)である場合に、新しいEMAインジケータを生成します。
- iMA関数を使ってEMAインジケータのハンドルを作成し、成功するとそのハンドルがm_handle_emaに代入されます。このインジケータは、ユーザーが設定したInpMATrendPeriodに基づいてEMAを計算します。
- 初期化に失敗した場合、MACD同様にエラーメッセージを出力してfalseを返し、エキスパートアドバイザーの実行を停止します。
初期化成功の確認
- 全てのインジケータの初期化が成功した場合、trueを返してエキスパートアドバイザーの実行を続行できる状態であることを示します。
InitIndicatorsメソッドは、エキスパートアドバイザーが取引シグナルの判断に必要なインジケータを生成するため、エキスパートアドバイザーが正常に機能するために欠かせない重要な初期設定を担っています。
サンプルコード解説9:LongClosedメソッドの処理記述部分
//+------------------------------------------------------------------+
//| ロングポジションのクローズ確認 |
//+------------------------------------------------------------------+
bool CSampleExpert::LongClosed(void)
{
bool res = false;
//--- クローズ条件の確認
if(m_macd_current > 0)
if(m_macd_current < m_signal_current && m_macd_previous > m_signal_previous)
if(m_macd_current > m_macd_close_level)
{
//--- ポジションのクローズ
if(m_trade.PositionClose(Symbol()))
printf("Long position by %s to be closed", Symbol()); // クローズ成功メッセージ出力
else
printf("Error closing position by %s : '%s'", Symbol(), m_trade.ResultComment()); // エラーメッセージ出力
res = true; // クローズ処理完了
}
//--- 結果を返す
return(res);
}
LongClosedメソッドは、現在のロングポジション(買いポジション)をクローズする条件が整っているかを確認し、条件が満たされた場合にクローズを実行するメソッドです。クローズが成功した場合にはtrueを返し、失敗した場合やクローズ条件を満たしていない場合にはfalseを返します。
処理内容
クローズ条件の確認
- まず、現在のMACD値が0より大きいことを確認します。この条件が満たされている場合のみ、MACDに基づいたポジションのクローズを試みます。
- 次に、MACDの現在の値がシグナルの現在値よりも小さく、また、前回のMACD値がシグナルの前回値よりも大きいことを確認します。これは、MACDがシグナルラインを上から下にクロスした状態を意味し、下降トレンドに入ったことを示唆しています。
- 最後に、MACDの現在値が指定されたクローズレベル(m_macd_close_level)を超えているかを確認します。これにより、十分なトレンド強度があるかを判断します。
ポジションのクローズ処理
- クローズ条件がすべて満たされた場合、PositionCloseメソッドを呼び出し、シンボルに関連付けられたロングポジションをクローズします。
- クローズが成功した場合は「Long position by シンボル名 to be closed」というメッセージを出力し、resにtrueを代入します。
- クローズが失敗した場合は「Error closing position by シンボル名 : エラーメッセージ」の形式でエラーメッセージを出力します。
クローズ結果の返却
- 最後に、クローズ処理が実行されたかどうかを示すresの値を返します。
サンプルコード解説10:ShortClosedメソッドの処理記述部分
//+------------------------------------------------------------------+
//| ショートポジションのクローズ確認 |
//+------------------------------------------------------------------+
bool CSampleExpert::ShortClosed(void)
{
bool res = false;
//--- クローズ条件の確認
if(m_macd_current < 0)
if(m_macd_current > m_signal_current && m_macd_previous < m_signal_previous)
if(MathAbs(m_macd_current) > m_macd_close_level)
{
//--- ポジションのクローズ
if(m_trade.PositionClose(Symbol()))
printf("Short position by %s to be closed", Symbol()); // クローズ成功メッセージ出力
else
printf("Error closing position by %s : '%s'", Symbol(), m_trade.ResultComment()); // エラーメッセージ出力
res = true; // クローズ処理完了
}
//--- 結果を返す
return(res);
}
ShortClosedメソッドは、現在のショートポジション(売りポジション)をクローズする条件が整っているかを確認し、条件が満たされた場合にクローズを実行するメソッドです。クローズが成功した場合にはtrueを返し、失敗した場合やクローズ条件を満たしていない場合にはfalseを返します。
処理内容
クローズ条件の確認
- まず、現在のMACD値が0より小さいことを確認します。この条件により、下降トレンドが発生している可能性があることを示唆します。
- 次に、MACDの現在の値がシグナルの現在値よりも大きく、また前回のMACD値がシグナルの前回値よりも小さいことを確認します。これは、MACDがシグナルラインを下から上にクロスした状態を示し、上昇トレンドへの転換を示唆しています。
- 最後に、MACDの絶対値が指定されたクローズレベル(m_macd_close_level)を超えていることを確認します。これにより、十分なトレンド強度があることを判断します。
ポジションのクローズ処理
- クローズ条件がすべて満たされた場合、PositionCloseメソッドを呼び出して、シンボルに関連付けられたショートポジションをクローズします。
- クローズが成功した場合、「Short position by シンボル名 to be closed」というメッセージを出力し、resにtrueを代入します。
- クローズが失敗した場合は「Error closing position by シンボル名 : エラーメッセージ」の形式でエラーメッセージを出力します。
クローズ結果の返却
- 最後に、クローズ処理が実行されたかどうかを示すresの値を返します。これにより、エキスパートアドバイザーがクローズの成否を確認できるようになります。
サンプルコード解説11:LongModifiedメソッドの処理記述部分
//+------------------------------------------------------------------+
//| ロングポジションの変更確認 |
//+------------------------------------------------------------------+
bool CSampleExpert::LongModified(void)
{
bool res = false;
//--- トレーリングストップの確認
if(InpTrailingStop > 0)
{
if(m_symbol.Bid() - m_position.PriceOpen() > m_adjusted_point * InpTrailingStop)
{
double sl = NormalizeDouble(m_symbol.Bid() - m_traling_stop, m_symbol.Digits()); // ストップロス価格の計算
double tp = m_position.TakeProfit(); // テイクプロフィットを取得
if(m_position.StopLoss() < sl || m_position.StopLoss() == 0.0)
{
//--- ポジションの変更
if(m_trade.PositionModify(Symbol(), sl, tp))
printf("Long position by %s to be modified", Symbol()); // 変更成功メッセージ出力
else
{
printf("Error modifying position by %s : '%s'", Symbol(), m_trade.ResultComment()); // エラーメッセージ出力
printf("Modify parameters : SL=%f,TP=%f", sl, tp); // エラー詳細出力
}
res = true; // 変更処理完了
}
}
}
//--- 結果を返す
return(res);
}
LongModifiedメソッドは、現在のロングポジション(買いポジション)に対してトレーリングストップを適用し、ポジションのストップロスやテイクプロフィットレベルを更新するかどうかを確認し、必要があれば更新を実行するメソッドです。ポジションが変更された場合にはtrueを返し、変更がなければfalseを返します。
処理内容
- トレーリングストップの設定確認
- トレーリングストップの設定(InpTrailingStop)が0より大きいかを確認します。トレーリングストップが設定されていない場合は、この処理をスキップします。
価格変動の確認
- 現在の買い価格(Bid)がポジションのオープン価格よりも指定されたトレーリングストップの範囲(m_adjusted_point * InpTrailingStop)だけ有利な方向に進んでいるかを確認します。これにより、価格が十分に有利な方向に進んだ際にストップロスの更新を行います。
ストップロスとテイクプロフィットの計算
- 新しいストップロス価格(sl)を、現在のBid価格からトレーリングストップレベル分引いた値として計算します。この計算は、NormalizeDouble関数で小数点以下の桁数に対応して調整されています。
- 現在のテイクプロフィット(tp)も取得しておきます。
ストップロス更新条件の確認
- 既存のストップロス値(m_position.StopLoss)が新しいストップロス値(sl)よりも低い、もしくはストップロスが未設定(0.0)の場合、ポジションの変更が必要と判断します。
ポジションの変更実行
- 上記の条件が満たされた場合、PositionModifyメソッドを使用して、現在のシンボルのロングポジションに対して新しいストップロス(sl)とテイクプロフィット(tp)を設定します。
- 変更が成功した場合には、「Long position by シンボル名 to be modified」という成功メッセージを出力し、resにtrueを代入します。
- 変更が失敗した場合には、「Error modifying position by シンボル名 : エラーメッセージ」とともにエラー詳細(ストップロスとテイクプロフィットの値)を出力します。
変更結果の返却
- 最後に、ポジションが変更されたかどうかを示すresの値を返します。これにより、エキスパートアドバイザーが変更の成否を確認し、次の処理を適切に進められるようになります。
サンプルコード解説12:ShortModifiedメソッドの処理記述部分
//+------------------------------------------------------------------+
//| ショートポジションの変更確認 |
//+------------------------------------------------------------------+
bool CSampleExpert::ShortModified(void)
{
bool res = false;
//--- トレーリングストップの確認
if(InpTrailingStop > 0)
{
if((m_position.PriceOpen() - m_symbol.Ask()) > (m_adjusted_point * InpTrailingStop))
{
double sl = NormalizeDouble(m_symbol.Ask() + m_traling_stop, m_symbol.Digits()); // ストップロス価格の計算
double tp = m_position.TakeProfit(); // テイクプロフィットを取得
if(m_position.StopLoss() > sl || m_position.StopLoss() == 0.0)
{
//--- ポジションの変更
if(m_trade.PositionModify(Symbol(), sl, tp))
printf("Short position by %s to be modified", Symbol()); // 変更成功メッセージ出力
else
{
printf("Error modifying position by %s : '%s'", Symbol(), m_trade.ResultComment()); // エラーメッセージ出力
printf("Modify parameters : SL=%f,TP=%f", sl, tp); // エラー詳細出力
}
res = true; // 変更処理完了
}
}
}
//--- 結果を返す
return(res);
}
ShortModifiedメソッドは、現在のショートポジション(売りポジション)に対してトレーリングストップを適用し、ポジションのストップロスやテイクプロフィットレベルを更新するかどうかを確認し、必要があれば更新を実行するメソッドです。ポジションが変更された場合にはtrueを返し、変更がなければfalseを返します。
処理内容
トレーリングストップの設定確認
- トレーリングストップの設定(InpTrailingStop)が0より大きいかを確認します。トレーリングストップが設定されていない場合は、この処理をスキップします。
価格変動の確認
- 現在の売り価格(Ask)がポジションのオープン価格よりも指定されたトレーリングストップの範囲(m_adjusted_point * InpTrailingStop)だけ有利な方向に進んでいるかを確認します。これにより、価格が十分に有利な方向に進んだ際にストップロスの更新を行います。
ストップロスとテイクプロフィットの計算
- 新しいストップロス価格(sl)を、現在のAsk価格にトレーリングストップレベルを足した値として計算します。この計算は、NormalizeDouble関数を用いて小数点以下の桁数に対応して調整されています。
- 現在のテイクプロフィット(tp)も取得しておきます。
ストップロス更新条件の確認
- 既存のストップロス値(m_position.StopLoss)が新しいストップロス値(sl)よりも高い、もしくはストップロスが未設定(0.0)の場合、ポジションの変更が必要と判断します。
ポジションの変更実行
- 上記の条件が満たされた場合、PositionModifyメソッドを使用して、現在のシンボルのショートポジションに対して新しいストップロス(sl)とテイクプロフィット(tp)を設定します。
- 変更が成功した場合には、「Short position by シンボル名 to be modified」という成功メッセージを出力し、resにtrueを代入します。
- 変更が失敗した場合には「Error modifying position by シンボル名 : エラーメッセージ」とともに、エラー詳細(ストップロスとテイクプロフィットの値)を出力します。
変更結果の返却
- 最後に、ポジションが変更されたかどうかを示すresの値を返します。これにより、エキスパートアドバイザーが変更の成否を確認し、次の処理を適切に進められるようになります。
サンプルコード解説13:LongOpenedメソッドの処理記述部分
//+------------------------------------------------------------------+
//| ロングポジションのオープン確認 |
//+------------------------------------------------------------------+
bool CSampleExpert::LongOpened(void)
{
bool res = false;
//--- ロングポジション(買い)のオープン条件を確認
if(m_macd_current < 0)
if(m_macd_current > m_signal_current && m_macd_previous < m_signal_previous)
if(MathAbs(m_macd_current) > m_macd_open_level && m_ema_current > m_ema_previous)
{
double price = m_symbol.Ask(); // 現在の買い価格を取得
double tp = m_symbol.Bid() + m_take_profit; // テイクプロフィット価格を計算
//--- フリーマージンの確認
if(m_account.FreeMarginCheck(Symbol(), ORDER_TYPE_BUY, InpLots, price) < 0.0)
printf("We have no money. Free Margin = %f", m_account.FreeMargin()); // フリーマージンが不足している場合
else
{
//--- ポジションをオープン
if(m_trade.PositionOpen(Symbol(), ORDER_TYPE_BUY, InpLots, price, 0.0, tp))
printf("Position by %s to be opened", Symbol()); // オープン成功メッセージ出力
else
{
printf("Error opening BUY position by %s : '%s'", Symbol(), m_trade.ResultComment()); // エラーメッセージ出力
printf("Open parameters : price=%f,TP=%f", price, tp); // エラー詳細出力
}
}
res = true; // 処理完了
}
//--- 結果を返す
return(res);
}
LongOpenedメソッドは、ロングポジション(買いポジション)のオープン条件が満たされているかを確認し、条件が満たされた場合に新規ポジションをオープンするためのメソッドです。このメソッドでは、MACDやEMAなどのインジケータをもとに、ロングポジションを開くべきかどうかの判断が行われます。ポジションがオープンされた場合にはtrueを返し、オープンされなかった場合はfalseを返します。
処理内容
ロングポジションのオープン条件の確認
- 現在のMACD値が0未満であることを確認し、下降している可能性をチェックします。
- MACDの現在値がシグナルの現在値よりも大きく、前回のMACD値がシグナルの前回値よりも小さいことを確認します。これは、MACDがシグナルラインを下から上にクロスしたことを示し、上昇トレンドへの転換を意味します。
- また、MACDの絶対値が指定されたオープンレベル(m_macd_open_level)を超えており、現在のEMAが前回のEMAを上回っているかを確認します。これにより、トレンドが十分な強さを持っていることを判断します。
価格の取得とテイクプロフィットの設定
- 現在の買い価格(Ask)を取得し、ポジションのエントリープライスとして使用します。
- テイクプロフィット価格(tp)を、現在の売り価格(Bid)にm_take_profitを加えた値として計算します。
必要証拠金の確認
- FreeMarginCheckメソッドで、ロングポジションをオープンするために必要証拠金(フリーマージン)が十分にあるかを確認します。
- 必要証拠金が不足している場合、「We have no money. Free Margin = フリーマージンの値」というエラーメッセージを出力し、ポジションをオープンせず処理を終了します。
ポジションのオープン実行
- 必要証拠金が十分にある場合、PositionOpenメソッドを使用してロングポジションをオープンします。ポジションの価格、ロット数、テイクプロフィットを設定し、ストップロスは0.0で指定されています。
- オープンが成功した場合、「Position by シンボル名 to be opened」という成功メッセージを出力し、resにtrueを代入します。
- オープンが失敗した場合は「Error opening BUY position by シンボル名 : エラーメッセージ」の形式でエラーメッセージを出力し、ポジションをオープンしなかった理由を示します。
オープン結果の返却
- 最後に、ポジションがオープンされたかどうかを示すresの値を返します。これにより、エキスパートアドバイザーがポジションのオープン状況を確認し、次の処理を適切に進められるようになります。
サンプルコード解説14:ShortOpenedメソッドの処理記述部分
//+------------------------------------------------------------------+
//| ショートポジションのオープン確認 |
//+------------------------------------------------------------------+
bool CSampleExpert::ShortOpened(void)
{
bool res = false;
//--- ショートポジション(売り)のオープン条件を確認
if(m_macd_current > 0)
if(m_macd_current < m_signal_current && m_macd_previous > m_signal_previous)
if(m_macd_current > m_macd_open_level && m_ema_current < m_ema_previous)
{
double price = m_symbol.Bid(); // 現在の売り価格を取得
double tp = m_symbol.Ask() - m_take_profit; // テイクプロフィット価格を計算
//--- フリーマージンの確認
if(m_account.FreeMarginCheck(Symbol(), ORDER_TYPE_SELL, InpLots, price) < 0.0)
printf("We have no money. Free Margin = %f", m_account.FreeMargin()); // フリーマージンが不足している場合
else
{
//--- ポジションをオープン
if(m_trade.PositionOpen(Symbol(), ORDER_TYPE_SELL, InpLots, price, 0.0, tp))
printf("Position by %s to be opened", Symbol()); // オープン成功メッセージ出力
else
{
printf("Error opening SELL position by %s : '%s'", Symbol(), m_trade.ResultComment()); // エラーメッセージ出力
printf("Open parameters : price=%f,TP=%f", price, tp); // エラー詳細出力
}
}
res = true; // 処理完了
}
//--- 結果を返す
return(res);
}
ShortOpenedメソッドは、ショートポジション(売りポジション)のオープン条件が満たされているかを確認し、条件が満たされた場合に新規ポジションをオープンするためのメソッドです。このメソッドでは、MACDやEMAなどのインジケータをもとに、ショートポジションを開くべきかどうかの判断が行われます。ポジションがオープンされた場合にはtrueを返し、オープンされなかった場合はfalseを返します。
処理内容
ショートポジションのオープン条件の確認
- 現在のMACD値が0より大きいことを確認し、上昇している可能性をチェックします。
- MACDの現在値がシグナルの現在値よりも小さく、前回のMACD値がシグナルの前回値よりも大きいことを確認します。これは、MACDがシグナルラインを上から下にクロスしたことを示し、下降トレンドへの転換を意味します。
- また、MACDの現在値が指定されたオープンレベル(m_macd_open_level)を超えており、現在のEMAが前回のEMAを下回っているかを確認します。これにより、トレンドが十分な強さを持っていることを判断します。
価格の取得とテイクプロフィットの設定
- 現在の売り価格(Bid)を取得し、ポジションのエントリープライスとして使用します。
- テイクプロフィット価格(tp)を、現在の買い価格(Ask)からm_take_profitを引いた値として計算します。
必要証拠金の確認
- FreeMarginCheckメソッドで、ショートポジションをオープンするために必要な証拠金が十分にあるかを確認します。
- 必要証拠金が不足している場合、「We have no money. Free Margin = 必要証拠金の値」というエラーメッセージを出力し、ポジションをオープンせず処理を終了します。
ポジションのオープン実行
- 必要証拠金が十分にある場合、PositionOpenメソッドを使用してショートポジションをオープンします。ポジションの価格、ロット数、テイクプロフィットを設定し、ストップロスは0.0で指定されています。
- オープンが成功した場合、「Position by シンボル名 to be opened」という成功メッセージを出力し、resにtrueを代入します。
- オープンが失敗した場合は「Error opening SELL position by シンボル名 : エラーメッセージ」の形式でエラーメッセージを出力し、ポジションをオープンしなかった理由を示します。
オープン結果の返却
- 最後に、ポジションがオープンされたかどうかを示すresの値を返します。これにより、エキスパートアドバイザーがポジションのオープン状況を確認し、次の処理を適切に進められるようになります。
サンプルコード解説15:Processingメソッドの処理記述部分
//+------------------------------------------------------------------+
//| メイン処理関数:ポジションが処理された場合にtrueを返す |
//+------------------------------------------------------------------+
bool CSampleExpert::Processing(void)
{
//--- レート情報の更新
if(!m_symbol.RefreshRates())
return(false);
//--- インジケータの更新確認
if(BarsCalculated(m_handle_macd) < 2 || BarsCalculated(m_handle_ema) < 2)
return(false);
if(CopyBuffer(m_handle_macd, 0, 0, 2, m_buff_MACD_main) != 2 ||
CopyBuffer(m_handle_macd, 1, 0, 2, m_buff_MACD_signal) != 2 ||
CopyBuffer(m_handle_ema, 0, 0, 2, m_buff_EMA) != 2)
return(false);
//--- データを内部変数に格納
m_macd_current = m_buff_MACD_main[0];
m_macd_previous = m_buff_MACD_main[1];
m_signal_current = m_buff_MACD_signal[0];
m_signal_previous = m_buff_MACD_signal[1];
m_ema_current = m_buff_EMA[0];
m_ema_previous = m_buff_EMA[1];
//--- 既存ポジションの有無を確認
if(m_position.Select(Symbol()))
{
if(m_position.PositionType() == POSITION_TYPE_BUY)
{
//--- ロングポジションのクローズまたは変更を確認
if(LongClosed())
return(true);
if(LongModified())
return(true);
}
else
{
//--- ショートポジションのクローズまたは変更を確認
if(ShortClosed())
return(true);
if(ShortModified())
return(true);
}
}
else
{
//--- ロングポジションのオープン確認
if(LongOpened())
return(true);
//--- ショートポジションのオープン確認
if(ShortOpened())
return(true);
}
//--- ポジションが処理されなかった場合
return(false);
}
Processingメソッドは、エキスパートアドバイザーのメイン処理を担うメソッドで、ポジションのクローズや変更、あるいは新規ポジションのオープンといった取引に関わる操作を実行します。各処理が成功した場合にはtrueを返し、処理が行われなかった場合にはfalseを返します。
まず、レート情報が最新の状態であるかを確認し、必要であればm_symbol.RefreshRatesメソッドで更新します。次に、インジケータのデータが最新かどうかをBarsCalculated関数で確認し、MACDやEMAインジケータのバッファが有効なデータを持っているかをCopyBuffer関数でチェックします。これらの確認がすべて成功した場合、インジケータのデータを内部変数に格納します。具体的には、m_macd_currentやm_macd_previousなどに現在のMACD値やシグナル値、EMA値が格納されます。
次に、現在のポジションを確認し、m_position.Selectメソッドで指定シンボルのポジションが存在するかをチェックします。ロングポジションが存在する場合は、LongClosedメソッドでクローズの条件が整っているか、LongModifiedメソッドで変更の条件が整っているかを確認し、いずれかの操作が実行された場合にはtrueを返します。ショートポジションが存在する場合も同様に、ShortClosedメソッドでクローズを、ShortModifiedメソッドで変更を確認します。
ポジションが存在しない場合は、LongOpenedメソッドでロングポジションを、ShortOpenedメソッドでショートポジションを開く条件が満たされているかを確認し、いずれかが成功した場合にはtrueを返します。
最後に、いずれのポジション操作も行われなかった場合にはfalseを返し、処理が終了します。このように、Processingメソッドは現在の相場やインジケータの状況に基づいて、ポジションのクローズ、変更、新規オープンを一括して管理しています。
サンプルコード解説16:OnInit関数部分
//+------------------------------------------------------------------+
//| エキスパート初期化関数 |
//+------------------------------------------------------------------+
int OnInit(void)
{
//--- エキスパートオブジェクトの初期化
if(!ExtExpert.Init())
return(INIT_FAILED); // 初期化失敗時にエキスパートの開始をキャンセル
//--- 初期化成功
return(INIT_SUCCEEDED); // 正常に初期化が完了したことを示す
}
OnInit関数は、エキスパートアドバイザーの初期化を行うための関数で、プログラム開始時に一度だけ実行されます。この関数内でエキスパートアドバイザーの主要オブジェクト(CSampleExpertクラスのインスタンス)であるExtExpertの初期化処理が行われ、エキスパートアドバイザーが正常に稼働できる状態に設定されます。
関数の最初では、ExtExpert.Initメソッドが呼び出されます。Initメソッドが成功しなかった場合には、OnInit関数はINIT_FAILEDを返し、エキスパートアドバイザーの起動がキャンセルされます。このようにして、エラーが発生した状態での稼働を防止し、安定した動作を確保します。
初期化が成功した場合には、INIT_SUCCEEDEDを返して初期化が完了したことを示します。これにより、エキスパートアドバイザーが稼働を開始し、次の処理(ティック更新ごとに呼ばれるOnTick関数など)へ進む準備が整います。
OnInit関数は、エキスパートアドバイザーが起動するための重要な初期チェックと設定を行う役割を持ち、エキスパートアドバイザー全体の動作基盤を確保する機能を果たしています。
サンプルコード解説17:OnTick関数部分
//+------------------------------------------------------------------+
//| エキスパートティック関数 |
//+------------------------------------------------------------------+
void OnTick(void)
{
static datetime limit_time = 0; // 最後の取引処理時間とタイムアウトを保持
//--- タイムアウトが経過しているか確認
if(TimeCurrent() >= limit_time)
{
//--- データが十分であることを確認
if(Bars(Symbol(), Period()) > 2 * InpMATrendPeriod)
{
//--- 処理が行われた場合は次のタイムアウト時間を設定
if(ExtExpert.Processing())
limit_time = TimeCurrent() + ExtTimeOut; // 次回の処理をタイムアウト設定に基づき遅延
}
}
}
//+------------------------------------------------------------------+
OnTick関数は、エキスパートアドバイザーがティックごとに呼び出される関数で、価格更新のたびに実行されます。この関数では、エキスパートアドバイザーの取引ロジックが実行され、ポジションの管理や新規ポジションのエントリーが行われます。
関数内では、limit_timeという静的なdateTime型の変数を使って、最後の取引処理時間を保持しています。これにより、処理の実行を指定したタイムアウト時間ごとに制限することができます。
最初に、現在の時間がlimit_timeを超えているかを確認し、タイムアウトが経過していれば処理を開始します。次に、チャート上のデータが十分であるかを確認し、Bars関数を用いて足(ローソク足)の数が2倍のInpMATrendPeriod以上であることをチェックします。このチェックがクリアされた場合にのみ、以下の処理が続行されます。
続けて、ExtExpert.Processingメソッドを呼び出してメインの取引ロジックを実行します。このメソッドがtrueを返した場合、limit_timeを更新し、次回の処理を指定したタイムアウト(ExtTimeOut)分遅延させます。このように、OnTick関数は一定のインターバルを設けながら取引ロジックを実行するため、無駄な処理を避け、効率的に取引判断を行います。
OnTick関数は、エキスパートアドバイザーの実行サイクルを管理し、タイムアウトとデータチェックを活用して、正確で安定した取引処理を提供する役割を果たしています。
「MACD Sample」EAの仕様まとめ
最後に、今回解説した「MACD Sample」EAの仕様をまとめておきます。
このEAは以下の戦略を実行するよう設計されています。
エントリー条件
- ロングポジション(買い)エントリー条件
- ショートポジション(売り)エントリー条件
クローズ条件
- ロングポジションのクローズ条件
- ショートポジションのクローズ条件
ポジションの変更(トレーリングストップ機能)
- ロングポジションのトレーリングストップ
- 現在の価格(Bid)がエントリー価格から設定されたトレーリングストップレベル以上に達した場合、ストップロスを更新。
- ショートポジションのトレーリングストップ
- 現在の価格(Ask)がエントリー価格から設定されたトレーリングストップレベル以上に達した場合、ストップロスを更新。
その他の機能
- タイムアウト設定:取引ロジックは指定されたタイムアウト(秒)ごとに実行し、頻繁な処理を防ぎ、リソースの効率化を図る。
- インジケータの利用:MACDとEMAを用いて取引シグナルを判断。
- 必要証拠金のチェック:エントリー前に証拠金が不足していないかを確認し、リスク管理を行う。
- エラー管理:ポジションオープンやクローズ、変更が失敗した場合にエラーメッセージを出力し、トレードの正確性を確保。
パラメータ設定
- InpLots:エントリー時のロット数。
- InpTakeProfit:テイクプロフィットの設定値。
- InpTrailingStop:トレーリングストップの設定値。
- InpMACDOpenLevel:MACDのエントリーレベル。
- InpMACDCloseLevel:MACDのクローズレベル。
- InpMATrendPeriod:EMAのトレンド期間。