不知道你有没有这种经历:明明是Java后端岗位的面试,聊着聊着忽然被问到“做空到底怎么实现?交易所靠什么判断一个仓位爆仓了”。又或者在项目里拿到一个加密货币合约交易的需求,产品经理嘴里的“开多”“杠杆”“强平价”每个词都听得懂,但一落要实现,后端连从哪个字段开始设计都没底。最近很多做Java后端的朋友都绕不开这类问题,因为钱包、行情站点、合约交易类项目对后端的需求越来越多,前后端分离架构下,后端必须把交易语义真正落实到接口、服务和存储层,这部分非常考验基本功。这篇文章不聊K线买卖技巧,更不给任何投资建议,只从一个Java后端开发者的视角,把加密货币交易里“做多、做空、杠杆和爆仓”这四个概念,拆成服务端能够落地的数据字段、计算公式和处理链路。看完之后,哪怕你从没写过交易系统,至少能在接口评审或面试时,把仓位、保证金、风险率这些词说得明明白白。
1. 从Java对象模型看合约交易:方向、保证金和价格缺一不可
1.1 账户、持仓、订单:后端必须先界定的三个维度
刚开始接触交易系统,Java后端最容易犯的毛病就是上来就问“下单接口怎么写”。实际上,写不写得好下单接口,取决于你脑子里有没有一张业务表关系的图。假设用户花了1000 USDT,用10倍杠杆开了一个BTC永续多单,这笔操作在后端至少动了三块数据:
- 账户侧:用户可用余额减少,占用保证金增加,同时落一条资金流水。
- 持仓侧:如果用户本来没有BTCUSDT多仓,就新建一条仓位;如果已经有仓位,就要计算合并后的开仓均价和持仓量。
- 委托侧:订单状态从NEW到FILLED,或者长期挂在盘口等待成交。
从领域模型角度来看,一笔合约持仓最核心的字段大概是这样的:
java复制public class ContractPosition {
private Long userId;
private String symbol; // 交易对,例如 BTCUSDT
private PositionSide side; // 枚举:LONG / SHORT
private BigDecimal quantity; // 持仓数量,或者张数
private BigDecimal entryPrice; // 开仓均价
private BigDecimal markPrice; // 最近一次标记价格,用于风控
private MarginType marginType; // 枚举:ISOLATED / CROSS
private BigDecimal isolatedMargin; // 逐仓模式下实际占用的保证金
private BigDecimal leverage; // 用户设置的杠杆倍数
private Long version; // 乐观锁版本号,后面会重点讲
}
这个对象模型之所以必须存在,是因为合约交易的“仓位”和现货交易里的“余额”是两套完全不同的账本。现货系统最核心的账本是“某个币的可用余额”,但合约系统最核心的是“一张带方向、带杠杆的仓位”。如果你在设计表的时候没给持仓表加side字段,就会出现一个很尴尬的情况:用户做空的仓位没法表达,或者你得用负数余额去表达,那整个账目会乱成一锅粥。
1.2 盈亏计算的第一个版本:先理解价格差乘以数量
很多后端工程师对做多比较有直觉:低价买入,高价卖出,赚的就是差价。所以做多仓位的浮动盈亏可以写成:
java复制public BigDecimal calculatePnl(ContractPosition position, BigDecimal currentPrice) {
if (PositionSide.LONG == position.getSide()) {
return currentPrice.subtract(position.getEntryPrice())
.multiply(position.getQuantity());
}
return position.getEntryPrice().subtract(currentPrice)
.multiply(position.getQuantity());
}
这段代码非常直观:多头盈亏是“当前价 - 开仓价”,空头盈亏是“开仓价 - 当前价”。但请注意,这只是第一版认知,真实合约系统的盈亏公式会因为“币本位合约”和“U本位合约”的差异而不同。在后面第2章我会展开讲,为什么直接把现货的“数量×价格差”照搬到合约里会出问题。
对于Java后端来说,比公式更重要的是“当前价从哪来”。真实系统里不能用最新成交价做每笔计算,因为最新成交价可能被大单瞬间打穿。业内一般会引入“标记价格”,由独立的行情服务计算并推送,防止异常波动影响仓位估值。这个价格是风控的基准,也是系统计算保证金率、触发强平的重要依据。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 做空到底“卖”了什么:订单语义与持仓撮合的账本逻辑
2.1 为什么不能把做空理解成“先借币再卖掉”
如果你百度做空,最常见的解释是:你先从平台借来币,高价卖掉,等价格跌了再低价买回来还给平台,赚取差价。这个解释在业务概念层面对了一半,但在后端系统设计层面,如果真按“借币 -> 卖币 -> 买币 -> 还币”这个流程设计,会陷入一种很别扭的账本模型:你得给每个用户维护一个“借币记录”,还要跟踪币从哪里扣、还到哪里。而且主流加密货币合约交易所本身并不是靠“借币给用户”来运转的,它更像一个撮合市场。
以一个U本位永续合约为例。用户A认为BTC会跌,他提交了一个“卖出开空”的委托。这个委托在成交以前只是订单系统里的一条记录,不会立刻从现货账户里转走任何BTC。真正进入撮合引擎时,交易所做的事情是把用户A的卖出开空单和另一个用户B的买入开多单或者平多单撮合到一起。如果反过来
