mirror of
https://github.com/TauricResearch/TradingAgents.git
synced 2026-09-27 06:56:39 +03:00
- each analyst is a graph of its own (model and tools on a private message history) that returns only its report; all start together and the research debate waits for every report - the message-clearing nodes are gone; a checkpoint saved by the sequential layout starts fresh - TradingAgentsGraph.stream_run streams the analysts' messages for debug mode and the CLI, whose status and timing now track the analysts side by side
121 lines
4.8 KiB
Python
121 lines
4.8 KiB
Python
"""Tests for deterministic instrument-identity resolution (#814) and the
|
|
context-anchored message placeholder (#888)."""
|
|
|
|
import unittest
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
|
|
from tradingagents.agents.context import (
|
|
build_instrument_context,
|
|
get_instrument_context_from_state,
|
|
resolve_instrument_identity,
|
|
)
|
|
|
|
|
|
@pytest.mark.unit
|
|
class ResolveInstrumentIdentityTests(unittest.TestCase):
|
|
def setUp(self):
|
|
resolve_instrument_identity.cache_clear()
|
|
|
|
def test_resolves_company_metadata_from_yfinance(self):
|
|
with patch("tradingagents.dataflows.vendors.yahoo.market.yf.Ticker") as mock:
|
|
mock.return_value.info = {
|
|
"longName": "TOTO LTD.",
|
|
"shortName": "TOTO",
|
|
"sector": "Industrials",
|
|
"industry": "Building Products & Equipment",
|
|
"exchange": "PNK",
|
|
"quoteType": "EQUITY",
|
|
}
|
|
identity = resolve_instrument_identity("totdy")
|
|
mock.assert_called_once_with("TOTDY")
|
|
self.assertEqual(identity["company_name"], "TOTO LTD.")
|
|
self.assertEqual(identity["sector"], "Industrials")
|
|
self.assertEqual(identity["industry"], "Building Products & Equipment")
|
|
self.assertEqual(identity["exchange"], "PNK")
|
|
|
|
def test_falls_back_to_short_name(self):
|
|
with patch("tradingagents.dataflows.vendors.yahoo.market.yf.Ticker") as mock:
|
|
mock.return_value.info = {"shortName": "TOTO", "sector": "Industrials"}
|
|
identity = resolve_instrument_identity("TOTDY")
|
|
self.assertEqual(identity["company_name"], "TOTO")
|
|
|
|
def test_skips_placeholder_values(self):
|
|
with patch("tradingagents.dataflows.vendors.yahoo.market.yf.Ticker") as mock:
|
|
mock.return_value.info = {"longName": " ", "sector": "None", "industry": "n/a"}
|
|
identity = resolve_instrument_identity("TOTDY")
|
|
self.assertEqual(identity, {})
|
|
|
|
def test_fails_open_on_exception(self):
|
|
with patch(
|
|
"tradingagents.dataflows.vendors.yahoo.market.yf.Ticker",
|
|
side_effect=RuntimeError("rate limited"),
|
|
):
|
|
self.assertEqual(resolve_instrument_identity("TOTDY"), {})
|
|
|
|
def test_result_is_cached(self):
|
|
with patch("tradingagents.dataflows.vendors.yahoo.market.yf.Ticker") as mock:
|
|
mock.return_value.info = {"longName": "TOTO LTD."}
|
|
first = resolve_instrument_identity("TOTDY")
|
|
second = resolve_instrument_identity("TOTDY")
|
|
mock.assert_called_once() # second call served from cache
|
|
self.assertEqual(first, second)
|
|
|
|
|
|
@pytest.mark.unit
|
|
class BuildInstrumentContextTests(unittest.TestCase):
|
|
def test_mentions_exact_symbol_without_identity(self):
|
|
context = build_instrument_context("7203.T")
|
|
self.assertIn("7203.T", context)
|
|
self.assertIn("exchange suffix", context)
|
|
self.assertNotIn("Resolved identity", context)
|
|
|
|
def test_injects_resolved_identity(self):
|
|
context = build_instrument_context(
|
|
"TOTDY", "stock",
|
|
{
|
|
"company_name": "TOTO LTD.",
|
|
"sector": "Industrials",
|
|
"industry": "Building Products & Equipment",
|
|
"exchange": "PNK",
|
|
},
|
|
)
|
|
self.assertIn("Company: TOTO LTD.", context)
|
|
self.assertIn("Industrials / Building Products & Equipment", context)
|
|
self.assertIn("Exchange: PNK", context)
|
|
self.assertIn("Do not substitute a different company", context)
|
|
|
|
def test_crypto_uses_name_label_and_keeps_hint(self):
|
|
context = build_instrument_context(
|
|
"BTC-USD", "crypto", {"company_name": "Bitcoin USD"}
|
|
)
|
|
self.assertIn("Name: Bitcoin USD", context)
|
|
self.assertIn("crypto asset rather than a company", context)
|
|
|
|
|
|
@pytest.mark.unit
|
|
class GetInstrumentContextFromStateTests(unittest.TestCase):
|
|
def test_prefers_precomputed_context(self):
|
|
state = {"company_of_interest": "TOTDY", "instrument_context": "PRECOMPUTED"}
|
|
self.assertEqual(get_instrument_context_from_state(state), "PRECOMPUTED")
|
|
|
|
def test_fallback_is_network_free_ticker_only(self):
|
|
# No instrument_context and no yfinance call — must not hit the network.
|
|
with patch("tradingagents.dataflows.vendors.yahoo.market.yf.Ticker") as mock:
|
|
context = get_instrument_context_from_state(
|
|
{"company_of_interest": "NVDA", "asset_type": "stock"}
|
|
)
|
|
mock.assert_not_called()
|
|
self.assertIn("NVDA", context)
|
|
|
|
def test_fallback_respects_asset_type(self):
|
|
context = get_instrument_context_from_state(
|
|
{"company_of_interest": "BTC-USD", "asset_type": "crypto"}
|
|
)
|
|
self.assertIn("crypto asset", context)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|