English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
MQL5(MQL4)에서 MySQL 데이터베이스에 액세스하는 방법

MQL5(MQL4)에서 MySQL 데이터베이스에 액세스하는 방법

MetaTrader 5통합 | 12 10월 2021, 14:17
218 0
Eugeniy Lugovoy
Eugeniy Lugovoy

소개

MQL과 데이터베이스의 상호 작용 문제는 어제오늘의 일은 아니지만 여전히 관련이 있습니다. 데이터베이스를 사용하면 MetaTrader의 가격 이력 저장 및 분석, 거래 플랫폼 간 거래 복사, 실시간으로 견적/트레이드 제공, 서버 측의 집중적인 분석 연산, 웹 기술을 이용한 계정 일정, 모니터링 및 원격 제어 등의 가능성을 크게 높일 수 있습니다.

어쨌든 MQL과 MySQL의 조합으로 많은 이점을 얻으려고 시도했으며, 코드베이스(CodeBase)에서 일부 솔루션을 사용할 수 있습니다.

예를 들어 "MySQL wrapper - MetaTrader 4를 위한 라이브러리"는 많은 프로그래머들이 더 많은 추가와 함께 자체 개발을 시작하는 프로젝트입니다. 이 솔루션의 단점 중 하나는 데이터베이스에서 데이터를 읽기 위한 특수 어레이를 할당하는 것이라고 생각합니다.

또 다른 프로젝트 "MySQL logger 1 - MetaTrader 4를 위한 EA"는 고도로 전문화되어 있으며 표준 라이브러리 libmysql.dll에 액세스하는 데 래퍼(wrapper)를 사용하지 않습니다. 따라서 MetaTrader4 Build 600+ 에서는 작동하지 않습니다, 왜냐하면 char 문자 유형이 wchar_t으로 대체되고, int 유형의 사용은, TMYSQL 구조 포인터 대신, 프로젝트에서 메모리 누수를 유발하기 때문입니다 (할당된 메모리를 제어/자유화 할 수 없음).

또 다른 흥미로운 프로젝트는 "EAX_Mysql - MySQL library - MetaTrader 5를 위한 라이브러리" 입니다. 그것은 꽤 좋은 구현입니다. 작성자가 언급한 단점 목록은 사용에 일부 제한을 가합니다.

MQL 프로젝트에서 데이터베이스를 사용해야 하는 모든 사용자는 두 가지 옵션을 사용할 수 있습니다. 즉, 자체 솔루션을 개발하여 모든 부분을 파악하거나 타사 솔루션을 사용/적응하여 사용 방법을 배우고 프로젝트를 방해할 수 있는 모든 결함을 탐지할 수 있습니다.

저는 다소 복잡한 거래 로봇을 개발하면서 이러한 필요성과 두 가지 옵션에 직면했습니다. 기존 프로젝트를 뒤지고 매우 많은 솔루션을 연구한 결과, 기본적인 구현이 아닌 것이 거래 로봇을 "전문가 수준"으로 끌어올리는 데 도움이 될 수 있다는 것을 깨달았습니다.

또한 표준 libmysql.dll을 사용하여 DML/DDL 작업(데이터베이스에 데이터 삽입/업데이트/삭제, 개체 생성/드롭)을 수행했으며 실제로 데이터 선택(SELECT)을 MySQL 서버 쪽의 웹 서버에 있는 PHP 스크립트에 대한 HTTP 요청(inet.dll 사용)으로 구현했습니다. SQL 쿼리는 PHP 스크립트로 작성되었습니다.

즉, 프로젝트를 실행하려면 다음 구성 요소를 사용 가능하도록, 구성 및 실행해야 합니다: MySQL 서버, Apache/IIS 웹 서버, 서버 쪽의 PHP/ASP 스크립트... 상당히 많은 기술의 조합입니다. 물론, 어떤 상황에서는 이것이 받아들여질 수도 있지만, 유일한 작업이 데이터베이스에서 데이터를 선택하는 것일 때는 이것은 말도 안 됩니다. 또한 이러한 번거로운 솔루션을 지원하려면 시간이 많이 걸립니다.

대부분의 솔루션은 데이터 삽입, 개체 생성 등에 문제가 없었습니다. 문제는 데이터를 호출 환경으로 반환해야 하기 때문에 데이터를 선택하는 것이었습니다.

이러한 목적으로 어레이를 사용하는 것은 비실용적이고 불편하다고 생각했습니다. 주 프로젝트의 개발/디버깅/지원 과정에서 데이터베이스에 대한 선택된 쿼리를 변경할 수 있고 어레이에 대한 올바른 메모리 할당도 제어해야 하기 때문입니다... 음, 이것은 피할 수 있고 또 피해야 합니다.

아래에서 논의한 MQL <-> MySql interfaced 는 Oracle PL/SQL, MS SQL T-SQL, AdoDB - 커서 사용에 사용되는 일반적인 접근 방식을 기반으로 합니다. 이 인터페이스는 프로그래밍과 유지관리의 용이성과 최소한의 구성요소를 목표로 개발되었습니다. 표준 라이브러리 libmysql.dll의 DLL wrapper로 구현되고 인터페이스 함수 집합은 .mqh 파일로 구현됩니다.


1. MQL <-> MySQL 인터페이스

MQL 프로그램을 통해 MetaTrader 터미널 간의 상호 작용은 다음 구성 요소의 도움을 받아 구현할 수 있습니다.

MQL과 MySQL의 상호 작용 체계

1. 인터페이스 라이브러리 MQLMySQL.mqh. 그것은 #include 디렉토리를 사용하여 프로젝트에 추가되며 취향에 따라 수정할 수 있습니다.

여기에는 MQLMySQL.dll 동적 라이브러리의 함수 가져오기 및 호출 및 오류 처리 기능이 포함되어 있습니다.

2. The MQLMySQL.dll 동적 라이브러리. 표준 라이브러리 libmysql.dll의 기능에 액세스하는 래퍼(wrapper)입니다.

또한 MQLMySQL.dll 라이브러리는 작업 결과와 데이터베이스 연결 및 커서에 대한 공유 액세스를 처리합니다. 즉, 하나 이상의 MQL 프로그램에서 한 번에 여러 연결을 만들고 사용할 수 있으며, 하나 이상의 데이터베이스에 대한 쿼리와 함께 몇 개의 커서를 열어 둘 수 있습니다. 뮤텍스(Mutexes)는 공유 리소스에 대한 액세스를 분리하는 데 사용됩니다.

3. 표준 동적 라이브러리 libmysql.dll은 기본 액세스 드라이버입니다. 모든 MySql 데이터베이스 배포판에서 복사할 수 있습니다. C:\Windows\Sytem32 or <Terminal>\MQL5\Libraries (MetaTrader 4 - <Terminal>\MQL4\Libraries).

실제로 데이터베이스에 쿼리를 보내고 결과를 검색하는 역할을 합니다.

연결 열기/닫기, DML/DDL 쿼리 수행 및 데이터 선택과 같은 주요 사항에 대해 자세히 살펴보겠습니다.

1.1. 연결을 열고 닫기

MySQL 데이터베이스와의 연결을 열기 위해 MySQLConnect 기능이 구현되었습니다:

유형

이름

매개 변수

설명

int

MySqlConnect

이 함수는 데이터베이스와의 연결을 구현하고 연결 식별자를 반환합니다. 이 ID는 데이터베이스를 쿼리하는 데 필요합니다.

연결이 실패할 경우 반환 값은 "-1"입니다. 오류 세부 정보를 보려면 변수 MySQLErrorNumberMySqlErrorDescription를 확인하십시오.

일반적으로 이 함수는 MQL 프로그램에서 OnInit() 이벤트를 처리할 때 호출됩니다.

string pHost

MySQL 서버의 DNS 이름 또는 IP 주소

string pUser

데이터베이스 사용자(예: 루트)

string pPassword

데이터베이스 사용자의 암호

string pDatabase

데이터베이스의 이름

int pPort

데이터베이스의 TCP/IP 포트(일반적으로 3306)

string pSocket

Unix 소켓(유닉스 기반 시스템용)

int pClientFlag

특수 플래그(일반적으로 0)의 조합

연결을 닫기 위해 MySqlDisconnect 인터페이스 기능이 구현되었습니다:

유형

이름 매개 변수 설명

void

MySqlDisconnect

이 기능은 MySQL 데이터베이스와의 연결을 닫습니다.

일반적으로 이 함수는 MQL 프로그램에서 OnDeinit() 이벤트를 처리할 때 호출됩니다.

