1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
| package main
import ( "fmt" "math" )
type Position struct { ID string Trader string IsLong bool Size float64 EntryPrice float64 Margin float64 }
type LiquidationParams struct { MMR float64 LiqFeeRate float64 KeeperReward float64 }
func CalcUnrealizedPnL(pos Position, markPrice float64) float64 { if pos.IsLong { return pos.Size * (markPrice - pos.EntryPrice) / pos.EntryPrice } return pos.Size * (pos.EntryPrice - markPrice) / pos.EntryPrice }
func CalcMarginRatio(pos Position, markPrice float64) float64 { pnl := CalcUnrealizedPnL(pos, markPrice) currentMargin := pos.Margin + pnl if currentMargin <= 0 { return 0 } return currentMargin / pos.Size }
func CalcLiquidationPrice(pos Position, mmr float64) float64 { mm := pos.Size * mmr buffer := (pos.Margin - mm) / pos.Size if pos.IsLong { return pos.EntryPrice * (1 - buffer) } return pos.EntryPrice * (1 + buffer) }
func IsLiquidatable(pos Position, markPrice float64, params LiquidationParams) bool { currentMargin := pos.Margin + CalcUnrealizedPnL(pos, markPrice) mm := pos.Size * params.MMR return currentMargin <= mm }
func CalcADLPriority(pos Position, markPrice float64) float64 { pnl := CalcUnrealizedPnL(pos, markPrice) if pnl <= 0 { return 0 } pnlPct := pnl / pos.Margin leverage := pos.Size / pos.Margin return pnlPct * leverage }
func main() { params := LiquidationParams{ MMR: 0.005, LiqFeeRate: 0.01, KeeperReward: 0.5, }
pos := Position{ ID: "pos-001", Trader: "0xAlice", IsLong: true, Size: 30_000, EntryPrice: 3_000, Margin: 3_000, }
liqPrice := CalcLiquidationPrice(pos, params.MMR) fmt.Printf("=== Position: %s ===\n", pos.ID) fmt.Printf("Direction: %s\n", map[bool]string{true: "Long", false: "Short"}[pos.IsLong]) fmt.Printf("Size: $%.0f\n", pos.Size) fmt.Printf("Entry Price: $%.0f\n", pos.EntryPrice) fmt.Printf("Margin: $%.0f (%.0fx leverage)\n", pos.Margin, pos.Size/pos.Margin) fmt.Printf("Liquidation Price: $%.2f\n", liqPrice) fmt.Printf("Buffer: %.2f%%\n\n", math.Abs(liqPrice-pos.EntryPrice)/pos.EntryPrice*100)
testPrices := []float64{3000, 2900, 2800, 2750, 2715, 2700} fmt.Println("Mark Price | Margin Ratio | Liquidatable?") fmt.Println("-----------|-------------|---------------") for _, price := range testPrices { ratio := CalcMarginRatio(pos, price) liquidatable := IsLiquidatable(pos, price, params) status := "Safe" if liquidatable { status = "** LIQUIDATE **" } fmt.Printf("$%-9.0f | %10.2f%% | %s\n", price, ratio*100, status) }
fmt.Println("\n=== ADL Priority Ranking ===") counterparties := []Position{ {ID: "cp-A", IsLong: false, Size: 10_000, EntryPrice: 2_800, Margin: 1_000}, {ID: "cp-B", IsLong: false, Size: 6_000, EntryPrice: 2_900, Margin: 2_000}, {ID: "cp-C", IsLong: false, Size: 20_000, EntryPrice: 2_700, Margin: 5_000}, } adlPrice := 2_600.0 fmt.Printf("Mark Price: $%.0f\n", adlPrice) fmt.Println("ID | PnL | Leverage | ADL Score") fmt.Println("------|-----------|----------|----------") for _, cp := range counterparties { pnl := CalcUnrealizedPnL(cp, adlPrice) lev := cp.Size / cp.Margin score := CalcADLPriority(cp, adlPrice) fmt.Printf("%-5s | $%7.0f | %6.1fx | %.2f\n", cp.ID, pnl, lev, score) } }
|