Modelo de Fator de Moeda Digital

Autora:Lydia., Criado: 2022-10-24 17:37:50, Atualizado: 2023-09-15 20:59:38

img

Quadro do modelo de factores

Os relatórios de pesquisa sobre o modelo multifator do mercado de ações são volumosos, com teorias e práticas ricas. Não importa o número de moedas, valor total de mercado, volume de negociação, mercado de derivativos, etc. no mercado de moeda digital, é suficiente realizar pesquisa de fatores. Este artigo é principalmente para iniciantes em estratégias quantitativas e não envolverá princípios matemáticos complexos e análise estatística.

O fator pode ser considerado como um indicador e uma expressão pode ser escrita. O fator muda constantemente, refletindo a informação de renda futura. Geralmente, o fator representa uma lógica de investimento.

Por exemplo, a suposição por trás do fator de preço de fechamento é que o preço das ações pode prever ganhos futuros, e quanto maior o preço das ações, maiores serão os ganhos futuros (ou podem ser menores). Na verdade, a construção de um portfólio baseado neste fator é um modelo/estratégia de investimento para comprar ações de alto preço em uma rodada regular.

Tanto o mercado de ações quanto o mercado de moeda digital são sistemas complexos. Não há nenhum fator que possa prever completamente os lucros futuros, mas eles ainda têm uma certa previsibilidade. O alfa efetivo (modo de investimento) gradualmente se tornará inválido com mais entrada de capital. No entanto, esse processo produzirá outros modelos no mercado, dando origem a um novo alfa. O fator de valor de mercado costumava ser uma estratégia muito eficaz no mercado de ações A. Basta comprar 10 ações com o valor de mercado mais baixo e ajustá-las uma vez por dia. Desde 2007, o backtest de 10 anos renderá mais de 400 vezes os lucros, superando em muito o mercado geral. No entanto, o teste de ações de cavalo branco em 2017 reflete o fracasso do fator de valor de mercado pequeno, e o fator de valor tornou-se popular. Portanto, precisamos constantemente verificar e tentar usar o equilíbrio alfa.

Os factores procurados são a base para o estabelecimento de estratégias, uma melhor estratégia pode ser construída através da combinação de múltiplos factores eficazes não relacionados.

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

Recursos de dados

Até agora, os dados de linha K por hora dos futuros perpétuos Binance USDT desde o início de 2022 até agora ultrapassaram 150 moedas. Como mencionamos anteriormente, o modelo de fator é um modelo de seleção de moeda, que é orientado para todas as moedas em vez de uma determinada moeda. Os dados de linha K incluem preços altos e baixos de abertura e fechamento, volume de negociação, número de transações, volume de compra do tomador e outros dados. Estes dados certamente não são a fonte de todos os fatores, como o índice de ações dos EUA, a expectativa de aumento da taxa de juros, a lucratividade, os dados sobre a cadeia, a popularidade das mídias sociais e assim por diante. Fontes de dados incomuns também podem encontrar alfa eficaz, mas o volume de preço básico também é suficiente.

## 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)

Fora:

['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))

Fora:

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)

Fora:

Index(['time', 'open', 'high', 'low', 'close', 'amount', 'end_time', 'volume',
       'count', 'buy_amount', 'buy_volume', 'null'],
      dtype='object')

Os dados que nos interessam: preço de fechamento, preço de abertura, volume de negociação, número de transações e proporção de compra do tomador são extraídos dos dados da linha K em primeiro lugar. Com base nesses dados, os fatores necessários são processados.

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')

O desempenho global do índice de mercado é sombrio, tendo caído 60% desde o início do ano até aos últimos dias.

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

img

Julgamento da validade dos fatores

  • Método de regressão O rendimento do período seguinte é a variável dependente, e o fator a ser testado é a variável independente. O coeficiente obtido por regressão também é o rendimento do fator. Após a equação de regressão ser construída, a validade e a volatilidade dos fatores são geralmente vistas em referência ao valor médio absoluto do valor do coeficiente t, a proporção da sequência de valores absolutos do valor do coeficiente t maior que 2, o retorno do fator anualizado, a volatilidade do lucro do fator anualizado e a proporção de Sharpe do fator lucro. Vários fatores podem ser regressos de uma vez.

  • IC, IR e outros indicadores O chamado IC é o coeficiente de correlação entre o fator e a taxa de retorno do próximo período. Agora, RANK_ IC também é usado geralmente, é o coeficiente de correlação entre a classificação de fatores e a taxa de retorno do próximo estoque. IR é geralmente o valor médio da sequência IC / o desvio padrão da sequência IC.

  • Método de regressão estratificada Neste artigo, usaremos esse método, que é classificar as moedas de acordo com os fatores a serem testados, dividi-las em N grupos para backtesting de grupo e usar um período fixo para ajuste de posição. Se a situação for ideal, a taxa de retorno das moedas do Grupo N mostrará uma boa monotonia, aumentando ou diminuindo monotonicamente, e a diferença de renda de cada grupo é grande. Tais fatores se refletem em uma boa discriminação. Se o primeiro grupo tiver os maiores lucros e o último grupo tiver os menores lucros, então vá longo no primeiro grupo e vá curto no último grupo para obter o rendimento final, que é o indicador de referência do rácio Sharp.

Operação de backtest real

As moedas a serem selecionadas são divididas em 3 grupos com base na classificação dos fatores do menor ao maior. Cada grupo de moedas representa cerca de 1/3 do total. Se um fator for eficaz, quanto menor o número de pontos em cada grupo, maior será a taxa de retorno, mas isso também significa que cada moeda tem relativamente mais fundos alocados. Se as posições longas e curtas forem dupla alavancagem, respectivamente, e o primeiro grupo e o último grupo forem 10 moedas, respectivamente, então uma moeda representa 10% do total. Se uma moeda que é curta é duplicada, então 20% é retirada; Se o número de grupos for 50, então 4% será retirada. As moedas diversificadas podem reduzir o risco de cisnes negros. Vá longo o primeiro grupo (fator de valor mínimo), vá para o terceiro grupo. Quanto maior o fator e o número de renda maior, você pode simplesmente transformar o fator curto e a posição curta ou curta em um retorno recíproco ou negativo.

Geralmente, a capacidade de previsão de fatores pode ser avaliada aproximadamente de acordo com a taxa de retorno e a proporção de Sharpe do backtest final. Além disso, também precisa se referir se a expressão do fator é simples, sensível ao tamanho do agrupamento, sensível ao intervalo de ajuste de posição e sensível ao tempo inicial do backtest.

No que diz respeito à frequência de ajuste de posição, o mercado de ações geralmente tem um período de 5 dias, 10 dias e um mês. No entanto, para o mercado de moeda digital, esse período é sem dúvida muito longo, e o mercado no bot real é monitorado em tempo real. Não é necessário aderir a um período específico para ajustar novamente as posições. Portanto, no bot real, ajustamos as posições em tempo real ou em um curto período de tempo.

No entanto, no caso do ajuste de posição em tempo real, algumas moedas podem estar apenas no limite, o que pode levar ao fechamento de posição para trás e para frente. Portanto, esta estratégia adota o método de esperar por mudanças de agrupamento e, em seguida, fechar a posição quando a posição na direção oposta precisa ser aberta. Por exemplo, o primeiro grupo vai longo. Quando as moedas no status de posição longa são divididas no terceiro grupo, então feche a posição e vá curto. Se a posição for fechada em um período fixo, como todos os dias ou a cada 8 horas, você também pode fechar a posição sem estar em um grupo. Tente mais quanto puder.

#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)

Teste de fatores simples

Fator de volume de negociação: moedas longas simples com baixo volume de negociação e moedas curtas com alto volume de negociação, que apresentam um desempenho muito bom, indicando que as moedas populares tendem a diminuir.

Fator de preço de negociação: o efeito de curto prazo de moedas com preços baixos e curto prazo de moedas com preços elevados são comuns.

Fator de número de transações: O desempenho é muito semelhante ao volume de transações. É óbvio que a correlação entre o fator de volume de transações e o fator de número de transações é muito alta. Na verdade, a correlação média entre eles em diferentes moedas atingiu 0,97, indicando que os dois fatores são muito semelhantes. Este fator precisa ser levado em conta ao sintetizar vários fatores.

3h fator de momento: (df_close - df_close. shift (3)) /df_ close. shift(3). Ou seja, o aumento de 3 horas do fator. Os resultados do backtest mostram que o aumento de 3 horas tem características de regressão óbvias, ou seja, o aumento é mais fácil de cair mais tarde. O desempenho geral é OK, mas também há um longo período de retirada e oscilação.

