FA-62086 / Currency rounding and FX conversion / Open access
Fractional forward points are truncated to whole pips · case 01
A 12.5-pip premium is applied as 12 pips.
ROOT CAUSE
The points string is truncated through int() before scaling by the pip size.
VERIFIED REPAIR
Use the exact decimal points value, including fractional pips.
Unsuccessful approach: Rounding points to the nearest whole pip through float still drops the fractional pip.
Case contract
solve(pair, spot, points, notional): pair is BASEQUOTE. The pip exponent depends on the quote currency: JPY 2, HUF 2, KRW 0, otherwise 4 (pip = 10**-exp). points is a decimal string of pips (fractional pips allowed, negative for discount). forward = spot + points*pip rounded half-even to exp+1 decimals (one fractional pip). The pip value in quote currency is notional*pip rounded half-even to 2 decimals. Return [forward, pip_value] as plain strings.
Why this case matters
Currency amounts must be rounded at the right stage and in the right unit, or ledgers, quotes and settlements drift by minor units.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
from decimal import Decimal, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_FLOOR, ROUND_CEILING, ROUND_DOWN, ROUND_UP, ROUND_HALF_DOWN
N = 1
observations = []
def solve(pair, spot, points, notional):
pip_exp = {'JPY': 2, 'HUF': 2, 'KRW': 0}
quote = pair[3:]
pe = pip_exp.get(quote, 4)
pip = Decimal(1).scaleb(-pe)
fwd = Decimal(spot) + Decimal(int(Decimal(points))) * pip
fwd = fwd.quantize(Decimal(1).scaleb(-(pe + 1)), rounding=ROUND_HALF_EVEN)
pv = (Decimal(notional) * pip).quantize(Decimal('0.01'), rounding=ROUND_HALF_EVEN)
return [format(fwd, 'f'), format(pv, 'f')]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression fractional-points 1', ('EURUSD', '1.08345', '12.5', 1000000), ['1.08470', '100.00']),
('regression fractional-points 2', ('USDJPY', '151.234', '-45.25', 1000000), ['150.782', '10000.00']),
('control: won pips', ('USDKRW', '1352.5', '3.2', 1000000), ['1355.7', '1000000.00']),
('control: forint', ('EURHUF', '395.12', '-0.35', 250000), ['395.116', '2500.00']),
('control: yen base pair', ('JPYSEK', '0.07012', '1.5', 5000000), ['0.07027', '500.00']),
('control: sterling', ('GBPUSD', '1.26501', '-0.75', 333333), ['1.26494', '33.33'])],
[('regression fractional-points 1', ('USDKRW', '1352.5', '3.2', 1000000), ['1355.7', '1000000.00']),
('regression fractional-points 2', ('EURHUF', '395.12', '-0.35', 250000), ['395.116', '2500.00']),
('control: yen base pair', ('JPYSEK', '0.07012', '1.5', 5000000), ['0.07027', '500.00']),
('control: sterling', ('GBPUSD', '1.26501', '-0.75', 333333), ['1.26494', '33.33']),
('control: zero points', ('AUDNZD', '1.09876', '0', 100000), ['1.09876', '10.00']),
('control: euro premium', ('EURUSD', '1.08345', '12.5', 1000000), ['1.08470', '100.00'])],
[('regression fractional-points 1', ('JPYSEK', '0.07012', '1.5', 5000000), ['0.07027', '500.00']),
('regression fractional-points 2', ('GBPUSD', '1.26501', '-0.75', 333333), ['1.26494', '33.33']),
('control: zero points', ('AUDNZD', '1.09876', '0', 100000), ['1.09876', '10.00']),
('control: euro premium', ('EURUSD', '1.08345', '12.5', 1000000), ['1.08470', '100.00']),
('control: yen discount', ('USDJPY', '151.234', '-45.25', 1000000), ['150.782', '10000.00']),
('control: won pips', ('USDKRW', '1352.5', '3.2', 1000000), ['1355.7', '1000000.00'])],
[('regression fractional-points 1', ('EURHUF', '698.3982', '193.71', 1000), ['700.335', '10.00']),
('regression fractional-points 2', ('EURHUF', '138.28482', '-67.66', 1000), ['137.608', '10.00']),
('control: won pips', ('USDKRW', '1352.5', '3.2', 1000000), ['1355.7', '1000000.00']),
('control: forint', ('EURHUF', '395.12', '-0.35', 250000), ['395.116', '2500.00']),
('control: yen base pair', ('JPYSEK', '0.07012', '1.5', 5000000), ['0.07027', '500.00']),
('control: sterling', ('GBPUSD', '1.26501', '-0.75', 333333), ['1.26494', '33.33'])],
[('regression fractional-points 1', ('EURHUF', '4938.658', '-58.12', 1000000), ['4938.077', '10000.00']),
('regression fractional-points 2', ('JPYSEK', '183.37113', '-118.52', 1000), ['183.35928', '0.10']),
('control: sterling', ('GBPUSD', '1.26501', '-0.75', 333333), ['1.26494', '33.33']),
('control: zero points', ('AUDNZD', '1.09876', '0', 100000), ['1.09876', '10.00']),
('control: euro premium', ('EURUSD', '1.08345', '12.5', 1000000), ['1.08470', '100.00']),
('control: yen discount', ('USDJPY', '151.234', '-45.25', 1000000), ['150.782', '10000.00'])]]
for label, args, expected in cases[N - 1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression fractional-points 1 | ['1.08465', '100.00'] | ['1.08470', '100.00'] | Failed |
| regression fractional-points 2 | ['150.784', '10000.00'] | ['150.782', '10000.00'] | Failed |
| control: won pips | ['1355.5', '1000000.00'] | ['1355.7', '1000000.00'] | Failed |
| control: forint | ['395.120', '2500.00'] | ['395.116', '2500.00'] | Failed |
| control: yen base pair | ['0.07022', '500.00'] | ['0.07027', '500.00'] | Failed |
| control: sterling | ['1.26501', '33.33'] | ['1.26494', '33.33'] | Failed |
SHA-256 / b61a4af1c324a55b55007f54e4d43a37f49d7cfc373f61023041a10e36309840
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
from decimal import Decimal, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_FLOOR, ROUND_CEILING, ROUND_DOWN, ROUND_UP, ROUND_HALF_DOWN
N = 1
observations = []
def solve(pair, spot, points, notional):
pip_exp = {'JPY': 2, 'HUF': 2, 'KRW': 0}
quote = pair[3:]
pe = pip_exp.get(quote, 4)
pip = Decimal(1).scaleb(-pe)
fwd = Decimal(spot) + Decimal(round(float(points))) * pip
fwd = fwd.quantize(Decimal(1).scaleb(-(pe + 1)), rounding=ROUND_HALF_EVEN)
pv = (Decimal(notional) * pip).quantize(Decimal('0.01'), rounding=ROUND_HALF_EVEN)
return [format(fwd, 'f'), format(pv, 'f')]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression fractional-points 1', ('EURUSD', '1.08345', '12.5', 1000000), ['1.08470', '100.00']),
('regression fractional-points 2', ('USDJPY', '151.234', '-45.25', 1000000), ['150.782', '10000.00']),
('control: won pips', ('USDKRW', '1352.5', '3.2', 1000000), ['1355.7', '1000000.00']),
('control: forint', ('EURHUF', '395.12', '-0.35', 250000), ['395.116', '2500.00']),
('control: yen base pair', ('JPYSEK', '0.07012', '1.5', 5000000), ['0.07027', '500.00']),
('control: sterling', ('GBPUSD', '1.26501', '-0.75', 333333), ['1.26494', '33.33'])],
[('regression fractional-points 1', ('USDKRW', '1352.5', '3.2', 1000000), ['1355.7', '1000000.00']),
('regression fractional-points 2', ('EURHUF', '395.12', '-0.35', 250000), ['395.116', '2500.00']),
('control: yen base pair', ('JPYSEK', '0.07012', '1.5', 5000000), ['0.07027', '500.00']),
('control: sterling', ('GBPUSD', '1.26501', '-0.75', 333333), ['1.26494', '33.33']),
('control: zero points', ('AUDNZD', '1.09876', '0', 100000), ['1.09876', '10.00']),
('control: euro premium', ('EURUSD', '1.08345', '12.5', 1000000), ['1.08470', '100.00'])],
[('regression fractional-points 1', ('JPYSEK', '0.07012', '1.5', 5000000), ['0.07027', '500.00']),
('regression fractional-points 2', ('GBPUSD', '1.26501', '-0.75', 333333), ['1.26494', '33.33']),
('control: zero points', ('AUDNZD', '1.09876', '0', 100000), ['1.09876', '10.00']),
('control: euro premium', ('EURUSD', '1.08345', '12.5', 1000000), ['1.08470', '100.00']),
('control: yen discount', ('USDJPY', '151.234', '-45.25', 1000000), ['150.782', '10000.00']),
('control: won pips', ('USDKRW', '1352.5', '3.2', 1000000), ['1355.7', '1000000.00'])],
[('regression fractional-points 1', ('EURHUF', '698.3982', '193.71', 1000), ['700.335', '10.00']),
('regression fractional-points 2', ('EURHUF', '138.28482', '-67.66', 1000), ['137.608', '10.00']),
('control: won pips', ('USDKRW', '1352.5', '3.2', 1000000), ['1355.7', '1000000.00']),
('control: forint', ('EURHUF', '395.12', '-0.35', 250000), ['395.116', '2500.00']),
('control: yen base pair', ('JPYSEK', '0.07012', '1.5', 5000000), ['0.07027', '500.00']),
('control: sterling', ('GBPUSD', '1.26501', '-0.75', 333333), ['1.26494', '33.33'])],
[('regression fractional-points 1', ('EURHUF', '4938.658', '-58.12', 1000000), ['4938.077', '10000.00']),
('regression fractional-points 2', ('JPYSEK', '183.37113', '-118.52', 1000), ['183.35928', '0.10']),
('control: sterling', ('GBPUSD', '1.26501', '-0.75', 333333), ['1.26494', '33.33']),
('control: zero points', ('AUDNZD', '1.09876', '0', 100000), ['1.09876', '10.00']),
('control: euro premium', ('EURUSD', '1.08345', '12.5', 1000000), ['1.08470', '100.00']),
('control: yen discount', ('USDJPY', '151.234', '-45.25', 1000000), ['150.782', '10000.00'])]]
for label, args, expected in cases[N - 1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression fractional-points 1 | ['1.08465', '100.00'] | ['1.08470', '100.00'] | Failed |
| regression fractional-points 2 | ['150.784', '10000.00'] | ['150.782', '10000.00'] | Failed |
| control: won pips | ['1355.5', '1000000.00'] | ['1355.7', '1000000.00'] | Failed |
| control: forint | ['395.120', '2500.00'] | ['395.116', '2500.00'] | Failed |
| control: yen base pair | ['0.07032', '500.00'] | ['0.07027', '500.00'] | Failed |
| control: sterling | ['1.26491', '33.33'] | ['1.26494', '33.33'] | Failed |
SHA-256 / 2887162b4a580160a6535aa6c60b0e2c2ff8d7584d813149416d581a4409b018
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
from decimal import Decimal, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_FLOOR, ROUND_CEILING, ROUND_DOWN, ROUND_UP, ROUND_HALF_DOWN
N = 1
observations = []
def solve(pair, spot, points, notional):
pip_exp = {'JPY': 2, 'HUF': 2, 'KRW': 0}
quote = pair[3:]
pe = pip_exp.get(quote, 4)
pip = Decimal(1).scaleb(-pe)
fwd = Decimal(spot) + Decimal(points) * pip
fwd = fwd.quantize(Decimal(1).scaleb(-(pe + 1)), rounding=ROUND_HALF_EVEN)
pv = (Decimal(notional) * pip).quantize(Decimal('0.01'), rounding=ROUND_HALF_EVEN)
return [format(fwd, 'f'), format(pv, 'f')]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression fractional-points 1', ('EURUSD', '1.08345', '12.5', 1000000), ['1.08470', '100.00']),
('regression fractional-points 2', ('USDJPY', '151.234', '-45.25', 1000000), ['150.782', '10000.00']),
('control: won pips', ('USDKRW', '1352.5', '3.2', 1000000), ['1355.7', '1000000.00']),
('control: forint', ('EURHUF', '395.12', '-0.35', 250000), ['395.116', '2500.00']),
('control: yen base pair', ('JPYSEK', '0.07012', '1.5', 5000000), ['0.07027', '500.00']),
('control: sterling', ('GBPUSD', '1.26501', '-0.75', 333333), ['1.26494', '33.33'])],
[('regression fractional-points 1', ('USDKRW', '1352.5', '3.2', 1000000), ['1355.7', '1000000.00']),
('regression fractional-points 2', ('EURHUF', '395.12', '-0.35', 250000), ['395.116', '2500.00']),
('control: yen base pair', ('JPYSEK', '0.07012', '1.5', 5000000), ['0.07027', '500.00']),
('control: sterling', ('GBPUSD', '1.26501', '-0.75', 333333), ['1.26494', '33.33']),
('control: zero points', ('AUDNZD', '1.09876', '0', 100000), ['1.09876', '10.00']),
('control: euro premium', ('EURUSD', '1.08345', '12.5', 1000000), ['1.08470', '100.00'])],
[('regression fractional-points 1', ('JPYSEK', '0.07012', '1.5', 5000000), ['0.07027', '500.00']),
('regression fractional-points 2', ('GBPUSD', '1.26501', '-0.75', 333333), ['1.26494', '33.33']),
('control: zero points', ('AUDNZD', '1.09876', '0', 100000), ['1.09876', '10.00']),
('control: euro premium', ('EURUSD', '1.08345', '12.5', 1000000), ['1.08470', '100.00']),
('control: yen discount', ('USDJPY', '151.234', '-45.25', 1000000), ['150.782', '10000.00']),
('control: won pips', ('USDKRW', '1352.5', '3.2', 1000000), ['1355.7', '1000000.00'])],
[('regression fractional-points 1', ('EURHUF', '698.3982', '193.71', 1000), ['700.335', '10.00']),
('regression fractional-points 2', ('EURHUF', '138.28482', '-67.66', 1000), ['137.608', '10.00']),
('control: won pips', ('USDKRW', '1352.5', '3.2', 1000000), ['1355.7', '1000000.00']),
('control: forint', ('EURHUF', '395.12', '-0.35', 250000), ['395.116', '2500.00']),
('control: yen base pair', ('JPYSEK', '0.07012', '1.5', 5000000), ['0.07027', '500.00']),
('control: sterling', ('GBPUSD', '1.26501', '-0.75', 333333), ['1.26494', '33.33'])],
[('regression fractional-points 1', ('EURHUF', '4938.658', '-58.12', 1000000), ['4938.077', '10000.00']),
('regression fractional-points 2', ('JPYSEK', '183.37113', '-118.52', 1000), ['183.35928', '0.10']),
('control: sterling', ('GBPUSD', '1.26501', '-0.75', 333333), ['1.26494', '33.33']),
('control: zero points', ('AUDNZD', '1.09876', '0', 100000), ['1.09876', '10.00']),
('control: euro premium', ('EURUSD', '1.08345', '12.5', 1000000), ['1.08470', '100.00']),
('control: yen discount', ('USDJPY', '151.234', '-45.25', 1000000), ['150.782', '10000.00'])]]
for label, args, expected in cases[N - 1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression fractional-points 1 | ['1.08470', '100.00'] | ['1.08470', '100.00'] | Passed |
| regression fractional-points 2 | ['150.782', '10000.00'] | ['150.782', '10000.00'] | Passed |
| control: won pips | ['1355.7', '1000000.00'] | ['1355.7', '1000000.00'] | Passed |
| control: forint | ['395.116', '2500.00'] | ['395.116', '2500.00'] | Passed |
| control: yen base pair | ['0.07027', '500.00'] | ['0.07027', '500.00'] | Passed |
| control: sterling | ['1.26494', '33.33'] | ['1.26494', '33.33'] | Passed |
SHA-256 / db16cca41cb2649a0a33b562451ab4f464d702c6d7d5782bfcae3f240d759bee
Verification & scope
A deterministic, bounded teaching model with a stipulated toy contract; it makes no claim of conformance to any real regulation, standard, or institution's rules. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:47:01.342329+00:00.
Case digest / 30693d81aa1fdb440df6c995cdad808eb3cd59be99d823e2b30967b4dcaeb430