//+------------------------------------------------------------------+
//| EAは、一連の不採算取引が指定された数に達すると
//| さらなる作業を求めるメッセージ ボックス ウィンドウを表示する
//| 指定されたバー数待って、作業を続行するリクエストを含むMessageBoxを
//| 表示する
//| 簡単にするために、EAはマジックナンバーによって独自の「ポジション」を
//| 制御しないため、確認するには、
//| 損失のある複数のポジションを手動で開閉する必要がある
//+------------------------------------------------------------------+
//--- 入力パラメータ
input uint InpMaxLossDeals = 3; // 最大損失取引
input uint InpInactivityNumBars = 5; // EAが非アクティブなバーの数
//--- グローバル変数
bool ExtFirstStart=true; // 初起動フラグ
bool ExtFlag=true; // EAの動作を許可するフラグ
uint ExtNumLoss; // 連続不採算取引の回数
datetime ExtTimeLastLoss; // 負けポジションを決済する最後の取引の時間
//+------------------------------------------------------------------+
//| エキスパート初期化関数 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 連続の負け取引の数と、ポジションを閉じるための最後の取引の時間を取得する
ExtNumLoss=GetNumLosingTradesInRow(ExtTimeLastLoss);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| エキスパート初期化解除関数 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Comment("");
}
//+------------------------------------------------------------------+
//| エキスパートティック関数 |
//+------------------------------------------------------------------+
void OnTick()
{
//--- シリーズで最後に閉じた負けポジションから経過したバー数を決定する
int bars_remaining=iBarShift(Symbol(),PERIOD_CURRENT,ExtTimeLastLoss);
//--- 初起動の場合
if(ExtFirstStart)
{
//--- 一連の不採算ポジションの後、指定された数のバーがすでに経過した場合、EA動作フラグを設定する
if(bars_remaining>(int)InpInactivityNumBars)
ExtFlag=true;
ExtFirstStart=false;
}
//--- EA操作フラグが無効な場合
if(!ExtFlag)
{
Comment(StringFormat("The advisor is stopped for %d bars. Num Loss positions: %u, Time last loss: %s",
(InpInactivityNumBars-bars_remaining),ExtNumLoss,TimeToString(ExtTimeLastLoss,TIME_DATE|TIME_MINUTES|TIME_SECONDS)));
//--- 一連の不採算ポジションの後、指定された数のバーが経過した場合
if(bars_remaining>(int)InpInactivityNumBars)
{
//--- 指定されたテキストとウィンドウタイトルを持つメッセージ ボックスウィンドウを表示する
//--- リクエストウィンドウには2つのはい/いいえボタンと疑問符の付いたアイコンがある
//--- デフォルトでは[はい]ボタンが選択されている
string mb_text="The specified number of bars of EA inactivity have passed.\n Continue its work?";
string mb_caption="Please note";
int mb_id=MessageBox(mb_text,mb_caption,MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON1);
//--- メッセージボックスからのリターンコードが[はい]ボタンが押されたことを示す場合、EA操作フラグを設定する
if(mb_id==IDYES)
{
ExtFlag=true;
return;
}
}
//--- EA操作フラグが無効な場合、OnTick()を終了する
return;
}
//--- EA操作フラグが設定されている - EAは以下のコードで提供されるように機能する
Comment(StringFormat("The advisor is working. Num Loss positions: %u, Time last loss: %s, Elapsed Bars: %d",
ExtNumLoss,TimeToString(ExtTimeLastLoss,TIME_DATE|TIME_MINUTES|TIME_SECONDS),bars_remaining));
}
//+------------------------------------------------------------------+
//| TradeTransaction関数 |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
const MqlTradeRequest& request,
const MqlTradeResult& result)
{
//--- 取引タイプが取引を履歴に追加する場合
if(trans.type==TRADE_TRANSACTION_DEAL_ADD)
{
//--- 取引チケットを取得し、チケットごとにリストから取引を選択する
ulong deal_ticket=trans.deal;
if(HistoryDealSelect(deal_ticket))
{
//--- これが市場からのエグジット取引の場合、連続の負け取引の数と最後の取引の時間を取得する
ENUM_DEAL_ENTRY entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(deal_ticket,DEAL_ENTRY);
if(entry==DEAL_ENTRY_OUT || entry==DEAL_ENTRY_INOUT || entry==DEAL_ENTRY_OUT_BY)
ExtNumLoss=GetNumLosingTradesInRow(ExtTimeLastLoss);
}
}
//--- 連続した負け取引の数が指定された値より大きく、EA操作フラグが有効な場合
if(ExtNumLoss>=InpMaxLossDeals && ExtFlag)
{
//--- 指定されたテキストとウィンドウタイトルを持つメッセージ ボックスウィンドウを表示する
//--- リクエストウィンドウには2つのはい/いいえボタンと感嘆符の付いたアイコンがある
//--- デフォルトでは[いいえ]ボタンが選択されている
string mb_text="The number of losing trades has reached the specified maximum. The advisor is stopped.\n Continue its work?";
string mb_caption="Attention!";
int mb_id=MessageBox(mb_text,mb_caption,MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2);
//--- メッセージボックスからのリターンコードが[いいえ]ボタンが押されたことを示す場合、EA操作フラグを無効にする
if(mb_id==IDNO)
ExtFlag=false;
}
}
//+------------------------------------------------------------------+
//| 連続不採算取引の回数と |
//| 損失ポジションを決済するための最後の取引の時刻を返す |
//+------------------------------------------------------------------+
uint GetNumLosingTradesInRow(datetime &time_last_deal)
{
//--- 履歴全部を選択する
if(!HistorySelect(0,TimeCurrent()))
return(0);
//--- ループ内の過去の取引のリストから次の取引チケットを取得する
uint res=0;
uint total=HistoryDealsTotal();
for(int i=(int)total-1; i>=0; i--)
{
ulong deal_ticket=HistoryDealGetTicket(i);
if(deal_ticket>0)
{
//--- ポジションを閉じるための取引ではない場合は、次の取引に進む
ENUM_DEAL_ENTRY entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(deal_ticket,DEAL_ENTRY);
if(entry!=DEAL_ENTRY_OUT && entry!=DEAL_ENTRY_OUT_BY && entry!=DEAL_ENTRY_INOUT)
continue;
//--- ポジションを閉じた結果利益が得られた場合、ループを中断する
if(!IsClosePositionWithLoss(deal_ticket))
break;
//--- 連続損失取引のカウンターを増やす
res++;
//--- 最大取引時間を変数に書き込む(最後の取引時間を探す)
datetime deal_time=(datetime)HistoryDealGetInteger(deal_ticket,DEAL_TIME);
if(deal_time>time_last_deal)
time_last_deal=deal_time;
}
}
//--- 連続不採算取引の回数を返す
return(res);
}
//+------------------------------------------------------------------+
//| 損失でポジションを閉じるフラグを返す |
//+------------------------------------------------------------------+
bool IsClosePositionWithLoss(const ulong deal_ticket)
{
//--- 取引からの利益に影響を与えるプロパティの値を取得する
double profit=HistoryDealGetDouble(deal_ticket,DEAL_PROFIT);
double comission=HistoryDealGetDouble(deal_ticket,DEAL_COMMISSION);
double swap=HistoryDealGetDouble(deal_ticket,DEAL_SWAP);
double fee=HistoryDealGetDouble(deal_ticket,DEAL_FEE);
//--- 受け取ったプロパティの合計値が負であることを示すフラグを返す
return(profit+comission+swap+fee<0);
}
|