最近,バイナンス・フューチャーズは第2回"バイナンス・チャンピオンシップ" (住所:https://www.binancezh.com/cn/futures/activity/anniversary-competition/129-38599440) 公式FMZ Quantプラットフォームもチームを組織し,直接
バイナンスチャンピオンシップのために準備した戦略は配達契約の蝶のヘッジです. この記事は戦略の研究報告です. 注意:戦略は参照のみです. この根拠に基づいて最適化のための独自のアイデアを提出することができます. 共有することも歓迎されています. 報告書はFMZウェブサイトの研究環境で直接使用できます (ダウンロードするには右上の角をクリックし,
ヘージングは安定した価格差を見つける必要があります.価格差が大きすぎると,価格差をショートする.価格差が小さすぎると,価格差をロングする.価格差がポジションを閉じるために戻ると,価格差を稼ぐでしょう.先物とスポットがヘージングしている場合,配送されていない先物価格がスポット価格よりもはるかに高いとき,先物契約をショートして,価格差をショートするためにスポット価格をロングすることができます.配送時間が異なる契約の時間間隔ヘージングもあります.先物とスポットヘージングで,彼らはまた価格差をロングすることができます.先物とスポットとクロスフューチャーズは激烈な競争のある一般的な戦略です.市場がない場合,価格差は比較的安定しています.長期市場である可能性がありますが,機会が少なく,手動操作も求められています.すべての価格差が安定しているため,価格の取引が可能な場合,バタフライ・ヘージングとしても知られています.
バイナンス通貨標準契約は,BTCとETHなどの3つの契約を同時に持つ.すなわち,恒久BTCUSD_PERP,現季度BTCUSD_200925,来季度BTCUSD_201225である.恒久契約はスポットとして使用できる.一般的に,2つの契約をヘッジするために,3つの価格差があります.現季度恒久,次季度恒久,次季度現季度.バターフライ・アービトラージには3つの契約が必要です.差は (次季度 - 現季度) - (現季度 - 恒久),すなわち差=次季度+恒久 - 2 * 現季度価格.差をロングするには,次の四半期と恒久契約のロングポジション契約を開き,現季度のために2つのショート契約を開く必要があります.
8月14日から9月14日までBinanceの5minKラインのデータをクロールしました. 直接読み取れます (時間差のため,表示される時間差は8hです).
[4] において
# Libraries to be imported
import pandas as pd
import requests
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import time
%matplotlib inline
[12] で:
#Read the data, you can also upload the data to the FMZ forum, which can be referenced in the "Analyze" directly
df = pd.read_csv('https://www.fmz.com/upload/asset/1420b2081ecd122522d.csv',index_col = 0)
df.index = pd.to_datetime(df.index)
df.tail(3)
アウト[12]:
まず,ビットコイン契約の価格差を見てみましょう. 8月17日,ビットコインの価格は急速に500u上昇しました. 一般的に言えば,配達された契約はスポット価格と比較してプレミアムで,スポット価格も上昇しました. 将来への期待はより楽観的です. 未配達された契約と永続契約の価格差は大きくなります. 例えば,次の四半期と永続契約の価格差は700uになります. 9月にビットコインの価格が下がると,人々の期待は急速に悪化し,次の四半期と永続契約の価格差は約150uに低下し,現在の四半期と永続契約の価格差はほとんどありませんでした. 次の四半期と永続契約の間のヘッジが実行された場合,長期価格の大きな返還のみが行うことができます. 400-600の間の差が8月に実施することを決定された場合,それは明らかに現在状態にロックされています.
[18]:
#Perpetual price
df['BTCUSD_PERP'].dropna().plot(figsize=(15,6),grid=True);
アウト[18]:
[15] について
# Price difference of next quarter - perpetual
(df['BTCUSD_201225']-df['BTCUSD_PERP']).dropna().plot(figsize=(15,6),grid=True);
アウト[15]:
[16]:
# Price difference of current quarter - perpetual
(df['BTCUSD_200925']-df['BTCUSD_PERP']).dropna().plot(figsize=(15,6),grid=True);
アウト[16]:
[17]:
# Price difference of next quarter - current quarter
(df['BTCUSD_201225']-df['BTCUSD_200925']).dropna().plot(figsize=(15,6),grid=True);
アウト[17]:
この時点で価格差はどのように変化しているのでしょうか? 下の図からわかるように,最近の価格差は100-200uで長い間安定しています. 9月上旬の急落でさえあまり影響を受けず,繰り返し仲介する余地が多くあります. 現在,価格差が100uに低下した場合,手動でロングに行くことはOKです.
スポット価格が変動すると,期限切れのない2つの契約は同時に将来の期待を反映する.価格差の削減プロセスは,この変動を大幅に抵消し,パフォーマンスが比較的安定している.ETHのバタフライ・アービタージ・スプレッドは,同様のパフォーマンスを有する.
[19]:
#(next quarter - current quarter)-(current quarter - perpetual)
(df['BTCUSD_201225']-df['BTCUSD_200925']-(df['BTCUSD_200925']-df['BTCUSD_PERP'])).dropna().plot(figsize=(15,6),grid=True);
アウト[19]:
[22]:
#The price difference of ETH
(df['ETHUSD_201225']+df['ETHUSD_PERP']-2*df['ETHUSD_200925']).dropna().plot(figsize=(15,6),grid=True);
アウト[22]:
時間を節約するために (ただの怠けさ) バックテストは,まだ最後のバイナンスチャンピオンシップ戦略のUSDT標準エンジンを使用しています.いくつかのエラーがあるかもしれませんが,問題も説明できます. バックテストエンジンはこのレポートの最後に配置されています. コードを実行するときに,記事の終わりを表示する必要があります. 通貨標準戦略は,USDTを稼ぎたい場合はヘッジを検討することができ,複雑ではありません.
価格差のミッドラインはEMAによって追跡され,ポジションはグリッドによって制御される.つまり,差が開かれるたびに (例えば30),N株をショートし,その逆である.価格差のミッドラインが100uである場合,価格差が90であるとき,3株をショートし,価格差が60になる.グリッドのサイズが重要なパラメータである.
以下は,特定のBTCとETHのバックテストコードと結果です.パフォーマンスが期待に沿っています.ETHとLINKは波動性が高く,価格差が安定しているため,パフォーマンスが良くなっています.ここでサービス料金は0.02%,バイナンスではデフォルトのVIP0テイカーサービス料金は0.04%です.サービス料金は非常に重要です.次の章でそれを分析します.
[39]:
trade_symbols = ['BTCUSD_201225', 'BTCUSD_200925', 'BTCUSD_PERP']
account = []
diff = df['BTCUSD_201225']+df['BTCUSD_PERP']-2*df['BTCUSD_200925']
diff_mean = diff.ewm(alpha=0.001).mean()
e = Exchange(trade_symbols,initial_balance=10000,taker_fee=0.0002)
for row in df[trade_symbols].dropna().iterrows():
date = row[0]
prices = row[1]
e.Update(date, trade_symbols, prices)
account.append([e.account['USDT']['margin'],e.account['USDT']['realised_profit']+e.account['USDT']['unrealised_profit']])
aim_amount = -round((diff[date] - diff_mean[date])/30,1)
now_amount = e.account['BTCUSD_PERP']['amount']
if aim_amount - now_amount < -1:
trade_amount = now_amount - aim_amount
e.Buy('BTCUSD_200925',prices['BTCUSD_200925'],2*trade_amount)
e.Sell('BTCUSD_201225',prices['BTCUSD_201225'],trade_amount)
e.Sell('BTCUSD_PERP',prices['BTCUSD_PERP'],trade_amount)
if aim_amount - now_amount > 1:
trade_amount = aim_amount - now_amount
e.Sell('BTCUSD_200925',prices['BTCUSD_200925'],2*trade_amount)
e.Buy('BTCUSD_201225',prices['BTCUSD_201225'],trade_amount)
e.Buy('BTCUSD_PERP',prices['BTCUSD_PERP'],trade_amount)
e.df = pd.DataFrame(index=df[trade_symbols].dropna().index,columns=['margin','profit'],data=account)
e.df['profit'].plot(figsize=(15,6),grid=True);
アウト[39]:
[59]:
symbol = 'ETH'
trade_symbols = [symbol+'USD_201225', symbol+'USD_200925', symbol+'USD_PERP']
fee = 0.0002
account = []
diff = df[trade_symbols[0]]+df[trade_symbols[2]]-2*df[trade_symbols[1]]
diff_mean = diff.ewm(alpha=0.001).mean()
e = Exchange(trade_symbols,initial_balance=10000,taker_fee=fee)
for row in df[trade_symbols].dropna().iloc[30:].iterrows():
date = row[0]
prices = row[1]
e.Update(date, trade_symbols, prices)
account.append([e.account['USDT']['margin'],e.account['USDT']['realised_profit']+e.account['USDT']['unrealised_profit']])
aim_amount = -round((diff[date] - diff_mean[date])/(15*prices[trade_symbols[2]]*fee),1)
now_amount = e.account[trade_symbols[2]]['amount']
if aim_amount - now_amount < -1:
trade_amount = 1
e.Buy(trade_symbols[1],prices[trade_symbols[1]],2*trade_amount)
e.Sell(trade_symbols[0],prices[trade_symbols[0]],trade_amount)
e.Sell(trade_symbols[2],prices[trade_symbols[2]],trade_amount)
if aim_amount - now_amount > 1:
trade_amount = 1
e.Sell(trade_symbols[1],prices[trade_symbols[1]],2*trade_amount)
e.Buy(trade_symbols[0],prices[trade_symbols[0]],trade_amount)
e.Buy(trade_symbols[2],prices[trade_symbols[2]],trade_amount)
e.df = pd.DataFrame(index=df[trade_symbols].dropna().iloc[30:].index,columns=['margin','profit'],data=account)
e.df['profit'].plot(figsize=(15,6),grid=True);
アウト[59]:
[60]では:
symbol = 'LINK'
trade_symbols = [symbol+'USD_201225', symbol+'USD_200925', symbol+'USD_PERP']
fee = 0.0002
account = []
diff = df[trade_symbols[0]]+df[trade_symbols[2]]-2*df[trade_symbols[1]]
diff_mean = diff.ewm(alpha=0.001).mean()
e = Exchange(trade_symbols,initial_balance=10000,taker_fee=fee)
for row in df[trade_symbols].dropna().iloc[30:].iterrows():
date = row[0]
prices = row[1]
e.Update(date, trade_symbols, prices)
account.append([e.account['USDT']['margin'],e.account['USDT']['realised_profit']+e.account['USDT']['unrealised_profit']])
aim_amount = -round((diff[date] - diff_mean[date])/(15*prices[trade_symbols[2]]*fee),1)
now_amount = e.account[trade_symbols[2]]['amount']
if aim_amount - now_amount < -1:
trade_amount = 1
e.Buy(trade_symbols[1],prices[trade_symbols[1]],2*trade_amount)
e.Sell(trade_symbols[0],prices[trade_symbols[0]],trade_amount)
e.Sell(trade_symbols[2],prices[trade_symbols[2]],trade_amount)
if aim_amount - now_amount > 1:
trade_amount = 1
e.Sell(trade_symbols[1],prices[trade_symbols[1]],2*trade_amount)
e.Buy(trade_symbols[0],prices[trade_symbols[0]],trade_amount)
e.Buy(trade_symbols[2],prices[trade_symbols[2]],trade_amount)
e.df = pd.DataFrame(index=df[trade_symbols].dropna().iloc[30:].index,columns=['margin','profit'],data=account)
e.df['profit'].plot(figsize=(15,6),grid=True);
出場[60]:
3つの契約が同時に運用される必要があるため,開設後にポジションを閉じるには8つのサービス料金が求められるため,サービス料金は戦略に大きな影響を与えます.0.01%のサービス料金がかかる場合,価格差グリッド間のギャップはさらに縮小できます.BTC
コミッションが0.03%である場合,BTCバックテスト結果は以下のとおりです.
ETHのバックテスト結果:
新規登録ユーザー向けVIP0のテイカーレートは0.0004で,招待された最初の月に10%減額され,30%返金され,BNB消費額は10%減額される.したがって,最終処理手数料は0.0002268である.また,Binance配送契約の最近の大きな取引額に対する直接報酬もあります.さらに,請求書の一部を配置し,請求書の一部を引き取ることができ,最終的な包括的なレートは0.02%に削減できます.さらに,FMZ関係者はBinanceとのサービス料金割引の問題を議論しています.楽しみにすることができます.
アビトレージの目的は,安定した価格差を見つけることです.価格差の価格差はより安定しています.したがって,蝶アビトレージはクロス期とフューチャースポットよりもリスクがはるかに少なく,手動でも操作できます.この戦略は紹介としてのみ使用されます.実際のボットに書き込むときに多くの問題を考慮する必要があります.皆さんにコミュニケーションを歓迎します.
[23]:
class Exchange:
def __init__(self, trade_symbols, leverage=20, maker_fee=0.0002,taker_fee=0.0004,log='',initial_balance=10000):
self.initial_balance = initial_balance #Initial assets
self.taker_fee = taker_fee
self.maker_fee = maker_fee
self.leverage = leverage
self.trade_symbols = trade_symbols
self.date = ''
self.log = log
self.df = pd.DataFrame()
self.account = {'USDT':{'realised_profit':0, 'margin':0, 'unrealised_profit':0,
'total':initial_balance, 'leverage':0, 'fee':0,'maker_fee':0,'taker_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='', maker=True):
if (self.date and symbol == self.log) or self.log == 'all':
print('%-26s%-15s%-5s%-10.8s%-8.6s %s'%(str(self.date)[:24], 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
if maker:
self.account['USDT']['realised_profit'] -= price*amount*self.maker_fee #Deduct service charge
self.account['USDT']['maker_fee'] += price*amount*self.maker_fee
self.account['USDT']['fee'] += price*amount*self.maker_fee
self.account[symbol]['fee'] += price*amount*self.maker_fee
else:
self.account['USDT']['realised_profit'] -= price*amount*self.taker_fee #Deduct service charge
self.account['USDT']['taker_fee'] += price*amount*self.taker_fee
self.account['USDT']['fee'] += price*amount*self.taker_fee
self.account[symbol]['fee'] += price*amount*self.taker_fee
if cover_amount > 0: #Close the 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 #Release 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
def Buy(self, symbol, price, amount, msg='', maker=False):
self.Trade(symbol, 1, price, amount, msg, maker)
def Sell(self, symbol, price, amount, msg='', maker=False):
self.Trade(symbol, -1, price, amount, msg,maker)
def Update(self, date, symbols, close_price): #Update the assets
self.date = date
self.close = close_price
self.account['USDT']['unrealised_profit'] = 0
for symbol in 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)
self.account['USDT']['leverage'] = round(self.account['USDT']['margin']*self.leverage/self.account['USDT']['total'],4)
[ ] で: