{
  "version": "1.0.0",
  "authored": "2026-10-09",
  "expected_origin": "Hand-derived literals; exact rational calculations in scripts/seed_benchmarks.py, never production JS.",
  "revisions": [
    {
      "date": "2026-10-09",
      "version": "1.0.0",
      "note": "Initial 25 public cases for five existing engines. / 首版5引擎25个公开样例。"
    }
  ],
  "cases": [
    {
      "id": "V01",
      "engine": "pip_value",
      "name": "EURUSD USD / 美元点值",
      "input": {
        "pair": "EURUSD",
        "accountCcy": "USD",
        "lots": 1
      },
      "expected": {
        "pip_value_account": 10
      },
      "expectedError": null,
      "derivation": ".0001 USD/EUR × 100000 EUR = 10 USD/pip.",
      "units": "USD/pip",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V02",
      "engine": "pip_value",
      "name": "USDJPY JPY / 日元点值",
      "input": {
        "pair": "USDJPY",
        "accountCcy": "JPY",
        "lots": 1
      },
      "expected": {
        "pip_value_account": 1000
      },
      "expectedError": null,
      "derivation": ".01 JPY/USD × 100000 USD = 1000 JPY/pip.",
      "units": "JPY/pip",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V03",
      "engine": "pip_value",
      "name": "USDJPY USD / 日元对换汇",
      "input": {
        "pair": "USDJPY",
        "accountCcy": "USD",
        "price": 150,
        "lots": 1
      },
      "expected": {
        "pip_value_account": 6.666666666666667
      },
      "expectedError": null,
      "derivation": "1000 JPY ÷ 150 JPY/USD = 6.6666666667 USD/pip.",
      "units": "USD/pip",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V04",
      "engine": "pip_value",
      "name": "EURUSD GBP / 第三币换算",
      "input": {
        "pair": "EURUSD",
        "accountCcy": "GBP",
        "quoteToAccountRate": 0.8,
        "lots": 1
      },
      "expected": {
        "pip_value_account": 8
      },
      "expectedError": null,
      "derivation": "10 USD/pip × .8 GBP/USD = 8 GBP/pip.",
      "units": "GBP/pip",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V05",
      "engine": "pip_value",
      "name": "Negative volume / 负手数",
      "input": {
        "pair": "EURUSD",
        "accountCcy": "USD",
        "lots": -1
      },
      "expected": {},
      "expectedError": "lots must be > 0",
      "derivation": "Volume −1 is outside lots > 0. / 手数必须大于零。",
      "units": "error",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V06",
      "engine": "position_size",
      "name": "Standard sizing / 标准仓位",
      "input": {
        "accountBalance": 10000,
        "riskPercent": 1,
        "stopLossPips": 20,
        "pipValuePerLot": 10
      },
      "expected": {
        "risk_amount": 100,
        "lots_standard_rounded": 0.5
      },
      "expectedError": null,
      "derivation": "10000×.01=100; 100/(20×10)=.5 lots.",
      "units": "account currency; lots",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V07",
      "engine": "position_size",
      "name": "Step .3 / 取整预算",
      "input": {
        "accountBalance": 10000,
        "riskPercent": 2,
        "stopLossPips": 25,
        "pipValuePerLot": 10,
        "step": 0.3
      },
      "expected": {
        "risk_amount": 200,
        "lots_standard_rounded": 0.6,
        "units_rounded": 60000
      },
      "expectedError": null,
      "derivation": "Budget200; raw lots200/250=.8; floor to .3=.6; units60000; planned risk .6×250=150 (budget remains200).",
      "units": "account currency; lots; base units",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V08",
      "engine": "position_size",
      "name": "Tiny step / 小步进",
      "input": {
        "accountBalance": 1,
        "riskPercent": 1,
        "stopLossPips": 100,
        "pipValuePerLot": 10,
        "step": 1e-06
      },
      "expected": {
        "risk_amount": 0.01,
        "lots_standard_rounded": 1e-05,
        "units_rounded": 1
      },
      "expectedError": null,
      "derivation": ".01/(100×10)=.00001 lots, exactly ten .000001 steps, one base unit.",
      "units": "account currency; lots; base units",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V09",
      "engine": "position_size",
      "name": "Zero stop / 零止损",
      "input": {
        "accountBalance": 10000,
        "riskPercent": 1,
        "stopLossPips": 0,
        "pipValuePerLot": 10
      },
      "expected": {},
      "expectedError": "stopLossPips must be > 0",
      "derivation": "Zero stop distance would divide by zero; must reject. / 止损距离为零必须拒绝。",
      "units": "error",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V10",
      "engine": "position_size",
      "name": "Risk over 100% / 风险比例越界",
      "input": {
        "accountBalance": 10000,
        "riskPercent": 101,
        "stopLossPips": 20,
        "pipValuePerLot": 10
      },
      "expected": {},
      "expectedError": "riskPercent must be at most 100",
      "derivation": "101% exceeds the supported risk-percent range. / 超出支持范围。",
      "units": "error",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V11",
      "engine": "margin",
      "name": "EURUSD USD / 美元保证金",
      "input": {
        "pair": "EURUSD",
        "accountCcy": "USD",
        "lots": 1,
        "price": 1.2,
        "leverage": 100
      },
      "expected": {
        "required_margin_account": 1200
      },
      "expectedError": null,
      "derivation": "100000 EUR×1.2 USD/EUR /100 =1200 USD.",
      "units": "USD",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V12",
      "engine": "margin",
      "name": "EURUSD EUR / 基础币保证金",
      "input": {
        "pair": "EURUSD",
        "accountCcy": "EUR",
        "lots": 1,
        "price": 1.2,
        "leverage": 100
      },
      "expected": {
        "required_margin_account": 1000
      },
      "expectedError": null,
      "derivation": "100000 EUR/100=1000 EUR; do not divide by price twice.",
      "units": "EUR",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V13",
      "engine": "margin",
      "name": "USDJPY half lot / 半手日元对",
      "input": {
        "pair": "USDJPY",
        "accountCcy": "USD",
        "lots": 0.5,
        "price": 150,
        "leverage": 50
      },
      "expected": {
        "required_margin_account": 1000
      },
      "expectedError": null,
      "derivation": "100000 USD×.5/50=1000 USD.",
      "units": "USD",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V14",
      "engine": "margin",
      "name": "Cross currency / 第三币保证金",
      "input": {
        "pair": "EURUSD",
        "accountCcy": "CHF",
        "quoteToAccountRate": 0.8,
        "lots": 1,
        "price": 1.2,
        "leverage": 100
      },
      "expected": {
        "required_margin_account": 960
      },
      "expectedError": null,
      "derivation": "120000 USD /100 × .8 CHF/USD=960 CHF.",
      "units": "CHF",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V15",
      "engine": "margin",
      "name": "Missing margin rule / 缺保证金规则",
      "input": {
        "pair": "EURUSD",
        "accountCcy": "USD",
        "lots": 1,
        "price": 1.2
      },
      "expected": {},
      "expectedError": "provide either leverage or marginPercent",
      "derivation": "Neither leverage nor margin percentage is supplied; no justified margin result. / 缺规则不能确认。",
      "units": "error",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V16",
      "engine": "pnl",
      "name": "Long gain / 多仓盈利",
      "input": {
        "pair": "EURUSD",
        "accountCcy": "USD",
        "direction": "long",
        "lots": 1,
        "openPrice": 1.2,
        "closePrice": 1.201
      },
      "expected": {
        "pnl_account": 100
      },
      "expectedError": null,
      "derivation": "(1.201−1.2)×100000=100 USD.",
      "units": "USD",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V17",
      "engine": "pnl",
      "name": "Short loss / 空仓亏损",
      "input": {
        "pair": "EURUSD",
        "accountCcy": "USD",
        "direction": "short",
        "lots": 1,
        "openPrice": 1.2,
        "closePrice": 1.201
      },
      "expected": {
        "pnl_account": -100
      },
      "expectedError": null,
      "derivation": "(1.2−1.201)×100000=−100 USD.",
      "units": "USD",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V18",
      "engine": "pnl",
      "name": "USDJPY short / 日元对空仓换算",
      "input": {
        "pair": "USDJPY",
        "accountCcy": "USD",
        "direction": "short",
        "lots": 0.5,
        "openPrice": 150,
        "closePrice": 149
      },
      "expected": {
        "pnl_account": 335.5704697986577
      },
      "expectedError": null,
      "derivation": "(150−149)×50000=50000 JPY; at close149, 50000/149 USD.",
      "units": "USD",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V19",
      "engine": "pnl",
      "name": "EUR account / 欧元账户盈亏",
      "input": {
        "pair": "EURUSD",
        "accountCcy": "EUR",
        "direction": "long",
        "lots": 1,
        "openPrice": 1.2,
        "closePrice": 1.212
      },
      "expected": {
        "pnl_account": 990.0990099009902
      },
      "expectedError": null,
      "derivation": ".012×100000=1200 USD; 1200/1.212 EUR at close.",
      "units": "EUR",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V20",
      "engine": "pnl",
      "name": "Zero exit price / 零平仓价",
      "input": {
        "pair": "EURUSD",
        "accountCcy": "USD",
        "direction": "long",
        "lots": 1,
        "openPrice": 1.2,
        "closePrice": 0
      },
      "expected": {},
      "expectedError": "closePrice must be > 0",
      "derivation": "Exit must be positive; zero is unsupported. / 平仓价须为正。",
      "units": "error",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V21",
      "engine": "spread_cost",
      "name": "Spread plus commission / 点差加双边佣金",
      "input": {
        "pair": "EURUSD",
        "accountCcy": "USD",
        "lots": 0.1,
        "spreadPips": 2,
        "commissionPerSide": 3.5
      },
      "expected": {
        "spread_cost_account": 2,
        "commission_cost_account": 0.7,
        "total_cost_account": 2.7
      },
      "expectedError": null,
      "derivation": "2pips×10USD/pip/lot×.1lot=2; commission3.5×2×.1=.7; total2.7.",
      "units": "USD",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V22",
      "engine": "spread_cost",
      "name": "Zero costs / 零成本情景",
      "input": {
        "pair": "EURUSD",
        "accountCcy": "USD",
        "lots": 1,
        "spreadPips": 0,
        "commissionPerSide": 0
      },
      "expected": {
        "total_cost_account": 0
      },
      "expectedError": null,
      "derivation": "0 spread +0 commission=0. This is a scenario, not a broker fee claim. / 示例并非券商报价。",
      "units": "USD",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V23",
      "engine": "spread_cost",
      "name": "GBP fee units / 英镑费用口径",
      "input": {
        "pair": "EURUSD",
        "accountCcy": "GBP",
        "quoteToAccountRate": 0.8,
        "lots": 1,
        "spreadPips": 2,
        "commissionPerSide": 2
      },
      "expected": {
        "total_cost_account": 20
      },
      "expectedError": null,
      "derivation": "2pips×10USD×.8=16GBP; commission2GBP×2=4GBP; total20GBP.",
      "units": "GBP",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V24",
      "engine": "spread_cost",
      "name": "Bid ask precision / 买卖价精度",
      "input": {
        "pair": "EURUSD",
        "accountCcy": "USD",
        "lots": 1,
        "bidPrice": 1.2,
        "askPrice": 1.2003
      },
      "expected": {
        "spread_pips": 3,
        "total_cost_account": 30
      },
      "expectedError": null,
      "derivation": "(1.2003−1.2)/.0001=3pips; 3×10USD=30USD. No extra ×10.",
      "units": "pips; USD",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    },
    {
      "id": "V25",
      "engine": "spread_cost",
      "name": "Crossed quotes / 卖价低于买价",
      "input": {
        "pair": "EURUSD",
        "accountCcy": "USD",
        "lots": 1,
        "bidPrice": 1.2,
        "askPrice": 1.1999
      },
      "expected": {},
      "expectedError": "must be >= 0",
      "derivation": "Ask−bid<0; reject crossed spread. / 负点差拒绝。",
      "units": "error",
      "assumptions": "Linear contract; fixed stated FX conversion; no unentered costs. / 线性合约；使用给定换算率；不含未填写费用。",
      "absTolerance": 1e-07,
      "relTolerance": 1e-10,
      "formulaVersion": "r4-2026-10-09",
      "caseVersion": "1.0.0"
    }
  ]
}
