Блог им. Replikant_mih

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

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


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

 

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

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

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

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

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

★2
Редко встретишь в торговле счастливого спекулянта .+. Я все оттестил до 2008года и всем желаю изучить волновую теорию и ничего не тестить.Там и одного глаза достаточно.
avatar

ezomm

ezomm, збазиба)

Ну ок, волновая. Но неужели не хочется автоматизировать, улучшить, одновременно находить входы на 200 инструментах и т.д.?)

avatar

Replikant_mih

ezomm, Не, ну среди начинающих воодушевленных много же)), это потом поубавляется их.
avatar

Replikant_mih

Replikant_mih, проги для определения волн давно придуманы.Если не веришь глазу используй проги типа EWA 3.0 ....6.0.
avatar

ezomm

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

 

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

avatar

Replikant_mih

Replikant_mih, Верно.Подошла цена к средней и вот вам сигнал !? Все просто.А понимать работу каждой свечи совсем не обязательно. Просто некоторых типа Эллиота заедает любопытство- почему цена танцует танец 3-2? Обычные волновики не доходят до свечного, который и есть цикличный анализ, а не просто расстановка цифр и букв.В общем -синусоида рулит, а кукл уродует синусоиду объемом. Вот такая сказка?

avatar

ezomm

ezomm, Сохранил коммент, возможно когда-нибудь смогу понять тот глубокий смысл, который здесь сокрыт. И надеюсь, что он здесь есть).
avatar

Replikant_mih

Replikant_mih, синусоида на синусоиде на синусоиде. локальные колебания вокруг глобального тренда.
avatar

Ra Ga

Ra Ga, Ну да, и чем меньше ТФ тем больше доля случайных шумов.
avatar

Replikant_mih

ezomm, второй глазик можно даже продать для взноса на депо, если почка уже тю-тю? 
Вестников, вы же культурный человек? Я вас помню с Комона.Зачем этот черный юмор?
avatar

ezomm

ezomm, ну это же всё равно юмор. Не?
И да, я тоже уже оплатил входной билет. 

 

ezomm, слился на камоне наверное )
avatar

astray

Динамика инструмента — это функция от состава (C ), мотивации (M) и экономики игроков (E). Формула выглядит так:

D = f(C,M,E)

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

Имхо, единственный рациональный метод тестирования алгоритма выглядит так
Сергей Симонов, а формула тренда вверх выглядит так L>ref (H,-2) .
Конечно система не только правило входа, но и анализ объема (как сути торговли) и ММ — расчета риска.
avatar

ezomm

свои формулы лучше размещать в своих темах
а потом раскидывать по темам чужим
Логарифм Интегралович, чё-чё-чё?))
Сергей Симонов, в формуле вы описали факторы, влияющие на цену, сгруппировав их в условные группы. Ну т.е. это по факту софистика во многом).
avatar

Replikant_mih

Replikant_mih, формула — всего лишь краткое изображение логики)

где вы тут софистику увидели? помогите рассмотреть))
Сергей Симонов, Ну приведите мне пример системы, которая по формуле и которая — нет, а я вам «докажу» почему которая «нет» она «да» или которая «да» она «нет»)).
avatar

Replikant_mih

Сергей Симонов, Или мне остаться на теоретическом уровне доказательства?)

avatar

Replikant_mih

Как минимум, оригинально. Свежо. Правда, я свою битву за оригинальность проиграл — ибо несколько лет ставил на Excel и VBA, но в итоге выяснилось что я тратил 90% своих усилий не на разработку стратегий, а на технические моменты, давно решенные в коробочных продуктах. Посему я сейчас на мультичартс. Все-таки, даже принимая во внимание врямяемкость оптимизационного перебора комбинаций, узкое место все же скорее в логическом поиске рыночных неоптимальностей и программировании качественного кода, а не в поиске банальным перебором исключительно математических закономерность и подгонки их параметров. Впрочем, здесь одной правды нет и знаю успешных алго, которые на мой взгляд наоборот не заморачиваются поиском логических причин — какая разница если система фактически сейчас зарабатывает? Главное держать руку на пульсе и вовремя соскочить.
avatar

Носорог

Носорог, Спасибо).

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

avatar

Replikant_mih

когда много систем возникает лотерея:

угадай систему
Логарифм Интегралович, В плане? Когда нагенерил много торговых систем — как набрать из них лучший портфель? — Ну тоже применить системный подход, запридумать какую-то систему формирования портфеля, проверить её и вперёд).
avatar

Replikant_mih

когда много систем вариантов пОртфеля
возникает лотерея:
угадай систему вариант пОртфеля
Логарифм Интегралович, Не будем на этом останавливаться) — когда много систем выбора из вариантов портфеля — возникает лотерея.
avatar

Replikant_mih

Кстати, если файл большой (мегабайт 50, например), имеет смысл его сначала целиком в память загрузить, а потом уже разбирать построчно. Я как-то заметил, на построчное чтение-запись (особенно) в файл может в разы больше тратиться времени, чем на вычисления.
avatar

tranquility

tranquility, Да, я не профи в кодинге, тоже по ходу написания проги время от время рисечу, экспериментирую в подобных направления. Вот буквально недавно запустил очередную свежую порцию кода и заподозрил, что не нормально, что 300К строк в csv файл пишутся несколько секунд, порисечил этот вопрос, оказалось, что собрать массив строк и записать через WriteAllLines() на порядки быстрее отрабатывает, чем через накапливание в одной текстовой переменной и потом записывание через WriteAllText().

 

А так да, загружаю полностью, потом разбираю. Более того, сохраняю некоторые данные в оперативке и при последующем обращении забираю из оперативки, а не из файла! Ну типа если на одном дата-сете гоняю прогоны — беру их один из файла, остальные — из оперативки.

avatar

Replikant_mih

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

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

tranquility

tranquility, а вот скажите-ка мне, товарисчи, раз уж вы подзаморочились и сконструировали тестеры под свои потребности и сами реализуете задумки, почему же исходные данные пишете в файлы в текстовом виде, а не в родном (бинарном), чтоб не приходилось преобразовывать туда-сюда?

Я как-то для сравнения преобразовывал данные из QSH-файлов и текстового вида (полученного из QSH) в свой собственный, так вот текст обрабатывался сущееественно дольше… Правда, тому могло быть объяснением мои кривые руки или тормоза Delphi при работе со строками, или и то и другое одновременно, но — правды не спрятать: родной формат все равно должен быть побыстрее
Владислав К, Мне с csv проще работать, понятней, работа с файлами для меня не является узким местом — как сказал — реализовал буферизацию ранее использовавшихся данных. + все реализовать невозможно — как сказал, пилю под себя (как и каждый в аналогичных случаях), мне конкретно это не нужно. А так да, в S#, например, одни и те же объемы данных считываются в бинарном формате, кажется, раза в 1,5-2 быстрее. Приятно, но не космос, конечно.
avatar

Replikant_mih

Владислав К, 
Qsh конечно же быстрее, но реализовать его на с++ под свои задачи у меня достаточно времени заняло. А текстовый вариант все равно полезен, в первую очередь для поиска ошибок (в бинарнике делать это куда сложнее), а во вторую — для построения графиков. Можно сохранять в базу да на С++, а потом читать ее на питоне, но у меня не возникло потребности так заморачиваться.
avatar

tranquility

tranquility, 1. цикл вынесите в отдельный метод, их код повторяется это не хорошо.
2. вычислять размер массива в цикле не правильно, он будет этим заниматься каждым проходом, присвойте один раз перед циклом, например так: 
int bookSize = _bids.size();
for(int i = 0; i < bookSize; i++) {}

p.s.: для работы с большими данными уже лет 30 используют базы данных.
avatar

Алексей

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

P.S. цикл и так в отдельном методе, там что-то вроде storeData() — после того как стратегия отторговала день, данные в нем сбрасываются в файлы логов. Это вообще можно отключить чтобы не тратить время, но и при бектестинге тоже иногда надо смотреть логи. Поэтому проще их оставлять включенными. В общем, это не проблема, будет напрягать — что-нибудь придумаем)
avatar

tranquility

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

Алексей

Алексей, Да, некоторые оптимизации кода прям на порядки улучшают производительность, а некоторые не сильно, но если системно такие мелочи учитывать, то накопительно тоже, наверно, выйдет прилично.
avatar

Replikant_mih

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

tranquility

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;
    }
}
на производительность это не влияет, но читать код приятней
avatar

Алексей

Алексей, а, понятно. Но как по мне — это для ревьюера читать приятно, а для пишушего — геморрой) Для такой короткой операции отдельную сущность в пространстве имен заводить. В новых версиях стандарта с++ анонимные функции имеются, вот такой вариант мне больше нравится. Но до изучения С++11/14 руки все никак не доходят. Вроде как и так жалоб нет, хотелось бы рабочую версию сделать, а потом уже глубоким рефакторингом заниматься, вот там новые знания не помешают, придет время — будем осваивать.
А так, из спортивного интереса откликнулся на вакансию прогера в хфт контору, там как раз С++14 им подавай, метапрограммирование — вот это все. Провалил собеседование то, ну да ладно, все равно бы не пошел туда работать, даже при успешном исходе. Что-то подход увиденный мне не нравится, надо показать что ты г-н Чегоизволите, а если скажешь на собеседовании, делая тестовое задание типа: «ну, если вам надо, запилю тут логарифмический поиск, плавали, знаем, но если позволите мне здесь сэкономить свое время — буду очень признателен» — то просто перестанут на сообщения отвечать. Рабов ищут, не иначе как…
avatar

tranquility

В новых версиях стандарта с++ анонимные функции имеются, вот такой вариант мне больше нравится.

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


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


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


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


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

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

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

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

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

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

avatar

Unworldly

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

Извиняюсь если дислайкнул коммент, мобильная версия, все дела…
avatar

tranquility

Unworldly, я боюсь пока переделывать проект под слвременные стандарты, вдруг придется его под какой-нибудь mingw собирать, тогда надо будет обратно под с++98 переводить что ли???

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

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

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

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

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

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

Unworldly

tranquility, спп14+метапрограммирование эт странно конечно…
Вот у меня знакомый некоторые методы и функции иногда на ассемблере писал — говорил это не по приколу, а ему так проще, -  вот это я понимаю…
на производительность это не влияет, но читать код приятней

Алексей, а уж ranged-based циклы из C++11 насколько приятней читать... 
avatar

Unworldly

Алексей, нет, тот босс — вообще крутой, он очень глубоко всегда вдается в процесс разработки своих подопечных, аж удивительно, он это делает уже на протяжении двух с лишним десятков лет…
avatar

tranquility

Алексей, Размер массива методом получается — оно там че, каждый раз заново вычисляется?) В C++ ещё не изобрели свойства?)
avatar

Replikant_mih

Replikant_mih, ну, там простая функция вроде
int vector::size() const
{
return m_size;
}
а свойство если получить, его же поменять можно случайно, а это уже небезопасно получается.
avatar

tranquility

tranquility, в C# можно запретить извне объекта менять свойство, при этом разрешить смотреть. Изнутри по-прежнему можно делать все что захочешь, в т.ч. небезопасно. Но в приведенном примере же тоже просто значение переменной возвращается.
avatar

Replikant_mih

Replikant_mih, ну, там простая функция вродеint vector::size() const{return m_size;}

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

А ranged-based цикл даже не заметит, что что-то изменилось…
avatar

Unworldly

Replikant_mih, с++ очень мощный язык, может всё, но и требования к знаниям приличные, но ничего всё приходит с опытом для этого общение и существует :)
avatar

Алексей

Алексей, В освоении нового больше помогает паханина, чем общение))), но да).
avatar

Replikant_mih

В C++ ещё не изобрели свойства?)

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

Правда, надо добавить опцию -fdeclspec в командную строку.
avatar

Unworldly

вычислять размер массива в цикле не правильно, он будет этим заниматься каждым проходом, присвойте один раз перед циклом, например так: 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';
}
avatar

Unworldly

У меня такой вот код долго работает

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

Почитайте
, чем std::endl занимается после того, как выведет '\n'.
avatar

Unworldly

тестер да, хорошая штука...
а оптимизатор ну… вреда от него нету конечно, но и помощи особой...
Интереса ради — что у вас там за оптимизация? GA, SA, ILS, SS, Path Relinking, брутфорс ?
avatar

Бабёр-Енот

Бабёр-Енот, Я ж говорю, у меня оптимизация без обратной связи, единоразово определяю наборы значений для прогонов, дальше идут прогоны по этим заданиям.

 

+ Оптимизация — это просто устоявшееся понятия, использую, чтоб люди понимали примерно о чем речь, но по факту применительно к моему подходу это никакая не оптимизация. Я формирую по каждой стратегии набор гипотез, определяю какие данные помогут мне каждую гипотезу верифицировать, далее задания для получения каждой гипотезы объединяю в один набор заданий и скармливаю оптимизатору. Дальше дата-майнинг как процесс верификации гипотез на основе полученных данных. При необходимости допроверка или новые гипотезы (с новыми заданиями на прогоны), по итогам имею работающие гипотезы, на их основе строю систему.

avatar

Replikant_mih

Бабёр-Енот, Хотя конечно использовать что-то из перечисленного было бы попроще, наверное)), оно тебе выдало значения и в бой)). Хотя у меня после множества итераций процесса тоже все довольно не сложно и отлажено).
avatar

Replikant_mih

Replikant_mih, хехе… возможно что проще, это да… но опыт показывает что если «тупо» запускать мощную оптимизацию и потом «тупо» с тем что она выдала сразу в бой, эт обычно плохо заканчивается)) 
Бабёр-Енот, Ну да, в трейдинге везде так, решают нюансы)).
avatar

Replikant_mih

Без ООП будет еще быстрее )
avatar

robomakerr

robomakerr, вот поэтому в высоконагруженной части кода я даже не думаю использовать обьекты с виртуальными функциями, хотя это моглт бы сказаться весьма неплохо на читабельности кожа и его лаконичности. А так, без классов продолжать разработку проекта с полдесятка тысяч строк кода просто очень больно, наверное) Особенно если вдруг принято решение проводить масштабный рефакторинг… Простой вариант — это когда вот не учитывал раньше миллисекунды времени, а тут теперь надо стало…
avatar

tranquility

robomakerr, Эт. да, я с умом вводил), для организации самой программы, а критические к скорости элементы — там все быстро), немного поэкспериментировал даже — например, для итерирования свечей пробовал через List<>, пробовал через class Candle, struct Candle, в итоге у меня отдельные массивы double Open[], double High[] и т.д.
avatar

Replikant_mih


Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.

Залогиниться

Зарегистрироваться
....все тэги
Регистрация
UPDONW