無期限先物のbotを作成するにあたって約定ごとの損益の計算が必要なのだが、すっきりと理解できていないので、公式ドキュメントなどを読みながら自分の理解を進めるためにも記事としてアウトプットしておく。

やりたいこと

無期限先物の例として、bybitBTCUSDインバース無期限先物のBTC建て損益計算を、bybitの約定履歴から行う場合を考える。

結論

インバース契約を基軸通貨建てでqの数量を決済した際の損益は、購入価格と売却価格の数列をpb,psp_b,p_sとして

PL=q(1Avg(pb)1Avg(ps))PL=q(\frac{1}{Avg(p_b)} - \frac{1}{Avg(p_s)})

となる。ただし、平均については約定サイズの加重平均で計算した平均約定価格を指す。

一般的な損益計算

基軸通貨建てでの価格、取引対象のリスク資産の枚数、取引方向の3つの情報を含む約定履歴が与えられたときの損益計算の場合は、次のような損益計算ができる。

各約定のサイズの数列をqnq_n、価格の数列をpnp_n、売買方向を買いを1、売りを−1として符号化した数列をsignnsign_nとする。ただし、任意のnnにおいてpn>0,qn>0p_n > 0, q_n > 0で、qnq_nの単位はリスク資産の枚数、pnp_nの単位は基軸通貨建て(円建て取引なら円)でのリスク資産の価格。signnsign_nは無次元量。

この約定履歴から計算される基軸通貨建てでの損益の数列は、

PLn=k=1npkqksignk+pnk=1nqksignkPL_{n} = -\sum_{k=1}^{n}{p_{k}q_{k}sign_{k}} + p_{n}\sum_{k=1}^{n}{q_{k}sign_{k}}

で与えられる。ここで、第一項は決済損益、第二項は含み損益を表す。

上記は一般化した言い方をしているため、分かりづらい場合には自身の取引している対象、例えばリスク資産をBTC、基軸通貨を円などと読み替えて欲しい。

インバース契約

ここまでの計算は比較的直感的だが、bybitやbitmexで採用されている「インバース契約」の場合には上記と事情が異なってくる。

インバース契約とは

インバースとは「逆」という意味で、身近な例で言うと線形代数で逆行列を取ることを、「インバースを取る」と言うことがある。

仮想通貨のデリバティブ取引所で採用されているインバース契約は、簡単に言うとBTCUSDをUSD単位で取引するような商品のことを指す。bitFlyerやGMOコインなどの国内取引所では、取引を行う際に発注サイズの指定を「x BTC」などと指定するが、インバース契約では「x USD」のような指定をする。また、保有ポジションのサイズもドルで計算される(ここが非常に重要)

それによって、通常のリスク資産建てでサイズを指定する場合には発生しなかった次のような状況が発生する。

  1. 100USD分のビットコインを価格10000USDで購入。これは0.01BTC相当。
  2. 100USD分のビットコインを価格20000USDで売却。これは0.005BTC相当。

このとき、トレーダーは1で0.01BTCを買ったはずなのだが、2で売却する際には0.005BTCしか売却していない。差分の0.005BTCはどうなるかというと、これがこのトレーダーの利益として払い出される。
証拠金をBTCで入金するBitmexやbybitでインバース契約が採用されているのは、このように払い出されるBTCの額が即座に決まり、利便性が高いためだと考えられる。

インバース契約の損益の定義

上記の計算を一般化すると、インバース契約でリスク資産を1回買って売うという取引を行ったときの損益は以下のように計算される。(ここでもリスク資産と基軸通貨を、自分が取引している対象に置き換えると分かりやすい。)

なお、ショートとロングは売却と購入の順番が異なるだけなので、上記の条件はショートの場合とロングの場合の両方を含んでいる。

リスク資産の購入価格pbp_b、売却価格psp_s、基軸通貨建てでの取引額をqqとして、

PL=qpbqps=q(1pb1ps)PL = \frac{q}{p_b} - \frac{q}{p_s} = q(\frac{1}{p_b} - \frac{1}{p_s})

となる。

実際の取引では購入や売却は部分約定等により、複数の約定を伴うものになる可能性があるため、pbp_bおよびpsp_sについては、それぞれ保有ポジションの平均約定価格および、反対売買を行う場合の平均約定価格を使用することになる。(ここで言う平均とは、約定サイズによる加重平均を指す)

つまり、取引回数を1回に限定せず、売買を行った結果基軸通貨建てでqの数量を決済した際に一般化した場合の損益は、

PL=q(1Avg(pb)1Avg(ps))PL=q(\frac{1}{Avg(p_b)} - \frac{1}{Avg(p_s)})

未決済のポジションの損益の場合には、決済を行ったと仮定して平均約定価格を計算することとなる。(bestask, bestbid, 最終約定価格などを約定価格と仮定する。)

これをもとに、買い売りそれぞれの約定価格、約定数量の数列を

Pb,Ps,Qb,QsP_b, P_s, Q_b, Q_s

と与えられたとき、時刻t時点での開始時点からの損益は、

インバース無期限の損益計算ロジック

PL(t)=max(Σ(Qb),Σ(Qs))×(AVG(Pb)(t)(1)AVG(Ps)(t)(1))PL(t) = max(\Sigma(Q_b), \Sigma(Q_s))\times(AVG(P_b)(t)^{(-1)}-AVG(P_s)(t)^{(-1)})

AVG(Pb)(t)=max(ΣPbvb,ΣPbvb+P(t)(ΣvsΣvb))max(Σvb,Σvs)AVG(P_b)(t) = \frac{max(\Sigma{P_bv_b}, \Sigma{P_bv_b} + P(t)(\Sigma{v_s} - \Sigma{v_b}))}{max(\Sigma{v_b}, \Sigma{v_s})}

AVG(Ps)(t)=max(ΣPsvs,ΣPsvs+P(t)(ΣvbΣvs))max(Σvb,Σvs)AVG(P_s)(t) = \frac{max(\Sigma{P_sv_s}, \Sigma{P_sv_s} + P(t)(\Sigma{v_b} - \Sigma{v_s}))}{max(\Sigma{v_b}, \Sigma{v_s})}

ただし、

Pb,Ps,Qb,Qs>0,vb=QbPs,vs=QbPsP_b, P_s, Q_b, Q_s > 0, v_b= \frac{Q_b}{P_s}, v_s = \frac{Q_b}{P_s}

として与えられ、この定義に従って計算を行えばpandasなどの2次元のテーブルによって、アルゴリズム論的な文脈で言うところのいわゆる計算量が少ない方法で、処理を済ませることができる。

参考