输入/搜索内容
入门
欢迎使用发明者量化交易平台
快速开始
密钥安全性
平台基础
账号与计费
实盘计费与充值
子账号
交易所
通用协议
本地凭据文件
交易所特殊说明
证券与期货
加密货币
托管者
策略库
实盘
编写策略
开发工具
回测系统
进阶专题
数据与研究
对外接口

Uniswap交易所对象在一条链上连接Uniswap或PancakeSwap的V2、V3资金池,把链上兑换映射为现货交易函数:用exchange.GetTicker()看价格、用exchange.CreateOrder()下单,不需要自己注册ABI、编码合约调用。选路、询价、代币授权、价格保护、发送交易都由交易所对象完成。

什么时候用Uniswap交易所对象,什么时候用Web3

  • 在Uniswap、PancakeSwap上兑换代币:用Uniswap交易所对象。
  • 调用其它合约、DEX的其它功能(如提供流动性、管理V3头寸)、其它链、自定义交易:用Web3交易所对象,见以太坊(EVM)。

一个策略可以同时添加两种交易所对象,使用同一个钱包。

配置交易所对象

字段说明
DEXUniswap或PancakeSwap
ChainEthereum、Arbitrum、Base、BNB Chain。一个交易所对象只对应一条链上的一个DEX
Private Key钱包私钥(十六进制字符串)。支持把私钥本地化部署在托管者上,参看密钥安全性
Rpc Address该链的节点地址,选择Chain时自动填入公共节点(如以太坊为https://ethereum-rpc.publicnode.com)。可以写多个节点,用逗号分隔,互为备用
Rpc Api Key节点鉴权,可以留空。写成名称: 值时作为该名称的请求头发送,否则作为Authorization: Basic <值>发送

第一次调用时会核对节点所在的链与Chain是否一致,不一致时报错,不会把交易发到别的链上。钱包里需要有该链的原生币(ETH或BNB)支付gas。

交易对

  • 交易对写作ETH_USDC、UNI_USDT这样的基础币_计价币。
  • 代币名按以下顺序解析:内置的常用代币(原生币、包装币、USDC、USDT等)→ 用exchange.IO("token", 名字, 合约地址)登记的代币 → 官方代币列表。官方列表中同一条链上有同名代币时,请改用合约地址。
  • 不在代币表中的代币可以直接用合约地址作为交易对的一部分,例如0x1f9840a85d5af5bf1d1762f925bdaddc4201f984_USDC。
  • 原生币与包装币是两种资产:ETH与WETH、BNB与WBNB分别是不同的币。交易原生币时路由合约会自动包装、解包。两者之间的转换不能下单,用exchange.IO("wrap", 数量)、exchange.IO("unwrap", 数量)直接调用包装币合约,1:1兑换,只花gas。
  • exchange.GetMarkets()只列出常用的交易对,没有列出的交易对同样可以交易。

标准函数的含义

函数行为
exchange.GetTicker()买一、卖一是按一定规模实际询价得到的可成交价格(已包含池子手续费);链上没有24小时统计
exchange.GetDepth()按逐档递增的规模在链上询价,推算出的价位,不是真实的挂单簿
exchange.GetTrades()该交易对资金池最近的链上兑换记录
exchange.GetAccount()、exchange.GetAssets()钱包中原生币和代币表中各代币的余额
exchange.CreateOrder()立即在链上兑换,见下文
exchange.GetOrder()订单ID就是交易哈希,状态来自交易回执:上链前为未完成,上链后为成交或失败
exchange.GetOrders()本次运行发出、还没有上链的订单
exchange.CancelOrder()用同一个nonce发送一笔替换交易,尽力撤销,见下文

不支持exchange.GetRecords()、exchange.GetTickers()、exchange.GetHistoryOrders()。

下单

DEX没有挂单簿,每笔订单都是一次立即执行的链上兑换:要么整笔成交,要么整笔回滚(只损失gas),不会部分成交、也不会挂在那里等价格。

  • 限价单:限价是最差成交价。下单时先询价,按当前价格达不到限价时直接报错,不发交易;达得到时把「最少得到/最多支付」写进链上交易,交易上链前价格变动导致达不到时整笔回滚。
  • 市价单:按询价结果扣除滑点得到最少得到/最多支付的数量,滑点默认0.5%,用exchange.IO("slippage", 比例)修改。
  • 数量:卖出时是卖出的基础币数量;限价买入时是要买到的基础币数量;市价买入时是要花费的计价币数量。
  • 单笔订单可以在方向参数后附加设置,例如exchange.CreateOrder("ETH_USDC", 'sell;{"slippage":0.01,"route":"v3"}', -1, 0.1):slippage为本单滑点,route限定路径类型(v2、v3、hop两跳、direct直连)。
  • 卖出代币(ERC20)前会检查路由合约的授权额度,不够时先发送授权交易并等待上链。默认只授权本次需要的数量,exchange.IO("approve", "max")改为无限授权,省去之后的授权交易。
  • 交易超过截止时间(默认120秒,exchange.IO("deadline", 秒数)修改)仍未上链时会回滚,避免在价格大幅变化后才成交。

撤单

exchange.CancelOrder()用原订单的nonce发送一笔转给自己的0金额交易,手续费更高,先上链则原订单失效。这只是尽力撤销:原订单可能在替换交易之前上链并成交;原订单已经上链时撤单直接报错。撤单后用exchange.GetOrder()确认最终状态。

常用的exchange.IO()指令

指令作用
exchange.IO("slippage", 比例)市价单滑点,默认0.005
exchange.IO("deadline", 秒数)交易截止时间,默认120秒
exchange.IO("gasMultiplier", 倍数)gas上限 = 节点估算值 × 倍数,默认1.2
exchange.IO("approve", "exact" 或 "max")授权模式
exchange.IO("token", 名字, 合约地址)登记代币;不传参数时列出代币表
exchange.IO("route", 交易对, 方向, 数量)只询价:各候选路径的报价和最优路径,不下单
exchange.IO("simulate", 交易对, 方向, 数量[, 价格])按下单逻辑构造交易,只在链上模拟执行,不花gas
exchange.IO("transfer", 收款地址, 数量[, 代币])转出原生币或代币,数量可以写"all"
exchange.IO("receipt", 交易哈希[, 等待毫秒])查询转账等交易的回执,可以等待上链
exchange.IO("wrap", 数量)、exchange.IO("unwrap", 数量)原生币与包装币1:1互换
exchange.IO("contracts")当前DEX在当前链上的合约地址
exchange.IO("base", 节点地址)、exchange.IO("sendBase", 节点地址)切换节点;设置只用于广播交易的节点(私有交易通道)
exchange.IO("address")钱包地址

各指令的参数与返回值见语法手册Uniswap分类。

示例

示例:询价、模拟,然后市价卖出

以以太坊上的ETH_USDC为例。注意CreateOrder会发出真实交易。

javascript
function main() { var symbol = "ETH_USDC" exchange.IO("slippage", 0.003) // 市价单滑点 0.3% var t = exchange.GetTicker(symbol) Log("买一:", t.Buy, "卖一:", t.Sell) // 只询价:卖出 0.1 ETH 的最优路径 var r = exchange.IO("route", symbol, "sell", 0.1) Log("最优路径:", r.best, "价格:", r.price) // 链上模拟一遍,不花 gas if (!exchange.IO("simulate", symbol, "sell", 0.1)) { Log("模拟失败:", GetLastError()) return } // 市价卖出 0.1 ETH,订单 ID 是交易哈希 var id = exchange.CreateOrder(symbol, "sell", -1, 0.1) if (!id) { Log("下单失败:", GetLastError()) return } while (true) { var o = exchange.GetOrder(id) if (o && o.Status != ORDER_STATE_PENDING) { Log("状态:", o.Status, "成交数量:", o.DealAmount, "成交均价:", o.AvgPrice) break } Sleep(3000) } }

参考