English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
가격 상관 관계 통계 데이터를 기반으로 신호 필터링

가격 상관 관계 통계 데이터를 기반으로 신호 필터링

MetaTrader 5트레이딩 | 4 8월 2021, 17:18
246 0
Михаил Тарачков
Михаил Тарачков

여기에 이르기까지

이 기사를 쓰게 된 계기는 세계 최고 투자 기록 보유자(1987년 자본금 11,000% 증가)가 이론이 풍부하고 가난한 대학 교수들과 다른 학자들의 신화를 완전히 떨쳐버리고 있다는 래리 윌리엄스의 책 "단기 트레이딩의 장기 비밀" 을 읽고 난 후 떠올랐습니다. 시장을 잘 알고 있어서.."과거 가격 행태와 미래의 추세 사이에 상관관계가 없는 것에 대해 설명합니다.

만약 동전을 100번 던지면, 50번은 앞면이, 50번은 뒷면이 위로 떨어질겁니다. 연속해서 동전을 던질 때, 앞면이 나올 확률은 50%, 뒷면도 마찬가지입니다. 모든 것은 우연에 의존하며 기록되지도 않기에 몇 번을 던져도 확률은 바뀌지 않습니다. 시장이 코인의 혼돈과 같다고 가정해보십시오.

따라서 새 막대가 나타나면 가격이 오르내릴 기회가 동일하며 이전 막대는 현재 막대에 전혀 영향을 미치지 않습니다. 맘마미아! 거래 시스템을 생성하고, 이익실현을 정지 손절매보다 크게 설정하면(즉, 예상 계산 설정을 양수값의 영역으로), 그러면 끝납니다. 약간의 숨고르기. 하지만 문제는 시장의 행동에 대한 우리의 가정은 사실이 아니라는 것입니다. 솔직히 말하면, 괴상할 정도죠! 이에 대해 입증하겠습니다.

MQL5 Wizard를 이용하여 Expert Advisor 템플릿을 만들고 간단한 영숫자 개입을 사용하여 과제 수행에 적합한 조건으로 제시합니다. Expert Advisor를 인코딩하여 1, 2, 3 막대를 닫은 후의 매수를 시뮬레이션합니다. 시뮬레이션은 프로그램이 분석된 막대의 패러미터를 단순히 기억한다는 것을 의미합니다. 스프레드 및 스왑이 수신된 정보의 신뢰성이 의심받을 수 있기 때문에 이 경우 주문 전송(일반적인 방식)이 작동하지 않습니다.

코드는 다음과 같습니다:

//+------------------------------------------------------------------+
//|                                                     explorer.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//---Variables---
double profit_percent,open_cur,close_cur;
double profit_trades=0,loss_trades=0,day_cur,hour_cur,min_cur,count;
double open[],close[];
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
/* Calculate percent of closures with increase from the total number */
   profit_percent=NormalizeDouble(profit_trades*100/(profit_trades+loss_trades),2);
   Print("Percent of closures with increase ",profit_percent,"%");   // Enter data to the Journal
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---find out the time---
   MqlDateTime time;                        // Create a structure to store time
   TimeToStruct(TimeCurrent(),time);         // Structuring the data
   day_cur=time.day_of_week;              // Receive the value of the current day
   hour_cur=time.hour;                    // Receive the current hour
   min_cur=time.min;                      // Receive the current minute
//---Find out the prices---
   CopyOpen(NULL,0,0,4,open);ArraySetAsSeries(open,true);
   CopyClose(NULL,0,0,4,close);ArraySetAsSeries(close,true);

   if(close[1]<open[1]/*&&close[2]<open[2]&&close[3]<open[3]*/ && count==0) // If it closed with a loss
     {
      open_cur=open[0];                   // Remember open price of the current bar
      count=1;
     }
   if(open_cur!=open[0] && count==1)      // The current bar has closed
     {
      close_cur=close[1];                 // Remember the close price of the formed bar
      count=0;
      if(close_cur>=open_cur)profit_trades+=1;  // If the close price is higher than open,
      else loss_trades+=1;                      // +1 to closures with profit, otherwise +1 to closures with loss
     }
  }
//+------------------------------------------------------------------+

테스트는 EUR/USD로, 2000년 1월 1일부터 2010년 12월 31일까지의 구간을 대상으로 실시됩니다.

1번 그림. 증가한 청산 비율

1번 그림. 증가한 청산 비율

