المكافأة لكل وحدة مخاطرة
استراتيجية تربح 12% بتقلب 20% ليست أفضل من أخرى تربح 6% بتقلب 5%. تضعهما نسبة شارب على مقياس واحد: متوسط العائد فوق معدل الخالي من المخاطر مقسومًا على التقلب (mean - rf) / std محوّلًا إلى سنوي بـ sqrt(الفترات). وقد رأيت الصيغة في موضوع المتوسط والتباين. وهذا الموضوع عن استخدامها: كيف تقرأ نسبة شارب وتحسّنها، وقبل ذلك كم تثق بها. شارب 0.5 متواضع و1 جيد و2 ممتاز ومثير للريبة.
يحسب التقلب الصعود والهبوط بالتساوي، مع أن أحدًا لا يشتكي من ربح مفاجئ. وتُبقي نسبة سورتينو الجانب السيئ وحده: تستبدل الانحراف المعياري بـالانحراف الهابط sqrt(mean(min(r - mar, 0)²)) حيث mar أدنى عائد مقبول. وتسهم الأيام فوق mar بصفر لكنها تدخل في المتوسط. واستراتيجية ذات قفزات موجبة كبيرة وخسائر صغيرة تحرز في سورتينو أفضل بكثير مما في شارب.
import math
import numpy as np
import pandas as pd
returns = np.array([0.004, -0.002, 0.001, 0.003, -0.004, 0.002, 0.006, -0.001, -0.010, 0.004, 0.002, -0.003])
sharpe = returns.mean() / returns.std(ddof=1) * math.sqrt(252)
print(round(sharpe, 3)) # 0.598
mar = 0.0 # a day below zero is a bad day
downside = math.sqrt(np.mean(np.minimum(returns - mar, 0) ** 2))
sortino = (returns.mean() - mar) / downside * math.sqrt(252)
print(round(downside, 5), round(sortino, 3)) # 0.00329 0.804 the up days no longer count as riskمراقبة تغيّرها
نسبة شارب واحدة لكل التاريخ تخفي القصة. ونسبة شارب المتحركة تعيد حسابها على آخر window من العوائد فترى أنظمة الاستراتيجية الجيدة والسيئة. وفي pandas هي المتوسط المتحرك مقسومًا على الانحراف المعياري المتحرك محوّلًا إلى سنوي. لاحظ كم تقفز النوافذ القصيرة: شهر من البيانات لا يكفي إطلاقًا لترتيب الاستراتيجيات.
series = pd.Series(returns)
rolling = series.rolling(5)
rolling_sharpe = rolling.mean() / rolling.std() * math.sqrt(252)
print(rolling_sharpe.round(2).tolist())
# [nan, nan, nan, nan, 1.89, 0.0, 6.96, 4.97, -3.66, 0.51, 0.51, -4.69] a 5-day Sharpe ratio is mostly noiseكم منها حظ؟
نسبة شارب تقدير، وللتقديرات أخطاء. لنسبة شارب لكل فترة sr مقيسة على n من العوائد يبلغ الخطأ المعياري نحو sqrt((1 + 0.5 * sr²) / n). ومع أيامنا الاثني عشر يساوي 0.29 يوميًا مقابل شارب 0.04: الخطأ سبعة أضعاف التقدير. وعند التحويل إلى سنوي تعطي الأيام نفسها 0.6 ± 4.6. ولنسبة شارب سنوية S رُصدت على years سنة يكون إحصاء t هو S * sqrt(years)، فتحتاج إلى (1.96 / S)² سنة لتتأكد بنسبة 95% أنها ليست صفرًا: 15 سنة لشارب 0.5 و4 سنوات لشارب 1. والاختبارات الرجعية القصيرة لاستراتيجيات متواضعة لا تثبت شيئًا.
per_period = returns.mean() / returns.std(ddof=1) # the per-day Sharpe ratio
std_error = math.sqrt((1 + 0.5 * per_period ** 2) / len(returns))
print(round(per_period, 4), round(std_error, 4)) # 0.0376 0.2888 the error is 7 times the estimate
print(round(std_error * math.sqrt(252), 3)) # 4.584 annualised: 0.6 +/- 4.6
# Years needed for an annual Sharpe ratio to reach t = 1.96
for annual in (0.5, 1.0, 2.0):
print(annual, round((1.96 / annual) ** 2, 1))
# 0.5 15.4
# 1.0 3.8
# 2.0 1.0# A yearly Sharpe of 1.0 observed over 4 years (1,008 days): how precise is it?
per_day = 1.0 / math.sqrt(252)
error_per_day = math.sqrt((1 + 0.5 * per_day ** 2) / 1008)
print(round(per_day, 4), round(error_per_day, 4), round(error_per_day * math.sqrt(252), 3)) # 0.063 0.0315 0.5 so 1.0 +/- 0.5- شارب =
(mean - rf) / std * sqrt(الفترات)؛ ويستبدل سورتينو الانحراف المعياري بالانحراف الهابطsqrt(mean(min(r - mar, 0)²)). - يُظهر شارب المتحرك (
rolling.mean() / rolling.std()) تغير النسبة؛ والنوافذ القصيرة ضجيج في معظمها. - خطؤه المعياري
sqrt((1 + 0.5 * sr²) / n)لكل فترة؛ وإحصاء t لشارب سنوي هوS * sqrt(years): شارب 1 يحتاج نحو 4 سنوات.
التالي: التراجعات (Drawdowns)، الخسائر من القمة التي يشعر بها المستثمرون فعلًا.
المختبر: ما الذي يُقيَّم
- عاقب الأيام السيئة فقط باستخدام
sortino_ratio25 نقطة - راقب تغير النسبة مع الزمن باستخدام
rolling_sharpe25 نقطة - قدّر الحظ في نسبة شارب باستخدام
sharpe_standard_error25 نقطة - اسأل هل هي حقيقية باستخدام
sharpe_t_stat25 نقطة