int pConnection

연결 식별자

MySQL 데이터베이스는 하드웨어 오류, 네트워크 정체 또는 시간 초과(오랜 시간 동안 데이터베이스로 쿼리를 보내지 않음) 시 자체적으로 연결을 닫을 수 있습니다.

종종 개발자는 데이터베이스에 데이터를 쓰기 위해 OnTick() 이벤트를 사용합니다. 하지만, 주말이 오고 마켓이 문을 닫으면, 연결은 여전히 "걸려" 있습니다. 이 경우 MySQL은 시간 초과로 닫힙니다(기본값: 8시간).

그리고 월요일, 마켓이 개방되면 프로젝트에서 오류가 발견됩니다. 따라서 MySQL 서버의 설정에 지정된 시간보다 작은 시간 간격 후에 연결을 확인하거나 데이터베이스에 다시 연결하는 것이 좋습니다.

1.2. Execution of DML/DDL 쿼리의 실행

DML 연산은 데이터 조작에 사용됩니다(Data Manipulation Language). 데이터 조작에는 다음과 같은 명령 집합이 포함됩니다: 삽입(INSERT), 업데이트(UPDATE) 및 삭제(DELETE).

DDL 연산은 데이터 정의에 사용됩니다(Data Definition Language). 여기에는 데이터베이스 개체(테이블, 보기, 저장 프로시저, 트리거 등)의 생성(CREATE), 수정(ALTER) 및 삭제(DROP)가 포함됩니다.

모든 DML/DDL 문은 아니며, 게다가 DCL (Data Control Language)이 데이터 액세스를 분리하는 데 사용되지만 SQL의 기능을 자세히 조사하지는 않을 것입니다. 다음 명령 중 하나는 MySqlExecute 인터페이스 함수를 사용하여 실행할 수 있습니다:


유형

이름

매개 변수

설명

부울(bool)

MySqlExecute

이 기능은 데이터베이스에 대한 연결이 성공적으로 설정된 후 (MySqlConnect 함수 사용),SQL의 비선택(non-SELECT) 구문을 실행하는 데 사용할 수 있습니다.

명령이 성공적으로 실행될 경우 함수는 true를 반환하고 그렇지 않으면 false를 반환합니다. 오류 세부 정보를 보려면 MySQLErrorNumberMySqlErrorDescription을 사용하십시오.

int pConnection

연결 식별자

string pQuery

SQL 쿼리

SQL 쿼리로 USE 명령을 사용하여 데이터베이스를 선택할 수도 있습니다. 저는 다중-구문 쿼리의 사용을 언급하고 싶습니다. 문자 ";"로 구분된 SQL 명령 집합입니다.

다중 구문 모드를 사용하려면 CLIENT_MULTI_STATEMENTS 플래그를 사용하여 데이터베이스와의 연결을 열어야 합니다:

...
int ClientFlag = CLIENT_MULTI_STATEMENTS; // Setting the multi-statements flag
int DB; 

DB = MySqlConnect(Host, User, Password, Database, Port, Socket, ClientFlag); // Connection to the database

if (DB == -1)
   {
    // Handling the connection error
   }
...

// Preparing a SQL query to insert data (3 rows in one query)
string SQL;
SQL = "INSERT INTO EURUSD(Ask,Bid) VALUES (1.3601,1.3632);";
SQL = SQL + "INSERT INTO EURUSD(Ask,Bid) VALUES (1.3621,1.3643);";
SQL = SQL + "INSERT INTO EURUSD(Ask,Bid) VALUES (1.3605,1.3629);";
...

if (!MySqlExecute(DB,SQL)) 
   {
    // Showing an error message
   }
...
-->

이 부분에서는 데이터베이스에 대한 단일 호출과 함께 3개의 항목이 EURUSD 테이블에 삽입됩니다. SQL 변수에 저장된 각 쿼리는 ";"로 구분됩니다.

이 접근 방식은 자주 삽입/업데이트/삭제하는 데 사용할 수 있습니다. 필요한 명령 집합이 하나의 "패키지"로 결합되어 네트워크 트래픽을 줄이고 데이터베이스 성능을 향상시킵니다.

MySQL의 INSERT 구문은 예외 처리 측면에서 상당히 잘 개발되었습니다.

예를 들어, 작업 시 가격 기록을 이동하는 경우 날짜 및 시간이 고유하므로 날짜/시간 유형의 기본 키를 사용하여 통화 쌍에 대한 테이블을 만들어야 합니다. 또한 (데이터 마이그레이션의 안정성을 향상시키기 위해) 데이터베이스에 특정 막대의 데이터가 있는지 확인해야 합니다. INSERT 구문은 중복(DUPLICATE) 키를 지원하므로 MySQL에서는 이 검사가 필요하지 않습니다.

간단히 말해, 데이터를 삽입하려고 시도했는데 테이블에 동일한 날짜와 시간을 가진 항목이 이미 있는 경우 INSERT 구문을 무시하거나 이 행에 대해 UPDATE로 바꿀 수 있습니다(참조하세요). (http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html).

1.3. 데이터 선택

SQL SELECT 문은 데이터베이스에서 데이터를 검색하는 데 사용됩니다. 아래 작업 순서는 데이터를 선택하고 선택 결과를 검색하는 데 사용됩니다:

  1. SELECT 구문을 준비하기.
  2. 커서를 열기.
  3. 쿼리에서 반환되는 행 수를 가져오기.
  4. 쿼리의 각 행을 루핑(Looping) 및 회수하기(retrieving).
  5. 루프 내부의 MQL 변수로 데이터를 가져오기.
  6. 커서를 닫기.

물론 이는 일반적인 계획이기 때문에 모든 경우에 모든 작업이 필요한 것은 아닙니다. 예를 들어, 테이블에 행이 있는지 확인하려면(어떤 기준으로든) 쿼리를 준비하고 커서를 열고 행 수를 가져오고 커서를 닫으면 됩니다. 실제로 필수 요소는 SELECT 구문 준비, 커서 열기 및 닫기입니다.

커서란 무엇입니까? 이것은 실제로 컨텍스트 메모리 영역, 즉 결과 값 집합에 대한 참조입니다. SELECT 쿼리를 보내면 데이터베이스는 결과에 메모리를 할당하고 한 행에서 다른 행으로 이동할 수 있는 행에 포인터를 만듭니다. 따라서 쿼리로 정의된 대기열의 순서로 모든 행에 액세스할 수 있습니다(SELECT 구문의 ORDER BY 구문).

데이터 선택에 사용되는 인터페이스 기능은 다음과 같습니다:

커서 열기:

유형

이름

매개 변수

설명

int

MySqlCursorOpen

이 함수는 SELECT 쿼리에 대한 커서를 열고 성공할 경우 커서 식별자를 반환합니다. 그렇지 않으면 함수는 "-1"을 반환합니다. 오류의 원인을 확인하려면 MySQLErrorNumberMySqlErrorDescription 변수를 사용하십시오.

int pConnection

데이터베이스와의 연결 식별자

string pQuery

SQL 쿼리(SELECT 구문)

쿼리에서 반환되는 행 수를 가져오기:

유형

이름

매개 변수

설명

int

MySqlCursorRows

이 함수는 쿼리에서 선택한 행 수를 반환합니다.

int pCursorID

MySqlCursorOpen에서 반환한 커서 식별자입니다.

쿼리 행을 가져오기:

유형

이름

매개 변수

설명

부울(bool)

MySqlCursorFetchRow

쿼리에 의해 반환된 데이터 집합에서 행 하나를 가져옵니다. 실행이 성공하면 데이터를 MQL 변수로 검색(회수)할 수 있습니다. 이 함수는 성공하면 true를 반환하고, 그렇지 않으면 false를 반환합니다.

int pCursorID

MySqlCursorOpen에서 반환한 커서 식별자입니다.

쿼리 행을 가져온 후 데이터를 MQL 변수로 가져오기:

유형

이름

매개 변수

설명

int

MySqlGetFieldAsInt

이 함수는 int 데이터 형식을 사용하여 테이블 필드 값의 표현을 반환합니다.

int pCursorID

MySqlCursorOpen에서 반환한 커서 식별자입니다.

int pField

SELECT 목록의 필드 번호(번호 지정은 0으로 시작합니다)

double

MySqlGetFieldAsDouble

이 함수는 double 데이터 형식을 사용하여 테이블 필드 값의 표현을 반환합니다.

int pCursorID

MySqlCursorOpen에서 반환한 커서 식별자입니다.

