AI 交易代理以太坊開發完整指南:從智慧合約到機器人實作

本文深入探討如何在以太坊生態系統中構建 AI 交易代理,涵蓋智慧合約開發、策略實現、風險控制、與 DeFi 協議交互等多個維度。提供完整的 Solidity 智慧合約範例和 TypeScript 交易機器人代碼,幫助開發者構建 24/7 自動化交易系統。文章涵蓋訂單管理、風險管理、機器學習策略、信號產生、訂單執行和即時監控等完整模組。

AI 交易代理以太坊開發完整指南:從智慧合約到機器人實作

概述

人工智慧與區塊鏈技術的結合正在催生一個全新的金融科技領域。AI 交易代理(Trading Bot)能夠自動分析市場數據、執行交易策略、管理風險,為投資者提供 24/7 的自動化交易服務。本文深入探討如何在以太坊生態系統中構建 AI 交易代理,涵蓋智慧合約開發、策略實現、風險控制、與 DeFi 協議交互等多個維度,提供完整的程式碼範例和實作指導。

本文假定讀者具備基本的 Solidity 開發經驗和 JavaScript/TypeScript 程式設計能力,對 DeFi 協議有基本理解。所有程式碼均基於 Solidity 0.8.x 和 ethers.js v6 版本,可直接在專案中使用。

第一章:AI 交易代理架構設計

1.1 系統架構概述

AI 交易代理的完整系統架構包含多個核心組件,每個組件負責不同的功能模組。

系統架構圖

AI 交易代理系統架構:

┌─────────────────────────────────────────────────────────────────────────┐
│                          數據層                                         │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ 價格數據    │  │ 鏈上數據    │  │ 社交數據    │  │ 新聞數據    │     │
│  │ Price Feed │  │ On-chain   │  │ Social     │  │ News       │     │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘     │
└─────────┼────────────────┼────────────────┼────────────────┼────────────┘
          │                │                │                │
          ▼                ▼                ▼                ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                          分析層                                         │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │                    AI 策略引擎                                    │   │
│  │  • 機器學習模型推理                                              │   │
│  │  • 技術指標計算                                                  │   │
│  │  • 訊號產生                                                     │   │
│  │  • 倉位管理                                                     │   │
│  └────────────────────────────┬────────────────────────────────────┘   │
└───────────────────────────────┼─────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                          執行層                                         │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ 訂單管理    │  │ 風險檢查    │  │ 交易執行    │  │ 監控告警    │     │
│  │ Order Mgr  │  │ Risk Check │  │ Executor   │  │ Monitor    │     │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘     │
└─────────┼────────────────┼────────────────┼────────────────┼────────────┘
          │                │                │                │
          ▼                ▼                ▼                ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                          區塊鏈層                                       │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ 錢包/私鑰   │  │ RPC 節點    │  │ DeFi 協議   │  │ 區塊瀏覽器  │     │
│  │ Wallet    │  │ RPC Node   │  │ Protocols  │  │ Explorer  │     │
│  └─────────────┘  └─────────────┘  └─────────────┘  └─────────────┘     │
└─────────────────────────────────────────────────────────────────────────┘

1.2 核心組件設計

訂單管理模組

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title OrderManager
 * @dev AI 交易代理訂單管理合約
 */
