第 8 章 · 04 实盘执行链路


文档摘要

第 8 章 · 04 实盘执行链路 本节摘要:本节把第 02 节的 、第 03 节的 ,加上查询持仓的 ,串成一条完整的实盘执行链路——从「想知道钱包有什么」到「真的完成一笔链上兑换」。整条链是:Agent 或脚本调用 看持仓 → 决定兑什么 → 拿未签名交易+报价 → 签名广播 → 拿到链上成交回执。本节还会讲清一个现实问题:这条链路虽然代码正确,却没有被任何 Agent 真正接入—— 的四个专家没一个绑定 ultratools, 收录了它们但没人调;而且整条链没有任何前置风控(不查金额上限、不审计路由、不防夹子),Agent 一旦决定交易就直奔签名。读完本节,你既会跑通这条链,也清楚它的危险缺口。 内容来源:原项目源码 的 + 整链串接,精读并套用体系化模板。

第 8 章 · 04 实盘执行链路

本节摘要:本节把第 02 节的 get_order、第 03 节的 execute_trade,加上查询持仓的 get_holdings,串成一条完整的实盘执行链路——从「想知道钱包有什么」到「真的完成一笔链上兑换」。整条链是:Agent 或脚本调用 get_holdings 看持仓 → 决定兑什么 → get_order 拿未签名交易+报价 → execute_trade 签名广播 → 拿到链上成交回执。本节还会讲清一个现实问题:这条链路虽然代码正确,却没有被任何 Agent 真正接入——workers.py 的四个专家没一个绑定 ultra_tools,get_tools() 收录了它们但没人调;而且整条链没有任何前置风控(不查金额上限、不审计路由、不防夹子),Agent 一旦决定交易就直奔签名。读完本节,你既会跑通这条链,也清楚它的危险缺口。

内容来源:原项目源码 autohedge/tools/ultra_tools.pyget_holdings + 整链串接,精读并套用体系化模板。

⚠️ 风险提示:这是全项目唯一真实动钱的链路。务必用测试钱包、小额、在测试网或主网丢点零钱试。没有任何风控闸门,Agent/脚本给什么参数就签什么,填错金额或 mint 直接成交,无法撤销。

学习目标

阅读完本节,你应当能够:

  1. 逐行读懂 get_holdings(查持仓)。
  2. 画出从「查持仓 → 取报价 → 签名广播 → 核对成交」的完整实盘链路
  3. 解释为什么这条链没被任何 Agent 接入(workers.py 里没绑定)。
  4. 指出链路上缺失的风控环节(金额上限/路由审计/防夹子/白名单)。
  5. 写出一段能真实跑通(测试网、小额)的最小调用脚本。

一、get_holdings:查钱包持有什么

get_holdings(ultra_tools.py 第 241-282 行)是这条链路的起点——先看钱包里有什么,才能决定兑什么:

def get_holdings(address: str) -> str: """ Get token balances and SOL balance for a wallet address (Jupiter Ultra). ... """ if not address or not address.strip(): raise ValueError("address is required") url = f"{JUPITER_ULTRA_BASE}/holdings/{address.strip()}" try: with httpx.Client(timeout=10) as client: resp = client.get(url, headers=_headers() or None) resp.raise_for_status() return json.dumps(resp.json()) except httpx.HTTPError as e: logger.error(f"Jupiter Ultra holdings request failed: {e}") raise

逐行:

  • 入参 address:要查的钱包地址(Solana 公钥 base58)。注意这里不需要私钥——查别人的持仓也可以(链上数据公开),只要地址。所以 get_holdings 和 get_order/execute_trade 不同,它不调 _get_wallet_pubkey(),直接吃外部传的地址。
  • 端点:GET /ultra/v1/holdings/{address}——Jupiter 把「这个地址有多少 SOL、有哪些代币、各多少」一次返回。
  • 超时 10 秒:和 price 工具一样短——查持仓是轻量读操作。
  • 鉴权:同样 _headers() 可选加 JUPITER_API_KEY
  • 失败 raise:HTTP 错误往上抛(和 price/search 一致,和 yahoo 的「返回 {}」不同)。

返回结构大致:

{ "amount": "1500000000", "uiAmount": 1.5, "uiAmountString": "1.5", "tokens": { "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": [ { "account": "...", "amount": "2000000", "uiAmount": 2.0, "uiAmountString": "2.0", "isFrozen": false, "decimals": 6 } ] } }
  • 顶层:SOL 余额,amount 是 lamports(1.5 SOL = 1.5e9 lamports),uiAmount 是人类单位。
  • tokens:代币账户 map,key 是 mint 地址,value 是该 mint 下所有代币账户的数组(一个钱包可能有多个 USDC 账户)。
  • isFrozen:代币账户是否被冻结(冻结状态下不能转)。

💡 查 vs 动的分离:get_holdings 只读,任何人查任何地址都行;get_order/execute_trade 要动钱,必须私钥。这条链路上「查」和「动」用不同的权限模型,是 Solana 公开账本的安全设计。

二、三个工具的分工

把三个工具放在链路里看分工:

工具 动作 要私钥吗 副作用
get_holdings 查持仓 ❌(只要地址) 无(只读)
get_order 拿未签名交易+报价 ❌(只要地址) 无(只是报价单)
execute_trade 签名+广播 ✅(要 SOLANA_PRIVATE_KEY) 真实动钱

这条链的风险完全集中在 execute_trade——前两步怎么调用都安全(最多浪费 API 额度),只有 execute_trade 一签,链上就动了。所以风控闸门必须加在 execute_trade 之前(本节末详述)。

三、完整实盘链路

把三步串起来,一笔「用 0.01 SOL 换 USDC」的完整链路:

每一步的代码片段(精简,真实可跑):

import json from autohedge.tools.ultra_tools import get_holdings, get_order, execute_trade MY_ADDR = "你的钱包地址" SOL = "So11111111111111111111111111111111111111112" USDC = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" # ① 查持仓 print(json.loads(get_holdings(MY_ADDR))) # ② 取报价(0.01 SOL = 10_000_000 lamports) order = json.loads(get_order(SOL, USDC, "10000000")) print("预计得 USDC:", order.get("outAmount"), "路由:", order.get("routePlan")) # ③ 签名广播 result = execute_trade(order["transaction"], order["requestId"]) print("成交:", json.loads(result))

这段代码在配置好 SOLANA_PRIVATE_KEYJUPITER_API_KEY、且钱包有 0.01 SOL + gas 的情况下,真的会成交。务必先在测试网/小额验证。

四、成交回执的核对

execute_trade 返回的 JSON(第 177-179 行 docstring 列了字段):

{ "status": "Success", "signature": "5KJ2...链上交易哈希...", "slot": 234567890, "totalInputAmount": "10000000", "totalOutputAmount": "...", "inputAmountResult": "...", "outputAmountResult": "...", "swapEvents": [...] }

核对要点:

  • status:SuccessFailed。Failed 时看 error/code 字段。
  • signature:链上交易哈希,可以用 Solana 浏览器(如 solscan.io)查这笔交易的完整链上记录。这是「这笔交易真的上链了」的证据。
  • slot:出块高度,可用于判断确认深度。
  • totalInputAmount / totalOutputAmount:实际成交的输入/输出量。和 get_order 的预估 outAmount 比,差额就是滑点。
  • swapEvents:链上各跳兑换事件的明细。

生产环境必须做「成交核对」:status==SuccesstotalOutputAmount 在可接受滑点范围内,才算这单成功。本项目完全没做这个核对,execute_trade 返回即结束。

五、整条链如何被 Agent 触发——其实没接

现在讲本节最重要的现实:这条链路代码正确,但在 AutoHedge 里没有被任何 Agent 触发。证据来自 workers.py(第 26-69 行):

sentiment_agent = Agent(..., tools=[exa_search]) # 只有 exa_search risk_agent = Agent(..., model_name="gpt-4.1") # 无 tools execution_agent = Agent(..., model_name="gpt-4.1") # 无 tools ← 本该下单的 Agent! quant_agent = Agent(..., model_name="gpt-4.1") # 无 tools

观察:

  1. execution_agent(执行 Agent)本应是下单的专家,但它没有 tools 参数——既没绑 execute_trade,也没绑 get_order/get_holdings。它只会用 LLM 写一段订单结构的文字(订单类型/数量/入场价/止损/止盈),不会真的下单。
  2. get_tools() 收录了 ultra_tools 三件套,但(第 6 章已指出)没有任何 Agent 调用 get_tools()
  3. 没有任何 prompt 引导 Agent 调用 ultra_tools——EXECUTION_PROMPT 让它「生成订单」,不是「调用工具执行」。

结论:AutoHedge 的 Solana 实盘链路只能由外部脚本显式调用(像上面的最小脚本),不会在「Director → 专家」的多 Agent 流程里自动发生。README 宣称的「Full autonomous trading on Solana」在主流程里并未实现——链路存在,但没接到 Agent 大脑上。

⚠️ 现实澄清:这正是第 1 章的判断在链路层面的印证:工具存在、签名正确,但「手」(工具)和「脑」(Agent)之间没有神经连上。要让它自主交易,得给 execution_agent 绑 tools=[get_order, execute_trade, get_holdings],并在 prompt 里明确「当你决定交易时,先 get_holdings、再 get_order、最后 execute_trade」——但这些都没做。

六、无前置风控的现实

假设我们补上 Agent 绑定,让 execution_agent 能调 execute_trade——下一个致命问题是:整条链没有任何前置风控。代码里:

  • ❌ 没有金额上限:Agent 传 amount="99999999999999" 也会照签。
  • ❌ 没有白名单 mint:Agent 传一个蜜罐代币的 mint,也会照签(买完即归零)。
  • ❌ 没有路由审计:get_order 返回的 routePlan 涉及哪些 DEX,没检查是否可信。
  • ❌ 没有滑点上限:outAmount 再低也照签(被三明治攻击)。
  • ❌ 没有频率限制:Agent 短时间疯狂下单不会被拦。
  • ❌ 没有人工确认闸门:execute_trade 一调即签即广播,无「确认」环节。

execute_trade 本身只检查「transaction 和 request_id 非空」「私钥有效」——和金额、对手、路由完全无关。这是个干净的签名机器,但不带任何判断。

生产级风控应在这条链上加的闸门:

get_order 之后、execute_trade 之前: ├─ 金额 ≤ 配置上限? ├─ mint 在白名单? ├─ routePlan 的 DEX 都可信? ├─ outAmount 滑点 ≤ 阈值? ├─ 钱包余量足够(别把全部 SOL 兑光,留 gas)? ├─ 频率未超限? └─ (大额)人工二次确认?

任何一条不过,拒绝 execute_trade。本项目这些都没有——这是它不能直接实盘的根本原因之一(第 10 章详讲)。

七、错误处理与重试

整条链的错误处理较粗:

工具 失败行为
get_holdings raise httpx.HTTPError(网络/HTTP 错)
get_order raise ValueError(参数错)或 raise httpx.HTTPError(网络)
execute_trade raise ValueError(参数/格式错)或 raise httpx.HTTPError(广播失败)

注意没有任何自动重试——网络抖动一次就抛异常。对于查持仓/取报价,失败重试是安全的;对于 execute_trade,重试要小心(可能重复下单),应基于 requestId 幂等判断。本项目两者都没做重试,留给调用方自行处理。

链上交易失败(如滑点保护触发)时,Jupiter 的 /execute 返回 status: "Failed" 而非 HTTP 错误——所以 execute_trade 不会 raise,会返回带 Failed 的 JSON。调用方必须自己检查 status 字段,不能光看有没有异常。本项目示例脚本没有这个检查。

八、一条能跑的最小链路(测试用)

给一个带基本核对和风控雏形的最小脚本,供学习:

import json, os from autohedge.tools.ultra_tools import get_holdings, get_order, execute_trade MY_ADDR = os.getenv("MY_WALLET_ADDR") SOL = "So11111111111111111111111111111111111111112" USDC = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" AMOUNT_LAMPORTS = "10000000" # 0.01 SOL MAX_SLIPPAGE_BPS = 100 # 1% 滑点上限(自行核对用) # ① 查持仓 holdings = json.loads(get_holdings(MY_ADDR)) if int(holdings.get("amount", 0)) < int(AMOUNT_LAMPORTS) + 5000000: # 留 0.005 SOL 当 gas raise SystemExit("SOL 不足或没留 gas") # ② 取报价 order = json.loads(get_order(SOL, USDC, AMOUNT_LAMPORTS)) expected_out = int(order.get("outAmount", 0)) print("预计得 USDC 最小单位:", expected_out) # ③ [风控闸门示例] 这里应加白名单/滑点/金额上限检查,本项目没有 # ④ 签名广播 result = json.loads(execute_trade(order["transaction"], order["requestId"])) if result.get("status") != "Success": raise SystemExit(f"链上失败: {result}") print("成交,signature:", result["signature"])

这个脚本至少加了「余额/gas 检查」和「成交 status 核对」两个本项目缺失的环节,但仍远不够生产级(没白名单、没滑点核对、没人工确认)。

本节要点回顾

  1. get_holdings:GET /ultra/v1/holdings/{address},返回 SOL 余额(lamports)+ 代币账户 map;只要地址不要私钥,任何人查任何地址(链上公开)。
  2. 三个工具分工:get_holdings(查,只读)/get_order(报价,不花钱)/execute_trade(签名,真实动钱);风险全集中在 execute_trade。
  3. 完整链路:查持仓 → 决策 → get_order 拿未签名tx+requestId → 核对 → execute_trade 签名广播 → 核对 status/signature/totalOutputAmount。
  4. 没被 Agent 接入:execution_agent 没绑 tools,get_tools() 没人调;链路只能由外部脚本触发,README 的「自主交易」在主流程未实现。
  5. 无前置风控:execute_trade 不检查金额/mint/路由/滑点/频率,只校验参数非空和私钥;Agent 传什么就签什么——生产必须加白名单+滑点+上限+人工确认闸门。
  6. 错误处理粗放:网络错直接 raise,无自动重试;链上失败返回 status=Failed 而非异常,须自行检查 status。
  7. 成交核对缺失:status/signature/totalOutputAmount 都要核对,本项目示例脚本完全没做。

至此第 8 章结束——你彻底理解了 AutoHedge 唯一真实动钱的链路:账户模型、Jupiter API、签名流程、整链串接。下一章我们看 experimental/ 目录下三段实验性代码:做市策略、BTC 地址监控、外部 Agent 封装。


发布者: 作者: 灏天文库 转发
评论区 (0)
U