Tools · 2026.10.02 · 5 min · Updated 2026.10.26
Automating a Bitfinex Lending Rate Report: A Claude Code Routine Opens a PR, a Human Merges It
The rate report is calculated only from Bitfinex's public candles, so anyone can reproduce it. A Claude Code cloud routine opens a PR every month, but nothing merges until a person reviews it.
Reading
If Claude Code writes a public Bitfinex lending rate report every month, other people need to be able to verify the numbers, and someone has to review the content.
Two decisions make that work. First, the numbers are calculated only from Bitfinex's public funding candles, so anyone can recalculate them, and they never touch my pricing method.
Second, producing the report is left to a Claude Code cloud routine that opens a PR every month but never merges, so every issue waits for my review.
In a trial run, the regenerated August numbers were identical to the version in the repo, which doubled as proof that the report can be reproduced.
The report lives in the guides section of EZLO, my Bitfinex auto-lending platform. I built it because people keep searching for "Bitfinex lending rates".
I wanted it to be something others could cite, without depending on me remembering to run it by hand every month.
Public candles only
EZLO records its own internal rate snapshots, but the report doesn't use them.
The data comes only from Bitfinex's public api-pub.bitfinex.com/v2/candles: mainly the 2-day period, with the 30-day and 120-day periods as comparisons, for both USD and USDT.
How the numbers are defined:
- Average annualized rate: hourly closing rates for the 2-day period, volume-weighted, multiplied by 365.
- After fees: further multiplied by 0.85, since Bitfinex takes 15% of lending income. Idle time isn't accounted for yet.
- Typical range: the volume-weighted P10 to P90 percentiles.
- Trend: monthly averages of the 2-day rate over the last 12 months.
Months are always cut in UTC, and the method is written up in the page's "How the numbers are calculated" section. For August, the 2-day average annualized rate was 7.11% for USD and 6.22% for USDT.
The August report, with the method written on the page.
Three kinds of things are deliberately left out: time-of-day patterns the engine has observed, how EZLO prices its offers, and EZLO users' returns.
The report only contains numbers anyone could calculate.
A metric has to say something
I originally wanted to count "hot days" with annualized rates above 15%, but over the last 12 months that was 0 every time. A column of zeros carries no information.
So I switched to "cold days" with a daily average annualized rate below 5%.
Single-trade highs and lows aren't listed either, since small trades often print numbers like 0% or 511%.
There's also a unit trap. Candles and the ticker give daily rates, but the FRR (the market-average lending rate) from funding/stats is the daily rate divided by 365 again. Mix the two up and you're off by a factor of 365.
Different APIs use different rate units, so check before mixing them.
The commentary has hard rules too: every number must trace back to the JSON, no predictions, no guessing at causes.
One routine, never merges
Scheduling uses a Claude Code cloud routine that runs at 10 a.m. Taipei time on the 2nd of every month.
One routine covers the whole job: run the script, write the commentary, add the issue to the list, run lint and build, open the PR. The rules in the prompt:
- If last month's JSON already exists, or a matching PR is already open, exit immediately. A rerun won't open a second PR.
- If the script fails, stop. Don't switch data sources, and don't estimate numbers.
- Only open the PR if lint and build both pass.
- Never merge.
The last rule is deliberate. My convention for personal projects is auto-merge, but the report is public-facing content, and every issue needs human review before it merges.
Prompts for scheduled tasks should be idempotent (rerunning gives the same result) and stop on failure, without finding workarounds or estimating numbers on their own.

The allowlist and the missing gh
Before setting up the real schedule, I did a trial with a one-off routine.
The cloud environment's default Trusted network allowlist blocked api-pub.bitfinex.com (CONNECT 403), so the script aborted on its first fetch. The container also had no gh CLI.
The network issue could have been solved by having GitHub Actions fetch the numbers and Claude only write the commentary, but that means maintaining another workflow.
I chose to switch the cloud environment's network to Full and keep a single routine. After the change, the rerun got a 200 from Bitfinex.
For the missing gh, the prompt now uses the GitHub MCP to look up and open PRs.
The cost of Full is that every cloud session using this environment can reach any website. To tighten it, switch to Custom and allow only api-pub.bitfinex.com.

For a cloud schedule that calls external services, trial-run it with a one-off routine first. The default allowlist doesn't include general external APIs.
The first real run on October 2 opened the PR for the September issue, and it has been merged.
Public content always keeps a human review step.

Engineering
Claude Code /code-review on an Entire Frontend: The Four Most Instructive Kinds Among 70-Plus Findings
I ran Claude Code's /code-review max over a whole frontend and confirmed 70-plus issues. Here are the four most instructive kinds, the rule that every test must fail on the unfixed build, and Playwright cross-browser results.
Letters
Loading comments…