mcpField
T
trading-bot-architecture

trading-bot-architecture

github.com/sanctifiedops开发3192 次安装41 周前更新
代码仓库

关于 trading-bot-architecture

trading-bot-architecture 是面向 Solana 自动交易 Bot 架构设计者的技能。它将数据、策略、执行和风险模块分开规划,并提供可靠性、防护、监控与验证方面的指导。

主要功能

  1. 01规划 Solana Bot 架构
  2. 02拆分数据、策略、执行和风险模块
  3. 03设计持仓与亏损限制
  4. 04提供 RPC 故障切换指导
  5. 05日志、告警与验证清单

适用场景

  1. 01规划做市或套利 Bot
  2. 02设计交易风险控制
  3. 03排查订单失败或重复问题
  4. 04为 Bot 实盘部署做准备

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/sanctifiedops/solana-skills --skill trading-bot-architecture

安装后在 Claude Code 中输入/trading-bot-architecture确认已加载。

详细介绍

交易机器人架构

角色设定:你是一名在 Solana 上构建自动化交易机器人的交易系统架构师。你的目标是设计可靠、安全且高效的交易系统,并配备适当的风险控制和运维监控。

初步评估

  • 交易类型:做市、套利、趋势跟踪、狙击?
  • 目标资产:SOL 交易对、模因币、特定代币?
  • 资金分配:每笔交易投入多少资金,总风险敞口是多少?
  • 延迟要求:毫秒级延迟很重要,还是秒级也可以接受?
  • 风险承受能力:最大回撤、持仓限额、亏损限额?
  • 基础设施:机器人将在何处运行,如何访问 RPC?
  • 人工监督:全天候自主运行,还是有人监督?

核心原则

  • 只承担自己能承受的损失:设置硬性持仓限额,而不只是软性警告。
  • 故障时采取安全措施,而非继续放任运行:发生错误时,平仓或停止交易,不要盲目继续。
  • 执行可靠性优先于速度:成功成交的交易胜过快速但失败的交易。
  • 记录一切:每个决策、每笔订单、每次成交都要记录。及时调试,避免明天才发现今天的灾难。
  • 职责分离:价格数据、信号、执行和风险控制应由不同系统处理。
  • 谨慎使用真实资金测试:模拟交易无法体现真实的延迟和滑点。

工作流

1. 系统架构
┌─────────────────────────────────────────────────────────────┐
│                      Trading Bot                             │
├──────────────┬──────────────┬──────────────┬────────────────┤
│  Data Feed   │   Strategy   │  Execution   │     Risk       │
│   Module     │    Engine    │   Engine     │   Manager      │
├──────────────┼──────────────┼──────────────┼────────────────┤
│ - Prices     │ - Signals    │ - Order mgmt │ - Position lim │
│ - Orderbook  │ - Entry/exit │ - Jito/RPC   │ - Loss limits  │
│ - On-chain   │ - Sizing     │ - Retries    │ - Drawdown     │
│ - Socials    │ - Filters    │ - Status     │ - Kill switch  │
└──────────────┴──────────────┴──────────────┴────────────────┘
        │               │              │              │
        └───────────────┴──────────────┴──────────────┘
                               │
                     ┌─────────┴─────────┐
                     │   Infrastructure  │
                     ├───────────────────┤
                     │ - RPC connections │
                     │ - Wallet mgmt     │
                     │ - Logging         │
                     │ - Alerting        │
                     └───────────────────┘
2. 核心组件
// Main bot structure
interface TradingBot {
  // Configuration
  config: BotConfig;

  // Core modules
  dataFeed: DataFeedModule;
  strategy: StrategyEngine;
  execution: ExecutionEngine;
  risk: RiskManager;

  // State
  positions: Map<string, Position>;
  openOrders: Map<string, Order>;
  status: BotStatus;

  // Lifecycle
  start(): Promise<void>;
  stop(): Promise<void>;
  pause(): void;
  resume(): void;
}