(첫 번째 열은 단일, 이중, 삼중 청산 후 두 번째, 세 번째, 네 번째 전체 기간에 대한 데이터를 표시합니다)

이것이 제가 말하고자했던 것입니다! 매매가 항상 손실을 만회하려 하기 때문에 이전의 막대는 현재 막대에 상당히 큰 영향을 미칩니다.


일 보 전진입니다

좋습니다! 각격 변동이 우연이 아니라는 것을 깨달았으니 우리는 이 놀라운 사실을 활용해야합니다. 물론, 독립 매매 시스템 기준으로는 충분치 않습니다만, 끈질기고 종종 오류가 섞이기까지하는 신호들에서 자유롭게 해준다는 점 만으로도 가치가 있습니다. 구현해보도록 하죠!

다음이 필요합니다:

  1. 최소한 지난 1년간 긍정적인 결과를 낳은 자동 매매 시스템.
  2. 가격변동에 상관관계가 있음을 확인하는 재미있는 예.

L. Williams가 저작한 책에서 많은 아이디어를 얻었습니다. 그 중 하나를 공유해드리겠습니다.

매매일(TDW, Trade Day of Week) 전략.만약 한 주의 며칠간은 매수만 할 것이고, 다른 날들엔 숏 포지션만 연다면 어떤 일이 벌어지는지 보게 될 것입니다. . 결국, 우리는 하루 안에 가격이 다른 날보다 더 큰 비율로 오른다고 가정할 수 있습니다. 이유가 뭘까요? 지정학적 상황, 거시경제 통계 또는 A. Elder가 자신의 책에 저술한 대로. 월요일과 화요일은 개미들의 날이고 목요일과 금요일은 전문가들의 시간이라고요? 이해해보도록 노력해봅시다.

먼저, 우리는 매 주의 특정 일에만 할 것이고, 그 다음엔 매도만 할 것입니다. 연구를 마치면 최상의 결과를 얻을 수 있으며 이는 거래 시스템에 대한 필터가 될 것입니다. 그나저나, 그에 관해 첨언하고 싶은 것이 몇 있습니다. 아주 당연하죠!

이 시스템은 두 개의 MAsMACDake에 기반을 두고 있습니다. 신호:                                                            

  1. 빠른 이동 평균이 느린 이동 평균을 아래에서 위로 가로지르고 MACD 히스토그램이 0 선보다 아래라면 매수.
  2. 빠른 이동 평균이 느린 이동 평균을 위에서 아래로 가로지르고 MACD 히스토그램이 0 선보다 위라면 매도

한 지점에서 후행 정지를 사용하여 위치를 종료합니다. 랏이 고정되었습니다 - 0,1. 

 편의 목적으로 제가 별도의 헤더 파일에 Expert Advisor 클래스를 넣어 두었습니다:

//+------------------------------------------------------------------+
//|                                                       moving.mqh |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| Класс my_expert                                                  |
//+------------------------------------------------------------------+
class my_expert
  {                                                  // Creating a class
   // Closed class members
private:
   int               ma_red_per,ma_yel_per;          // Periods of MAs
   int               ma_red_han,ma_yel_han,macd_han; // Handles
   double            sl,ts;                          // Stop orders
   double            lots;                           // Lot
   double            MA_RED[],MA_YEL[],MACD[];       // Arrays for the indicator values
   MqlTradeRequest   request;                         // Structure of a trade request
   MqlTradeResult    result;                          // Structure of a server response
                                                    // Open class members   
public:
   void              ma_expert();                                   // Constructor
   void get_lot(double lot){lots=lot;}                               // Receiving a lot  
   void get_periods(int red,int yel){ma_red_per=red;ma_yel_per=yel;} // Receiving the periods of MAs
   void get_stops(double SL,double TS){sl=SL;ts=TS;}                  // Receiving the values of stops
   void              init();                                         // Receiving the indicator values
   bool              check_for_buy();                                // Checking for buy
   bool              check_for_sell();                               // Checking for sell
   void              open_buy();                                     // Open buy
   void              open_sell();                                    // Open sell
   void              position_modify();                              // Position modification
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
/* Function definition */
//---Constructor---
void my_expert::ma_expert(void)
  {
//--- Reset the values of variables
   ZeroMemory(ma_red_han);
   ZeroMemory(ma_yel_han);
   ZeroMemory(macd_han);
  }
//---The function for receiving the indicator values---
void  my_expert::init(void)
  {
   ma_red_han=iMA(_Symbol,_Period,ma_red_per,0,MODE_EMA,PRICE_CLOSE); // Handle of the slow MA
   ma_yel_han=iMA(_Symbol,_Period,ma_yel_per,0,MODE_EMA,PRICE_CLOSE); // Handle of the fast MA
   macd_han=iMACD(_Symbol,_Period,12,26,9,PRICE_CLOSE);               // Handle of MACDaka
//---Copy data into arrays and set indexing like in a time-series---
   CopyBuffer(ma_red_han,0,0,4,MA_RED);
   CopyBuffer(ma_yel_han,0,0,4,MA_YEL);
   CopyBuffer(macd_han,0,0,2,MACD);
   ArraySetAsSeries(MA_RED,true);
   ArraySetAsSeries(MA_YEL,true);
   ArraySetAsSeries(MACD,true);
  }
//---Function to check conditions to open buy---   
bool my_expert::check_for_buy(void)
  {
   init();  //Receive values of indicator buffers
/* If the fast MA has crossed the slow MA from bottom up between 2nd and 3rd bars, 
   and there was no crossing back. MACD-hist is below zero */
   if(MA_RED[3]>MA_YEL[3] && MA_RED[1]<MA_YEL[1] && MA_RED[0]<MA_YEL[0] && MACD[1]<0)
     {
      return(true);
     }
   return(false);
  }
//----Function to check conditions to open sell---
bool my_expert::check_for_sell(void)
  {
   init();  //Receive values of indicator buffers
/* If the fast MA has crossed the slow MA from up downwards between 2nd and 3rd bars,
  and there was no crossing back. MACD-hist is above zero */
   if(MA_RED[3]<MA_YEL[3] && MA_RED[1]>MA_YEL[1] && MA_RED[0]>MA_YEL[0] && MACD[1]>0)
     {
      return(true);
     }
   return(false);
  }
//---Open buy---
/* Form a standard trade request to buy */
void my_expert::open_buy(void)
  {
   request.action=TRADE_ACTION_DEAL;
   request.symbol=_Symbol;
   request.volume=lots;
   request.price=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
   request.sl=request.price-sl*_Point;
   request.tp=0;
   request.deviation=10;
   request.type=ORDER_TYPE_BUY;
   request.type_filling=ORDER_FILLING_FOK;
   OrderSend(request,result);
   return;
  }
//---Open sell---
/* Form a standard trade request to sell */
void my_expert::open_sell(void)
  {
   request.action=TRADE_ACTION_DEAL;
   request.symbol=_Symbol;
   request.volume=lots;
   request.price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
   request.sl=request.price+sl*_Point;
   request.tp=0;
   request.deviation=10;
   request.type=ORDER_TYPE_SELL;
   request.type_filling=ORDER_FILLING_FOK;
   OrderSend(request,result);
   return;
  }
//---Position modification---
void my_expert::position_modify(void)
  {
   if(PositionGetSymbol(0)==_Symbol)
     {     //If a position is for our symbol
      request.action=TRADE_ACTION_SLTP;
      request.symbol=_Symbol;
      request.deviation=10;
      //---If a buy position---
      if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
        {
/* if distance from price to stop loss is more than trailing stop
   and the new stop loss is not less than the previous one */
         if(SymbolInfoDouble(Symbol(),SYMBOL_BID)-PositionGetDouble(POSITION_SL)>_Point*ts)
           {
            if(PositionGetDouble(POSITION_SL)<SymbolInfoDouble(Symbol(),SYMBOL_BID)-_Point*ts)
              {
               request.sl=SymbolInfoDouble(Symbol(),SYMBOL_BID)-_Point*ts;
               request.tp=PositionGetDouble(POSITION_TP);
               OrderSend(request,result);
              }
           }
        }
      //---If it is a sell position---                
      else if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
        {
/*  if distance from price to stop loss is more than the trailing stop value
   and the new stop loss is not above the previous one. Or the stop loss from the moment of opening is equal to zero */
         if((PositionGetDouble(POSITION_SL)-SymbolInfoDouble(Symbol(),SYMBOL_ASK))>(_Point*ts))
           {
            if((PositionGetDouble(POSITION_SL)>(SymbolInfoDouble(Symbol(),SYMBOL_ASK)+_Point*ts)) || 
               (PositionGetDouble(POSITION_SL)==0))
              {
               request.sl=SymbolInfoDouble(Symbol(),SYMBOL_ASK)+_Point*ts;
               request.tp=PositionGetDouble(POSITION_TP);
               OrderSend(request,result);
              }
           }
        }
     }
  }
//+------------------------------------------------------------------

"MQL5의 객체 지향 접근으로 Expert Advisor 작성하기" 문서의 저자분께 경의를 표합니다. 그게 없었더라면 전 아무것도 할 수 없었을 것입니다! 만약 악랄하지만서도 몹시 쓸모있는 객체 지향 프로그래밍에 익숙치 않으신 분은 이 문서를 읽는 것을 추천드립니다.

Expert Advisor의 메인 코드에 클래스와 파일을 추가한다? 객체를 생성하고 함수를 초기화합니다:

//+------------------------------------------------------------------+
//|                                                       Moving.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//---Include a file with the class---
#include <moving.mqh>
//---External Variables---
input int MA_RED_PERIOD=7; // The period of a slow MA
input int MA_YEL_PERIOD=2; // The period of a fast MA
input int STOP_LOSS=800;   // Stop loss
input int TRAL_STOP=800;   // Trailing stop
input double LOTS=0.1;     // Lot
//---Create an object---
my_expert expert;
//---Initialize the MqlDataTime structure---
MqlDateTime time;
int day_of_week;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---Initialize the EA
   expert.get_periods(MA_RED_PERIOD,MA_YEL_PERIOD);   // Set the MA periods
   expert.get_lot(LOTS);                              // Set the lot
   expert.get_stops(STOP_LOSS,TRAL_STOP);             // Set stop orders  
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   TimeToStruct(TimeCurrent(),time);
   day_of_week=time.day_of_week;
   if(PositionsTotal()<1)
     {
      if(day_of_week==5 && expert.check_for_buy()==true){expert.open_buy();}
      else if(day_of_week==1 && expert.check_for_sell()==true){expert.open_sell();}
     }
   else expert.position_modify();
  }
