3
focar em
1444
Seguidores

Modelo de fator de criptomoeda

Criado em: 2022-09-27 16:10:28, atualizado em: 2024-12-02 21:31:13
comments   12
hits   12085

[TOC]

Modelo de fator de criptomoeda

Estrutura do modelo de fator

Existem inúmeros relatórios de pesquisa sobre o modelo multifatorial do mercado de ações, com rica teoria e prática. O mercado de moeda digital é suficiente para pesquisa de fatores em termos de número de moedas, valor total de mercado, volume de transações, mercado de derivativos, etc. Este artigo é voltado principalmente para iniciantes em estratégias quantitativas e não envolverá princípios matemáticos complexos e análise estatística. Tomando o mercado futuro como fonte de dados, uma estrutura simples de pesquisa de fatores é construída para facilitar a avaliação de indicadores de fatores.

Um fator pode ser visto como um indicador e pode ser escrito como uma expressão. Fatores mudam continuamente e refletem informações de retorno futuro. Normalmente, fatores representam uma lógica de investimento.

Por exemplo, o fator preço de fechamento é baseado na suposição de que os preços das ações podem prever retornos futuros. Quanto maior o preço das ações, maiores os retornos futuros (ou menores os retornos). Construir um portfólio com base neste fator é, na verdade, um investimento modelo/estratégia de rotação regular de posições para comprar ações de alto preço. Em termos gerais, os fatores que podem gerar consistentemente retornos excedentes são frequentemente chamados de Alfa. Por exemplo, fatores de capitalização de mercado e fatores de momentum foram verificados pela academia e pela comunidade de investimentos como fatores eficazes.

Seja o mercado de ações ou o mercado de moeda digital, é um sistema complexo. Nenhum fator pode prever completamente os retornos futuros, mas ainda tem um certo grau de previsibilidade. O alfa efetivo (modelo de investimento) gradualmente se torna ineficaz à medida que mais fundos são investidos. Mas esse processo gerará outros modelos no mercado, dando origem a novos alfas. O fator de capitalização de mercado já foi uma estratégia muito eficaz no mercado de ações A. Basta comprar 10 ações com a menor capitalização de mercado e ajustá-las uma vez por dia. O backtest de dez anos de 2007 ganhará mais de 400 vezes o retorno, muito superando o mercado em geral. . No entanto, o mercado de ações de primeira linha em 2017 refletiu a ineficácia do fator de pequena capitalização de mercado, enquanto o fator de valor se tornou popular. Portanto, é necessário equilibrar e experimentar constantemente entre a verificação e o uso do alfa.

Os fatores que buscamos são a base para estabelecer estratégias. Melhores estratégias podem ser construídas combinando múltiplos fatores efetivos 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

Fonte de dados

Até agora, os dados horários da linha K dos futuros perpétuos USDT da Binance, do início de 2022 até o presente, ultrapassaram 150 moedas. Conforme mencionado anteriormente, o modelo de fatores é um modelo de seleção de moedas que tem como alvo todas as moedas e não apenas uma moeda específica. Os dados da linha K incluem dados como preços altos de abertura e baixos de fechamento, volume de negociação, número de transações, volume de compra ativa, etc. Esses dados certamente não são a fonte de todos os fatores, como o índice de ações dos EUA, expectativas de aumento da taxa de juros , lucratividade, dados on-chain, atenção nas mídias sociais, etc. Fontes de dados menos populares também podem revelar alfa efetivo, mas dados básicos de volume e preço também são suficientes.

## 当前交易对
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)

Out:

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

Out:

153

#获取任意周期K线的函数
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)

Out:

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

Inicialmente, extraímos os dados de interesse dos dados da linha K: preço de fechamento, preço de abertura, volume de negociação, número de transações e taxa de compra ativa, e usamos esses dados como base para processar os fatores necessários.

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

Olhando para o desempenho do índice de mercado, pode-se dizer que ele é bastante sombrio, com uma queda de 60% desde o início do ano.

