OnTick

この関数は、NewTickイベントが発生して新しい相場が処理されるときに、EAで呼び出されます。

void  OnTick(void);

戻り値

なし

注意事項

NewTickイベントは、EAが取り付けられているチャートのシンボルに対して新しいティックを受け取ったときに、EAに対してのみ生成されます。NewTickイベントが生成されていないため、カスタム指標またはスクリプトでOnTick()関数を定義することはできません。

TickイベントはEAに対してのみ生成されますが、Timer、BookEvent、およびChartEventイベントはNewTickに加えてEAに対しても生成されるため、EAにOnTick()関数を実装する必要はありません。

全てのイベントは、受信された順に次々に処理されます。キューにすでに NewTickイベントがある、またはこのイベントが処理段階にある場合、新しいNewTickイベントはMQL5アプリケーションキューには追加されません。

NewTickイベントは、自動取引が有効になっているかどうかに関係なく生成されます(自動取引ボタン)。自動取引の無効化とは、EAからの取引リクエスト送信を禁止することのみを意味します。EAの動作は停止されません。

AutoTradingボタンを押して自動取引を無効にしても、OnTick()関数の現在の実行が中断されることはありません。

OnTick()関数内の取引ロジック全体を特長とするEAの例

//+------------------------------------------------------------------+
//|                                                   TradeByATR.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2024, MetaQuotes Ltd."
#property link     "https://www.mql5.com"
#property version   "1.00"
#property description "Sample EA trading in the \"explosive\" candle direction"
#property description "\"Explosive\" candle has the body size exceeding k*ATR"
#property description "The \"revers\" parameter reverses the signal direction"
 
input double lots=0.1;       // ロット単位のボリューム
input double kATR=3;         // ATRのシグナルローソク足の長さ
input int   ATRperiod=20;   // ATR指標期間
input int   holdbars=8;     // ポジションのバー数
input int   slippage=10;     // 許容されるスリッページ
input bool   revers=false;   // シグナルを反転するかどうか
input ulong EXPERT_MAGIC=0; // EAのマジックナンバー
//--- ATR指標ハンドルを格納
int atr_handle;
//--- ここで最後のATR値とローソク足のの実体を保存する
double last_atr,last_body;
datetime lastbar_timeopen;
double trade_lot;
//+------------------------------------------------------------------+
//| エキスパート初期化関数                                                |
//+------------------------------------------------------------------+
int OnInit()
 {
//--- グローバル変数を初期化する
  last_atr=0;
  last_body=0;
//--- 正しいボリュームを設定する
  double min_lot=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
  trade_lot=lots>min_lot?lots:min_lot;  
//--- ATR指標ハンドルを作成する
  atr_handle=iATR(_Symbol,_Period,ATRperiod);
  if(atr_handle==INVALID_HANDLE)
    {
    PrintFormat("%s: failed to create iATR, error code %d",__FUNCTION__,GetLastError());
    return(INIT_FAILED);
    }
//--- EA初期化が成功した
  return(INIT_SUCCEEDED);
 }
//+------------------------------------------------------------------+
//| エキスパート初期化解除に使用される関数                                    |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
 {
//--- EA操作終了コードを通知する
  Print(__FILE__,": Deinitialization reason code = ",reason);
 }
//+------------------------------------------------------------------+
//| エキスパートティック関数                                                 |
//+------------------------------------------------------------------+
void OnTick()
 {
//--- 取引シグナル
  static int signal=0; // +1は買いシグナル、 -1は売りシグナル
//--- 'holdbars'バーより前に開かれた以前のポジションを確認して決済する
  ClosePositionsByBars(holdbars,slippage,EXPERT_MAGIC);
//--- 新しいバーを確認する
  if(isNewBar())
    {
    //--- シグナルの存在を確認する
     signal=CheckSignal();
    }
//--- ネットポジションが開かれている場合は、信号をスキップして終了する
  if(signal!=0 && PositionsTotal()>0 && (ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_NETTING)
    {
     signal=0;
    return; // NewTickイベントハンドラを終了し、新しいバーが現れる前に市場に入らない
    }
//--- ヘッジ口座の場合、各ポジションは個別に保持され、決済される
  if(signal!=0)
    {
    //--- 買いシグナル
    if(signal>0)
       {
        PrintFormat("%s: Buy signal!Revers=%s",__FUNCTION__,string(revers));
        if(Buy(trade_lot,slippage,EXPERT_MAGIC))
           signal=0;
       }
    //--- 売りシグナル
    if(signal<0)
       {
        PrintFormat("%s: Sell signal!Revers=%s",__FUNCTION__,string(revers));
        if(Sell(trade_lot,slippage,EXPERT_MAGIC))
           signal=0;
       }
    }
//--- OnTick関数の終わり
 }
//+------------------------------------------------------------------+
//| 新しい取引シグナルを確認する                                            |
//+------------------------------------------------------------------+
int CheckSignal()
 {
//--- 0はシグナルが不在なことを意味する
  int res=0;
//--- 終わりから2番目の完全なバーにATR値を取得する(バーのインデックスは2)
  double atr_value[1];
  if(CopyBuffer(atr_handle,0,2,1,atr_value)!=-1)
    {
     last_atr=atr_value[0];
    //--- 最後に閉じたバーのデータをMqlRates型配列に取得する
    MqlRates bar[1];
    if(CopyRates(_Symbol,_Period,1,1,bar)!=-1)
       {
        //--- 最後の完全なバーでバー本体のサイズを計算する
        last_body=bar[0].close-bar[0].open;
        //--- 最後のバー(インデックス1)の本体が以前のATR値(インデックス2のバー上)を超える場合、取引シグナルが受信される
        if(MathAbs(last_body)>kATR*last_atr)
           res=last_body>0?1:-1; // 上昇ローソク足では正の値
       }
    else
        PrintFormat("%s: Failed to receive the last bar!Error",__FUNCTION__,GetLastError());
    }
  else
    PrintFormat("%s: Failed to receive ATR indicator value!Error",__FUNCTION__,GetLastError());
//--- 反転取引モードが有効な場合
  res=revers?-res:res; // 必要に応じてシグナルを反転させる(1の代わりに-1を返し、逆も同様)
//--- 取引シグナル値を返す
  return (res);
 }
//+------------------------------------------------------------------+
//|   新しいバーが現れると'true'                                           |
//+------------------------------------------------------------------+
bool isNewBar(const bool print_log=true)
 {
  static datetime bartime=0; // 現在のバーの開いた時刻を格納する
//--- ゼロバーの開いた時間を取得する
  datetime currbar_time=iTime(_Symbol,_Period,0);
//--- 新しいバーが到着すると開いた時刻が変わる
  if(bartime!=currbar_time)
    {
     bartime=currbar_time;
     lastbar_timeopen=bartime;
    //--- ログに新しいバーが開いている時間のデータを表示する
    if(print_log && !(MQLInfoInteger(MQL_OPTIMIZATION)||MQLInfoInteger(MQL_TESTER)))
       {
        //--- 新しいバーを開いた時間のメッセージを表示する
        PrintFormat("%s: new bar on %s %s opened at %s",__FUNCTION__,_Symbol,
                    StringSubstr(EnumToString(_Period),7),
                    TimeToString(TimeCurrent(),TIME_SECONDS));
        //--- 最後のティックのデータを取得する
        MqlTick last_tick;
        if(!SymbolInfoTick(Symbol(),last_tick))
          Print("SymbolInfoTick() failed, error = ",GetLastError());
        //--- 最後のティックタイムをミリ秒まで表示する
        PrintFormat("Last tick was at %s.%03d",
                    TimeToString(last_tick.time,TIME_SECONDS),last_tick.time_msc%1000);
       }
    //--- 新しいバーがある
    return (true);
    }
//--- 新しいバーがない
  return (false);
 }
//+------------------------------------------------------------------+
//| 成行価格で指定された量で買う                                           |
//+------------------------------------------------------------------+
bool Buy(double volume,ulong deviation=10,ulong  magicnumber=0)
 {
//--- 成行価格で買う
  return (MarketOrder(ORDER_TYPE_BUY,volume,deviation,magicnumber));
 }
//+------------------------------------------------------------------+
//| 成行価格で指定された量で売る                                           |
//+------------------------------------------------------------------+
bool Sell(double volume,ulong deviation=10,ulong  magicnumber=0)
 {
//--- 成行価格で売る
  return (MarketOrder(ORDER_TYPE_SELL,volume,deviation,magicnumber));
 }
//+------------------------------------------------------------------+
//| バー数によるポジション保留時間ごとにポジションを決済する                          |
//+------------------------------------------------------------------+
void ClosePositionsByBars(int holdtimebars,ulong deviation=10,ulong  magicnumber=0)
 {
  int total=PositionsTotal(); // ポジション数
//--- ポジションをすべて見る
  for(int i=total-1; i>=0; i--)
    {
    //--- ポジションパラメータ
    ulong  position_ticket=PositionGetTicket(i);                                     // ポジションチケット
    string position_symbol=PositionGetString(POSITION_SYMBOL);                       // シンボル
    ulong  magic=PositionGetInteger(POSITION_MAGIC);                                 // ポジションマジックナンバー
    datetime position_open=(datetime)PositionGetInteger(POSITION_TIME);               // ポジションの開かれた時刻
    int bars=iBarShift(_Symbol,PERIOD_CURRENT,position_open)+1;                       // ポジションがどれだけ前(バー数)に開かれたか
 
    //--- マジックナンバーとシンボルが一致していてポジションがすでに長くある場合
    if(bars>holdtimebars && magic==magicnumber && position_symbol==_Symbol)
       {
        int   digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS);           // 小数点以下桁数
        double volume=PositionGetDouble(POSITION_VOLUME);                             // ポジションボリューム
        ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // ポジションの種類
        string str_type=StringSubstr(EnumToString(type),14);
        StringToLower(str_type); // 正しいメッセージ書式設定のために小文字にする
        PrintFormat("Close position #%I64u %s %s %.2f",
                    position_ticket,position_symbol,str_type,volume);
        //--- 注文タイプを設定し、取引リクエストを送信する
        if(type==POSITION_TYPE_BUY)
           MarketOrder(ORDER_TYPE_SELL,volume,deviation,magicnumber,position_ticket);
        else
           MarketOrder(ORDER_TYPE_BUY,volume,deviation,magicnumber,position_ticket);
       }
    }
 }
