Использование линейного адаптивного фильтра LMS для прогнозирования цен на фондовом рынке

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

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

Временная последовательность

временной ряд - это серия точек данных, проиндексированных (или занесенных в список или нанесенных на график) во временном порядке.

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

Для более практичной ситуации мы будем использовать цены акций ABEV3 (ON) в течение 178 дней 2019 года. Если вы считаете, что к таким данным трудно получить доступ, вы ошибаетесь . Я получил эти данные на веб-сайте b3, официальном бразильском фондовом рынке, и это бесплатно :)

Хорошо, когда у нас есть данные, давайте поговорим об алгоритме.

LMS фильтр

LMS-фильтр - это своего рода адаптивный фильтр, который используется для решения линейных задач. Идея фильтра состоит в том, чтобы имитировать систему (найти коэффициенты фильтра) путем минимизации наименьшего среднего квадрата сигнала ошибки.

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

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

Система

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

Когда мы применяем фильтр LMS, мы обучаем фильтр первым 178 данным. После этого мы установим ошибку равной нулю, поэтому система начнет выводить ответы как исходная система с последними значениями l. Мы будем называть сложную модификацию алгоритмом LMSPred.

Наконец, давайте начнем писать код!

Сначала нам нужно импортировать библиотеки, которые мы будем использовать в этом коде:

import numpy as np
import matplotlib.pyplot as plt

Следующим шагом является реализация LMSPred, вы можете попробовать самостоятельно, глядя на псевдокод, вот моя реализация:

def lmsPred(x,l,u,N):
    xd= np.block([np.zeros((1,l)), x]).T
    y=np.zeros((len(xd),1))
    xn=np.zeros((N+1,1))
    xn = np.matrix(xn)
    wn=np.random.rand(N+1,1)/10
    M=len(xd)
    for n in range(0,M):
        xn = np.block([[xd[n]], [xn[0:N]]]);
        y[n]= np.matmul(wn.T, xn);
        if(n>M-l-1):
            e =0;
        else:
            e=int(x[n]-y[n]);
        wn = wn + 2*u*e*xn;
        
    return y,wn;

Теперь мы определим наш вектор x, который имеет 178 значений ABEV3 (ON):

x = np.array([1655, 1648, 1615, 1638, 1685, 1729, 1754, 1770, 1780, 1785, 1800, 1800, 1754, 1718, 1716, 1795, 1787, 1797, 1751, 1811, 1845, 1864, 1809, 1875, 1822, 1871, 1867, 1839, 1859, 1849, 1819, 1832, 1815, 1832, 1832, 1839, 1849, 1836, 1723, 1683, 1637, 1669, 1659, 1711, 1700, 1690, 1666, 1676, 1731, 1719, 1700, 1698, 1672, 1652, 1699, 1654, 1675, 1683, 1682, 1677, 1684, 1732, 1744, 1735, 1769, 1755, 1725, 1706, 1742, 1753, 1705, 1708, 1750, 1767, 1772, 1831, 1829, 1835, 1847, 1795, 1792, 1806, 1765, 1792, 1749, 1730, 1701, 1694, 1661, 1664, 1649, 1649, 1709, 1721, 1721, 1706, 1722, 1731, 1726, 1743, 1755, 1742, 1735, 1741, 1764, 1761, 1765, 1772, 1768, 1785, 1764, 1780, 1805, 1820, 1845, 1830, 1817, 1810, 1805, 1789, 1781, 1813, 1887, 1900, 1900, 1894, 1902, 1869, 1820, 1825, 1810, 1799, 1825, 1809, 1799, 1803, 1796, 1949, 1980, 2050, 2034, 2013, 2042, 2049, 2016, 2048, 2063, 2017, 2007, 1948, 1938, 1901, 1878, 1890, 1911, 1894, 1880, 1847, 1833, 1809, 1817, 1815, 1855, 1872, 1838, 1852, 1880, 1869, 1872, 1887, 1882, 1891, 1937, 1910, 1915, 1943, 1926, 1935]);

