484 lines
16 KiB
Python
484 lines
16 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
Comprehensive Integration Testing for TradingAgents
|
||
Tests all integration points between new features and existing functionality.
|
||
"""
|
||
|
||
import os
|
||
import sys
|
||
from decimal import Decimal
|
||
from pathlib import Path
|
||
from dotenv import load_dotenv
|
||
|
||
# Load environment
|
||
load_dotenv()
|
||
|
||
|
||
def test_llm_factory_tradingagents_integration():
|
||
"""Test 1: LLM Factory + TradingAgents Integration"""
|
||
print("\n" + "="*70)
|
||
print("INTEGRATION TEST 1: LLM Factory + TradingAgents")
|
||
print("="*70)
|
||
|
||
try:
|
||
from tradingagents.llm_factory import LLMFactory
|
||
from tradingagents.graph.trading_graph import TradingAgentsGraph
|
||
from tradingagents.default_config import DEFAULT_CONFIG
|
||
|
||
# Test 1.1: Provider switching
|
||
print("\n1.1: Testing provider configuration...")
|
||
config = DEFAULT_CONFIG.copy()
|
||
|
||
providers_to_test = []
|
||
for provider in ["openai", "anthropic", "google"]:
|
||
validation = LLMFactory.validate_provider_setup(provider)
|
||
if validation["valid"]:
|
||
providers_to_test.append(provider)
|
||
print(f" ✓ {provider} is configured and ready")
|
||
else:
|
||
print(f" ⚠ {provider} not configured (skipping)")
|
||
|
||
if not providers_to_test:
|
||
print(" ⚠ No LLM providers configured - cannot test provider switching")
|
||
print(" ℹ Configure at least one provider in .env to test this feature")
|
||
return "SKIPPED"
|
||
|
||
# Test 1.2: TradingAgents initialization with different providers
|
||
print("\n1.2: Testing TradingAgents initialization with different providers...")
|
||
for provider in providers_to_test[:1]: # Test first available provider
|
||
try:
|
||
config["llm_provider"] = provider
|
||
models = LLMFactory.get_recommended_models(provider)
|
||
config["deep_think_llm"] = models["deep_thinking"]
|
||
config["quick_think_llm"] = models["quick_thinking"]
|
||
|
||
ta = TradingAgentsGraph(
|
||
selected_analysts=["market"],
|
||
config=config,
|
||
debug=False
|
||
)
|
||
print(f" ✓ TradingAgents initialized with {provider}")
|
||
print(f" ✓ Deep think model: {models['deep_thinking']}")
|
||
print(f" ✓ Quick think model: {models['quick_thinking']}")
|
||
except Exception as e:
|
||
print(f" ✗ Failed to initialize with {provider}: {e}")
|
||
return "FAIL"
|
||
|
||
# Test 1.3: Error handling for invalid provider
|
||
print("\n1.3: Testing error handling for invalid provider...")
|
||
try:
|
||
config["llm_provider"] = "invalid_provider"
|
||
validation = LLMFactory.validate_provider_setup("invalid_provider")
|
||
if not validation["valid"]:
|
||
print(" ✓ Invalid provider correctly rejected")
|
||
else:
|
||
print(" ✗ Invalid provider not rejected")
|
||
return "FAIL"
|
||
except Exception as e:
|
||
print(f" ✓ Invalid provider raises error (expected)")
|
||
|
||
print("\n✓ LLM Factory + TradingAgents Integration: PASS")
|
||
return "PASS"
|
||
|
||
except Exception as e:
|
||
print(f"\n✗ LLM Factory + TradingAgents Integration: FAIL - {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return "FAIL"
|
||
|
||
|
||
def test_broker_portfolio_integration():
|
||
"""Test 2: Broker + Portfolio System Integration"""
|
||
print("\n" + "="*70)
|
||
print("INTEGRATION TEST 2: Broker + Portfolio Integration")
|
||
print("="*70)
|
||
|
||
try:
|
||
from tradingagents.brokers.base import (
|
||
BrokerOrder, BrokerPosition, OrderSide, OrderType, OrderStatus
|
||
)
|
||
from tradingagents.portfolio import Portfolio
|
||
from tradingagents.portfolio.orders import Order, OrderType as PortfolioOrderType
|
||
|
||
# Test 2.1: Data structure compatibility
|
||
print("\n2.1: Testing broker and portfolio data structure compatibility...")
|
||
|
||
# Create broker order
|
||
broker_order = BrokerOrder(
|
||
symbol="AAPL",
|
||
side=OrderSide.BUY,
|
||
quantity=Decimal("10"),
|
||
order_type=OrderType.MARKET
|
||
)
|
||
print(f" ✓ Broker order created: {broker_order.symbol} {broker_order.side.value} {broker_order.quantity}")
|
||
|
||
# Create portfolio order
|
||
portfolio_order = Order(
|
||
symbol="AAPL",
|
||
order_type=PortfolioOrderType.MARKET,
|
||
quantity=10,
|
||
side="BUY"
|
||
)
|
||
print(f" ✓ Portfolio order created: {portfolio_order.symbol} {portfolio_order.side} {portfolio_order.quantity}")
|
||
|
||
# Test 2.2: Position tracking consistency
|
||
print("\n2.2: Testing position tracking...")
|
||
broker_position = BrokerPosition(
|
||
symbol="AAPL",
|
||
quantity=Decimal("10"),
|
||
avg_entry_price=Decimal("150.50"),
|
||
current_price=Decimal("155.25"),
|
||
market_value=Decimal("1552.50"),
|
||
unrealized_pnl=Decimal("47.50")
|
||
)
|
||
print(f" ✓ Broker position: {broker_position.symbol} @ ${broker_position.avg_entry_price}")
|
||
print(f" ✓ P&L tracking: ${broker_position.unrealized_pnl}")
|
||
|
||
# Test 2.3: Portfolio initialization
|
||
print("\n2.3: Testing portfolio initialization...")
|
||
portfolio = Portfolio(initial_cash=100000.0)
|
||
print(f" ✓ Portfolio created with ${portfolio.cash:,.2f} cash")
|
||
print(f" ✓ Total value: ${portfolio.total_value:,.2f}")
|
||
|
||
print("\n✓ Broker + Portfolio Integration: PASS")
|
||
return "PASS"
|
||
|
||
except Exception as e:
|
||
print(f"\n✗ Broker + Portfolio Integration: FAIL - {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return "FAIL"
|
||
|
||
|
||
def test_configuration_management():
|
||
"""Test 3: Configuration Management"""
|
||
print("\n" + "="*70)
|
||
print("INTEGRATION TEST 3: Configuration Management")
|
||
print("="*70)
|
||
|
||
try:
|
||
# Test 3.1: .env.example completeness
|
||
print("\n3.1: Testing .env.example completeness...")
|
||
env_example = Path("/home/user/TradingAgents/.env.example")
|
||
|
||
required_sections = [
|
||
"OPENAI_API_KEY",
|
||
"ANTHROPIC_API_KEY",
|
||
"ALPHA_VANTAGE_API_KEY",
|
||
"ALPACA_API_KEY",
|
||
"ALPACA_SECRET_KEY",
|
||
"LLM_PROVIDER",
|
||
]
|
||
|
||
with open(env_example, 'r') as f:
|
||
content = f.read()
|
||
found = 0
|
||
for section in required_sections:
|
||
if section in content:
|
||
found += 1
|
||
else:
|
||
print(f" ✗ Missing: {section}")
|
||
|
||
print(f" ✓ Found {found}/{len(required_sections)} required configuration variables")
|
||
|
||
# Test 3.2: Default configuration
|
||
print("\n3.2: Testing default configuration...")
|
||
from tradingagents.default_config import DEFAULT_CONFIG
|
||
|
||
required_keys = [
|
||
"llm_provider",
|
||
"deep_think_llm",
|
||
"quick_think_llm",
|
||
"max_debate_rounds",
|
||
"max_risk_discuss_rounds",
|
||
]
|
||
|
||
found_keys = 0
|
||
for key in required_keys:
|
||
if key in DEFAULT_CONFIG:
|
||
print(f" ✓ {key}: {DEFAULT_CONFIG[key]}")
|
||
found_keys += 1
|
||
else:
|
||
print(f" ✗ Missing: {key}")
|
||
|
||
# Test 3.3: Environment variable loading
|
||
print("\n3.3: Testing environment variable loading...")
|
||
from tradingagents.llm_factory import LLMFactory
|
||
|
||
env_vars = {
|
||
"OPENAI_API_KEY": os.getenv("OPENAI_API_KEY"),
|
||
"ANTHROPIC_API_KEY": os.getenv("ANTHROPIC_API_KEY"),
|
||
"ALPHA_VANTAGE_API_KEY": os.getenv("ALPHA_VANTAGE_API_KEY"),
|
||
}
|
||
|
||
configured = 0
|
||
for var, value in env_vars.items():
|
||
if value:
|
||
print(f" ✓ {var} is set")
|
||
configured += 1
|
||
else:
|
||
print(f" ⚠ {var} not set")
|
||
|
||
if configured == 0:
|
||
print(" ℹ No API keys configured - this is expected for fresh installations")
|
||
|
||
print("\n✓ Configuration Management: PASS")
|
||
return "PASS"
|
||
|
||
except Exception as e:
|
||
print(f"\n✗ Configuration Management: FAIL - {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return "FAIL"
|
||
|
||
|
||
def test_data_flow_integration():
|
||
"""Test 4: Data Flow Through System"""
|
||
print("\n" + "="*70)
|
||
print("INTEGRATION TEST 4: Data Flow Through System")
|
||
print("="*70)
|
||
|
||
try:
|
||
# Test 4.1: Signal flow
|
||
print("\n4.1: Testing signal processing flow...")
|
||
from tradingagents.graph.signal_processing import SignalProcessing
|
||
|
||
signal_processor = SignalProcessing()
|
||
test_signals = ["BUY", "SELL", "HOLD"]
|
||
|
||
for signal in test_signals:
|
||
result = signal_processor.process_signal(signal)
|
||
print(f" ✓ Signal '{signal}' processed to '{result}'")
|
||
|
||
# Test 4.2: Order flow
|
||
print("\n4.2: Testing order flow...")
|
||
from tradingagents.brokers.base import BrokerOrder, OrderSide, OrderType
|
||
|
||
order = BrokerOrder(
|
||
symbol="NVDA",
|
||
side=OrderSide.BUY,
|
||
quantity=Decimal("5"),
|
||
order_type=OrderType.MARKET
|
||
)
|
||
|
||
print(f" ✓ Order created: {order.symbol} {order.side.value} {order.quantity}")
|
||
print(f" ✓ Order type: {order.order_type.value}")
|
||
|
||
# Test 4.3: Portfolio update flow
|
||
print("\n4.3: Testing portfolio update flow...")
|
||
from tradingagents.portfolio import Portfolio
|
||
from tradingagents.portfolio.orders import Order as PortfolioOrder, OrderType as POrderType
|
||
|
||
portfolio = Portfolio(initial_cash=100000.0)
|
||
|
||
# Simulate order execution
|
||
test_order = PortfolioOrder(
|
||
symbol="NVDA",
|
||
order_type=POrderType.MARKET,
|
||
quantity=5,
|
||
side="BUY",
|
||
timestamp=None
|
||
)
|
||
|
||
print(f" ✓ Portfolio order created: {test_order.symbol} {test_order.side} {test_order.quantity}")
|
||
print(f" ✓ Initial cash: ${portfolio.cash:,.2f}")
|
||
|
||
print("\n✓ Data Flow Integration: PASS")
|
||
return "PASS"
|
||
|
||
except Exception as e:
|
||
print(f"\n✗ Data Flow Integration: FAIL - {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return "FAIL"
|
||
|
||
|
||
def test_web_app_components():
|
||
"""Test 5: Web App Component Integration"""
|
||
print("\n" + "="*70)
|
||
print("INTEGRATION TEST 5: Web App Component Integration")
|
||
print("="*70)
|
||
|
||
try:
|
||
# Test 5.1: Web app file structure
|
||
print("\n5.1: Testing web app file structure...")
|
||
web_app_path = Path("/home/user/TradingAgents/web_app.py")
|
||
|
||
if not web_app_path.exists():
|
||
print(" ✗ web_app.py not found")
|
||
return "FAIL"
|
||
|
||
with open(web_app_path, 'r') as f:
|
||
content = f.read()
|
||
|
||
# Check for required integrations
|
||
integrations = {
|
||
"chainlit": "Chainlit framework",
|
||
"TradingAgentsGraph": "TradingAgents integration",
|
||
"AlpacaBroker": "Broker integration",
|
||
"LLMFactory": "LLM factory integration",
|
||
}
|
||
|
||
for component, description in integrations.items():
|
||
if component in content:
|
||
print(f" ✓ {description} integrated")
|
||
else:
|
||
print(f" ⚠ {description} not found")
|
||
|
||
# Test 5.2: Configuration file
|
||
print("\n5.2: Testing Chainlit configuration...")
|
||
chainlit_config = Path("/home/user/TradingAgents/.chainlit")
|
||
|
||
if chainlit_config.exists():
|
||
print(" ✓ .chainlit configuration exists")
|
||
else:
|
||
print(" ⚠ .chainlit configuration not found")
|
||
|
||
print("\n✓ Web App Component Integration: PASS")
|
||
return "PASS"
|
||
|
||
except Exception as e:
|
||
print(f"\n✗ Web App Component Integration: FAIL - {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return "FAIL"
|
||
|
||
|
||
def test_docker_integration():
|
||
"""Test 6: Docker Integration"""
|
||
print("\n" + "="*70)
|
||
print("INTEGRATION TEST 6: Docker Integration")
|
||
print("="*70)
|
||
|
||
try:
|
||
# Test 6.1: Dockerfile validity
|
||
print("\n6.1: Testing Dockerfile...")
|
||
dockerfile = Path("/home/user/TradingAgents/Dockerfile")
|
||
|
||
if not dockerfile.exists():
|
||
print(" ✗ Dockerfile not found")
|
||
return "FAIL"
|
||
|
||
with open(dockerfile, 'r') as f:
|
||
content = f.read()
|
||
|
||
required_elements = {
|
||
"FROM python:": "Base image",
|
||
"WORKDIR": "Working directory",
|
||
"COPY requirements.txt": "Requirements file",
|
||
"pip install": "Package installation",
|
||
"EXPOSE 8000": "Port exposure",
|
||
"CMD": "Default command",
|
||
}
|
||
|
||
for element, description in required_elements.items():
|
||
if element in content:
|
||
print(f" ✓ {description}")
|
||
else:
|
||
print(f" ⚠ Missing: {description}")
|
||
|
||
# Test 6.2: Docker Compose
|
||
print("\n6.2: Testing docker-compose.yml...")
|
||
compose = Path("/home/user/TradingAgents/docker-compose.yml")
|
||
|
||
if not compose.exists():
|
||
print(" ✗ docker-compose.yml not found")
|
||
return "FAIL"
|
||
|
||
with open(compose, 'r') as f:
|
||
content = f.read()
|
||
|
||
compose_elements = {
|
||
"version:": "Compose version",
|
||
"services:": "Services definition",
|
||
"tradingagents:": "Main service",
|
||
"volumes:": "Volume mounts",
|
||
"environment:": "Environment variables",
|
||
"ports:": "Port mapping",
|
||
}
|
||
|
||
for element, description in compose_elements.items():
|
||
if element in content:
|
||
print(f" ✓ {description}")
|
||
else:
|
||
print(f" ⚠ Missing: {description}")
|
||
|
||
# Test 6.3: Docker documentation
|
||
print("\n6.3: Testing Docker documentation...")
|
||
docker_md = Path("/home/user/TradingAgents/DOCKER.md")
|
||
|
||
if docker_md.exists():
|
||
print(" ✓ DOCKER.md exists")
|
||
with open(docker_md, 'r') as f:
|
||
doc_content = f.read()
|
||
if "docker-compose up" in doc_content:
|
||
print(" ✓ Contains usage instructions")
|
||
else:
|
||
print(" ⚠ DOCKER.md not found")
|
||
|
||
print("\n✓ Docker Integration: PASS")
|
||
return "PASS"
|
||
|
||
except Exception as e:
|
||
print(f"\n✗ Docker Integration: FAIL - {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return "FAIL"
|
||
|
||
|
||
def main():
|
||
"""Run all integration tests"""
|
||
print("="*70)
|
||
print("TRADINGAGENTS COMPREHENSIVE INTEGRATION TESTING")
|
||
print("="*70)
|
||
print("\nThis test suite verifies that all new features integrate")
|
||
print("properly with existing TradingAgents functionality.")
|
||
print("\n" + "="*70)
|
||
|
||
results = []
|
||
|
||
# Run all integration tests
|
||
results.append(("LLM Factory + TradingAgents", test_llm_factory_tradingagents_integration()))
|
||
results.append(("Broker + Portfolio", test_broker_portfolio_integration()))
|
||
results.append(("Configuration Management", test_configuration_management()))
|
||
results.append(("Data Flow Integration", test_data_flow_integration()))
|
||
results.append(("Web App Components", test_web_app_components()))
|
||
results.append(("Docker Integration", test_docker_integration()))
|
||
|
||
# Summary
|
||
print("\n" + "="*70)
|
||
print("INTEGRATION TEST SUMMARY")
|
||
print("="*70)
|
||
|
||
passed = sum(1 for _, result in results if result == "PASS")
|
||
skipped = sum(1 for _, result in results if result == "SKIPPED")
|
||
failed = sum(1 for _, result in results if result == "FAIL")
|
||
total = len(results)
|
||
|
||
for name, result in results:
|
||
if result == "PASS":
|
||
print(f"✓ PASS: {name}")
|
||
elif result == "SKIPPED":
|
||
print(f"⚠ SKIPPED: {name}")
|
||
else:
|
||
print(f"✗ FAIL: {name}")
|
||
|
||
print(f"\nResults:")
|
||
print(f" Passed: {passed}/{total}")
|
||
print(f" Skipped: {skipped}/{total}")
|
||
print(f" Failed: {failed}/{total}")
|
||
print(f" Success Rate: {(passed/total)*100:.1f}%")
|
||
|
||
if failed == 0:
|
||
print("\n✓ All integration tests passed!")
|
||
if skipped > 0:
|
||
print(f" ({skipped} test(s) skipped due to missing configuration)")
|
||
return 0
|
||
else:
|
||
print(f"\n⚠ {failed} integration test(s) failed")
|
||
return 1
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|