Every exchange has fee tiers. What you actually pay depends on your volume, what you hold, and whatever else that venue counts — so the number on its public fees page is usually the entry-level tier, and usually not yours.
Routing picks venues on what you pay, so using the published number makes it wrong on every order. SORY never reads fees from a venue. You give it yours.
Turning them on
Two parts: where the rates live, and which venues to apply them to.
Use taker when you are crossing the spread, which is what a market order does. Use maker when you are pricing your own quote.
book.all_in tells you whether the prices you are holding include fees.
Fees are optional. Leave fee_offset out and you get quoted prices everywhere, and you need no fee file at all.
If a rate is missing
Asking SORY to apply a fee it does not have stops the client from starting. It will not fall back to zero.
That sounds strict, but a zero fee is not a small error — it produces prices that look fee-adjusted and are not, and every routing decision on that venue is quietly wrong from then on. Failing at startup is the cheap version of that problem.
The arithmetic
Against a quoted price of 100:
Rebates work by sign, with no special case. There is a test pinning these exact numbers, because getting the sign wrong on a rebate breaks nothing visibly — it just makes every decision quietly backwards.
Trade prints are never adjusted, even when the book is. You did not pay a fee on someone else’s trade.