見出し画像

【Bybit】FRデルタニュートラルの複利運用をpythonで自動化

Bybitで8時間おきに受け取るファンディング相当のショートポジションを自動で建てる簡易的なプログラムです。

ファンディングのデルタニュートラル戦略はすでに界隈では広く知られています。

手動自動問わず複利で運用されている金利トレーダーは多くいらっしゃると思いますが、軽く検索してみたところ自動化の記事が見当たらなかったので共有します。

FR(ファンディングレート)デルタニュートラル戦略とは

より詳細かつ分かりやすい解説記事がたくさんありますので、簡単な説明に留めます。理解をされている方は読み飛ばしてください。

ファンディングレート(FR/資金調達率)とは仮想通貨取引市場における現物市場と無期限先物市場の価格乖離を抑制するための仕組みです。

・ファンディングレートが「プラス」 → ロンガーがショーターに支払い
・ファンディングレートが「マイナス」 → ショーターがロンガーに支払い

画像1

仮想通貨市場ではこれまでの傾向として無期限先物市場が現物市場よりも割高で推移しやすく、これは多くの期間でショートポジション保有者にファンディング(金利)収入が発生することを意味します。

Bybitでは一日に3度(日本時間1時、9時、17時)、ファンディングの徴収付与が行われます。

画像の赤丸で囲った取引所は仮想通貨現物をデリバティブ取引の証拠金として預け入れることができ(インバース型契約)、損益やファンディングの支払い/受け取りも預け入れた現物証拠金で計算されます。

このインバース型契約の仕組みにより、預け入れた現物と同額のショートポジションを建てることで価格変動による損益の影響を受けないポジション(デルタニュートラル)を組むことが可能になります。

(厳密には現物無期限間の乖離が拡大している間は一時的に無期限ショート含み損>現物含み益となる為この限りではないのですが、ファンディングの受取りによりニュートラルになります)

両建てによって価格変動による損益の影響を受けないため、受取FRがプラスであり続ける限り、無期限ショートポジションからの金利収入のみが積み上がります。

これがファンディング デルタニュートラル戦略です。

この記事のプログラムはデリバティブ取引所の中でも特にFR利回りが高いBybitで運用するためのものです。口座を持っていない方は以下のアフィリンクから開設をお願いします。

Bybit 口座開設ページ

受け取ったファンディングを再投資するべきか

ファンディングは証拠金として預け入れている現物で付与されます。
つまりファンディングを受け取った時点で現物デルタ>ショートポジションデルタとなり、デルタニュートラルが崩れてしまいます。

これを放置していると時間経過とともにデルタの乖離がどんどん大きくなり、下落局面で金利収入<現物の評価損となることが想定されます。

個人的には、現物の価格上昇にベットするのであればデルニューなど組まず現物を裸で握っておけばいいと思っているので、FRで受け取った現物はすぐに利確するか同額のショートポジションを建てることでデルタをニュートラルに戻してあげたいという訳です。

受け取ったファンディングをFiat転することで利益を確定してもよいのですが、せっかくの高利率なので複利パワーを活かしたいところです。

単利・複利比較シミュレーション

開始証拠金を10,000ドルとして、単利(受取ファンディングを利確)と複利(受取ファンディングを再投資)で運用した場合の資産推移をそれぞれ比較してみます。

Bybit BTCUSD / ETHUSD 

画像2

【BTCUSD】
期間 : 2018-11-14 〜 2021-04-16
証拠金    :(単利)$10,000 → $15,385
      (複利)$10,000 → $18,278
累積利率 :(単利) 53.85%
      (複利) 82.78%

【ETHUSD】
期間 : 2019-01-25 〜 2021-04-16
証拠金    :(単利)$10,000 → $17,987
      (複利)$10,000 → $24,358
累積利率 :(単利) 79.87%
      (複利)143.58%

このシミュレーションでは簡単のため全期間でポジションを持ち続けていますが、FRがマイナスの期間はショートポジションを解消して現物をFiatに戻すなど、工夫次第で更に利率を上げる事ができるでしょう。

BybitのFR履歴は以下のリンクから一覧が取れます。
https://www.bybit.com/data/basic/inverse/funding-history?symbol=BTCUSD

pythonコード

やっていること
・受け取ったファンディング相当のショートポジション(成行)を建てる
・時刻、現物残高、ドル換算資産をCSVファイルに定期保存

APIラッパーは技術系botterの まちゅけん(@MtkN1XBt)さんが公開されているPyBybitを利用しています。感謝です。

python 3.8 での動作を確認済み。

import pybybit
from pprint import pprint
import time
import os
import csv
from datetime import datetime, timedelta , timezone
import concurrent.futures
import traceback

api_key = ""  
api_secret = ""
bybit = pybybit.API(key=api_key, secret=api_secret)
coin = ""     # 取引対象の銘柄を入力(BTC/ETH/EOS/XRP)
symbol = coin + "USD"
save_dir = "" # csvを保存するディレクトリのパスを入力

def get_wallet_balance():
   wallet_balance = bybit.rest.inverse.private_wallet_balance(coin=coin).json()["result"][f"{coin}"]["wallet_balance"# 現物残高
   wallet_usd_value = round(bybit.rest.inverse.private_wallet_balance(coin=coin).json()["result"][f"{coin}"]["equity"] * get_index_price(),2# USD評価額
   return wallet_balance , wallet_usd_value
   
def get_index_price():
   index_price = float(bybit.rest.inverse.public_tickers(symbol=symbol).json()["result"][0]["index_price"])
   return index_price
   
def auto_place_market_short_order():
   while True:
       try:
           initial_balance = get_wallet_balance()[0]
           while get_wallet_balance()[0] <= initial_balance:
               time.sleep(60)
           
           order_size = round((get_wallet_balance()[0] - initial_balance) * get_index_price()) # 注文数量 (FR付与によって増加した現物枚数 * インデックス価格)
           order = bybit.rest.inverse.private_order_create(side='Sell', symbol=symbol, order_type='Market', qty=order_size, time_in_force='GoodTillCancel').json() # 成行注文
           
           print("======== ORDER =======")
           print(datetime.now().strftime("%Y/%m/%d %H:%M"))
           print("{} balance : {} -- {} | increase : {}".format(coin,initial_balance,get_wallet_balance()[0],get_wallet_balance()[0]-initial_balance))
           print("order_size : {} | order_status : {}".format(order_size,order["result"]["order_status"]))
           print("======================")     
           
           if order["result"]["order_status"] != "Created"# 発注失敗時
               pprint(order)
               break
           
           time.sleep(60)
       except:
           traceback.print_exc()
           continue

def balance_to_csv():
   file_name = "bybit_balance.csv"
   if os.path.isfile(save_dir + file_name) == False:
       header = ["timestamp","usd_value","balance"]
       with open(file_name ,'a'as f:
           writer = csv.writer(f)
           writer.writerow(header)
   
   while True:
       try:
           now=datetime.now().strftime("%Y/%m/%d %H:%M")
           balance = get_wallet_balance()[0]
           wallet_usd_value = get_wallet_balance()[1]
           with open(file_name ,'a'as f:
               writer = csv.writer(f)
               writer.writerow([now,str(wallet_usd_value),str(balance)])
   
           time.sleep(600# 書き込み間隔
       
       except:
           traceback.print_exc()
           continue
           
if __name__ == "__main__":
   executor = concurrent.futures.ThreadPoolExecutor(max_workers=2)
   executor.submit(auto_place_market_short_order)
   executor.submit(balance_to_csv)
注意事項
プログラムの使用は自己責任でお願いします。
万が一、損失を被ったとしても責任は負えません。

稼働や設定のサポートは出来ませんが、質問等あれば私のTwitter(@javeleeer)のリプやDMで送ってみてください。余裕があれば返します。

それから、記事の内容や認識に間違いなどあれば、指摘していただけると助かります。

以上です。
少しでも役に立ったと感じたら、拡散RTしていただけると嬉しいです。

この記事が気に入ったらサポートをしてみませんか?