diff --git a/tests/test_structured_agent_prompts.py b/tests/test_structured_agent_prompts.py index d876225cc..d7b24061c 100644 --- a/tests/test_structured_agent_prompts.py +++ b/tests/test_structured_agent_prompts.py @@ -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"]) diff --git a/tests/test_structured_agents.py b/tests/test_structured_agents.py index 6f5cdb206..50566cdd4 100644 --- a/tests/test_structured_agents.py +++ b/tests/test_structured_agents.py @@ -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" diff --git a/tradingagents/agents/trader/trader.py b/tradingagents/agents/trader/trader.py index 6c8ac50e4..402023bf1 100644 --- a/tradingagents/agents/trader/trader.py +++ b/tradingagents/agents/trader/trader.py @@ -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." ), }, ]