用 Python 构建一个 Bitfinex 放贷机器人
Bitfinex 的 API 用来做自动化确实很顺手,一个最小可用的放贷机器人大约六十行 Python 就能写完,除 requests 外没有任何依赖。本教程真刀真枪地做一个:限定权限的密钥、轮询利率、签名下单、一个朴素的策略循环。文末有一节坦诚的讨论,讲这六十行与一个你敢托付真实余额的机器人之间的差距——因为真正的工作量在那个差距里,不在这些 API 调用里。
我们要做什么
一个盯着 USD 融资市场的机器人:始终挂一笔比当前 Flash Return Rate(FRR)高 10% 的报价,等借款需求自己找上门。这个单一行为——始终在市场上方挂着报价——是大多数融资策略的核心,因为利率飙升太短,手动根本追不上。
前置条件:Python 3.10+、pip install requests、一个 Bitfinex 账户,以及资金钱包里 $150 以上的资金(交易所的单笔报价最低额度)。其余全在下文。
第 0 步:一把伤不到你的密钥
在 Bitfinex 创建 API 密钥(API Keys → Create New Key),只勾选这些权限:Margin Funding 读 + 写、Wallets 读、Account Info 读。提现和交易全部关闭——放贷机器人永远用不着它们,而一把限定权限的密钥意味着即使泄露,最坏也只是把你的放贷定错价,绝不可能掏空你的账户。
逐项权限的完整说明见我们的面向放贷者的 Bitfinex API 指南;简单说,本文的一切只需要上述权限,多一项都不用。
第 1 步:读取行情(不需要密钥)
利率是公开的。融资 ticker 在索引 0 处返回按日计的 FRR——乘以 365 就是 APR。这个循环就是机器人的眼睛:
跑起来你就有了一条实时利率数据流。现在就要内化两条惯例:Bitfinex 的所有利率都是按日计的(0.0003 ≈ 10.95% APR),而且所有利率都是毛利率——交易所会抽走已赚利息的 15%,所以乘以 0.85 才是真正落进你钱包的数字。
import requests, time
PUB = "https://api-pub.bitfinex.com"
def frr_apr(symbol: str = "fUSD") -> float:
ticker = requests.get(f"{PUB}/v2/ticker/{symbol}", timeout=10).json()
return ticker[0] * 365 * 100 # index 0 = FRR, a daily rate
while True:
print(f"FRR now: {frr_apr():.2f}% APR")
time.sleep(300) # poll every 5 minutes — stay well inside rate limits
第 2 步:提交一笔签名报价
写操作需要鉴权:对路径做 HMAC-SHA384 签名、一个严格递增的 nonce,再加上 JSON 请求体。这就是整个鉴权层——不需要任何 SDK:
period 是以天计的贷款期限(2–120)。短期限让你保持流动性;长期限把利率锁死。金额是字符串,最低 $150 等值。如果你收到 nonce: small 错误,说明另一个进程用了这把密钥——永远一把密钥对应一个进程。
import hashlib, hmac, json, time, requests
KEY, SECRET = "your-key", "your-secret"
BASE = "https://api.bitfinex.com"
def auth_post(path: str, body: dict):
nonce = str(int(time.time() * 1_000_000)) # must strictly increase per key
raw = f"/api/{path}{nonce}{json.dumps(body)}"
sig = hmac.new(SECRET.encode(), raw.encode(), hashlib.sha384).hexdigest()
return requests.post(f"{BASE}/{path}", data=json.dumps(body), timeout=15, headers={
"bfx-nonce": nonce, "bfx-apikey": KEY, "bfx-signature": sig,
"content-type": "application/json",
}).json()
def place_offer(rate_daily: float, amount: str = "150", period: int = 2):
return auth_post("v2/auth/w/funding/offer/submit", {
"type": "LIMIT", "symbol": "fUSD",
"amount": amount, "rate": f"{rate_daily:.8f}", "period": period,
})
第 3 步:策略循环
现在是机器人本体:如果没有报价在挂,就挂一笔比当前 FRR 高 10% 的报价,然后等待。利率上冲时借款需求会把它吃掉;否则它就静静待着。这是百分位下限的一个粗糙版本——用固定加价代替了随市场状态自适应的加价:
这就是一个能运转的放贷机器人。它确实会赚到融资利息,在平静的几周里也不会让你难堪。但它同样是——刻意为之——故事的开头,而不是结尾。
def tick():
apr = frr_apr()
# naive floor strategy: rest 10% above the current FRR and wait to be hit
target_daily = (apr * 1.10) / 365 / 100
offers = auth_post("v2/auth/r/funding/offers/fUSD", {})
if not offers: # nothing resting -> place one
place_offer(target_daily)
# a real bot also reprices stale offers, sizes per wallet balance,
# handles partial fills, retries 429s, and survives restarts
while True:
tick()
time.sleep(600)
这 60 行没有做的事
坦诚清单——每一条都是业余机器人悄悄死掉的地方:
- 策略。"FRR + 10%" 是拍脑袋的。下限应该设在过去 60 天的第 96 百分位吗?利率处于状态高位时应该锁 120 天吗?要答好这些问题,需要用多年数据回放规则——这就是脚本和策略的区别。
- 重新定价。市场一动,挂着的报价就会过时。生产级机器人会持续对照当前订单簿重新定价,同时不把即将成交的单子折腾没了。
- 状态与重启。循环中途崩溃后重启:哪些报价是你的?宕机期间成交了什么?把交易所状态和你的意图对齐,才是一个真正的机器人的大部分代码。
- 故障处理。429 限流、5xx 响应、WebSocket 掉线、nonce 冲突、部分成交、贷款提前归还——每一种都需要一个决策,而不是凌晨三点的一个未捕获异常。
- 记账。你的真实收益在账本里(利息入账减去 15% 费用),不在你报出的利率里。逐笔核对账本条目,才能让收益和税务数字变成真的。
教程 FAQ
在 Bitfinex 上跑机器人合法/被允许吗?
允许——API 就是为此存在的,融资自动化是官方明确支持的用途。遵守各端点的限流(HTTP 429 意味着要退避),并保持一把 API 密钥对应一个进程。
我该用官方的 bfxapi 库来代替裸 requests 吗?
生产环境大概率该用——它替你维护签名、重连和 WebSocket 这些管道。本教程手写鉴权,是为了让你看清线路上到底发生了什么;这些概念可以直接迁移。
这样的机器人能赚多少?
融资市场付多少它就赚多少——历史上 USD 在平静状态约 8–12% 毛 APR,需求飙升时更高,再减去交易所 15% 的费用。机器人不创造收益;它只是比手动放贷更可靠地捕获市场收益。真实分布请看我们的三年数据研究。
自己造,或者直接跳到策略这一层
这个机器人所有的难点都在策略和可靠性上,不在 API 调用上。Stratum 就是那个生产层:11 个经过回测的策略、重新定价、状态核对和报表,同样基于禁用提现的密钥权限——固定费用,不抽收益分成。或者拿走上面的代码,自己掌控整套体系;无论哪种,这个页面都会留在这里。