Inventory and pricing for a money changer: stock, cost and rates
A currency-exchange business is really an inventory business. Here is how MEXAR models accounts and balances, tracks cost with a moving average, and separates the six rate types that drive a transaction.
Run a money changer for a week and you realise it is an inventory business wearing a finance costume. You buy currency at one cost, hold it, and sell it at a price — and your real profit depends on what that stock actually cost you, not on the headline spread. MEXAR models this explicitly, so operators can see true margin instead of guessing at it.
Accounts, balances, and flows
Money lives in a three-layer structure. An Account is a container with a type; each account holds one AccountCurrencyBalance per currency; and every movement is recorded as an AccountFlow.
Accounts come in fourteen types, because “cash in the drawer” and “money owed to
an agent” behave nothing alike: CASH, BANK, CRYPTO, APP, EWALLET,
PAYABLE, BALANCE, VIRTUAL, TEMPORARY, CONTRA, DEBT, DEBIT, CREDIT,
and EXPENSE. A balance is not a single number either — it splits into
balance_available (usable now) and balance_hold (committed but not yet
settled):
balance = balance_available + balance_hold
balance_available = free to use for new transactions
balance_hold = frozen, occupied by transactions in progress
That split powers anticipated flow: when a transaction is created but not yet completed, MEXAR pre-occupies the balance it will need. The stock is reserved, so two transactions cannot both sell the same notes — over-selling is prevented before it can happen, and the hold converts into a formal flow once the transaction settles.
Cost that follows the stock: Moving Average Cost
To know profit, you need cost — and cost changes every time you restock. MEXAR uses Moving Average Cost (MAC): each inflow recomputes the blended cost basis of what you hold.
New Average Cost = (Q_old × C_old + Q_new × C_new) / (Q_old + Q_new)
When you later sell, profit is measured against that basis, not against a market quote:
profit = Outflow Amount × (Outflow Rate − Average Cost)
Costs and profit are expressed in the account’s base currency (base_cost /
cost_to_base), so a multi-currency operation can roll everything up into one
denomination for P&L. When there is no inventory to cost against, a spot rate
stands in as the reference instead.
Six rates, one transaction
“The rate” is never just one number. MEXAR distinguishes six rate types, each with a job:
| Rate type | What it is |
|---|---|
| Base currency | the internal denomination all cost and profit roll up into |
| Average cost | per-unit cost of held inventory, from MAC |
| Spot rate | external market reference when there is no inventory |
| Public buy | what you pay a customer selling currency to you |
| Public sell | what you charge a customer buying currency from you |
| Sell rate (internal) | public rate adjusted by your margin, for profit control |
The internal sell rate is derived, not hand-set, so margin stays deliberate:
SellRate(X) = PublicSell(X) × (1 + Markup)
BuyRate(X) = PublicBuy(X) × (1 − Markdown)
One flag that prevents a whole class of bugs
Currency pairs are quoted in two directions — and mixing up the direct and
indirect format is how rounding errors and mispriced deals creep in. Is a USD
rate “rupiah per dollar” or “dollars per rupiah”? Get it backwards and every
amount is wrong. MEXAR makes the direction explicit with a use_reverse_rate
flag at the department-currency level:
- direct (
use_reverse_rate = false):converted = amount × rate - indirect (
use_reverse_rate = true):converted = amount ÷ rate
Set it once per currency and every calculation downstream applies the conversion the same way — there is no per-transaction guesswork about which side of the pair you are on, and the same money math helper enforces it everywhere.
Rates as an operating surface
All of this is exposed to operators, not buried in code. Staff manage public buy, sell, and spot rates per currency from one screen — editing inline or pushing a CSV bulk update across many currencies at once — and customer groups can carry their own rates, so a walk-in price and a partner price coexist without a second system. Crucially, a rate change applies only to new transactions: anything already in flight keeps the rate it was created with. That is the append-only ledger doing its job — pricing can move without rewriting the deals you have already struck.
Why model it this way
An operator could track stock in a spreadsheet and price by feel. The reason to build it into the platform is that cost, holds, and rate direction are where a money changer quietly loses money — to over-selling, to mispriced inventory, to a reversed conversion. By making average cost, anticipated holds, and rate direction first-class, MEXAR turns “roughly profitable” into a number you can actually see per transaction, per currency, per department — on the same append-only ledger that keeps the history honest.