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);
//待機注文関数
bool PendingOpen(string parSymbol, ENUM_ORDER_TYPE parType, double parVolume,
double parPrice, double parStop = 0, double parProfit = 0,
double parStopLimit = 0, datetime parExpiration = 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);
//買いのリミット待機注文を出す
bool BuyLimit(string parSymbol, double parVolume, double parPrice, double parStop =0.000000, double parProfit = 0.000000, datetime parExpiration = 0, string parComment = NULL);
//売りのリミット待機注文を出す
bool SellLimit(string parSymbol, double parVolume, double parPrice, double parStop =0.000000, double parProfit = 0.000000, datetime pExpiration = 0, string parComment = NULL);
//買いのストップ待機注文を出す
bool BuyStop(string parSymbol, double parVolume, double parPrice, double parStop = 0.000000, double parProfit = 0.000000, datetime parExpiration = 0, string parComment = NULL);
//売りのストップ待機注文を出す
bool SellStop(string parSymbol, double parVolume, double parPrice, double parStop = 0.000000, double parProfit = 0.000000, datetime parExpiration = 0, string parComment = NULL);
//買いのストップリミット待機注文を出す
bool BuyStopLimit(string parSymbol, double parVolume, double parPrice, double parStopLimit, double parStop = 0.000000, double parProfit = 0.000000, datetime parExpiration = 0, string parComment = NULL);
//売りのストップリミット待機注文を出す
bool SellStopLimit(string parSymbol, double parVolume, double parPrice, double parStopLimit, double parStop = 0.000000, double parProfit = 0.000000, datetime parExpiration = 0, string parComment = NULL);
//マジックナンバーを設定する関数
void SetMagicNumber(ulong parMagic);
// スリッページを設定する
void SetDeviation(ulong parDeviation);
// フィルポリシーを設定する
void SetFillType(ENUM_ORDER_TYPE_FILLING parFill);
//ストップロスとテイクプロフィットを設定する
bool SetSLTP(ulong parTicket, double parStop, double parProfit = 0.000000);
//待機注文を修正する
bool ChangePending(ulong parTicket, double parPrice, double parStop, double parProfit, datetime parExpiration = 0);
//待機注文を削除する
bool DeletePending(ulong parTicket);
//ポジションをクローズする
bool ClosePosition(ulong parTicket, double parVolume = 0.000000, string parComment = NULL);
};//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
//+------------------------------------------------------------------+
//待機注文を実行する関数
bool OriginalCTrade::PendingOpen(string parSymbol, ENUM_ORDER_TYPE parType, double parVolume,
double parPrice, double parStop = 0, double parProfit = 0,
double parStopLimit = 0, datetime parExpiration = 0, string parComment = NULL)
{ //構造体インスタンスのリセット
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_PENDING;//取引の種類を設定する
request.symbol = parSymbol;//取引銘柄を設定する
request.type = parType;//取引タイプを設定する
request.sl = parStop;//損切り価格を設定する
request.tp = parProfit;//利益確定価格を設定する
request.comment = parComment;//コメントを設定する
request.price = parPrice;//約定予定価格を設定する
request.volume = parVolume;//ロット数を設定する
request.stoplimit = parStopLimit;//ストップリミットを設定する
request.deviation = deviation;//スリッページを設定する
request.type_filling = fillType;//フィルポリシーを設定する
request.magic = magicNumber;//マジックナンバーを設定する
if(parExpiration > 0)//有効期限が設定されている時
{
request.expiration = parExpiration;
request.type_time = ORDER_TIME_SPECIFIED;
}
//有効期限が設定されていない時
else request.type_time = ORDER_TIME_GTC;
// リトライ回数とリターンコード用の変数を宣言
int retryCount = 0;
int checkCode = 0;
do
{ //注文を出す
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++;
}
}
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,", Price: ",request.price,
", Bid: ",SymbolInfoDouble(parSymbol,SYMBOL_BID),
", Ask: ",SymbolInfoDouble(parSymbol,SYMBOL_ASK),
", SL: ",request.sl,", TP: ",request.tp,
", Stop Limit: ",request.stoplimit,
", 有効期限: ",request.expiration);
if(checkCode == CHECK_RETCODE_OK)
{
Comment(orderType," 待機注文を出しました ",request.price," on ",parSymbol);
return(true);
}
else return(false);
}//PendingOpen
//+------------------------------------------------------------------+
// ポジションをクローズする関数
bool OriginalCTrade::ClosePosition(ulong parTicket, double parVolume=0.000000, string parComment=NULL)
{
//構造体インスタンスのリセット
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_DEAL;//取引の種類を設定する
request.position = parTicket;//ポジション番号を設定する
request.deviation = deviation;//スリッページを設定する
request.type_filling = fillType;//フィルポリシーを設定する
request.magic=magicNumber;//マジックナンバーを設定する
double closeVol = 0;
long openType = WRONG_VALUE;
string symbol;
//ポジションを選択出来たら
if(PositionSelectByTicket(parTicket) == true)
{
//ポジションのロット数を代入
closeVol = PositionGetDouble(POSITION_VOLUME);
//ポジションタイプを代入
openType = PositionGetInteger(POSITION_TYPE);
//ポジションの銘柄情報を代入
symbol = PositionGetString(POSITION_SYMBOL);
}
//ポジション選択できなければfalseを返して終了
else return(false);
request.symbol = symbol;//銘柄情報を設定する
/*指定したクローズロット数がポジションのロット数より大きいか、指定したクローズロット数が0以下の時は、
ポジションのロット数をクローズするロット数とする*/
if(parVolume > closeVol || parVolume <= 0) request.volume = closeVol;
//それ以外の場合は、指定したクローズロット数をクローズする
else request.volume = parVolume;
// リトライ回数とリターンコードを格納する変数を宣言する
int retryCount = 0;
int checkCode = 0;
do
{ //ポジションが買いの場合の注文価格と注文タイプの設定
if(openType == POSITION_TYPE_BUY)
{
request.type = ORDER_TYPE_SELL;
request.price = SymbolInfoDouble(symbol,SYMBOL_BID);
}
//ポジションが売りの場合の注文価格と注文タイプの設定
else if(openType == POSITION_TYPE_SELL)
{
request.type = ORDER_TYPE_BUY;
request.price = SymbolInfoDouble(symbol,SYMBOL_ASK);
}
//注文を出す
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++;
}
}
while(retryCount < RETRY_LIMIT);
//再注文上限回数に達した時
if(retryCount >= RETRY_LIMIT)
{ //エラーコードの格納
string errDesc = TradeServerReturnCodeDescription(result.retcode);
Alert("再注文上限回数に達しました: エラー内容 ",result.retcode," - ",errDesc);
}
//ログ出力用のポジションタイプ格納変数
string posType;
if(openType == POSITION_TYPE_BUY) posType = "Buy";
else if(openType == POSITION_TYPE_SELL) posType = "Sell";
//エラーコードの格納
string errDesc = TradeServerReturnCodeDescription(result.retcode);
Print("Close ",posType,//ポジションタイプ
" position #",parTicket,//ポジション番号
": ",result.retcode," - ",errDesc,//リターンコードとエラーコード
", Volume: ",result.volume,//約定ロット数
", Price: ",result.price);//約定価格
if(checkCode == CHECK_RETCODE_OK)
{
Comment(posType," ポジションをクローズしました。 ",symbol," at ",result.price);
return(true);
}
else return(false);
}
//-------------------------------------------------------------------------------
// リターンコードによって、次の行動を決めるための列挙型
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);
}
//買いのリミット待機注文を出す
bool OriginalCTrade::BuyLimit(string parSymbol,double parVolume,double parPrice,double parStop=0.000000,double parProfit=0.000000,datetime parExpiration=0,string parComment=NULL)
{
bool success = PendingOpen(parSymbol,ORDER_TYPE_BUY_LIMIT,parVolume,parPrice,parStop,parProfit,0,parExpiration,parComment);
return(success);
}
//売りのリミット待機注文を出す
bool OriginalCTrade::SellLimit(string parSymbol,double parVolume,double parPrice,double parStop=0.000000,double parProfit=0.000000,datetime parExpiration=0,string parComment=NULL)
{
bool success = PendingOpen(parSymbol,ORDER_TYPE_SELL_LIMIT,parVolume,parPrice,parStop,parProfit,0,parExpiration,parComment);
return(success);
}
//買いのストップ待機注文を出す
bool OriginalCTrade::BuyStop(string parSymbol,double parVolume,double parPrice,double parStop=0.000000,double parProfit=0.000000,datetime parExpiration=0,string parComment=NULL)
{
bool success = PendingOpen(parSymbol,ORDER_TYPE_BUY_STOP,parVolume,parPrice,parStop,parProfit,0,parExpiration,parComment);
return(success);
}
//売りのストップ待機注文を出す
bool OriginalCTrade::SellStop(string parSymbol,double parVolume,double parPrice,double parStop=0.000000,double parProfit=0.000000,datetime parExpiration=0,string parComment=NULL)
{
bool success = PendingOpen(parSymbol,ORDER_TYPE_SELL_STOP,parVolume,parPrice,parStop,parProfit,0,parExpiration,parComment);
return(success);
}
//買いのストップリミット待機注文を出す
bool OriginalCTrade::BuyStopLimit(string parSymbol,double parVolume,double parPrice,double parStopLimit,double parStop=0.000000,double parProfit=0.000000,datetime parExpiration=0,string parComment=NULL)
{
bool success = PendingOpen(parSymbol,ORDER_TYPE_BUY_STOP_LIMIT,parVolume,parPrice,parStop,parProfit,parStopLimit,parExpiration,parComment);
return(success);
}
//売りのストップリミット待機注文を出す
bool OriginalCTrade::SellStopLimit(string parSymbol,double parVolume,double parPrice,double parStopLimit,double parStop=0.000000,double parProfit=0.000000,datetime parExpiration=0,string parComment=NULL)
{
bool success = PendingOpen(parSymbol,ORDER_TYPE_SELL_STOP_LIMIT,parVolume,parPrice,parStop,parProfit,parStopLimit,parExpiration,parComment);
return(success);
}
// マジックナンバーを設定する
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);
}
//待機注文の内容を修正する
bool OriginalCTrade::ChangePending(ulong parTicket,double parPrice,double parStop,double parProfit,datetime parExpiration=0)
{
//インスタンスのリセット
ZeroMemory(request);
ZeroMemory(result);
//各種メンバ変数への値代入
request.action = TRADE_ACTION_MODIFY;
request.order = parTicket;
request.sl = parStop;
request.tp = parProfit;
//待機注文の選択
bool select = OrderSelect(parTicket);
//parPriceに値が入力されていれば、parPriceの値をrequest.priceにセット
if(parPrice > 0) request.price = parPrice;
else request.price = OrderGetDouble(ORDER_PRICE_OPEN);
//parExpirationに値が入力されていれば、request.expirationにセット
if(parExpiration > 0)
{
request.expiration = parExpiration;
request.type_time = ORDER_TIME_SPECIFIED;
}
else request.type_time = ORDER_TIME_GTC;
// リトライ回数とリターンコードを格納する変数を宣言
int retryCount = 0;//再試行回数を格納する
int checkCode = 0;//リターンコードを格納する
do
{ //待機注文の修正注文を出す。
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("待機注文修正エラー: エラー内容 ",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);
}
select = OrderSelect(parTicket);
string errDesc = TradeServerReturnCodeDescription(result.retcode);
Print("待機注文の修正 #",parTicket,": ",
result.retcode," - ",errDesc,", Price: ",
OrderGetDouble(ORDER_PRICE_OPEN),", SL: ",request.sl,
", TP: ",request.tp,", Expiration: ",request.expiration);
if(checkCode == CHECK_RETCODE_OK)
{
Comment("待機注文 ",parTicket," 修正後の内容,",
" Price: ",OrderGetDouble(ORDER_PRICE_OPEN),
", SL: ",request.sl,", TP: ",request.tp);
//注文が成功した場合、trueを返す
return(true);
}
//注文が失敗した場合、falseを返す
else return(false);
}
//待機注文を削除する
bool OriginalCTrade::DeletePending(ulong parTicket)
{ //インスタンスのリセット
ZeroMemory(request);
ZeroMemory(result);
//各種メンバ変数への値代入
request.action = TRADE_ACTION_REMOVE;
request.order = parTicket;
// リトライ回数とリターンコードを格納する変数を宣言
int retryCount = 0;//再試行回数を格納する
int checkCode = 0;//リターンコードを格納する
do
{ //待機注文の削除注文を出す。
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("待機注文削除エラー: エラー内容 ",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("待機注文削除エラー #",parTicket,": ",
result.retcode," - ",errDesc);
if(checkCode == CHECK_RETCODE_OK)
{
Comment("待機注文 ",parTicket," 削除されました");
return(true);
}
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);
}
// ストップレベルを修正する(最小値)
double ModifyUpperStopLevel(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(parPrice);
else
{//注文価格がストップレベルを違反している場合は修正した価格を戻り値として返す
double newPrice = stopPrice + addPoints;
Print("注文価格はストップレベルに適合した価格に修正されました→ "+DoubleToString(newPrice));
return(newPrice);
}
}
// ストップレベルを修正する(最大値)
double ModifyLowerStopLevel(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(parPrice);
else
{ //注文価格がストップレベルを違反している場合は修正した価格を戻り値として返す
double newPrice = stopPrice - addPoints;
Print("注文価格はストップレベルに適合した価格に修正されました→ "+DoubleToString(newPrice));
return(newPrice);
}
}
//ポジション情報を管理するクラス------------------------------
class OriginalCPositions
{
protected:
ulong BuyPosNum[];
ulong SellPosNum[];
ulong PosNum[];
int BuyPosCount;
int SellPosCount;
int TotalPosCount;
void GetPosInfo(ulong parMagicNum = 0);
int ChangeArraySize(ulong &parArray[]);
public:
int GetBuyPosCount(ulong parMagicNum);
int GetSellPosCount(ulong parMagicNum);
int GetTotalPosCount(ulong parMagicNum);
void GetBuyPosNum(ulong parMagicNum,ulong &parTickets[]);
void GetSellPosNum(ulong parMagicNum,ulong &parTickets[]);
void GetTotalPosNum(ulong parMagicNum,ulong &parTickets[]);
};
// ポジション情報を取得・振り分けする関数
void OriginalCPositions::GetPosInfo(ulong parMagicNumber = 0)
{
//ポジション数を格納する変数の初期化
BuyPosCount = 0;
SellPosCount = 0;
TotalPosCount = 0;
//ポジション番号格納配列の初期化とリサイズ
ArrayResize(BuyPosNum, 1);
ArrayInitialize(BuyPosNum, 0);
ArrayResize(SellPosNum, 1);
ArrayInitialize(SellPosNum, 0);
ArrayResize(PosNum, 1);
ArrayInitialize(PosNum, 0);
for(int i = 0; i < PositionsTotal(); i++)//未決済ポジション内を一番古いポジからチェック
{
ulong posNumber = PositionGetTicket(i);//ポジションプール内からインデックス順にポジション番号を取得
PositionSelectByTicket(posNumber);//ポジション選択
if(PositionGetInteger(POSITION_MAGIC) != parMagicNumber && parMagicNumber > 0) continue;
//当該EAからの注文でなければスキップ
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{ //買いポジションの数を1増加させる
BuyPosCount++;
int arrayIndex = ChangeArraySize(BuyPosNum);//配列をリサイズし、インデックスを戻り値として返す
BuyPosNum[arrayIndex] = PositionGetInteger(POSITION_TICKET);//Buy ポジション番号情報を配列に格納
}
else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
{ ////売りポジションの数を1増加させる
SellPosCount++;
int arrayIndex = ChangeArraySize(SellPosNum);//配列をリサイズし、インデックスを戻り値として返す
SellPosNum[arrayIndex] = PositionGetInteger(POSITION_TICKET);//Sell ポジション番号情報を配列に格納
}
//全体のポジション数を1増加させる
TotalPosCount++;
int arrayIndex = ChangeArraySize(PosNum);//配列をリサイズし、インデックスを戻り値として返す
PosNum[arrayIndex] = PositionGetInteger(POSITION_TICKET);//全てのポジションの ポジション番号情報を配列に格納
}// for(int i = 0; i < PositionsTotal(); i++)の終端
//各種ポジカウント変数とポジション番号格納配列に必要な情報を振り分けて作業を終える
}
//配列サイズを変更し、配列インデックスを返す関数
int OriginalCPositions::ChangeArraySize(ulong &parArray[])
{
int arrayIndex = 0;//配列のインデックスを格納する変数
//配列サイズが1より大きいとき
if(ArraySize(parArray) > 1)
{//配列要素に+1したサイズにリサイズして、その値を変数「newSize」に格納
int newSize = ArrayResize(parArray, ArraySize(parArray) + 1);
//変数「newSize」の値に-1することによって、インデックス値に変換。その値を変数「arrayIndex」に格納
arrayIndex = newSize - 1;
}
//変数「arrayIndex」の値を戻り値として返す
return arrayIndex;
}//int OriginalCPositions::ChangeArraySize(ulong &parArray[])
//買いポジションの数を取得する関数
int OriginalCPositions::GetBuyPosCount(ulong parMagicNum)
{
GetPosInfo(parMagicNum);//各種ポジカウント変数とポジション番号格納配列に、必要な情報を振り分けるprotected関数
//protected変数の「BuyPosCount」を呼び出し、戻り値として返す
return BuyPosCount;
}
//売りポジションの数を取得する関数
int OriginalCPositions::GetSellPosCount(ulong parMagicNum)
{
GetPosInfo(parMagicNum);//各種ポジカウント変数とポジション番号格納配列に、必要な情報を振り分けるprotected関数
//protected変数の「BuyPosCount」を呼び出し、戻り値として返す
return SellPosCount;
}
//買いと売りの合計ポジションの数を取得する関数
int OriginalCPositions::GetTotalPosCount(ulong parMagicNum)
{
GetPosInfo(parMagicNum);//各種ポジカウント変数とポジション番号格納配列に、必要な情報を振り分けるprotected関数
//protected変数の「BuyPosCount」を呼び出し、戻り値として返す
return TotalPosCount;
}
void OriginalCPositions::GetBuyPosNum(ulong parMagicNum,ulong &parTickets[])
{
GetPosInfo(parMagicNum);//各種ポジカウント変数とポジション番号格納配列に、必要な情報を振り分けるprotected関数
ArrayCopy(parTickets,BuyPosNum);
return;
}
void OriginalCPositions::GetSellPosNum(ulong parMagicNum,ulong &parTickets[])
{
GetPosInfo(parMagicNum);//各種ポジカウント変数とポジション番号格納配列に、必要な情報を振り分けるprotected関数
ArrayCopy(parTickets,SellPosNum);
return;
}
void OriginalCPositions::GetTotalPosNum(ulong parMagicNum,ulong &parTickets[])
{
GetPosInfo(parMagicNum);//各種ポジカウント変数とポジション番号格納配列に、必要な情報を振り分けるprotected関数
ArrayCopy(parTickets,PosNum);
return;
}
//+------------------------------------------------------------------+
//|ポジション情報を取得する関数群 |
//+------------------------------------------------------------------+
string PositionComment(ulong parTicket = 0)
{//ポジション選択可否を格納する変数
bool select = false;
//ポジション番号を選択する
if(parTicket > 0) select = PositionSelectByTicket(parTicket);
//ポジション選択ができていれば、コメント情報を取得して戻り値として返す
if(select == true) return(PositionGetString(POSITION_COMMENT));
//選択ができなかった場合は、事前定義された値を返す
else return(NULL);
}
long PositionType(ulong parTicket = 0)
{//ポジション選択可否を格納する変数
bool select = false;
//ポジション番号を選択する
if(parTicket > 0) select = PositionSelectByTicket(parTicket);
//ポジション選択ができていれば、ポジションタイプを取得して戻り値として返す
if(select == true) return(PositionGetInteger(POSITION_TYPE));
else return(WRONG_VALUE);
}
long PositionOpenTime(ulong parTicket = 0)
{//ポジション選択可否を格納する変数
bool select = false;
//ポジション番号を選択する
if(parTicket > 0) select = PositionSelectByTicket(parTicket);
//ポジション選択ができていれば、ポジションタイプを取得して戻り値として返す
if(select == true) return(PositionGetInteger(POSITION_TIME));
else return(WRONG_VALUE);
}
double PositionOpenPrice(ulong parTicket = 0)
{//ポジション選択可否を格納する変数
bool select = false;
//ポジション番号を選択する
if(parTicket > 0) select = PositionSelectByTicket(parTicket);
//ポジション選択ができていれば、ポジションを持った時の価格を取得して戻り値として返す
if(select == true) return(PositionGetDouble(POSITION_PRICE_OPEN));
else return(WRONG_VALUE);
}
double PositionVolume(ulong parTicket = 0)
{//ポジション選択可否を格納する変数
bool select = false;
//ポジション番号を選択する
if(parTicket > 0) select = PositionSelectByTicket(parTicket);
//ポジション選択ができていれば、ロット数を取得して戻り値として返す
if(select == true) return(PositionGetDouble(POSITION_VOLUME));
else return(WRONG_VALUE);
}
double PositionStopLoss(ulong parTicket = 0)
{//ポジション選択可否を格納する変数
bool select = false;
//ポジション番号を選択する
if(parTicket > 0) select = PositionSelectByTicket(parTicket);
//ポジション選択ができていれば、損切り値を取得して戻り値として返す
if(select == true) return(PositionGetDouble(POSITION_SL));
else return(WRONG_VALUE);
}
double PositionTakeProfit(ulong parTicket = 0)
{//ポジション選択可否を格納する変数
bool select = false;
//ポジション番号を選択する
if(parTicket > 0) select = PositionSelectByTicket(parTicket);
//ポジション選択ができていれば、利益確定値を取得して戻り値として返す
if(select == true) return(PositionGetDouble(POSITION_TP));
else return(WRONG_VALUE);
}
double PositionProfit(ulong parTicket = 0)
{//ポジション選択可否を格納する変数
bool select = false;
//ポジション番号を選択する
if(parTicket > 0) select = PositionSelectByTicket(parTicket);
//ポジション選択ができていれば、損益情報を取得して戻り値として返す
if(select == true) return(PositionGetDouble(POSITION_PROFIT));
else return(WRONG_VALUE);
}
long PositionMagicNumber(ulong parTicket = 0)
{//ポジション選択可否を格納する変数
bool select = false;
//ポジション番号を選択する
if(parTicket > 0) select = PositionSelectByTicket(parTicket);
//ポジション選択ができていれば、マジックナンバーを取得して戻り値として返す
if(select == true) return(PositionGetInteger(POSITION_MAGIC));
else return(NULL);
}