DeFi 借貸協議風險模擬與實際操作完整指南:從理論到實戰

去中心化金融借貸協議蘊含著複雜的風險,包括清算風險、智慧合約風險、利率風險、跨鏈風險等。本指南從實際操作的角度出發,提供完整的風險模擬程式碼、情境分析、以及風險管理策略。透過實際的計算和模擬,讓讀者能夠量化並理解各種風險場景,從而在參與 DeFi 借貸時做出更合理的資金管理決策。

DeFi 借貸協議風險模擬與實際操作完整指南:從理論到實戰

概述

去中心化金融(DeFi)借貸協議是以太坊生態系統中最具影響力的應用場景之一。透過 Aave、Compound、Morpho 等借貸協議,用戶可以存入加密資產獲得利息收益,或以其加密資產作為抵押品進行借款。然而,DeFi 借貸蘊含著複雜的風險,包括清算風險、智慧合約風險、利率風險、跨鏈風險等。本指南將從實際操作的角度出發,提供完整的風險模擬程式碼、情境分析、以及風險管理策略,幫助讀者在 DeFi 借貸領域做出更明智的決策。

本指南的核心理念是「風險可視化」——透過實際的計算和模擬,讓讀者能夠量化並理解各種風險場景,從而在參與 DeFi 借貸時做出更合理的資金管理決策。

第一章:DeFi 借貸機制深度解析

1.1 借貸協議的核心運作原理

DeFi 借貸協議的核心機制是「超額抵押」。與傳統金融需要信用審查不同,DeFi 借貸協議要求借款人提供價值超過借款金額的加密資產作為抵押品。這種設計雖然限制了槓桿倍數,但消除了對借款人信用評估的需求,實現了真正的無許可借貸。

抵押率(Collateral Factor):每種資產都有其抵押率,決定了借款人最多可以藉入多少價值的其他資產。例如,若 ETH 的抵押率為 80%,則質押 1 ETH 的借款人最多可以藉入價值 0.8 ETH 的穩定幣。

清算閾值(Liquidation Threshold):這是抵押品的「紅線」,當抵押品價值下跌至閾值以下時,協議將觸發清算程序。清算閾值通常高於抵押率,提供額外的安全緩衝。

健康因子(Health Factor):這是衡量借款人帳戶健康狀況的核心指標。健康因子越高,帳戶越安全;當健康因子降至 1 以下時,帳戶將被清算。

// 健康因子計算示例
// 這是 Aave V3 風格的健康因子計算邏輯

pragma solidity ^0.8.19;

library HealthFactorCalculation {
    
    struct UserCollateralData {
        uint256 collateralBalance;  // 抵押品餘額(以 ETH 計價)
        uint256 borrowBalance;      // 借款餘額(以 ETH 計價)
        uint256 collateralFactor;  // 抵押率(0.8 = 80%)
        uint256 liquidationThreshold; // 清算閾值(0.85 = 85%)
    }
    
    /**
     * @dev 計算健康因子
     * 
     * 健康因子公式:
     * HF = (collateralBalance * liquidationThreshold) / borrowBalance
     * 
     * 當 HF < 1 時,帳戶將被清算
     */
    function calculateHealthFactor(
        uint256 collateralBalance,
        uint256 borrowBalance,
        uint256 liquidationThreshold,
        uint256 decimals
    ) internal pure returns (uint256) {
        if (borrowBalance == 0) {
            return type(uint256).max;  // 無借款時,健康因子為最大值
        }
        
        // 計算加權抵押價值
        uint256 weightedCollateral = (collateralBalance * liquidationThreshold) / 1e18;
        
        // 計算健康因子(考慮小數位)
        uint256 healthFactor = (weightedCollateral * (10 ** decimals)) / borrowBalance;
        
        return healthFactor;
    }
    
    /**
     * @dev 計算最大借款金額(維持健康因子 > 1)
     */
    function calculateMaxBorrow(
        uint256 collateralBalance,
        uint256 liquidationThreshold,
        uint256 targetHealthFactor,
        uint256 decimals
    ) internal pure returns (uint256) {
        if (collateralBalance == 0 || liquidationThreshold == 0) {
            return 0;
        }
        
        // 根據目標健康因子計算最大借款金額
        // maxBorrow = (collateral * liquidationThreshold) / targetHF
        uint256 maxBorrow = (collateralBalance * liquidationThreshold) / targetHealthFactor;
        
        return maxBorrow;
    }
    
    /**
     * @dev 計算清算價格
     * 當抵押品價格低於此價格時,將觸發清算
     */
    function calculateLiquidationPrice(
        uint256 borrowBalance,
        uint256 collateralAmount,
        uint256 liquidationThreshold,
        uint256 decimals
    ) internal pure returns (uint256) {
        if (collateralAmount == 0) {
            return type(uint256).max;
        }
        
        // liquidationPrice = (borrowBalance / liquidationThreshold) / collateralAmount
        uint256 liquidationPrice = (borrowBalance * (10 ** decimals)) / 
                                   (collateralAmount * liquidationThreshold / 1e18);
        
        return liquidationPrice;
    }
}

1.2 利率模型與清算機制

