Финансовая лаборатория

Биржевая торговля и торговые роботы


Недавно я рассказывал о генераторе механических торговых систем. При этом приводился пример создания техники сопровождения позиции из чужой механической торговой системы. В сегодняшней статье я более подробно расскажу о том, как создавать технику сопровождения позиции и о том, как выбрать те финансовые инструменты, которые подходят для данной торговой техники.

Выбор акций и тестирование торговых техник

При этом на конкретных примерах собираюсь показать методику тестирования успешности техник сопровождения.

Для того, чтобы мы с Вами говорили "на одном языке" давайте введем понятие "обвязка".

Что такое обвязка торговой системы и для чего она нужна

Давайте представим, что мы придумали или где-то "подсмотрели" новую технику генерации торгового сигнала (входа в позицию) либо новую технику сопровождения позиции (выхода из позиции).

Совершенно ясно, что имея в своем арсенале несколько уникальных техник и комбинируя их мы можем создать десятки уникальных торговых систем и каждая из таких торговых систем будет обладать своими особенностями, давать независимые друг от друга результаты.

Как можно "навскидку" оценить - будет ли полезна новая техника торговли, либо она гроша ломанного не стоит? На помощь приходит обвязка торговой системы.

Обвязка торговой системы - это простейшая техника, которая применяется для оценки эффективности новой торговой техники.

К примеру, если мы хотим тестировать технику входа, то обвязкой чаще всего будет выход с установленными сразу после входа в позицию стопа и тейк профита.

Если же цель - протестировать технику сопровождения, то нужна обвязка, генерирующая достаточно большое количество входов. Удачным вариантом здесь будет техника ударного дня  "HotDay_Enter", т.е. вход в позицию, когда цена закрытия текущей свечи либо превышает максимум предыдущей (покупка), либо опускается ниже минимума предыдущей (продажа).

Точно также, используя обвязку можно проверить - какая техника на конкретном временном промежутке и конкретной акции показывает себя лучше и какую технику лучше использовать в торговле.

Понимаю, что теоретически рассуждая, а особенно читая такие теоретические рассуждения трудно понять - о чем идет речь. Давайте на конкретном примере посмотрим - как использовать обвязку для того, чтобы определить стоит ли заносить в свою коллекцию новой техники. Попутно расскажу Вам о выборе финансовых инструментов, которые наилучшим образом подходят для данной техники торговли.

1. Техника сопровождения позиции

Идея в следующем. В одной из статей Игоря Чечета, которая была посвящена технике сопровождения позиции было упомянуто об интересной возможности выхода из позиции используя скользящую среднюю с уменьшающимся периодом. Т.е. идея такая - при входе в позицию мы рассчитываем по минимумам цен предыдущих нескольких периодов скользящую среднюю и ставим стоп на этом уровне. Затем с каждым новым баром период этой скользящей средней постепенно уменьшается и скользящая средняя медленно приближается к текущим ценам. При этом существует некий минимальный период, меньше которого период скользящей средней быть не может.

Техника внешне очень напоминает параболик, но на мой взгляд интереснее тем, что не приходится искуственно подбирать параметры ускорения и начального отступа. В то время, когда писалась эта статья Игорь коды для своих техник еще не выкладывал, поэтому пришлось самостоятельно закодировать эту технику. Единственное отличие, у Игоря использовалась экспоненциальная скользящая средняя, я же не стал мудрить и взял простую скользящую среднюю.

Для простоты восприятия пусть эта техника называется "TrailingSmaExit". Выглядит она следующим образом:


/*Это блок сопровождения позиции (выхода)

 Технология выхода: TrailingSmaExit:
 Для Wealth-Lab Developer 6
 Автор: Власов Дмитрий Викторович http://finlabportal.ru
 Дата создания: 11.06.2012

 Описание технологии выхода:
 - устанавливаем стоп по скользящей средней с начальным большим периодом (n);
 - На каждом последующем баре период скользящей средней уменьшается доходя до самого маленького периода (m);
 - Выходим только по срабатыванию стопа на текущем баре
*/

using System;
using System.Drawing;
using WealthLab;
using WealthLab.Indicators;

namespace GeneratorMTS.Exits
{
    class TrailingEmaExit : WealthScript
    {

        #region Объявление параметров торговой системы

        StrategyParameter _smaStartPeriod; // Начальный период усреднения EMA
        StrategyParameter _smaMinPeriod; //   Минимальный Период скользящей средней

        #endregion

        #region Инициализация параметров торговой системы

        public TrailingEmaExit()
        {
            _smaStartPeriod = CreateParameter("Start Period", 100, 1, 50, 1);
            _smaMinPeriod   = CreateParameter("Min Period", 4, 1, 20, 1);
        }

        #endregion

        protected override void Execute()
        {
            int firstValidValue = 1 + Math.Max(_smaMinPeriod.ValueInt, _smaStartPeriod.ValueInt); // Первое значение свечки, при котором существуют все индикаторы

            #region Индикаторы

            #endregion

            #region Переменные для обслуживания позиции

            bool signalBuy = false, signalShort = false; // Сигналы на вход в длинную и короткую позиции

            // для сопровождения позиции
            int period = 1; // переменная для периода
            int smaStartPeriod = _smaStartPeriod.ValueInt;
            int smaMinPeriod = _smaMinPeriod.ValueInt;

            double orderTrailingStop = 0; // Ордер T/S

            #endregion

            #region Представление цен с необходимой разрядностью для отображения ордеров

            string PricePattern = "0.";
            for (int i = 0; i < this.Bars.SymbolInfo.Decimals; i++)
                PricePattern += "0";

            #endregion

            PlotStops(); // Отображать уровни, на которых были попытки выхода по S/L
            HideVolume(); //скрываем область графика с объемами

            for (int bar = firstValidValue; bar < Bars.Count; bar++) // Пробегаемся по всем свечкам
            {
                #region Сигналы на вход в позицию и выход из нее
                /*

                signalBuy =  (определяем условие на вход в длинную позицию и выход из короткой)

                signalShort = (определяем условие на вход в короткую позицию и выход из длинной)

                */

                #endregion

                #region Сопровождение и выход из позиции по TralingSmaExit

                if (!IsLastPositionActive) // Если позиции нет
                {
                    period = smaStartPeriod;
                    if (period < smaMinPeriod) period = smaMinPeriod; //определяем начальный период усреднения:

                    if (signalBuy) // При получении сигнала на вход в длинную позицию
                    {
                        RiskStopLevel = SMA.Value(bar-1, Low, period); //находим первоначальный стоп на уровне скользящей средней минимальных цен, определенной на предыдущем баре
                        BuyAtMarket(bar + 1, "Buy");
                        orderTrailingStop = RiskStopLevel; //устанавливаем трейлинг стоп на уровне минимума текущего бара

                        AnnotateBar(orderTrailingStop.ToString(PricePattern), bar, true, Color.Blue, Color.Yellow);
                    }
                    else if (signalShort) // При получении сигнала на вход в короткую позицию
                    {
                        RiskStopLevel = SMA.Value(bar - 1, High, period); //находим первоначальный стоп на уровне скользящей средней максимальных цен, определенной на предыдущем баре
                        ShortAtMarket(bar + 1, "Buy");
                        orderTrailingStop = RiskStopLevel; //устанавливаем трейлинг стоп на уровне максимумов предыдущих баров

                        AnnotateBar(orderTrailingStop.ToString(PricePattern), bar, true, Color.Blue, Color.Yellow);
                    }
                }
                else // Если позиция есть
                {
                    period = smaStartPeriod - (bar - LastActivePosition.EntryBar);
                    if (period < smaMinPeriod) period = smaMinPeriod;

                    if (LastActivePosition.PositionType == PositionType.Long)  // Для длинной позиции
                    {

                        orderTrailingStop  =  Math.Max (orderTrailingStop, SMA.Value(bar-1,Low,period));

                        SellAtStop(bar, LastActivePosition, orderTrailingStop, "Sell Stop"); // Попробовать выйти по T/S

                    }
                    else  // Для короткой позиции
                    {
                        orderTrailingStop = Math.Min(orderTrailingStop, SMA.Value(bar - 1, High, period));

                        CoverAtStop(bar, LastActivePosition, orderTrailingStop, "Cover Stop"); // Попробовать выйти по T/S

                    }
                }

                #endregion
            }
        }
    }
}

Код получился лаконичный, удобный и понятный для восприятия. Даже самому понравилось, как он был реализован. Кто пока еще не очень хорошо разбирается в программировании на языке C#, используя библиотеку WealthScript программы Wealth-Lab - читайте целый раздел о том, как это сделать, который фактически является инструкцией по созданию торговых стратегий. Инструкция специально написана простым, понятным языком для непрограммистов, к которым я себя тоже отношу с большим количеством примеров.

Однако мне показалось, что будет более логичным несколько модифицировать эту технику сопровождения. Было бы более логичным, если мы входим с "коротким стопом", чтобы зарезать возможный убыток в самом начале после входа и лишь по мере того, как позиция пойдет в нужном направлении узкий стоп можно будет постепенно расширять, по ходу фиксируя определенную уже накопленную прибыль.

Исходя из этой логики мной была создана техника, которую я назвал "TrailingSmaContraExit" - т.е. она действует наоборот. У Игоря сначала устанавливается максимальный период усреднения, и потом этот период усреднения постепенно уменьшается, приближая таким образом стоп к текущей цене, но не ближе, чем позволяет минимальный период усреднения.

В новой технике сначала устанавливается минимальный период усреднения (этот параметр можно оптимизировать) и затем с каждым баром существования позиции период усреднения постепенно увеличивается пока на достигнет своего порогового значения, который определяется максимальным периодом усреднения (это тоже оптимизируемый параметр).

В общем, техника сопровождения "TrailingSmaContraExit" получилась достаточно любопытная. Вот ее код:

/*Это блок сопровождения позиции (выхода)

 Технология выхода: TrailingSmaContraExit:
 Для Wealth-Lab Developer 6
 Автор: Власов Дмитрий Викторович http://finlabportal.ru
 Дата создания: 11.06.2012

 Описание технологии выхода:
 - устанавливаем стоп по скользящей средней с первоначальным периодом (n);
 - На каждом последующем баре период скользящей средней увеличивается доходя до самого большого периода (m);
 - Выходим только по срабатыванию стопа на текущем баре
*/

