Возможно, это станет для Вас сюрпризом, но существует большое количество ситуаций в которых код программы по факту заглядывая в будущее тем не менее не является по своей сути ошибочным "заглядыванием". Далее в этой статье приводятся некоторые примеры таких ситуаций, однако в реальности таких примеров может быть намного больше.
Заглядывание в будущее с помощью кода программы при построении торговой стратегии в Велс Лаб будет оправданным в следующих случаях:
Проверка - не наступит ли на следующем баре заранее известное событие
Обоснованным заглядывание в будущее может быть для проверки - не наступит ли там некоторое заранее известное событие. Таким событием может быть:
- день экспирации опционов;
- последний торговый день месяца;
- день сплита акций;
Заглядывая в будущее, т.е. исследуя следующий за текущим бар мы проверяем - не там ли наступит известное событие.
Точно таким же образом, как Вы смотрите в календарь и определяете - не наступит ли завтра новый месяц, приводящийся в следующем примере метод NextBarIsNewMonth() проверяет - не является ли дата следующего бара датой другого месяца.
Однако обратите внимание, что скрипт может проверить дату на следующем баре только в том случае, если следующий бар в настоящее время уже существует на текущем графике. Именно по этой причине (и для упрощения) когда цикл достигает последний бар на графике, данный метод считает, что следующий бар является баром нового месяца. В результате этого, когда позиция не является активной, стратегия всегда будет генерировать алерт для открытия новой позиции.
Поэтому для того, чтобы выставить ордер на открытие позиции Вы должны будете лично заглянуть в календарь и убедиться, что следующий день действительно является днем нового месяца.
Пример (как выполнить пример приведенного кода)...
//создаем новый метод, проверяющий не является ли следующий бар днем нового месяца public bool NextBarIsNewMonth(int bar) { if (bar < Bars.Count - 1) return Date[bar + 1].Day < Date[bar].Day; //если номер следующего дня больше, то это не новый месяц else /* Предполагается, что следующий бар является новым месяцем. Взгляните в календарь и просто проигнорируйте алерт на вход в позицию если это не так */ return true; } protected override void Execute() { for(int bar = 1; bar < Bars.Count; bar++) { if (IsLastPositionActive) { // выход после 3-х баров Position p = LastPosition; if (bar + 1 - p.EntryBar >= 3) SellAtMarket(bar + 1, p, "Time-based"); } else if (NextBarIsNewMonth(bar)) // вход в первый торговый день нового месяца BuyAtMarket(bar + 1); } }
В результате выполнения данного кода получается вот такой график:
Здесь четко видно, что вход в позицию происходит в первый день месяца, а выход из позиции ровно через 3 бара.
Определение - исполнился ли приказ типа AtStop либо AtLimit по цене открытия следующего бара - для назначения такой позиции высшего приоритета
Если говорить в целом, то свойство Position.Priority сложно применять при проведении бектестинга стратегий, использующих закрытие позиций в конце дня и одновременно использующих стоп и лимитные ордера. Эти сложности возникают из-за того, что текущая последовательность сделок должна выстраиваться в зависимости от времени дня в которое текущая цена достигает цены торгового приказа. С другой стороны, достаточно легко определить - исполнился ли стоп или лимитный ордер в момент открытия торговой сессии. В этом случае, Вы можете установить приоритет больше чем единица для того, чтобы Велс Лаб выполнила этот ордер в первую очередь.
Пример (как выполнить пример приведенного кода)...
protected override void Execute() { for(int bar = 1; bar < Bars.Count; bar++) { if (IsLastPositionActive) { // правила для выхода из позиции } else { double limitPrice = Close[bar] * 0.98; // падение от цены закрытия текущего бара в 2% if ( BuyAtLimit(bar + 1, limitPrice, "") != null ) //если произошла сделка на следующем баре if ( bar < Bars.Count - 1 && Open[bar+1] <= limitPrice ) //если сделка произошла в момент открытия торговой сессии LastActivePosition.Priority = 1.0; } } }
Поиск подходящих условий для разделения позиции с целью частичного выхода из этой позиции
Когда Вы торгуете в реале, Вы не должны думать в терминах "разделения позиции" на части, ведь для закрытия половины позиции, состоящей из 1000 лотов Вы просто берете и вводите торговый приказ на закрытие пятисот лотов от текущей позиции. Если же Вы хотите смоделировать частичный выход из позиции при проведении бектестинга в программе Wealth-Lab, то для этого нужно будет сначала разделить первоначальную позицию на две самостоятельных позиции и только после этого выйти из одной из этих позиций - когда это будет необходимо.
Но что же делать, если ВЫ хотите разделить позицию для того, чтобы зафиксировать прибыль только по части этой позиции, но выйти из всей позиции только при срабатывании стоп-лосса?
Если Вы всегда будете разделять всю позицию на две части и продавать каждую из этих частей отдельно по исполнению стоп-лосса, Вы понесете дополнительные издержки в виде дополнительной комиссии. Вместо этого Вы можете дождаться, пока не наступят условия на выход из позиции (точно также, как и в реальном трейдинге) и определить именно в этот момент - когда необходимо разделение. В приведенном ниже примере происходит "заглядывание вперед" - там отслеживается максимальная цена следующего бара, чтобы определить - можно ли на следующем баре закрыть по тейк-профиту в размере 5% от цены входа половину начальной позиции. Если это так, то на текущем баре позиция разбивается на 2 части.
Пример (как выполнить пример приведенного кода)...
protected override void Execute() { bool hasSplit = false; for(int bar = 1; bar < Bars.Count; bar++) { if (IsLastPositionActive) { Position p = LastPosition; // сначала попробуйте выйти по Стоп-Лоссу if (!SellAtStop(bar + 1, p, p.EntryPrice * 0.975, "Stop Loss")) if (!hasSplit) //если ожидается СПЛИТ { // выход половиной позиции по тейк-профиту размером 5% double target = p.EntryPrice * 1.05; if( bar < Bars.Count - 1 && target <= High[bar+1] ) { Position s = SplitPosition( p, 49.99 ); // s является теперь последней позицией (LastPosition), так что нужно продать позицию p для того, чтобы иметь возможность использовать логику LastPosition hasSplit = SellAtLimit(bar + 1, p, target, "5% Profit"); } } else // Sell the rest at 20% profit target SellAtLimit(bar + 1, p, p.EntryPrice * 1.2, "20% Profit"); } else { BuyAtLimit(bar + 1, Close[bar] * 0.97); hasSplit = false; } } }
Выполнив этот код Вы увидите следующую картину:
Здесь зеленой линией обозначена та часть позиции, которую удалось закрыть по тейкпрофиту (для этого на предыдущем от срабатывания тейк-профита баре изначальную позицию пришлось разбить на 2). Красной же позицией показана та часть изначальной позиции, которую пришлось закрыть по Стоп-Лоссу.
Чтобы Вы еще нагляднее смогли понять о чем здесь идет речь - посмотрите список трейдов. Красной рамкой выделена ситуация, отображенная на графике.
Все предыдущие позиции (до красной рамки) закрывались по Стоп-Лоссу, поэтому не приходилось прибегать к разделению позиции. Но так как в коде мы прописали, что если позиция может закрыться на следующем баре по тейк-профиту, то на текущем баре производится разделение (сплит) этой позиции. Что и произошло.
Как видите, заглядывание вперед позволило нам не принимать решение о вхождение или выходе из позиции, а помогает принять решение о расщеплении текущей позиции на две части, чтобы моделирование выглядело точно также, как и торговля в условиях реальной жизни.
Сегодня мы увидели, что при программировании торговых стратегий в программе Wealth-Lab не любое заглядывание в будущее является предосудительным. Иногда можно получать данные от баров, находящихся справа от текущего, но это можно делать только в тех случаях, когда эта информация была бы доступна и в условиях настоящих торгов.
[...] [...]