Auction fees foundation: buyer-premium schedules (data/fees/auction-houses.json), fees.ts (marginal tiers, min/max/fixed, all-in price with basis), sales.all_in_usd/fee_basis, auction_lots USD + assessment columns; migration 0007
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
8 changed files +9,523 −1
added
data/fees/auction-houses.json
+66 −0
@@ -0,0 +1,66 @@ | |||||
| 1 | +{ | ||||
| 2 | + "$comment": "Buyer's premium schedules (§35). Marginal tiers on the hammer price, in the house's billing currency (tiers are approximated in other currencies at the current FX rate). confidence: 'published' = taken from the house's terms at as_of; 'approximate' = widely reported but not re-verified against the current terms — shown as ≈ and labelled 'estimated' everywhere; 'none' = no buyer premium by design. Anything not listed falls back to `default` (auction_house 22 %, labelled 'default'). VAT/sales tax on the premium, import duties and shipping are NOT included and are stated as such in the UI. Never present these numbers as the exact invoice a buyer will receive.", | ||||
| 3 | + "version": 1, | ||||
| 4 | + "as_of": "2026-09-11", | ||||
| 5 | + "default": { "auction_house": { "rate": 0.22, "confidence": "default", "note": "Typical contemporary buyer's premium for a regional auction house; used only when the house is unknown." }, "marketplace": { "rate": 0, "confidence": "none", "note": "Fixed-price marketplaces bill the asking price; fees are the seller's." } }, | ||||
| 6 | + "houses": [ | ||||
| 7 | + { "id": "sothebys", "name": "Sotheby's", "aliases": ["Sotheby's", "Sothebys", "sothebys", "RM Sotheby's Online"], "currency": "USD", "tiers": [{ "upTo": 1000000, "rate": 0.27 }, { "upTo": 8000000, "rate": 0.22 }, { "upTo": null, "rate": 0.15 }], "confidence": "published", "source": "https://www.sothebys.com/en/buy-sell/buying/buyers-premium", "note": "Standard schedule reinstated Feb 2025; wine, cars and some online sales use different rates." }, | ||||
| 8 | + { "id": "christies", "name": "Christie's", "aliases": ["Christie's", "Christies", "christies"], "currency": "USD", "tiers": [{ "upTo": 1000000, "rate": 0.26 }, { "upTo": 6000000, "rate": 0.21 }, { "upTo": null, "rate": 0.15 }], "confidence": "published", "source": "https://www.christies.com/en/help/buying-guide/financial-information" }, | ||||
| 9 | + { "id": "phillips", "name": "Phillips", "aliases": ["Phillips", "phillips-watches", "phillips-art"], "currency": "USD", "tiers": [{ "upTo": 1000000, "rate": 0.27 }, { "upTo": 6000000, "rate": 0.21 }, { "upTo": null, "rate": 0.145 }], "confidence": "approximate", "source": "https://www.phillips.com/buysell/buy" }, | ||||
| 10 | + { "id": "bonhams", "name": "Bonhams", "aliases": ["Bonhams", "the-market-bonhams", "Bonhams Skinner", "Bonhams Cornette de Saint Cyr"], "currency": "USD", "tiers": [{ "upTo": 50000, "rate": 0.28 }, { "upTo": 1000000, "rate": 0.27 }, { "upTo": 6000000, "rate": 0.21 }, { "upTo": null, "rate": 0.145 }], "confidence": "approximate", "source": "https://www.bonhams.com/buyers_guide/" }, | ||||
| 11 | + { "id": "heritage", "name": "Heritage Auctions", "aliases": ["Heritage Auctions", "Heritage", "HA.com"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0.2 }], "minimum": 19, "confidence": "approximate", "source": "https://www.ha.com/c/ref/terms-and-conditions.zx", "note": "20 % (min $19) for most categories; some comics/art sessions differ." }, | ||||
| 12 | + { "id": "goldin", "name": "Goldin", "aliases": ["Goldin", "Goldin Auctions"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0.2 }], "confidence": "published", "source": "https://goldin.co/terms" }, | ||||
| 13 | + { "id": "catawiki", "name": "Catawiki", "aliases": ["Catawiki"], "currency": "EUR", "tiers": [{ "upTo": null, "rate": 0.09 }], "fixedFee": 1, "confidence": "approximate", "source": "https://www.catawiki.com/en/help_center", "note": "Buyer protection fee ≈ 9 % + €1 per lot." }, | ||||
| 14 | + { "id": "bring-a-trailer", "name": "Bring a Trailer", "aliases": ["Bring a Trailer", "bring-a-trailer", "BaT"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0.05 }], "minimum": 250, "maximum": 7500, "confidence": "published", "source": "https://bringatrailer.com/faq/" }, | ||||
| 15 | + { "id": "cars-and-bids", "name": "Cars & Bids", "aliases": ["Cars & Bids", "cars-and-bids"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0.05 }], "minimum": 225, "maximum": 7500, "confidence": "approximate", "source": "https://carsandbids.com/faq" }, | ||||
| 16 | + { "id": "collecting-cars", "name": "Collecting Cars", "aliases": ["Collecting Cars", "collecting-cars"], "currency": "GBP", "tiers": [{ "upTo": null, "rate": 0.072 }], "maximum": 6000, "confidence": "approximate", "note": "6 % + VAT on the fee, capped." }, | ||||
| 17 | + { "id": "mecum", "name": "Mecum Auctions", "aliases": ["Mecum Auctions", "Mecum", "mecum"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0.1 }], "confidence": "approximate", "note": "10 % on-site; internet/phone bidders pay more." }, | ||||
| 18 | + { "id": "rm-sothebys", "name": "RM Sotheby's", "aliases": ["RM Sotheby's", "rm-sothebys", "RM Auctions"], "currency": "USD", "tiers": [{ "upTo": 250000, "rate": 0.12 }, { "upTo": null, "rate": 0.1 }], "confidence": "approximate" }, | ||||
| 19 | + { "id": "gooding", "name": "Gooding & Company", "aliases": ["Gooding & Company", "Gooding", "gooding"], "currency": "USD", "tiers": [{ "upTo": 250000, "rate": 0.12 }, { "upTo": null, "rate": 0.1 }], "confidence": "approximate" }, | ||||
| 20 | + { "id": "hakes", "name": "Hake's Auctions", "aliases": ["Hake's Auctions", "Hake's", "hakes"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0.2 }], "confidence": "approximate" }, | ||||
| 21 | + { "id": "scp", "name": "SCP Auctions", "aliases": ["SCP Auctions", "scp-auctions"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0.2 }], "confidence": "approximate" }, | ||||
| 22 | + { "id": "lelands", "name": "Lelands", "aliases": ["Lelands", "lelands"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0.2 }], "confidence": "approximate" }, | ||||
| 23 | + { "id": "comiclink", "name": "ComicLink", "aliases": ["ComicLink", "comiclink"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0 }], "confidence": "none", "note": "No buyer's premium; the seller pays the commission." }, | ||||
| 24 | + { "id": "comicconnect", "name": "ComicConnect", "aliases": ["ComicConnect", "comicconnect"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0 }], "confidence": "approximate", "note": "No buyer's premium on most sales." }, | ||||
| 25 | + { "id": "yahoo-auctions-jp", "name": "Yahoo! Auctions Japan", "aliases": ["Yahoo! Auctions Japan", "Yahoo! Auctions Japan (ヤフオク!)", "yahoo-auctions-jp", "ヤフオク!"], "currency": "JPY", "tiers": [{ "upTo": null, "rate": 0 }], "confidence": "none", "note": "No buyer's fee; the seller pays the system fee. Proxy/forwarding fees for overseas buyers are not modelled." }, | ||||
| 26 | + { "id": "noonans", "name": "Noonans Mayfair", "aliases": ["Noonans Mayfair", "Noonans", "noonans", "DNW"], "currency": "GBP", "tiers": [{ "upTo": null, "rate": 0.24 }], "confidence": "approximate", "note": "VAT on the premium not included." }, | ||||
| 27 | + { "id": "potter", "name": "Potter & Potter Auctions", "aliases": ["Potter & Potter Auctions", "Potter & Potter", "potter-auctions"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0.2 }], "confidence": "approximate", "note": "Online bidding platforms add their own surcharge." }, | ||||
| 28 | + { "id": "swann", "name": "Swann Auction Galleries", "aliases": ["Swann Auction Galleries", "Swann", "swann"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0.25 }], "confidence": "approximate" }, | ||||
| 29 | + { "id": "pba", "name": "PBA Galleries", "aliases": ["PBA Galleries", "pba-galleries"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0.25 }], "confidence": "approximate" }, | ||||
| 30 | + { "id": "doyle", "name": "Doyle", "aliases": ["Doyle", "doyle", "Doyle New York"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0.27 }], "confidence": "approximate" }, | ||||
| 31 | + { "id": "wright", "name": "Wright", "aliases": ["Wright", "wright", "Rago/Wright", "Rago"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0.25 }], "confidence": "approximate" }, | ||||
| 32 | + { "id": "lama", "name": "Los Angeles Modern Auctions", "aliases": ["Los Angeles Modern Auctions", "LAMA", "lama"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0.25 }], "confidence": "approximate" }, | ||||
| 33 | + { "id": "whisky-auction", "name": "Whisky.Auction", "aliases": ["Whisky.Auction", "whisky-auction"], "currency": "GBP", "tiers": [{ "upTo": null, "rate": 0.12 }], "confidence": "approximate", "note": "≈ 10 % buyer fee + VAT on the fee." }, | ||||
| 34 | + { "id": "just-whisky", "name": "Just Whisky", "aliases": ["Just Whisky", "just-whisky"], "currency": "GBP", "tiers": [{ "upTo": null, "rate": 0.12 }], "confidence": "approximate" }, | ||||
| 35 | + { "id": "whisky-hammer", "name": "Whisky Hammer", "aliases": ["Whisky Hammer", "whisky-hammer"], "currency": "GBP", "tiers": [{ "upTo": null, "rate": 0.12 }], "confidence": "approximate" }, | ||||
| 36 | + { "id": "scotch-whisky-auctions", "name": "Scotch Whisky Auctions", "aliases": ["Scotch Whisky Auctions", "scotch-whisky-auctions"], "currency": "GBP", "tiers": [{ "upTo": null, "rate": 0.12 }], "confidence": "approximate" }, | ||||
| 37 | + { "id": "hdh", "name": "Hart Davis Hart Wine Co.", "aliases": ["Hart Davis Hart Wine Co.", "HDH", "hdh-wine"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0.24 }], "confidence": "approximate" }, | ||||
| 38 | + { "id": "winebid", "name": "WineBid", "aliases": ["WineBid", "winebid"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0.17 }], "confidence": "approximate" }, | ||||
| 39 | + { "id": "tokyo-chuo", "name": "Tokyo Chuo Auction", "aliases": ["Tokyo Chuo Auction", "tokyo-chuo"], "currency": "JPY", "tiers": [{ "upTo": null, "rate": 0.15 }], "confidence": "approximate" }, | ||||
| 40 | + { "id": "sgbaldwins", "name": "Stanley Gibbons Baldwin's", "aliases": ["Stanley Gibbons Baldwin's", "Baldwin's", "sgbaldwins"], "currency": "GBP", "tiers": [{ "upTo": null, "rate": 0.2 }], "confidence": "approximate", "note": "VAT on the premium not included." }, | ||||
| 41 | + { "id": "corinphila", "name": "Corinphila Auctions", "aliases": ["Corinphila Auctions", "Corinphila", "corinphila"], "currency": "CHF", "tiers": [{ "upTo": null, "rate": 0.22 }], "confidence": "approximate" }, | ||||
| 42 | + { "id": "kuenker", "name": "Künker", "aliases": ["Künker", "Kuenker", "kuenker", "Fritz Rudolf Künker"], "currency": "EUR", "tiers": [{ "upTo": null, "rate": 0.25 }], "confidence": "approximate" }, | ||||
| 43 | + { "id": "noble", "name": "Noble Numismatics", "aliases": ["Noble Numismatics", "noble"], "currency": "AUD", "tiers": [{ "upTo": null, "rate": 0.1925 }], "confidence": "approximate", "note": "17.5 % + GST." }, | ||||
| 44 | + { "id": "dunbar-sloane", "name": "Dunbar Sloane", "aliases": ["Dunbar Sloane", "dunbar-sloane"], "currency": "NZD", "tiers": [{ "upTo": null, "rate": 0.175 }], "confidence": "approximate" }, | ||||
| 45 | + { "id": "miller-miller", "name": "Miller & Miller Auctions", "aliases": ["Miller & Miller Auctions", "Miller & Miller", "miller-miller"], "currency": "CAD", "tiers": [{ "upTo": null, "rate": 0.18 }], "confidence": "approximate" }, | ||||
| 46 | + { "id": "aguttes", "name": "Aguttes", "aliases": ["Aguttes", "aguttes"], "currency": "EUR", "tiers": [{ "upTo": null, "rate": 0.3 }], "confidence": "approximate", "note": "≈ 25 % HT + TVA." }, | ||||
| 47 | + { "id": "artcurial", "name": "Artcurial", "aliases": ["Artcurial", "artcurial"], "currency": "EUR", "tiers": [{ "upTo": 700000, "rate": 0.3 }, { "upTo": null, "rate": 0.24 }], "confidence": "approximate", "note": "TTC; motorcars use a different schedule." }, | ||||
| 48 | + { "id": "millon", "name": "Millon", "aliases": ["Millon", "millon"], "currency": "EUR", "tiers": [{ "upTo": null, "rate": 0.3 }], "confidence": "approximate" }, | ||||
| 49 | + { "id": "piasa", "name": "PIASA", "aliases": ["PIASA", "piasa"], "currency": "EUR", "tiers": [{ "upTo": null, "rate": 0.3 }], "confidence": "approximate" }, | ||||
| 50 | + { "id": "ader", "name": "Ader", "aliases": ["Ader", "ader"], "currency": "EUR", "tiers": [{ "upTo": null, "rate": 0.28 }], "confidence": "approximate" }, | ||||
| 51 | + { "id": "osenat", "name": "Osenat", "aliases": ["Osenat", "osenat"], "currency": "EUR", "tiers": [{ "upTo": null, "rate": 0.3 }], "confidence": "approximate" }, | ||||
| 52 | + { "id": "chiswick", "name": "Chiswick Auctions", "aliases": ["Chiswick Auctions", "Chiswick", "chiswick"], "currency": "GBP", "tiers": [{ "upTo": null, "rate": 0.3 }], "confidence": "approximate", "note": "25 % + VAT." }, | ||||
| 53 | + { "id": "dominic-winter", "name": "Dominic Winter Auctioneers", "aliases": ["Dominic Winter Auctioneers", "Dominic Winter", "dominic-winter"], "currency": "GBP", "tiers": [{ "upTo": null, "rate": 0.288 }], "confidence": "approximate", "note": "24 % + VAT." }, | ||||
| 54 | + { "id": "sworders", "name": "Sworders", "aliases": ["Sworders", "sworders"], "currency": "GBP", "tiers": [{ "upTo": null, "rate": 0.3 }], "confidence": "approximate", "note": "25 % + VAT." }, | ||||
| 55 | + { "id": "woolley-wallis", "name": "Woolley & Wallis", "aliases": ["Woolley & Wallis", "woolley-wallis"], "currency": "GBP", "tiers": [{ "upTo": null, "rate": 0.312 }], "confidence": "approximate", "note": "26 % + VAT." }, | ||||
| 56 | + { "id": "lyon-turnbull", "name": "Lyon & Turnbull", "aliases": ["Lyon & Turnbull", "lyon-turnbull"], "currency": "GBP", "tiers": [{ "upTo": null, "rate": 0.312 }], "confidence": "approximate", "note": "26 % + VAT." }, | ||||
| 57 | + { "id": "auctionet", "name": "Auctionet", "aliases": ["Auctionet", "auctionet"], "currency": "EUR", "tiers": [{ "upTo": null, "rate": 0.225 }], "confidence": "approximate", "note": "Varies by partner house." }, | ||||
| 58 | + { "id": "aste-bolaffi", "name": "Aste Bolaffi", "aliases": ["Aste Bolaffi", "Bolaffi", "aste-bolaffi"], "currency": "EUR", "tiers": [{ "upTo": null, "rate": 0.24 }], "confidence": "approximate" }, | ||||
| 59 | + { "id": "antiquorum", "name": "Antiquorum", "aliases": ["Antiquorum", "antiquorum"], "currency": "CHF", "tiers": [{ "upTo": null, "rate": 0.25 }], "confidence": "approximate" }, | ||||
| 60 | + { "id": "dlrc", "name": "David Lawrence Rare Coins", "aliases": ["David Lawrence Rare Coins", "DLRC", "dlrc"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0.1 }], "confidence": "approximate" }, | ||||
| 61 | + { "id": "kelleher", "name": "Kelleher Auctions", "aliases": ["Kelleher Auctions", "Kelleher", "kelleher"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0.2 }], "confidence": "approximate" }, | ||||
| 62 | + { "id": "clean-sweep", "name": "Clean Sweep Auctions", "aliases": ["Clean Sweep Auctions", "clean-sweep"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0.2 }], "confidence": "approximate" }, | ||||
| 63 | + { "id": "mycomicshop", "name": "MyComicShop", "aliases": ["MyComicShop", "mycomicshop"], "currency": "USD", "tiers": [{ "upTo": null, "rate": 0 }], "confidence": "approximate", "note": "No buyer's premium on MyComicShop auctions." }, | ||||
| 64 | + { "id": "e-rocks", "name": "e-Rocks", "aliases": ["e-Rocks", "e-rocks"], "currency": "EUR", "tiers": [{ "upTo": null, "rate": 0 }], "confidence": "approximate", "note": "Marketplace auctions billed at the hammer price." } | ||||
| 65 | + ] | ||||
| 66 | +} | ||||
added
packages/database/migrations/0007_organic_colonel_america.sql
+21 −0
@@ -0,0 +1,21 @@ | |||||
| 1 | +ALTER TABLE "auction_lots" ADD COLUMN "estimate_low_usd" numeric(18, 4);--> statement-breakpoint | ||||
| 2 | +ALTER TABLE "auction_lots" ADD COLUMN "estimate_high_usd" numeric(18, 4);--> statement-breakpoint | ||||
| 3 | +ALTER TABLE "auction_lots" ADD COLUMN "current_bid_usd" numeric(18, 4);--> statement-breakpoint | ||||
| 4 | +ALTER TABLE "auction_lots" ADD COLUMN "hammer_price_usd" numeric(18, 4);--> statement-breakpoint | ||||
| 5 | +ALTER TABLE "auction_lots" ADD COLUMN "fx_rate" real;--> statement-breakpoint | ||||
| 6 | +ALTER TABLE "auction_lots" ADD COLUMN "fx_date" date;--> statement-breakpoint | ||||
| 7 | +ALTER TABLE "auction_lots" ADD COLUMN "buyer_premium_rate" real;--> statement-breakpoint | ||||
| 8 | +ALTER TABLE "auction_lots" ADD COLUMN "fee_basis" text;--> statement-breakpoint | ||||
| 9 | +ALTER TABLE "auction_lots" ADD COLUMN "all_in_bid_usd" numeric(18, 4);--> statement-breakpoint | ||||
| 10 | +ALTER TABLE "auction_lots" ADD COLUMN "all_in_estimate_low_usd" numeric(18, 4);--> statement-breakpoint | ||||
| 11 | +ALTER TABLE "auction_lots" ADD COLUMN "all_in_estimate_high_usd" numeric(18, 4);--> statement-breakpoint | ||||
| 12 | +ALTER TABLE "auction_lots" ADD COLUMN "riv_usd_at_assessment" numeric(18, 4);--> statement-breakpoint | ||||
| 13 | +ALTER TABLE "auction_lots" ADD COLUMN "bid_vs_riv" real;--> statement-breakpoint | ||||
| 14 | +ALTER TABLE "auction_lots" ADD COLUMN "estimate_vs_riv" real;--> statement-breakpoint | ||||
| 15 | +ALTER TABLE "auction_lots" ADD COLUMN "assessment_verdict" text;--> statement-breakpoint | ||||
| 16 | +ALTER TABLE "auction_lots" ADD COLUMN "assessed_at" timestamp with time zone;--> statement-breakpoint | ||||
| 17 | +ALTER TABLE "sales" ADD COLUMN "all_in_usd" numeric(18, 4);--> statement-breakpoint | ||||
| 18 | +ALTER TABLE "sales" ADD COLUMN "fee_basis" text;--> statement-breakpoint | ||||
| 19 | +ALTER TABLE "sales" ADD COLUMN "buyer_premium_rate" real;--> statement-breakpoint | ||||
| 20 | +CREATE INDEX "auction_lots_status_ends_idx" ON "auction_lots" USING btree ("status","ends_at");--> statement-breakpoint | ||||
| 21 | +CREATE INDEX "auction_lots_bid_vs_riv_idx" ON "auction_lots" USING btree ("bid_vs_riv") WHERE bid_vs_riv is not null and status in ('live','upcoming'); | ||||
| \ No newline at end of file | |||||
added
packages/database/migrations/meta/0007_snapshot.json
+9186 −0
Large diff (9,187 lines) is not loaded by default to keep the page fast.Load diff
modified
packages/database/migrations/meta/_journal.json
+7 −0
Large diff (14 lines) is not loaded by default to keep the page fast.Load diff
modified
packages/database/src/schema/market.ts
+27 −1
Large diff (46 lines) is not loaded by default to keep the page fast.Load diff
added
packages/valuation/src/fees.test.ts
+48 −0
Large diff (48 lines) is not loaded by default to keep the page fast.Load diff
added
packages/valuation/src/fees.ts
+167 −0
Large diff (167 lines) is not loaded by default to keep the page fast.Load diff
modified
packages/valuation/src/index.ts
+1 −0
Large diff (5 lines) is not loaded by default to keep the page fast.Load diff