int pField

SELECT 목록의 필드 번호(번호 지정은 0으로 시작합니다)

datetime

MySqlGetFieldAsDatetime

이 함수는 datetime 데이터 형식을 사용하여 테이블 필드 값의 표현을 반환합니다.

int pCursorID

MySqlCursorOpen에서 반환한 커서 식별자입니다.

int pField

SELECT 목록의 필드 번호(번호 지정은 0으로 시작합니다)

string

MySqlGetFieldAsString

이 함수는 string 데이터 형식을 사용하여 테이블 필드 값의 표현을 반환합니다.

int pCursorID

MySqlCursorOpen에서 반환한 커서 식별자입니다.

int pField

SELECT 목록의 필드 번호(번호 지정은 0으로 시작합니다)


MySQL에서 반환되는 모든 데이터는 기본 표현(타입 없이 문자열(strings)로 표시)을 가집니다.

따라서 이러한 기능을 사용하여 선택한 데이터를 원하는 유형으로 캐스팅할 수 있습니다. 유일한 단점은 이름 대신 SELECT 목록의 열 번호(0부터 시작)의 사양입니다. 그러나 응용 프로그램을 개발할 때 SELECT 구문을 준비하고 결과를 얻는 것은 거의 항상 한 페이지에 있으므로 데이터 가져오기 로직을 지정할 때 SELECT 쿼리를 볼 수 있습니다.

따라서 SELECT 목록의 필드 수를 항상 알고 있습니다(이 접근 방식은 AdoDB를 사용하여 데이터에 액세스할 때도 사용됩니다). 글쎄요, 이 부분은 앞으로 더 수정할 수 있습니다. 그러나 이는 개발된 솔루션의 기능에는 거의 영향을 미치지 않습니다.

커서 닫기:

유형

이름

매개 변수

설명

void

MySqlCursorClose

이 함수는 지정된 커서를 닫고 메모리를 해제합니다.

int pCursorID

MySqlCursorOpen에서 반환한 커서 식별자입니다.

커서를 닫는 것은 중요한 작업입니다. 커서를 닫는 것을 잊지 마십시오.

커서를 열고 닫는 것을 잊었다고 상상해 보십시오. OnTick() 이벤트를 처리하는 동안 모든 체크 표시와 함께 데이터가 커서로 검색되고, 새 커서가 열릴 때마다 메모리가 커서에 할당된다고 가정해 보십시오(클라이언트 측과 서버 측 모두). 일정 포인트에서, 열린 커서의 제한에 도달하여 서버가 서비스를 거부하게 되고 이로 인해 버퍼 오버플로(buffer overflow)가 발생할 수 있습니다.

물론 이러한 결과는 libmysql.dll로 직접 작업할 때 과장된 것입니다. 그러나, MQLMySQL.DLL 동적 라이브러리는 커서에 대한 메모리를 배포하고 허용 한도를 초과하는 커서의 열기를 거부합니다.

실제 작업을 구현할 때는 2-3개의 커서를 열어두면 됩니다. 각 커서는 한 개의 데카르트(Cartesian) 데이터 측정을 처리할 수 있습니다; 두 세 개의 커서를 동시에 사용하는 경우(예: 한 커서가 다른 커서에 파라메트릭적으로 의존하는 경우) 2, 3차원을 포함합니다. 이것은 대부분의 작업에 완벽하게 적합합니다. 또한 복잡한 데이터 선택을 구현하기 위해 항상 이러한 개체를 사용하여 데이터베이스(VIEW)를 표시하고 서버 측에서 생성한 다음 테이블과 같은 MQL 코드에서 쿼리를 보낼 수 있습니다.

1.4. 추가 정보

추가 기능으로 다음 사항을 언급할 수 있습니다:

1.4.1. .INI 파일에서 데이터 읽기

유형

이름

매개 변수

설명

String

ReadIni

INI 파일의 지정된 섹션 키 값을 반환합니다.

string pFileName

INI 파일의 이름

string pSection

섹션 이름

string pKey

키 이름


서버를 이동할 수 있고 주소가 동적으로 변경될 수 있기 때문에 MQL 코드(또는 Expert Advisor의 매개 변수, 스크립트 표시기)에 직접 데이터베이스 연결 정보(서버의 IP 주소, 사용자 이름, 암호 등)를 저장하는 것은 합리적이지 않은 경우가 많습니다. 이 경우 MQL 코드를 수정해야 합니다. 따라서, 이 모든 데이터는 표준 .INI 파일에 저장되어야 하며, 그것의 이름만 MQL 프로그램에 기록해야 합니다. 그런 다음, 연결 파라미터를 읽고 사용하기 위해서 ReadINI 함수를 사용합니다.

예를 들어 INI 파일에는 다음 정보가 포함되어 있습니다:

[MYSQL]
Server = 127.0.0.1
User = root
Password = Adm1n1str@t0r
Database = mysql
Port = 3306
-->

서버의 IP 주소를 가져오려면 다음을 실행합니다:

string vServer = ReadIni("C:\\MetaTrader5\\MQL5\\Experts\\MyConnection.ini", "MYSQL", "Server");
-->

INI 파일은 C:\MetaTrader5\MQL5\Experts 에 있고 "MyConnection.ini"라고 하며, 서버 키(MYSQL 섹션)에 액세스합니다. 하나의 INI 파일에서 프로젝트에 사용되는 다양한 서버에 설정을 저장할 수 있습니다.

1.4.2. 문제 영역 추적하기

인터페이스 라이브러리에서 추적 모드를 제공하므로 MQL 프로그램의 모든 곳에서 SQL 쿼리를 디버깅할 수 있습니다.

문제 영역에서 다음을 지정합니다:

SQLTrace = true;
-->

그런 다음,

SQLTrace = false;
-->

MQL 프로그램 시작 부분에서 추적을 활성화하고 사용하지 않도록 설정하지 않으면 데이터베이스에 대한 모든 호출이 기록됩니다. 로그는 터미널 콘솔에 보관됩니다(인쇄(Print) 명령 사용).


2. 예시

이 섹션에서는 개발된 라이브러리의 연결 및 사용에 대한 몇 가지 예를 제공합니다. 이러한 자료를 보고 소프트웨어 솔루션의 사용성을 추정해 보십시오.

MySQL-003.mq5 예제는 데이터베이스 연결(연결 매개 변수는 .ini 파일에 저장됨), 테이블 만들기, 데이터 삽입(다중-구문을 사용함) 및 데이터베이스와의 연결 끊기를 보여줍니다.

//+------------------------------------------------------------------+
//|                                                    MySQL-003.mq5 |
//|                                   Copyright 2014, Eugene Lugovoy |
//|                                              https://www.mql5.com |
//| Inserting data with multi-statement (DEMO)                       |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, Eugene Lugovoy."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

#include <MQLMySQL.mqh>

string INI;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
 string Host, User, Password, Database, Socket; // database credentials
 int Port,ClientFlag;
 int DB; // database identifier
 
 Print (MySqlVersion());

 INI = TerminalInfoString(TERMINAL_PATH)+"\\MQL5\\Scripts\\MyConnection.ini";
 
 // reading database credentials from INI file
 Host = ReadIni(INI, "MYSQL", "Host");
 User = ReadIni(INI, "MYSQL", "User");
 Password = ReadIni(INI, "MYSQL", "Password");
 Database = ReadIni(INI, "MYSQL", "Database");
 Port     = (int)StringToInteger(ReadIni(INI, "MYSQL", "Port"));
 Socket   = ReadIni(INI, "MYSQL", "Socket");
 ClientFlag = CLIENT_MULTI_STATEMENTS; //(int)StringToInteger(ReadIni(INI, "MYSQL", "ClientFlag"));  

 Print ("Host: ",Host, ", User: ", User, ", Database: ",Database);
 
 // open database connection
 Print ("Connecting...");
 
 DB = MySqlConnect(Host, User, Password, Database, Port, Socket, ClientFlag);
 
 if (DB == -1) { Print ("Connection failed! Error: "+MySqlErrorDescription); } else { Print ("Connected! DBID#",DB);}
 
 string Query;
 Query = "DROP TABLE IF EXISTS `test_table`";
 MySqlExecute(DB, Query);
 
 Query = "CREATE TABLE `test_table` (id int, code varchar(50), start_date datetime)";
 if (MySqlExecute(DB, Query))
    {
     Print ("Table `test_table` created.");
     
     // Inserting data 1 row
     Query = "INSERT INTO `test_table` (id, code, start_date) VALUES ("+(string)AccountInfoInteger(ACCOUNT_LOGIN)+",\'ACCOUNT\',\'"+TimeToString(TimeLocal(), TIME_DATE|TIME_SECONDS)+"\')";
     if (MySqlExecute(DB, Query))
        {
         Print ("Succeeded: ", Query);
        }
     else
        {
         Print ("Error: ", MySqlErrorDescription);
         Print ("Query: ", Query);
        }
     
     // multi-insert
     Query =         "INSERT INTO `test_table` (id, code, start_date) VALUES (1,\'EURUSD\',\'2014.01.01 00:00:01\');";
     Query = Query + "INSERT INTO `test_table` (id, code, start_date) VALUES (2,\'EURJPY\',\'2014.01.02 00:02:00\');";
     Query = Query + "INSERT INTO `test_table` (id, code, start_date) VALUES (3,\'USDJPY\',\'2014.01.03 03:00:00\');";
     if (MySqlExecute(DB, Query))
        {
         Print ("Succeeded! 3 rows has been inserted by one query.");
        }
     else
        {
         Print ("Error of multiple statements: ", MySqlErrorDescription);
        }
    }
 else
    {
     Print ("Table `test_table` cannot be created. Error: ", MySqlErrorDescription);
    }
 
 MySqlDisconnect(DB);
 Print ("Disconnected. Script done!");
}
-->

