میانگین متحرک وزن دار در پایتون — راهنمای گام به گام

۴۷۰ بازدید
آخرین به‌روزرسانی: ۰۷ شهریور ۱۴۰۲
زمان مطالعه: ۵ دقیقه
میانگین متحرک وزن دار در پایتون — راهنمای گام به گام

در مطالب گذشته مجله فراردس، با میانگین متحرک ساده (SMA)، میانگین متحرک نمایی (EMA) و میانگین متحرک نمایی دوگانه و سه‌گانه آشنا شدیم. در این آموزش، روش پیاده سازی میانگین متحرک وزن دار در پایتون را شرح می‌دهیم.

میانگین متحرک وزن دار

علاوه بر روش وزن‌دهی نمایی، می‌توان وزن‌دهی خطی را نیز استفاده کرد. به این روش، میانگین متحرک وزن‌دار (Weighted Moving Average) یا WMA گفته می‌شود که بعضاً با اسم میانگین متحرک وزن‌دار زمانی (Time Weighted Moving Average) یا TWMA نیز شناخته می‌شود.

در این روش نیز به داده‌های اخیر وزن بیشتری داده می‌شود و تأخیر کمتری نسبت به میانگین متحرک ساده ایجاد می‌شود. وزن‌ها، با یکدیگر یک دنباله عددی ایجاد می‌کنند که مجموع آن‌ها برابر $$1$$ است. برای مثال اگر طول پنجره برابر $$3$$ باشد، میانگین متحرک وزن‌دار به شکل زیر محاسبه می‌شود:

$$ W M A_{t}=\sum_{i=1}^{3} w_{i} x_{t-i+1}=w_{1} x_{t}+w_{2} x_{t-1}+w_{3} x_{t-2} $$

برای وزن‌ها می‌توان روابط زیر را نوشت:

$$\begin{aligned}
w_{1}-w_{2}& =w_{2}-w_{3}=d \\
w_{1}+w_{2}+w_{3}&=1
\end{aligned} $$

به این ترتیب، با حل روابط، مقادیر وزن‌ها به شکل زیر محاسبه می‌شود:

$$ \begin{aligned}
&w_{1}=\frac{3}{6} \\
&w_{2}=\frac{2}{6} \\
&w_{3}=\frac{1}{6}
\end{aligned} $$

به این ترتیب، قدر نسبت بین وزن‌ها برابر $$\frac 1 6 $$ بوده و مجموع وزن‌ها نیز برابر $$1$$ است.

برای یادگیری برنامه‌نویسی با زبان پایتون، پیشنهاد می‌کنیم به مجموعه آموزش‌های مقدماتی تا پیشرفته پایتون فرادرس مراجعه کنید که لینک آن در ادامه آورده شده است.

محاسبه وزن‌ها در پایتون

وارد محیط برنامه‌نویسی پایتون شده و کتابخانه‌های مورد نیاز را فراخوانی می‌کنیم:

1import numpy as np
2import matplotlib.pyplot as plt

سپس تنظیمات مربوط به نمودار را تعیین می‌کنیم:

1plt.style.use('ggplot')

حال طول بازه را تعیین می‌کنیم:

1L = 15

اکنون می‌توانیم یک دنباله هندسی با قدر نسبت $$1$$ تولید کنیم:

1W = np.arange(start=L, stop=0, step=-1)

می‌دانیم که مجموع آرایه وزن‌ها، برابر $$1$$ نخواهد بود، به همین دلیل باید تمامی وزن‌ها را به مجموع مقادیر وزن‌ها تقسیم کنیم:

1W = W / W.sum()

حال اگر مجموع مقادیر وزن‌ها را نشان دهیم:

1print(f'Sum of Weights are: {np.sum(W)}')

خروجی به صورت زیر خواهد بود:

Sum of Weights are: 1.0

برای بررسی قدر نسبت بین وزن‌ها نیز می‌توان نوشت:

1D = W[:-1] - W[1:]
2
3print(f'Difference of Weights are:\n{D}')

که در این خروجی نیز خواهیم داشت:

Difference of Weights are:
[0.00833333 0.00833333 0.00833333
 0.00833333 0.00833333 0.00833333
 0.00833333 0.00833333 0.00833333
 0.00833333 0.00833333 0.00833333
 0.00833333 0.00833333]

به این ترتیب، مشاهده می‌کنیم که اختلاف وزن‌ها با هم برابر بوده و مجموعه نیز برای 1 است.

