trader.llm.rank_prompt module¶
Building the ranking prompt, and parsing what comes back.
Two rules define this module, and they are the same two that define prompt.py — which is why it lives next to it.
Nothing here raises. Every malformed, missing, hallucinated, duplicated or omitted response shape degrades to a valid permutation of exactly the candidates passed in, with the fault recorded. The ranker cannot create a trade — every candidate was already approved by its own decision and must still clear every guardrail — so a degraded order is safe in a way a degraded decision would not be. But it must be visible: a guard that silently swallows a fault leaves nothing able to tell a good ranking from a rescued one.
The prompt is reconstructible. RANK_PROMPT_VERSION is stored with every decision alongside the inputs. Bump it whenever the wording changes, or rankings either side of the change become indistinguishable. It is deliberately separate from PROMPT_TEMPLATE_VERSION: the two prompts change independently, and this work does not touch the decision prompt at all.
- trader.llm.rank_prompt.RANK_PROMPT_VERSION = '1'¶
Bump on any wording change. Stored with every ranked decision.
- trader.llm.rank_prompt.RANK_SCHEMA: dict[str, object] = {'properties': {'ranking': {'items': {'properties': {'reason': {'type': 'string'}, 'symbol': {'type': 'string'}}, 'required': ['symbol', 'reason'], 'type': 'object'}, 'type': 'array'}}, 'required': ['ranking'], 'type': 'object'}¶
Note the absence of a rank integer. Array order is authoritative, so order and rank cannot contradict each other — the same reasoning that removed position_open: bool from Strategy.evaluate.
- trader.llm.rank_prompt.build_rank_messages(candidates)[source]¶
Return (system, user) messages for one ranking.
Candidates are presented in symbol order, not confidence order. Deterministic, so prompt_hash replay works — and position bias being real, pre-sorting by confidence would make the laziest possible response (repeat the given order) indistinguishable from a considered ranking. Since distrust of raw confidence is the whole reason a comparative call exists, hiding that failure would defeat the purpose.
- Parameters:
candidates (Sequence[Candidate])
- Return type:
tuple[str, str]
- trader.llm.rank_prompt.parse_ranking(payload, candidates)[source]¶
Turn a model response into (order, notes, problems). Never raises.
The returned order is always a permutation of exactly the candidate symbols — never shorter, never longer, never containing a symbol nobody proposed. Recognised symbols keep the order given; unknown ones are dropped; duplicates keep their first place; anything omitted is appended in fallback order. problems records every degradation, because a silent rescue is indistinguishable from a good ranking.
- Parameters:
payload (object)
candidates (Sequence[Candidate])
- Return type:
tuple[tuple[str, …], dict[str, str], list[str]]