[TOC]
近期,FMZ 平台新增支持了 Hyperliquid DEX 这一高性能去中心化交易所,为用户参与去中心化交易提供了更多选择。目前,FMZ 平台的托管者功能已全面更新,支持 Hyperliquid 的现货及永续合约交易,并覆盖该 DEX 的全部 API 功能。
Hyperliquid 平台简介
Hyperliquid 是一个从零开始优化的高性能 L1 区块链,其愿景是构建一个完全链上的开放金融系统。用户可通过与高效的原生组件交互,自主创建应用程序,同时确保终端用户体验的流畅性。
Hyperliquid L1 的性能足以支持一个无许可的金融应用生态系统。所有订单、撤单、交易及清算都以完全透明的方式在链上完成,区块延迟低于 1 秒。目前,链上支持每秒高达 10 万笔订单的处理能力。
Hyperliquid L1 采用了名为 HyperBFT 的定制共识算法,其灵感来源于 Hotstuff 及其后续算法。无论是共识机制还是网络架构,均从底层优化,以满足高性能区块链的需求。
通过本指南,希望能够帮助您在 FMZ 平台上快速上手 Hyperliquid DEX 的程序化与量化交易,并从中发掘更多的交易机会。
REST协议 - 行情接口实践。 - 交易接口实践(下单、撤单)。 - 交易相关查询实践(账户、订单)。 - 其它功能(现货、合约划转、金库存取、划转资产至钱包等)。
Websocket 协议 - 成交流信息订阅实践(REST接口中没有Trades接口,以Websocket接口补充)
在FMZ平台的添加交易所页面,可以配置 Hyperliquid 现货、期货交易所对象:
环境划分 与大多数交易所一样,Hyperliquid 也有测试环境。
实际使用感受,主网比较稳定,速度也不错。
与之对应的REST协议API接口节点地址:https://api.hyperliquid.xyz
。
消息签名相关信息也有所不同:source == "a"
,chainId = 42161
测试网经常宕机,不过仅仅作为测试接口、熟悉DEX上的交易功能使用。
与之对应的REST协议API接口节点地址:https://api.hyperliquid-testnet.xyz
。
消息签名相关信息也有所不同:source == "b"
,chainId = 421614
与大多数DEX交易所的钱包连接方式一样,可以使用钱包APP扫二维码连接到 Hyperliquid (钱包切换到 Arbitrum 扫码登录,测试网、主网都是一样的方式)。
如果希望先从测试网熟悉的同学,可以在钱包连接到 Hyperliquid 之后,直接在 Hyperliquid 页面上找到水龙头
可以领取测试资产,领取测试用的USDC之后,点击「存款」按钮存入 Hyperliquid 就可以了(Arbitrum 测试网 最好有一点ETH)。
点击「存款」按钮存入,需要钱包验证,会消耗一点点 Arbitrum 上的 ETH。
在 Hyperliquid APP页面进行手动交易时,页面会自动生成一个代理钱包地址和私钥,是记录在浏览器中的,用于浏览器页面上的下单等操作,那么如果我们要做程序化,量化交易需要怎么获取这个配置信息呢?
可以在 Hyperliquid 的 API 页面创建需要的代理钱包地址和对应的私钥:
1、给即将创建的代理钱包起个名字。
2、生成地址和私钥。
3、使用连接到 Hyperliquid 的钱包对代理钱包授权。
在FMZ上配置代理钱包地址、私钥
然后就可以在FMZ平台上配置这些信息了(配置界面见上文中提及)。
配置交易所对象需要的信息:
当配置完成后,我们就可以在FMZ平台上测试使用了,我们直接使用FMZ平台的「调试工具」进行测试实践。
如果您使用的是测试网信息配置的 Hyperliquid 交易所对象,使用时需要做一些切换操作,例如:
function main() {
// REST协议API地址切换到测试网
exchange.SetBase("https://api.hyperliquid-testnet.xyz")
// source : a 主网 , b 测试网
exchange.IO("source", "b")
return exchange.GetAccount()
}
主网配置则不需要以上切换操作,Hyperliquid DEX交易所中现货、期货品种相关的API接口几乎相同,只有略微细节差别,接下来我们使用主网配置信息和测试网配置信息的 Hyperliquid 期货交易所对象来测试。
function main() {
var markets = exchange.GetMarkets()
if (!markets) {
throw "get markets error"
}
var tbl = {
type: "table",
title: "test markets",
cols: [
"key", "Symbol", "BaseAsset", "QuoteAsset", "TickSize", "AmountSize", "PricePrecision", "AmountPrecision", "MinQty",
"MaxQty", "MinNotional", "MaxNotional", "CtVal", "CtValCcy"
],
rows: []
}
for (var symbol in markets) {
var market = markets[symbol]
tbl.rows.push([
symbol, market.Symbol, market.BaseAsset, market.QuoteAsset, market.TickSize, market.AmountSize,
market.PricePrecision, market.AmountPrecision, market.MinQty, market.MaxQty, market.MinNotional, market.MaxNotional, market.CtVal, market.CtValCcy
])
}
LogStatus("`" + JSON.stringify(tbl) + "`")
}
function main() {
var depth = exchange.GetDepth("ETH_USD.swap")
var asks = depth.Asks
var bids = depth.Bids
Log("买3", bids[2])
Log("买2", bids[1])
Log("买1", bids[0])
Log("卖1", asks[0])
Log("卖2", asks[1])
Log("卖3", asks[2])
}
function main() {
var account = exchange.GetAccount()
return account
}
function main() {
var symbols = ["ETH_USD.swap", "XRP_USD.swap", "HYPE_USD.swap"]
var arrDir = ["market_buy", "sell", "buy"]
var markets = exchange.GetMarkets()
var ids = []
for (var i in symbols) {
var symbol = symbols[i]
var side = arrDir[i]
var ticker = exchange.GetTicker(symbol)
var info = markets[symbol]
exchange.SetPrecision(info.PricePrecision, info.AmountPrecision)
// USDC
var qty = 15
var price = null
var amount = null
if (side == "market_buy") {
price = -1
side = "buy"
amount = qty / ticker.Last
} else {
price = side == "buy" ? ticker.Last * 0.9 : ticker.Last * 1.1
amount = qty / price
}
var id = exchange.CreateOrder(symbol, side, price, amount)
ids.push(id)
}
var tbl = {type: "table", title: "test", cols: ["Symbol", "Id", "Price", "Amount", "DealAmount", "AvgPrice", "Status", "Type", "Offset", "ContractType"], rows: []}
for (var id of ids) {
var order = exchange.GetOrder(id)
tbl.rows.push([order.Symbol, order.Id, order.Price, order.Amount, order.DealAmount, order.AvgPrice, order.Status, order.Type, order.Offset, order.ContractType])
Sleep(500)
}
LogStatus("`" + JSON.stringify(tbl) + "`")
}
function main() {
var orders = exchange.GetOrders("USD.swap")
for (var order of orders) {
exchange.CancelOrder(order.Id, order)
Sleep(1000)
}
var tbl = {type: "table", title: "test", cols: ["Symbol", "Id", "Price", "Amount", "DealAmount", "AvgPrice", "Status", "Type", "Offset", "ContractType"], rows: []}
for (var order of orders) {
tbl.rows.push([order.Symbol, order.Id, order.Price, order.Amount, order.DealAmount, order.AvgPrice, order.Status, order.Type, order.Offset, order.ContractType])
}
LogStatus("`" + JSON.stringify(tbl) + "`")
}
function main() {
// 设置当前为全仓
exchange.IO("cross", true)
// 设置杠杆
exchange.SetMarginLevel("ETH_USD.swap", 10)
return exchange.GetRawJSON()
}
exchange.GetRawJSON() 返回设置杠杆请求的应答信息:
{“status”:“ok”,“response”:{“type”:“default”}}
由于交易所的接口参数比较复杂,无法使用url encode方式传参,所以在使用exchange.IO
函数调用时,只能使用JSON字符串作为参数传入,以下是各个接口调用范例。
hyperliquid 参考文档: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#place-an-order
var params = {"type": "scheduleCancel", "time": new Date().getTime()}
return exchange.IO("api", "POST", "/exchange", null, JSON.stringify(params))
{“status”:“err”,“response”:“Cannot set scheduled cancel time until enough volume traded. Required: \(1000000. Traded: \)174.57424.”}
该功能有限制:账户达到交易级别才能用该功能。
创建TWAP订单。
function main() {
var params = {
"type": "twapOrder",
"twap": {
"a": 0,
"b": true,
"s": "1",
"r": false,
"m": 10,
"t": false
}
}
// SOL_USDT.swap , 订单量 : 1 , twapOrder 订单有头寸要求,最少100美元价值
// a : 0 , 即 SOL_USDT.swap 这个品种
return exchange.IO("api", "POST", "/exchange", null, JSON.stringify(params))
}
撤销TWAP订单。
function main() {
var params = {
"type": "twapCancel",
"a": 0,
"t": 3805
}
return exchange.IO("api", "POST", "/exchange", null, JSON.stringify(params))
}
测试网,授权一个新的代理钱包。
function main() {
var params = {
"type": "approveAgent",
"hyperliquidChain": "Testnet",
"signatureChainId": "0x66eee",
"agentAddress": "0xAAAA",
"agentName": "test02",
"nonce": new Date().getTime()
}
return exchange.IO("api", "POST", "/exchange", null, JSON.stringify(params))
}
授权成功返回:
{“status”:“ok”,“response”:{“type”:“default”}}
https://app.hyperliquid-testnet.xyz/API
中。向金库存取资产。
function main() {
var params = {
"type": "vaultTransfer",
"vaultAddress": "0xAAA",
"isDeposit": true,
"usd": 5000000
}
return exchange.IO("api", "POST", "/exchange", null, JSON.stringify(params))
}
测试网,资产提出到钱包。
function main() {
var params = {
"type": "withdraw3",
"hyperliquidChain": "Testnet",
"signatureChainId": "0x66eee",
"amount": "5",
"time": new Date().getTime(),
"destination": "0xAAA"
}
return exchange.IO("api", "POST", "/exchange", null, JSON.stringify(params))
}
现货/期货(永续合约)之间资产划转。
function main() {
var params = {
"type": "usdClassTransfer",
"hyperliquidChain": "Testnet",
"signatureChainId": "0x66eee",
"amount": "5",
"toPerp": false,
"nonce": new Date().getTime()
}
return exchange.IO("api", "POST", "/exchange", null, JSON.stringify(params))
}
false
表示划转方向:futures -> spot 。true
表示划转方向:spot -> futures 。主网的WS接口地址:
Mainnet: wss://api.hyperliquid.xyz/ws
由于REST协议API接口没有获取近期成交数据的接口,但是Websocket接口有这个频道可以订阅。
订阅消息结构
{
"method": "subscribe",
"subscription": {
"type": "trades",
"coin": "SOL"
}
}
在调试工具中执行的测试范例:
function main() {
var loopCount = 20
var subMsg = {
"method": "subscribe",
"subscription": {
"type": "trades",
"coin": "SOL"
}
}
var conn = Dial("wss://api.hyperliquid.xyz/ws")
conn.write(JSON.stringify(subMsg))
if (conn) {
for (var i = 0; i < loopCount; i++) {
var msg = conn.read(1000)
if (msg) {
Log(msg)
}
}
}
conn.close()
Log("测试结束")
}
以上测试,基于最新的托管者,需要下载最新的托管者才支持 Hyperliquid DEX 交易所。
感谢支持,感谢您的阅读。