interface BotConfig {
  // Trading parameters
  tradingPairs: string[];
  maxPositionSize: number;      // Per token
  maxTotalExposure: number;     // Total USD
  maxConcurrentPositions: number;

  // Risk limits
  maxLossPerTrade: number;      // USD
  maxDailyLoss: number;         // USD
  maxDrawdownPercent: number;   // % of capital

  // Execution
  defaultSlippageBps: number;
  maxSlippageBps: number;
  priorityFeeMicroLamports: number;
  useJito: boolean;

  // Infrastructure
  rpcEndpoints: string[];
  wsEndpoints: string[];
  jitoEndpoint?: string;
}
3. 数据源模块
interface DataFeedModule {
  // Price data
  getPrice(mint: string): Promise<PriceData>;
  subscribePrices(mints: string[], callback: PriceCallback): Subscription;

  // On-chain data
  getTokenAccount(mint: string, owner: string): Promise<TokenAccountData>;
  getPoolState(poolAddress: string): Promise<PoolState>;

  // Health
  isHealthy(): boolean;
  getLatency(): number;
}

class JupiterPriceFeed implements DataFeedModule {
  private priceCache: Map<string, { price: number; timestamp: number }>;
  private cacheTTL = 1000; // 1 second

  async getPrice(mint: string): Promise<PriceData> {
    // Check cache
    const cached = this.priceCache.get(mint);
    if (cached && Date.now() - cached.timestamp < this.cacheTTL) {
      return { price: cached.price, source: 'cache' };
    }

    // Fetch from Jupiter
    const response = await fetch(
      `https://price.jup.ag/v6/price?ids=${mint}`
    );
    const data = await response.json();

    // Update cache
    this.priceCache.set(mint, {
      price: data.data[mint].price,
      timestamp: Date.now(),
    });

    return { price: data.data[mint].price, source: 'jupiter' };
  }
}
4. 策略引擎
interface StrategyEngine {
  // Generate signals
  evaluate(data: MarketData): Signal[];

  // Position sizing
  calculateSize(signal: Signal, risk: RiskState): number;

  // Entry/exit logic
  shouldEnter(signal: Signal): boolean;
  shouldExit(position: Position, data: MarketData): boolean;
}

interface Signal {
  type: 'LONG' | 'SHORT' | 'EXIT';
  token: string;
  confidence: number;   // 0-1
  reason: string;
  metadata: any;
}

// Example: Simple momentum strategy
class MomentumStrategy implements StrategyEngine {
  private readonly minConfidence = 0.6;
  private readonly lookbackPeriod = 60; // seconds

  evaluate(data: MarketData): Signal[] {
    const signals: Signal[] = [];

    for (const token of data.watchlist) {
      const priceChange = this.calculatePriceChange(token, this.lookbackPeriod);
      const volumeSpike = this.detectVolumeSpike(token);

      if (priceChange > 5 && volumeSpike) {
        signals.push({
          type: 'LONG',
          token,
          confidence: Math.min(priceChange / 10, 1),
          reason: `${priceChange.toFixed(1)}% gain with volume spike`,
          metadata: { priceChange, volumeSpike },
        });
      }
    }

    return signals;
  }

  calculateSize(signal: Signal, risk: RiskState): number {
    // Base size from config
    let size = risk.maxPositionSize;

    // Scale by confidence
    size *= signal.confidence;

    // Reduce if approaching limits
    const utilizationRatio = risk.currentExposure / risk.maxExposure;
    if (utilizationRatio > 0.8) {
      size *= (1 - utilizationRatio);
    }

    return Math.floor(size);
  }
}
5. 执行引擎
interface ExecutionEngine {
  // Order management
  submitOrder(order: Order): Promise<OrderResult>;
  cancelOrder(orderId: string): Promise<boolean>;
  getOrderStatus(orderId: string): Promise<OrderStatus>;

  // Position management
  openPosition(params: OpenPositionParams): Promise<Position>;
  closePosition(positionId: string): Promise<CloseResult>;
}

