用 web3.js 获取币安 ETHUSDT 与任意代币实时价格的完全指南

·

在前端 DApp、链上套利、价格预警系统中,“如何将 ETH/USDT 价格币安交易所某代币/USDT 价格实时拿到本地”是最常被问到的问题。本文手把手从 API 选择、代码构造到节点配置,帮你 10 分钟跑通示例程序,并一次性解答常见坑点。

1、两种数据源:链上 DEX 与中心化交易所

场景数据源方法典型代表
链上价格调用 DEX Router 合约getAmountsOutPancake、Uniswap V3
行情盘口中心化交易所 REST/WS API公共接口签名币安、OKX

场景区别在于:

下文同时给出 web3.js 配合“DEX Router”与调用“币安行情接口”两段源码,你按需求自由组合。

2、准备工作

2.1 安装库

npm i web3 axios ethers

2.2 免费 RPC

👉 新手也能秒部署的高稳定节点集合,别错过!

3、用 web3.js 读取 PancakeRouter 的 USDT 价格

步骤拆解

  1. 连接节点
  2. 生成 Router Contract 实例
  3. 指定 tokenIn、tokenOut、amountIn
  4. 调用 getAmountsOut 得到 price

3.1 币安交易对:token/USDT

假设目标资产为 CAKE,合约地址:

CAKE = 0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82
USDT = 0x55d398326f99059fF775485246999027B3197955
router = 0x10ED43C718714eb63d5aA57B78B54704E256024E
// price-token-usdt.js
const Web3 = require('web3');
const web3 = new Web3('https://bsc-dataseed.binance.org/');

const ROUTER_ABI = [{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"}];

const ROUTER_ADDR = '0x10ED43C718714eb63d5aA57B78B54704E256024E';

async function getTokenPriceUSDT(token, decimals = 18) {
  const TOKEN_IN = token;
  const TOKEN_OUT = '0x55d398326f99059fF775485246999027B3197955'; // USDT
  const amountIn = web3.utils.toBN(10).pow(web3.utils.toBN(decimals));
  const path = [TOKEN_IN, TOKEN_OUT];

  const contract = new web3.eth.Contract(ROUTER_ABI, ROUTER_ADDR);
  const [amountOut] = await contract.methods.getAmountsOut(amountIn, path).call();
  return Number(amountOut) / 1e18;
}

getTokenPriceUSDT('0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82')
  .then(p => console.log('1 CAKE ≈', p, 'USDT'))
  .catch(console.error);

3.2 ETH/USDT(以太坊主网版)

同理替换节点、RouterTOKEN_IN 即可:

// price-eth-usdt.js
const web3 = new Web3('https://mainnet.infura.io/v3/xxxxxxxx');
const USDT_ETH = '0xdAC17F958D2ee523a2206206994597C13D831ec7';
// UniswapV2 Router
const ROUTER_ETH = '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D';

async function getETHPriceUSDT() {
  const amountIn = web3.utils.toWei('1'); // 1 ETH
  const path = [
    '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH
    USDT_ETH
  ];
  const router = new web3.eth.Contract(ROUTER_ABI, ROUTER_ETH);
  const [,, out] = await router.methods.getAmountsOut(amountIn, path).call();
  return Number(out) / 1e6;
}

4、直接抓取 binance 汇率 API

若只希望在前端显示币安现货行情,无需链上交互。签名 Header 都省掉,这是最快的办法。

// binance-ticker.js
const axios = require('axios');

async function getBinanceTicker(symbol = 'ETHUSDT') {
  const { data } = await axios
    .get(`https://api.binance.com/api/v3/ticker/price?symbol=${symbol}`);
  return Number(data.price);
}

getBinanceTicker('CAKEUSDT')
  .then(p => console.log('Binance CAKE/USDT:', p));

可同时将 CAKE、ETH、BTC、BNB 等推送到前端,用 Promise.all() 批量抓取。

5、常见进阶坑点

  1. 滑点过高:DEX 价格会因池子深度波动,大额兑换请使用 汇率预言机 如 Chainlink。
  2. 精度错乱:币安结果 6 位,BSC 代币常见 18 位,做除法前先看清 decimals
  3. 节点延迟:公网 RPC 高峰期 2–4 秒,可在项目里做缓存 3–5 秒。

6、FAQ:5 个你一定会用到的问题

Q1:只用 web3.js 能否调用 Binance 行情?
A:不能。web3.js 只针对链上智能合约。Binance 数据源自中心服务器,需走 REST/WS。

Q2:getAmountsOut 得到的只是“理论价”,会随时变吗?
A:会变,任何人下一笔交易都会把价格推倒新平衡。如需保险,先用 reserves() 读池子深度,再去估算滑点。

Q3:如何避免前端被限速?
A:三个技巧:
a. 前端缓存 LocalStorage/IndexedDB 5 秒;
b. 用 Vercel Function / Cloudflare Workers 做一层代理解决 CORS;
c. 签专用 API-KEY 额外请求额度。

Q4:直接用 Chainlink 价格 feed 是不是更省心?
A:Chainlink Feed 延迟 1~10 分钟,单节点报错也无法自动熔断。适合结算场景;交易撮合仍建议实时读 Router。

Q5:本地测试链没有流动性怎么办?
A:Hardhat Fork BSC/ETH 主网。默认 2,000 区块深度,足够大多数模拟需求。


最后别忘了:把 Router 版本、数据源切换、精度处理放进统一配置文件,后期上新链就像拼积木一样简单。现在动手改两行代码,你就拥有全功能 实时链上加中心化行情看板