매매 전략 다목적 엑스퍼트 어드바이저
개요
모든 매매 전략의 기초는 가격 및 기술적 지표의 분석입니다. 이는 포지션을 오픈하는 데에 기반이 되죠. 이것을 시장 분석라고 부르는데요. 시장에서 일어나는 모든 행위와 우리가 통제하지 못하는 모든 것이 여기에 포함됩니다.
이 밖에 또 다른 분석이 필요한 경우도 있습니다. 현재 거래 상황 분석라는 건데요. 거래 포지션 형태에 대한 분석과 대기 주문이 있는 경우 모든 대기 주문에 대한 분석을 포함합니다. 이런 분석을 통해 포지션 및 주문 관련 결정을 내리는 것이죠. 예를 들어 포지션 청산이라든지, 손절매 이동, 대기 주문 설정 및 삭제 등 말입니다. 다시 말해 분석은 시장 활동, 즉 우리가 (혹은 엑스퍼트 어드바이저가) 만들어 낸 상황에 따른 액션 및 사용되는 전략의 규칙에 대해 연구하는 것입니다.
많이들 알고 계시는 추적 손절매도 어떻게 보면 아래의 두 번째 요소에 속한다고 볼 수 있죠. 다음을 생각해 볼까요? 설정 값보다 높은 수익을 창출하는 포지션이 오픈되어 있으나 손절매가 설정되어있지 않거나 현재 가격에서 설정된 거리보다 먼 곳에 위치하는 경우, 손절매 주문이 취소됩니다.
이때 추적 손절매는 눈길이 갈만한 동시에 꽤 간단한 기능이죠. 게다가 포지션 관리 기능이므로 완전히 다른 매매 전략 카테고리로 분류됩니다. 따라서 매매 전략은 다음의 세 가지 요소로 구성됩니다:
시장 분석 및 시장 분석 결과를 기반으로 하는 투자 행위.
시장 상황 분석 및 시장 상황 분석 결과를 기반으로 하는 투자 행위.
포지션 관리.
이 글은 대기 주문을 활용하는 전략(이하 매매 전략) 및 해당 전략 개발에 사용되는 Metalanguage, 그리고 그 Metalanguage를 기반으로 작동하는 다목적 도구(엑스퍼트 어드바이저)에 관한 글입니다.
매매 전략 예시
보통 초기 포지션 오픈이 매매의 시작점이 됩니다. 여기에는 다음과 같은 여러 방법이 있는데요.
시장에 포지션 오픈하기
인디케이터가 나타내는 방향을 따라 오픈.
엑스퍼트 어드바이저에서 사용자가 선택한 방향을 따라 오픈.
마지막 포지션 청산 결과에 따라 오픈. 초기 포지션이 아닌 중간 운용 단계에 해당.
서로 다른 방향의 두 가지 스탑오더 설정. 둘 중 한 오더가 체결되는 경우 나머지 하나는 취소됨.
서로 다른 방향의 두 가지 리미트오더 설정. 둘 중 한 오더가 체결되는 경우 나머지 하나는 취소됨.
리미트오더와 스탑오더가 동일한 방향으로 설정된 경우. 1의 경우처럼 방향 설정이 필요.
한번 포지션을 오픈하고 나면 다양한 매매 전략을 사용해 볼 수 있습니다.
리미트오더를 이용한 스케일링(그림 1.)
초기 포지션 오픈 후 랏 크기가 증가된 동일한 방향의 리미트오더를 하나 이상 설정합니다. 리미트오더가 발동하면, 이익실현 설정 가격에서 포지션이 청산될 때까지 계속해서 새로운 리미트오더가 설정됩니다. 이익실현 설정 가격에서 포지션이 청산될 경우 남은 대기 주문은 취소됩니다.
그림 1. 리미트오더를 이용한 스케일링
SAR(그림 2.)
초기 포지션 오픈 후 손절가에서 랏 크기가 증가하는 스탑오더를 설정합니다. 손절가에서 포지션이 청산되면 대기 주문이 실행되며 새로운 스탑오더가 손절가에서 설정되어 포지션이 청산될 때까지 반복됩니다. 이익실현 설정 가격에서 포지션이 청산될 경우 남은 대기 주문은 취소됩니다.
그림 2. SAR
피라미딩(그림 3.)
초기 포지션 오픈 후 수익 발생 시 비중을 확대하고 스탑오더 가격을 최초 진입가로 설정합니다. 이익실현 설정 가격에서 포지션이 청산될 경우 포지션 사이즈와 그에 따른 수익이 상당할 수 있습니다. 그러나중간 단계에서 스탑오더 발생 시 수익은 없습니다.
그림 3. 피라미딩
리오프닝(그림 4.)
포지션을 오픈합니다. 스탑오더로 포지션 청산 후 랏 크기가 증가된 포지션을 오픈하고 이를 이익실현 시까지 반복합니다. 리미트오더를 이용한 스케일링과 비슷하죠.
그림 4. 리오프닝
언급된 모든 전략을 결합시킬 수도 있습니다. 수익이 창출되는 포지션의 경우 피라미딩이 편리하게 쓰입니다. 반대로, 손실이 있는 경우 리미트오더를 이용한 스케일링이 보다 효과적일 수 있습니다. 하지만 리미트오더를 이용한 스케일링을 계속 사용할 필요는 없죠. 예를 들어, 처음 세 번은 스케일링을 사용하고, SAR도 몇 번 사용하다가, 다시 리미트오더를 이용한 스케일링을 사용할 수도 있습니다.
실제로 매매 전략 개발 시 코딩 과정 뿐만 아니라 케이스에 따른 창의적 전략 구상에 많은 시간이 소요됩니다. 어떤 매매 전략이라도 실행할 수 있게 해주는 다목적 엑스퍼트 어드바이저를 만들어서 전략 수립에 소모되는 시간을 줄여 보도록 할게요.
기본 원칙
매매 기술 개발의 기본 원칙은 현재 사용 중인 기술의 운용 단계를 확인하고 그에 따른 작전을 수행하는 것이죠.
다음의 예를 볼까요? 포지션을 오픈해야 하는데, 매매 포지션이 다음과 같다고 가정해 볼게요. 일단 포지션을 오픈하고 나면 두 가지 대기 주문을 설정해야 합니다. 스탑오더와 리미트오더죠. 포지션을 오픈하거나 주문을 실행한 적이 없는 상태이니 포지션 오픈이 필요한 초기 운용 단계라고 볼 수 있습니다. 이미 시장에 오픈된 포지션이 있다면 그 다음 운용 단계가 되는 것이죠. 따라서 운용 단계는 다음과 같이 나눌 수 있습니다.
포지션 또는 주문이 설정되지 않은 경우. 포지션 오픈 필요.
포지션은 오픈했으나 설정된 주문이 없는 경우. 스탑오더가 필요.
포지션이 오픈되었으며 스탑오더도 설정된 경우. 리미트오더가 필요.
위의 규칙을 따르면 신뢰할 수 있는 결과가 나올 겁니다. 다만 세 가지 틱이 필요한데요. 첫 번째는 포지션이 없는 경우 포지션 오픈을 위해, 두 번째는 포지션은 있으나 주문이 없는 경우를 위해, 그리고 세 번째는 이미 존재하는 포지션과 주문을 확인하기 위함입니다. 이 세 가지는 동시에 수행되어야 합니다.
한번 동시에 실행시켜 볼게요: 포지션 또는 주문이 설정되지 않은 경우, 포지션을 오픈해야 합니다. 성공적으로 포지션이 오픈되었다면, 스탑오더와 리미트오더를 각각 요청해야 합니다. 대기 주문 설정 요청이 승낙되지 않을 수도 있습니다만(연결 문제, 가격 정보 부족 등) 일단 포지션이 오픈된 새로운 단계로 넘어가게 됐습니다. 그렇다면 이번에는 모든 중간 과정 시나리오를 살펴보아야 겠죠:
포지션이 없는 경우. 포지션 오픈 필요. 성공적으로 포지션이 오픈된 경우 스탑오더와 리미트오더를 각각 요청할 것.
포지션은 있으나 설정된 대기 주문이 없는 경우. 스탑오더와 리미트오더를 각각 요청할 것.
포지션이 오픈되고 스톱오더가 설정되었으나 리미트오더가 없는 경우. 리미트오더를 요청할 것.
포지션이 오픈되고 리미트오더가 설정되었으나 스톱오더가 없는 경우. 스톱오더를 요청할 것.
해당 예시의 운용 단계 판단 시 거래 상황이 위의 규칙과 완전히 동일해야 함을 유의하세요. 한 가지 포지션이 있고 주문이 없는 경우 또는 포지션이 있고 두 가지 중 한 가지 주문만 있는 경우의 두 가지 경우만이 발생 가능합니다. 이러한 원칙을 따르는 전략 운용 단계의 설명은 매우 복잡한 데다가 가능한 경우를 하나하나 확인하다 보면 소요 시간도 늘어나기 때문에 전략 실행이 불가능할 수도 있습니다. 그래서 약간 다른 방법으로 위의 예시에 해당하는 운용 규칙을 살펴볼까 해요:
포지션이 없는 경우. 포지션 오픈 필요. 성공적으로 포지션이 오픈된 경우 스탑오더와 리미트오더를 각각 요청할 것.
포지션이 있는 경우. 이 경우, 두 가지 대기 주문이 설정된 상태여야 함. 스탑오더가 있는지 확인 후 없을 경우 설정할 것. 리미트오더가 있는지 확인 후 없을 경우 설정할 것.
이 경우에 사용될 수 있는 운용 단계 식별용 몇 가지 최소 규칙과 단계별 해당 거래 상황에 대한 완벽한 설명을 만들었습니다.
해당 원칙을 적용하기 위해서는 현재 포지션이 최초 포지션인지 혹은 이미 발동한 주문이 있는지를 확인해야 합니다. 시스템이 새로운 운용 단계에 있으므로 두 번째 주문을 설정할 필요는 없죠. 주문의 종류도 식별해야 하는데 우선은 포지션에 대해 알아보기로 하겠습니다. 매매 전략 코딩 기본 원칙을 좀 더 간략하고 이해하기 쉬운 방법으로 설명해 드릴게요:
최소한의 방법으로 현재 운용 단계를 식별할 수 있는 방법이 필요합니다.
각각의 운용 단계에 부합하는 상황에 대한 설명이 있어야 하고요.
시장의 움직임(개장, 폐장, 스케일링 등) 또는 대기 주문이 요구되는 단계는 두 가지 하위 단계로 분류합니다: 시장 움직임 전과 후 (한번에 모두 실행하고 대기 주문 실패 시 재실행 가능하도록)
시장의 움직임(개장, 폐장, 스케일링 등) 또는 대기 주문이 요구되는 단계의 경우, 대기주문은 시장 움직임 완료 후 실행됩니다.
하나의 단계는 하나의 시장 움직임 또는 복수 개의 대기 주문에 해당합니다.
주문 및 포지션 식별
포지션과 주문은 다음의 방법으로 식별 가능합니다: 주석, 매직 넘버 또는 전역 변수. 주석을 사용해 보겠습니다. 주석 사용의 가장 큰 문제는 글자수에 제한이 있는데 브로커가 내용을 추가할 수 있다는 점이죠. 남은 공간이 부족하면 브로커의 주석이 잘리고 맙니다.
그렇기 때문에 최소한의 주석을 남기고 브로커의 주석과 분리할 수 있는 방법을 강구해야 하는데요. 각각의 주문은 단 하나의 식별자만을 필요로 합니다. 실제 사용되는 식별자는 숫자 한 두개 또는 알파벳 하나와 숫자 한 두개가 혼합된 경우가 많습니다. 식별자 끝에는 마킹을 할 거예요. 예를 들어 '='를 넣는다고 하죠(브로커들이 거의 사용하지 않는 것 같아서 골랐어요.) 최대 4자까지인데요. 주석에서 식별자를 구하기 위해서는 다음과 같은 함수를 사용할 수 있습니다:
//+------------------------------------------------------------------+ //| Function for obtaining the identifier from the aComment string | //+------------------------------------------------------------------+ string GetID(string aComment) { int p =StringFind(aComment,"=",0); // Determine the position of the separator string id=StringSubstr(aComment,0,p); // Get the substring located before the separator return(id); } //+------------------------------------------------------------------+
식별자를 이용해 포지션 또는 주문을 확인해야 하는 경우 다음을 따라해 보세요:
//+------------------------------------------------------------------+ //| Checking the comment against the set identifier | //+------------------------------------------------------------------+ bool FitsID(string aID,string aComment) { return(StringFind(aComment,aID+"=",0)==0); } //+------------------------------------------------------------------+
Metalanguage를 이용한 매매 전략 작성
매매 전략 작성에 쓰이는 언어에 대해 알아 볼게요. 간결하고, 명확하며, 직관적인 동시에 MQL5 형식에 부합하여 불필요한 연산 없이 빠른 실행이 가능해야 합니다. 결과가 어떤지는 말하지 않아도 아실 거예요.
전략은 텍스트 파일에 작성한 후 엑스퍼트 어드바이저 설정창에서 지정해 엑스퍼트 어드바이저로 연결되도록 합니다.
파일 내 행 하나가 하나의 운용 단계에 해당하죠. 각 행은 두 개의 필드로 나뉘어 있는데요. 첫 번째 필드는 단계 식별 규칙을 나타냅니다. 두 번째 필드는 거래 행위에 관한 설명이죠. 두 필드는 세로줄 '|'로 나뉘어 있습니다. 식별 규칙과 거래 행위 항목은 ';'로 구분됩니다.
명령 이외에도, 각 행의 오른쪽에 '#'로 분리되는 주석을 추가할 수 있습니다. 예:
Nothing | Buy(M1,1,0,0) #If there is no position or order in the market, open a Buy position, mark it with "М1", lot 1, no Stop Loss, no Take Profit.
단계 식별
단계 식별에는 현재 포지션, 대기 주문 또는 지난 거래 등에 대한 정보가 필요할 수 있습니다. 포지션의 형태와 더불어 가격, 수익, 손절가 등 기타 세부 정보가 요구될 수도 있고요. 지난 거래에 대한 정보는 거래 결과를 의미할 수도 있겠죠. 대기 주문의 경우, 시초가, 손절가, 이익실현가(주로 실행 단계) 등의 구체적인 정보가 필요할 수 있습니다.
이런 정보는 거래 데이터 액세스 명령을 통해 얻을 수 있습니다. 여기에 필요한 명령은 대부분 두 가지 매개 변수를 갖는데요. 포지션 또는 주문 식별자와 매개 변수 식별자입니다. 매개 변수 식별자가 지정되지 않은 경우, 명령 및 식별자로 지정된 거래 대상의 존재만 확인 가능합니다.
예를 들어 명령어 Buy(M1)은 식별자 'M1'을 갖는 포지션이 있음을 의미하죠. Buy() 명령이 혼자 쓰이는 경우(혹은 괄호 없이 Buy만 쓰이는 경우), 불특정 식별자를 갖는 포지션이 있음을 의미합니다. 매개 변수 식별자를 특정하면 매개 변수 값을 나타낼 수 있습니다. 예: Buy(M1,StopLossInPoints) - 'M1' 식별자를 갖는 매수 포지션에 대한 손절가. 특정한 식별자가 없는 경우 - Buy(,StopLossInPoints), 불특정 식별자를 갖는 매수 포지션에 대한 손절매만으로 간주합니다(매수 포지션이 있는 경우).
획득 값은 조건 검사에 사용됩니다. 예: Buy(M1,StopLossInPoints)>=0 - 해당 포지션의 손익분기점. 포지션이 없거나 식별자가 다른 포지션이 있는 경우에는 식별되지 않습니다. 즉, 두 가지 조건을 한번에 검사할 수는 없는거죠. 그러나 해당 경우 손절매 여부를 미리 확인해야 할 필요는 있죠. - Buy(M1,StopLossExists); Buy(M1,StopLossInPoints)>=0.
입력 값 확인 시에는 모든 부등호를 사용할 수 있습니다: '>=', '<=', '==', '!=', '>', '<'. 부등호 오른쪽에 위치하는 값은 숫자 또는 Var1, Var2 등의 특수 변수로 나타낼 수 있습니다. Var20도 가능하죠. 숫자 또는 변수에 'p'가 붙게 되면 해당 값에 포인트 값이 곱해집니다(_포인트 변수).
부등호 오른쪽에는 보다 복잡한 연산이 올 수도 있습니다. 예: X1*X2+X3*X4 (물론 '+' 대신 '-'도 사용 가능), X1, X2, X3과 X4는 숫자, 변수 또는 데이터 액세스 명령. 하단의 예시는 이론적으로 옳다고 볼 수 있습니다(실용성은 없지만요).
-BuyStop(BS1,StopLossInPoints)*-SellLimit(SL1,StopLossInPoints)+-SellStop(SS1,StopLossInPoints)*-BuyLimit(SL1,StopLossInPoints)
표 1은 사용 가능한 모든 액세스 명령을 나타냅니다.
표 1. 데이터 액세스 명령
인덱스 | 명령 | 설정 가능 매개 변수 | 목적 |
---|---|---|---|
0 | Nothing | 매개 변수 없음 | 포지션 또는 대기 주문 없음 |
1 | NoPos | 매개 변수 없음 | 포지션 없음 |
2 | Pending | 객체 식별자, 주문 매개 변수 식별자 | 해당 객체 식별자를 포함하는 모든 대기 주문 식별. 특정한 객체 식별자가 없는 경우 객체 식별자와 관계 없이 모든 대기 주문 식별 |
3 | Buy | 객체 식별자, 포지션 매개 변수 식별자 | 해당 객체 식별자를 포함하는 매수 포지션 식별. 특정한 객체 식별자가 없는 경우 존재하는 매수 포지션 식별 |
4 | Sell | 객체 식별자, 포지션 매개 변수 식별자 | 해당 객체 식별자를 포함하는 매도 포지션 식별. 특정한 객체 식별자가 없는 경우 존재하는 매도 포지션 식별 |
5 | BuyStop | 객체 식별자, 주문 매개 변수 식별자 | 해당 객체 식별자를 포함하는 역지정가 매수 주문 식별. 특정한 객체 식별자가 없는 경우 존재하는 역지정가 매수 주문 식별 |
6 | SellStop | 객체 식별자, 주문 매개 변수 식별자 | 해당 객체 식별자를 포함하는 역지정가 매도 주문 식별. 특정한 객체 식별자가 없는 경우 존재하는 역지정가 매도 주문 식별 |
7 | BuyLimit | 객체 식별자, 주문 매개 변수 식별자 | 해당 객체 식별자를 포함하는 지정가 매수 주문 식별. 특정한 객체 식별자가 없는 경우 존재하는 지정가 매수 주문 식별 |
8 | SelLimit | 객체 식별자, 주문 매개 변수 식별자 | 해당 객체 식별자를 포함하는 지정가 매도 주문 식별. 특정한 객체 식별자가 없는 경우 존재하는 지정가 매도 주문 식별 |
9 | BuyStopLimit | 객체 식별자, 주문 매개 변수 식별자 | 해당 객체 식별자를 포함하는 스탑-리밋 매수 주문 식별. 특정한 객체 식별자가 없는 경우 존재하는 스탑-리밋 매수 주문 식별 |
10 | SellStopLimit | 객체 식별자, 주문 매개 변수 식별자 | 해당 객체 식별자를 포함하는 스탑-리밋 매도 주문 식별. 특정한 객체 식별자가 없는 경우 존재하는 스탑-리밋 매도 주문 식별 |
11 | LastDeal | 빈 값, 거래 매개 변수 식별자 | 직전 매매 |
12 | LastDealBuy | 빈 값, 거래 매개 변수 식별자 | 직전 매매가 매수 거래인 경우 |
13 | LastDealSell | 빈 값, 거래 매개 변수 식별자 | 직전 매매가 매도 거래인 경우 |
14 | NoLastDeal | 매개 변수 없음 | 매매 기록 없음; 엑스퍼트 어드바이저를 처음 실행하는 경우 필요 |
15 | SignalOpenBuy | 매개 변수 없음 | 매수 포지션 오픈 인디케이터 시그널 |
16 | SignalOpenSell | 매개 변수 없음 | 매도 포지션 오픈 인디케이터 시그널 |
17 | SignalCloseBuy | 매개 변수 없음 | 매수 포지션 청산 인디케이터 시그널 |
18 | SignalCloseSell | 매개 변수 없음 | 매도 포지션 청산 인디케이터 시그널 |
19 | UserBuy | 매개 변수 없음 | 사용자 매수 명령 |
20 | UserSell | 매개 변수 없음 | 사용자 매도 명령 |
21 | Bid | 매개 변수 없음 | 매수호가 |
22 | Ask | 매개 변수 없음 | 매도호가 |
23 | ThisOpenPrice | 매개 변수 없음 | 매개 변수가 계산된 주문의 시초가. 스탑-리밋 주문을 제외한 모든 대기 주문 관련 액션 명령에 사용 |
24 | ThisOpenPrice1 | 매개 변수 없음 | 매개 변수가 계산된 주문의 시초가-1. 스탑-리밋 대기 주문 관련 액션 명령에 사용 |
25 | ThisOpenPrice2 | 매개 변수 없음 | 매개 변수가 계산된 주문의 시초가-2. 스탑-리밋 대기 주문 관련 액션 명령에 사용 |
26 | LastEADeal | 객체 식별자, 거래 매개 변수 식별자 | 엑스퍼트 어드바이저에서 실행된 직전 거래. 코멘트에 '='를 포함하는 직전 거래는 기록에서 검색 후 객체 식별자가 검사됨 |
27 | LastEADealBuy | 객체 식별자, 거래 매개 변수 식별자 | 엑스퍼트 어드바이저에서 실행된 직전 거래가 매수 거래인 경우. 코멘트에 '='를 포함하는 직전 거래는 기록에서 검색 후 객체 식별자가 검사됨 |
28 | LastEADealSell | 객체 식별자, 거래 매개 변수 식별자 | 엑스퍼트 어드바이저에서 실행된 직전 거래가 매도 거래인 경우. 코멘트에 '='를 포함하는 직전 거래는 기록에서 검색 후 객체 식별자가 검사됨 |
29 | NoTradeOnBar | 매개 변수 없음 | 마지막 바에 거래가 없는 경우 |
표1의 명령어를 활용하면 다음 매매 객체에 대한 액세스가 가능해 집니다: 포지션, 매매, 거래 및 작성 예정 주문. 객체가 다르면 매개 변수도 달라지죠.
표 2는 모든 매개 변수 식별자 및 적용 가능한 객체 타입에 대한 설명입니다.
표 2. 데이터 액세스 식별자.
인덱스 | 식별자 | 목적 | 거래 객체 타입 |
---|---|---|---|
0 | ProfitInPoints | 포인트 수익 | 포지션 |
1 | ProfitInValute | 예금 통화 수익 | 포지션, 거래 |
2 | OpenPrice | 시초가 | 포지션, 대기 주문(스탑-리밋 주문 제외) |
3 | LastPrice | 가격 | 거래 |
4 | OpenPrice1 | 스탑-리밋 지정가 전환 가격 | 스탑-리밋 대기 주문. 해당 주문이 지정가 주문으로 전환되는 경우 |
5 | OpenPrice2 | 스탑-리밋 포지션 전환 가격 | 스탑-리밋 대기 주문. 해당 주문이 지정가 주문으로 전환되는 경우 |
6 | StopLossValue | 손절가 | 포지션, 대기 주문 |
7 | TakeProfitValue | 손익분기점 | 포지션, 대기 주문 |
8 | StopLossInPoints | 포인트 손절가 | 포지션, 대기 주문 |
9 | TakeProfitInPoints | 포인트 손익분기점 | 포지션, 대기 주문 |
10 | StopLossExists | 손절가 존재 여부 | 포지션, 대기 주문 |
11 | TakeProfitExists | 손익분기점 존재 여부 | 포지션, 대기 주문 |
12 | Direction | 방향 1 - 매수, -1 - 매도 | 포지션, 대기 주문, 거래 |
액션
액션은 개장 및 폐장, 대기 주문의 설정, 정정 및 취소, 이 밖에 추적 손절매, 손익분기점, 대기 주문 추적 손절매 등의 관리 도구 실행을 포함합니다.
포지션 오픈과 매매 주문 설정 시 필요한 매개 변수가 사용되는데요. 매개 변수는 명령어 다음에 오는 괄호 안에 표시됩니다. 일반적인 함수가 호출되는 방식으로요. 모든 명령의 첫 번째 매개 변수는 식별자입니다. 매개 변수 지정 시에는 숫자 값, 변수, 기존 포지션 또는 주문에서 사용된 매개 변수를 이용할 수 있습니다. 단계 식별 섹션에서 언급된 X1*X2+X3*X4와 같은 연산도 매개 변수로 쓸 수 있고요.
표 3에 모든 액션 명령이 설명되어 있습니다.
표 3. 액션 명령
인덱스 | 명령 | 목적 |
---|---|---|
0 | Buy(ID,Lot,StopLoss,TakeProfit) | 매수 포지션 오픈 |
1 | Sell(ID,Lot,StopLoss,TakeProfit) | 매도 포지션 오픈 |
2 | Close(ID) | 포지션 청산 |
3 | BuyStop(ID,Lot,Price,StopLoss,TakeProfit) | 역지정가 매수 주문 설정 |
4 | SellStop(ID,Lot,Price,StopLoss,TakeProfit) | 역지정가 매도 주문 설정 |
5 | BuyLimit(ID,Lot,Price,StopLoss,TakeProfit) | 지정가 매수 주문 설정 |
6 | SellLimit(ID,Lot,Price,StopLoss,TakeProfit) | 지정가 매도 주문 설정 |
7 | BuyStopLimit(ID,Lot,Price1,Price2,StopLoss,TakeProfit) | 스탑-리밋 매수 주문 설정 |
8 | SellStopLimit(ID,Lot,Price1,Price2,StopLoss,TakeProfit) | 스탑-리밋 매도 주문 설정 |
9 | Delete(ID) | 대기 주문 취소 |
10 | DeleteAll(ID,BuyStop,SellStop,BuyLimit,SellLimit,BuyStopLimit,SellStopLimit) | 특정 형식의 대기 주문 취소 |
11 | Modify(ID,Price1,Price2,StopLoss,TakeProfit) | 포지션 또는 주문 수정 |
12 | TrailingStop | 추적손절매 기능 설정. 엑스퍼트 어드바이저 설정창에서 매개 변수 설정 |
13 | BreakEven | 수익분기점 기능 설정. 엑스퍼트 어드바이저 설정창에서 매개 변수 설정 |
액션 명령 매개 변수는 표4 참조
표 4. 액션 명령 매개 변수
매개 변수 | 목적 |
---|---|
ID | 거래 객체(포지션, 주문) 식별자 |
랏 | 유닛별 랏 사이즈 엑스퍼트 어드바이저 설정 창에서 유닛 변수를 나타내는 랏 변수 설정 가능 |
StopLoss | 손절가 |
TakeProfit | 손익분기점 |
가격 | 대기 주문 가격(스탑-리밋 주문 제외) |
Price1 | 스탑-리밋 지정가 전환 가격 |
Price2 | 스탑-리밋 포지션 전환 가격 |
이제 Metalanguage를 사용하여 매매 전략을 직접 작성해 볼게요.
Metalanguage를 이용한 매매 전략 예시
여러분의 간편한 이해를 위해 각 단계와 액션 명령, 코멘트란의 설명이 포함된 프로그래밍 방법을 표로 만들었습니다. 첨부파일은 엑스퍼트 어드바이저에서 사용 가능한 프로그래밍별 텍스트 파일입니다.
리미트오더를 이용한 스케일링
최초 포지션은 사용자가 설정한 속성에 따라 오픈됩니다. 스케일링은 최대 5회 가능합니다(리미트오더). 동시에 세 개의 주문만이 존재할 수 있고요.
표 5. 리미트오더를 이용한 스케일링을 위한 Metaprogram
단계 번호 | 단계 식별 | 액션 | 코멘트 |
---|---|---|---|
1 | Nothing; UserBuy | Buy(1,1,0,Ask+Var1p); BuyLimit(2,2,Buy(1,OpenPrice)-Var2p,0,ThisOpenPrice+Var3p); BuyLimit(3,4,BuyLimit(2,OpenPrice)-Var2p,0,ThisOpenPrice+Var3p); BuyLimit(4,8,BuyLimit(3,OpenPrice)-Var2p,0,ThisOpenPrice+Var3p) | 포지션 또는 주문이 없는 경우 엑스퍼트 어드바이저 속성에서 매수 주문이 설정되며 초기 랏이 적용된 포지션을 오픈합니다. 포지션이 성공적으로 오픈된 경우, 세 가지 리미트오더 설정을 시도합니다. 주문 가격이 이전 주문 가격을 기반으로 하므로 이전 주문이 성공적으로 체결된 경우 다음 주문 또한 성공적으로 체결됩니다. |
2 | Buy(1) | BuyLimit(2,2,Buy(1,OpenPrice)-Var2p,0,ThisOpenPrice+Var3p); BuyLimit(3,4,BuyLimit(2,OpenPrice)-Var2p,0,ThisOpenPrice+Var3p); BuyLimit(4,8,BuyLimit(3,OpenPrice)-Var2p,0,ThisOpenPrice+Var3p) | 1단계에서 포지션이 성공적으로 오픈되었으나 전체 대기 주문이 설정되지 않은 경우 계속해서 남은 대기 주문을 설정합니다. |
3 | Buy(2) | BuyLimit(3,4,Buy(2,OpenPrice)-Var2p,0,ThisOpenPrice+Var3p); BuyLimit(4,8,BuyLimit(3,OpenPrice)-Var2p,0,ThisOpenPrice+Var3p); BuyLimit(5,16,BuyLimit(4,OpenPrice)-Var2p,0,ThisOpenPrice+Var3p) | 첫 번째 리미트오더(식별자 2)가 실행된 경우 나머지 두 리미트오더 또한 지난 단계에서 실행되었어야 합니다. 그러나 실패하였으므로 계속해서 실행 시도를 하며 항상 세 가지 리미트오더가 존재하도록 새 오더를 설정합니다. |
4 | Buy(3) | BuyLimit(4,8,Buy(3,OpenPrice)-Var2p,0,ThisOpenPrice+Var3p); BuyLimit(5,16,BuyLimit(4,OpenPrice)-Var2p,0,ThisOpenPrice+Var3p); BuyLimit(6,32,BuyLimit(4,OpenPrice)-Var2p,0,ThisOpenPrice+Var3p) | 새로운 리미트오더가 발동되었으며 이전 단계에서와 같이 세 가지 리미트오더가 모두 존재함을 확인합니다. |
5 | Buy(4) | BuyLimit(5,16,Buy(4,OpenPrice)-Var2p,0,ThisOpenPrice+Var3p); BuyLimit(6,32,BuyLimit(5,OpenPrice)-Var2p,0,ThisOpenPrice+Var3p) | 해당 단계는 총 주문의 수가 최대 주문 가능 건수에 근접한 경우 두 대기 주문의 존재를 확인합니다. |
6 | Buy(5) | BuyLimit(6,32,Buy(5,OpenPrice)-Var2p,0,ThisOpenPrice+Var3p) | 해당 단계는 한 건의 마지막 주문만을 갖습니다. |
7 | Buy(6) | Modify(6,,,Buy(6,OpenPrice)-Var4p,) | 마지막 주문이 실행된 경우 손절매가 설정됩니다. |
8 | Nothing; UserSell | Sell(1,1,0,Var1p); SellLimit(2,2,Sell(1,OpenPrice)+Var2p,0,ThisOpenPrice-Var3p); SellLimit(3,4,SellLimit(2,OpenPrice)+Var2p,0,ThisOpenPrice-Var3p); SellLimit(4,8,SellLimit(3,OpenPrice)+Var2p,0,ThisOpenPrice-Var3p) | 1단계와 유사하나 매도 주문의 경우입니다. |
9 | Sell(1) | SellLimit(2,2,Sell(1,OpenPrice)+Var2p,0,ThisOpenPrice-Var3p); SellLimit(3,4,SellLimit(2,OpenPrice)+Var2p,0,ThisOpenPrice-Var3p); SellLimit(4,8,SellLimit(3,OpenPrice)+Var2p,0,ThisOpenPrice-Var3p) | 2단계와 유사하나 매도 주문의 경우입니다. |
10 | Sell(2) | SellLimit(3,4,Sell(2,OpenPrice)+Var2p,0,Var3); SellLimit(4,8,SellLimit(3,OpenPrice)+Var2p,0,ThisOpenPrice-Var3p); SellLimit(5,16,SellLimit(4,OpenPrice)+Var2p,0,ThisOpenPrice-Var3p) | 3단계와 유사하나 매도 주문의 경우입니다. |
11 | Sell(3) | SellLimit(4,8,Sell(3,OpenPrice)+Var2p,0,Var3); SellLimit(5,16,SellLimit(4,OpenPrice)+Var2p,0,ThisOpenPrice-Var3p); SellLimit(6,32,SellLimit(4,OpenPrice)+Var2p,0,ThisOpenPrice-Var3p) | 4단계와 유사하나 매도 주문의 경우입니다. |
12 | Sell(4) | SellLimit(5,16,Sell(4,OpenPrice)+Var2p,0,Var3); SellLimit(6,32,SellLimit(5,OpenPrice)+Var2p,0,ThisOpenPrice-Var3p) | 5단계와 유사하나 매도 주문의 경우입니다. |
13 | Sell(5) | SellLimit(6,32,Sell(5,OpenPrice)+Var2p,0,ThisOpenPrice-Var3p) | 6단계와 유사하나 매도 주문의 경우입니다. |
14 | Sell(6) | Modify(6,,,Sell(6,OpenPrice)+Var4p,) | 7단계와 유사하나 매도 주문의 경우입니다. |
15 | NoPos; Pending | DeleteAll(,0,0,1,1,0,0) | 대기 주문은 있으나 포지션이 없는 경우입니다. 이익실현이 발동된 경우 발생합니다. 이 경우 모든 주문은 삭제되어야 합니다. 주문이 삭제되면 시스템이 1단계 또는 9단계로 전환됩니다. 사용자가 초기 방향 설정을 해제한 경우에는 아무 액션이 발생하지 않습니다. |
변수의 사용: Var1 - 최초 주문 이익실현, Var2 - 이전 주문의 시초가에 비례해 설정된 리미트오더 값, Var3 - 직전 주문 손절매
그림 5는 해당 Metaprogram이 실행된 차트입니다.
그림 5. 리미트오더를 이용한 스케일링을 위한 Metaprogram 실행
주의사항: 매수와 매도 관련 규칙은 각각 설명되어 있습니다. 모든 대기 주문의 주문 가격은 직전 주문을 기준으로 설정됩니다. 따라서 주문 설정 시도가 실패하는 경우 매개 변수 값 부족으로 다음 주문은 설정되지 않습니다. 포지션을 기준으로 가격을 설정하면 안되니까요. 그렇게 되면 놓치는 주문도 생기거든요.
SAR
우선 두 개의 스탑오더가 대기 중이어야 합니다. 반전은 5개까지 가능합니다.
표 6. SAR을 위한 Metaprogram
단계 번호 | 단계 식별 | 액션 | 코멘트 |
---|---|---|---|
1 | Nothing | BuyStop(1,1,Ask+Var1p,ThisOpenPrice-Var2p,ThisOpenPrice+Var3p); SellStop(1,1,Bid-Var1p,ThisOpenPrice+Var2p,ThisOpenPrice-Var3p) | 포지션이나 주문이 없습니다; 식별자 1을 사용해 두 개의 스탑오더 설정을 시도합니다. |
2 | NoPos; BuyStop(1) | SellStop(1,1,Bid-Var1p,ThisOpenPrice+Var2p,ThisOpenPrice-Var3p) | 포지션은 없으나 식별자 1을 포함하는 역지정가 매수 주문이 있으므로 식별자 1을 포함하는 역지정가 매도 주문 또한 있어야 합니다. |
3 | NoPos; SellStop(1) | BuyStop(1,1,Ask+Var1p,ThisOpenPrice-Var2p,ThisOpenPrice+Var3p) | 포지션은 없으나 식별자 1을 포함하는 역지정가 매도 주문이 있으므로 식별자 1을 포함하는 역지정가 매수 주문 또한 있어야 합니다. |
4 | Buy(1) | Delete(1); SellStop(2,2,Buy(1,StopLossValue),ThisOpenPrice+Var2p,ThisOpenPrice-Var3p) | 식별자 1을 포함하는 매수 포지션이 설정되어 있습니다. 이 경우 식별자 1을 포함하는 다른 주문은 없어야 하며 식별자 2를 포함하는 역지정가 매도 주문이 있어야 합니다. |
5 | Sell(1) | Delete(1); BuyStop(2,2,Sell(1,StopLossValue),ThisOpenPrice-Var2p,ThisOpenPrice+Var3p) | 4단계와 유사하나 역지정가 매도 주문이 발동한 경우입니다. |
6 | Buy(2) | SellStop(3,4,Buy(2,StopLossValue),ThisOpenPrice+Var2p,ThisOpenPrice-Var3p) | 두 번째 역지정가 매수 주문이 발동했으므로 세 번째 역지정가 매도 주문이 설정되어야 합니다. |
7 | Sell(2) | BuyStop(3,4,Sell(2,StopLossValue),ThisOpenPrice-Var2p,ThisOpenPrice+Var3p) | 두 번째 역지정가 매도 주문이 발동했으므로 세 번째 역지정가 매수 주문이 설정되어야 합니다. |
8 | Buy(3) | SellStop(4,8,Buy(3,StopLossValue),ThisOpenPrice+Var2p,ThisOpenPrice-Var3p) | 세 번째 역지정가 매도 주문이 실행되었으므로 네 번째 역지정가 매수 주문이 설정되어야 합니다. |
9 | Sell(3) | BuyStop(4,8,Sell(3,StopLossValue),ThisOpenPrice-Var2p,ThisOpenPrice+Var3p) | 세 번째 역지정가 매수 주문이 실행되었으므로 네 번째 역지정가 매도 주문이 설정되어야 합니다. |
10 | Buy(4) | SellStop(5,16,Buy(4,StopLossValue),ThisOpenPrice+Var2p,ThisOpenPrice-Var3p) | 네 번째 역지정가 매수 주문이 실행되었으므로 다섯 번째 역지정가 매도 주문이 설정되어야 합니다. |
11 | Sell(4) | BuyStop(5,16,Sell(4,StopLossValue),ThisOpenPrice-Var2p,ThisOpenPrice+Var3p) | 네 번째 역지정가 매도 주문이 실행되었으므로 다섯 번째 역지정가 매수 주문이 설정되어야 합니다. |
12 | Buy(5) | SellStop(6,32,Buy(5,StopLossValue),ThisOpenPrice+Var2p,ThisOpenPrice-Var3p) | 다섯 번째 역지정가 매수 주문이 실행되었으므로 여섯 번째 역지정가 매도 주문이 설정되어야 합니다. |
13 | Sell(5) | BuyStop(6,32,Sell(5,StopLossValue),ThisOpenPrice-Var2p,ThisOpenPrice+Var3p) | 다섯 번째 역지정가 매도 주문이 실행되었으므로 여섯 번째 역지정가 매수 주문이 설정되어야 합니다. |
14 | NoPos; BuyStop(2) | Delete(2) | 포지션은 없으나 역지정가 매수 주문이 있는 경우입니다. 포지션이 이익실현 설정 가격에서 청산된 경우 발생할 수 있습니다. 해당 경우 남은 주문은 삭제되며 시스템은 1단계로 돌아갑니다. |
15 | NoPos; SellStop(2) | Delete(2) | 14단계와 유사합니다. |
16 | NoPos; BuyStop(3) | Delete(3) | 14단계와 유사합니다. |
17 | NoPos; SellStop(3) | Delete(3) | 14단계와 유사합니다. |
18 | NoPos; BuyStop(4) | Delete(4) | 14단계와 유사합니다. |
19 | NoPos; SellStop(4) | Delete(4) | 14단계와 유사합니다. |
20 | NoPos; BuyStop(5) | Delete(5) | 14단계와 유사합니다. |
21 | NoPos; SellStop(5) | Delete(5) | 14단계와 유사합니다. |
22 | NoPos; BuyStop(6) | Delete(6) | 14단계와 유사합니다. |
23 | NoPos; SellStop(6) | | Delete(6) | 14단계와 유사합니다. |
변수의 사용: Var1 - 현재 시장 가격으로 최초 주문 가격이 설정된 경우, Var2 - 손절매, Var3 - 이익실현.
그림 6은 해당 Metaprogram이 실행된 차트입니다.
그림 6. SAR을 위한 Metaprogram 실행
피라미딩
최초 포지션은 인디케이터 시그널을 기반으로 오픈됩니다. 최대 5회의 스케일링이 가능합니다.
표 7. 피라미딩을 위한 Metaprogram
단계 번호 | 단계 식별 | 액션 | 코멘트 |
---|---|---|---|
1 | Nothing; SignalOpenBuy | Buy(1,1,Ask-Var1p,Ask+Var2p*6) | 포지션이나 주문이 없습니다. 인디케이터 시그널을 따라 매수 포지션을 오픈합니다. 손익분기점이 Var2p*6 만큼 떨어진 곳에 설정됩니다. 다음에는 Var2p*5에 설정될 것입니다. 이는 손익분기점이 비슷한 가격대에 형성되도록 하기 위함입니다. |
2 | Buy(1); Buy(1,ProfitInPoints)>=Var3 | Buy(2,1,Ask-Var1p,Ask+Var2p*5) | 가격이 상승세인 매수 포지션이 있으므로 매수 스케일 오더를 실행합니다. |
3 | Buy(2) | Modify(2,,,Buy(2,OpenPrice),) | 포지션의 인덱스 2는 해당 포지션이 초기 포지션이 아니며 매수 스케일 오더가 실행되었음을 의미합니다. 손절매가 수익분기점에서 일어납니다. |
4 | Buy(2); Buy(2,ProfitInPoints)>=Var3 | Buy(3,1,Ask-Var1p,Ask+Var2p*4) | 다시 상승세이므로 매수 스케일 오더를 실행합니다. |
5 | Buy(3) | Modify(3,,,Buy(3,OpenPrice),) | 매수 스케일 오더가 실행될 때마다 손절매가 수익분기점으로 설정됩니다. |
6 | Buy(3); Buy(3,ProfitInPoints)>=Var3 | Buy(4,1,Ask-Var1p,Ask+Var2p*3) | 4단계와 유사합니다. |
7 | Buy(4) | Modify(4,,,Buy(4,OpenPrice),) | 5단계와 유사합니다. |
8 | Buy(4); Buy(4,ProfitInPoints)>=Var3 | Buy(5,1,Ask-Var1p,Ask+Var2p*2) | 4단계와 유사합니다. |
9 | Buy(5) | Modify(5,,,Buy(5,OpenPrice),) | 5단계와 유사합니다. |
10 | Buy(5); Buy(5,ProfitInPoints)>=Var3 | Buy(6,1,Ask-Var1p,Ask+Var2p) | 4단계와 유사합니다. |
11 | Buy(6) | Modify(6,,,Buy(6,OpenPrice),) | 5단계와 유사합니다. |
12 | Nothing; SignalOpenSell | Sell(1,1,Bid+Var1p,Bid-Var2p*6) | 1단계와 유사하나 매도 포지션의 경우입니다. |
13 | Sell(1); Sell(1,ProfitInPoints)>=Var3 | Sell(2,1,Bid+Var1p,Bid-Var2p*5) | 2단계와 유사하나 매도 포지션의 경우입니다. |
14 | Sell(2) | Modify(2,,,Sell(2,OpenPrice),) | 3단계와 유사하나 매도 포지션의 경우입니다. |
15 | Sell(2); Sell(2,ProfitInPoints)>=Var3 | Sell(3,1,Bid+Var1p,Bid-Var2p*4) | 4단계와 유사하나 매도 포지션의 경우입니다. |
16 | Sell(3); | Modify(3,,,Sell(3,OpenPrice),) | 5단계와 유사하나 매도 포지션의 경우입니다. |
17 | Sell(3); Sell(3,ProfitInPoints)>=Var3 | Sell(4,1,Bid+Var1p,Bid-Var2p*3) | 6단계와 유사하나 매도 포지션의 경우입니다. |
18 | Sell(4); | Modify(4,,,Sell(4,OpenPrice),) | 7단계와 유사하나 매도 포지션의 경우입니다. |
19 | Sell(4); Sell(4,ProfitInPoints)>=Var3 | Sell(5,1,Bid+Var1p,Bid-Var2p*2) | 8단계와 유사하나 매도 포지션의 경우입니다. |
20 | Sell(5); | Modify(5,,,Sell(5,OpenPrice),) | 9단계와 유사하나 매도 포지션의 경우입니다. |
21 | Sell(5); Sell(5,ProfitInPoints)>=Var3 | Sell(6,1,Bid+Var1p,Bid-Var2p) | 10단계와 유사하나 매도 포지션의 경우입니다. |
22 | Sell(6); | Modify(6,,,Sell(6,OpenPrice),) | 11단계와 유사하나 매도 포지션의 경우입니다. |
변수의 사용: Var1 - 초기 손절매, Var2 - 마지막 주문 이익실현, Var3 - 매도 스케일 주문 실행 및 손절매의 수익분기점으로 이동 시 포인트 수익.
그림 7은 해당 Metaprogram이 실행된 차트입니다.
그림 7. 피라미딩을 위한 Metaprogram 실행
리오프닝
우선 두 가지 리미트 오더를 설정합니다. 하나가 발동하면 다른 하나는 삭제됩니다. 손절매가 실행되면 새로운 포지션이 오픈되고 이익실현 설정 가격에서 청산되거나 최대 포지션 개수인 5개에 도달할 때까지 유지됩니다.
표 8. 리오프닝을 위한 Metaprogram
단계 번호 | 단계 식별 | 액션 | 코멘트 |
---|---|---|---|
1 | Nothing; NoLastDeal | BuyLimit(1,1,Ask-Var1p,ThisOpenPrice-Var2p,ThisOpenPrice+Var3p); SellLimit(1,1,Bid+Var1p,ThisOpenPrice+Var2p,ThisOpenPrice-Var3p) | 포지션 또는 주문이 없으며 계정에 해당 심볼 거래 기록이 없습니다. 시스템 운용의 첫 단계인 것이죠. 최초 액션으로 두 개의 리미트오더가 설정됩니다. |
2 | Nothing; LastDeal(,ProfitInValute)>0 | BuyLimit(1,1,Ask-Var1p,ThisOpenPrice-Var2p,ThisOpenPrice+Var3p); SellLimit(1,1,Bid+Var1p,ThisOpenPrice+Var2p,ThisOpenPrice-Var3p) | 포지션 또는 주문이 없으나 이익을 창출한 거래 기록이 있습니다. 전 단계가 완료된 것이므로 1단계부터 다시 시작해 두 개의 리미트오더를 설정합니다. |
3 | Nothing; LastEADeal(5) | BuyLimit(1,1,Ask-Var1p,ThisOpenPrice-Var2p,ThisOpenPrice+Var3p); SellLimit(1,1,Bid+Var1p,ThisOpenPrice+Var2p,ThisOpenPrice-Var3p) | 포지션 또는 주문이 없으나 마지막 식별자가 포함된 거래 기록이 있습니다. 전 단계가 완료된 것으로 간주되므로 창출된 이익은 중요하지 않으며 1단계부터 다시 시작해 두 개의 리미트오더를 설정합니다. |
4 | NoPos; BuyLimit(1) | SellLimit(1,1,Bid+Var1p,ThisOpenPrice-Var2p,ThisOpenPrice+Var3p) | 포지션 또는 주문이 없으나 하나의 리미트오더가 있으며 이는 리미트오더가 총 두 개임을 의미합니다. |
5 | NoPos; SellLimit(1) | BuyLimit(1,1,Ask-Var1p,ThisOpenPrice+Var2p,ThisOpenPrice-Var3p) | 4단계와 유사합니다. |
6 | Buy(1); SellLimit(1) | Delete(1) | 식별자 1을 포함하는 포지션이 있습니다. 리미트오더 중 하나가 실행되었다는 의미이며 나머지 리미트 오더는 삭제되어야 합니다. |
7 | Sell(1); BuyLimit(1) | Delete(1) | 6단계와 유사합니다. |
8 | Nothing; LastDeal(1,ProfitInValute)<=0; LastEADeal(1,Direction)==1 | Buy(2,2,Ask-Var2p,Ask+Var3p) | 포지션이 없으며 마지막 거래에서 수익이 창출되지 않았습니다. 엑스퍼트 어드바이저에서 실행된 마지막 거래의 방향을 확인합니다. 매수 거래였을 경우 다음으로 오픈하는 포지션은 매수 포지션이 됩니다. |
9 | Nothing; LastDeal(1,ProfitInValute)<=0; LastEADeal(1,Direction)==-1 | Sell(2,2,Bid+Var2p,Bid-Var3p) | 포지션이 없으며 마지막 거래에서 수익이 창출되지 않았습니다. 엑스퍼트 어드바이저에서 실행된 마지막 거래의 방향을 확인합니다. 매도 거래였을 경우 다음으로 오픈하는 포지션은 매도 포지션이 됩니다. |
10 | Nothing; LastDeal(2,ProfitInValute)<=0; LastEADeal(2,Direction)==1 | Buy(3,4,Ask-Var2p,Ask+Var3p) | 8단계와 유사합니다. |
11 | Nothing; LastDeal(2,ProfitInValute)<=0; LastEADeal(2,Direction)==-1 | Sell(3,4,Bid+Var2p,Bid-Var3p) | 9단계와 유사합니다. |
12 | Nothing; LastDeal(3,ProfitInValute)<=0; LastEADeal(3,Direction)==1 | Buy(4,8,Ask-Var2p,Ask+Var3p) | 8단계와 유사합니다. |
13 | Nothing; LastDeal(3,ProfitInValute)<=0; LastEADeal(3,Direction)==-1 | Sell(4,8,Bid+Var2p,Bid-Var3p) | 9단계와 유사합니다. |
14 | Nothing; LastDeal(4,ProfitInValute)<=0; LastEADeal(4,Direction)==1 | Buy(5,16,Ask-Var2p,Ask+Var3p) | 8단계와 유사합니다. |
15 | Nothing; LastDeal(4,ProfitInValute)<=0; LastEADeal(4,Direction)==-1 | Sell(5,16,Bid+Var2p,Bid-Var3p) | 9단계와 유사합니다. |
변수의 사용: Var1 - 리미트오더가 설정된 시장 가격, Var2 - 손절매, Var3 - 이익실현.
그림 8은 해당 Metaprogram이 실행된 차트입니다.
그림 8. 리오프닝을 위한 Metaprogram 실행
아래는 거래 시그널, 추적 손절매 및 손익분기점 등의 기능을 실행시키는 간단한 프로그래밍 방법입니다.
거래 시그널
진입과 청산은 거래 시그널을 기반으로 합니다.
표 9. 트레이딩 시그널을 위한 Metaprogram
단계 번호 | 단계 식별 | 액션 | 코멘트 |
---|---|---|---|
1 | Nothing; SignalOpenBuy; NoTradeOnBar | Buy(1,1,0,0) | 포지션 또는 주문이 없으나 매수 포지션 오픈을 알리는 시그널이 있습니다. 현재 바에 거래가 없으며 매수 포지션을 오픈합니다. |
2 | Nothing; SignalOpenSell; NoTradeOnBar | Sell(1,1,0,0) | 포지션 또는 주문이 없으나 매도 포지션 오픈을 알리는 시그널이 있습니다. 현재 바에 거래가 없으며 매도 포지션을 오픈합니다. |
3 | SignalCloseBuy; Buy(1) | Close(1); | 매수 포지션이 있으며 포지션 청산을 알리는 시그널이 있습니다. 매수 포지션을 청산합니다. |
4 | SignalCloseSell; Sell(1) | Close(1); | 매도 포지션이 있으며 포지션 청산을 알리는 시그널이 있습니다. 매도 포지션을 청산합니다. |
그림 9는 해당 Metaprogram이 실행된 차트입니다.
그림 9. 트레이딩 시그널을 위한 Metaprogram 실행
추적 손절매가 있는 트레이딩 시그널
표 10. 추적 손절매가 있는 트레이딩 시그널을 위한 Metaprogram
단계 번호 | 단계 식별 | 액션 | 코멘트 |
---|---|---|---|
1 | Nothing; SignalOpenBuy; NoTradeOnBar | Buy(1,1,0,0) | 포지션 또는 주문이 없으나 매수 포지션 오픈을 알리는 시그널이 있습니다. 현재 바에 거래가 없으며 매수 포지션을 오픈합니다. |
2 | Nothing; SignalOpenSell; NoTradeOnBar | Sell(1,1,0,0) | 포지션 또는 주문이 없으나 매도 포지션 오픈을 알리는 시그널이 있습니다. 현재 바에 거래가 없으며 매도 포지션을 오픈합니다. |
3 | SignalCloseBuy; Buy(1) | Close(1); | 매수 포지션이 있으며 포지션 청산을 알리는 시그널이 있습니다. 매수 포지션을 청산합니다. |
4 | SignalCloseSell; Sell(1) | Close(1); | 매도 포지션이 있으며 포지션 청산을 알리는 시그널이 있습니다. 매도 포지션을 청산합니다. |
5 | Buy(1) | TrailingStop | 매수 포지션이 있습니다. 추적 손절매 기능이 활성화되어야 합니다. |
6 | Sell(1) | TrailingStop | 매도 포지션이 있습니다. 추적 손절매 기능이 활성화되어야 합니다. |
그림 10은 해당 Metaprogram이 실행된 차트입니다.
그림 10. 추적 손절매가 있는 트레이딩 시그널을 위한 Metaprogram
이익실현 기능을 동반한 트레이딩 시그널
표 11. 이익실현 기능을 동반한 트레이딩 시그널을 위한 Metaprogram
단계 번호 | 단계 식별 | 액션 | 코멘트 |
---|---|---|---|
1 | Nothing; SignalOpenBuy; NoTradeOnBar | Buy(1,1,0,0) | 포지션 또는 주문이 없으나 매수 포지션 오픈을 알리는 시그널이 있습니다. 현재 바에 거래가 없으므로 매수 포지션을 오픈합니다. |
2 | Nothing; SignalOpenSell; NoTradeOnBar | Sell(1,1,0,0) | 포지션 또는 주문이 없으나 매도 포지션 오픈을 알리는 시그널이 있습니다. 현재 바에 거래가 없으므로 매도 포지션을 오픈합니다. |
3 | SignalCloseBuy; Buy(1) | Close(1); | 매수 포지션이 있으며 포지션 청산을 알리는 시그널이 있습니다. 매수 포지션을 청산합니다. |
4 | SignalCloseSell; Sell(1) | Close(1); | 매도 포지션이 있으며 포지션 청산을 알리는 시그널이 있습니다. 매도 포지션을 청산합니다. |
5 | Buy(1) | BreakEven | 매수 포지션이 있습니다. 이익실현 기능이 활성화되어야 합니다. |
6 | Sell(1) | BreakEven | 매도 포지션이 있습니다. 이익실현 기능이 활성화되어야 합니다. |
그림 11은 해당 Metaprogram이 실행된 차트입니다.
그림 11. 이익실현 기능을 동반한 트레이딩 시그널을 위한 Metaprogram 실행
명령어 인터프리터
매매 전략을 정형화하는 위의 접근법은 전략에 대한 이해도를 높여줄 뿐 아니라 알고리즘을 작성해 엑스퍼트 어드바이저에서 적용할 수 있도록 해 줍니다. 또한 정교하게 고안된 규칙을 쉽게 해석하고 따를 수 있게도 해 주죠. 엑스퍼트 어드바이저의 인터프리터는 이를 염두에 두고 개발되었습니다(첨부 파일 참조). 엑스퍼트 어드바이저의 매개 변수 및 각각에 대한 설명은 표 12에서 찾아볼 수 있습니다.
표 12. 엑스퍼트 어드바이저 인터프리터 매개 변수
매개 변수 | 목적 |
---|---|
Lots | 랏 계수가 1일 때 주문량 |
UserTradeDir | 사용자가 특정한 거래 방향(단계 식별 시 UserBuy 및 UserSell 명령 실행을 통해 확인). |
ProgramFileName | Metaprogram 파일명(계정 로그인 시). 테스팅 또는 최적화 시 Metaprogram은 TesterMetaProgram.txt 파일에 저장할 것. |
DeInterpritate | 명령 해석 반전. 실행 시 파일명 앞에 'De_'가 붙은 파일이 생성되며 ProgramFileName 파일에서 어떻게 적용되었는지 확인 가능. |
사용자 변수 | |
Var1 - Var20 | 사용자 변수. |
추적 손절매 | |
TR_ON | 추적 손절매 기능 활성화 |
TR_Start | 추적 손절매 기능이 활성화되는 포인트 수익. |
TR_Level | 추적 손절매 가격. 현재 시장 가격에서 손절매까지의 포인트 거리. |
TR_Step | 손절매 수정을 위한 포인트 스텝. |
이익실현 | |
BE_ON | 이익실현 기능 활성화. |
BE_Start | 이익실현 기능이 활성화되는 포인트 수익. |
BE_Level | 이익실현 발동 시 손절매 이동 위치. BE_Start와 BE_Level 사이의 포인트 수익 고정. |
오픈 시그널 | |
OS_ON | 오픈 시그널 활성화. |
OS_Shift | 인디케이터 확인 바: 0 - 새 인디케이터, 1 - 완료. |
OS_TimeFrame | 인디케이터 타임프레임. |
OS_MA2FastPeriod | 빠른 이동평균 기간. |
OS_MA2FastShift | 빠른 이동평균 시프트. |
OS_MA2FastMethod | 빠른 이동평균법. |
OS_MA2FastPrice | 빠른 이동평균가. |
OS_MA2SlowPeriod | 느린 이동평균 기간. |
OS_MA2SlowShift | 느린 이동평균 시프트. |
OS_MA2SlowMethod | 느린 이동평균법. |
OS_MA2SlowPrice | 느린 이동평균가. |
청산 시그널 | |
CS_ON | 청산 시그널 활성화. |
CS_Shift | 인디케이터 확인 바: 0 - 새 인디케이터, 1 - 완료. |
CS_TimeFrame | 인디케이터 타임프레임. |
CS_CCIPeriod | CCI 기간. |
CS_CCIPrice | CCI 가격. |
CS_CCILevel | 상위 CCI 레벨(매수 포지션 청산). 매수 포지션 청산 시그널은 레벨의 하향 교차점에서 발생합니다. 매도 포지션과는 완전히 반대죠. |
엑스퍼트 어드바이저 작동법
엑스퍼트 어드바이저는 우선 파일에서 Metaprogram을 열어 검토하고 분석합니다. 중대한 오차 발생 시, 경고창이 나타납니다. Metaprogram 분석을 진행하면서 엑스퍼트 어드바이저가 데이터 구조에 텍스트 명령어에 상응하는 수치 값을 채웁니다. 이는 엑스퍼트 어드바이저의 최대 성능을 끌어내는 데 도움이 됩니다. 분석이 성공적으로 완료되면 다음 메세지가 로그에 나타납니다: '인터프리터 초기화 완료'.
Deinterpritate 변수가 포함된 경우, 엑스퍼트 어드바이저는 반전 해석 테스트를 진행합니다(차트와의 연결이 끊기며 전략 테스터의 모든 테스트가 강제 종료됩니다). 반전 해석 시, 엑스퍼트 어드바이저는 수치 값을 텍스트 명령어로 전환합니다. 명령어 입력 값이 다르기는 하지만, 반전 해석된 Metaprogram은 엑스퍼트 어드바이저의 명령 분석 과정을 이해하는 데에 도움이 됩니다.
다음 문자열을 한번 볼게요:
Buy(6) | Modify(6,,,ThisOpenPrice-Var4p,)
반전 해석이 끝나고 나면 문자열이 다음과 같이 바뀝니다:
Buy(6)==1*1+0*0; | Modify(6,,,ThisOpenPrice()*1-0.0025*1,)
간단한 Buy(6) 명령어가 오른쪽에 결과가 1이 되는 X1*X2+X3*X4 연산이 위치하는 등식으로 전환된 걸 볼 수 있네요. 액션 필드의 경우, 사용자 변수는 수치 값으로 대체됩니다.
엑스퍼트 어드바이저 커스터마이징 팁
아마 엑스퍼트 어드바이저 커스터마이징을 원하는 분들도 계실 겁니다. 분석 단계와 명령 실행 단계에 자신만의 명령어를 더하거나 다른 포지션 관리 기능을 추가할 수 있겠죠. 엑스퍼트 어드바이저의 구조 덕분에 커스터마이징은 매우 쉽습니다. 그렇지 않으면 엑스퍼트 어드바이저는 실용성이 없겠죠.
데이터 명령어 추가
InfoCommand 배열에서 데이터 명령어를 찾을 수 있습니다. 각 열에 5가지 명령어가 배열되어 있어 개수를 세거나 새로운 인덱스 값을 찾기가 용이합니다.
InfoCommand 배열에 명령어가 추가되면 새로운 인덱스에 해당하는 케이스문을 추가하여 SetValue() 함수의 구조를 바꿉니다. 해당 값을 구하려면 우선 값이 구해질 개체를 선택해야 합니다. 그렇지 않으면 해당 값을 구할 수 없습니다. 데이터가 얻어지는 개체의 형태에 따라 개체 선택에 사용되는 함수가 달라집니다. 해당 함수들은 표 13에서 확인할 수 있습니다.
표 13. 객체 선택을 위한 엑스퍼트 어드바이저 함수
함수 | 목적 및 매개 변수 |
---|---|
Pos.Select(_Symbol) | 포지션 선택. PositionSelect() 함수와 비슷한 표준 방식. |
SelectOrder(long aType,string aID,bool & aSelected) | 엑스퍼트 어드바이저 심볼, 형태(aType) 및 식별자(aID)에 따른 주문 선택 함수. 객체가 선택된 경우 aSelected 참조 형식 매개 변수가 트루를 반환합니다. |
bool SelectLastDeal(int aType,bool & aSelected) | 엑스퍼트 어드바이저 심볼 및 형태(aType)에 따른 직전 거래 선택 함수. 객체가 선택된 경우 aSelected 참조 형식 매개 변수가 트루를 반환합니다. |
SelectLastEADeal(int aType,string aID,bool & aSelected) | 엑스퍼트 어드바이저 심볼 및 형태(aType)에 따른 직전 실행 거래 선택 함수. 객체가 선택된 경우 aSelected 참조 형식 매개 변수가 트루를 반환합니다. |
직전 거래와 직전 실행 거래의 차이는 직전 거래에서는 손절매매와 이익실현 주문이 이루어진다는 점입니다. 직전 거래 데이터는 직전 포지션 청산 결과를 얻기 위해 필요할 수 있습니다. 직전 실행 거래 결과는 거래의 마지막 방향이나 엑스퍼트 어드바이저 운용 단계를 알기 위해 사용되죠.
거래 개체 데이터 외에도, 가격 등의 시장 데이터에 대한 액세스도 가능합니다. 다만 데이터를 실제로 획득할 수 있도록 하는 게 중요하죠. 객체 선택 시도 후에는 aSelected 값을 이용해 객체가 선택되었음을 반드시 확인해야 하며, 필요한 매개 변수 값을 획득하여 Val.Value 변수에 적용해 트루가 반환되는지 검사합니다.
표 14는 다양한 객체로부터 매개 변수를 구하는 데에 사용되는 함수를 나타냅니다.
표 14. 선택된 객체로부터 매개 변수 획득을 위한 엑스퍼트 어드바이저 함수
함수 | 목적 및 매개 변수 |
---|---|
double SelPosParam(int aIndex) | aIndex 인덱스를 활용하여 포지션 매개 변수 구하기. |
double SelOrdParam(int aIndex) | aIndex 인덱스를 활용하여 주문 매개 변수 구하기. |
double SelDealParam(int aIndex) | aIndex 인덱스를 활용하여 거래 매개 변수 구하기. |
가져올 데이터의 식별자 인덱스는 함수로 전달됩니다. 인덱스 값은 Val.InfoIdentifierIndex 변수에 포함됩니다.
새로운 액세스 명령어 추가 시, 가지고 나갈 데이터의 식별자만 필요한 경우가 있으며 가져올 데이터의 식별자도 필요한 경우도 있습니다.
데이터 식별자 추가
InfoIdentifier 배열에서 식별자를 찾을 수 있습니다. 새로운 식별자를 추가하고 나면, 인덱스를 찾아 SelPosParam(), SelOrdParam() 및 SelDealParam() 함수를 업데이트해야 합니다. 모든 개체에 대한 새로운 식별자의 적용 여부에 따라 업데이트는 일부 또는 전체의 함수를 대상으로 할 수 있습니다. 함수가 업데이트되면 새로운 인덱스에 해당하는 케이스문을 추가하여 구조를 바꿉니다.
액션 명령어 추가
ActCommand 배열에 액션 명령어를 추가합니다. 명령어는 문자열로 배열되어 있어 필요한 인덱스를 찾는 것이 조금 어렵습니다. 명령어를 추가한 후에 매개 변수 개수와 유형을 지정해야 하므로 문자열이 나타납니다. 매개 변수 개수는 ActCmndPrmCnt 배열에 지정되며 유형은 ActCmndType 배열에 나타납니다. 유형의 예: 0 - 시장 움직임, 1 - 대기 주문 액션, 2 - 포지션 관리.
명령어를 배열에 추가한 후 DoAction() 함수에 새로운 케이스문을 추가해 스위치를 요청합니다. 새로운 함수는 불리언 자료형이어야 하며 성공적으로 실행된 경우 트루를, 에러가 발생한 경우 폴스를 리턴해야 합니다. 추적 손절매 함수와 같이 성능 측정이 필요하지 않은 경우에는 트루를 리턴합니다.
대기 주문과 관련된 함수의 경우 실행 이전에 주문 존재 여부에 대한 확인이 우선되어야 한다는 것을 꼭 기억하세요.
트레이딩 시그널 함수 변화
엑스퍼트 어드바이저에서 트레이딩 시그널을 구하는 데에 쓰이는 함수는 두 가지(오픈, 청산 두 개씩) 뿐입니다.
CloseSignalsInit() 함수(청산 시그널 초기화) 및 OpenSignalsInit() 함수(오픈 시그널 초기화)는 엑스퍼트 어드바이저의 OnInit()에 요청됩니다. 인디케이터를 불러오는 함수들인데요. CloseSignalsMain() (청산 시그널 식별)과 OpenSignalsMain() (오픈 시그널 식별)은 각 틱의 OnTick() 함수에 요청됩니다.
함수 실행 초기에 GlobalCloseBuySignal, GlobalCloseSellSignal(청산 시그널) 및 GlobalOpenBuySignal, GlobalOpenSellSignal(오픈 시그널)은 폴스를 반환해야 하며 해당하는 인디케이터를 읽어들인 후에 트루를 반환해야 합니다.
또한, 엑스퍼트 어드바이저의 OnDeinit() 함수를 사용할 때에는 IndicatorRelease()를 실행해야 합니다.
첨부파일
eInterpretator.mq5 - 터미널 데이터 디렉토리 내 MQL5/Experts에 배치되어야 하는 엑스퍼트 어드바이저.
LimitAdd.txt - 리미트오더를 이용한 스케일링을 위한 Metaprogram.
StopRev.txt - SAR을 위한 Metaprogram.
Piramiding.txt - 피라미딩을 위한 Metaprogram.
ReOpen.txt.txt - 리오프닝을 위한 Metaprogram.
TradeSignals.txt - 트레이딩 시그널을 위한 Metaprogram.
TradeSignalsTR.txt - 추적 손절매가 있는 트레이딩 시그널을 위한 Metaprogram.
TradeSignalsBE.txt - 이익실현 기능을 동반한 트레이딩 시그널을 위한 Metaprogram.
limitadd.set -리미트오더를 이용한 스케일링을 위한 매개 변수 파일.
stoprev.set - SAR을 위한 매개 변수 파일.
piramiding.set - 피라미딩을 위한 매개 변수 파일.
reopen.set - 리오프닝을 위한 매개 변수 파일.
tradesignals.set - 트레이딩 시그널을 위한 매개 변수 파일.
tradesignalstr.set - 추적 손절매가 있는 트레이딩 시그널을 위한 매개 변수 파일.
tradesignalsbe.set - 이익실현 기능을 동반한 트레이딩 시그널을 위한 매개 변수 파일.
유의사항 트레이딩 시그널, 추적 손절매 및 이익실현이 포함된 프로그램을 사용하는 경우 엑스퍼트 어드바이저 속성창에서 해당 함수를 활성화 시키는 것을 잊지 마세요. 전략 테스터 사용 시 Metaprogram 파일을 TesterMetaProgram.txt file로 복사하세요(원격 테스트 에이전트 사용을 위해 필요). 해당 파일은 터미널 데이터 디렉토리 내 MQL5/Files에 저장되어야 합니다(터미널: 파일 -> 데이터 폴더 열기).
Metalanguage를 이용한 매매 전략 예시 섹션 내 차트에서 실행된 프로그램은 매개 변수 파일에 포함된 매개 변수를 기반으로 한 것입니다. 지난 몇 개월간 M1의 OHLC 모델 EURUSD H1에 대해 테스팅이 이루어졌습니다(2012년 8월 29일 기준).
결론
매매 전략 개발을 처음 시작하면 헷갈리는 부분이 많을 거예요. 어디에서 시작하고, 뭐가 중요하고, 실제 환경에서 엑스퍼트 어드바이저의 안정성은 어떻게 유지하며, 거래 전략 알고리즘의 실행과 신뢰도 등 신경 쓰이는 부분이 많죠.
이번 글은 전략 정형화를 통해 EA 개발을 도와주는 개발자와 투자자 모두가 전략 개발 과정 및 관련 고려 사항을 이해하도록 돕는 것이 목표로 했습니다. 엑스퍼트 어드바이저의 eInterpretator 인터프리터와 함께라면 최소한의 시간과 노력으로 다양한 매매 전략을 테스트해 볼 수 있는 기회가 열린답니다.
마지막으로, 제가 MetaTrader5에 얼마나 감탄했는지 꼭 알리고 싶어요. 엑스퍼트 어드바이저 인터프리터의 작동 속도는 정말 기대 이상이더라고요!
MetaQuotes 소프트웨어 사를 통해 러시아어가 번역됨.
원본 기고글: https://www.mql5.com/ru/articles/495