Исследовательские отчеты о многофакторной модели фондового рынка являются объемными, с богатыми теориями и практиками. Независимо от количества валют, общей рыночной стоимости, объема торговли, рынка производных продуктов и т. Д. на рынке цифровой валюты достаточно провести исследование факторов.
Фактор может рассматриваться как индикатор и выражение может быть написано. Фактор постоянно меняется, отражая будущую информацию о доходах. Как правило, фактор представляет собой инвестиционную логику.
Например, предположение, лежащее в основе фактора ценового закрытия, заключается в том, что цена акций может предсказывать будущие доходы, и чем выше цена акций, тем выше будут будущие доходы (или могут быть ниже). На самом деле, построение портфеля на основе этого фактора является инвестиционной моделью / стратегией для покупки высокоценных акций в регулярном раунде.
Как фондовый рынок, так и рынок цифровой валюты являются сложными системами. Нет фактора, который мог бы полностью предсказать будущую прибыль, но у них все еще есть определенная предсказуемость. Эффективный альфа (режим инвестирования) постепенно станет недействительным с большим вложением капитала. Однако этот процесс приведет к появлению других моделей на рынке, тем самым рождая новую альфу. Фактор рыночной стоимости раньше был очень эффективной стратегией на рынке акций А. Просто покупайте 10 акций с самой низкой рыночной стоимостью и корректируйте их один раз в день.
Поисковые факторы служат основой для разработки стратегии.Лучшая стратегия может быть построена путем объединения нескольких независимых эффективных факторов.
import requests
from datetime import date,datetime
import time
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import requests, zipfile, io
%matplotlib inline
До сих пор ежечасовые K-линейные данные бинарных USDT-вечных фьючерсов с начала 2022 года до сих пор превысили 150 валют. Как мы упоминали ранее, факторная модель - это модель выбора валюты, которая ориентирована на все валюты, а не на определенную валюту. К-линейные данные включают в себя открытие высоких и закрытие низких цен, объем торговли, количество транзакций, объем покупки покупателя и другие данные. Эти данные, конечно, не являются источником всех факторов, таких как индекс акций США, ожидание роста процентных ставок, прибыльность, данные о цепочке, популярность социальных сетей и так далее. Необычные источники данных также могут найти эффективную альфу, но базовый объем цен также достаточен.
## Current trading pair
Info = requests.get('https://fapi.binance.com/fapi/v1/exchangeInfo')
symbols = [s['symbol'] for s in Info.json()['symbols']]
symbols = list(filter(lambda x: x[-4:] == 'USDT', [s.split('_')[0] for s in symbols]))
print(symbols)
Выйти:
['BTCUSDT', 'ETHUSDT', 'BCHUSDT', 'XRPUSDT', 'EOSUSDT', 'LTCUSDT', 'TRXUSDT', 'ETCUSDT', 'LINKUSDT',
'XLMUSDT', 'ADAUSDT', 'XMRUSDT', 'DASHUSDT', 'ZECUSDT', 'XTZUSDT', 'BNBUSDT', 'ATOMUSDT', 'ONTUSDT',
'IOTAUSDT', 'BATUSDT', 'VETUSDT', 'NEOUSDT', 'QTUMUSDT', 'IOSTUSDT', 'THETAUSDT', 'ALGOUSDT', 'ZILUSDT',
'KNCUSDT', 'ZRXUSDT', 'COMPUSDT', 'OMGUSDT', 'DOGEUSDT', 'SXPUSDT', 'KAVAUSDT', 'BANDUSDT', 'RLCUSDT',
'WAVESUSDT', 'MKRUSDT', 'SNXUSDT', 'DOTUSDT', 'DEFIUSDT', 'YFIUSDT', 'BALUSDT', 'CRVUSDT', 'TRBUSDT',
'RUNEUSDT', 'SUSHIUSDT', 'SRMUSDT', 'EGLDUSDT', 'SOLUSDT', 'ICXUSDT', 'STORJUSDT', 'BLZUSDT', 'UNIUSDT',
'AVAXUSDT', 'FTMUSDT', 'HNTUSDT', 'ENJUSDT', 'FLMUSDT', 'TOMOUSDT', 'RENUSDT', 'KSMUSDT', 'NEARUSDT',
'AAVEUSDT', 'FILUSDT', 'RSRUSDT', 'LRCUSDT', 'MATICUSDT', 'OCEANUSDT', 'CVCUSDT', 'BELUSDT', 'CTKUSDT',
'AXSUSDT', 'ALPHAUSDT', 'ZENUSDT', 'SKLUSDT', 'GRTUSDT', '1INCHUSDT', 'CHZUSDT', 'SANDUSDT', 'ANKRUSDT',
'BTSUSDT', 'LITUSDT', 'UNFIUSDT', 'REEFUSDT', 'RVNUSDT', 'SFPUSDT', 'XEMUSDT', 'BTCSTUSDT', 'COTIUSDT',
'CHRUSDT', 'MANAUSDT', 'ALICEUSDT', 'HBARUSDT', 'ONEUSDT', 'LINAUSDT', 'STMXUSDT', 'DENTUSDT', 'CELRUSDT',
'HOTUSDT', 'MTLUSDT', 'OGNUSDT', 'NKNUSDT', 'SCUSDT', 'DGBUSDT', '1000SHIBUSDT', 'ICPUSDT', 'BAKEUSDT',
'GTCUSDT', 'BTCDOMUSDT', 'TLMUSDT', 'IOTXUSDT', 'AUDIOUSDT', 'RAYUSDT', 'C98USDT', 'MASKUSDT', 'ATAUSDT',
'DYDXUSDT', '1000XECUSDT', 'GALAUSDT', 'CELOUSDT', 'ARUSDT', 'KLAYUSDT', 'ARPAUSDT', 'CTSIUSDT', 'LPTUSDT',
'ENSUSDT', 'PEOPLEUSDT', 'ANTUSDT', 'ROSEUSDT', 'DUSKUSDT', 'FLOWUSDT', 'IMXUSDT', 'API3USDT', 'GMTUSDT',
'APEUSDT', 'BNXUSDT', 'WOOUSDT', 'FTTUSDT', 'JASMYUSDT', 'DARUSDT', 'GALUSDT', 'OPUSDT', 'BTCUSDT',
'ETHUSDT', 'INJUSDT', 'STGUSDT', 'FOOTBALLUSDT', 'SPELLUSDT', '1000LUNCUSDT', 'LUNA2USDT', 'LDOUSDT',
'CVXUSDT']
print(len(symbols))
Выйти:
153
#Function to obtain any period of K-line
def GetKlines(symbol='BTCUSDT',start='2020-8-10',end='2021-8-10',period='1h',base='fapi',v = 'v1'):
Klines = []
start_time = int(time.mktime(datetime.strptime(start, "%Y-%m-%d").timetuple()))*1000 + 8*60*60*1000
end_time = min(int(time.mktime(datetime.strptime(end, "%Y-%m-%d").timetuple()))*1000 + 8*60*60*1000,time.time()*1000)
intervel_map = {'m':60*1000,'h':60*60*1000,'d':24*60*60*1000}
while start_time < end_time:
mid_time = start_time+1000*int(period[:-1])*intervel_map[period[-1]]
url = 'https://'+base+'.binance.com/'+base+'/'+v+'/klines?symbol=%s&interval=%s&startTime=%s&endTime=%s&limit=1000'%(symbol,period,start_time,mid_time)
res = requests.get(url)
res_list = res.json()
if type(res_list) == list and len(res_list) > 0:
start_time = res_list[-1][0]+int(period[:-1])*intervel_map[period[-1]]
Klines += res_list
if type(res_list) == list and len(res_list) == 0:
start_time = start_time+1000*int(period[:-1])*intervel_map[period[-1]]
if mid_time >= end_time:
break
df = pd.DataFrame(Klines,columns=['time','open','high','low','close','amount','end_time','volume','count','buy_amount','buy_volume','null']).astype('float')
df.index = pd.to_datetime(df.time,unit='ms')
return df
start_date = '2022-1-1'
end_date = '2022-09-14'
period = '1h'
df_dict = {}
for symbol in symbols:
df_s = GetKlines(symbol=symbol,start=start_date,end=end_date,period=period,base='fapi',v='v1')
if not df_s.empty:
df_dict[symbol] = df_s
symbols = list(df_dict.keys())
print(df_s.columns)
Выйти:
Index(['time', 'open', 'high', 'low', 'close', 'amount', 'end_time', 'volume',
'count', 'buy_amount', 'buy_volume', 'null'],
dtype='object')
Данные, которые нас интересуют: цена закрытия, цена открытия, объем торговли, количество сделок и доля покупателей, сначала извлекаются из данных K-линии.
df_close = pd.DataFrame(index=pd.date_range(start=start_date, end=end_date, freq=period),columns=df_dict.keys())
df_open = pd.DataFrame(index=pd.date_range(start=start_date, end=end_date, freq=period),columns=df_dict.keys())
df_volume = pd.DataFrame(index=pd.date_range(start=start_date, end=end_date, freq=period),columns=df_dict.keys())
df_buy_ratio = pd.DataFrame(index=pd.date_range(start=start_date, end=end_date, freq=period),columns=df_dict.keys())
df_count = pd.DataFrame(index=pd.date_range(start=start_date, end=end_date, freq=period),columns=df_dict.keys())
for symbol in df_dict.keys():
df_s = df_dict[symbol]
df_close[symbol] = df_s.close
df_open[symbol] = df_s.open
df_volume[symbol] = df_s.volume
df_count[symbol] = df_s['count']
df_buy_ratio[symbol] = df_s.buy_amount/df_s.amount
df_close = df_close.dropna(how='all')
df_open = df_open.dropna(how='all')
df_volume = df_volume.dropna(how='all')
df_count = df_count.dropna(how='all')
df_buy_ratio = df_buy_ratio.dropna(how='all')
В целом показатели рыночного индекса мрачны: с начала года до последних дней он упал на 60%.
df_norm = df_close/df_close.fillna(method='bfill').iloc[0] #normalization
df_norm.mean(axis=1).plot(figsize=(15,6),grid=True);
#Final index profit chart
Метод регрессии Доходность следующего периода - зависимая переменная, а проверяемый фактор - независимая переменная. Коэффициент, полученный регрессией, также является доходностью фактора. После построения регрессионного уравнения, валидность и волатильность факторов обычно рассматриваются по отношению к абсолютному среднему значению значения t коэффициента, доле последовательности абсолютных значений значения t коэффициента, превышающей 2, годовой доходности фактора, годовой волатильности прибыли фактора и коэффициенту Шарпа коэффициента прибыли фактора. Некоторые факторы могут быть регрессированы одновременно.
IC, IR и другие показатели Так называемый IC - это коэффициент корреляции между фактором и показателем доходности следующего периода. Теперь RANK_ IC также используется в целом, это коэффициент корреляции между рейтингом факторов и следующим показателем доходности акций.
Метод стратифицированной регрессии В этой статье мы будем использовать этот метод, который заключается в том, чтобы сортировать валюты в соответствии с факторами, которые должны быть протестированы, разделить их на N групп для группового обратного тестирования и использовать фиксированный период для корректировки позиции. Если ситуация идеальна, процент доходности валют группы N будет показывать хорошую монотонность, увеличиваясь или уменьшаясь монотонно, и разрыв в доходах каждой группы большой. Такие факторы отражаются в хорошей дискриминации. Если первая группа имеет наибольшую прибыль, а последняя группа имеет наименьшую прибыль, то зайдите в первую группу и зайдите в последнюю группу, чтобы получить конечную доходность, которая является эталонным показателем коэффициента Шарпа.
Монеты, которые должны быть выбраны, делятся на 3 группы на основе ранжирования факторов от самого маленького до самого большого. Каждая группа валют составляет около 1/3 от общего количества. Если фактор эффективен, чем меньше количество пунктов в каждой группе, тем выше будет коэффициент возврата, но это также означает, что каждая валюта имеет относительно больше средств, выделенных. Если длинные и короткие позиции являются двойным плечо, соответственно, и первая группа и последняя группа - 10 валют соответственно, то одна валюта составляет 10% от общего количества. Если валюта, которая является короткой, удвоена, то 20% выводится; Если количество групп составляет 50, то 4% будет выведено. Диверсификация валют может снизить риск черных лебедей.
Как правило, способность к предсказанию факторов может быть приблизительно оценена в соответствии со скоростью возврата и соотношением Шарпа окончательного бэкстеста. Кроме того, это также должно относиться к тому, является ли выражение фактора простым, чувствительным к размеру группировки, чувствительным к интервалу корректировки положения и чувствительным к начальному времени бэкстеста.
Что касается частоты корректировки позиции, то на фондовом рынке обычно есть период 5 дней, 10 дней и один месяц. Однако для рынка цифровой валюты такой период, несомненно, слишком длинный, и рынок в реальном боте отслеживается в режиме реального времени. Не нужно придерживаться определенного периода, чтобы снова корректировать позиции. Поэтому в реальном боте мы корректируем позиции в режиме реального времени или в короткий промежуток времени.
Как закрыть позицию, согласно традиционному методу, позиция может быть закрыта, если она не в группе при сортировке в следующий раз. Однако в случае корректировки позиции в режиме реального времени некоторые валюты могут находиться прямо на границе, что может привести к закрытию позиции вперед и назад. Поэтому эта стратегия использует метод ожидания изменений группировки, а затем закрыть позицию, когда позиция в противоположном направлении должна быть открыта. Например, первая группа идет в длинный. Когда валюты в статусе длинной позиции разделены на третью группу, затем закрыть позицию и идти в короткий. Если позиция закрыта в фиксированный период, например, каждый день или каждые 8 часов, вы также можете закрыть позицию, не будучи в группе. Постарайтесь как можно больше.
#Backtest engine
class Exchange:
def __init__(self, trade_symbols, fee=0.0004, initial_balance=10000):
self.initial_balance = initial_balance #Initial assets
self.fee = fee
self.trade_symbols = trade_symbols
self.account = {'USDT':{'realised_profit':0, 'unrealised_profit':0, 'total':initial_balance, 'fee':0, 'leverage':0, 'hold':0}}
for symbol in trade_symbols:
self.account[symbol] = {'amount':0, 'hold_price':0, 'value':0, 'price':0, 'realised_profit':0,'unrealised_profit':0,'fee':0}
def Trade(self, symbol, direction, price, amount):
cover_amount = 0 if direction*self.account[symbol]['amount'] >=0 else min(abs(self.account[symbol]['amount']), amount)
open_amount = amount - cover_amount
self.account['USDT']['realised_profit'] -= price*amount*self.fee #Net of fees
self.account['USDT']['fee'] += price*amount*self.fee
self.account[symbol]['fee'] += price*amount*self.fee
if cover_amount > 0: #Close position first
self.account['USDT']['realised_profit'] += -direction*(price - self.account[symbol]['hold_price'])*cover_amount #Profits
self.account[symbol]['realised_profit'] += -direction*(price - self.account[symbol]['hold_price'])*cover_amount
self.account[symbol]['amount'] -= -direction*cover_amount
self.account[symbol]['hold_price'] = 0 if self.account[symbol]['amount'] == 0 else self.account[symbol]['hold_price']
if open_amount > 0:
total_cost = self.account[symbol]['hold_price']*direction*self.account[symbol]['amount'] + price*open_amount
total_amount = direction*self.account[symbol]['amount']+open_amount
self.account[symbol]['hold_price'] = total_cost/total_amount
self.account[symbol]['amount'] += direction*open_amount
def Buy(self, symbol, price, amount):
self.Trade(symbol, 1, price, amount)
def Sell(self, symbol, price, amount):
self.Trade(symbol, -1, price, amount)
def Update(self, close_price): #Update assets
self.account['USDT']['unrealised_profit'] = 0
self.account['USDT']['hold'] = 0
for symbol in self.trade_symbols:
if not np.isnan(close_price[symbol]):
self.account[symbol]['unrealised_profit'] = (close_price[symbol] - self.account[symbol]['hold_price'])*self.account[symbol]['amount']
self.account[symbol]['price'] = close_price[symbol]
self.account[symbol]['value'] = abs(self.account[symbol]['amount'])*close_price[symbol]
self.account['USDT']['hold'] += self.account[symbol]['value']
self.account['USDT']['unrealised_profit'] += self.account[symbol]['unrealised_profit']
self.account['USDT']['total'] = round(self.account['USDT']['realised_profit'] + self.initial_balance + self.account['USDT']['unrealised_profit'],6)
self.account['USDT']['leverage'] = round(self.account['USDT']['hold']/self.account['USDT']['total'],3)
#Function of test factor
def Test(factor, symbols, period=1, N=40, value=300):
e = Exchange(symbols, fee=0.0002, initial_balance=10000)
res_list = []
index_list = []
factor = factor.dropna(how='all')
for idx, row in factor.iterrows():
if idx.hour % period == 0:
buy_symbols = row.sort_values().dropna()[0:N].index
sell_symbols = row.sort_values().dropna()[-N:].index
prices = df_close.loc[idx,]
index_list.append(idx)
for symbol in symbols:
if symbol in buy_symbols and e.account[symbol]['amount'] <= 0:
e.Buy(symbol,prices[symbol],value/prices[symbol]-e.account[symbol]['amount'])
if symbol in sell_symbols and e.account[symbol]['amount'] >= 0:
e.Sell(symbol,prices[symbol], value/prices[symbol]+e.account[symbol]['amount'])
e.Update(prices)
res_list.append([e.account['USDT']['total'],e.account['USDT']['hold']])
return pd.DataFrame(data=res_list, columns=['total','hold'],index = index_list)
Фактор объема торговли: простые длинные валюты с низким объемом торговли и короткие валюты с высоким объемом торговли, который работает очень хорошо, что указывает на то, что популярные валюты имеют тенденцию к снижению.
Фактор цены торговли: эффект от длинных валют с низкими ценами и коротких валют с высокими ценами являются обычными.
Фактор количества транзакций: производительность очень похожа на объем транзакций. Очевидно, что корреляция между фактором объема транзакций и фактором количества транзакций очень высока. Фактически, средняя корреляция между ними в разных валютах достигла 0,97, что указывает на то, что два фактора очень похожи. Этот фактор необходимо учитывать при синтезе нескольких факторов.
3h импульсный фактор: (df_close - df_close. shift (3)) /df_ close. shift(3). То есть 3-часовой рост фактора. Результаты бэкстеста показывают, что 3-часовой рост имеет явные регрессивные характеристики, то есть рост легче падать позже. Общая производительность в порядке, но также существует длительный период отступления и колебаний.
Фактор импульса в 24 часа: результат 24-часового периода корректировки позиции хорош, урожайность аналогична импульсу в 3 часа, а отвод меньше.
Коэффициент изменения объема транзакций: df_ volume.rolling(24).mean() /df_ volume.rolling (96). mean(), то есть соотношение объема транзакций за последний день к объему транзакций за последние три дня. Позиция корректируется каждые 8 часов. Результаты обратного тестирования были хорошими, а вывод также был относительно низким, что указывает на то, что те, у кого активный объем транзакций, более склонны к снижению.
Коэффициент изменения числа транзакций: df_ count.rolling ((24).mean() /df_ count.rolling ((96). mean (), то есть соотношение числа транзакций за последний день к числу транзакций за последние три дня. Позиция корректируется каждые 8 часов. Результаты обратного тестирования были хорошими, а вывод также относительно низкий, что указывает на то, что те, у кого активный объем транзакций, были более склонны к снижению.
Коэффициент изменения стоимости одной сделки: - ((df_volume.rolling(24).mean()/df_count.rolling(24.mean())/(df_volume.rolling(24.mean()/df_count.rolling(96.mean()) , то есть соотношение стоимости транзакции последнего дня к стоимости транзакции последних трех дней, и позиция будет корректироваться каждые 8 часов. Этот фактор также сильно коррелирует с коэффициентом объема транзакций.
Коэффициент изменения покупателя по пропорции транзакции: df_buy_ratio.rolling ((24).mean() /df_buy_ratio.rolling ((96).mean(), то есть соотношение покупателя по объему к общему объему транзакций за последний день к стоимости транзакций за последние три дня, и позиция будет корректироваться каждые 8 часов. Этот фактор работает довольно хорошо и имеет небольшую корреляцию с фактором объема транзакций.
Фактор волатильности: (df_close/df_open).rolling(24).std(), ходить длинные валюты с низкой волатильностью, это имеет определенный эффект.
Коэффициент корреляции между объемом сделок и ценой закрытия: df_close.rolling ((96).corr ((df_volume), цена закрытия за последние четыре дня имеет коэффициент корреляции объема сделок, который в целом хорошо развился.
Факторы, перечисленные здесь, основаны на объеме цены. На самом деле комбинация формул факторов может быть очень сложной без очевидной логики. Вы можете обратиться к известному методу построения факторов ALPHA101:https://github.com/STHSF/alpha101.
#transaction volume
factor_volume = df_volume
factor_volume_res = Test(factor_volume, symbols, period=4)
factor_volume_res.total.plot(figsize=(15,6),grid=True);
#transaction price
factor_close = df_close
factor_close_res = Test(factor_close, symbols, period=8)
factor_close_res.total.plot(figsize=(15,6),grid=True);
#transaction count
factor_count = df_count
factor_count_res = Test(factor_count, symbols, period=8)
factor_count_res.total.plot(figsize=(15,6),grid=True);
print(df_count.corrwith(df_volume).mean())
0.9671246744996017
#3h momentum factor
factor_1 = (df_close - df_close.shift(3))/df_close.shift(3)
factor_1_res = Test(factor_1,symbols,period=1)
factor_1_res.total.plot(figsize=(15,6),grid=True);
#24h momentum factor
factor_2 = (df_close - df_close.shift(24))/df_close.shift(24)
factor_2_res = Test(factor_2,symbols,period=24)
tamenxuanfactor_2_res.total.plot(figsize=(15,6),grid=True);
#factor of transaction volume
factor_3 = df_volume.rolling(24).mean()/df_volume.rolling(96).mean()
factor_3_res = Test(factor_3, symbols, period=8)
factor_3_res.total.plot(figsize=(15,6),grid=True);
#factor of transaction number
factor_4 = df_count.rolling(24).mean()/df_count.rolling(96).mean()
factor_4_res = Test(factor_4, symbols, period=8)
factor_4_res.total.plot(figsize=(15,6),grid=True);
#factor correlation
print(factor_4.corrwith(factor_3).mean())
0.9707239580854841
#single transaction value factor
factor_5 = -(df_volume.rolling(24).mean()/df_count.rolling(24).mean())/(df_volume.rolling(24).mean()/df_count.rolling(96).mean())
factor_5_res = Test(factor_5, symbols, period=8)
factor_5_res.total.plot(figsize=(15,6),grid=True);
print(factor_4.corrwith(factor_5).mean())
0.861206620552479
#proportion factor of taker by transaction
factor_6 = df_buy_ratio.rolling(24).mean()/df_buy_ratio.rolling(96).mean()
factor_6_res = Test(factor_6, symbols, period=4)
factor_6_res.total.plot(figsize=(15,6),grid=True);
print(factor_3.corrwith(factor_6).mean())
0.1534572192503726
#volatility factor
factor_7 = (df_close/df_open).rolling(24).std()
factor_7_res = Test(factor_7, symbols, period=2)
factor_7_res.total.plot(figsize=(15,6),grid=True);
#correlation factor between transaction volume and closing price
factor_8 = df_close.rolling(96).corr(df_volume)
factor_8_res = Test(factor_8, symbols, period=4)
factor_8_res.total.plot(figsize=(15,6),grid=True);
Безусловно, наиболее важной частью процесса построения стратегии является постоянное открытие новых эффективных факторов, но без хорошего метода синтеза факторов отличный единственный альфа-фактор не может играть свою максимальную роль.
Метод равного веса: все факторы, которые должны быть синтезированы, добавляются с равными весами, чтобы получить новые факторы после синтеза.
Метод взвешивания исторического коэффициента возврата факторов: все факторы, которые должны быть объединены, добавляются в соответствии с арифметическим средним исторического коэффициента возврата факторов в последний период в качестве веса для получения нового фактора после синтеза.
Максимальный метод взвешивания IC_IR: среднее значение IC композитного фактора за определенный период истории используется в качестве оценки значения IC композитного фактора в следующем периоде, а ковариантная матрица исторического значения IC используется в качестве оценки волатильности композитного фактора в следующем периоде.
Анализ основных компонентов (PCA): PCA является распространенным методом уменьшения размерности данных, и корреляция между факторами может быть высокой.
В данном документе будет ссылаться на присвоение фактора валидности вручную.ae933a8c-5a94-4d92-8f33-d92b70c36119.pdf
При тестировании одиночных факторов сортировка фиксирована, но мультифакторный синтез должен объединять совершенно разные данные, поэтому все факторы должны быть стандартизированы, и крайнее значение и недостающее значение должны быть устранены в целом.
#standardize functions, remove missing values and extreme values, and standardize
def norm_factor(factor):
factor = factor.dropna(how='all')
factor_clip = factor.apply(lambda x:x.clip(x.quantile(0.2), x.quantile(0.8)),axis=1)
factor_norm = factor_clip.add(-factor_clip.mean(axis=1),axis ='index').div(factor_clip.std(axis=1),axis ='index')
return factor_norm
df_volume_norm = norm_factor(df_volume)
factor_1_norm = norm_factor(factor_1)
factor_6_norm = norm_factor(factor_6)
factor_7_norm = norm_factor(factor_7)
factor_8_norm = norm_factor(factor_8)
factor_total = 0.6*df_volume_norm + 0.4*factor_1_norm + 0.2*factor_6_norm + 0.3*factor_7_norm + 0.4*factor_8_norm
factor_total_res = Test(factor_total, symbols, period=8)
factor_total_res.total.plot(figsize=(15,6),grid=True);
В статье представлен метод тестирования одного фактора и тестирования общих одиночных факторов, и первоначально представлен метод синтеза мультифактора. Однако существует много исследовательского содержания мультифактора. Каждый пункт, упомянутый в статье, может быть дополнительно разработан. Это осуществимый способ превратить исследование различных стратегий в исследование альфа-фактора. Использование методологии фактора может значительно ускорить проверку торговых идей, и есть много материалов для ссылки.
Настоящий бот из:https://www.fmz.com/robot/486605