//+------------------------------------------------------------------+

끝났네요! 몇가지 특수 기능을 언급하고 넘어가고 싶습니다. 소프트웨어 단에서 한 주의 요일들을 구분하기 위해 저는 MqlDateTime 구조를 사용했습니다. 첫째, 현재 서버 시간을 구조화된 형식으로 변환합니다. 현재(1-월, ...일, 5-금)에 대한 인덱스를 입수하여 설정한 값과 비교합니다.

시도해보세요! 지루한 조사와 추가 자릿수로 부담을 주지 않기 위해 모든 결과를 표로 가져오겠습니다.

여기에 있습니다: 

테이블 1. 주중 매수 요약

테이블 1. 주중 매수 요약

테이블 2. 주중 매도 요약

테이블 2. 주중 매도 요약

최고의 결과는 녹색으로, 최악의 결과는 주황색으로 표기되어 있습니다.

위에서 설명한 조치 후에 시스템이 낮은 상대적 하락과 함께 수익을 보장해야 하며, 매매마다 고수익을 올리면서 상당한 비율의 거래를 성사시켜야 한다고 예약합니다 (여기선 매매가 적을수록 좋음).

보다시피 가장 효과적인 시스템은 금요일에 매수하고 월요일에 매도하는 것입니다. 이 두가지 조건을 합치면:

if(PositionsTotal()<1){
      if(day_of_week==5&&expert.check_for_buy()==true){expert.open_buy();}
      else if(day_of_week==1&&expert.check_for_sell()==true){expert.open_sell();}}
   else expert.position_modify();

이제 Expert Advisor가 포지션을 양쪽으로 열지만 딱 정해진 날에만 하게 됩니다 이해하기 쉬우시도록 필터를 넣은, 그리고 넣지 않은 도표를 각각 그리겠습니다:

2번 그림. 필터를 사용하지 않은 EA 테스트 결과(EURUSD, H1, 01.01.2010-31.12.2010,)

2번 그림. 필터를 사용하지 않은 EA 테스트 결과(EURUSD, H1, 01.01.2010-31.12.2010,)

3번 그림. 필터를 사용한 EA 테스트 결과(EURUSD, H1, 01.01.2010-31.12.2010,)

3번 그림. 필터를 사용한 EA 테스트 결과(EURUSD, H1, 01.01.2010-31.12.2010,)