using System;
using System.Drawing;
using WealthLab;
using WealthLab.Indicators;

namespace GeneratorMTS.Exits
{
    class TrailingSmaContraExit : WealthScript
    {

        #region Объявление параметров торговой системы

        //для сопровождения позиции
        StrategyParameter _smaStartPeriod; // Начальный период усреднения SMA
        StrategyParameter _smaMaxPeriod; //   Максимальный период скользящей средней

        #endregion

        #region Инициализация параметров торговой системы

        public TrailingSmaContraExit()
        {
            //для сопровождения позиции
            _smaStartPeriod = CreateParameter("Start Period", 3, 1, 20, 1); // Начальный период усреднения SMA
            _smaMaxPeriod   = CreateParameter("Max Period", 20, 1, 200, 1); //   Максимальный период скользящей средней

        }

        #endregion

        protected override void Execute()
        {
            int firstValidValue = 1 + Math.Max(_smaMaxPeriod.ValueInt, _smaStartPeriod.ValueInt); // Первое значение свечки, при котором существуют все индикаторы

            #region Индикаторы

            #endregion

            #region Переменные для обслуживания позиции

            bool signalBuy = false, signalShort = false; // Сигналы на вход в длинную и короткую позиции

            // для сопровождения позиции
            int period = 1; // переменная для периода
            int smaStartPeriod = _smaStartPeriod.ValueInt;
            int smaMaxPeriod = _smaMaxPeriod.ValueInt;

            double orderTrailingStop = 0; // Ордер T/S

            #endregion

            #region Представление цен с необходимой разрядностью для отображения ордеров

            string PricePattern = "0.";
            for (int i = 0; i < this.Bars.SymbolInfo.Decimals; i++)
                PricePattern += "0";

            #endregion

            PlotStops(); // Отображать уровни, на которых были попытки выхода по S/L
            HideVolume(); //скрываем область графика с объемами

            for (int bar = firstValidValue; bar < Bars.Count; bar++) // Пробегаемся по всем свечкам
            {
                #region Сигналы на вход в позицию и выход из нее
                /*

                signalBuy =  (определяем условие на вход в длинную позицию и выход из короткой)

                signalShort = (определяем условие на вход в короткую позицию и выход из длинной)

                */

                #endregion

                #region Сопровождение и выход из позиции по TralingSmaExit

                if (!IsLastPositionActive) // Если позиции нет
                {
                    period = smaStartPeriod;
                    if (period > smaMaxPeriod) period = smaMaxPeriod; //определяем начальный период усреднения:

                    if (signalBuy) // При получении сигнала на вход в длинную позицию
                    {
                        RiskStopLevel = SMA.Value(bar-1, Low, period); //находим первоначальный стоп на уровне скользящей средней минимальных цен, определенной на предыдущем баре
                        BuyAtMarket(bar + 1, "Buy");
                        orderTrailingStop = RiskStopLevel; //устанавливаем трейлинг стоп на уровне минимума текущего бара

                        AnnotateBar(orderTrailingStop.ToString(PricePattern), bar, true, Color.Blue, Color.Yellow);
                    }
                    else if (signalShort) // При получении сигнала на вход в короткую позицию
                    {
                        RiskStopLevel = SMA.Value(bar - 1, High, period); //находим первоначальный стоп на уровне скользящей средней максимальных цен, определенной на предыдущем баре
                        ShortAtMarket(bar + 1, "Buy");
                        orderTrailingStop = RiskStopLevel; //устанавливаем трейлинг стоп на уровне максимумов предыдущих баров

                        AnnotateBar(orderTrailingStop.ToString(PricePattern), bar, true, Color.Blue, Color.Yellow);
                    }
                }
                else // Если позиция есть
                {
                    period = smaStartPeriod + (bar - LastActivePosition.EntryBar);

                    if (period > smaMaxPeriod) period = smaMaxPeriod;

                    if (LastActivePosition.PositionType == PositionType.Long)  // Для длинной позиции
                    {

                        orderTrailingStop  =  Math.Max (orderTrailingStop, SMA.Value(bar-1,Low,period));

                        SellAtStop(bar, LastActivePosition, orderTrailingStop, "Sell Stop"); // Попробовать выйти по T/S

                    }
                    else  // Для короткой позиции
                    {
                        orderTrailingStop = Math.Min(orderTrailingStop, SMA.Value(bar - 1, High, period));

                        CoverAtStop(bar, LastActivePosition, orderTrailingStop, "Cover Stop"); // Попробовать выйти по T/S

                    }
                }

                #endregion
            }
        }
    }
}

Отличий, как Вы заметили от техники "TrailingSmaExit" не так уж и много, хотя принцип в основу положен совсем другой.

2. Техника генерации сигналов на вход в позицию

После того, как код готов - необходимо проверить а рабочий ли этот код. Будет ли эффективной использование этой техники? Не построили ли мы "воздушный замок", который в реальной жизни и в реальной торговле работать не будет. Именно здесь приходит на помощью обвязка торговой системы.

У нас есть техника сопровождения под названием TrailingSmaExit. Остается придумать - как будем входить в позиции. А зачем придумывать, зачем изобретать велосипед, если у нас уже есть целая коллекция торговая техника для генерации сигналов на вход в позицию.

Вот как, к примеру, выглядит эта коллекция торговых техник у меня:

Торговые техники

Коллекция торговых техник для МТС

Выберем из списка торговых техник генерации сигналов на вход в позицию (EnterSygnals) торгоую технику под названием ударный день "HotDay_Enter".

Этот выбор обусловлен тем, что:

  • для этой торговой техники вообще не нужны никакие индикаторы с оптимизируемыми параметрами;
  • она генерирует достаточное количество торговых сигналов;
  • является логичной с точки зрения здравого смысла.

Для примера привожу также код техники "HotDay_Enter"

/*Это блок генерации сигнала на вход
 Генератор сигналов на вход: HotDay_Enter
 Для Wealth-Lab Developer 6
 Автор: Власов Дмитрий Викторович http://finlabportal.ru
 Дата создания: 10.06.2012

 Описание технологии входа:
 - Закрытие свечи выше предыдущего максимума приводит к покупке на следующем баре;
 - Закрытие свечи ниже предыдущего минимума приводит к продаже на следующем баре;

 Резюме: входы для тестирования практически без индикаторов.
*/

using System;
using System.Drawing;
using WealthLab;
using WealthLab.Indicators;

namespace GeneratorMTS.ENTERS
{

    class HotDay_ENTER : WealthScript
    {
        #region Объявление параметров торговой системы

        //параметры для входа в позицию:
        //здесь нет...

        // параметры для выхода из позиции (для примера)

  //      StrategyParameter _atrPeriod; // Период ATR (для примера)

        #endregion

        #region Инициализация параметров торговой системы

        public HotDay_ENTER()
        {

            //для входа в позицию
            //тут нет

            //для выхода из позиции
            // _atrPeriod = CreateParameter("ATR Period", 12, 1, 30, 1); //для примера

        }

        #endregion

        protected override void Execute()
        {
            int firstValidValue = 1; // Первое значение свечки, при котором существуют все индикаторы

            #region Индикаторы

            //для сопровождения позиции
            //тут нет

            //для входа в позицию:

            //// ATR - для примера

            //int atrPeriod = _atrPeriod.ValueInt;
            //SetScaleDaily(); // Переход на дневной масштаб
            //DataSeries atr = ATR.Series(Bars, atrPeriod); // Дневной ATR
            //RestoreScale(); // Возврат текущего масштаба
            //DataSeries hourlyATR = Synchronize(atr); // Перенос с большего масштаба ATR на текущий масштаб
            //ChartPane ATRPane = CreatePane(20, false, true); // Область для отрисовки ATR высотой 20%, ниже графика, с сеткой
            //PlotSeries(ATRPane, hourlyATR, Color.Red, LineStyle.Solid, 1, "ATR(" + atrPeriod.ToString() + ")"); // Отрисовка ATR
            //firstValidValue = Math.Max(firstValidValue, (atr.FirstValidValue + 1) * atrPeriod);

            #endregion

            #region Переменные для обслуживания позиции

            //для генерации входов
            bool signalBuy = false, signalShort = false; // Сигналы на вход в длинную и короткую позиции
            double orderStopLoss = 0, orderTakeProfit = 0; // Ордера S/L и T/P

            //для сопровождения позиции

            #endregion

            #region Представление цен с необходимой разрядностью для отображения ордеров

            string PricePattern = "0.";
            for (int i = 0; i < this.Bars.SymbolInfo.Decimals; i++)
                PricePattern += "0";

            #endregion

            HideVolume();
            PlotStops(); // Отображать уровни, на которых были попытки выхода по S/L

            for (int bar = firstValidValue; bar < Bars.Count; bar++) // Пробегаемся по всем свечкам
            {
                #region Сигналы на вход в позицию и выход из нее

               //  Вариант 3. Вход по тренду по модифицированному "Ударному дню" Ларри Вильямса
                signalBuy = Bars.Close[bar] > Bars.High[bar - 1]; // Закрытие выше предыдущего максимума
                signalBuy = signalBuy && (!IsLastPositionActive || LastActivePosition.PositionType == PositionType.Short); // генерируется когда не в длинной позиции
                signalShort = Bars.Close[bar] < Bars.Low[bar - 1]; // Закрытие ниже предыдущего минимума
                signalShort = signalShort && (!IsLastPositionActive || LastActivePosition.PositionType == PositionType.Long); // генерируется когда не в короткой позиции

                #endregion

                #region Сопровождение и выход из позиции по Take Profit

                if (!IsLastPositionActive) // Если позиции нет
                {
                    if (signalBuy) // При получении сигнала на вход в длинную позицию
                    {
                        //для входа в  позицию
                        BuyAtMarket(bar + 1, "Buy"); // Купить по рынку на открытии следующей свечки

                        //условия сопровождения позиции

                        //  orderStopLoss = Bars.Close[bar] - atrStopPercent * hourlyATR[bar] / 100;
                      //  orderTakeProfit = Bars.Close[bar] + atrStopPercent * winLoss * hourlyATR[bar] / 100;
                       // PrintDebug(orderStopLoss.ToString(PricePattern) + "  :  " + orderTakeProfit.ToString(PricePattern));
                    }
                    else if (signalShort) // При получении сигнала на вход в короткую позицию
                    {
                        //для входа в позицию
                        ShortAtMarket(bar + 1, "Short"); // Продать по рынку на открытии следующей свечки

                        //для сопровождения позиции
                        //orderStopLoss = Bars.Close[bar] + atrStopPercent * hourlyATR[bar] / 100;
                        //orderTakeProfit = Bars.Close[bar] - atrStopPercent * winLoss * hourlyATR[bar] / 100;
                        //PrintDebug(orderStopLoss.ToString(PricePattern) + "  :  " + orderTakeProfit.ToString(PricePattern));
                    }
                }
                else // Если позиция есть
                {
                    if (LastActivePosition.PositionType == PositionType.Long) // Для длинной позиции
                    {
                        //условия для сопровождения позиции

                    //    SellAtStop(bar, LastActivePosition, orderStopLoss, "Sell Stop"); // Попробовать выйти по S/L
                    //    SellAtLimit(bar, LastActivePosition, orderTakeProfit, "Sell"); // Попробовать выйти по T/P
                    }
                    else // Для короткой позиции
                    {
                        //условия для сопровождения позиции

                        //CoverAtStop(bar, LastActivePosition, orderStopLoss, "Cover Stop"); // Попробовать выйти по S/L
                        //CoverAtLimit(bar, LastActivePosition, orderTakeProfit, "Cover"); // Попробовать выйти по T/P
                    }
                }

                #endregion
            }
        }
    }
}

Для тестирования новой техники сопровождения позиции "TrailingSmaContraExit" именно техника "HotDay_Enter", генерирующая сигналы на вход в позицию и будет обвязкой. Скажу здесь, что в качестве обвязки мы могли бы выбрать любую технику входов из всего списка, который есть в нашем распоряжении.

3. Конструирование МТС из техники сопровождения и техники входа в позицию

Теперь, имея перед глазами правила сопровождения позиции (TrailingSmaContraExit) и правила входа в позицию (HotDay_Enter) мы можем сделать полноценную торговую систему типа "Обвязка"... Т.е. мы, образно говоря, собираем пазл из имеющихся кусочков и получаем готовую картину в виде новой торговой системы. Для того, чтобы при одном взгляде на название торговой системы можно было понять - как она торгует предлагаю называть торговые системы однотипно. Сначала идет название техники входа в позицию, а затем после нижнего подчеркивания писать название техники сопровождения.

Для нашего случая МТС будет называться так: HotDayEnter_TrailingSmaContraExit. Далее привожу для Вас получившийся код торговой системы для Wealth-Lab.


// Эта ТС сгенерирована для Wealth-Lab Developer 6
// Автор: Власов Дмитрий Викторович (http://finlabportal.ru)
// Дата создания: 11.06.2012
// Генератор сигналов на вход: HotDayEnter
// Направление следования сигналам: Forward
// Фильтр тренда: None
// Фильтр флета: None
// Временной фильтр: None
// Технология выхода: TrailingSmaContraExit
// оптимизирована для фьючерса на индекс РТС (15-ти минутки) при комиссии 0,07% от оборота

using System;
using System.Drawing;
using WealthLab;
using WealthLab.Indicators;

namespace GeneratorMTS.MTS
{
    class HotDayEnter_TrailingSmaContraExit : WealthScript
    {

        #region Объявление параметров торговой системы

        //для входа в позицию
        //параметров нет

        //для сопровождения позиции
        StrategyParameter _smaStartPeriod; // Начальный период усреднения EMA
        StrategyParameter _smaMaxPeriod; //   Максимальный период скользящей средней

        #endregion

        #region Инициализация параметров торговой системы

        public HotDayEnter_TrailingSmaContraExit()
        {
            //для сопровождения позиции
            _smaStartPeriod = CreateParameter("Start Period", 3, 1, 20, 1); // Начальный период усреднения SMA
            _smaMaxPeriod = CreateParameter("Max Period", 20, 1, 200, 1); //   Максимальный период скользящей средней

        }

        #endregion

