spec_name = 'manual_generic' fields = {'account': 'cuixia', 'action': 'trim', 'dip_n': 1, 'dip_variant': '', ...} spec = CoidSpec(name='manual_generic', strategy_label='manual', prefix='manual-', regex=re.compile('^manual-', re.IGNORECASE)...ID (any `manual-*` prefix). Protected from auto-trim by buying_power_trim._manual_protected_symbols.', is_legacy=False) norm_fields = {'account': 'cuixia', 'action': 'trim', 'dip_n': 1, 'dip_variant': '', ...} k = 'dip_variant', v = '' e = ValueError("format_coid: spec='manual_generic' template requires field 'tag' (template='manual-{tag}-{symbol}-{account...b_id', 'entry_count', 'mmdd', 'hold_days', 'action', 'side', 'ts', 'uniq', 'kind', 'source', 'dip_n', 'dip_variant'])") def format_coid(spec_name: str, **fields: Any) -> str: """Format and return a COID per the named spec. The template's required fields are derived from the f-string's `{name}` placeholders. Missing fields raise ValueError (loud failure) — never silently substitute an empty string, because that produces malformed coids that parse to wrong specs. Strings are lowercased before substitution. `uniq` is auto-filled with a 6-char uuid hex when not provided (matches the ovf-* pattern and avoids collisions on repeated calls). The result is truncated to the spec's max_len (default 48 = Alpaca's client_order_id cap). Truncation preserves the prefix — if the template would exceed max_len the trailing fields are clipped. Raises: ValueError if `spec_name` is not in the registry, the spec is flagged is_legacy (read-only), or a required field is missing. """ spec = _BY_NAME.get(spec_name) if spec is None: raise ValueError( f"format_coid: unknown spec_name={spec_name!r}. " f"Add a CoidSpec to rtrader/utils/coid_registry.REGISTRY." ) if spec.is_legacy or not spec.format_template: raise ValueError( f"format_coid: spec={spec_name!r} is legacy/read-only. " f"New emit sites must use a non-legacy spec." ) # Lowercase string fields; pass through ints/floats unchanged. norm_fields: Dict[str, Any] = {} for k, v in fields.items(): if isinstance(v, str): norm_fields[k] = v.lower() else: norm_fields[k] = v # Auto-fill uniq when the template needs it but caller didn't supply. if "{uniq}" in spec.format_template and "uniq" not in norm_fields: norm_fields["uniq"] = uuid.uuid4().hex[:6] try: > coid = spec.format_template.format(**norm_fields) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'tag' rtrader/utils/coid_registry.py:1253: KeyError The above exception was the direct cause of the following exception: spec = CoidSpec(name='manual_generic', strategy_label='manual', prefix='manual-', regex=re.compile('^manual-', re.IGNORECASE)...ID (any `manual-*` prefix). Protected from auto-trim by buying_power_trim._manual_protected_symbols.', is_legacy=False) @pytest.mark.parametrize( "spec", [s for s in REGISTRY if not s.is_legacy], ids=lambda s: s.name, ) def test_each_spec_round_trips(spec): """format_coid(name, ...) → parse_coid(...) → same spec.""" > coid = format_coid(spec.name, **_SAMPLE_FIELDS) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/utils/test_coid_registry.py:66: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ spec_name = 'manual_generic' fields = {'account': 'cuixia', 'action': 'trim', 'dip_n': 1, 'dip_variant': '', ...} spec = CoidSpec(name='manual_generic', strategy_label='manual', prefix='manual-', regex=re.compile('^manual-', re.IGNORECASE)...ID (any `manual-*` prefix). Protected from auto-trim by buying_power_trim._manual_protected_symbols.', is_legacy=False) norm_fields = {'account': 'cuixia', 'action': 'trim', 'dip_n': 1, 'dip_variant': '', ...} k = 'dip_variant', v = '' e = ValueError("format_coid: spec='manual_generic' template requires field 'tag' (template='manual-{tag}-{symbol}-{account...b_id', 'entry_count', 'mmdd', 'hold_days', 'action', 'side', 'ts', 'uniq', 'kind', 'source', 'dip_n', 'dip_variant'])") def format_coid(spec_name: str, **fields: Any) -> str: """Format and return a COID per the named spec. The template's required fields are derived from the f-string's `{name}` placeholders. Missing fields raise ValueError (loud failure) — never silently substitute an empty string, because that produces malformed coids that parse to wrong specs. Strings are lowercased before substitution. `uniq` is auto-filled with a 6-char uuid hex when not provided (matches the ovf-* pattern and avoids collisions on repeated calls). The result is truncated to the spec's max_len (default 48 = Alpaca's client_order_id cap). Truncation preserves the prefix — if the template would exceed max_len the trailing fields are clipped. Raises: ValueError if `spec_name` is not in the registry, the spec is flagged is_legacy (read-only), or a required field is missing. """ spec = _BY_NAME.get(spec_name) if spec is None: raise ValueError( f"format_coid: unknown spec_name={spec_name!r}. " f"Add a CoidSpec to rtrader/utils/coid_registry.REGISTRY." ) if spec.is_legacy or not spec.format_template: raise ValueError( f"format_coid: spec={spec_name!r} is legacy/read-only. " f"New emit sites must use a non-legacy spec." ) # Lowercase string fields; pass through ints/floats unchanged. norm_fields: Dict[str, Any] = {} for k, v in fields.items(): if isinstance(v, str): norm_fields[k] = v.lower() else: norm_fields[k] = v # Auto-fill uniq when the template needs it but caller didn't supply. if "{uniq}" in spec.format_template and "uniq" not in norm_fields: norm_fields["uniq"] = uuid.uuid4().hex[:6] try: coid = spec.format_template.format(**norm_fields) except KeyError as exc: # Missing required template field — surface to Sentry then raise. e = ValueError( f"format_coid: spec={spec_name!r} template requires field " f"{exc!s} (template={spec.format_template!r}, " f"provided={list(fields.keys())})" ) sentry_sdk.capture_exception(e) > raise e from exc E ValueError: format_coid: spec='manual_generic' template requires field 'tag' (template='manual-{tag}-{symbol}-{account}-{uniq}', provided=['symbol', 'account', 'plan_id', 'job_id', 'entry_count', 'mmdd', 'hold_days', 'action', 'side', 'ts', 'uniq', 'kind', 'source', 'dip_n', 'dip_variant']) rtrader/utils/coid_registry.py:1262: ValueError