예제 MySQL-004.mq5은 "MySQL-003.mq5" 스크립트로 만든 테이블에서 선택한 데이터를 보여줍니다. 

//+------------------------------------------------------------------+
//|                                                    MySQL-004.mq5 |
//|                                   Copyright 2014, Eugene Lugovoy |
//|                                              https://www.mql5.com |
//| Select data from table (DEMO)                                    |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, Eugene Lugovoy."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

#include <MQLMySQL.mqh>

string INI;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
 string Host, User, Password, Database, Socket; // database credentials
 int Port,ClientFlag;
 int DB; // database identifier
 
 Print (MySqlVersion());

 INI = TerminalInfoString(TERMINAL_PATH)+"\\MQL5\\Scripts\\MyConnection.ini";
 
 // reading database credentials from INI file
 Host = ReadIni(INI, "MYSQL", "Host");
 User = ReadIni(INI, "MYSQL", "User");
 Password = ReadIni(INI, "MYSQL", "Password");
 Database = ReadIni(INI, "MYSQL", "Database");
 Port     = (int)StringToInteger(ReadIni(INI, "MYSQL", "Port"));
 Socket   = ReadIni(INI, "MYSQL", "Socket");
 ClientFlag = (int)StringToInteger(ReadIni(INI, "MYSQL", "ClientFlag"));  

 Print ("Host: ",Host, ", User: ", User, ", Database: ",Database);
 
 // open database connection
 Print ("Connecting...");
 
 DB = MySqlConnect(Host, User, Password, Database, Port, Socket, ClientFlag);
 
 if (DB == -1) { Print ("Connection failed! Error: "+MySqlErrorDescription); return; } else { Print ("Connected! DBID#",DB);}
 
 // executing SELECT statement
 string Query;
 int    i,Cursor,Rows;
 
 int      vId;
 string   vCode;
 datetime vStartTime;
 
 Query = "SELECT id, code, start_date FROM `test_table`";
 Print ("SQL> ", Query);
 Cursor = MySqlCursorOpen(DB, Query);
 
 if (Cursor >= 0)
    {
     Rows = MySqlCursorRows(Cursor);
     Print (Rows, " row(s) selected.");
     for (i=0; i<Rows; i++)
         if (MySqlCursorFetchRow(Cursor))
            {
             vId = MySqlGetFieldAsInt(Cursor, 0); // id
             vCode = MySqlGetFieldAsString(Cursor, 1); // code
             vStartTime = MySqlGetFieldAsDatetime(Cursor, 2); // start_time
             Print ("ROW[",i,"]: id = ", vId, ", code = ", vCode, ", start_time = ", TimeToString(vStartTime, TIME_DATE|TIME_SECONDS));
            }
     MySqlCursorClose(Cursor); // NEVER FORGET TO CLOSE CURSOR !!!
    }
 else
    {
     Print ("Cursor opening failed. Error: ", MySqlErrorDescription);
    }
    
 MySqlDisconnect(DB);
 Print ("Disconnected. Script done!");
}
-->

