Часто во время торговли трейдер (особенно начинающий) не может надлежащим образом контролировать свои действия, что приводит к плачевным результатам. Чтобы избежать подобных ситуаций, спекулянты используют различные правила управления капиталом. Однако даже чёткий план по рискам, числу одновременно открытых сделок, величине допустимого убытка и т.п. не даёт никаких гарантий, ведь заветные кнопки «Sell» и «Buy» доступны по-прежнему. В такой ситуации на помощь могут прийти программные скрипты, которые позволят не открывать лишних сделок, не допускать критических потерь, не действовать необдуманно. Как правило, в данном контексте речь идёт о полноценных торговых роботах, которые сами и торгуют, и следят за своей работой. Кстати, это является несомненным их достоинством. Но что если торговать должен по-прежнему человек, а на программу желательно возложить только функции контроля действий?
В данной статье мы подойдём к решению данной проблемы радикально. Предлагаемая программа при некоторой просадке будет «прятать» кнопки открытия сделок. В качестве просадки мы возьмём разницу «эквити» и «баланса» в процентном соотношении. Условие для выключения кнопок открытия сделок будет звучать так: «если «эквити» будет меньше «баланса» на N%, то скрываем кнопки», где N — входной параметр программы.
В своей работе программа будет сталкиваться с двумя ситуациями: трейдер вызвал окно открытия новой сделки (F9, Новый ордер) и трейдер вызвал окно закрытия/модификации ранее существующего ордера (где также можно открыть новую сделку). В обоих случаях программа должна скрывать кнопки открытия новых сделок при выполнении условия для ограничения торговли.
1. Реализация mql-скрипта
Для решения подобной задачи стандартных функций MQL4 будет не достаточно, ведь речь идёт о том, что программа будет вмешиваться в окна торгового терминала. Но существует прекрасный инструмент для подобных задач — WinAPI, с которым MQL4 может работать, если подключить необходимые библиотеки и функции.
Программа реализована в виде пользовательского индикатора, при этом ничего не индицируя. Подобный приём часто используется по той причине, что индикатор не будет выключаться по нажатию кнопки «Советники», тем самым, давая трейдеру гибкую возможность использовать другие роботы, выполненные в формате советников.
Код самой программы представлен ниже:
#include <WinUser32.mqh>
#import «user32.dll»
int GetLastActivePopup(int hWndOwner);
int GetDlgItem(int hDlg, int nIDDlgItem);
int GetAncestor(int hwnd,int gaFlags);
#import
extern double Stop_Eq_Perc=10.0; //процент просадки, при котором робот будет скрывать кнопки открытия ордеров
#property copyright «Copyright © 2010, ENSED Team»
#property link «http://www.ensed.org»
#property indicator_chart_window
//+——————————————————————————————————————-+
//| функция, выполняющаяся при инициализации программы |
void init() {
return;
} //end void init()
//| функция, выполняющаяся при инициализации программы |
//+——————————————————————————————————————-+
//+——————————————————————————————————————-+
//| функция, выполняющаяся при деинициализации программы |
void deinit() {
return;
} //end void deinit()
//| функция, выполняющаяся при деинициализации программы |
//+——————————————————————————————————————-+
//+——————————————————————————————————————-+
//| функция, которая делает невидимыми кнопки открытия рыночных ордеров |
void stop_1(int hwnd, int cwnd) {
int fw = 0,
i = 0;
//поиск нужного окна путём обычного перебора
while(fw==0) { //перебираем все элементы окна cwnd в поисках необходимого (для однозначного определения нужного окна)
cwnd=GetWindow(cwnd, GW_HWNDNEXT);
fw=GetDlgItem(cwnd,0x508); //а вот так должен «выглядеть» искомый элемент (кнопка «Sell» в окне нового ордера)
//0x508 — ID кнопки, для определения использования специальных программ (например, WinSpy++)
i++;
if(i>50) break; //если после 50-ти итераций так и не нашли нужного подокна — выходим из цикла
} //end while(fw==0)
if(fw!=0) { //если нашли нужное окно, делаем невидымими кнопки «Sell» и «Buy»
ShowWindow(GetDlgItem(cwnd,0x508),0); //для «Sell»
ShowWindow(GetDlgItem(cwnd,0x40C),0); //для «Buy»
} //end if(fw!=0)
return;
} //end void stop_1(int hwnd, int cwnd)
//| функция, которая делает невидимыми кнопки открытия рыночных ордеров |
//+——————————————————————————————————————-+
//+——————————————————————————————————————-+
//| функция, которая делает невидимой кнопку открытия отложенных ордеров |
void stop_2(int hwnd, int cwnd) {
int fw = 0,
i = 0;
//поиск нужного окна путём обычного перебора
while(fw==0) { //перебираем все элементы окна cwnd в поисках необходимого (для однозначного определения нужного окна)
cwnd=GetWindow(cwnd, GW_HWNDNEXT);
fw=GetDlgItem(cwnd,0x4D5); //а вот так должен «выглядеть» искомый элемент (кнопка «Установить ордер» в окне нового ордера)
i++;
if(i>50) break; //если после 50-ти итераций так и не нашли нужного подокна — выходим из цикла
} //end while(fw==0)
if(fw!=0) //если нашли нужное окно, делаем невидимой кнопку «Установить ордер»
ShowWindow(fw,0);
return;
} //end void stop_2(int hwnd, int cwnd)
//| функция, которая делает невидимой кнопку открытия отложенных ордеров |
//+——————————————————————————————————————-+
//+——————————————————————————————————————-+
//| функция проверки условия для препятствия открытию новых сделок |
bool check() {
/* в случае выполнения условия для препятствия открытию новых ордеров, функция возвращает true */
int n = 0;
double check_value=0.0;
if((AccountEquity()-AccountBalance())/(AccountBalance()/100)<=Stop_Eq_Perc*(-1))
return(true);
return(false);
} //end bool check()
//| функция проверки условия для препятствия открытию новых сделок |
//+——————————————————————————————————————-+
//+——————————————————————————————————————-+
//| главная функция (как Main в C/C++) |
void start() {
if(!check()) //если условие для препятствия открытию новых сделок не выполнено — выходим из функции
return;
int hwnd = 0,
cwnd = 0,
mode = 0,
i = 0;
string name = «»,
null;
hwnd = FindWindowA(null, «Ордер»); //ищем окно открытия ордера
//если окно не нашли, предполагаем, что трейдер может открыть окно изменения ранее открытого ордера
if(hwnd==0) {
hwnd=GetLastActivePopup(GetAncestor(WindowHandle(Symbol(),Period()),2));
GetWindowTextA(hwnd,name,6);
name=StringTrimRight(StringTrimLeft(name)); //на всякий случай избавляемся от пробелов в начале и в конце строки
/* Если заголовок последнего открытого окна начинается не на «Ордер», то выходим из функции.
Прямое сравнение строк здесь не работает, потому используем проверку кодов символов первых пяти букв. */
if(StringGetChar(name,0)!=’О’) return(0);
if(StringGetChar(name,1)!=’р’) return(0);
if(StringGetChar(name,2)!=’д’) return(0);
if(StringGetChar(name,3)!=’е’) return(0);
if(StringGetChar(name,4)!=’р’) return(0);
} //end if(hwnd==0)
if(hwnd==0)
return;
cwnd=GetWindow(hwnd,GW_CHILD);
stop_1(hwnd, cwnd); //не даём открыть рыночные ордера при активном окне открытия нового ордера
stop_2(hwnd, cwnd); //не даём открыть отложенные ордера при активном окне открытия нового ордера
return;
} //end void start()
//| главная функция (как Main в C/C++) |
//+——————————————————————————————————————-+
Программа снабжена комментариями, благодаря которым желающие могут разобраться в её работе. Основная смысловая нагрузка в данном скрипте ложится на возможности WinAPI. В общем случае работа с WinAPI в MQL ничем не отличается от работы в любых других языках программирования. Благодаря этому при изучении данных функций можно использовать практически любые справочные материалы, будь они написаны для Delphi, или, к примеру, для C++.
Ограничения и недостатки торгового скрипта
Скрипт никак не ограничивает торговых роботов, т.е. может мешать открытию сделок только в ручном режиме. Однако полноценные торговые роботы, как правило, снабжаются своими собственными функциями слежения за рисками, числом открытых сделок и т.п.
Следует обратить внимание на то, что программа будет работать, только если разрешён импорт функций из dll в настройках терминала: Сервис/Настройки/Советники/Разрешить импорт dll.
Заключение
Подобные программы могут оказаться полезны на стадии обучения торговле на финансовых рынках. Безусловно, опытным трейдерам подобные инструменты не нужны.
В данном торговом скрипте реализован только один критерий, исходя из которого действия трейдера ограничиваются. Аналогичным образом можно «научить» программу реагировать на слишком большое число открытых сделок, не давать открывать новые сделки, пока есть хоть одна без установленного уровня StopLoss, или «научить» любому другому критерию, на основе которого предполагается ограничение действий трейдера.