English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
다른 애플리케이션에 대한 MetaTrader 5 Quotes을 준비하는 방법

다른 애플리케이션에 대한 MetaTrader 5 Quotes을 준비하는 방법

MetaTrader 5 | 11 10월 2021, 16:31
99 0
Anatoli Kazharski
Anatoli Kazharski

컨텐츠

소개
1. 관련 주제
2. 데이터 형식
3. 프로그램의 외부 매개 변수
4. 사용자가 입력한 매개 변수 확인하기
5. 글로벌 변수
6. 정보 패널
.7. 응용 프로그램의 주 블록
8. 폴더를 만들고 데이터를 파일링하기
결론


소개

저는 MQL5를 공부하기 전에 거래 시스템 개발을 위해 다른 많은 어플리케이션을 사용해 보았습니다. 제가 시간을 낭비했다고 말할 수는 없어요. 그 중 일부는 사용자가 프로그래밍 언어를 모르는 상태에서 시간을 절약하고, 많은 문제를 해결하고, 일부 신화를 파괴하고, 신속하게 개발 방향을 선택할 수 있는 몇 가지 유용한 도구를 포함하고 있습니다.

이러한 애플리케이션에는 기록 데이터가 필요합니다. 일부 표준 데이터 형식이 없기 때문에, 필요한 프로그램에 적용되는 형식을 준수하기 위해 데이터를 사용하기 전에(예: Excel에서) 편집해야 하는 경우가 종종 있었습니다. 필요한 모든 세부 사항을 파악할 수 있더라도 많은 작업을 수동으로 수행해야 합니다. 사용자는 MetaTrader 4에서 필요한 형식으로 견적을 복사하도록 설계된 다양한 버전의 스크립트를 찾을 수 있습니다. 이러한 요구가 있다면 MQL5용 스크립트 버전도 개발할 수 있습니다.


1. 관련 주제

이 문서에서는 다음 주제를 다룹니다:

  • 마켓 워치 창의 기호 목록 및 서버의 공통 기호 목록으로 작업합니다.
  • 다양한 상황을 올바르게 처리하여 필요한 경우 사용 가능한 데이터 깊이를 확인하고 누락된 양을 다운로드합니다.
  • 요청한 데이터에 대한 정보를 사용자 지정 패널 차트 및 저널에 표시합니다..
  • 사용자 정의 형식의 파일링 데이터를 준비하기
  • 파일 디렉토리 생성하기.
  • 데이터 파일링.


2. 데이터 형식

NSDT(NeuroShell DayTrader Professional)에서 사용할 데이터를 준비하는 예를 보여 드리겠습니다. NSDT 버전 5와 6을 사용해 본 결과 데이터 형식에 대한 요구사항이 다르다는 것을 알게 되었습니다. NSDT 버전 5 날짜 및 시간 데이터는 서로 다른 열에 있어야 합니다. 파일의 첫 번째 행은 다음과 같은 모양이어야 합니다.

"날짜" "시간" "열림" "높음" "낮음" "닫힘" "볼륨"

응용 프로그램이 파일을 허용하려면 NSDT 버전 6의 머리글줄 모양이 달라야 합니다. 즉, 날짜와 시간이 동일한 열에 있어야 합니다:

날짜, 열기, 높음, 낮음, 닫기, 볼륨

MetaTrader 5를 사용하면 *.csv 파일에 견적을 저장할 수 있습니다. 파일의 데이터는 다음과 같습니다:

그림. 1. MetaTrader 5 단말기로 저장된 데이터

그림. 1. MetaTrader 5 단말기로 저장된 데이터


그러나 날짜가 다른 형식이어야 하므로 헤더 라인만 편집할 수는 없습니다. NSDT v.5 의 경우:

dd.mm.yyyy,hh:mm(날짜, 시간), 열기, 높음, 낮음, 닫기, 볼륨
NSDT v.6 의 경우:
dd/mm/yyyy hh:mm(날짜, 시간), 열기, 높음, 낮음, 닫기, 볼륨

드롭다운 목록은 사용자가 필요한 형식을 선택할 수 있는 스크립트 외부 매개 변수에 사용됩니다. 헤더 및 날짜 형식을 선택하는 것 외에도 사용자가 파일에 쓸 기호 수와 데이터를 선택할 수 있도록 허용합니다. 이를 위해 다음 세 가지 버전을 준비할 것입니다:

  • (ONLY CURRENT SYMOBOL) 스크립트가 시작된 차트에는 현재 기호에만 데이터를 기록합니다.
  • 마켓워치 창에 있는 기호(MARKETWATCH SYMBOLS)에 데이터를 기록합니다.
  • 서버에서 사용할 수 있는 모든 기호(ALL LIST SYMBOLS)에 데이터를 기록합니다.

다음 코드를 스크립트 코드의 외부 매개 변수 앞에 입력하여 해당 목록을 작성하겠습니다:

//_________________________________
// HEADER_FORMATS_ENUMERATION
enum FORMAT_HEADERS
  {
   NSDT_5 = 0, // "Date" "Time" "Open" "High" "Low" "Close" "Volume"
   NSDT_6 = 1  // Date,Open,High,Low,Close,Volume
  };
//---
//___________________________
// ENUMERATION_OF_DATA_FORMATS
enum FORMAT_DATETIME
  {
   SEP_POINT1 = 0, // dd.mm.yyyy hh:mm
   SEP_POINT2 = 1, // dd.mm.yyyy, hh:mm
   SEP_SLASH1 = 2, // dd/mm/yyyy hh:mm
   SEP_SLASH2 = 3  // dd/mm/yyyy, hh:mm
  };
//---
//____________________________
// ENUMERATION_OF_FILING_MODES
enum CURRENT_MARKETWATCH
  {
   CURRENT          = 0, // ONLY CURRENT SYMBOLS
   MARKETWATCH      = 1, // MARKETWATCH SYMBOLS
   ALL_LIST_SYMBOLS = 2  // ALL LIST SYMBOLS
  };

자세한 열거 정보는 MQL5 참조에서 확인할 수 있습니다.


3. 프로그램의 외부 매개 변수

이제 스크립트의 모든 외부 매개 변수의 전체 목록을 만들 수 있습니다:

//____________________________________________________________________
//+------------------------------------------------------------------+
//| EXTERNAL_PARAMETERS                                              |
//+------------------------------------------------------------------+
input datetime            start_date     = D'01.01.2011'; // Start Date
input datetime            end_date       = D'18.09.2012'; // End Date
input FORMAT_HEADERS      format_headers = NSDT_5;     // Format Headers
input FORMAT_DATETIME     format_date    = SEP_POINT2; // Format Datetime
input CURRENT_MARKETWATCH curr_mwatch    = CURRENT;    // Mode Write Symbols
input bool                clear_mwatch   = true;        // Clear Market Watch
input bool                show_progress  = true;        // Show Progress (%)