위의 예에는 실제 프로젝트에 사용되는 일반적인 오류 처리가 포함되어 있습니다.

실제로 MQL 프로그램에 사용되는 각 쿼리는 모든 MySQL 클라이언트(PHPmyAdmin, DB Ninja, MySQL 콘솔)에서 디버깅되어야 합니다. 개인적으로 저는 데이터베이스 개발을 위해 "Quest TOAD for MySQL" 전문 소프트웨어를 사용하고 추천합니다.


결론

이 문서에서는 Microsoft Visual Studio 2010(C/C++) 환경에서 개발된 MQLMySQL.DLL의 구현에 대한 자세한 내용은 설명하지 않습니다. 이 소프트웨어 솔루션은 실용적으로 사용하도록 설계되었으며 MQL 소프트웨어 개발의 다양한 영역(복잡한 거래 시스템 생성부터 웹 퍼블리싱에 이르기까지)에서 100개 이상의 성공적인 구현을 보유하고 있습니다.

  • MQL4 및 MQL5용 라이브러리의 버전이 아래에 첨부되어 있습니다. 첨부 파일에는 MQLMySQL.DLL의 소스 코드와 함께 zip 파일도 포함되어 있습니다;
  • 문서는 아카이브에 포함되어 있습니다;
  • 예제를 사용하려면, \Scripts\MyConnection.ini 파일에 데이터베이스 연결 매개 변수를 지정해야 합니다.

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

MQL5 마법사: 주문, 손실 중지 및 계산된 가격에서 이익 취하기. 표준 라이브러리 확장 MQL5 마법사: 주문, 손실 중지 및 계산된 가격에서 이익 취하기. 표준 라이브러리 확장
이 문서에서는 MQL5 표준 라이브러리 확장을 설명합니다, 이로써, MQL5 마법사를 사용하여 Expert Advisor를 생성하고, 주문, 손실 중지 및 이익 취하기를 포함된 모듈에서 받은 가격으로 설명합니다. 이 접근 방식은 모듈 수에 대한 추가 제한을 적용하지 않으며 모듈 공동 작업에서 충돌을 일으키지 않습니다.
소셜 테크놀로지 스타트업을 구축하기, 1부: MetaTrader 5 신호를 트윗하세요 소셜 테크놀로지 스타트업을 구축하기, 1부: MetaTrader 5 신호를 트윗하세요
오늘은 EA의 거래 신호를 트윗할 수 있도록 MetaTrader 5 단말기를 트위터와 연결하는 방법에 대해 알아보겠습니다. 우리는 RESTful 웹 서비스를 기반으로 PHP의 사회적 의사결정 지원 시스템을 개발하고 있습니다. 이 아이디어는 컴퓨터 지원 거래라고 불리는 자동 거래의 특별한 개념에서 나온 것입니다. 우리는 휴먼 거래자들의 인지 능력이 Expert Advisor가 자동으로 시장에 내놓는 거래 신호를 걸러내기를 원합니다.
가상 호스팅으로 마이그레이션하기 위해 거래 계정을 준비하는 방법 가상 호스팅으로 마이그레이션하기 위해 거래 계정을 준비하는 방법
MetaTrader 클라이언트 터미널은 거래 전략 자동화에 완벽합니다. 이 제품은 로봇 개발자를 거래하는 데 필요한 모든 도구, 강력한 C++ 기반 MQL4/MQL5 프로그래밍 언어, 편리한 MetaEditor 개발 환경 및 MQL5 클라우드 네트워크에서 분산 컴퓨팅을 지원하는 멀티 스레드 전략 테스터를 갖추고 있습니다. 이 문서에서는 모든 사용자 지정 요소가 포함된 가상 환경으로 클라이언트 터미널을 이동하는 방법에 대해 설명합니다.
거래 로봇 이야기: 더 적은 것이 더 많은 것인가요? 거래 로봇 이야기: 더 적은 것이 더 많은 것인가요?
2년 전 "마지막 십자군"에서 우리는 꽤 흥미롭지만 현재 널리 사용되지 않는 시장 정보 표시 방법인 포인트 및 피겨(point and figure) 차트를 검토했습니다. 이제 포인트 및 피겨 차트에서 감지된 패턴을 기반으로 거래 로봇을 작성해 보십시오.