mirror of
https://github.com/TauricResearch/TradingAgents.git
synced 2026-09-24 13:32:34 +03:00
fix(agents): require absolute price levels from the Trader
- asking the Trader for concrete entry/stop levels invited a percentage (stop_loss: '15%'), which is not a price and failed the whole structured parse, dropping the run to a free-text retry - state the requirement in the prompt and in both field descriptions - a percentage now nulls that field instead of failing the proposal; it is never salvaged, since 15% must not become a 15 stop. Human-formatted prices with a currency symbol or thousands separator parse #1288
This commit is contained in:
@@ -31,9 +31,23 @@ _NULLISH_FLOAT = {"", "none", "n/a", "na", "null", "nil", "-", "tbd", "unknown"}
|
|||||||
|
|
||||||
|
|
||||||
def _coerce_optional_float(value):
|
def _coerce_optional_float(value):
|
||||||
if isinstance(value, str) and value.strip().lower() in _NULLISH_FLOAT:
|
"""Normalise an LLM-written optional numeric field before validation.
|
||||||
|
|
||||||
|
Three shapes show up in practice: a placeholder string ("None", "N/A") in
|
||||||
|
place of an omitted value (#1058); a percentage where a price was asked for
|
||||||
|
("15%", #1288); and a human-formatted price ("$1,234.50"). A percentage
|
||||||
|
cannot be salvaged into an absolute level -- reading "15%" as 15 would put a
|
||||||
|
stop at $15 on a $600 stock -- so it is dropped like a placeholder, leaving
|
||||||
|
one bad field to null out instead of failing the whole proposal. A formatted
|
||||||
|
price is reduced to its number. Anything else passes through to pydantic.
|
||||||
|
"""
|
||||||
|
if not isinstance(value, str):
|
||||||
|
return value
|
||||||
|
text = value.strip()
|
||||||
|
if text.lower() in _NULLISH_FLOAT or text.endswith("%"):
|
||||||
return None
|
return None
|
||||||
return value
|
cleaned = text.replace(",", "").lstrip("$€£¥").strip()
|
||||||
|
return cleaned or None
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -140,11 +154,19 @@ class TraderProposal(BaseModel):
|
|||||||
)
|
)
|
||||||
entry_price: float | None = Field(
|
entry_price: float | None = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Optional entry price target in the instrument's quote currency.",
|
description=(
|
||||||
|
"Optional entry price target as an absolute number in the instrument's "
|
||||||
|
"quote currency (e.g. 189.5), never a percentage or a range. Omit it "
|
||||||
|
"if you cannot state a specific level."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
stop_loss: float | None = Field(
|
stop_loss: float | None = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Optional stop-loss price in the instrument's quote currency.",
|
description=(
|
||||||
|
"Optional stop-loss as an absolute price in the instrument's quote "
|
||||||
|
"currency (e.g. 172.0), never a percentage. Convert a percentage "
|
||||||
|
"distance to the price level it implies, or omit it."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
position_sizing: str | None = Field(
|
position_sizing: str | None = Field(
|
||||||
default=None,
|
default=None,
|
||||||
|
|||||||
@@ -50,6 +50,13 @@ def create_trader(llm):
|
|||||||
"You are a trading agent analyzing market data to make investment decisions. "
|
"You are a trading agent analyzing market data to make investment decisions. "
|
||||||
"Based on your analysis, provide a specific recommendation to buy, sell, or hold. "
|
"Based on your analysis, provide a specific recommendation to buy, sell, or hold. "
|
||||||
+ grounding
|
+ grounding
|
||||||
|
# Entry/stop are numeric price fields. Asking for concrete
|
||||||
|
# levels invites a percentage ("15%"), which is not a price
|
||||||
|
# and fails the structured parse (#1288).
|
||||||
|
+ "State entry price and stop-loss as absolute price levels in the "
|
||||||
|
"instrument's quote currency (for example 189.5), never a percentage "
|
||||||
|
"or a range; convert a percentage distance to the price level it "
|
||||||
|
"implies, or omit the field if you cannot state a number. "
|
||||||
+ NO_EXTERNAL_TOOLS
|
+ NO_EXTERNAL_TOOLS
|
||||||
+ get_language_instruction()
|
+ get_language_instruction()
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user