简繁
ESC
↑↓ 选择↵ 打开站内全文搜索
注册币安 ↗

Python 用 CCXT 连接币安和欧易:查行情、余额、下单与撤单

用 Python 的 CCXT 库,同一套代码就能连接币安和欧易:公开接口不需要 API Key 即可查行情、K 线和交易对精度,私有接口用环境变量传入 Key 后可查余额、挂单、撤单。本文附实测输出、测试网与模拟盘切换方法、异常处理与重试写法和完整可运行脚本。

识途编辑部更新 阅读 约 29 分钟来源 4 个官方资料
目录本文共 8 节
  1. 01CCXT 是什么?为什么用它连接币安和欧易?
  2. 02怎么安装 CCXT?
  3. 03不用 API Key 怎么查行情、K 线和交易对规则?
  4. 04私有接口要准备什么?
  5. 05CCXT 怎么切换到币安测试网和欧易模拟盘?
  6. 06完整脚本:查余额、挂单、查挂单、撤单
  7. 07新手用 CCXT 最常遇到哪些问题?
  8. 08CCXT 异常怎么处理?哪些错误可以重试?

CCXT 是一个开源的加密货币交易所接口库,用 pip install ccxt 安装后,同一套 Python 代码就能连接币安和欧易:fetch_ticker 查行情、fetch_ohlcv 取 K 线、load_markets 读交易对精度,这些公开接口不需要 API Key;传入 Key 后再用 fetch_balance 查余额、create_limit_buy_order 挂单、cancel_order 撤单。本文所有公开接口代码都在 CCXT 4.5.89、Python 3.13 下实际运行过,私有接口请先在币安现货测试网或欧易模拟盘运行。

CCXT 是什么?为什么用它连接币安和欧易?

每家交易所的 API 写法都不一样:币安的交易对叫 BTCUSDT,签名放在查询参数里;欧易叫 BTC-USDT,签名放在请求头里,还要多一个 Passphrase。CCXT 把这些差异封装起来,对外提供统一的方法名和统一的数据格式:

  • 交易对统一写成 BTC/USDT,CCXT 自动换成各交易所的内部代码。
  • 签名、时间戳、请求头都由 CCXT 处理,你只需要提供 Key。
  • 错误统一成 AuthenticationError、InsufficientFunds、InvalidOrder 等异常类型。

CCXT 支持上百家交易所,本文只讲币安和欧易。同一个安装包里有三种用法:import ccxt 是同步写法,最适合入门和写小脚本,本文全部使用这种;import ccxt.async_support 是异步写法,适合同时请求很多交易对;import ccxt.pro 提供 WebSocket 实时推送,例如 watch_ticker,适合需要持续接收行情的程序。三者的方法名和返回格式基本一致,学会同步版本后迁移很容易。

要注意的是,CCXT 只是帮你「发请求」的工具,它不保管你的资产,也不会替你做任何交易决定。Key 存在你自己的电脑上,请求从你的电脑直接发往交易所,中间不经过第三方服务器。要了解底层签名是怎么算的,可以看 交易所 API 签名原理。

怎么安装 CCXT?

建议为每个项目建一个虚拟环境,避免和电脑自带的 Python 环境互相干扰:

python3 -m venv .venv
source .venv/bin/activate        # Windows 用 .venv\Scripts\activate
pip install ccxt
python -c "import ccxt; print(ccxt.__version__)"

我们运行时输出的版本号是 4.5.89。CCXT 更新很频繁,方法名基本稳定,但个别交易所的默认参数可能变化,遇到和本文不一致的行为,先看看自己的版本号。

不用 API Key 怎么查行情、K 线和交易对规则?

下面这个脚本对币安和欧易依次查询服务器时间、BTC/USDT 最新行情、最近 3 根 1 小时 K 线和交易对规则,全部是公开接口:

import ccxt

print("CCXT 版本:", ccxt.__version__)