Для обучения системы мы возьмем первые 173 значения со скоростью обучения 2 ^ (- 30), порядком фильтрации N = 60 и l = 5 дней прогнозирования.

x_train = x[0:173]
u = 2**(-30);
l=5;
N=60;
y,wn = lmsPred(x_train,l,u,N)

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

plt.plot(x, color = 'black')
plt.plot(y, color = 'red')
plt.show()

И чтобы оценить процентную ошибку нашего прогноза:

pred = y[-l:]
realvalues = x[-l]
error = 100*(pred.T-realvalues)/realvalues
print(abs(error))

Итак, полный код:

import numpy as np
import matplotlib.pyplot as plt
def lmsPred(x,l,u,N):
    xd= np.block([np.zeros((1,l)), x]).T
    y=np.zeros((len(xd),1))
    xn=np.zeros((N+1,1))
    xn = np.matrix(xn)
    wn=np.random.rand(N+1,1)/10
    M=len(xd)
    for n in range(0,M):
        xn = np.block([[xd[n]], [xn[0:N]]]);
        y[n]= np.matmul(wn.T, xn);
        if(n>M-l-1):
            e =0;
        else:
            e=int(x[n]-y[n]);
        wn = wn + 2*u*e*xn;
        
    return y,wn;
x = np.array([1655, 1648, 1615, 1638, 1685, 1729, 1754, 1770, 1780, 1785, 1800, 1800, 1754, 1718, 1716, 1795, 1787, 1797, 1751, 1811, 1845, 1864, 1809, 1875, 1822, 1871, 1867, 1839, 1859, 1849, 1819, 1832, 1815, 1832, 1832, 1839, 1849, 1836, 1723, 1683, 1637, 1669, 1659, 1711, 1700, 1690, 1666, 1676, 1731, 1719, 1700, 1698, 1672, 1652, 1699, 1654, 1675, 1683, 1682, 1677, 1684, 1732, 1744, 1735, 1769, 1755, 1725, 1706, 1742, 1753, 1705, 1708, 1750, 1767, 1772, 1831, 1829, 1835, 1847, 1795, 1792, 1806, 1765, 1792, 1749, 1730, 1701, 1694, 1661, 1664, 1649, 1649, 1709, 1721, 1721, 1706, 1722, 1731, 1726, 1743, 1755, 1742, 1735, 1741, 1764, 1761, 1765, 1772, 1768, 1785, 1764, 1780, 1805, 1820, 1845, 1830, 1817, 1810, 1805, 1789, 1781, 1813, 1887, 1900, 1900, 1894, 1902, 1869, 1820, 1825, 1810, 1799, 1825, 1809, 1799, 1803, 1796, 1949, 1980, 2050, 2034, 2013, 2042, 2049, 2016, 2048, 2063, 2017, 2007, 1948, 1938, 1901, 1878, 1890, 1911, 1894, 1880, 1847, 1833, 1809, 1817, 1815, 1855, 1872, 1838, 1852, 1880, 1869, 1872, 1887, 1882, 1891, 1937, 1910, 1915, 1943, 1926, 1935]);
x_train = x[0:173]
u = 2**(-30);
l=5;
N=60;
y,wn = lmsPred(x_train,l,u,N)
plt.plot(x, color = 'black')
plt.plot(y, color = 'red')
plt.show()
pred = y[-l:]
realvalues = x[-l]
error = 100*(pred.T-realvalues)/realvalues
print(abs(error))

Полученные результаты

Мы выбрали черный в качестве реальных данных и красный в качестве нашего прогноза, как вы можете видеть, изначально. они сильно различаются, но ближе к значению, соответствующему порядку фильтрации (в данном случае 60), две кривые очень близки.

И для этого случая погрешность вывода в процентах за день составляет:

[[0.79837693 1.12168626 1.24557245 2.24050302 3.16604697]]

Итак, 5-й день имеет ошибку 3,16%, что является довольно хорошим значением, поскольку мы используем очень простой метод.

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

Если у вас есть вопросы, вы можете подписаться на меня в моем профиле LinkedIn!