Skip to content

Copy Trade 跟单

概述

Copy Trade(跟单交易)基于 Smart Account(SA)+ TEE 架构,允许用户自动跟随目标钱包地址的链上交易行为,实现跟买、跟卖、止盈止损等自动化策略。本文涵盖前端业务架构与后端技术方案。


一、跟单策略系统

1.1 系统交互全景

sequenceDiagram
    participant User as 用户
    participant API as Strategy API
    participant Trigger as Trigger 引擎
    participant Analysis as 链上解析
    participant Trade as Trade 服务
    participant Vault as Vault 签名

    Note over User,Vault: 创建跟单策略
    User->>API: 创建 Copy Trade Order
    API->>Trigger: 事件:创建跟单索引

    Note over User,Vault: 链上信号触发跟买
    Analysis->>Trigger: 链上交易事件
    Trigger->>Trigger: 匹配跟单策略索引
    Trigger->>Trade: 构建跟买交易
    Trade->>Vault: TEE 签名 + 广播

    Note over User,Vault: 跟买结果处理
    Analysis->>Trade: 链上事件匹配跟买 TxHash
    Trade->>Trigger: 回调跟买结果
    Trigger->>Trigger: 创建 TP/SL + 跟卖订单

    Note over User,Vault: 价格触发止盈止损
    Trigger->>Trade: 构建 TP/SL 交易
    Trade->>Vault: TEE 签名 + 广播

1.2 表单字段定义

Copy Trade 表单字段定义在 FormItemEnum 枚举中,按功能分组:

分组字段说明
基础信息strategyName, trackedWalletAddress策略名称、跟单地址(必填)
购买类型buyTypepercentage(2) / fixedAmount(1)
百分比模式buyPercent, maxBuyAmount, onlyBuyOnce百分比(1-1000)、最大金额、仅买一次
固定金额模式buyAmount, onlyBuyOnce固定金额、仅买一次
卖出设置copySell, isAutoSell跟单卖出、自动卖出
Token 过滤器threshold, minMc/maxMc, minLiquidity/maxLiquidity, minAge/maxAge, blackCoinList目标金额、市值、流动性、代币年龄、黑名单
其他配置expireTime/expireTimeType, serviceFee过期时间(4选1)、服务费(只读)

1.3 策略单下单流程

graph TB
    A["打开弹窗"] --> B{"判断模式"}

    B -->|创建| C["createInit()<br/>Storage 读取预设<br/>并行请求 defaultConfig + tokenList<br/>初始化 AutoSell"]
    B -->|编辑/再跟单| D["editInit()<br/>并行请求 config + tokenList + detail<br/>接口→表单转换<br/>获取代币余额"]

    C --> E["生成初始表单"]
    D --> E

    E --> F["用户点击提交"]

    F -->|创建| G["getParams → 钱包签名 → POST /create"]
    F -->|编辑| H["getParams → 钱包签名 → POST /modify"]
    F -->|再跟单| I["getParams → 钱包签名 → POST /create"]

    G --> J["关闭弹窗<br/>reset Store<br/>保存 Storage"]
    H --> J
    I --> K["保存 Storage<br/>打开成功弹窗"]

二、状态机

2.1 Copy Trade 策略生命周期

stateDiagram-v2
    [*] --> ACTIVE: 用户创建跟单策略
    ACTIVE --> PAUSE: 用户暂停
    ACTIVE --> DELETED: 用户删除
    PAUSE --> ACTIVE: 用户恢复
    PAUSE --> DELETED: 用户删除

2.2 跟买/跟卖订单生命周期

stateDiagram-v2
    [*] --> IN_TRADING: 跟单策略触发执行
    IN_TRADING --> SUCCESS: 执行成功
    IN_TRADING --> FAILED: 执行失败

2.3 TP/SL 订单生命周期

stateDiagram-v2
    [*] --> ACTIVE: 跟买成功后创建

    ACTIVE --> IN_TRADING: 价格触发
    ACTIVE --> CANCELED: 用户删除 / 停止策略 / TEE SA 失效

    IN_TRADING --> SUCCESS: 执行成功
    IN_TRADING --> ACTIVE: 执行失败(可重试)
    IN_TRADING --> FAILED: 执行失败(不可重试)

