Избранное трейдера MrD
Решил начать писать небольшие заметки по алгоритмической торговле и всему что с ней связано. Возможно, когда-нибудь расширю, склею и опубликую в виде книжки. Пока же это просто наброски заметок, сделанные на скорую руку.
Можно часто слышать от тех, кто торгует алгоритмически, да и просто систематически, такие понятия как «оверфиттинг», «курвафиттинг», «зафит» и прочие ругательства с корнем «фит». Что все это значит?
На самом деле, все эти слова, как правило, используются для описания одного и того же явления, являющегося врагом всех трейдеров, торгующих систематически и пытающихся оценить исторический перформанс своих торговых логик — а именно, что «живой» аут-оф-сампл перформанс на реальном счете, как правило, хуже ожиданий, полученных ими при проверке своих идей на истории. Например, при тестировании торговой логики на истории трейдер с помощью своей модели «зарабатывал» 30% годовых, а в реале может в среднем иметь 10% годовых. Разница 20% годовых — может объясняться именно оверфиттингом (если нет других факторов — например, некорректный учет комиссионных и проскальзываний, или ошибка в торговом коде; но прочие факторы легко устранить, в отличие от оверфиттинга). На картинке в начале статьи — пример перформанса некоторого фонда в бэктесте и в реальности, наглядно иллюстрирующий написанное выше.
Оверфиттинг является следствием комбинации одного или нескольких из следующих факторов, положительно влияющих на бэктест (результаты прогонки модели на истории), что и создает у трейдера завышенные ожидания от своей модели. В этой части мы рассмотрим основные источники оверфиттинга, в следующей — поговорим о способах избежания или минимизации оверфиттинга при историческом тестировании моделей.
Итак, как я и обещал, исходники торгового терминала RTS-Robot версии 1.0 выложены на GitHub!
Напоминаю, что язык программирования — Python 2.7, брокер — Финам, коннектор — Transaq XML Connector. (в том числе и Transaq HFT)
Что умеет:
Выложенное решение имеет некоторые ограничения, а именно:
— Упрощенный код, многое из «планов на будущее» отключено и/или убрано.
— Торговые алгоритмы работают только с одной бумагой. (несложно доделывается.)
— Коннектор только один
— Бесплатной поддержки нет и не будет (мне работать надо!)
— Короткий документ о том, «как это всё собрать и заставить работать» если напишу, то позже
— Сайт проекта обновлю позже, сейчас нет времени заниматься.
В остальном же — это работающий торговый терминал, запускаемый как под Windows, так и под Wine.
Будьте осторожны. Нужны специальные знания и навыки профессионального программиста.
Вчера появился пост с вопросом, что же за сделки происходят в голубых акциях, когда торги закончились. Что за глюки, мол.
Я попробую пояснить, и если в чем-то окажусь неточным, надеюсь, меня поправят более понимающие в этом товарищи.
В 18:40 заканчивается торговый период сессии и проходит его последняя сделка.
Наступает аукцион закрытия, который идет 10 минут.
Первые пять минут – до 18:45 – происходит аукционное определение цены закрытия сессии, и еще 5 минут по этой и только по этой цене могут пройти дополнительные сделки.
Как это происходит
Наступает 18:40 по мск, все заявки, выставленные игроками в торговый период, и которые защищали рынок от резких ложных движений, исчезают, появляются заявки людей, которые решили принять участие в аукционе.
В стакане становятся видны те заявки, которые попадают в 10-ку лучших заявок на продажу и покупку соответственно, остальные заявки не отражаются.
Использую торговую систему, реализованную на базе Excel. Возникла идея, изучить Питон и переписать системку на его основе. В связи с этим пару вопросов:
Settings= { Name = "Piton", N = 100, legend = "price2", line = { { Name = "Sint", Color = RGB(0, 132, 0), Type = TYPE_LINE, Width = 1 } } } function Init() return 1 end Candles = {}; function OnCalculate(index) local numCandles = getNumCandles(Settings.legend); if index <= Settings.N or numCandles <= Settings.N then return nil; end Candles, n, _ = getCandlesByIndex(Settings.legend, 0, index - Settings.N, Settings.N); if n ~= Settings.N then return nil; end -- Предварительный расчет sum1, sum2, sum3 = advancePaynemt(index); -- расчет коэффициента корреляции Пирсона r = sum3/math.sqrt(sum1*sum2); return r; end -- Предварительный расчет ---------------------------------------- function advancePaynemt(index) local sum1 = 0; local sum2 = 0; local sum3 = 0; local j = 0; -- Вычислить среднее арифметическое for i=index - Settings.N + 1, index, 1 do sum1 = sum1 + C(i); sum2 = sum2 + Candles[j].close; j = j + 1; end aver1 = sum1/Settings.N; aver2 = sum2/Settings.N; -- Вычислить сумму квадратов отклонений sum1 = 0; sum2 = 0; j = 0; for i=index - Settings.N+1, index, 1 do sum1 = sum1 + math.pow(C(i) - aver1, 2); sum2 = sum2 + math.pow(Candles[j].close - aver2, 2); j = j + 1; end -- Вычислить сумму произведений разности j=0; for i=index - Settings.N+1, index, 1 do sum3 = sum3 + (aver1 - C(i))*(aver2 - Candles[j].close); j = j + 1; end return sum1, sum2, sum3; endКак запустить и настроить: