Aspiring Data Science
385 subscribers
465 photos
12 videos
12 files
2.16K links
Заметки экономиста о программировании, прогнозировании и принятии решений, научном методе познания.
Контакт: @fingoldo

I call myself a data scientist because I know just enough math, economics & programming to be dangerous.
Download Telegram
#trading #tradingpolicy #backtesting #optimization

Итак, продолжаем с трейдингом. В соответствии с предыдущим постом, я определился с несложной стратегией, которая открывает позицию на ожидании роста или падения цены актива, и закрывает её по стоп-лоссу или тейк-профиту. Согласно плану, надо её потестировать на истории (у нас есть 1 месяц срочного рынка ММВБ) без ML, и, если получится не сильно убыточно, попробовать внедрить, чтобы набить шишек, набраться опыта, и т.д.

У неё 3 параметра:

order_offset: float,
takeprofit_size: float,
stoploss_size: float.

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

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

Видимо, надо проверять некую связность параметров на последовательных интервалах. Если "лучшие" или "хорошие" параметры по инструменту изменяются от часа к часу достаточно плавно, есть надежда, что, подбирая "лучшие на текущий момент" параметры брутфорсом и применяя их следующий, скажем, час, мы приземлимся не очень далеко от "истинных лучших параметров" за этот будущий час, и имеем шансы заработать. (На самом деле, ещё более продвинута идея прогнозирования лучших будущих параметров, её продвигают ДеПрадо и Чан.)

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

Попробую проверить результаты следующего подхода: каждый час по каждому инструменту находим "лучшие" (в терминах прибыли, просадки, устойчивости) параметры с начала торгового дня до текущего момента, следующий час торгуем по ним. Под устойчивостью понимается тот факт, что небольшое изменение параметра не должно приводить к резкому изменению целевой функции. Для этого целевую функцию думаю оценивать не только в заданной точке M-мерного пространства параметров (в нашем случае M=3), но и в K ближайших (в смысле некоторой метрики, к примеру, эвклидовой) точках. Как оценку набора параметров можно брать отношение среднего (mean) целевой функции в этой и K ближайших точек к её вариации (std).

Как это можно реализовать:
1) сделать низкоуровневые черновые расчёты:

разбить все дни/инструменты на куски фиксированного размера, например, каждый 1 час, или каждые 10_000 сделок.
выбрать подлежащее проверке число сочетаний, например, P=1_000_000. Сгенерировать P случайных (но валидных) комбинаций параметров.
для каждого куска данных отправить на кластер задачи бэктеста всех этих P комбинаций для этого куска.
как результат, централизованно сохранить день, час, инструмент, параметры, итоговые метрики (прибыль, просадку, и тд)

2) провести, собственно, метабэктест:

каждый час находим, не забывая K точек окрестности, сочетание с лучшей оценкой (что лучше - за прошлый час или за весь день?), в качестве результата просто берём из базы уже известный кусок для этого сочетания и следующего часа. суммируем по всем дням и инструментам. тем самым и получим искомую оценку пригодности торговой стратегии.

Единственная проблема пока в том, что если открыта позиция на весь лимит риска, пока она не закроется, сделки в следующий период совершить будет нельзя, и расчёт теряет практический смысл. Но, наверное, это можно обойти большим депозитом и установкой "лимита на час".
#trading #backtesting #ml #chan

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

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

В данном случае, периоды этих 2 средних, ну ещё отступы и какие-нибудь дополнительные параметры, добавляются в обучающий набор (содержащий рыночные данные и фундаменталку), а таргетом выступет кэф Шарпа от применения этих торговых параметров на сл месяц.

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

Но ещё один важный аспект такого подхода в том, что традиционная идея "сначала МЛ (модель даёт прогнозы), потом бэктест (а что же делать с этими прогнозами, при каких значениях покупать/продавать) с боязнью оверфита" заменяется на "в каждой точке сэмплим сотни комбинаций управляющих параметров, смело делаем бэктестовые "виртуальные забеги" с этими параметрами, потом уже обучаем на всём МЛ, борьбу с оверфитом отдаём на откуп МЛ."

Конечно, это сильно снижает операционное пространство по сравнению с 1м подходом, т.к. МЛ исходы становится ограниченны конкретной торговой политикой. Но я придумал комбайн, как обойти это ограничение. Вторая модель! Пусть она даёт, как и обычно, прогнозы рынка и/или инструмента, и уже эти прогнозы будут считаться частью управляющий переменных. Тогда не надо будет ждать, условно говоря, пересечения 2 SMA, всегда будет некий прогноз и решающие пороги, по которым можно действовать. Такой своеобразный Double ML.

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


https://www.youtube.com/watch?v=sXYW0KgCKbE
👍1
#trading #backtesting #masters

"Thank you Dr. Masters for an outstanding sharing of your insight and experience and for agreeing to be interviewed! The clear descriptions of Monte Carlo Permutation Tests (MCPT-3 variants) and application BEFORE looking at precious out-of-sample data, Parameter Sensitivity, Stationarity, Entropy, Predictive Indicators and Bootstrapping are tremendously helpful to me as a strategy developer. I realize now that MCPT needs to be added to my strategy development process as well as the other elements you've articulated. Thank you, Andrew, for continually bringing gifted trading professionals to Better System Trader here on Youtube!"

https://www.youtube.com/watch?v=1RKz9v_0WDo
#trading #backtesting #masters

Пример реализации тестирования перестановкой из книги Мастерса.

Подчёркивается преимущество permutation test перед "простым" walkforward: OOS данные из walkforward очень ценны, и их желательно использовать пореже, чтобы не оверфиттиться на высоком уровне, а инсэмпловых перестановок намешать мы можем бесконечно много без проблем.

https://www.youtube.com/watch?v=NLBXgSmRBgU
👍1
#trading #backtesting #bestpractices #tradinggems

Узнал сегодня что-то новое.

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

do a system/backtesting framework sanity check. ensure:

1) random entry/exit signals produce very bad trading metrics (PnL, PF, Sharpe)
2) faked perfect entry/exit signals produce amazing trading metrics (PnL, PF, Sharpe)
3) your real trading policy on valid data is somewhere in the middle

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

Конечно, это касается не только одного отдельно взятого бэктеста, эти же условия должны быть справедливы и для оптимизатора.

Если ваш оптимизатор торговой политики (основанный на бэктестере) находит "прибыльные политики" на случайных сигналах либо случайных рыночных данных, шерше ля ошибку в его реализации.

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

Выяснилось следуюющее:

Стратегия на барах и лимитных ордерах (для контроля проскальзывания), решение об изменении позиции принимается в конце текущего бара.
Я хотел открывать/закрывать позицию в течение следующего бара по цене не сильно хуже чем цена close последнего известного бара.
Если же такая не была доступна на рынке, я предпочитал позицию не менять, до следующего сигнала.

Покажу проблему на примере закрытия позиции. ИИ транслировал мои пожелания вот в такой невинный код

expected_fill_price=prev_close*(1+slippage_pct*np.sign(current_position)) #  для реалистичности закладываем проскальзывание
close_ok= l<= expected_fill_price <=h

if close_ok:
#здесь закрываем позу
else:
# сохраняем позу


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

Ну и действительно, такая небрежность в принятии решения, когда всё делается красивым универсальнынм однострочником close_ok= l<= expected_fill_price <=h, приводила к тому, что случайные позиции быстро закрывались с небольшими убытками, но оставались открытыми для "хороших баров", причём факт хорошести брался из будущего.

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

Вот какой код был правильным:

# close_ok= l<= expected_fill_price <=h leads to a fatal future leak, so that even random backtest becomes positive!

if pos_units[tk] > 0: # Closing long (sell limit)
close_ok = h >= expected_fill_price # Fill if market reaches limit or better (higher prices)
expected_fill_price = max(expected_fill_price, l) # Conservative: lowest price in range >= limit (worst PNL for seller)
else: # Closing short (buy limit)
close_ok = l <= expected_fill_price # Fill if market reaches limit or better (lower prices)
expected_fill_price = min(expected_fill_price, h) # Conservative: highest price in range <= limit (worst PNL for buyer)


С такими правками (симметрично для открытия позы) бэктесты на случайности пошли ожидаемо провальные.

Что интересно, ИИ (не платный) оказался не способен найти верное решение.
Будьте внимательны, калибруйтесь и делайте "защиту от дурака", в общем. От себя то есть ) Часто помогает.
🔥5