В предыдущей статьеhttps://www.fmz.com/digest-topic/4187В этом разделе мы покажем, как использовать данные и математический анализ для создания и автоматизации торговых стратегий.
Стратегия многопространственного сбалансированного баланса является естественным продолжением параллельной стратегии торговли, которая применяется к одной корзине торговых индикаторов. Она особенно применима к разнообразным и взаимосвязанным торговым рынкам, таким как рынок цифровых денег и рынок товарных фьючерсов.
Полибалансированная стратегия - это одновременная сделка на много и на мало. Как и параллельная сделка, она определяет, какие инвестиционные индексы дешевле, а какие дороже. В отличие от нее, полибалансированная стратегия выстраивает все инвестиционные индексы в один выбранный пакет акций, чтобы определить, какие инвестиционные индексы относительно дешевы или дорогие.
Помните, что мы говорили ранее, что параллельная торговля является нейтральной для рынка стратегией? То же самое касается и многопространственной балансированной стратегии, поскольку равное количество многоголовых и пустых позиций гарантирует, что стратегия будет оставаться нейтральной для рынка ("не подвержена влиянию рыночных колебаний"). Эта стратегия также является статистически стабильной; путем ранжирования инвестиций и владения несколькими позициями вы можете открывать несколько позиций в своей рейтинговой модели, а не только разовые рисковые позиции.
Рейтинговая схема - это модель, в которой приоритеты могут быть распределены по каждому индикатору в зависимости от ожидаемого показателя его эффективности. Факторы могут быть стоимостными факторами, техническими показателями, ценовыми моделями или комбинацией всех вышеперечисленных факторов. Например, вы можете использовать индикаторы динамики для ранжирования инвестиционных индикаторов, отслеживающих ряд тенденций: инвестиционные индикаторы с наибольшим потенциалом, как ожидается, будут продолжать хорошо работать и получить наивысший рейтинг; инвестиции с наименьшим потенциалом будут работать хуже и иметь наименьший уровень доходности.
Успех этой стратегии почти полностью зависит от используемой рейтинговой схемы, т.е. ваша рейтинговая схема может отделить высокопроизводительные инвестиционные показатели от низкопроизводительных инвестиционных показателей, чтобы лучше реализовать возвраты от стратегии с многопространственными инвестиционными показателями. Поэтому разработка рейтинговой схемы очень важна.
После того, как мы определили схему рейтинга, мы, очевидно, хотим извлечь выгоду из нее. Мы делаем это, вкладывая одинаковое количество средств в инвестиции в более рангированные инвестиции, а в низко рангированные инвестиции - в пустые. Это гарантирует, что стратегия будет делать деньги только пропорционально качеству рейтинга и будет "рыночно нейтральной".
Предположим, что вы занимаетесь рейтингом всех индикаторов m, имеете инвестиции в $n и хотите держать позиции на сумму 2p ((из которых m> 2p). Если индикаторы ранга 1 ожидаются наихудшими, то индикаторы ранга m ожидаются наилучшими:
Вы выбираете точку, расположенную в положении: 1,..., p, и делаете точку $2/2p пустой.
Вы расставляете свои инвестиционные марки в таких местах, как: m-p,..., m, и делаете инвестиционные марки больше n/2p долларов.
** Примечание: ** Поскольку цены на инвестиционные индикаторы, вызванные скачками цен, не всегда равномерно распределяются по n/2p, и некоторые инвестиционные индикаторы должны быть куплены в целом, то есть некоторые неточные алгоритмы, которые должны быть как можно ближе к этому числу. Для стратегии, которая работает на n = 100000 и p = 500, мы видим:
n/2p = 100000/1000 = 100
Это создает большие проблемы для цены с показателем, превышающим 100 (например, на рынке товарных фьючерсов), поскольку вы не можете занять позиции с показателем цены (этого не существует на рынке цифровых валют). Мы смягчаем ситуацию, уменьшая показатель цены или увеличивая капитал.
Во-первых, для того, чтобы работа шла гладко, нам нужно построить нашу исследовательскую среду, в которой мы будем использовать квантовую платформу для изобретателей.FMZ.COMПостроение исследовательской среды, в основном для использования платформы с удобным и быстрым интерфейсом API и полной упаковкой системы Docker.
В официальном названии платформы количественного измерения изобретателей система Docker называется системой хостеров.
Для того, чтобы узнать, как развернуть хостеров и ботов, обратитесь к моей предыдущей статье:https://www.fmz.com/bbs-topic/4140
Читатели, которые хотят купить хост для развертывания собственных облачных серверов, могут ознакомиться с этой статьей:https://www.fmz.com/bbs-topic/2848
После успешного развертывания хороших облачных сервисов и систем хостеров, следующим шагом будет установка самого большого храма Python: Anaconda.
Для реализации всех необходимых программных условий ("зависимость библиотеки, управление версиями и т. д.) самый простой способ - использовать Anaconda.
О том, как установить Anaconda, читайте в официальном руководстве:https://www.anaconda.com/distribution/
本文还将用到numpy和pandas这两个目前在Python科学计算方面十分流行且重要的库.
Вышеперечисленные основные работы также могут быть рассмотрены в моей предыдущей статье о том, как настроить среду Anaconda и две библиотеки numpy и pandas.https://www.fmz.com/digest-topic/4169
Мы создаем и ранжируем случайные инвестиционные показатели и случайные факторы. Предположим, что наши будущие доходы фактически зависят от этих показателей.
import numpy as np
import statsmodels.api as sm
import scipy.stats as stats
import scipy
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
## PROBLEM SETUP ##
# Generate stocks and a random factor value for them
stock_names = ['stock ' + str(x) for x in range(10000)]
current_factor_values = np.random.normal(0, 1, 10000)
# Generate future returns for these are dependent on our factor values
future_returns = current_factor_values + np.random.normal(0, 1, 10000)
# Put both the factor values and returns into one dataframe
data = pd.DataFrame(index = stock_names, columns=['Factor Value','Returns'])
data['Factor Value'] = current_factor_values
data['Returns'] = future_returns
# Take a look
data.head(10)
Теперь, когда у нас есть факторная стоимость и прибыль, мы можем увидеть, что происходит, если мы ранжируем инвестиционные показатели по факторной стоимости, а затем открываем многообещающие и пустые позиции.
# Rank stocks
ranked_data = data.sort_values('Factor Value')
# Compute the returns of each basket with a basket size 500, so total (10000/500) baskets
number_of_baskets = int(10000/500)
basket_returns = np.zeros(number_of_baskets)
for i in range(number_of_baskets):
start = i * 500
end = i * 500 + 500
basket_returns[i] = ranked_data[start:end]['Returns'].mean()
# Plot the returns of each basket
plt.figure(figsize=(15,7))
plt.bar(range(number_of_baskets), basket_returns)
plt.ylabel('Returns')
plt.xlabel('Basket')
plt.legend(['Returns of Each Basket'])
plt.show()
Наша стратегия заключается в том, чтобы занять первое место в бассейне инвестиционных показателей; занять десятое место в бассейне инвестиционных показателей.
basket_returns[number_of_baskets-1] - basket_returns[0]
Результат - 4.172.
Вложите деньги в нашу модель рейтинга, чтобы она могла отличать высокопроизводительные инвестиции от низкопроизводительных.
Позже в этой статье мы рассмотрим, как оценивать рейтинговые схемы. Преимущество ставки на основе рейтинга заключается в том, что она не подвержена влиянию рыночного хаоса, а может быть использована.
Мы загрузили данные о 32 акциях S&P 500 в разных отраслях и попытались их ранжировать.
from backtester.dataSource.yahoo_data_source import YahooStockDataSource
from datetime import datetime
startDateStr = '2010/01/01'
endDateStr = '2017/12/31'
cachedFolderName = '/Users/chandinijain/Auquan/yahooData/'
dataSetId = 'testLongShortTrading'
instrumentIds = ['ABT','AKS','AMGN','AMD','AXP','BK','BSX',
'CMCSA','CVS','DIS','EA','EOG','GLW','HAL',
'HD','LOW','KO','LLY','MCD','MET','NEM',
'PEP','PG','M','SWN','T','TGT',
'TWX','TXN','USB','VZ','WFC']
ds = YahooStockDataSource(cachedFolderName=cachedFolderName,
dataSetId=dataSetId,
instrumentIds=instrumentIds,
startDateStr=startDateStr,
endDateStr=endDateStr,
event='history')
price = 'adjClose'
Давайте рассмотрим стандартные показатели динамики на месячный цикл.
## Define normalized momentum
def momentum(dataDf, period):
return dataDf.sub(dataDf.shift(period), fill_value=0) / dataDf.iloc[-1]
## Load relevant prices in a dataframe
data = ds.getBookDataByFeature()[‘Adj Close’]
#Let's load momentum score and returns into separate dataframes
index = data.index
mscores = pd.DataFrame(index=index,columns=assetList)
mscores = momentum(data, 30)
returns = pd.DataFrame(index=index,columns=assetList)
day = 30
Теперь мы будем анализировать поведение наших акций, чтобы увидеть, как наши акции работают на рынке в зависимости от того, какой фактор ранжирования мы выбираем.
Акции
Давайте посмотрим, как выбранная нами корзина акций будет выглядеть в нашей модели ранжирования. Для этого давайте вычислим долгосрочную недельную отдачу всех акций. Затем мы сможем посмотреть на взаимосвязь между доходами каждой акции за неделю до этого и динамикой за предыдущие 30 дней. Акции, которые показывают положительную зависимость, следуют за тенденцией, а акции, которые показывают отрицательную зависимость, являются равномерными.
# Calculate Forward returns
forward_return_day = 5
returns = data.shift(-forward_return_day)/data -1
returns.dropna(inplace = True)
# Calculate correlations between momentum and returns
correlations = pd.DataFrame(index = returns.columns, columns = [‘Scores’, ‘pvalues’])
mscores = mscores[mscores.index.isin(returns.index)]
for i in correlations.index:
score, pvalue = stats.spearmanr(mscores[i], returns[i])
correlations[‘pvalues’].loc[i] = pvalue
correlations[‘Scores’].loc[i] = score
correlations.dropna(inplace = True)
correlations.sort_values(‘Scores’, inplace=True)
l = correlations.index.size
plt.figure(figsize=(15,7))
plt.bar(range(1,1+l),correlations[‘Scores’])
plt.xlabel(‘Stocks’)
plt.xlim((1, l+1))
plt.xticks(range(1,1+l), correlations.index)
plt.legend([‘Correlation over All Data’])
plt.ylabel(‘Correlation between %s day Momentum Scores and %s-day forward returns by Stock’%(day,forward_return_day));
plt.show()
Все наши акции возвращаются в какой-то степени равноценными! ((Очевидно, что именно так работает наш выбранный мир)) Это говорит нам, что если акция имеет высокий рейтинг в динамическом анализе, мы должны ожидать, что она будет плохо работать на следующей неделе.
Далее нам нужно посмотреть на взаимосвязь между нашими рейтинговыми показателями и перспективными доходами на рынке в целом, то есть, зависит ли предсказание ожидаемого уровня доходности от нашего рейтингового фактора, а более высокий уровень корреляции может предсказывать более низкие относительные доходы или наоборот?
Для этого мы рассчитали суточную корреляцию между 30-дневным движением всех акций и долгосрочной доходностью за неделю.
correl_scores = pd.DataFrame(index = returns.index.intersection(mscores.index), columns = [‘Scores’, ‘pvalues’])
for i in correl_scores.index:
score, pvalue = stats.spearmanr(mscores.loc[i], returns.loc[i])
correl_scores[‘pvalues’].loc[i] = pvalue
correl_scores[‘Scores’].loc[i] = score
correl_scores.dropna(inplace = True)
l = correl_scores.index.size
plt.figure(figsize=(15,7))
plt.bar(range(1,1+l),correl_scores[‘Scores’])
plt.hlines(np.mean(correl_scores[‘Scores’]), 1,l+1, colors=’r’, linestyles=’dashed’)
plt.xlabel(‘Day’)
plt.xlim((1, l+1))
plt.legend([‘Mean Correlation over All Data’, ‘Daily Rank Correlation’])
plt.ylabel(‘Rank correlation between %s day Momentum Scores and %s-day forward returns’%(day,forward_return_day));
plt.show()
Ежедневная корреляция очень шумная, но очень незначительная (это ожидается, потому что мы сказали, что все акции будут возвращаться в равной степени); мы также посмотрим на среднемесячную корреляцию доходности за месяц до этого.
monthly_mean_correl =correl_scores['Scores'].astype(float).resample('M').mean()
plt.figure(figsize=(15,7))
plt.bar(range(1,len(monthly_mean_correl)+1), monthly_mean_correl)
plt.hlines(np.mean(monthly_mean_correl), 1,len(monthly_mean_correl)+1, colors='r', linestyles='dashed')
plt.xlabel('Month')
plt.xlim((1, len(monthly_mean_correl)+1))
plt.legend(['Mean Correlation over All Data', 'Monthly Rank Correlation'])
plt.ylabel('Rank correlation between %s day Momentum Scores and %s-day forward returns'%(day,forward_return_day));
plt.show()
Мы видим, что средняя корреляция снова немного отрицательная, но она также сильно меняется с каждым месяцем.
Мы уже рассчитали доход от одной корзины акций, выведенных из нашего рейтинга. Если мы выведем все акции из нашего рейтинга и разделим их на группы nn, то какой будет средний доход каждой группы?
Первым шагом является создание функции, которая будет давать средний доход и коэффициент ранжирования для каждой корзины в месяц.
def compute_basket_returns(factor, forward_returns, number_of_baskets, index):
data = pd.concat([factor.loc[index],forward_returns.loc[index]], axis=1)
# Rank the equities on the factor values
data.columns = ['Factor Value', 'Forward Returns']
data.sort_values('Factor Value', inplace=True)
# How many equities per basket
equities_per_basket = np.floor(len(data.index) / number_of_baskets)
basket_returns = np.zeros(number_of_baskets)
# Compute the returns of each basket
for i in range(number_of_baskets):
start = i * equities_per_basket
if i == number_of_baskets - 1:
# Handle having a few extra in the last basket when our number of equities doesn't divide well
end = len(data.index) - 1
else:
end = i * equities_per_basket + equities_per_basket
# Actually compute the mean returns for each basket
#s = data.index.iloc[start]
#e = data.index.iloc[end]
basket_returns[i] = data.iloc[int(start):int(end)]['Forward Returns'].mean()
return basket_returns
Мы рассчитываем средний доход от каждой корзины, когда мы ранжируем акции по этому показателю. Это должно дать нам представление об их отношениях в течение длительного времени.
number_of_baskets = 8
mean_basket_returns = np.zeros(number_of_baskets)
resampled_scores = mscores.astype(float).resample('2D').last()
resampled_prices = data.astype(float).resample('2D').last()
resampled_scores.dropna(inplace=True)
resampled_prices.dropna(inplace=True)
forward_returns = resampled_prices.shift(-1)/resampled_prices -1
forward_returns.dropna(inplace = True)
for m in forward_returns.index.intersection(resampled_scores.index):
basket_returns = compute_basket_returns(resampled_scores, forward_returns, number_of_baskets, m)
mean_basket_returns += basket_returns
mean_basket_returns /= l
print(mean_basket_returns)
# Plot the returns of each basket
plt.figure(figsize=(15,7))
plt.bar(range(number_of_baskets), mean_basket_returns)
plt.ylabel('Returns')
plt.xlabel('Basket')
plt.legend(['Returns of Each Basket'])
plt.show()
По-видимому, мы смогли разделить высокоосуществляемых и низкоосуществляемых.
Разумеется, это только средние отношения. Чтобы понять, насколько это совпадает, и готовы ли мы к сделке, мы должны изменить с течением времени наш подход и отношение к этому. Далее мы рассмотрим их месячные разрывы за первые два года. Мы можем увидеть больше изменений и провести дальнейший анализ, чтобы определить, можно ли торговать этой динамикой.
total_months = mscores.resample('M').last().index
months_to_plot = 24
monthly_index = total_months[:months_to_plot+1]
mean_basket_returns = np.zeros(number_of_baskets)
strategy_returns = pd.Series(index = monthly_index)
f, axarr = plt.subplots(1+int(monthly_index.size/6), 6,figsize=(18, 15))
for month in range(1, monthly_index.size):
temp_returns = forward_returns.loc[monthly_index[month-1]:monthly_index[month]]
temp_scores = resampled_scores.loc[monthly_index[month-1]:monthly_index[month]]
for m in temp_returns.index.intersection(temp_scores.index):
basket_returns = compute_basket_returns(temp_scores, temp_returns, number_of_baskets, m)
mean_basket_returns += basket_returns
strategy_returns[monthly_index[month-1]] = mean_basket_returns[ number_of_baskets-1] - mean_basket_returns[0]
mean_basket_returns /= temp_returns.index.intersection(temp_scores.index).size
r = int(np.floor((month-1) / 6))
c = (month-1) % 6
axarr[r, c].bar(range(number_of_baskets), mean_basket_returns)
axarr[r, c].xaxis.set_visible(False)
axarr[r, c].set_title('Month ' + str(month))
plt.show()
plt.figure(figsize=(15,7))
plt.plot(strategy_returns)
plt.ylabel(‘Returns’)
plt.xlabel(‘Month’)
plt.plot(strategy_returns.cumsum())
plt.legend([‘Monthly Strategy Returns’,’Cumulative Strategy Returns’])
plt.show()
Наконец, если мы сделаем еще одну корзину и освободим первую корзину каждый месяц, давайте посмотрим на доходность (предположим, что распределение капитала на каждую ценную бумагу равное).
total_return = strategy_returns.sum()
ann_return = 100*((1 + total_return)**(12.0 /float(strategy_returns.index.size))-1)
print('Annual Returns: %.2f%%'%ann_return)
Годовая доходность: 5.03%
Мы видим, что у нас очень слабая система рейтинга, которая лишь умеренно отличает высокопроизводительные акции от низкопроизводительных акций. Кроме того, эта система рейтинга не является последовательной и сильно меняется с месяца на месяц.
Для реализации стратегии многопространственного сбалансированного интереса, вам фактически нужно только определить схему ранжирования. После этого все будет механическим. Как только у вас будет стратегия многопространственного сбалансированного интереса, вы сможете обмениваться различными факторами ранжирования, ничего другого не требуя больших изменений.
Рейтинговые схемы также могут быть получены практически из любой модели. Это не обязательно будет факторная модель, основанная на стоимости, это может быть технология машинного обучения, которая может предсказывать возвраты за месяц и ранжировать их в соответствии с этим рейтингом.
Рейтинговые схемы являются преимуществом и важнейшей составляющей стратегии многопространственного сбалансированного права и интересов. Выбор хорошей рейтинговой схемы - это системный процесс, и нет простых ответов.
Хорошим началом является выбор существующих известных технологий, чтобы увидеть, можете ли вы их немного изменить для получения более высокой прибыли.
Клонирование и корректировкаВыберите часто обсуждаемую тему и посмотрите, можно ли немного изменить ее, чтобы получить преимущество. Обычно публичные факторы больше не будут иметь торговых сигналов, поскольку они полностью реализованы на рынке. Однако иногда они помогают вам двигаться в правильном направлении.
Модель ценообразования: любая модель, которая предсказывает будущие доходы, может быть фактором, который потенциально может быть использован для ранжирования ваших торговых индикаторов в одной корзине. Вы можете использовать любую сложную модель ценообразования и преобразовать ее в рейтинг.
Факторы, основанные на цене (технические показатели)Примеры могут быть показатели движущегося среднего, динамического или волатильного показателей.
Возвращение и движениеПримечательно, что некоторые факторы считают, что цена движется в одном направлении и будет продолжать двигаться в том же направлении. Некоторые факторы верят в обратное. Оба являются эффективными моделями различных временных рамок и активов, и важно исследовать, основывается ли поведение на динамике или на регрессии.
Основные факторы (на основе ценности): это использование комбинации базовых ценностей, таких как PE, дивиденды и т. д. Основные ценности содержат информацию, относящуюся к реальным фактам в мире компании, и поэтому во многих отношениях могут быть сильнее цены.
В конечном счете, прогнозные факторы роста - это гонка вооружений, и вы пытаетесь остаться впереди. Факторы будут выведены из рынка и имеют срок службы, поэтому вы должны постоянно работать над тем, чтобы определить, сколько ваших факторов пережили спад, и какие новые факторы могут быть использованы для их замены.
Каждая система рейтинга прогнозирует прибыль в несколько разных временных интервалах. Средняя вертикаль возврата, основанная на цене, может быть предсказуема в течение нескольких дней, в то время как факторная модель, основанная на стоимости, может быть предсказуемой в течение нескольких месяцев. Определять временные интервалы, в которых модель должна предсказывать, очень важно, и проводить статистическую проверку перед выполнением стратегии.
У каждой стратегии есть минимальный и максимальный объем капитала, и минимальные пороги, как правило, определяются затратами на транзакцию.
Торговля слишком большим количеством акций приведет к высоким транзакционным расходам. Предположим, вы хотите купить 1000 акций, и каждый перебалансированный курс будет стоить несколько тысяч долларов. Ваша капитальная база должна быть достаточно высокой, чтобы транзакционные расходы составляли небольшую часть от прибыли от вашей стратегии.
Минимальный порог активов, в основном, зависит от количества торгуемых акций. Тем не менее, максимальная емкость также очень высока, и многопространственная стратегия балансирования может торговать сотнями миллионов долларов, не теряя преимущества. Это правда, потому что стратегия сравнительно редко перебалансируется.