binance = ccxt.binance({
    "enableRateLimit": True,
    "options": {"fetchMarkets": {"types": ["spot"]}},  # 只加载现货市场,启动更快
})
okx = ccxt.okx({"enableRateLimit": True})

SYMBOL = "BTC/USDT"

for ex in (binance, okx):
    print(f"\n===== {ex.id} =====")

    # 1. 服务器时间:签名请求前先确认本机时间没有偏差
    server_ms = ex.fetch_time()
    print("服务器时间:", ex.iso8601(server_ms), "本机偏差(ms):", ex.milliseconds() - server_ms)

    # 2. 最新行情
    t = ex.fetch_ticker(SYMBOL)
    print("最新价:", t["last"], "买一:", t["bid"], "卖一:", t["ask"],
          "24h 涨跌%:", round(t["percentage"], 2), "24h 成交量:", t["baseVolume"])

    # 3. 最近 3 根 1 小时 K 线:[时间, 开, 高, 低, 收, 成交量]
    for ts, o, h, l, c, v in ex.fetch_ohlcv(SYMBOL, timeframe="1h", limit=3):
        print(ex.iso8601(ts), o, h, l, c, round(v, 4))

    # 4. 交易对规则:精度与最小下单量
    markets = ex.load_markets()
    m = ex.market(SYMBOL)
    print("市场数量:", len(markets), "交易所内部代码:", m["id"])
    print("价格步长:", m["precision"]["price"], "数量步长:", m["precision"]["amount"])
    print("最小数量:", m["limits"]["amount"]["min"], "最小金额:", m["limits"]["cost"]["min"])
    print("数量 0.123456789 规整后:", ex.amount_to_precision(SYMBOL, 0.123456789))
    print("价格 65432.123456 规整后:", ex.price_to_precision(SYMBOL, 65432.123456))

2026 年 10 月 22 日运行时的真实输出(价格为运行时数据,仅作格式示例):

CCXT 版本: 4.5.89

===== binance =====
服务器时间: 2026-10-22T09:33:27.310Z 本机偏差(ms): -124
最新价: 81838.01 买一: 81838.0 卖一: 81838.01 24h 涨跌%: -2.11 24h 成交量: 21704.10475
2026-10-22T07:00:00.000Z 82491.56 82531.17 82111.0 82239.46 1264.4365
2026-10-22T08:00:00.000Z 82239.46 82267.79 81844.01 81861.24 1017.8519
2026-10-22T09:00:00.000Z 81861.25 81933.02 81653.0 81838.0 477.5245
市场数量: 3736 交易所内部代码: BTCUSDT
价格步长: 0.01 数量步长: 1e-05
最小数量: 1e-05 最小金额: 5.0
数量 0.123456789 规整后: 0.12345
价格 65432.123456 规整后: 65432.12

===== okx =====
服务器时间: 2026-10-22T09:33:28.170Z 本机偏差(ms): -119
最新价: 81834.5 买一: 81834.4 卖一: 81834.5 24h 涨跌%: -2.13 24h 成交量: 7411.60789259
2026-10-22T07:00:00.000Z 82500.1 82543.3 82131.4 82249.9 669.1373
2026-10-22T08:00:00.000Z 82249.9 82278.4 81850.0 81861.2 445.3618
2026-10-22T09:00:00.000Z 81861.2 81940.0 81638.8 81834.5 214.3707
市场数量: 4578 交易所内部代码: BTC-USDT
价格步长: 0.1 数量步长: 1e-08
最小数量: 1e-05 最小金额: None
数量 0.123456789 规整后: 0.12345678
价格 65432.123456 规整后: 65432.1

fetch_ticker 和 fetch_ohlcv 返回了什么?

fetch_ticker 返回一个字典,常用字段有 last(最新成交价)、bid/ask(买一、卖一)、high/low(24 小时最高最低)、baseVolume(24 小时成交量,单位是 BTC)、percentage(24 小时涨跌幅)。fetch_ohlcv 返回列表,每一项依次是 K 线开盘时间(毫秒时间戳)、开、高、低、收、成交量,最后一根是还没走完的当前 K 线。时间周期写 1m、5m、1h、1d 等,limit 控制根数。

