|
|
|
|
|
|
|
|
Первое правило бизнеса: защищайте свои инвестиции
Этикет банкира. 1775 год
До сих пор в советнике мы использовали только ордера с жестко установленным уровнем StopLoss и TakeProfit. Таким образом, открыв покупку, мы ждем срабатывания одного из двух уровней – либо мы получим прибыль, либо получим убыток. Третьего не дано. Но многие трейдеры считают более важным в торговой системе не вход в сделку, а систему выхода. Для более оптимального управления открытой позицией трейдеры используют скользящий стоп ( Trailing Stop). Это позволяет передвигать уровень защитного стопа вслед за ценой, и в случае внезапного разворота забрать часть бумажной ( незафиксированной ) прибыли, вместо того, чтобы получить убыток по первоначальному стопу.
Прежде чем заняться написанием функции скользящего стопа, мы исправим все недостатки нашего советника торгующего по случайным сигналам. Для этого нам придется написать его фактически заново (Назовем его RTS.mq4 – Random Trade + Statistika).
|
|
|
|
Я использовал при создании функции-пустышки, то есть функции объявлены, но в них ничего не вычисляется, они возвращают пустые значения. Это бывает удобно при написании сложных систем, если у вас уже есть готовый алгоритм. Советник в таком виде компилируется без ошибок (функция isNewBar() просто не видна). Теперь мы можем каждую пустую функцию наполнять кодом и компилировать наш советник для проверки сделанных изменений на отсутствие грубых ошибок.
Схематически я изобразил это так:
|
|
|
|
Блок №1 реализован через проверку нового бара, если isNewBar() возвращает true (появился новый бар) , то сначала проверяется наличие сигнала на открытие позиции в покупку (SignalExist(OP_BUY)), и если такой сигнал есть, то делается попытка открыть ордер в покупку (GetOrder(OP_BUY)) . Аналогично делается проверка на открытие позиции в продажу. Теперь сигналы в покупку и продажу у нас разделены и не влияют друг на друга, мы избавились от недостатка предыдущей версии.
Обратите внимание ,что в качестве параметров я использовал зарезервированные слова из MQL-4 (OP_BUY и OP_SELL). Это облегчает понимание кода и вам самим, и тем, кто будет читать ваш код. Если бы я использовал вместо этого конкретные значения, то вам пришлось бы открывать справку, чтобы вспомнить, что означает параметр 0 при вызове функции GetOrder(0) .
|
|
|
|
Кроме того, в дальнейшем учет тонкостей открытия позиций OP_BUY и OP_SELL позволит нам отдельно оптимизировать советник в режимах LongOnly и ShortOnly.
Блок №2 состоит из простого вызова функции EveryTick(), которая также пока является пустой. В предыдущем советнике в функции deinit() мы использовали вызов функции HistoryCalculate(), я немного изменил вызов, чтобы расчет статистики производился только в тестере.
|
|
|
|
При работе в онлайне эта функция теперь не вызывается, но есть еще и оптимизация. При оптимизации она нам также не требуется. Добавим проверку IsOptimization().
|
|
|
|
Первой напишем функцию получения сигнала, для вычисления времени закрытия последнего времени добавили новую функцию – GetLastCloseTime().
|
|
|
|
Вы можете сами убедиться, что теперь вычисление периода времени с последнего момента закрытия ордера происходит более корректно, промежуток времени между вечером пятницы и утром понедельника не включает выходные.
Теперь пишем функцию GetOrder() на основе предыдущей версии. Я только изменил заполнение комментария, чтобы теперь мы могли анализировать движение цены за последние 3 бара. То есть, открываем позиции мы по-прежнему против тренда, но хотим найти связь между результатом сделки и направлением и размахом движения прямо перед открытием сделки. В дальнейшем вы можете в комментарий записывать любую интересующую вас информацию для последующего анализа.
|
|
|
|
Советник вроде полностью готов, но не хватает еще чуть-чуть. В предыдущей версии мы проверяли наличие открытых ордеров
|
|
|
|
и признали эту практику порочной. Но если не ставить проверку наличия открытых позиций, то теряем возможность контроля количества этих ордеров. Поэтому добавим новую внешнюю переменную MaxOpenOrder и функцию AllowedOpenOrder() (допустимость открытия новых ордеров определенного типа).
|
|
|
|
Теперь мы можем снова проверить нашу гипотезу о том, что при параметрах StopLoss=65 пунктов и TakeProfit=130 пунктов нужно совершать сделки против показаний индикатора MACD. Сохраним эту версию под именем RTS2.mq4. Запустим вновь тестирование на EURUSD H1 и получим один из результатов.
|
|
|
|
Прибыли нет, соотношение между прибыльными и убыточными сделками отражает соотношение между SL и TP. Но количество сделок в покупку и продажу теперь не зависит от модели LongOnly и ShortOnly. Теперь мы можем заняться написанием функции TrailingStop().
Основная функция скользящего стопа – защита бумажной прибыли с помощью передвижения уровня StopLoss в направлении открытой позиции. Если мы передвигаем стоп слишком быстро, то случайное движение против нашей позиции может выбить нас из сделки, после чего цена может опять пойти в нашем направлении. А если стоп передвигать слишком медленно – то неблагоприятный разворот может съесть большую часть нашей прибыли. Как видите, от алгоритма зависит все. Поэтому, сначала выдвигаем некую идею, а потом пытаемся ее запрограммировать.
Существует множество алгоритмов трейлинга, я рассмотрю только два. Я их для себя назвал динамический и статический. Динамический трейлинг – это перемещение защитного стопа при каждом изменении цены, если цена прыгнула в нашем направлении на 100 пунктов (допустим вверх для покупки) , то и защитный стоп тут же будет подтянут (вверх) на те же 100 пунктов. Статический трейлинг – это перемещение стопа по некоторым условиям, независящим от текущей цены. Например, перемещение стопов на каждом новом баре по какому-то алгоритму. Это позволяет игнорировать дерганье цены внутри бара.
Сначала реализуем трейлинг стоп динамический.
|
|
|
|
В этой функции все просто и дополнительного описания не требуется. Если TS=50, то текущий стоп будет на уровне 1.2643.
|
|
|
|
Добавим вызов трейлинга в вызов для каждого нового бара. В этом случае модификация ордеров будет происходить всегда одинаково (при появлении нового бара), независимо от модели тестирования.
|
|
|
|
Эту версию советника я сохранил под именем RTS+TS.mq4 (TS – Trailing Stop). Скомпилируем и прогоним на EURUSD H1.
|
|
|
|
Теперь мы можем рассмотреть вариант статического трейлинга.Введем понятие риска. Риск – это потенциальный убыток, который равен ходу цены от уровня открытия к уровню стопа. Это конечно некорректно, но не в этом суть. Идея будет такая: уровень риска должен уменьшаться пропорционально квадрату от времени. Если с момента открытия позиции прошло X времени и риск равен Y, то через X*2 времени риск должен уменьшиться в 4 раза. Грубо говоря, мы попытаемся реализовать скользящий стоп по аналогии с индикатором Parabolic.
|
|
|
|
Многие пытаются реализовать в советниках трейлинг на основе показаний индикатора Parabolic SAR. Но у этого способа есть один недостаток – индикатору все равно где вы вошли в позицию, фактически мы подстраиваемся под индикатор. Поэтому мы напишем алгоритм, который будет действительно менять уровень защитного стопа по принципу параболы и будет привязан к нашей точке входа.
Пусть в момент открытия ордера мы выставляем StopLoss на расстоянии S пунктов. При этом мы считаем, что если мы открыли сделку в правильном направлении, то через N баров мы уже будем в безубытке (уровень StopLoss можно будет передвинуть на уровень открытия ордера). Из школьной физики мы помним, что при движении по параболе расстояние S=(a*t^2)/2+V*t+C. Параметр а – ускорение, параметр V- начальная скорость, она у нас равна нулю, и параметр С – начальное смещение, оно равно значению стопа со знаком минус. Тогда S=(a*t^2)/2 или a=2*S/t^2 .
|
|
|
|
Если у нас первоначальный стоп равен 50 пунктов, а позиция должна выходить в безубыток через 5 баров, то a=(2*50)/5^2=100/25=4пункта/бар^2. Через 1 бар у нас стоп будет 4*1/2-50=-48, то есть на расстоянии 48 пунктов от цены открытия. Через 2 бара 4*2^2/2-50=-42 . Через 3 бара стоп 32 пункта, через 4 бара – 18 пунктов, через 5 баров: 4*5^2/2-50=0 – можем поставить ордер в безубыток , если к этому времени нас не закроет по стопу. Алгоритм есть, осталось написать код.
|
|
|
|
Функцию start() слегка меняем:
|
|
|
|
Компилируем советник RTS+TS2.mq4 и тестируем при тех же условиях и параметрах. Увы, этот вид трейлинг стопа не принес нам улучшения результатов. Возможно, это не та стратегия, где подходит параболический трейлинг. Мы можем еще немного изменить функцию EveryTick().
|
|
|
|
Тогда тестирование на других моделях («Все тики», например) изменит поведение нашего советника кардинально. Вы можете сами поэкспериментировать.Все варианты экспертов находятся здесь .
Перейти к статье «Видит око, да код неймет».
|
|