OnTick

이 함수는 새 값을 처리하기 위해 NewTick 이벤트가 발생할 때 EA로 호출됩니다.

void  OnTick(void);

반환 값

반환값 없음

참고

NewTick 이벤트는 EA가 첨부된 차트의 기호에 대한 새로운 틱을 수신하는 즉시 EA에 대해서만 생성됩니다. 커스텀 지표 또는 스크립트에서 OnTick() 기능을 정의해도 새Tick 이벤트가 생성되지 않으므로 의미가 없습니다.

Tick 이벤트는 EA에 대해서만 생성되지만, NewTick 외에 EA에 대해서도 Timer, BookEvent 및 ChartEvent 이벤트가 생성되므로 EA에서 OnTick() 함수를 사용할 필요는 없습니다.

모든 이벤트는 영수증 순서대로 하나씩 처리됩니다. 대기열에 이미 NewTick 이벤트가 포함되어 있거나 이 이벤트가 처리 단계에 있는 경우 새 NewTick 이벤트가 mql5 애플리케이션 대기열에 추가되지 않습니다.

NewTick 이벤트는 자동 거래 활성화 여부에 관계없이 생성됩니다(AutoTrading 버튼). 비활성화된 자동 거래란 EA로부터의 거래 요청 전송만 금지하는 것을 의미합니다. EA 작업은 중지되지 않습니다.

AutoTrading 버튼을 눌러 자동 거래를 비활성화해도 OnTick() 함수의 현재 실행이 중단되지는 않습니다.

EA의 예제, OnTick() 함수에 전체 거래 논리 포함

//+------------------------------------------------------------------+
//|                                                   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 "EA 거래 예시 \"폭발적\" 캔들 방향"
#property description "\"폭발적\" 캔들의 몸체 크기가 k*ATR을 초과합니다"
#property description "\"리버스\" 파라미터가 시그널 방향을 리버스합니다"
 
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's MagicNumber
//--- ATR 지표 핸들 보관용
int atr_handle;
//--- 여기에 마지막 ATR 값과 캔들 바디를 저장할 것입니다.
double last_atr,last_body;
datetime lastbar_timeopen;
double trade_lot;
//+------------------------------------------------------------------+
//| Expert 초기화 함수                                   |
//+------------------------------------------------------------------+
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: iATR 생성 실패, 에러 코드 %d",__FUNCTION__,GetLastError());
      return(INIT_FAILED);
     }
//--- EA 초기화 성공
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert 초기화 해제 함수                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- EA 작업 종료 코드 통지
   Print(__FILE__,": 초기화해제 근거 코드 = ",reason);
  }
//+------------------------------------------------------------------+
//| Expert 틱 함수                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- 거래 시그널
   static int signal=0; // +1은 매수 시그널을, -1은 매도 시그널을 의미합니다
//--- 'holdbars' 막대 보다 이전에 오픈된 포지션을 확인 후 마감합니다
   ClosePositionsByBars(holdbars,slippage,EXPERT_MAGIC);
//--- 새 막대 점검
   if(isNewBar())
     {
      //--- 시그널 유무를 확인      
      signal=CheckSignal();
     }
//--- netting 포지션이 오픈한 경우 시그널을 스킵합니다 - 시그널 마감까지 대기하십시오
   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: 매수 시그널! Revers=%s",__FUNCTION__,string(revers));
         if(Buy(trade_lot,slippage,EXPERT_MAGIC))
            signal=0;
        }
      //--- 매도 시그널
      if(signal<0)
        {
         PrintFormat("%s: 매도 시그널! Revers=%s",__FUNCTION__,string(revers));
         if(Sell(trade_lot,slippage,EXPERT_MAGIC))
            signal=0;
        }
     }
//--- OnTick 함수 종료
  }
//+------------------------------------------------------------------+
//| 새 거래 신호 점검                                   |
//+------------------------------------------------------------------+
int CheckSignal()
  {
//--- 0은 시그널이 없음을 의미합니다
   int res=0;
//--- 끝에서 두번째의 완성된 막대에서 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: 최근 막대 수령에 실패! Error",__FUNCTION__,GetLastError());
     }
   else
      PrintFormat("%s: ATR 지표 값 수신 실패! Error",__FUNCTION__,GetLastError());
//--- 역거래 모드가 활성화된 경우
   res=revers?-res:res;  // 필요한 경우 시그널을 역방향으로(1이 아닌 -1을 반환하고 그 반대로도 반환)
//--- 거래 시그널 값을 반환
   return (res);
  }
//+------------------------------------------------------------------+
//|  새 막대가 나타나면 'true'를 반환                            |
//+------------------------------------------------------------------+
bool isNewBar(const bool print_log=true)
  {
   static datetime bartime=0; // 현재 막대의 오픈 시간 저장
//--- 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);                                  // 포지션 MagicNumber
      datetime position_open=(datetime)PositionGetInteger(POSITION_TIME);               // 포지션 오픈 시간
      int bars=iBarShift(_Symbol,PERIOD_CURRENT,position_open)+1;                       // 몇 개 막대 전에 포지션이 오픈되었는지
 
      //--- MagicNumber와 심볼이 일치하는 동안 포지션의 수명이 이미 큰 경우
      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("클로즈 포지션 #%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={0};
   MqlTradeResult  result={0};
   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;                           // 주문 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 functions, Program running, Client terminal events, OnTimer, OnBookEvent, OnChartEvent