fix(agents): ground the Trader in the technical market report

- the Trader received only the digested investment plan, so its entry / stop /
  sizing levels were not anchored to real price structure (ATR, support and
  resistance, current price)
- inject the market report and instruct the Trader to take concrete price levels
  from it and direction/strategy from the plan; when the market analyst was not
  selected the report is empty, so the section and grounding note are omitted #1167
This commit is contained in:
Yijia-Xiao
2026-08-31 02:35:50 +00:00
parent 45c1744b86
commit e93c5c53c2
3 changed files with 50 additions and 7 deletions

View File

@@ -52,6 +52,7 @@ def test_trader_prompt_states_constraint():
create_trader(llm)({
"company_of_interest": "NVDA",
"investment_plan": "**Recommendation**: Buy",
"market_report": "Current price $189.5; ATR 4.2.",
})
assert NO_EXTERNAL_TOOLS in _prompt_text(captured["prompt"])

View File

@@ -131,6 +131,7 @@ def _make_trader_state():
return {
"company_of_interest": "NVDA",
"investment_plan": "**Recommendation**: Buy\n**Rationale**: ...\n**Strategic Actions**: ...",
"market_report": "Current price $189.5; 14-day ATR 4.2; support $178, resistance $196.",
}
@@ -200,6 +201,31 @@ class TestTraderAgent:
prompt = captured["prompt"]
assert any("Proposed Investment Plan" in m["content"] for m in prompt)
def test_prompt_includes_market_report_for_price_levels(self):
# #1167: the Trader must see the technical market report so entry/stop
# levels are grounded in real price structure, not just the digested plan.
captured = {}
trader = create_trader(_structured_trader_llm(captured))
trader(_make_trader_state())
user = " ".join(m["content"] for m in captured["prompt"] if m["role"] == "user")
system = " ".join(m["content"] for m in captured["prompt"] if m["role"] == "system")
assert "Technical Market Report:" in user
assert "14-day ATR 4.2" in user # the actual report content reached the Trader
assert "support $178, resistance $196" in user
assert "Ground concrete price levels" in system
def test_empty_market_report_omits_the_section_and_grounding(self):
# #1167: when the market analyst wasn't selected the report is empty, so
# don't tell the Trader to ground levels in a report it doesn't have.
captured = {}
state = _make_trader_state()
state["market_report"] = ""
create_trader(_structured_trader_llm(captured))(state)
text = " ".join(m["content"] for m in captured["prompt"])
assert "Technical Market Report:" not in text
assert "Ground concrete price levels" not in text
assert "Proposed Investment Plan" in text # still present
def test_falls_back_to_freetext_when_structured_unavailable(self):
plain_response = (
"**Action**: Sell\n\nGuidance cut hits margins.\n\n"

View File

@@ -25,6 +25,23 @@ def create_trader(llm):
company_name = state["company_of_interest"]
instrument_context = get_instrument_context_from_state(state)
investment_plan = state["investment_plan"]
# The research plan digests the debate but loses exact price structure;
# give the Trader the technical market report so entry/stop levels are
# grounded in real ATR / support-resistance / current price (#1167). The
# report is empty when the user did not select the market analyst, so
# only offer it (and the grounding instruction) when it has content.
market_report = (state["market_report"] or "").strip()
if market_report:
grounding = (
"Ground concrete price levels (entry, stop-loss, position sizing) in the technical "
"market report's price structure -- current price, support/resistance, ATR, and "
"volatility -- and use the research plan for direction and strategy. "
)
report_section = f"Technical Market Report:\n{market_report}\n\n"
else:
grounding = ""
report_section = ""
messages = [
{
@@ -32,7 +49,7 @@ def create_trader(llm):
"content": (
"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. "
"Anchor your reasoning in the analysts' reports and the research plan. "
+ grounding
+ NO_EXTERNAL_TOOLS
+ get_language_instruction()
),
@@ -40,12 +57,11 @@ def create_trader(llm):
{
"role": "user",
"content": (
f"Based on a comprehensive analysis by a team of analysts, here is an investment "
f"plan tailored for {company_name}. {instrument_context} This plan incorporates "
f"insights from current technical market trends, macroeconomic indicators, and "
f"social media sentiment. Use this plan as a foundation for evaluating your next "
f"trading decision.\n\nProposed Investment Plan: {investment_plan}\n\n"
f"Leverage these insights to make an informed and strategic decision."
f"Here is the research team's investment plan for {company_name}. "
f"{instrument_context}\n\n"
f"{report_section}"
f"Proposed Investment Plan:\n{investment_plan}\n\n"
f"Make an informed, strategic trading decision."
),
},
]