本机偏差那一行也值得留意:签名请求带时间戳,币安默认只接受 5 秒内的请求,欧易超过 30 秒会拒绝。偏差在几百毫秒内很正常,如果差了好几秒,先开启电脑的自动对时。

fetch_order_book:怎么看买卖盘深度?

想知道当前价位挂了多少单,用 fetch_order_book。下面的代码取买卖盘前 3 档,并顺便演示交易对写错时的异常:

import ccxt

binance = ccxt.binance({"options": {"fetchMarkets": {"types": ["spot"]}}})
okx = ccxt.okx()

for ex in (binance, okx):
    ob = ex.fetch_order_book("BTC/USDT", limit=5)
    asks = [row[:2] for row in ob["asks"][:3]]  # 每档只取 [价格, 数量]
    bids = [row[:2] for row in ob["bids"][:3]]
    print(ex.id, "卖盘:", asks)
    print(ex.id, "买盘:", bids)
    print(ex.id, "买卖价差:", round(asks[0][0] - bids[0][0], 2))

try:
    binance.fetch_ticker("BTC/USDC.X")  # 故意写一个不存在的交易对
except ccxt.BadSymbol as e:
    print("BadSymbol:", e)

运行时输出:

binance 卖盘: [[81791.5, 0.13627], [81791.51, 0.00042], [81791.69, 7e-05]]
binance 买盘: [[81791.49, 11.21318], [81791.25, 0.04184], [81791.24, 2.06615]]
binance 买卖价差: 0.01
okx 卖盘: [[81796.8, 1.38093972], [81797.7, 0.21551712], [81798.0, 1.02e-05]]
okx 买盘: [[81796.7, 1.0170818], [81796.6, 0.04428254], [81796.3, 0.15659987]]
okx 买卖价差: 0.1
BadSymbol: binance does not have market symbol BTC/USDC.X

卖盘按价格从低到高排,买盘从高到低排,第一档就是卖一和买一。BTC/USDT 这种主流交易对的价差只有一个价格步长;小币种的价差和每档数量可能差很多,市价单滑点也会更大。欧易返回的每档数据比币安多一个字段,所以代码里用 row[:2] 只取价格和数量,两家的处理方式就一致了。

为什么下单前一定要看精度和最小下单量?

交易所对每个交易对都规定了价格步长、数量步长和最小下单量,不符合就会被拒单。从上面的输出整理成表:

规则 币安 BTC/USDT 欧易 BTC/USDT
价格步长 0.01 0.1
数量步长 0.00001 BTC 0.00000001 BTC
最小数量 0.00001 BTC 0.00001 BTC
最小金额 5 USDT 接口未返回(以数量限制为准)

另外,币安现货还有 PERCENT_PRICE_BY_SIDE 规则:运行时 BTCUSDT 的买单价格不能低于近 5 分钟均价的 50%,否则报价格过滤失败。所以测试挂单时,价格「远离市价」也要有个度。

amount_to_precision 和 price_to_precision 会按步长规整数字,数量是向下截断而不是四舍五入:0.123456789 在币安变成 0.12345。截断后金额可能掉到最小金额以下,计算数量时要留一点余量。各种订单类型的区别见 限价单、市价单与止盈止损。

私有接口要准备什么?

查余额、下单、撤单需要 API Key。申请方法和权限设置分别见 币安 API Key 申请教程 和 欧易 API 创建教程,核心原则只有三条:只开读取和现货交易、不开提现、绑定 IP。

Key 不要写进代码,用环境变量传入:

# macOS / Linux:只在当前终端窗口有效
export BINANCE_API_KEY="你的币安测试网 API Key"
export BINANCE_API_SECRET="你的币安测试网 Secret Key"
export OKX_API_KEY="你的欧易模拟盘 API Key"
export OKX_API_SECRET="你的欧易模拟盘 Secret Key"
export OKX_API_PASSPHRASE="你的欧易模拟盘 Passphrase"

Windows PowerShell 写成 $env:BINANCE_API_KEY="..."。不要把带 Key 的命令保存进脚本文件再上传到代码仓库。

环境变量只在当前终端窗口有效,关掉就没了。长期使用时,可以把这几行放进一个只有你自己能读的本地配置文件,在运行前加载;如果项目用 Git 管理,记得把这个文件加进 .gitignore。私有接口的权限也要对得上:只查余额,读取权限就够;要跑下面的挂单和撤单脚本,测试网 Key 需要同时有读取和现货交易权限。

CCXT 怎么切换到币安测试网和欧易模拟盘?

截至 CCXT 4.5.89,两家交易所的切换方式如下(均已实测):

写法 效果
币安 set_sandbox_mode(True) 请求地址换成 testnet.binance.vision,只能用现货 /api 接口
币安 enable_demo_trading(True) 请求地址换成 demo-api.binance.com,对应币安网页版模拟交易
欧易 set_sandbox_mode(True) 域名不变,所有请求自动加上 x-simulated-trading: 1

币安的两种模式不能同时打开,实测先开 sandbox 再开 demo 会抛出 NotSupported。另外,欧易模拟盘有独立的订单簿,价格和实盘不同,不要用模拟盘行情做判断。

完整脚本:查余额、挂单、查挂单、撤单

下面的脚本流程是:查 USDT 余额 → 按市价的 70% 计算一个不会成交的限价买单 → 下单 → 查当前挂单 → 立即撤单。保存为 trade_demo.py,运行 python trade_demo.py binance 或 python trade_demo.py okx:

import os
import sys
import time

import ccxt

USE_TESTNET = True      # 先在币安现货测试网 / 欧易模拟盘跑通,再考虑改成 False
SYMBOL = "BTC/USDT"


def make_exchange(name):
    if name == "binance":
        ex = ccxt.binance({
            "apiKey": os.environ["BINANCE_API_KEY"],
            "secret": os.environ["BINANCE_API_SECRET"],
            "enableRateLimit": True,
            "options": {"defaultType": "spot", "fetchMarkets": {"types": ["spot"]}},
        })
    elif name == "okx":
        ex = ccxt.okx({
            "apiKey": os.environ["OKX_API_KEY"],
            "secret": os.environ["OKX_API_SECRET"],
            "password": os.environ["OKX_API_PASSPHRASE"],  # 欧易的 Passphrase 填在 password
            "enableRateLimit": True,
        })
    else:
        raise ValueError("只支持 binance 或 okx")
    if USE_TESTNET:
        ex.set_sandbox_mode(True)  # 币安→testnet.binance.vision;欧易→加请求头 x-simulated-trading: 1
    return ex


RETRYABLE = (ccxt.RequestTimeout, ccxt.ExchangeNotAvailable, ccxt.RateLimitExceeded, ccxt.DDoSProtection)


def with_retry(fn, *args, retries=3, **kwargs):
    """只用于查询类请求:网络抖动或限频时等待后重试。"""
    for i in range(retries):
        try:
            return fn(*args, **kwargs)
        except RETRYABLE as e:
            wait = 2 ** i
            print(f"{type(e).__name__},{wait} 秒后重试……")
            time.sleep(wait)
    return fn(*args, **kwargs)


def main(name):
    ex = make_exchange(name)
    with_retry(ex.load_markets)
    market = ex.market(SYMBOL)

    # 1. 查余额
    balance = with_retry(ex.fetch_balance)
    usdt = balance.get("USDT", {})
    print("USDT 可用:", usdt.get("free"), "冻结:", usdt.get("used"))

    # 2. 算一个远低于市价、不会成交的限价买单
    last = with_retry(ex.fetch_ticker, SYMBOL)["last"]
    price = float(ex.price_to_precision(SYMBOL, last * 0.7))
    min_cost = market["limits"]["cost"]["min"] or 5
    amount = max(market["limits"]["amount"]["min"], min_cost * 1.2 / price)
    amount = float(ex.amount_to_precision(SYMBOL, amount))
    print(f"准备挂单:买入 {amount} BTC,价格 {price}(市价约 {last})")

    # 3. 下单:不自动重试,避免网络超时后重复下单
    order = ex.create_limit_buy_order(SYMBOL, amount, price)
    print("下单成功,订单号:", order["id"], "状态:", order["status"])

    try:
        # 4. 查当前挂单
        open_orders = with_retry(ex.fetch_open_orders, SYMBOL)
        print("当前挂单:", [(o["id"], o["price"], o["amount"]) for o in open_orders])
    finally:
        # 5. 无论如何都撤掉刚才的订单
        ex.cancel_order(order["id"], SYMBOL)
        print("已撤单:", order["id"])


if __name__ == "__main__":
    name = sys.argv[1] if len(sys.argv) > 1 else "binance"
    try:
        main(name)
    except KeyError as e:
        print("缺少环境变量:", e)
    except ccxt.AuthenticationError as e:
        print("认证失败:检查 Key/Secret/Passphrase、IP 白名单、权限,以及是不是用了实盘 Key 连测试环境。", e)
    except ccxt.InsufficientFunds as e:
        print("余额不足:", e)
    except ccxt.InvalidOrder as e:
        print("订单参数不符合交易对规则(价格、数量、最小金额):", e)
    except ccxt.NetworkError as e:
        print("网络问题,稍后再试:", e)
    except ccxt.ExchangeError as e:
        print("交易所返回错误:", e)

这个脚本我们测到了哪一步?