DeFi 借貸協議採用「利率演算法」動態調整借款和存款利率。當資金利用率較高時,借款利率上升,激勵借款人歸還借款或激勵存款人存入更多資金;當資金利用率較低時,存款利率下降,激勵借款人借款或存款人撤回資金。

利率公式(以 Aave 為例)

borrowRate = baseRate + utilizationRate * slope1 + utilizationRate^2 * slope2

其中:

# 利率模型計算示例
class AaveInterestRateModel:
    """
    Aave V3 利率模型實現
    """
    
    def __init__(self, config):
        self.OPTIMAL_UTILIZATION_RATE = config.get('optimal_utilization', 0.8)
        self.BASE_RATE = config.get('base_rate', 0)
        self.SLOPE1 = config.get('slope1', 0.04)  # 線性增長階段斜率
        self.SLOPE2 = config.get('slope2', 0.75)  # 飽和階段斜率
        self.EXCESS_UTILIZATION_RATE = 1e18 - self.OPTIMAL_UTILIZATION_RATE
        
    def calculate_borrow_rate(self, utilization_rate: int) -> int:
        """
        計算借款利率
        
        參數:
            utilization_rate: 資金利用率 (1e18 = 100%)
            
        返回:
            借款利率 (1e18 = 100% 年化)
        """
        # 確保 utilization_rate 為整數
        utilization_rate = int(utilization_rate)
        
        if utilization_rate <= self.OPTIMAL_UTILIZATION_RATE:
            # 線性增長階段
            excess_utilization = utilization_rate - self.BASE_RATE
            rate = self.BASE_RATE + (
                excess_utilization * self.SLOPE1 / self.OPTIMAL_UTILIZATION_RATE
            )
        else:
            # 飽和階段
            excess_utilization = utilization_rate - self.OPTIMAL_UTILIZATION_RATE
            rate = self.BASE_RATE + self.SLOPE1 + (
                excess_utilization * self.SLOPE2 / self.EXCESS_UTILIZATION_RATE
            )
            
        return rate
    
    def calculate_deposit_rate(self, utilization_rate: int, borrow_rate: int) -> int:
        """
        計算存款利率
        
        存款利率 = 借款利率 * 資金利用率 * (1 - 儲備因子)
        """
        reserve_factor = 0.1  # 10% 儲備因子
        deposit_rate = borrow_rate * utilization_rate * (1 - reserve_factor) / 1e18
        
        return deposit_rate
    
    def calculate_apr(self, rate: int, compound_frequency: int = 365 * 86400) -> float:
        """
        將利率轉換為年化收益率 (APR)
        """
        return rate / 1e18 * 365 * 86400 / compound_frequency
    
    def calculate_apy(self, rate: int, compound_frequency: int = 365) -> float:
        """
        將利率轉換為年化收益率 (APY),考慮複利效應
        APY = (1 + r/n)^n - 1
        """
        r = rate / 1e18
        apy = (1 + r / compound_frequency) ** compound_frequency - 1
        return apy

1.3 清算過程詳解

當借款人抵押品價值下跌導致健康因子降至 1 以下時,清算程序會被觸發。清算人(Keeper 或arbitrageur)可以透過支付部分未償還債務來獲取抵押品,通常有 5-10% 的清算獎勵。

// 清算邏輯示例
pragma solidity ^0.8.19;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract LiquidationSimulation {
    
    struct Position {
        address user;
        uint256 collateralAmount;  // 抵押品數量
        uint256 collateralPrice;   // 抵押品價格(USD)
        uint256 borrowAmount;      // 借款數量
        uint256 borrowPrice;       // 借款資產價格(USD)
        uint256 liquidationThreshold; // 清算閾值
    }
    
    // 清算參數
    uint256 public constant LIQUIDATION_BONUS = 10500;  // 5% 清算獎勵 (1e4 = 100%)
    uint256 public constant MIN_HEALTH_FACTOR = 10000;  // 1.0 (1e4 = 100%)
    
    /**
     * @dev 模擬清算
     */
    function simulateLiquidation(
        Position memory position
    ) public pure returns (
        uint256 debtToCover,      // 需償還的債務
        uint256 collateralReceived, // 獲得的抵押品
        uint256 bonus             // 清算獎勵
    ) {
        // 計算當前健康因子
        uint256 healthFactor = calculateHealthFactor(position);
        
        // 只有當健康因子 < 1 時才能清算
        require(healthFactor < MIN_HEALTH_FACTOR, "Position not liquidatable");
        
        // 計算抵押品價值(以借款資產計價)
        uint256 collateralValueInBorrow = (
            position.collateralAmount * position.collateralPrice
        ) / position.borrowPrice;
        
        // 計算最大可清算金額(通常為 50% 的借款餘額)
        uint256 maxLiquidatable = position.borrowAmount * 50 / 100;
        
        // 計算清算所需的抵押品
        // collateralNeeded = debtToCover * LIQUIDATION_BONUS / 10000
        // debtToCover = maxLiquidatable (假設全部清算)
        
        debtToCover = maxLiquidatable;
        
        // 計算可獲得的抵押品數量
        collateralReceived = (debtToCover * LIQUIDATION_BONUS * position.borrowPrice) / 
                            (10000 * position.collateralPrice);
                            
        // 計算清算獎勵
        bonus = collateralReceived - (debtToCover * position.borrowPrice / position.collateralPrice);
        
        return (debtToCover, collateralReceived, bonus);
    }
    
    /**
     * @dev 計算健康因子
     */
    function calculateHealthFactor(Position memory pos) 
        public pure returns (uint256) 
    {
        if (pos.borrowAmount == 0) {
            return type(uint256).max;
        }
        
        // 計算加權抵押價值
        uint256 weightedCollateralValue = (
            pos.collateralAmount * pos.collateralPrice * pos.liquidationThreshold
        ) / (10000 * pos.borrowPrice);
        
        // 返回健康因子(放大 10000 倍)
        return weightedCollateralValue;
    }
}

第二章:風險模擬程式碼實作

2.1 清算風險模擬器

以下是一個完整的清算風險模擬器,可以幫助借款人理解在不同市場條件下可能面臨的清算風險:

# 清算風險模擬器
import random
import numpy as np
from dataclasses import dataclass
from typing import List, Optional
import json

@dataclass
class LoanPosition:
    """借貸倉位"""
    collateral_asset: str
    borrow_asset: str
    collateral_amount: float
    borrow_amount: float
    collateral_price: float
    borrow_price: float
    collateral_factor: float  # 抵押率
    liquidation_threshold: float  # 清算閾值

@dataclass
class PriceScenario:
    """價格情境"""
    name: str
    collateral_price_change: float  # 抵押品價格變化率 (e.g., -0.3 = 下跌 30%)
    borrow_price_change: float      # 借款資產價格變化率

class LiquidationRiskSimulator:
    """清算風險模擬器"""
    
    def __init__(self):
        self.positions: List[LoanPosition] = []
        self.price_histories: dict = {}
        
    def add_position(self, position: LoanPosition):
        """添加借貸倉位"""
        self.positions.append(position)
        
    def calculate_health_factor(self, position: LoanPosition) -> float:
        """計算健康因子"""
        collateral_value = position.collateral_amount * position.collateral_price
        borrow_value = position.borrow_amount * position.borrow_price
        
        if borrow_value == 0:
            return float('inf')
        
        weighted_collateral = collateral_value * position.liquidation_threshold
        health_factor = weighted_collateral / borrow_value
        
        return health_factor
    
    def calculate_liquidation_price(
        self, 
        position: LoanPosition
    ) -> float:
        """計算清算價格(抵押品價格跌至此值時觸發清算)"""
        borrow_value = position.borrow_amount * position.borrow_price
        liquidation_threshold = position.liquidation_threshold
        
        # liquidation_price = (borrow_value / liquidation_threshold) / collateral_amount
        liquidation_price = (borrow_value / liquidation_threshold) / position.collateral_amount
        
        return liquidation_price
    
    def calculate_price_drop_to_liquidation(
        self, 
        position: LoanPosition
    ) -> float:
        """計算距離清算的價格跌幅百分比"""
        current_price = position.collateral_price
        liquidation_price = self.calculate_liquidation_price(position)
        
        if current_price == 0:
            return 0
        
        price_drop_pct = (current_price - liquidation_price) / current_price
        return price_drop_pct
    
    def simulate_price_scenario(
        self, 
        position: LoanPosition,
        scenario: PriceScenario
    ) -> dict:
        """模擬特定價格情境"""
        # 計算新價格
        new_collateral_price = position.collateral_price * (1 + scenario.collateral_price_change)
        new_borrow_price = position.borrow_price * (1 + scenario.borrow_price_change)
        
        # 創建新倉位
        new_position = LoanPosition(
            collateral_asset=position.collateral_asset,
            borrow_asset=position.borrow_asset,
            collateral_amount=position.collateral_amount,
            borrow_amount=position.borrow_amount,
            collateral_price=new_collateral_price,
            borrow_price=new_borrow_price,
            collateral_factor=position.collateral_factor,
            liquidation_threshold=position.liquidation_threshold
        )
        
        # 計算健康因子
        new_health_factor = self.calculate_health_factor(new_position)
        
        # 計算距離清算的價格跌幅
        price_drop_to_liq = self.calculate_price_drop_to_liquidation(new_position)
        
        # 判斷是否清算
        is_liquidated = new_health_factor < 1.0
        
        return {
            'scenario': scenario.name,
            'collateral_price_change': scenario.collateral_price_change,
            'borrow_price_change': scenario.borrow_price_change,
            'new_collateral_price': new_collateral_price,
            'new_borrow_price': new_borrow_price,
            'health_factor': new_health_factor,
            'price_drop_to_liquidation': price_drop_to_liq,
            'is_liquidated': is_liquidated,
            'liquidation_loss': self._calculate_liquidation_loss(position, new_position) if is_liquidated else 0
        }
    
    def _calculate_liquidation_loss(
        self, 
        original: LoanPosition,
        simulated: LoanPosition
    ) -> float:
        """計算清算損失"""
        # 假設清算獎勵為 5%
        bonus_rate = 0.05
        
        # 抵押品被清算時的價值
        collateral_value = simulated.collateral_price * original.collateral_amount
        
        # 借款價值
        borrow_value = simulated.borrow_price * original.borrow_amount
        
        # 清算後收到的抵押品價值(扣除獎勵)
        liquidated_value = collateral_value * (1 - bonus_rate)
        
        # 淨損失 = 借款價值 - 清算後價值
        # 如果抵押品價值 > 借款價值,借款人還能收回部分
        loss = max(0, borrow_value - liquidated_value)
        
        # 以借款價值的百分比表示
        loss_pct = loss / borrow_value if borrow_value > 0 else 0
        
        return loss_pct
    
    def monte_carlo_simulation(
        self,
        position: LoanPosition,
        num_simulations: int = 10000,
        volatility: float = 0.5  # 年化波動率
    ) -> dict:
        """蒙特卡羅模擬"""
        
        # 假設價格服從對數正態分佈
        # 使用 30 天的時間範圍
        days = 30
        daily_vol = volatility / np.sqrt(365)
        
        liquidation_counts = 0
        losses = []
        health_factors = []
        
        for _ in range(num_simulations):
            # 生成隨機價格變化
            daily_returns = np.random.normal(0, daily_vol, days)
            cumulative_return = np.exp(np.sum(daily_returns)) - 1
            
            # 模擬抵押品價格變化
            new_collateral_price = position.collateral_price * (1 + cumulative_return)
            
            # 創建新倉位
            new_position = LoanPosition(
                collateral_asset=position.collateral_asset,
                borrow_asset=position.borrow_asset,
                collateral_amount=position.collateral_amount,
                borrow_amount=position.borrow_amount,
                collateral_price=new_collateral_price,
                borrow_price=position.borrow_price,
                collateral_factor=position.collateral_factor,
                liquidation_threshold=position.liquidation_threshold
            )
            
            # 計算健康因子
            hf = self.calculate_health_factor(new_position)
            health_factors.append(hf)
            
            if hf < 1.0:
                liquidation_counts += 1
                loss = self._calculate_liquidation_loss(position, new_position)
                losses.append(loss)
        
        liquidation_probability = liquidation_counts / num_simulations
        avg_loss = np.mean(losses) if losses else 0
        max_loss = np.max(losses) if losses else 0
        var_95 = np.percentile(losses, 95) if losses else 0
        
        return {
            'liquidation_probability': liquidation_probability,
            'expected_loss': avg_loss,
            'max_loss': max_loss,
            'var_95': var_95,
            'avg_health_factor': np.mean(health_factors),
            'min_health_factor': np.min(health_factors),
            'simulations': num_simulations
        }
    
    def stress_test(
        self, 
        position: LoanPosition,
        price_drops: List[float] = None
    ) -> List[dict]:
        """壓力測試"""
        
        if price_drops is None:
            price_drops = [-0.10, -0.20, -0.30, -0.40, -0.50, -0.60, -0.70, -0.80]
        
        results = []
        
        for drop in price_drops:
            scenario = PriceScenario(
                name=f"Price Drop {int(drop*100)}%",
                collateral_price_change=drop,
                borrow_price_change=0
            )
            
            result = self.simulate_price_scenario(position, scenario)
            results.append(result)
            
        return results