결과가 어떻습니까? 필터를 사용하는 것으로 매매 시스템이 더 안정적으로 변합니다. 수정하기 전에 Expert Advisor는 주로 테스트 기간의 상반기에 잔고를 증가시켰으며, "업그레이드" 후에는 전체 기간 동안 잔고를 증가시켰습니다.

이제 리포트들을 비교합니다:

테이블 3. 필터를 사용하기 전과 후의 결과

테이블 3. 필터를 사용하기 전과 후의 결과

유일한 골칫거리는 순이익이 거의 1000달러(26%)나 감소한 것입니다. 하지만 거래 건수는 거의 3, 5분의 1으로 줄이고 있습니다. 첫째, 손실을 보는 매매를 시도할 가능성을 크게 줄이고 둘째, 스프레드 비용(218*2-62*2=312 USD, EUR/USD에 한함). 을 얻어낼 가능성이 57%로 상승했는데, 이는 꽤나 의미있습니다. 매매 당 이득은 14% 올라 113 USD가 되었고요. L. Williams라면 이리 말했을 겁니다: "이거야 말로 매매할 가치가 있는 액수지!"


마치며

가격변동은 랜덤이 아닙니다 - 이것은 명백한 사실입니다. 이 사실은 충분히 이용할 수 있으며, 이용해야만 합니다. 거래 시스템의 성능을 향상시킬 수 있는 무수한 변형과 기법의 극히 일부에 불과한 예를 하나 드렸습니다. 그러나 이러한 다양성엔 결점이 있습니다. 모든 필터를 통합할 수 있는 것은 아니므로 모든 가능한 시나리오를 고려하여 신중하게 선택해야 합니다.

필터가 아무리 뛰어나더라도 수익을 올릴 매매 또한 솎아내는 경우가 있단 것을 잊지 마세요... 행운을 빕니다!


MetaQuotes 소프트웨어 사를 통해 러시아어가 번역됨.
원본 기고글: https://www.mql5.com/ru/articles/269

파일 첨부됨 |
explorer.mq5 (2.84 KB)
moving.mq5 (2.28 KB)
moving.mqh (6.98 KB)
선형 회귀 예시를 통한 인디케이터 가속 그 3가지 방법 선형 회귀 예시를 통한 인디케이터 가속 그 3가지 방법
이 문서에서는 인디케이터들의 메소드와 최적화 알고리즘에 대해 다루어볼 것입니다. 모든 독자분이 자신에게 적합한 메소드를 찾을 수 있을것입니다. 총 3개의 메소드가 다뤄집니다. 그 중 하나는 몹시 간단하며, 두번째 것은 탄탄한 수학적 지식을 필요로 하며 마지막 것은 약간 지혜가 필요합니다. 설명된 메소드 대부분을 이해하기 위해 인디케이터나 MetaTrader5 터미널 디자인 기능이 사용되었습니다. 이 메소드들은 매우 보편적이며 선형 회귀 계산의 가속뿐만 아니라 다른 많은 지표에도 사용할 수 있습니다.
트레이딩 내 통계적 분산의 역할 트레이딩 내 통계적 분산의 역할
본 문서는 MQL5의 통계 확률 분포에 대해 논하고 이론적 통계 분산을 다루는 클래스들을 다룬 제 다른 문서의 논리적 후속작입니다. 이제 이론적 기반이 확보되었으므로 실제 데이터 셋으로 직접 이동하여 이 기반을 정보적으로 활용할 것을 제안합니다.
MQL5 에서의 통계적 확률 분산 MQL5 에서의 통계적 확률 분산
이 문서에서는 적용 통계에 사용되는 랜덤 변수의 확률 분포(정규 분포, 로그-정규 분포, 이항 분포, 로그 분포, 지수 분포, 코시 분포, 스튜던트 t 분포, 라플라스 분포, 푸아송 분포, 쌍곡 시컨트 분포, 베타 및 감마 분포)를 다룹니다. 또한 이러한 배포를 처리하기 위한 클래스도 제공됩니다.
C++ 템플릿의 대안으로 가짜 템플릿 사용 C++ 템플릿의 대안으로 가짜 템플릿 사용
이 글은 템플릿을 사용하지 않고 ihernet 프로그래밍 스타일을 유지하는 프로그래밍 방법을 설명합니다. 사용자 지정 방법을 사용하여 템플릿을 구현하는 방법에 대해 설명하고 지정된 템플릿을 기반으로 코드를 생성하기 위해 미리 만들어진 스크립트가 첨부되어 있습니다.