{"abstract":"A long position flipped short reports the old long average for the new short lot.","category":"Currency rounding and FX conversion","checks":8,"contract":"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.","evaluation_group":"w2-currency_rounding_and_fx_conversion-fx-position-average-rate","failed_approach":"Setting avg to the trade rate on every close also reports an average for a flat position.","family":"w2-currency_rounding_and_fx_conversion-fx-position-average-rate-flip-reset","id":"FA-62036","implementations":{"attempt":{"sha256":"8754593baa12dcaad25849fa953bc14a3bfb24556db2b73761dfc57ae1901512","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nfrom decimal import Decimal, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_FLOOR, ROUND_CEILING, ROUND_DOWN, ROUND_UP, ROUND_HALF_DOWN\nfrom fractions import Fraction\nN = 1\nobservations = []\ndef solve(trades, spot):\n    def fmt(fr, e):\n        d = (Decimal(fr.numerator) / Decimal(fr.denominator)).quantize(Decimal(1).scaleb(-e), rounding=ROUND_HALF_EVEN)\n        return format(abs(d) if d == 0 else d, 'f')\n    pos, avg, realized = 0, None, Fraction(0)\n    for qty, rate in trades:\n        r = Fraction(rate)\n        if qty == 0: continue\n        if pos == 0 or (pos > 0) == (qty > 0):\n            avg = r if pos == 0 else (abs(pos) * avg + abs(qty) * r) / (abs(pos) + abs(qty))\n            pos += qty\n        else:\n            closed = min(abs(qty), abs(pos))\n            sgn = 1 if pos > 0 else -1\n            realized += closed * (r - avg) * sgn\n            pos += qty\n            if pos == 0 or (pos > 0) != (sgn > 0): avg = r\n    unreal = pos * (Fraction(spot) - avg) if pos else Fraction(0)\n    return [pos, None if avg is None else fmt(avg, 6), fmt(realized, 2), fmt(unreal, 2)]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\ncases = [[('regression flip-reset 1', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),\n  ('regression flip-reset 2', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),\n  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),\n  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),\n   [0, None, '0.64', '0.00']),\n  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),\n   [150, '1.150000', '7.50', '15.00']),\n  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),\n  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),\n  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),\n   [20, '1.400000', '5.00', '2.00'])],\n [('regression flip-reset 1', ([[-90, '1.0708'], [540, '1.1315']], '1.0885'), [450, '1.131500', '-5.46', '-19.35']),\n  ('regression flip-reset 2', ([[-220, '1.1085'], [310, '1.1162'], [-140, '1.1499']], '1.1267'),\n   [-50, '1.149900', '1.34', '1.16']),\n  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),\n  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),\n   [0, None, '0.64', '0.00']),\n  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),\n  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),\n  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),\n   [20, '1.400000', '5.00', '2.00']),\n  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00'])],\n [('regression flip-reset 1',\n   ([[0, '1.0601'], [0, '1.0705'], [-110, '1.1230'], [310, '1.0559'], [400, '1.1307']], '1.1024'),\n   [600, '1.105767', '7.38', '-2.02']),\n  ('regression flip-reset 2',\n   ([[160, '1.0719'], [-230, '1.0804'], [-80, '1.1289'], [50, '1.1492'], [570, '1.1139'], [570, '1.1011']], '1.0962'),\n   [1040, '1.106885', '-1.55', '-11.11']),\n  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),\n  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),\n   [0, None, '0.64', '0.00']),\n  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),\n   [20, '1.400000', '5.00', '2.00']),\n  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),\n  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),\n   [150, '1.150000', '7.50', '15.00']),\n  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50'])],\n [('regression flip-reset 1',\n   ([[-430, '1.0685'], [30, '1.0569'], [100, '1.0804'], [540, '1.0505'], [0, '1.0888'], [-490, '1.0791']], '1.0807'),\n   [-250, '1.079100', '11.42', '-0.40']),\n  ('regression flip-reset 2', ([[440, '1.0718'], [-570, '1.0726'], [40, '1.1343'], [-160, '1.1482']], '1.1222'),\n   [-250, '1.120984', '-2.12', '-0.30']),\n  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),\n  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),\n   [0, None, '0.64', '0.00']),\n  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),\n  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),\n  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),\n  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),\n   [20, '1.400000', '5.00', '2.00'])],\n [('regression flip-reset 1',\n   ([[-560, '1.1226'], [90, '1.1160'], [300, '1.0734'], [-220, '1.0848'], [500, '1.0820']], '1.1354'),\n   [110, '1.082000', '22.87', '5.87']),\n  ('regression flip-reset 2', ([[-290, '1.1340'], [220, '1.0570'], [420, '1.0731']], '1.1418'),\n   [350, '1.073100', '21.20', '24.04']),\n  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),\n  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),\n   [0, None, '0.64', '0.00']),\n  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),\n  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),\n   [20, '1.400000', '5.00', '2.00']),\n  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),\n  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),\n   [150, '1.150000', '7.50', '15.00'])]]\nfor label, args, expected in cases[N - 1]:\n    check(label, solve(*args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"},"broken":{"sha256":"127a188c654ae9542c547d41080d6abff481c4b9d14fef825afd2bb171902e3c","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nfrom decimal import Decimal, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_FLOOR, ROUND_CEILING, ROUND_DOWN, ROUND_UP, ROUND_HALF_DOWN\nfrom fractions import Fraction\nN = 1\nobservations = []\ndef solve(trades, spot):\n    def fmt(fr, e):\n        d = (Decimal(fr.numerator) / Decimal(fr.denominator)).quantize(Decimal(1).scaleb(-e), rounding=ROUND_HALF_EVEN)\n        return format(abs(d) if d == 0 else d, 'f')\n    pos, avg, realized = 0, None, Fraction(0)\n    for qty, rate in trades:\n        r = Fraction(rate)\n        if qty == 0: continue\n        if pos == 0 or (pos > 0) == (qty > 0):\n            avg = r if pos == 0 else (abs(pos) * avg + abs(qty) * r) / (abs(pos) + abs(qty))\n            pos += qty\n        else:\n            closed = min(abs(qty), abs(pos))\n            sgn = 1 if pos > 0 else -1\n            realized += closed * (r - avg) * sgn\n            pos += qty\n            if pos == 0: avg = None\n    unreal = pos * (Fraction(spot) - avg) if pos else Fraction(0)\n    return [pos, None if avg is None else fmt(avg, 6), fmt(realized, 2), fmt(unreal, 2)]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\ncases = [[('regression flip-reset 1', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),\n  ('regression flip-reset 2', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),\n  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),\n  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),\n   [0, None, '0.64', '0.00']),\n  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),\n   [150, '1.150000', '7.50', '15.00']),\n  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),\n  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),\n  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),\n   [20, '1.400000', '5.00', '2.00'])],\n [('regression flip-reset 1', ([[-90, '1.0708'], [540, '1.1315']], '1.0885'), [450, '1.131500', '-5.46', '-19.35']),\n  ('regression flip-reset 2', ([[-220, '1.1085'], [310, '1.1162'], [-140, '1.1499']], '1.1267'),\n   [-50, '1.149900', '1.34', '1.16']),\n  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),\n  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),\n   [0, None, '0.64', '0.00']),\n  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),\n  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),\n  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),\n   [20, '1.400000', '5.00', '2.00']),\n  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00'])],\n [('regression flip-reset 1',\n   ([[0, '1.0601'], [0, '1.0705'], [-110, '1.1230'], [310, '1.0559'], [400, '1.1307']], '1.1024'),\n   [600, '1.105767', '7.38', '-2.02']),\n  ('regression flip-reset 2',\n   ([[160, '1.0719'], [-230, '1.0804'], [-80, '1.1289'], [50, '1.1492'], [570, '1.1139'], [570, '1.1011']], '1.0962'),\n   [1040, '1.106885', '-1.55', '-11.11']),\n  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),\n  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),\n   [0, None, '0.64', '0.00']),\n  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),\n   [20, '1.400000', '5.00', '2.00']),\n  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),\n  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),\n   [150, '1.150000', '7.50', '15.00']),\n  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50'])],\n [('regression flip-reset 1',\n   ([[-430, '1.0685'], [30, '1.0569'], [100, '1.0804'], [540, '1.0505'], [0, '1.0888'], [-490, '1.0791']], '1.0807'),\n   [-250, '1.079100', '11.42', '-0.40']),\n  ('regression flip-reset 2', ([[440, '1.0718'], [-570, '1.0726'], [40, '1.1343'], [-160, '1.1482']], '1.1222'),\n   [-250, '1.120984', '-2.12', '-0.30']),\n  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),\n  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),\n   [0, None, '0.64', '0.00']),\n  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),\n  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),\n  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),\n  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),\n   [20, '1.400000', '5.00', '2.00'])],\n [('regression flip-reset 1',\n   ([[-560, '1.1226'], [90, '1.1160'], [300, '1.0734'], [-220, '1.0848'], [500, '1.0820']], '1.1354'),\n   [110, '1.082000', '22.87', '5.87']),\n  ('regression flip-reset 2', ([[-290, '1.1340'], [220, '1.0570'], [420, '1.0731']], '1.1418'),\n   [350, '1.073100', '21.20', '24.04']),\n  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),\n  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),\n   [0, None, '0.64', '0.00']),\n  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),\n  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),\n   [20, '1.400000', '5.00', '2.00']),\n  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),\n  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),\n   [150, '1.150000', '7.50', '15.00'])]]\nfor label, args, expected in cases[N - 1]:\n    check(label, solve(*args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"},"fixed":{"sha256":"c6fe2b8dcc06edbee9bb0887496458202102181ba16e447ddacee897533ad743","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nfrom decimal import Decimal, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_FLOOR, ROUND_CEILING, ROUND_DOWN, ROUND_UP, ROUND_HALF_DOWN\nfrom fractions import Fraction\nN = 1\nobservations = []\ndef solve(trades, spot):\n    def fmt(fr, e):\n        d = (Decimal(fr.numerator) / Decimal(fr.denominator)).quantize(Decimal(1).scaleb(-e), rounding=ROUND_HALF_EVEN)\n        return format(abs(d) if d == 0 else d, 'f')\n    pos, avg, realized = 0, None, Fraction(0)\n    for qty, rate in trades:\n        r = Fraction(rate)\n        if qty == 0: continue\n        if pos == 0 or (pos > 0) == (qty > 0):\n            avg = r if pos == 0 else (abs(pos) * avg + abs(qty) * r) / (abs(pos) + abs(qty))\n            pos += qty\n        else:\n            closed = min(abs(qty), abs(pos))\n            sgn = 1 if pos > 0 else -1\n            realized += closed * (r - avg) * sgn\n            pos += qty\n            if pos == 0: avg = None\n            elif (pos > 0) != (sgn > 0): avg = r\n    unreal = pos * (Fraction(spot) - avg) if pos else Fraction(0)\n    return [pos, None if avg is None else fmt(avg, 6), fmt(realized, 2), fmt(unreal, 2)]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\ncases = [[('regression flip-reset 1', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),\n  ('regression flip-reset 2', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),\n  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),\n  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),\n   [0, None, '0.64', '0.00']),\n  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),\n   [150, '1.150000', '7.50', '15.00']),\n  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),\n  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),\n  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),\n   [20, '1.400000', '5.00', '2.00'])],\n [('regression flip-reset 1', ([[-90, '1.0708'], [540, '1.1315']], '1.0885'), [450, '1.131500', '-5.46', '-19.35']),\n  ('regression flip-reset 2', ([[-220, '1.1085'], [310, '1.1162'], [-140, '1.1499']], '1.1267'),\n   [-50, '1.149900', '1.34', '1.16']),\n  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),\n  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),\n   [0, None, '0.64', '0.00']),\n  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),\n  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),\n  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),\n   [20, '1.400000', '5.00', '2.00']),\n  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00'])],\n [('regression flip-reset 1',\n   ([[0, '1.0601'], [0, '1.0705'], [-110, '1.1230'], [310, '1.0559'], [400, '1.1307']], '1.1024'),\n   [600, '1.105767', '7.38', '-2.02']),\n  ('regression flip-reset 2',\n   ([[160, '1.0719'], [-230, '1.0804'], [-80, '1.1289'], [50, '1.1492'], [570, '1.1139'], [570, '1.1011']], '1.0962'),\n   [1040, '1.106885', '-1.55', '-11.11']),\n  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),\n  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),\n   [0, None, '0.64', '0.00']),\n  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),\n   [20, '1.400000', '5.00', '2.00']),\n  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),\n  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),\n   [150, '1.150000', '7.50', '15.00']),\n  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50'])],\n [('regression flip-reset 1',\n   ([[-430, '1.0685'], [30, '1.0569'], [100, '1.0804'], [540, '1.0505'], [0, '1.0888'], [-490, '1.0791']], '1.0807'),\n   [-250, '1.079100', '11.42', '-0.40']),\n  ('regression flip-reset 2', ([[440, '1.0718'], [-570, '1.0726'], [40, '1.1343'], [-160, '1.1482']], '1.1222'),\n   [-250, '1.120984', '-2.12', '-0.30']),\n  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),\n  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),\n   [0, None, '0.64', '0.00']),\n  ('control: flip long to short', ([[100, '1.10'], [-150, '1.00']], '1.05'), [-50, '1.000000', '-10.00', '-2.50']),\n  ('control: zero trade only', ([[0, '1.10']], '1.05'), [0, None, '0.00', '0.00']),\n  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),\n  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),\n   [20, '1.400000', '5.00', '2.00'])],\n [('regression flip-reset 1',\n   ([[-560, '1.1226'], [90, '1.1160'], [300, '1.0734'], [-220, '1.0848'], [500, '1.0820']], '1.1354'),\n   [110, '1.082000', '22.87', '5.87']),\n  ('regression flip-reset 2', ([[-290, '1.1340'], [220, '1.0570'], [420, '1.0731']], '1.1418'),\n   [350, '1.073100', '21.20', '24.04']),\n  ('partial repair guard 1', ([[-100, '1.10'], [100, '1.00']], '1.05'), [0, None, '10.00', '0.00']),\n  ('partial repair guard 2', ([[300, '1.0711'], [-100, '1.0733'], [-100, '1.0745'], [-100, '1.0719']], '1.07'),\n   [0, None, '0.64', '0.00']),\n  ('control: short add', ([[-30, '1.0833'], [-70, '1.0851']], '1.0800'), [-100, '1.084560', '0.00', '0.46']),\n  ('control: zero between', ([[50, '1.1'], [-50, '1.2'], [0, '1.3'], [20, '1.4']], '1.5'),\n   [20, '1.400000', '5.00', '2.00']),\n  ('control: flip short to long', ([[-40, '1.2'], [100, '1.1']], '1.15'), [60, '1.100000', '4.00', '3.00']),\n  ('control: add then reduce', ([[100, '1.10'], [100, '1.20'], [-50, '1.30']], '1.25'),\n   [150, '1.150000', '7.50', '15.00'])]]\nfor label, args, expected in cases[N - 1]:\n    check(label, solve(*args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"}},"limitations":"A deterministic, bounded teaching model with a stipulated toy contract; it makes no claim of conformance to any real regulation, standard, or institution's rules. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.","method":"Deterministic executable model with adversarial boundary fixtures.","provenance":{"created_by":"Failure Map","dependencies":"Python standard library","family":"w2-currency_rounding_and_fx_conversion-fx-position-average-rate-flip-reset","generated_at":"2026-09-29T14:47:00.789232+00:00","license":"CC0-1.0","python":"3.12.14","seed":1,"split":"open-access"},"relevance":"Currency amounts must be rounded at the right stage and in the right unit, or ledgers, quotes and settlements drift by minor units.","repair":"When the sign of the position changes, open the remainder at the trade rate.","root_cause":"After a reduction that crosses zero the average is not reset to the flipping trade's rate.","sha256":"caea61d4796fee740ed91592fc076bce3ffc698d6dbee502c046c35eabae1fcd","title":"A position flip keeps the old lot's average rate · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":43.052,"exit_code":1,"observations":[{"actual":[-50,"1.000000","-10.00","-2.50"],"check":"regression flip-reset 1","expected":[-50,"1.000000","-10.00","-2.50"],"passed":true},{"actual":[60,"1.100000","4.00","3.00"],"check":"regression flip-reset 2","expected":[60,"1.100000","4.00","3.00"],"passed":true},{"actual":[0,"1.000000","10.00","0.00"],"check":"partial repair guard 1","expected":[0,null,"10.00","0.00"],"passed":false},{"actual":[0,"1.071900","0.64","0.00"],"check":"partial repair guard 2","expected":[0,null,"0.64","0.00"],"passed":false},{"actual":[150,"1.150000","7.50","15.00"],"check":"control: add then reduce","expected":[150,"1.150000","7.50","15.00"],"passed":true},{"actual":[0,null,"0.00","0.00"],"check":"control: zero trade only","expected":[0,null,"0.00","0.00"],"passed":true},{"actual":[-100,"1.084560","0.00","0.46"],"check":"control: short add","expected":[-100,"1.084560","0.00","0.46"],"passed":true},{"actual":[20,"1.400000","5.00","2.00"],"check":"control: zero between","expected":[20,"1.400000","5.00","2.00"],"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression flip-reset 1\", \"actual\": [-50, \"1.000000\", \"-10.00\", \"-2.50\"], \"expected\": [-50, \"1.000000\", \"-10.00\", \"-2.50\"], \"passed\": true}, {\"check\": \"regression flip-reset 2\", \"actual\": [60, \"1.100000\", \"4.00\", \"3.00\"], \"expected\": [60, \"1.100000\", \"4.00\", \"3.00\"], \"passed\": true}, {\"check\": \"partial repair guard 1\", \"actual\": [0, \"1.000000\", \"10.00\", \"0.00\"], \"expected\": [0, null, \"10.00\", \"0.00\"], \"passed\": false}, {\"check\": \"partial repair guard 2\", \"actual\": [0, \"1.071900\", \"0.64\", \"0.00\"], \"expected\": [0, null, \"0.64\", \"0.00\"], \"passed\": false}, {\"check\": \"control: add then reduce\", \"actual\": [150, \"1.150000\", \"7.50\", \"15.00\"], \"expected\": [150, \"1.150000\", \"7.50\", \"15.00\"], \"passed\": true}, {\"check\": \"control: zero trade only\", \"actual\": [0, null, \"0.00\", \"0.00\"], \"expected\": [0, null, \"0.00\", \"0.00\"], \"passed\": true}, {\"check\": \"control: short add\", \"actual\": [-100, \"1.084560\", \"0.00\", \"0.46\"], \"expected\": [-100, \"1.084560\", \"0.00\", \"0.46\"], \"passed\": true}, {\"check\": \"control: zero between\", \"actual\": [20, \"1.400000\", \"5.00\", \"2.00\"], \"expected\": [20, \"1.400000\", \"5.00\", \"2.00\"], \"passed\": true}], \"passed\": false}\n"},"broken":{"elapsed_ms":45.939,"exit_code":1,"observations":[{"actual":[-50,"1.100000","-10.00","2.50"],"check":"regression flip-reset 1","expected":[-50,"1.000000","-10.00","-2.50"],"passed":false},{"actual":[60,"1.200000","4.00","-3.00"],"check":"regression flip-reset 2","expected":[60,"1.100000","4.00","3.00"],"passed":false},{"actual":[0,null,"10.00","0.00"],"check":"partial repair guard 1","expected":[0,null,"10.00","0.00"],"passed":true},{"actual":[0,null,"0.64","0.00"],"check":"partial repair guard 2","expected":[0,null,"0.64","0.00"],"passed":true},{"actual":[150,"1.150000","7.50","15.00"],"check":"control: add then reduce","expected":[150,"1.150000","7.50","15.00"],"passed":true},{"actual":[0,null,"0.00","0.00"],"check":"control: zero trade only","expected":[0,null,"0.00","0.00"],"passed":true},{"actual":[-100,"1.084560","0.00","0.46"],"check":"control: short add","expected":[-100,"1.084560","0.00","0.46"],"passed":true},{"actual":[20,"1.400000","5.00","2.00"],"check":"control: zero between","expected":[20,"1.400000","5.00","2.00"],"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression flip-reset 1\", \"actual\": [-50, \"1.100000\", \"-10.00\", \"2.50\"], \"expected\": [-50, \"1.000000\", \"-10.00\", \"-2.50\"], \"passed\": false}, {\"check\": \"regression flip-reset 2\", \"actual\": [60, \"1.200000\", \"4.00\", \"-3.00\"], \"expected\": [60, \"1.100000\", \"4.00\", \"3.00\"], \"passed\": false}, {\"check\": \"partial repair guard 1\", \"actual\": [0, null, \"10.00\", \"0.00\"], \"expected\": [0, null, \"10.00\", \"0.00\"], \"passed\": true}, {\"check\": \"partial repair guard 2\", \"actual\": [0, null, \"0.64\", \"0.00\"], \"expected\": [0, null, \"0.64\", \"0.00\"], \"passed\": true}, {\"check\": \"control: add then reduce\", \"actual\": [150, \"1.150000\", \"7.50\", \"15.00\"], \"expected\": [150, \"1.150000\", \"7.50\", \"15.00\"], \"passed\": true}, {\"check\": \"control: zero trade only\", \"actual\": [0, null, \"0.00\", \"0.00\"], \"expected\": [0, null, \"0.00\", \"0.00\"], \"passed\": true}, {\"check\": \"control: short add\", \"actual\": [-100, \"1.084560\", \"0.00\", \"0.46\"], \"expected\": [-100, \"1.084560\", \"0.00\", \"0.46\"], \"passed\": true}, {\"check\": \"control: zero between\", \"actual\": [20, \"1.400000\", \"5.00\", \"2.00\"], \"expected\": [20, \"1.400000\", \"5.00\", \"2.00\"], \"passed\": true}], \"passed\": false}\n"},"fixed":{"elapsed_ms":40.471,"exit_code":0,"observations":[{"actual":[-50,"1.000000","-10.00","-2.50"],"check":"regression flip-reset 1","expected":[-50,"1.000000","-10.00","-2.50"],"passed":true},{"actual":[60,"1.100000","4.00","3.00"],"check":"regression flip-reset 2","expected":[60,"1.100000","4.00","3.00"],"passed":true},{"actual":[0,null,"10.00","0.00"],"check":"partial repair guard 1","expected":[0,null,"10.00","0.00"],"passed":true},{"actual":[0,null,"0.64","0.00"],"check":"partial repair guard 2","expected":[0,null,"0.64","0.00"],"passed":true},{"actual":[150,"1.150000","7.50","15.00"],"check":"control: add then reduce","expected":[150,"1.150000","7.50","15.00"],"passed":true},{"actual":[0,null,"0.00","0.00"],"check":"control: zero trade only","expected":[0,null,"0.00","0.00"],"passed":true},{"actual":[-100,"1.084560","0.00","0.46"],"check":"control: short add","expected":[-100,"1.084560","0.00","0.46"],"passed":true},{"actual":[20,"1.400000","5.00","2.00"],"check":"control: zero between","expected":[20,"1.400000","5.00","2.00"],"passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression flip-reset 1\", \"actual\": [-50, \"1.000000\", \"-10.00\", \"-2.50\"], \"expected\": [-50, \"1.000000\", \"-10.00\", \"-2.50\"], \"passed\": true}, {\"check\": \"regression flip-reset 2\", \"actual\": [60, \"1.100000\", \"4.00\", \"3.00\"], \"expected\": [60, \"1.100000\", \"4.00\", \"3.00\"], \"passed\": true}, {\"check\": \"partial repair guard 1\", \"actual\": [0, null, \"10.00\", \"0.00\"], \"expected\": [0, null, \"10.00\", \"0.00\"], \"passed\": true}, {\"check\": \"partial repair guard 2\", \"actual\": [0, null, \"0.64\", \"0.00\"], \"expected\": [0, null, \"0.64\", \"0.00\"], \"passed\": true}, {\"check\": \"control: add then reduce\", \"actual\": [150, \"1.150000\", \"7.50\", \"15.00\"], \"expected\": [150, \"1.150000\", \"7.50\", \"15.00\"], \"passed\": true}, {\"check\": \"control: zero trade only\", \"actual\": [0, null, \"0.00\", \"0.00\"], \"expected\": [0, null, \"0.00\", \"0.00\"], \"passed\": true}, {\"check\": \"control: short add\", \"actual\": [-100, \"1.084560\", \"0.00\", \"0.46\"], \"expected\": [-100, \"1.084560\", \"0.00\", \"0.46\"], \"passed\": true}, {\"check\": \"control: zero between\", \"actual\": [20, \"1.400000\", \"5.00\", \"2.00\"], \"expected\": [20, \"1.400000\", \"5.00\", \"2.00\"], \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}