mirror of
https://github.com/TauricResearch/TradingAgents.git
synced 2026-11-03 16:12:44 +02:00
fix(portfolio): refuse a portfolio with a number that is not finite (#1509)
- cash, quantities and average prices reject NaN and infinity when the file loads
This commit is contained in:
@@ -96,6 +96,20 @@ def test_a_holding_keeps_the_instrument_it_was_listed_as():
|
||||
assert "Other positions: WTI 100" in text and "CL=F" not in text
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.parametrize("book", [
|
||||
'{"cash": NaN}',
|
||||
'{"positions": [{"ticker": "AAPL", "quantity": Infinity}]}',
|
||||
'{"positions": [{"ticker": "AAPL", "quantity": 1, "average_price": "nan"}]}',
|
||||
])
|
||||
def test_load_rejects_a_number_that_is_not_finite(tmp_path, book):
|
||||
# Python's json writes NaN and Infinity, and they would reach the agents as "nan units".
|
||||
bad = tmp_path / "p.json"
|
||||
bad.write_text(book)
|
||||
with pytest.raises(ValueError, match="portfolio"):
|
||||
load_portfolio(bad)
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_load_reads_a_valid_file(tmp_path):
|
||||
good = tmp_path / "p.json"
|
||||
|
||||
@@ -17,18 +17,22 @@ import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from pydantic import BaseModel, Field, ValidationError
|
||||
from pydantic import BaseModel, ConfigDict, Field, ValidationError
|
||||
|
||||
from tradingagents.dataflows.symbols import normalize_symbol
|
||||
|
||||
|
||||
class Position(BaseModel):
|
||||
model_config = ConfigDict(allow_inf_nan=False)
|
||||
|
||||
ticker: str = Field(description="Instrument symbol, e.g. AAPL")
|
||||
quantity: float = Field(description="Signed units held; negative is short")
|
||||
average_price: float | None = Field(default=None, description="Average entry price per unit")
|
||||
|
||||
|
||||
class PortfolioContext(BaseModel):
|
||||
model_config = ConfigDict(allow_inf_nan=False)
|
||||
|
||||
cash: float | None = Field(default=None, description="Free cash available")
|
||||
currency: str | None = Field(default=None, description="Currency label for cash and prices")
|
||||
positions: list[Position] = Field(default_factory=list)
|
||||
|
||||
Reference in New Issue
Block a user