Секреты TSLab | Торговые роботы | События
30 Янв

Торговый робот “Хомяк”

Осенью 2015 года нами был разработан и отправлен в бой торговый робот “Хомяк”. Почему “Хомяк”? Так получилось, что я решил для названий выбирать животных, а данный торговый робот отличается способностью набивать щеки кучей позиций и постепенно от них избавляться. После периода полевых испытаний, он зарекомендовал себя как отлично работающий и дающий профит, поэтому статья о нем и использованных технических решениях.

Торговый робот “Хомяк”. Техническое задание.

Торговый робот реализован на заказ.

Итоговая цена разработки: 22000 рублей.

Отличный бот за не большие деньги. Раньше, данный робот был выполнен в визуальном редакторе и насчитывал в себе более 2-ух тысяч блоков, что было просто жутко не удобно с постоянными лагами в вижуале и большим пересчетом скрипта (около 100 мс). Наконец, я устал от постоянных тормозов собрался с мыслями и написал ТЗ, робота сразу решил сделать с адаптацией под большие объемы.
Проблемы по ходу разработки тоже возникали, но не критические. Самый серьезный баг который был слил мне 50к за пару минут. Пару часов споров с разработчиком, и на следующий день я получаю нового бота. Робот работает как часы, быстро, без глюков, вмешательство в бота нужно только на экспирациях, и то что бы только контракты поменять) В общем роботом довольны, все требования выполнены. Робот себя окупил в первый же день полноценной работы.

Заказчик

Исходное ТЗ предполагало переложить реализованный в визуальном редакторе алгоритм на TSLab API. При этом было необходимо улучшить его характеристики и возможности и обеспечить бесперебойную работу (избавиться от проблемы пропущенных входов/выходов).

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

Торговый робот Хомяк

Рисунок 1. Базовая логика алгоритма.

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

  1. Избавиться от проблемы пропущенных входов и выходов, работать должно без вмешательства человека.
  2. Неограниченное число уровней, регулируемое переменной.
  3. На каждом уровне вход не должен приводить в большому проскальзыванию, то есть обеспечить вход по хорошей цене хорошим сайзом.
  4. Все позиции всегда должны открываться на заданный объем. Не должно быть частичных позиций.
  5. При старте, если имеем несколько пробитых уровней, робот должен плавно набирать позицию до необходимой, а не лупить сразу получая большое проскальзывание. Аналогично, он должен плавно позиции закрывать если мы возле экспирации.
  6. Защитить алгоритм от биржевых сбоев, когда стаканы и другие биржевые данные приходят от брокера с ошибками.
  7. Обеспечить возможность тестирования.

Самые проблематичные элементы – это 1, 3, 4. Если использовать обычную модель построения алгоритма, то эти пункты невозможно реализовать, поэтому необходимо было выбрать нужную модель, как мы это делали когда разрабатывали торговый робот Бегемот.

Выбор модели скрипта.

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

Минусы модели ISecurityRt:

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

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

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

Что было сделано чтобы обойти эти проблемы:

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

В общем и целом, все задачи были решены. Давайте посмотрим как это делалось.

Реализация

Неограниченное число уровней

Данный пункт НЕВОЗМОЖНО реализовать в визуальном редакторе, так как для каждого уровня у нас будет несколько позиций и для каждой из них нужно заранее прописать все необходимые блоки. Каждый уровень разрастается в кучу блоков и таких куч будет очень много. Как следствие, подобные алгоритмы разрастаются в 1000 а то и более блоков, как изображено на картинке ниже.

Торговый робот Хомяк

Рисунок 2. Скрипт на 1000 блоков.

Работать с таким скриптом достаточно тяжело, хотя бы потому что все это начинает тормозить. Да и шевелиться он будет все медленнее с добавлением каждого нового уровня. В TSLab API  все решается простым циклом.

Проблема кажется простой, но есть нюанс. Необходимо было обеспечить вполне четкую очередность открытия и закрытия позиций, коих могло одновременно быть больше 50 и вполне реально 80, а так же, обеспечить временную задержку между двумя операциями открытия/закрытия. Для маркировки позиций была выбрана обычная для меня схема “сигнал+номер поз+номер порции”. LE_0_1, LE_0_2 – примеры сигналов. Первая цифра это номер позиции = номер уровня. Второе число это номер порции на данном уровне. Если открывать будем на уровне позиции с номерами порций от 0 до Х, то закрывать нужно так же, от 0 до Х, то есть в таком же порядке. При этом, уровни закрываются наоборот от большего к меньшему. И это правило соблюдается везде. Небольшой рисунок поясняющий это:

Торговый робот Хомяк

Рисунок 3. Порядок открытия и закрытия позиций.

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

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

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

 //SE_2_2
 //SE_2_1
 //SE_2_0
 //SE_1_2
 //SE_1_1
 //SE_1_0
 //--------------------
 //LE_1_0
 //LE_1_1
 //LE_1_2
 //LE_2_0
 //LE_2_1
 //LE_2_2
 var upLevelsOpenSignals = new string[maxLevels * portionPerLevel];
 var downLevelsOpenSignals = new string[maxLevels * portionPerLevel];
 var upLevelsCloseSignals = new string[maxLevels * portionPerLevel];
 var downLevelsCloseSignals = new string[maxLevels * portionPerLevel];
 var l = 1;
 var portion = 0;
 for (int i = 0; i < upLevelsOpenSignals.Length; i++)
 {
     var openPortion = portion;
     var closePortion = portionPerLevel - 1 - portion;
     upLevelsOpenSignals[i] = ParsedComment.MakeComment("SE", l, openPortion);
     downLevelsOpenSignals[i] = ParsedComment.MakeComment("LE", l, openPortion);
     upLevelsCloseSignals[i] = ParsedComment.MakeComment("SE", l, closePortion);
     downLevelsCloseSignals[i] = ParsedComment.MakeComment("LE", l, closePortion);
    
     // 0,1,2,3 => 4
     portion++;
     if (portion < portionPerLevel)
         continue;

     portion = 0;
     l++;
 }

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

Задержка между операциями открытия/закрытия позиции

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

if (operDone)
{
    StoreNow(ctx, _cacheKey); // сохранить время операции
    goto charts;              // сразу переходим к отрисовке графики не делая больше ничего
} 

Да, применяется оператор goto и не нужно тыкать пальцем :). В некоторых случаях его применение вполне оправдано и он не портит код.

Избавление от пропущенных входов/выходов

Это очень просто. Мы удаляем из кода торговый цикл. Работаем всегда ТОЛЬКО по последнему бару. Если следовать этому простому правилу, то пропусков входа и выхода не будет. К тому же, мы используем только рыночные ордера, что ликвидирует проблему частичных позиции, так как маркет ордер всегда исполняется.

Пропуск входа/выхода появляется только тогда, когда на баре был сгенерирован сигнал, но в реале сделки не было. Если сигнал всегда генерировать на самом последнем баре и по рынку, то пропусков не будет никогда. Это НЕВОЗМОЖНО реализовать в визуальном редакторе, но легко делается в TSLab API.

Защита от сбоев и ошибочной генерации сигналов

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

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

 var key = "__scriptStartDate__";
 var cache = ctx.LoadObject(key);
 if (cache == null)
     ctx.StoreObject(key, DateTime.UtcNow);

 cache = ctx.LoadObject(key);
 var startDate = (DateTime) cache;
 if (DateTime.UtcNow - startDate < TimeSpan.FromSeconds(startDelay))
 {
     ctx.Log("пауза перед стартом скрипта", new Color());
     return;
 }

Снова используется кэш скриптов. Очень полезная штуковина.

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

Итоги

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

По итогам эксплуатации торговый робот “Хомяк” показал изображенные ниже результаты на разных  инструментах. Смотреть нужно на линию Зафиксировано, ибо она отражает реальный результат.

Торговый робот Хомяк

Рисунок 4. Эквити инструмент 1.

Торговый робот Хомяк

 Рисунок 5. Результат инструмент 1.

Торговый робот Хомяк

 Рисунок 6. Эквити инструмент 2.

Торговый робот Хомяк

Рисунок 7. Результат инструмент 2.


comments powered by HyperComments

Alexandr ♂
2016-01-30 17:56:39
На экспирации просадка фиксируется и остаётся П/У по зеленой ?
ra81
2016-01-31 19:13:05
на экспирации происходит смена контракта и по факту да, фикс просадка а потом на другом она закрывается в профит. Так что ее как бы нет.
Alex Golubev
2016-01-31 21:28:07
Родион , действительно есть такая стратегия , торгую её руками :)) , так как пока что не владею программированием на таком уровне как Вы . Действительно , средний уровень есть , но я еще использую некоторый показатель который доступен только в Квике .
ra81
2016-02-01 10:02:19
я полагаю из квика любые показатели можно перетащить в тслаб :). да и руками вести 50 позиций сложновато будет :)
Alex Golubev
2016-02-01 10:05:00
Совершенно верно ! в TSLab очень многое возможно .
Alex Golubev
2016-02-01 10:06:43
да , 50 позиций будет сложновато . у меня всего лишь 3 контракта Ri :))
Alexandr ♂
2016-02-02 10:59:54
Но залипшие ближе к началу позы не переоткрываются ведь и когда цена идет обратно к ним, не фиксируется по ним прибыль, ведь их там уже нет. Или не такая логика?
ra81
2016-02-02 15:30:18
они есть. просто набраны уже в новом инструменте. и естественно по хорошей цене ведь берем по той что была а не по той что должна быть на уровне. При начале нового контракта всегда происходит набор позиции автоматом до положенного уровня.
Amon53
2016-03-23 10:04:29
интересно конечно. я в этом направлении экспериментирую. есть реализованный алгоритм похожего типа, только проще в реализации.В статье как то обходится проблема просадки. Не верится что ее нет. В рынке есть случайная составляющая которая всегда найдет вариант чтобы утопить алгоритм. Нет информации как ведет себя этот алгоритм при флете.
ra81
2016-03-23 10:09:50
Ну вообще статья особо и не раскрывает даже суть алгоритма :). Задача была не в этом и в реализации. Приемы и хитрости которые можно перенять и применить.
Amon53
2016-03-23 10:35:50
Да, согласен. Люди хотят похвастаться:=).Графики трудночитаемые, особенно для тех кто кроме МТ; не знает другого ПО. А я завидую тому что мой уровень программиста явно ниже чем их. :=(. И объеденить с ними усилия не могу, потому что хочу стать мильенщиком в одиночку.:=). Думаю в этом роботе есть проблемы которые выявятся при эксплуатации.У моего робота в зависимости от настроек доходность можно установить до 35000% годовых. при МО около 1000. но всегда есть один вариант из этих тысяч который обнулит депозит. Реальная цель достижимая и проверенная 30% в месяц при некатастрофических просадках. Ну и за 22000 руб стать мильенщиком....не верю:=)
ra81
2016-03-23 10:58:49
проблем в эксплуатации нет. Все работает уже который месяц. Никто не ставит себе цели 30% в месяц ибо эта цифра слегка неадекватная. Ну и цена невелика потому что опыт большой и многие вещи делаются быстро благодаря наработкам. Вот и все. Отдадите делать кому то другому - возможно они захотят 100 000 и сделают хуже. Все зависит от жадности отдельного взятого разработчика.
Amon53
2016-03-23 11:10:31
прошу парбону за ошибку -3500%. Хотя на таких уровнях это не важно :=)
Amon53
2016-03-23 12:05:49
мне интересно как Ваш советник проходит ситуацию "флэт", какова максимальная просадка. 30 процентов складываются из 10 при запуске 3-х советников с разными настройками.График прибыли представляет из себя прямую линию с наклоном.На этой линии есть выступы вниз - просадки. При разных настройках у разных графиков эти просадки не совпадают по времени. Сразу оговорюсь, пока идут эксперименты, и не факт что в реале будет все так же хороша. Но в алгоритме также не используются никакие индикаторы, а это предполагает что неважно какой сигнал используется при тестировании.Идеальным был бы не исторические данные а случайные. Аналог "розового шума". Тогда результат тестирования был бы абсолютно точен. К вашему советнику есть вопросы -как он пересиживает свопордера -как реквоты. При такой плотности сетки это должно быть проблемой -как выполняются требования брокера на объем и количество открытых ордеров.
Denis Gabaydulin
2016-03-28 11:30:37
Вопрос про tslab api. А правильно ли я понимаю, что если у меня в скрипте открытие позиций только по рынку, то галочка "открываться лимитными заявками" не работает? И на проскальзывание пофиг?
Denis Gabaydulin
2016-03-28 11:45:35
По алгоритму. У меня тоже есть похожий. Здесь вся изюминка в том чтобы правильно выбрать mean revertion инструменты, а также по возможности использовать опционный хедж от больших просадок.
ra81
2016-03-28 16:11:43
Если есть много вопросов, то задавать их стоит уже не мне. Переживает вполне себе нормально. Вы опять забыли что здесь описана технология, а не логика. Логика есть страшная тайна :)
ra81
2016-03-28 16:42:48
Какая галочка про лимитные заявки? Она кажется для тейков. Вы уж поточнее вопросы задавайте :)
ra81
2016-03-28 17:46:14
Ну алгоритм не такой элементарный но базис изложен верно. В общем и целом он много где изложен. Опционного хеджа нет. Но конечно придумать можно разные хитрые ходы. Тут вопрос был в реализации. Обычно такое не работает стабильно. Задача была сделать чтобы как в танке.
Denis Gabaydulin
2016-03-29 11:15:30
В настройках торгового агента.
Amon53
2016-04-01 19:43:55
Да, "у нас есть такие приборы...но мы вам о них не расскажем" Я с этого алгоритма начинал свою работу. Она по сути основана на законах статистики. Беда в том что всегда есть случайная срставляющая которая пагубно сказывается на алгоритме. Борьба с ней в случае мартингейла обычная- большой пополняемый депозит. Я от этого алгоритма отказался, и разработал новый на его базе. Теперь программа разрослась до 1500 строк. И совсем на дедушку не похожа:=) Что касается Вашего алгоритма то мне показалось что его убивает движение рынка в виде например тренда с откатами типа зубьев. На флете алгоритм в принципе неэффективен. Если Вы решили эти проблемы, то я рад за вас . Значит и я на верном пути:=)
ra81
2016-04-04 21:48:06
да опция работает только для условных заявок. для маркет ордеров не работает
ra81
2016-04-04 23:20:54
верно. системе все равно куда идти лишь бы болтало туда сюда
Amon53
2016-04-14 19:38:02
ценное замечание!Это говорит что робот торгует волатильностью. Но опять повторяю-при очень маленьких колебаниях нарастаеют убытки. Как минимум от спреда. Увеличение горизонта событий за счет например увеличения шага сетки приводит к тому что час слива переносится на будущее, но не отменяет его. Советую не жадничать и почаще выводить средства. Чтобы к моменту слива сохранить прибыль. В общем на моем собственном опыте основанном на работе подобных алгоритмов надо очень тщательно их тестировать. И если ваш советник создан за два месяца, то это значит что у Вас большой опыт, либо впереди большие неожиданности.
ra81
2016-04-14 19:45:09
неожиданности они бывают у тех кто прошел какой то псевдокурс и там ему надавали "зарабатывающих роботов". А у нас все посчитано :)
Amon53
2016-04-18 15:56:13
Все выглядит очень хорошо, но вот результаты указанные в таблице вызывают вопросы. Например откуда взята доходность за год, если робот работает пару- тройку месяцев? Похвастаюсь своим результатом на истории. Без оптимизации :=)
ra81
2016-04-18 18:03:57
Спросите у математики как идет расчет доходности за год. Да и вообще на нее смотреть не стоит.
Amon53
2016-04-18 18:56:29
И я о том же. Если за день прибыль 10 прОцентов, то сколько это будет ежели приумножить на 365 дён в году? По такой логике китайцы во времена Большого Скачка устанавливали планы по производству зерна. Сажали в горшок семена, потом умножали на посевную площадь. Но меня не юмор интнресует, а ваше мнение по поводу представленной мною картинке. Судя по всему вы люди опытные. В моем роботе можно настройками менять результаты. Увеличивать прибыль и естественно просадку. есть экспериментальные варианты в которых просадки увеличиваются медленнее чем рост прибыли. Моя цель иметь просадку в пределах 10 % и прибыль 30 % годовых в расчете простого увеличения числа роботов с разными настройками до трех и в результате 100% годовых. Денег лишних у меня нет, потому меня больше волнуют просадки и риск. Есть вариант настроек с режимом разгона депозита. В общем исследовательской работы полно.
ra81
2016-04-18 19:04:18
это вопрос формирования портфеля. К данному боту не имеет никакого уже отношения. Отдельная большая тема как и что. Методик куча. На сайте есть статья где предложена одна из простых.
Серега
2016-10-04 08:08:02
Это парный арбитраж?
ra81
2016-10-04 10:58:41
не очень.
Гриша
2017-01-02 05:40:28
Секс знакомства http://bit.ly/2hkF2s9
6
Ноя
2017

Доверительное управление. Результаты в октябре 2017 года.

Доверительное управление. Результаты в октябре 2017 года. В октябре продолжался боковик на всех торгуемых активах. Российский… »

7
Окт
2017

Доверительное управление. Результаты в сентябре 2017 года.

Доверительное управление. Результаты в сентябре 2017 года. В сентябре на основных торгуемых активах (Ri и… »

8
Сен
2017

Доверительное управление. Результаты в августе 2017 года.

Доверительное управление. Результаты в августе 2017 года. Стратегия “Опционы” принесла в августе прибыль в размере… »

6
Авг
2017

Доверительное управление. Результаты в июле 2017 года.

Доверительное управление. Результаты в июле 2017 года. В июле индекс РТС вновь колебался в достаточно узком… »

14
Июл
2017

Доверительное управление. Результаты в июне 2017 года.

Доверительное управление. Результаты в июне 2017 года. Июнь индекс РТС вновь провел преимущественно в боковых движениях, а… »