Что такое предубеждение о выживании и как его избежать?

Простой фактор, который необходимо учитывать при оценке различных торговых стратегий.

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

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

Мой опыт

Как уже упоминалось, я построил торговый симулятор и протестировал на нем стратегию. Период тестирования был установлен с 01–19000 по 31.12.2019. За этот период эта стратегия могла принести 9438% прибыли при торговле акциями, входящими в индекс S & P500.

Один из комментариев позже показал, что я использовал акции, которые в настоящее время активны. Это было правдой, вся симуляция предполагала, что в начале 2000 года мы наблюдаем те же символы, которые составляют индекс в 2019 году. Это предположение в корне неверно!

Вместо этого, перебирая время, я должен был сделать следующее:

  1. Составьте список символов, из которых состоял индекс S & P500 в 2000–1–1.
  2. При каждом обновлении индекса (один символ добавляется, другой удаляется) я также должен обновлять свой список символов.

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

«Историю пишут победители» - Уинстон Черчилль.

Поиск соответствующих данных

После поиска в Google некоторых соответствующих данных я обнаружил, что решение, которое я искал, было нетривиальным. Согласно Википедии, за период с 1 января 1963 г. по 31 декабря 2014 г. в компоненты S & P500 было внесено 1186 изменений, и их всего 227. Ясно, что этому нельзя полностью доверять.

Другой результат от Google говорит мне, что я могу купить список всех изменений индекса S & P500 за 97 долларов. Для незначительного любопытства это многовато. Я был немного удивлен, что такие тривиальные знания не передаются бесплатно.

Следующий результат был интересным:



Этот автор довольно долго собирал данные индекса и в результате собрал красивый файл JSON. Записи содержат две пары имя-значение: одну для даты, а другую для символов, составляющих индекс S & P500. Поскольку его довольно сложно читать, я не собираюсь вставлять сюда весь файл. Вместо этого на следующем изображении показано содержимое двух записей в файле JSON. Вы только посмотрите, сколько это времени!

Теперь, когда мы познакомились с файлом JSON, давайте перейдем к кодированию.

Помещая это в код

Если мы внимательно рассмотрим этот файл JSON, мы увидим, что это список словарей - каждая запись представлена ​​одним словарем Python. Мы можем загрузить данные с помощью следующего кода:

import json
with open('sp500-historical-components.json') as json_file:
    data = json.load(json_file)

Еще раз, data - это просто список, содержащий разные словари. Этот список неупорядочен, и, наверное, здорово, что он упорядочен. Во-первых, давайте создадим список дат:

dates = []
for entry in data:
    dates.append(entry["Date"])

Мой кодовый терминал показывает, что список dates выглядит следующим образом:

['2012/11/30', '2016/10/31', '2017/04/28', '2017/05/03', '2017/03/31', '2016/12/30', '2016/08/31', '2016/09/30', '2017/01/31', '2017/02/28', '2016/07/29', '2016/06/30', '2016/04/29', '2016/05/31', '2015/10/30', '2015/07/31', '2016/01/29', '2016/02/29', '2016/03/31', '2015/12/31', '2015/11/30', '2015/09/30', '2015/08/31', '2015/06/30', '2015/05/29', '2015/04/30', '2014/12/31', '2015/01/30', '2014/10/31', '2014/11/28', '2015/02/27', '2014/09/30', '2015/03/31', '2014/08/29', '2014/05/30', '2014/06/30', '2014/07/31', '2014/03/31', '2014/04/30', '2013/12/31', '2013/11/29', '2014/01/31', '2014/02/28', '2013/10/31', '2013/08/30', '2013/07/31', '2013/09/30', '2012/12/31', '2013/05/31', '2013/06/28', '2012/10/31', '2013/02/28', '2013/03/28', '2013/01/31', '2013/04/30', '2012/08/31', '2016/11/30', '2012/09/28', '2012/04/30', '2012/06/29', '2012/03/30', '2012/07/31', '2012/05/31', '2012/02/29', '2011/10/31', '2012/01/31', '2011/08/31', '2011/05/31', '2011/06/30', '2011/02/28', '2011/03/31', '2010/12/31', '2010/11/30', '2011/12/30', '2011/11/30', '2010/09/30', '2010/10/29', '2011/09/30', '2011/07/29', '2010/06/30', '2011/04/29', '2011/01/31', '2010/02/26', '2010/01/29', '2009/12/31', '2010/08/31', '2010/04/30', '2010/07/30', '2010/03/31', '2010/05/28', '2009/09/30', '2009/08/31', '2009/10/30', '2009/04/30', '2009/11/30', '2009/03/31', '2009/06/30', '2009/07/31', '2009/02/27', '2009/05/29', '2009/01/30', '2008/10/31', '2008/11/28', '2008/12/31', '2008/09/30', '2008/08/29', '2008/07/31', '2008/06/30', '2008/04/30', '2008/05/30', '2008/01/31', '2008/02/29', '2008/03/31']

Теперь мы точно видим, что наш список данных был неупорядоченным. Более того, даты идут с 2008 по 2017 год. Поскольку в этом списке не так много дат (примерно 100), мы можем использовать надежный способ вызова упорядоченных данных:

datescopy = dates.copy()
datescopy.sort()
indices = []
for date in datescopy:
    indices.append(dates.index(date))

Этот метод создает копию dates и приводит ее в порядок. Список indices помогает нам сопоставить даты между упорядоченными и неупорядоченными данными. Посмотреть на себя:

for index in indices:
    print(data[index]["Date"])

Распечатанные даты заказываются. Прохладный!

Допустим, вы хотите протестировать свою торговую стратегию на истории. Вы создали свой торговый симулятор и хотите, в частности, включить в него акции, котирующиеся на S & P500 в период с 2008–1–31 по 2017–05–03.

Вы запускаете свои торгуемые символы с помощью data[indices[0]]["Symbols"], и как только происходит обновление в соответствии с data, вы также обновляете свой список символов, выполняя итерацию во времени.

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

Резюме

  1. Список компонентов S & P500 в Википедии: https://en.wikipedia.org/wiki/List_of_S%26P_500_companies
  2. Ссылка на набор данных: https://nemozny.github.io/datasets/

Ресурсы