English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
Expert Advisor 작업 중 균형 곡선의 기울기 조절

Expert Advisor 작업 중 균형 곡선의 기울기 조절

MetaTrader 5트레이딩 | 5 7월 2021, 16:14
76 0
Dmitriy Skub
Dmitriy Skub


소개

이 기사에서는 피드백 생성을 통해 Expert Advisor의 성과를 개선 할 수 있는 접근 방식 중 하나를 설명합니다. 이 경우 피드백은 균형 곡선의 기울기 측정을 기반으로 합니다. 작업량을 조절하여 슬로프 제어를 자동으로 수행합니다. Expert Advisor는 컷 볼륨, 랏 작업량 (초기 조정된 항목에 따라) 및 중간 볼륨으로 거래 할 수 있습니다. 작업 모드가 자동으로 전환됩니다.

피드백 체인에는 계단식, 히스테리시스가 있는 계단식, 선형 등 다양한 조절 특성이 사용됩니다. 특정 시스템의 특성에 맞게 균형 곡선의 기울기를 제어하는 ​​시스템을 조정할 수 있습니다.

주요 아이디어는 자신의 거래 시스템을 모니터링하면서 거래자를위한 의사 결정 프로세스를 자동화하는 것입니다. 작업 중 불리한 기간 동안 위험을 줄이는 것이 합리적입니다. 정상 작동 모드로 돌아 가면 위험은 초기 수준으로 복원될 수 있습니다.

물론 이 시스템은 만병 통치약이 아니며 패배한 Expert Advisor을 수익성 있는 것으로 바꿔주지는 않습니다. 어쩐지 이것은 Expert Advisor의 MM (money management)에 추가되어 계정에서 상당한 손실을 입지 않도록 합니다.

이 기사에는 이 기능을 Expert Advisor의 코드에 포함 할 수 있는 라이브러리가 포함되어 있습니다.


작동 원리

균형 곡선의 기울기를 제어하는 ​​시스템의 작동 원리를 살펴 보겠습니다. 거래 Expert Advisor가 있다고 가정합니다. 가설적인 균형 곡선은 다음과 같습니다.

균형 곡선의 기울기를 제어하는 ​​시스템의 작동 원리

그림 1. 균형 곡선의 기울기를 제어하는 ​​시스템의 작동 원리

일정한 거래량을 사용하는 Expert Advisor의 초기 잔액 곡선은 위에 나와 있습니다. 닫힌 거래는 빨간색 포인트로 표시됩니다. 거래 중 Expert Advisor의 잔액 변화를 나타내는 곡선 (굵은 검은 색 선)으로 이러한 점을 연결해 보겠습니다.

이제 시간 축 (가는 파란색 선으로 표시됨)에 대한이 선의 기울기 각도를 지속적으로 추적 할 것입니다. 또는 더 정확하게 말하면 신호로 각 거래를 개시하기 전에 이전에 마감된 두 거래 (또는 설명을 더 간단하게 하기 위해 두 번의 거래)로 기울기 각도를 계산합니다. 경사각이 지정된 값보다 작아지면 제어 시스템이 작동하기 시작합니다. 계산된 각도 값과 지정된 조절 기능에 따라 볼륨을 줄입니다.

이러한 방식으로 거래가 실패한 기간에 접어 들면 거래량은 Vmax.에서 Vmin.으로 감소합니다. Т3... Т5 거래 기간 내에서... Т5 포인트 거래가 최소 지정 거래량으로 수행 된 후 거래량 거부 모드에서 말이죠. Expert Advisor의 수익성이 회복되고 균형 곡선의 기울기 각도가 지정된 값 이상으로 상승하면 볼륨이 증가하기 시작합니다. 이는 Т8 ... Т10 간격 내에서 발생합니다. Т10 지점 이후 거래량은 초기 상태 Vmax로 복원됩니다.

이러한 규제의 결과로 형성된 균형 곡선은 그림 1의 하단에 나와 있습니다. B1에서 B2까지의 초기 감소폭이 감소하고 B1에서 B2*로 변경되었음을 알 수 있습니다. 또한 최대 볼륨 Т8 ... Т10 복원 기간 동안 수익이 약간 감소한 것을 볼 수 있습니다. 이것은 메달의 반대입니다.

녹색은 최소 지정 거래량으로 거래를 수행했을 때 잔액 곡선의 일부를 강조합니다. 노란색은 최대 볼륨에서 최소 볼륨으로의 전환 부분을 나타냅니다. 여기에서 몇 가지 전환 변형이 가능합니다.

  • 계단식 - 최대 볼륨에서 최소 볼륨까지 이산 단계로 볼륨이 변경됩니다.
  • 선형 - 조절된 간격 내에서 균형 곡선의 기울기 각도에 따라 볼륨이 선형으로 변경됩니다.
  • 히스테리시스로 계단식 - 최대 볼륨에서 최소 볼륨으로 전환하고 기울기 각도의 차이 값에서 뒤로 가 수행됩니다.

그림으로 설명해 봅시다.

조절 특성의 유형

그림 2. 조절 특성의 유형

조절 특성은 제어 시스템의 속도에 영향을 미칩니다. 활성화/비활성화, 최대 볼륨에서 최소 볼륨으로 전환하는 과정의 지연이라는 측면에서 말이죠. 최상의 테스트 결과에 도달 할 때 실험적으로 특성을 선택하는 것이 좋습니다.

따라서 균형 곡선의 기울기 각도에 따른 피드백으로 거래 시스템을 강화합니다. 이러한 볼륨 규제는 거래 시스템 자체의 일부로 볼륨이 없는 시스템에만 적합합니다. 예를 들어 Martingale 원칙을 사용하는 경우 초기 Expert Advisor를 변경하지 않고는 이 시스템을 직접 사용할 수 없습니다.

또한 다음과 같은 중요한 사항에 주의를 기울여야 합니다.

  • 밸런스 라인의 기울기를 관리하는 효과는 볼륨 거부 모드의 볼륨에 대한 정상 작동 모드의 작업 볼륨 비율에 직접적으로 의존합니다. 이 비율이 클수록 관리가 더 효과적입니다. 이것이 초기 작업량이 가능한 최소 작업량보다 훨씬 커야하는 이유입니다.
  • Expert Advisor 잔액의 상승 및 하강 평균 변경 기간은 제어 시스템의 반응 시간보다 상당히 길어야 합니다. 그렇지 않으면 시스템이 균형 곡선의 기울기를 조절하지 못합니다. 반응 시간에 대한 평균 기간의 비율이 클수록 시스템이 더 효과적입니다. 이 요구 사항은 거의 모든 자동 조절 시스템에 적용됩니다.

객체 지향 프로그래밍을 사용하여 MQL5에서 구현

