T23 · Perp DEX
証拠金、ファンディング、リスクエンジンはどう一つのシステムを構成するのか?
- 練習する能力
- BuilderFinancial Literacy
- 実践
- ポジションと証拠金の計算を実装し、連鎖清算をシミュレーションして保険基金の消耗を記録する。
- AI Lab
- AI にファンディングレートの式を設計させ、過去データで価格を現物価格へ戻せるかバックテストする。
現実の問題
永久先物の取引所を公開して三週間。最も力を入れたのはマッチングだ。板、価格優先と時間優先、部分約定、注文取消、イベント配信。負荷試験でも遅延は安定し、約定記録に一件の漏れもない。
ところが、ある深夜、対象資産が十二分で18%下落した。
翌朝照合すると、すべてのサブシステムのログは正常だった。
- マッチングは一度も停止せず、全約定が保存された。
- 清算エンジンは214回動き、すべて成功した。
- 価格配信は止まらず、T21の四つの検査も一度も警告しなかった。
それでも 帳尻が合わない。
永久先物はゼロサムの台帳だ。ロングの利益一円はショートの損失一円でなければならない。その日の全ポジションの損益を合計すると、ゼロのはずがマイナスになった。システムが利用者に支払うべき金が不足している。
差額をたどると原因は単純だった。31のロングが決済された時点で、損失が預けた証拠金を超えていた。相手方の利益は存在するが、払う側にはもう金がない。三週間かけたマッチングエンジンは、一行も間違っておらず、この問題を解決する力もない。
この穴は誰の損失なのか。誰が埋めるのか?
思考実験
取引所をすべて取り払い、紙一枚と担当者一人だけ残す。紙にはAが10単位のロング、Bが10単位のショートとある。現在価格は100で、価格が1動くたびに片方がもう片方へ10払う。
担当者の仕事はマッチングではない。AとBはすでに組になっている。仕事はただ一つ、紙に記録したすべての残高をいつでも支払えるようにすること。さらに条件を加える。AもBも1000ではなく50だけ証拠金を預けている。
価格が動き始めると、常に四つの問いに答えなければならない。この四つが本章のすべてだ。
第一、各人に今いくら残っているか? 価格103ならAの含み益は30、Bの含み損は30で、Bの純資産は20しかない。この数値は決済する日まで待つのではなく、いつでも計算可能でなければならない。
第二、いつ退出させなければならないか? Bの純資産がゼロになってから動けば価格は105だが、105ぴったりで決済できるだろうか。できない。処理には時間がかかり、価格は待ってくれない。だから 前もって、まだ資金が残るうちに動く必要がある。いくら残ったら動くかは、明文化すべき数値だ。
第三、退出が遅れて生じた不足をどうするか? 価格が104から108へ飛べばBの純資産はマイナス30になる。Aは80受け取る権利があるが、Bは50しか払えない。台帳を合わせるには この30を誰かから取らなければならない。未処理のままではAの残高が実在しないことになる。
第四、全員がロングしたいときは? 紙の上ではロングとショートが対にならなければならない。買い手100人、売り手3人なら、残り97人の相手は誰か。
第四の答えは第18章のファンディングだ。混み合う側に立つことに価格を付けることで、支払いを通じて人を不足している側へ動かす。あの章は「なぜ価格を引き戻せるか」を問い、本章は「コードではどう書くか」を問う。
四つを合わせると一つの機械になる。価格を継続して読み、各人の純資産を再計算し、底をつく前に退出させ、遅れたら別の誰かから不足分を補う。
マッチングは誰と誰が約定するかを決める。この機械はシステムが支払いを履行できるかを決める。
あなたが決める
冒頭の31の証拠金超過損失に戻ろう。不足額は確定しており、今日中に誰かの負担にしなければならない。
誰を選ぶか?
結果を観察する
四つの選択肢は同じ問いに答えている。ゼロサム台帳の穴を、今日中に誰が負担するか。
| 負担者 | 利用者が予測できるか | 発動時点 | 主な代償 |
|---|---|---|---|
| 不良債権として放置 | いいえ | 精算されない | 早い者勝ちの取り付けになる |
| 専用資金プール | はい | 最優先 | 規模は有限で、保有資産も同時に下がり得る |
| 利益の比例減額 | いいえ | 資金プール枯渇後 | 損失源を事前に価格付けできない |
| 利益ポジションの強制決済 | 一部可能 | 最後 | 正しい方向でも全利益を受け取れない |
一行目だけが根本的に誤った選択肢で、残る三つは同じ防衛線の別の層だ。順番に並べると本章の骨格になる。
- 維持証拠金ラインで清算する
- ポジション自身の残存証拠金
- 専用資金プール
- 利益側を強制決済する
証拠金を超える損失の条件を不等式にしよう。T22の不等式と同じ形だ。
証拠金を超える損失の条件:
清算発動から決済完了までのマーク価格の変動幅
>
維持証拠金率 + 清算用に確保した部分
内訳:
左辺 = 相場の速度 × 清算遅延 ← 自分では制御できない部分
右辺 = 設定したパラメータ ← 設計できる部分T22と同じ構造だが二つ違う。その違いが本章を設けた理由だ。右辺が一桁小さい。貸付の余裕は二十数ポイントでも、高レバレッジの永久先物では維持証拠金率が数%、時には数‰になる。そして 不足を帳簿に残したままにできない。貸付の損失は徐々に吸収できるが、永久先物では今日中に誰かから補う必要がある。
したがって、永久先物の本体は継続稼働するリスクエンジンであり、マッチングはその外殻である。マッチングは約定品質を決め、リスクエンジンは深夜に利用者への支払いが不足するかを決める。
モデルを作る
五つの部品を、一度の価格変動で動く順に見よう。
一、マーク価格:すべての判断の土台
永久先物市場には三つの価格がある。混同すると本章で最も高くつく。
| 名前 | 内容 | 用途 |
|---|---|---|
| 指数価格 | 複数の現物取引所価格の加重平均 | ファンディングの基準、マーク価格の材料 |
| マーク価格 | 指数価格からの偏差を制限した価格 | 損益計算と清算判定 |
| 最終約定価格 | この契約で直近に成立した価格 | 表示、マッチング |
清算にはマーク価格を使い、最終約定価格を使ってはいけない。自分の板は一件の取引で動かせる。清算の基準にすれば、薄い板で取引する意思のある誰にでも、清算対象を決める権限を渡すことになる。
最も素朴な方法は 外部の指数価格を基準に、約定価格をその周りの固定帯域内に収めることだ。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
uint256 constant BPS = 10_000;
/// マーク価格:外部指数を基準に、小さな偏差だけを許す
function markPrice() public view returns (uint256) {
uint256 index = priceGuard.readPrice(); // T21の四つの検査はこの関数内にある
uint256 last = lastTradePrice;
uint256 upper = index * (BPS + markBandBps) / BPS; // markBandBpsは設定可能。典型的には数十から数百
uint256 lower = index * (BPS - markBandBps) / BPS;
if (last > upper) return upper;
if (last < lower) return lower;
return last;
}価値は 攻撃費用を「自分の板を動かす額」から「外部現物市場を動かす額」へ引き上げることにある。外部市場の厚さはT21の安全余裕の分子だ。T21の章全体がこの readPrice() に収まっている。操作された値を返せば、以下の四部品はすべて機能を失う。それでも正常実行され、エラーは出ない。
二、ポジションと証拠金:いつでも計算できる純資産
int256 constant WAD = 1e18;
struct Position {
int256 size; // 正ならロング、負ならショート。単位は対象資産数量
uint256 margin; // このポジションに預けた証拠金
uint256 entryPrice; // 建玉時のマーク価格
int256 entryFunding; // 建玉時の累積ファンディング指数。次節参照
}
/// 未実現損益:符号付きsizeによりロングとショートを一行で扱う
function unrealizedPnl(Position memory p, uint256 mark) pure returns (int256) {
return p.size * (int256(mark) - int256(p.entryPrice)) / WAD;
}
/// 想定元本 = ポジションの絶対数量 × マーク価格
function notional(Position memory p, uint256 mark) pure returns (uint256) {
int256 s = p.size >= 0 ? p.size : -p.size;
return uint256(s) * mark / uint256(WAD);
}size を符号付き整数にするのが、ここで特に強調すべき設計判断だ。損益、ファンディング、清算判定を共通式で扱え、各関数で方向別に分岐しなくてよい。分岐する実装はロングとショートの非対称な境界で間違いやすい。
三、ファンディング:全ポジションを走査してはいけない
第18章では価格を引き戻せる 理由を説明した。実装には制約がある。八時間ごとに数万のポジションを走査して徴収することはできない。チェーン上にその計算予算はない。
T22の利息と同じ解法を使う。全体の累積指数を保持し、各ポジションは建玉時の指数だけを記録する。任意時点の支払額は一回の引き算で得られる。
int256 public cumulativeFunding; // ロング一単位あたりの累積支払額。符号付き
uint256 public lastFundingAt;
/// 前回から現在までのファンディングを指数に積算する。O(1)で建玉数に依存しない
function accrueFunding(uint256 mark, uint256 index) internal {
uint256 elapsed = block.timestamp - lastFundingAt;
if (elapsed == 0) return;
// プレミアム項:マーク価格と指数価格の偏差をWAD倍する
int256 premium = (int256(mark) - int256(index)) * WAD / int256(index);
// 料率 = プレミアムを秒あたりに配分 + 金利項。必ず上下限内に収める
int256 rate = premium / int256(fundingPeriod) + interestPerSecond;
if (rate > fundingCapPerSecond) rate = fundingCapPerSecond;
if (rate < -fundingCapPerSecond) rate = -fundingCapPerSecond;
cumulativeFunding += rate * int256(elapsed) * int256(index) / WAD;
lastFundingAt = block.timestamp;
}
/// 支払うファンディング:正なら支払い、負なら受け取り
function fundingOwed(Position memory p, int256 cumulative) pure returns (int256) {
return p.size * (cumulative - p.entryFunding) / WAD;
}
/// 純資産 = 証拠金 + 未実現損益 − 支払うファンディング
function equity(Position memory p, uint256 mark, int256 cumulative) pure returns (int256) {
return int256(p.margin) + unrealizedPnl(p, mark) - fundingOwed(p, cumulative);
}自分で決める三つの値はすべて 設定可能にする。普遍的に正しい数値はない。
| パラメータ | 決めること | 誤ると |
|---|---|---|
fundingPeriod | 偏差を何秒に配分して徴収するか | 長すぎると拘束が弱く、短すぎると平穏時にも繰り返し課金する |
fundingCapPerSecond | このアンカーの 力の上限 | 狭すぎると極端な相場で上限に達し、それ以上圧力を増やせない |
| 課金基準 | 想定元本か証拠金か | レバレッジ倍の差があり、誤れば桁が違う |
二行目は見落としやすい。上下限は安全措置であるだけでなく、アンカーが引く力の最大値だ。偏差がその力を超えると料率は一定になり、偏差が拡大しても増えない。残るのは裁定取引者だが、極端な相場ほど撤退しやすい。
さらに 清算判定前にファンディングを積算する必要がある。長く動かさないポジションは、価格が動かなくても累積支払いだけで維持ラインを割り得る。この一行を忘れると、健全に見える建玉が実は以前から清算対象だったと気づく日が来る。
四、清算:この段階で帳尻を合わせる
error NotLiquidatable();
/// 清算可能条件:純資産が維持必要額以下になる
function isLiquidatable(
Position memory p,
uint256 mark,
int256 cumulative,
uint256 maintenanceBps // 維持証拠金率。典型的には数十から数百bps。通常は規模別に段階設定し、必ず変更可能にする
) pure returns (bool) {
int256 e = equity(p, mark, cumulative);
if (e <= 0) return true;
return uint256(e) <= notional(p, mark) * maintenanceBps / BPS;
}
function liquidate(address trader) external {
Position storage p = positions[trader];
uint256 mark = markPrice();
accrueFunding(mark, priceGuard.readPrice()); // 先にファンディングを精算してから判定する
if (!isLiquidatable(p, mark, cumulativeFunding, maintenanceBps)) revert NotLiquidatable();
int256 e = equity(p, mark, cumulativeFunding);
uint256 fee = notional(p, mark) * liquidationFeeBps / BPS; // 清算者が参加する動機のすべて
if (e > int256(fee)) {
_payout(msg.sender, fee); // 清算者に手数料を払う
_payout(trader, uint256(e) - fee); // 残りを利用者に返す
} else if (e > 0) {
_payout(msg.sender, uint256(e)); // 手数料の一部しか払えない
} else {
// 純資産が負:証拠金超過損失。この取引内で不足を負担する主体を決める
_coverShortfall(uint256(-e));
}
_closePosition(trader);
}
function _coverShortfall(uint256 gap) internal {
emit ShortfallCovered(gap);
if (insuranceFund >= gap) {
insuranceFund -= gap;
return;
}
uint256 remaining = gap - insuranceFund;
insuranceFund = 0;
_autoDeleverage(remaining); // 利益とレバレッジで順位を付け、利益側を一部強制決済する
}_coverShortfall は契約内で唯一 revertしてはいけない分岐だ。資金プールを使い切っても、最後の防衛線を使ってもよいが、必ず戻る必要がある。この取引内で帳尻を合わせる義務があるからだ。
T22と比べよう。貸付の _recordBadDebt は「記録し、後で処理する」、永久先物の _coverShortfall は「今すぐ資金を見つける」。同じ位置にあっても義務は全く違う。
五、清算者はなぜ来るのか
T22と同じだ。清算者に給与も義務もなく、想定元本に清算料率を掛けた額が、Gasと決済のスリッページを上回るときだけ来る。小さな建玉は放置され、混雑時は採算が取れず、十人で一機会を争えば九人は手数料だけ払う。違いは結果だ。貸付では不良債権が徐々に増え、永久先物では 今日出金できない人が出る。
何と呼ぶか
市場でまだ決済していない利用者のエクスポージャー。方向、数量、建値、預けた証拠金を含む。
方向を真偽値ではなく 符号付き数量にすれば、損益、ファンディング、清算判定を共通の式で扱える。方向別の分岐は境界で間違いやすい。
レバレッジポジションのために預ける元手。
二つを区別する。初期証拠金は建てられる規模を、維持証拠金は清算される時点を決める。分離証拠金では清算価格を事前計算できるが、クロス証拠金では他の建玉の損益により 動き続ける。建玉時の数値を定数として使ってはいけない。
損益計算と清算発動に使う価格。外部指数を基準に、偏差を限定した帯域内に収める。
存在する理由は 清算判断の基準を薄い市場から厚い市場へ移すこと。最終約定価格に置き換えれば、誰でも一件の取引で清算対象を決められる。永久先物史で繰り返された事故の型だ。
マーク価格と指数価格の偏差に応じ、周期的にロングとショートの間で精算する支払い。
手数料ではなく、利用者間で資金が移る。全建玉を走査して徴収せず、累積指数を使い、各建玉は建玉時の指数だけを記録する。周期、上下限、課金基準の三つを必ず確認する。二つ目がアンカーの 力の上限だ。
証拠金を超える損失を埋める専用資金。通常は清算時の残余や手数料の留保で積み立てる。
問いは二つ。何建てか。自社発行資産なら最も必要なときに同時に価値が減る。そして 未決済建玉に対してどれほどの規模か。基金の絶対額だけでは意味がない。市場に積み上がるレバレッジのストックである未決済建玉が分母になる。
保険基金で不足を補えないとき、順位に従って利益側の建玉を一部強制決済し、エクスポージャーを引き受けさせる仕組み。
最後の防衛線であり、永久先物特有のリスクだ。方向が正しく、利益が出ていても規則によって決済され得る。順位規則を事前公開し、利用者が自分の位置を確認できる必要がある。
実践
中核構造と四つの純粋関数を実装する。 Position と unrealizedPnl、notional、fundingOwed、equity を作り、size を符号付き整数にする。
まず純粋関数だけを書き、すべて手計算で確かめる。
- 10単位のロング、建値100、マーク価格103なら含み益30。同じ数量のショート(sizeが負)なら含み損30。
- 累積ファンディング指数が0から2へ上がると、10単位のロングは20払い、同量のショートは20受け取る。
- 両側のファンディング合計はゼロでなければならない。ゼロサム性の最初のテストで、以降の全試験でも成立させる。
マーク価格とファンディング積算を実装する。 指数価格に帯域を加える方法を使い、価格源はT21の PriceGuard につなぐ。四検査を一つも除かない。制御可能なスタブ価格源で三点を確認する。約定価格が帯域内ならそれを返す。帯域外なら約定価格ではなく 制限された境界値を返す。価格が古い場合は、T21で 明示的に選んだ戦略どおりに清算経路全体が動く。
清算と二つの補填策を実装する。 liquidate の三分岐をすべて書き、特に e が負の場合を確認する。_coverShortfall は基金不足でも続行し、revertしてはいけない。基金を0にし、証拠金超過損失の建玉を清算する専用テストを書く。成功して戻り、自動デレバレッジを発動しなければならない。
revertすれば、永久に清算できない建玉が契約内に残る。 T22の教訓の永久先物版で、結果はさらに重い。相手方の建玉を占有し続け、他人の含み益を永久に実現不能にする。
連鎖清算を作り、保険基金の消耗を記録する。これがLabの中心だ。 レバレッジの異なる三群のロングを作り、下落系列を与える。重要なのは 各段階でマーク価格を読み直し、ファンディングを積算し、判定し直すこと。一度の計算で済ませないことだ。
初期マーク価格100。維持証拠金率は自分で設定する
三群のロング: A群5倍レバレッジ1億、B群10倍3億、C群20倍2億
深さの仮定: 想定元本5000万を決済するたびマーク価格がさらに1%下がる(最重要の仮定)
初期ショック: マーク価格が96へ下がる各ラウンドを実行し、一行ずつ記録する。
| 回 | マーク価格 | 今回清算した想定元本 | 今回の証拠金超過不足額 | 保険基金残高 | 自動デレバレッジ発動 |
|---|---|---|---|---|---|
| 1 | |||||
| 2 | |||||
| 3 |
基金がゼロになるラウンドを見つける。 そこがこの設定で、正しく方向を選んだ人を規則が傷つけ始める時点だ。
次に 深さの仮定だけを変え、「5000万で1%下落」を「2億で1%下落」にして再実行する。他は変えない。表を並べると核心が見える。同じレバレッジ構造、設定、コードでも、深さの仮定によって、一方は調整で済み、他方は基金を使い切る。 同じ契約でも流動性の乏しい対象資産ではリスクが一桁上がる理由だ。問題は契約の中だけにはない。
攻撃費用を計算する。これが本章の定量演習だ。
これまでは相場が自分を破綻させるかを計算した。今度は 誰かが意図的に攻撃すると、いくら必要かを問う。
状況:市場で想定元本Nがあるレバレッジ水準に集中し、
清算価格が現在価格からd(百分率)離れている
第1段階:マーク価格をdだけ動かす費用
マーク価格は外部指数が基準なので、外部現物市場を動かす
T21の式:約 現物市場の深さ × (sqrt(1+d) − 1)
第2段階:発動する清算規模と、強制決済でさらに価格が下がる幅
前の深さの仮定を使う連鎖効果
第3段階:攻撃者の受取額
a) 事前に建てた逆方向の建玉が下落で得る利益
b) 清算者として受け取る清算手数料
c) 強制決済で安く取得する資産
第4段階:純利益 = 第3段階 − 第1段階 − 手数料 − Gas現物の深さ500万、5000万、5億と、d=5%で三組を計算する。第一組は純利益が正になりやすい。薄い対象市場では清算は単なる下落の結果ではなく、意図的に作れる商売になる。
二つ逆算する。一、この設定で攻撃が割に合わなくなる最低限の外部現物深度は? これが安全な上場に必要な最低流動性で、T21の担保受入基準と同じものだ。二、マーク価格を最終約定価格に替えると第1段階の費用は? 自分の板を動かす費用は外部市場より一桁から二桁低いことが多い。その倍率こそマーク価格設計の価値だ。
すべてローカルネットワークで行い、実資金を接続しない。 実資金は卒業制作でのみ扱い、先に第五段階の安全検査を通過する必要がある。
AI Lab
三段階で問う。第三段階が本当の成果物だ。
第一段階:
永久先物市場のファンディング式を設計してください。完全な式、各項の意味、
上下限の選び方、O(1)のチェーン上実装を示してください(建玉走査は禁止)。
周期長と上下限がそれぞれ何を守るのか説明してください。
第二段階:
対象資産の現物価格と同時期の永久先物約定価格の系列を渡します。
先ほどの式で各期のファンディングを計算し、各期について
偏差、料率、ロングの保有費用の年率、ショートの収益の年率を出してください。
上下限に達した期間を示してください。
第三段階:
第二段階で上限に達した期間について答えてください。
偏差はさらに拡大しましたか、収束しましたか。拡大なら何を意味しますか。
どのパラメータをどう変えますか。その変更に伴う新しい代償は何ですか。多くのモデルは第一段階で形の正しい式を出すが、誤りは実装に集中する。全建玉をループしたり、チェーン外に丸投げしたりする。「数万建玉を八時間ごとに処理したらGasはいくらか」と追問する。
第二段階は 実際の過去データを使い、AIに作らせない。公開データ源から現物と先物の価格系列を取得して渡す。平穏時より急変時が有用だ。三期を自分で抽出し、紙とペンで料率を再計算する。
第三段階がLabの価値だ。上限に達しても偏差が拡大するなら、帳簿が正常でも仕組みは機能していない。 その状態で誰が価格を引き戻すか問おう。答えは裁定取引者だが、そのときこそ撤退しやすい。最後に式をLabの契約へ接続し、見た目の美しさだけでなく連鎖清算シミュレーションでの働きを確かめる。
AI の回答後、自分で必ず検証すること
- 式に上下限があるか。ない式は極端な相場で非現実的な数値を返す
- 上下限を代入し、10%偏差時の最大の引き戻す力を計算する。十分か
- 想定元本と証拠金のどちらに課金するか明示したか。レバレッジ倍の差がある
- 全建玉を走査して徴収していないか。チェーン上にその予算はなく、累積指数が必要
- 負の料率ではショートからロングへ払うことと、その際の資金プール会計を説明したか
- バックテストで指数価格とマーク価格を区別したか。混同すると結果を信用できない
- 周期、上下限、維持証拠金率などの数値を事実ではなく調整可能な出発点として扱ったか
実例
初期の取引所には契約自身の最終約定価格で清算を判定するものがあった。攻撃経路は計算できる。建玉群の清算価格と、自分の板をそこまで動かす費用を見積もり、発動する清算規模が費用を超えれば商売になる。強制決済注文は同じ薄い板へ戻り、価格の針を伸ばしてさらに清算を呼ぶ。針が戻っても、消えた建玉は戻らない。
後に業界は 外部現物の加重指数と偏差を制限したマーク価格へ移った。これは本章の markPrice() と同じ変更で、清算判断を薄い市場から厚い市場へ移す。T21と同じ問題の別の出口だ。
攻撃者は現物流動性が乏しいのに永久先物が上場された資産を選び、先物で大きなロングを作ってから現物を買い上げた。指数価格が上がり、含み益は巨大になった。その取引所では含み益を使って直ちに資産を引き出せた。
コードは一行も間違っていなかった。 利益が出ているので清算は起きず、現物が本当に上がったので価格源も嘘ではなく、証拠金計算も正しかった。破られたのは「含み益が実在する」という仮定だ。
教訓は二つ。上場前に現物深度が市場のエクスポージャー上限を支えられるか計算する。そして 未実現損益をすぐ出金可能にするかは独立して決める設定であり、多くの実装が制限を設けている。
価格が飛び、大量の建玉が維持ライン以下でようやく決済され、不足が清算で補える額を超えた。基金が急減し、自動デレバレッジが大量発動した。正しい方向を選び利益が出ていた多数の利用者も、一部を強制決済された。 何も誤っておらず、警告も受けていなかった。規則に書かれてはいたが読んでいなかった。
その後の典型的な変更は、基金残高と未決済建玉の比率公開、自動デレバレッジ順位の公開、そして 建玉規模に応じた維持証拠金率の引上げだ。大きな建玉に厚い余裕を求める三つ目が最も有効で、大口には最も嫌われる。
一方向の相場が続くと、料率が複数期にわたり上下限に張り付き、それでも価格偏差が広がることがある。
誤読しやすいのは 料率が最大でも、圧力が十分大きいとは限らないことだ。偏差が増えても料率は増えず、引く力には上限がある。残るのは裁定取引者だが、現物側で逆方向の建玉を作る必要があり、緊張した相場ほど難しい。
上下限はアンカーの力の上限だ。必ず確認すべきなのに大多数は確認していない。永久先物市場を見るならチェックリストの先頭三項に置こう。
変数を一つ変える
板が厚ければ違いは見えず、速度もテスト結果も同じだ。違いは板が薄いときに出る。変わるのはリスクの大きさではなく 性質だ。価格変動で清算される構造が、意図的に清算を作れる構造になる。
Lab最後の倍率がこの変更の代償だ。本章で最も変更してはいけない一行で、攻撃費用を外部現物市場から自分の板へ下げるスイッチになる。
一建玉の清算までの距離は4.5%から0.5%へ縮むが、本当の変化は全体にある。同じ証拠金が五倍の想定元本を支え、未決済建玉が増え、その追加分は薄い余裕の上に積まれる。基金規模は増えない。最初のドミノを倒すのに必要だった5%下落が、0.5%で足りる。
新しいレバレッジで表を再計算すると、基金がゼロになる回は早まる。上限引上げは利用者に選択肢を増やすだけでなく、市場が平穏から制御不能になるためのショックの大きさを変える。
偏差が出ればすぐ課金するため、精算時刻を待たず、アンカーは強まる。累積指数なら変更費用はほとんどなく、各状態変更前に accrueFunding を呼べばよい。
新しい論点は三つ。精算時刻の前後に建玉を開閉する裁定がなくなるのは利点だ。各取引で価格取得と指数更新が増えるのでGasは上がる。そして 精度。一ブロックの料率は小さく、整数の切捨てが繰り返されると体系的な過少徴収や過大徴収になり、数十万ブロックで大きな額になる。丸め方向はプールが損をしない側にする。T19の各丸めでプールを守る原則と同じだ。
平時は大きな基金を低コストで用意でき、帳簿は美しい。だがフィードバックが生まれる。極端な相場で不足が増すと同時に、その資産も下がりやすい。最も必要なときに実際の補填能力が縮む。三層の防衛線があるつもりでも、第一層の失敗と同時に第二層も失敗する。
第21章の構造でさらに問おう。保険基金と保険対象のリスクは同じものに左右されていないか? そうなら保険ではなくレバレッジだ。
持ち帰る問い
独立した三つの資金移動を分ける。ファンディングはロングとショートの間で動き、プロトコルを経由しない。清算手数料は清算対象者から清算者へ、超過損失の補填は基金または利益側から損失側の相手方へ動く。払うのはすべて利用者で、受け取るのも多くは利用者だ。
プロトコルの主な役割は受取人ではなく、記帳と補填の主体である。その失敗形態は利益が減ることより、支払いを履行できなくなることだ。
永久先物の流動性には三層あり、一つ欠ければ不完全だ。契約の板の深さは開閉時のスリッページを、外部現物の深さはマーク価格の操作可能性を決め、保険基金は不足時に相手方を探さず使える唯一の資金になる。第一層しか見ない分析は多い。板は厚く見えても外部現物が薄い市場こそ、本章で警戒してほしい対象だ。
防衛線の順に四層で答える。平時はレバレッジ利用者、清算時は一部が清算者へ移り、スリッページや競争敗北の費用を負う。証拠金超過時は基金、基金不足時は利益側へ移る。最後は永久先物特有だ。正しく判断しても規則で決済され得るため、基金規模、保有資産、順位規則は必須確認事項になる。
具体的には 取引所の発行資産がゼロになったら基金はいくら残るか? と問う。さらに、価格変動するものに依存する箇所を探す。基金の保有資産、清算者のヘッジ手段、マーケットメーカーの報酬などだ。どの依存も、極端な相場でリスクと一緒に悪化する部品になり得る。
章末チェック
マッチングは誰が誰とどの価格で約定するかを決める。だが永久先物はゼロサム台帳で、一方の利益をもう一方の損失で払う必要がある。その成立を常に保証するのは別の機械だ。マーク価格を読み、純資産を再計算し、底をつく前に決済し、遅れたら基金や利益側から不足を補う。
判定は単純だ。マッチングを誤れば約定価格が悪化し、リスクエンジンを誤れば残高が架空になる。 前者は製品品質、後者は支払能力の問題だ。
最終約定価格は自分の板で決まり、一取引で動かせる。清算基準にすると、薄い板で取引する意思のある誰にでも清算対象を決める力を渡してしまう。
マーク価格は 複数の外部現物取引所の加重指数を基準に、約定価格の偏差を制限する。攻撃費用を自分の板から外部現物市場へ引き上げるための設計だ。
安全性を見るには指数の参照先とその市場深度を先に調べる。参照市場が薄いほど防護も弱い。T21の安全余裕の分子と同じ数字だ。
建玉数に上限がなくても、一取引の計算予算には上限がある。数万の走査は一取引に収まらず、成長とともに遅くなり、やがて実行不能になる。
全体の累積指数でロング一単位の累積支払額を保持し、各状態変更前に経過時間分を加える。建玉には建玉時の指数だけを保存し、支払額は引き算で求める。T22の利息積算と同じ技法だ。多数の口座へ周期的に同じ処理をする必要を見たら、ループより先に累積指数を考える。
債権者が違う。貸付では利用者がプロトコルに借りるので、損失を認め、準備金で吸収し、公開しても帳簿の整合性は保てる。
永久先物では 別の利用者に支払う。未精算なら利益側の残高は架空だ。公開数値ではなく、先に来た人だけ出金できる現象として表れる。放置した不足額は、まだ発見されていないだけで始まっている取り付け騒ぎだ。
だから _coverShortfall はrevertしてはいけない。基金枯渇や自動デレバレッジを使っても、この取引内で答えを出す必要がある。
唯一の正解はないが、次の項目が含まれ、第一項が本当に最初にあるか確かめる。
- 外部現物市場の深さと取引所の分布。指数の操作可能性と後続設定の上限を決める。これが不適格なら残りは無意味だ。
- 市場のエクスポージャー上限。未決済建玉の上限は第一項に連動させ、勘で決めない。
- 最大レバレッジと維持証拠金率の段階表。大きな建玉の決済は価格影響も大きく、厚い余裕が必要だ。
- マーク価格の帯域と価格源が使えない場合の各入口の動作。T21の表をここでも埋め直す。
- ファンディングの周期、上下限、課金基準。上下限はアンカーの力を制限する。
- 基金の規模、保有資産、補充方法と、自動デレバレッジ順位を利用者が見られるか。
T22と同様、土台から上へ進む。価格源、エクスポージャー、事故後の処理の順だ。多くは第三項から考えるが、リスクの桁を決めるのは第一項である。
要点
無期限先物の本質は動き続けるリスクエンジンであり、注文のマッチングはその外側にすぎない。