nautechsystems/nautilus_trader · error · anyhow::Error
AX maintenance_margin_pct {maintenance_margin_pct} exceeds i
Error message
AX maintenance_margin_pct {maintenance_margin_pct} exceeds initial_margin_pct {initial_margin_pct} What it means
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.
Source
Thrown at crates/adapters/architect_ax/src/http/parse.rs:392
ts_init,
);
Ok(InstrumentAny::PerpetualContract(instrument))
}
fn parse_margin_rates(
initial_margin_pct: Decimal,
maintenance_margin_pct: Decimal,
) -> anyhow::Result<(Decimal, Decimal)> {
anyhow::ensure!(
initial_margin_pct > Decimal::ZERO,
"AX initial_margin_pct must be positive, was {initial_margin_pct}"
);
anyhow::ensure!(
maintenance_margin_pct > Decimal::ZERO,
"AX maintenance_margin_pct must be positive, was {maintenance_margin_pct}"
);
anyhow::ensure!(
maintenance_margin_pct <= initial_margin_pct,
"AX maintenance_margin_pct {maintenance_margin_pct} exceeds initial_margin_pct {initial_margin_pct}"
);
Ok((
margin_percent_to_rate(initial_margin_pct, "initial_margin_pct")?,
margin_percent_to_rate(maintenance_margin_pct, "maintenance_margin_pct")?,
))
}
fn margin_percent_to_rate(value: Decimal, field: &str) -> anyhow::Result<Decimal> {
let normalized = value.normalize();
let scale = normalized.scale();
anyhow::ensure!(
scale <= 26,
"AX {field} scale must not exceed 26 for exact percent conversion, was {scale}"
);
Decimal::try_from_i128_with_scale(normalized.mantissa(), scale + 2)View on GitHub (pinned to a4b06ed870)
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
Example fix
// before (AX contract metadata)
{"initial_margin_pct": "0.5", "maintenance_margin_pct": "1.5"}
// after
{"initial_margin_pct": "1.5", "maintenance_margin_pct": "0.5"} Defensive patterns
Strategy: try-catch
Validate before calling
// Lint margin ordering before definitions reach the parser
fn margin_order_ok(initial: Decimal, maintenance: Decimal) -> bool {
initial > Decimal::ZERO && maintenance > Decimal::ZERO && maintenance <= initial
}
if !margin_order_ok(definition.initial_margin_pct, definition.maintenance_margin_pct) {
anyhow::bail!("symbol {} margin percents inverted or invalid", definition.symbol);
} Try / catch
match parse_instrument(&definition, ts_event, ts_init) {
Ok(instrument) => Ok(instrument),
Err(e) if e.to_string().contains("exceeds initial_margin_pct") => {
log::error!("symbol {} has maintenance > initial margin; swap values in venue config", definition.symbol);
Err(e)
}
Err(e) => Err(e),
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- AX initial_margin_pct must be positive, was {initial_margin_
- AX maintenance_margin_pct must be positive, was {maintenance
- AX instrument product must be non-empty without surrounding
- AX minimum_order_size must be a positive whole number, was {
- AX dated contract {} has different quote and settlement curr
AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16).
Data as JSON: /api/errors/f4aabfc28ba40275.
Report an issue: GitHub.