2021 touche à sa fin, et des points chauds de DEFI à GAMEFI émergent dans un flux sans fin, et le marché global est toujours un marché haussier. Maintenant, regardez en arrière et résumez, combien avez-vous gagné en 2021? Quelles opportunités avez-vous manquées? Quels ont été quelques investissements réussis? Récemment, j'ai jeté un coup d'œil au marché historique de l'année écoulée et j'ai trouvé une stratégie de profit simple et inattendue, qui est un indice multi-monnaies.
Il y a tellement de devises sur l'échange, dont beaucoup sont destinées à être inconnues et peuvent même être retirées du commerce. Ici, nous choisissons la monnaie du contrat perpétuel Binance qui a été utilisée sur le marché. Ils sont généralement testés et reconnus comme des devises traditionnelles, qui sont relativement sûres. Après un simple criblage, certaines devises d'indice ont été retirées et 134 devises ont finalement été obtenues.
Dans [1]:
import requests
from datetime import date,datetime
import time
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
Dans [144]:
## Current trading pairs
Info = requests.get('https://fapi.binance.com/fapi/v1/exchangeInfo')
symbols = [s['symbol'] for s in Info.json()['symbols']]
Dans [154]:
symbols_f = list(set(filter(lambda x: x[-4:] == 'USDT', [s.split('_')[0] for s in symbols]))-
set(['1000SHIBUSDT','1000XECUSDT','BTCDOMUSDT','DEFIUSDT','BTCSTUSDT'])) + ['SHIBUSDT','XECUSDT']
print(symbols_f)
Dans [155]:
print(len(symbols_f))
Nous obtenons ensuite leurs prix de clôture quotidiens pour l'année écoulée, en notant que certaines devises ont été sur l'étagère pendant une courte période de temps, nous devons donc remplir les données.
Le rendement final de l'indice est d'environ 12 fois, c'est-à-dire que si vous achetez les 134 pièces le 1er janvier 2021 en moyenne, le rendement final de ne rien faire sera de 12 fois. On estime que plus de 90% des traders ne dépassent pas l'indice moyen. Parmi eux, les devises avec la plus forte baisse sont: ICP a chuté de 93%, DODO a chuté de 85% et LINA a chuté de 75%. Alors que SOL, FTM, LUNA, MATIC, SAND et AXS ont augmenté de près de 100 fois. Parmi eux, AXS a augmenté de 168 fois, ce qui en fait le plus grand cheval noir. La médiane a augmenté de 3 fois, ce qui a été principalement motivé par la chaîne publique et les jeux. Afin d'éviter le biais de survie, nous avons exclu la nouvelle monnaie perpétuelle au cours de la période, et nous avons également réalisé près de 11 fois le bénéfice. C'est 7 fois le bénéfice de BTC pour la survie.
Il s'agit d'un taux de rendement désespéré. J'ai travaillé dur pour faire toutes sortes de stratégies, mais il était loin des bénéfices de ne rien faire en un an. Cependant, il convient de noter que certaines des augmentations spécifiques sont trop grandes et il était dévier de l'indice évidemment. Si ces devises ne sont pas sélectionnées au début de l'année, les bénéfices seront proches de la médiane, ce qui est beaucoup moins rentable.
Dans [157]:
#Obtain the function of K-line in any period
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 = int(time.mktime(datetime.strptime(end, "%Y-%m-%d").timetuple()))*1000 + 8*60*60*1000
intervel_map = {'m':60*1000,'h':60*60*1000,'d':24*60*60*1000}
while start_time < end_time:
mid_time = min(start_time+1000*int(period[:-1])*intervel_map[period[-1]],end_time)
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]
Klines += res_list
elif type(res_list) == list:
start_time = start_time+1000*int(period[:-1])*intervel_map[period[-1]]
else:
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
Dans [164]:
df_all_s = pd.DataFrame(index=pd.date_range(start='2021-1-1', end='2021-12-28', freq='1d'),columns=symbols_s)
for i in range(len(symbols_f)):
#print(symbols_s[i])
symbol_s = symbols_f[i]
df_s = GetKlines(symbol=symbol_s,start='2021-1-1',end='2021-12-28',period='1d',base='api',v='v3')
df_all_s[symbol_s] = df_s[~df_s.index.duplicated(keep='first')].close
Dans [165]:
df_all_s.tail() #data structure
À l'extérieur [1]:
Dans [174]:
df_all = df_all_s.fillna(method='bfill')#filled data
df_norm = df_all/df_all.iloc[0] #normalization
df_norm.mean(axis=1).plot(figsize=(12,4),grid=True);
#The final index return chart
À l'extérieur [1]:
Dans [175]:
#The median increase
df_norm.median(axis=1).plot(figsize=(12,4),grid=True);
À l'extérieur [1]:
Dans [168]:
#Ranking for increase/decrease
print(df_norm.iloc[-1].round(2).sort_values().to_dict())
Dans [317]:
#Maximum rollback of current price compared with the highest point in the year
print((1-df_norm.iloc[-1]/df_norm.max()).round(2).sort_values().to_dict())
Dans [177]:
df_all_f = pd.DataFrame(index=pd.date_range(start='2021-1-1', end='2021-12-28', freq='1d'),columns=symbols_s)
for i in range(len(symbols_f)):
#print(symbols_s[i])
symbol_f = symbols_f[i]
df_f = GetKlines(symbol=symbol_f,start='2021-1-1',end='2021-12-28',period='1d',base='fapi',v='v1')
df_all_f[symbol_f] = df_f[~df_f.index.duplicated(keep='first')].close
Dans [208]:
#Excluding new currency
df = df_all_s[df_all_s.columns[~df_all_f.iloc[0].isnull()]]
df = df.fillna(method='bfill')
df = df/df.iloc[0]
df.mean(axis=1).plot(figsize=(12,4),grid=True);
À l'extérieur[208]:
Dans [212]:
#Compared with Bitcoin
(df.mean(axis=1)/df.BTCUSDT).plot(figsize=(12,4),grid=True);
À l'extérieur [1]:
Dans [213]:
#Use the original 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}}
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 #Deduct the handling fee
self.account['USDT']['fee'] += price*amount*self.fee
self.account[symbol]['fee'] += price*amount*self.fee
if cover_amount > 0: #Close the 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 the assets
self.account['USDT']['unrealised_profit'] = 0
for symbol in self.trade_symbols:
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']['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)
Dans [418]:
#The hourly K-line was taken to make the backtest more accurate
df_all_s = pd.DataFrame(index=pd.date_range(start='2021-1-1', end='2021-12-28', freq='1h'),columns=symbols_s)
for i in range(len(symbols_f)):
#print(symbols_s[i])
symbol_s = symbols_f[i]
df_s = GetKlines(symbol=symbol_s,start='2021-1-1',end='2021-12-28',period='1h',base='api',v='v3')
df_all_s[symbol_s] = df_s[~df_s.index.duplicated(keep='first')].close
Dans [419]:
df = df_all_s[df_all_s.columns[~df_all_f.iloc[0].isnull()]]
df = df.fillna(method='bfill')
df = df/df.iloc[0]
df.mean(axis=1).plot(figsize=(12,4),grid=True);
À l'extérieur[419]:
Dans le backtest, toutes les devises du contrat perpétuel Binance en ligne du 1er janvier 2021 ont été sélectionnées. La période de la ligne K était de 1h. Le paramètre a commencé à évoluer dans les positions lorsque la position était inférieure de 5% à la moyenne, et à les vendre lorsque la position était supérieure à 5%. Lorsque le backtest est toutes les devises, le rendement stratégique final est de 7,7 fois. Il n'est évidemment pas aussi bon que le rendement moyen de 13 fois. Cela est également attendu. Après tout, plusieurs devises qui ont augmenté cent fois sont trop spéciales, et la stratégie de balance les vendra toutes.
Si l'on retire du backtest les dix monnaies ayant connu la plus forte hausse, seules les monnaies relativement médiocres seront prises en considération et le revenu final sera de 4,8 fois, ce qui dépasse de loin la performance moyenne de 3,4 fois.
Si seulement les 3 devises avec la plus forte hausse sont rotées, les profits finaux seront 373 fois, ce qui est beaucoup plus que la performance moyenne de 160 fois.
Dans [494]:
#Full currency backtest
symbols = list(df.iloc[-1].sort_values()[:].index)
e = Exchange(symbols, fee=0.001, initial_balance=10000)
res_list = []
avg_pct = 1/len(symbols)
for row in df[symbols].iterrows():
prices = row[1]
total = e.account['USDT']['total']
e.Update(prices)
for symbol in symbols:
pct = e.account[symbol]['value']/total
if pct < 0.95*avg_pct:
e.Buy(symbol,prices[symbol],(avg_pct-pct)*total/prices[symbol])
if pct > 1.05*avg_pct:
e.Sell(symbol,prices[symbol],(pct-avg_pct)*total/prices[symbol])
res_list.append([e.account[symbol]['value'] for symbol in symbols] + [e.account['USDT']['total']])
res = pd.DataFrame(data=res_list, columns=symbols+['total'],index = df.index)
Dans [495]:
e.account['USDT']
À l'extérieur[495]:
Dans [496]:
# Backtest performance of full currencies
(res.total/10000).plot(figsize=(12,4),grid = True);
df[symbols].mean(axis=1).plot(figsize=(12,4),grid=True);
Extrait[496]:
Dans [498]:
#Remove currencies with huge growth
symbols = list(df.iloc[-1].sort_values()[:-10].index)
e = Exchange(symbols, fee=0.001, initial_balance=10000)
res_list = []
avg_pct = 1/len(symbols)
for row in df[symbols].iterrows():
prices = row[1]
total = e.account['USDT']['total']
e.Update(prices)
for symbol in symbols:
pct = e.account[symbol]['value']/total
if pct < 0.95*avg_pct:
e.Buy(symbol,prices[symbol],(avg_pct-pct)*total/prices[symbol])
if pct > 1.05*avg_pct:
e.Sell(symbol,prices[symbol],(pct-avg_pct)*total/prices[symbol])
res_list.append([e.account[symbol]['value'] for symbol in symbols] + [e.account['USDT']['total']])
res = pd.DataFrame(data=res_list, columns=symbols+['total'],index = df.index)
Dans [501]:
e.account['USDT']
À l'extérieur [1]:
Dans [499]:
(res.total/10000).plot(figsize=(12,4),grid = True);
df[symbols].mean(axis=1).plot(figsize=(12,4),grid=True);
À l'extérieur [499]:
Dans [503]:
#Only the currency with the highest increase is tested
symbols = list(df.iloc[-1].sort_values()[-3:].index)
e = Exchange(symbols, fee=0.001, initial_balance=10000)
res_list = []
avg_pct = 1/len(symbols)
for row in df[symbols].iterrows():
prices = row[1]
total = e.account['USDT']['total']
e.Update(prices)
for symbol in symbols:
pct = e.account[symbol]['value']/total
if pct < 0.95*avg_pct:
e.Buy(symbol,prices[symbol],(avg_pct-pct)*total/prices[symbol])
if pct > 1.05*avg_pct:
e.Sell(symbol,prices[symbol],(pct-avg_pct)*total/prices[symbol])
res_list.append([e.account[symbol]['value'] for symbol in symbols] + [e.account['USDT']['total']])
res = pd.DataFrame(data=res_list, columns=symbols+['total'],index = df.index)
Dans [504]:
e.account['USDT']
Extrait[504]:
Dans [505]:
(res.total/10000).plot(figsize=(12,4),grid = True);
df[symbols].mean(axis=1).plot(figsize=(12,4),grid=True);
À l'extérieur[505]:
En général, 2021 sera un marché haussier pour les pièces contrefaites et une année à la baisse pour Bitcoin. La valeur marchande de Bitcoin est tombée à 40% maintenant, contre 70% au début de l'année, ce qui est le niveau le plus bas de l'histoire. Par conséquent, les bénéfices moyens de l'achat et de la détention de marchandises contrefaites au cours de l'année écoulée sont beaucoup plus élevés que ceux de la détention de Bitcoin.