سلسلة تتذكر نفسها
تحمل سلاسل كثيرة معلومات عن مستقبلها. فهوامش الفائدة والتقلب والفجوة بين سعرين مرتبطين تنجرف عائدة إلى مستوى بدل أن تهيم بحرية. وتلتقط نماذج ARIMA ذلك بثلاث أفكار: I أي تفاضل السلسلة لتصبح مستقرة؛ AR أي انحدارها على تأخيراتها؛ MA أي استخدام أخطاء التنبؤ الأخيرة. أما عوائد الأسهم نفسها فلا تُظهر هذه الذاكرة تقريبًا، فمكان ARIMA هو السلاسل المستمرة أو الراجعة إلى المتوسط.
import numpy as np
prices = np.array([100.0, 101.5, 103.2, 104.1, 106.0, 107.2])
print(np.diff(prices)) # first differences: the changes [1.5 1.7 0.9 1.9 1.2]
print(np.diff(prices, n=2)) # second differences: the change of the changes
print(np.diff(np.log(prices))) # the differenced log price is the log returnالتفاضل والارتباط الذاتي
تهيم الأسعار ولا متوسط مستقرًا لها؛ وتغيراتها غالبًا لها. وأخذ الفرق الأول (الرتبة d = 1) يزيل اتجاهًا، والثاني (d = 2) اتجاهًا منحنيًا. ثم تُظهر دالة الارتباط الذاتي (ACF) الذاكرة: قيمتها عند التأخير k هي ارتباط السلسلة بنفسها قبل k خطوة، sum((x[t] - m) * (x[t+k] - m)) / sum((x[t] - m)**2). وتدل ACF بطيئة التناقص على نموذج AR؛ وACF قريبة من الصفر عند كل التأخيرات تعني أنه لا شيء يُتنبأ به.
# The ACF of a persistent series decays slowly; the ACF of noise is near zero
import numpy as np
def acf(series, lags):
dev = series - series.mean()
total = np.sum(dev ** 2)
return np.array([np.sum(dev[:len(series) - k] * dev[k:]) / total for k in range(1, lags + 1)])
rng = np.random.default_rng(1)
noise = rng.normal(size=500)
persistent = np.empty(500)
persistent[0] = 0.0
for t in range(1, 500):
persistent[t] = 0.8 * persistent[t - 1] + noise[t] # an AR(1) with phi = 0.8
print(np.round(acf(persistent, 4), 3)) # decays slowly: 0.74, 0.58, 0.48, 0.39 in this sample
print(np.round(acf(noise, 4), 3)) # all near 0# Differencing a trending series makes its mean stable
import numpy as np
rng = np.random.default_rng(6)
trend = 100 + 0.5 * np.arange(200) + rng.normal(0, 1, size=200).cumsum() # a trending random walk
changes = np.diff(trend)
print(round(float(trend[:100].mean()), 1), round(float(trend[100:].mean()), 1)) # the level drifts: the halves differ a lot
print(round(float(changes[:100].mean()), 2), round(float(changes[100:].mean()), 2)) # the changes have a similar mean in both halvesملاءمة AR(1) والتنبؤ
يقول AR(1) إن x[t] = c + phi * x[t-1] + ضجيج. وهو انحدار خطي لكل قيمة على التي قبلها، فـphi الميل وc المقطع، من المجاميع نفسها التي في بيتا موضوع CAPM. والتنبؤ تكراري: الخطوة الأولى c + phi * last وكل لاحقة تستخدم التنبؤ السابق. وعندما |phi| < 1 تتقارب التنبؤات إلى المتوسط الطويل الأجل c / (1 - phi) بسرعة يحددها phi: سلسلة راجعة إلى المتوسط.
import numpy as np
def fit_ar1(series):
a, b = series[:-1], series[1:]
phi = np.sum((a - a.mean()) * (b - b.mean())) / np.sum((a - a.mean()) ** 2)
return float(b.mean() - phi * a.mean()), float(phi)
def forecast_ar1(last, c, phi, steps):
out, value = [], last
for _ in range(steps):
value = c + phi * value
out.append(value)
return np.array(out)
rng = np.random.default_rng(3)
x = np.empty(400)
x[0] = 2.0
for t in range(1, 400):
x[t] = 0.5 + 0.75 * x[t - 1] + rng.normal(0, 0.3) # true c = 0.5, phi = 0.75, mean 2.0
c, phi = fit_ar1(x)
print(round(c, 3), round(phi, 3))
print(np.round(forecast_ar1(4.0, c, phi, 5), 3), round(c / (1 - phi), 3))phi ذات دلالة إحصائية على هامش لا تضمن ربحًا: فالتكاليف وحجم الحركة قياسًا بالضجيج وعدم استقرار التقدير كلها مهمة. حافظ على الانضباط المعتاد: اضبط على فترة، وتنبأ بالتالية، وقارن بالتنبؤ الساذج «لا تغيير». والنموذج الذي لا يتفوق عليه لم يجد شيئًا.- ARIMA = تفاضل (I) + انحدار ذاتي (AR) + أخطاء سابقة (MA)؛ والتفاضل يحول السلسلة ذات الاتجاه إلى مستقرة.
- ACF عند التأخير
kهي ارتباط السلسلة بنفسها قبلkخطوة؛ والتناقص البطيء يشير إلى نموذج AR. - ملاءمة AR(1) هي انحدار
x[1:]علىx[:-1]؛ والتنبؤات تتغذى على بعضها وتتقارب إلىc / (1 - phi)إذا|phi| < 1؛ وتفوّق دائمًا على تنبؤ «لا تغيير».
التالي: نماذج التقلب GARCH، التنبؤ لا بمستوى العوائد بل بمدى عنف حركتها.
المختبر: ما الذي يُقيَّم
- أزل الاتجاه باستخدام
difference25 نقطة - قِس الذاكرة باستخدام
acf25 نقطة - اضبط النموذج باستخدام
fit_ar125 نقطة - انظر إلى الأمام باستخدام
forecast_ar125 نقطة