一、Robinhood 链带来的这一波
Robinhood 链上线以后,链上交易明显热了起来。新币持续上线,池子一个接一个建起来,股票代币、meme 币、稳定币池同时活跃。热度也没有停留在一条链上:资金和用户在 Robinhood、Solana、BSC 之间来回流动,Solana 和 BSC 上的新币和流动性池也跟着活跃起来,有点鲶鱼效应的意思。
这一波行情的主战场是一级市场:币刚上线、池子刚建好,中心化交易所还没上,机会都在链上。用户的需求很具体:
- 在链上第一时间买到新币,卖出时不被滑点吃掉;
- 给新池子提供流动性,赚交易手续费;
- 在几条链、几个池子之间比较,哪里价格更好、手续费更高;
- 而且最好都能写成策略,自动执行、统一记账。
发明者很早就支持 Web3,方式是一个统一的接口:通过 exchange.IO 连接节点、调用合约。这个接口很灵活,理论上什么都能做,但对大多数用户来说门槛太高。想在 Uniswap 上换一次币,要自己查合约地址、编码 ABI、处理代币授权、算滑点、估 Gas、等交易确认;想提供一次集中流动性,还要换算 tick、计算两种代币的配比、管理仓位 NFT。更麻烦的是每条链、每家 DEX 都不一样:Uniswap 有 V2、V3、V4,PancakeSwap 有自己的 Infinity,Aerodrome 有 basic 池和 Slipstream,Solana 上又是 Meteora、Raydium、Orca 另一套体系。真正写策略的时间,大部分花在了和合约打交道上。
二、这次补全了什么
这次我们把 DEX 模块整体补全了。思路是:不再让用户直接面对合约,而是把每家 DEX 做成一个交易所对象,像接入中心化交易所一样接入,再为链上特有的操作提供专门的函数。
添加交易所时选好链和钱包,之后在策略里就是熟悉的写法:GetTicker 取价格,GetAssets 查余额,Buy / Sell / CreateOrder 下单。授权、路由、滑点、Gas、交易确认由平台处理。需要精细控制时,可以通过参数指定路由版本(v2 / v3 / v4)、费率档位和具体池子。新上线几小时的币,平台币种表里还没有,用一行 exchange.IO("token", 名称, 合约地址) 登记进来,就能像普通交易对一样交易。
| 类型 | 交易所 | 说明 | 文档 |
|---|---|---|---|
| Swap / 聚合路由(新) | Uniswap(含 PancakeSwap、Aerodrome、Velodrome 等)、KyberSwap、1inch、OKX DEX、Jupiter | 链上买卖、指定路由与池子;Uniswap 系与 Jupiter 支持集中流动性 LP | Uniswap、KyberSwap、1inch、OKX DEX、Jupiter |
| 链上永续 / 现货订单簿(更新) | Hyperliquid、Lighter、edgeX、Aster、Aevo、WOOFi Pro | 用法接近中心化交易所,持仓、保证金、成交均价、条件单等字段口径对齐 | Hyperliquid、Lighter、edgeX、Aster、Aevo、WOOFi Pro |
| 收益率 / 利率交易 | Pendle、Boros(Futures_Boros) | Pendle 交易 PT / YT,按收益率定价;Boros 在链上订单簿交易永续合约的资金费率 | Pendle 与 Boros |
各交易所支持哪些函数,可以在能力矩阵里对照查看。
对一级市场用户来说,补全之后最直接的变化是三点:
- 一套写法跨链跨 DEX。同一份策略,交易所换成 Robinhood 上的 Uniswap、BNB Chain 上的 PancakeSwap 或 Solana 上的 Jupiter,函数和字段都一样,只是链和池子不同。
- 新币即登记即交易。不用等平台收录,拿到合约地址(Solana 上是 mint 地址)就能报价、下单、做市。
- 流动性做市(LP)有了专门的函数。找池子、定区间、建仓、领手续费、撤出,各有一个
lp.*函数,原来要自己换算的 tick、配比、授权都收进了函数里。
下面用一个 LP 示范策略,把这些能力串起来看一遍。先花两分钟说说 LP 是怎么回事。
三、先花两分钟理解 LP
DEX 上没有传统的买卖挂单,交易是和“池子”完成的。池子里放着两种币,比如 CASHCAT 和 WETH,谁想买 CASHCAT,就把 WETH 放进池子、把 CASHCAT 拿走,同时付一笔手续费(这个池子是 1%)。池子里的币来自 LP,手续费也按份额分给 LP。
Uniswap V3 之后有了集中流动性:LP 可以只在自己选定的价格区间里提供流动性。一个仓位在不同价格下装的东西不一样:
- 价格在区间内:仓位里两种币都有,每笔经过这个区间的交易都会付给你手续费。
- 价格往下跌:别人不断把代币卖给池子,你的仓位在一路买入代币;跌破下沿时,仓位里全部是代币。
- 价格往上涨:反过来,你的仓位在一路卖出代币;涨破上沿时,全部变成计价币。
所以一个 LP 仓位可以理解为一张自动执行的“低买高卖”挂单,成交时还能收手续费:
- 收入是手续费。价格在区间里来回波动越多,收的手续费越多;区间越窄,资金越集中,分到的比例越高。
- 风险是单边行情。一路跌穿区间,手里全是代币;一路涨穿区间,早早把代币卖光了。相对“一直拿着不动”的差额,就是常说的无常损失。
做 LP 赚不赚钱,本质上是一道算术题:手续费收入能不能超过价格波动带来的损失。
3.1 平台提供的 LP 函数
lp.* 函数对应一个 LP 仓位从找池子到撤出的完整过程,统一通过 exchange.IO("lp.xxx", ...) 调用。Uniswap 系(含 PancakeSwap、Aerodrome 等)和 Jupiter(Solana 上的 Meteora DLMM、Raydium CLMM、Orca)用的是同一组函数名和返回字段:
| 函数 | 作用 | 主要返回 |
|---|---|---|
lp.pools(代币[, 计价币]) | 列出该币的池子;不传计价币时列出全部计价币的池子 | 协议、费率档、TVL、24h 成交额与手续费、现价、是否空池 |
lp.select(代币, 预算[, 选项]) | 按规则自动挑一个池子 | 一个池子 + 选择理由 |
lp.pool(池子 ID) / lp.ticks(...) | 池子实时状态 / 各价格段的流动性分布 | tick(或 bin)、价格、流动性 |
lp.plan(参数) | 按预算、区间、形状生成建仓计划(只读,不发交易) | 每档上下沿与数量、是否需换币、占池比例、预估日手续费 |
lp.simulate(计划) | 不签名,模拟执行建仓交易 | 模拟得到的仓位 |
lp.add(计划) | 换币、授权、添加流动性 | 交易哈希、各仓位 ID 与区间 |
lp.increase / lp.decrease | 给仓位加仓 / 按比例减仓 | 交易哈希、收到的币 |
lp.collect(仓位 ID 列表[, 卖出]) | 领取手续费,可直接卖成计价币 | 领到的手续费 |
lp.remove(仓位 ID 列表[, 比例[, 卖出]]) | 撤出流动性并领取手续费,可直接卖成计价币 | 撤回的本金与手续费 |
lp.positions([过滤[, 钱包]]) | 查询钱包里的仓位 | 区间、是否在区间内、两币数量、价值、未领手续费 |
lp.track(仓位 ID 列表) | 登记 V4 等仓位,便于查询 | 已登记的 ID |
Aerodrome / Velodrome 还额外提供 lp.stake、lp.unstake、lp.claim,用于质押仓位领取奖励。完整参数见文档 Uniswap · 集中流动性(LP) 和 Jupiter。
四、示范策略:web3 流动性做市
我们用这些函数写了一个示范策略「web3 流动性做市示范策略」。它不是全自动的黑盒,而是把一轮 LP 拆成几个清楚的步骤:选池 → 配置头寸 → 看规划和情景分析 → 建仓 → 领取手续费 / 减仓 / 撤池子。建仓、领取、撤出都由状态栏按钮手动触发,策略负责计算、展示、换币、记账,并把每一步写进日志。
参数只有三个:币种(已收录的填名称,新币填“名称,合约地址”)、每次投入的金额、是否实盘。不勾实盘就是模拟:只读链上数据,仓位在本地按 Uniswap 公式记账,不发任何交易。
整体流程和每一步用到的函数:
4.1 识别链、登记新币
启动时先识别当前交易所在哪条链,据此确定资金币和 Gas 币:Robinhood 用 USDG,BNB Chain 用 USDT,其余链和 Solana 用 USDC。Uniswap 系通过 contracts 读链信息,Jupiter 按交易所名识别为 Solana。然后登记新币、读现价和钱包:
javascript
var ct = exchange.IO("contracts") // chainId、链名、常用合约
exchange.IO("token", "CASHCAT", "0x020bfc650a365f8bb26819deaabf3e21291018b4") // 名称 + 合约地址
var ticker = exchange.GetTicker() // 链上现价
var assets = exchange.GetAssets() // 钱包余额
启动日志把这些逐条写清楚:哪条链、资金币和 Gas 币、新币是否登记成功、现价、钱包余额、当前是模拟还是实盘;实盘时余额不够或 Gas 偏少会直接提示。
4.2 选池:一个币的全部池子
一级市场的新币,往往同时有好几个池子:不同计价币(USDG、WETH、原生 ETH)、不同协议版本、不同费率档。lp.pools 不传计价币时,会把该币所有计价币的池子都列出来:
javascript
var pools = exchange.IO("lp.pools", "CASHCAT") // 不限计价币
pools.forEach(function (p) {
if (p.empty) return // 现价附近没有流动性的空池
p.dailyYield = p.fees24hUsd / p.tvlUsd * 100 // 日费率:每 1 美元一天分到多少手续费
})
LP 赚的是手续费,所以比的不是成交量,而是日费率 = 24 小时手续费 / TVL。策略把有效池子按计价币分页列表:费率档、现价(非资金币计价的同时折算成资金币)、TVL、24h 成交与手续费、日费率、年化、日周转,以及按默认头寸估算的“本次投入预估日收益”。空池单独排除。
实盘里 CASHCAT 扫出多个有效池子(USDG、WETH、ETH)。WETH 计价的 1% 池子 TVL 最深,约 250 万美元。
池子的计价币不是资金币(比如 CASHCAT/WETH)也可以直接选:建仓时策略先用钱包里已有的 WETH,不够的部分用 USDG 自动兑换;撤出后再把 WETH 换回 USDG,盈亏统一按资金币记账。这类跨计价币的操作,在原来需要自己串好几笔合约调用,现在就是一次 Buy / Sell。
4.3 配置头寸,看规划和情景分析
在池子上点“配置头寸”,设置三样东西:
- 流动性分布:均匀 Spot、中心集中 Curve、两端集中 Bid-Ask;
- 区间:相对现价的下沿和上沿,上沿填负数表示只在现价下方分批挂“买单”;
- 档数:均匀分布时把区间按对数价格等分成几档。
确认后策略立即调用 lp.plan 规划(不发交易),出现两张表:
javascript
var plan = exchange.IO("lp.plan", {
symbol: "CASHCAT_WETH",
budget: 0.0041, // 投入的计价币(按资金币金额换算)
range: {lower: a, upper: b}, // 这一档的价格上下沿
shape: "spot",
pool: pool.id,
slippage: 0.01
})
// plan.positions:价格上下沿、两种币数量;plan.swap:要先换多少币;plan.estDailyFeesUsd:预估日手续费
- 头寸规划:每一档的价格区间、两种币各多少、折合多少资金币;
- 收益与情景分析:预估日手续费和年化、占池比例、资金准备、建仓换币、钱包余额是否够用,以及价格跌到下沿 / 涨到上沿时的盈亏和无常损失、跌到下沿需要几天手续费才能补回。
多档规划有一个细节:池子的价格只能落在 tick 间距的整数倍上(1% 费率的池子一格约 2%),lp.plan 会把每档上下沿向外对齐。如果各档独立规划,相邻两档就会重叠。策略的做法是下一档的下沿取上一档对齐后的实际上沿,保证首尾相接;某档窄到被并进上一档,就跳过并提示减少档数。
收益合适,就在情景分析表里点“建仓”;不合适,直接在别的池子上重新配置。
4.4 建仓
lp.add 按规划执行:需要换币就先换,处理授权,然后逐档添加流动性。实际 Gas 通过回执读出(Solana 上取交易费和不可退的账户租金),计入这一轮的成本:
javascript
var r = exchange.IO("lp.add", part) // 每一档一笔
var rc = exchange.IO("receipt", r.txHash) // rc.fee:实际 Gas
链上交易偶尔会超时没被打包(Solana 上比较常见)。平台在报错里会明确说明交易是否已经上链:确认没上链的,策略按最新价格重新规划这一档并自动补发,最多 2 次;状态不确定的不重试,避免重复建仓。
建仓日志按“规划 → 换币 → 逐档上链 → 完成”四步输出,每一档的仓位 ID 和交易哈希都能在日志里查到。
4.5 持仓管理
建仓后,“头寸规划”表变成实际持仓,每 10 秒用 lp.positions 刷新一次:
javascript
var ps = exchange.IO("lp.positions", "CASHCAT_WETH")
ps.forEach(function (p) {
// p.priceLower / p.priceUpper / p.amountBase / p.amountQuote / p.value / p.feesValue
})
每一档显示价格区间、状态、两种币数量、投入、价值、未收手续费和盈亏(扣除分摊的 Gas,各档相加正好等于本组盈亏)。状态一栏直接说明这一档在干什么:
- 🟢 区间内:距下沿、上沿各多少;
- ⏳ 未触及,价格需跌 x% 进入:当前全是计价币,等着买入代币;
- ⏳ 未触及,价格需涨 x% 进入:当前全是代币,等着卖出。
每一档和合计行都有三个按钮:
| 按钮 | 函数 | 作用 |
|---|---|---|
| 领取手续费 | lp.collect(ids, true) | 领取后卖回计价币,再换回资金币 |
| 减仓 | lp.remove(ids, 比例, true) | 按输入的比例撤出 |
| 撤池子并卖出 | lp.remove(ids, 1, true) + Sell | 全部撤出、领取手续费,代币和计价币全部卖回资金币 |
撤池子时,平台逐个仓位发交易,中途某笔超时会在报错里带上已完成的仓位。策略先把已完成的记账,剩下的确认没上链就自动补;撤之前也会先核对链上还在哪些仓位,不会重复撤。
上方的指标卡、价格与区间图、手续费覆盖率、区间位置、资金与收益明细、收益归因(价格变动 / 无常损失 / 手续费 / Gas / 计价币汇率),把“手续费能不能补上波动损失”这道算术题实时摆在眼前。
4.6 一份代码,多条链
因为 DEX 都做成了交易所对象,这份策略不改代码就能在几条链上运行,只需要换交易所:
| 链 | 交易所配置 | 资金币 | 示例币种参数 |
|---|---|---|---|
| Robinhood | Uniswap | USDG | CASHCAT,0x020b…18b4 |
| BNB Chain | Uniswap(DEX 选 PancakeSwap,含 Infinity) | USDT | CAKE,0x0E09…cE82 |
| Base / Arbitrum / Ethereum | Uniswap(或 Aerodrome) | USDC | WETH |
| Solana | Jupiter(Meteora / Raydium / Orca) | USDC | SOL,或 ORCA,orcaEKTd…ktZE |
Solana 上有两点不同,策略已经处理:币名和 mint 地址区分大小写;仓位 ID 带协议前缀,比如 orca:地址、meteora:地址。
五、实盘情况
我们在 Robinhood 链上用 10 USDG 跑了一轮实盘,选的是 CASHCAT/WETH 1% 池子,均匀 3 档、区间 ±6%:
| 步骤 | 实际情况 |
|---|---|
| 选池 | 4 个有效池子、9 个空池被排除;选 WETH 计价、TVL 约 250 万美元的 1% 池子 |
| 换币 | 钱包没有 WETH,用 10.15 USDG 自动兑换 |
| 建仓 | 3 笔 lp.add 依次上链,投入约 9.97 USDG,Gas 约 0.056 USDG |
| 管理 | 进场后 2 档在区间内,最下面一档等待价格回落;试了一次 50% 减仓,收回的 WETH 自动换回 USDG |
Solana 上用 ORCA 也跑了一轮,Orca 池子建仓、撤池子都正常;期间遇到交易超时,就是 4.4、4.5 节里自动补发和部分完成记账的来源。
小资金跑一轮说明不了长期收益。比较稳妥的做法是先用模拟模式跑几天,看手续费覆盖率、区间内时间、和同期“买入持有”的对比,再用小资金上实盘,确认真实的 Gas 和滑点。Solana 上建议给 Jupiter 交易所配置私有 RPC,公共节点限频严重,容易交易超时。
六、顺带一提:新版状态栏
上面这些截图用的是平台新版的状态栏。LogStatus 现在可以直接传对象渲染组件:指标卡、仪表盘、进度条、各类图表、日历热力图、标签页等,原有的表格和按钮也照样能用。比如持仓页顶部的指标卡:
javascript
LogStatus("流动性做市 · CASHCAT", {type: "badge", items: [{text: "持仓中", color: "up"}, {text: "实盘", color: "down"}]}, "\n", [
{type: "alert", level: "success", title: "在区间内,正在赚手续费", text: "2/3 档在区间内"},
{type: "grid", cols: 3, items: [
{type: "kpi", title: "策略权益", value: 9.998, unit: "USDG"},
{type: "kpi", title: "手续费收入", value: 0, unit: "USDG", color: "up"},
{type: "progress", title: "区间位置", value: 0.62}
]}
])
| 组件 | 本策略中的用途 |
|---|---|
badge / alert | 阶段、模式标签,区间状态提示 |
kpi / grid | 策略权益、本组盈亏、手续费、年化、现价 |
chart | 价格与区间图、收益归因、每日盈亏 |
gauge / progress | 手续费覆盖率、区间位置、区间内时间 |
stat | 资金与收益明细 |
calendar | 每日收益率日历 |
tabs / table | 每日收益、历史轮次;选池表、规划表、持仓表(带按钮) |
各组件的完整写法见文档 LogStatus。
七、接下来
DEX 模块补全以后,一级市场的几类玩法:抢新币、做市赚手续费、跨链跨池比价、链上永续和收益率交易,都可以在同一套 API 下写进策略。这个 LP 示范策略只是其中一个例子,我们会继续开发更多链上策略,陆续和大家分享。如果你有想在链上实现的玩法,或者在使用中遇到问题,欢迎在社区留言。
参考文档
- 1







