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

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

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

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

Генератор МТС

Что такое генератор механических торговых систем

Начну издалека. Однажды Сэр Исаак Ньютон сказал: "Если я видел дальше других, то потому, что стоял на плечах гигантов".

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

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

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

Блоки генератора торговых систем

Перечислю здесь все те блоки, которые нужно анализировать и периодически пополнять:

  1. Техники сопровождения позиции (технология выхода);
  2. Генерация входных сигналов (технология входа);
  3. Фильтры тренда;
  4. Фильтры флета;
  5. Временные фильтры.

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

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

А если мы имеем, к примеру 6 различных техник сопровождения и 7 входных сигналов (смотрите рисунок)?

Генератор МТС

Схема генерации механических торговых систем

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

А если учесть, что входить можем как в направлении торгового сигнала (Forward) так и против направления торгового сигнала (Revers), то количество возможных торговых систем увеличивается до 84.  А если еще добавить два разных типа фильтрации? Уже 168 систем. И так далее.

Как Вы видите, если мы используем 6 техник сопровождения, 7 входных сигналов, 2 направления входа и 2 фильтра, то у нас появляется 168 уникальных, не похожих друг на друга систем.

Еще один вопрос - если мы придумываем, допустим один новый тип входа - как изменится в этом случае наше общее количество систем? Давайте посчитаем:

6 техник сопровождения * 8 (входных сигналов) * 2 (типа входа) *   2 (виды фильтрации) = 192. То есть найдя  и проработав всего лишь одну технику нового входа мы увеличиваем свой арсенал потенциально доходных торговых стратегий с 168 до 192 штук, т.е. на 24 новых торговых системы.

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

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

Где взять идеи для создания новых торговых техник

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

Где брать новые техники? Способов здесь очень много:

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

Во-вторых, нужно периодически разбирать "по косточкам" чужие торговые системы. Это так называемый метод анализа и синтеза, когда с помощью анализа мы разбираем систему на отдельные составляющие, а затем с помощью синтеза создаем из выявленных и изученных частей нечто новое. Для меня неиссякаемым источником таких идей является английский сайт для пользователей Wealth-Lab. Мало того, что там уже выложено более 180 готовых торговых систем (для официальных пользователей), так еще и в форуме постоянно можно перехватить интересную информацию.

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

RSS подписка на блоги по трейдингу

RSS подписка на блоги системных трейдеров

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

Анализ чужой механической торговой системы

Ту идею входа в позицию, о которой я хотел рассказать сегодня я как раз и подсмотрел в одном из блогов, который ведет Максим (mirovan). Блог очень интересный - всем его рекомендую. Максим не жадничает и выкладывает коды торговых систем, которые он разрабатывает. Конечно, код у этих систем не такой профессиональный, как у Игоря Чечета, но идеи - отличные. А если применить здесь метод анализа и синтеза... ну, Вы поняли...

Те, кто прочитает пост, который написал Максим про торговую систему с использованием индикаторов ADX и CCI - увидит, что от его торговой системы, которую он торгует осталось в получившейся торговой технике не так уж много. Если разложить по полочкам - что предлагает Максим - получится следующая схема торговой стратегии:

Рабочий инструмент:

фьюч на индекс РТС (15 минут);

Условия на вход в длинную позицию:

  • ADX (период индикатора ADX является оптимизированным параметром торговой системы) должен расти;
  • ADX должен быть небольшим, чтобы входить в начале тренда (<20) - хотя отмечу, что это по-сути параметр, который автор просто зафиксировал.
  • CCI должен быть больше 100 (период CCI - оптимизируемый параметр стратегии) - что подтверждает силу тренда. Отмечу, что уровень 100 - по сути тоже зафиксированный торговый параметр.
  • Свеча должна быть белой (Close > Open);
  • верхняя тень свечи должна быть не больше 200 пунктов (это тоже заранее установленный параметр торговой стратегии);
  • время входа: с 11 часов утра до 23 часов.

Условия выхода из длинной позиции:

  • ставится первоначальный стоп (его величина в пунктах оптимизируется у автора системы);
  • вводится трейлинг стоп (его параметр также подбирается при оптимизации);
  • позиция закрывается в конце рабочего дня (в 23-30);

Условия на вход в короткую позицию и на выход из короткой позиции - зеркально противоположны условиям на вход.

В общем, система получается, конечно с довольно большим количеством параметров, но в ее основе лежит здравая идея о том, что:

  • нужно входить по тренду;
  • нужно входить в начале тренда (не вскакивать в ушедший поезд);
  • ограничивать убытки.

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

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

Давайте теперь, имея перед глазами схему генератора МТС попробуем найти новую технику, опираясь на систему Максима.

Итак, технику сопровождения позиции беру самую первую, которая существует на рисунке - TakeProfitPercent.

Применение готовой техники сопровождения позиции при создании МТС:

Берем уже готовую технику, которую мы создали, изучили, протестировали и формализовали ранее. Эта техника сопровождения позиции называется TakeProfitPercent.

Смысл ее заключается в том, что берется процентный отступ от цены входа в позицию (этот параметр оптимизируется). После чего подбирается коэффициент, на который величина тейк профита должна быть больше чем величина Стоп Лоса. Таким образом, после входа в позицию выставляется два ордера:

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

Выглядеть это будет примерно так:


     //техника сопровождения позиции TakeProfitPercent

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

        StrategyParameter _StopPercent; // S/L в % от среднедневного ATR
        StrategyParameter _winLoss; // T/P в размерах S/L

     #endregion

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

        public CCI_ADX_percent_Levels()
        {
            _StopPercent = CreateParameter("Stop %", 0.8, 0.3, 1.5, 0.10);
            _winLoss = CreateParameter("Win/Loss", 8, 3, 10, 0.5); // Отношение выигрыша к проигрышу
        }

        #endregion
     protected override void Execute()
        {

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

            double StopPercent = _StopPercent.Value; // Процент для установки S/L
            int winLoss = _winLoss.ValueInt; // Отношение ордера T/P к S/L
            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

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

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

                /*

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

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

                */

                #endregion

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

                if (!IsLastPositionActive) // Если позиции нет
                {
                    if (signalBuy) // При получении сигнала на вход в длинную позицию
                    {
                        BuyAtMarket(bar + 1, "Buy"); // Купить по рынку на открытии следующей свечки
                        orderStopLoss = Bars.Close[bar] * (100 - StopPercent) / 100;
                        orderTakeProfit = Bars.Close[bar] * (100 + StopPercent * winLoss) / 100;
                        AnnotateBar(orderStopLoss.ToString(PricePattern) + "  :  " + orderTakeProfit.ToString(PricePattern), bar, true, Color.Blue, Color.Yellow);
                    }
                    else if (signalShort) // При получении сигнала на вход в короткую позицию
                    {
                        ShortAtMarket(bar + 1, "Short"); // Продать по рынку на открытии следующей свечки
                        orderStopLoss = Bars.Close[bar] * (100 + StopPercent) / 100;
                        orderTakeProfit = Bars.Close[bar] * (100 - StopPercent * winLoss) / 100;
                        AnnotateBar(orderStopLoss.ToString(PricePattern) + "  :  " + orderTakeProfit.ToString(PricePattern), bar, true, Color.Blue, Color.Yellow);
                    }
                }
                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
            }
        }

Как видите, все четко и предельно просто. Спасибо еще раз Игорю Чечету за разработанный им удобный шаблон.

Критический анализ чужой торговой системы с целью создания новой торговой техники

Теперь посмотрим - какие элементы торговой стратегии возьмем для новой техники входа.

  • Оставляем индикатор ADX - его период делаем первым оптимизируемым параметром;
  • Оставляем условие о том, что индикатора ADX должен расти, т.е. должно выполняться условие  ADX [bar]  >  ADX [bar-1];
  • Соглашаемся с тем, что ADX должен быть небольшим, чтобы входить в начале тренда. Однако уровень ADX, выше которого индикатор не может быть при входе в позицию, делаем вторым параметром системы (а не фиксированной величиной как это делал автор).
  • Оставляем индикатор CCI - его период также делаем параметром торговой системы.
  • Соглашаемся с автором, что CCI должен быть больше определенного уровня. Однако величину этого уровня делаем тоже параметром (а не фиксированной величиной 100, как это делал автор)

Отказываемся от следующих элементов системы, которые предлагал автор:

  • От условия, что Свеча должна быть белой (Close > Open) отказываемся;
  • Условие о том, что верхняя тень свечи должна быть не больше 200 пунктов также игнорируем;
  • Не обращаем внимания на время входа (по версии автора с 11 часов утра до 23 часов).

Вот и все. У нас получилась новая техника, генерирующая вход в позицию. Выглядеть она будет так:


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

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

namespace VDV.Strategies
{

    class CCI_ADX_percent_Levels : WealthScript
    {
        const int PeriodsInDay = 9; // Кол-во интервалов за сессию

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

        //	StrategyParameter _atrDailyPeriod; // Дневной период ATR
        StrategyParameter _StopPercent; // S/L в % от среднедневного ATR
        StrategyParameter _winLoss; // T/P в размерах S/L

        StrategyParameter _periodADX; // период индикатора ADX
        StrategyParameter _periodCCI; // период индикатора CCI
        StrategyParameter _cciLevel; // Уровень, забираясь выше которого CCI генерирует сигнал на вход в лонг (зеркально для короткой)
        StrategyParameter _adxLevel; // Если ADX находится выше этого уровня, то тренд уже развился и мы в него "не впрыгиваем"

        #endregion

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

        public CCI_ADX_percent_Levels()
        {
            _StopPercent = CreateParameter("Stop %", 0.7, 0.3, 1.5, 0.10); //Процент отдаления стоп-лосса от цены входа в позицию
            _winLoss = CreateParameter("Win/Loss", 5, 3, 10, 0.5); // Отношение выигрыша к проигрышу (во сколько раз тейк-профит больше стоп-лосса)

            _periodADX = CreateParameter("ADX Period", 118, 10, 200, 1);
            _periodCCI = CreateParameter("CCI Period", 98, 10, 200, 1);
            _cciLevel = CreateParameter("CCI Level", 196, 70, 200, 1);
            _adxLevel = CreateParameter("ADX Level", 44, 10, 50, 1);

        }

        #endregion

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

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

            // Индикатор ADX:

            int periodADX = _periodADX.ValueInt;

            DataSeries adx = ADX.Series(Bars, periodADX);
            ChartPane ADXPane = CreatePane(20, false, true); // Область для отрисовки ADX высотой 20%, ниже графика, с сеткой
            PlotSeries(ADXPane, adx, Color.Blue, LineStyle.Solid, 2); // отрисовка ADX
            firstValidValue = Math.Max(firstValidValue, adx.FirstValidValue + 1);

            // Индикатор CCI:

            int periodCCI = _periodCCI.ValueInt;

            DataSeries cci = CCI.Series(Bars, periodCCI);
            ChartPane CCIPane = CreatePane(20, false, true); // Область для отрисовки CCI высотой 20%, ниже графика, с сеткой
            PlotSeries(CCIPane, cci, Color.Red, LineStyle.Solid, 2); // отрисовка CCI
            firstValidValue = Math.Max(firstValidValue, cci.FirstValidValue + 1);

            int cciLevel = _cciLevel.ValueInt; //забираем значение из параметра
            int adxLevel = _adxLevel.ValueInt; //забираем значение из параметра

            #endregion

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

            bool signalBuy = false, signalShort = false; // Сигналы на вход в длинную и короткую позиции
            double StopPercent = _StopPercent.Value; // Процент для установки S/L
            int winLoss = _winLoss.ValueInt; // Отношение ордера T/P к S/L
            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

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

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

                signalBuy = adx[bar] > adx[bar - 1]; // индикатор adx растет
                signalBuy = signalBuy && cci[bar] > cciLevel; //индикатор CCI забрался выше установленного уровня
                signalBuy = signalBuy && adx[bar] < adxLevel; //индикатор ADX не превышает установленного уровня (тренд находится в начале)
                signalBuy = signalBuy && (!IsLastPositionActive || LastActivePosition.PositionType == PositionType.Short); // генерируется когда не в длинной позиции

                signalShort = adx[bar] > adx[bar - 1]; // индикатор adx растет
                signalShort = signalShort && cci[bar] < -1.0 * cciLevel; //индикатор CCI забрался ниже установленного уровня
                signalShort = signalShort && adx[bar] < adxLevel; //индикатор ADX не превышает установленного уровня (тренд находится в начале)
                signalShort = signalShort && (!IsLastPositionActive || LastActivePosition.PositionType == PositionType.Long); // генерируется когда не в короткой позиции

                #endregion

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

                if (!IsLastPositionActive) // Если позиции нет
                {
                    if (signalBuy) // При получении сигнала на вход в длинную позицию
                    {
                        RiskStopLevel = Bars.Close[bar] * (100 - StopPercent) / 100; //устанавливаем величину riskStopLevel - чтобы можно было тестировать в режиме "MaxPercentRisk"
                        BuyAtMarket(bar + 1, "Buy"); // Купить по рынку на открытии следующей свечки
                        orderStopLoss = Bars.Close[bar] * (100 - StopPercent) / 100; //устанавливаем стоп-лосс
                        orderTakeProfit = Bars.Close[bar] * (100 + StopPercent * winLoss) / 100; // устанавливаем тейк-профит
                        //AnnotateBar(orderStopLoss.ToString(PricePattern) + "  :  " + orderTakeProfit.ToString(PricePattern), bar, true, Color.Blue, Color.Yellow); //при желании можно сделать надпись
                    }
                    else if (signalShort) // При получении сигнала на вход в короткую позицию
                    {
                        RiskStopLevel = Bars.Close[bar] * (100 + StopPercent) / 100; //устанавливаем величину riskStopLevel - чтобы можно было тестировать в режиме "MaxPercentRisk"
                        ShortAtMarket(bar + 1, "Short"); // Продать по рынку на открытии следующей свечки
                        orderStopLoss = Bars.Close[bar] * (100 + StopPercent) / 100; //устанавливаем стоп-лосс
                        orderTakeProfit = Bars.Close[bar] * (100 - StopPercent * winLoss) / 100; //устанавливаем тейк-профит
                        //AnnotateBar(orderStopLoss.ToString(PricePattern) + "  :  " + orderTakeProfit.ToString(PricePattern), bar, true, Color.Blue, Color.Yellow); //при желании можно сделать надпись
                    }
                }
                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
            }
        }
    }
}

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

Создание готовой механической торговой системы с использованием техники сопровождения позиции и техники генерации входного сигнала

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

Пример (как выполнить пример приведенного кода)...


// Эта ТС сгенерирована для Wealth-Lab Developer 6
// Автор: Власов Дмитрий Викторович (http://finlabportal.ru)
// Генератор сигналов на вход: ADX_CCI_Enter
// Направление следования сигналам: Forward
// Фильтр тренда: None
// Фильтр флета: None
// Временной фильтр: None
// Технология выхода: TakeProfitPercent

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

namespace VDV.Strategies
{

    class CCI_ADX_percent_Levels : WealthScript
    {
        const int PeriodsInDay = 9; // Кол-во интервалов за сессию

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

        //	StrategyParameter _atrDailyPeriod; // Дневной период ATR
        StrategyParameter _StopPercent; // S/L в % от среднедневного ATR
        StrategyParameter _winLoss; // T/P в размерах S/L

        StrategyParameter _periodADX; // период индикатора ADX
        StrategyParameter _periodCCI; // период индикатора CCI
        StrategyParameter _cciLevel; // Уровень, забираясь выше которого CCI генерирует сигнал на вход в лонг (зеркально для короткой)
        StrategyParameter _adxLevel; // Если ADX находится выше этого уровня, то тренд уже развился и мы в него "не впрыгиваем"

        #endregion

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

        public CCI_ADX_percent_Levels()
        {
            _StopPercent = CreateParameter("Stop %", 0.8, 0.3, 1.5, 0.10); //Процент отдаления стоп-лосса от цены входа в позицию
            _winLoss = CreateParameter("Win/Loss", 8, 3, 10, 0.5); // Отношение выигрыша к проигрышу (во сколько раз тейк-профит больше стоп-лосса)

            _periodADX = CreateParameter("ADX Period", 127, 10, 200, 1);
            _periodCCI = CreateParameter("CCI Period", 98, 10, 200, 1);
            _cciLevel = CreateParameter("CCI Level", 100, 70, 200, 1);
            _adxLevel = CreateParameter("ADX Level", 20, 10, 50, 1);

        }

        #endregion

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

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

            // Индикатор ADX:

            int periodADX = _periodADX.ValueInt;

            DataSeries adx = ADX.Series(Bars, periodADX);
            ChartPane ADXPane = CreatePane(20, false, true); // Область для отрисовки ADX высотой 20%, ниже графика, с сеткой
            PlotSeries(ADXPane, adx, Color.Blue, LineStyle.Solid, 2); // отрисовка ADX
            firstValidValue = Math.Max(firstValidValue, adx.FirstValidValue + 1);

            // Индикатор CCI:

            int periodCCI = _periodCCI.ValueInt;

            DataSeries cci = CCI.Series(Bars, periodCCI);
            ChartPane CCIPane = CreatePane(20, false, true); // Область для отрисовки CCI высотой 20%, ниже графика, с сеткой
            PlotSeries(CCIPane, cci, Color.Red, LineStyle.Solid, 2); // отрисовка CCI
            firstValidValue = Math.Max(firstValidValue, cci.FirstValidValue + 1);

            int cciLevel = _cciLevel.ValueInt; //забираем значение из параметра
            int adxLevel = _adxLevel.ValueInt; //забираем значение из параметра

            #endregion

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

            bool signalBuy = false, signalShort = false; // Сигналы на вход в длинную и короткую позиции
            double StopPercent = _StopPercent.Value; // Процент для установки S/L
            int winLoss = _winLoss.ValueInt; // Отношение ордера T/P к S/L
            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

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

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

                signalBuy = adx[bar] > adx[bar - 1]; // индикатор adx растет
                signalBuy = signalBuy && cci[bar] > cciLevel; //индикатор CCI забрался выше установленного уровня
                signalBuy = signalBuy && adx[bar] < adxLevel; //индикатор ADX не превышает установленного уровня (тренд находится в начале)
                signalBuy = signalBuy && (!IsLastPositionActive || LastActivePosition.PositionType == PositionType.Short); // генерируется когда не в длинной позиции

                signalShort = adx[bar] > adx[bar - 1]; // индикатор adx растет
                signalShort = signalShort && cci[bar] < -1.0 * cciLevel; //индикатор CCI забрался ниже установленного уровня
                signalShort = signalShort && adx[bar] < adxLevel; //индикатор ADX не превышает установленного уровня (тренд находится в начале)
                signalShort = signalShort && (!IsLastPositionActive || LastActivePosition.PositionType == PositionType.Long); // генерируется когда не в короткой позиции

                #endregion

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

                if (!IsLastPositionActive) // Если позиции нет
                {
                    if (signalBuy) // При получении сигнала на вход в длинную позицию
                    {
                        RiskStopLevel = Bars.Close[bar] * (100 - StopPercent) / 100; //устанавливаем величину riskStopLevel - чтобы можно было тестировать в режиме "MaxPercentRisk"
                        BuyAtMarket(bar + 1, "Buy"); // Купить по рынку на открытии следующей свечки
                        orderStopLoss = Bars.Close[bar] * (100 - StopPercent) / 100; //устанавливаем стоп-лосс
                        orderTakeProfit = Bars.Close[bar] * (100 + StopPercent * winLoss) / 100; // устанавливаем тейк-профит
                        //AnnotateBar(orderStopLoss.ToString(PricePattern) + "  :  " + orderTakeProfit.ToString(PricePattern), bar, true, Color.Blue, Color.Yellow); //при желании можно сделать надпись
                    }
                    else if (signalShort) // При получении сигнала на вход в короткую позицию
                    {
                        RiskStopLevel = Bars.Close[bar] * (100 + StopPercent) / 100; //устанавливаем величину riskStopLevel - чтобы можно было тестировать в режиме "MaxPercentRisk"
                        ShortAtMarket(bar + 1, "Short"); // Продать по рынку на открытии следующей свечки
                        orderStopLoss = Bars.Close[bar] * (100 + StopPercent) / 100; //устанавливаем стоп-лосс
                        orderTakeProfit = Bars.Close[bar] * (100 - StopPercent * winLoss) / 100; //устанавливаем тейк-профит
                        //AnnotateBar(orderStopLoss.ToString(PricePattern) + "  :  " + orderTakeProfit.ToString(PricePattern), bar, true, Color.Blue, Color.Yellow); //при желании можно сделать надпись
                    }
                }
                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
            }
        }
    }
}

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

Анализ показателей созданной МТС

Теперь пришло время подобрать оптимальные параметры для системы. Буду делать это с помощью генетического оптимизатора, минимизируя показатель "Recovery Factor" (иногда лучше максимизировать показатель NetProfit).

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

Стратегия оптимизироалась по состоянию на 03.06.2012 года за 2 последних года. Время оптимизации заняло примерно 30 минут (2-х ядерный процессор, 64 битная Wealth-Lab).

Эта таблица показывает результаты оптимизации:

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

Результаты работы генетического оптимизатора Wealth-Lab

Чтобы выбрать оптимальные параметры я проделал следующее:

  • Провел сортировку результатов генетической оптимизации по мере убывания показателя Recovery Factor. Это сделано потому, что нам предпочтително, чтобы эквити торговой стратегии имела ровную форму без больших взлетов и падений.
  • Далее из топовых результатов наборов параметров оптимизации был выбран результат с наилучшим показателем "Avg Profit, %" - этот показатель показывает сколько в среднем с одной сделки мы получали дохода. Чем больше этот показатель, тем менее чувствительна торговая стратегия к проскальзываниям и комиссии.
  • Красным горизонтальным выделением показаны прочие подходящие показатели оптимизации. С этими параметрами был визуально изучен график эквити. В результате были выбраны лучшие на мой взгляд из найденных параметров торговой системы. Вы их можете увидеть в таблице в сине строке (4-я строка сверху).

При этом несмотря на то, что оптимизировались только 2 последних года буду исследовать все показатели начиная с января 2008 года, чтобы посмотреть - как вела себя стратегия в кризис 2008 года.

После того, как я с помощью генетического оптимизатора подобрал параметры к этой стратегии вот какие результаты она показывает:

График просадок стратегии

График просадок исследуемой стратегии

Как видите, при торговле на 100% от эквити (без плеча) максимальная просадка, которую мы видели на всей торговой истории (включая кризис 2008 года) составляет 16 %. Это вполне приемлемые результаты, особенно если учитывать что здесь учитывается комиссия (0,07% от оборота) и оптимизировались только последние два года. Если бы мы провели оптимизацию по всему 5-ти летнему периоду - результаты были бы еще лучше.

Дольше всего эквити не достигала новых максимумов в течение 5 500 пятнадцатиминутных баров, что составляет примерно 1375 часов или 114 торговых сессий. Готовы ли Вы столько ждать без новых хаев по прибыли? Если нет, то это система не для Вас. Судя по пилообразному нижнему графику система достаточно устойчива и постоянно стремится вверх.

Теперь посмотрим - как вылядит график эквити.

График эквити стртегии

График эквити с янвая 2008 года (за 4,5 года)

Учитывайте, что для расчета количества контрактов применяется следующий механизм:

Допустим, у нас есть 1000 000 пунктов (обратите внимание, не рублей) - расчет в пунктах ведется для упрощения. Тогда эта сумма делится на цену контракта (в пунктах) - также обращаю внимание, что для наглядности я здесь не оперирую гарантийным обеспечением. И округленная сумма показывает то количество контрактов, которое мы можем купить или продать. Т.е. торговля идет на 100% эквити без плечей (как будто торгуем не фьючерсом, а акцией).

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

Вот отчет по всем прочим показателям (картинка кликабельна).

Результаты тестирования стратегии

Сводные результаты тестирования стратегии

Особенно радует то, что несмотря на комиссию средний доход на сделку составляет 0,78%. Среднее время удержания позиции составляет 91,66 пятнадцатиминутных баров (1374 минуты, или 22 часа), т.е. сделка удерживается в среднем в течение 2-х торговых сессий. Показатель Recovery Factor равен 12,68, что очень даже хорошо.

Теперь давайте посмотрим, сколько можно было бы заработать в разрезе дней, месяцев и лет... (график кликабелен).

Анализ доходности стратегии за период

Результаты стратегии за пириоды (дни, месяцы, годы)

Как видите, в среднем система генерирует 4,53 % в месяц и 58 % в год. И это без плеча и с максимальной просадкой всего в 16 %. Обращают на себя внимание следующие вещи:

  • количество прибыльных дней подряд состаило 7 штку, а максимальное количество убытоных дней подряд - 10 штук;
  • 74% месяцев заканчивались с прибылью, при этом наилучший месяц дал 22,51%, в худший месяц было потеряно 7,28%.
  • Все годы были прибыльны (учитывайте, что 2012 год прошел только наполовину).
  • все эти результаты достигнуты с учетом комиссии  в 0,07% от оборота (на самом деле, даже с учетом проскальзывания и комиссии брокера и биржи это значение будет меньше).

Можно использовать плечо 1:2, но тогда и максимальная просадка и среднемесячная прибыль возрастет в 3 раза.

По каким направлениям можно улучшить торговую систему

В общем, система получилась довольно симпатичная. Конечно, можно ее значительно улучшить.

Я бы поработал по следующим направлениям:

  1. Попробовать другие техники сопровождения позиции (особенно трейлинг стопы, например TralingStopParabolic);
  2. Попробовать оптимизировать отдельно только лонги и только шорты (ведь характер рынка растущего и падающего сильно отличается);
  3. Попробовать разные таймфреймы (а не только 15-ти минутный таймфрейм);
  4. Попробовать разные финансовые инструменты (а не только фьючерс на индекс РТС);
  5. Добавить фильтр времени (для входов и / или выходов) - как предлагает это изначально автор;
  6. Попробовать закрывать позиции в конце дня...

В общем, построение торговой системы - это творческий процесс. Надеюсь, я Вас сегодня убедил в этом.

Я собираюсь здесь на блоге создать коллекцию торговых техник для каждого из блоков генератора МТС. Для этого создал соответствующие рубрики. Если У Вас есть желание пополнить эту коллекцию - присылайте код торговых систем или техник через форму обратной связи. Периодически буду делать обзор таких систем и выкладывать эти техники для всеобщего пользования. Чтобы не пропустить новые сообщения - не забудьте подписаться на обновления моего блога по RSS.

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

  1. Игорь пишет:

    Дмитрий, прошу прощения, но ссылка на материал “как можно автоматизировать процесс построения торговой системы”, битая, а где можно ознакомится со статьей?

  2. Игорь пишет:

    И еще хотел сказать Вам – огромное спасибо, за Ваш труд. Я просто офигиваю :) Читаю Ваши посты как захватывающий детектив, Акунин нервно отдыхает :)

    • Спасибо, Игорь, за добрые слова. Просто мне самому интересно этим заниматься. Если вовремя пост не опубликую – в конце концов потом забуду – чем весь день занимался.

  3. Игорь пишет:

    Спасибо, линк заработал. Теперь точно не засну :) Вопросы, мысли…. :) Надо все обдумать, а можно завтра сюда же вопросы задать?

  4. Vladimir пишет:

    Тоже решил пользоваться googleReader. Только Вы пишите, что если автор удалит свой пост, то он останется в google.reader. Но у меня ( может это зависит от настроек), доступно только часть текста, а чтобы читать пост полностью надо нажимать “Читать Далее” и соответственно происходит переход на страничку автора…

    Если не секрет, то не могли бы вы опубликовать адресса RSS рассылок, которые Вы сами читаете, из общедоступных, бесплатных?

    На Вашу уже подписался.

  5. Приветствую. У меня вверху блога есть страничка – называется “Что почитать – там ссылки на те ресурсы, которые мне нравятся и которые я могу порекомендовать. У каждого из них есть RSS лента. Чтобы поподробнее о RSS узнать – есть специальный сайт: оrss.ru

  6. rasswet пишет:

    попробовал за 2ю половину 2011 года прогнать-показывает гораздо худшие результаты. не могли бы вы прогнать отдельно 2е полугодие 2011. фьючерс на индекс ртс.
    не могу понять в чем дело.

    • А фьючерс берете 15-ти минутки? с какого по какое число нужно Вам прогнать данные? Комиссия и проскальзывание у Вас какие установлены?

      • rasswet пишет:

        может лучше через скайп? я вам послал запрос.
        15ть. 1.07-31.12
        комиссия 2 р. проскальзывание 10 пунктов

        • У меня за этот период (с комиссией 0,07% от оборота и режиме тестирования 100% equity) получается доход 22,56% при максимальной просадке 9%. Период для тестирования этой системы очень маленький. Лучше брать минимум один год. Параметры при этом 0,8; 8; 168; 72; 186; 50 – как указано в статье.

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

          • rasswet пишет:

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

          • to rasswet: Как то мы официально общаемся – как в английском клубе – на Вы.

            Примеры стратегий в рубрике Примеры МТС посмотреть можно.

            Для себя считаю приемлемым доход в размере 2х или 3х размеров банковского депозита (на сегодняшний день это 25% или 35% годовых). Но в некоторых случаях (как неожиданный подарок) – значительно больше. Риск на уровне 5% или 15%.

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

  7. Игорь пишет:

    Добрый вечер, Дмитрий

    Еще раз внимательно перечитал пост. Особенно, ту часть, где Вы описываете процесс оптимизации.
    “Чтобы выбрать оптимальные параметры я проделал следующее:

    Провел сортировку результатов генетической оптимизации по мере убывания показателя Recovery Factor. Это сделано потому, что нам предпочтително, чтобы эквити торговой стратегии имела ровную форму без больших взлетов и падений.
    Далее из топовых результатов наборов параметров оптимизации был выбран результат с наилучшим показателем “Avg Profit, %” – этот показатель показывает сколько в среднем с одной сделки мы получали дохода. Чем больше этот показатель, тем менее чувствительна торговая стратегия к проскальзываниям и комиссии.
    Красным горизонтальным выделением показаны прочие подходящие показатели оптимизации. С этими параметрами был визуально изучен график эквити. В результате были выбраны лучшие на мой взгляд из найденных параметров торговой системы. Вы их можете увидеть в таблице в сине строке (4-я строка сверху).

    При этом несмотря на то, что оптимизировались только 2 последних года буду исследовать все показатели начиная с января 2008 года, чтобы посмотреть – как вела себя стратегия в кризис 2008 года.”

    Теперь несколько вопросов:
    На форму эквити торговой системы влияет только показатель Recovery Factor? Наверняка нет, но мне не совсем понятно, почему фактор восстановления, Вы выделили особо?
    Что, Вы, считаете топовым набором параметров оптимизации и почему?
    Каковы основные принципы, помимо выше описанных выбора лучших показателей оптимизируемых значений?
    Какое окно выборки данных для теста считается оптимальным для минуток? Месяц, квартал, полгода, год? Какими критериями пользоваться для выбора оптимального окна выборки?

    Вопросы, вопросы… :) Дмитрий, я понимаю, что ответы на вопросы по грамотной оптимизации это достаточно объемный материал, но может ответите хотя бы на эти вопросы? Или может посвятите этой теме парочку следующих постов? Грамотная оптимизация, как мне кажется это смесь точных методик и исскуства :) но так мало об этом пишут, а ведь это важнейшая часть создаваемых ТС
    Спасибо

    • Игорь, постараюсь ответить по-порядку:

      1) Recovery Factor в качестве параметра оптимизации выбираю потому, что по-опыту знаю, что те системы, которые обладают высоким показателем Recovery Factor – лучше больше 5-ти имеют ровную эквити и их можно торговать с плечом. Это естественно, т.к. это чистая прибыль, деленная на максимальную просадку в абсолютном значении. Соответственно Recovery Factor будет тем больше, чем меньше будет просадка. А генетический оптимизатор ищет именно такие ситуации.

      2) Еще одним удобным параметром для оптимизации является Sharpe Ratio (отношение/коэффициент Шарпа). Отношение годовой средней арифметической процентной доходности торговой стратегии к годовой средней процентной волатильности (стандартному отклонению). Хорошая торговая система должна иметь коэффициент Шарпа не меньше единицы. Отличным считаются значения свыше двух.

      3) Ну и конечно, же Net Profit. Однако иногда – при максимизации этого показателя получаются неприемлемые параметры (например одна сделка за весь период) либо очень волатильная эквити.

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

      Это мое субъективное мнение – никому его не навязываю. Можете на блоге у Чечета про это все тоже почитать.

  8. Игорь пишет:

    Спасибо, Дмитрий. Все обосновано и понятно, единственный момент, если тестить фьючерсы то сразу встает вопрос с непрерывными данными за тот же год, например. А, вы как боретесь с данной проблемой? Читал, что некоторые, чтобы не заморачиваться, тестируют базис фьючерса, мне такой метод кажется сомнительным.

    • В лицензионной версии Велса есть поставщик исторических данных от Финама. Там есть уже “склеенный” фьючерс. Я пользуюсь им, т.к. самому лениво заниматься склейкой.

  9. Максим пишет:

    Здравствуйте Дмитрий,а как написать скрипт тейк-профита и стоп-лосса,чтобы было не в %,а в пунктах,если брать фьючерс РТС,скажем после открытия позиции сразу выставлялись заявки на 60 и 30 пунктов соответственно.Спасибо.

    • Это очень легко сделать. Просто чуть переделываете технику сопровождения, которая здесь указана. Вот, буквально за 2 минуты код переделал. Смотрите:

      /*Это блок сопровождения позиции (выхода)
       
       Технология выхода: TakeProfitPunkt:
       Для Wealth-Lab Developer 6 
       Автор: Власов Дмитрий Викторович http://finlabportal.ru
       Дата создания: 06.06.2012
       
       Описание технологии выхода:
       - устанавливаем величину стоп-лоса в пунктах;
       - определяем соотношение между Тейк-профитом и стопом;
       - после входа в сделку ставим стоп и профит.
      */
      
      
      
      
      using System;
      using System.Drawing;
      using WealthLab;
      using WealthLab.Indicators;
      
      namespace GeneratorMTS.Exits
      {
      
          class TakeProfitPunkt : WealthScript
          {
              #region Объявление параметров торговой системы
      
              StrategyParameter _stopPunkt; // Величина СтопЛосса в пунктах
              StrategyParameter _winLoss; // во сколько раз тейк-профит больше чем СтопЛосс
      
              #endregion
      
      	#region Инициализация параметров торговой системы
      
      		public TakeProfitPunkt()
      		{
      			_stopPunkt = CreateParameter("Стоп, пунктов", 30, 30, 500, 5); //пробуем устанавливать стоп от 30 до 500 пунктов с шагом 5 (по умолчанию 30 пунктов)
      			_winLoss = CreateParameter("EMA Period", 2, 1, 10, 1); //Тейк профит располагаем дальше чем стоп-лосс от 1 до 10 раз
      		}
      
      		#endregion
      
              protected override void Execute()
              {
                  int firstValidValue = 0; // Первое значение свечки, при котором существуют все индикаторы      
      
      
                  #region Переменные для обслуживания позиции
                  
                  //для генерации сигналов на вход
                  bool signalBuy = false, signalShort = false; // Сигналы на вход в длинную и короткую позиции
      
                  //для сопровождения позиции
                  double StopPunkt = _stopPunkt.Value; // Пункты для установки СтопЛоса
                  int winLoss = _winLoss.ValueInt; // Отношение ордера T/P к S/L
                  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
      
                  PlotStops(); // Отображать уровни, на которых были попытки выхода по S/L
      
                  for (int bar = firstValidValue; bar < Bars.Count; bar++) // Пробегаемся по всем свечкам
                  {
                      #region Сигналы на вход в позицию и выход из нее
      
                      /*
                      
                      signalBuy =  (определяем условие на вход в длинную позицию и выход из короткой)
      
                      signalShort = (определяем условие на вход в короткую позицию и выход из длинной)
                        
                      */
      
                      #endregion
      
                      #region Сопровождение и выход из позиции по Take Profit
      
                      if (!IsLastPositionActive) // Если позиции нет
                      {
                          if (signalBuy) // При получении сигнала на вход в длинную позицию
                          {
                              RiskStopLevel = Bars.Close[bar] - StopPunkt; //устанавливаем величину riskStopLevel - чтобы можно было тестировать в режиме "MaxPercentRisk" 
                              BuyAtMarket(bar + 1, "Buy"); // Купить по рынку на открытии следующей свечки
                              orderStopLoss = Bars.Close[bar] - StopPunkt;
                              orderTakeProfit = Bars.Close[bar] + StopPunkt * winLoss;
                              AnnotateBar(orderStopLoss.ToString(PricePattern) + "  :  " + orderTakeProfit.ToString(PricePattern), bar, true, Color.Blue, Color.Yellow);
                          }
                          else if (signalShort) // При получении сигнала на вход в короткую позицию
                          {
                              RiskStopLevel = Bars.Close[bar] + StopPunkt; //устанавливаем величину riskStopLevel - чтобы можно было тестировать в режиме "MaxPercentRisk"
                              ShortAtMarket(bar + 1, "Short"); // Продать по рынку на открытии следующей свечки
                              orderStopLoss = Bars.Close[bar] + StopPunkt;
                              orderTakeProfit = Bars.Close[bar] - StopPunkt * winLoss;
                              AnnotateBar(orderStopLoss.ToString(PricePattern) + "  :  " + orderTakeProfit.ToString(PricePattern), bar, true, Color.Blue, Color.Yellow);
                          }
                      }
                      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
                  }
              }
          }
      }
      
  10. rasswet пишет:

    “Попробовать другие техники сопровождения позиции (особенно трейлинг стопы, например TralingStopParabolic)”
    а есть у вас готовый пример посмотреть?

    • Есть конечно. У меня целый набор таких техник сопровождения и я его постоянно пополняю.

      Собираюсь постепенно здесь в блое все эти техники выкладывать, в надежде что кто-то пришлет по образцу свои торговые техники (и генерации входов и сопровождения позиции).

      Готов обменяться. Вы мне по образцу выложенную, я Вам в обмен одну из своих техник. :-)
      Если не готовы на такой обмен, тогда ждите. Что-же я все техники в комментариях повыложу сразу – о чем дальше-то писать буду??? :-)

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

  11. Alexanr A. пишет:

    Дмитрий, здравствуйте! Не могли бы вы подсказать какая идея лежит в основе входного сигнала CandleElasticity?

  12. olegon11 пишет:

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

    • Генетический оптимизатор – только для лицензионных пользователь. Максимум чем могу поделиться – купоном на скидку при покупке официальной версии. Кому нужно – обращайтесь – 100 долларов скидка по купону.

  13. Максим пишет:

    Здравствуйте Дмитрий,спасибо Вам за код генерации ТР с СЛ,но он для подходит для велслаба 5{пока с ним не знаком},а я изучаю пока 4,и вход в позицию писал в четверке,а как-то можно его переделать.

    • Максим, приветствую. Переделать, конечно можно, но в 4-ке нет тех возможностей для описания и тестирования стратегий, что в 6-ке…

      Попробуйте зарегится и 30 дней бесплатно попользоваться версией 6.3 – почувствуете всю мощь этой системы.

      Код, написанный в 4-ке переделать под код 6-ки можно. Об этом есть официальный ответ службы поддержки Велс-Лаб – вот ссылка:

      А вот наоборот – код из WLD-6 в код WLD-4 переделать можно, я думаю, только вручную. Если ошибаюсь – может кто здесь напишет.

  14. Максим пишет:

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

    • Максим, если хотите – можете прислать письмо через “Контакты” – вверху сайта с тем кодом, который нужно переделать. Я постараюсь помочь, если смогу.

  15. [...] помочь их запрограммировать. Имея под глазами схему генератора МТС для меня (несмотря на то, что я не являюсь [...]

  16. [...] Техника сопровождения (EXIT). Недавно я рассказывал о генераторе механических торговых систем. При этом приводился пример создания техники [...]

  17. Максим пишет:

    Здравствуйте Дмитрий,я Вам прислал письмо через контакты.Можно ли переделать код,чтобы он четко работал по ТП и СЛ.

    • Максим, прошу прощения, но я думал, что Вы не можете переделать код из 4-й версии в 6-ю. И вызвался ВАм помочь.

      Однако у Вас ситуация обратная – ВЫ хотите из кода 6-й версии переделать в старую версию (в 4-ке). Здесь я Вам не помощник, т.к. на 4-ке все идеи, которые на 6-ке написаны написать не могу.

      Извините, что ввел Вас в заблуждение.

  18. Максим пишет:

    Дмитрий я Вам выслал код на четверке,хотел,чтобы Вы посмотрели по сигналам ТП и СЛ,почему у меня выход происходит не по ТП,хотя цена в 60 пунктов проходит,а по СЛ,и поэтому моя сделка получается не прибыльной,как это должно быть,а убыточной.

  19. Максим пишет:

    Здравствуйте Дмитрий,выслал код на 6,помогите ,пожалуйста, исправить ошибки.

  20. Gerig пишет:

    Добрый день, Дмитрий! Я немного изменил в вашей стратегии выход по стоп-лосс. Я сделал его следящим, если позиция оказалась в нужном направлении, то стопы переводятся в безубыток.
    Тестировал на таймфрейме 1 минута. Результат порадовал.
    Код стратегии:

    using System;
    using System.Drawing;
    using WealthLab;
    using WealthLab.Indicators;
     
    namespace MyStrategies
    {
     
    	class CCI_ADX_percent_Levels : WealthScript
    	{
    		const int PeriodsInDay = 9; // Кол-во интервалов за сессию
     
    		#region Объявление параметров торговой системы
     
    		//  StrategyParameter _atrDailyPeriod; // Дневной период ATR
    	    
    		StrategyParameter _periodADX; // период индикатора ADX
    		StrategyParameter _periodCCI; // период индикатора CCI
    		StrategyParameter _cciLevel; // Уровень, забираясь выше которого CCI генерирует сигнал на вход в лонг (зеркально для короткой)
    		StrategyParameter _adxLevel; // Если ADX находится выше этого уровня, то тренд уже развился и мы в него "не впрыгиваем"
    		StrategyParameter _LO; // Уровни low стопов из позиции long
    		StrategyParameter _HI; // Уровни high стопов из позиции short
    		#endregion
     
    		#region Инициализация параметров торговой системы
     
    		public CCI_ADX_percent_Levels()
    		{
     			_periodADX = CreateParameter("ADX Period", 127, 10, 200, 1);
    			_periodCCI = CreateParameter("CCI Period", 98, 10, 200, 1);
    			_cciLevel = CreateParameter("CCI Level", 100, 70, 200, 1);
    			_adxLevel = CreateParameter("ADX Level", 20, 10, 50, 1);
    			_LO = CreateParameter("ChanLO Period",5,2,200,20);
    			_HI = CreateParameter("ChanHI Period",5,2,200,20);
    		}
     
    		#endregion
     
    		protected override void Execute()
    		{
    			int firstValidValue = 1; // Первое значение свечки, при котором существуют все индикаторы
     
    			#region Индикаторы
     
    			// Индикатор ADX:
     
    			int periodADX = _periodADX.ValueInt;
     
    			DataSeries adx = ADX.Series(Bars, periodADX);
    			ChartPane ADXPane = CreatePane(20, false, true); // Область для отрисовки ADX высотой 20%, ниже графика, с сеткой
    			PlotSeries(ADXPane, adx, Color.Blue, LineStyle.Solid, 2); // отрисовка ADX
    			firstValidValue = Math.Max(firstValidValue, adx.FirstValidValue + 1);
     
    			// Индикатор CCI:
     
    			int periodCCI = _periodCCI.ValueInt;
     
    			DataSeries cci = CCI.Series(Bars, periodCCI);
    			ChartPane CCIPane = CreatePane(20, false, true); // Область для отрисовки CCI высотой 20%, ниже графика, с сеткой
    			PlotSeries(CCIPane, cci, Color.Red, LineStyle.Solid, 2); // отрисовка CCI
    			firstValidValue = Math.Max(firstValidValue, cci.FirstValidValue + 1);
     
    			int cciLevel = _cciLevel.ValueInt; //забираем значение из параметра
    			int adxLevel = _adxLevel.ValueInt; //забираем значение из параметра
     
    			#endregion
     
    			#region Переменные для обслуживания позиции
     
    			bool signalBuy = false, signalShort = false; // Сигналы на вход в длинную и короткую позиции
    		 
    			#endregion
     
    			#region Представление цен с необходимой разрядностью для отображения ордеров
     
    			string PricePattern = "0.";
    			for (int i = 0; i &lt; this.Bars.SymbolInfo.Decimals; i++)
    				PricePattern += &quot;0&quot;;
     
    			#endregion
     
    			PlotStops(); // Отображать уровни, на которых были попытки выхода по S/L
     
    			for (int bar = firstValidValue * 5; bar  adx[bar - 1]; // индикатор adx растет
    				signalBuy = signalBuy &amp;&amp; cci[bar] &gt; cciLevel; //индикатор CCI забрался выше установленного уровня
    				signalBuy = signalBuy &amp;&amp; adx[bar]  adx[bar - 1]; // индикатор adx растет
    				signalShort = signalShort &amp;&amp; cci[bar] &lt; -1.0 * cciLevel; //индикатор CCI забрался ниже установленного уровня
    				signalShort = signalShort &amp;&amp; adx[bar] &lt; adxLevel; //индикатор ADX не превышает установленного уровня (тренд находится в начале)
    				signalShort = signalShort &amp;&amp; (!IsLastPositionActive || LastActivePosition.PositionType == PositionType.Long); // генерируется когда не в короткой позиции
     
    				#endregion
     
    				#region Сопровождение и выход из позиции по Take Profit
                   
    				Position p = LastPosition;
    				
    				if (!IsLastPositionActive) // Если позиции нет
    				{
    					if (signalBuy) // При получении сигнала на вход в длинную позицию
    					{
    						BuyAtMarket(bar + 1, &quot;Buy&quot;); // Купить по рынку на открытии следующей свечки
    					
    					}
    					else if (signalShort) // При получении сигнала на вход в короткую позицию
    					{
    				
    						ShortAtMarket(bar + 1, &quot;Short&quot;); // Продать по рынку на открытии следующей свечки
    					
    					}
    				}
    				else // Если позиция есть
    				{
    					if (LastActivePosition.PositionType == PositionType.Long) // Для длинной позиции
    					{
    					    SellAtStop(bar + 1, p, Lowest.Value(bar, Low, _LO.ValueInt), &quot;Stop_long&quot;);// Выход по LO
    						SellAtLimit(bar + 1, p, Highest.Value(bar, High, _HI.ValueInt), &quot;tk_lg&quot;); // Попробовать выйти по тайкпрофит для лонга
    					}
    					else // Для короткой позиции
    					{
    						CoverAtStop(bar + 1, p, Highest.Value(bar, High, _HI.ValueInt), &quot;Stop_short&quot;); // Выход по HI
    						CoverAtLimit(bar + 1, p, Lowest.Value(bar, Low, _LO.ValueInt), &quot;tk_sh&quot;); // Попробовать выйти по тайкпрофит для шорта
    					}
    				}
     
    				#endregion
    			}
    		}
    	}
    }
    
  21. Максим пишет:

    Дмитрий, я так понял, что в данной системе 6 (!) оптимизируемых параметров. Вопрос – не подонка ли это под историю, так как чем больше количество переменных используется, тем точнее возможно описать любую кривую?

  22. Эдуард пишет:

    Дмитрий, здравствуйте.
    Ситуация в следующем: стратегию, приведенную Вами в этой статье решил разбить на две техники (входа и выхода). Учитывая, что раздел Сопровождения торговой позиции содержит элементы техники как входа, так и выхода, то код пришлось несколько изменить. Для проверки из получившихся техник решил вновь собрать систему. В результате в Wealth-Lab (кстати спасибо за предоставленную возможность купить его со скидкой) код компелируется, но при запуске стратегии выдает ошибку: “RunTime error: Ссылка на объект не указывает на экземпляр объекта”. В чем может быть ошибка. Готов скинуть Вам на почту код. Заранее благодарю.

    • Обычно такая ошибка появляется в тот момент, когда пытаетесь обратиться к тому объекту, который еще не создан или не существует. К примеру, пытаетесь что-то сделать с объектом “позиция”, когда такого объекта еще не существует. Но чтобы разобраться, конечно, код нужно смотреть. Или можете Wealth-Lab состыковать с Visual Studio и по шагам потихонько пройти всю стратегию – тогда точно увидите тот момент, когда наступает ошибка…

  23. Эдуард пишет:

    Спасибо Дмитрий за наводку – нашел ошибку ))). Но возникло все же еще 2 вопроса: 1) можно ли состыковать WealthLab и VS Express 2012; 2) загнал в Велс Вашу стратегию (из этой статьи) и то что у меня получилось в результате переделки. На тестировании (фьюч на RTS, 15 мин. за период 01.09-30.09.12) по оригиналу получается 3 сделки, по переделанному варианту 6 . Посмотрел 3 выпавших сделки – вроде подходят под условия входа в позиция, тогда почему они выпадают из оригинала? Хэлп лиз. Куда можно скинуть переделанный вариант стратегии?

    • Состыковать точно можно. Я знаю, что Игорь Чечет для участников нашего курса специальное видео записал в качестве бонуса – где подробно показал, как можно связать Wealth-Lab с версией Express (а не только с Pro) – как я показывал. Можете у него уточнить – где взять это дело. По поводу кода – можете выслать мне, воспользовавшись формочкой “Контакты” на этом блоге.

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