-
Notifications
You must be signed in to change notification settings - Fork 0
Pricing Model
RoyalBazaar is not a fixed-price shop. Every item sits on an AMM-style (automated-market-maker) price curve, and the server is always the counterparty with infinite depth — so there's no order book and no waiting for a matching offer. Prices move purely from supply and demand.
Every parameter below is set per item (with category-wide defaults) — see Categories.
Each item has a mid price: its current fair value, held in memory and persisted between restarts. Everything else derives from it.
- Buying pushes the mid up.
- Selling pushes the mid down.
- Over time, mean reversion pulls the mid back toward the item's configured base price.
The price a player pays or receives straddles the mid by half the spread:
buy price = mid × (1 + spread/2)
sell price = mid × (1 − spread/2)
So spread is the gap between what players pay to buy and receive to sell. It's your margin and a passive inflation sink — money spent crossing the spread leaves the economy. A spread: 0.05 is a 5% gap.
Large orders are not priced at a flat quantity × price. Cost and proceeds are the integral along the curve, so each additional unit is priced a little worse than the last:
buy cost = elasticity × mid × (e^( q/elasticity) − 1) × (1 + spread/2)
sell yield = elasticity × mid × (1 − e^(−q/elasticity)) × (1 − spread/2)
elasticity is how many units it takes to move the price by a factor of e — higher = more stable, lower = more reactive. Because the curve steepens as you walk it:
Buying a stack and immediately selling it back is a guaranteed loss. Round-tripping and "whale-draining" the market aren't profitable by construction — you can't extract money the market didn't already contain.
After a trade of q units, the mid moves exponentially and is then clamped to the item's floor/ceiling:
mid after buy = clamp( mid × e^( q/elasticity), floor, ceiling )
mid after sell = clamp( mid × e^(−q/elasticity), floor, ceiling )
On each engine tick (engine.tick-interval-seconds, default 60s) every mid is pulled a fraction of the way back toward its base price, in log-space:
new mid = clamp( exp( ln(mid) + (ln(base) − ln(mid)) × reversion_rate ), floor, ceiling )
A reversion_rate: 0.02 closes 2% of the gap to base each tick. This heals one-off spikes and crashes on their own without ever snapping the price back instantly.
floor_pct and ceiling_pct are fractions of the item's base price, and hard-cap how far it can ever move:
floor = base × floor_pct # e.g. 0.4 → never below 40% of base
ceiling = base × ceiling_pct # e.g. 3.0 → never above 300% of base
Every quote, trade, and reversion result is clamped into [floor, ceiling].
| Want… | Change |
|---|---|
| Prices to move less per trade | Raise elasticity
|
| Prices to move more per trade | Lower elasticity
|
| A bigger buy/sell margin (inflation sink) | Raise spread
|
| Prices to recover faster after a dump | Raise reversion_rate
|
| A tighter or wider allowed price band | Adjust floor_pct / ceiling_pct
|
See Categories for where these are configured, and Configuration for the engine tick rate.
RoyalBazaar · part of the eco suite (RoyalBank · RoyalAuctions · EconGuard) · Source on GitHub
Getting started
Using it
Help