می‌توان در نموداری رابطه وزن‌ها را با یکدیگر نشان داد:

1plt.bar(np.arange(L), W, width=0.3, color='lime')
2plt.title(f'Weighted for L={L}')
3plt.xlabel('Lag')
4plt.ylabel('Weight')
5plt.xticks(np.arange(L))
6plt.show()

و نمودار زیر حاصل می‌شود.

میانگین متحرک وزن دار در پایتون

به این ترتیب، مشاهده می‌کنیم که آخرین روز، بیشترین وزن را دارد و در طی یک روند خطی، با دور شدن از آخرین روز، وزن داده نیز کاهش می‌یابد.

پیاده‌سازی میانگین متحرک وزن دار در پایتون

پیاده‌سازی میانگین متحرک وزن‌دار در پایتون، ابتدا کتابخانه‌های زیر را فراخوانی می‌کنیم:

1import numpy as np
2import pandas as pd
3import yfinance as yf
4import matplotlib.pyplot as plt

حال تنظیمات نمودارها را اعمال کرده و داده مورد نیاز را دریافت می‌کنیم:

1plt.style.use('ggplot')
2
3Ticker = yf.Ticker('AAPL')
4DF = Ticker.history(interval='1d', start='2021-01-01', end='2022-01-01')

در دو سطر کد فوق، نماد مربوط به شرکت Apple تعریف شده و سپس داده قیمت روزانه مربوط به یک سال از آن در قالب یک دیتافریم (Data Frame) دریافت می‌شود.

حال می‌توانیم پنج سطر ابتدایی داده را مشاهده کنیم:

1print(DF.head())

که خواهیم داشت:

                  Open        High         Low       Close     Volume  Dividends  Stock Splits
Date
2020-12-31  133.088923  133.744048  130.746367  131.709198   99116600        0.0             0
2021-01-04  132.533082  132.622413  125.823047  128.453461  143301900        0.0             0
2021-01-05  127.937271  130.766210  127.480664  130.041595   97664900        0.0             0
2021-01-06  126.775939  130.081327  125.445840  125.664215  155088000        0.0             0
2021-01-07  127.411211  130.657044  126.914907  129.952286  109578200        0.0             0

به این ترتیب، مشاهده می‌کنیم که مجموعه داده به‌درستی دریافت شده است.

حال می‌توانیم مقادیر ستون Close را تبدیل به یک آرایه کرده و یک نمودار خطی (Line Plot) برای قیمت آن رسم کنیم:

1S = DF['Close'].to_numpy()
2
3plt.semilogy(S, lw=0.9, c='crimson')
4plt.title('AAPL 1 Year Historical Price')
5plt.xlabel('Time (Day)')
6plt.ylabel('Price ($)')
7plt.show()

به این ترتیب، شکل زیر را خواهیم داشت.

میانگین متحرک وزن‌دار در پایتون

به این ترتیب نمودار قیمت حاصل شد.

حال تابعی برای محاسبه میانگین متحرک وزن‌دار ایجاد می‌کنیم که در ورودی، داده سری زمانی و طول بازه میانگین‌گیری را دریافت می‌کند:

1def WMA(S:np.ndarray, L:int):

اکنون می‌توانیم ماتریس وزن را داخل تابع محاسبه کنیم:

1def WMA(S:np.ndarray, L:int):
2    W = np.arange(start=1, stop=L+1, step=1)
3    W = W / W.sum()

توجه داشته باشید که آخرین روز داده، در انتهای پنجره زمانی قرار دارد، به همین دلیل، ماتریس وزن باید به صورت صعودی ایجاد شود.

حال اندازه سری ورودی و سایز سری خروجی را محاسبه می‌کنیم:

1def WMA(S:np.ndarray, L:int):
2    W = np.arange(start=1, stop=L+1, step=1)
3    W = W / W.sum()
4    nD0 = S.size
5    nD = nD0 - L + 1

حال یک آرایه خالی برای ذخیره مقدار میانگین متحرک ایجاد می‌کنیم:

1def WMA(S:np.ndarray, L:int):
2    W = np.arange(start=1, stop=L+1, step=1)
3    W = W / W.sum()
4    nD0 = S.size
5    nD = nD0 - L + 1
6    wma = np.zeros(nD)

حال می‌توانیم یک حلقه ایجاد کرده و مقدار را برای هر روز محاسبه کنیم و در نهایت ماتریس خروجی را برگردانیم:

1def WMA(S:np.ndarray, L:int):
2    W = np.arange(start=1, stop=L+1, step=1)
3    W = W / W.sum()
4    nD0 = S.size
5    nD = nD0 - L + 1
6    wma = np.zeros(nD)
7    for i in range(nD):
8        wma[i] = np.multiply(S[i:i + L], W).sum()
9    return wma

توجه داشته باشید که تابع np.multiply اعضای دو ماتریس ورودی را نظیر به نظیر به همدیگر ضرب می‌کند. برای گرفتن مجموع، باید از متد sum استفاده کنیم.

حال برای استفاده از تابع پیاده‌سازی شده، به شکل زیر عمل می‌کنیم:

1wma = WMA(S, 15)

حال برای رسم نمودار، به شکل زیر عمل می‌کنیم:

1T = np.arange(S.size)
2
3plt.semilogy(T, S, lw=0.9, c='crimson', label='Price')
4plt.semilogy(T[-wma.size:], wma, lw=0.9, c='teal', label='WMA(15)')
5plt.title('AAPL 1 Year Historical Price')
6plt.xlabel('Time (Day)')
7plt.ylabel('Price ($)')
8plt.legend()
9plt.show()

به این ترتیب، نمودار زیر حاصل می‌شود.

نمودار میانگین

به این ترتیب، میانگین متحرک وزن‌دار محاسبه شده، به خوبی نقش حمایت و مقاومت را ایفا می‌کند.

برای مقایسه رفتار میانگین متحرک ساده، نمایی و وزن‌دار، ابتدا توابع مربوط به آن‌ها را وارد برنامه می‌کنیم:

1def SMA(S:np.ndarray, L:int):
2    nD0 = np.size(S)
3    nD = nD0 - L + 1
4    sma = np.zeros(nD)
5    for i in range(nD):
6        sma[i] = np.mean(S[i:i + L])
7    return sma
8
9def EMA(S:np.ndarray, L:int, r:float=1):
10    a = (1 + r) / (L + r)
11    nD0 = S.size
12    nD = nD0 - L + 1
13    ema = np.zeros(nD)
14    ema[0] = np.mean(S[:L])
15    for i in range(1, nD):
16        ema[i] = a * S[i+L-1] + (1-a) * ema[i-1]
17    return ema

حال به شکل زیر هر سه اندیکاتور را محاسبه کرده و نمودار را رسم می‌کنیم:

1sma = SMA(S, 30)
2ema = EMA(S, 30)
3wma = WMA(S, 30)
4
5T = np.arange(S.size)
6
7plt.semilogy(T, S, lw=0.9, c='crimson', label='Price')
8plt.semilogy(T[-sma.size:], sma, lw=0.9, c='teal', label='SMA(30)')
9plt.semilogy(T[-ema.size:], ema, lw=0.9, c='k', label='EMA(30)')
10plt.semilogy(T[-wma.size:], wma, lw=0.9, c='lime', label='WMA(30)')
11plt.title('AAPL 1 Year Historical Price')
12plt.xlabel('Time (Day)')
13plt.ylabel('Price ($)')
14plt.legend()
15plt.show()

که نمودار زیر حاصل می‌شود.

میانگین متحرک وزن دار

به این ترتیب مشاهده می‌کنیم که میانگین متحرک وزن‌دار، رفتار نسبتاً بهتری از خود نشان می‌دهد.

جمع‌بندی

در این آموزش، میانگین متحرک وزن‌دار را بررسی و پیاده‌سازی و در نهایت مزیت آن نسبت به سایر روش‌ها که قبلاً بررسی شده بودند را مطالعه کردیم.

برای مطالعه بیشتر می‌توان موارد زیر را بررسی کرد:

  1. تقاطع کدام دو میانگین متحرک می‌تواند سیگنال بهتری برای رشد یا ریزش قیمت باشد؟
  2. کدام میانگین متحرک با شیب بیشتری به تغییر جهت واکنش نشان می‌دهد؟
  3. از بین میانگین متحرک نمایی و میانگین متحرک وزن‌دار، کدامیک سطوح معتبرتری را نشان می‌دهد؟

مطلبی که در بالا مطالعه کردید بخشی از مجموعه مطالب «آموزش پیاده‌سازی انواع میانگین های متحرک‌ در پایتون» است. در ادامه، می‌توانید فهرست این مطالب را ببینید:

بر اساس رای ۱۲ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
مجله فرادرس
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *