OASIS BLOG
← 回到七日冲刺← D1 笔记D3 笔记 →
写给没碰过股票、期货、合约的 Java 程序员 · 接着 D1

D2 零基础速成笔记

今天讲交易系统里最核心的三样东西:一张订单从下单到结束会经历什么,价格和数量为什么要"取整",以及永续合约里那几个听起来很吓人的词:标记价格、资金费率、强平价。页面里带下划虚线的词,点一下就能看解释。

怎么读按顺序读,一共 12 节,大约 2–3 小时。前 5 节讲订单和精度,后 6 节讲永续合约。
每个概念都分四层大白话 → 生活例子 → 算一遍 → Java 类比。前两层看懂就够了。
读完以后回到七日冲刺的 D2,订单状态机图、精度取整和强平价计算器就都能看懂了。
1

一张订单的一生

本节新词订单状态 · 挂着 · 部分成交 · 全部成交 · 已撤销 · 被拒绝

订单提交以后不是"成功"或"失败"这么简单。它会经历好几个阶段,每个阶段叫一个订单状态。交易系统里一大半的 bug,都出在状态没处理对。

订单状态 order status

大白话
订单现在走到哪一步了。一共六种,括号里是进组后你会在代码里看到的英文:
挂着
交易所收下了订单,挂在订单簿上等人来成交。OPEN 或 NEW
部分成交
要买 1 个,已经买到 0.3 个,剩下 0.7 个还挂着。每成交一次,交易所会给你一条成交记录(第 2 节细讲)。PARTIALLY_FILLED
全部成交
1 个全买到了,订单结束。FILLED
已撤销
你(或系统)主动取消了,还没成交的部分不再成交,订单结束。CANCELED
被拒绝
交易所一开始就没收,比如钱不够、价格不合法。订单根本没进订单簿。REJECTED
生活例子
网购下单买 10 箱水:商家接单(挂着)→ 先发了 3 箱(部分成交)→ 剩下 7 箱你不要了,申请取消(已撤销)。订单状态是"已取消",但那 3 箱水已经在你家了。
Java 类比
一个 enum OrderStatus(Order 就是订单,代码里都用这个词)加一个状态机:只允许某些状态跳到某些状态,比如"全部成交"之后不能再"撤单"。跟电商订单、支付单的状态机是一回事。
 submit ──► OPEN ──fill──► PARTIALLY_FILLED ──fill──► FILLED
             │                    │
           cancel               cancel
             ▼                    ▼
          CANCELED       CANCELED (filledQty > 0)   ← 最容易漏的情况
 reject ──► REJECTED      (never reached the book)

"部分成交后撤单"最容易出 bug:订单状态是已撤销,看上去像"什么都没发生",但其实已经买到了 0.3 个,仓位变了。如果程序只看订单状态,就会漏掉这 0.3 个。
图里的英文:submit = 提交,fill = 成交,cancel = 撤单,reject = 拒绝,filledQty = 已成交数量,never reached the book = 从没进过订单簿。

点一点:一张"限价买 1.0 个 BTC @ 60000"的订单按钮只在当前状态允许时可点

滚到这里会自动按"提交订单 → 成交 0.3 个 → 撤单"演示一遍,每一步被按下的按钮会圈出来;点任何按钮就停下,换你自己点。按顺序点"提交订单 → 成交 0.3 个 → 撤单",看最上面的状态条和下面的红色警告:状态是已撤销,但仓位是 0.3。再点"重来",试"剩下的全部成交":之后"撤单"按钮会变灰,因为全部成交的订单已经结束了。

订单数量1.0
已成交0.0
还挂着没成交–
你的仓位(手里的 BTC)0.0
成交记录几条0
Tips · 写订单代码的三条纪律① 仓位和资金只按成交记录累加,不按订单算;② 状态只许往前走(挂着 → 部分成交 → 全部成交 / 已撤销),收到"倒退"的旧消息直接丢掉;③ 看到"已撤销"也要看已成交数量(filledQty)是不是 0。进组后读订单模块,先找这三处是怎么写的。
2

订单和成交是两回事

本节新词成交记录

一张订单可以分好几次成交,每成交一次就产生一条成交记录。钱和仓位要按成交记录来算,不能按订单来算。

成交记录 fill / trade

大白话
"在什么价格成交了多少个"的一条流水。
算一遍
你下了一张买 1.0 个、最高出价 60050 的订单。订单簿上 60010 有 0.3 个、60020 有 0.5 个、60050 有 1.0 个,于是产生了 3 条成交记录(见下图)。
一共花了 18003 + 30010 + 12010 = 60023 U,买到 1.0 个,成交均价 60023。
生活例子
一张网购订单分三个包裹发货,每个包裹是一条物流记录。你收到多少货,要看包裹,不是看订单。
Java 类比
Order 和 Fill 是一对多。仓位、资金、手续费都从 List<Fill> 累加出来,跟"支付单"和"支付流水"的关系一样。
 Order A1   BUY 1.0 BTC   limit 60,050
   ├─ Fill f1   0.3 @ 60,010   =  18,003 U
   ├─ Fill f2   0.5 @ 60,020   =  30,010 U
   └─ Fill f3   0.2 @ 60,050   =  12,010 U
 filledQty = 1.0    cost = 60,023 U    avg = 60,023    → position +1.0 BTC

图里的英文:Order = 订单,Fill = 成交记录,limit = 限价(最高愿意出的价),filledQty = 已成交数量,cost = 一共花的钱,avg = 成交均价,position = 仓位。

3

下单时的附加要求

本节新词post-only · IOC · FOK · reduce-only · 平仓 · 止损

下限价单时,可以额外加一句"要求",告诉交易所:碰到某种情况该怎么处理。这四个是最常见的,名字是英文缩写,意思都很简单。

post-only 只挂单

大白话
"我只想挂在订单簿上等别人,如果一进去就会马上成交,那就别收我这张单。"
为什么
D1 讲过:挂单手续费比吃单便宜。网格机器人挂很多单,用 post-only 能保证每一张都按便宜的费率算。
例子
卖一价 60010。你挂"post-only 买 @ 60020":这个价格会马上吃掉 60010 的卖单,于是整张单被拒绝。挂"post-only 买 @ 60000":不会马上成交,正常挂上去。

IOC Immediate Or Cancel,立即成交,剩下的撤掉

大白话
"现在能成交多少就成交多少,剩下的别挂着,直接撤掉。"
生活例子
去菜市场说"白菜有多少我要多少,最多 10 斤",只有 3 斤就买 3 斤走人,不等明天进货。

FOK Fill Or Kill,要么全成交,要么全撤

大白话
"必须一次性全部成交,差一点都不行,否则整张作废。"
生活例子
"10 斤白菜,凑不够 10 斤我一斤都不要。"

reduce-only 只减仓

大白话
"这张单只能用来减少我现在的仓位,绝不能让我反过来开一个新方向的仓位。"只在合约里用。
算一遍
你在合约里做多,持有 0.5 个。你下了一张"卖 0.8 个":
· 不加 reduce-only:先卖 0.5 个,把原来做多的仓位了结掉(把仓位了结、归零,行话叫平仓),多出来的 0.3 个变成做空 0.3 个(D1 第 10 节讲过做空)。你本来只想平仓,结果反过来开了一个做空的仓位(行话叫空单)。
· 加 reduce-only:只会卖掉 0.5 个,多出来的 0.3 个自动作废。
为什么重要
止盈(赚到目标就卖)、止损(亏到事先定好的程度就卖掉,防止越亏越多)、平仓这类单子都应该带 reduce-only。机器人因为重复下单导致卖多了,有它兜底,至少不会莫名其妙开出反向仓位。
同一张订单簿,换不同的附加要求卖单:60010 × 0.3 · 60020 × 0.5 · 60050 × 1.0

