2015年4月17日金曜日

クラスを作成する。注文クラス 改造版

EAのサンプルを作成してみようと思いましたが、前回アップしたクラスがあまりにバグだらけだったため、とりあえずバックテストを通して一応^^;;動作したクラスをアップしなおします。
以降のEA関係の記事は、このファイルがInclude/Customフォルダの下にTradingWrapper.mqhというファイル名で保存されている前提です。

//------------------------------------------------------------------
// 注文関係ラッパークラス
#property copyright "Copyright 2015,  Daisuke"
#property link      "http://mt4program.blogspot.jp/"
#property version   "1.10"
#property strict

#include 
#include 
#include 

//------------------------------------------------------------------
// 注文関係ラッパークラス
class CTradingWrapper
{
private:
// マジックナンバー
int m_magicNumber;

// 最大ポジション数
int m_maxPosition;

// Pips倍率
int m_pipsRate;

// 対象通貨ペア
string m_symbol;

// 保有ポジション
CArrayInt m_positions ;

// タイムアウト値
uint m_timeout;

// 少数桁数
int m_digit;
public:
//------------------------------------------------------------------
// コンストラクタ
CTradingWrapper(
string symbol,      //対象通貨ペア
int magicNumber,    //マジックナンバー
int maxPosition,    //最大ポジション数
uint timeout        //タイムアウト
);

//------------------------------------------------------------------
// デストラクタ
~CTradingWrapper();

//------------------------------------------------------------------
// 発注する
// Return   発注成功時インデックス それ以外-1
int SendOrder(
int cmd,                //売買種別
double volume,          //売買ロット
double price,           //価格
uint slippage,          //許容スリッピング(Pips単位)
uint stoploss,          //ストップロス(Pips単位)
uint takeprofit,        //利確値(Pips単位)
string comment,         //コメント
datetime expiration,    //注文有効期限
color arrowColor        //注文矢印の色
);

//------------------------------------------------------------------
// 成行き決済を行う。
// Return   発注成功時ture それ以外false
bool CloseOrder(
int index,                    //決済するインデックス
uint slippage,                //許容スリッピング
color arrowColor = clrNONE    //注文矢印の色
);

//------------------------------------------------------------------
// 全ポジションを成行き決済を行う。
// Return   発注成功時ture それ以外false
bool CloseOrderAll(
uint slippage,                //許容スリッピング
color arrowColor = clrNONE    //注文矢印の色
);

//------------------------------------------------------------------
// 注文を変更する。
// Return   発注成功時ture それ以外false
bool ModifyOrder(
int index,              //決済するインデックス
double price,           //価格
uint stoploss,          //ストップロス(Pips単位)
uint takeprofit,        //利確値(Pips単位)
datetime expiration,    //注文有効期限
color arrowColor        //注文矢印の色
);

//------------------------------------------------------------------
// すべての注文を変更する。
bool ModifyOrderAll(
double price,           //価格
uint stoploss,          //ストップロス(Pips単位)
uint takeprofit,        //利確値(Pips単位)
datetime expiration,    //注文有効期限
color arrowColor        //注文矢印の色
);

//------------------------------------------------------------------
// 注文を変更する。
// Return   発注成功時ture それ以外false
bool ModifyOrder(
int index,              //決済するインデックス
uint stoploss,          //ストップロス(Pips単位)
uint takeprofit,        //利確値(Pips単位)
color arrowColor        //注文矢印の色
);

//------------------------------------------------------------------
// すべての注文を変更する。
bool ModifyOrderAll(
uint stoploss,          //ストップロス(Pips単位)
uint takeprofit,        //利確値(Pips単位)
color arrowColor        //注文矢印の色
);

//------------------------------------------------------------------
// 現在のポジション数を取得する。
// Return   現在のポジション数を取得する。
int GetPositionCount(){ return m_positions.Total(); };

//------------------------------------------------------------------
// 最大のポジション数を取得する。
// Return   最大のポジション数を取得する。
int GetMaxPosition() { return m_maxPosition; } ;

//------------------------------------------------------------------
// 1pipsあたりの値を取得する。
// Return   1pipあたりの値
double GetPipsValue() { return Point() * m_pipsRate; } ;

//------------------------------------------------------------------
// ポジションリストを更新する。
void RefreshPositions();

private:

//------------------------------------------------------------------
// 設定パラメータが安全かどうか
// Return 安全ture それ以外false
bool IsSafeParameter();

};

//------------------------------------------------------------------
// コンストラクタ
CTradingWrapper::CTradingWrapper(
string symbol,          //対象通貨ペア
int magicNumber = 0,    //マジックナンバー
int maxPosition = 3,    //最大ポジション数
uint timeout = 1000     //タイムアウト(ms)
)
{
m_symbol = symbol;
m_magicNumber = magicNumber;
m_maxPosition = maxPosition;
m_timeout = timeout;
m_positions.Resize(m_maxPosition);

//Pips計算 小数点桁数が3or5の場合、Point()*10=1pips
m_digit =  (int)MarketInfo(m_symbol, MODE_DIGITS);

m_pipsRate = m_digit == 3 || m_digit == 5 ? 10 : 1;

for( int i = 0 ; i < OrdersTotal(); i++)
{
if( OrderSelect(i, SELECT_BY_POS) )
{
if( OrderMagicNumber() == m_magicNumber && OrderSymbol() == m_symbol)
{
m_positions.Add(OrderTicket());
}
}
}
}

//------------------------------------------------------------------
// デストラクタ
CTradingWrapper::~CTradingWrapper()
{
}

//------------------------------------------------------------------
// 発注する
// Return   発注成功時インデックス それ以外-1
int CTradingWrapper::SendOrder(
int cmd,                      //売買種別
double volume,                //売買ロット
double price,                 //価格(成行き時は現在値を自動設定)
uint slippage,                //許容スリッピング(Pips単位)
uint stoploss = 0,            //ストップロス(Pips単位)
uint takeprofit = 0,          //利確値(Pips単位)
string comment = NULL,        //コメント
datetime expiration = 0,      //注文有効期限
color arrowColor = clrNONE    //注文矢印の色
)
{
if( !this.IsSafeParameter() ) return -1;
if( m_positions.Total() >= m_positions.Max() ) return -1 ;

// 計算用 負数フラグ
int flag = cmd == OP_BUY || cmd == OP_BUYLIMIT || cmd == OP_BUYSTOP ? 1 : -1;

uint start = GetTickCount();
while(true)
{
if( (GetTickCount() - start ) > m_timeout ) return -1;

double bid = MarketInfo(m_symbol, MODE_BID);
double ask = MarketInfo(m_symbol, MODE_ASK);

if( cmd == OP_SELL ) price = bid;
if( cmd == OP_BUY ) price = ask;

double closeTarget = cmd == OP_BUY || cmd == OP_BUYLIMIT || cmd == OP_BUYSTOP ? bid : ask;

//pips値からストップロス値、利益確定値を取得する。
double stoplossValue = 0 ;
double takeprofitValue = 0;
if( stoploss != 0 )
{
stoplossValue = NormalizeDouble(closeTarget - this.GetPipsValue() * stoploss * flag, m_digit );
}
if( takeprofit != 0)
{
takeprofitValue = NormalizeDouble(closeTarget + this.GetPipsValue() * takeprofit * flag, m_digit );
}

if( IsTradeAllowed() )
{
if( AccountFreeMarginCheck(m_symbol, cmd, volume) < 0 )
{
return -1;
}

int tiket = ::OrderSend(m_symbol, cmd, volume, price,
slippage * m_pipsRate, stoplossValue, takeprofitValue,
comment, m_magicNumber, expiration, arrowColor);

if( tiket >= 0 )
{
m_positions.Add(tiket);
return m_positions.Total() - 1;
}
else
{
int errorCode = GetLastError();

// リトライしても仕方がないエラーの時は終了してしまう。
if( errorCode == ERR_INVALID_PRICE ||
errorCode == ERR_INVALID_STOPS ||
errorCode == ERR_INVALID_TRADE_VOLUME ||
errorCode == ERR_NOT_ENOUGH_MONEY )
{
return -1;
}
}
}
Sleep(100);
}
Print("SendOrder Timeout");
return -1;
}

//------------------------------------------------------------------
// 成行き決済を行う。
// Return   発注成功時ture それ以外false
bool CTradingWrapper::CloseOrder(
int index,                    //決済するインデックス
uint slippage,                //許容スリッピング
color arrowColor = clrNONE    //注文矢印の色
)
{
uint start = GetTickCount();
while(true)
{
if( (GetTickCount() - start ) > m_timeout ) return false;

if( IsTradeAllowed() )
{
// オーダーが選択できない状態(すでに存在しない)場合は、リストから削除して終了する。
int targetTicket = m_positions.At(index);
if( !OrderSelect(targetTicket, SELECT_BY_TICKET) )
{
m_positions.Delete(index);
return false;
}

if( OrderClose(OrderTicket(),OrderLots(), OrderClosePrice(), slippage * m_pipsRate, arrowColor) )
{
m_positions.Delete(index);
return true;
}
else
{
int errorCode = GetLastError();
Print("Close Error[",  errorCode, "] ");

// リトライしても仕方がないエラーの時は終了してしまう。
if( errorCode == ERR_INVALID_TICKET)
{
m_positions.Delete(index);
return false;
}
}
}
Sleep(100);
}

Print("CloseOrder Timeout");

return false;
}

//------------------------------------------------------------------
// 全ポジションを成行き決済を行う。
// Return   発注成功時ture それ以外false
bool CTradingWrapper::CloseOrderAll(
uint slippage,                // 許容スリッピング
color arrowColor = clrNONE    // 注文矢印の色
)
{
RefreshPositions();
bool result = true;
for( int i = m_positions.Total() - 1; i >= 0; i--)
{
result &= this.CloseOrder(i, slippage, arrowColor);
}

return result;
}

