Автор: xantia.
Здравствуйте, коллеги!
Я разрабатываю стратегию торговли по объемным спайкам с коротким стопом, в результате тестирования получаю следующие результаты:
%profitable = 36%
profit factor = 2.76
risk/reward ratio = 5.04
sharpe ratio = 0.37
sortino ratio = 1.55
expectatio = 0.18
немного измененная стратегия
%profitable = 64%
profit factor = 4.37
risk/reward ratio = 2.43
sharpe ratio = 0.47
sortino ratio = 1.72
expectatio = 0.35
Первая стратегия работает лучше на низко-волатильном рынке, вторая на высоко-волатильном рынке, комбинирую эти стратегия получаются неплохие результаты, на мой взгляд. Но меня беспокоит низкий коэффициент шарпа (<1), я его считаю как mean(returns)/std(returns), т.е. не учитывая безрисковую ставку. Монте-карло обоих стратегий показывает «красивый купол».
Смотрел список крупных фондов с рейтингом по коэффициенту шарпа, крайне редко он выше 1. Не могли бы Вы прокомментировать следующие вещи:
1. Ваше персональное мнение о представленных стратегиях, вы бы запустили их на реальные деньги?
2. Есть ли примеры реальных алгоритмических стратегий на одном инструменте, где шарп выше 1. Или низкий шарп как раз и отражает рискованность подобных стратегий?
3. В рейтингах крупных фондов, какой период для подсчета шарпа используется?
Заранее спасибо.
Комментарии:
mehanizator: Шарп всегда годовой считается. Вы про таймфрейм стратегий вообще не упомянули.
mehanizator: чтобы получить годовой Шарп, нужно домножить на корень из N, где N это число ваших returns в году.
xantia: Спасибо за ответы, таймфрейм — минуты, стратегия внутридневная на нефти. количество сделок 113 для первой и 81 для второй (за последние 17 месяцев).
mehanizator: если по результатам сделок шарп посчитан, надо его домножать на корень из среднего числа сделок в году, тогда будет годовой.
dobrachev: Да ладно…
Получается что при одной и той же доходности за год, и при одном и том же стандартном отклонении, лучше чтобы было 1000 сделок в год чем 100?
Потому что Шарп будет в 3 раза больше.
Ну и что это за метрика оценивающая доходность/риск, если игра одна и та же (только партий больше).
Тут что-то не так…
mehanizator: вы не получите одинаковое стандартное отклонение, потому что стандартное отклонение будет обратно пропорционально корню из числа сделок.
dobrachev: Открываю википедию и читаю про стандартное отклонение
После чего понимаю что если мы играем в игру, когда мы подкидываем монетку и либо выпадает 1, либо -1, то совершенно не важно сыграли мы в игру 100 раз или 1000 раз.
Стандартное отклонение в такой игре будет равно 1.
mehanizator: в такой игре наверное. ну так и справедливо, что Шарп будет выше, потому что годовая эквити будет более гладкой на 1000 сделках, чем на 100 сделках.
dobrachev: Годовой Шарп — это когда доходность в числителе формулы указана за год. То есть если за 17 месяцев стало на 17% больше денег, то годовая доходность будет 1.1
mehanizator: нет, годовой Шарп это Шарп, приведенный к годовому периоду. доходности в формуле считаются по сделкам или по барам нужного периода.
Vitas: Если в году N торговых периодов, на каждом из которых есть свои матожидание и дисперсия, то надо рассматривать год как совокупность случайных выборок, на этом корень из N и возникает
dobrachev: Ну если привести к годовому периоду и считать по сделкам за год, то конечно ошибки не будет. Но что делать если есть 1000 сделок за 7 лет или 10000 сделок за 3 мес. Как тогда считать, чтобы использовать всю имеющуюся информацию о доходности и риске?
Ок… Формулу в студию:
Коэф. Шарпа = Среднее_значение_доходности_на_сделку/стандартное_отклонение
(если нужно точнее в википедии есть нормальное определение)
Как поменяется коэф. Шарпа для 1000 сделок, если эти сделки прошли за 3 мес. или за 7 лет? Да никак не поменяется.
(за свой прошлый ошибочный коммент я прошу прощения, так как в Шарпе считается средняя доходность от сделки, а не какая-то годовая доходность)
xantia: Коллеги, я правильно понимаю, что если у меня торговая система выполняет сделки каждый день, то для того что бы посчитать годовой Шарп нужно:
annual_sharpe_ratio = (mean(returns)/sd(return))*sqrt(365)
спасибо.
dobrachev: Пусть у нас было 100 сделок за год, тогда мы для них посчитали коэф. Шарпа и сидим довольные — всё как надо. А вот если бы нам дали 99 сделок за период в 50 недель, то нам бы пришлось сначала посчитать наш обычный Шарп, а потом ещё домножить на (корень из 100)… Так ведь получается…
Но сделки-то все те же самые, только одной не хватает, а шарп в 10 раз отличается
dobrachev: Xantia: Я внимательно читал определение коэф. Шарпа в википедии. Я считаю, что он не зависит от того периода на котором были совершены эти сделки. Всё что нам нужно,чтобы посчитать Шарп — это знать доходность для каждой из сделок.
Если очень хочется, то можно конечно определить annual_sharpe_ratio как (mean(returns)/sd(return))*sqrt(365). Только зачем?
sharpe_ratio = (mean(returns)/sd(return))
Вот и вся формула
mehanizator: «просто» коэффициент Шарпа никто не использует, используют именно приведенный к году коэффициент Шарпа, именно он указывается для фондов.
mehanizator: xantia 365 торговых дней у вас может случиться только если вы торгуете криптовалютами. для остальных активов нужно считать рабочие дни, их 250 примерно.
dobrachev: Хорошо. А какая формула тогда у приведённого к году коэф. Шарпа. Я правда не понимаю как его считать…
mehanizator: annual_sharpe_ratio = (mean(returns)/sd(return))*sqrt(N), где N — число «returns» на годовом периоде.
dobrachev: Ладно, определение annual_sharpe_ratio было дано. Но остаётся несколько вопросов:
Где можно почитать про annual_sharpe_ratio (потому что в википедии Шарп определяется как mean(returns)/sd(return))
Ну а во вторых теряется при таком определении коэф. Шарпа теряется смысл в метрике. Получается что если у нас есть две стратегии с одинаковыми annual_sharpe_ratio, то качество сигналов от стратегий может сильно отличаться. Например одна стратегия даёт 100 сделок в год со средним выигрышем X и стандартным отклонением Y, а другая выдаёт 10000 сделок в год со средним выигрышем X/10 и точно таким же стандартным отклонением Y.
Коэф. Шарпа приведенные к году у них одинаковые, но ёжику понятно что лучше торговать ту стратегию, которая даёт выигрыш в 10 раз больше при одном и том же стандартном отклонении.
mehanizator: одинаковое «стандартное отклонение на сделку» не означает одинаковое «стандартное отклонение за время». у второй системы годовое стандартное отклонение будет в 10 раз больше (в 100 раз больше сделок).
dobrachev: Не, тут что-то не то…
У нас есть определение
annual_sharpe_ratio = (mean(returns)/sd(return))*sqrt(N)
В определение ничего не сказано про «стандартное отклонение за время». В примере никто не говорит, что это две какие-то похожие системы. Я надеюсь, никто не думает что если существут система с выигрышем X и стандартным отклонением Y (и 100 сделками в год), то отсюда следует что НЕ существует второй системы с выигрышем X/10 и стандартным отклонением Y (и 10000 сделками в год)
mehanizator: в формуле для Шарпа мы умножаем на sqrt(N) для того, чтобы привести все к одному временному периоду. то есть для того, чтобы спроецировать «стандартное отклонение за сделку» на «стандартное отклонение за год».
вторая система у вас будет давать в 10 раз большую прибыль при в 10 раз большем годовом стандартном отклонении. если качество понимать как отношение прибыли к стандартному отклонению, то системы имеют одинаковое качество.
dobrachev: Ничего не понимаю…:
С каких пор умножение на sqrt(N) приводит всё к одному временному периоду (особенно учитывая то, что в примере все уже приведено к 1 году). Что это за механизм такой, мне например совершенно не очевидно как это работает.
Что такое «годовое стандартное отклонение»? В формуле
annual_sharpe_ratio = (mean(returns)/sd(return))*sqrt(N)
ничего такого нет.
То что вторая система принёсет в 10 раз больше прибыли за год, это конечно правда, но к коэф. Шарпа это никак не относится.
Стандартное отклонение зависит только от результатов сделок. Больше ничего на стандартное отклонение не влияет.
mehanizator: уточните, что в примере такое «стандартное отклонение Y» — это стандартное отклонение одной сделки?
dobrachev: Я использую определение стандартного отклонения (а точнее: Среднеквадрати́ческое отклоне́ние) из википедии. Я так понимаю что оно как раз совпадает с sd(return). Вот это sd(return) = Y
mehanizator: если у вас стандартное отклонение сделки Y, то стандартное отклонение серии из N сделок будет Y * sqrt(N).
Vitas: дисперсия суммы независимых случайных величин равна сумме дисперсий, соответственно за N одинаковых промежутков дисперсия увеличится в N раз, а стандартное отклонение в sqrt(N) раз. в числителе сумма N увеличится в N раз. N деленное на sqrt(N) и даст итоговый множитель sqrt(N)
dobrachev: Господа, хочется привести простой пример.
В Excel умеет считать стандартное отклонение.
В нем функция СТАНДОТКЛОНП Вычисляет стандартное отклонение по генеральной совокупности(это как раз то что нам нужно, формула совпадает с википедией). «Стандартное отклонение — это мера того, насколько широко разбросаны точки данных относительно их среднего.»
Итак вбиваем набор «1,2,3,4,5,6,7,8,9,10», для него СТАНДОТКЛОНП=2,87
Теперь делаем двойной набор «1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10» и для него ТОЖЕ СТАНДОТКЛОНП=2,87 (осталось прежним)
Если мы возьмем N раз любой одинаковый набор, то стандартное отклонение не изменится. Никакого увеличения в sqrt(N) раз не будет.
(Возможно конечно что мы продолжаем недопонимать друг друга из-за того что никак не договоримся об определениях)
Vitas: понятно. проблема в том, что это РАЗНЫЕ стандартные отклонения: 1) стандартное отклонение последовательности сделок 2) стандартное отклонение сумм за год. первая величина есть свойство распределения и от размера выборки, разумеется, не зависит. но для шарпа нужна вторая величина. вот она будет меняться.
mehanizator: надо брать суммы из N элементов исходного набора и для них считать стандартное отклонение.
mehanizator: поясняю зачем Шарп к году приводится:
если вы возьмете эквити фонда и нарубите его по кварталам и посчитаете Шарп (не приводя к году), будет одно значение, если нарубите по месяцам — второе, если по дням — третье.
а если вы будете приводить к году, то как ни руби, будет получаться примерно одно и то же.
dobrachev: Ну хорошо. Теперь бы ещё понять как считать Шарп для эквити.
Я думал так, что чем мельче мы нарубим эквити тем лучше (если на ней ещё не видны точки «перегибов»). А дальше считаем что разница значений наших кусков — и есть одна сделка. Дальше считаем Шарп как обычно для последовательности сделок. В идеале бы конечно хотелось бы просто увидеть множество всех сделок, но если его нет то надо рубить эквити помельче. Чем мельче — тем ближе к правде.
Теперь пример: Был капитал 100р. За первый месяц заработали 1р, за второй месяц заработали 2р. и т.д…за 12 месяц заработали 12р. Вопрос как в данном примере правильно посчитать приведённый к году коэф. шарпа?
xantia: По нашей формуле, годовой шарп получается такой:
returns = [1,2,3,4,5,6,7,8,9,10,11,12]
mean(returns) = 6.5
sd(returns) = 3.6
sqrt(12) = 3.5
annual_sharpe_ratio = (6.5/3.6)*3.5 = 6.3
Kent: «annual_sharpe_ratio = (6.5/3.6)*3.5 = 6.3»
неверно имхо, на это sqrt(12) = 3.5 не надо умножать
dobrachev: Xantia: Всё посчитано верно (исходя из определения). Нашу дискуссию я думаю Вы прочли. Выводы делайте сами. А так annual_sharpe_ratio и sharpe_ratio вы посчитать уж точно можете.
Kent: Поддерживаю. Мне тоже кажется, что умножать не надо, как и не надо вводить никакой annual_sharpe_ratio. Тут вся дискуссия по этому поводу только и велась.
xantia: Коллеги, большое спасибо за Ваши комментарии. Мне есть над чем подумать.
Kent: annual_sharpe_ratio вводить можно, если хочется, но умножать не надо в конкретном примере от xantia:
Kent: моя думает навскидку, что если бы это annual_sharpe_ratio было посчитано на дневках только в январе, тогда следовало умножать на sqrt(12) = 3.5
а поскольку посчитано за год то не следует
Kent: и вообще все неправильно посчитано )) серьезно
Kent: тут посмотрите про Шарпа и преобразование волы и доходностей
http://www.chiefriskofficer.ru/analysis/documentation/coefficient/#5
Kent: http://blog.quantquant.com/blog/money_management/15.html
В чем смысл коэффициента Шарпа?
Kent: НАЙДИТЕ В ЛОГАХ ЧАТА ссылку на сайт/блог Шарпа я давал, там оригинальная метода изложена
Kent: http://monetarism.ru/dictionary/05/06/23/1847211.shtml
Коэффициент Шарпа — оценка эффективности фондов и трейдеров.
Отправлено elite on 23/06/05 1:48
Kent: Может быть и так, что коэффициент Шарпа, расчитанный по эквити, равен 0.3, а коэффициент Шарпа расчитанный по сделкам 3.0, что обесценивает сам критерий Шарпа. http://monetarism.ru/article.pl?sid=07/08/30/0453216
xantia: Kent, спасибо, буду разбираться. А как на Ваш взгляд параметры стратегий — заслуживают ли они выхода в реальный мир?
xantia: По ссылке, предоставленной Kent и для нашего примера получается так:
returns = [1,2,3,4,5,6,7,8,9,10,11,12] — это ежемесячные доходности, нужно привести к годовой. нам нужно каждую месячную доходность перевести в годовую умножив каждый элемент массива на 12, получим следующий массив:
returns12 = [12,24,36,48,60,72,84,96,108,120,132,144]
теперь посчитаем среднегодовую доходность, т.е. среднее этого массива, получим:
annual_return = 78
теперь нужно посчитать волатильность, для этого волатильность исходного массива умножаем на корень из 12, т.е.:
annual_vola = mean(returns)*sqrt(12) = 6.5*3.5 = 22.75
вот теперь можем посчитать коэффициент шарпа:
sharpe_ratio = annual_return/annual_vola = 78/22.75 = 3.42
mehanizator: а чего это у вас доходности абсолютные, а не относительные?
xantia: точно, доходности должны считаться так: math.log(returns[i]/returns[i-1]). сейчас пересчитаю.
mehanizator: на первом шаге ln(101/100) = 0.00995
на втором шаге ln(103/101) = 0.01960
…
но вообще предложенные цифры распределены явно не нормально, так что оценка дисперсии этой выборки вещь рискованая. а то, знаете ли, бывают распределения, где дисперсия в принципе не определена.
xantia: Сценарий: исходный капитал 10 у.е. ежемесячно фиксировали прибыль в у.е. 1, 2, 3 ….. 12. Ниже скрипт расчета шарпа на питоне, получилось 17.43.
Алгоритм:
1. строим массив роста капитала
2. вычисляем относительные доходности для каждого месяца
3. вычисляем волатильность относительных доходностей
4. приводим волатильность относительных доходностей к годовому исчислению
5. вычисляем среднегодовую доходность
6. вычисляем шарпа разделив среднегодовую доходность на волатильность в годовом исчислении
———————————————————————
import math
import numpy as np
# initial capital and a list of absolute returns per month
capital = 10;
returns_abs = [1,2,3,4,5,6,7,8,9,10,11,12];
# build equity
equity = [capital];
for r in returns_abs:
equity.append(equity[-1]+r)
# calculate log returns
returns = [];
for i in range(1,len(equity)):
returns.append(math.log(equity[i]/equity[i-1]));
# calculate annual volatility of returns
annual_vola = np.std(returns)*math.sqrt(12);
# calculate annual return
returns = [r*12 for r in returns];
annual_return = np.mean(returns);
# calculate sharpe ratio
sharpe = annual_return/annual_vola;
print(sharpe);
———————————————————————
xantia: пересчитал для своих стратегий шарпа, получается 4.85 и 3.19 соотвественно. что интересно, так это то, что в первой стратегии очень короткий стоп и соответственно win/loss ratio выше и у нее же шарп выше, что вполне логично
dobrachev: Xantia: Отлично! Прога что надо 🙂
А теперь представьте что это прибыль в у.е. 1, 2, 3 ….. 12 за каждые 2 недели торговли (а не по месяцу как исходно было). Как вы теперь будете считать sharpe = annual_return/annual_vola? И на кокой корень домножать?
Вы вообще хоть где-нибудь видели (из предложенный ссылок на определение Шарпа) чтобы там домножали на sqrt(N)? Почему домножение на sqrt(N) превращает vola в annual_vola (при том что эти N сделок были совершены в течении недели). Если Вы всё это поняли, ну может мне объясните 🙂
xantia: Вот несколько ссылок:
Книжка «Математика управления капиталом», стр.219 (шаг 6)
https://books.google.com.au/books?id=xZ073E4kFUEC&pg=PA219&lpg=PA219&dq=%D0%B3%D0%BE%D0%B4%D0%BE%D0%B2%D0%B0%D1%8F+%D0%B2%D0%BE%D0%BB%D0%B0%D1%82%D0%B8%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D1%8C+%D0%BF%D0%BE+%D0%B4%D0%BD%D0%B5%D0%B2%D0%BD%D1%8B%D0%BC+%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D0%BC&source=bl&ots=M8S-_rTO7Z&sig=Y8NpgNmdKbLmh1bjQnUThogkUE8&hl=en&sa=X&ved=0CCYQ6AEwAWoVChMIzPyx-66VxgIVBka8Ch2p4Afx#v=onepage&q=%D0%B3%D0%BE%D0%B4%D0%BE%D0%B2%D0%B0%D1%8F%20%D0%B2%D0%BE%D0%BB%D0%B0%D1%82%D0%B8%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D1%8C%20%D0%BF%D0%BE%20%D0%B4%D0%BD%D0%B5%D0%B2%D0%BD%D1%8B%D0%BC%20%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D0%BC&f=false
А вот расчет из википедии, раздел «Расчет исторической волатильности».
https://ru.wikipedia.org/wiki/%D0%92%D0%BE%D0%BB%D0%B0%D1%82%D0%B8%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D1%8C
Я понял алгоритм следующим образом:
1. шарп расчитывается по годовым данным только
2. все, что у нас есть — нужно привести к годовому виду
Соответственно у меня сделки за каждые две недели, то дисперсию я бы умножал на количество двух-недельных периодов в году (52/2 = 26), т.е. на корень из 26.
Другой вопрос, что годовой шарп нужен скорее для маркетинга, а управляющему в общем достаточно иметь понимание просто отношения mean(returns)/std(returns) для всех своих сделок и вернее даже не шарп, а сортино (только по волатильности вниз).
Kent: неверно
# calculate annual volatility of returns
annual_vola = np.std(returns)*math.sqrt(12);
Kent: неверно
# calculate annual return
returns = [r*12 for r in returns];
annual_return = np.mean(returns);
Kent: НАЙДИТЕ В ЛОГАХ ЧАТА ссылку на сайт/блог Шарпа я давал, там оригинальная метода изложена
dobrachev: Кстати, Кент прав.
annual_vola = np.std(returns)*math.sqrt(12) — это совсем не правильно.
Если помните, Mehanizator сказал что:
annual_sharpe_ratio = (mean(returns)/sd(return))*sqrt(N), где N — число «returns» на годовом периоде.
Теперь я кстати понял, почему это правильно 🙂
dobrachev: Спасибо, Xantia, за ссылку на статью о волатильности в википедии:
https://ru.wikipedia.org/wiki/%D0%92%D0%BE%D0%BB%D0%B0%D1%82%D0%B8%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D1%8C
Там так и написано:
Среднегодовая волатильность annual_vola пропорциональна стандартному отклонению sd(return) доходности финансового инструмента и обратно пропорциональна квадратному корню временно́го периода:
annual_vola = sd(return)/sqrt(P)
где sd(return) — стандартное отклонение доходности финансового инструмента; P — временной период в годах.
Читаем дальше:
Например, если стандартное отклонение доходности финансового инструмента в течение дня составляет 0,01, а в году насчитывается 252 торговых дня (то есть временной период — 1 день = 1/252 года), то годовая волатильность будет равна:
annual_vola = 0.01/sqrt(1/252)= 0.1587
Видно, что P=1/N, где N — число «returns» на годовом периоде. В данном случае 1 return — это один торговый день.
Итого получается, что:
annual_vola = sd(return)*sqrt(N)
Если считать, что годовая доходность
annual_return= mean(returns)*N
то отсюда получаем искомую формулу для расчета коэф. Шарпа приведенного к году:
annual_sharpe_ratio = annual_return/annual_vola = (mean(returns)*N)/(sd(return)*sqrt(N)) = (mean(returns)/(sd(return))*sqrt(N) = sharpe_ratio*sqrt(N)
Получается, что если у нас есть данные о прибыли за 12 месяцев, то нам просто надо рассчитать коэф. Шарпа, и это будет коэф. Шарпа приведённый к году.
А вот если у нас есть данные и сделках за пол-года, то в этом случае N=2 (так как в году два периода по пол-года)
И поэтому, чтобы узнать коэф.Шарпа для эквити приведенный к году, нам нужно найденный коэф. Шарпа для сделок за пол-года ещё домножить на (корень из 2).
Надеюсь, я достаточно подробно рассказал как считать коэф. Шарпа приведённый к году 🙂
Kent: dobrachev быстро глянул, вроде все верно
Vitas: dobrachev, ну собственно это же я и писал, только в меньшем объеме текста 😉
xantia: спасибо, коллеги. я запутался с параметром N, думал что это количество периодов в году (например 12 если у нас месячные данные), а это оказывается количество периодов в году за которые у нас есть измерения в сумме.