先保持"普通限价单",拖动限价,看三栏里"马上成交""挂上去""被撤掉"怎么分配;再依次点 post-only、IOC、FOK,同一个价格下对比三栏的变化。默认限价 60020、买 1.0 个:普通单成交 0.8 挂 0.2,IOC 成交 0.8 撤 0.2,FOK 整张作废,post-only 整张被拒。

马上成交(吃单)–
挂到订单簿上(挂单)–
被撤掉 / 被拒绝–
4

下单超时:不知道到底成功没有

本节新词超时 · clientOid · 幂等

程序发出下单请求,等了几秒没收到回复。这时候订单可能已经下成功了,也可能根本没到交易所,你不知道。这是交易系统里最常见、也最危险的情况。

超时 timeout

大白话
请求发出去了,规定时间内没收到回复。
两种可能
A:交易所收到了,订单已经挂上,只是回复在路上丢了。
B:请求根本没到交易所。
从你这边看,A 和 B 一模一样,都是"没回复"。
生活例子
你给饭店打电话订位,说完电话断了,不知道对方记下没有。如果再打一次说"订一桌",对方可能记两桌。正确做法是报上名字问"刚才张三订的那桌记下了吗"。

clientOid 客户端订单号

大白话
由你这边给每张订单起的编号,下单时一起发给交易所。交易所通常保证:同一个编号只会收一次,第二次来直接拒绝;你也可以拿这个编号去查订单。(有的交易所只在一段时间内、或只对还没结束的订单保证编号不重复,各家规则不同,进组后要确认你们对接的规则。)
例子
网格机器人可以按规则起名:网格编号-第几格-买卖-第几轮,比如 G7-3-B-12。程序重启以后,靠同样的规则能把编号重新算出来,再拿去查。
Java 类比
你做支付时的"商户订单号"(out_trade_no),或者接口防重复提交的 token。本质是一个幂等键。

幂等 idempotent

大白话
同一件事做一次和做十次,结果一样。下单要做到:同一张单不管重试多少次,交易所上最多只有一张。
关键规则
超时后绝对不能换一个新编号重发。先用原来的编号去查:查到了就接管它;查不到,就用原来的编号重发。原编号重发是安全的,因为就算第一次的请求迟到了,交易所也只会收其中一个。
超时了,你会怎么做?先选"真实情况",再选"你的做法"

四种组合都点一遍。重点看两处:A + 换新编号为什么多出一张单;B + 换新编号为什么只是"碰巧没事"(因为你事先分不清是 A 还是 B)。

真实情况(你其实看不到):
你的做法:
5

精度:价格和数量为什么要取整

本节新词tickSize · lotSize · 最小下单金额 · 取整 · 浮点数

交易所规定了价格和数量能精确到哪一位。程序算出来的数字往往位数更多,下单前必须按规定取整,而且往哪个方向取整,关系到钱。

tickSize 价格最小单位

大白话
价格只能是这个数的整数倍。
生活例子
人民币最小到"分",你不能付 3.456 元。BTC-USDT 的 tickSize 如果是 0.1,价格只能是 27123.4、27123.5,不能是 27123.456。

lotSize 数量最小单位

大白话
数量只能是这个数的整数倍。lotSize 是 0.001,你就不能买 0.00123 个,只能买 0.001 或 0.002 个。

最小下单金额 min notional

大白话
价格 × 数量不能太小,否则交易所不收。常见是几 U 到十几 U,各家、各交易对都不同。
例子
最小下单金额 5 U,BTC 60000:买 0.00005 个 = 3 U,被拒绝。

往哪个方向取整

买价
向下。算出来 27123.456,挂 27123.4。多付的钱一分都不给。
卖价
向上。算出来 27123.456,挂 27123.5。保证卖价不低于网格算出来的目标价,一轮的利润不会缩水。
数量
向下。你只有 0.00567 个,lotSize 0.001,最多卖 0.005 个。向上取整成 0.006,就超过你手里有的了,交易所会拒绝。
注意
这是网格场景的常见约定,具体方向以团队规范为准。关键是:每个取整都要想清楚往哪边取、为什么。

浮点数 double

大白话
计算机用二进制存小数,很多十进制小数存不准。0.1 在 double 里其实是 0.1000000000000000055…。
算一遍
0.1 + 0.2 得到 0.30000000000000004。
0.3 / 0.1 得到 2.9999999999999996,向下取整变成 2,于是 0.3 被取整成了 0.2。价格凭空少了一格。
Java 类比
所有金额、价格、数量都用 BigDecimal,而且必须用字符串构造:new BigDecimal("0.1")。写成 new BigDecimal(0.1) 会把那个不准的 double 原样带进来。你做支付时应该已经踩过这个坑了。
BigDecimal raw  = new BigDecimal("27123.456");  // 程序算出来的价格
BigDecimal tick = new BigDecimal("0.1");
BigDecimal buy  = raw.divide(tick, 0, RoundingMode.DOWN).multiply(tick);  // 27123.4
BigDecimal sell = raw.divide(tick, 0, RoundingMode.UP).multiply(tick);    // 27123.5
double 和正确算法对比可以直接改输入框

把下面五个预设挨个点一遍,对比左右两栏:左边是用 double 算的结果,右边是正确结果;最下面的结论说明 double 错在哪(错一格,或者多出一长串小数尾巴)。

试试这些:
用 double 算–
正确结果(和 BigDecimal 一样)–
常见误区 · 用了 BigDecimal 就不会错BigDecimal 自己也有两个坑。① new BigDecimal(0.1) 得到的是 0.1000000000000000055511…,要写 new BigDecimal("0.1") 或 BigDecimal.valueOf(0.1)。② new BigDecimal("1.0").equals(new BigDecimal("1.00")) 是 false,因为 equals 连小数位数也比。比大小用 compareTo;要当 HashMap 的 key,先 stripTrailingZeros()。
6

从期货到永续合约

本节新词期货 · 交割 · 到期日 · 永续合约

D1 讲过:合约不是真的买币,而是按价格涨跌算盈亏。合约分两种:有到期日的叫期货,没有到期日的叫永续合约。你们交易所的合约产品,主要是永续合约。

期货 futures

大白话
今天约定好:将来某一天,按今天定的价格买卖。约定的那一天叫到期日,到期那天按约定结算叫交割。
生活例子
面包店老板怕明年面粉涨价,今天跟磨坊签约:"明年 3 月 1 日,按每吨 3000 元买 10 吨。"到了 3 月 1 日,不管那时候面粉多少钱,都按 3000 元结算。
算一遍
如果 3 月 1 日面粉涨到 3500 元,老板每吨省了 500,10 吨省 5000 元,相当于赚了 5000。如果跌到 2800,他多付了 2000。

永续合约 perpetual,常简称"永续"

大白话
没有到期日的合约。只要不被强平,想拿多久拿多久。
带来的问题
期货到期那天必须按现货价格结算,所以越接近到期日,期货价格自然会贴近现货价格。永续没有到期日,就没有这股力量,它的价格可能越跑越偏。交易所用一个叫"资金费率"的机制把它拉回来(第 8 节)。
Java 类比
期货像一个带 TTL 的 key,到期必须结算;永续是不过期的 key,所以需要另一个后台任务定期"校准"它,这个任务就是资金费。
7

三个价格和插针

本节新词最新成交价 · 指数价格 · 标记价格 · 溢价 · 插针

在合约里,同一时刻的行情里有三个不同的"价格"。你只需要记住一句话:算盈亏和判断强平,用的是标记价格,不是最新成交价。

最新成交价 last price

大白话
这个交易所里最近一笔成交的价格。你在 App 上看到跳来跳去的那个数字就是它。

指数价格 index price

大白话
把好几家大交易所的现货价格按一定权重平均。代表"全市场公认的价格"。
生活例子
判断一套房值多少钱,不看某一次成交,而是看同小区几套房的均价。

溢价 和 标记价格 premium / mark price

溢价
永续合约价格比指数价格高出(或低出)的部分。比如指数 60000,永续成交在 60030,溢价 +30。
标记价格
指数价格 + 一个"被平滑过的"溢价。平滑的意思是:溢价突然跳一下,标记价格只会动一点点。具体算法各家不同。
为什么需要
防止插针。

插针 wick / spike

大白话
价格在一瞬间暴跌(或暴涨)然后马上弹回来,在 K 线图上留下一根像针一样的细线(K 线图就是交易软件里由一根根小柱子组成的价格图,D3 会细讲)。常见原因是有人突然用市价单大量卖出,而订单簿很"薄"(挂着的单子很少),一下子就把价格打穿了好几档。
为什么危险
如果按最新成交价判断强平,这一瞬间价格会跌破很多人的强平价(价格到这里就会被强平,第 10 节教你算),把大量本来没事的仓位强平掉。有人甚至会故意制造插针,让别人被强平,自己从中获利。用标记价格就不怕:一个交易所里一瞬间的异常价格,对指数和平滑后的溢价影响很小。
 exchange A spot   60,010 ─┐
 exchange B spot   59,990 ─┼─► index price  60,000   (weighted average)
 exchange C spot   60,005 ─┘          │
                                      │ + smoothed premium
 last trade here   53,500             ▼
 (one-second spike)            mark price   59,940   → 算盈亏、判断强平都用它

图里的英文:exchange A spot = A 交易所的现货价格,weighted average = 加权平均,smoothed premium = 平滑后的溢价,last trade here = 本交易所的最新成交价,one-second spike = 一秒钟的插针,mark price = 标记价格。

制造一根插针你做多 1 个 BTC · 60000 · 10 倍 · 强平价 54,271.36
最新成交价最低到–
标记价格最低到–
如果按最新成交价判断–
按标记价格判断(实际做法)–

拖动"插针插到"再点"制造插针":细线是最新成交价,粗的橙色线是标记价格,红色虚线是你的强平价。细线戳穿红线时,"如果按最新成交价判断"会显示被强平(误杀),而橙色线几乎不动,按标记价格一直是安全的。这里用"指数 + 溢价的移动平均"来模拟标记价格,真实算法各家不同,但思路一样。

Tips · 设止损时要选"按什么价格触发"按最新成交价触发反应快,但一根插针就可能把你止损出去,然后价格又弹回来;按标记价格触发不怕插针,但触发后按市价平仓,成交价可能比止损价差一些。网格、马丁这类机器人的止损,常见做法是按标记价格触发。D10 实操会让你在界面上选一次。
8

资金费率:多空之间定期转账

本节新词资金费率 · 资金费

每隔一段时间,做多的人和做空的人之间要互相转一笔钱。转多少、谁给谁,由资金费率决定。它的作用是把永续合约的价格拉回到指数价格附近。

资金费率 和 资金费 funding rate / funding fee

规则
费率为正:做多的人付钱给做空的人。
费率为负:做空的人付钱给做多的人。
每次付多少:资金费 = 持仓价值 × 资金费率。
多久一次:常见是每 8 小时一次(一天 3 次),各家、各交易对都可能不同。
算一遍
你做多,持仓价值 10000 U,费率 +0.01%:
每次付 10000 × 0.01% = 1 U;一天 3 次 = 3 U;30 天约 90 U。
如果你是做空,那就是每次收到 1 U。
为什么能拉回价格
大家都在做多,永续价格被买得比指数高 → 费率变成正的 → 做多要付钱,一部分人不想付就平仓(卖出),做空的人有钱收会更愿意做空 → 永续价格回落,靠近指数。反过来也一样。
生活例子
共享单车某个站点车太多,平台就给"骑走一辆"发小红包、给"骑来一辆"收点钱,车就会自己慢慢均衡。
注意
资金费是用户之间互相转账,交易所一般不从中赚钱(这点和手续费不同)。
资金费计算器费率可以填负数

先看默认:做多、10000 U、+0.01%,每次付 1 U。把费率改成 −0.01,看"付"变成"收";再把方向改成做空对比。绿色是你收钱,红色是你付钱。

每次–
每天–
30 天–
9

逐仓和全仓

本节新词逐仓 · 全仓

开合约时要选:这笔仓位亏钱时,最多亏掉哪些钱?只亏这一笔押金,叫逐仓;整个账户的钱都拿来兜底,叫全仓。

逐仓 isolated margin

大白话
每个仓位单独放一笔押金。爆了只亏这笔押金,账户里其他钱不受影响。
算一遍
账户 1000 U。拿 100 U 当押金,10 倍做多,相当于持有 1000 U 的 BTC。BTC 跌 10% → 亏 100 U → 这个仓位被强平(这是 D1 的简化算法,第 10 节会算出实际在跌 9.5% 左右就强平)。账户还剩 900 U。
生活例子
每次去赌场只带 100 块现金,银行卡放家里。输光了就回家。

全仓 cross margin

大白话
账户里所有可用的钱一起给所有仓位当押金。更不容易爆,但一旦爆,亏的是整个账户。
算一遍
同样账户 1000 U,全仓开了 5000 U 的多仓。BTC 跌 10% 亏 500 U,账户还剩 500,不会强平。但 BTC 跌到接近 20% 时,亏损接近 1000 U,整个账户被强平,一分不剩。
生活例子
带着银行卡去赌场,输了可以一直刷卡,能扛得更久,但也可能把卡刷爆。
Java 类比
逐仓像每个线程池各自有隔离的资源(舱壁隔离,Resilience4j / Hystrix 里的 bulkhead),一个出事不影响别的;全仓像所有任务共用一个大池子,利用率高,但一个任务把池子耗光,大家一起挂。
10

维持保证金和强平价

本节新词初始保证金 · 维持保证金 · 维持保证金率 · 强平价

D1 说过"押金快亏光时会被强平"。今天把"快亏光"说精确:押金亏到只剩维持保证金那么多时,就强平。这个时刻对应的价格,就是强平价。

初始保证金 initial margin

大白话
开仓时交的押金。初始保证金 = 仓位价值 ÷ 杠杆。
算一遍
60000 做多 1 个 BTC,仓位价值 60000 U,10 倍杠杆 → 押金 6000 U。

维持保证金 和 维持保证金率 maintenance margin / MMR

大白话
押金最少要留这么多,低于它就强平。维持保证金 = 当前仓位价值 × 维持保证金率。维持保证金率常见是零点几个百分点,仓位越大通常越高,各家不同。
为什么不等押金亏到 0
强平时交易所要把你的仓位在市场上卖掉,卖的过程中价格还会继续变。留一点余量,就是为了让它卖完时尽量不亏到负数。
算一遍
维持保证金率 0.5%。价格在 54271 时,仓位价值 54271 U,维持保证金 = 54271 × 0.5% ≈ 271 U。

强平价 liquidation price

核心等式
押金 + 浮动盈亏 = 维持保证金
左边是"你账户里还剩的钱",右边是"必须留下的钱"。两边相等的那个价格,就是强平价。
做多推导
开仓价 60000,1 个,10 倍,维持保证金率 0.5%,设强平价为 P:
① 押金 = 60000 ÷ 10 = 6000
② 浮动盈亏 = (P − 60000) × 1
③ 维持保证金 = 0.5% × P × 1 = 0.005P
④ 6000 + P − 60000 = 0.005P → 0.995P = 54000 → P ≈ 54271.36
也就是跌了约 9.55% 就强平,而不是 D1 简化版说的 10%。
做空推导
做空的浮动盈亏是 (60000 − P) × 1,价格涨了亏钱:
6000 + 60000 − P = 0.005P → 1.005P = 66000 → P ≈ 65671.64
通用公式
做多:P = 开仓价 × (1 − 1/杠杆) ÷ (1 − 维持保证金率)
做空:P = 开仓价 × (1 + 1/杠杆) ÷ (1 + 维持保证金率)
这是逐仓、不算手续费的简化版,真实交易所还会考虑手续费、分档的维持保证金率等。
分步计算强平价逐仓 · 忽略手续费