df_norm = df_close/df_close.fillna(method='bfill').iloc[0] #归一化
df_norm.mean(axis=1).plot(figsize=(15,6),grid=True);
#最终指数收益图

Modelo de fator de criptomoeda

Determinação da validade fatorial

  • Método de regressão A taxa de retorno do próximo período é tomada como variável dependente, o fator a ser testado é tomado como variável independente e o coeficiente obtido pela regressão é a taxa de retorno do fator. Após construir a equação de regressão, normalmente nos referimos à média absoluta do valor do coeficiente t, à proporção da sequência de valores absolutos do valor do coeficiente t maior que 2, ao retorno anualizado do fator, à volatilidade do retorno anualizado do fator, ao índice de Sharpe de o retorno do fator e outros parâmetros. Eficácia e volatilidade do fator. Você pode regredir vários fatores de uma só vez. Consulte a documentação do barra para obter detalhes.

  • 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. RANK_IC é geralmente usado agora, que é o coeficiente de correlação entre a classificação do fator e a taxa de retorno da ação do próximo período. IR é geralmente a média da sequência IC/o desvio padrão da sequência IC.

  • Regressão hierárquica Este artigo usará este método, que consiste em classificar os fatores a serem testados, dividir as moedas em N grupos para backtesting em grupo e usar um período fixo para ajustar as posições. Se a situação for ideal, os rendimentos de N grupos de moedas mostrarão boa monotonicidade, aumentando ou diminuindo monotonicamente, e a diferença de rendimento entre cada grupo será grande. Tais fatores se refletem em melhor discriminação. Se o primeiro grupo tiver o maior retorno e o último grupo tiver o menor retorno, então vá longo no primeiro grupo e curto no último grupo. A taxa final de retorno é um indicador de referência do índice de Sharpe.

Operação de backtesting real

De acordo com os fatores, as moedas selecionadas são divididas em 3 grupos de acordo com a classificação de pequeno a grande. Cada grupo de moedas responde por cerca de 13. Se um fator for eficaz, quanto menor a proporção de cada grupo, maior será rendimento, mas também significa que os fundos alocados para cada moeda são relativamente grandes. Se as posições longas e curtas forem alavancadas 1x cada, e o primeiro e o último grupos forem 10 moedas, respectivamente, então cada um representa 10%. Se uma moeda que é aumentos em curto prazo, se o valor do investimento aumentar em 2 vezes, o retrocesso será de 20%; correspondentemente, se o número de grupos for 50, o retrocesso será de 4%. Diversificar moedas pode reduzir o risco de cisnes negros. Posicione-se longo no primeiro grupo (com o menor valor de fator) e curto no terceiro grupo. Se quanto maior o fator, maior o retorno, você pode inverter as posições longas e curtas ou simplesmente tornar o fator negativo ou inverso.

O poder preditivo de um fator geralmente pode ser avaliado aproximadamente com base no retorno do backtest final e no índice de Sharpe. Além disso, também é necessário verificar se a expressão fatorial é simples, insensível ao tamanho do agrupamento, insensível ao intervalo de ajuste de posição, insensível ao tempo inicial do backtest, etc.

Em relação à frequência de ajuste de posição, o mercado de ações geralmente tem um ciclo de 5 dias, 10 dias e um mês, mas para o mercado de moeda digital, esse ciclo é, sem dúvida, muito longo, e as condições de mercado no mercado real são monitoradas em tempo real, então é difícil manter um ciclo específico. Não há necessidade de ajustar as posições novamente, então, na negociação real, ajustamos as posições em tempo real ou em períodos curtos de tempo.

Sobre como fechar uma posição, de acordo com o método tradicional, você pode fechar a posição se ela não estiver no grupo durante a próxima classificação. Entretanto, no caso de ajuste de posição em tempo real, algumas moedas podem estar na linha divisória, e as posições podem ser fechadas para frente e para trás. Portanto, essa estratégia adota a abordagem de esperar por mudanças de agrupamento e fechar posições quando for necessário abrir posições na direção oposta. Por exemplo, se você for longo no primeiro grupo, quando a moeda na posição longa for dividida no terceiro grupo, você pode fechar a posição e operar vendido. Se você fechar posições em um período fixo, como todos os dias ou a cada 8 horas, também poderá fechar as posições sem estar em um grupo. Você pode tentar mais.

#回测引擎
class Exchange:
    
    def __init__(self, trade_symbols, fee=0.0004, initial_balance=10000):
        self.initial_balance = initial_balance #初始的资产
        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 #扣除手续费
        self.account['USDT']['fee'] += price*amount*self.fee
        self.account[symbol]['fee'] += price*amount*self.fee

        if cover_amount > 0: #先平仓
            self.account['USDT']['realised_profit'] += -direction*(price - self.account[symbol]['hold_price'])*cover_amount  #利润
            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): #对资产进行更新
        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)

#测试因子的函数
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 fator simples

Fator de volume: simplesmente operar comprado em moedas com baixo volume e vendido em moedas com alto volume tem um desempenho muito bom, o que mostra que moedas populares têm mais probabilidade de cair.

Fator de preço de transação: longo em moedas de baixo preço, curto em moedas de alto preço, o efeito é médio.

Fator de número de transações: o desempenho é muito semelhante ao volume. É óbvio que a correlação entre o fator volume e o fator número de transações é muito alta. Na verdade, a correlação média entre eles em moedas diferentes é de 0,97, o que mostra que esses dois fatores são muito semelhantes. Esse fator precisa ser levado em consideração em consideração.

Fator de momento 3h: (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 uma característica de regressão óbvia, ou seja, o aumento tem mais probabilidade de cair no próximo período. O desempenho geral é bom, mas também há períodos mais longos de retração e oscilação.

Fator de momentum de 24 horas: Os resultados do ciclo de rebalanceamento de 24 horas são muito bons, com retornos semelhantes ao momentum de 3 horas e um drawdown menor.

Fator de mudança de rotatividade: df_volume.rolling(24).mean() / df_volume.rolling(96).mean(), que é a razão entre a rotatividade do dia mais recente e a rotatividade dos três dias mais recentes. A posição é ajustado a cada 8 horas. Os resultados do backtest são relativamente bons e a retração é relativamente baixa, o que mostra que ações com volume de negociação ativo têm maior probabilidade de cair.

Fator de alteração do número de transações: df_count.rolling(24).mean() / df_count.rolling(96).mean(), que é 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 8 horas. . Os resultados do backtest são relativamente bons e a retração é relativamente baixa, o que mostra que, à medida que o número de transações aumenta, o mercado tende a cair mais ativamente.

Fator de alteração do valor da transação única: -(df_volume.rolling(24).mean()/df_count.rolling(24).mean())/(df_volume.rolling(24).mean()/df_count.rolling(96).mean()) , que é a razão entre o valor da transação do dia mais recente e o valor da transação dos três dias mais recentes, e a posição é ajustada a cada 8 horas. Este fator também está altamente correlacionado com o fator volume.

Fator de mudança na taxa de transação ativa: df_buy_ratio.rolling(24).mean()/df_buy_ratio.rolling(96).mean(), ou seja, a proporção do volume de compra ativa para o volume total de transações no último dia para a transação valor nos últimos três dias, ajuste a posição a cada 8 horas. Este fator tem bom desempenho e pouca correlação com o fator volume.

Fator de volatilidade: (df_close/df_open).rolling(24).std(), que tem um certo efeito ao operar comprado em moedas com baixa volatilidade.

Fator de correlação entre o volume de negociação e o preço de fechamento: df_close.rolling(96).corr(df_volume), o fator de correlação entre o preço de fechamento e o volume de negociação nos últimos 4 dias, o desempenho geral é bom.

Listados aqui estão apenas alguns dos fatores baseados em quantidade e preço. Na verdade, a combinação de fórmulas de fatores pode ser muito complexa e pode não ter lógica óbvia. Você pode consultar o famoso método de construção de fatores ALPHA101: https://github.com/STHSF/alpha101.

#成交量
factor_volume = df_volume
factor_volume_res = Test(factor_volume, symbols, period=4)
factor_volume_res.total.plot(figsize=(15,6),grid=True);

Modelo de fator de criptomoeda

#成交价
factor_close = df_close
factor_close_res = Test(factor_close, symbols, period=8)
factor_close_res.total.plot(figsize=(15,6),grid=True);

Modelo de fator de criptomoeda

#成交笔数
factor_count = df_count
factor_count_res = Test(factor_count, symbols, period=8)
factor_count_res.total.plot(figsize=(15,6),grid=True);

Modelo de fator de criptomoeda

print(df_count.corrwith(df_volume).mean())

0.9671246744996017

#3小时动量因子
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);

Modelo de fator de criptomoeda

#24小时动量因子
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);

Modelo de fator de criptomoeda

#成交量因子
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);

Modelo de fator de criptomoeda

#成交笔数因子
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);

Modelo de fator de criptomoeda

#因子相关性
print(factor_4.corrwith(factor_3).mean())

0.9707239580854841

#单笔成交价值因子
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);

Modelo de fator de criptomoeda

print(factor_4.corrwith(factor_5).mean())

0.861206620552479

#主动成交比例因子
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);

Modelo de fator de criptomoeda

print(factor_3.corrwith(factor_6).mean())

0.1534572192503726

#波动率因子
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);

Modelo de fator de criptomoeda

#成交量和收盘价相关性因子
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);

Modelo de fator de criptomoeda

Síntese multifatorial

Descobrir continuamente novos fatores eficazes é certamente a parte mais importante do processo de construção de estratégias, mas sem um bom método de síntese de fatores, um único fator Alfa excelente não pode desempenhar seu papel máximo. Os métodos comuns de síntese multifatorial incluem:

Método de pesos iguais: Todos os fatores a serem sintetizados são adicionados com pesos iguais para obter novos fatores sintetizados.

Método ponderado dos retornos históricos dos fatores: Todos os fatores a serem sintetizados são somados de acordo com a média aritmética dos retornos históricos dos fatores no período mais recente como pesos para obter novos fatores sintetizados. Este método dá pesos maiores aos fatores que apresentam bom desempenho.

Método ponderado de maximização do IC_IR: O valor médio do IC do fator composto ao longo de um período histórico é usado como uma estimativa do valor do IC do fator composto no próximo período, e a matriz de covariância do valor histórico do IC é usada como uma estimativa da volatilidade do fator composto no próximo período. É igual ao valor esperado de IC dividido pelo desvio padrão de IC, e a solução de peso ótima para maximizar o fator composto IC_IR pode ser obtida.

Método de análise de componentes principais (PCA): PCA é um método comumente usado para redução de dimensionalidade de dados. A correlação entre fatores pode ser relativamente alta, e os componentes principais após a redução de dimensionalidade são usados ​​como fatores sintetizados.

Este artigo se referirá manualmente à ponderação da validade fatorial. O método descrito acima pode se referir a:ae933a8c-5a94-4d92-8f33-d92b70c36119.pdf

Ao testar um único fator, a ordem é fixa, mas a síntese multifatorial requer a fusão de dados completamente diferentes, portanto, todos os fatores precisam ser padronizados e, geralmente, valores extremos e valores ausentes precisam ser removidos. Aqui usamos df_volume\factor_1\factor_7\factor_6\factor_8 para síntese.

#标准化函数,去除缺失值和极值,并且进行标准化处理
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);

Modelo de fator de criptomoeda

Resumir

Este artigo apresenta o método de teste de fator único e testa os fatores únicos comuns, e introduz preliminarmente o método de síntese multifatorial. No entanto, o conteúdo da pesquisa multifatorial é muito rico. Cada ponto mencionado no artigo pode ser expandido em profundidade . É uma abordagem viável transformar tal pesquisa de estratégia na descoberta de fatores alfa. Usar metodologia de fatores pode acelerar muito a verificação de ideias de negociação, e há muito material de referência disponível.

Endereço real: https://www.fmz.com/robot/486605