Reference
referenceUses Decimal at full precision and rounds only the fee and the final destination amount.
03 · FX transfers
Quote a currency transfer with the fee taken in the source currency and each currency's own decimal places.
referenceUses Decimal at full precision and rounds only the fee and the final destination amount.
alt_validExact Fraction scaling and integer half-even rounding instead of Decimal amount arithmetic.
wrong_fee_after_conversionRounds destination fees after conversion instead of source fees before it.
wrong_round_cross_legRounds the intermediate USD amount in a cross quote.
wrong_two_decimalsAssumes every currency has two decimal places.
weak_validationExpect: rejectObserved: rejectedAccepts bool amounts and fees over 10000 bps, violating the stated integer and fee range rules.
infers_inverseExpect: rejectObserved: rejectedInfers inverse rates, violating the direct-or-USD-only routing rule.
cross_rate_6dpExpect: rejectObserved: rejectedRounds the cross product to six decimals, violating full precision with no intermediate rounding.
default_context_prec28Expect: rejectObserved: rejectedTruncates the cross rate at the default Decimal precision, violating the full product rate_used rule.
Each row groups a test’s parameterized cases; any failing case marks the row as Fail. * marks a wrong solution’s declared must_fail test.
| Test | Starter | Reference | Alternative | fee after conversion | round cross leg | two decimals |
|---|---|---|---|---|---|---|
| Jpy and kwd units | Fail | Pass | Pass | Fail | Pass | Fail * |
| Cross has no intermediate rounding | Fail | Pass | Pass | Pass | Fail * | Pass |
| Source fee before conversion | Fail | Pass | Pass | Fail * | Pass | Pass |
| Discovered half even ties | Pass | Pass | Pass | Pass | Pass | Pass |
| Unavailable and zero | Pass | Pass | Pass | Pass | Pass | Pass |
| Inverse only is unavailable | Pass | Pass | Pass | Pass | Pass | Pass |
| Full precision cross rate | Fail | Pass | Pass | Fail | Fail | Pass |
| Invalid amount and fee | Pass | Pass | Pass | Pass | Pass | Pass |
| Exact scaling and monotonicity | Fail | Pass | Pass | Fail | Pass | Fail |
| Zero fee roundtrip | Pass | Pass | Pass | Pass | Pass | Pass |
| Test | Starter | Reference | Alternative | fee after conversion | round cross leg | two decimals |
|---|---|---|---|---|---|---|
| Direct cad usd | Fail | Pass | Pass | Pass | Pass | Pass |
| Ticket example cross quote | Fail | Pass | Pass | Pass | Pass | Pass |
| Ticket example zero decimal currency | Fail | Pass | Pass | Pass | Pass | Fail |
| Unknown route rejected | Pass | Pass | Pass | Pass | Pass | Pass |
fx.quote.quote_transfer(amount_minor:int,src:str,dst:str,rates:dict[tuple[str,str],Decimal],fee_bps:int) returns frozen Quote(fee_minor:int,converted_minor:int,rate_used:Decimal,path:tuple[str,...]). Expose RateUnavailable(ValueError) for unavailable currencies/pairs.
Minor units: CAD/USD/EUR/GBP=2, JPY=0, KWD/BHD=3. Rates are positive finite Decimals in destination major units per source major unit. All money values returned are int minor units. Amount is nonnegative int, never bool; fee_bps integer in [0,10000]; invalid values -> ValueError. Inputs use distinct src/dst; an unsupported currency -> RateUnavailable.
(src,dst) rate if present, path (src,dst). Otherwise require both (src,"USD") and ("USD",dst), multiply at full precision, path (src,"USD",dst). Do not infer inverses or other routes. Missing required rates -> RateUnavailable. Direct rate takes precedence.Worked examples. (a) Cross quote: rates = {("GBP","USD"): Decimal("1.25"), ("USD","CAD"): Decimal("1.40")}, quote_transfer(20000, "GBP", "CAD", rates, 50): fee = 20000 x 50 / 10000 = 100 (1.00 GBP); net 19900 = 199.00 GBP; rate_used = 1.25 x 1.40 = 1.7500; 199.00 x 1.7500 = 348.25 CAD, so Quote(100, 34825, Decimal("1.7500"), ("GBP","USD","CAD")). (b) Zero-decimal currency: quote_transfer(5000, "CAD", "JPY", {("CAD","JPY"): Decimal("110")}, 0): 50.00 CAD x 110 = 5500 JPY, so Quote(0, 5500, Decimal("110"), ("CAD","JPY")).
Do not mutate rates. Zero amount returns zero amounts while still resolving the declared route. No actual currency market or customer is represented. Run python -m pytest tests -q from starter.