//+------------------------------------------------------------------+
//| 取引リクエストを準備して送信する                                          |
//+------------------------------------------------------------------+
bool MarketOrder(ENUM_ORDER_TYPE type,double volume,ulong slip,ulong magicnumber,ulong pos_ticket=0)
 {
//--- 構造体の宣言と初期化
  MqlTradeRequest request={};
  MqlTradeResult  result={};
  double price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
  if(type==ORDER_TYPE_BUY)
     price=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
//--- リクエストパラメータ
  request.action   =TRADE_ACTION_DEAL;                     // 取引操作の種類
  request.position =pos_ticket;                           // 決済する場合のポジションチケット
  request.symbol   =Symbol();                             // シンボル
  request.volume   =volume;                               // ボリューム
  request.type     =type;                                 // 注文の種類
  request.price    =price;                                 // 取引価格
  request.deviation=slip;                                 // 価格からの許容偏差
  request.magic    =magicnumber;                           // 注文のマジックナンバー
//--- リクエストを送信する
  if(!OrderSend(request,result))
    {
    //--- 失敗したらデータを表示する
    PrintFormat("OrderSend %s %s %.2f at %.5f error %d",
                 request.symbol,EnumToString(type),volume,request.price,GetLastError());
    return (false);
    }
//--- 操作の成功を知らせる
  PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
  return (true);
 }

参照

Event handling functionsProgram runningClient terminal eventsOnTimerOnBookEventOnChartEvent