        protected override void Execute()
        {
            int firstValidValue = 1 + Math.Max(_smaMaxPeriod.ValueInt, _smaStartPeriod.ValueInt); // Первое значение свечки, при котором существуют все индикаторы

            #region Индикаторы

                //Индикаторов здесь не существует скользящая средняя считается с помощью метода SMA.Value()

            #endregion

            #region Переменные для обслуживания позиции

            //для входа в позицию
            bool signalBuy = false, signalShort = false; // Сигналы на вход в длинную и короткую позиции

            // для сопровождения позиции
            int period = 1; // переменная для периода
            int smaStartPeriod = _smaStartPeriod.ValueInt;
            int smaMaxPeriod = _smaMaxPeriod.ValueInt;

            double orderTrailingStop = 0; // Ордер T/S

            #endregion

            #region Представление цен с необходимой разрядностью для отображения ордеров

            string PricePattern = "0.";
            for (int i = 0; i < this.Bars.SymbolInfo.Decimals; i++)
                PricePattern += "0";

            #endregion

            PlotStops(); // Отображать уровни, на которых были попытки выхода по S/L
            HideVolume(); //скрываем область графика с объемами

            for (int bar = firstValidValue; bar < Bars.Count; bar++) // Пробегаемся по всем свечкам
            {
                #region Сигналы на вход в позицию и выход из нее

                //  Вариант 3. Вход по тренду по модифицированному "Ударному дню" Ларри Вильямса
                signalBuy = Bars.Close[bar] > Bars.High[bar - 1]; // Закрытие выше предыдущего максимума
                signalBuy = signalBuy && (!IsLastPositionActive || LastActivePosition.PositionType == PositionType.Short); // генерируется когда не в длинной позиции
                signalShort = Bars.Close[bar] < Bars.Low[bar - 1]; // Закрытие ниже предыдущего минимума
                signalShort = signalShort && (!IsLastPositionActive || LastActivePosition.PositionType == PositionType.Long); // генерируется когда не в короткой позиции

                #endregion

                #region Сопровождение и выход из позиции по TralingSmaExit

                if (!IsLastPositionActive) // Если позиции нет
                {
                    period = smaStartPeriod;
                    if (period > smaMaxPeriod) period = smaMaxPeriod; //определяем начальный период усреднения:

                    if (signalBuy) // При получении сигнала на вход в длинную позицию
                    {
                        RiskStopLevel = SMA.Value(bar - 1, Low, period); //находим первоначальный стоп на уровне скользящей средней минимальных цен, определенной на предыдущем баре
                        BuyAtMarket(bar + 1, "Buy");
                        orderTrailingStop = RiskStopLevel; //устанавливаем трейлинг стоп на уровне минимума текущего бара

                        AnnotateBar(orderTrailingStop.ToString(PricePattern), bar, true, Color.Blue, Color.Yellow);
                    }
                    else if (signalShort) // При получении сигнала на вход в короткую позицию
                    {
                        RiskStopLevel = SMA.Value(bar - 1, High, period); //находим первоначальный стоп на уровне скользящей средней максимальных цен, определенной на предыдущем баре
                        ShortAtMarket(bar + 1, "Buy");
                        orderTrailingStop = RiskStopLevel; //устанавливаем трейлинг стоп на уровне максимумов предыдущих баров

                        AnnotateBar(orderTrailingStop.ToString(PricePattern), bar, true, Color.Blue, Color.Yellow);
                    }
                }
                else // Если позиция есть
                {
                    period = smaStartPeriod + (bar - LastActivePosition.EntryBar);

                    if (period > smaMaxPeriod) period = smaMaxPeriod;

                    if (LastActivePosition.PositionType == PositionType.Long)  // Для длинной позиции
                    {

                        orderTrailingStop = Math.Max(orderTrailingStop, SMA.Value(bar - 1, Low, period));

                        SellAtStop(bar, LastActivePosition, orderTrailingStop, "Sell Stop"); // Попробовать выйти по T/S

                    }
                    else  // Для короткой позиции
                    {
                        orderTrailingStop = Math.Min(orderTrailingStop, SMA.Value(bar - 1, High, period));

                        CoverAtStop(bar, LastActivePosition, orderTrailingStop, "Cover Stop"); // Попробовать выйти по T/S

                    }
                }

                #endregion

            }
        }
    }
}

Как Вы уже заметили, весь код торговой системы состоит из кода двух техник, которые я приводил выше. Мы просто взяли уже готовый код из двух техник и сложили из него "пазл", сделав новую торговую систему. Cразу скажу, что торговать такую систему пока еще нельзя (хотя если хочется - пожалуйста - торгуйте).

Просто цель такой "обвязочной" системы в том, чтобы потестировать какую-либо гипотезу. В качестве гипотезы здесь выдвигается следующее утверждение: техника сопровождения позиции с помощью выставления стопов, использующих скользящую среднюю с постепенно возрастающим периодом эффективна.

Давайте теперь посмотрим, что делать с получившейся торговой системой.

Как найти финансовые инструменты для эффективного использования торговых техник

На мой взгляд, совершенно ясно, что никакая техника торговли не является универсальной. Проще говоря, нет и никогда не будет такой торговой техники, которая будет эффективна для всех без исключения финансовых инструментов для всех без исключения таймфреймов.

Наша гипотеза подтвердится, если мы найдем некоторое количество финансовых инструментов при использовании с которыми на некоторых таймфреймах торговая техника будет показывать свою эффективность.

Как Вы знаете, на бирже ММВБ-РТС торгуется очень большое количество инструментов. Из этого многообразия нам необходимо отобрать те инструменты, которые подходят к данной конкретной технике сопровождения.

Конечно же, можно все эти инструменты оптимизировать по очереди, но тогда это потребует очень большого времени. Я придумал технику, которая позволяет проведя всего лишь 5 тестов определить "шорт лист" тех инструментов, которые с очень большой вероятностью можно эффективно использовать для торговли с применением данной конкретной техники на данном конкретном таймфрейме.

Сейчас я расскажу, как я подхожу к этому вопросу:

Шаг 1: выбор таймфрейма

На первом этапе нужно определиться - на каком таймфрейме мы будем тестировать нашу торговую систему. В данный раз я выбираю часовой таймфрейм. Это позволит быстрее протестировать торговую систему для составления представления о новой технике. Кроме того, чем реже сделки, тем меньше мы несем издержек на комиссию и проскальзывания.

Но в тоже время часовой таймфрейм позволит сгенерировать достаточное количество сделок для статистической достоверности результата.

Шаг 2: выбор ширины окна тестирования

Окно тестирования - это тот временной промежуток, который мы используем для бэктестинга. Сегодня я использовал окно шириной в 2 года - с 1 мая 2010 года по 1 мая 2012 года.

Скажу сразу, что обычно ширина окна тестирования составляет один год.

Шаг 3: выбор и оптимизация первого инструмента.

Какой инструмент взять в качестве первого испытуемого?

Здесь все зависит от Вашего желания. Я захотел в качестве первого инструмента использовать обыкновенные акции Сбербанка.

Проводим оптимизацию торговой системы HotDayEnter_TrailingSmaContraExit на периоде с 01.05.2010 по 01.05.2012 по акциям сбербанка.

Какие параметры здесь оптимизируются? Оптимизируются 2 параметра:

  • StartPeriod - это период, который применяется для усреднения скользящей средней в момент входа в позицию, чтобы установить на такой скользящей средней первоначальный стоп. Это также будет минимальный период усреднения, который с каждым баром существования позиции будет увеличиваться на единицу.
  • MaxPeriod - это максимальный период усреднения скользящей средней. Больше чем этот период период скользящей средней быть не может.

Для оптимизации я использую генетический оптимизатор торговых стратегий программы Wealth-Lab. При этом оптимизируется (максимизируется) показатель торговой системы, который называется Recovery Factor. Это отношение дохода к максимальной просадке.

Режим, в котором оптимизируется торговая система - в каждой сделке мы входим в позицию на 100 тыс. рублей - именно с этим учетом программа подбирает количество лотов. Это сделано для того, чтобы результаты по разным финансовым инструментам были сопоставимы.

Комиссия и проскальзывание не учитываются, т.к. это пока лишь проверка выдвинутой гипотезы, а не оптимизация торговой системы, которую мы собираемся торговать.

В результате оптимизации у нас появляются вот такие результаты:

Результаты оптимизации

Результаты оптимизации МТС по акции SBER

Итак, мы получили таблицу с огромным количеством результатом. Как выбрать наилучший? Предлагаю действовать по такому механизму:

  • Сортируем результаты по показателю Recovery Factor по убыванию (сверху самые большие значения и уменьшаются вниз). Сортировка показана синей стрелочкой вниз.
  • Выбираем TOP-10 результатов с лучшим показателем Recovery Factor - на рисунке отмечено большой синей рамкой.
  • Из TOP-10 выбираем те критерии, которые показывают наибольшую NetProfit, т.е. итоговую прибыль. На рисунке отмечен красной рамкой
  • В указанной строке смотрим оптимальные параметры торговой системы - отмечены зеленой рамкой.

Действуя таким образом мы однозначно выбираем лучшие параметры торговой системы. Для акции SBER для часового таймфрейма лучшими параметрами оказались следующие: стартовый (первоначальный) период усреднения равен 1, а минимальный 4. По-сути здесь в процессе оптимизации выяснилось, что период сразу после входа в позицию Стоп-лосс должен выставляться по экстремуму предыдущей свечи. Затем стоп лосс сдвигается на уровень, который рассчитывается по экстремумам 2-х свечей, затем 3-х, четырех и далее период скользящей средней на всем протяжении должен быть неизменным и составляет 4 часа.

Просто для иллюстрации привожу Вам график Эквити торговой системы для акций Сбербанка

График наличного капитала для акции СБЕРБАНК

График Наличного капитала для СБЕРБАНКа

и график просадок.

График просадок для СБЕРБАНКа

График просадок для акции СБЕРБАНК

Согласитесь, что это уже неплохо для "обвязочной" торговой системы, которая просто является тестом гипотезы.

Шаг 4: Тестирования всей совокупности акций, входящей в набор данных (DataSet)

Используя получившиеся оптимизационные параметры проводим тестирование для всего набора данных (DataSet), который содержит в себе все акции, имеющиеся в нашем распоряжении.

Для этого нужно проделать следующую последовательность действий:

  1. Устанавливаем параметры торговой системы, которые мы определили на предыдущем этапе (в нашем случае при нахождении оптимальных параметров для акций Сбербанка).
  2. Выбираем тот набор данных (DataSet), который содержит список всех финансовых инструментов, из которого мы хотим найти те финансовые инструменты, которые эффективно используют тестируемую технику.
  3. Нажимаем на кнопку "Backtest on all Symbols in ММВБ Акции (1 час)" говоря таким образом программе Wealth-Lab, что мы хотим протестировать одновременно все акции.
Тестирование набора данных (DataSet)

Тестирование всех акций, входящих в набор данных DataSet