# 使用示例
def main():
    # 創建模擬器
    simulator = LiquidationRiskSimulator()
    
    # 創建借貸倉位:質押 1 ETH,借入 2000 USDC
    # 假設 ETH 價格為 3000 USD,USDC 價格為 1 USD
    position = LoanPosition(
        collateral_asset='ETH',
        borrow_asset='USDC',
        collateral_amount=1.0,  # 1 ETH
        borrow_amount=2000.0,   # 2000 USDC
        collateral_price=3000.0,  # ETH 價格 3000 USD
        borrow_price=1.0,         # USDC 價格 1 USD
        collateral_factor=0.80,   # 80% 抵押率
        liquidation_threshold=0.85  # 85% 清算閾值
    )
    
    # 計算當前健康因子
    hf = simulator.calculate_health_factor(position)
    print(f"當前健康因子: {hf:.4f}")
    
    # 計算清算價格
    liq_price = simulator.calculate_liquidation_price(position)
    print(f"清算價格: ${liq_price:.2f}")
    
    # 計算距離清算的價格跌幅
    price_drop = simulator.calculate_price_drop_to_liquidation(position)
    print(f"距離清算的價格跌幅: {price_drop*100:.2f}%")
    
    # 壓力測試
    print("\n=== 壓力測試結果 ===")
    stress_results = simulator.stress_test(position)
    
    for result in stress_results:
        status = "⚠️ 已清算" if result['is_liquidated'] else "✅ 安全"
        print(f"{result['scenario']}: 健康因子={result['health_factor']:.4f} {status}")
    
    # 蒙特卡羅模擬
    print("\n=== 蒙特卡羅模擬結果 (10000 次) ===")
    mc_results = simulator.monte_carlo_simulation(
        position, 
        num_simulations=10000,
        volatility=0.80  # 80% 年化波動率
    )
    
    print(f"清算機率: {mc_results['liquidation_probability']*100:.2f}%")
    print(f"平均損失: {mc_results['expected_loss']*100:.2f}%")
    print(f"最大損失: {mc_results['max_loss']*100:.2f}%")
    print(f"95% VaR: {mc_results['var_95']*100:.2f}%")
    print(f"平均健康因子: {mc_results['avg_health_factor']:.4f}")
    print(f"最低健康因子: {mc_results['min_health_factor']:.4f}")

