Подход, использующий библиотеку Pycaret, бета-вариантность и Yahoo Finance для создания метрик для составления будущего портфеля акций.

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

До открытия Австралии люди в Старом Свете были убеждены, что все лебеди белые, и это непоколебимое убеждение, поскольку оно казалось полностью подтвержденным эмпирическими данными.” , Насим Николас Талеб

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

Модель CAPM предлагает теорию, называемую бета-дисперсией. Эту функцию можно использовать для расчета систематического риска акций путем сравнения дисперсии между акциями и другими индексами, такими как, например, индикаторы S&P500. Эта метрика может выступать в качестве фактора, который можно использовать для выбора менее нестабильной акции на основе некоторого индекса; подробнее вы можете прочитать в этой статье.

Нет больше слов, давайте погрузимся в данные!!

Чтобы организовать, я разделил этот пост на 6 больших шагов: образец, исследование, изменение, моделирование, заключение.

Все эти шаги и код доступны в этом git repo.

Образец

Во-первых, чтобы приступить к этому, нам нужно собрать акции из SP 500. С помощью простого веб-скрейпинга мы собираемся собрать значения символов акций SP500 со страницы Википедии.

#Identify after how much time they started at the SP500 after their foundation
#Show how sectors are at the SP500
#show quantity based on security
#show GICS Sub-Industry
#function to take stocks and values
import pandas as pd

def returnstocks():
    table=pd.read_html('https://en.wikipedia.org/wiki/List_of_S%26P_500_companies')
    stocksdf = table[0]
    stocksdf.to_csv('S&P500-Info.csv')
    stocksdf.to_csv("S&P500-Symbols.csv", columns=['Symbol'])
    stocksdf['Symbol'] = stocksdf['Symbol'].replace('.B','', regex=True)
    return stocksdf

def eachstock():
  myList = ['^GSPC']
  for stick in returnstocks()['Symbol'].unique(): 
    myList.insert(0, stick)
  return myList
tickers = ['^GSPC','ZTS','ZION','H','RA','YUM'..]

Функция eachstock() возвращает список акций, инициализированных SP500.

Исследовать

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

Для этого шага мы используем компонент из Википедии, и собираемся ввести нового агента yahoo Finance. У Yahoo Finance есть горячие данные с https://finance.yahoo.com, и мы можем использовать эти данные, чтобы улучшить нашу способность принимать решения, касающиеся создания портфеля акций.

#@title Yahoo Finance request and beta/Alpha calculation
#@markdown For this step, we are using the component from Wikipedia, and we are going to introduce a new agent, the yahoo finance. Yahoo Finance, has hot data from https://finance.yahoo.com, and we can use these data to improve our power to decision making, regarding to create a stocks portfolio.

yfin.pdr_override() #override method from pandas_datareader by importing data as pdr

tickers = eachstock()

#tickers = ['ZTS', 'ZION', '^GSPC']

#function for receive list of stocks, source where to search and initial date/lastdate
def stockdoublebench_returns(ticker, initialdate, lastdate): #future change ticker for returnstocks()['Symbol'].unique()
    stockdouble = yfin.download(ticker, initialdate, lastdate) #data = yf.download("SPY AAPL", period="max",)
    return stockdouble['Adj Close']

#stockdoublebench_returns #run just this command to check the volatility of each one. 

def stockdoublebench_percent(ticker, initialdate, lastdate): #future change ticker for returnstocks()['Symbol'].unique()
    stockdoublepercent = yfin.download(ticker, initialdate, lastdate)
    #return stockdouble['Adj Close']] #add this line to use the graph to compare the volatility
    return stockdoublepercent['Adj Close'].pct_change()[1:]

#alpha, beta and stock
abstocks = pd.DataFrame(columns=['Alpha', 'Beta', 'stocks']) #created dataframe

def alphabetastock(df, index): #Function for generate alpha and beta from stocks
    for col in df: #for column in dataframe do
        x = sm.add_constant(df[index].values) #create a matrix using 1 and the value
        model = sm.regression.linear_model.OLS(df[col].values,x).fit() #linear regression to get values https://www.statsmodels.org/dev/generated/statsmodels.regression.linear_model.OLS.html
        abstocks.loc[len(abstocks.index)] = [model.params[0], model.params[1], col] #add each value to the dataframe
    return abstocks #model.params[0], model.params[1], col

#need to add a new line at the df for show the predicted values from each stock, and its important add the value
#from the accuracy from test as well. 

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

Настроив нашу конфигурацию, мы можем проверить больше полезной информации.

Изменить

Нам нужно подготовить наши данные для использования, так как акции имеют высокую волатильность, чем нам нужно нормализовать наши данные, мы собираемся использовать библиотеку MinMaxScaler() из sklearn с функциями fit_transform и inverse_transform, теперь мы можем для доставки этого требования. Поскольку ARIMA дает лучшие результаты со скаляром minmax, чем с методом z-оценки, мы выберем minmax() напрямую, чтобы соответствовать и масштабировать наши данные.

stockdfs = pd.DataFrame()
def datenormalization(stockdf): 
  global stockdfs
  stockdf = stockdf.groupby('Date').sum()
  stockdf = stockdf.asfreq(freq ='D'); 
  stockdfs = stockdf.ffill() #associate frequency by day to get hollidays
  stockdfs.sort_index(ascending=True, inplace=True)
  return pd.DataFrame(stockdfs)
  
