Replikant_mih
Replikant_mih личный блог
17 марта 2019, 11:46

Вот он мой бэктестер-оптимизатор, моя прееелесть.

У хорошего мастера должны быть хорошие инструменты – у кузнеца – молот, у столяра – рубанок, у алготрейдера… — оптимизатор.


Выкатил новую версию.

 

Настоящий мужской оптимизатор конечно же должен быть консольным. Этот красавчик быстр – 10 лет 5-минуток на простой стратегии вместе с вычислением всяких там PF, RF 0,3 секунды. И это на одном потоке! (с многопоточностью, к слову, пока не смог подружить, но заложил такую возможность).

Бэктестер берет задания из csv файла и пашет. Т.е. на данный момент задания на оптимизацию задаются в момент создания файла с заданиями, решил поменять план оптимизации – меняю файл – меняется дальнейшая оптимизация. Т.е. по факту сейчас план на оптимизацию предустановленный, но легко прикрутить в дальнейшем оптимизацию с обратной связью на результаты предыдущих бэктестов. Меня всегда смущали стандартные оптимизаторы в этой части – где перебирается один параметр, или несколько строго итерационно, но я не мог задать явно другие алгоритмы перебора или в общем случае даже не перебора, а «изменения» значений. А здесь могу: т.е., могу за раз закинуть задания сразу на нужное количество гипотез, хочу посмотреть, как стратегия себя ведет между тикерам – не трогаю ничего, меняю только тикер, хочу проверить как ведет себя между тайм-фреймами – меняю только тайм-фреймы и т.д., т.е. минут за 5-10 во всемогущем экселе можно создать файл с заданиями для нужного набора гипотез. Потом когда бэктестер отработает – берешь эксельку и дата-майнишь данные.

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

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

Если вдруг кто-то собирался завидовать – не надо, вам бы не понравился мой оптимизатор. Думаю, он будет нравиться только мне! :)

