
如果你在 Bitfinex 上做过借贷一定体会过“手动挂着时不时刷一下利率”的滋味。利率不是恒定不变的报价单挂在市场里可能几小时都不成交也可能下一秒就被人借走。更麻烦的是一笔借贷到期之后如果不去重新挂单资金就躺在那吃土。看到“Show HN: Bitfinex lending automation that runs on your PC, not a server”这个标题很多人第一反应可能是“哦又一个自动挂单脚本”。但真正让我停下来的是后半句runs on your PC, not a server。这不是一个部署方式的差异而是一整套关于密钥、控制权、运行成本和故障责任的取舍。这篇东西不打算复述那个项目本身因为拿到的信息只有标题我想借这个切入把“在本地跑一个 Bitfinex 借贷自动化”从最小可运行版本讲到可长期维护把最容易忽略的坑一个个点出来。1. 先想清楚“PC 而不是服务器”到底省了什么又带来了什么1.1 借贷自动化到底在自动化什么借贷自动化的对象是一连串重复且低认知的操作。Bitfinex 的借贷市场可以理解成一个资金撮合市场有资金的人把资产挂出去标明愿意借出的金额、期限和利率需要用资金的人按自己的条件来成交。整个过程有几个状态需要盯住市场利率随时变化自己挂的订单可能未成交、部分成交、全部成交已经成交的借贷契约会到期到期后资金回到账户如果设置自动续借到期后平台会按规则重新报价如果没有设置自动续借你需要重新挂单。人的精力很难持续跟踪这些状态。手动操作通常是每隔一段时间刷一次页面看到利率合适就点一下挂单看到订单没成交就撤掉重挂。一天下来时间花了不少实际收益可能并不高。更重要的是手动操作很容易受情绪影响利率稍微往下滑一点就犹豫要不要降价看到行情波动又担心资金借出去后错过机会。自动化要做的就是把这些状态检查和订单操作固化成一段逻辑。脚本定期拉取账户余额、市场利率、当前活动订单然后根据预设规则决定是新建订单、修改订单还是撤销订单。整个过程不引入情绪也不依赖人盯着页面。这里的关键认知是自动化解决的是“重复操作”和“反应速度”问题它不解决“策略是否盈利”问题。如果你的利率阈值、资金分配思路本身有问题脚本只会让你用一个更快的方式重复错误。1.2 “PC”和“服务器”的真实差异不仅仅是钱的问题标题特意强调“runs on your PC, not a server”说明作者认为这是一个卖点。但从工程角度看这个选择带来的是一组交换。先说服务器方案。把脚本放在一台 24 小时开机、公网可达的 VPS 上天然有几个优势稳定在线、断网概率低、不容易被人为关闭、还能通过公网 API 随时远程查看状态。但它的代价同样明显API 密钥存放在远程机器上一旦机器被入侵、配置错误或第三方日志泄露密钥就暴露了你需要额外处理服务器的系统更新、安全补丁、防火墙规则服务器本身有租金即使一个月几美元对小资金量用户来说也可能吃掉了相当比例的收益。本地 PC 方案正好相反。密钥和脚本都留在自己手里被第三方窃取的风险面更小运行成本为零调试也非常直观打开终端就能看日志改脚本不需要走远端部署流程。但你要付出的是电脑要保持开机、不休眠、不断网操作系统更新、蓝屏、意外重启都会让脚本中断一旦你需要出门而电脑被人碰到或者系统弹出验证窗口可能就在你不知情时停掉了公网调用和第三方通知如果都依赖本地网络故障修复会慢半拍。把这个对比列出来能更清楚看到边界维度本地 PC 方案服务器方案密钥存放位置本地硬盘自己控制远程磁盘风险更高运行时长依赖 PC 通电和系统状态通常 7x24 稳定网络异常影响家庭网络波动就能中断数据中心网络更稳定额外成本几乎没有每月租金部署复杂度低本机直接运行需要远程环境搭建维护方式人工看本机日志需要远程登录或告警故障恢复必须回到本机前可远程处理适合资金量小到中等个人策略较大资金、多账户、重度依赖没有哪个方案绝对正确。我的判断是对绝大多数刚开始尝试借贷自动化、资金量还在个人级别、策略还处在“边用边改”阶段的用户本地 PC 是更合理的起点。因为这时候你更需要的是快速迭代、低摩擦试错和密钥风险控制而不是那种“全年无休”的工业级稳定性。1.3 本地运行真正意味着什么把控制权收回来很多人把“跑在哪”理解成“省不省服务器钱”。在我看来这个标题真正有价值的信息是它强调了用户对运行环境的控制权。服务器方案隐藏着一个容易被忽略的问题你是在把资金管理工具放在一个不完全受你控制的机器上。无论平台宣称多安全多一层传输、多一个第三方机器就多一个攻击面。而本地运行至少可以让密钥只存在于你亲自控制的磁盘和内存里减少中间环节。对交易类工具来说这个因素甚至比高可用更重要。当然控制权也意味着责任。本地脚本崩溃了不会有人给你发告警你必须自己设计监控电脑休眠了你必须自己禁用睡眠密钥丢了你必须自己备份和恢复。这并不适合所有人。所以在决定“跑在 PC 上”之前先问自己一句我能不能接受这台电脑以后不随便关机并且我愿意为它写一个“看门狗”脚本如果答案是犹豫那可能服务器方案才是更适合你的起点。2. 一个最小可运行的本地借贷自动化应该先长成什么样2.1 先准备好环境能少装就少装很多人一上来就想把架构设计得很全要数据库、消息队列、Docker、监控大盘。对于一个个人借贷自动化脚本来说前期真不需要这些。最少的环境是这样的一台普通的开发电脑一个脚本语言运行时比如 Python 或 Node.jsHTTP 请求库官方 API 文档一个可以写日志的目录。Python 环境的常见配置可以是这样# 示例结构不要直接运行 pip install requests如果你的机器已经装了其他环境不需要为此创建新的虚拟机或容器。借贷自动化不是高频交易系统它的核心逻辑非常简单查询、条件判断、下单。复杂的是异常处理和长期数据积累而不是运行环境本身。2.2 API 密钥权限最小化别拿主账户密钥随便试在 Bitfinex 这类交易所创建 API 密钥时通常可以选择权限范围。一个常见的错误是为了省事把“读取”“交易”“提现”“借入”等权限全部勾上。对于借贷自动化正确的做法是只勾选它必需的最小权限查询账户余额和订单状态创建和取消借贷订单也许还需要查询市场资金利率。尽量不要给脚本开通提现权限。自动化的交易工具只需要在账户内部挂订单、撤订单用不到把资产转走的权限。万一脚本被外部利用最小权限可以直接避免资产被转走。此外还需要留意 API 密钥是否绑定 IP 限制。本地 PC 的公网 IP 经常变化如果开启了 IP 白名单更新不及时会导致调用失败。这里还要提醒一个经验先用测试账户或者极小的金额验证权限是否够用。不要一上来就把大资金交给一个“读权限不够”的脚本结果它连余额都查不到你还以为是网络问题。2.3 最小轮询循环先跑通再谈策略一个可用的自动化脚本不需要很复杂。它至少包含四个步骤读取账户余额拉取市场资金利率判断是否需要挂单通过 API 创建订单。用伪代码描述大概是这个结构# 示例结构不要直接用于真实资金 import time import requests API_KEY 你的密钥 API_SECRET 你的私钥 BASE_URL https://api.example.com # 以官方文档为准 def get_free_balance(): # 调用余额接口返回可用于借贷的资金数量 pass def get_market_rate(): # 调用市场利率接口返回当前最优借贷利率 pass def create_offer(amount, rate, period): # 调用创建借贷订单接口返回订单信息 pass def cancel_offer(offer_id): # 调用撤销订单接口 pass while True: try: balance get_free_balance() rate get_market_rate() if rate TARGET_RATE: create_offer(balance * 0.9, rate, 2) time.sleep(60) except Exception as e: print(error:, e) time.sleep(60)这个骨架能跑但离“生产可用”还很远。它没有处理 API 返回状态、没有幂等、没有日志持久化、没有异常分类。但它的价值是让你先在一条清晰链路上把期望的效果看到能查询余额、能拿到利率、能创建订单。这一步跑通后面补工程细节才有意义。2.4 参数看起来简单但每个参数背后都有一个坑脚本里往往有几个关键参数新手很容易随手填TARGET_RATE你愿意接受的最低利率。设得太高可能长时间不成交设得太低可能导致收益很差。建议先参考历史区间取一个中间值观察一段时间再调。借贷金额比例不要一次把全部可用余额都挂出去。留一小部分应对提现、转账和补保证金的意外需求。常见经验是挂可用余额的 80% 到 90%。借贷期限Bitfinex 常见的资金借贷期限是按“天”为周期有的平台支持自动续借。这个要以官方文档为准。如果不设期限订单可能只能用默认值。轮询间隔间隔太密会触发限流太疏会错过利率窗口。对个人借贷来说1 到 5 分钟是常见选择。先把间隔调大确认稳定后再缩小。这些参数不能照抄别人因为账户资金量、网络延迟、平台风控规则都不一样。最好的方式是先用一个低风险配置跑一两天看日志里的成交记录和错误信息再逐步调整。3. 从单次成功到稳定运行必须补上的工程化细节3.1 错误处理把“未知异常”拆成“可重试”和“必须停”最小骨架里的except Exception把所有问题一视同仁。这在早期可以但一旦进入真实运行就会很危险。网络超时这类是瞬时错误。可以重试两三次但要用指数退避不要立刻重试。连续失败多次后等待时间要拉长。鉴权失败API 密钥无效、签名错误、IP 被限制。这类错误反复重试没有意义反而可能触发更严格的风控。正确做法是停止脚本并发出告警让你人工检查。请求参数错误订单金额太小、利率超出平台允许范围、期限不合法。这类通常是代码 bug 或配置错误也需要人工介入。频率限制平台返回 429 或类似限流响应。这时候不能硬刚最好记录响应头里的Retry-After等待合适的时长再继续。一个更接近真实运行的处理分支是这样的try: balance get_free_balance() rate get_market_rate() if should_create_offer(balance, rate): result create_offer(...) log.info(fcreated offer: {result}) except ApiAuthError: alarm(API auth failed, stop) raise SystemExit(1) except RateLimitError as e: wait_time e.retry_after or 60 log.warning(frate limited, wait {wait_time}) time.sleep(wait_time) except NetworkError: retry_count 1 if retry_count 3: alarm(network error too many times) retry_count 0 time.sleep(300) else: time.sleep(10)这个代码是示例但你应该能看出真正的自动化脚本里“错误后怎么办”比“正常流程怎么办”更关键。因为它决定了脚本长期运行是“自我恢复”还是“带病运行”。3.2 日志和审计别等出问题才后悔没记录借贷自动化的操作对象是真金白银所以日志不只是调试工具更是审计证据。建议至少记录以下信息每次循环的开始时间和结束时间每次 API 请求的方法、路径、参数哈希、返回状态码每次创建/修改/撤销订单的完整响应每次异常发生的堆栈和上下文本地策略参数的快照比如当前设置的阈值、金额比例、间隔。实际落地时最简单的做法是把日志输出到文件。Python 里可以用logging库同时输出到控制台和文件并设置RotatingFileHandler防止文件无限膨胀。关键操作日志可以单独存一份比如audit.log只记录创建订单、撤销订单、修改参数等敏感动作。如果平台上支持客户端订单 ID尽量在创建订单时传入唯一 ID这样后续可以通过 ID 回查不至于同一笔订单被脚本重复处理时完全无迹可寻。3.3 幂等性自动化最容易翻车的“重复下单”本地脚本崩溃后重启或者网络超时但服务端实际已经创建了订单这两种情况都可能导致重复挂单。一个借贷自动化脚本如果没有幂等机制可能在重启后产生一堆重复订单白白占用资金甚至触发平台的异常风控。常用的幂等策略包括本地状态文件脚本启动时读取自己最后一轮保存的状态然后和交易所实际的活动订单做比对。客户端订单 ID如果 API 支持在创建订单时带上一个在本地生成的唯一 ID服务端可以用这个 ID 去重。启动时“先查后下”每次创建订单前先列出当前活动订单如果没有对应订单再创建。如果发现已经被创建的订单但本地不记得就记录到本地状态跳过创建。不要以为“我的脚本不会崩溃”。PC 上的脚本会因为内存溢出、系统更新、电源异常、手动关闭终端而崩溃。设计幂等是为了让崩溃后的恢复不需要人工核对每一笔订单。3.4 时间同步一个容易被忽视的签名失败来源交易所 API 的很多请求需要携带签名。签名通常会包含时间戳用于防止重放。如果你的电脑系统时间出现偏差API 会直接拒绝请求返回一个类似“时间戳不合法”的错误。这类问题的一个隐蔽场景是电脑休眠一段时间后恢复系统时钟没有重新同步而脚本已经用错误的时间戳发了请求。解决方式很简单在操作系统里开启自动时间同步脚本启动时检查当前时间和标准时间例如通过 NTP 服务器的偏差如果偏差超过一定阈值就拒绝启动并提示用户校正时间。另外脚本内部计算订单时间、日志时间时最好统一使用 UTC 时间戳避免时区转换带来的混淆。尤其在做跨日统计时本地时间的“今天凌晨”和 UTC 的“今天 0 点”不是一回事。3.5 本地监控让电脑帮你看着脚本而不是让你一直盯着电脑既然跑在本地就需要一个“看门狗”。最简单的方式是利用操作系统本身Windows 下可以用“任务计划程序”定时执行一个检查脚本如果发现主脚本不是运行状态就重新启动它。Linux 下可以用 systemd 服务或 cron 定时检查。看门狗本身可以很小只做三件事检查主脚本进程是否存在检查心跳文件是否在一段时间内更新过比如最近 10 分钟如果以上条件不满足就尝试重启主脚本或者执行一个告警动作。告警方式不需要很复杂。常见的有邮件、即时通信机器人。如果你不想引入过多依赖至少可以写一个日志文件等自己有空时看一眼。但如果资金量大到你觉得“半天不看就难受”那就要把告警加上。注意告警不是让脚本“自动解决问题”而是让人尽快知道故障。很多故障是无法自动恢复的比如 API 密钥失效、订单参数错误人不在脚本重启多少次都是白搭。4. 常见问题排查不是猜而是按一条固定链路走4.1 现象第一次跑成功第二次跑不成功这是本地自动化脚本最经典的现象。昨天还能正常挂单今天一运行就报错。很多人的第一反应是“是不是交易所出问题了”实际上大多数情况都不是。排查时应该按输入、环境、权限、参数、日志这个顺序来输入API 密钥是否过期或变更脚本读取的配置文件是否被改过密钥文件路径是否还是原来的环境当前电脑时间和标准时间是否一致网络能否正常访问 API 域名系统是否处于睡眠或网络受限状态权限API 密钥的权限是否被改成只读是否触发了 IP 白名单账户是否因为其他原因被限制交易参数当前余额是否少到不满足订单最小量利率阈值是否高到市场不可能成交订单数量是否达到平台限制日志回到日志文件看第一次成功和失败之间发生了什么变化。失败时的响应体是什么状态码是什么每一步都不要停留太久。先用一个最小的请求去测试 API 是否通再逐步放大。4.2 常见错误背后的真实原因“余额不足”但你在账户里明明看到有资产这里的“余额”可能是冻结余额已经被其他订单占用了。“利率无效”或“订单被拒绝”平台可能对借贷利率区间、最小金额有硬性限制。检查 API 文档里的合法范围而不是相信脚本里写的默认值。“请求频率过高”多次快速循环导致限流。先停止脚本一段时间等限流解除再把轮询间隔调大。“签名失败”优先检查时间同步。其次才是密钥和签名算法是否正确。“订单一直未成交”可能不是 bug而是市场流动性不足或者你挂的利率没有竞争力。这种情况不应该撤单重挂而是要结合行情判断。要记住API 返回的错误码和响应信息通常比日志里的一句话更有价值。遇到问题不要只盯着脚本的控制台输出要把 HTTP 响应体完整地打出来。4.3 边界脚本永远只是执行工具不做情绪的放大器本地借贷自动化的边界在于它并不能降低策略本身的风险。你挂出去的资产仍然会面临市场波动、平台风控、借贷方违约等风险。自动化能把“我想挂单”这个动作做成秒级响应但它不改变借贷市场的本质。所以在实际使用中要给自己设定一些底线最多只用账户里“允许闲置”的资金做自动化不要所有资金都挂进去。设置合理的利率阈值不要为了追求“高成交”而无限压低利率最后拿到不划算的收益。脚本里不引入“梭哈”式的资金管理逻辑每一次发单都应该是可回退的。如果你发现自己开始频繁修改参数去追行情那就先停一停。自动化的价值是让重复部分自动化而不是把人的贪婪和焦虑也自动化。5. 从本地脚本到长期策略个人开发者的四条演进路径5.1 第一阶段手动触发脚本最初版本不需要开机自启、不需要守护只需要在你想跑的时候运行一下。这个阶段适合验证 API 密钥、熟悉数据结构、确认账户操作是否正常。5.2 第二阶段由操作系统定时调度当脚本逻辑稳定后可以用任务计划程序或 cron 定时触发。这个阶段要把电脑设置成“从不睡眠”并在脚本里加入幂等和日志。此时你才真正拥有一个“本地常驻”的自动化系统。5.3 第三阶段策略参数独立化把利率阈值、借贷金额比例、检查间隔、是否启用自动续借等从硬编码中移到配置文件中。这会让后续调整策略变得容易也能在不改代码的情况下应对行情变化。同一个脚本可以根据不同配置组合跑出不同策略的对比效果。5.4 第四阶段加入模拟盘或极小资金验证很多交易所提供模拟环境可以先在模拟盘上跑一整天观察成交率和收益曲线。没有模拟盘就用最小资金跑让脚本经历完整的挂单、成交、到期、重新挂单流程。这一步能发现很多“日志上看起来没问题但实际资金行为不对劲”的 bug。5.5 什么时候才需要迁移到服务器“跑在 PC 上”是一个理性选择但不是一个永久选择。当以下情况出现时你应该认真考虑迁移到服务器PC 经常断电、休眠或被家人误关你需要同时运行多个账户或策略本机资源开始吃紧你希望脚本不依赖某台具体电脑方便随时远程查看或重启资金量已经大到“停机一小时”的损失超过服务器年费。迁移不是简单把脚本复制过去。你需要重新处理密钥存储、系统日志、防火墙、远程访问安全等问题。可以先在服务器上用小资金运行一两周再逐步切换主账户。那么回到最初那个标题。Bitfinex 借贷自动化跑在 PC 上还是服务器上本质上不是一道“哪个更好”的选择题而是一道“你愿意在哪里承担风险、在哪里保有控制、在哪里付出维护成本”的思考题。我个人的观点很明确如果这是一个个人项目如果你还在摸索策略如果你的资金量还没有大到需要 7x24 小时机器待命那么先跑在本地 PC 上是一个让你对每一步都有掌控感的起点。但自动化真正考验你的永远不是那几行循环代码而是你面对异常时有没有一套及时止损、可追溯、可恢复的手段。