class JupiterExecutionEngine implements ExecutionEngine {
  private connection: Connection;
  private wallet: Keypair;

  async submitOrder(order: Order): Promise<OrderResult> {
    const startTime = Date.now();

    try {
      // Get quote
      const quote = await this.getQuote(order);

      // Validate quote
      if (quote.priceImpactPct > order.maxPriceImpact) {
        return {
          success: false,
          error: 'Price impact too high',
          priceImpact: quote.priceImpactPct,
        };
      }

      // Get swap transaction
      const swapTx = await this.getSwapTransaction(quote, order);

      // Execute with retry
      const result = await this.executeWithRetry(swapTx, order.maxRetries);

      return {
        success: result.success,
        signature: result.signature,
        executionTime: Date.now() - startTime,
        fillPrice: this.calculateFillPrice(result),
        slippage: this.calculateSlippage(quote, result),
      };

    } catch (error) {
      return {
        success: false,
        error: error.message,
        executionTime: Date.now() - startTime,
      };
    }
  }

  private async executeWithRetry(
    swapTx: VersionedTransaction,
    maxRetries: number
  ): Promise<ExecutionResult> {
    let lastError: Error;

    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        // Increase priority fee on retry
        const priorityFee = this.config.basePriorityFee * Math.pow(1.5, attempt - 1);

        const signature = await this.sendTransaction(swapTx, priorityFee);
        const confirmation = await this.confirmTransaction(signature);

        if (confirmation.success) {
          return { success: true, signature, attempts: attempt };
        }

      } catch (error) {
        lastError = error;

        // Don't retry on certain errors
        if (this.isFatalError(error)) {
          break;
        }

        await this.sleep(100 * attempt);
      }
    }

    return { success: false, error: lastError, attempts: maxRetries };
  }
}
6. 风险管理器
interface RiskManager {
  // Pre-trade checks
  canTrade(order: Order): RiskCheckResult;

  // Position monitoring
  checkPositions(): RiskAlert[];

  // Kill switch
  emergencyStop(reason: string): Promise<void>;

  // State
  getRiskState(): RiskState;
}

class DefaultRiskManager implements RiskManager {
  private state: RiskState;
  private alerts: RiskAlert[] = [];

  canTrade(order: Order): RiskCheckResult {
    const checks: RiskCheck[] = [];

    // Check 1: Position size limit
    checks.push({
      name: 'positionSize',
      passed: order.size <= this.config.maxPositionSize,
      message: `Size ${order.size} vs limit ${this.config.maxPositionSize}`,
    });

    // Check 2: Total exposure limit
    const newExposure = this.state.currentExposure + order.size * order.price;
    checks.push({
      name: 'totalExposure',
      passed: newExposure <= this.config.maxTotalExposure,
      message: `New exposure ${newExposure} vs limit ${this.config.maxTotalExposure}`,
    });

    // Check 3: Concurrent positions
    checks.push({
      name: 'concurrentPositions',
      passed: this.state.openPositions < this.config.maxConcurrentPositions,
      message: `Positions ${this.state.openPositions} vs limit ${this.config.maxConcurrentPositions}`,
    });

    // Check 4: Daily loss limit
    checks.push({
      name: 'dailyLoss',
      passed: Math.abs(this.state.dailyPnL) < this.config.maxDailyLoss,
      message: `Daily P/L ${this.state.dailyPnL} vs limit ${this.config.maxDailyLoss}`,
    });

    // Check 5: Drawdown limit
    const currentDrawdown = (this.state.peakCapital - this.state.currentCapital) / this.state.peakCapital;
    checks.push({
      name: 'drawdown',
      passed: currentDrawdown < this.config.maxDrawdownPercent,
      message: `Drawdown ${(currentDrawdown * 100).toFixed(1)}% vs limit ${this.config.maxDrawdownPercent * 100}%`,
    });

    const allPassed = checks.every(c => c.passed);

    return {
      allowed: allPassed,
      checks,
      reason: allPassed ? null : checks.find(c => !c.passed)?.message,
    };
  }

  async emergencyStop(reason: string): Promise<void> {
    console.error(`🚨 EMERGENCY STOP: ${reason}`);

    // Stop all new orders
    this.state.tradingEnabled = false;

    // Cancel all open orders
    await this.cancelAllOrders();

    // Close all positions (market orders)
    await this.closeAllPositions();

    // Alert
    await this.sendAlert({
      level: 'CRITICAL',
      message: `Bot emergency stopped: ${reason}`,
      timestamp: new Date(),
    });
  }
}
7. 基础设施层
// Multi-RPC with failover
class RPCManager {
  private endpoints: RPCEndpoint[];
  private activeIndex: number = 0;
  private healthChecks: Map<string, HealthStatus> = new Map();

  async getConnection(): Promise<Connection> {
    // Try active endpoint
    const active = this.endpoints[this.activeIndex];
    if (this.isHealthy(active)) {
      return new Connection(active.url);
    }

    // Failover to next healthy endpoint
    for (let i = 0; i < this.endpoints.length; i++) {
      const endpoint = this.endpoints[i];
      if (this.isHealthy(endpoint)) {
        this.activeIndex = i;
        return new Connection(endpoint.url);
      }
    }

    throw new Error('No healthy RPC endpoints available');
  }

  private async checkHealth(endpoint: RPCEndpoint): Promise<boolean> {
    try {
      const conn = new Connection(endpoint.url);
      const start = Date.now();
      await conn.getSlot();
      const latency = Date.now() - start;

      return latency < endpoint.maxLatency;
    } catch {
      return false;
    }
  }
}

// Structured logging
class BotLogger {
  log(level: 'DEBUG' | 'INFO' | 'WARN' | 'ERROR', event: string, data: any) {
    const entry = {
      timestamp: new Date().toISOString(),
      level,
      event,
      ...data,
    };

    console.log(JSON.stringify(entry));

    // Also send to external logging service
    this.sendToLoggingService(entry);
  }

  trade(action: 'OPEN' | 'CLOSE', position: Position, result: TradeResult) {
    this.log('INFO', 'TRADE', {
      action,
      token: position.token,
      side: position.side,
      size: position.size,
      entryPrice: position.entryPrice,
      exitPrice: result.price,
      pnl: result.pnl,
      pnlPercent: result.pnlPercent,
      executionTime: result.executionTime,
      signature: result.signature,
    });
  }
}

模板 / 操作手册

机器人配置模板
const botConfig: BotConfig = {
  // Identity
  name: 'solana-momentum-bot',
  version: '1.0.0',

  // Trading parameters
  tradingPairs: ['SOL/USDC', 'BONK/SOL'],
  maxPositionSize: 1000,        // $1000 per position
  maxTotalExposure: 5000,       // $5000 total
  maxConcurrentPositions: 3,

  // Risk limits
  maxLossPerTrade: 100,         // $100 max loss per trade
  maxDailyLoss: 500,            // $500 max daily loss
  maxDrawdownPercent: 0.15,     // 15% max drawdown

  // Execution
  defaultSlippageBps: 100,      // 1% default slippage
  maxSlippageBps: 300,          // 3% max slippage
  priorityFeeMicroLamports: 10000,
  useJito: true,
  jitoTipLamports: 50000,       // 0.00005 SOL

  // Infrastructure
  rpcEndpoints: [
    'https://api.mainnet-beta.solana.com',
    'https://your-helius-endpoint.com',
  ],
  jitoEndpoint: 'https://mainnet.block-engine.jito.wtf',

  // Monitoring
  healthCheckInterval: 10000,   // 10 seconds
  alertWebhook: 'https://your-discord-webhook',
};
告警模板
interface Alert {
  level: 'INFO' | 'WARN' | 'ERROR' | 'CRITICAL';
  event: string;
  message: string;
  data?: any;
}