先别看结果,按上面第 ④ 步自己手算 60000、10 倍、0.5%,再对照下面每一步。然后把杠杆改成 20、50、100,看"距开仓价"缩到多小:杠杆越高,价格动一点点就强平。

    强平价–
    距开仓价–
    强平那一刻押金还剩–
    11

    强平之后:穿仓、保险基金和自动减仓

    本节新词穿仓 · 保险基金 · 自动减仓

    强平不是"到了强平价就瞬间按强平价卖掉"。交易所要在市场上把仓位卖掉,实际卖出的价格可能比强平价好,也可能更差。

    穿仓 bankruptcy / negative equity

    大白话
    卖出的价格太差,亏损超过了你的押金。多亏的这部分,主流交易所的常见规则是不用你赔(各家不同),但总得有人赔。
    算一遍
    接上一节:做多 1 个,开仓 60000,押金 6000,强平价 54271.36。
    · 行情平稳,实际在 54100 卖掉:亏 5900,押金还剩 100 U。这 100 U 常见做法是划进保险基金(各家规则不同),你拿不回来。
    · 行情急跌,实际在 53800 才卖掉:亏 6200,比押金多了 200 U,这就是穿仓。

    保险基金 insurance fund

    大白话
    交易所攒的一个资金池,专门用来填穿仓的窟窿。钱主要来自上面那种"强平后剩下的押金"。
    生活例子
    小区的维修基金:平时每家交一点,哪天电梯坏了从里面出。

    自动减仓 ADL,Auto-Deleveraging

    大白话
    如果行情极端,保险基金也不够填,交易所会找到和你方向相反、而且正在赚钱的人,按规则强制平掉他们的一部分仓位,用来抵消亏损。通常赚得最多、杠杆最高的人排在最前面。
    生活例子
    维修基金也不够了,物业只好向用电梯最多的几户先收一笔。被收的人没做错什么,只是规则这么定。
    为什么你要知道
    ADL 发生时,一个没被强平、正在赚钱的用户,仓位会突然被系统减掉。机器人如果不认识这种事件,本地仓位就和交易所对不上了。
     position hits liquidation price (by MARK price)
            │
            ▼
     exchange closes it in the market
            ├─ closed with equity left  ──► leftover goes to insurance fund
            └─ closed below zero (loss > margin)
                      │
                      ▼
              insurance fund pays the gap
                      │ fund not enough
                      ▼
              ADL: reduce profitable opposite positions   → 被减仓的人也要能正确对账

    图里的英文:position hits liquidation price = 仓位碰到强平价;closes it in the market = 在市场上把它卖掉;equity left = 押金还有剩;loss > margin = 亏损超过押金;insurance fund pays the gap = 保险基金补窟窿;fund not enough = 保险基金不够;reduce profitable opposite positions = 减掉方向相反、正在赚钱的仓位。

    12

    词典和自测

    今天和 D1 用到的词,这里都能查到。

    自测 8 题

    读完以后

    回到 七日冲刺 D2,按这个顺序过一遍:先看订单状态机图(现在 PARTIALLY_FILLED、CANCELED 这些英文都认识了);再看精度那段,做 roundToStep 编程题(先直接跑一次起始代码,看 double 怎么出错);然后看永续合约图;最后用强平价计算器,自己先手算一遍 60000、10 倍、0.5%,再核对。

    今天讲的是用户能看到的规则。这些规则在交易所后台是怎么跑的:下单时钱怎么冻结、撮合怎么排队、资金费怎么批量结算、强平由谁来执行,放在 D8 讲。