72 Комментария
  • ezomm
    17 марта 2019, 12:17
    Редко встретишь в торговле счастливого спекулянта .+. Я все оттестил до 2008года и всем желаю изучить волновую теорию и ничего не тестить.Там и одного глаза достаточно.
      • ezomm
        17 марта 2019, 12:31
        Replikant_mih, проги для определения волн давно придуманы.Если не веришь глазу используй проги типа EWA 3.0 ....6.0.
          • ezomm
            17 марта 2019, 12:55
            Replikant_mih, Верно.Подошла цена к средней и вот вам сигнал !? Все просто.А понимать работу каждой свечи совсем не обязательно. Просто некоторых типа Эллиота заедает любопытство- почему цена танцует танец 3-2? Обычные волновики не доходят до свечного, который и есть цикличный анализ, а не просто расстановка цифр и букв.В общем -синусоида рулит, а кукл уродует синусоиду объемом. Вот такая сказка?

              • R🐼G
                17 марта 2019, 13:49
                Replikant_mih, синусоида на синусоиде на синусоиде. локальные колебания вокруг глобального тренда.
    • ezomm, второй глазик можно даже продать для взноса на депо, если почка уже тю-тю? 
      • ezomm
        17 марта 2019, 13:06
        Вестников, вы же культурный человек? Я вас помню с Комона.Зачем этот черный юмор?
        • ezomm, ну это же всё равно юмор. Не?
          И да, я тоже уже оплатил входной билет. 

           

        • astray
          18 марта 2019, 12:29
          ezomm, слился на камоне наверное )
  • Сергей Симонов
    17 марта 2019, 12:55
    Динамика инструмента — это функция от состава (C ), мотивации (M) и экономики игроков (E). Формула выглядит так:

    D = f(C,M,E)

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

    Имхо, единственный рациональный метод тестирования алгоритма выглядит так
    • ezomm
      17 марта 2019, 13:05
      Сергей Симонов, а формула тренда вверх выглядит так L>ref (H,-2) .
      Конечно система не только правило входа, но и анализ объема (как сути торговли) и ММ — расчета риска.
      • Сергей Симонов
        17 марта 2019, 13:38
        Replikant_mih, формула — всего лишь краткое изображение логики)

        где вы тут софистику увидели? помогите рассмотреть))
  • Носорог
    17 марта 2019, 13:16
    Как минимум, оригинально. Свежо. Правда, я свою битву за оригинальность проиграл — ибо несколько лет ставил на Excel и VBA, но в итоге выяснилось что я тратил 90% своих усилий не на разработку стратегий, а на технические моменты, давно решенные в коробочных продуктах. Посему я сейчас на мультичартс. Все-таки, даже принимая во внимание врямяемкость оптимизационного перебора комбинаций, узкое место все же скорее в логическом поиске рыночных неоптимальностей и программировании качественного кода, а не в поиске банальным перебором исключительно математических закономерность и подгонки их параметров. Впрочем, здесь одной правды нет и знаю успешных алго, которые на мой взгляд наоборот не заморачиваются поиском логических причин — какая разница если система фактически сейчас зарабатывает? Главное держать руку на пульсе и вовремя соскочить.
  • Логарифм Интегралыч
    17 марта 2019, 13:25
    когда много систем возникает лотерея:

    угадай систему
      • Логарифм Интегралыч
        17 марта 2019, 13:34
        когда много систем вариантов пОртфеля
        возникает лотерея:
        угадай систему вариант пОртфеля
  • tranquility
    17 марта 2019, 14:06
    Кстати, если файл большой (мегабайт 50, например), имеет смысл его сначала целиком в память загрузить, а потом уже разбирать построчно. Я как-то заметил, на построчное чтение-запись (особенно) в файл может в разы больше тратиться времени, чем на вычисления.
      • tranquility
        17 марта 2019, 17:06
        Replikant_mih, 
        У меня такой вот код долго работает (конкретно этот — пару секунд, т.к. лучшие цены меняются в несколько раз чаще чем сделки происходят и данных очень много получается, сотни тысяч записей):

        Сам понимаю, что можно сначала в память весь этот текст записать, а потом уже в файл целиком сбрасывать, но все лень как-то заморачиваться. Но надо уж как-нибудь собраться с этим...
        • Дед Нечипор
          17 марта 2019, 18:09
          tranquility, а вот скажите-ка мне, товарисчи, раз уж вы подзаморочились и сконструировали тестеры под свои потребности и сами реализуете задумки, почему же исходные данные пишете в файлы в текстовом виде, а не в родном (бинарном), чтоб не приходилось преобразовывать туда-сюда?

          Я как-то для сравнения преобразовывал данные из QSH-файлов и текстового вида (полученного из QSH) в свой собственный, так вот текст обрабатывался сущееественно дольше… Правда, тому могло быть объяснением мои кривые руки или тормоза Delphi при работе со строками, или и то и другое одновременно, но — правды не спрятать: родной формат все равно должен быть побыстрее
          • tranquility
            17 марта 2019, 19:27
            Владислав К, 
            Qsh конечно же быстрее, но реализовать его на с++ под свои задачи у меня достаточно времени заняло. А текстовый вариант все равно полезен, в первую очередь для поиска ошибок (в бинарнике делать это куда сложнее), а во вторую — для построения графиков. Можно сохранять в базу да на С++, а потом читать ее на питоне, но у меня не возникло потребности так заморачиваться.
        • Алексей
          17 марта 2019, 18:39
          tranquility, 1. цикл вынесите в отдельный метод, их код повторяется это не хорошо.
          2. вычислять размер массива в цикле не правильно, он будет этим заниматься каждым проходом, присвойте один раз перед циклом, например так: 
          int bookSize = _bids.size();
          for(int i = 0; i < bookSize; i++) {}

          p.s.: для работы с большими данными уже лет 30 используют базы данных.
          • tranquility
            17 марта 2019, 19:33
            Алексей, да, я в курсе, что скобочки значат лишний вызов функции, а это время. Но, подозреваю, современные компиляторы это оптимизируют и Ваш вариант ускорения кода будет совершенно не заметен. Главное в оптимизации — логарифмический поиск и вменяемо написанный код, который легко менять, это как по мне). Кстати, я вон тоже там оптимизировал немного — ссылку на элемент один раз вычисляю, чтобы не делать это несколько раз для каждого поля. Но это тоже дает совсем не заметный выигрыш по времени, но хоть красиво и лишних имен переменных не появляется, только внутри маленьких изолированных блоков)

            P.S. цикл и так в отдельном методе, там что-то вроде storeData() — после того как стратегия отторговала день, данные в нем сбрасываются в файлы логов. Это вообще можно отключить чтобы не тратить время, но и при бектестинге тоже иногда надо смотреть логи. Поэтому проще их оставлять включенными. В общем, это не проблема, будет напрягать — что-нибудь придумаем)
            • Алексей
              17 марта 2019, 20:29
              tranquility, нет компиляторы пока ещё не такие умные и я надеюсь что на моём веку таких не появится :)
              он же не знает для чего вы каждый раз функцию вызываете, может у вас размерность меняется или счётчик какой обновляете.
              я лишь указал на две нехороших вещи которые увидел. привычка, кодревью все дела, соррян если что:) вообще на плюсах уже лет 10 не писал.
              • tranquility
                17 марта 2019, 21:57
                Алексей, да норм, про первый пункт я не понял, если честно)) Мне как-то босс в авральном режиме сказал подобные штуки в критичном месте оптимизировать, я день провозился, потом протестили и вообще никакой разницы не заметили)) После этого у меня некоторое чутье выработалось чем стоит заморачиваться и чем не стоит. Частенько это самому проверять приходится…
                • Алексей
                  17 марта 2019, 22:57
                  tranquility, боссы они такие сами не знают чего хотят :) а чутьё это очень хорошо.

                  про первый пункт, я имел веду что у вас одинаковые циклы меняется только источник и по хорошему их нужно в отдельный метод вытащить, примерно так:
                      printBook(«asks», _asks);
                      printBook(«bids», _bids);

                  void printBook(std::string name, std::vector<int> book)
                  {
                      int size = book.size();
                      cout<<name<<":"<<size<<endl;
                      for(int i = 0; i < size; i ++)
                      {
                          cout<<i<<endl;
                      }
                  }
                  на производительность это не влияет, но читать код приятней
                  • tranquility
                    17 марта 2019, 23:27
                    Алексей, а, понятно. Но как по мне — это для ревьюера читать приятно, а для пишушего — геморрой) Для такой короткой операции отдельную сущность в пространстве имен заводить. В новых версиях стандарта с++ анонимные функции имеются, вот такой вариант мне больше нравится. Но до изучения С++11/14 руки все никак не доходят. Вроде как и так жалоб нет, хотелось бы рабочую версию сделать, а потом уже глубоким рефакторингом заниматься, вот там новые знания не помешают, придет время — будем осваивать.
                    А так, из спортивного интереса откликнулся на вакансию прогера в хфт контору, там как раз С++14 им подавай, метапрограммирование — вот это все. Провалил собеседование то, ну да ладно, все равно бы не пошел туда работать, даже при успешном исходе. Что-то подход увиденный мне не нравится, надо показать что ты г-н Чегоизволите, а если скажешь на собеседовании, делая тестовое задание типа: «ну, если вам надо, запилю тут логарифмический поиск, плавали, знаем, но если позволите мне здесь сэкономить свое время — буду очень признателен» — то просто перестанут на сообщения отвечать. Рабов ищут, не иначе как…
                    • Unworldly
                      18 марта 2019, 03:01
                      В новых версиях стандарта с++ анонимные функции имеются, вот такой вариант мне больше нравится.

                      tranquility, вот вам набросочек. С «анонимной» функцией. 


                      Но до изучения С++11/14 руки все никак не доходят.


                      Range-based циклы выучить не легко, а очень легко. По сравнению со всем остальным, конечно. 


                      А так, из спортивного интереса откликнулся на вакансию прогера в хфт контору, там как раз С++14 им подавай, метапрограммирование — вот это все. Провалил собеседование то, ну да ладно, все равно бы не пошел туда работать, даже при успешном исходе.


                      А как бы вы работали с C++14 кодом, если вы его не понимаете?
                      Даже если бы сами не писали именно C++14-й код...

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

                      Программирование нынче очень сложно, очень объёмно (обогнало медицину) и, главное, оно продолжает расти и усложняться, причём, скорость, похоже, растёт. 

                      С++ — самый hardcore. Каждые 3 года новый стандарт. Я не знаю, что делать. На любительском уровне — точно не угнаться.

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

                      ЗЗЫ. И после отправки потом в том же HTML'е расставлять элементы br, чтобы промежутки между текстом и цитатами смотрелись нормально...

                      • tranquility
                        18 марта 2019, 14:00
                        Unworldly, я боюсь пока переделывать проект под слвременные стандарты, вдруг придется его под какой-нибудь mingw собирать, тогда надо будет обратно под с++98 переводить что ли???
                        Насчет 'не понимаете' — сложно согласиться, практика показывает, мне все равно на каком процедурном языке писать, хоть на ассемблере опять, ей б-гу, это же не хаскель какой-нибудь с нуля учить. А вектор перебирать можно и через итератор, если не ошибаюсь, будет та же эффективность, что и с использованием ключевого слова auto. Хотя, последнее как видно, дает новые возможности для написания шаблонов, может быть полезным не тоьько для чтения кода, но и при его непосредственной разработке...

                        Извиняюсь если дислайкнул коммент, мобильная версия, все дела…
                        • Unworldly
                          19 марта 2019, 00:11
                          Unworldly, я боюсь пока переделывать проект под слвременные стандарты, вдруг придется его под какой-нибудь mingw собирать, тогда надо будет обратно под с++98 переводить что ли???

                          tranquility, чем больше времени проходит, тем меньше вероятность такого исхода. На сайте mingw указано, что туда входит gcc версии 8.2.0. Он не только практически полностью поддерживает 17-й стандарт, но и частично 20-й. Под Linux'ами обычно и то древнее версии, чем в mingw.

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

                          Надо просто попробовать, и тогда согласиться станет намного легче. 

                          А вектор перебирать можно и через итератор, если не ошибаюсь, будет та же эффективность, что и с использованием ключевого слова auto.

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

                          Ключевое слово auto не имеет к этому никакого отношения. Оно здесь лишь для того, чтобы не выписывать лишний раз тип, а также, чтобы его не пришлось править во многих местах, в том числе и в этом, если потом, в результате рефакторинга, этот тип станет другим.
                    • tranquility, спп14+метапрограммирование эт странно конечно…
                      Вот у меня знакомый некоторые методы и функции иногда на ассемблере писал — говорил это не по приколу, а ему так проще, -  вот это я понимаю…
                  • Unworldly
                    18 марта 2019, 02:22
                    на производительность это не влияет, но читать код приятней

                    Алексей, а уж ranged-based циклы из C++11 насколько приятней читать... 
                  • tranquility
                    18 марта 2019, 13:49
                    Алексей, нет, тот босс — вообще крутой, он очень глубоко всегда вдается в процесс разработки своих подопечных, аж удивительно, он это делает уже на протяжении двух с лишним десятков лет…
            • tranquility
              17 марта 2019, 22:04
              Replikant_mih, ну, там простая функция вроде
              int vector::size() const
              {
              return m_size;
              }
              а свойство если получить, его же поменять можно случайно, а это уже небезопасно получается.
              • Unworldly
                18 марта 2019, 02:31
                Replikant_mih, ну, там простая функция вродеint vector::size() const{return m_size;}

                tranquility, если впоследствии решите сменить контейнер на std::list, — мало не покажется, искать потом, откуда тормоза взялись…

                А ranged-based цикл даже не заметит, что что-то изменилось…
            • Алексей
              17 марта 2019, 22:23
              Replikant_mih, с++ очень мощный язык, может всё, но и требования к знаниям приличные, но ничего всё приходит с опытом для этого общение и существует :)
            • Unworldly
              18 марта 2019, 03:37
              В C++ ещё не изобрели свойства?)

              Replikant_mih, некоторые компиляторы поддерживают

              Правда, надо добавить опцию -fdeclspec в командную строку.
          • Unworldly
            18 марта 2019, 02:17
            вычислять размер массива в цикле не правильно, он будет этим заниматься каждым проходом, присвойте один раз перед циклом, например так: int bookSize = _bids.size();for(int i = 0; i < bookSize; i++) {}

            Алексей, сюда ranged-based циклы из C++11 идеально ложатся:

            for (auto const &be: _bids) {
            	os << be.time - zeroTime << '\t'
            	   << be.price << '\t'
            	   << be.qty << '\n';
            }
            
        • Unworldly
          18 марта 2019, 01:21
          У меня такой вот код долго работает

          tranquility, std::endl в нагруженном цикле?
          А пробовали на '\n' заменить?

          Почитайте
          , чем std::endl занимается после того, как выведет '\n'.
  • тестер да, хорошая штука...
    а оптимизатор ну… вреда от него нету конечно, но и помощи особой...
    Интереса ради — что у вас там за оптимизация? GA, SA, ILS, SS, Path Relinking, брутфорс ?
      • Replikant_mih, хехе… возможно что проще, это да… но опыт показывает что если «тупо» запускать мощную оптимизацию и потом «тупо» с тем что она выдала сразу в бой, эт обычно плохо заканчивается)) 
  • robomakerr
    18 марта 2019, 13:31
    Без ООП будет еще быстрее )
    • tranquility
      18 марта 2019, 14:21
      robomakerr, вот поэтому в высоконагруженной части кода я даже не думаю использовать обьекты с виртуальными функциями, хотя это моглт бы сказаться весьма неплохо на читабельности кожа и его лаконичности. А так, без классов продолжать разработку проекта с полдесятка тысяч строк кода просто очень больно, наверное) Особенно если вдруг принято решение проводить масштабный рефакторинг… Простой вариант — это когда вот не учитывал раньше миллисекунды времени, а тут теперь надо стало…
  • Quntag
    20 апреля 2022, 09:32

    А входной csv содержит тики или OHLC? 

    Тиковые csv значительно весят ведь. Да еще и по нескольким символам, да за 10 лет..

      • Quntag
        20 апреля 2022, 10:06
        Replikant_mih, Понял. Тогда конечно csv значительно легче. Я то в мт тестирую на реальных тиках, а там объемы данных весьма и весьма.
          • Quntag
            20 апреля 2022, 10:44
            Replikant_mih, А работа в питоне и на c# на паузе? Теперь только mql?

              • Quntag
                20 апреля 2022, 12:21
                Replikant_mih, Понял. А то читал блог с начала — там про с# разговоры были. 

Активные форумы
Что сейчас обсуждают

Старый дизайн
Старый
дизайн