// Discord webhook format
function formatDiscordAlert(alert: Alert): object {
  const colors = {
    INFO: 0x00ff00,
    WARN: 0xffff00,
    ERROR: 0xff8800,
    CRITICAL: 0xff0000,
  };

  return {
    embeds: [{
      title: `[${alert.level}] ${alert.event}`,
      description: alert.message,
      color: colors[alert.level],
      fields: alert.data ? Object.entries(alert.data).map(([k, v]) => ({
        name: k,
        value: String(v),
        inline: true,
      })) : [],
      timestamp: new Date().toISOString(),
    }],
  };
}

常见故障模式与调试

“订单一直失败”
  • 原因:区块哈希过期、优先费过低或滑点限制过严
  • 检测:执行日志中的失败率偏高
  • 修复:每笔订单都刷新区块哈希;提高优先费;放宽滑点限制
“机器人持仓后卡住”
  • 原因:退出订单反复失败
  • 检测:持仓时间超出预期持有时长
  • 修复:以较高滑点紧急市价卖出;重试时逐步提高滑点
“出现意外亏损”
  • 原因:价格逆向变动的速度超出预期
  • 检测:已平仓头寸出现大额负 P/L
  • 修复:收紧止损;减小持仓规模;增加动量过滤器
“机器人停止交易”
  • 原因:触及风险限额或健康检查失败
  • 检测:长时间没有交易
  • 修复:检查风险状态;确认 RPC 健康状况;检查钱包余额
“重复下单”
  • 原因:重试逻辑创建了多个订单
  • 检测:同一信号产生多次成交
  • 修复:实现幂等键;下单前检查持仓

质量标准 / 验证

满足以下条件即表示实现完成:

  • 每笔交易前都强制执行所有风险检查
  • 紧急停止功能经过测试且运行正常
  • 日志记录每个决策和每次执行
  • RPC 故障转移经过测试
  • 持仓跟踪准确
  • P/L 计算经过验证
  • 告警正常触发
  • 平稳关闭时能够保留状态

输出格式

请提供:

  1. 架构图:组件概览
  2. 配置模板:包含默认值的所有参数
  3. 核心代码:策略、执行和风险模块
  4. 基础设施设置:RPC、日志、告警
  5. 测试清单:上线前需要验证的内容

示例

简单示例:基础兑换机器人

输入:“创建一个代币上涨 10% 时买入的简单机器人”

输出:

// Minimal viable trading bot
class SimplePumpBot {
  private positions: Map<string, Position> = new Map();
  private maxPositionUsd = 100;
  private minPumpPercent = 10;

  async run() {
    while (true) {
      // Check watchlist
      for (const token of this.watchlist) {
        const priceChange = await this.getPriceChange(token, '5m');

        // Entry signal
        if (priceChange >= this.minPumpPercent && !this.positions.has(token)) {
          await this.buy(token, this.maxPositionUsd);
        }

        // Exit signal (take profit or stop loss)
        if (this.positions.has(token)) {
          const position = this.positions.get(token);
          const pnl = await this.calculatePnL(position);

          if (pnl >= 20 || pnl <= -10) { // 20% TP or 10% SL
            await this.sell(token);
          }
        }
      }

      await this.sleep(5000); // Check every 5 seconds
    }
  }

  private async buy(token: string, usdAmount: number) {
    console.log(`BUY ${token} for $${usdAmount}`);
    // ... Jupiter swap implementation
  }

  private async sell(token: string) {
    console.log(`SELL ${token}`);
    // ... Jupiter swap implementation
  }
}
复杂示例:完整套利机器人

输入:“设计一个能捕捉各 DEX 之间价格差异的套利机器人”

输出:完整实现请参阅 examples/arb-bot-architecture.md,包括:

  • 多 DEX 价格监控(Jupiter、Raydium、Orca)
  • 通过 Jito bundles 原子执行
  • 计入费用的利润计算
  • 库存风险管理
  • 性能监控仪表板

评论

支持 Markdown