외부 매개 변수는 다음과 같은 용도로 사용됩니다:

  • 사용자는 시작 날짜(start_date) 및 종료 날짜(end_date) 매개 변수를 사용하여 날짜 간격을 지정할 수 있습니다:
  • 헤더 형식 지정(format_headers) 드롭다운 목록에서 헤더 형식을 선택할 수 있습니다.
  • Format Datetime(format_date) 드롭다운 목록에서 날짜 및 시간 형식을 선택할 수 있습니다.
  • Mode Write Symbols(curr_mwatch) 드롭다운 목록을 통해 사용자는 파일에 사용할 기호 수를 선택할 수 있습니다.
  • Clear Market Watch(clear_mwatch) 매개 변수가 true이면 파일 작업 후 Market Watch 창에서 모든 기호를 삭제할 수 있습니다. 이 문제는 현재 활성화되지 않은 차트가 있는 기호에만 적용됩니다.
  • Show Progress (%) (show_progress) 매개변수는 데이터 패널에 파일 진행률을 표시합니다. 이 매개 변수를 사용하지 않도록 설정하면 파일이 더 빠르게 수행됩니다.

다음은 실행 중에 외부 매개 변수가 표시되는 방식입니다:

그림. 2. 응용 프로그램의 외부 매개 변수

그림. 2. 응용 프로그램의 외부 매개 변수


4. 사용자가 입력한 매개변수 확인하기

기본 코드 이전에 사용자가 입력한 파라미터를 확인하는 함수를 생성하겠습니다. 예를 들어, 시작 날짜 매개 변수의 시작 날짜는 종료 날짜보다 빨라야 합니다. 헤더 형식은 날짜 및 시간 형식과 일치해야 합니다. 사용자가 매개변수를 설정할 때 오류가 발생한 경우 다음 경고 메시지가 표시되고 프로그램이 중지됩니다.

샘플 경고 메시지:

그림. 3. 잘못 지정된 값에 대한 경고

그림. 3. 잘못 지정된 파라미터에 대한 샘플 오류 메시지


유효성 검사 매개 변수-ValidationParameters():

//____________________________________________________________________
//+------------------------------------------------------------------+
//| CHECKING_CORRECTNESS_OF_PARAMETERS                               |
//+------------------------------------------------------------------+
bool ValidationParameters()
  {
   if(start_date>=end_date)
     {
      MessageBox("The start date should be earlier than the ending one!\n\n"
                 "Application cannot continue. Please retry.",
                 //---
                 "Parameter error!",MB_ICONERROR);
      //---
      return(true);
     }
//---
   if(format_headers==NSDT_5 && 
      (format_date==SEP_POINT1 || format_date==SEP_SLASH1))
     {
      MessageBox("For the headers of the following format:\n\n"
                 "\"Date\" ""\"Time\" ""\"Open\" ""\"High\" ""\"Low\" ""\"Close\" ""\"Volume\"\n\n"
                 "Date/time format can be selected out of two versions:\n\n"
                 "dd.mm.yyyy, hh:mm\n"
                 "dd/mm/yyyy, hh:mm\n\n"
                 "Application cannot continue. Please retry.",
                 //---
                 "Header and date/time formats do not match!",MB_ICONERROR);
      //---
      return(true);
     }
//---
   if(format_headers==NSDT_6 && 
      (format_date==SEP_POINT2 || format_date==SEP_SLASH2))
     {
      MessageBox("For the headers of the following format:\n\n"
                 "Date,Open,High,Low,Close,Volume\n\n"
                 "Date/time format can be selected out of two versions:\n\n"
                 "dd.mm.yyyy hh:mm\n"
                 "dd/mm/yyyy hh:mm\n\n"
                 "Application cannot continue. Please retry.",
                 //---
                 "Header and date/time formats do not match!",MB_ICONERROR);
      //---
      return(true);
     }
//---
   return(false);
  }


5. 글로벌 변수

다음으로 스크립트에 사용될 모든 글로벌 변수와 어레이를 결정해야 합니다:

//____________________________________________________________________
//+------------------------------------------------------------------+
//| GLOBAL_VARIABLES_AND_ARRAYS                                      |
//+------------------------------------------------------------------+
MqlRates rates[]; // Array for copying data
//---
string symbols[]; // Symbol array
//---
// Array of graphic object names
string arr_nmobj[22]=
  {
   "fon","hd01",
   "nm01","nm02","nm03","nm04","nm05","nm06","nm07","nm08","nm09","nm10",
   "nm11","nm12","nm13","nm14","nm15","nm16","nm17","nm18","nm19","nm20"
  };
//---
// Array of displayed text containing graphic objects
string arr_txtobj[21];
//---
string path="";         // File path
int cnt_symb=0;         // Number of symbols
int sz_arr_symb=0;      // Symbol array size
int bars=0;             // Number of bars according to the specified TF
int copied_bars=0;      // Number of bars copied for writing
double pgs_pcnt=0;      // Writing progress
int hFl=INVALID_HANDLE;  // File handle
//---
string   // Variables for data formatting
sdt="",  // Date line
dd="",   // Day
mm="",   // Month
yyyy="", // Year
tm="",   // Time
sep="";  // Separator
//---
int max_bars=0; // Maximum number of bars in the terminal settings
//---
datetime
first_date=0,        // First available data in a specified period
first_termnl_date=0, // First available data in the terminal's database
first_server_date=0, // First available data in the server's database
check_start_date=0;  // Checked correct date value


6. 정보 패널

이제, 우리는 정보 패널에 표시될 요소들을 다뤄야 합니다. 세 가지 유형의 그래픽 객체를 배경으로 사용할 수 있습니다:

  • 가장 간단하고 분명한 것 – "직사각형 레이블" (OBJ_RECTANGLE_LABEL).
  • 인터페이스를 고유하게 표시하려는 사용자는 "Bitmap" 객체 (OBJ_BITMAP)를 사용할 수 있습니다.
  • "편집" 객체 (OBJ_EDIT) 를 배경으로 사용할 수도 있습니다. 텍스트 입력 가능성을 제거하려면 "읽기 전용" 속성을 설정하십시오. 또한 "편집" 객체를 사용하는 또 다른 장점이 있습니다. Expert Advisor에서 정보 패널을 만든 경우 시각화 모드에서 테스트하는 동안 동일한 모양을 유지하려면 마지막 유형만 사용해야 합니다. 시각화 모드에서 테스트 중에는 OBJ_RECTANGLE_LABEL, 또는 OBJ_BITMAP 은 표시되지 않습니다.

