broken_source:
"""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
from fractions import Fraction
N = 1
observations = []
def solve(trades, spot):
    def fmt(fr, e):
        d = (Decimal(fr.numerator) / Decimal(fr.denominator)).quantize(Decimal(1).scaleb(-e), rounding=ROUND_HALF_EVEN)
        return format(abs(d) if d == 0 else d, 'f')
    pos, avg, realized = 0, None, Fraction(0)
    for qty, rate in trades:
        r = Fraction(rate)
        if qty == 0: continue
        if pos == 0 or (pos > 0) == (qty > 0):
            avg = r if pos == 0 else (abs(pos) * avg + abs(qty) * r) / (abs(pos) + abs(qty))
            pos += qty
        else:
            closed = min(abs(qty), abs(pos))
            sgn = 1 if pos > 0 else -1
            realized += closed * (r - avg) * sgn
            if pos + qty != 0: avg = (pos * avg + qty * r) / (pos + qty)
            pos += qty
            if pos == 0: avg = None
            elif (pos > 0) != (sgn > 0): avg = r
    unreal = pos * (Fraction(spot) - avg) if pos else Fraction(0)
    return [pos, None if avg is None else fmt(avg, 6), fmt(realized, 2), fmt(unreal, 2)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression reduction-average 1', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('regression reduction-average 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46'])],
 [('regression reduction-average 1',
   ([[340, '1.0922'], [380, '1.0595'], [0, '1.1288'], [220, '1.0703'], [220, '1.0901'], [-390, '1.1478']], '1.0752'),
   [770, '1.076936', '27.64', '-1.34']),
  ('regression reduction-average 2', ([[270, '1.1098'], [-40, '1.1476']], '1.0552'),
   [230, '1.109800', '1.51', '-12.56']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00'])],
 [('regression reduction-average 1',
   ([[-540, '1.1190'], [-60, '1.0677'], [20, '1.1443'], [-240, '1.1212'], [0, '1.0908']], '1.0791'),
   [-820, '1.116015', '-0.61', '30.27']),
  ('regression reduction-average 2',
   ([[-450, '1.1009'], [0, '1.1001'], [230, '1.0743'], [0, '1.0884'], [-190, '1.0956'], [30, '1.0635']], '1.0627'),
   [-380, '1.098444', '7.17', '13.58']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50'])],
 [('regression reduction-average 1',
   ([[-40, '1.1445'], [-570, '1.0711'], [530, '1.1387'], [-450, '1.0688'], [-300, '1.1071']], '1.1211'),
   [-830, '1.083329', '-33.28', '-31.35']),
  ('regression reduction-average 2',
   ([[-460, '1.1380'], [-260, '1.0732'], [-130, '1.1234'], [-300, '1.0815'], [210, '1.0636']], '1.0880'),
   [-940, '1.106960', '9.11', '17.82']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46'])],
 [('regression reduction-average 1',
   ([[0, '1.0935'], [100, '1.0751'], [570, '1.0814'], [280, '1.1411'], [-350, '1.1101'], [590, '1.1297']], '1.0775'),
   [1190, '1.113885', '4.12', '-43.30']),
  ('regression reduction-average 2',
   ([[0, '1.0983'], [-530, '1.1416'], [-170, '1.1049'], [280, '1.1333'], [-140, '1.0910'], [0, '1.0954']], '1.0893'),
   [-560, '1.122265', '-0.17', '18.46']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.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)

source:
"""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
from fractions import Fraction
N = 1
observations = []
def solve(trades, spot):
    def fmt(fr, e):
        d = (Decimal(fr.numerator) / Decimal(fr.denominator)).quantize(Decimal(1).scaleb(-e), rounding=ROUND_HALF_EVEN)
        return format(abs(d) if d == 0 else d, 'f')
    pos, avg, realized = 0, None, Fraction(0)
    for qty, rate in trades:
        r = Fraction(rate)
        if qty == 0: continue
        if pos == 0 or (pos > 0) == (qty > 0):
            avg = r if pos == 0 else (abs(pos) * avg + abs(qty) * r) / (abs(pos) + abs(qty))
            pos += qty
        else:
            closed = min(abs(qty), abs(pos))
            sgn = 1 if pos > 0 else -1
            realized += closed * (r - avg) * sgn
            if pos + qty != 0: avg = (abs(pos) * avg + abs(qty) * r) / (abs(pos) + abs(qty))
            pos += qty
            if pos == 0: avg = None
            elif (pos > 0) != (sgn > 0): avg = r
    unreal = pos * (Fraction(spot) - avg) if pos else Fraction(0)
    return [pos, None if avg is None else fmt(avg, 6), fmt(realized, 2), fmt(unreal, 2)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression reduction-average 1', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('regression reduction-average 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46'])],
 [('regression reduction-average 1',
   ([[340, '1.0922'], [380, '1.0595'], [0, '1.1288'], [220, '1.0703'], [220, '1.0901'], [-390, '1.1478']], '1.0752'),
   [770, '1.076936', '27.64', '-1.34']),
  ('regression reduction-average 2', ([[270, '1.1098'], [-40, '1.1476']], '1.0552'),
   [230, '1.109800', '1.51', '-12.56']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00'])],
 [('regression reduction-average 1',
   ([[-540, '1.1190'], [-60, '1.0677'], [20, '1.1443'], [-240, '1.1212'], [0, '1.0908']], '1.0791'),
   [-820, '1.116015', '-0.61', '30.27']),
  ('regression reduction-average 2',
   ([[-450, '1.1009'], [0, '1.1001'], [230, '1.0743'], [0, '1.0884'], [-190, '1.0956'], [30, '1.0635']], '1.0627'),
   [-380, '1.098444', '7.17', '13.58']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50'])],
 [('regression reduction-average 1',
   ([[-40, '1.1445'], [-570, '1.0711'], [530, '1.1387'], [-450, '1.0688'], [-300, '1.1071']], '1.1211'),
   [-830, '1.083329', '-33.28', '-31.35']),
  ('regression reduction-average 2',
   ([[-460, '1.1380'], [-260, '1.0732'], [-130, '1.1234'], [-300, '1.0815'], [210, '1.0636']], '1.0880'),
   [-940, '1.106960', '9.11', '17.82']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46'])],
 [('regression reduction-average 1',
   ([[0, '1.0935'], [100, '1.0751'], [570, '1.0814'], [280, '1.1411'], [-350, '1.1101'], [590, '1.1297']], '1.0775'),
   [1190, '1.113885', '4.12', '-43.30']),
  ('regression reduction-average 2',
   ([[0, '1.0983'], [-530, '1.1416'], [-170, '1.1049'], [280, '1.1333'], [-140, '1.0910'], [0, '1.0954']], '1.0893'),
   [-560, '1.122265', '-0.17', '18.46']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.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)

prompt:
After selling part of a long position the remaining lot shows a new average and wrong unrealized P&L.

solve(trades, spot): trades are [qty, rate] in foreign units (buy positive, sell negative) at home-per-foreign decimal rates. Adding in the position's direction updates the weighted average rate; reducing realizes closed_qty * (rate - avg) * sign(position) without changing avg; a flip realizes the closed part and opens the remainder at the trade rate; a flat position has no average. Zero-quantity trades are ignored. Unrealized = position * (spot - avg). Return [position, avg to 6 dp or None, realized to 2 dp, unrealized to 2 dp], rounded half-even only at output with unsigned zeros.

split: open-access


broken_source:
"""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
from fractions import Fraction
N = 1
observations = []
def solve(trades, spot):
    def fmt(fr, e):
        d = (Decimal(fr.numerator) / Decimal(fr.denominator)).quantize(Decimal(1).scaleb(-e), rounding=ROUND_HALF_EVEN)
        return format(abs(d) if d == 0 else d, 'f')
    pos, avg, realized = 0, None, Fraction(0)
    for qty, rate in trades:
        r = Fraction(rate)
        if qty == 0: continue
        if pos == 0 or (pos > 0) == (qty > 0):
            avg = r if pos == 0 else (abs(pos) * avg + abs(qty) * r) / (abs(pos) + abs(qty))
            pos += qty
        else:
            closed = min(abs(qty), abs(pos))
            sgn = 1 if pos > 0 else -1
            realized += closed * (r - avg) * sgn
            pos += qty
            if pos == 0: avg = None
    unreal = pos * (Fraction(spot) - avg) if pos else Fraction(0)
    return [pos, None if avg is None else fmt(avg, 6), fmt(realized, 2), fmt(unreal, 2)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression flip-reset 1', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('regression flip-reset 2', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),
  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00'])],
 [('regression flip-reset 1', ([[-90, '1.0708'], [540, '1.1315']], '1.0885'), [450, '1.131500', '-5.46', '-19.35']),
  ('regression flip-reset 2', ([[-220, '1.1085'], [310, '1.1162'], [-140, '1.1499']], '1.1267'),
   [-50, '1.149900', '1.34', '1.16']),
  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00'])],
 [('regression flip-reset 1',
   ([[0, '1.0601'], [0, '1.0705'], [-110, '1.1230'], [310, '1.0559'], [400, '1.1307']], '1.1024'),
   [600, '1.105767', '7.38', '-2.02']),
  ('regression flip-reset 2',
   ([[160, '1.0719'], [-230, '1.0804'], [-80, '1.1289'], [50, '1.1492'], [570, '1.1139'], [570, '1.1011']], '1.0962'),
   [1040, '1.106885', '-1.55', '-11.11']),
  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50'])],
 [('regression flip-reset 1',
   ([[-430, '1.0685'], [30, '1.0569'], [100, '1.0804'], [540, '1.0505'], [0, '1.0888'], [-490, '1.0791']], '1.0807'),
   [-250, '1.079100', '11.42', '-0.40']),
  ('regression flip-reset 2', ([[440, '1.0718'], [-570, '1.0726'], [40, '1.1343'], [-160, '1.1482']], '1.1222'),
   [-250, '1.120984', '-2.12', '-0.30']),
  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00'])],
 [('regression flip-reset 1',
   ([[-560, '1.1226'], [90, '1.1160'], [300, '1.0734'], [-220, '1.0848'], [500, '1.0820']], '1.1354'),
   [110, '1.082000', '22.87', '5.87']),
  ('regression flip-reset 2', ([[-290, '1.1340'], [220, '1.0570'], [420, '1.0731']], '1.1418'),
   [350, '1.073100', '21.20', '24.04']),
  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.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)

meaning: Fixture-count band, not measured model difficulty

deps: stdlib

source:
"""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
from fractions import Fraction
N = 1
observations = []
def solve(trades, spot):
    def fmt(fr, e):
        d = (Decimal(fr.numerator) / Decimal(fr.denominator)).quantize(Decimal(1).scaleb(-e), rounding=ROUND_HALF_EVEN)
        return format(abs(d) if d == 0 else d, 'f')
    pos, avg, realized = 0, None, Fraction(0)
    for qty, rate in trades:
        r = Fraction(rate)
        if qty == 0: continue
        if pos == 0 or (pos > 0) == (qty > 0):
            avg = r if pos == 0 else (abs(pos) * avg + abs(qty) * r) / (abs(pos) + abs(qty))
            pos += qty
        else:
            closed = min(abs(qty), abs(pos))
            sgn = 1 if pos > 0 else -1
            realized += closed * (r - avg) * sgn
            pos += qty
            if pos == 0 or (pos > 0) != (sgn > 0): avg = r
    unreal = pos * (Fraction(spot) - avg) if pos else Fraction(0)
    return [pos, None if avg is None else fmt(avg, 6), fmt(realized, 2), fmt(unreal, 2)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression flip-reset 1', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('regression flip-reset 2', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),
  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00'])],
 [('regression flip-reset 1', ([[-90, '1.0708'], [540, '1.1315']], '1.0885'), [450, '1.131500', '-5.46', '-19.35']),
  ('regression flip-reset 2', ([[-220, '1.1085'], [310, '1.1162'], [-140, '1.1499']], '1.1267'),
   [-50, '1.149900', '1.34', '1.16']),
  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00'])],
 [('regression flip-reset 1',
   ([[0, '1.0601'], [0, '1.0705'], [-110, '1.1230'], [310, '1.0559'], [400, '1.1307']], '1.1024'),
   [600, '1.105767', '7.38', '-2.02']),
  ('regression flip-reset 2',
   ([[160, '1.0719'], [-230, '1.0804'], [-80, '1.1289'], [50, '1.1492'], [570, '1.1139'], [570, '1.1011']], '1.0962'),
   [1040, '1.106885', '-1.55', '-11.11']),
  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50'])],
 [('regression flip-reset 1',
   ([[-430, '1.0685'], [30, '1.0569'], [100, '1.0804'], [540, '1.0505'], [0, '1.0888'], [-490, '1.0791']], '1.0807'),
   [-250, '1.079100', '11.42', '-0.40']),
  ('regression flip-reset 2', ([[440, '1.0718'], [-570, '1.0726'], [40, '1.1343'], [-160, '1.1482']], '1.1222'),
   [-250, '1.120984', '-2.12', '-0.30']),
  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00'])],
 [('regression flip-reset 1',
   ([[-560, '1.1226'], [90, '1.1160'], [300, '1.0734'], [-220, '1.0848'], [500, '1.0820']], '1.1354'),
   [110, '1.082000', '22.87', '5.87']),
  ('regression flip-reset 2', ([[-290, '1.1340'], [220, '1.0570'], [420, '1.0731']], '1.1418'),
   [350, '1.073100', '21.20', '24.04']),
  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.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)

prompt:
A long position flipped short reports the old long average for the new short lot.

solve(trades, spot): trades are [qty, rate] in foreign units (buy positive, sell negative) at home-per-foreign decimal rates. Adding in the position's direction updates the weighted average rate; reducing realizes closed_qty * (rate - avg) * sign(position) without changing avg; a flip realizes the closed part and opens the remainder at the trade rate; a flat position has no average. Zero-quantity trades are ignored. Unrealized = position * (spot - avg). Return [position, avg to 6 dp or None, realized to 2 dp, unrealized to 2 dp], rounded half-even only at output with unsigned zeros.

split: open-access


broken_source:
"""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
from fractions import Fraction
N = 1
observations = []
def solve(trades, spot):
    def fmt(fr, e):
        d = (Decimal(fr.numerator) / Decimal(fr.denominator)).quantize(Decimal(1).scaleb(-e), rounding=ROUND_HALF_EVEN)
        return format(abs(d) if d == 0 else d, 'f')
    pos, avg, realized = 0, None, Fraction(0)
    for qty, rate in trades:
        r = Fraction(rate)
        if qty == 0: continue
        if pos == 0 or (pos > 0) == (qty > 0):
            avg = r if pos == 0 else (abs(pos) * avg + abs(qty) * r) / (abs(pos) + abs(qty))
            pos += qty
        else:
            closed = min(abs(qty), abs(pos))
            sgn = 1 if pos > 0 else -1
            realized += closed * (r - avg)
            pos += qty
            if pos == 0: avg = None
            elif (pos > 0) != (sgn > 0): avg = r
    unreal = pos * (Fraction(spot) - avg) if pos else Fraction(0)
    return [pos, None if avg is None else fmt(avg, 6), fmt(realized, 2), fmt(unreal, 2)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression short-realized-sign 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('regression short-realized-sign 2', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),
  ('partial repair guard 2', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00'])],
 [('regression short-realized-sign 1', ([[-90, '1.0708'], [540, '1.1315']], '1.0885'),
   [450, '1.131500', '-5.46', '-19.35']),
  ('regression short-realized-sign 2', ([[-220, '1.1085'], [310, '1.1162'], [-140, '1.1499']], '1.1267'),
   [-50, '1.149900', '1.34', '1.16']),
  ('partial repair guard 1', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00'])],
 [('regression short-realized-sign 1',
   ([[-540, '1.1190'], [-60, '1.0677'], [20, '1.1443'], [-240, '1.1212'], [0, '1.0908']], '1.0791'),
   [-820, '1.116015', '-0.61', '30.27']),
  ('regression short-realized-sign 2',
   ([[0, '1.0601'], [0, '1.0705'], [-110, '1.1230'], [310, '1.0559'], [400, '1.1307']], '1.1024'),
   [600, '1.105767', '7.38', '-2.02']),
  ('partial repair guard 1', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('partial repair guard 2', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00'])],
 [('regression short-realized-sign 1',
   ([[-450, '1.1009'], [0, '1.1001'], [230, '1.0743'], [0, '1.0884'], [-190, '1.0956'], [30, '1.0635']], '1.0627'),
   [-380, '1.098444', '7.17', '13.58']),
  ('regression short-realized-sign 2',
   ([[-40, '1.1445'], [-570, '1.0711'], [530, '1.1387'], [-450, '1.0688'], [-300, '1.1071']], '1.1211'),
   [-830, '1.083329', '-33.28', '-31.35']),
  ('partial repair guard 1',
   ([[340, '1.0922'], [380, '1.0595'], [0, '1.1288'], [220, '1.0703'], [220, '1.0901'], [-390, '1.1478']], '1.0752'),
   [770, '1.076936', '27.64', '-1.34']),
  ('partial repair guard 2', ([[270, '1.1098'], [-40, '1.1476']], '1.0552'), [230, '1.109800', '1.51', '-12.56']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46'])],
 [('regression short-realized-sign 1',
   ([[-460, '1.1380'], [-260, '1.0732'], [-130, '1.1234'], [-300, '1.0815'], [210, '1.0636']], '1.0880'),
   [-940, '1.106960', '9.11', '17.82']),
  ('regression short-realized-sign 2',
   ([[0, '1.0983'], [-530, '1.1416'], [-170, '1.1049'], [280, '1.1333'], [-140, '1.0910'], [0, '1.0954']], '1.0893'),
   [-560, '1.122265', '-0.17', '18.46']),
  ('partial repair guard 1', ([[-90, '1.0708'], [540, '1.1315']], '1.0885'), [450, '1.131500', '-5.46', '-19.35']),
  ('partial repair guard 2', ([[-220, '1.1085'], [310, '1.1162'], [-140, '1.1499']], '1.1267'),
   [-50, '1.149900', '1.34', '1.16']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.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)

source:
"""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
from fractions import Fraction
N = 1
observations = []
def solve(trades, spot):
    def fmt(fr, e):
        d = (Decimal(fr.numerator) / Decimal(fr.denominator)).quantize(Decimal(1).scaleb(-e), rounding=ROUND_HALF_EVEN)
        return format(abs(d) if d == 0 else d, 'f')
    pos, avg, realized = 0, None, Fraction(0)
    for qty, rate in trades:
        r = Fraction(rate)
        if qty == 0: continue
        if pos == 0 or (pos > 0) == (qty > 0):
            avg = r if pos == 0 else (abs(pos) * avg + abs(qty) * r) / (abs(pos) + abs(qty))
            pos += qty
        else:
            closed = min(abs(qty), abs(pos))
            sgn = 1 if pos > 0 else -1
            realized += closed * (r - avg) * (1 if qty > 0 else -1)
            pos += qty
            if pos == 0: avg = None
            elif (pos > 0) != (sgn > 0): avg = r
    unreal = pos * (Fraction(spot) - avg) if pos else Fraction(0)
    return [pos, None if avg is None else fmt(avg, 6), fmt(realized, 2), fmt(unreal, 2)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression short-realized-sign 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('regression short-realized-sign 2', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),
  ('partial repair guard 2', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00'])],
 [('regression short-realized-sign 1', ([[-90, '1.0708'], [540, '1.1315']], '1.0885'),
   [450, '1.131500', '-5.46', '-19.35']),
  ('regression short-realized-sign 2', ([[-220, '1.1085'], [310, '1.1162'], [-140, '1.1499']], '1.1267'),
   [-50, '1.149900', '1.34', '1.16']),
  ('partial repair guard 1', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00'])],
 [('regression short-realized-sign 1',
   ([[-540, '1.1190'], [-60, '1.0677'], [20, '1.1443'], [-240, '1.1212'], [0, '1.0908']], '1.0791'),
   [-820, '1.116015', '-0.61', '30.27']),
  ('regression short-realized-sign 2',
   ([[0, '1.0601'], [0, '1.0705'], [-110, '1.1230'], [310, '1.0559'], [400, '1.1307']], '1.1024'),
   [600, '1.105767', '7.38', '-2.02']),
  ('partial repair guard 1', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('partial repair guard 2', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00'])],
 [('regression short-realized-sign 1',
   ([[-450, '1.1009'], [0, '1.1001'], [230, '1.0743'], [0, '1.0884'], [-190, '1.0956'], [30, '1.0635']], '1.0627'),
   [-380, '1.098444', '7.17', '13.58']),
  ('regression short-realized-sign 2',
   ([[-40, '1.1445'], [-570, '1.0711'], [530, '1.1387'], [-450, '1.0688'], [-300, '1.1071']], '1.1211'),
   [-830, '1.083329', '-33.28', '-31.35']),
  ('partial repair guard 1',
   ([[340, '1.0922'], [380, '1.0595'], [0, '1.1288'], [220, '1.0703'], [220, '1.0901'], [-390, '1.1478']], '1.0752'),
   [770, '1.076936', '27.64', '-1.34']),
  ('partial repair guard 2', ([[270, '1.1098'], [-40, '1.1476']], '1.0552'), [230, '1.109800', '1.51', '-12.56']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46'])],
 [('regression short-realized-sign 1',
   ([[-460, '1.1380'], [-260, '1.0732'], [-130, '1.1234'], [-300, '1.0815'], [210, '1.0636']], '1.0880'),
   [-940, '1.106960', '9.11', '17.82']),
  ('regression short-realized-sign 2',
   ([[0, '1.0983'], [-530, '1.1416'], [-170, '1.1049'], [280, '1.1333'], [-140, '1.0910'], [0, '1.0954']], '1.0893'),
   [-560, '1.122265', '-0.17', '18.46']),
  ('partial repair guard 1', ([[-90, '1.0708'], [540, '1.1315']], '1.0885'), [450, '1.131500', '-5.46', '-19.35']),
  ('partial repair guard 2', ([[-220, '1.1085'], [310, '1.1162'], [-140, '1.1499']], '1.1267'),
   [-50, '1.149900', '1.34', '1.16']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.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)

prompt:
Buying back a short below its average books a loss.

solve(trades, spot): trades are [qty, rate] in foreign units (buy positive, sell negative) at home-per-foreign decimal rates. Adding in the position's direction updates the weighted average rate; reducing realizes closed_qty * (rate - avg) * sign(position) without changing avg; a flip realizes the closed part and opens the remainder at the trade rate; a flat position has no average. Zero-quantity trades are ignored. Unrealized = position * (spot - avg). Return [position, avg to 6 dp or None, realized to 2 dp, unrealized to 2 dp], rounded half-even only at output with unsigned zeros.

split: open-access


broken_source:
"""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
from fractions import Fraction
N = 1
observations = []
def solve(trades, spot):
    def fmt(fr, e):
        d = (Decimal(fr.numerator) / Decimal(fr.denominator)).quantize(Decimal(1).scaleb(-e), rounding=ROUND_HALF_EVEN)
        return format(abs(d) if d == 0 else d, 'f')
    pos, avg, realized = 0, None, Fraction(0)
    for qty, rate in trades:
        r = Fraction(rate)
        if qty == 0: continue
        if pos == 0 or (pos > 0) == (qty > 0):
            avg = r if pos == 0 else (abs(pos) * avg + abs(qty) * r) / (abs(pos) + abs(qty))
            pos += qty
        else:
            closed = min(abs(qty), abs(pos))
            sgn = 1 if pos > 0 else -1
            realized += closed * (r - avg) * sgn
            pos += qty
            if pos == 0: avg = None
            elif (pos > 0) != (sgn > 0): avg = r
    unreal = pos * (avg - Fraction(spot)) if pos else Fraction(0)
    return [pos, None if avg is None else fmt(avg, 6), fmt(realized, 2), fmt(unreal, 2)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression unrealized-direction 1', ([[100, '1.10'], [-150, '1.00']], '1.05'),
   [-50, '1.000000', '-10.00', '-2.50']),
  ('regression unrealized-direction 2', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'),
   [-100, '1.084560', '0.00', '0.46']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00'])],
 [('regression unrealized-direction 1', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('regression unrealized-direction 2', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('partial repair guard 1', ([[-220, '1.1085'], [310, '1.1162'], [-140, '1.1499']], '1.1267'),
   [-50, '1.149900', '1.34', '1.16']),
  ('partial repair guard 2', ([[-580, '1.0680']], '1.1073'), [-580, '1.068000', '0.00', '-22.79']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00'])],
 [('regression unrealized-direction 1', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),
  ('regression unrealized-direction 2', ([[80, '1.1282']], '1.0902'), [80, '1.128200', '0.00', '-3.04']),
  ('partial repair guard 1',
   ([[-540, '1.1190'], [-60, '1.0677'], [20, '1.1443'], [-240, '1.1212'], [0, '1.0908']], '1.0791'),
   [-820, '1.116015', '-0.61', '30.27']),
  ('partial repair guard 2', ([[-400, '1.1002'], [-30, '1.1375'], [0, '1.0641']], '1.1316'),
   [-430, '1.102802', '0.00', '-12.38']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00'])],
 [('regression unrealized-direction 1', ([[480, '1.0533'], [0, '1.0736']], '1.1048'),
   [480, '1.053300', '0.00', '24.72']),
  ('regression unrealized-direction 2',
   ([[340, '1.0922'], [380, '1.0595'], [0, '1.1288'], [220, '1.0703'], [220, '1.0901'], [-390, '1.1478']], '1.0752'),
   [770, '1.076936', '27.64', '-1.34']),
  ('partial repair guard 1',
   ([[-450, '1.1009'], [0, '1.1001'], [230, '1.0743'], [0, '1.0884'], [-190, '1.0956'], [30, '1.0635']], '1.0627'),
   [-380, '1.098444', '7.17', '13.58']),
  ('partial repair guard 2',
   ([[-40, '1.1445'], [-570, '1.0711'], [530, '1.1387'], [-450, '1.0688'], [-300, '1.1071']], '1.1211'),
   [-830, '1.083329', '-33.28', '-31.35']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46'])],
 [('regression unrealized-direction 1', ([[270, '1.1098'], [-40, '1.1476']], '1.0552'),
   [230, '1.109800', '1.51', '-12.56']),
  ('regression unrealized-direction 2', ([[-90, '1.0708'], [540, '1.1315']], '1.0885'),
   [450, '1.131500', '-5.46', '-19.35']),
  ('partial repair guard 1',
   ([[-460, '1.1380'], [-260, '1.0732'], [-130, '1.1234'], [-300, '1.0815'], [210, '1.0636']], '1.0880'),
   [-940, '1.106960', '9.11', '17.82']),
  ('partial repair guard 2', ([[-510, '1.0855']], '1.1262'), [-510, '1.085500', '0.00', '-20.76']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.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)

source:
"""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
from fractions import Fraction
N = 1
observations = []
def solve(trades, spot):
    def fmt(fr, e):
        d = (Decimal(fr.numerator) / Decimal(fr.denominator)).quantize(Decimal(1).scaleb(-e), rounding=ROUND_HALF_EVEN)
        return format(abs(d) if d == 0 else d, 'f')
    pos, avg, realized = 0, None, Fraction(0)
    for qty, rate in trades:
        r = Fraction(rate)
        if qty == 0: continue
        if pos == 0 or (pos > 0) == (qty > 0):
            avg = r if pos == 0 else (abs(pos) * avg + abs(qty) * r) / (abs(pos) + abs(qty))
            pos += qty
        else:
            closed = min(abs(qty), abs(pos))
            sgn = 1 if pos > 0 else -1
            realized += closed * (r - avg) * sgn
            pos += qty
            if pos == 0: avg = None
            elif (pos > 0) != (sgn > 0): avg = r
    unreal = abs(pos) * (Fraction(spot) - avg) if pos else Fraction(0)
    return [pos, None if avg is None else fmt(avg, 6), fmt(realized, 2), fmt(unreal, 2)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression unrealized-direction 1', ([[100, '1.10'], [-150, '1.00']], '1.05'),
   [-50, '1.000000', '-10.00', '-2.50']),
  ('regression unrealized-direction 2', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'),
   [-100, '1.084560', '0.00', '0.46']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00'])],
 [('regression unrealized-direction 1', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('regression unrealized-direction 2', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('partial repair guard 1', ([[-220, '1.1085'], [310, '1.1162'], [-140, '1.1499']], '1.1267'),
   [-50, '1.149900', '1.34', '1.16']),
  ('partial repair guard 2', ([[-580, '1.0680']], '1.1073'), [-580, '1.068000', '0.00', '-22.79']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00'])],
 [('regression unrealized-direction 1', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),
  ('regression unrealized-direction 2', ([[80, '1.1282']], '1.0902'), [80, '1.128200', '0.00', '-3.04']),
  ('partial repair guard 1',
   ([[-540, '1.1190'], [-60, '1.0677'], [20, '1.1443'], [-240, '1.1212'], [0, '1.0908']], '1.0791'),
   [-820, '1.116015', '-0.61', '30.27']),
  ('partial repair guard 2', ([[-400, '1.1002'], [-30, '1.1375'], [0, '1.0641']], '1.1316'),
   [-430, '1.102802', '0.00', '-12.38']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00'])],
 [('regression unrealized-direction 1', ([[480, '1.0533'], [0, '1.0736']], '1.1048'),
   [480, '1.053300', '0.00', '24.72']),
  ('regression unrealized-direction 2',
   ([[340, '1.0922'], [380, '1.0595'], [0, '1.1288'], [220, '1.0703'], [220, '1.0901'], [-390, '1.1478']], '1.0752'),
   [770, '1.076936', '27.64', '-1.34']),
  ('partial repair guard 1',
   ([[-450, '1.1009'], [0, '1.1001'], [230, '1.0743'], [0, '1.0884'], [-190, '1.0956'], [30, '1.0635']], '1.0627'),
   [-380, '1.098444', '7.17', '13.58']),
  ('partial repair guard 2',
   ([[-40, '1.1445'], [-570, '1.0711'], [530, '1.1387'], [-450, '1.0688'], [-300, '1.1071']], '1.1211'),
   [-830, '1.083329', '-33.28', '-31.35']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46'])],
 [('regression unrealized-direction 1', ([[270, '1.1098'], [-40, '1.1476']], '1.0552'),
   [230, '1.109800', '1.51', '-12.56']),
  ('regression unrealized-direction 2', ([[-90, '1.0708'], [540, '1.1315']], '1.0885'),
   [450, '1.131500', '-5.46', '-19.35']),
  ('partial repair guard 1',
   ([[-460, '1.1380'], [-260, '1.0732'], [-130, '1.1234'], [-300, '1.0815'], [210, '1.0636']], '1.0880'),
   [-940, '1.106960', '9.11', '17.82']),
  ('partial repair guard 2', ([[-510, '1.0855']], '1.1262'), [-510, '1.085500', '0.00', '-20.76']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.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)

prompt:
A long position shows a loss when spot is above its average.

solve(trades, spot): trades are [qty, rate] in foreign units (buy positive, sell negative) at home-per-foreign decimal rates. Adding in the position's direction updates the weighted average rate; reducing realizes closed_qty * (rate - avg) * sign(position) without changing avg; a flip realizes the closed part and opens the remainder at the trade rate; a flat position has no average. Zero-quantity trades are ignored. Unrealized = position * (spot - avg). Return [position, avg to 6 dp or None, realized to 2 dp, unrealized to 2 dp], rounded half-even only at output with unsigned zeros.

split: open-access


broken_source:
"""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
from fractions import Fraction
N = 1
observations = []
def solve(trades, spot):
    def fmt(fr, e):
        d = (Decimal(fr.numerator) / Decimal(fr.denominator)).quantize(Decimal(1).scaleb(-e), rounding=ROUND_HALF_EVEN)
        return format(abs(d) if d == 0 else d, 'f')
    pos, avg, realized = 0, None, Fraction(0)
    for qty, rate in trades:
        r = Fraction(rate)
        pass
        if pos == 0 or (pos > 0) == (qty > 0):
            avg = r if pos == 0 else (abs(pos) * avg + abs(qty) * r) / (abs(pos) + abs(qty))
            pos += qty
        else:
            closed = min(abs(qty), abs(pos))
            sgn = 1 if pos > 0 else -1
            realized += closed * (r - avg) * sgn
            pos += qty
            if pos == 0: avg = None
            elif (pos > 0) != (sgn > 0): avg = r
    unreal = pos * (Fraction(spot) - avg) if pos else Fraction(0)
    return [pos, None if avg is None else fmt(avg, 6), fmt(realized, 2), fmt(unreal, 2)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression zero-quantity-trade 1', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('regression zero-quantity-trade 2', ([[50, '1.1'], [-50, '1.2'], [0, '1.3']], '1.5'), [0, None, '5.00', '0.00']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46'])],
 [('regression zero-quantity-trade 1', ([[0, '1.1473'], [0, '1.0737']], '1.1228'), [0, None, '0.00', '0.00']),
  ('regression zero-quantity-trade 2', ([[0, '1.1043']], '1.1389'), [0, None, '0.00', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00'])],
 [('regression zero-quantity-trade 1', ([[0, '1.0667']], '1.1026'), [0, None, '0.00', '0.00']),
  ('regression zero-quantity-trade 2', ([[0, '1.0905']], '1.0908'), [0, None, '0.00', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50'])],
 [('regression zero-quantity-trade 1', ([[0, '1.1082']], '1.0890'), [0, None, '0.00', '0.00']),
  ('regression zero-quantity-trade 2', ([[0, '1.0848']], '1.0930'), [0, None, '0.00', '0.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46'])],
 [('regression zero-quantity-trade 1', ([[0, '1.1213'], [0, '1.0823']], '1.1168'), [0, None, '0.00', '0.00']),
  ('regression zero-quantity-trade 2', ([[0, '1.0532']], '1.1383'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.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)

source:
"""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
from fractions import Fraction
N = 1
observations = []
def solve(trades, spot):
    def fmt(fr, e):
        d = (Decimal(fr.numerator) / Decimal(fr.denominator)).quantize(Decimal(1).scaleb(-e), rounding=ROUND_HALF_EVEN)
        return format(abs(d) if d == 0 else d, 'f')
    pos, avg, realized = 0, None, Fraction(0)
    for qty, rate in trades:
        r = Fraction(rate)
        if qty == 0 and pos != 0: continue
        if pos == 0 or (pos > 0) == (qty > 0):
            avg = r if pos == 0 else (abs(pos) * avg + abs(qty) * r) / (abs(pos) + abs(qty))
            pos += qty
        else:
            closed = min(abs(qty), abs(pos))
            sgn = 1 if pos > 0 else -1
            realized += closed * (r - avg) * sgn
            pos += qty
            if pos == 0: avg = None
            elif (pos > 0) != (sgn > 0): avg = r
    unreal = pos * (Fraction(spot) - avg) if pos else Fraction(0)
    return [pos, None if avg is None else fmt(avg, 6), fmt(realized, 2), fmt(unreal, 2)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression zero-quantity-trade 1', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('regression zero-quantity-trade 2', ([[50, '1.1'], [-50, '1.2'], [0, '1.3']], '1.5'), [0, None, '5.00', '0.00']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46'])],
 [('regression zero-quantity-trade 1', ([[0, '1.1473'], [0, '1.0737']], '1.1228'), [0, None, '0.00', '0.00']),
  ('regression zero-quantity-trade 2', ([[0, '1.1043']], '1.1389'), [0, None, '0.00', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00'])],
 [('regression zero-quantity-trade 1', ([[0, '1.0667']], '1.1026'), [0, None, '0.00', '0.00']),
  ('regression zero-quantity-trade 2', ([[0, '1.0905']], '1.0908'), [0, None, '0.00', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50'])],
 [('regression zero-quantity-trade 1', ([[0, '1.1082']], '1.0890'), [0, None, '0.00', '0.00']),
  ('regression zero-quantity-trade 2', ([[0, '1.0848']], '1.0930'), [0, None, '0.00', '0.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46'])],
 [('regression zero-quantity-trade 1', ([[0, '1.1213'], [0, '1.0823']], '1.1168'), [0, None, '0.00', '0.00']),
  ('regression zero-quantity-trade 2', ([[0, '1.0532']], '1.1383'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.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)

prompt:
A flat book reports an average rate after a zero-quantity booking correction.

solve(trades, spot): trades are [qty, rate] in foreign units (buy positive, sell negative) at home-per-foreign decimal rates. Adding in the position's direction updates the weighted average rate; reducing realizes closed_qty * (rate - avg) * sign(position) without changing avg; a flip realizes the closed part and opens the remainder at the trade rate; a flat position has no average. Zero-quantity trades are ignored. Unrealized = position * (spot - avg). Return [position, avg to 6 dp or None, realized to 2 dp, unrealized to 2 dp], rounded half-even only at output with unsigned zeros.

split: open-access


broken_source:
"""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
from fractions import Fraction
N = 1
observations = []
def solve(trades, spot):
    def fmt(fr, e):
        d = (Decimal(fr.numerator) / Decimal(fr.denominator)).quantize(Decimal(1).scaleb(-e), rounding=ROUND_HALF_EVEN)
        return format(abs(d) if d == 0 else d, 'f')
    pos, avg, realized = 0, None, Fraction(0)
    for qty, rate in trades:
        r = Fraction(rate)
        if qty == 0: continue
        if pos == 0 or (pos > 0) == (qty > 0):
            avg = r if pos == 0 else (abs(pos) * avg + abs(qty) * r) / (abs(pos) + abs(qty))
            pos += qty
        else:
            closed = min(abs(qty), abs(pos))
            sgn = 1 if pos > 0 else -1
            realized += closed * (r - avg) * sgn
            realized = Fraction(fmt(realized, 2))
            pos += qty
            if pos == 0: avg = None
            elif (pos > 0) != (sgn > 0): avg = r
    unreal = pos * (Fraction(spot) - avg) if pos else Fraction(0)
    return [pos, None if avg is None else fmt(avg, 6), fmt(realized, 2), fmt(unreal, 2)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression realized-accumulation-rounding 1', ([[3, '1'], [-1, '1.005'], [-1, '1.005'], [-1, '1.005']], '1'),
   [0, None, '0.02', '0.00']),
  ('regression realized-accumulation-rounding 2', ([[2, '1'], [-1, '1.00252'], [-1, '1.00251']], '1'),
   [0, None, '0.01', '0.00']),
  ('partial repair guard 1', ([[1, '1'], [-1, '1.00502']], '1'), [0, None, '0.01', '0.00']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00'])],
 [('regression realized-accumulation-rounding 1',
   ([[-160, '1.1445'], [370, '1.0518'], [470, '1.1207'], [-420, '1.1186'], [0, '1.1436'], [-430, '1.0692']], '1.1002'),
   [-170, '1.069200', '15.03', '-5.27']),
  ('regression realized-accumulation-rounding 2',
   ([[-440, '1.1376'], [320, '1.1062'], [-500, '1.1066'], [0, '1.0745'], [-450, '1.0551'], [560, '1.0788']], '1.1271'),
   [-510, '1.088418', '15.43', '-19.73']),
  ('partial repair guard 1', ([[1, '1'], [-1, '1.00502']], '1'), [0, None, '0.01', '0.00']),
  ('partial repair guard 2', ([[2, '1'], [-1, '1.00252'], [-1, '1.00251']], '1'), [0, None, '0.01', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00'])],
 [('regression realized-accumulation-rounding 1', ([[500, '1.1350'], [-210, '1.0625'], [-530, '1.1133']], '1.1442'),
   [-240, '1.113300', '-21.52', '-7.42']),
  ('regression realized-accumulation-rounding 2',
   ([[420, '1.0549'], [-340, '1.1155'], [-600, '1.1019'], [120, '1.0728'], [120, '1.0952'], [300, '1.0728']], '1.1408'),
   [20, '1.072800', '36.81', '1.36']),
  ('partial repair guard 1', ([[1, '1'], [-1, '1.00502']], '1'), [0, None, '0.01', '0.00']),
  ('partial repair guard 2', ([[2, '1'], [-1, '1.00252'], [-1, '1.00251']], '1'), [0, None, '0.01', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50'])],
 [('regression realized-accumulation-rounding 1',
   ([[-330, '1.0644'], [460, '1.1022'], [130, '1.1361'], [0, '1.0789'], [-160, '1.0850']], '1.0640'),
   [100, '1.119150', '-17.94', '-5.52']),
  ('regression realized-accumulation-rounding 2', ([[10, '1.1411'], [-370, '1.0726'], [50, '1.0616']], '1.1081'),
   [-310, '1.072600', '-0.14', '-11.00']),
  ('partial repair guard 1', ([[1, '1'], [-1, '1.00502']], '1'), [0, None, '0.01', '0.00']),
  ('partial repair guard 2', ([[2, '1'], [-1, '1.00252'], [-1, '1.00251']], '1'), [0, None, '0.01', '0.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46'])],
 [('regression realized-accumulation-rounding 1',
   ([[120, '1.1265'], [-100, '1.1177'], [270, '1.1372'], [-530, '1.1150'], [510, '1.0931'], [-490, '1.0584']],
    '1.1400'),
   [-220, '1.058400', '-11.22', '-17.95']),
  ('regression realized-accumulation-rounding 2',
   ([[460, '1.0523'], [340, '1.1064'], [-460, '1.1068'], [0, '1.1268'], [-560, '1.0903'], [190, '1.0925']], '1.0886'),
   [-30, '1.090300', '19.18', '0.05']),
  ('partial repair guard 1', ([[1, '1'], [-1, '1.00502']], '1'), [0, None, '0.01', '0.00']),
  ('partial repair guard 2', ([[2, '1'], [-1, '1.00252'], [-1, '1.00251']], '1'), [0, None, '0.01', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.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)

source:
"""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
from fractions import Fraction
N = 1
observations = []
def solve(trades, spot):
    def fmt(fr, e):
        d = (Decimal(fr.numerator) / Decimal(fr.denominator)).quantize(Decimal(1).scaleb(-e), rounding=ROUND_HALF_EVEN)
        return format(abs(d) if d == 0 else d, 'f')
    pos, avg, realized = 0, None, Fraction(0)
    for qty, rate in trades:
        r = Fraction(rate)
        if qty == 0: continue
        if pos == 0 or (pos > 0) == (qty > 0):
            avg = r if pos == 0 else (abs(pos) * avg + abs(qty) * r) / (abs(pos) + abs(qty))
            pos += qty
        else:
            closed = min(abs(qty), abs(pos))
            sgn = 1 if pos > 0 else -1
            realized += closed * (r - avg) * sgn
            realized = Fraction(fmt(realized, 4))
            pos += qty
            if pos == 0: avg = None
            elif (pos > 0) != (sgn > 0): avg = r
    unreal = pos * (Fraction(spot) - avg) if pos else Fraction(0)
    return [pos, None if avg is None else fmt(avg, 6), fmt(realized, 2), fmt(unreal, 2)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression realized-accumulation-rounding 1', ([[3, '1'], [-1, '1.005'], [-1, '1.005'], [-1, '1.005']], '1'),
   [0, None, '0.02', '0.00']),
  ('regression realized-accumulation-rounding 2', ([[2, '1'], [-1, '1.00252'], [-1, '1.00251']], '1'),
   [0, None, '0.01', '0.00']),
  ('partial repair guard 1', ([[1, '1'], [-1, '1.00502']], '1'), [0, None, '0.01', '0.00']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00'])],
 [('regression realized-accumulation-rounding 1',
   ([[-160, '1.1445'], [370, '1.0518'], [470, '1.1207'], [-420, '1.1186'], [0, '1.1436'], [-430, '1.0692']], '1.1002'),
   [-170, '1.069200', '15.03', '-5.27']),
  ('regression realized-accumulation-rounding 2',
   ([[-440, '1.1376'], [320, '1.1062'], [-500, '1.1066'], [0, '1.0745'], [-450, '1.0551'], [560, '1.0788']], '1.1271'),
   [-510, '1.088418', '15.43', '-19.73']),
  ('partial repair guard 1', ([[1, '1'], [-1, '1.00502']], '1'), [0, None, '0.01', '0.00']),
  ('partial repair guard 2', ([[2, '1'], [-1, '1.00252'], [-1, '1.00251']], '1'), [0, None, '0.01', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00'])],
 [('regression realized-accumulation-rounding 1', ([[500, '1.1350'], [-210, '1.0625'], [-530, '1.1133']], '1.1442'),
   [-240, '1.113300', '-21.52', '-7.42']),
  ('regression realized-accumulation-rounding 2',
   ([[420, '1.0549'], [-340, '1.1155'], [-600, '1.1019'], [120, '1.0728'], [120, '1.0952'], [300, '1.0728']], '1.1408'),
   [20, '1.072800', '36.81', '1.36']),
  ('partial repair guard 1', ([[1, '1'], [-1, '1.00502']], '1'), [0, None, '0.01', '0.00']),
  ('partial repair guard 2', ([[2, '1'], [-1, '1.00252'], [-1, '1.00251']], '1'), [0, None, '0.01', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),
  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),
   [150, '1.150000', '7.50', '15.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50'])],
 [('regression realized-accumulation-rounding 1',
   ([[-330, '1.0644'], [460, '1.1022'], [130, '1.1361'], [0, '1.0789'], [-160, '1.0850']], '1.0640'),
   [100, '1.119150', '-17.94', '-5.52']),
  ('regression realized-accumulation-rounding 2', ([[10, '1.1411'], [-370, '1.0726'], [50, '1.0616']], '1.1081'),
   [-310, '1.072600', '-0.14', '-11.00']),
  ('partial repair guard 1', ([[1, '1'], [-1, '1.00502']], '1'), [0, None, '0.01', '0.00']),
  ('partial repair guard 2', ([[2, '1'], [-1, '1.00252'], [-1, '1.00251']], '1'), [0, None, '0.01', '0.00']),
  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),
  ('control: close short', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),
  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46'])],
 [('regression realized-accumulation-rounding 1',
   ([[120, '1.1265'], [-100, '1.1177'], [270, '1.1372'], [-530, '1.1150'], [510, '1.0931'], [-490, '1.0584']],
    '1.1400'),
   [-220, '1.058400', '-11.22', '-17.95']),
  ('regression realized-accumulation-rounding 2',
   ([[460, '1.0523'], [340, '1.1064'], [-460, '1.1068'], [0, '1.1268'], [-560, '1.0903'], [190, '1.0925']], '1.0886'),
   [-30, '1.090300', '19.18', '0.05']),
  ('partial repair guard 1', ([[1, '1'], [-1, '1.00502']], '1'), [0, None, '0.01', '0.00']),
  ('partial repair guard 2', ([[2, '1'], [-1, '1.00252'], [-1, '1.00251']], '1'), [0, None, '0.01', '0.00']),
  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),
  ('control: three reductions', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),
   [0, None, '0.64', '0.00']),
  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),
   [20, '1.400000', '5.00', '2.00']),
  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.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)

prompt:
Several small closes accumulate a cent-level discrepancy against the exact realized total.

solve(trades, spot): trades are [qty, rate] in foreign units (buy positive, sell negative) at home-per-foreign decimal rates. Adding in the position's direction updates the weighted average rate; reducing realizes closed_qty * (rate - avg) * sign(position) without changing avg; a flip realizes the closed part and opens the remainder at the trade rate; a flat position has no average. Zero-quantity trades are ignored. Unrealized = position * (spot - avg). Return [position, avg to 6 dp or None, realized to 2 dp, unrealized to 2 dp], rounded half-even only at output with unsigned zeros.

split: open-access


broken_source:
"""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(amount, rate, src_exp, dst_exp, fee_bps, min_fee):
    if fee_bps < 0 or amount <= 0: return 'ERR:input'
    conv = lambda m: Decimal(m) * Decimal(rate) * Decimal(10) ** (dst_exp - src_exp)
    rq = lambda d: int(d.quantize(Decimal(1), rounding=ROUND_HALF_EVEN))
    pct = -(-amount * fee_bps // 10000)
    fee = max(min_fee, pct)
    if fee >= amount: return 'ERR:amount-below-fee'
    return [fee, rq(conv(amount)) - rq(conv(fee))]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression fee-conversion-order 1', (123456, '0.92', 2, 2, 250, 199), [3087, 110739]),
  ('regression fee-conversion-order 2', (314862, '122.2171', 2, 2, 5, 1000), [1000, 38359303]),
  ('partial repair guard 1', (10000, '151.37', 2, 0, 150, 50), [150, 14910]),
  ('partial repair guard 2', (20000, '0.3071', 2, 3, 25, 100), [100, 61113]),
  ('control: fee rounds up', (1001, '1', 2, 2, 100, 0), [11, 990]),
  ('control: fee equals amount', (500, '0.9', 2, 2, 10, 500), 'ERR:amount-below-fee'),
  ('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842]),
  ('control: invalid amount', (0, '1.1', 2, 2, 10, 0), 'ERR:input')],
 [('regression fee-conversion-order 1', (234309, '91.3439', 3, 3, 333, 100), [7803, 20689941]),
  ('regression fee-conversion-order 2', (440114, '2728.61', 0, 0, 333, 1), [14656, 1160908953]),
  ('partial repair guard 1', (123456, '0.92', 2, 2, 250, 199), [3087, 110739]),
  ('partial repair guard 2', (197637, '16116.34', 0, 2, 333, 100), [6582, 307910733870]),
  ('control: minimum fee applies', (20000, '0.3071', 2, 3, 25, 100), [100, 61113]),
  ('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842]),
  ('control: invalid amount', (0, '1.1', 2, 2, 10, 0), 'ERR:input'),
  ('control: minimum exceeds amount', (99, '1.2', 2, 2, 5, 150), 'ERR:amount-below-fee')],
 [('regression fee-conversion-order 1', (41069, '21.2905', 3, 3, 333, 1000), [1368, 845254]),
  ('regression fee-conversion-order 2', (449567, '33.1467', 2, 0, 150, 50), [6744, 146781]),
  ('partial repair guard 1', (22226, '179.9447', 0, 2, 150, 100), [334, 393934937]),
  ('partial repair guard 2', (50411, '12342.04', 3, 3, 333, 1), [1679, 601452293]),
  ('control: invalid amount', (0, '1.1', 2, 2, 10, 0), 'ERR:input'),
  ('control: minimum exceeds amount', (99, '1.2', 2, 2, 5, 150), 'ERR:amount-below-fee'),
  ('control: yen payout', (10000, '151.37', 2, 0, 150, 50), [150, 14910]),
  ('control: fee rounds up', (1001, '1', 2, 2, 100, 0), [11, 990])],
 [('regression fee-conversion-order 1', (55979, '2.35354', 3, 0, 0, 1000), [1000, 129]),
  ('regression fee-conversion-order 2', (409473, '130.7752', 3, 3, 333, 1), [13636, 51765663]),
  ('partial repair guard 1', (268603, '16.66106', 2, 0, 150, 50), [4030, 44081]),
  ('partial repair guard 2', (269350, '9.84392', 0, 3, 333, 0), [8970, 2563159890]),
  ('control: fee rounds up', (1001, '1', 2, 2, 100, 0), [11, 990]),
  ('control: fee equals amount', (500, '0.9', 2, 2, 10, 500), 'ERR:amount-below-fee'),
  ('control: minimum fee applies', (20000, '0.3071', 2, 3, 25, 100), [100, 61113]),
  ('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842])],
 [('regression fee-conversion-order 1', (34239, '182.6706', 2, 0, 25, 1), [86, 62387]),
  ('regression fee-conversion-order 2', (180714, '131.9673', 3, 0, 150, 0), [2711, 23491]),
  ('partial repair guard 1', (314862, '122.2171', 2, 2, 5, 1000), [1000, 38359303]),
  ('partial repair guard 2', (84375, '129.7381', 0, 0, 99, 250), [836, 10838191]),
  ('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842]),
  ('control: large percentage fee', (123456, '0.92', 2, 2, 250, 199), [3087, 110739]),
  ('control: invalid amount', (0, '1.1', 2, 2, 10, 0), 'ERR:input'),
  ('control: minimum exceeds amount', (99, '1.2', 2, 2, 5, 150), 'ERR:amount-below-fee')]]
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)

source:
"""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(amount, rate, src_exp, dst_exp, fee_bps, min_fee):
    if fee_bps < 0 or amount <= 0: return 'ERR:input'
    conv = lambda m: Decimal(m) * Decimal(rate) * Decimal(10) ** (dst_exp - src_exp)
    rq = lambda d: int(d.quantize(Decimal(1), rounding=ROUND_HALF_EVEN))
    pct = -(-amount * fee_bps // 10000)
    fee = max(min_fee, pct)
    if fee >= amount: return 'ERR:amount-below-fee'
    return [fee, rq(conv(amount)) - fee]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression fee-conversion-order 1', (123456, '0.92', 2, 2, 250, 199), [3087, 110739]),
  ('regression fee-conversion-order 2', (314862, '122.2171', 2, 2, 5, 1000), [1000, 38359303]),
  ('partial repair guard 1', (10000, '151.37', 2, 0, 150, 50), [150, 14910]),
  ('partial repair guard 2', (20000, '0.3071', 2, 3, 25, 100), [100, 61113]),
  ('control: fee rounds up', (1001, '1', 2, 2, 100, 0), [11, 990]),
  ('control: fee equals amount', (500, '0.9', 2, 2, 10, 500), 'ERR:amount-below-fee'),
  ('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842]),
  ('control: invalid amount', (0, '1.1', 2, 2, 10, 0), 'ERR:input')],
 [('regression fee-conversion-order 1', (234309, '91.3439', 3, 3, 333, 100), [7803, 20689941]),
  ('regression fee-conversion-order 2', (440114, '2728.61', 0, 0, 333, 1), [14656, 1160908953]),
  ('partial repair guard 1', (123456, '0.92', 2, 2, 250, 199), [3087, 110739]),
  ('partial repair guard 2', (197637, '16116.34', 0, 2, 333, 100), [6582, 307910733870]),
  ('control: minimum fee applies', (20000, '0.3071', 2, 3, 25, 100), [100, 61113]),
  ('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842]),
  ('control: invalid amount', (0, '1.1', 2, 2, 10, 0), 'ERR:input'),
  ('control: minimum exceeds amount', (99, '1.2', 2, 2, 5, 150), 'ERR:amount-below-fee')],
 [('regression fee-conversion-order 1', (41069, '21.2905', 3, 3, 333, 1000), [1368, 845254]),
  ('regression fee-conversion-order 2', (449567, '33.1467', 2, 0, 150, 50), [6744, 146781]),
  ('partial repair guard 1', (22226, '179.9447', 0, 2, 150, 100), [334, 393934937]),
  ('partial repair guard 2', (50411, '12342.04', 3, 3, 333, 1), [1679, 601452293]),
  ('control: invalid amount', (0, '1.1', 2, 2, 10, 0), 'ERR:input'),
  ('control: minimum exceeds amount', (99, '1.2', 2, 2, 5, 150), 'ERR:amount-below-fee'),
  ('control: yen payout', (10000, '151.37', 2, 0, 150, 50), [150, 14910]),
  ('control: fee rounds up', (1001, '1', 2, 2, 100, 0), [11, 990])],
 [('regression fee-conversion-order 1', (55979, '2.35354', 3, 0, 0, 1000), [1000, 129]),
  ('regression fee-conversion-order 2', (409473, '130.7752', 3, 3, 333, 1), [13636, 51765663]),
  ('partial repair guard 1', (268603, '16.66106', 2, 0, 150, 50), [4030, 44081]),
  ('partial repair guard 2', (269350, '9.84392', 0, 3, 333, 0), [8970, 2563159890]),
  ('control: fee rounds up', (1001, '1', 2, 2, 100, 0), [11, 990]),
  ('control: fee equals amount', (500, '0.9', 2, 2, 10, 500), 'ERR:amount-below-fee'),
  ('control: minimum fee applies', (20000, '0.3071', 2, 3, 25, 100), [100, 61113]),
  ('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842])],
 [('regression fee-conversion-order 1', (34239, '182.6706', 2, 0, 25, 1), [86, 62387]),
  ('regression fee-conversion-order 2', (180714, '131.9673', 3, 0, 150, 0), [2711, 23491]),
  ('partial repair guard 1', (314862, '122.2171', 2, 2, 5, 1000), [1000, 38359303]),
  ('partial repair guard 2', (84375, '129.7381', 0, 0, 99, 250), [836, 10838191]),
  ('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842]),
  ('control: large percentage fee', (123456, '0.92', 2, 2, 250, 199), [3087, 110739]),
  ('control: invalid amount', (0, '1.1', 2, 2, 10, 0), 'ERR:input'),
  ('control: minimum exceeds amount', (99, '1.2', 2, 2, 5, 150), 'ERR:amount-below-fee')]]
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)

prompt:
The payout differs by a minor unit from converting the net amount once.

solve(amount, rate, src_exp, dst_exp, fee_bps, min_fee): amount and min_fee are source minor units, fee_bps a non-negative integer. fee = max(min_fee, ceil(amount*fee_bps/10000)) in source minor units, deducted before conversion. A fee greater than or equal to the amount returns 'ERR:amount-below-fee'; a non-positive amount or negative bps returns 'ERR:input'. The net amount is converted exactly (net * rate * 10**(dst_exp - src_exp)) and rounded half-even. Return [fee, converted].

split: open-access


broken_source:
"""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(amount, rate, src_exp, dst_exp, fee_bps, min_fee):
    if fee_bps < 0 or amount <= 0: return 'ERR:input'
    conv = lambda m: Decimal(m) * Decimal(rate) * Decimal(10) ** (dst_exp - src_exp)
    rq = lambda d: int(d.quantize(Decimal(1), rounding=ROUND_HALF_EVEN))
    pct = amount * fee_bps // 10000
    fee = max(min_fee, pct)
    if fee >= amount: return 'ERR:amount-below-fee'
    return [fee, rq(conv(amount - fee))]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression fee-ceiling 1', (1001, '1', 2, 2, 100, 0), [11, 990]),
  ('regression fee-ceiling 2', (1003, '1', 2, 2, 100, 0), [11, 992]),
  ('control: yen payout', (10000, '151.37', 2, 0, 150, 50), [150, 14910]),
  ('control: fee equals amount', (500, '0.9', 2, 2, 10, 500), 'ERR:amount-below-fee'),
  ('control: minimum fee applies', (20000, '0.3071', 2, 3, 25, 100), [100, 61113]),
  ('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842])],
 [('regression fee-ceiling 1', (123456, '0.92', 2, 2, 250, 199), [3087, 110739]),
  ('regression fee-ceiling 2', (197637, '16116.34', 0, 2, 333, 100), [6582, 307910733870]),
  ('control: minimum fee applies', (20000, '0.3071', 2, 3, 25, 100), [100, 61113]),
  ('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842]),
  ('control: invalid amount', (0, '1.1', 2, 2, 10, 0), 'ERR:input'),
  ('control: minimum exceeds amount', (99, '1.2', 2, 2, 5, 150), 'ERR:amount-below-fee')],
 [('regression fee-ceiling 1', (22226, '179.9447', 0, 2, 150, 100), [334, 393934937]),
  ('regression fee-ceiling 2', (50411, '12342.04', 3, 3, 333, 1), [1679, 601452293]),
  ('partial repair guard 2', (268603, '16.66106', 2, 0, 150, 50), [4030, 44081]),
  ('control: invalid amount', (0, '1.1', 2, 2, 10, 0), 'ERR:input'),
  ('control: minimum exceeds amount', (99, '1.2', 2, 2, 5, 150), 'ERR:amount-below-fee'),
  ('control: yen payout', (10000, '151.37', 2, 0, 150, 50), [150, 14910]),
  ('control: fee rounds up', (1001, '1', 2, 2, 100, 0), [11, 990])],
 [('regression fee-ceiling 1', (268603, '16.66106', 2, 0, 150, 50), [4030, 44081]),
  ('regression fee-ceiling 2', (269350, '9.84392', 0, 3, 333, 0), [8970, 2563159890]),
  ('partial repair guard 2', (84375, '129.7381', 0, 0, 99, 250), [836, 10838191]),
  ('control: fee rounds up', (1001, '1', 2, 2, 100, 0), [11, 990]),
  ('control: fee equals amount', (500, '0.9', 2, 2, 10, 500), 'ERR:amount-below-fee'),
  ('control: minimum fee applies', (20000, '0.3071', 2, 3, 25, 100), [100, 61113]),
  ('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842])],
 [('regression fee-ceiling 1', (84375, '129.7381', 0, 0, 99, 250), [836, 10838191]),
  ('regression fee-ceiling 2', (90216, '1.62136', 0, 2, 1000, 250), [9022, 13164470]),
  ('partial repair guard 1', (234309, '91.3439', 3, 3, 333, 100), [7803, 20689941]),
  ('partial repair guard 2', (462525, '13331.53', 0, 0, 1000, 50), [46253, 5549542656]),
  ('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842]),
  ('control: large percentage fee', (123456, '0.92', 2, 2, 250, 199), [3087, 110739]),
  ('control: invalid amount', (0, '1.1', 2, 2, 10, 0), 'ERR:input'),
  ('control: minimum exceeds amount', (99, '1.2', 2, 2, 5, 150), 'ERR:amount-below-fee')]]
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)

source:
"""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(amount, rate, src_exp, dst_exp, fee_bps, min_fee):
    if fee_bps < 0 or amount <= 0: return 'ERR:input'
    conv = lambda m: Decimal(m) * Decimal(rate) * Decimal(10) ** (dst_exp - src_exp)
    rq = lambda d: int(d.quantize(Decimal(1), rounding=ROUND_HALF_EVEN))
    pct = round(amount * fee_bps / 10000)
    fee = max(min_fee, pct)
    if fee >= amount: return 'ERR:amount-below-fee'
    return [fee, rq(conv(amount - fee))]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression fee-ceiling 1', (1001, '1', 2, 2, 100, 0), [11, 990]),
  ('regression fee-ceiling 2', (1003, '1', 2, 2, 100, 0), [11, 992]),
  ('control: yen payout', (10000, '151.37', 2, 0, 150, 50), [150, 14910]),
  ('control: fee equals amount', (500, '0.9', 2, 2, 10, 500), 'ERR:amount-below-fee'),
  ('control: minimum fee applies', (20000, '0.3071', 2, 3, 25, 100), [100, 61113]),
  ('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842])],
 [('regression fee-ceiling 1', (123456, '0.92', 2, 2, 250, 199), [3087, 110739]),
  ('regression fee-ceiling 2', (197637, '16116.34', 0, 2, 333, 100), [6582, 307910733870]),
  ('control: minimum fee applies', (20000, '0.3071', 2, 3, 25, 100), [100, 61113]),
  ('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842]),
  ('control: invalid amount', (0, '1.1', 2, 2, 10, 0), 'ERR:input'),
  ('control: minimum exceeds amount', (99, '1.2', 2, 2, 5, 150), 'ERR:amount-below-fee')],
 [('regression fee-ceiling 1', (22226, '179.9447', 0, 2, 150, 100), [334, 393934937]),
  ('regression fee-ceiling 2', (50411, '12342.04', 3, 3, 333, 1), [1679, 601452293]),
  ('partial repair guard 2', (268603, '16.66106', 2, 0, 150, 50), [4030, 44081]),
  ('control: invalid amount', (0, '1.1', 2, 2, 10, 0), 'ERR:input'),
  ('control: minimum exceeds amount', (99, '1.2', 2, 2, 5, 150), 'ERR:amount-below-fee'),
  ('control: yen payout', (10000, '151.37', 2, 0, 150, 50), [150, 14910]),
  ('control: fee rounds up', (1001, '1', 2, 2, 100, 0), [11, 990])],
 [('regression fee-ceiling 1', (268603, '16.66106', 2, 0, 150, 50), [4030, 44081]),
  ('regression fee-ceiling 2', (269350, '9.84392', 0, 3, 333, 0), [8970, 2563159890]),
  ('partial repair guard 2', (84375, '129.7381', 0, 0, 99, 250), [836, 10838191]),
  ('control: fee rounds up', (1001, '1', 2, 2, 100, 0), [11, 990]),
  ('control: fee equals amount', (500, '0.9', 2, 2, 10, 500), 'ERR:amount-below-fee'),
  ('control: minimum fee applies', (20000, '0.3071', 2, 3, 25, 100), [100, 61113]),
  ('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842])],
 [('regression fee-ceiling 1', (84375, '129.7381', 0, 0, 99, 250), [836, 10838191]),
  ('regression fee-ceiling 2', (90216, '1.62136', 0, 2, 1000, 250), [9022, 13164470]),
  ('partial repair guard 1', (234309, '91.3439', 3, 3, 333, 100), [7803, 20689941]),
  ('partial repair guard 2', (462525, '13331.53', 0, 0, 1000, 50), [46253, 5549542656]),
  ('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842]),
  ('control: large percentage fee', (123456, '0.92', 2, 2, 250, 199), [3087, 110739]),
  ('control: invalid amount', (0, '1.1', 2, 2, 10, 0), 'ERR:input'),
  ('control: minimum exceeds amount', (99, '1.2', 2, 2, 5, 150), 'ERR:amount-below-fee')]]
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)

prompt:
A 1% fee on 1001 minor units is 10 instead of 11.

solve(amount, rate, src_exp, dst_exp, fee_bps, min_fee): amount and min_fee are source minor units, fee_bps a non-negative integer. fee = max(min_fee, ceil(amount*fee_bps/10000)) in source minor units, deducted before conversion. A fee greater than or equal to the amount returns 'ERR:amount-below-fee'; a non-positive amount or negative bps returns 'ERR:input'. The net amount is converted exactly (net * rate * 10**(dst_exp - src_exp)) and rounded half-even. Return [fee, converted].

split: open-access