合约交易系统
1. 合约类型
1.1 永续合约 (Perpetual Contract)
永续合约是没有到期日的期货合约,通过资金费率机制使合约价格锚定现货价格。
特点:
- 无到期日,可永久持有
- 资金费率每8小时结算一次
- 支持高杠杆(1x - 125x)
- 双向交易(做多/做空)
数据结构:
type PerpetualContract struct {
Symbol string // "BTC-PERP"
BaseAsset string // "BTC"
QuoteAsset string // "USDT"
ContractSize float64 // 合约面值,如1 BTC
PricePrecision int
QuantityPrecision int
// 杠杆配置
MaxLeverage int // 最大杠杆
LeverageTiers []*LeverageTier
// 资金费率
FundingInterval time.Duration // 8小时
FundingRate float64 // 当前资金费率
// 风险参数
MaintenanceMarginRate float64 // 维持保证金率
InitialMarginRate float64 // 起始保证金率
Status string // "active", "settling", "suspended"
}
type LeverageTier struct {
Tier int
MaxNotional float64 // 最大名义价值
MaxLeverage int
MaintenanceMargin float64
InitialMargin float64
}
杠杆分级示例(BTC-PERP):
{
"tiers": [
{
"tier": 1,
"maxNotional": 50000,
"maxLeverage": 125,
"maintenanceMargin": 0.004,
"initialMargin": 0.008
},
{
"tier": 2,
"maxNotional": 250000,
"maxLeverage": 100,
"maintenanceMargin": 0.005,
"initialMargin": 0.01
},
{
"tier": 3,
"maxNotional": 1000000,
"maxLeverage": 50,
"maintenanceMargin": 0.01,
"initialMargin": 0.02
},
{
"tier": 4,
"maxNotional": 5000000,
"maxLeverage": 20,
"maintenanceMargin": 0.025,
"initialMargin": 0.05
}
]
}
1.2 交割合约 (Delivery Futures)
有明确到期日的期货合约,到期时按结算价交割。
类型:
- 当周合约:每周五交割
- 次周合约:下周五交割
- 当季合约:本季度最后一个周五交割
- 次季合约:下季度最后一个周五交割
数据结构:
type DeliveryContract struct {
Symbol string // "BTC-0331" (3月31日交割)
BaseAsset string
QuoteAsset string
ContractSize float64
DeliveryTime time.Time // 交割时间
SettlementPrice float64 // 结算价(交割时确定)
Status string // "trading", "settling", "settled"
}
2. 仓位管理
2.1 仓位结构
type Position struct {
UserID string
Symbol string
Side string // "long" or "short"
// 仓位数量
Quantity float64 // 持仓量
// 价格信息
EntryPrice float64 // 开仓均价
MarkPrice float64 // 标记价格(用于计算未实现盈亏)
LiquidationPrice float64 // 强平价格
// 保证金
InitialMargin float64 // 起始保证金
MaintenanceMargin float64 // 维持保证金
Margin float64 // 仓位保证金
// 盈亏
UnrealizedPnL float64 // 未实现盈亏
RealizedPnL float64 // 已实现盈亏
// 杠杆
Leverage int
// 模式
MarginMode string // "isolated" or "cross"
CreatedAt time.Time
UpdatedAt time.Time
}
2.2 开仓逻辑
type PositionManager struct {
positions map[string]*Position // userID:symbol -> Position
mu sync.RWMutex
}
func (pm *PositionManager) OpenPosition(order *Order, fillPrice float64) error {
pm.mu.Lock()
defer pm.mu.Unlock()
key := fmt.Sprintf("%s:%s", order.UserID, order.Symbol)
position := pm.positions[key]
// 如果没有仓位,创建新仓位
if position == nil {
position = &Position{
UserID: order.UserID,
Symbol: order.Symbol,
Side: order.Side,
Quantity: order.Quantity,
EntryPrice: fillPrice,
Leverage: order.Leverage,
MarginMode: order.MarginMode,
}
// 计算初始保证金
position.InitialMargin = pm.calculateInitialMargin(position)
position.MaintenanceMargin = pm.calculateMaintenanceMargin(position)
position.Margin = position.InitialMargin
// 计算强平价格
position.LiquidationPrice = pm.calculateLiquidationPrice(position)
pm.positions[key] = position
return nil
}
// 已有仓位,判断是加仓还是减仓
if position.Side == order.Side {
// 加仓:更新开仓均价
totalCost := position.EntryPrice*position.Quantity + fillPrice*order.Quantity
totalQuantity := position.Quantity + order.Quantity
position.EntryPrice = totalCost / totalQuantity
position.Quantity = totalQuantity
// 重新计算保证金和强平价
position.InitialMargin = pm.calculateInitialMargin(position)
position.MaintenanceMargin = pm.calculateMaintenanceMargin(position)
position.LiquidationPrice = pm.calculateLiquidationPrice(position)
} else {
// 反向开仓:先平掉原仓位,再开新仓
if order.Quantity < position.Quantity {
// 部分平仓
pnl := pm.calculateClosePnL(position, fillPrice, order.Quantity)
position.RealizedPnL += pnl
position.Quantity -= order.Quantity
// 释放部分保证金
position.Margin *= position.Quantity / (position.Quantity + order.Quantity)
} else if order.Quantity == position.Quantity {
// 完全平仓
pnl := pm.calculateClosePnL(position, fillPrice, position.Quantity)
position.RealizedPnL += pnl
delete(pm.positions, key)
} else {
// 平仓后反向开仓
pnl := pm.calculateClosePnL(position, fillPrice, position.Quantity)
remainQuantity := order.Quantity - position.Quantity
position.Side = order.Side
position.Quantity = remainQuantity
position.EntryPrice = fillPrice
position.RealizedPnL += pnl
// 重新计算保证金
position.InitialMargin = pm.calculateInitialMargin(position)
position.MaintenanceMargin = pm.calculateMaintenanceMargin(position)
position.Margin = position.InitialMargin
position.LiquidationPrice = pm.calculateLiquidationPrice(position)
}
}
return nil
}
2.3 盈亏计算
未实现盈亏(Unrealized PnL):
func (pm *PositionManager) calculateUnrealizedPnL(position *Position, markPrice float64) float64 {
if position.Side == "long" {
// 多仓:(标记价 - 开仓价) * 数量
return (markPrice - position.EntryPrice) * position.Quantity
} else {
// 空仓:(开仓价 - 标记价) * 数量
return (position.EntryPrice - markPrice) * position.Quantity
}
}
// 示例:
// 开多仓:100 BTC @ 50,000 USDT
// 标记价:51,000 USDT
// 未实现盈亏 = (51,000 - 50,000) * 100 = 100,000 USDT
已实现盈亏(Realized PnL):
func (pm *PositionManager) calculateClosePnL(position *Position, closePrice float64, quantity float64) float64 {
if position.Side == "long" {
return (closePrice - position.EntryPrice) * quantity
} else {
return (position.EntryPrice - closePrice) * quantity
}
}
回报率(ROE - Return on Equity):
func (pm *PositionManager) calculateROE(position *Position, markPrice float64) float64 {
unrealizedPnL := pm.calculateUnrealizedPnL(position, markPrice)
return unrealizedPnL / position.Margin
}
// 示例:
// 保证金:10,000 USDT
// 未实现盈亏:2,000 USDT
// ROE = 2,000 / 10,000 = 20%
3. 保证金计算
3.1 逐仓模式 (Isolated Margin)
每个仓位独立使用保证金,爆仓只影响该仓位。
func (pm *PositionManager) calculateInitialMargin(position *Position) float64 {
// 初始保证金 = 名义价值 / 杠杆
notionalValue := position.EntryPrice * position.Quantity
return notionalValue / float64(position.Leverage)
}
func (pm *PositionManager) calculateMaintenanceMargin(position *Position) float64 {
contract := pm.getContract(position.Symbol)
tier := pm.findLeverageTier(contract, position)
notionalValue := position.EntryPrice * position.Quantity
return notionalValue * tier.MaintenanceMargin
}
// 示例:
// 开仓:10 BTC @ 50,000 USDT,杠杆 10x
// 名义价值 = 50,000 * 10 = 500,000 USDT
// 初始保证金 = 500,000 / 10 = 50,000 USDT
// 维持保证金 = 500,000 * 0.005 = 2,500 USDT(假设维持保证金率0.5%)
3.2 全仓模式 (Cross Margin)
所有仓位共享账户全部保证金,爆仓会损失账户所有资金。
func (pm *PositionManager) calculateCrossMarginLevel(userID string) float64 {
pm.mu.RLock()
defer pm.mu.RUnlock()
var totalMaintenanceMargin float64
var totalUnrealizedPnL float64
// 遍历用户所有仓位
for key, position := range pm.positions {
if !strings.HasPrefix(key, userID+":") {
continue
}
if position.MarginMode != "cross" {
continue
}
markPrice := pm.getMarkPrice(position.Symbol)
totalMaintenanceMargin += pm.calculateMaintenanceMargin(position)
totalUnrealizedPnL += pm.calculateUnrealizedPnL(position, markPrice)
}
// 获取账户余额
balance := pm.getAccountBalance(userID)
// 保证金率 = (账户余额 + 未实现盈亏) / 维持保证金
marginLevel := (balance + totalUnrealizedPnL) / totalMaintenanceMargin
return marginLevel
}
// 保证金率 < 100% 时触发强平
3.3 强平价格计算
逐仓多头强平价:
func (pm *PositionManager) calculateLiquidationPrice(position *Position) float64 {
if position.MarginMode != "isolated" {
return 0 // 全仓模式无固定强平价
}
contract := pm.getContract(position.Symbol)
tier := pm.findLeverageTier(contract, position)
mmr := tier.MaintenanceMargin // 维持保证金率
if position.Side == "long" {
// 多仓强平价 = 开仓价 * (1 - 1/杠杆 + 维持保证金率)
return position.EntryPrice * (1 - 1/float64(position.Leverage) + mmr)
} else {
// 空仓强平价 = 开仓价 * (1 + 1/杠杆 - 维持保证金率)
return position.EntryPrice * (1 + 1/float64(position.Leverage) - mmr)
}
}
// 示例(多仓):
// 开仓价:50,000 USDT
// 杠杆:10x
// 维持保证金率:0.5%
// 强平价 = 50,000 * (1 - 0.1 + 0.005) = 50,000 * 0.905 = 45,250 USDT
4. 资金费率机制
资金费率用于锚定合约价格与现货价格,多空双方每8小时结算一次。
4.1 资金费率计算
type FundingRateCalculator struct {
symbol string
}
func (frc *FundingRateCalculator) Calculate() float64 {
// 1. 计算溢价指数
premiumIndex := frc.calculatePremiumIndex()
// 2. 计算利率
interestRate := frc.calculateInterestRate()
// 3. 资金费率 = 溢价指数 + clamp(利率 - 溢价指数, -0.05%, 0.05%)
fundingRate := premiumIndex + clamp(interestRate-premiumIndex, -0.0005, 0.0005)
return fundingRate
}
// 溢价指数 = (标记价格 - 现货指数价格) / 现货指数价格
func (frc *FundingRateCalculator) calculatePremiumIndex() float64 {
markPrice := frc.getMarkPrice()
indexPrice := frc.getIndexPrice()
return (markPrice - indexPrice) / indexPrice
}
// 利率 = (USDT利率 - BTC利率) / 资金费率周期
func (frc *FundingRateCalculator) calculateInterestRate() float64 {
// 简化处理,通常设为固定值
return 0.0001 // 0.01% per 8h
}
func clamp(value, min, max float64) float64 {
if value < min {
return min
}
if value > max {
return max
}
return value
}
4.2 资金费用结算
type FundingSettlement struct {
positions *PositionManager
}
func (fs *FundingSettlement) Settle(symbol string, fundingRate float64) error {
fs.positions.mu.Lock()
defer fs.positions.mu.Unlock()
for key, position := range fs.positions.positions {
if position.Symbol != symbol {
continue
}
// 计算资金费用
notionalValue := position.Quantity * position.MarkPrice
fundingFee := notionalValue * fundingRate
// 多仓支付正费率,空仓收取
if position.Side == "long" {
fundingFee = -fundingFee
}
// 更新账户余额
err := fs.updateBalance(position.UserID, fundingFee)
if err != nil {
return err
}
// 记录资金费用历史
fs.recordFundingHistory(&FundingHistory{
UserID: position.UserID,
Symbol: symbol,
PositionQty: position.Quantity,
MarkPrice: position.MarkPrice,
FundingRate: fundingRate,
FundingFee: fundingFee,
Timestamp: time.Now(),
})
}
return nil
}
// 示例:
// 仓位:100 BTC 多仓
// 标记价:50,000 USDT
// 资金费率:0.01%
// 名义价值 = 100 * 50,000 = 5,000,000 USDT
// 资金费用 = 5,000,000 * 0.0001 = 500 USDT(多仓需支付)
4.3 资金费率历史
type FundingHistory struct {
UserID string
Symbol string
PositionQty float64
MarkPrice float64
FundingRate float64
FundingFee float64
Timestamp time.Time
}
5. 标记价格 vs 最新价
5.1 标记价格 (Mark Price)
标记价格用于计算未实现盈亏和强平价,防止市场操纵导致恶意爆仓。
type MarkPriceCalculator struct {
symbol string
}
// 标记价格 = 现货指数价格 + 移动平均资金基差
func (mpc *MarkPriceCalculator) Calculate() float64 {
indexPrice := mpc.getIndexPrice()
basis := mpc.calculateMovingAverageBasis()
return indexPrice + basis
}
// 现货指数价格:多个现货交易所的加权平均价
func (mpc *MarkPriceCalculator) getIndexPrice() float64 {
prices := []struct {
exchange string
price float64
weight float64
}{
{"binance", 50000, 0.4},
{"coinbase", 50010, 0.3},
{"kraken", 49990, 0.3},
}
var totalWeightedPrice float64
var totalWeight float64
for _, p := range prices {
totalWeightedPrice += p.price * p.weight
totalWeight += p.weight
}
return totalWeightedPrice / totalWeight
}
// 移动平均资金基差:合约价 - 现货价的移动平均
func (mpc *MarkPriceCalculator) calculateMovingAverageBasis() float64 {
// 获取过去1分钟的基差数据
basis := mpc.getBasisHistory(time.Minute)
var sum float64
for _, b := range basis {
sum += b
}
return sum / float64(len(basis))
}
5.2 最新价 (Last Price)
最新价是合约最新一笔成交价格,用于K线、市价单等场景。
type PriceManager struct {
lastPrices map[string]float64 // symbol -> last price
markPrices map[string]float64 // symbol -> mark price
mu sync.RWMutex
}
func (pm *PriceManager) UpdateLastPrice(symbol string, price float64) {
pm.mu.Lock()
defer pm.mu.Unlock()
pm.lastPrices[symbol] = price
}
func (pm *PriceManager) UpdateMarkPrice(symbol string, price float64) {
pm.mu.Lock()
defer pm.mu.Unlock()
pm.markPrices[symbol] = price
}
func (pm *PriceManager) GetLastPrice(symbol string) float64 {
pm.mu.RLock()
defer pm.mu.RUnlock()
return pm.lastPrices[symbol]
}
func (pm *PriceManager) GetMarkPrice(symbol string) float64 {
pm.mu.RLock()
defer pm.mu.RUnlock()
return pm.markPrices[symbol]
}
6. 风险限额
风险限额用于限制单个用户的最大持仓,降低系统风险。
6.1 风险限额配置
type RiskLimit struct {
Tier int
MaxNotional float64 // 最大名义价值
MaintenanceMargin float64
InitialMargin float64
}
type RiskLimitManager struct {
limits map[string][]*RiskLimit // symbol -> risk limits
}
func (rlm *RiskLimitManager) GetRiskLimit(symbol string, notional float64) *RiskLimit {
limits := rlm.limits[symbol]
for _, limit := range limits {
if notional <= limit.MaxNotional {
return limit
}
}
// 返回最高档
return limits[len(limits)-1]
}
// 示例:BTC-PERP 风险限额
// Tier 1: 0-50,000 USDT, 维持保证金 0.4%
// Tier 2: 50,000-250,000 USDT, 维持保证金 0.5%
// Tier 3: 250,000-1,000,000 USDT, 维持保证金 1.0%
// Tier 4: 1,000,000+ USDT, 维持保证金 2.5%
6.2 风险限额检查
func (rlm *RiskLimitManager) CheckRiskLimit(position *Position, additionalQty float64) error {
newQuantity := position.Quantity + additionalQty
newNotional := newQuantity * position.MarkPrice
limit := rlm.GetRiskLimit(position.Symbol, newNotional)
if newNotional > limit.MaxNotional {
return fmt.Errorf("exceeds maximum notional value: %.2f > %.2f",
newNotional, limit.MaxNotional)
}
return nil
}
7. 合约结算
7.1 交割合约结算
type DeliverySettlement struct {
contracts map[string]*DeliveryContract
}
func (ds *DeliverySettlement) Settle(symbol string) error {
contract := ds.contracts[symbol]
if contract == nil {
return fmt.Errorf("contract not found: %s", symbol)
}
// 1. 计算结算价(过去1小时的TWAP)
settlementPrice := ds.calculateSettlementPrice(symbol)
contract.SettlementPrice = settlementPrice
// 2. 获取所有持仓
positions := ds.getAllPositions(symbol)
// 3. 结算每个仓位
for _, position := range positions {
// 计算盈亏
var pnl float64
if position.Side == "long" {
pnl = (settlementPrice - position.EntryPrice) * position.Quantity
} else {
pnl = (position.EntryPrice - settlementPrice) * position.Quantity
}
// 结算:保证金 + 盈亏
settlement := position.Margin + pnl
// 更新账户余额
ds.updateBalance(position.UserID, settlement)
// 清除仓位
ds.closePosition(position)
// 记录结算历史
ds.recordSettlement(&Settlement{
UserID: position.UserID,
Symbol: symbol,
Quantity: position.Quantity,
EntryPrice: position.EntryPrice,
SettlementPrice: settlementPrice,
PnL: pnl,
Settlement: settlement,
Timestamp: time.Now(),
})
}
// 4. 更新合约状态
contract.Status = "settled"
return nil
}
// 结算价计算(时间加权平均价格)
func (ds *DeliverySettlement) calculateSettlementPrice(symbol string) float64 {
// 获取交割前1小时的所有成交
trades := ds.getTrades(symbol, time.Hour)
var totalWeightedPrice float64
var totalQuantity float64
for _, trade := range trades {
totalWeightedPrice += trade.Price * trade.Quantity
totalQuantity += trade.Quantity
}
return totalWeightedPrice / totalQuantity
}
7.2 结算记录
type Settlement struct {
UserID string
Symbol string
Quantity float64
EntryPrice float64
SettlementPrice float64
PnL float64
Settlement float64
Timestamp time.Time
}
8. 完整示例
8.1 合约交易完整流程
package main
import (
"fmt"
"sync"
"time"
)
type ContractTradingSystem struct {
contracts *ContractManager
positions *PositionManager
funding *FundingRateCalculator
settlement *FundingSettlement
prices *PriceManager
mu sync.RWMutex
}
func NewContractTradingSystem() *ContractTradingSystem {
return &ContractTradingSystem{
contracts: NewContractManager(),
positions: NewPositionManager(),
funding: NewFundingRateCalculator(),
settlement: NewFundingSettlement(),
prices: NewPriceManager(),
}
}
// 开仓
func (cts *ContractTradingSystem) OpenPosition(userID, symbol string, side string,
quantity float64, leverage int, marginMode string) error {
// 1. 获取当前价格
markPrice := cts.prices.GetMarkPrice(symbol)
// 2. 创建订单
order := &Order{
UserID: userID,
Symbol: symbol,
Side: side,
Quantity: quantity,
Leverage: leverage,
MarginMode: marginMode,
}
// 3. 检查风险限额
// ... 省略风险检查代码
// 4. 冻结保证金
requiredMargin := (markPrice * quantity) / float64(leverage)
err := cts.freezeMargin(userID, requiredMargin)
if err != nil {
return err
}
// 5. 开仓
err = cts.positions.OpenPosition(order, markPrice)
if err != nil {
cts.unfreezeMargin(userID, requiredMargin)
return err
}
fmt.Printf("开仓成功: %s %s %.4f @ %.2f, 杠杆 %dx\n",
side, symbol, quantity, markPrice, leverage)
return nil
}
// 平仓
func (cts *ContractTradingSystem) ClosePosition(userID, symbol string, quantity float64) error {
position := cts.positions.GetPosition(userID, symbol)
if position == nil {
return fmt.Errorf("position not found")
}
markPrice := cts.prices.GetMarkPrice(symbol)
// 计算盈亏
pnl := cts.positions.calculateClosePnL(position, markPrice, quantity)
// 平仓
err := cts.positions.ClosePosition(userID, symbol, quantity, markPrice)
if err != nil {
return err
}
// 释放保证金并结算盈亏
settlement := (position.Margin * quantity / position.Quantity) + pnl
err = cts.updateBalance(userID, settlement)
if err != nil {
return err
}
fmt.Printf("平仓成功: %s %.4f @ %.2f, 盈亏: %.2f USDT\n",
symbol, quantity, markPrice, pnl)
return nil
}
// 资金费率结算定时任务
func (cts *ContractTradingSystem) StartFundingRateSettlement() {
ticker := time.NewTicker(8 * time.Hour)
defer ticker.Stop()
for range ticker.C {
// 计算资金费率
fundingRate := cts.funding.Calculate()
// 结算所有仓位
err := cts.settlement.Settle("BTC-PERP", fundingRate)
if err != nil {
fmt.Printf("资金费率结算失败: %v\n", err)
continue
}
fmt.Printf("资金费率结算完成: %.4f%%\n", fundingRate*100)
}
}
// 标记价格更新定时任务
func (cts *ContractTradingSystem) StartMarkPriceUpdate() {
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
calculator := NewMarkPriceCalculator("BTC-PERP")
for range ticker.C {
markPrice := calculator.Calculate()
cts.prices.UpdateMarkPrice("BTC-PERP", markPrice)
// 检查强平
cts.checkLiquidations("BTC-PERP", markPrice)
}
}
// 强平检查
func (cts *ContractTradingSystem) checkLiquidations(symbol string, markPrice float64) {
positions := cts.positions.GetAllPositions(symbol)
for _, position := range positions {
if position.MarginMode == "isolated" {
// 逐仓:检查是否触及强平价
if (position.Side == "long" && markPrice <= position.LiquidationPrice) ||
(position.Side == "short" && markPrice >= position.LiquidationPrice) {
cts.liquidatePosition(position)
}
} else {
// 全仓:检查保证金率
marginLevel := cts.positions.calculateCrossMarginLevel(position.UserID)
if marginLevel < 1.0 {
cts.liquidatePosition(position)
}
}
}
}
func (cts *ContractTradingSystem) liquidatePosition(position *Position) {
fmt.Printf("触发强平: 用户 %s, %s %.4f\n",
position.UserID, position.Symbol, position.Quantity)
// 执行强平逻辑(详见第6章清算系统)
// ...
}
func main() {
system := NewContractTradingSystem()
// 启动标记价格更新
go system.StartMarkPriceUpdate()
// 启动资金费率结算
go system.StartFundingRateSettlement()
// 模拟交易
system.OpenPosition("user001", "BTC-PERP", "long", 1.0, 10, "isolated")
time.Sleep(10 * time.Second)
system.ClosePosition("user001", "BTC-PERP", 1.0)
select {}
}
小结
本章介绍了合约交易系统的核心内容:
- 合约类型:永续合约和交割合约的区别
- 仓位管理:开仓、平仓、加仓、减仓逻辑
- 保证金计算:逐仓和全仓模式的保证金计算
- 资金费率:锚定现货价格的机制
- 标记价格:防止市场操纵的价格计算
- 风险限额:控制用户最大持仓
- 合约结算:交割合约的结算流程
下一章将讲解数据库设计与优化,包括订单表、仓位表、成交表的设计和分库分表策略。