Fator de impulso de 24 horas: o resultado do período de ajustamento de posição de 24 horas é bom, o rendimento é semelhante ao impulso de 3 horas e a retirada é menor.

Fator de mudança do volume de transações: df_ volume.rolling(24).mean() /df_ volume. rolling (96). mean(), ou seja, a relação do volume de transações no último dia com o volume de transações nos últimos três dias. A posição é ajustada a cada 8h. Os resultados do backtesting foram bons e a retirada também foi relativamente baixa, indicando que aqueles com volume de transações ativo eram mais propensos a diminuir.

Fator de mudança do número de transações: df_ count.rolling ((24).mean() /df_ count.rolling ((96). mean (), ou seja, a proporção do número de transações no último dia para o número de transações nos últimos três dias. A posição é ajustada a cada 8h. Os resultados do backtesting foram bons e a retirada também é relativamente baixa, o que indica que aqueles com volume de transações ativas eram mais propensos a diminuir.

Fator de variação do valor de uma única transacção: - ((df_volume.rolling(24).mean()/df_count.rolling(24.mean())/(df_volume.rolling(24.mean()/df_count.rolling(96.mean()) , ou seja, a relação entre o valor da transacção do último dia e o valor da transacção dos últimos três dias, e a posição será ajustada a cada 8h. Este fator também está altamente correlacionado com o fator de volume de transacções.

Fator de mudança do tomador por proporção de transação: df_buy_ratio.rolling ((24).mean() /df_buy_ratio.rolling ((96).mean(), ou seja, a proporção do tomador por volume ao volume total de transações no último dia ao valor de transações nos últimos três dias, e a posição será ajustada a cada 8 horas.

Fator de volatilidade: (df_close/df_open).rolling ((24).std ((), ir longo moedas com baixa volatilidade, tem um certo efeito.

Fator de correlação entre o volume de transacções e o preço de encerramento: df_close.rolling ((96).corr ((df_volume), o preço de encerramento nos últimos quatro dias tem um fator de correlação do volume de transacções, que teve um bom desempenho em geral.

Os fatores listados aqui são baseados no volume do preço. Na verdade, a combinação de fórmulas de fatores pode ser muito complexa sem lógica óbvia.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);

img

#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);

img

#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);

img

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);

img

#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);

img

#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);

img

#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);

img

#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);

img

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);

img

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);

img

#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);

img

Síntese multifatorial

É certamente a parte mais importante do processo de construção de estratégia descobrir novos fatores eficazes constantemente, mas sem um bom método de síntese de fatores, um excelente fator alfa único não pode desempenhar seu papel máximo.

Método de igual peso: todos os fatores a sintetizar são adicionados com pesos iguais para obter novos fatores após a síntese.

Método de ponderação da taxa de retorno do fator histórico: todos os fatores a serem combinados são adicionados de acordo com a média aritmética da taxa de retorno do fator histórico no último período como o peso para obter um novo fator após a síntese.

Método de ponderação de IC_IR maximizar: o valor médio de IC do fator composto durante um período da história é usado como a estimativa do valor de IC do fator composto no período seguinte, e a matriz de covariância do valor histórico de IC é usada como a estimativa da volatilidade do fator composto no período seguinte.

Análise de componentes principais (PCA): O PCA é um método comum para a redução da dimensionalidade dos dados, e a correlação entre os fatores pode ser alta.

Este documento irá fazer referência à atribuição de validade do fator manualmente.ae933a8c-5a94-4d92-8f33-d92b70c36119.pdf

Ao testar fatores únicos, a classificação é fixa, mas a síntese de múltiplos fatores precisa combinar dados completamente diferentes, então todos os fatores precisam ser padronizados e o valor extremo e o valor faltante precisam ser removidos em geral.

#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);

img

Resumo

Este artigo introduz o método de teste de fator único e testa fatores comuns e inicialmente introduz o método de síntese de fator múltipla. No entanto, há muitos conteúdos de pesquisa de fator múltipla. Cada ponto mencionado no artigo pode ser desenvolvido ainda mais. É uma maneira viável de transformar a pesquisa em várias estratégias na exploração do fator alfa. O uso da metodologia de fator pode acelerar muito a verificação de ideias de negociação e há muitos materiais para referência.

O verdadeiro robô de:https://www.fmz.com/robot/486605


Relacionados

Mais.