Add lofty account rebates — recover the undocumented maker-rebate rate - #17
Conversation
Lofty advertises "maker rebates - paid at fill" but publishes no rate, and the amounts appear only on the signed-in account page. That makes rebates invisible to any API consumer, and a stale scrape of that page can report zero for weeks while rebates are actually being paid. The rate is recoverable from your own fills: `account trades` carries buyerFeeAmount and sellerFeeAmount, and a maker rebate is 50% of the fee on YOUR side of the trade. Verified to the cent against real paid rebates on both a buy and a sell, and reproduced live against the account page's all-time total. Rebates are paid only to the RESTING side. A fill that crossed the book earned nothing, which is the corroboration that "paid at fill" means paid to the maker. Trade records carry no maker/taker flag, so it is inferred from whether one of our orders rested at that exact price and side; unmatched trades are reported as takers rather than optimistically credited. Figures in the README example are illustrative.
piekstra-dev
left a comment
There was a problem hiding this comment.
Automated PR Review
Reviewed commit: d10bc3bc8e16
Profile: reviewer - Posting as: piekstra-dev
Summary
| Reviewer | Findings |
|---|---|
| policies:conventions | 0 |
| documentation:docs | 1 |
documentation:docs (1 finding)
Minor - README.md:276
The
account rebatessummary line is printed by a singleeprintln!inrender_rebates(src/commands/account.rs), so real output is one unbroken line:total $0.5625 across 1 maker fill(s) at 50% of your side's fee; 0 taker fill(s) earned nothing (crossing the book pays no rebate). The README example splits this into two lines (... 0 taker fill(s)/earned nothing (crossing the book pays no rebate)), which misrepresents the actual console output and could mislead someone diffing or scripting against it. Join it back into one line to match the real output (contrast with therewards reconcileexample a few sections up, which genuinely emits two separateeprintln!calls and is correctly shown as two lines).
Reviewer Coverage
| Reviewer | Status | Inspected | Skipped | Constraints |
|---|---|---|---|---|
| policies:conventions | complete_broad | src/commands/account.rs | unavailable | unavailable |
| documentation:docs | complete_broad | README.md | unavailable | unavailable |
0 PR discussion threads considered. 0 summarized; 0 resolved.
Completed in 2m 23s | $1.68 | claude-sonnet-5 | cr 0.10.268
| Field | Value |
|---|---|
| Model | claude-sonnet-5 |
| Reviewers | policies:conventions, documentation:docs |
| Engine | claude_cli · claude-sonnet-5 |
| Reviewed by | cr · piekstra-dev |
| Duration | 2m 23s wall · 3m 23s compute |
| Cost | $1.68 |
| Tokens | 82 in / 14.3k out |
Per-workstream usage
| Workstream | Model | In | Out | Cache read | Cache create | Cost | Duration |
|---|---|---|---|---|---|---|---|
| orchestrator-selection | claude-sonnet-5 | 6 | 1.7k | 36.3k | 22.1k | $0.17 | 21s |
| policies:conventions | claude-sonnet-5 | 30 | 4.6k | 656.2k | 66.3k | $0.66 | 1m 02s |
| documentation:docs | claude-sonnet-5 | 40 | 7.6k | 718.1k | 68.1k | $0.74 | 1m 49s |
| orchestrator-rollup | claude-sonnet-5 | 6 | 408 | 56.8k | 14.7k | $0.11 | 10s |
| $ lofty account rebates | ||
| PRICE | PROPERTY | QTY | REBATE | SIDE | YOUR FEE | ||
| $45.00 | 01SAMPLE…| 1.0 | $0.5625 | buy | $1.1250 | ||
| total $0.5625 across 1 maker fill(s) at 50% of your side's fee; 0 taker fill(s) |
There was a problem hiding this comment.
The account rebates summary line is printed by a single eprintln! in render_rebates (src/commands/account.rs), so real output is one unbroken line: total $0.5625 across 1 maker fill(s) at 50% of your side's fee; 0 taker fill(s) earned nothing (crossing the book pays no rebate). The README example splits this into two lines (... 0 taker fill(s) / earned nothing (crossing the book pays no rebate)), which misrepresents the actual console output and could mislead someone diffing or scripting against it. Join it back into one line to match the real output (contrast with the rewards reconcile example a few sections up, which genuinely emits two separate eprintln! calls and is correctly shown as two lines).
Reply inline to this comment.
There was a problem hiding this comment.
Correct — fixed in f1ab165. It is one eprintln!, so the example now shows one line. Good catch on the contrast with rewards reconcile, which genuinely emits two.
Review: the README split one eprintln! across two lines, so anyone diffing or scripting against the example would mismatch real output. The reconcile example above it genuinely emits two calls and is correctly shown as two lines.
The gap
Lofty advertises "maker rebates — paid at fill" but publishes the rate nowhere — not on the marketing page, not in
llms-full.txt, not in the SDK docs. The amounts appear only on the signed-in account page, so they're invisible to any API consumer.That's not academic. A cached scrape of that page can report $0 for weeks while rebates are actually being paid — which is precisely what happened, and it led to the confident conclusion "we earn no rebates."
The rate, recovered
account tradeshas carriedbuyerFeeAmountandsellerFeeAmountthe whole time. Comparing them against rebates actually paid:Verified to the cent on both a buy (rebate = ½ the buyer fee) and a sell (rebate = ½ the seller fee), then reproduced live — the command's total matched the account page's all-time figure.
The corroboration is the nice part: a fill that crossed the book earned nothing. That's what "paid at fill" means in practice — paid to the maker, not the taker.
Usage
--property-idand--sincefilter;--jsonemitsaccount-rebates/v1. Figures above are illustrative.Inference, stated honestly
A trade record carries no maker/taker flag, so it's inferred: a fill counts as maker when one of your orders rested at that exact price and side. Unmatched trades are reported as takers (no rebate) rather than optimistically credited — the conservative direction.
Testing
5 unit tests, including reproducing the real paid rebates, a taker fill earning nothing, the correct side's fee being used (mixing them up silently misprices every rebate), an opposite-side order not counting as maker, and
--sincefiltering. 87 tests,fmt,clippy -D warningsclean.Resolves the project's long-open note that the maker-rebate rate was undocumented.