if __name__ == "__main__":
    main()

2.2 利率風險模擬

利率變動是 DeFi 借貸中的重要風險因素。以下程式碼模擬不同市場條件下的利率變化:

# 利率風險模擬器
import numpy as np
from typing import List, Tuple

class InterestRateRiskSimulator:
    """利率風險模擬器"""
    
    def __init__(self, initial_utilization: float = 0.6):
        self.utilization = initial_utilization
        self.interest_rate_model = AaveInterestRateModel({})
        
    def simulate_utilization_change(
        self,
        target_utilization: float,
        num_steps: int = 30
    ) -> List[dict]:
        """模擬資金利用率變化"""
        
        results = []
        
        for i in range(num_steps):
            # 線性插值
            current_util = self.utilization + (target_utilization - self.utilization) * i / num_steps
            
            # 計算利率
            borrow_rate = self.interest_rate_model.calculate_borrow_rate(
                int(current_util * 1e18)
            )
            deposit_rate = self.interest_rate_model.calculate_deposit_rate(
                int(current_util * 1e18),
                borrow_rate
            )
            
            # 轉換為年化利率
            borrow_apr = self.interest_rate_model.calculate_apr(borrow_rate)
            deposit_apr = self.interest_rate_model.calculate_apr(deposit_rate)
            deposit_apy = self.interest_rate_model.calculate_apy(deposit_rate)
            
            results.append({
                'step': i,
                'utilization': current_util,
                'borrow_apr': borrow_apr,
                'deposit_apr': deposit_apr,
                'deposit_apy': deposit_apy
            })
            
        return results
    
    def calculate_cost_of_borrowing(
        self,
        borrow_amount: float,
        duration_days: int,
        utilization_rate: float
    ) -> float:
        """計算借款成本"""
        
        borrow_rate = self.interest_rate_model.calculate_borrow_rate(
            int(utilization_rate * 1e18)
        )
        
        # 計算借款利息
        daily_rate = borrow_rate / 1e18 / 365
        interest = borrow_amount * daily_rate * duration_days
        
        return interest
    
    def monte_carlo_utilization(
        self,
        initial_utilization: float,
        days: int,
        volatility: float = 0.1,
        num_simulations: int = 1000
    ) -> dict:
        """蒙特卡羅模擬資金利用率"""
        
        all_paths = []
        
        for _ in range(num_simulations):
            path = [initial_utilization]
            current = initial_utilization
            
            for _ in range(days):
                # 隨機波動
                change = np.random.normal(0, volatility)
                current = max(0.01, min(0.99, current + change))
                path.append(current)
                
            all_paths.append(path)
        
        # 計算統計數據
        all_paths = np.array(all_paths)
        
        return {
            'mean_utilization': np.mean(all_paths, axis=0),
            'median_utilization': np.median(all_paths, axis=0),
            'percentile_5': np.percentile(all_paths, 5, axis=0),
            'percentile_95': np.percentile(all_paths, 95, axis=0),
            'max_utilization': np.max(all_paths),
            'min_utilization': np.min(all_paths),
            'prob_over_80': np.mean(all_paths > 0.8, axis=0),
            'prob_over_90': np.mean(all_paths > 0.9, axis=0)
        }

2.3 清算概率即時計算工具

以下是一個實用的清算概率計算工具,可以幫助借款人評估當前倉位的風險:

# 清算預警系統
import requests
import time
from typing import Optional

class LiquidationAlertSystem:
    """清算預警系統"""
    
    def __init__(self, rpc_url: str, aave_addresses: dict):
        self.rpc_url = rpc_url
        self.aave_addresses = aave_addresses
        self.web3 = Web3(Web3.HTTPProvider(rpc_url))
        
        # 常用代幣價格(從 Chainlink 獲取)
        self.price_feeds = {
            'ETH': '0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419',
            'USDC': '0x8fFfFfd4AfB6115b954bd326cbe7B4BA576818f6',
            'USDT': '0x3E7d1eAB13ad0104d5510F417B90dC3B49f68489',
            'DAI': '0xAed0c38402a5d19df6E4c02B4B2A2e5c5b5e5b5c',
            'WBTC': '0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c'
        }
        
    def get_token_price(self, token: str) -> Optional[float]:
        """從 Chainlink 獲取代幣價格"""
        
        if token not in self.price_feeds:
            return None
            
        # 這裡應該調用 Chainlink 合約
        # 簡化版本返回模擬數據
        mock_prices = {
            'ETH': 3000.0,
            'USDC': 1.0,
            'USDT': 1.0,
            'DAI': 1.0,
            'WBTC': 65000.0
        }
        
        return mock_prices.get(token)
    
    def calculate_position_risk(
        self,
        user_address: str,
        collateral_asset: str,
        borrow_asset: str,
        collateral_amount: float,
        borrow_amount: float,
        collateral_factor: float = 0.80,
        liquidation_threshold: float = 0.85
    ) -> dict:
        """計算倉位風險"""
        
        # 獲取價格
        collateral_price = self.get_token_price(collateral_asset)
        borrow_price = self.get_token_price(borrow_asset)
        
        if collateral_price is None or borrow_price is None:
            return {'error': 'Unable to fetch prices'}
        
        # 計算價值
        collateral_value = collateral_amount * collateral_price
        borrow_value = borrow_amount * borrow_price
        
        # 計算健康因子
        if borrow_value > 0:
            health_factor = (collateral_value * liquidation_threshold) / borrow_value
        else:
            health_factor = float('inf')
        
        # 計算清算價格
        if collateral_amount > 0:
            liquidation_price = (borrow_value / liquidation_threshold) / collateral_amount
            price_drop_to_liquidation = (collateral_price - liquidation_price) / collateral_price
        else:
            liquidation_price = 0
            price_drop_to_liquidation = 0
        
        # 計算最大借款金額(維持 HF > 1.5)
        if liquidation_threshold > 0:
            max_borrow = (collateral_value * liquidation_threshold) / 1.5
        else:
            max_borrow = 0
        
        # 計算建議的借款金額(維持 HF > 2.0)
        safe_borrow = (collateral_value * liquidation_threshold) / 2.0
        
        return {
            'collateral_value': collateral_value,
            'borrow_value': borrow_value,
            'health_factor': health_factor,
            'liquidation_price': liquidation_price,
            'price_drop_to_liquidation': price_drop_to_liquidation,
            'current_collateral_factor': borrow_value / collateral_value if collateral_value > 0 else 0,
            'max_borrow_safe': max_borrow,
            'recommended_borrow': safe_borrow,
            'risk_level': self._assess_risk_level(health_factor),
            'warnings': self._generate_warnings(health_factor, price_drop_to_liquidation)
        }
    
    def _assess_risk_level(self, health_factor: float) -> str:
        """評估風險等級"""
        
        if health_factor == float('inf'):
            return 'SAFE'
        elif health_factor >= 2.0:
            return 'SAFE'
        elif health_factor >= 1.5:
            return 'LOW'
        elif health_factor >= 1.2:
            return 'MEDIUM'
        elif health_factor >= 1.0:
            return 'HIGH'
        else:
            return 'CRITICAL'
    
    def _generate_warnings(
        self, 
        health_factor: float,
        price_drop_to_liquidation: float
    ) -> List[str]:
        """生成警告"""
        
        warnings = []
        
        if health_factor < 1.0:
            warnings.append('⚠️ 您的倉位即將被清算!請立即增加抵押品或償還借款。')
        elif health_factor < 1.2:
            warnings.append('🔴 您的倉位風險較高,健康因子低於 1.2。')
        elif health_factor < 1.5:
            warnings.append('🟡 您的倉位風險中等,健康因子低於 1.5。')
        
        if price_drop_to_liquidation < 0.1:
            warnings.append(f'🚨 抵押品價格僅需下跌 {price_drop_to_liquidation*100:.1f}% 就會觸發清算!')
        elif price_drop_to_liquidation < 0.2:
            warnings.append(f'⚠️ 抵押品價格下跌 {price_drop_to_liquidation*100:.1f}% 將觸發清算。')
        
        return warnings
    
    def start_monitoring(
        self,
        user_address: str,
        check_interval: int = 60
    ):
        """啟動監控"""
        
        print(f"開始監控地址: {user_address}")
        print(f"檢查間隔: {check_interval} 秒")
        
        while True:
            try:
                # 這裡應該從區塊鏈獲取真實數據
                # 簡化版本使用模擬數據
                
                risk_info = self.calculate_position_risk(
                    user_address=user_address,
                    collateral_asset='ETH',
                    borrow_asset='USDC',
                    collateral_amount=1.0,
                    borrow_amount=2000.0
                )
                
                if 'error' not in risk_info:
                    print(f"\n[{time.strftime('%Y-%m-%d %H:%M:%S')}]")
                    print(f"  健康因子: {risk_info['health_factor']:.4f}")
                    print(f"  風險等級: {risk_info['risk_level']}")
                    print(f"  清算價格: ${risk_info['liquidation_price']:.2f}")
                    
                    if risk_info['warnings']:
                        for warning in risk_info['warnings']:
                            print(f"  {warning}")
                
            except Exception as e:
                print(f"Error: {e}")
                
            time.sleep(check_interval)

第三章:實際操作風險管理策略

3.1 借款人的風險管理策略

維持健康的健康因子

建議借款人維持健康因子在 1.5 以上,以提供足夠的安全緩衝。以下是具體策略:

class RiskManagement:
    """風險管理策略"""
    
    @staticmethod
    def calculate_safe_borrow_params(
        collateral_amount: float,
        collateral_price: float,
        collateral_factor: float,
        liquidation_threshold: float,
        target_health_factor: float = 2.0
    ) -> dict:
        """計算安全的借款參數"""
        
        collateral_value = collateral_amount * collateral_price
        
        # 根據目標健康因子計算最大安全借款
        max_safe_borrow = (
            collateral_value * liquidation_threshold / target_health_factor
        )
        
        # 計算建議的借款比例(使用 50% 安全邊際)
        recommended_borrow = max_safe_borrow * 0.5
        
        # 計算緩衝金額(預留多少資金應對價格波動)
        buffer_amount = max_safe_borrow - recommended_borrow
        
        return {
            'collateral_value': collateral_value,
            'max_safe_borrow': max_safe_borrow,
            'recommended_borrow': recommended_borrow,
            'buffer_amount': buffer_amount,
            'recommended_health_factor': target_health_factor,
            'borrow_ratio': recommended_borrow / collateral_value if collateral_value > 0 else 0
        }
    
    @staticmethod
    def rebalancing_strategy(
        current_health_factor: float,
        target_health_factor: float,
        collateral_value: float,
        borrow_value: float,
        collateral_price: float
    ) -> dict:
        """倉位再平衡策略"""
        
        actions = []
        
        if current_health_factor < 1.2:
            # 緊急情況:需要立即增加抵押品或償還借款
            if borrow_value > 0:
                # 計算需要償還的金額
                required_repayment = borrow_value - (
                    collateral_value * 0.85 / target_health_factor
                )
                actions.append({
                    'action': 'repay',
                    'amount': max(0, required_repayment),
                    'priority': 'HIGH',
                    'reason': 'Health factor critically low'
                })
            else:
                actions.append({
                    'action': 'add_collateral',
                    'amount': collateral_value * 0.2,
                    'priority': 'HIGH',
                    'reason': 'Increase collateral buffer'
                })
                
        elif current_health_factor < target_health_factor:
            # 温和情況:可以選擇性調整
            gap = target_health_factor - current_health_factor
            
            if gap > 0.3:
                # 差距較大,增加抵押品
                additional_collateral = (borrow_value * gap) / (target_health_factor * 0.85)
                actions.append({
                    'action': 'add_collateral',
                    'amount': additional_collateral,
                    'priority': 'MEDIUM',
                    'reason': 'Gradual rebalancing'
                })
        
        return {
            'actions': actions,
            'current_health_factor': current_health_factor,
            'target_health_factor': target_health_factor,
            'status': 'OK' if current_health_factor >= target_health_factor else 'NEEDS_ACTION'
        }

3.2 清算人的套利策略

對於清算人而言,識別清算機會並執行清算交易是獲取收益的方式。以下是基本策略:

class LiquidationStrategy:
    """清算套利策略"""
    
    def __init__(self, web3, aave_addresses: dict):
        self.web3 = web3
        self.aave_addresses = aave_addresses
        
    def find_liquidation_opportunities(
        self,
        users: List[str]
    ) -> List[dict]:
        """尋找清算機會"""
        
        opportunities = []
        
        for user in users:
            # 獲取用戶倉位數據
            user_data = self.get_user_data(user)
            
            # 檢查是否可清算
            if user_data['health_factor'] < 1.0:
                # 計算清算收益
                profit = self.calculate_liquidation_profit(
                    user_data
                )
                
                opportunities.append({
                    'user': user,
                    'collateral_asset': user_data['collateral_asset'],
                    'collateral_amount': user_data['collateral_amount'],
                    'borrow_asset': user_data['borrow_asset'],
                    'borrow_amount': user_data['borrow_amount'],
                    'health_factor': user_data['health_factor'],
                    'potential_profit': profit,
                    'gas_estimate': self.estimate_liquidation_gas(user)
                })
        
        # 按收益排序
        opportunities.sort(key=lambda x: x['potential_profit'], reverse=True)
        
        return opportunities
    
    def calculate_liquidation_profit(self, user_data: dict) -> float:
        """計算清算收益"""
        
        # 假設清算獎勵為 5%
        bonus_rate = 0.05
        
        # 抵押品價值
        collateral_value = user_data['collateral_amount'] * user_data['collateral_price']
        
        # 清算獎勵價值
        bonus_value = collateral_value * bonus_rate
        
        # 扣除 Gas 成本(估算)
        gas_cost = 0.005  # ETH
        
        # 淨收益
        profit = bonus_value - gas_cost
        
        return profit
    
    def execute_liquidation(
        self,
        user: str,
        debt_to_cover: int
    ) -> str:
        """執行清算交易"""
        
        # 這裡應該調用 Aave 的清算函數
        # 簡化版本返回交易雜湊
        
        tx = {
            'from': self.liquidator_address,
            'to': self.aave_addresses['pool'],
            'gas': 500000,
            # ... 其他交易參數
        }
        
        signed_tx = self.web3.eth.account.sign_transaction(
            tx, 
            self.private_key
        )
        
        tx_hash = self.web3.eth.send_raw_transaction(
            signed_tx.rawTransaction
        )
        
        return tx_hash.hex()

第四章:風險監控儀表板

以下是一個完整的風險監控系統,可以幫助借款人即時監控倉位風險:

# 風險監控儀表板
class RiskDashboard:
    """風險監控儀表板"""
    
    def __init__(self):
        self.simulator = LiquidationRiskSimulator()
        self.alert_system = LiquidationAlertSystem()
        self.risk_manager = RiskManagement()
        
    def generate_position_report(
        self,
        position: LoanPosition,
        market_volatility: float = 0.8
    ) -> dict:
        """生成完整倉位風險報告"""
        
        # 基本指標
        health_factor = self.simulator.calculate_health_factor(position)
        liquidation_price = self.simulator.calculate_liquidation_price(position)
        price_drop = self.simulator.calculate_price_drop_to_liquidation(position)
        
        # 安全借款計算
        safe_params = self.risk_manager.calculate_safe_borrow_params(
            position.collateral_amount,
            position.collateral_price,
            position.collateral_factor,
            position.liquidation_threshold
        )
        
        # 蒙特卡羅模擬
        mc_results = self.simulator.monte_carlo_simulation(
            position,
            volatility=market_volatility
        )
        
        # 壓力測試
        stress_results = self.simulator.stress_test(position)
        
        return {
            'position_summary': {
                'collateral_asset': position.collateral_asset,
                'borrow_asset': position.borrow_asset,
                'collateral_value': position.collateral_amount * position.collateral_price,
                'borrow_value': position.borrow_amount * position.borrow_price,
                'collateral_ratio': position.borrow_amount * position.borrow_price / 
                                   (position.collateral_amount * position.collateral_price)
            },
            'risk_metrics': {
                'health_factor': health_factor,
                'liquidation_price': liquidation_price,
                'price_drop_to_liquidation': price_drop,
                'liquidation_probability_30d': mc_results['liquidation_probability'],
                'var_95': mc_results['var_95']
            },
            'recommendations': {
                'max_safe_borrow': safe_params['max_safe_borrow'],
                'recommended_borrow': safe_params['recommended_borrow'],
                'current_status': 'SAFE' if health_factor >= 2.0 else 
                                 'LOW' if health_factor >= 1.5 else
                                 'MEDIUM' if health_factor >= 1.2 else
                                 'HIGH' if health_factor >= 1.0 else 'CRITICAL'
            },
            'stress_test': stress_results,
            'monte_carlo': mc_results
        }
    
    def print_dashboard(self, report: dict):
        """打印儀表板"""
        
        print("=" * 60)
        print("DeFi 借貸風險監控儀表板")
        print("=" * 60)
        
        # 倉位摘要
        print("\n【倉位摘要】")
        summary = report['position_summary']
        print(f"  抵押資產: {summary['collateral_asset']}")
        print(f"  抵押數量: {summary['collateral_value']:,.2f} USD")
        print(f"  借款資產: {summary['borrow_asset']}")
        print(f"  借款金額: {summary['borrow_value']:,.2f} USD")
        print(f"  借款比例: {summary['collateral_ratio']*100:.1f}%")
        
        # 風險指標
        print("\n【風險指標】")
        risk = report['risk_metrics']
        print(f"  健康因子: {risk['health_factor']:.4f}")
        print(f"  清算價格: ${risk['liquidation_price']:,.2f}")
        print(f"  距離清算跌幅: {risk['price_drop_to_liquidation']*100:.2f}%")
        print(f"  30天清算概率: {risk['liquidation_probability_30d']*100:.2f}%")
        print(f"  95% VaR: {risk['var_95']*100:.2f}%")
        
        # 建議
        print("\n【建議】")
        rec = report['recommendations']
        print(f"  狀態: {rec['current_status']}")
        print(f"  最大安全借款: ${rec['max_safe_borrow']:,.2f}")
        print(f"  建議借款: ${rec['recommended_borrow']:,.2f}")
        
        print("\n" + "=" * 60)


# 使用示例
def main():
    # 創建倉位
    position = LoanPosition(
        collateral_asset='ETH',
        borrow_asset='USDC',
        collateral_amount=10.0,  # 10 ETH
        borrow_amount=25000.0,   # 25000 USDC
        collateral_price=3000.0,
        borrow_price=1.0,
        collateral_factor=0.80,
        liquidation_threshold=0.85
    )
    
    # 創建儀表板
    dashboard = RiskDashboard()
    
    # 生成報告
    report = dashboard.generate_position_report(
        position,
        market_volatility=0.80
    )
    
    # 打印儀表板
    dashboard.print_dashboard(report)

if __name__ == "__main__":
    main()

結論

DeFi 借貸協議為加密貨幣持有者提供了前所未有的金融自由度,但同時也蘊含著複雜的風險。透過本指南提供的風險模擬工具和策略,借款人可以更好地理解和管理自己的風險暴露。關鍵原則包括:

  1. 維持健康的健康因子:始終保持健康因子在 1.5 以上,為市場波動預留足夠的安全緩衝。
  1. 了解清算機制:清楚了解自己的清算價格和距離清算的價格跌幅。
  1. 多元化抵押品:不要將所有資產集中在單一抵押品上。
  1. 持續監控:使用本指南提供的工具持續監控倉位風險。
  1. 制定應急計劃:提前規劃在市場大幅波動時的應對策略。

記住,在 DeFi 借貸中,保護本金永遠比追求收益更重要。

參考來源

延伸閱讀與來源

這篇文章對您有幫助嗎?

評論

發表評論

注意:由於這是靜態網站,您的評論將儲存在本地瀏覽器中,不會公開顯示。

目前尚無評論,成為第一個發表評論的人吧!