这是课程《套利:从零开始,写出自己的扫描器》的第1课。你不需要交易经验,只需要会 Python,并抽出十分钟。
用铅笔举个例子
想象一条街上有两家商店。A 店以 100 美元卖一双运动鞋,B 店愿意以 108 美元向任何人收购同一双鞋。你在 A 店买下鞋,走二十米到 B 店卖掉,赚下 8 美元。你不用赌运动鞋会不会更受欢迎。你只需要发现两家店的价格不一样。
这就是套利:在便宜的地方买入某样东西,同时在贵的地方卖出同样的东西,并留下差价。
这句话里有两个要点:
- “同样的东西”:两家店里的运动鞋完全相同;
- “同时”:如果等一周,价格可能会变,差价也可能消失。
为什么会有差价?
在加密货币交易所,每秒都有成千上万的人和程序买卖比特币。每家交易所都有各自的交易者,所以价格会略有不同。消息传到它们那里的时间也不完全一样。资金在交易所之间转移得比较慢。因此,同一种币在两家交易所的价格几乎相同,却很少完全一样。
监视并缩小这些差价的程序,正是差价一直很小的原因。今天你会编写一个非常简化的版本。
必须认识的两个词:买价和卖价
交易所会列出一张报价清单。想买的人会报出自己愿意买入的价格,想卖的人会报出自己愿意卖出的价格。
- **买价(Bid)**是此刻有人愿意为这枚币支付的最高价格。
- **卖价(Ask)**是此刻有人愿意卖出这枚币的最低价格。
如果你想马上买入,就要付卖价。如果你想马上卖出,就会收到买价。在同一家交易所,卖价总是高于买价。两者之间的距离叫作价差,这是交易所内交易本身带来的成本。
看一个简单的数字例子:
| 买价(你在此卖出) | 卖价(你在此买入) | |
|---|---|---|
| 交易所 A | 100.00 | 100.10 |
| 交易所 B | 100.30 | 100.40 |
在 A 以卖价 100.10 买入,在 B 以买价 100.30 卖出。差价是每枚币 100.30 − 100.10 = 0.20。买卖 1000 枚,手续费前就是 200。
现在反过来:在 B 以 100.40 买入,在 A 以 100.00 卖出。每枚币会亏 0.40。所以差价即便存在,也只会出现在一个方向。
用一行规则表示:
差价 = 卖出位置的买价 − 买入位置的卖价。
如果差价为正,就值得看一看。如果为零或负数,就没什么可做的。
写代码前,先了解三个实际问题
- 手续费。每家交易所都会从每笔交易中收取一小部分费用。价格为 100 时,0.20 的差价是 0.2%。如果两笔交易的手续费加起来也是 0.2%,利润就为零。后面的课程会仔细讲手续费。
- 数量。最佳买价和最佳卖价只对少量币有效。如果想交易更多,就会按更差的价格逐档成交下一批报价。第 9、10 课会讲这个问题。
- 速度。等你看到差价时,可能已经有人把它抹平了。第 11 课会讲这个问题。
今天的程序就像温度计:它会显示有没有差价,但不会告诉你能不能靠它赚钱。
小型扫描器
这个扫描器故意采用最直接的方式:每家交易所一次请求,一次减法,不考虑手续费、数量或错误处理。它是能完成任务的最简单程序,但会在后面的课程里暴露问题(第 4 课讲手续费,第 9 课讲订单簿深度,第 11 课讲时机)。先搭建这个直接版本,这样之后的每一个改进,都能解决你已经见过的问题。
程序会向两家交易所查询同一种币的最佳买价和最佳卖价,并打印两个方向的差价。它只使用公开数据,不需要账户、API 密钥或资金。
import json
import urllib.request
def get(url):
with urllib.request.urlopen(url, timeout=10) as r:
return json.load(r)
# 交易所 A:Binance,BTC / USDT 币对
a = get("https://api.binance.com/api/v3/ticker/bookTicker?symbol=BTCUSDT")
a_bid, a_ask = float(a["bidPrice"]), float(a["askPrice"])
# 交易所 B:Kraken,同一种币
b = get("https://api.kraken.com/0/public/Ticker?pair=XBTUSDT")
b = next(iter(b["result"].values()))
b_bid, b_ask = float(b["b"][0]), float(b["a"][0])
print("A bid/ask:", a_bid, a_ask)
print("B bid/ask:", b_bid, b_ask)
print("buy A, sell B:", round(b_bid - a_ask, 2))
print("buy B, sell A:", round(a_bid - b_ask, 2))
把它保存为 scanner.py,然后运行 python3 scanner.py。
你应该看到什么结果
你会看到四个价格和两个数字。对于两家大型交易所上的比特币,这两个数字通常是负数或接近零。有时其中一个会是小幅正数。一次测试中,一家交易所的买价和卖价在 75,782 左右,另一家在 75,786 左右,因此一个方向显示 +3.89,另一个方向显示 −4.00。正数对应的差价是 3.89 / 75,782 = 0.005%,远低于约 0.2% 的手续费。这很正常,也正是这一课的重点:在交易活跃的交易所买卖流动性高的币,市场效率很高,足以支付手续费的差价既少见,持续时间也很短。
每隔一分钟运行一次程序,运行几次。观察这两个数字如何变化,并记下你看到的最大值。
如果某个请求失败了,可能是交易所屏蔽了你所在的国家或网络。可以换成另一个提供公开价格接口的交易所。程序的结构不变。
让 AI 智能体帮你敲代码
在这门课程里,你会和 Claude Code 或 Codex 这样的 AI 智能体一起编写自己的套利机器人。智能体负责写代码,你来决定要做什么并检查结果。检查这一步不能交给别人:智能体可能会打印一个看似可信、实际却错误的数字。
比较一下两种提出今天这个程序需求的方式。
含糊的请求:
给我做一个套利扫描器。
智能体只能猜所有细节:用哪些交易所、选哪种币、“扫描器”应该打印什么、是否计算手续费。它可能会做出一个很大的程序,让你看不懂。
把需求说清楚的请求:
用 Python 编写 scanner.py,不要使用额外的库。通过 Binance 和 Kraken 的公开 REST 接口,获取 BTC/USDT 的最佳买价和最佳卖价。打印两个交易所的报价,以及两个方向的差价,按卖出买价减去买入卖价来计算。不要 API 密钥,不要交易。代码控制在 40 行以内,并把交易对符号放在文件顶部。
这样你就能自己检查结果:每个方向的差价都必须等于一个买价减去一个卖价,你可以用计算器验证。整个课程都要保持这个习惯:每次只要一小部分代码,运行它,手算核对一个数字,然后保存一个版本(用 git 提交,或者直接复制文件)。
练习
- 运行扫描器三次,每次记下四个价格和两个差价。
- 把
BTCUSDT和XBTUSDT换成两家交易所都支持的另一种币(例如 ETH)。它的差价比比特币更大还是更小?交易较少的币通常差价更大。想想为什么。 - 手算差价占买入价格的百分比:
gap / ask * 100。再与每家交易所收取 0.1%、总计 0.2% 的手续费比较。你运行的三次中,有没有一次超过这个数?
接下来学什么
今天你比较了两个数字。真正的套利系统会对成千上万个交易对和许多家交易所做同样的事,然后仔细检查最有希望的候选项。第 2 课会介绍不同类型的套利,第 3 课会讲每个系统都要经过哪些阶段。