改めて前回の内容をおさらいをしておくと、
- ストップレベルとは、そのSLやTPの値、待機注文の約定希望価格を設定する際に、「現在のBid値とAsk値から最低限離さなくてはいけないポイント」の事である。
- ストップレベルを守っていない、現在のBid値とAsk値から近すぎる価格は「適切ではない価格(invalid price)」として、エラーが発生する可能性がある。
- ストップレベル情報を取得するには、SymbolInfoInteger関数の第2引数に定数値「SYMBOL_TRADE_STOPS_LEVEL」を記述する。
- EAを作る際にはストップレベルに違反しないようなコード記述をプログラム内に組み込む必要がある。
ということをお伝えしました。
をOriginalTrade.mqhファイルに追加・実装していきたいと思います。
ストップレベルをチェックする関数実装のロードマップ
前回の講座記事で書いたように、ストップレベルの値は、注文する種類によって算出方法が変わってきます。
- 買い注文のTP値
- 売り注文のSL値
- 買い逆指値注文の約定希望価格
- 売り指値注文の約定希望価格
上記の価格は、要は、現在価格よりも高い価格帯を設定する時の注文です。
これらに関しては、ストップレベルの最小値 を求める必要があります。
一方で、
- 買い注文のSL値
- 売り注文のTP値
- 売り逆指値注文の約定希望価格
- 買い指値注文の約定希望価格
上記の価格は、要は、現在価格よりも低い価格帯を設定する時の注文です。
これらに関しては、ストップレベルの最大値 を求める必要があります。
従って、
ストップレベルの最小値要件を満たしているかをチェックする関数
と
ストップレベルの最大値要件を満たしているかをチェックする関数
この2つをまずは作ります。
※買い指値注文については→のORDER_TYPE_BUY_LIMITリンクをご覧ください。
※買い逆指値注文については→のORDER_TYPE_BUY_STOPリンクをご覧ください。
※売り指値注文については→のORDER_TYPE_SELL_LIMITリンクをご覧ください。
※売り逆指値注文については→のORDER_TYPE_SELL_STOPリンクをご覧ください。
※買いのストップリミット待機注文については→のORDER_TYPE_BUY_STOP_LIMITリンクをご覧ください。
※売りのストップリミット待機注文については→のORDER_TYPE_SELL_STOP_LIMITリンクをご覧ください。
ストップレベルの最小値要件を満たしているかをチェックする関数
ストップレベルの最小値をチェックする関数の概要は以下の通りです
// ストップレベルをチェックする関数(最小値)
bool CheckUpperStopLevel(string parSymbol, double parPrice, int parPoints = 10)
{ //現在値の取得
double currentPrice = SymbolInfoDouble(parSymbol,SYMBOL_ASK);
//ポイントの取得
double point = SymbolInfoDouble(parSymbol,SYMBOL_POINT);
//ストップレベル情報を取得し、価格ベースに変換
double stopLevel = SymbolInfoInteger(parSymbol,SYMBOL_TRADE_STOPS_LEVEL) * point;
//ストップレベル最小値を算出
double stopPrice = currentPrice + stopLevel;
//任意に設定・加算するポイント
double addPoints = parPoints * point;
//注文価格がストップレベルに違反していないかをチェックし、戻り値を返す
if(parPrice >= stopPrice + addPoints) return(true);
else return(false);
}
関数名は「CheckUpperStopLevel」としました。戻り値はbool型です。
CheckUpperStopLevel関数の引数構成
bool CheckUpperStopLevel(string parSymbol, double parPrice, int parPoints = 10)
parSymbolには、通貨ペア・取引銘柄、parPriceには注文する価格が入ります。第3引数のparPointsには初期値を設けてあり、省略が可能です。
引数「parPoints」は算出されたストップレベルの最小値に、値を追加する為に用います。この値を大きくすれば、ストップレベルの最小値も、上振れします(言い方を変えれば算出されたストップレベルの最小値よりもストップレベルを自身で厳しくしている、という言い方もできます)
続いて処理実装記述を見ていきましょう。
CheckUpperStopLevel関数の処理実装記述
ストップレベルの算出に必要な各種値を取得
まずはストップレベルの算出に必要な各種値を取得します。
必要な情報は、
の3つです
//現在値の取得
double currentPrice = SymbolInfoDouble(parSymbol,SYMBOL_ASK);
//ポイントの取得
double point = SymbolInfoDouble(parSymbol,SYMBOL_POINT);
//ストップレベル情報を取得し、価格ベースに変換
double stopLevel = SymbolInfoInteger(parSymbol,SYMBOL_TRADE_STOPS_LEVEL) * point;
現在値は、SymbolInfoDouble関数の第2引数にSYMBOL_ASKを記述して取得します。
ポイントは、SymbolInfoDouble関数の第2引数にSYMBOL_POINTを記述して取得します。
価格ベースに変換したストップレベル情報は、SymbolInfoInteger関数の第2引数にSYMBOL_TRADE_STOPS_LEVELを記述して取得したものに、ポイントをかけて算出します。
ストップレベル最小値の算出と任意に設定・加算するポイントの取得
//ストップレベル最小値を算出
double stopPrice = currentPrice + stopLevel;
//任意に設定・加算するポイント
double addPoints = parPoints * point;
ストップレベル最小値は、現在値Ask値+価格ベースに変換されたストップレベル情報になります。これが変数「stopPrice」に格納されます。
変数「addPoints」には、ストップレベル最小値に追加する価格ベースのポイントが格納されます。
最終的には[変数「stopPrice」 + 変数「addPoints」]の値と、第2引数parPriceの注文価格と比較して、ストップレベルに違反していないかを確認します。
注文価格がストップレベルに違反していないかをチェックし、戻り値を返す
//注文価格がストップレベルに違反していないかをチェックし、戻り値を返す
if(parPrice >= stopPrice + addPoints) return(true);
else return(false);
第2引数parPriceには注文価格が入るようになっており、先ほど「ストップレベル最小値の算出と任意に設定・加算するポイントの取得」セクションでも説明したように、stopPrice + addPointsはストップレベル最小値の最終形となる値です。
if文でparPriceの値がstopPrice + addPoints以上なら、ストップレベルに違反していないとしてtrueを返します。
逆にparPriceの値の方がstopPrice + addPointsより小さければ、ストップレベルに違反しているとしてfalseを返します。
CheckUpperStopLevel関数の処理実装記述は以上になります。
ストップレベルの最大値要件を満たしているかをチェックする関数
ストップレベルの最大値をチェックする関数の概要は以下の通りです
// ストップレベルをチェックする関数(最大値)
bool CheckLowerStopLevel(string parSymbol, double parPrice, int parPoints = 10)
{ //現在値の取得
double currentPrice = SymbolInfoDouble(parSymbol,SYMBOL_BID);
//ポイントの取得
double point = SymbolInfoDouble(parSymbol,SYMBOL_POINT);
//ストップレベル情報を取得し、価格ベースに変換
double stopLevel = SymbolInfoInteger(parSymbol,SYMBOL_TRADE_STOPS_LEVEL) * point;
//ストップレベル最大値を算出
double stopPrice = currentPrice - stopLevel;
//任意に設定・加算するポイント
double addPoints = parPoints * point;
//注文価格がストップレベルに違反していないかをチェックし、戻り値を返す
if(parPrice <= stopPrice - addPoints) return(true);
else return(false);
}
関数名は「CheckLowerStopLevel」としました。戻り値はCheckUpperStopLevel関数と同じくbool型です。
CheckLowerStopLevel関数の引数構成
引数構成は↓の通りです。仮引数は3つで、その働きもCheckUpperStopLevel関数と全く同じです。
bool CheckLowerStopLevel(string parSymbol, double parPrice, int parPoints = 10)
CheckLowerStopLevel関数の処理実装記述
ストップレベルの算出に必要な各種値を取得
まずはストップレベルの算出に必要な各種値を取得します。
CheckUpperStopLevel関数と同様、必要な情報は、
の3つです
//現在値の取得
double currentPrice = SymbolInfoDouble(parSymbol,SYMBOL_BID);
//ポイントの取得
double point = SymbolInfoDouble(parSymbol,SYMBOL_POINT);
//ストップレベル情報を取得し、価格ベースに変換
double stopLevel = SymbolInfoInteger(parSymbol,SYMBOL_TRADE_STOPS_LEVEL) * point;
現在値は、SymbolInfoDouble関数の第2引数にSYMBOL_BIDを記述して取得します。
ポイントは、SymbolInfoDouble関数の第2引数にSYMBOL_POINTを記述して取得します。
価格ベースに変換したストップレベル情報は、SymbolInfoInteger関数の第2引数にSYMBOL_TRADE_STOPS_LEVELを記述して取得したものに、ポイントをかけて算出します。
ストップレベル最大値の算出と任意に設定・加算するポイントの取得
//ストップレベル最大値を算出
double stopPrice = currentPrice - stopLevel;
//任意に設定・加算するポイント
double addPoints = parPoints * point;
ストップレベル最大値は、現在値Bid値 – 価格ベースに変換されたストップレベル情報になります。これが変数「stopPrice」に格納されます。
変数「addPoints」には、ストップレベル最大値に追加する価格ベースのポイントが格納されます。
最終的には変数「stopPrice」 - 変数「addPoints」の値と、第2引数parPriceの注文価格と比較して、ストップレベルに違反していないかを確認します。
注文価格がストップレベルに違反していないかをチェックし、戻り値を返す
//注文価格がストップレベルに違反していないかをチェックし、戻り値を返す
if(parPrice <= stopPrice - addPoints) return(true);
else return(false);
第2引数parPriceには注文価格が入るようになっており、stopPrice – addPointsはストップレベル最大値の最終形となる値です。
if文でparPriceの値がstopPrice – addPoints以下なら、ストップレベルに違反していないとしてtrueを返します。
逆にparPriceの値の方がstopPrice – addPointsより大きければ、ストップレベルに違反しているとしてfalseを返します。
CheckLowerStopLevel関数の処理実装記述は以上になります。
これまでのOriginalTrade.mqhファイル全体の記述内容
これまでのOriginalTrade.mqhファイル全体の記述内容は以下の通りです↓
//+------------------------------------------------------------------+
//| OriginalTrade.mqh |
//| MQL5ssei |
//| https://mqlinvestmentlab.com/ |
//+------------------------------------------------------------------+
#property copyright "MQL5ssei"
#property link "https://mqlinvestmentlab.com/"
#define RETRY_LIMIT 3//エラー時に再注文を出す上限回数
#define RETRY_MILLISECONDS 3000//再注文処理に移るまでの待機時間
#include <errordescription.mqh>
//トレード用のクラス「OriginalCTrade」を定義する
class OriginalCTrade
{
protected:
MqlTradeRequest request;
ulong magicNumber;//マジックナンバーを格納する
ulong deviation;//スリッページを格納する
ENUM_ORDER_TYPE_FILLING fillType;//フィルポリシーを格納する
void TradeLog();//注文内容と結果をエキスパートログに残す
//ポジションオープンクラスの実装
ulong PositionOpen(string parSymbol, ENUM_ORDER_TYPE parType, double parVolume, double parStop = 0, double parProfit = 0, string parComment = NULL);
public:
MqlTradeResult result;
//買い注文を出す関数
ulong Buy(string parSymbol, double parVolume, double parStop = 0, double parProfit = 0, string parComment = NULL);
//売り注文を出す関数
ulong Sell(string parSymbol, double parVolume, double parStop = 0, double parProfit = 0, string parComment = NULL);
//マジックナンバーを設定する関数
void OriginalCTrade::SetMagicNumber(ulong parMagic);
// スリッページを設定する
void SetDeviation(ulong parDeviation);
// フィルポリシーを設定する
void SetFillType(ENUM_ORDER_TYPE_FILLING parFill);
//ストップロスとテイクプロフィットを設定する
bool SetSLTP(ulong parTicket, double parStop, double parProfit = 0);
};//class OriginalCTrade
//PositionOpen関数の処理内容を実装
ulong OriginalCTrade::PositionOpen(string parSymbol, ENUM_ORDER_TYPE parType, double parVolume, double parStop = 0, double parProfit = 0, string parComment = NULL)
{
//構造体インスタンスのリセット
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_DEAL;//取引の種類を設定する
request.symbol = parSymbol;//取引銘柄を設定する
request.type = parType;//注文タイプを設定する
request.sl = parStop;//ストップロスを設定する
request.tp = parProfit;//テイクプロフィットを設定する
request.comment = parComment;//コメントを設定する
request.volume = parVolume;//ロット数を設定する
request.deviation = deviation;//スリッページを設定する
request.type_filling = fillType;//フィルポリシーを設定する
request.magic = magicNumber;////マジックナンバーを設定する
// リトライ回数とリターンコードを格納する変数を宣言
int retryCount = 0;
int checkCode = 0;
//発注回路の記述
do
{
//買いの場合の注文価格
if(parType == ORDER_TYPE_BUY)
request.price = SymbolInfoDouble(parSymbol,SYMBOL_ASK);
//売りの場合の注文価格
else
if(parType == ORDER_TYPE_SELL)
request.price = SymbolInfoDouble(parSymbol,SYMBOL_BID);
//注文を出す
bool sent = OrderSend(request,result);
//リターンコードを変数checkCode に格納する
checkCode = ReturnCodeCheck(result.retcode);
if(checkCode == CHECK_RETCODE_OK) break;
else if(checkCode == CHECK_RETCODE_ERROR)
{
string errDesc = TradeServerReturnCodeDescription(result.retcode);
Alert("注文エラー: エラー内容 ",result.retcode," - ",errDesc);
TradeLog();
break;
}
else//CHECK_RETCODE_RETRYの場合
{
Print("サーバーエラーを検知。 再試行中...");
Sleep(RETRY_MILLISECONDS);
retryCount++;
}//else
}//do
while(retryCount < RETRY_LIMIT);
//再注文上限回数に達した時
if(retryCount >= RETRY_LIMIT)
{
string errDesc = TradeServerReturnCodeDescription(result.retcode);
Alert("再注文上限回数に達しました: エラー内容 ",result.retcode," - ",errDesc);
}
//注文種類を確認する関数を呼び出し戻り値を変数に格納
string orderType = ConfirmOrderType(parType);
string errDesc = TradeServerReturnCodeDescription(result.retcode);
//ログ出力
Print("注文種類",orderType,
"オーダー番号 #",result.order,
" リターンコード: ",result.retcode,
" - ",errDesc,
", ロット数: ",result.volume,
", 約定価格: ",result.price);
//戻り値を返す
if(checkCode == CHECK_RETCODE_OK)
{
Comment("注文種類: ",orderType," オーダー番号 #",result.order," 約定価格 ",result.price);
return(result.order);
}
else return(0);
}//OriginalCTrade::PositionOpen
//+------------------------------------------------------------------+
// リターンコードによって、次の行動を決めるための列挙型
enum ENUM_CHECK_RETCODE
{
CHECK_RETCODE_OK,
CHECK_RETCODE_ERROR,
CHECK_RETCODE_RETRY
};
// リターンコードのチェックをする関数
int ReturnCodeCheck(uint parRetCode)
{
int status;
switch(parRetCode)
{
case TRADE_RETCODE_REQUOTE:
case TRADE_RETCODE_CONNECTION:
case TRADE_RETCODE_PRICE_CHANGED:
case TRADE_RETCODE_TIMEOUT:
case TRADE_RETCODE_PRICE_OFF:
case TRADE_RETCODE_REJECT:
case TRADE_RETCODE_ERROR:
status = CHECK_RETCODE_RETRY;
break;
case TRADE_RETCODE_DONE:
case TRADE_RETCODE_DONE_PARTIAL:
case TRADE_RETCODE_PLACED:
case TRADE_RETCODE_NO_CHANGES:
status = CHECK_RETCODE_OK;
break;
default: status = CHECK_RETCODE_ERROR;
}
return(status);
}
//注文内容と結果をエキスパートログに残す
void OriginalCTrade::TradeLog()
{
Print("MqlTradeRequest - 取引の種類:",request.action,
", コメント:",request.comment,
",スリッページ:",request.deviation,
", 注文有効期限:",request.expiration,
", マジックナンバー:",request.magic,
", オーダー番号:",request.order,
", ポジション番号:",request.position,
", 反対ポジションの番号:",request.position_by,
", ポジション価格:",request.price,
", ストップロス:",request.sl,
", テイクプロフィット:",request.tp,
", ストップリミット:",request.stoplimit,
", 取引銘柄:",request.symbol,
", オーダー種類:",request.type,
", フィルポリシー:",request.type_filling,
", 有効期限の種類:",request.type_time,
", ロット数:",request.volume);
Print("MqlTradeResult - ask:",result.ask,
", bid:",result.bid,
", コメント:",result.comment,
", 約定番号:",result.deal,
", オーダー番号:",result.order,
", ポジション価格:",result.price,
", リクエストID:",result.request_id,
", リターンコード:",result.retcode,
", リターンコード(外部):",result.retcode_external,
", ロット数:",result.volume);
}//void OriginalCTrade::TradeLog()
//注文種類を確認する関数
string ConfirmOrderType(ENUM_ORDER_TYPE parType)
{
string orderType;
if(parType == ORDER_TYPE_BUY) orderType = "buy";
else if(parType == ORDER_TYPE_SELL) orderType = "sell";
else if(parType == ORDER_TYPE_BUY_STOP) orderType = "buy stop";
else if(parType == ORDER_TYPE_BUY_LIMIT) orderType = "buy limit";
else if(parType == ORDER_TYPE_SELL_STOP) orderType = "sell stop";
else if(parType == ORDER_TYPE_SELL_LIMIT) orderType = "sell limit";
else if(parType == ORDER_TYPE_BUY_STOP_LIMIT) orderType = "buy stop limit";
else if(parType == ORDER_TYPE_SELL_STOP_LIMIT) orderType = "sell stop limit";
else orderType = "不適切な注文種類です。";
return(orderType);
}
// 買い注文を出す
ulong OriginalCTrade::Buy(string parSymbol, double parVolume, double parStop = 0, double parProfit = 0, string parComment = NULL)
{
ulong ticket = PositionOpen(parSymbol,ORDER_TYPE_BUY,parVolume,parStop,parProfit,parComment);
return(ticket);
}
// 売り注文を出す
ulong OriginalCTrade::Sell(string parSymbol, double parVolume, double parStop = 0, double parProfit = 0, string parComment = NULL)
{
ulong ticket = PositionOpen(parSymbol,ORDER_TYPE_SELL,parVolume,parStop,parProfit,parComment);
return(ticket);
}
// マジックナンバーを設定する
void OriginalCTrade::SetMagicNumber(ulong parMagic)
{
magicNumber = parMagic;
}
// スリッページを設定する
void OriginalCTrade::SetDeviation(ulong parDeviation)
{
deviation = parDeviation;
}
// フィルポリシーを設定する
void OriginalCTrade::SetFillType(ENUM_ORDER_TYPE_FILLING parFill)
{
fillType = parFill;
}
//+------------------------------------------------------------------+
//口座の適切なフィルポリシーを返す関数
ENUM_ORDER_TYPE_FILLING FillPolicy()
{
long fillType = SymbolInfoInteger(_Symbol, SYMBOL_FILLING_MODE);
if(fillType==SYMBOL_FILLING_IOC)return ORDER_FILLING_IOC;
else if(fillType==SYMBOL_FILLING_FOK)return ORDER_FILLING_FOK;
else return ORDER_FILLING_RETURN;
}
//ストップロスとテイクプロフィットを設定する
bool OriginalCTrade::SetSLTP(ulong parTicket,double parStop,double parProfit=0.000000)
{
//インスタンスのリセット
ZeroMemory(request);
ZeroMemory(result);
//ポジション番号を取得し、変数に格納
bool select = PositionSelectByTicket(parTicket);
//銘柄を取得し、変数に格納
string symbol = PositionGetString(POSITION_SYMBOL);
request.action = TRADE_ACTION_SLTP;//取引種別の設定
request.sl = parStop;//ストップロスの設定
request.tp = parProfit;//テイクプロフィットの設定
request.position = parTicket;//ポジション番号の設定
request.symbol = symbol;//銘柄情報の設定
request.type_filling = fillType;//フィルポリシーを設定
request.magic = magicNumber;////マジックナンバーを設定
// リトライ回数とリターンコードを格納する変数を宣言
int retryCount = 0;//再試行回数を格納する
int checkCode = 0;//リターンコードを格納する
do
{ //SLTP設定注文を出す。
bool sent = OrderSend(request,result);
//注文結果を返す
checkCode = ReturnCodeCheck(result.retcode);
//約定成功の場合do-whileループを抜ける
if(checkCode == CHECK_RETCODE_OK) break;
//再試行しても解決しないエラーの場合
else if(checkCode == CHECK_RETCODE_ERROR)
{ //リターンコードを取得
string errDesc = TradeServerReturnCodeDescription(result.retcode);
//アラートを発出
Alert("SLTP設定エラー:エラー内容 ",result.retcode," - ",errDesc);
//ログの出力
TradeLog();
break;//ループを抜ける
}
//再試行すれば解決する可能性のあるエラーの場合
else
{ //ログ出力
Print("サーバーエラーを検知。 再試行中...");
//次の処理までの待機
Sleep(RETRY_MILLISECONDS);
//再試行回数をカウントする変数をインクリメントする
retryCount++;
}
}
while(retryCount < RETRY_LIMIT);
if(retryCount >= RETRY_LIMIT)
{
string errDesc = TradeServerReturnCodeDescription(result.retcode);
Alert("再注文上限回数に達しました: エラー内容 ",result.retcode," - ",errDesc);
}
string errDesc = TradeServerReturnCodeDescription(result.retcode);
Print("SLTP設定ポジション番号 #",parTicket,
": ",result.retcode," - ",errDesc,
", SL: ",request.sl,", TP: ",request.tp,
", Bid: ",SymbolInfoDouble(symbol,SYMBOL_BID),
", Ask: ",SymbolInfoDouble(symbol,SYMBOL_ASK),
", ストップレベル: ",SymbolInfoInteger(symbol,SYMBOL_TRADE_STOPS_LEVEL));
//注文が成功した場合、trueを返す
if(checkCode == CHECK_RETCODE_OK)
{
Comment("ポジション番号 #",parTicket," SLTP設定した銘柄 ",symbol,", SL: ",request.sl,", TP: ",request.tp);
return(true);
}
//注文が失敗した場合、falseを返す
else return(false);
}
//+------------------------------------------------------------------+
//| ストップロスとテイクプロフィットを計算する関数
//+------------------------------------------------------------------+
//買いのSLを設定する関数
double CalBuySL(string parSymbol,int parStopPoints, double parOpenPrice = 0)
{
if(parStopPoints <= 0) return(0);
double openPrice;
if(parOpenPrice > 0) openPrice = parOpenPrice;
else openPrice = SymbolInfoDouble(parSymbol,SYMBOL_ASK);
//指定があればその値、なければASKを基準値として採用
double point = SymbolInfoDouble(parSymbol,SYMBOL_POINT);
double stopLoss = openPrice - (parStopPoints * point);
//現在値-pStopPoints * pointを損切りプライスとして代入
long digits = SymbolInfoInteger(parSymbol,SYMBOL_DIGITS);
stopLoss = NormalizeDouble(stopLoss,(int)digits);
return(stopLoss);
}
//買いのTPを設定する関数
double CalBuyTP(string parSymbol,int parProfitPoints, double parOpenPrice = 0)
{
if(parProfitPoints <= 0) return(0);
double openPrice;
if(parOpenPrice > 0) openPrice = parOpenPrice;
else openPrice = SymbolInfoDouble(parSymbol,SYMBOL_ASK);
double point = SymbolInfoDouble(parSymbol,SYMBOL_POINT);
double takeProfit = openPrice + (parProfitPoints * point);
long digits = SymbolInfoInteger(parSymbol,SYMBOL_DIGITS);
takeProfit = NormalizeDouble(takeProfit,(int)digits);
return(takeProfit);
}
//売りのSLを設定する関数
double CalSellSL(string parSymbol,int parStopPoints, double parOpenPrice = 0)
{
if(parStopPoints <= 0) return(0);
double openPrice;
if(parOpenPrice > 0) openPrice = parOpenPrice;
else openPrice = SymbolInfoDouble(parSymbol,SYMBOL_BID);
double point = SymbolInfoDouble(parSymbol,SYMBOL_POINT);
double stopLoss = openPrice + (parStopPoints * point);
long digits = SymbolInfoInteger(parSymbol,SYMBOL_DIGITS);
stopLoss = NormalizeDouble(stopLoss,(int)digits);
return(stopLoss);
}
//売りのTPを設定する関数
double CalSellTP(string parSymbol,int parProfitPoints, double parOpenPrice = 0)
{
if(parProfitPoints <= 0) return(0);
double openPrice;
if(parOpenPrice > 0) openPrice = parOpenPrice;
else openPrice = SymbolInfoDouble(parSymbol,SYMBOL_BID);
double point = SymbolInfoDouble(parSymbol,SYMBOL_POINT);
double takeProfit = openPrice - (parProfitPoints * point);
long digits = SymbolInfoInteger(parSymbol,SYMBOL_DIGITS);
takeProfit = NormalizeDouble(takeProfit,(int)digits);
return(takeProfit);
}
// ストップレベルをチェックする関数(最小値)
bool CheckUpperStopLevel(string parSymbol, double parPrice, int parPoints = 10)
{ //現在値の取得
double currentPrice = SymbolInfoDouble(parSymbol,SYMBOL_ASK);
//ポイントの取得
double point = SymbolInfoDouble(parSymbol,SYMBOL_POINT);
//ストップレベル情報を取得し、価格ベースに変換
double stopLevel = SymbolInfoInteger(parSymbol,SYMBOL_TRADE_STOPS_LEVEL) * point;
//ストップレベル最小値を算出
double stopPrice = currentPrice + stopLevel;
//任意に設定・加算するポイント
double addPoints = parPoints * point;
//注文価格がストップレベルに違反していないかをチェックし、戻り値を返す
if(parPrice >= stopPrice + addPoints) return(true);
else return(false);
}
// ストップレベルをチェックする関数(最大値)
bool CheckLowerStopLevel(string parSymbol, double parPrice, int parPoints = 10)
{ //現在値の取得
double currentPrice = SymbolInfoDouble(parSymbol,SYMBOL_BID);
//ポイントの取得
double point = SymbolInfoDouble(parSymbol,SYMBOL_POINT);
//ストップレベル情報を取得し、価格ベースに変換
double stopLevel = SymbolInfoInteger(parSymbol,SYMBOL_TRADE_STOPS_LEVEL) * point;
//ストップレベル最大値を算出
double stopPrice = currentPrice - stopLevel;
//任意に設定・加算するポイント
double addPoints = parPoints * point;
//注文価格がストップレベルに違反していないかをチェックし、戻り値を返す
if(parPrice <= stopPrice - addPoints) return(true);
else return(false);
}
※これまでにOriginalTrade.mqhファイルに、講座記事を通して追加してきた関数の解説ページへのリンクを↓に貼っておきますので、参考にしてください。
- PositionOpen関数(ポジションをオープンさせる関数。アクセスレベル=protected。OriginalCTradeクラスのメンバ関数)
- ReturnCodeCheck関数(リターンコードをチェックする独立関数。)
- TradeLog関数(注文内容と結果をエキスパートログに残す関数。アクセスレベル=protected。OriginalCTradeクラスのメンバ関数)
- ConfirmOrderType関数(注文種類を確認する独立関数)
- Buy関数(買い注文を出す関数。アクセスレベル=public。OriginalCTradeクラスのメンバ関数)
- Sell関数(売り注文を出す関数。アクセスレベル=public。OriginalCTradeクラスのメンバ関数)
- SetMagicNumber関数(マジックナンバーを設定する関数。アクセスレベル=public。OriginalCTradeクラスのメンバ関数)
- SetDeviation関数(スリッページを設定する関数。アクセスレベル=public。OriginalCTradeクラスのメンバ関数)
- SetFillType関数(フィルポリシーを設定する関数。アクセスレベル=public。OriginalCTradeクラスのメンバ関数)
- FillPolicy関数(口座の適切なフィルポリシーを返す独立関数)
- SetSLTP関数(ストップロスとテイクプロフィットを設定する関数。アクセスレベル=public。OriginalCTradeクラスのメンバ関数)
- CalBuySL関数(買いポジションのSL値を算出する独立関数)
- CalBuyTP関数(買いポジションのTP値を算出する独立関数)
- CalSellSL関数(売りポジションのSL値を算出する独立関数)
- CalSellTP関数(売りポジションのTP値を算出する独立関数)
- CheckUpperStopLevel関数(ストップレベルの最小値要件を満たしているかをチェックする独立関数)
- CheckLowerStopLevel関数(ストップレベルの最大値要件を満たしているかをチェックする独立関数)
まとめ
今回実装した関数は、ストップレベルに違反しているかどうかをチェックするだけで、違反していた場合に自動修正する処理は盛り込まれていません。
注文価格がストップレベルに違反していた場合に、自動修正する関数は、次回解説・実装予定です。
今回は以上になります。最後までお読みいただきありがとうございました。<m(__)m>
コメント