2.4 Open Order 状态(含 CANCELING)

TP/SL 的 Open Order 增加了 CANCELING 中间状态:

ACTIVE → CANCELING → CANCELED  (用户删除/停止策略)
ACTIVE → CANCELED              (TEE SA 失效,直接取消)
ACTIVE → TRADING → SUCCESS/FAILED

三、PnL 计算体系

3.1 核心公式

指标公式
净持仓max(0, 净持仓_before + 本次交易量)
虚拟持仓min(钱包实际余额, 净持仓)
平均成本(本次买入量 × 本次价格 + 净持仓_before × 旧均价) / (本次买入量 + 净持仓_before)
未实现 PnL (Token)虚拟持仓 × (当前价格 - 平均成本)
已实现 PnL (Trade)min(卖出量, 净持仓_before) × (卖出价格 - 平均成本)

3.2 聚合层级

graph BT
    A["Trade 级别<br/>单笔交易 PnL"] --> B["Token 级别<br/>策略内单币种汇总"]
    B --> C["Strategy 级别<br/>单策略所有币种汇总"]
    C --> D["Copy Trade 级别<br/>用户所有策略汇总"]

每个层级都有对应的 PnL 比例计算:%PnL = $PnL / $total_cost

3.3 已实现 PnL 汇总流程

graph TB
    A["卖出交易结果"] --> B["生成 Strategy Order 消息"]
    B --> C["发送 Kafka<br/>Partition Key: ChainId + WalletAddress"]
    C --> D["Consumer 消费"]
    D --> E["计算已实现 PnL"]
    E --> F["更新 Rollup 聚合表<br/>pnl_sum += 计算结果"]

四、EVM 授权

4.1 Copy Buy 授权

graph TB
    A["创建跟单策略事件"] --> B["请求 Quote Token 授权"]
    B --> C{"授权成功?"}
    C -->|是| D["激活跟单策略"]
    C -->|否| E["创建失败流程"]

4.2 Copy Sell / TP / SL 授权

graph TB
    A["跟买交易结果"] --> B["请求 Base Token 授权"]
    B --> C{"授权成功?"}
    C -->|是| D["创建 Token Position"]
    D --> E["创建 Copy Sell 订单"]
    E --> F["创建 TP/SL 订单"]
    C -->|否| G["处理授权失败"]

五、回滚处理

采用 BSC 延迟 2 秒 方案:

场景SolanaBSC
订单状态流转实时处理实时处理,回滚后糾正
仓位 & Auto Sell 订单创建实时延迟 2 秒
PnL 计算实时延迟 2 秒

BSC 出块时间短,延迟约 2 秒基本不会发生回滚。


六、Open Order 多数据源分页

6.1 背景

新的 JWT 鉴权方式无需端上存储全量订单,改为每次分页查询后端。由于跨区域部署(EU 策略服务 ↔ HK 请求),数据量超过 100KB 时有性能问题,需分页缩小查询量。

6.2 方案:游标分页 + 内存排序

以每页 5 条为例:

步骤一:分别从 Swap 库和 Strategy 库各查 5 条
  Swap:     [1, 2, 3, 4, 5]
  Strategy: [A, B, C, D, E]

步骤二:合并排序,取前 5 条
  排序后: [1, 2, A, B, C, 3, 4, 5, D, E]
  返回:   [1, 2, A, B, C]
  游标:   Swap→2, Strategy→C

步骤三:端上携带游标查下一页
  Swap 从 2 之后查 5 条
  Strategy 从 C 之后查 5 条
  重复步骤二

边界情况处理:

Case说明游标策略
两源都有结果集包含两个数据源各取最后一条点位
只有源A(源B有数据)全部来自源A源A取最后一条,源B取第一条+1
只有源A(源B无数据)源B已耗尽源A取最后一条,源B=null
都无数据无下一页

七、前端 Table 架构

7.1 表格总览

页面表格数据级别分页
DashboardOpenCopyTrade策略级别limit:10, 无分页
DashboardCopyTradeHistory策略级别pageSize:10, 有分页
DetailOpenOrder订单级别pageSize:20, 有分页
DetailHistory订单级别pageSize:20, 有分页
DetailFiltered订单级别pageSize:20, 有分页
DetailTrades订单级别pageSize:20, 有分页

