输入/搜索内容
内置函数
结构体
内置变量与常量
通用约定
交易所

按建仓计划建立集中流动性仓位:缺哪种代币先用Jupiter换,每个仓位一笔链上交易。

exchange.IO(k, plan)

示例

  • 按SOL/USDC现价上下5%建仓。

    javascript
    function main() { var r = exchange.IO("lp.add", {symbol: "SOL_USDC", budget: 100, range: {pct: [-5, 5]}}) if (!r) { Log("建仓失败:", GetLastError()) return } if (r.swapTxHash) { Log("先换币:", r.swapTxHash) } r.positions.forEach(function(p) { Log(p.id, p.priceLower.toFixed(2), "-", p.priceUpper.toFixed(2), "存入", p.amountBase, "SOL", p.amountQuote, "USDC", "租金", p.rentSol, "SOL") }) }
  • 完整流程:选池 → 规划 → 模拟 → 建仓 → 监控与领取 → 撤出。

    javascript
    var BUDGET = 100 // 预算(USDC) var MIN_FEES = 1 // 未领手续费超过1 USDC就领取 function main() { // 1. 列出池子并自动选一个 var pools = exchange.IO("lp.pools", "SOL", "USDC") if (!pools || pools.length == 0) { Log("没有池子:", GetLastError()) return } var pool = exchange.IO("lp.select", "SOL", BUDGET, {quote: "USDC"}) if (!pool) { Log("选池失败:", GetLastError()) return } Log("候选", pools.length, "个,选中", pool.dex, pool.id, pool.reason) // 2. 规划:现价上下5% var plan = exchange.IO("lp.plan", {symbol: "SOL_USDC", budget: BUDGET, pool: pool.id, range: {pct: [-5, 5]}, shape: "spot"}) if (!plan || plan.shortfall) { Log("规划失败或余额不足:", plan ? plan.shortfall : GetLastError()) return } Log("仓位数", plan.positions.length, "先换币", JSON.stringify(plan.swap), "租金", plan.rentSol) // 3. 模拟 var sim = exchange.IO("lp.simulate", plan) if (!sim || !sim.ok) { Log("模拟未通过:", sim ? JSON.stringify(sim.positions) : GetLastError()) return } // 4. 建仓 var r = exchange.IO("lp.add", plan) if (!r) { Log("建仓失败:", GetLastError()) return } var ids = r.positions.map(function(p) { return p.id }) Log("已建仓", ids.join(", "), "交易", r.txHashes.join(", ")) // 5. 监控:价格出区间就退出循环,手续费够多就领取 while (true) { Sleep(60 * 1000) var list = exchange.IO("lp.positions", "SOL_USDC") if (!list) { continue } var mine = list.filter(function(p) { return ids.indexOf(p.id) >= 0 }) var out = mine.some(function(p) { return !p.inRange }) var fees = mine.reduce(function(s, p) { return s + p.feesValue }, 0) LogStatus(_D(), "仓位", mine.length, "出区间", out, "未领手续费", fees.toFixed(4)) if (out) { break } if (fees > MIN_FEES) { var c = exchange.IO("lp.collect", ids) Log("领取手续费:", c ? c.txHashes.join(", ") : GetLastError()) } } // 6. 全部撤出、关仓退租金,并把拿回的SOL卖成USDC var rm = exchange.IO("lp.remove", ids, 1, true) if (!rm) { Log("撤出失败:", GetLastError()) return } rm.positions.forEach(function(p) { Log(p.id, "拿回", p.receivedBase, "SOL", p.receivedQuote, "USDC", "手续费", p.feesBase, p.feesQuote, "退租金", p.rentRefundSol) }) }

返回值

类型描述

object / 空值

{txHash, txHashes, swapTxHash, pool, protocol, symbol, positions}:txHash为第一笔建仓交易签名,txHashes为全部;swapTxHash为建仓前换币的交易签名(没有换币为null);positions每项为{id, txHash, lowerBinId, upperBinId, priceLower, priceUpper, amountBase, amountQuote, rentSol, feeSol}(Raydium、Orca为tickLower、tickUpper)。余额不足、模拟失败、交易失败时返回空值。

参数

名称类型必填描述

k

string

是

固定为lp.add,用于建仓。

plan

object

是

lp.plan返回的计划,或计划参数(同lp.plan的params)。

参考

备注

执行步骤
  1. 按计划的params在最新池价与钱包余额下重新规划;有shortfall时报错,不发任何交易。
  2. 计划要先换币时,用本交易所对象的Jupiter市价单换(滑点见exchange.IO("slippage")),等确认。
  3. 换币后再重新规划一次;余额因滑点、手续费略少于计划量时,各仓位按持有量等比缩小。
  4. 每个仓位一笔交易:DLMM的仓位账户、Raydium与Orca的仓位NFT mint用新生成的密钥创建,并由它一起签名。
  5. 交易确认后,按交易前后的余额给出实际存入的amountBase、amountQuote;rentSol为这笔交易押的租金(含新建BinArray、TickArray与仓位账户的),feeSol为网络费。

交易的执行

每笔交易发送前都用节点模拟一遍,模拟失败不发送并报出原因(DLMM、Raydium CLMM、Orca Whirlpool的错误码附名字);计算单元上限按模拟用量加余量,优先费按最近写这些账户的交易的费率取第75百分位,不超过exchange.IO("priorityFee")的上限。交易确认后才返回,实际数量按交易前后的余额计算。120秒内既没确认也证明不了过期时报outcome is unknown并附交易签名:交易可能已经上链,先用exchange.IO("receipt")核对再决定是否重试。

仓位ID与失败处理
  • 仓位id写成meteora:仓位账户地址、raydium:仓位NFT的mint或orca:仓位NFT的mint,传给lp.increase、lp.decrease、lp.collect、lp.remove;本进程建的仓位会自动记住,lp.positions一定查得到。
  • 换币之后的步骤失败时,错误信息带换币交易签名(换到的币留在钱包);多个仓位中途失败时,错误信息列出已经建好的仓位。

风险
  • 无常损失:价格偏离建仓价越远,仓位价值相对单纯持有越低。
  • 价格出区间后仓位只剩一种代币,不再赚手续费。
  • 新建BinArray、TickArray的租金不退;拆成多个仓位时每个都要押一份仓位租金。
  • 每次建仓、调仓、领取、撤出都是链上交易,频繁调仓的成本可能超过手续费收入。