第四章:库存模型基础——AVCO、FIFO、LIFO
做市商的库存管理,说白了就是一门「怎么管货」的学问。你手里有多少资产、以什么成本拿到的、先卖哪一批——这些细节直接决定了你的盈亏。我个人习惯把库存模型比作记账方式,不同的记账法,算出来的利润天差地别。
今天咱们就聊聊三种最基础的库存模型:AVCO(平均成本法)、FIFO(先进先出)和LIFO(后进先出)。嗯,别被这些英文缩写吓到,其实逻辑都很朴素。
4.1 为什么做市商需要库存模型?
先问一个问题:你同时买入了两批BTC,第一批价格30000,第二批价格40000。现在你卖出一枚,成本该算30000还是40000?
不同的答案,会直接影响你的已实现盈亏、未实现盈亏,甚至税务计算。我在早期做市的时候,就因为没统一库存模型,导致回测结果和实盘对不上——那叫一个头疼。
库存模型的核心作用有三个:
- 成本核算:明确每笔卖出对应的买入成本
- 盈亏计算:区分已实现和未实现损益
- 风险管理:了解当前持仓的真实成本基础
核心观点:库存模型不是会计游戏,它直接影响你的交易决策。选错了模型,你可能会误判自己的风险敞口。
4.2 AVCO模型(平均成本法)
AVCO,全称Average Cost,平均成本法。这是我最常用的模型,没有之一。为什么?因为它简单、平滑,不会因为某笔极端成交而扭曲整体成本。
算法其实就一句话:总成本 ÷ 总数量 = 平均成本。每次新买入,重新计算一次平均价。
举个例子:
| 操作 | 价格 | 数量 | 总成本 | 平均成本 |
|---|---|---|---|---|
| 买入 | 100 | 10 | 1000 | 100 |
| 买入 | 120 | 10 | 2200 | 110 |
| 卖出5个 | 115 | -5 | — | 110(不变) |
看到没?卖出时平均成本不变。已实现盈亏 = (115 - 110) × 5 = 25。就这么简单。
我的经验:AVCO特别适合做高频做市。因为你的买卖频率极高,用FIFO或LIFO会导致成本频繁跳动,干扰判断。AVCO就像给库存打了个「平滑滤镜」。
代码实现也很直接:
class AVCOInventory:
def __init__(self):
self.avg_cost = 0.0
self.quantity = 0.0
def buy(self, price, qty):
total_cost = self.avg_cost * self.quantity + price * qty
self.quantity += qty
self.avg_cost = total_cost / self.quantity
def sell(self, price, qty):
if qty > self.quantity:
raise ValueError("库存不足")
realized_pnl = (price - self.avg_cost) * qty
self.quantity -= qty
return realized_pnl
4.3 FIFO模型(先进先出)
FIFO,First In First Out。字面意思:先买的货,先卖出去。这其实最符合物理世界的直觉——你仓库里的东西,总得先把旧的卖掉吧?
但在做市商的世界里,FIFO有个大问题:它会放大已实现盈亏的波动。
为什么?你想想看,如果市场在上涨,你早期低价买入的库存会先被卖出,产生大量已实现盈利。反过来,市场下跌时,早期高价库存先出,亏损会集中爆发。
我曾经在一个波动率极高的币对上用过FIFO,结果每天已实现盈亏像过山车一样。风控部门天天找我喝茶……后来我学乖了,改用AVCO。
FIFO的实现需要维护一个队列:
from collections import deque
class FIFOInventory:
def __init__(self):
self.lots = deque() # 每个元素是 (price, qty)
def buy(self, price, qty):
self.lots.append((price, qty))
def sell(self, price, qty):
realized_pnl = 0.0
while qty > 0 and self.lots:
lot_price, lot_qty = self.lots[0]
if lot_qty <= qty:
# 整个批次卖完
realized_pnl += (price - lot_price) * lot_qty
qty -= lot_qty
self.lots.popleft()
else:
# 部分卖出
realized_pnl += (price - lot_price) * qty
self.lots[0] = (lot_price, lot_qty - qty)
qty = 0
return realized_pnl
避坑指南:我曾经在回测中用了FIFO,结果发现夏普比率被严重高估。因为早期低价库存带来的巨额盈利,掩盖了后期策略失效的风险。如果你用FIFO做回测,一定要看滚动收益曲线,别只看总收益。
4.4 LIFO模型(后进先出)
LIFO,Last In First Out。后买的货先卖。这在传统行业里不太常见,但在做市商领域,LIFO其实有它独特的价值。
为什么?因为做市商最关心的是当前市场价和最新成本的关系。LIFO能让你更敏感地反映近期市场变化。
举个例子:你刚以110的价格买入一批货,市场突然跌到105。用LIFO的话,你下一笔卖出就会优先用110的成本去算,亏损立刻体现。而用FIFO的话,可能还在用100的老成本,账面看着还是盈利的——这就有点自欺欺人了。
LIFO的实现和FIFO很像,只不过队列变成了栈:
class LIFOInventory:
def __init__(self):
self.lots = [] # 用列表模拟栈
def buy(self, price, qty):
self.lots.append((price, qty))
def sell(self, price, qty):
realized_pnl = 0.0
while qty > 0 and self.lots:
lot_price, lot_qty = self.lots[-1] # 取最后一个
if lot_qty <= qty:
realized_pnl += (price - lot_price) * lot_qty
qty -= lot_qty
self.lots.pop()
else:
realized_pnl += (price - lot_price) * qty
self.lots[-1] = (lot_price, lot_qty - qty)
qty = 0
return realized_pnl
个人建议:LIFO适合做短线做市,尤其是日内交易。它能让你更早地「认亏」,避免死扛。但要注意,LIFO在税务上可能不太友好(某些地区不允许用LIFO报税),实盘前一定要确认合规性。
4.5 三种模型的对比与选择
好了,三种模型都讲完了。咱们来做个横向对比:
| 维度 | AVCO | FIFO | LIFO |
|---|---|---|---|
| 实现复杂度 | 低 | 中 | 中 |
| 已实现盈亏波动 | 平滑 | 高 | 中高 |
| 对市场敏感度 | 低 | 低(依赖早期成本) | 高(依赖近期成本) |
| 适用场景 | 高频做市、长期持仓 | 传统金融、税务优化 | 短线交易、风险敏感型 |
我个人习惯是:回测用AVCO,实盘也用AVCO。只有在特定策略需要监控近期成本时,我才会切换到LIFO。至于FIFO……嗯,除非客户指定,否则我基本不用。
一个小技巧:你可以在系统中同时维护三种模型的成本数据。AVCO用于日常风控,FIFO用于税务报告,LIFO用于短线决策。互不冲突,各取所需。
4.6 本章小结
库存模型看似是个小问题,但它会渗透到你交易系统的每一个角落。选错了模型,轻则盈亏计算失真,重则风控指标失效。
记住三点:
- AVCO最平滑,适合大多数做市场景
- FIFO最直观,但波动大,小心被误导
- LIFO最敏感,适合需要快速反应的市场
下一章,我们会深入讨论库存风险的量化方法。到时候你会看到,库存模型的选择如何影响VaR和压力测试的结果。嗯,那才是真正有意思的部分。