obj = '' #global variable
def scaler_fit(series):
  global obj
  scaler = MinMaxScaler()
  obj = scaler.fit(series)
  return obj

def min_max_fit(series): #normalization
  scaler_fit(series)
  scaler = MinMaxScaler()
  series[list(series.columns)] = scaler.fit_transform(series)
  return series

def min_max_inverse(series, obj): #denormalization
  series[list(series.columns)] = obj.inverse_transform(series)
  return series

Модель

Модели ARIMA используют разность для преобразования нестационарных временных рядов в стационарные, а затем прогнозируют будущие значения на основе исторических данных. Эти модели используют автоматические корреляции и скользящие средние по остаточным ошибкам в данных для прогнозирования будущих значений. https://www.capitalone.com/tech/machine-learning/understanding-arima-models/

Настройка модели

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

Во-первых, мы просто создаем нашу настройку, передавая значения fh (горизонта прогноза), а кратность используется для перекрестной проверки. Аргумент session_id используется для доставки случайного числа для этой настройки.

fh: Горизонт прогноза — это период времени в будущем, на который должны быть подготовлены прогнозы.

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



После процесса настройки нам нужно выбрать модель, так как у меня уже есть выбор модели ARIMA. Если вы хотите, чтобы Pycaret выбрал/протестировал лучший алгоритм для вас, вы можете использовать функцию compare-models(), вы можете проверить глубже через pycaret документация.

Создать модель

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

Определите и прочитайте показатели

Сходство показателей стенда (MAE и MRSE)

1 — Стенд метрик выражает среднюю ошибку на основе прогнозируемой модели относительно исходного кода (поезд/тест).

2 — они находятся в диапазоне от 0 до бесконечности и возвращают ошибку величины.

3 — ближе к нулю (0), лучше значение.

Подробнее: MAE и MRSE

Проверка результатов — созданная модель

Создать модель

Доработка модели

На данный момент полученные результаты оправдывают ожидания, мы будем дорабатывать модель.

Построить прогнозные значения — на 5 вперед.

Поскольку мы создали нашу модель, мы прогнозируем 5 дней для будущих значений.

Разрабатываем все вместе

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

Весь алгоритм работает в соответствии с приведенным ниже рабочим процессом:

minmax() → setup() → финализировать модель() → предсказать модель() → inverseminmax() → mergeresults() → Dataframe[] → проверка → Delviery

 #@title Engineering All to Predict Stocks
 #@markdown Engineering to predict all 500 stocks
from pycaret.time_series import *

pred_unseen_deno = pd.DataFrame()
dffdstocks = pd.DataFrame()
transpredicted = pd.DataFrame()
dfstocks = pd.DataFrame()
dfstocks.iloc[0:0]

def train_and_normalize(stock, initialdate, finaldate, predictdays, predictdaysx, crossvalidation):
  global pred_unseen_deno
  global transpredicted
  stock_returns = datenormalization(stockdoublebench_returns(stock, initialdate, finaldate))
  print(stock_returns)
  exp2 = setup(min_max_fit(stock_returns[['Adj Close']]), fh = predictdays, fold = crossvalidation, session_id = 123)
  arima2 = exp2.create_model('arima')
  #pred_holdout = predict_model(arima2) 
  pred_unseen_deno = min_max_inverse(predict_model(exp2.finalize_model(arima2), fh = predictdaysx), obj)
  #if you need to see the pred_holdout value
  #pred_unseen_deno = min_max_inverse(predict_model(finalize_model(arima2), fh = predictdaysx), obj)
  transpredicted = pred_unseen_deno.T
  transpredicted['stocks'] = stock
  return transpredicted

def iterate_predicted_stocks(initialdate, finaldate, predictdays,predictdaysx, crossvalidation): 
  global dffdstocks
  global dfstocks
  for value in (abstocksna['stocks']):
    try: 
      train_and_normalize(value, initialdate, finaldate, predictdays, predictdaysx,crossvalidation) 
      dffdstocks = dffdstocks.append(transpredicted, ignore_index = True)
      dfstocks = pd.merge(dffdstocks, abstocks, on='stocks')
    except:
      continue
  return dfstocks
  #We are going to use this function to start up our algoritm to predict future values. 
#initial date, last date, predictdays(for test), predictdate for future to be used after last date, and how 
#many values fold we are going to use for cross validation.

abstocks = alphabetastock(stockdoublebench_percent(tickers, '2015-01-01', '2022-12-25'),'^GSPC')
abstocksna = abstocks.dropna()
iterate_predicted_stocks('2015-01-01', '2022-12-25', 30, 10 ,5) 

Функция Alphastastock() сначала вызывается для вычисления всех значений из альфы и беты, после чего значения сохраняются в фрейме данных abstocksna, после чего функция iterate_predicted_stocks() начинает выполнять итерацию и доставляет каждое значение в нашу функцию train_and_normalize(). , видя это, мы предлагаем начальную дату, конечную дату, тестовый набор (30), прогнозируемое значение для будущего (10), а 5 — это количество, используемое для перекрестной проверки.

Заключение

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

Дальнейшие шаги

  • Увеличьте окончательный фрейм данных новыми значениями, чтобы лучше принимать решения.
  • Многокритериальный алгоритм для определения портфеля акций.
  • Оптимизируйте будущий портфель.