contract OrderManager {
    // 訂單類型
    enum OrderType {
        Market,      // 市價單
        Limit,       // 限價單
        StopLoss,    // 止損單
        TakeProfit   // 止盈單
    }

    // 訂單狀態
    enum OrderStatus {
        Pending,     // 待執行
        Executed,    // 已執行
        Cancelled,   // 已取消
        Expired      // 已過期
    }

    // 訂單結構
    struct Order {
        bytes32 orderId;
        address owner;
        OrderType orderType;
        address inputToken;
        address outputToken;
        uint256 inputAmount;
        uint256 price;          // 限價/止損/止盈價格
        uint256 stopLossPrice;
        uint256 takeProfitPrice;
        uint256 deadline;
        OrderStatus status;
        uint256 filledAmount;
        uint256 createdAt;
    }

    // 狀態變量
    mapping(bytes32 => Order) public orders;
    mapping(address => bytes32[]) public userOrders;
    address public priceOracle;
    uint256 public maxSlippage = 300; // 3%

    // 事件
    event OrderCreated(bytes32 indexed orderId, address indexed owner);
    event OrderExecuted(bytes32 indexed orderId, uint256 inputAmount, uint256 outputAmount);
    event OrderCancelled(bytes32 indexed orderId);

    /**
     * @dev 創建市價單
     */
    function createMarketOrder(
        address inputToken,
        address outputToken,
        uint256 inputAmount,
        uint256 deadline
    ) external returns (bytes32 orderId) {
        require(inputAmount > 0, "Invalid amount");
        require(deadline > block.timestamp, "Invalid deadline");

        orderId = keccak256(abi.encode(
            msg.sender,
            inputToken,
            outputToken,
            inputAmount,
            block.timestamp
        ));

        orders[orderId] = Order({
            orderId: orderId,
            owner: msg.sender,
            orderType: OrderType.Market,
            inputToken: inputToken,
            outputToken: outputToken,
            inputAmount: inputAmount,
            price: 0,
            stopLossPrice: 0,
            takeProfitPrice: 0,
            deadline: deadline,
            status: OrderStatus.Pending,
            filledAmount: 0,
            createdAt: block.timestamp
        });

        userOrders[msg.sender].push(orderId);
        emit OrderCreated(orderId, msg.sender);
    }

    /**
     * @dev 創建限價單
     */
    function createLimitOrder(
        address inputToken,
        address outputToken,
        uint256 inputAmount,
        uint256 limitPrice,
        uint256 deadline
    ) external returns (bytes32 orderId) {
        require(inputAmount > 0, "Invalid amount");
        require(limitPrice > 0, "Invalid price");
        require(deadline > block.timestamp, "Invalid deadline");

        orderId = keccak256(abi.encode(
            msg.sender,
            inputToken,
            outputToken,
            inputAmount,
            limitPrice,
            block.timestamp
        ));

        orders[orderId] = Order({
            orderId: orderId,
            owner: msg.sender,
            orderType: OrderType.Limit,
            inputToken: inputToken,
            outputToken: outputToken,
            inputAmount: inputAmount,
            price: limitPrice,
            stopLossPrice: 0,
            takeProfitPrice: 0,
            deadline: deadline,
            status: OrderStatus.Pending,
            filledAmount: 0,
            createdAt: block.timestamp
        });

        userOrders[msg.sender].push(orderId);
        emit OrderCreated(orderId, msg.sender);
    }

    /**
     * @dev 創建止損單
     */
    function createStopLossOrder(
        address inputToken,
        address outputToken,
        uint256 inputAmount,
        uint256 stopLossPrice,
        uint256 deadline
    ) external returns (bytes32 orderId) {
        require(inputAmount > 0, "Invalid amount");
        require(stopLossPrice > 0, "Invalid stop loss price");

        orderId = keccak256(abi.encode(
            msg.sender,
            inputToken,
            outputToken,
            inputAmount,
            stopLossPrice,
            block.timestamp
        ));

        orders[orderId] = Order({
            orderId: orderId,
            owner: msg.sender,
            orderType: OrderType.StopLoss,
            inputToken: inputToken,
            outputToken: outputToken,
            inputAmount: inputAmount,
            price: 0,
            stopLossPrice: stopLossPrice,
            takeProfitPrice: 0,
            deadline: deadline,
            status: OrderStatus.Pending,
            filledAmount: 0,
            createdAt: block.timestamp
        });

        userOrders[msg.sender].push(orderId);
        emit OrderCreated(orderId, msg.sender);
    }

    /**
     * @dev 取消訂單
     */
    function cancelOrder(bytes32 orderId) external {
        Order storage order = orders[orderId];
        require(order.owner == msg.sender, "Not owner");
        require(order.status == OrderStatus.Pending, "Order not pending");

        order.status = OrderStatus.Cancelled;
        emit OrderCancelled(orderId);
    }

    /**
     * @dev 查詢訂單
     */
    function getOrder(bytes32 orderId) external view returns (Order memory) {
        return orders[orderId];
    }

    /**
     * @dev 批量查詢訂單
     */
    function getOrders(bytes32[] calldata orderIds)
        external
        view
        returns (Order[] memory)
    {
        Order[] memory result = new Order[](orderIds.length);
        for (uint256 i = 0; i < orderIds.length; i++) {
            result[i] = orders[orderIds[i]];
        }
        return result;
    }
}

1.3 風險控制模組

風險管理合約

/**
 * @title RiskManager
 * @dev AI 交易代理風險控制合約
 */
contract RiskManager {
    // 風險參數
    struct RiskParams {
        uint256 maxPositionSize;     // 最大倉位規模
        uint256 maxDailyLoss;        // 每日最大虧損
        uint256 maxDrawdown;         // 最大回撤
        uint256 maxLeverage;         // 最大槓桿
        uint256 minPositionSize;     // 最小倉位規模
        uint256 maxSlippage;         // 最大滑點
    }

    // 風險狀態
    struct RiskState {
        uint256 dailyVolume;         // 今日交易量
        uint256 dailyProfitLoss;     // 今日損益
        uint256 peakBalance;         // 歷史最高餘額
        uint256 lastResetTime;       // 上次重置時間
        uint256 consecutiveLosses;    // 連續虧損次數
    }

    // 狀態變量
    RiskParams public params;
    RiskState public state;
    address public owner;

    // 事件
    event RiskLimitTriggered(string reason, uint256 value);
    event PositionOpened(uint256 size);
    event PositionClosed(uint256 size, uint256 pnl);

    constructor() {
        owner = msg.sender;
        params = RiskParams({
            maxPositionSize: 100e18,      // 100 ETH
            maxDailyLoss: 10e18,         // 10 ETH
            maxDrawdown: 2000,           // 20%
            maxLeverage: 3,              // 3x
            minPositionSize: 0.1e18,     // 0.1 ETH
            maxSlippage: 300             // 3%
        });
        state.peakBalance = address(this).balance;
    }

    /**
     * @dev 檢查交易前風險
     */
    function checkPreTrade(uint256 size, uint256 slippage)
        external
        view
        returns (bool allowed, string memory reason)
    {
        // 檢查倉位規模
        if (size < params.minPositionSize) {
            return (false, "Position too small");
        }

        if (size > params.maxPositionSize) {
            return (false, "Position too large");
        }

        // 檢查滑點
        if (slippage > params.maxSlippage) {
            return (false, "Slippage too high");
        }

        // 檢查每日虧損限額
        if (state.dailyProfitLoss > params.maxDailyLoss) {
            return (false, "Daily loss limit exceeded");
        }

        // 檢查回撤
        uint256 currentBalance = address(this).balance;
        if (state.peakBalance > 0) {
            uint256 drawdown = ((state.peakBalance - currentBalance) * 10000) / state.peakBalance;
            if (drawdown > params.maxDrawdown) {
                return (false, "Max drawdown exceeded");
            }
        }

        return (true, "");
    }

    /**
     * @dev 記錄交易
     */
    function recordTrade(uint256 size, uint256 pnl) external {
        require(msg.sender == owner, "Not authorized");

        state.dailyVolume += size;
        state.dailyProfitLoss += int256(pnl);
        state.consecutiveLosses = pnl > 0 ? 0 : state.consecutiveLosses + 1;

        // 更新歷史最高餘額
        uint256 currentBalance = address(this).balance;
        if (currentBalance > state.peakBalance) {
            state.peakBalance = currentBalance;
        }

        // 重置每日統計(如果超過 24 小時)
        if (block.timestamp - state.lastResetTime > 24 hours) {
            state.dailyVolume = 0;
            state.dailyProfitLoss = 0;
            state.lastResetTime = block.timestamp;
        }

        emit PositionOpened(size);
        if (pnl != 0) {
            emit PositionClosed(size, uint256(int256(pnl) >= 0 ? 1 : 0));
        }
    }

    /**
     * @dev 獲取風險評分
     */
    function getRiskScore() external view returns (uint256 score) {
        uint256 currentBalance = address(this).balance;
        score = 50; // 基礎分數

        // 根據回撤調整
        if (state.peakBalance > 0) {
            uint256 drawdown = ((state.peakBalance - currentBalance) * 10000) / state.peakBalance;
            if (drawdown > 1500) score += 30; // >15% 回撤
            else if (drawdown > 1000) score += 20;
            else if (drawdown > 500) score += 10;
        }

        // 根據連續虧損調整
        if (state.consecutiveLosses >= 5) score += 20;
        else if (state.consecutiveLosses >= 3) score += 10;

        return score;
    }

    /**
     * @dev 更新風險參數
     */
    function updateRiskParams(RiskParams memory _params) external {
        require(msg.sender == owner, "Not authorized");
        params = _params;
    }
}

第二章:策略實現與機器人開發

2.1 TypeScript 交易機器人框架

完整交易機器人代碼

// trading-bot.ts - AI 交易機器人實現
import { ethers, BigNumber } from 'ethers';
import { Contract, Wallet, providers } from 'ethers';
import axios from 'axios';

// 類型定義
interface TradingConfig {
    rpcUrl: string;
    privateKey: string;
    maxSlippage: number;
    minTradeAmount: BigNumber;
    maxTradeAmount: BigNumber;
    pollingInterval: number;
}

interface MarketData {
    price: number;
    volume: number;
    timestamp: number;
    bid: number;
    ask: number;
}

interface TradingSignal {
    action: 'BUY' | 'SELL' | 'HOLD';
    confidence: number;
    price: number;
    size: BigNumber;
    reason: string;
}

// ERC20 代幣 ABI
const ERC20_ABI = [
    'function approve(address spender, uint256 amount) returns (bool)',
    'function allowance(address owner, address spender) view returns (uint256)',
    'function balanceOf(address account) view returns (uint256)',
    'function transfer(address to, uint256 amount) returns (bool)'
];

// Uniswap V3 Router ABI
const UNISWAP_ROUTER_ABI = [
    'function exactInputSingle((address tokenIn, address tokenOut, uint24 fee, address recipient, uint256 deadline, uint256 amountIn, uint256 amountOutMinimum, uint160 sqrtPriceLimitX96)) external payable returns (uint256 amountOut)'
];

/**
 * AI 交易機器人類
 */
class AITradingBot {
    private provider: providers.JsonRpcProvider;
    private wallet: Wallet;
    private config: TradingConfig;
    private isRunning: boolean = false;
    private position: BigNumber = BigNumber.from(0);
    private entryPrice: number = 0;

    // 合約地址
    private readonly WETH = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
    private readonly USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
    private readonly UNISWAP_ROUTER = '0xE592427A0AEce92De3Edee1F18E0157C05861564';

    constructor(config: TradingConfig) {
        this.config = config;
        this.provider = new providers.JsonRpcProvider(config.rpcUrl);
        this.wallet = new Wallet(config.privateKey, this.provider);
    }

    /**
     * 啟動交易機器人
     */
    async start(): Promise<void> {
        console.log('🤖 AI Trading Bot starting...');
        this.isRunning = true;
        await this.mainLoop();
    }

    /**
     * 停止交易機器人
     */
    stop(): void {
        console.log('🛑 AI Trading Bot stopping...');
        this.isRunning = false;
    }

    /**
     * 主循環
     */
    private async mainLoop(): Promise<void> {
        while (this.isRunning) {
            try {
                // 1. 獲取市場數據
                const marketData = await this.fetchMarketData();

                // 2. 生成交易訊號
                const signal = await this.generateSignal(marketData);

                // 3. 執行交易
                if (signal.action !== 'HOLD') {
                    await this.executeTrade(signal);
                }

                // 4. 監控倉位
                await this.monitorPosition(marketData);

            } catch (error) {
                console.error('Error in main loop:', error);
            }

            // 等待下次輪詢
            await this.sleep(this.config.pollingInterval);
        }
    }

    /**
     * 獲取市場數據
     */
    private async fetchMarketData(): Promise<MarketData> {
        // 從多個來源獲取價格數據
        const [priceData, volumeData] = await Promise.all([
            this.getPriceFromUniswap(),
            this.getVolumeFromDEX()
        ]);

        return {
            price: priceData,
            volume: volumeData,
            timestamp: Date.now(),
            bid: priceData * 0.9995,  // 買入價
            ask: priceData * 1.0005   // 賣出價
        };
    }

    /**
     * 從 Uniswap 獲取價格
     */
    private async getPriceFromUniswap(): Promise<number> {
        const provider = this.provider;
        
        // 使用合約 call 獲取價格(簡化版)
        // 實際應使用 subgraph 或價格預言機
        const response = await axios.get('https://api.coingecko.com/api/v3/simple/price', {
            params: {
                ids: 'ethereum',
                vs_currencies: 'usd'
            }
        });
        
        return response.data.ethereum.usd;
    }

    /**
     * 獲取交易量
     */
    private async getVolumeFromDEX(): Promise<number> {
        // 從 DEX 獲取 24 小時交易量
        // 實際應使用 The Graph 或DEX API
        return 1_000_000_000; // 簡化返回值
    }

    /**
     * 生成交易訊號(AI 策略)
     */
    private async generateSignal(marketData: MarketData): Promise<TradingSignal> {
        // 簡化的 AI 策略邏輯
        // 實際應使用機器學習模型

        const indicators = await this.calculateIndicators(marketData);
        
        // 簡單的均值回歸策略
        const movingAverage = indicators.movingAverage;
        const currentPrice = marketData.price;
        
        let action: 'BUY' | 'SELL' | 'HOLD' = 'HOLD';
        let confidence = 0;
        let reason = '';

        if (currentPrice < movingAverage * 0.95) {
            // 價格低於均值,買入
            action = 'BUY';
            confidence = Math.min(90, ((movingAverage - currentPrice) / movingAverage) * 200);
            reason = `Price ${currentPrice} below MA ${movingAverage}`;
        } else if (currentPrice > movingAverage * 1.05) {
            // 價格高於均值,賣出
            action = 'SELL';
            confidence = Math.min(90, ((currentPrice - movingAverage) / movingAverage) * 200);
            reason = `Price ${currentPrice} above MA ${movingAverage}`;
        }

        // 根據 RSI 調整訊號
        if (indicators.rsi < 30 && action === 'HOLD') {
            action = 'BUY';
            confidence = 70;
            reason = 'RSI oversold';
        } else if (indicators.rsi > 70 && action === 'HOLD') {
            action = 'SELL';
            confidence = 70;
            reason = 'RSI overbought';
        }

        // 計算交易大小
        const balance = await this.provider.getBalance(this.wallet.address);
        const tradeSize = balance.div(10); // 使用 10% 的餘額

        return {
            action,
            confidence,
            price: currentPrice,
            size: tradeSize,
            reason
        };
    }

    /**
     * 計算技術指標
     */
    private async calculateIndicators(marketData: MarketData): Promise<{
        movingAverage: number;
        rsi: number;
        macd: number;
    }> {
        // 獲取歷史價格數據
        const prices = await this.getHistoricalPrices(20);
        
        // 計算簡單移動平均
        const sum = prices.reduce((a, b) => a + b, 0);
        const movingAverage = sum / prices.length;

        // 計算 RSI
        const rsi = this.calculateRSI(prices);

        // 計算 MACD
        const macd = this.calculateMACD(prices);

        return { movingAverage, rsi, macd };
    }

    /**
     * 獲取歷史價格
     */
    private async getHistoricalPrices(days: number): Promise<number[]> {
        // 從 API 獲取歷史價格
        // 這裡返回模擬數據
        const prices: number[] = [];
        let price = 2000;
        for (let i = 0; i < days; i++) {
            price += (Math.random() - 0.5) * 100;
            prices.push(price);
        }
        return prices;
    }

    /**
     * 計算 RSI
     */
    private calculateRSI(prices: number[]): number {
        if (prices.length < 2) return 50;

        let gains = 0;
        let losses = 0;

        for (let i = 1; i < prices.length; i++) {
            const change = prices[i] - prices[i - 1];
            if (change > 0) gains += change;
            else losses -= change;
        }

        const avgGain = gains / (prices.length - 1);
        const avgLoss = losses / (prices.length - 1);

        if (avgLoss === 0) return 100;

        const rs = avgGain / avgLoss;
        return 100 - (100 / (1 + rs));
    }

    /**
     * 計算 MACD
     */
    private calculateMACD(prices: number[]): number {
        if (prices.length < 26) return 0;

        // 簡化的 MACD 計算
        const ema12 = this.calculateEMA(prices, 12);
        const ema26 = this.calculateEMA(prices, 26);

        return ema12 - ema26;
    }

    /**
     * 計算 EMA
     */
    private calculateEMA(prices: number[], period: number): number {
        if (prices.length < period) return prices[prices.length - 1];

        const multiplier = 2 / (period + 1);
        let ema = prices[0];

        for (let i = 1; i < prices.length; i++) {
            ema = (prices[i] - ema) * multiplier + ema;
        }

        return ema;
    }

    /**
     * 執行交易
     */
    private async executeTrade(signal: TradingSignal): Promise<void> {
        console.log(`\n📊 Trading Signal: ${signal.action}`);
        console.log(`   Confidence: ${signal.confidence.toFixed(2)}%`);
        console.log(`   Size: ${ethers.utils.formatEther(signal.size)} ETH`);
        console.log(`   Reason: ${signal.reason}`);

        // 風險檢查
        const riskCheck = await this.checkRisk(signal);
        if (!riskCheck.allowed) {
            console.log(`   ⚠️ Risk check failed: ${riskCheck.reason}`);
            return;
        }

        try {
            if (signal.action === 'BUY') {
                await this.executeBuy(signal);
            } else if (signal.action === 'SELL') {
                await this.executeSell(signal);
            }
        } catch (error) {
            console.error('Trade execution failed:', error);
        }
    }

