English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
MQL5에서 WinInet 사용하기 파트 2: POST 리퀘스트 및 파일

MQL5에서 WinInet 사용하기 파트 2: POST 리퀘스트 및 파일

MetaTrader 5 | 11 10월 2021, 15:42
257 0
---
---


들어가며

이전 레슨 "인터넷을 경유로 터미널간 데이터 교환을 위해 WinInet.dll 활용하기" 에서 라이브러리를 다루는 법, 홈페이지를 여는 법, GET 리퀘스트를 통해 데이터를 보내고 받는 법에 대해 알아봤습니다.

이번 레슨에서는 이하를 배울 것입니다.

  • 서버에 POST 리퀘스트를 보내기
  • multipart/form-data 표현 메소드를 이용하여 서버에 파일 송신하기
  • Cookies를 다루고 로그인 시 홈페이지에서 정보 읽기

예전에도 말씀드렸다시피 로컬 프록시 서버 Charles를 셋업 하시는 것을 추천드립니다. 앞으로 배우시고, 시험할 때에 필요할 것입니다.


POST 리퀘스트

정보를 보내려면 wininet.dll 함수들이 필요하고, 이전 문서에서 생성한 CMqlNet 클래스가 필요합니다.

CMqlNet::Request 메소드 내의 다량의 필드때문에 리퀘스트에 필요한 모든 필드를 갖춘 별도의 구조 tagRequest를 생성해야합니다. 

//------------------------------------------------------------------ struct tagRequest
struct tagRequest
{
  string stVerb;   // method of the request GET/POST/…
  string stObject; // path to an instance of request, for example "/index.htm" или "/get.php?a=1"  
  string stHead;   // request header
  string stData;   // addition string of data
  bool fromFile;   // if =true, then stData designates the name of a data file
  string stOut;    // string for receiving an answer
  bool toFile;     // if =true, then stOut designates the name of a file for receiving an answer

  void Init(string aVerb, string aObject, string aHead, 
            string aData, bool from, string aOut, bool to); // function of initialization of all fields
};
//------------------------------------------------------------------ Init
void tagRequest::Init(string aVerb, string aObject, string aHead, 
                      string aData, bool from, string aOut, bool to)
{
  stVerb=aVerb;     // method of the request GET/POST/…
  stObject=aObject; // path to the page "/get.php?a=1" or "/index.htm"
  stHead=aHead;     // request header, for example "Content-Type: application/x-www-form-urlencoded"
  stData=aData;     // addition string of data
  fromFile=from;    // if =true, the stData designates the name of a data file
  stOut=aOut;       // field for receiving an answer
  toFile=to;        // if =true, then stOut designates the name of a file for receiving an answer
}

추가로 CMqlNet::Request 메소드의 헤더를 더 짧게 변경해야 합니다.

//+------------------------------------------------------------------+
bool MqlNet::Request(tagRequest &req)
  {
   if(!TerminalInfoInteger(TERMINAL_DLLS_ALLOWED))
     {
      Print("-DLL not allowed"); return(false);
     }
//--- checking whether DLLs are allowed in the terminal
   if(!MQL5InfoInteger(MQL5_DLLS_ALLOWED))
     {
      Print("-DLL not allowed");
      return(false);
     }
//--- checking whether DLLs are allowed in the terminal
   if(req.toFile && req.stOut=="")
     {
      Print("-File not specified ");
      return(false);
     }
   uchar data[]; 
    int hRequest,hSend;
   string Vers="HTTP/1.1"; 
    string nill="";

//--- read file to array
   if(req.fromFile)
     {
      if(FileToArray(req.stData,data)<0)
        {
         Print("-Err reading file "+req.stData);
         return(false);
        }
     }
   else StringToCharArray(req.stData,data);

   if(hSession<=0 || hConnect<=0)
     {
      Close();
      if(!Open(Host,Port,User,Pass,Service))
        {
         Print("-Err Connect");
         Close();
         return(false);
        }
     }
//--- creating descriptor of the request
   hRequest=HttpOpenRequestW(hConnect,req.stVerb,req.stObject,Vers,nill,0,
   INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_RELOAD|INTERNET_FLAG_PRAGMA_NOCACHE,0);
   if(hRequest<=0)
     {
      Print("-Err OpenRequest");
      InternetCloseHandle(hConnect);
      return(false);
     }
//--- sending the request
   hSend=HttpSendRequestW(hRequest,req.stHead,StringLen(req.stHead),data,ArraySize(data));
//--- sending the file
   if(hSend<=0)
     {
      int err=0;
      err=GetLastError(err);
      Print("-Err SendRequest= ",err);
     }
//--- reading the page
   if(hSend>0) ReadPage(hRequest,req.stOut,req.toFile);
//--- closing all handles
   InternetCloseHandle(hRequest); InternetCloseHandle(hSend);

   if(hSend<=0)
     {
      Close();
      return(false);
     }
   return(true);
  }

자 이제 시작해봅시다.


"application/x-www-form-urlencoded" 타입 홈페이지에 자료 보내기

이전 레슨에서 우리는 MetaArbitrage 예제 (견적 모니터링)를 분석했습니다.

EA는 GET 리퀘스트를 사용하여 심볼의 입찰 가격을 전송하고, 다른 터미널에서 동일한 방식으로 서버로 전송되는 다른 브로커의 가격을 수신한다는 점을 기억하십시오.

GET 리퀘스트를 POST 리퀘스트로 바꾸려면 헤더 뒤에 따라오는 리퀘스트 바디 안의 리퀘스트 라인을 "숨기는"것으로 충분합니다.

BOOL HttpSendRequest(
  __in  HINTERNET hRequest,
  __in  LPCTSTR lpszHeaders,
  __in  DWORD dwHeadersLength,
  __in  LPVOID lpOptional,
  __in  DWORD dwOptionalLength
);

  • hRequest [in]
    HttpOpenRequest에 의해 리턴된 핸들.
  • lpszHeaders [in]
    리퀘스트에 첨부될 헤더를 담은 줄에 대한 포인터. 이 패러미터는 비어있어야합니다.
  • dwHeadersLength [in]
    헤더 사이즈 (바이트)
  • lpOptional [in]
    헤더 다음으로 송신되는 uchar 데이터 어레이를 향한 포인터. 일반적으로 이 패러미터는 POST 그리고 PUT 작업에 사용됩니다.
  • dwOptionalLength [in]
    데이터 크기를 바이트로 나타낸 값. 패러미터=0인 경우도 있을 수 있는데, 이는 아무런 정보도 보내지지않았다는 의미입니다.

함수 설명에서 데이터가 uchar 어레이 (함수의 4번째 패러미터)로 보내진다는 것을 확인할 수 있습니다. 이 단계에서 알아야할 것은 이게 전부입니다.

MetaArbitrage 예제에서 GET 리퀘스트는 다음과 같이 보입니다.

www.fxmaster.de/metaarbitr.php?server=Metaquotes&pair=EURUSD&bid=1.4512&time=13286794


리퀘스트 자체는 빨간색으로 강조됩니다. 만약 POST리퀘스트를 해야한다면 텍스트를 lpOptional 데이터 어레이로 옮겨야합니다.

심볼 교환에 대한 정보를 받고 보낼 MetaSwap 스크립트를 만들어봅시다. 

#include <InternetLib.mqh>

string Server[];        // array of server names
double Long[], Short[]; // array for swap information
MqlNet INet;           // class instance for working

//------------------------------------------------------------------ OnStart
void OnStart()
{
//--- opening a session
  if (!INet.Open("www.fxmaster.de", 80, "", "", INTERNET_SERVICE_HTTP)) return;
 
//--- zeroizing arrays
  ArrayResize(Server, 0); ArrayResize(Long, 0); ArrayResize(Short, 0);
//--- the file for writing an example of swap information
  string file=Symbol()+"_swap.csv";
//--- sending swaps
  if (!SendData(file, "GET")) 
  { 
    Print("-err RecieveSwap"); 
    return; 
  }
//--- read data from the received file
  if (!ReadSwap(file)) return; 
//--- refresh information about swaps on the chart
  UpdateInfo();               
}

스크립트 작동은 매우 간단합니다.

먼저 INet.Open 인터넷 세션이 열립니다. 그 후 SendData 함수가 현 심볼에 대한 교환 정보를 보냅니다. 만약 성공적으로 송신이 완료되었다면 ReadSwap 을 통해 읽고 UpdateInfo를 통해 차트에 표시합니다.

현 시점에서 관심가지고 다룰 것은 SendData 함수입니다.

//------------------------------------------------------------------ SendData bool SendData(string file, string mode) {   string smb=Symbol();   string Head="Content-Type: application/x-www-form-urlencoded"; // header   string Path="/mt5swap/metaswap.php"; // path to the page   string Data="server="+AccountInfoString(ACCOUNT_SERVER)+               "&pair="+smb+               "&long="+DTS(SymbolInfoDouble(smb, SYMBOL_SWAP_LONG))+               "&short="+DTS(SymbolInfoDouble(smb, SYMBOL_SWAP_SHORT));   tagRequest req; // initialization of parameters   if (mode=="GET")  req.Init(mode, Path+"?"+Data, Head, "",   false, file, true);   if (mode=="POST") req.Init(mode, Path,          Head, Data, false, file, true);   return(INet.Request(req)); // sending request to the server }

이 스크립트에서는 GET 및 POST를 사용하여 정보를 전송하는 두 가지 방법을 시연하여 정보의 차이를 느낄 수 있습니다.

이 함수의 변수들을 하나 하나 들여다봅시다.

  • Head - 내용물들에 대한 내용이 들어있는 리퀘스트 헤더 이게 리퀘스트 헤더 전체는 아닙니다. 헤더의 나머지 필드는 wininet.dll 라이브러리를 통해 생성됩니다. 그러나 HttpAddRequestHeaders 함수를 통해 수정될 수 있습니다.
  • Path - 초기 도메인 www.fxmaster.de. 에 대한 상대주소입니다. 달리 말하면 이는 리퀘스트를 처리할 php 스크립트에 대한 주소입니다. 그나저나 php 스크립트만 요청할 필요는 없고, 일반적인 html 페이지일 수 있습니다(첫 번째 레슨 때 mq5 파일도 요청하려 했습니다).
  • Data - 서버에 보내질 정보입니다. Data는 패러미터명=값 규칙에 따라 전달되어 쓰여집니다. "&" 기호는 데이터 구분자입니다.

그리고 제일 중요하게, tagRequest::Init에서 GET와 POST 리퀘스트는 차이에 대해 주목하십시오.

GET 메소드에서는 패스가 리퀘스트 바디 와 함께 (?" 기호로 묶인) 보내지고, 데이터 필드 lpOptional (구조에선 stData) 는 빈 채로 남겨집니다.
POST 메소드
에서는 패스는 패스 자체만 있고 리퀘스트 바디는 lpOptional로 옮겨집니다.

보다시피 큰 차이는 아닙니다. 리퀘스트를 받아서 처리하는 서버 스크립트 metaswap.php는 본 문서에 첨부되어 있습니다.


"multipart/form-data" 데이터 보내기

실제로 POST 리퀘스트는 GET 리퀘스트와 유사하지 않습니다(만약 비슷했으면 다른 리퀘스트일 이유가 없죠). POST 리퀘스트를 사용하면 파일을 바이너리 컨텐츠와 함께 보낼 수있다는 큰 장점이 있습니다.

문제는 urlencoded 타입 리퀘스트로는 제한된 수의 심볼만 보낼 수 있다는 것입니다. 그러지않으면 "허가되지않은" 심볼들은 코드를 통해 대체됩니다. 이 때문에 바이너리 데이터를 보낼때에 데이터가 오염됩니다. 따라서 GET 리퀘스트를 슬때엔 아무리 작은 gif 파일이라도 보낼 수 없습니다.

이 문제를 해결하기 위해 리퀘스트를 설명하는 특수 규칙이 있습니다. 이 규칙을 사용하면 텍스트 파일 외에 바이너리 파일과도 교환할 수 있습니다.

이를 위해서 리퀘스트는 여러 섹션으로 나뉘어야합니다. 각 섹션은 자신들만의 데이터 타입을 가질 수 있습니다. 예를들면 첫 섹션은 텍스트, 두번째 섹션은 image/jpeg 를 가지는 등, 달리 말하면 서버로 보내지는 하나의 리퀘스트 안에 여러 데이터 타입을 보관할 수 있다는 것입니다.

MetaSwap 스크립트를 통해 넘겨진 데이터 예시를 통해 그러한 구조를 한 번 보도록 합시다.

리퀘스트 헤더 Head는 다음처럼 보일 것입니다.

Content-Type: multipart/form-data; boundary=SEPARATOR\r\n


키워드 SEPARATOR – 이것은 랜덤한 기호 세트 입니다. 하지만 이 내용은 리퀘스트 데이터 밖에서 확인해야합니다. 달리 말하면 이 줄은 고유해야한다는 것인데, hdsJK263shxaDFHLsdhsDdjf9같이 생각나는 아무거나 넣으면 된다는 것입니다. PHP에서는 그런 줄은 현재 시각의 MD5 코드를 사용하여 만들어집니다.

POST 리퀘스트는 다음과 같이 보입니다(보다 이해를 쉽게하기 위하여 일부 필드는 일반적인 의미에 따라 강조되어있습니다).

\r\n
--SEPARATOR\r\n

Content-Disposition: form-data; name="Server"\r\n
\r\n
MetaQuotes-Demo

\r\n
--SEPARATOR\r\n

Content-Disposition: form-data; name="Pair"\r\n
\r\n
EURUSD

\r\n
--SEPARATOR\r\n

Content-Disposition: form-data; name="Long"\r\n
\r\n
1.02

\r\n
--SEPARATOR\r\n

Content-Disposition: form-data; name="Short"\r\n
\r\n
-0.05

\r\n
--SEPARATOR--\r\n


따로 "\r\n" 기호를 명시하는데, 리퀘스트 안에 꼭 있어야하는 기호이기 때문입니다. 보시는 바와 같이, 동일한 네 개의 필드가 리퀘스트에 전달되어 일반적인 텍스트 방식으로 수행됩니다.

구분자를 배치하는 것에 있어 중요한 점

  • 두 기호 "--"가 구분자 앞에 배치됩니다..
  • 구분자를 닫을땐 두개의 추가 기호 "--"가 뒤에 추가됩니다.


다음 예시에서 리퀘스트를 통해 파일을 넘기는 올바른 방법을 보게되실겁니다.

Expert Advisor가 포지션을 청산할 때에 차트 스냅샷과 자세한 리포트를 합쳐 텍스트 파일로 만들어서 계정에 보내는 상황을 가정해봅시다.

\r\n
--SEPARATOR\r\n

Content-Disposition: form-data; name="ExpertName"\r\n
\r\n
MACD_Sample

\r\n
--SEPARATOR\r\n

Content-Disposition: file; name="screen"; filename="screen.gif"\r\n
Content-Type: image/gif\r\n
Content-Transfer-Encoding: binary\r\n
\r\n
......gif 파일의 내용물.....

\r\n
--SEPARATOR\r\n

Content-Disposition: form-data; name="statement"; filename="statement.csv"\r\n
Content-Type: application/octet-stream\r\n
Content-Transfer-Encoding: binary\r\n
\r\n
......csv 파일의 내용물.....

\r\n
--SEPARATOR--\r\n


리퀘스트에는 헤더가 두 개 있습니다.

Content-Type - 컨텐츠의 타입을 설명합니다. 모든 가능한 타입은 RFC[2046] 표준에 따라 설명되어있습니다. 우리가 사용한 두개의 타입은 - image/gifapplication/octet-stream입니다.

Content-Disposition - 파일과 form-data를 쓰는 방법은 동일하며 이들 모두 PHP에서 올바르게 처리되었습니다. 따라서 form-data를 우리가 원하는 목적을 위해 사용할 수 있습니다. 나중에 그 차이는 Charles에서 확인하실 수 있습니다.

Content-Transfer-Encoding - 컨텐츠 인코딩을 설명합니다 텍스트 데이터엔 없을 수도 있습니다.

자료를 정리하는 김에 서버에 스크린샷을 보내는 스크립트 ScreenPost를 작성해봅시다
.

#include <InternetLib.mqh>

MqlNet INet; // class instance for working

//------------------------------------------------------------------ OnStart
void OnStart()
{
  // opening session
  if (!INet.Open("www.fxmaster.de", 80, "", "", INTERNET_SERVICE_HTTP)) return;

  string giffile=Symbol()+"_"+TimeToString(TimeCurrent(), TIME_DATE)+".gif"; // name of file to be sent
 
  // creating screenshot 800х600px
  if (!ChartScreenShot(0, giffile, 800, 600)) { Print("-err ScreenShot "); return; }
 
  // reading gif file to the array
  int h=FileOpen(giffile, FILE_ANSI|FILE_BIN|FILE_READ); if (h<0) { Print("-err Open gif-file "+giffile); return; }
  FileSeek(h, 0, SEEK_SET);
  ulong n=FileSize(h); // determining the size of file
  uchar gif[]; ArrayResize(gif, (int)n); // creating uichar array according to the size of data
  FileReadArray(h, gif); // reading file to the array
  FileClose(h); // closing the file
 
  // creating file to be sent
  string sendfile="sendfile.txt";
  h=FileOpen(sendfile, FILE_ANSI|FILE_BIN|FILE_WRITE); if (h<0) { Print("-err Open send-file "+sendfile); return; }
  FileSeek(h, 0, SEEK_SET);

  // forming a request
  string bound="++1BEF0A57BE110FD467A++"; // separator of data in the request
  string Head="Content-Type: multipart/form-data; boundary="+bound+"\r\n"; // header
  string Path="/mt5screen/screen.php"; // path to the page
 
  // writing data
  FileWriteString(h, "\r\n--"+bound+"\r\n");
  FileWriteString(h, "Content-Disposition: form-data; name=\"EA\"\r\n"); // the "name of EA" field
  FileWriteString(h, "\r\n");
  FileWriteString(h, "NAME_EA");
  FileWriteString(h, "\r\n--"+bound+"\r\n");
  FileWriteString(h, "Content-Disposition: file; name=\"data\"; filename=\""+giffile+"\"\r\n"); // field of the gif file
  FileWriteString(h, "Content-Type: image/gif\r\n");
  FileWriteString(h, "Content-Transfer-Encoding: binary\r\n");
  FileWriteString(h, "\r\n");
  FileWriteArray(h, gif); // writing gif data
  FileWriteString(h, "\r\n--"+bound+"--\r\n");
  FileClose(h); // closing the file

  tagRequest req; // initialization of parameters
  req.Init("POST", Path, Head, sendfile, true, "answer.htm", true);
 
  if (INet.Request(req)) Print("-err Request"); // sending the request to the server
  else Print("+ok Request");
} 

정보를 받는 서버 스크립트

<?php
$ea=$_POST['EA'];
$data=file_get_contents($_FILES['data']['tmp_name']); // information in the file
$file=$_FILES['data']['name'];
$h=fopen(dirname(__FILE__)."/$ea/$file", 'wb'); // creating a file in the EA folder
fwrite($h, $data); fclose($h); // saving data
?>

보안 문제를 방지하려면 서버에서 파일을 수신하는 규칙을 숙지하는 것이 좋습니다!


쿠키 다루기

이 주제는 저번 레슨에 더한 덤 같은 것으로, 그냥 가볍게 들어주세요.

아시다시피, 쿠키는 서버에 의한 지속적인 개인 정보 요청을 방지하기 위한 것입니다. 서버가 사용자로부터 현재 작업 세션에 필요한 개인 정보를 수신하면 해당 정보가 포함된 텍스트 파일을 사용자 컴퓨터에 남깁니다. 또한 사용자가 페이지 사이를 이동할 때 서버는 해당 정보를 사용자에게 다시 요청하지 않고 브라우저 캐시에서 자동으로 정보를 가져옵니다.

예를들어 www.mql5.com 서버에서 만약 "계속 로그인 상태 유지하기"를 활성화 시켰다면, 자세한 내용을 담아 쿠키의 형태로 컴퓨터에 저장하는 것입니다. 다음 웹 사이트 방문 시 브라우저는 사용자에게 묻지 않고 쿠키를 서버에 전달합니다.

만약 관심있으시다면 윈도우즈 XP의 경우 C:\Documents and Settings\<User>\Cookies 로 가셔서 여태까지 방문한 홈페이지들에 대한 컨텐츠를 볼 수 있습니다.

우리가 원하는대로 쿠키는 MQL5 포럼을 읽는 데에 활용될 수 있습니다. 즉, 로그인 시 웹사이트에서 권한이 부여된 것처럼 정보를 읽은 후 얻은 페이지를 분석합니다. 한가지 최적화된 방법 중 하나는 로컬 프록시 서버 Charles를 통해 쿠키를 분석하는 것입니다. 쿠키를 포함하여 수신/발송된 모든 리퀘스트에 대한 자세한 정보가 표시됩니다.

예를 들어

  • Expert Advisor (혹은 외부 어플리케이션)이 한 시간마다 https://www.mql5.com/en/job를 요청해서 새로운 일자리 목록을 받습니다.
  • 또한 예를들면 https://www.mql5.com/en/forum/53를 리퀘스트한 후, 새 메세지가 있는지 확인합니다.
  • 또한 포럼에 새로운 "개인 메시지"가 있는지 확인할 수 있습니다.

리퀘스트 안에서 쿠키를 설정하기 위해 InternetSetCookie 함수가 이용됩니다.

BOOL InternetSetCookie(
  __in  LPCTSTR lpszUrl,
  __in  LPCTSTR lpszCookieName,
  __in  LPCTSTR lpszCookieData
);

  • lpszUrl [in] - 서버명, 예를 들면 www.mql5.com
  • lpszCookieName [in]- 쿠키 명
  • lpszCookieData [in] - 쿠키 자료

쿠키를 여러개 설정하려면 각각에 대해 이 함수를 호출하십시오.

한가지 흥미로운 것은 InternetSetCookie 는 언제건 사용될 수 있으며 이 언제건이란 말에는 서버에 연결되어있지 않을 때 역시 포함한다는 점입니다.


마치며

지금까지 다른 유형의 HTTP 요청을 숙지하고 바이너리 파일 전송, 서버 작업 기능을 확장할 수 있는 기능 확보 및 쿠키 작업 방법을 배웠습니다.

다음 추가 개발 방향 목록을 작성할 수 있습니다.

  • 보고서 원격 스토리지 정리
  • 유저간 파일 교환, Expert Advisor/인디케이터 버전 업데이트;
  • 사용자 계정으로 작동하고 웹 사이트에서 활동을 모니터링하는 사용자 지정 스캐너 만들기.


쓸모 있는 자료

  1. 보낸 헤더를 확인하기 위한 프록시 서버 - http://www.charlesproxy.com/
  2. WinHTTP 설명 - http://msdn.microsoft.com/en-us/library/aa385331%28VS.85%29.aspx
  3. HTTP 세션 설명 - http://msdn.microsoft.com/en-us/library/aa384322%28VS.85%29.aspx
  4. Apache+PHP 로컬 설치용 Denwar 툴킷 - http://www.denwer.ru/
  5. 리퀘스트 헤더 타입 - http://www.codenet.ru/webmast/php/HTTP-POST.php#part_3_2
  6. 리퀘스트 타입 - http://www.w3.org/TR/REC-html40/interact/forms.html#form-content-type
  7. 리퀘스트 타입 - ftp://ftp.isi.edu/in-notes/iana/assignments/media-types/media-types.
  8. HINTERNET 사용 구조 - http://msdn.microsoft.com/en-us/library/aa383766%28VS.85%29.aspx
  9. 파일 다루기 - http://msdn.microsoft.com/en-us/library/aa364232%28VS.85%29.aspx
  10. MQL에 보낼 데이터 타입 - http://msdn.microsoft.com/en-us/library/aa383751%28VS.85%29.aspx


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

파일 첨부됨 |
metaswap.zip (0.66 KB)
screenpost.zip (0.33 KB)
internetlib.mqh (12.82 KB)
screenpost.mq5 (2.63 KB)
metaswap.mq5 (4.84 KB)
결제 및 결제 수단 결제 및 결제 수단
MQL5.커뮤니티 서비스는 트레이더들 뿐만 아니라 MetaTrader 터미널용 어플리케이션을 개발하는 개발자들에게도 최고의 기회를 제공합니다. 이 기사에서는 MQL5 서비스에 대한 결제가 어떻게 수행되는지, 번 돈이 어떻게 인출될 수 있는지, 운영 보안이 어떻게 보장되는지 설명합니다.
MQL5에서의 엘리엇 파동(Elliot Waves) 자동 분석 도입 MQL5에서의 엘리엇 파동(Elliot Waves) 자동 분석 도입
시장 분석에서 가장 인기 좋은 방법 중 하나는 엘리엇 파동(Elliot Wave) 이론입니다. 하지만 이 과정은 꽤나 복잡하기때문에 다른 툴을 사용해야합니다. 그런 툴 중 하나는 자동 마커입니다. 본 문서에서는 MQL5로 엘리엇 파동 자동 분석기를 만드는 법에 대해서 다뤄보겠습니다.
MetaTrader 5 시장 분석에 피셔 변환(Fisher Transform)과 인버스 피셔 변환 적용하기 MetaTrader 5 시장 분석에 피셔 변환(Fisher Transform)과 인버스 피셔 변환 적용하기
시장 주기의 확률 밀도 함수(PDF)는 가우스 파 보다는 사인파의 PDF와 비슷해보는데, 대부분의 인디케이터는 시장 주기 PDF가 가우스파라고 가정합니다. 우리는 이를 "수정"할 수 있는 방법이 필요합니다. 해법은 피셔 변환을 사용하는 것입니다. 피셔 변환은 어떠한 형태의 PDF건 가우스 파 형태로 변환합니다. 이 글은 피셔 변환과 인버스 피셔 변환의 이면에 있는 수학과 이들의 거래 적용에 대해 설명합니다. 인버스 피셔 변환 기반으로 하는 독점 거래 신호 모듈을 제시하고 평가합니다.
보조 인디케이터 메모리 소모량 감소시키기 보조 인디케이터 메모리 소모량 감소시키기
인디케이터가 다른 인디케이터들의 값을 받아와 계산하는 경우 많은 메모리량이 필요합니다. 본 문서에서는 보조 인디케이터를 사용할 때에 소모되는 메모리량을 감소시키는 다양한 방법에 대하여 논할 것입니다. 메모리를 절약하면 클라이언트 내에서 동시에 이용 가능한 화폐쌍, 인디케이터, 전략을 늘려 더욱 ㅏㄴ은 여지를 줍니다. 이는 매매 포트폴리오의 안정성을 증진시킵니다. 이러한 간단한 관리만으로도 당신의 컴퓨터 리소스가 자산으로 환원될 수 있습니다.