В результате выполнения данных действий мы получим результаты тестирования по всем финансовым инструментам, которые входят в текущий набор данных.

Шаг 5: Ранжирование финансовых инструментов и определение нового финансового инструмента для оптимизации.

В результате выполнения предыдущего шага у нас есть результаты по всем акциям.

Но где посмотреть эти результаты? Просто нужно перейти на вкладку "BySymbol" - что отображено здесь красной рамкой.

Результаты тестирования по акциям

Результаты тестирования всех акций "скопом"

После этого сортируем получившиеся результаты в порядке убывания прибыли. Порядок сортировки отображен на рисунке красной стрелкой.

Обратите внимание, мы проводили тестирование всех акций, используя оптимальные параметры, которые были получены для одной акции SBER. Но при этом наилучший результат (при использовании оптимальных параметров для сбера) показал не сбербанк, а акция шакты "Распадская". Еще нужно обратить внимание на то, что все акции разбились на две группы - вверху те, которые показывают положительные результаты от гипотетической торговли, а внизу те - которые показывают отрицательные результаты.

Как результат - мы получаем предварительные результаты и можем утверждать, что чем выше находится акция вверху, тем больше вероятность того, что при ее персональной оптимизации мы получим намного лучшие результаты.

Однако для вывода нам нужно провести как минимум пять тестирований набора данных, используя оптимальные параметры для конкретной бумаги. И лишь анализируя результаты этих пяти тестирований мы сможем составить список пригодных для этой торговой техники акций.

Чтобы было что анализировать - сохраним результаты (эту таблицу) в программе Excel. Для этого нужно нажать на таблицу в Wealth-Lab правой кнопкой и сохранить таблицу в буфер обмена. Затем перейти в эксель и просто вставить данные из буфера обмена. В результате получится таблица в экселе.

Давайте выберем следующего кандидата на оптимизацию - это очевидно будет акция RASP.

Проходим с этой акцией все предыдущие шаги от шага №3 до шага №5 включительно.

На 5-м шаге вновь сохраняем результаты тестирования в таблицу и вновь находим новую акцию - и так проделываем 5 раз.

Шаг №6: Анализ результатов оптимизации и тестирования и подтверждение либо опровержение гипотезы

По результатам выполнения предыдущих шагов у нас получилась такая аналитическая таблица:

Результаты отбора акций

Аналитическая таблица для выбора акций

Используя эту таблицу - можно сделать следующий главный вывод: Существует некоторое количество финансовых инструментов, используя которые в "обвязочной" торговой системе на таймфрейме в 1 час можно получить приемлемые результаты. Следовательно техника "TrailingSmaContraExit" показала себя эффективной и можно пополнить ей свой арсенал торговых техник для сопровождения позиций.

Кроме того, используя данную таблицу можно утверждать, что наилучшие результаты при использовании торговой техники "TralingSmaContraExit" будут давать акции, расположившиеся вверху таблицы и окрашенные оттенками зеленого цвета. Приемлемые результаты будут давать акции желтого цвета и наихудшие результаты - акции, окрашенные оранжевым и красным цветами.

Заметьте, что эти результаты являются усредненными по 5-ти тестам, которые были оптимальны только для одной из акций. Если мы проведем индивидуальную оптимизацию для конкретной акции из таблицы, то результаты будут значительно (до 50%) лучше, чем указаны здесь. И еще раз подчеркну - это не полностью готовая торговая система, а просто "обвязка", которая позволяет оценить эффективность торговых техник.

Таким образом мы определили не только пригодность торговой техники, но и попутно составили "шорт-лист" финансовых инструментов, которые нужно использовать с этой техникой.

В следующий раз я собираюсь показать как можно использовать обвязку для сравнения двух техник, и конечно же буду периодически пополнять свою копилку новыми торговыми техниками. Чтобы не пропустить - подписывайтесь на RSS. Если что-то непонятно - пишите в комментах - постараюсь ответить. Если у кого-то есть идея - как создать новую технику, но не хватает навыков программирования - пишите мне с помощью меню "Контакты" - ссылка вверху сайта - постараюсь Вам помочь.

Комментариев: 3

  1. Andrey пишет:

    Интересная методика, спасибо. Но появился вопрос. Не получится ли так, что подобным методом мы привяжем систему к акциям с определенным поведением, подобным поведению Сбера. Т.е. акции, сливающие со Сберовсими параметрами, но которые могут дать лучшие результаты при других параметрах, мы исключим из рассмотрения. Может лучше на каждом этапе выбирать одну-две лучших акций и одну-две худших акций и их оптимизировать? Работы больше, но можем найти более интереные варианты. Как вы думаете?

  2. ring10 пишет:

    Дмитрий, там в сопровождении позиции TrailingSmaExit и в конта надо поставить Sell наверное, а не Buy?

    ShortAtMarket(bar + 1, “Sell”);

    • Дмитрий Власов пишет:

      Да, конечно. На торговую логику это не влияет, но в таблице всех трейдов будет вводить в заблуждение… Только не “Sell”, а “Short”. т.е. Sell – это выход из длинной позиции, а Short – это формирование новой короткой позиции. А это принципиально разные вещи.

Оставить комментарий