위에서 설명한 접근 방식을 실현하는 라이브러리를 작성해 보겠습니다. 이를 위해 MQL5의 새로운 기능인 객체 지향 접근 방식을 사용하겠습니다. 이 접근 방식을 사용하면 코드의 큰 부분을 처음부터 다시 작성하지 않고도 향후 라이브러리를 쉽게 개발하고 확장 할 수 있습니다.


TradeSymbol 클래스

다중 통화 테스트는 새로운 MetaTrader 5 플랫폼에서 구현되기 때문에 모든 작업 기호로 전체 작업을 자체적으로 캡슐화하는 클래스가 필요합니다. 다중 통화 Expert Advisors에서이 라이브러리를 사용할 수 있습니다. 이 클래스는 제어 시스템과 직접적인 관련이 없으며 보조입니다. 따라서 이 클래스는 작업 기호가 있는 작업에 사용됩니다.

//---------------------------------------------------------------------
//  Operations with work symbol:
//---------------------------------------------------------------------
class TradeSymbol
{
private:
  string  trade_symbol;                          // work symbol

private:
  double  min_trade_volume;                      // minimum allowed volume for trade operations
  double  max_trade_volume;                      // maximum allowed volume for trade operations
  double  min_trade_volume_step;                 // minimum change of volume
  double  max_total_volume;                      // maximum change of volume
  double  symbol_point;                          // size of one point
  double  symbol_tick_size;                      // minimum change of price
  int     symbol_digits;                        // number of digits after decimal point

protected:

public:
  void    RefreshSymbolInfo( );                  // refresh market information about the work symbol
  void    SetTradeSymbol( string _symbol );      // set/change work symbol
  string  GetTradeSymbol( );                     // get work symbol
  double  GetMaxTotalLots( );                    // get maximum cumulative volume
  double  GetPoints( double _delta );            // get change of price in points

public:
  double  NormalizeLots( double _requied_lot );  // get normalized trade volume
  double  NormalizePrice( double _org_price );   // get normalized price with consideration of step of change of quote

public:
  void    TradeSymbol( );                       // constructor
  void    ~TradeSymbol( );                      // destructor
};

클래스 구조는 매우 간단합니다. 목적은 지정된 기호로 현재 시장 정보를 가져오고 저장하고 처리하는 것입니다. 주요 메소드는 TradeSymbol::RefreshSymbolInfo, TradeSymbol::NormalizeLots, TradeSymbol::NormalizePrice입니다. 하나씩 고려해 봅시다.


TradeSymbol::RefreshSymbolInfo 메소드는 작업 기호로 시장 정보를 새로 고치기 위한 것입니다.

//---------------------------------------------------------------------
//  Refresh market information by work symbol:
//---------------------------------------------------------------------
void
TradeSymbol::RefreshSymbolInfo( )
{
//  If a work symbol is not set, don't do anything:
  if( GetTradeSymbol( ) == NULL )
  {
    return;
  }

//  Calculate parameters necessary for normalization of volume:
  min_trade_volume = SymbolInfoDouble( GetTradeSymbol( ), SYMBOL_VOLUME_MIN );
  max_trade_volume = SymbolInfoDouble( GetTradeSymbol( ), SYMBOL_VOLUME_MAX );
  min_trade_volume_step = SymbolInfoDouble( GetTradeSymbol( ), SYMBOL_VOLUME_STEP );

  max_total_volume = SymbolInfoDouble( GetTradeSymbol( ), SYMBOL_VOLUME_LIMIT );

  symbol_point = SymbolInfoDouble( GetTradeSymbol( ), SYMBOL_POINT );
  symbol_tick_size = SymbolInfoDouble( GetTradeSymbol( ), SYMBOL_TRADE_TICK_SIZE );
  symbol_digits = ( int )SymbolInfoInteger( GetTradeSymbol( ), SYMBOL_DIGITS );
}

여러 방법에서 사용되는 한 가지 중요한 점에 주의하십시오. MQL5의 현재 실현에서는 매개 변수가 있는 생성자를 사용할 수 없으므로 작업 기호의 기본 설정을 위해 다음 메소드를 호출해야 합니다.

void    SetTradeSymbol( string _symbol );      // set/change work symbol


TradeSymbol::NormalizeLots 메소드는 정확하고 정규화된 거래량을 얻기 위해 사용됩니다. 포지션의 크기는 브로커가 허용하는 최소값보다 작을 수 없다는 것을 알고 있습니다. 포지션 변경의 최소 단계도 브로커에 의해 결정되며 다를 수 있습니다. 이 메소드는 바닥에서 가장 가까운 볼륨 값을 반환합니다.

또한 예상 포지션의 볼륨이 브로커가 허용하는 최대 값을 초과하는지 확인합니다.

//---------------------------------------------------------------------
//  Get normalized trade volume:
//---------------------------------------------------------------------
//  - input necessary volume;
//  - output is normalized volume;
//---------------------------------------------------------------------
double
TradeSymbol::NormalizeLots( double _requied_lots )
{
  double   lots, koeff;
  int      nmbr;

//  If a work symbol is not set, don't do anything:
  if( GetTradeSymbol( ) == NULL )
  {
    return( 0.0 );
  }

  if( this.min_trade_volume_step > 0.0 )
  {
    koeff = 1.0 / min_trade_volume_step;
    nmbr = ( int )MathLog10( koeff );
  }
  else
  {
    koeff = 1.0 / min_trade_volume;
    nmbr = 2;
  }
  lots = MathFloor( _requied_lots * koeff ) / koeff;

//  Lower limit of volume:
  if( lots < min_trade_volume )
  {
    lots = min_trade_volume;
  }

//  Upper limit of volume:
  if( lots > max_trade_volume )
  {
    lots = max_trade_volume;
  }

  lots = NormalizeDouble( lots, nmbr );
  return( lots );
}


TradeSymbol::NormalizePrice 메소드는 정확하고 정규화된 가격을 얻기 위해 사용됩니다. 주어진 기호에 대해 소수점 뒤의 유효 자릿수 (가격의 정확성)를 결정해야 하므로 가격을 잘라야 합니다. 또한 일부 심볼 (예 : 선물)은 최소 가격 변동 단계가 1 포인트 이상입니다. 그렇기 때문에 가격의 가치를 최소 불분명도의 배수로 만들어야 합니다.

//---------------------------------------------------------------------
//  Normalization of price with consideration of step of price change:
//---------------------------------------------------------------------
double
TradeSymbol::NormalizePrice( double _org_price )
{
//  Minimal step of quote change in points:
  double  min_price_step = NormalizeDouble( symbol_tick_size / symbol_point, 0 );

  double  norm_price = NormalizeDouble( NormalizeDouble(( NormalizeDouble( _org_price / symbol_point, 0 )) / min_price_step, 0 ) * min_price_step * symbol_point, symbol_digits );
  return( norm_price );
}

