{"record":{"id":"f4aabfc28ba40275","repo":"nautechsystems/nautilus_trader","slug":"ax-maintenance-margin-pct-maintenance-margin-pct","errorCode":null,"errorMessage":"AX maintenance_margin_pct {maintenance_margin_pct} exceeds initial_margin_pct {initial_margin_pct}","messagePattern":"AX maintenance_margin_pct (.+?) exceeds initial_margin_pct (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/architect_ax/src/http/parse.rs","lineNumber":392,"sourceCode":"        ts_init,\n    );\n\n    Ok(InstrumentAny::PerpetualContract(instrument))\n}\n\nfn parse_margin_rates(\n    initial_margin_pct: Decimal,\n    maintenance_margin_pct: Decimal,\n) -> anyhow::Result<(Decimal, Decimal)> {\n    anyhow::ensure!(\n        initial_margin_pct > Decimal::ZERO,\n        \"AX initial_margin_pct must be positive, was {initial_margin_pct}\"\n    );\n    anyhow::ensure!(\n        maintenance_margin_pct > Decimal::ZERO,\n        \"AX maintenance_margin_pct must be positive, was {maintenance_margin_pct}\"\n    );\n    anyhow::ensure!(\n        maintenance_margin_pct <= initial_margin_pct,\n        \"AX maintenance_margin_pct {maintenance_margin_pct} exceeds initial_margin_pct {initial_margin_pct}\"\n    );\n\n    Ok((\n        margin_percent_to_rate(initial_margin_pct, \"initial_margin_pct\")?,\n        margin_percent_to_rate(maintenance_margin_pct, \"maintenance_margin_pct\")?,\n    ))\n}\n\nfn margin_percent_to_rate(value: Decimal, field: &str) -> anyhow::Result<Decimal> {\n    let normalized = value.normalize();\n    let scale = normalized.scale();\n    anyhow::ensure!(\n        scale <= 26,\n        \"AX {field} scale must not exceed 26 for exact percent conversion, was {scale}\"\n    );\n    Decimal::try_from_i128_with_scale(normalized.mantissa(), scale + 2)","sourceCodeStart":374,"sourceCodeEnd":410,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/a4b06ed870971b5671d12754ea138a3ab99b1dec/crates/adapters/architect_ax/src/http/parse.rs#L374-L410","documentation":"parse_margin_rates enforces maintenance_margin_pct <= initial_margin_pct; an inverted pair (maintenance exceeding initial) is nonsensical for risk modeling and fails instrument parsing. Both values may individually be positive — only their ordering is wrong.","triggerScenarios":"Venue config for a symbol swaps the two fields (maintenance 5, initial 2); an integration or spreadsheet import maps the API fields backwards; a fat-fingered template applied to new listings.","commonSituations":"Manual contract configuration with swapped margin columns; upstream API field-order changes misinterpreted by a sync tool; inherited misconfigurations surfacing when the symbol is first loaded.","solutions":["Inspect both margin fields for the symbol in AX and swap them so maintenance <= initial","Audit the integration/tool that writes venue config for swapped field mapping","Reload instruments and confirm the symbol parses","Add a config lint (maintenance <= initial) before publishing contract metadata"],"exampleFix":"// before (AX contract metadata)\n{\"initial_margin_pct\": \"0.5\", \"maintenance_margin_pct\": \"1.5\"}\n// after\n{\"initial_margin_pct\": \"1.5\", \"maintenance_margin_pct\": \"0.5\"}","handlingStrategy":"try-catch","validationCode":"// Lint margin ordering before definitions reach the parser\nfn margin_order_ok(initial: Decimal, maintenance: Decimal) -> bool {\n    initial > Decimal::ZERO && maintenance > Decimal::ZERO && maintenance <= initial\n}\n\nif !margin_order_ok(definition.initial_margin_pct, definition.maintenance_margin_pct) {\n    anyhow::bail!(\"symbol {} margin percents inverted or invalid\", definition.symbol);\n}","typeGuard":null,"tryCatchPattern":"match parse_instrument(&definition, ts_event, ts_init) {\n    Ok(instrument) => Ok(instrument),\n    Err(e) if e.to_string().contains(\"exceeds initial_margin_pct\") => {\n        log::error!(\"symbol {} has maintenance > initial margin; swap values in venue config\", definition.symbol);\n        Err(e)\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Add maintenance <= initial as a hard lint in the venue-config publish pipeline","When importing contract parameters from spreadsheets, unit-test the column mapping once — swapped fields are the top cause","Review margin config for new listings before enabling the symbol for trading"],"tags":["architect-ax","instrument","margin","validation","config-mistake"],"backgroundTag":"invalid-margin-parameters","analyzedSha":"a4b06ed870971b5671d12754ea138a3ab99b1dec","analyzedAt":"2026-08-16T22:54:50.089Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}