7.2 架构模式(MobX Store)

graph TB
    subgraph 用户交互层
        A["index.tsx 入口"] --> B["Table 组件"]
        B --> C["列定义 Columns"]
    end

    subgraph 状态管理层
        D["MobX Store"]
        D1["Observable<br/>list / loading / cursor / hasNext"]
        D2["Computed<br/>computedList / computedIsEmpty / computedStatus"]
        D --> D1
        D --> D2
    end

    subgraph 业务逻辑层
        E["Action"]
        E1["init() / fetch() / refresh()"]
        E2["WebSocket Handlers"]
        E --> E1
        E --> E2
    end

    subgraph 数据层
        F["dataProxy → API"]
        G["WebSocket 推送"]
    end

    B --> D
    D -.-> E
    E --> F
    G -.-> D

7.3 WebSocket 实时更新

graph TB
    A["WebSocket 推送<br/>eventType + data"] --> B{"事件类型"}

    B -->|CREATE| C["获取订单详情 → list.unshift()"]
    B -->|CHANGE| D{"订单状态"}
    B -->|STATUS_CHANGE| E{"策略状态"}
    B -->|TRIGGER| F["更新 PnL 数据"]

    D -->|已完成| G["从 list 移除"]
    D -->|状态更新| H["获取最新数据 → 更新 list 对应项"]
    E -->|已结束| I["从 list 移除"]
    E -->|状态变更| J["更新 useStatus"]

7.4 策略操作

操作级别API说明
Stop策略POST /updateCopyTradeStatus (useStatus=2)终止策略
Pause策略POST /updateCopyTradeStatus (useStatus=0)暂停策略
Restart策略POST /updateCopyTradeStatus (useStatus=1)需 SA 校验
Edit策略打开编辑抽屉需 SA 校验
Copy Again策略打开创建抽屉需 SA 校验 + 上限检查(10个)
Cancel订单POST /cancel需 JWT 认证

所有 API 操作失败返回 10026 时触发重新认证。


八、UML 类图

classDiagram
    class StrategyAPI {
        +createCopyTradeStrategy()
        +retrievePnL()
    }

    class CopyTradeStrategyLifecycle {
        +createCopyTradeIndex()
        +manageStrategyState()
    }

    class CopyTradeOrderLifecycle {
        +manageOrderState()
    }

    class CopyBuyTrigger {
        +matchOrders()
        +triggerExecution()
    }

    class CopySellTrigger {
        +matchOrders()
        +triggerExecution()
    }

    class CopyBuyResultHandler {
        +handleCopyBuyResult()
    }

    class CopySellResultHandler {
        +handleCopySellResult()
    }

    class PnLImpl {
        +calculatePnL()
        +retrievePnLData()
    }

    StrategyAPI --> CopyTradeStrategyLifecycle
    StrategyAPI --> PnLImpl
    CopyTradeStrategyLifecycle --> CopyTradeOrderLifecycle
    CopyBuyTrigger --> CopyTradeOrderLifecycle
    CopySellTrigger --> CopyTradeOrderLifecycle
    CopyBuyResultHandler --> PnLImpl
    CopySellResultHandler --> PnLImpl

知识图谱

graph TB
    subgraph 策略管理
        A["Copy Trade 策略<br/>跟单地址 + 规则配置"]
        B["表单校验<br/>6组校验规则"]
        C["策略操作<br/>创建/编辑/暂停/删除/再跟单"]
    end

    subgraph 执行引擎
        D["链上信号<br/>DexAnalysis 事件"]
        E["跟买触发<br/>CopyBuyTrigger"]
        F["跟卖/TP/SL<br/>价格触发"]
    end

    subgraph 数据层
        G["PnL 计算<br/>净持仓·虚拟持仓·平均成本"]
        H["多源分页<br/>游标+内存排序"]
        I["Rollup 聚合<br/>已实现PnL汇总"]
    end

    subgraph 前端架构
        J["MobX Store<br/>Observable/Computed/Action"]
        K["WebSocket<br/>实时订单更新"]
        L["JWT 认证<br/>静默签名"]
    end

    A --> E
    D --> E
    E --> F
    F --> G
    G --> I
    H --> J
    K --> J
    L --> J