Как ограничить количество одновременно открытых позиций/отложенных ордеров
По плану в этом выпуске у меня было изложение теории сортировки глобального массива методом пузырька (медленным методом, но простым в реализации), после вчерашнего письма от клиента мне показалось, что читателям моего блога будет интересно узнать, как можно ограничить количество одновременно открытых позиций и выставленных отложенных ордеров.
Дело в том, что если просто проверять количество позиций с помощью функции OrdersTotal() и сразу же открытие новой позиции, то в случае, когда эксперт прикреплен на графики разных периодов, но по одному и тому же инструменту, мы получим "лишние" открытые позиции. Чтобы избежать этого, надо использовать критические секции.
Функции Lock() и Unlock() я описывал в выпуске "Критическая секция": разграничение доступа к ресурсу".
//+------------------------------------------------------------------+ //| Lock() | //| | //| Возвращает: | //| 0 - если "критическая секция" успешно | //| заблокирована | //| 1 - в случае ошибки | //| 2 - эксперт остановлен | //| 3 - по таймауту (слишком долго ждали) | //+------------------------------------------------------------------+ int Lock(string GlobVarName, int timeout = 0) { string critical_section = GlobVarName+"Lock";
// проверим, существует ли переменная critical_section if (!GlobalVariableCheck(critical_section)) { if (GetLastError()!=0) return(1);
// переменная не существует, создадим ее if (GlobalVariableSet(critical_section, -1.0)==0) return(1); // переменная создана }
int StartTime = GetTickCount();
// ждем "зеленового света" while (true) { // проверить, не загорелся ли "зеленый свет" if (GlobalVariableGet(critical_section)==-1.0) { // "зеленый свет" загорелся, зажигаем "красный свет" if (GlobalVariableSetOnCondition(critical_section, 1.0, -1.0)) return(0);
// нас опередили, поэтому ждем "зеленового света" }
// проверим, не остановлен ли эксперт if (IsStopped()) return(2);
// таймаут не истек? if (timeout!=0) { if ((GetTickCount()-StartTime)>timeout*1000) return(3); }
// спим 0.1 секунды Sleep(100); } }
//+------------------------------------------------------------------+ //| Unlock() | //| | //| Возвращает: | //| 0 - если "критическая секция" успешно | //| разблокирована | //| 1 - в случае ошибки | //| 2 - эксперт остановлен | //| 3 - по таймауту (слишком долго ждали) | //+------------------------------------------------------------------+ int Unlock(string GlobVarName, int timeout = 0) { string critical_section = GlobVarName+"Lock";
// проверим, существует ли переменная critical_section if (!GlobalVariableCheck(critical_section)) { if (GetLastError()!=0) return(1);
// переменная не существует, создадим ее if (GlobalVariableSet(critical_section, -1.0)==0) return(1);
// переменная создана, поэтому выходим return(-1.0); }
int StartTime = GetTickCount();
// бесконечный цикл while (true) { // пытаемся установить "зеленый свет" if (GlobalVariableSetOnCondition(critical_section, -1.0, 1.0)) return(0);
// проверим, не остановлен ли эксперт if (IsStopped()) return(2);
// таймаут не истек? if (timeout!=0) { if ((GetTickCount()-StartTime)>timeout*1000) return(3); }
// спим 0.1 секунды Sleep(100); } }
Для решения нашей задачи создадим дополнительно функции StartTrading() и StopTrading().
В функции StartTrading() последовательность действий такова:
- Локируем критическую секцию, чтобы исключить одновременный доступ из нескольких экспертов к функции OrdersTotal() и для исключения одновременной торговли нескольких экспертов.
- Если количество открытых позиций/ордеров меньше лимита, то возвращаем true.
- Если количество открытых позиций/ордеров больше или равно лимиту, то пишем об этом в лог, разлокируем критичсекую секцию и возвращаем false.
Вот исходный код функции StartTrading():
bool StartTrading(int max_trades) { // залокируем критическую секцию if (Lock("MaxTrades")!=0) return(false);
int open_trades = OrdersTotal();
if (open_trades<max_trades) return(true); else { Print("Уже открыто ", open_trades, " позиций"); Unlock("MaxTrades"); return(false); } }
В функции StopTrading() мы просто разлокируем критическую секцию:
void StopTrading() { Unlock("MaxTrades"); return; }
В следующем выпуске я приведу пример использования этих функций.
Все статьи по теме "Пишем советников для MetaTrader 4".
- Механическая торговая система - миф или реальность?
- С чего начать при написании советника:
- Создаем нового советника - Настраиваем параметры. - Язык MetaQuotes Language 4: