Заметка

Обзор торговых роботов, изготовленных в 2012-м, и новые подходы в 2013-м

  1  

В 2012-м — начале 2013-го года я выкладывал на robostroy.ru несколько торговых систем, которые предлагал обсудить посетителям сайта. Теперь, спустя год, интересно посмотреть, какие результаты они показали и посмотреть за счет чего они могли отработать лучше. Так же поделюсь своими наработками по написанию роботов в программе Tradematic Trader

1. Стратегия "цены растут — покупаем, цены падают — продаем", которая была опубликована 15 мая 2012 года. Стратегия была изготовлена с помощью Мастера стратегий в программе Tradematic Trader: в коде ничего не делалось — правила входа и выхода были выбраны из тех, вариантов, что предлагал Tradematic. В случае последовательного роста цены на трех часовых барах — покупка, в обратной ситуации — короткая продажа. Тейк-профит после оптимизации получился 2,4% для лонга и 2% для шорта. Стоп-лоссы 0,6% и 1,1% соответственно. Код стратегии вложением (Стратегия 1).

После оптимизации у нас получилась вот такая картинка (все результаты буду приводить с комиссией 0,06% на сделку)

По прошествии полутора лет она кривая капитала приобрела такие очертания

Почти сразу робот ушел в просадку, из которой ему удалось выйти к августу 2013 года. С началом осени кривая капитала снова устремилась вниз. В итоге с апреля 2012 года робот отдал рынку в районе 20%. Интересно посмотреть, можно ли выровнять результаты с помощью новой оптимизации четырех параметров — двух тейк-профитов и двух стоп-лоссов или сам паттерн на этом отрезке в принципе нежизнеспособен. Повторим оптимизация с теми же условиями: для тейк-профитов перебираем значения от 2 до 4 процентов с шагом 0,1. Для стоп-лоссов ищем оптимальные значения в диапазоне от 0,5 до 2 процентов с шагом 0,1 теперь на истории с 2008 года.

Попарная оптимизация тейка и стопа для лонгов и шортов с начала 2008 года по сегодняшний день позволяет получить вот такую картинку:

 

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

2. Стратегия "направленное движение цены + рост объема" В этом стратегии так же с помощью мастера стратегий к первой стратегии были прикручены объемы в виде условия

Volume [bar] > Volume [bar-1] + Volume [bar-2]

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

Мод

 Модифицировав условия на вход в короткую позицию (

Volume [bar] > Volume [bar-1] & Volume [bar-1] > Volume [bar-2] - последовательный рост объема

) получали такую кривую капитала:

Повторный тест стратегии выдает такие результаты для первого и второго условия соответственно:

Оба варианта стратегии с объямами за полтора года ничего не заработали и не потеряли при этом были значительные просадки. Коды стратегий вложением (Стратегия 2, Стратегия 2.1)

3. Торговая система на основе пробоя ценового канала В заметке от 31 мая 2012 года рассматривалась стратегия на основе пробития ценового канала. Для входа в позиции параметр ценового канала равен 8, для выхода — 7. Для улучшения результат был использован временной фильтр, который вызвал нарекания в комментариях. Шорты стратегия закрывает с 11.00 до 16.00, лонги с 14.00 и до конца сессии (вложение Стратегия 3).

Кривая из прошлого:

Тут картина действительно катастрофическая. Повторное тестирование стратегии выводит вот такой результат

Отказ от временного фильтра картину не улучшает

Основа стратегии — пробой ценового канала с использованнными параметрами 8 баров на вход, 7 баров на выход на 15 минутках была, по всей видимости, не слишком хороша. Удивительно, что с помощью оптимизации этих двух параметров удалось в 2012-м  получить приличную кривую капитала.

4. Стратегия "последовательное движение цены + время входа" заметка от 7 июня 2012 года

Здесь я оптимизировал стратегию из первой заметки по времени входа (код вложением Стратегия 4). Оптимизиция на истории выдала мне рекомендацию входить в лонг только в 15.00, а в шорт только в 14.00. В результате удалось получить такую картину.

В целом стратегия отработала примерно так же, как ее первая версия. Движение вниз до 2013 года, взлет в первой половине 2103-го и новая просадка заканчивающейся осенью. Картинка ниже:

 

Оптимизация значений временного фильтра с 2008 года по сегодняшний день выделяет в качевте оптимальных те же значений 15.00 для входа в лонг, 14.00 для входа в шорт.

5. Стратегия "Вход относительно открытия свечей старших таймфреймов" от 23 августа 2012 года

Перетестируем вторую весию стратегии, которая позволяла получить более высокие результаты (вложением Стратегия 5). Напомню условия:

Вход в лонг — часовая свеча закрывается выше открытий текущих дня и месяца.

Вход в шорт — часовая свеча закрывается ниже открытий текущих дня и месяца.

Сигнал по первой дневной свече не отрабатываем — ждем второй.

Выходим по тейк-профиту и стоп-лоссу. Значения оптимизируем, оптимально для лонга - 2,2% и 1,3%, для шорта - 2,2% и 1,1%.

Картинка из прошлого:

<

Новое тестирование покаызвает

Вывод — стратегия сливает и оптимизация тейков и стопов тут вряд ли поможет.

6. Робот на простом паттерне заметка от 16 января 2013 года

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

(Math.Abs(Close[bar-3]-Open[bar-3])>(Math.Abs(Close[bar]-Open[bar])+Math.Abs(Close[bar-1]-Open[bar-1])+Math.Abs(Close[bar-2]-Open[bar-2])+Math.Abs(Close[bar-6]-Open[bar-6])+Math.Abs(Close[bar-5]-Open[bar-5]))&Close[bar-3]> Open[bar-3])

Мы ловим белую свечу, величина тела которой больше суммы двух предыдущих, а также больше суммы трех последующих. Описать это можно так — цены были в боковике, совершили движение вверх и снова легли в боковик. (Код стратегии вложение Стратегия 6) Стратегия работает только в лонг, входим на 50% счета по каждой из бумаг. Инструменты: Сбербанк, Сбербанк-пр, Транснефть и ХолМРСК — теперь Россети.

Для выхода из позиций использовался скользящий стоп со значением 2%. Результат был таким:

В 2013-м роботу удалось заработать около 2%. Кривая ниже

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

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Из шести приведенных систем в работе использую идеи первой и шестой.

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

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

Временной фильтр на вход в позиции тоже использую. В большинстве роботов он симметричен для лонгов и шортов — например, не торгую в первый и последний час. Но есть системы, где фильтр не симметричен: дает больше возможностей для входа в лонг, чем для входа в шорт. Робот с таким фильтром отработал 2013 год лучше, чем его вариант без такого фильтра. На истории результаты тоже стабильнее. Если рынки по статистике все же растут, то незначительный дисбаланс в пользу лонгов может иметь смысл? Как считаете?

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

1. if ((LastPosition.NetProfitAsOfBarPercent(bar)-LastPosition.MFEPercentAsOfBar(bar)) < -parameter1.Value)

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

2. if ((p.NetProfitAsOfBarPercent(bar) < -parameter1.Value) || (p.MFEPercentAsOfBar(bar) > parameter2.Value) && ((p.NetProfitAsOfBarPercent(bar) — p.MFEPercentAsOfBar(bar)) < -parameter3.Value))

Убыток фиксируется с помощью жесткого стоп-лосса. Скользящий стоп подклчюается при достижении определенного размера профита.

3. if ((p.NetProfitAsOfBarPercent(bar) > parameter1.Value) || ((p.NetProfitAsOfBarPercent(bar) — p.MFEPercentAsOfBar(bar)) < -parameter3.Value))

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

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

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

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using TradeMatic;
using TradeMatic.Indicators;

namespace ScriptNamespace
{
 class MyScript : Script
 {
  private StrategyParameter parameter0;
  private StrategyParameter parameter2;
  private StrategyParameter parameter3;
  private StrategyParameter parameter5;
  private StrategyParameter parameter1;
  private StrategyParameter parameter12;
  private StrategyParameter parameter14;
  private StrategyParameter parameter15;
  private StrategyParameter parameter16;
  private StrategyParameter parameter17;

  public MyScript()
  {
  

   parameter1 = CreateParameter("Параметер1", 1.9, -1, 3, 0.1);
   parameter2 = CreateParameter("Параметер2", 1.9, -1, 3, 0.1);
   parameter3 = CreateParameter("Параметер3", 1.9, 1, 3, 0.1);
  }
  
  // Размер позции делаем динамическим: в зависимости от заданных условий определяем каким процентом средств от счета будем оперировать
  public override PositionSize CalculatePositionSize(Position p, double cash, double equity)
  {
     
   return new PositionSize(PositionSizeMode.PercentOfEquity, (double)p.Tag);
   
  }
  
  // В одной стратегии используем несоклько подстратегий, чтобы сделать стратегию более стабильной
  public int MarketPositionBySignal(string signal)
  {
   foreach(Position pos in ActivePositions)
   {
    if(pos.EntrySignal.Contains(signal))
    {
     if (pos.PositionType == PositionType.Long)
      return 1;
     else if (pos.PositionType == PositionType.Short)
      return -1;
    }
   }
           
   return 0;
  }
       
  public Position GetPositionBySignal(string signal)
  {
   foreach(Position pos in ActivePositions)
   {
    if(pos.EntrySignal.Contains(signal))
    {
     return pos;
    }
   }
           
   return null;
  }

  double S = 49;
  double SS = 49;
  
  
  public override void Execute()
  {
   
   // Вызываем внешние инструменты, которые используем для анализа ситуации. Трейдматик анализирует каждый инструмент, который используется
   в стратегии по отдельности. Чтобы посмотреть, перед принятием решения, что происходит с другим инструментом, нужно вызвать инструмент в качестве
   внешнего
   
   
   Symbol SBER = GetExternalSymbol("Сбербанк", true);//
   Symbol GAZP = GetExternalSymbol("ГАЗПРОМ ао", true);//
   Symbol GMKN = GetExternalSymbol("ГМКНорНик", true);//
  
   
   // Если по внешним сиволам, которые используем для анализа, сделок делать на нужно, используем этот блок
   
   if(Symbol.SymbolName == "Сбербанк")
   {
    return;
   }
   if(Symbol.SymbolName == "ГАЗПРОМ ао")
   {
    return;
   }
   if(Symbol.SymbolName == "ГМКНорНик")
   {
    return;
   }
   
   for (int bar = 5; bar < Symbol.Count; bar++)
   {
    
    
    if (MarketPositionBySignal("1") == 1)
    {
     Position p = GetPositionBySignal("1");
     
     if (Условия на выход из длинной позиции для Стратегии 1)
     {
      SellAtClose(bar, p, "1");
     }
    }
    
    if (MarketPositionBySignal("2") == 1)
    {
     
     Position p = GetPositionBySignal("2");
     
     if (Условия на выход из длинной позиции для Стратегии 2)
     {
      SellAtClose(bar, p, "2");
     }
    }
   
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    
    if (MarketPositionBySignal("1") == -1 )
    {
     Position p = GetPositionBySignal("1");
     
     if (Условия на выход из короткой позиции для Стратегии 1)
     {
      CoverAtClose(bar, p, "1");
     }
    }
    
    if (MarketPositionBySignal("2") == -1)
    {
     Position p = GetPositionBySignal("2");
     
     if (Условия на выход из короткой позиции для Стратегии 2)
     {
      CoverAtClose(bar, p, "2");
     }
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    
    
    if (MarketPositionBySignal("1") == 0)
    {
     if (Условие на вход в лонг для Стратегии 1)
     {
      Position p = GetPositionBySignal("2");
     
       BuyAtClose(bar, "1");
      
      if (Уловия для определиня размера позиции)
      {
       S = 49;
      }
      else
      {
       S = 33;
      }
       
       // Здесь определяем с помощью переменной S процент от счета, которым входим в сделку для Стратегии 1
       LastPosition.Tag = S;
      
     }
    }
    
    if (MarketPositionBySignal("2") == 0)
    {
     if (Условие на вход в лонг для Стратегии 2)
     {
      BuyAtClose(bar, "2");
      
      if (Уловия для определиня размера позиции)
      {
       SS = 49;
      }
      else
      {
       SS = 33;
      }
      
      // Здесь определяем с помощью переменной SS процент от счета, которым входим в сделку для Стратегии 2
      LastPosition.Tag = SS;
      a = 0;
     }
    }
     
    
    ////////////////////
    
   
    
    if (MarketPositionBySignal("1") == 0)
    {
     if (Условие на вход в шорт для Стратегии 1)
     {
       ShortAtClose(bar, "1");
      
      if (Уловия для определиня размера позиции)
      {
       S = 49;
      }
      else
      {
       S = 33;
      }
      
      // Здесь определяем с помощью переменной S процент от счета, которым входим в сделку для Стратегии 1
       LastPosition.Tag = S;
     }
    }
    
    if (MarketPositionBySignal("2") == 0)
    {
     if (Условие на вход в шорт для Стратегии 2)
     {
      ShortAtClose(bar, "2");
      
      if (Уловия для определиня размера позиции)
      {
       SS = 49;
      }
      else
      {
       SS = 33;
      }
      
      // Здесь определяем с помощью переменной S процент от счета, которым входим в сделку для Стратегии 2
      LastPosition.Tag = SS;
     }
    
    }
   }
  }
 }
}

P.S.

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

Прикрепленные файлы

·   Коды стратегий.rar

Комментарии

autosignals — 4 декабря 2013 г.

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

0 +

ALendi — 4 декабря 2013 г.

autosignals, так попробуйте сделать так, как в шаблоне. Размер определяется для текущей сделки

0 +

autosignals — 4 декабря 2013 г.

Да, уже нашел ошибку у себя, спасибо.

0 +

Написать комментарий

Чтобы написать комментарий, необходимо авторизоваться.

Написать администратору