필요한 비정규화 가격이 함수에 입력됩니다. 그리고 필요한 가격에 가장 가까운 정규화된 가격을 반환합니다.

다른 방법의 목적은 주석에 명확하게 설명되어 있습니다. 추가 설명이 필요하지 않습니다.


TBalanceHistory 클래스

이 클래스는 계정 잔액의 내역을 사용하기 위한 것으로 이름이 분명합니다. 아래에서 설명하는 여러 클래스의 기본 클래스이기도 합니다. 이 클래스의 주요 목적은 Expert Advisor의 거래 내역에 액세스하는 것입니다. 또한 작업 기호, "매직 넘버", Expert Advisor 모니터링 시작 날짜 또는 세 요소 모두를 동시에 사용하여 이력을 필터링 할 수 있습니다.

//---------------------------------------------------------------------
//  Operations with balance history:
//---------------------------------------------------------------------
class TBalanceHistory
{
private:
  long      current_magic;            // value of "magic number" when accessing the history of deals ( 0 - any number )
  long      current_type;             // type of deals ( -1 - all )
  int       current_limit_history;   // limit of depth of history ( 0 - all history )
  datetime   monitoring_begin_date;   // date of start of monitoring history of deals
  int       real_trades;             // number of actual trades already performed

protected:
  TradeSymbol  trade_symbol;          // operations with work symbol

protected:
//  "Raw" arrays:
  double    org_datetime_array[ ];                                                                                                                                                      // date/time of trade
  double    org_result_array[ ];                                                                                                                                                                // result of trade

//  Arrays with data grouped by time:
  double    group_datetime_array[ ];                                                                                                                                            // date/time of trade
  double    group_result_array[ ];                                                                                                                                                      // result of trade

  double    last_result_array[ ];     // array for storing results of last trades ( points on the Y axis )
  double    last_datetime_array[ ];   // array for storing time of last trades ( points on the X axis )

private:
  void      SortMasterSlaveArray( double& _m[ ], double& _s[ ] );  // synchronous ascending sorting of two arrays

public:
  void      SetTradeSymbol( string _symbol );                      // set/change work symbol
  string    GetTradeSymbol( );                                    // get work symbol
  void      RefreshSymbolInfo( );                                 // refresh market information by work symbol
  void      SetMonitoringBeginDate( datetime _dt );                // set date of start of monitoring
  datetime  GetMonitoringBeginDate( );                            // get date of start of monitoring
  void      SetFiltrParams( long _magic, long _type = -1, int _limit = 0 );// set parameters of filtration of deals

public:
// Get results of last trades:
  int       GetTradeResultsArray( int _max_trades );

public:
  void      TBalanceHistory( );       // constructor
  void      ~TBalanceHistory( );      // destructor
};

마지막 거래 및 이력의 결과를 읽을 때 필터링 설정은 TBalanceHistory::SetFiltrParams 메소드를 사용하여 설정됩니다. 다음과 같은 입력 매개 변수가 있습니다.

  • _magic           - 기록에서 읽어야 하는 거래의 "매직 넘버"입니다. 0 값이 지정되면 "매직 넘버"로 거래를 읽습니다.
  • _유형             - 읽어야 할 거래 유형입니다. 다음 값을 가질 수 있습니다. DEAL_TYPE_BUY (매수 거래 읽기 전용), DEAL_TYPE_SELL (짧은 거래 읽기 전용) 및 -1 (매수 및 매도 거래 모두 읽기)
  • _한도             - 분석된 거래 내역의 깊이를 제한합니다. 0과 같으면 사용 가능한 모든 기록이 분석됩니다.

기본적으로 TBalanceHistory 클래스의 개체가 생성 될 때 다음 값이 설정됩니다. _magic = 0, _type = -1, _limit = 0.


이 클래스의 주요 메소드는 TBalanceHistory::GetTradeResultsArray입니다. 클래스 멤버 배열 last_result_arraylast_datetime_array를 마지막 거래의 결과로 채우기 위한 것입니다. 이 메소드에는 다음과 같은 입력 매개 변수가 있습니다.

  • _max_trades - 히스토리에서 읽고 출력 배열에 기록해야 하는 최대 거래 수입니다. 경사각을 계산하려면 최소 2 개의 점이 필요하므로 이 값은 2 이상이어야 합니다. 이 값이 0이면 사용 가능한 전체 거래 내역이 분석됩니다. 실제로 균형 곡선의 기울기 계산에 필요한 점의 수를 여기에 지정합니다.