Expert Advisor가 아닌 스크립트만 개발되었지만, OBJ_EDIT 객체가 있는 배경은 예시로 작성될 예정입니다. 결과는 아래 그림에 나와 있습니다.

그림. 4. 정보 패널

그림. 4. 정보 패널


패널에 표시된 모든 데이터에 대해 설명하겠습니다:

  • 기호 (현재/전체) – 현재 다운로드/복사/작성되는 데이터 기호. 대괄호 안의 왼쪽 번호는 현재 기호 번호를 나타냅니다. 오른쪽 번호는 스크립트가 사용할 일반적인 기호 수를 나타냅니다.
  • 경로 기호 – 해당 항목이 속한 기호 경로 또는 범주. 마켓워치 창에서 마우스 오른쪽 단추를 클릭하여 상황에 맞는 메뉴를 열고 "기호…"(Symbols)를 선택하면 모든 기호 목록이 있는 창이 나타납니다. 자세한 내용은 터미널의 사용자 안내서에서 확인할 수 있습니다.
  • 시간 범위 – 기간 (timeframe). 스크립트가 시작되는 기간을 사용합니다.
  • 입력 시작 날짜 – 스크립트 매개 변수에 사용자가 지정한 데이터 시작 날짜.
  • 첫 번째 날짜 (H1) – 현재 기간의 첫 번째 사용 가능한 데이터 날짜(bar).
  • 첫 번째 터미널 날짜 (M1) – 이미 존재하는 터미널 데이터에서 M1의 첫 번째 사용 가능한 날짜.
  • 첫 번째 서버 날짜 (M1) – 서버에서 M1 시간대의 첫 번째 사용 가능한 날짜.
  • 최대값. 옵션 터미널의 막대 – 터미널 설정에 지정된 차트에 표시할 최대 막대 수.
  • 복사된 막대 – 작성을 위해 복사된 막대 수.
  • 진행 값 현재 기호 – 현재 기호의 기록된 데이터의 백분율 값.

다음은 해당 정보 패널의 코드입니다:

//____________________________________________________________________
//+------------------------------------------------------------------+
//| INFORMATION_PANEL                                                |
//|------------------------------------------------------------------+
void InfoTable(int s)
  {
   int fnt_sz=8;            // Font size
   string fnt="Calibri";     // Header font
   color clr=clrWhiteSmoke;  // Color
//---
   int xH=300;
   int height_pnl=0;
   int yV1=1,yV2=12,xV1=165,xV2=335,xV3=1;
//---
   string sf="",stf="",ssf="";
   bool flg_sf=false,flg_stf=false,flg_ssf=false;
//---
   if(show_progress) { height_pnl=138; } else { height_pnl=126; }
//---
   flg_sf=SeriesInfoInteger(symbols[s],_Period,SERIES_FIRSTDATE,first_date);
   flg_stf=SeriesInfoInteger(symbols[s],PERIOD_M1,SERIES_TERMINAL_FIRSTDATE,first_termnl_date);
   flg_ssf=SeriesInfoInteger(symbols[s],PERIOD_M1,SERIES_SERVER_FIRSTDATE,first_server_date);
//---
   if(flg_sf) { sf=TSdm(first_date); } else { sf="?"; }
   if(flg_stf) { stf=TSdm(first_termnl_date); } else { stf="?"; }
   if(flg_ssf) { ssf=TSdm(first_server_date); } else { ssf="?"; }
//---
   if(cnt_symb==0) { cnt_symb=1; }
//---
   int anchor1=ANCHOR_LEFT_UPPER,anchor2=ANCHOR_RIGHT_UPPER,corner=CORNER_LEFT_UPPER;
//---
   string path_symbol=SymbolInfoString(symbols[s],SYMBOL_PATH);
   path_symbol=StringSubstr(path_symbol,0,StringLen(path_symbol)-StringLen(symbols[s]));
//---
   arr_txtobj[0]="INFO TABLE";
   arr_txtobj[1]="Symbol (current / total) : ";
   arr_txtobj[2]=""+symbols[s]+" ("+IS(s+1)+"/"+IS(cnt_symb)+")";
   arr_txtobj[3]="Path Symbol : ";
   arr_txtobj[4]=path_symbol;
   arr_txtobj[5]="Timeframe : ";
   arr_txtobj[6]=gStrTF(_Period);
   arr_txtobj[7]="Input Start Date : ";
   arr_txtobj[8]=TSdm(start_date);
   arr_txtobj[9]="First Date (H1) : ";
   arr_txtobj[10]=sf;
   arr_txtobj[11]="First Terminal Date (M1) : ";
   arr_txtobj[12]=stf;
   arr_txtobj[13]="First Server Date (M1) : ";
   arr_txtobj[14]=ssf;
   arr_txtobj[15]="Max. Bars In Options Terminal : ";
   arr_txtobj[16]=IS(max_bars);
   arr_txtobj[17]="Copied Bars : ";
   arr_txtobj[18]=IS(copied_bars);
   arr_txtobj[19]="Progress Value Current Symbol : ";
   arr_txtobj[20]=DS(pgs_pcnt,2)+"%";
//---
   Create_Edit(0,0,arr_nmobj[0],"",corner,fnt,fnt_sz,clrDimGray,clrDimGray,345,height_pnl,xV3,yV1,2,C'15,15,15');
//---
   Create_Edit(0,0,arr_nmobj[1],arr_txtobj[0],corner,fnt,8,clrWhite,C'64,0,0',345,12,xV3,yV1,2,clrFireBrick);
//---
   Create_Label(0,arr_nmobj[2],arr_txtobj[1],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2,0);
   Create_Label(0,arr_nmobj[3],arr_txtobj[2],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2,0);
//---
   Create_Label(0,arr_nmobj[4],arr_txtobj[3],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*2,0);
   Create_Label(0,arr_nmobj[5],arr_txtobj[4],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*2,0);
//---
   Create_Label(0,arr_nmobj[6],arr_txtobj[5],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*3,0);
   Create_Label(0,arr_nmobj[7],arr_txtobj[6],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*3,0);
//---
   Create_Label(0,arr_nmobj[8],arr_txtobj[7],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*4,0);
   Create_Label(0,arr_nmobj[9],arr_txtobj[8],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*4,0);
//---
   Create_Label(0,arr_nmobj[10],arr_txtobj[9],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*5,0);
   Create_Label(0,arr_nmobj[11],arr_txtobj[10],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*5,0);
//---
   Create_Label(0,arr_nmobj[12],arr_txtobj[11],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*6,0);
   Create_Label(0,arr_nmobj[13],arr_txtobj[12],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*6,0);
//---
   Create_Label(0,arr_nmobj[14],arr_txtobj[13],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*7,0);
   Create_Label(0,arr_nmobj[15],arr_txtobj[14],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*7,0);
//---
   Create_Label(0,arr_nmobj[16],arr_txtobj[15],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*8,0);
   Create_Label(0,arr_nmobj[17],arr_txtobj[16],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*8,0);
//---
   Create_Label(0,arr_nmobj[18],arr_txtobj[17],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*9,0);
   Create_Label(0,arr_nmobj[19],arr_txtobj[18],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*9,0);
//---
   if(show_progress)
     {
      Create_Label(0,arr_nmobj[20],arr_txtobj[19],anchor2,corner,fnt,fnt_sz,clr,xV1,yV1+yV2*10,0);
      Create_Label(0,arr_nmobj[21],arr_txtobj[20],anchor2,corner,fnt,fnt_sz,clr,xV2,yV1+yV2*10,0);
     }
  }
//____________________________________________________________________
//+------------------------------------------------------------------+
//| CREATING_LABEL_OBJECT                                            |
//+------------------------------------------------------------------+
void Create_Label(long   chrt_id,   // chart id
                  string lable_nm,  // object name
                  string rename,    // displayed name
                  long   anchor,    // anchor point
                  long   corner,    // attachment corner
                  string font_bsc,  // font
                  int    font_size, // font size
                  color  font_clr,  // font color
                  int    x_dist,    // X scale coordinate
                  int    y_dist,    // Y scale coordinate
                  long   zorder)    // priority
  {
   if(ObjectCreate(chrt_id,lable_nm,OBJ_LABEL,0,0,0)) // creating object
     {
      ObjectSetString(chrt_id,lable_nm,OBJPROP_TEXT,rename);          // set name
      ObjectSetString(chrt_id,lable_nm,OBJPROP_FONT,font_bsc);        // set font
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_COLOR,font_clr);      // set font color
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_ANCHOR,anchor);       // set anchor point
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_CORNER,corner);       // set attachment corner
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_FONTSIZE,font_size);  // set font size
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_XDISTANCE,x_dist);    // set X coordinates
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_YDISTANCE,y_dist);    // set Y coordinates
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_SELECTABLE,false);     // unable to highlight the object, if FALSE
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_ZORDER,zorder);       // Higher/lower priority
      ObjectSetString(chrt_id,lable_nm,OBJPROP_TOOLTIP,"\n");         // no tooltip, if "\n"
     }
  }
//____________________________________________________________________
//+------------------------------------------------------------------+
//| CREATING_EDIT_OBJECT                                             |
//+------------------------------------------------------------------+
void Create_Edit(long   chrt_id,       // chart id
                 int    nmb_win,       // window (subwindow) index
                 string lable_nm,      // object name
                 string text,          // displayed text
                 long   corner,        // attachment corner
                 string font_bsc,      // font
                 int    font_size,     // font size
                 color  font_clr,      // font color
                 color  font_clr_brd,  // font color
                 int    xsize,         // width
                 int    ysize,         // height
                 int    x_dist,        // X scale coordinate
                 int    y_dist,        // Y scale coordinate
                 long   zorder,        // priority
                 color  clr)           // background color
  {
   if(ObjectCreate(chrt_id,lable_nm,OBJ_EDIT,nmb_win,0,0)) // creating object
     {
      ObjectSetString(chrt_id,lable_nm,OBJPROP_TEXT,text);                     // set name
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_CORNER,corner);                // set attachment corner
      ObjectSetString(chrt_id,lable_nm,OBJPROP_FONT,font_bsc);                 // set font
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_ALIGN,ALIGN_CENTER);         // center alignment
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_FONTSIZE,font_size);           // set font size
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_COLOR,font_clr);               // font color
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_BORDER_COLOR,font_clr_brd);    // background color
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_BGCOLOR,clr);                  // background color
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_XSIZE,xsize);                  // width
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_YSIZE,ysize);                  // height
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_XDISTANCE,x_dist);             // set X coordinate
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_YDISTANCE,y_dist);             // set Y coordinate
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_SELECTABLE,false);              // unable to highlight the object, if FALSE
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_ZORDER,zorder);                // Higher/lower priority
      ObjectSetInteger(chrt_id,lable_nm,OBJPROP_READONLY,true);                // Read only
      ObjectSetString(chrt_id,lable_nm,OBJPROP_TOOLTIP,"\n");                  // no tooltip if "\n"
     }
  }

스크립트 작업이 완료되거나 사용자가 미리 스크립트를 삭제한 후에는 스크립트에서 만든 모든 그래픽 개체를 삭제해야 합니다. 이를 위해 다음 기능이 사용됩니다:

//____________________________________________________________________
//+------------------------------------------------------------------+
//| DELETE_ALL_GRAPHICAL_OBJECTS_CREATED_BY_THE_SCRIPT               |
//+------------------------------------------------------------------+
void DelAllScriptObjects()
  {
// Receive the size of graphical object names array
   int sz_arr1=ArraySize(arr_nmobj);
//---
// Delete all objects
   for(int i=0; i<sz_arr1; i++)
     { DelObjbyName(arr_nmobj[i]);  }
  }
//____________________________________________________________________
//+------------------------------------------------------------------+
//| DELETE_OBJECTS_BY_NAME                                           |
//+------------------------------------------------------------------+
int DelObjbyName(string Name)
  {
   int nm_obj=0;
   bool res=false;
//---
   nm_obj=ObjectFind(ChartID(),Name);
//---
   if(nm_obj>=0)
     {
      res=ObjectDelete(ChartID(),Name);
      //---
      if(!res) { Print("Object deletion error: - "+ErrorDesc(Error())+""); return(false); }
     }
//---
   return(res);
  }


7. 응용 프로그램의 기본 블록

스크립트의 주요 기능은 OnStart()입니다. 실행을 위해 다른 모든 함수를 호출하는 데 사용되는 기능입니다. 프로그램 작동 세부 정보가 코드에 표시됩니다:

//____________________________________________________________________
//+------------------------------------------------------------------+
//| SCRIPT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> |
//+------------------------------------------------------------------+
void OnStart()
  {
// If user-defined parameters are incorrect,
// error message is shown and the program is closed
   if(ValidationParameters()) { return; }
//---
   max_bars=TerminalInfoInteger(TERMINAL_MAXBARS); // Receive available number of bars in the window
//---
   GetSymbolsToArray();           // Filling symbol array with names
   sz_arr_symb=ArraySize(symbols); // Receive symbol array size
//---
   SetSeparateForFormatDate();    // Set a separator for date format
//---
// Revise all symbols and write their data to file
   for(int s=0; s<=sz_arr_symb-1; s++)
     {
      copied_bars=0; // Reset copied bars variable to zero for writing
      pgs_pcnt=0.0;  // Reset variable of the symbol data writing progress 
      //---
      InfoTable(s); ChartRedraw();
      //---
      // Receive current symbol data
      int res=GetDataCurrentSymbol(s);
      //---
      if(res==0) { BC } // If zero, break the loop or start the next iteration
      //---
      if(res==2)        // Program operation interrupted by user
        {
         DelAllScriptObjects(); // Deleted objects created by the script from the chart
         //---
         Print("------\nUser deleted the script!"); break;
        }
      //---
      // Receive the path for creating the file and create directories for them
      // If the string is empty, break the loop or start the next iteration
      if((path=CheckCreateGetPath(s))=="") { BC }
      //---
      WriteDataToFile(s); // Write data to file
     }
//---
// Delete symbols from Market Watch window if necessary
   DelSymbolsFromMarketWatch();
//---
// Delete objects created by the script from the chart
   Sleep(1000); DelAllScriptObjects();
  }

주요 활동이 이루어지는 기능을 살펴보겠습니다.

기호 배열 (symbols[])은 GetSymbolsToArray() 함수에 기호 이름으로 채워집니다. 배열 크기와 그 안의 기호 수는 사용자가 모드 쓰기 기호(curr_mwatch) 매개 변수에서 선택한 변형에 따라 달라집니다.

사용자가 하나의 기호에서만 데이터를 얻어야 하는 경우 배열 크기는 1과 같습니다.

ArrayResize(symbols,1); // Set the array size to be equal to 1
symbols[0]=_Symbol;     // Specify the current symbol's name

사용자가 MarketWatch 창에서 모든 기호 또는 사용 가능한 모든 기호에서 데이터를 수신하려는 경우 배열 크기는 다음 함수로 정의됩니다.

int SymbolsTotal(
   bool selected   // true – only MarketWatch symbols
);

코드가 거의 동일한 두 변형에 대해 두 개의 블록이 생성되지 않도록 MWatchOrAllList() 포인터 함수를 만들어 true 또는 false를 반환합니다. 이 값은 기호 목록을 가져올 위치를 정의합니다 - Market Watch 창(true) 또는 사용 가능한 공통 기호 목록(false)에서만 취하게 됩니다.

//____________________________________________________________________
//+------------------------------------------------------------------+
//| POINTER_TO_MARKET_WATCH_WINDOW_OR_TO_COMMON_LIST                 |
//+------------------------------------------------------------------+
bool MWatchOrAllList()
  {
   if(curr_mwatch==MARKETWATCH) { return(true); }
   if(curr_mwatch==ALL_LIST_SYMBOLS) { return(false); }
//---
   return(true);
  }

루프의 기호 수를 구한 후 전체 목록을 살펴보고 반복할 때마다 기호 이름을 배열에 넣어 배열 크기를 하나씩 늘려야 합니다. 기호 이름은 차례로 SymbolName() 함수를 사용하여 인덱스 번호로 가져옵니다.

int SymbolName(
   int pos,        // list index number
   bool selected   // true – only MarketWatch symbols
);

MWatchOrAllList() 포인터 기능은 기호 목록을 선택하는 SymbolName() 함수에도 사용됩니다. GetSymbolsToArray() 함수 완료 코드:

//____________________________________________________________________
//+------------------------------------------------------------------+
//| FILLING_SYMBOL_ARRAY_WITH_NAMES                                  |
//+------------------------------------------------------------------+
void GetSymbolsToArray()
  {
// If only the current symbol data is required
   if(curr_mwatch==CURRENT)
     { ArrayResize(symbols,1); symbols[0]=_Symbol; }
//---
// If data on all symbols  from Market Watch window or
// or the entire symbol list is required
   if(curr_mwatch==MARKETWATCH || curr_mwatch==ALL_LIST_SYMBOLS)
     {
      // Receive the number of symbols in Market Watch window
      cnt_symb=SymbolsTotal(MWatchOrAllList());
      //---
      for(int i=0; i<=cnt_symb-1; i++)
        {
         string nm_symb="";
         //---
         ArrayResize(symbols,i+1); // Increase the array size by one once again
         //---
         // Receive a name of a symbol from Market Watch window
         nm_symb=SymbolName(i,MWatchOrAllList());
         symbols[i]=nm_symb; // Put the symbol name into the array
        }
     }
  }

SetSeparateForFormatDate() 함수는 매우 간단합니다. 포맷 데이터 (format_date) 매개변수의 드롭다운 목록에서 사용자의 선택에 따라 날짜에 사용할 구분 기호 유형을 정의하는 데 사용됩니다.

//____________________________________________________________________
//+------------------------------------------------------------------+
//| DEFINING_SEPARATOR_FOR_DATE_FORMAT                               |
//+------------------------------------------------------------------+
void SetSeparateForFormatDate()
  {
   switch(format_date)
     {
      case SEP_POINT1 : case SEP_POINT2 : sep="."; break; // Full point as a separator
      case SEP_SLASH1 : case SEP_SLASH2 : sep="/"; break; // Slash as a separator
     }
  }

그 다음에는 다양한 체크가 있는 기본 루프가 나옵니다. 모든 검사가 성공하면 데이터가 파일에 기록됩니다. 그렇지 않으면 루프가 끊어지고 차트에서 모든 개체가 삭제되며 스크립트가 제거되거나(기호가 둘 이상인 경우) 다음 반복이 시작됩니다. 기호 배열의 각 기호는 루프에서 일관되게 호출됩니다. 인덱스 번호는 루프의 각 함수로 전송됩니다. 따라서 모든 함수의 정확한 시퀀스가 보존됩니다.

루프의 현재 기호에 대한 데이터는 루프 본문의 맨 앞에 있는 각 반복에서 수신됩니다. GetDataCurrentSymbol() 함수가 사용됩니다. 이 기능에서 어떤 일이 일어나는지 살펴보겠습니다.

rate[] 배열에 기호 데이터를 복사하기 전에 CheckLoadHistory() 함수를 사용하여 데이터 가용성을 확인합니다. 이 기능은 개발자들이 예로 제공한 것입니다. 초기 버전은 MQL5 참조에서 확인할 수 있습니다. 저는 이 스크립트에서 사용할 때 약간의 수정만 했습니다. 참고문헌에는 자세한 설명이 포함되어 있으며(참조문헌을 공부하는 것도 좋음), 제 버전은 거의 동일하므로 여기에 표시하지 않을 것입니다. 또한 코드에 자세한 코멘트가 있는 것으로 확인하실 수 있습니다.

제 CheckLoadHistory() 함수가 오류 또는 성공적인 실행 코드를 반환하고, 이에 따라 switch(스위치) 연산자 블록의 해당 메시지가 저널에 저장됩니다. 수신된 코드에 따르면 GetDataCurrentSymbol() 함수는 작업을 진행하거나 코드를 반환합니다.

모든 작업이 잘 수행되면 기록 데이터가 CopyRates() 함수를 사용하여 복사됩니다. 배열 크기는 글로벌 변수에 저장됩니다. 그런 다음 코드 1 반환과 함께 기능 종료가 수행됩니다. 문제가 발생하면 이 기능은 스위치 연산자에서 작동을 중지하고 코드 0 또는 2를 반환합니다.

//____________________________________________________________________
//+------------------------------------------------------------------+
//| RECEIVE_SYMBOL_DATA                                              |
//+------------------------------------------------------------------+
int GetDataCurrentSymbol(int s)
  {
   Print("------\n№"+IS(s+1)+" >>>"); // Save a symbol number in the journal
//---
// Check and download the necessary amount of requested data
   int res=CheckLoadHistory(s,_Period);
//---
   InfoTable(s); ChartRedraw(); // Update the data in the data table
//---
   switch(res)
     {
      case -1 : Print("Unknown symbol "+symbols[s]+" (code: -1)!");                        return(0);
      case -2 :
         Print("Number of requested bars exceeds the maximum number that can be displayed on a chart (code: -2)!...\n"
               "...The available amount of data will be used for writing.");                break;
      //---
      case -3 : Print("Execution interrupted by user (code: -3)!");                         return(2);
      case -4 : Print("Download failed (code: -4)!");                                      return(0);
      case  0 : Print("All symbol data downloaded (code: 0).");                             break;
      case  1 : Print("Time series data is sufficient (code: 1).");                          break;
      case  2 : Print("Time series created based on existing terminal data (code: 2).");      break;
      //---
      default : Print("Execution result is not defined!");
     }
//---
// Copy data to the array
   if(CopyRates(symbols[s],_Period,check_start_date,end_date,rates)<=0)
     { Print("Error when copying symbol data "+symbols[s]+" - ",ErrorDesc(Error())+""); return(0); }
   else
     {
      copied_bars=ArraySize(rates); // Receive array size
      //---
      Print("Symbol: ",symbols[s],"; Timeframe: ",gStrTF(_Period),"; Copied bars: ",copied_bars);
     }
//---
   return(1); // Return 1, if all is well
  }

그런 다음 프로그램은 다시 메인 루프 본문인 OnStart() 함수에 위치합니다. 코드는 res 로컬 변수에 의해 할당되며 해당 값에 따라 검사가 수행됩니다. 0 값은 오류를 나타냅니다. 루프에 있는 현재 기호의 데이터를 쓸 수 없다는 뜻입니다. 오류 설명이 저널에 저장되었으며 루프를 중단(중단)하거나 다음 반복을 시작해야(계속) 결정할 수 있습니다.

if(res==0) { BC } // If zero, the loop is interrupted or the next iteration starts

위의 코드 행은 이 선택이 일부 신비한 BC 문자에 의해 수행된다는 것을 나타냅니다. 이것은 매크로 확장입니다. 자세한 내용은 MQL5 참조에서 확인할 수 있습니다. 여기서 언급해야 하는 유일한 사항은 위의 예(BC)와 같이 전체 식(한 줄로 입력)을 짧은 항목에 붙여넣을 수 있다는 것입니다. 경우에 따라서는 이 방법이 함수보다 훨씬 더 편리하고 간결할 수 있습니다. 현재 경우에는 다음과 같이 표시됩니다:

// Macro expansion with further action selection
#define BC if(curr_mwatch==CURRENT) { break; } if(curr_mwatch==MARKETWATCH || curr_mwatch==ALL_LIST_SYMBOLS) { continue; }

다음은 이 스크립트에서 사용되는 매크로 확장의 다른 예입니다:

#define nmf __FUNCTION__+": " // Macro expansion of the function name before sending the message to the journal
//---
#define TRM_DP TerminalInfoString(TERMINAL_DATA_PATH) // Folder for storing the terminal data

If GetDataCurrentSymbol() 이 2를 반환하면, 사용자가 프로그램을 삭제한 것입니다. MQL5에는 이 이벤트를 식별하는IsStopped() 함수가 있습니다. 이 기능은 프로그램 작동을 제때에 올바르게 중지하는 루프에 매우 유용합니다. 함수가 true를 반환하면 프로그램이 강제로 삭제되기 전에 모든 작업을 수행할 수 있는 시간이 약 3초 정도 있습니다. 이 경우 모든 그래픽 객체가 제거되고 다음과 같은 메시지가 저널로 전송됩니다:

if(res==2) // Program execution interrupted by user
   {
    DelAllScriptObjects(); // Delete all objects created by the script from the chart
    //---
    Print("------\nUser deleted the script!"); break;
   }


8. 폴더를 만들고 데이터를 파일링하기

CheckCreateGetPath() 함수는 루트 데이터 폴더의 존재 여부를 확인합니다. DATA_OHLC 이라 지정하고, C:\Metatrader 5\MQL5\Files에 배치합니다. 기호 이름이 있는 폴더가 포함됩니다. 데이터 쓰기 파일이 여기에 생성됩니다.

루프의 현재 기호에 대한 루트 폴더 또는 폴더가 없는 경우 함수는 해당 폴더를 만듭니다. 모두 잘되면 함수는 파일 작성 경로를 포함하는 문자열을 반환합니다. 이 함수는 오류가 발생하거나 사용자가 수행한 차트에서 프로그램을 삭제하려고 할 경우 빈 문자열을 반환합니다.

아래 코드에는 자세한 설명이 포함되어 있으므로 쉽게 이해할 수 있습니다.

//____________________________________________________________________
//+------------------------------------------------------------------+
//| CHECK_DIRECTORY_AND_CREATE_NECESSARY_DATA_FOLDERS                |
//+------------------------------------------------------------------+
string CheckCreateGetPath(int s)
  {
   int i=1;
   long search=-1;
   string ffname="",lpath="";
   string file="*.csv",folder="*";
   string
   root="DATA_OHLC\\",         // Root data folder
   fSmb=symbols[s]+"\\",     // Symbol name
   fTF=gStrTF(_Period)+"\\"; // Symbol time frame
//---
   bool flgROOT=false,flgSYMBOL=false;
//---
//+------------------------------------------------------------------+
//| SEARCHING_FOR_DATA_OHLC_ROOT_FOLDER                              |
//+------------------------------------------------------------------+
   lpath=folder;
   search=FileFindFirst(lpath,ffname); // Set search handle in Metatrader 5\MQL5\Files
//---
   Print("Directory: ",TRM_DP+"\\MQL5\\Files\\");
//---
// Set the flag if the first folder is a root one
   if(ffname==root)
     { flgROOT=true; Print("Root folder "+root+" present"); }
//---
   if(search!=INVALID_HANDLE) // If search handle received
     {
      if(!flgROOT) // If the first folder is not a root one
        {
         // Sort out all files searching for the root folder
         while(FileFindNext(search,ffname))
           {
            if(IsStopped()) // Execution interrupted by user
              {
               // Delete objects created by the script from the chart
               DelAllScriptObjects();
               //---
               Print("------\nUser deleted the script!"); return("");
              }
            //---
            if(ffname==root) // Set the flag if found
              { flgROOT=true; Print("Root folder "+root+" present"); break; }
           }
        }
      //---
      FileFindClose(search); search=-1; // Close root folder search handle
     }
   else { Print("Error when receiving the search handle or directory "+TRM_DP+" is empty: ",ErrorDesc(Error())); }
//---
//+------------------------------------------------------------------+
//| SEARCHING_SYMBOL_FOLDER                                          |
//+------------------------------------------------------------------+
   lpath=root+folder;
//---
// Set search handle in the root folder ..\Files\DATA OHLC\
   search=FileFindFirst(lpath,ffname);
//---
// Set the flag if the first folder of the current symbol
   if(ffname==fSmb) { flgSYMBOL=true; Print("Symbol folder "+fSmb+" present"); }
//---
   if(search!=INVALID_HANDLE) // If search handle is received
     {
      if(!flgSYMBOL) // If the first folder is not of the current symbol
        {
         // Sort out all the files in the root folder searching the symbol folder
         while(FileFindNext(search,ffname))
           {
            if(IsStopped()) // Execution interrupted by user
              {
               // Delete objects created by the script from the chart
               DelAllScriptObjects();
               //---
               Print("------\nUser deleted the script!"); return("");
              }
            //---
            if(ffname==fSmb) // Set the flag if found
              { flgSYMBOL=true; Print("Symbol folder"+fSmb+" present"); break; }
           }
        }
      //---
      FileFindClose(search); search=-1; // Close symbol folder search handle
     }
   else { Print("Error when receiving search handle or the directory "+path+" is empty"); }
//---
//+------------------------------------------------------------------+
//| CREATE_NECESSARY_DIRECTORIES_ACCORDING_TO_CHECK_RESULTS          |
//+------------------------------------------------------------------+
   if(!flgROOT) // If there is no DATA_OHLC... root folder
     {
      if(FolderCreate("DATA_OHLC")) // ...we should create it
        { Print("..\DATA_OHLC\\ root folder created"); }
      else
        { Print("Error when creating DATA_OHLC: root folder",ErrorDesc(Error())); return(""); }
     }
//---
   if(!flgSYMBOL) // If there is no folder of the symbol, the values of which should be received...
     {
      if(FolderCreate(root+symbols[s])) // ...we should create it
        {
         Print("..\DATA_OHLC\\" symbol folder created+fSmb+"");
         //---
         return(root+symbols[s]+"\\"); // Return the path for creating the file for writing
        }
      else
        { Print("Error when creating ..\DATA_OHLC\\ symbol folder"+fSmb+"\: ",ErrorDesc(Error())); return(""); }
     }
//---
   if(flgROOT && flgSYMBOL)
     {
      return(root+symbols[s]+"\\"); // Return the path for creating the file for writing
     }
//---
   return("");
  }

If CheckCreateGetPath() 함수가 빈 줄을 반환하면 루프가 중단되거나 다음 반복이 이미 익숙한 매크로 확장(BC)을 사용하여 시작됩니다.

// Receive the path for creating a file and create directories for them
// If the line is empty, the loop is interrupted or the next iteration starts
if((path=CheckCreateGetPath(s))=="") { BC }

이 단계에 도달한 경우 데이터가 성공적으로 복사되었으며 경로 문자열 변수는 루프에서 현재 기호의 데이터를 쓰기 위한 파일 작성 경로를 포함합니다.

파일에 데이터를 쓰는 WriteDataToFile() 함수 생성하기 [Path]+[file name] 은 함수 시작 시 생성됩니다. 파일 이름은 기호 이름과 현재 기간으로 구성됩니다. 예를 들어, EURUSD_H1.csv 해당 이름의 파일이 이미 있는 경우 작성을 위해 열립니다. 이전에 작성한 데이터는 삭제됩니다. 대신 새로운 데이터가 작성될 것입니다. 파일이 성공적으로 생성/열린 경우, FileOpen() 함수는 파일에 액세스하는 데 사용할 핸들을 반환합니다.

핸들 확인하기. 있으면 머리글줄이 작성됩니다. 사용자가 선택한 헤더에 따라 적절한 줄이 작성됩니다. 기록 데이터를 쓰는 기본 루프는 그 후에 시작됩니다.

다음 행을 쓰기 전에 사용자가 지정한 형식으로 변환해야 합니다. 그러려면 막대 열기 시간을 수신하고 StringSubstr() 함수를 사용하여 변수별로 일, 월, 연도 및 시간을 별도로 정렬해야 합니다. 그런 다음 사용자가 지정한 형식에 따라 날짜와 시간을 단일 열에 배치할 것인지 아니면 별도의 열에 배치할 것인지 정의해야 합니다. 그런 다음 StringConcatenate()함수를 사용하여 모든 부분을 한 줄로 결합합니다. 모든 라인이 작성된 후, 파일은 FileClose() 함수에 의해 닫힙니다.

전체 WriteDataToFile() 함수 코드가 아래에 나와 있습니다:

//____________________________________________________________________
//+------------------------------------------------------------------+
//| WRITE_DATA_TO_FILE                                               |
//+------------------------------------------------------------------+
void WriteDataToFile(int s)
  {
// Number of decimal places in the symbol price
   int dgt=(int)SymbolInfoInteger(symbols[s],SYMBOL_DIGITS);
//---
   string nm_fl=path+symbols[s]+"_"+gStrTF(_Period)+".csv"; // File name
//---
// Receive file handle for writing
   hFl=FileOpen(nm_fl,FILE_WRITE|FILE_CSV|FILE_ANSI,',');
//---
   if(hFl>0) // If the handle is received
     {
      // Write the headers
      if(format_headers==NSDT_5)
        { FileWrite(hFl,"\"Date\" ""\"Time\" ""\"Open\" ""\"High\" ""\"Low\" ""\"Close\" ""\"Volume\""); }
      //---
      if(format_headers==NSDT_6)
        { FileWrite(hFl,"Date","Open","High","Low","Close","Volume"); }
      //---
      // Write the data
      for(int i=0; i<=copied_bars-1; i++)
        {
         if(IsStopped()) // If program execution interrupted by a user
           {
            DelAllScriptObjects(); // Delete objects created by the script from the chart
            //---
            Print("------\nUser deleted the script!"); break;
           }
         //---
         sdt=TSdm(rates[i].time); // Bar open time
         //---
         // Divide the date by year, month and time
         yyyy=StringSubstr(sdt,0,4);
         mm=StringSubstr(sdt,5,2);
         dd=StringSubstr(sdt,8,2);
         tm=StringSubstr(sdt,11);
         //---
         string sep_dt_tm=""; // Separator of Date and Time columns
         //---
         // Join the data with the separator in the necessary order
         if(format_date==SEP_POINT1 || format_date==SEP_SLASH1) { sep_dt_tm=" "; }
         if(format_date==SEP_POINT2 || format_date==SEP_SLASH2) { sep_dt_tm=","; }
         //---
         // Join everything in one line
         StringConcatenate(sdt,dd,sep,mm,sep,yyyy,sep_dt_tm,tm);
         //---
         FileWrite(hFl,
                   sdt,// Date-time
                   DS_dgt(rates[i].open,dgt),      // Open price
                   DS_dgt(rates[i].high,dgt),      // High price
                   DS_dgt(rates[i].low,dgt),       // Low price
                   DS_dgt(rates[i].close,dgt),     // Close price
                   IS((int)rates[i].tick_volume)); // Tick volume price
         //---
         // Update writing progress value for the current symbol
         pgs_pcnt=((double)(i+1)/copied_bars)*100;
         //---
         // Update data in the table
         InfoTable(s); if(show_progress) { ChartRedraw(); }
        }
      //---
      FileClose(hFl); // Close the file
     }
   else { Print("Error when creating/opening file!"); }
  }

이것은 OnStart() 함수의 기본 루프에서 마지막 함수였습니다. 마지막 기호가 아니라면 다음 기호에 대해 모든 것이 반복됩니다. 그렇지 않으면 루프가 끊어집니다. 사용자가 스크립트 매개 변수의 MarketWatch 창에서 기호 목록을 지우도록 지정한 경우 현재 활성 상태가 아닌 차트가 있는 기호는 DelSymbolsFromMarketWatch() 함수에 의해 삭제됩니다. 그런 다음 스크립트에서 만든 모든 그래픽 개체가 삭제되고 프로그램이 중지됩니다. 데이터를 사용할 준비가 되었습니다.

NeuroShell DayTrader Professional 에 데이터를 다운로드하는 방법에 대한 자세한 내용은 제 블로그에서 확인할 수 있습니다. 다음은 스크립트 작업을 보여 주는 비디오입니다:


결론

거래 전략을 개발하기 위해 어떤 프로그램을 사용했건 간에, 저는 항상 제 아이디어가 더 이상 발전하지 못하게 하는 몇 가지 한계점에 도달했습니다. 결국, 저는 여기서 프로그래밍이 필수라는 것을 깨달았습니다. MQL5 는 진정으로 성공하고자 하는 사용자를 위한 최상의 솔루션입니다. 그러나 새로운 아이디어를 찾을 때 거래 전략의 데이터 분석 및 개발을 위한 다른 프로그램도 유용할 수 있습니다. 한 가지 도구만 사용했더라면 찾는데 훨씬 더 오래 걸렸을 거예요.

행운을 빌어요!

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

파일 첨부됨 |
writedatatofile.mq5 (68.96 KB)
DLLs을 사용하지 않고 명명된 파이프를 사용하여 MetaTrader 5와 통신하기 DLLs을 사용하지 않고 명명된 파이프를 사용하여 MetaTrader 5와 통신하기
많은 개발자가 동일한 문제에 직면하고 있습니다 - 안전하지 않은 DLL을 사용하지 않고 거래 터미널 샌드박스로 이동하는 방법. 가장 쉽고 안전한 방법 중 하나는 정상적인 파일 작업으로 작동하는 표준 명명된 파이프를 사용하는 것입니다. 프로그램 간의 프로세서 간 클라이언트-서버 통신을 구성할 수 있습니다. C++ 및 MQL5에서 서버, 클라이언트, 두 서버 간의 데이터 교환 및 성능 벤치마크를 포함하는 실용적인 예를 살펴 보십시오.
MetaTrader Market에서 거래용 로봇을 구입하여 설치하는 방법은 무엇입니까? MetaTrader Market에서 거래용 로봇을 구입하여 설치하는 방법은 무엇입니까?
MetaTrader 마켓의 제품은 MQL5.com 웹 사이트에서 구입하거나 MetaTrader 4 및 MetaTrader 5 트레이딩 플랫폼에서 직접 구입할 수 있습니다. 거래 스타일에 맞는 상품을 선택하고 선호하는 결제 방법으로 결제한 후 제품을 활성화하세요.
거래신호에 가입하는 방법 거래신호에 가입하는 방법
시그널(신호) 서비스는 MetaTrader 4 및 MetaTrader 5와의 소셜 트레이딩을 소개합니다. 이 서비스는 거래 플랫폼에 통합되어 있으며 누구나 전문 거래자의 거래를 쉽게 복사할 수 있습니다. 수천 개의 신호 공급자 중 하나를 선택하고 몇 번의 클릭으로 가입하면 해당 공급자의 거래가 귀하의 계정에 복사됩니다.
신경망 네트워크: 이론에서 실전까지 신경망 네트워크: 이론에서 실전까지
요즘, 모든 거래자들은 신경망에 대해 들어봤을 것이고, 신경망을 사용하는 것이 얼마나 멋진지 알고 있을 것입니다. 대다수는 신경망을 다룰 수 있는 사람들이 일종의 초인적인 존재라고 믿습니다. 이 기사에서는 신경 네트워크 아키텍처를 설명하고, 그 적용 사례를 설명하며, 실제 사용 사례를 보여 드리겠습니다.