查余额、下单这些私有接口需要你自己的测试网 Key。下面是 2026 年 10 月用这段代码实际运行的结果:

  • 没设环境变量时输出 缺少环境变量: 'BINANCE_API_KEY'。
  • 用假 Key 连币安测试网,异常被正确捕获:认证失败:…… binance {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."}。
  • 用假 Key 连欧易模拟盘:认证失败:…… okx {"msg":"Invalid OK-ACCESS-KEY","code":"50111"}。
  • 挂单参数计算(拦截请求、不实际发送):币安算出价格 57281.01、数量 0.0001、金额约 5.73 USDT,满足 5 USDT 最小金额;欧易算出价格 57849.3、数量 0.00010371。CCXT 实际发往币安测试网的是 POST /api/v3/order,发往欧易的是 POST /api/v5/trade/batch-orders,订单模式为现货 cash。

换成你自己的测试网 Key 后,正常会依次打印余额、挂单参数、订单号、当前挂单列表和「已撤单」。

两个细节:一是 CCXT 默认会在订单的自定义订单号里加上自己的标识前缀(币安是 x- 开头的 newClientOrderId,欧易是 clOrdId 和 tag),想用自己的订单号,可以在下单时通过 params 传入 newClientOrderId 或 clOrdId;二是 CCXT 对币安默认使用 10000 毫秒的 recvWindow,比币安文档默认的 5000 毫秒宽松。

新手用 CCXT 最常遇到哪些问题?

现象 原因 解决办法
BadSymbol: ... does not have market symbol 交易对写错,或该交易所没有这个交易对 用 BTC/USDT 这种统一写法,先 load_markets() 再查 ex.symbols
币安 load_markets 很慢 默认同时加载现货、U 本位和币本位合约市场 实测默认加载 4697 个市场用时约 1.6 秒,只加载现货是 3736 个、约 0.5 秒
欧易提示缺少 password 没传 Passphrase 在 password 参数里填 Passphrase
测试网能查行情,查余额报 -2015 用了实盘 Key,或测试网 Key 已随重置失效 到 testnet.binance.vision 重新生成 Key
订单状态一直是 open 限价单价格没到,正常挂单中 用 fetch_order 查询,或 cancel_order 撤单

订单的 status 字段在 CCXT 里统一为几种取值:open 表示还在挂单,closed 表示全部成交,canceled 表示已撤单。部分成交的订单仍然是 open,可以看 filled(已成交数量)和 remaining(剩余数量)两个字段判断进度。

CCXT 异常怎么处理?哪些错误可以重试?

CCXT 把各交易所的错误码映射成统一的异常类,大致分两类:

异常 含义 能否重试
RequestTimeout、ExchangeNotAvailable 超时、交易所暂时不可用 查询可以,下单要先确认
RateLimitExceeded、DDoSProtection 请求太快 等待后重试
InvalidNonce 时间戳过期,例如欧易 50102 对时后重试
AuthenticationError Key、签名、Passphrase、IP 有问题,例如币安 -2015、欧易 50113 不要重试,先修配置
InsufficientFunds 余额不足,例如欧易 51008 不要重试
InvalidOrder 订单参数违规,例如币安 -2010、欧易 51020 不要重试,改参数

前三类在 CCXT 里都属于 NetworkError,后三类属于 ExchangeError。下单请求超时并不代表没下成功:请求可能已经到达交易所,只是响应没回来。如果这时盲目重发,可能挂出两笔一样的订单。稳妥的做法是:下单时传入自己生成的订单号,超时后先用 fetch_open_orders 查一下这笔订单在不在,再决定是否补单。

常见问题

CCXT 连接欧易为什么提示缺少 password?

欧易的 API 除了 API Key 和 Secret Key,还需要创建 Key 时你自己设置的 Passphrase。在 CCXT 里 Passphrase 填在 password 参数中,不传或填错就无法调用余额、下单等私有接口,欧易会返回 50104 或 50105。

CCXT 查行情需要 API Key 吗?

不需要。fetch_ticker、fetch_ohlcv、fetch_order_book、load_markets 这些行情类方法调用的都是交易所公开接口,直接创建 ccxt.binance() 或 ccxt.okx() 实例就能用。只有查余额、下单、撤单等私有接口才需要 Key。

CCXT 下单报 InvalidOrder 怎么办?

InvalidOrder 通常是订单参数不符合交易对规则,例如价格步长不对、数量低于最小值、下单金额低于最小金额,或限价偏离市价太多。先用 load_markets 读出精度和限制,再用 amount_to_precision 和 price_to_precision 规整。

CCXT 支持币安测试网和欧易模拟盘吗?

支持。截至 CCXT 4.5.89,对币安调用 set_sandbox_mode(True) 会切到现货测试网,enable_demo_trading(True) 会切到币安模拟交易;对欧易调用 set_sandbox_mode(True) 会自动加上 x-simulated-trading: 1 请求头。三者都要配合对应环境的专用 Key。

CCXT 的 enableRateLimit 有什么用?

开启后,CCXT 会按交易所的限频规则在请求之间自动等待,避免请求过快被拒绝或封禁 IP。新版 CCXT 默认就是开启状态,代码里写上可以让意图更清楚。

准备好出发了吗?

币安邀请
币安

全球交易量最大的加密货币交易所之一,币种与流动性领先

邀请码
注册币安 ↗含推广链接 · 注册前请确认当地法规 · 币安评测
欧易邀请
欧易

老牌头部交易所,App 体验与 Web3 钱包整合出色

邀请码
注册欧易 ↗含推广链接 · 注册前请确认当地法规 · 欧易评测

参考来源

  1. CCXT 官方文档(Manual)
  2. Binance Spot API 文档:Filters(PRICE_FILTER、LOT_SIZE、NOTIONAL)
  3. Binance Spot Test Network
  4. OKX API v5 文档:Demo Trading Services

以上信息核实于 2026-10-22,交易所规则可能调整,请以官方最新说明为准。

本文仅供学习参考,不构成投资建议。交易所的费率、活动与功能可能随时调整,请以官方页面为准。文中部分链接为推广链接,详见推广披露。