बिनेंस फ्यूचर्स मल्टी-करेंसी हेजिंग रणनीति भाग 2 पर शोध

लेखक:अच्छाई, बनाया गयाः 2020-05-09 16:03:01, अद्यतन किया गयाः 2023-11-04 19:49:47

img

मूल शोध रिपोर्ट का पता:https://www.fmz.com/digest-topic/5584आप इसे पहले पढ़ सकते हैं, इस लेख में डुप्लिकेट सामग्री नहीं होगी। यह लेख दूसरी रणनीति के अनुकूलन प्रक्रिया पर प्रकाश डालेगा। अनुकूलन के बाद, दूसरी रणनीति स्पष्ट रूप से बेहतर है, इस लेख के अनुसार रणनीति को अपग्रेड करने की सिफारिश की जाती है। बैकटेस्ट इंजन ने हैंडलिंग शुल्क के आंकड़े जोड़े।

# Libraries to import
import pandas as pd
import requests
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
%matplotlib inline
symbols = ['ETH', 'BCH', 'XRP', 'EOS', 'LTC', 'TRX', 'ETC', 'LINK', 'XLM', 'ADA', 'XMR', 'DASH', 'ZEC', 'XTZ', 'BNB', 'ATOM', 'ONT', 'IOTA', 'BAT', 'VET', 'NEO', 'QTUM', 'IOST']
price_usdt = pd.read_csv('https://www.fmz.com/upload/asset/20227de6c1d10cb9dd1.csv ', index_col = 0)
price_usdt.index = pd.to_datetime(price_usdt.index)
price_usdt_norm = price_usdt/price_usdt.fillna(method='bfill').iloc[0,]
price_usdt_btc = price_usdt.divide(price_usdt['BTC'],axis=0)
price_usdt_btc_norm = price_usdt_btc/price_usdt_btc.fillna(method='bfill').iloc[0,]
class Exchange:
    
    def __init__(self, trade_symbols, leverage=20, commission=0.00005,  initial_balance=10000, log=False):
        self.initial_balance = initial_balance # Initial asset
        self.commission = commission
        self.leverage = leverage
        self.trade_symbols = trade_symbols
        self.date = ''
        self.log = log
        self.df = pd.DataFrame(columns=['margin','total','leverage','realised_profit','unrealised_profit'])
        self.account = {'USDT':{'realised_profit':0, 'margin':0, 'unrealised_profit':0, 'total':initial_balance, 'leverage':0, 'fee':0}}
        for symbol in trade_symbols:
            self.account[symbol] = {'amount':0, 'hold_price':0, 'value':0, 'price':0, 'realised_profit':0, 'margin':0, 'unrealised_profit':0,'fee':0}
            
    def Trade(self, symbol, direction, price, amount, msg=''):
        if self.date and self.log:
            print('%-20s%-5s%-5s%-10.8s%-8.6s %s'%(str(self.date), symbol, 'buy' if direction == 1 else 'sell', price, amount, msg))
            
        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.commission # Minus handling fee
        self.account['USDT']['fee'] += price*amount*self.commission
        self.account[symbol]['fee'] += price*amount*self.commission
        
        if cover_amount > 0: # close position first
            self.account['USDT']['realised_profit'] += -direction*(price - self.account[symbol]['hold_price'])*cover_amount  # Profit
            self.account['USDT']['margin'] -= cover_amount*self.account[symbol]['hold_price']/self.leverage # Free margin
            
            self.account[symbol]['realised_profit'] += -direction*(price - self.account[symbol]['hold_price'])*cover_amount
            self.account[symbol]['amount'] -= -direction*cover_amount
            self.account[symbol]['margin'] -=  cover_amount*self.account[symbol]['hold_price']/self.leverage
            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['USDT']['margin'] +=  open_amount*price/self.leverage            
            self.account[symbol]['hold_price'] = total_cost/total_amount
            self.account[symbol]['amount'] += direction*open_amount
            self.account[symbol]['margin'] +=  open_amount*price/self.leverage
            
        self.account[symbol]['unrealised_profit'] = (price - self.account[symbol]['hold_price'])*self.account[symbol]['amount']
        self.account[symbol]['price'] = price
        self.account[symbol]['value'] = abs(self.account[symbol]['amount'])*price
        
        return True
    
    def Buy(self, symbol, price, amount, msg=''):
        self.Trade(symbol, 1, price, amount, msg)
        
    def Sell(self, symbol, price, amount, msg=''):
        self.Trade(symbol, -1, price, amount, msg)
        
    def Update(self, date, close_price): # Update assets
        self.date = date
        self.close = close_price
        self.account['USDT']['unrealised_profit'] = 0
        for symbol in self.trade_symbols:
            if np.isnan(close_price[symbol]):
                continue
            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']
            if self.date.hour in [0,8,16]:
                pass
                self.account['USDT']['realised_profit'] += -self.account[symbol]['amount']*close_price[symbol]*0.01/100
        
        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']['margin']/self.account['USDT']['total'],4)*self.leverage
        self.df.loc[self.date] = [self.account['USDT']['margin'],self.account['USDT']['total'],self.account['USDT']['leverage'],self.account['USDT']['realised_profit'],self.account['USDT']['unrealised_profit']]

मुद्रा प्रकार के चयन के बाद मूल रणनीति का प्रदर्शन अच्छा रहा, लेकिन अभी भी कई होल्डिंग पोजीशन हैं, आम तौर पर लगभग 4 गुना

सिद्धांत:

  • बाजार उद्धरणों और खाता रखने की स्थिति को अद्यतन करें, प्रारंभिक मूल्य को पहले रन में दर्ज किया जाएगा (नई जोड़ी गई मुद्राओं की गणना शामिल होने के समय के अनुसार की जाती है)
  • सूचकांक अद्यतन करें, सूचकांक altcoin-बिटकॉइन मूल्य सूचकांक है = औसत (कुल ((altcoin मूल्य / बिटकॉइन मूल्य) / (altcoin प्रारंभिक मूल्य / बिटकॉइन प्रारंभिक मूल्य))
  • विचलन सूचकांक के अनुसार लंबे और छोटे संचालन का न्याय करना और विचलन के आकार के अनुसार स्थिति के आकार का न्याय करना
  • आदेश देने पर, आदेश मात्रा आइसबर्ग कमीशन रणनीति द्वारा निर्धारित किया जाता है और लेनदेन नवीनतम निष्पादित मूल्य के अनुसार निष्पादित किया जाता है
  • फिर से लूप करें
trade_symbols = list(set(symbols)-set(['LINK','XTZ','BCH', 'ETH'])) # Remaining currencies
price_usdt_btc_norm_mean = price_usdt_btc_norm[trade_symbols].mean(axis=1)
e = Exchange(trade_symbols,initial_balance=10000,commission=0.0005,log=False)
trade_value = 300
for row in price_usdt.iloc[:].iterrows():
    e.Update(row[0], row[1])
    empty_value = 0
    for symbol in trade_symbols:
        price = row[1][symbol]
        if np.isnan(price):
            continue
        diff = price_usdt_btc_norm.loc[row[0],symbol] - price_usdt_btc_norm_mean[row[0]]
        aim_value = -trade_value*round(diff/0.01,1)
        now_value = e.account[symbol]['value']*np.sign(e.account[symbol]['amount'])
        empty_value += now_value
        if aim_value - now_value > 20:
            e.Buy(symbol, price, round((aim_value - now_value)/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2))
        if aim_value - now_value < -20:
            e.Sell(symbol, price, -round((aim_value - now_value)/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2))
stragey_2b = e
(stragey_2b.df['total']/stragey_2b.initial_balance).plot(figsize=(17,6),grid = True);

img

stragey_2b.df['leverage'].plot(figsize=(18,6),grid = True); # leverage

img

pd.DataFrame(e.account).T.apply(lambda x:round(x,3)) # holding position

img

क्यों सुधार करें

मूल सबसे बड़ी समस्या नवीनतम मूल्य और रणनीति द्वारा शुरू की गई प्रारंभिक मूल्य के बीच तुलना है। जैसे-जैसे समय बीतता है, यह अधिक से अधिक विचलित हो जाएगा। हम इन मुद्राओं में बहुत सारी स्थिति जमा करेंगे। फ़िल्टरिंग मुद्राओं के साथ सबसे बड़ी समस्या यह है कि हमारे अतीत के अनुभव के आधार पर भविष्य में हमारे पास अभी भी अद्वितीय मुद्राएं हो सकती हैं। निम्नलिखित गैर-फ़िल्टरिंग मोड का प्रदर्शन है। वास्तव में, जब trade_value = 300, रणनीति चलाने के मध्य चरण में, यह पहले से ही सब कुछ खो चुका है। भले ही यह नहीं है, LINK और XTZ भी 10000USDT से ऊपर की स्थिति रखते हैं, जो बहुत बड़ा है। इसलिए, हमें इस समस्या को बैकटेस्ट में हल करना चाहिए और सभी मुद्राओं का परीक्षण पास करना चाहिए।

trade_symbols = list(set(symbols)) # Remaining currencies
price_usdt_btc_norm_mean = price_usdt_btc_norm[trade_symbols].mean(axis=1)
e = Exchange(trade_symbols,initial_balance=10000,commission=0.0005,log=False)
trade_value = 300
for row in price_usdt.iloc[:].iterrows():
    e.Update(row[0], row[1])
    empty_value = 0
    for symbol in trade_symbols:
        price = row[1][symbol]
        if np.isnan(price):
            continue
        diff = price_usdt_btc_norm.loc[row[0],symbol] - price_usdt_btc_norm_mean[row[0]]
        aim_value = -trade_value*round(diff/0.01,1)
        now_value = e.account[symbol]['value']*np.sign(e.account[symbol]['amount'])
        empty_value += now_value
        if aim_value - now_value > 20:
            e.Buy(symbol, price, round((aim_value - now_value)/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2))
        if aim_value - now_value < -20:
            e.Sell(symbol, price, -round((aim_value - now_value)/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2))
stragey_2c = e
(stragey_2c.df['total']/stragey_2c.initial_balance).plot(figsize=(17,6),grid = True);

img

pd.DataFrame(stragey_2c.account).T.apply(lambda x:round(x,3)) # Last holding position

img

((price_usdt_btc_norm.iloc[-1:] - price_usdt_btc_norm_mean[-1]).T) # Each currency deviates from the initial situation

img

चूंकि समस्या का कारण प्रारंभिक मूल्य के साथ तुलना करना है, इसलिए यह अधिक से अधिक पक्षपाती हो सकता है। हम इसे पिछली अवधि के चलती औसत के साथ तुलना कर सकते हैं, पूर्ण मुद्रा का बैकटेस्ट कर सकते हैं और नीचे परिणाम देख सकते हैं।

Alpha = 0.05
#price_usdt_btc_norm2 = price_usdt_btc/price_usdt_btc.rolling(20).mean() #Ordinary moving average
price_usdt_btc_norm2 = price_usdt_btc/price_usdt_btc.ewm(alpha=Alpha).mean() # Here is consistent with the strategy, using EMA
trade_symbols = list(set(symbols))#All currencies
price_usdt_btc_norm_mean = price_usdt_btc_norm2[trade_symbols].mean(axis=1)
e = Exchange(trade_symbols,initial_balance=10000,commission=0.0005,log=False)
trade_value = 300
for row in price_usdt.iloc[:].iterrows():
    e.Update(row[0], row[1])
    empty_value = 0
    for symbol in trade_symbols:
        price = row[1][symbol]
        if np.isnan(price):
            continue
        diff = price_usdt_btc_norm2.loc[row[0],symbol] - price_usdt_btc_norm_mean[row[0]]
        aim_value = -trade_value*round(diff/0.01,1)
        now_value = e.account[symbol]['value']*np.sign(e.account[symbol]['amount'])
        empty_value += now_value
        if aim_value - now_value > 20:
            e.Buy(symbol, price, round((aim_value - now_value)/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2))
        if aim_value - now_value < -20:
            e.Sell(symbol, price, -round((aim_value - now_value)/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2))
stragey_2d = e
#print(N,stragey_2d.df['total'][-1],pd.DataFrame(stragey_2d.account).T.apply(lambda x:round(x,3))['value'].sum())

रणनीति के प्रदर्शन ने हमारी अपेक्षाओं को पूरी तरह से पूरा किया है, और रिटर्न लगभग समान हैं। सभी मुद्राओं की मूल मुद्रा में खाता पदों के फटने की स्थिति भी सुचारू रूप से संक्रमण कर गई है, और लगभग कोई प्रतिगमन नहीं है। एक ही उद्घाटन स्थिति का आकार, लगभग सभी लीवरेज 1 गुना से नीचे है, 12 मार्च 2020 को मूल्य चरम मामले में गिर गया, यह अभी भी 4 गुना से अधिक नहीं है, जिसका अर्थ है कि हम व्यापार_मूल्य को बढ़ा सकते हैं, और उसी लीवरेज के तहत, लाभ को दोगुना कर सकते हैं। अंतिम होल्डिंग स्थिति केवल 1000USDT से अधिक BCH है, जो बहुत अच्छी है।

स्थिति को कम क्यों किया जाएगा? कल्पना कीजिए कि अल्टकोइन सूचकांक में शामिल होने में कोई बदलाव नहीं हुआ है, एक सिक्का 100% बढ़ गया है, और यह लंबे समय तक बनाए रखा जाएगा। मूल रणनीति लंबे समय तक 300 * 100 = 30000USDT की छोटी स्थिति बनाए रखेगी, और नई रणनीति अंततः बेंचमार्क मूल्य को ट्रैक करेगी।

(stragey_2d.df['total']/stragey_2d.initial_balance).plot(figsize=(17,6),grid = True);
#(stragey_2c.df['total']/stragey_2c.initial_balance).plot(figsize=(17,6),grid = True);

img

stragey_2d.df['leverage'].plot(figsize=(18,6),grid = True);
stragey_2b.df['leverage'].plot(figsize=(18,6),grid = True); # Screen currency strategy leverage

img

pd.DataFrame(stragey_2d.account).T.apply(lambda x:round(x,3))

img

स्क्रीनिंग तंत्र के साथ मुद्रा का क्या होगा, समान मापदंडों के साथ, पहले चरण के लाभ बेहतर प्रदर्शन करते हैं, रिट्रेसमेंट छोटा होता है, लेकिन समग्र रिटर्न थोड़ा कम होता है। इसलिए, एक स्क्रीनिंग तंत्र की सिफारिश की जाती है।

#price_usdt_btc_norm2 = price_usdt_btc/price_usdt_btc.rolling(50).mean()
price_usdt_btc_norm2 = price_usdt_btc/price_usdt_btc.ewm(alpha=0.05).mean()
trade_symbols = list(set(symbols)-set(['LINK','XTZ','BCH', 'ETH'])) # Remaining currencies
price_usdt_btc_norm_mean = price_usdt_btc_norm2[trade_symbols].mean(axis=1)
e = Exchange(trade_symbols,initial_balance=10000,commission=0.0005,log=False)
trade_value = 300
for row in price_usdt.iloc[:].iterrows():
    e.Update(row[0], row[1])
    empty_value = 0
    for symbol in trade_symbols:
        price = row[1][symbol]
        if np.isnan(price):
            continue
        diff = price_usdt_btc_norm2.loc[row[0],symbol] - price_usdt_btc_norm_mean[row[0]]
        aim_value = -trade_value*round(diff/0.01,1)
        now_value = e.account[symbol]['value']*np.sign(e.account[symbol]['amount'])
        empty_value += now_value
        if aim_value - now_value > 20:
            e.Buy(symbol, price, round((aim_value - now_value)/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2))
        if aim_value - now_value < -20:
            e.Sell(symbol, price, -round((aim_value - now_value)/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2))
stragey_2e = e
#(stragey_2d.df['total']/stragey_2d.initial_balance).plot(figsize=(17,6),grid = True);
(stragey_2e.df['total']/stragey_2e.initial_balance).plot(figsize=(17,6),grid = True);

img

stragey_2e.df['leverage'].plot(figsize=(18,6),grid = True);

img

pd.DataFrame(stragey_2e.account).T.apply(lambda x:round(x,3))

img

पैरामीटर अनुकूलन

घातीय चलती औसत के अल्फा पैरामीटर की सेटिंग जितनी बड़ी होगी, बेंचमार्क मूल्य ट्रैकिंग उतनी ही संवेदनशील होगी, जितने कम लेनदेन होंगे, अंतिम होल्डिंग स्थिति उतनी ही कम होगी। जब लीवरेज कम होगा, रिटर्न भी कम होगा। अधिकतम रिट्रेसमेंट को कम करने से लेनदेन की मात्रा बढ़ सकती है। बैकटेस्ट के परिणामों के आधार पर विशिष्ट संतुलन संचालन की आवश्यकता होगी।

चूंकि बैकटेस्ट एक 1h K लाइन है, इसलिए इसे केवल एक घंटे में एक बार अपडेट किया जा सकता है, वास्तविक बाजार को तेजी से अपडेट किया जा सकता है, और विशिष्ट सेटिंग्स को व्यापक रूप से तौलना आवश्यक है।

यह अनुकूलन का परिणाम हैः

for Alpha in [i/100 for i in range(1,30)]:
    #price_usdt_btc_norm2 = price_usdt_btc/price_usdt_btc.rolling(20).mean() # Ordinary moving average
    price_usdt_btc_norm2 = price_usdt_btc/price_usdt_btc.ewm(alpha=Alpha).mean() # Here is consistent with the strategy, using EMA
    trade_symbols = list(set(symbols))# All currencies
    price_usdt_btc_norm_mean = price_usdt_btc_norm2[trade_symbols].mean(axis=1)
    e = Exchange(trade_symbols,initial_balance=10000,commission=0.0005,log=False)
    trade_value = 300
    for row in price_usdt.iloc[:].iterrows():
        e.Update(row[0], row[1])
        empty_value = 0
        for symbol in trade_symbols:
            price = row[1][symbol]
            if np.isnan(price):
                continue
            diff = price_usdt_btc_norm2.loc[row[0],symbol] - price_usdt_btc_norm_mean[row[0]]
            aim_value = -trade_value*round(diff/0.01,1)
            now_value = e.account[symbol]['value']*np.sign(e.account[symbol]['amount'])
            empty_value += now_value
            if aim_value - now_value > 20:
                e.Buy(symbol, price, round((aim_value - now_value)/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2))
            if aim_value - now_value < -20:
                e.Sell(symbol, price, -round((aim_value - now_value)/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2))
    stragey_2d = e
    # These are the final net value, the initial maximum backtest, the final position size, and the handling fee
    print(Alpha, round(stragey_2d.account['USDT']['total'],1), round(1-stragey_2d.df['total'].min()/stragey_2d.initial_balance,2),round(pd.DataFrame(stragey_2d.account).T['value'].sum(),1),round(stragey_2d.account['USDT']['fee']))
0.01 21116.2 0.14 15480.0 2178.0
0.02 20555.6 0.07 12420.0 2184.0
0.03 20279.4 0.06 9990.0 2176.0
0.04 20021.5 0.04 8580.0 2168.0
0.05 19719.1 0.03 7740.0 2157.0
0.06 19616.6 0.03 7050.0 2145.0
0.07 19344.0 0.02 6450.0 2133.0
0.08 19174.0 0.02 6120.0 2117.0
0.09 18988.4 0.01 5670.0 2104.0
0.1 18734.8 0.01 5520.0 2090.0
0.11 18532.7 0.01 5310.0 2078.0
0.12 18354.2 0.01 5130.0 2061.0
0.13 18171.7 0.01 4830.0 2047.0
0.14 17960.4 0.01 4770.0 2032.0
0.15 17779.8 0.01 4531.3 2017.0
0.16 17570.1 0.01 4441.3 2003.0
0.17 17370.2 0.01 4410.0 1985.0
0.18 17203.7 0.0 4320.0 1971.0
0.19 17016.9 0.0 4290.0 1955.0
0.2 16810.6 0.0 4230.6 1937.0
0.21 16664.1 0.0 4051.3 1921.0
0.22 16488.2 0.0 3930.6 1902.0
0.23 16378.9 0.0 3900.6 1887.0
0.24 16190.8 0.0 3840.0 1873.0
0.25 15993.0 0.0 3781.3 1855.0
0.26 15828.5 0.0 3661.3 1835.0
0.27 15673.0 0.0 3571.3 1816.0
0.28 15559.5 0.0 3511.3 1800.0
0.29 15416.4 0.0 3481.3 1780.0

संबंधित

अधिक