——————
前回は、指定期間における「最高値」「最安値」の取得方法について解説しました。
直近高値・直近安値の取得方法については大きく分けて、
1:iHighest関数やiLowest関数を使って取得する方法
2:ArrayMaximum関数やArrayMinimum関数を使って取得する方法
の2パターンがあることを伝えた上で、前回の記事では2の方法であるArrayMaximum関数及びArrayMinimum関数を使った最高値・最安値取得手順について主に解説を行いました。
※1の方法については講座記事第81回をご覧ください。
実際の取得手順については↓
前回の記事の、
「ArrayMaximum関数を使った最高値の取得手順」セクション
「ArrayMinimum関数を使った最安値の取得手順」セクション
をそれぞれご覧ください。
そして、上記のセクションにてArrayMaximum関数及びArrayMinimum関数を使ったノーマルな最高値・最安値取得手順をお伝えした上で、より手順を簡略化できる、
という2つのオリジナル関数を作り、 「OriginalPrice.mqh」ファイル内に追加しました。
※HighestHigh関数、LowestLow関数の追加に伴う、講座記事第106回時点での「OriginalPrice.mqh」ファイルのソースコード全容は↓のリンク記事にて確認できます。
・講座記事第106回時点でのOriginalPrice.mqhファイル全体のコード記述について
——————————————-
今回は「価格情報からトレードシグナルを生成する」というトピックで解説をしていきたいと思います。
トレードシグナルとは?
トレードシグナルというと大仰な言い方になりますが、要はエントリー条件の事です。
EAはとどのつまり「こうなったら、買う・売る」という事を指示するだけのプログラムです。
今回の記事はその「こうなったら、買う・売る」という部分を、相場の価格情報に焦点を絞って考察していこうという回になります。
確定足の動きを見てエントリーシグナルを生成する
相場の価格情報に焦点を絞って、トレードシグナルを考察する一つの例として
確定足の動きを見て、トレードシグナルを生成する、というEA開発のアプローチ方法があります。
確定足とは?→現在足よりも過去のローソク足の事。
ここで確定足について簡単に説明しておきたいと思います。
確定足とは現在足ではない足、現在足よりも過去のローソク足の事を指します。
終値情報を取得する関数ですが、この関数の第3引数には終値を取得する位置を指定します。
終値のデータは、最新のデータが0番に格納され、時間軸が古い方に向かって、1.2.3・・・n番目と並んでいます。
従って、最新足の終値を取得したい場合はこの第3引数に「0」と記述する、という事はiClose関数の所で説明しました。(最新足の終値=リアルタイムで動いている値、という事です)
言い換えればiClose関数の第3引数で0より大きい値を指定した場合は、過去の終値、すなわち確定足を取得しているという事になります。
例えば以下のような記述をした場合↓なのですが、
//一本前の確定足を取得する
double close=iClose(_Symbol,0,1);
第3引数に「1」を指定しているので、1本前の確定足を取得してdouble型の変数「close」に代入している、という意味合いになります。
※図にすると↓のような関係になります。
68-69回で作ったEAの売買条件に確定足の要素を反映させてみる
確定足という言葉についての確認をしたところで、今度は確定足を売買条件にどのように反映させるか、という部分を見ていきたいと思います。
例えば、
にてEAを作った訳ですが、このEAの売買条件は、現在値と単純移動平均(SMA)の現在足との関係で決定されていました。
この回で作ったEAの売買条件は
<買い条件>
現在値が単純移動平均(SMA)を上回っていて、ポジション数が0の時にエントリーする
<売り条件>
現在値が単純移動平均(SMA)を下回っていて、ポジション数が0の時にエントリーする
というものでした。
この売買条件のコード箇所を改めて見ていくと
<買い条件>
// 買いの注文に関する記述
if(close> sma[0] && BuyPosition == false)
<売り条件>
//売り注文に関する記述
if(close <sma[0] && SellPosition== false)
となっています。
※第68-69回で作ったEAのコード全体を見たい方はコチラのリンクをクリックしてください。
この時作ったEAは現在のSMAの値と、価格の現在値(=リアルタイムで動いている価格値)との比較で売買条件を決定していました。
確定足と相場原則の関係性について
EAの開発にはいろんな考え方があります。従って、
68–69回の時に作ったEAの、「単純移動平均(SMA)の現在の値と、価格の現在値を比較する」というエントリー条件自体が悪いという訳ではありませんが、
その一方で相場にはいくつかの原理原則(とされるもの)があります。
そのうちの1つに
確定足の終値には相場における一定の合意形成がある。
という考え方があります。
例えば、
・日足チャートにおける直近高値をリアルタイム値で一時的に上抜けても、その後価格が押し戻されて直近高値を下回る価格で終値を迎えた場合、「直近高値を上抜けた」という合意形成の度合いは薄い→上昇トレンドはまだ開始していない。
一方で、
・日足チャートにおける直近高値をリアルタイム値で一時的に上抜けて、そのまま直近高値を上回る価格で終値を迎えた場合、「直近高値を上抜けた」という合意形成の度合いは濃い→上昇トレンドの開始である。
という相場観です。
EAを適用するチャートの時間軸によっても、その合意形成の有効度合いには差があるかと思いますし、そもそもこの原理原則自体に優位性があるかどうか、という議論はあるかと思いますが、一旦その議論は置いておきましょう。
確定足をエントリー条件に落とし込むためのロードマップ
それでは、この
確定足の終値には一相場における一定の合意形成がある。
という考えをEAに反映させるにはどうすればよいでしょうか?
以下の売買条件をEAの仕様に組み込むとします。
<買い条件>
2本前の確定足の終値は2本前の単純移動平均(SMA)を下回っているが、1本前の確定足の終値は1本前の単純移動平均(SMA)を上回っている。
※図にすると以下のような状態になります。
<売り条件>
2本前の確定足の終値は2本前の単純移動平均(SMA)を上回っているが、1本前の確定足の終値は1本前の単純移動平均(SMA)を下回っている。
※図にすると以下のような状態になります。
この売買条件は先程説明した、
確定足の終値には相場における一定の合意形成がある。
という前提に従ったものになります。
すなわち、
<買いの場合>
2本前の確定足では単純移動平均(SMA)の下に終値価格が位置していたが、1本前の確定足では単純移動平均(SMA)の上に終値価格が位置している→上昇トレンドに転じたと判断し現在足のオープン価格で買いエントリー。
<売りの場合>
2本前の確定足では単純移動平均(SMA)の上に終値価格が位置していたが、1本前の確定足では単純移動平均(SMA)の下に終値価格が位置している→下落トレンドに転じたと判断し現在足のオープン価格で売りエントリー。
という相場判断になります。
確定足を加味したエントリー条件をMQL5のコードに落とし込む
これをMQL5のコードに落とし込むと以下のようになります。
※記述方法は他にもいくつかある訳ですが、今回は第105回で解説したCopyClose関数を用いた方法で記述してみたいと思います。
まずは必要な値を取得する記述です。
// 単純移動平均の値取得
//単純移動平均の値を格納する配列宣言
double sma[];
//配列を時系列にセット
ArraySetAsSeries(sma,true);
//単純移動平均のハンドルを取得
int smaHandle=iMA(_Symbol,0,MAPeriod,MODE_SMA,0,PRICE_CLOSE);
///単純移動平均の値を配列にコピー
CopyBuffer(smaHandle,0,0,1,sma);
//価格情報を格納する配列を用意
double close[];
//配列を時系列にセット
ArraySetAsSeries(close,true);
//始値情報を配列にコピー
CopyClose(_Symbol,_Period,0,10,close);
以上の記述を行い、まずは単純移動平均(SMA)の値と、終値情報を取得する必要があります。
SMAの値を取得する手順
単純移動平均(SMA)の値を取得するには
・単純移動平均(SMA)の値を格納する配列の用意
・ArraySetAsSeries関数による配列の時系列セット
・iMA関数による移動平均線のハンドル(移動平均線の値を取得する為のカギみたいなもの)の取得
・CopyBuffer関数により、単純移動平均(SMA)の値を配列にコピー
という手順を踏みます。
※ArraySetAsSeries関数についてはコチラのリンクをご参照ください。
※CopyBuffer関数についてはコチラのリンクをご参照ください。
※また、移動平均線自体の詳しい解説は↓の記事で行っていますので、移動平均線についての理解を深めたい方はご覧ください。
終値情報を取得する手順
続いて、終値情報の取得についてですが、
・終値の値を格納する配列の用意
・ArraySetAsSeries関数による配列の時系列セット
・CopyClose関数により終値情報を配列にコピー
という手順を踏みます。
※CopyClose関数についてはコチラのリンクをご参照ください。
※Copy~関数の基本的な使い方についてはコチラのリンクをご参照ください。
取得した値を使って、エントリー条件を記述する
以上のプロセスを経て、単純移動平均(SMA)の値と終値の値を配列に格納できた所でエントリー条件を記述します。
<買いの場合>
// 買いの注文に関する記述
if(close[1]> sma[1] &&close[2]<= sma[2] )
上記のif文は
「1本前の終値は1本前の単純移動平均(SMA)より高く、2本前の終値は2本前の単純移動平均(SMA)より低い」
と読み解けます。
<売りの場合>
// 売りの注文に関する記述
if(close[1]< sma[1] &&close[2]>= sma[2] )
上記のif文は
「1本前の終値は1本前の単純移動平均(SMA)より低く、2本前の終値は2本前の単純移動平均(SMA)より高い」
と読み解けます。
68–69回で作ったEAの、エントリー条件文を上記の記述に切り替える事で、確定足の相場状況を加味したエントリーを実装する事ができました。
68–69回で作ったEAのエントリー条件の部分を変更したEAの挙動は以下の通りです。
エントリー条件を変更したEAのコード全体記述は以下の通りです。
//+------------------------------------------------------------------+
//| testEA5.mq5 |
//| MQL5ssei |
//| https://mqlinvestmentlab.com/ |
//+------------------------------------------------------------------+
#property copyright "MQL5ssei"
#property link "https://mqlinvestmentlab.com/"
#property version "1.00"
//OriginalTrade.mqhファイルを呼び出す
#include <OriginalTrade.mqh>
//トレード用のクラス「OriginalCTrade」のインスタンスを生成する
OriginalCTrade Trade;
//必要なパラメータ
input double Volume=0.1;//ロット数
input int SL=200;//ストップロス
input int TP=200;//テイクプロフィット
input int MAPeriod = 20;//移動平均期間
input int Deviation=50;//スリッページ
input int Magic=1234;//マジックナンバー
//直近の注文状況をチェックするグローバル変数
bool BuyPosition, SellPosition;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
ENUM_ACCOUNT_TRADE_MODE tradeMode=(ENUM_ACCOUNT_TRADE_MODE)AccountInfoInteger(ACCOUNT_TRADE_MODE);
if(tradeMode != ACCOUNT_TRADE_MODE_DEMO) // デモ口座以外の場合
{
MessageBox("このEAはデモ口座でのみ稼働します","口座エラー");
return INIT_FAILED; // 処理終了
}
//適切なフィルポリシーを格納する変数を宣言
ENUM_ORDER_TYPE_FILLING filltype=FillPolicy();
//マジックナンバーを返す関数を呼び出す
Trade.SetMagicNumber(Magic);
//スリッページを返す関数を呼び出す
Trade.SetDeviation(Deviation);
//フィルポリシーを設定する関数を呼び出す
Trade.SetFillType(filltype);
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//インスタンスの生成
MqlTradeRequest request;
MqlTradeResult result;
//構造体の初期化
ZeroMemory(request);
// ZeroMemory(result);
//フィルポリシーを設定する。
request.type_filling=FillPolicy();
// 単純移動平均の値取得
//単純移動平均の値を格納する配列宣言
double sma[];
//配列を時系列にセット
ArraySetAsSeries(sma,true);
//単純移動平均のハンドルを取得
int smaHandle=iMA(_Symbol,0,MAPeriod,MODE_SMA,0,PRICE_CLOSE);
///単純移動平均の値を配列にコピー
CopyBuffer(smaHandle,0,0,10,sma);
//終値情報の取得
//の値を格納する配列宣言
double close[];
// double close=iClose(NULL,0,0);
//配列を時系列にセット
ArraySetAsSeries(close,true);
//終値情報の値を配列にコピー
CopyClose(_Symbol,0,0,10,close);
// ポジション状況の確認とポジション番号の取得
//買いポジションと売りポジションのチケット番号を格納する変数を宣言
ulong buyPosNum = 0, sellPosNum = 0;
for(int i = 0; i < PositionsTotal(); i++)
{
ulong ticketNum = PositionGetTicket(i);
PositionSelectByTicket(ticketNum);
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
buyPosNum = ticketNum;
BuyPosition = true;
}//if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
else
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
{
sellPosNum = ticketNum;
SellPosition = true;
}// else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
}//for(int i = 0; i < PositionsTotal(); i++)
// 買いの注文に関する記述
if(close[1]> sma[1] &&close[2]<= sma[2] && BuyPosition == false)
{
// 売りポジションがあれば決済する。
if(sellPosNum > 0)
{
PositionSelectByTicket(sellPosNum);
request.action = TRADE_ACTION_DEAL;
request.type = ORDER_TYPE_BUY;
request.symbol = _Symbol;
request.position = sellPosNum;
request.volume = PositionGetDouble(POSITION_VOLUME);
request.price = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
request.deviation = Deviation;
bool sent = OrderSend(request, result);
}
// 買い注文を出す
buyPosNum=Trade.Buy(_Symbol,Volume);
// ストップロスとテイクプロフィットを設定する
if(buyPosNum>0)
{
request.action = TRADE_ACTION_SLTP;
request.position = buyPosNum;
PositionSelectByTicket(buyPosNum);
double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);
if(SL > 0)
request.sl = positionOpenPrice - (SL * _Point);
if(TP > 0)
request.tp = positionOpenPrice + (TP * _Point);
if(request.sl > 0 || request.tp > 0)
bool sent = OrderSend(request,result);
SellPosition = false;
}
}
//売り注文に関する記述
if(close[1]< sma[1] &&close[2]>= sma[2] && SellPosition== false)
{
// 買いポジションがあれば決済する。
if(buyPosNum > 0)
{
PositionSelectByTicket(buyPosNum);
request.action = TRADE_ACTION_DEAL;
request.type = ORDER_TYPE_SELL;
request.symbol = _Symbol;
request.position = buyPosNum;
request.volume = PositionGetDouble(POSITION_VOLUME);
request.price = SymbolInfoDouble(_Symbol,SYMBOL_BID);
request.deviation = Deviation;
bool sent = OrderSend(request, result);
}//if(buyPosNum > 0)
// 売り注文を出す
sellPosNum=Trade.Sell(_Symbol,Volume);
// ストップロスとテイクプロフィットを設定する
if(sellPosNum>0)
{
request.action = TRADE_ACTION_SLTP;
request.position = sellPosNum;
PositionSelectByTicket(sellPosNum);
double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);
if(SL > 0)
request.sl = positionOpenPrice + (SL * _Point);
if(TP > 0)
request.tp = positionOpenPrice - (TP * _Point);
if(request.sl > 0 || request.tp > 0)
bool sent = OrderSend(request,result);
BuyPosition = false;
}
}// if(close <ma[0] && SellPosition== false)
}//OnTick
//+------------------------------------------------------------------+
<参照>
OnInit関数/OnDeinit関数/AccountInfoInteger関数/MessageBox関数/ZeroMemory関数/MqlTradeRequest構造体/MqlTradeResult構造体/ArraySetAsSeries関数/iMA関数/CopyBuffer関数/PositionGetTicket関数/PositionSelectByTicket関数/PositionGetInteger関数/PositionGetDouble関数/SymbolInfoDouble関数/OrderSend関数
ローソク足の形状(キャンドルパターン)からエントリーシグナルを生成する
ここまでの内容で、確定足についての理解が深まり、確定足をエントリー条件に組み込める知識が身についたはずです。
続いては、ローソク足の形状(キャンドルパターン)からトレードシグナルを生成する方法をコード記述に落とし込んでいこうと思います。
キャンドルパターンとは?
キャンドルパターンとは、ローソク足の形状(長さなど)や、前後のローソク足との位置関係などから相場の将来を予測したり(上昇・下降トレンドの発生や継続、価格反転の可能性など)するのに使われるチャートパターンの事を指します。
長年の相場研究結果の集積から、
「ローソク足がこのような形状になれば将来の相場はこのように動く可能性が高い」
とされるものをパターン化してまとめたものになります。
これらのキャンドルパターンは基本的に
1:取得したい時間の確定足情報を適切に把握し、
2:取得したい時間の確定足における始値、終値、高値、安値などの情報を取得する
という手順を踏むことによって、
MQL5のコード記述に落とし込む事ができるようになります。
そして、それを達成するにはこれまでに学んできた、
・第103回「価格とバーに関するデータへのアクセス:その1現在値」
・第104回「価格とバーに関するデータへのアクセス:その2バー情報」
などで解説した知識を駆使していく事で比較的容易に実現する事ができます。
例えば「抱き線(包み足)」というキャンドルパターンがあります。
抱き線(包み足)とは?
抱き線(包み足)とは、
1本前のローソク足の実体部分を、直近のローソク足が包み込むような形で覆っているような形状のローソク足形状
の事を指します。図にすると以下のようになります。↓
<上昇トレンドにおける抱き線(包み足))>
<下降トレンドにおける抱き線(包み足)>
抱き線(包み足)が上昇トレンドの局面で出現すると、その相場におけ当面の天井である可能性が高く、
一方で抱き線(包み足)が下降トレンドの局面で出現すると、その相場におけ当面の底である可能性が高い
とされています。
これをMQL5のコードに落とし込むにはどうすればよいか?
この場合、まずは日本語で抱き線(包み足)の状態を構造分解して整理し、その後でコード記述に落とし込んでいくのがコツです。
例えば、現在足を基準として1本前のローソク足と2本前のローソク足との比較で、上昇トレンド局面における抱き線(包み足)の定義するとどうなるでしょうか?
箇条書きにまとめてみると以下のようになります。
・2本前のローソク足は陽線(始値より終値の方が価格が高い)
・1本前のローソク足は隠線(始値より終値の方が価格が低い)
・2本前のローソク足の始値よりも1本前のローソク足の終値が低い位置にある。
これをMQL5のコード記述に落とし込むと以下のようになります。
※CopyClose関数やCopyOpen関数を使って、配列[]close 配列[]openには正しく始値や終値の情報が時系列に沿って格納されているもの、とします。
//上昇トレンド局面における抱き線(包み足)の定義
close[2]>open[2] && close[1]<open[1] && close[1]<open[2];
それでは、下降トレンド局面における抱き線(包み足)の定義はどうすればよいか?と言えば、要所要所を上昇トレンド局面と逆に考えれば良いだけですから簡単ですね。
箇条書きにまとめてみると以下のようになります。
・2本前のローソク足は隠線(始値より終値の方が価格が低い)
・1本前のローソク足は陽線(始値より終値の方が価格が高い)
・2本前のローソク足の始値よりも1本前のローソク足の終値が高い位置にある。
これをMQL5のコード記述に落とし込むと以下のようになります。
※上昇局面の時と同様に、CopyClose関数やCopyOpen関数を使って、配列[]close 配列[]openには正しく始値や終値の情報が時系列に沿って格納されているもの、とします。
//下降トレンド局面における抱き線(包み足)の定義
close[2]<open[2] && close[1]>open[1] && close[1]>open[2];
抱き線(包み足)をEAのエントリー条件に反映させたEAの挙動は以下の通りです。
抱き線(包み足)をエントリー条件に反映させたEAのコード全体記述は以下の通りです
//+------------------------------------------------------------------+
//| testEA5.mq5 |
//| MQL5ssei |
//| https://mqlinvestmentlab.com/ |
//+------------------------------------------------------------------+
#property copyright "MQL5ssei"
#property link "https://mqlinvestmentlab.com/"
#property version "1.00"
//OriginalTrade.mqhファイルを呼び出す
#include <OriginalTrade.mqh>
//トレード用のクラス「OriginalCTrade」のインスタンスを生成する
OriginalCTrade Trade;
//必要なパラメータ
input double Volume=0.1;//ロット数
input int SL=200;//ストップロス
input int TP=200;//テイクプロフィット
input int MAPeriod = 20;//移動平均期間
input int Deviation=50;//スリッページ
input int Magic=1234;//マジックナンバー
//直近の注文状況をチェックするグローバル変数
bool BuyPosition, SellPosition;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
ENUM_ACCOUNT_TRADE_MODE tradeMode=(ENUM_ACCOUNT_TRADE_MODE)AccountInfoInteger(ACCOUNT_TRADE_MODE);
if(tradeMode != ACCOUNT_TRADE_MODE_DEMO) // デモ口座以外の場合
{
MessageBox("このEAはデモ口座でのみ稼働します","口座エラー");
return INIT_FAILED; // 処理終了
}
//適切なフィルポリシーを格納する変数を宣言
ENUM_ORDER_TYPE_FILLING filltype=FillPolicy();
//マジックナンバーを返す関数を呼び出す
Trade.SetMagicNumber(Magic);
//スリッページを返す関数を呼び出す
Trade.SetDeviation(Deviation);
//フィルポリシーを設定する関数を呼び出す
Trade.SetFillType(filltype);
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//インスタンスの生成
MqlTradeRequest request;
MqlTradeResult result;
//構造体の初期化
ZeroMemory(request);
// ZeroMemory(result);
//フィルポリシーを設定する。
request.type_filling=FillPolicy();
// 単純移動平均の値取得
//単純移動平均の値を格納する配列宣言
double sma[];
//配列を時系列にセット
ArraySetAsSeries(sma,true);
//単純移動平均のハンドルを取得
int smaHandle=iMA(_Symbol,0,MAPeriod,MODE_SMA,0,PRICE_CLOSE);
///単純移動平均の値を配列にコピー
CopyBuffer(smaHandle,0,0,10,sma);
//始値情報の取得
//始値の値を格納する配列宣言
double open[];
//配列を時系列にセット
ArraySetAsSeries(open,true);
//始値情報の値を配列にコピー
CopyOpen(_Symbol,0,0,10,open);
//終値情報の取得
//の値を格納する配列宣言
double close[];
//配列を時系列にセット
ArraySetAsSeries(close,true);
//終値情報の値を配列にコピー
CopyClose(_Symbol,0,0,10,close);
// ポジション状況の確認とポジション番号の取得
//買いポジションと売りポジションのチケット番号を格納する変数を宣言
ulong buyPosNum = 0, sellPosNum = 0;
for(int i = 0; i < PositionsTotal(); i++)
{
ulong ticketNum = PositionGetTicket(i);
PositionSelectByTicket(ticketNum);
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
buyPosNum = ticketNum;
BuyPosition = true;
}//if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
else
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
{
sellPosNum = ticketNum;
SellPosition = true;
}// else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
}//for(int i = 0; i < PositionsTotal(); i++)
// 買いの注文に関する記述
if(close[2]<open[2] && close[1]>open[1] && close[1]>open[2] && BuyPosition == false)
{
// 売りポジションがあれば決済する。
if(sellPosNum > 0)
{
PositionSelectByTicket(sellPosNum);
request.action = TRADE_ACTION_DEAL;
request.type = ORDER_TYPE_BUY;
request.symbol = _Symbol;
request.position = sellPosNum;
request.volume = PositionGetDouble(POSITION_VOLUME);
request.price = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
request.deviation = Deviation;
bool sent = OrderSend(request, result);
}
// 買い注文を出す
buyPosNum=Trade.Buy(_Symbol,Volume);
// ストップロスとテイクプロフィットを設定する
if(buyPosNum>0)
{
request.action = TRADE_ACTION_SLTP;
request.position = buyPosNum;
PositionSelectByTicket(buyPosNum);
double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);
if(SL > 0)
request.sl = positionOpenPrice - (SL * _Point);
if(TP > 0)
request.tp = positionOpenPrice + (TP * _Point);
if(request.sl > 0 || request.tp > 0)
bool sent = OrderSend(request,result);
SellPosition = false;
}
}
//売り注文に関する記述
if(close[2]>open[2] && close[1]<open[1] && close[1]<open[2] && SellPosition== false)
{
// 買いポジションがあれば決済する。
if(buyPosNum > 0)
{
PositionSelectByTicket(buyPosNum);
request.action = TRADE_ACTION_DEAL;
request.type = ORDER_TYPE_SELL;
request.symbol = _Symbol;
request.position = buyPosNum;
request.volume = PositionGetDouble(POSITION_VOLUME);
request.price = SymbolInfoDouble(_Symbol,SYMBOL_BID);
request.deviation = Deviation;
bool sent = OrderSend(request, result);
}//if(buyPosNum > 0)
// 売り注文を出す
sellPosNum=Trade.Sell(_Symbol,Volume);
// ストップロスとテイクプロフィットを設定する
if(sellPosNum>0)
{
request.action = TRADE_ACTION_SLTP;
request.position = sellPosNum;
PositionSelectByTicket(sellPosNum);
double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);
if(SL > 0)
request.sl = positionOpenPrice + (SL * _Point);
if(TP > 0)
request.tp = positionOpenPrice - (TP * _Point);
if(request.sl > 0 || request.tp > 0)
bool sent = OrderSend(request,result);
BuyPosition = false;
}
}// if(close <ma[0] && SellPosition== false)
}//OnTick
//+------------------------------------------------------------------+
※抱き線(包み足)の他にもキャンドルパターンにはたくさんの種類があります。
当サイトはMQL5のコード記述とEAへの実装方法を解説するサイトなので、キャンドルパターンの1つ1つについて説明する事は割愛させて頂きますが、
詳しい事は下記↓の外為どっとコムさんの記事などをご参照ください。
いずれにしても、ここまでの講座記事を読んできている方でしたら、特定の時間の確定足における、始値、終値、高値、安値を自在に取得できるようになっている筈です。
もし、EAのロジックに実装したいキャンドルパターンがあれば、そのキャンドルパターンをまずは日本語で分かり易い形にまずは落とし込んで、それをMQL5の記述に変換させればいいだけです。
今回の記事を読めば、だいぶ作れるEAの幅が広がってきた、と感じる方も多いのではないでしょうか?
まとめ
今回はトレードシグナル、つまりエントリー条件の生成について、相場の価格情報に焦点をあてて解説しました。
まずは確定足とはそもそも何か?という説明を行った上で、確定足をエントリー条件に加味する方法をお伝えしました。
相場の価格情報からトレードシグナルを生成するもう一つの例として、キャンドルパターンというものがある事を説明し、キャンドルパターンの1つである抱き線(包み足)をエントリー条件に追加するコード記述について解説いたしました。
今回は以上とさせていただきます。
次回からはインジケータの値を使って、トレードシグナルを生成するコード記述について解説していきます。
最終的にはインジケータの値をトレードシグナルに取り入れていくにあたり、値の取得をより簡単に行う事ができるようなオリジナルクラスをこれから作っていく予定ですので、是非楽しみながら読んで頂ければと思います。
最後までお読みいただきありがとうございました。
※トレードシグナルについては以下の記事群も参考になるかと思います↓
・ウィリアムズ%レンジ(WPR)の売買シグナルを取得する方法