//---------------------------------------------------------------------
//  Reads the results of last (by time) trades to arrays:
//---------------------------------------------------------------------
//  - returns the number of actually read trades but not more than specified;
//---------------------------------------------------------------------
int
TBalanceHistory::GetTradeResultsArray( int _max_trades )
{
  int       index, limit, count;
  long      deal_type, deal_magic, deal_entry;
  datetime   deal_close_time, current_time;
  ulong     deal_ticket;                        // ticket of deal
  double    trade_result;
  string    symbol, deal_symbol;

  real_trades = 0;

//  Number of trades should be no less than two:
  if( _max_trades < 2 )
  {
    return( 0 );
  }

//  If a work symbol is not specified, don't do anything:
  symbol = trade_symbol.GetTradeSymbol( );
  if( symbol == NULL )
  {
    return( 0 );
  }

//  Request the history of deals and orders from the specified time to the current moment:
  if( HistorySelect( monitoring_begin_date, TimeCurrent( )) != true )
  {
    return( 0 );
  }

//  Calculate number of trades:
  count = HistoryDealsTotal( );

//  If there are less trades in the history than it is necessary, then exit:
  if( count < _max_trades )
  {
    return( 0 );
  }

//  If there are more trades in the history than it is necessary, then limit them:
  if( current_limit_history > 0 && count > current_limit_history )
  {
    limit = count - current_limit_history;
  }
  else
  {
    limit = 0;
  }

//  If needed, adjust dimension of "raw" arrays by the specified number of trades:
  if(( ArraySize( org_datetime_array )) != ( count - limit ))
  {
    ArrayResize( org_datetime_array, count - limit );
    ArrayResize( org_result_array, count - limit );
  }

//  Fill the "raw" array with trades from history base:
  real_trades = 0;
  for( index = count - 1; index >= limit; index-- )
  {
    deal_ticket = HistoryDealGetTicket( index );

//  If those are not closed deals, don't go further:
    deal_entry = HistoryDealGetInteger( deal_ticket, DEAL_ENTRY );
    if( deal_entry != DEAL_ENTRY_OUT )
    {
      continue;
    }

//  Check "magic number" of deal if necessary:
    deal_magic = HistoryDealGetInteger( deal_ticket, DEAL_MAGIC );
    if( current_magic != 0 && deal_magic != current_magic )
    {
      continue;
    }

//  Check symbol of deal:
    deal_symbol = HistoryDealGetString( deal_ticket, DEAL_SYMBOL );
    if( symbol != deal_symbol )
    {
      continue;
    }
                
//  Check type of deal if necessary:
    deal_type = HistoryDealGetInteger( deal_ticket, DEAL_TYPE );
    if( current_type != -1 && deal_type != current_type )
    {
      continue;
    }
    else if( current_type == -1 && ( deal_type != DEAL_TYPE_BUY && deal_type != DEAL_TYPE_SELL ))
    {
      continue;
    }
                
//  Check time of closing of deal:
    deal_close_time = ( datetime )HistoryDealGetInteger( deal_ticket, DEAL_TIME );
    if( deal_close_time < monitoring_begin_date )
    {
      continue;
    }

//  So, we can read another trade:
    org_datetime_array[ real_trades ] = deal_close_time / 60;
    org_result_array[ real_trades ] = HistoryDealGetDouble( deal_ticket, DEAL_PROFIT ) / HistoryDealGetDouble( deal_ticket, DEAL_VOLUME );
    real_trades++;
  }

//  if there are less trades than necessary, return:
  if( real_trades < _max_trades )
  {
    return( 0 );
  }

  count = real_trades;

//  Sort the "raw" array by date/time of closing the order:
  SortMasterSlaveArray( org_datetime_array, org_result_array );

// If necessary, adjust dimension of group arrays for the specified number of points:
  if(( ArraySize( group_datetime_array )) != count )
  {
    ArrayResize( group_datetime_array, count );
    ArrayResize( group_result_array, count );
  }
  ArrayInitialize( group_datetime_array, 0.0 );
  ArrayInitialize( group_result_array, 0.0 );

//  Fill the output array with grouped data ( group by the identity of date/time of position closing ):
  for( index = 0; index < count; index++ )
  {
//  Get another trade:
    deal_close_time = ( datetime )org_datetime_array[ index ];
    trade_result = org_result_array[ index ];

//  Now check if the same time already exists in the output array:
    current_time = ( datetime )group_datetime_array[ real_trades ];
    if( current_time > 0 && MathAbs( current_time - deal_close_time ) > 0.0 )
    {
      real_trades++;                      // move the pointer to the next element
      group_result_array[ real_trades ] = trade_result;
      group_datetime_array[ real_trades ] = deal_close_time;
    }
    else
    {
      group_result_array[ real_trades ] += trade_result;
      group_datetime_array[ real_trades ] = deal_close_time;
    }
  }
  real_trades++;                          // now this is the number of unique elements

//  If there are less trades than necessary, exit:
  if( real_trades < _max_trades )
  {
    return( 0 );
  }

  if( ArraySize( last_result_array ) != _max_trades )
  {
    ArrayResize( last_result_array, _max_trades );
    ArrayResize( last_datetime_array, _max_trades );
  }

//  Write the accumulated data to the output arrays with reversed indexation:
  for( index = 0; index < _max_trades; index++ )
  {
    last_result_array[ _max_trades - 1 - index ] = group_result_array[ index ];
    last_datetime_array[ _max_trades - 1 - index ] = group_datetime_array[ index ];
  }

//  In the output array replace the results of single trades with the accumulating total:
  for( index = 1; index < _max_trades; index++ )
  {
    last_result_array[ index ] += last_result_array[ index - 1 ];
  }

  return( _max_trades );
}

작업 기호가 지정되어 있고 입력 매개 변수가 올바른지 여부를 확인하기 위해 처음에 의무 검사가 수행됩니다.

그런 다음 지정된 날짜부터 현재까지의 거래 및 주문 내역을 읽습니다. 코드의 다음 부분에서 수행됩니다.

//  Request the history of deals and orders from the specified time to the current moment:
  if( HistorySelect( monitoring_begin_date, TimeCurrent( )) != true )
  {
    return( 0 );
  }

//  Calculate number of trades:
  count = HistoryDealsTotal( );

//  If there are less trades in the history than it is necessary, then exit:
  if( count < _max_trades )
  {
    return( 0 );
  }

또한 이력의 총 거래 수가 확인됩니다. 지정된 것보다 적으면 추가 작업은 의미가 없습니다. "원시"배열이 준비 되자마자 거래 내역의 정보로 채우는 주기가 실행됩니다. 다음과 같은 방식으로 수행됩니다.

//  Fill the "raw" array from the base of history of trades:
  real_trades = 0;
  for( index = count - 1; index >= limit; index-- )
  {
    deal_ticket = HistoryDealGetTicket( index );

//  If the trades are not closed, don't go further:
    deal_entry = HistoryDealGetInteger( deal_ticket, DEAL_ENTRY );
    if( deal_entry != DEAL_ENTRY_OUT )
    {
      continue;
    }

//  Check "magic number" of deal if necessary:
    deal_magic = HistoryDealGetInteger( deal_ticket, DEAL_MAGIC );
    if( _magic != 0 && deal_magic != _magic )
    {
      continue;
    }

//  Check symbols of deal:
    deal_symbol = HistoryDealGetString( deal_ticket, DEAL_SYMBOL );
    if( symbol != deal_symbol )
    {
      continue;
    }
                
//  Check type of deal if necessary:
    deal_type = HistoryDealGetInteger( deal_ticket, DEAL_TYPE );
    if( _type != -1 && deal_type != _type )
    {
      continue;
    }
    else if( _type == -1 && ( deal_type != DEAL_TYPE_BUY && deal_type != DEAL_TYPE_SELL ))
    {
      continue;
    }
                
//  Check time of closing of deal:
    deal_close_time = ( datetime )HistoryDealGetInteger( deal_ticket, DEAL_TIME );
    if( deal_close_time < monitoring_begin_date )
    {
      continue;
    }

//  So, we can rad another trade:
    org_datetime_array[ real_trades ] = deal_close_time / 60;
    org_result_array[ real_trades ] = HistoryDealGetDouble( deal_ticket, DEAL_PROFIT ) / HistoryDealGetDouble( deal_ticket, DEAL_VOLUME );
    real_trades++;
  }

//  If there are less trades than necessary, exit:
  if( real_trades < _max_trades )
  {
    return( 0 );
  }

처음에는 HistoryDealGetTicket 함수를 사용하여 내역에서 거래 티켓을 읽습니다. 획득한 티켓을 사용하여 딜 세부 정보를 더 읽을 수 있습니다. 마감된 거래에만 관심이 있기 때문에 (잔액을 분석할 것입니다) 거래 유형이 먼저 확인됩니다. DEAL_ENTRY 매개 변수와 함께 HistoryDealGetInteger 함수를 호출하면 됩니다. 함수가 DEAL_ENTRY_OUT을 반환하면 포지션 청산입니다.

거래의 "매직 넘버" 이후 거래의 유형 (메소드의 입력 매개 변수가 지정됨) 및 거래의 기호가 확인됩니다. 거래의 모든 매개 변수가 요구 사항을 충족하면 마지막 매개 변수인 거래 마감 시간이 확인됩니다. 다음과 같은 방식으로 수행됩니다.

//  Check the time of closing of deal:
    deal_close_time = ( datetime )HistoryDealGetInteger( deal_ticket, DEAL_TIME );
    if( deal_close_time < monitoring_begin_date )
    {
      continue;
    }

거래 날짜/시간은 기록 모니터링 시작 날짜/시간과 비교됩니다. 거래 날짜/시간이 주어진 거래 시간보다 크면 거래를 배열로 읽어옵니다. 거래 결과와 거래 시간을 분 단위로 읽습니다 (이 경우, 클로징 시간). 그 후, 읽기 거래 real_trades의 카운터가 증가합니다. 주기는 계속됩니다.

"원시" 배열이 필요한 양의 정보로 채워지면 거래 마감 시간이 저장되는 배열을 정렬해야 합니다. 동시에 org_datetime_array 배열의 마감 시간과 org_result_array 배열의 거래 결과의 대응 관계를 유지해야 합니다. 이것은 특별히 작성된 방법을 사용하여 수행됩니다.

TBalanceHistory::SortMasterSlaveArray( double&_master[ ], double&_slave[ ] ). 첫 번째 매개 변수는 _master - 오름차순으로 정렬된 배열입니다. 두 번째 매개 변수는 _ slave입니다. 이 배열의 요소는 첫 번째 배열의 요소와 동기적으로 이동되어야 합니다. 정렬은 "버블" 방법을 통해 수행됩니다.

위에서 설명한 모든 작업 후에 시간별로 정렬된 거래 결과와 시간이 포함된 두 개의 배열이 있습니다. 균형 곡선의 한 지점 (Y 축의 지점)만이 각 시간 (X 축의 지점)에 해당할 수 있으므로, 동일한 마감 시간 (있는 경우)으로 배열의 요소를 그룹화해야 합니다. 코드의 다음 부분은 이 작업을 수행합니다.

//  Fill the output array with grouped data ( group by identity of date/time of closing of position ):
  real_trades = 0;
  for( index = 0; index < count; index++ )
  {
//  Get another trade:
    deal_close_time = ( datetime )org_datetime_array[ index ];
    trade_result = org_result_array[ index ];

//  Now check, if the same time already exists in the output array:
    current_time = ( datetime )group_datetime_array[ real_trades ];
    if( current_time > 0 && MathAbs( current_time - deal_close_time ) > 0.0 )
    {
      real_trades++;                      // move the pointer to the next element
      group_result_array[ real_trades ] = trade_result;
      group_datetime_array[ real_trades ] = deal_close_time;
    }
    else
    {
      group_result_array[ real_trades ] += trade_result;
      group_datetime_array[ real_trades ] = deal_close_time;
    }
  }
  real_trades++;                          // now this is the number of unique elements

실질적으로 "동일" 마감 시간을 가진 모든 거래가 여기에 합산됩니다. 결과는 TBalanceHistory::group_datetime_array (종료 시간) 및 TBalanceHistory::group_result_array (거래 결과) 배열에 기록됩니다. 그 후 우리는 고유한 요소를 가진 두 개의 정렬된 배열을 얻습니다. 이 경우 시간의 정체는 1 분 이내로 고려됩니다. 이 변환은 그래픽으로 설명할 수 있습니다.

같은 시간에 거래 그룹화

그림 3. 같은 시간에 거래 그룹화

1 분 이내의 모든 거래 (그림의 왼쪽 부분)는 시간을 반올림하고 결과를 합산하여 (그림의 오른쪽 부분) 단일 거래로 그룹화됩니다. 이를 통해 거래 성사 시간의 "채터링"을 완화하고 규제의 안정성을 개선할 수 있습니다.

그 후에 얻은 배열을 두 번 더 변형해야 합니다. 가장 빠른 거래가 0 요소에 해당하도록 요소의 순서를 반대로합니다. 단일 거래의 결과를 누적 총액, 즉 잔액으로 대체합니다. 다음 코드 조각에서 수행됩니다.

//  Write the accumulated data into output arrays with reversed indexation:
  for( index = 0; index < _max_trades; index++ )
  {
    last_result_array[ _max_trades - 1 - index ] = group_result_array[ index ];
    last_datetime_array[ _max_trades - 1 - index ] = group_datetime_array[ index ];
  }

//  Replace the results of single trades with the cumulative total in the output array:
  for( index = 1; index < _max_trades; index++ )
  {
    last_result_array[ index ] += last_result_array[ index - 1 ];
  }


TBalanceSlope 클래스

이 클래스는 계정의 잔액 곡선을 사용하여 작업을 수행하기 위한 것입니다. TBalanceHistory 클래스에서 생성됩니다. 보호되고 공개된 모든 데이터와 방법을 상속합니다. 구조를 자세히 살펴 보겠습니다.

//---------------------------------------------------------------------
//  Operations with the balance curve:
//---------------------------------------------------------------------
class TBalanceSlope : public TBalanceHistory
{
private:
  double    current_slope;               // current angle of slope of the balance curve
  int       slope_count_points;          // number of points ( trades ) for calculation of slope angle
        
private:
  double    LR_koeff_A, LR_koeff_B;      // rates for the equation of the straight-line regression
  double    LR_points_array[ ];          // array of point of the straight-line regression

private:
  void      CalcLR( double& X[ ], double& Y[ ] );  // calculate the equation of the straight-line regression

public:
  void      SetSlopePoints( int _number );        // set the number of points for calculation of angle of slope
  double    CalcSlope( );                         // calculate the slope angle

public:
  void      TBalanceSlope( );                     // constructor
  void      ~TBalanceSlope( );                    // destructor
};


균형 곡선에 지정된 포인트 (거래) 수에 대해 그려진 선형 회귀선의 경사각으로 균형 곡선의 경사각을 결정합니다. 따라서 먼저 다음 형식의 직선 회귀 방정식을 계산해야 합니다. A*x + B. 다음 방법이 이 작업을 수행합니다.

//---------------------------------------------------------------------
//  Calculate the equation of the straight-line regression:
//---------------------------------------------------------------------
//  input parameters:
//    X[ ] - arras of values of number series on the X axis;
//    Y[ ] - arras of values of number series on the Y axis;
//---------------------------------------------------------------------
void
TBalanceSlope::CalcLR( double& X[ ], double& Y[ ] )
{
  double    mo_X = 0, mo_Y = 0, var_0 = 0, var_1 = 0;
  int       i;
  int       size = ArraySize( X );
  double    nmb = ( double )size;

//  If the number of points is less than two, the curve cannot be calculated:
  if( size < 2 )
  {
    return;
  }

  for( i = 0; i < size; i++ )
  {
    mo_X += X[ i ];
    mo_Y += Y[ i ];
  }
  mo_X /= nmb;
  mo_Y /= nmb;

  for( i = 0; i < size; i++ )
  {
    var_0 += ( X[ i ] - mo_X ) * ( Y[ i ] - mo_Y );
    var_1 += ( X[ i ] - mo_X ) * ( X[ i ] - mo_X );
  }

//  Value of the A coefficient:
  if( var_1 != 0.0 )
  {
    LR_koeff_A = var_0 / var_1;
  }
  else
  {
    LR_koeff_A = 0.0;
  }

//  Value of the B coefficient:
  LR_koeff_B = mo_Y - LR_koeff_A * mo_X;

//  Fill the array of points that lie on the regression line:
  ArrayResize( LR_points_array, size );
  for( i = 0; i < size; i++ )
  {
    LR_points_array[ i ] = LR_koeff_A * X[ i ] + LR_koeff_B;
  }
}

여기서는 최소 제곱 법을 사용하여 초기 데이터에 대한 회귀선 포지션의 최소 오차를 계산합니다. 계산된 선에있는 Y 좌표를 저장하는 배열도 채워집니다. 이 어레이는 당분간 사용되지 않으며 향후 개발을 위한 것입니다.


주어진 클래스에서 사용되는 주요 방법은 TBalanceSlope::CalcSlope입니다. 마지막 거래의 지정된 양으로 계산된 균형 곡선의 기울기 각도를 반환합니다. 실현은 다음과 같습니다.

//---------------------------------------------------------------------
//  Calculate slope angle:
//---------------------------------------------------------------------
double
TBalanceSlope::CalcSlope( )
{
//  Get result of trading from the history of trades:
  int      nmb = GetTradeResultsArray( slope_count_points );
  if( nmb < slope_count_points )
  {
    return( 0.0 );
  }

//  Calculate the regression line by the results of last trades:
  CalcLR( last_datetime_array, last_result_array );
  current_slope = LR_koeff_A;

  return( current_slope );
}

우선 균형 곡선의 마지막 점의 지정된 양을 분석합니다. 기본 클래스 TBalanceSlope::GetTradeResultsArray의 메소드를 호출하여 수행됩니다. 읽기 포인트의 양이 지정된 것보다 적지 않으면 회귀선이 계산됩니다. >TBalanceSlope::CalcLR 메소드를 사용하여 수행됩니다. 이전 단계에서 채워진 기본 클래스에 속한 last_result_arraylast_datetime_array 배열이 인수로 사용됩니다.

나머지 방법은 간단하며 자세한 설명이 필요하지 않습니다.


TBalanceSlopeControl 클래스

작업량을 수정하여 균형 곡선의 기울기를 관리하는 기본 클래스입니다. TBalanceSlope 클래스에서 생성되며 모든 공개 및 보호 메소드와 데이터를 상속합니다. 이 클래스의 유일한 목적은 균형 곡선의 현재 경사각에 따라 현재 작업량을 계산하는 것입니다. 자세히 살펴보겠습니다:

//---------------------------------------------------------------------
//  Managing slope of the balance curve:
//---------------------------------------------------------------------
enum LotsState
{
  LOTS_NORMAL = 1,            // mode of trading with normal volume
  LOTS_REJECTED = -1,         // mode of trading with lowered volume
  LOTS_INTERMEDIATE = 0,      // mode of trading with intermediate volume
};
//---------------------------------------------------------------------
class TBalanceSlopeControl : public TBalanceSlope
{
private:
  double    min_slope;          // slope angle that corresponds to the mode of volume rejection
  double    max_slope;          // slope angle that corresponds to the mode of normal volume
  double    centr_slope;        // slope angle that corresponds to the mode of volume switching without hysteresis

private:
  ControlType  control_type;    // type of the regulation function

private:
  double    rejected_lots;      // volume in the rejection mode
  double    normal_lots;        // volume in the normal mode
  double    intermed_lots;      // volume in the intermediate mode

private:
  LotsState current_lots_state; // current mode of volume

public:
  void      SetControlType( ControlType _control );  // set type of the regulation characteristic
  void      SetControlParams( double _min_slope, double _max_slope, double _centr_slope );

public:
  double    CalcTradeLots( double _min_lots, double _max_lots );  // get trade volume

protected:
  double    CalcIntermediateLots( double _min_lots, double _max_lots, double _slope );

public:
  void      TBalanceSlopeControl( );   // constructor
  void      ~TBalanceSlopeControl( );  // destructor
};


현재 볼륨을 계산하기 전에 초기 매개 변수를 설정해야 합니다. 다음 메소드를 호출하여 수행됩니다.

  void      SetControlType( ControlType _control );  // set type of the regulation characteristic

입력 매개 변수_제어 - 조절 특성의 유형입니다. 다음 값을 가질 수 있습니다.

  • STEP_WITH_HYSTERESISH      - 히스테리시스 조절 특성으로 계단식;
  • STEP_WITHOUT_HYSTERESIS  - 히스테리시스 조절 특성없이 계단식;
  • LINEAR                                   - 선형 조절 특성;
  • NON_LINEAR                           - 비선형 조절 특성 (이 버전에서는 구현되지 않음);


  void      SetControlParams( double _min_slope, double _max_slope, double _centr_slope );

입력 매개 변수는 다음과 같습니다.

  • _min_slope - 최소 거래량에 해당하는 잔액 곡선의 기울기 각도;
  • _max_slope - 최대 거래량을 가진 거래에 해당하는 균형 곡선의 기울기 각도;
  • _centr_slope - 히스테리시스없이 계단식 조절 특성에 해당하는 균형 곡선의 기울기 각도;


부피는 다음 방법을 사용하여 계산됩니다.