    /**
     * 執行買入
     */
    private async executeBuy(signal: TradingSignal): Promise<void> {
        const router = new Contract(
            this.UNISWAP_ROUTER,
            UNISWAP_ROUTER_ABI,
            this.wallet
        );

        const amountOutMin = signal.size
            .mul(95) // 5% 滑點容忍
            .div(100);

        const tx = await router.exactInputSingle({
            tokenIn: this.WETH,
            tokenOut: this.USDC,
            fee: 3000,
            recipient: this.wallet.address,
            deadline: Math.floor(Date.now() / 1000) + 600,
            amountIn: signal.size,
            amountOutMinimum: amountOutMin,
            sqrtPriceLimitX96: 0
        });

        console.log(`   📝 Transaction sent: ${tx.hash}`);
        await tx.wait();
        console.log(`   ✅ Trade confirmed!`);

        this.position = this.position.add(signal.size);
        this.entryPrice = signal.price;
    }

    /**
     * 執行賣出
     */
    private async executeSell(signal: TradingSignal): Promise<void> {
        // 類似買入邏輯,方向相反
        console.log(`   📤 Executing SELL order...`);
        
        // 更新倉位
        this.position = this.position.sub(signal.size);
    }

    /**
     * 風險檢查
     */
    private async checkRisk(signal: TradingSignal): Promise<{allowed: boolean; reason: string}> {
        // 檢查交易大小
        if (signal.size.lt(this.config.minTradeAmount)) {
            return { allowed: false, reason: 'Below minimum trade size' };
        }

        if (signal.size.gt(this.config.maxTradeAmount)) {
            return { allowed: false, reason: 'Above maximum trade size' };
        }

        // 檢查信心度
        if (signal.confidence < 60) {
            return { allowed: false, reason: 'Low confidence' };
        }

        return { allowed: true, reason: '' };
    }

    /**
     * 監控倉位
     */
    private async monitorPosition(marketData: MarketData): Promise<void> {
        if (this.position.gt(0)) {
            const pnl = (marketData.price - this.entryPrice) / this.entryPrice;
            console.log(`\n📈 Position PnL: ${(pnl * 100).toFixed(2)}%`);

            // 止損檢查
            if (pnl < -0.05) {
                console.log('   ⚠️ Stop loss triggered!');
                // 執行止損
                await this.executeSell({
                    action: 'SELL',
                    confidence: 100,
                    price: marketData.price,
                    size: this.position,
                    reason: 'Stop loss'
                });
            }

            // 止盈檢查
            if (pnl > 0.10) {
                console.log('   🎯 Take profit triggered!');
                // 執行止盈
                await this.executeSell({
                    action: 'SELL',
                    confidence: 100,
                    price: marketData.price,
                    size: this.position,
                    reason: 'Take profit'
                });
            }
        }
    }

    /**
     * 工具函數:睡眠
     */
    private sleep(ms: number): Promise<void> {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
}

// 使用範例
async function main() {
    const config: TradingConfig = {
        rpcUrl: process.env.RPC_URL || 'https://eth-mainnet.alchemyapi.io/v2/YOUR_API_KEY',
        privateKey: process.env.PRIVATE_KEY || '',
        maxSlippage: 300,     // 3%
        minTradeAmount: ethers.utils.parseEther('0.1'),
        maxTradeAmount: ethers.utils.parseEther('10'),
        pollingInterval: 60000 // 1 分鐘
    };

    const bot = new AITradingBot(config);

    // 優雅退出處理
    process.on('SIGINT', () => {
        bot.stop();
        process.exit(0);
    });

    await bot.start();
}

main().catch(console.error);

2.2 策略信號產生器

機器學習策略實現

// strategy/signal-generator.ts - 信號產生器
import { TensorFlow } from '@tensorflow/tfjs-node';
import { RSI, MACD, BollingerBands } from 'technicalindicators';

/**
 * 機器學習信號產生器
 */
class MLSignalGenerator {
    private model: TensorFlow.LayersModel | null = null;
    private lookbackPeriod: number = 60;
    private features: string[] = ['rsi', 'macd', 'bb', 'volume', 'price'];

    /**
     * 加載預訓練模型
     */
    async loadModel(modelPath: string): Promise<void> {
        this.model = await TensorFlow.loadLayersModel(`file://${modelPath}`);
        console.log('✅ ML Model loaded');
    }

    /**
     * 生成交易信號
     */
    async generateSignal(prices: number[], volumes: number[]): Promise<{
        signal: number; // -1: Sell, 0: Hold, 1: Buy
        confidence: number;
    }> {
        // 計算技術指標
        const features = this.extractFeatures(prices, volumes);

        // 標準化特徵
        const normalizedFeatures = this.normalizeFeatures(features);

        // 轉換為模型輸入格式
        const input = TensorFlow.tensor2d([normalizedFeatures]);

        // 進行預測
        const prediction = this.model!.predict(input) as TensorFlow.Tensor;
        const probabilities = await prediction.data();

        // 解析預測結果
        const buyProb = probabilities[0];
        const sellProb = probabilities[1];
        const holdProb = probabilities[2];

        // 確定信號
        let signal = 0;
        let confidence = holdProb;

        if (buyProb > sellProb && buyProb > holdProb) {
            signal = 1;
            confidence = buyProb;
        } else if (sellProb > buyProb && sellProb > holdProb) {
            signal = -1;
            confidence = sellProb;
        }

        // 清理內存
        input.dispose();
        prediction.dispose();

        return { signal, confidence };
    }