//------------------------------------------------------------------
// 注文を変更する。
// Return   発注成功時ture それ以外false
bool CTradingWrapper::ModifyOrder(
int index,                 //決済するインデックス
double price,              //価格
uint stoploss = 0,         //ストップロス(Pips単位)
uint takeprofit = 0,       //利確値(Pips単位)
datetime expiration = 0,   //注文有効期限
color arrowColor = clrNONE // 注文矢印の色
)
{
uint start = GetTickCount();
while(true)
{
if( (GetTickCount() - start ) > m_timeout ) return false;

if( IsTradeAllowed() )
{
// オーダーが選択できない状態(すでに存在しない)場合は、リストから削除して終了する。
int targetTicket = m_positions.At(index);
if( !OrderSelect(targetTicket, SELECT_BY_TICKET) )
{
m_positions.Delete(index);
return false;
}

double bid = MarketInfo(m_symbol, MODE_BID);
double ask = MarketInfo(m_symbol, MODE_ASK);

int cmd = OrderType();
// 計算用 負数フラグ
int flag = cmd == OP_BUY || cmd == OP_BUYLIMIT || cmd == OP_BUYSTOP ? 1 : -1;

double closeTarget = cmd == OP_BUY || cmd == OP_BUYLIMIT || cmd == OP_BUYSTOP ? bid : ask;
//pips値からストップロス値、利益確定値を取得する。
double stoplossValue = 0 ;
double takeprofitValue = 0;
if( stoploss != 0 )
{
stoplossValue = NormalizeDouble(closeTarget - this.GetPipsValue() * stoploss * flag, m_digit );
}
if( takeprofit != 0)
{
takeprofitValue = NormalizeDouble(closeTarget + this.GetPipsValue() * takeprofit * flag, m_digit );
}

if( OrderModify(targetTicket, price, stoplossValue, takeprofitValue, expiration, arrowColor ))
{
return true;
}
else
{
int errorCode = GetLastError();
Print("Order Error[",  errorCode, "] ");

// リトライしても仕方がないエラーの時は終了してしまう。
if( errorCode == ERR_INVALID_PRICE ||
errorCode == ERR_INVALID_STOPS ||
errorCode == ERR_INVALID_TRADE_VOLUME ||
errorCode == ERR_NOT_ENOUGH_MONEY)
{
return false;
}
}
}
}
Print("ModifyOrder Timeout");
return false;
}

//------------------------------------------------------------------
// すべての注文を変更する。
bool CTradingWrapper::ModifyOrderAll(
double price,              //価格
uint stoploss = 0,         //ストップロス(Pips単位)
uint takeprofit = 0,       //利確値(Pips単位)
datetime expiration = 0,   //注文有効期限
color arrowColor = clrNONE // 注文矢印の色
)
{
RefreshPositions();
bool result = true;
for( int i = m_positions.Total() - 1; i >= 0; i--)
{
result &= this.ModifyOrder(i, price, stoploss, takeprofit, expiration, arrowColor);
}

return result;
}

//------------------------------------------------------------------
// 注文を変更する。
// Return   発注成功時ture それ以外false
bool CTradingWrapper::ModifyOrder(
int index,                 //決済するインデックス
uint stoploss,             //ストップロス(Pips単位)
uint takeprofit = 0,       //利確値(Pips単位)
color arrowColor = clrNONE //注文矢印の色
)
{
return this.ModifyOrder(index, 0, stoploss, takeprofit, 0, arrowColor);
}

//------------------------------------------------------------------
// すべての注文を変更する。
bool CTradingWrapper::ModifyOrderAll(
uint stoploss,             //ストップロス(Pips単位)
uint takeprofit = 0,       //利確値(Pips単位)
color arrowColor = clrNONE //注文矢印の色
)
{
RefreshPositions();
return this.ModifyOrderAll(0, stoploss, takeprofit, 0, arrowColor);
}

//------------------------------------------------------------------
// 設定パラメータが安全かどうか
// Return 安全ture それ以外false
bool CTradingWrapper::IsSafeParameter()
{
if( m_symbol == NULL ) return false;
if( m_maxPosition == 0 ) return false;
return true;
}

//------------------------------------------------------------------
// ポジションリストを更新する。
void CTradingWrapper::RefreshPositions()
{
m_positions.Clear();
for( int i = 0 ; i < OrdersTotal(); i++)
{
if( OrderSelect(i, SELECT_BY_POS) )
{
if( OrderMagicNumber() == m_magicNumber && OrderSymbol() == m_symbol)
{
m_positions.Add(OrderTicket());
}
}
}
}


2015.4.17 クラスのコードを修正しました。
2015.5.15 新しい記事をアップしています。