//---------------------------------------------------------------------
//  Get trade volume:
//---------------------------------------------------------------------
double
TBalanceSlopeControl::CalcTradeLots( double _min_lots, double _max_lots )
{
//  Try to calculate slope of the balance curve:
  double    current_slope = CalcSlope( );

//  If the specified amount of trades is not accumulated yet, trade with minimal volume:
  if( GetRealTrades( ) < GetSlopePoints( ))
  {
    current_lots_state = LOTS_REJECTED;
    rejected_lots = trade_symbol.NormalizeLots( _min_lots );
    return( rejected_lots );
  }

//  If the regulation function is stepped without hysteresis:
  if( control_type == STEP_WITHOUT_HYSTERESIS )
  {
    if( current_slope < centr_slope )
    {
      current_lots_state = LOTS_REJECTED;
      rejected_lots = trade_symbol.NormalizeLots( _min_lots );
      return( rejected_lots );
    }
    else
    {
      current_lots_state = LOTS_NORMAL;
      normal_lots = trade_symbol.NormalizeLots( _max_lots );
      return( normal_lots );
    }
  }

//  If the slope of linear regression for the balance curve is less than the allowed one:
  if( current_slope < min_slope )
  {
    current_lots_state = LOTS_REJECTED;
    rejected_lots = trade_symbol.NormalizeLots( _min_lots );
    return( rejected_lots );
  }

//  If the slope of linear regression for the balance curve is greater than specified:
  if( current_slope > max_slope )
  {
    current_lots_state = LOTS_NORMAL;
    normal_lots = trade_symbol.NormalizeLots( _max_lots );
    return( normal_lots );
  }

//  The slope of linear regression for the balance curve is within specified borders (intermediate state):
  current_lots_state = LOTS_INTERMEDIATE;

//  Calculate the value of intermediate volume:
  intermed_lots = CalcIntermediateLots( _min_lots, _max_lots, current_slope );
  intermed_lots = trade_symbol.NormalizeLots( intermed_lots );

  return( intermed_lots );
}

TBalanceSlopeControl::CalcTradeLot s 메소드 구현의 주요 중요 사항은 다음과 같습니다.

  • 지정된 최소 거래량이 누적될 때까지 최소 거래량으로 거래하십시오. 거래를 위해 설정한 직후 Expert Advisor가 현재 어느 기간 (수익성 여부)에 있는지 알 수 없기 때문에 논리적입니다.
  • 조절 기능이 히스테리시스가없는 단계 인 경우 TBalanceSlopeControl::SetControlParams 메소드를 통해 거래 모드 간 전환 각도를 설정하려면 _만 사용해야 합니다. centr_slope 매개 변수. _ min_slope_ max_slope 매개 변수는 무시됩니다. MetaTrader 5 전략 테스터에서이 매개 변수에 의해 올바른 최적화를 수행하기 위해 수행됩니다.

계산된 경사각에 따라 최소, 최대 또는 중간 볼륨으로 거래가 수행됩니다. 중간 볼륨은 간단한 방법인 TBalanceSlopeControl::CalcIntermediateLots를 통해 계산됩니다. 이 방법은 보호되며 클래스 내에서 사용됩니다. 코드는 다음과 같습니다.

//---------------------------------------------------------------------
//  Calculation of intermediate volume:
//---------------------------------------------------------------------
double
TBalanceSlopeControl::CalcIntermediateLots( double _min_lots, double _max_lots, double _slope )
{
  double    lots;

//  If the regulation function is stepped with hysteresis:
  if( control_type == STEP_WITH_HYSTERESISH )
  {
    if( current_lots_state == LOTS_REJECTED && _slope > min_slope && _slope < max_slope )
    {
      lots = _min_lots;
    }
    else if( current_lots_state == LOTS_NORMAL && _slope > min_slope && _slope < max_slope )
    {
      lots = _max_lots;
    }
  }
//  If the regulation function is linear:
  else if( control_type == LINEAR )
  {
    double  a = ( _max_lots - _min_lots ) / ( max_slope - min_slope );
    double  b = normal_lots - a * .max_slope;
    lots = a * _slope + b;
  }
//  If the regulation function is non-linear ( not implemented yet ):
  else if( control_type == NON_LINEAR )
  {
    lots = _min_lots;
  }
//  If the regulation function is unknown:
  else
  {
    lots = _min_lots;
  }

  return( lots );
}

이 클래스의 다른 메소드는 설명이 필요하지 않습니다.


시스템을 Expert Advisor에 임베드하는 예

Exert Advisor에서 균형 곡선의 기울기를 제어하는 ​​시스템을 단계별로 구현하는 프로세스를 고려해 보겠습니다.


1 단계 - 개발 된 라이브러리를 Expert Advisor에 연결하는 지침 추가:

#include  <BalanceSlopeControl.mqh>


2 단계 - 균형 선의 기울기를 제어하는 ​​시스템의 매개 변수를 설정하기위한 외부 변수를 Expert Advisor에 추가합니다.

//---------------------------------------------------------------------
//  Parameters of the system of controlling the slope of the balance curve;
//---------------------------------------------------------------------
enum SetLogic 
{
  No = 0,
  Yes = 1,
};
//---------------------------------------------------------------------
input SetLogic     UseAutoBalanceControl = No;
//---------------------------------------------------------------------
input ControlType  BalanceControlType = STEP_WITHOUT_HYSTERESIS;
//---------------------------------------------------------------------
//  Amount of last trades for calculation of LR of the balance curve:
input int          TradesNumberToCalcLR = 3;
//---------------------------------------------------------------------
//  Slope of LR to decrease the volume to minimum:
input double       LRKoeffForRejectLots = -0.030;
//---------------------------------------------------------------------
//  Slope of LR to restore the normal mode of trading:
input double       LRKoeffForRestoreLots = 0.050;
//---------------------------------------------------------------------
//  Slope of LR to work in the intermediate mode:
input double       LRKoeffForIntermedLots = -0.020;
//---------------------------------------------------------------------
//  Decrease the initial volume to the specified value when the LR is inclined down
input double       RejectedLots = 0.10;
//---------------------------------------------------------------------
//  Normal work volume in the mode of MM with fixed volume:
input double       NormalLots = 1.0;


3 단계 - Expert Advisor에 TBalanceSlopeControl 유형의 개체 추가:

TBalanceSlopeControl  BalanceControl;

이 선언은 기능 정의 전에 Expert Advisor의 시작 부분에 추가할 수 있습니다.


4 단계 - 균형 곡선 제어 시스템 초기화 코드를 Expert Advisor의 OnInit 기능에 추가합니다.

//  Adjust our system of controlling the slope of the balance curve:
  BalanceControl.SetTradeSymbol( Symbol( ));
  BalanceControl.SetControlType( BalanceControlType );
  BalanceControl.SetControlParams( LRKoeffForRejectLots, LRKoeffForRestoreLots, LRKoeffForIntermedLots );
  BalanceControl.SetSlopePoints( TradesNumberToCalcLR );
  BalanceControl.SetFiltrParams( 0, -1, 0 );
  BalanceControl.SetMonitoringBeginDate( 0 );


5 단계 - 현재 시장 정보를 새로 고치는 메소드 호출을 Expert Advisor의 OnTick 기능에 추가합니다.

//  Refresh market information:
  BalanceControl.RefreshSymbolInfo( );

이 메소드의 호출은 OnTick 함수의 맨 처음에 추가하거나 새로운 바를 확인한 후에 추가할 수 있습니다 (이러한 확인이있는 Expert Advisors의 경우).


6 단계 - 포지션이 열린 코드 앞에 현재 볼륨 계산 코드를 추가합니다.

  if( UseAutoBalanceControl == Yes )
  {
    current_lots = BalanceControl.CalcTradeLots( RejectedLots, NormalLots );
  }
  else
  {
    current_lots = NormalLots;
  }

Expert Advisor에서 Money Management 시스템을 사용하는 경우 대신 NormalLots 대신 TBalanceSlopeControl::CalcTradeLots 메소드를 작성해야 합니다. 이 방법은 Expert Advisor의 MM 시스템에서 계산한 현재 볼륨입니다.

위에 설명된 내장 시스템이 있는 Test Expert Advisor BSCS-TestExpert.mq5가 이 문서에 첨부되어 있습니다. 작동 원리는 CCI 인디케이터 레벨의 교차점을 기반으로 합니다. 이 Expert Advisor는 테스트 용으로 개발되었으며 실제 계정 작업에는 적합하지 않습니다. EURUSD의 H4 기간 (2008.07.01-2010.09.01)에서 테스트 할 것입니다.

이 EA의 작업 결과를 분석해봅시다. 사면 제어 시스템이 비활성화 된 균형 변화 차트는 다음과 같습니다. 이를 보려면 UseAutoBalanceControl 외부 매개 변수에 대해 No 값을 설정하십시오.

잔액 변경의 초기 차트

그림 4. 잔액 변경의 초기 차트


이제 UseAutoBalanceControl 외부 매개 변수를 로 설정하고 Expert Advisor를 테스트합니다. 균형의 기울기를 제어하는 ​​시스템이 활성화된 차트를 얻을 수 있습니다.

제어 시스템이 활성화된 균형 변화 차트

그림 5. 제어 시스템이 활성화된 균형 변화 차트

상단 차트 (그림 4)에서 대부분의 기간은 잘린 것처럼 보이며 하단 차트 (그림 5)에서는 평평한 형태를 보입니다. 이것은 우리 시스템이 작동한 결과입니다. Expert Advisor 작업의 주요 매개 변수를 비교할 수 있습니다.

 매개 변수
 UseAutoBalanceControl = 아니요  UseAutoBalanceControl = 예
 총 순이익: 18 378.0017 261.73
 이익 요인: 1.471.81
 복구 요인: 2.66 3.74
 예상 수익:  117.81110.65
 균형의 절대적 인출:1 310.50131.05
 절대적 자본 감소: 1 390.50514.85
 균형의 최대 감소: 5 569.50 (5.04%) 3 762.15 (3.35%)
 자본의 최대 감소:6 899.50 (6.19%)
4 609.60 (4.08%)


비교 대상 중 가장 좋은 매개 변수는 녹색으로 강조 표시됩니다. 이익과 기대 수익이 약간 감소했습니다. 이것은 작업량 상태 간 전환 지연의 결과로 나타나는 규제의 다른 측면입니다. 대체로 Expert Advisor의 작업 속도가 향상되었습니다. 특히 하락 및 수익률 개선.


결론

이 시스템을 개선하는 몇 가지 방법이 있습니다.
  • Expert Advisor가 불리한 근무 기간에 들어갈 때 가상 거래를 사용합니다. 그러면 정상적인 작업량은 더 이상 중요하지 않습니다. 하락을 줄일 수 있습니다.
  • Expert Advisor의 현재 작업 상태 (수익성 여부)를 결정하기 위해 더 복잡한 알고리즘을 사용합니다. 예를 들어, 우리는 그러한 분석을 위해 신경망을 적용해 볼 수 있습니다. 물론 이 경우 추가 조사가 필요합니다.

따라서 우리는 Expert Advisor의 품질 특성을 향상시킬 수있는 시스템 작동의 원리와 결과를 고려했습니다. 자금 관리 시스템과의 공동 운영은 경우에 따라 위험을 증가시키지 않고 수익성을 높일 수 있습니다.

다시 한 번 상기시켜드립니다: 어떠한 보조 시스템도 패배로 인해 수익성 있는 Expert Advisor을 만들 수 없습니다.


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

자동 거래 챔피언십 2010을 위한 Expert Advisor를 신속하게 만드는 방법을 알아보십시오. 자동 거래 챔피언십 2010을 위한 Expert Advisor를 신속하게 만드는 방법을 알아보십시오.
Automated Trading Championship 2010에 참여할 전문가를 양성하기 위해 준비된 Expert Advisor의 템플릿을 사용해 보겠습니다. 기본 클래스, 기능, 템플릿이 이미 개발되었기 때문에 초보 MQL5 프로그래머도 이 작업을 수행할 수 있습니다. 거래 아이디어를 구현하기 위한 최소한의 코드만으로도 충분합니다.
Expert Advisor 작성시 MQL5 Standard Trade Class 라이브러리 사용 Expert Advisor 작성시 MQL5 Standard Trade Class 라이브러리 사용
`이 글에서는 거래를 하기 전에 포지션 청산 및 수정, 주문 보류 및 삭제 및 마진 확인을 구현하는 Expert Advisors를 작성하는 데 MQL5 표준 라이브러리 거래 클래스의 주요 함수를 사용하는 방법을 설명합니다. 또한 트레이드 클래스를 사용하여 주문 및 거래 세부 정보를 얻는 방법을 시연했습니다.
오류 찾기 및 로깅 오류 찾기 및 로깅
MetaEditor 5에는 디버깅 기능이 있습니다. 그러나 MQL5 프로그램을 작성할 때 종종 개별 값이 아니라 테스트 및 온라인 작업 중에 나타나는 모든 메시지를 표시하려고 합니다. 로그 파일 내용이 큰 경우 필요한 메시지의 빠르고 쉬운 검색을 자동화하는 것이 분명합니다. 이 기사에서는 MQL5 프로그램에서 오류를 찾는 방법과 로깅 방법을 고려할 것입니다. 또한 파일 로그인을 단순화하고 로그를 편안하게 볼 수 있는 간단한 프로그램인 LogMon을 알게 될 것입니다.
TesterWithdrawal() 함수를 이용한 수익 인출 모델링 TesterWithdrawal() 함수를 이용한 수익 인출 모델링
이 글에서는 운용 중에 자산의 특정 부분을 인출하는 것을 의미하는 거래 시스템의 위험을 추정하기 위해 TesterWithDrawal() 함수를 사용하는 방법에 대해 설명합니다. 또한 이 함수가 전략 테스터의 지분 하락 계산 알고리즘에 미치는 영향을 설명합니다. 이 함수는 Expert Advisors의 매개 변수를 최적화 할 때 유용합니다.