    /**
     * 提取特徵
     */
    private extractFeatures(prices: number[], volumes: number[]): number[] {
        // RSI
        const rsiValues = RSI.calculate({ values: prices, period: 14 });
        const rsi = rsiValues[rsiValues.length - 1] / 100;

        // MACD
        const macdValues = MACD.calculate({
            values: prices,
            fastPeriod: 12,
            slowPeriod: 26,
            signalPeriod: 9,
            SimpleMAOscillator: false,
            SimpleMASignal: false
        });
        const macd = macdValues[macdValues.length - 1].MACD || 0;

        // Bollinger Bands
        const bbValues = BollingerBands.calculate({
            values: prices,
            period: 20,
            stdDev: 2
        });
        const bb = bbValues[bbValues.length - 1];
        const bbPosition = (prices[prices.length - 1] - bb.lower) / (bb.upper - bb.lower);

        // 成交量變化
        const volumeChange = (volumes[volumes.length - 1] - volumes[volumes.length - 2]) 
            / volumes[volumes.length - 2];

        // 價格動量
        const momentum = (prices[prices.length - 1] - prices[prices.length - 10]) 
            / prices[prices.length - 10];

        return [rsi, macd / 1000, bbPosition, volumeChange, momentum];
    }

    /**
     * 標準化特徵
     */
    private normalizeFeatures(features: number[]): number[] {
        // 簡單的 min-max 標準化
        const minMax = [
            [0, 1],           // RSI
            [-1, 1],          // MACD
            [0, 1],          // BB Position
            [-1, 1],         // Volume Change
            [-0.5, 0.5]      // Momentum
        ];

        return features.map((value, index) => {
            const [min, max] = minMax[index];
            return (value - min) / (max - min);
        });
    }
}

/**
 * 組合策略管理器
 */
class StrategyManager {
    private strategies: Map<string, Function> = new Map();

    constructor() {
        // 註冊內置策略
        this.strategies.set('ma_cross', this.maCrossStrategy.bind(this));
        this.strategies.set('rsi', this.rsiStrategy.bind(this));
        this.strategies.set('ml', this.mlStrategy.bind(this));
    }

    /**
     * 移動平均交叉策略
     */
    private maCrossStrategy(prices: number[]): { signal: number; confidence: number } {
        const maShort = this.calculateSMA(prices, 10);
        const maLong = this.calculateSMA(prices, 50);

        if (maShort > maLong * 1.02) return { signal: 1, confidence: 80 };
        if (maShort < maLong * 0.98) return { signal: -1, confidence: 80 };
        return { signal: 0, confidence: 50 };
    }

    /**
     * RSI 策略
     */
    private rsiStrategy(prices: number[]): { signal: number; confidence: number } {
        const rsi = RSI.calculate({ values: prices, period: 14 });
        const currentRSI = rsi[rsi.length - 1];

        if (currentRSI < 30) return { signal: 1, confidence: 70 };
        if (currentRSI > 70) return { signal: -1, confidence: 70 };
        return { signal: 0, confidence: 50 };
    }

    /**
     * ML 策略
     */
    private async mlStrategy(prices: number[]): Promise<{ signal: number; confidence: number }> {
        // ML 策略需要 volumes 數據
        const volumes = new Array(prices.length).fill(1000000);
        const mlGenerator = new MLSignalGenerator();
        
        // 這裡應該加載實際模型
        // await mlGenerator.loadModel('./models/trading_model.h5');
        
        // 返回預設值
        return { signal: 0, confidence: 50 };
    }

    /**
     * 計算 SMA
     */
    private calculateSMA(prices: number[], period: number): number {
        const slice = prices.slice(-period);
        return slice.reduce((a, b) => a + b, 0) / period;
    }

    /**
     * 執行策略
     */
    async execute(strategyName: string, prices: number[], volumes?: number[]): Promise<{
        signal: number;
        confidence: number;
    }> {
        const strategy = this.strategies.get(strategyName);
        if (!strategy) {
            throw new Error(`Strategy ${strategyName} not found`);
        }

        return await strategy(prices, volumes);
    }
}

export { AITradingBot, MLSignalGenerator, StrategyManager };

2.3 訂單執行器

高頻交易執行器

// executor/order-executor.ts - 訂單執行器
import { ethers, BigNumber, Wallet, providers } from 'ethers';

interface Order {
    id: string;
    type: 'BUY' | 'SELL';
    tokenIn: string;
    tokenOut: string;
    amountIn: BigNumber;
    minAmountOut: BigNumber;
    deadline: number;
    gasLimit: number;
}

interface ExecutionResult {
    success: boolean;
    transactionHash?: string;
    actualAmountOut?: BigNumber;
    gasUsed?: BigNumber;
    error?: string;
}

/**
 * 訂單執行器
 */
class OrderExecutor {
    private wallet: Wallet;
    private provider: providers.JsonRpcProvider;
    private gasPriceStrategy: 'fast' | 'standard' | 'economy';
    private maxGasPrice: BigNumber;

    constructor(
        privateKey: string,
        rpcUrl: string,
        gasStrategy: 'fast' | 'standard' | 'economy' = 'fast',
        maxGasPriceGwei: number = 100
    ) {
        this.provider = new providers.JsonRpcProvider(rpcUrl);
        this.wallet = new Wallet(privateKey, this.provider);
        this.gasPriceStrategy = gasStrategy;
        this.maxGasPrice = ethers.utils.parseUnits(maxGasPriceGwei.toString(), 'gwei');
    }

    /**
     * 執行市價單
     */
    async executeMarketOrder(order: Order): Promise<ExecutionResult> {
        try {
            // 估算 Gas 價格
            const gasPrice = await this.estimateGasPrice();
            
            // 估算交易費用
            const feeData = await this.provider.getFeeData();
            const maxFeePerGas = feeData.maxFeePerGas || gasPrice;
            const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas || gasPrice.div(2);

            // 構建交易
            const tx = {
                to: order.tokenIn === ethers.constants.AddressZero ? order.tokenOut : this.getRouterAddress(),
                value: order.tokenIn === ethers.constants.AddressZero ? order.amountIn : BigNumber.from(0),
                gasLimit: order.gasLimit || 200000,
                maxFeePerGas: maxFeePerGas,
                maxPriorityFeePerGas: maxPriorityFeePerGas
            };

            // 發送交易
            console.log(`📤 Sending transaction...`);
            const response = await this.wallet.sendTransaction(tx);

            console.log(`⏳ Waiting for confirmation...`);
            const receipt = await response.wait();

            if (receipt.status === 1) {
                console.log(`✅ Transaction confirmed! Hash: ${receipt.transactionHash}`);
                return {
                    success: true,
                    transactionHash: receipt.transactionHash,
                    gasUsed: receipt.gasUsed
                };
            } else {
                return {
                    success: false,
                    transactionHash: receipt.transactionHash,
                    error: 'Transaction reverted'
                };
            }
        } catch (error: any) {
            console.error(`❌ Execution failed:`, error.message);
            return {
                success: false,
                error: error.message
            };
        }
    }

    /**
     * 執行閃電貸套利
     */
    async executeFlashSwap(
        borrower: string,
        tokenIn: string,
        amountIn: BigNumber,
        path: string[]
    ): Promise<ExecutionResult> {
        const flashLoanExecutor = new ethers.Contract(
            this.getFlashLoanExecutorAddress(),
            [
                'function execute((address token, uint256 amount, bytes data)) external'
            ],
            this.wallet
        );

        const data = ethers.utils.defaultAbiCoder.encode(
            ['address[]', 'address'],
            [path, this.wallet.address]
        );

        try {
            const gasPrice = await this.estimateGasPrice();
            const tx = await flashLoanExecutor.execute(
                [tokenIn, amountIn, data],
                {
                    gasLimit: 500000,
                    gasPrice
                }
            );

            const receipt = await tx.wait();
            return {
                success: receipt.status === 1,
                transactionHash: receipt.transactionHash,
                gasUsed: receipt.gasUsed
            };
        } catch (error: any) {
            return {
                success: false,
                error: error.message
            };
        }
    }

    /**
     * 批量執行訂單
     */
    async batchExecute(orders: Order[]): Promise<ExecutionResult[]> {
        const results: ExecutionResult[] = [];

        for (const order of orders) {
            const result = await this.executeMarketOrder(order);
            results.push(result);

            // 避免觸發速率限制
            await this.sleep(1000);
        }

        return results;
    }

    /**
     * 估算 Gas 價格
     */
    private async estimateGasPrice(): Promise<BigNumber> {
        const feeData = await this.provider.getFeeData();
        let baseGasPrice = feeData.gasPrice || await this.provider.getGasPrice();

        // 根據策略調整
        let multiplier = 1;
        switch (this.gasPriceStrategy) {
            case 'fast':
                multiplier = 1.2;
                break;
            case 'standard':
                multiplier = 1.0;
                break;
            case 'economy':
                multiplier = 0.8;
                break;
        }

        let adjustedPrice = baseGasPrice.mul(Math.floor(multiplier * 100)).div(100);

        // 檢查是否超過最大限制
        if (adjustedPrice.gt(this.maxGasPrice)) {
            adjustedPrice = this.maxGasPrice;
        }

        return adjustedPrice;
    }

    /**
     * 獲取路由器地址(簡化)
     */
    private getRouterAddress(): string {
        return '0xE592427A0AEce92De3Edee1F18E0157C05861564'; // Uniswap V3
    }

    /**
     * 獲取閃電貸執行器地址
     */
    private getFlashLoanExecutorAddress(): string {
        return '0x...'; // 部署的執行器地址
    }

    /**
     * 睡眠函數
     */
    private sleep(ms: number): Promise<void> {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
}

export { OrderExecutor, Order, ExecutionResult };

第三章:風險管理與監控

3.1 實時監控儀表板

監控系統實現

// monitor/dashboard.ts - 監控儀表板
import { ethers } from 'ethers';
import { DiscordWebhook, TelegramBot } from './notification';

interface BotMetrics {
    totalTrades: number;
    profitableTrades: number;
    totalVolume: BigNumber;
    totalProfitLoss: BigNumber;
    averageExecutionTime: number;
    lastTradeTime: number;
}

interface Position {
    token: string;
    size: BigNumber;
    entryPrice: number;
    currentPrice: number;
    pnl: number;
    timestamp: number;
}

/**
 * 交易監控系統
 */
class TradingMonitor {
    private provider: ethers.providers.JsonRpcProvider;
    private metrics: BotMetrics;
    private positions: Map<string, Position> = new Map();
    private alerts: AlertConfig[] = [];
    private discord?: DiscordWebhook;
    private telegram?: TelegramBot;

    constructor(
        rpcUrl: string,
        alertConfig?: { discord?: string; telegram?: string }
    ) {
        this.provider = new ethers.providers.JsonRpcProvider(rpcUrl);
        this.metrics = {
            totalTrades: 0,
            profitableTrades: 0,
            totalVolume: ethers.constants.Zero,
            totalProfitLoss: ethers.constants.Zero,
            averageExecutionTime: 0,
            lastTradeTime: 0
        };

        // 初始化通知渠道
        if (alertConfig?.discord) {
            this.discord = new DiscordWebhook(alertConfig.discord);
        }
        if (alertConfig?.telegram) {
            this.telegram = new TelegramBot(alertConfig.telegram);
        }
    }

    /**
     * 記錄交易
     */
    recordTrade(
        token: string,
        side: 'BUY' | 'SELL',
        size: BigNumber,
        price: number,
        executionTime: number
    ): void {
        this.metrics.totalTrades++;
        this.metrics.totalVolume = this.metrics.totalVolume.add(size);
        this.metrics.averageExecutionTime = 
            (this.metrics.averageExecutionTime * (this.metrics.totalTrades - 1) + executionTime) 
            / this.metrics.totalTrades;
        this.metrics.lastTradeTime = Date.now();

        // 更新倉位
        if (side === 'BUY') {
            this.positions.set(token, {
                token,
                size,
                entryPrice: price,
                currentPrice: price,
                pnl: 0,
                timestamp: Date.now()
            });
        } else {
            const position = this.positions.get(token);
            if (position) {
                const pnl = (price - position.entryPrice) / position.entryPrice;
                this.metrics.totalProfitLoss = this.metrics.totalProfitLoss.add(
                    position.size.mul(ethers.utils.parseUnits(pnl.toString(), 18))
                );
                
                if (pnl > 0) this.metrics.profitableTrades++;
                this.positions.delete(token);

                this.sendNotification(`Position closed: ${side} ${ethers.utils.formatEther(size)} ${token} @ ${price}, PnL: ${pnl * 100}%`);
            }
        }
    }

    /**
     * 更新持倉價格
     */
    async updatePositions(): Promise<void> {
        for (const [token, position] of this.positions) {
            const currentPrice = await this.getPrice(token);
            position.currentPrice = currentPrice;
            position.pnl = (currentPrice - position.entryPrice) / position.entryPrice;
        }
    }

    /**
     * 檢查風險閾值
     */
    checkRiskThresholds(): void {
        // 檢查總虧損
        const totalLoss = this.metrics.totalProfitLoss.lt(ethers.constants.Zero);
        if (totalLoss) {
            const lossAmount = Math.abs(parseFloat(ethers.utils.formatEther(this.metrics.totalProfitLoss)));
            if (lossAmount > 10) { // 超過 10 ETH
                this.sendAlert('HIGH_LOSS', `Total loss exceeds 10 ETH: ${lossAmount}`);
            }
        }

        // 檢查持倉風險
        for (const [token, position] of this.positions) {
            if (position.pnl < -0.1) { // 虧損超過 10%
                this.sendAlert('STOP_LOSS', `Stop loss triggered for ${token}: ${position.pnl * 100}%`);
            }
        }

        // 檢查交易頻率
        const timeSinceLastTrade = Date.now() - this.metrics.lastTradeTime;
        if (timeSinceLastTrade > 3600000) { // 超過 1 小時
            this.sendAlert('INACTIVE', 'No trades in the last hour');
        }
    }

    /**
     * 獲取儀表板數據
     */
    getDashboardData(): {
        metrics: BotMetrics;
        positions: Position[];
        health: string;
    } {
        return {
            metrics: this.metrics,
            positions: Array.from(this.positions.values()),
            health: this.calculateHealth()
        };
    }

    /**
     * 計算健康度
     */
    private calculateHealth(): string {
        if (this.metrics.totalTrades === 0) return 'NEW';
        
        const winRate = this.metrics.profitableTrades / this.metrics.totalTrades;
        
        if (winRate > 0.6) return 'HEALTHY';
        if (winRate > 0.4) return 'NEUTRAL';
        if (winRate > 0.2) return 'WARNING';
        return 'CRITICAL';
    }

    /**
     * 發送通知
     */
    private async sendNotification(message: string): Promise<void> {
        console.log(`📢 Notification: ${message}`);
        
        if (this.discord) {
            await this.discord.send(message);
        }
        
        if (this.telegram) {
            await this.telegram.send(message);
        }
    }

    /**
     * 發送告警
     */
    private async sendAlert(type: string, message: string): Promise<void> {
        const alertMessage = `🚨 ALERT [${type}]: ${message}`;
        console.error(alertMessage);
        
        if (this.discord) {
            await this.discord.send(alertMessage);
        }
        
        if (this.telegram) {
            await this.telegram.send(alertMessage);
        }
    }

    /**
     * 獲取代幣價格(簡化)
     */
    private async getPrice(token: string): Promise<number> {
        // 實際應從價格預言機獲取
        return 2000;
    }
}

interface AlertConfig {
    type: string;
    threshold: number;
    message: string;
}

export { TradingMonitor, BotMetrics, Position };

結論

本文詳細介紹了 AI 交易代理在以太坊上的完整開發實踐,從系統架構設計、智慧合約開發、到 TypeScript 交易機器人實現,提供了一套完整的解決方案。通過風險管理模組和監控系統的整合,構建了一個可實際運行的自動化交易系統。

關鍵要點回顧

  1. 系統架構設計需要考慮可擴展性和容錯性
  2. 智慧合約實現風險控制邏輯,確保資金安全
  3. 交易機器人需要整合市場數據、分析引擎和執行模組
  4. 持續監控和告警是運維的關鍵

後續優化方向

  1. 部署機器學習模型進行更精準的價格預測
  2. 實現多策略組合以分散風險
  3. 整合更多數據源(社交媒體、新聞等)進行情感分析
  4. 優化 Gas 費用策略以降低交易成本
  5. 實現分布式部署以提高系統可用性

風險提示

加密貨幣交易存在極高風險,AI 交易代理並不保證盈利。在實際部署前,請務必在測試網充分測試,並根據自身風險承受能力設定合理的止損和倉位管理規則。

延伸閱讀與來源

這篇文章對您有幫助嗎?

評論

發表評論

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

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