বাইনারেন্স ফিউচার মাল্টি-কার্উয়েন্সি হেজিং স্ট্র্যাটেজি পার্ট ২ নিয়ে গবেষণা

লেখক:ভাল, তৈরিঃ 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-bitcoin মূল্য সূচক = গড় (সংখ্যা ((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, কৌশল চলার মাঝামাঝি পর্যায়ে, এটি ইতিমধ্যে সবকিছু হারিয়েছে। এমনকি যদি এটি না হয় তবে লিংক এবং এক্সটিজেডও 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 বারের বেশি নয়, যার অর্থ আমরা trade_value বৃদ্ধি করতে পারি, এবং একই লিভারেজের অধীনে, মুনাফা দ্বিগুণ করতে পারি। চূড়ান্ত হোল্ডিং অবস্থানটি কেবলমাত্র BCH 1000USDT ছাড়িয়ে গেছে, যা খুব ভাল।

কেন পজিশনটি হ্রাস করা হবে? কল্পনা করুন অ্যাল্টকয়েন সূচকে অপরিবর্তিত যোগদান, একটি মুদ্রা 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

প্যারামিটার অপ্টিমাইজেশন

এক্সপোনেন্সিয়াল মুভিং এভারেজের আলফা প্যারামিটারের সেটিং যত বড়, বেঞ্চমার্ক মূল্য ট্র্যাকিং তত বেশি সংবেদনশীল, কম লেনদেন, চূড়ান্ত হোল্ডিং অবস্থান তত কম। যখন লিভারেজ কম হয়, রিটার্নও হ্রাস পায়। সর্বাধিক পুনরুদ্ধার হ্রাস করা, এটি লেনদেনের পরিমাণ বাড়িয়ে তুলতে পারে। ব্যাকটেস্টের ফলাফলের উপর ভিত্তি করে নির্দিষ্ট ভারসাম্য অপারেশন প্রয়োজন।

যেহেতু ব্যাকটেস্টটি 1 ঘন্টা 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

সম্পর্কিত

আরো