# TradingAgents: Medium-Term Enhancements (1-5 Days) **Strategic Features for Competitive Advantage** --- ## 🎯 MEDIUM-TERM ENHANCEMENTS ### 1. Real-Time Alert System **Value:** Proactive trading opportunities **Effort:** 2-3 days **Impact:** Game-changer for active traders **Use Cases:** - Price alerts (when NVDA hits $900) - Signal alerts (when TradingAgents recommends BUY) - Risk alerts (portfolio drops 5%) - News alerts (breaking news about held positions) **Implementation:** ```python # tradingagents/alerts/alert_system.py from enum import Enum from typing import Callable, List, Dict from dataclasses import dataclass from datetime import datetime import smtplib from twilio.rest import Client import asyncio class AlertType(Enum): PRICE = "price" SIGNAL = "signal" RISK = "risk" NEWS = "news" PORTFOLIO = "portfolio" class AlertChannel(Enum): EMAIL = "email" SMS = "sms" WEBHOOK = "webhook" PUSH = "push" TELEGRAM = "telegram" @dataclass class Alert: """Alert configuration.""" id: str type: AlertType condition: Callable channels: List[AlertChannel] message_template: str enabled: bool = True cooldown: int = 300 # seconds between alerts class AlertManager: """Manage trading alerts.""" def __init__(self, config: Dict): self.config = config self.alerts: Dict[str, Alert] = {} self.last_triggered: Dict[str, datetime] = {} def add_alert(self, alert: Alert): """Add new alert.""" self.alerts[alert.id] = alert async def check_alerts(self, context: Dict): """Check all alerts against current context.""" for alert_id, alert in self.alerts.items(): if not alert.enabled: continue # Check cooldown if self._is_in_cooldown(alert_id, alert.cooldown): continue # Evaluate condition try: if alert.condition(context): await self._trigger_alert(alert, context) self.last_triggered[alert_id] = datetime.now() except Exception as e: print(f"Error checking alert {alert_id}: {e}") def _is_in_cooldown(self, alert_id: str, cooldown: int) -> bool: """Check if alert is in cooldown period.""" if alert_id not in self.last_triggered: return False elapsed = (datetime.now() - self.last_triggered[alert_id]).total_seconds() return elapsed < cooldown async def _trigger_alert(self, alert: Alert, context: Dict): """Send alert through configured channels.""" message = alert.message_template.format(**context) tasks = [] for channel in alert.channels: if channel == AlertChannel.EMAIL: tasks.append(self._send_email(message)) elif channel == AlertChannel.SMS: tasks.append(self._send_sms(message)) elif channel == AlertChannel.WEBHOOK: tasks.append(self._send_webhook(message, context)) elif channel == AlertChannel.TELEGRAM: tasks.append(self._send_telegram(message)) await asyncio.gather(*tasks) async def _send_email(self, message: str): """Send email alert.""" smtp_server = self.config.get("smtp_server") from_email = self.config.get("from_email") to_email = self.config.get("alert_email") msg = f"Subject: TradingAgents Alert\n\n{message}" with smtplib.SMTP(smtp_server, 587) as server: server.starttls() server.login(from_email, self.config.get("email_password")) server.sendmail(from_email, to_email, msg) async def _send_sms(self, message: str): """Send SMS via Twilio.""" client = Client( self.config.get("twilio_account_sid"), self.config.get("twilio_auth_token") ) client.messages.create( body=message, from_=self.config.get("twilio_from_number"), to=self.config.get("alert_phone_number") ) async def _send_webhook(self, message: str, context: Dict): """Send webhook notification.""" import aiohttp webhook_url = self.config.get("webhook_url") async with aiohttp.ClientSession() as session: await session.post( webhook_url, json={ "message": message, "context": context, "timestamp": datetime.now().isoformat() } ) async def _send_telegram(self, message: str): """Send Telegram message.""" import aiohttp bot_token = self.config.get("telegram_bot_token") chat_id = self.config.get("telegram_chat_id") url = f"https://api.telegram.org/bot{bot_token}/sendMessage" async with aiohttp.ClientSession() as session: await session.post( url, json={"chat_id": chat_id, "text": message} ) # Example usage alert_manager = AlertManager(config) # Price alert price_alert = Alert( id="nvda_price_900", type=AlertType.PRICE, condition=lambda ctx: ctx["price"] >= 900, channels=[AlertChannel.EMAIL, AlertChannel.SMS], message_template="🚨 NVDA hit ${price}! Time to consider your position." ) # Signal alert signal_alert = Alert( id="buy_signal", type=AlertType.SIGNAL, condition=lambda ctx: ctx["signal"] == "BUY" and ctx["confidence"] > 0.8, channels=[AlertChannel.EMAIL, AlertChannel.TELEGRAM], message_template="💰 Strong BUY signal for {ticker}: {confidence:.0%} confidence" ) # Risk alert risk_alert = Alert( id="portfolio_drawdown", type=AlertType.RISK, condition=lambda ctx: ctx["drawdown"] > 0.05, channels=[AlertChannel.EMAIL, AlertChannel.SMS, AlertChannel.WEBHOOK], message_template="⚠️ Portfolio drawdown: {drawdown:.1%}. Review your positions!" ) alert_manager.add_alert(price_alert) alert_manager.add_alert(signal_alert) alert_manager.add_alert(risk_alert) # Check alerts continuously async def monitor_loop(): while True: context = { "price": get_current_price("NVDA"), "signal": get_latest_signal("NVDA"), "confidence": get_signal_confidence("NVDA"), "drawdown": get_portfolio_drawdown(), "ticker": "NVDA" } await alert_manager.check_alerts(context) await asyncio.sleep(60) # Check every minute ``` **Web UI Integration:** ```python # Add to web_app.py @cl.on_message async def main(message: cl.Message): # ... elif command == "alert": await setup_alert(parts) async def setup_alert(parts): """Setup a new alert.""" if len(parts) < 4: await cl.Message( content="Usage: `alert TICKER CONDITION VALUE`\n\n" "Examples:\n" "- `alert NVDA price 900` - Alert when NVDA hits $900\n" "- `alert AAPL buy 0.8` - Alert on BUY signal with 80%+ confidence\n" "- `alert portfolio drop 5` - Alert on 5% drawdown" ).send() return ticker = parts[1].upper() condition_type = parts[2].lower() threshold = float(parts[3]) # Create alert alert = create_alert(ticker, condition_type, threshold) alert_manager.add_alert(alert) await cl.Message( content=f"✅ Alert created!\n\n" f"**Ticker:** {ticker}\n" f"**Condition:** {condition_type} {threshold}\n" f"**Channels:** Email, Telegram\n\n" f"You'll be notified when this condition is met." ).send() ``` --- ### 2. Interactive Broker Integration **Value:** Access to professional trading **Effort:** 3-4 days **Impact:** Opens door to serious traders **Implementation:** ```python # tradingagents/brokers/ib_broker.py from ib_insync import IB, Stock, MarketOrder, LimitOrder from decimal import Decimal from .base import BaseBroker, BrokerOrder, BrokerPosition, BrokerAccount class InteractiveBrokersBroker(BaseBroker): """Interactive Brokers integration.""" def __init__( self, host: str = "127.0.0.1", port: int = 7497, # 7497 for paper, 7496 for live client_id: int = 1, paper_trading: bool = True ): super().__init__(paper_trading) self.host = host self.port = port self.client_id = client_id self.ib = IB() def connect(self) -> bool: """Connect to IB Gateway or TWS.""" try: self.ib.connect(self.host, self.port, clientId=self.client_id) self.connected = True return True except Exception as e: raise ConnectionError(f"Failed to connect to IB: {e}") def disconnect(self) -> None: """Disconnect from IB.""" self.ib.disconnect() self.connected = False def get_account(self) -> BrokerAccount: """Get account information.""" account_values = self.ib.accountValues() cash = Decimal(0) equity = Decimal(0) buying_power = Decimal(0) for value in account_values: if value.tag == "CashBalance": cash = Decimal(value.value) elif value.tag == "NetLiquidation": equity = Decimal(value.value) elif value.tag == "BuyingPower": buying_power = Decimal(value.value) return BrokerAccount( account_number=self.ib.wrapper.accounts[0], cash=cash, buying_power=buying_power, portfolio_value=equity, equity=equity, last_equity=equity, multiplier=Decimal("1"), ) def get_positions(self) -> List[BrokerPosition]: """Get all positions.""" positions = [] for position in self.ib.positions(): current_price = self._get_last_price(position.contract) positions.append(BrokerPosition( symbol=position.contract.symbol, quantity=Decimal(str(position.position)), avg_entry_price=Decimal(str(position.avgCost)), current_price=current_price, market_value=current_price * Decimal(str(position.position)), unrealized_pnl=Decimal(str(position.unrealizedPNL)), unrealized_pnl_percent=( Decimal(str(position.unrealizedPNL)) / Decimal(str(position.avgCost * position.position)) ), cost_basis=Decimal(str(position.avgCost * position.position)), )) return positions def submit_order(self, order: BrokerOrder) -> BrokerOrder: """Submit order to IB.""" contract = Stock(order.symbol, "SMART", "USD") if order.order_type == OrderType.MARKET: ib_order = MarketOrder( "BUY" if order.side == OrderSide.BUY else "SELL", float(order.quantity) ) elif order.order_type == OrderType.LIMIT: ib_order = LimitOrder( "BUY" if order.side == OrderSide.BUY else "SELL", float(order.quantity), float(order.limit_price) ) trade = self.ib.placeOrder(contract, ib_order) order.order_id = str(trade.order.orderId) order.status = self._convert_ib_status(trade.orderStatus.status) return order def _get_last_price(self, contract) -> Decimal: """Get last traded price.""" ticker = self.ib.reqTickers(contract)[0] return Decimal(str(ticker.last)) # Example usage ib_broker = InteractiveBrokersBroker( host="127.0.0.1", port=7497, # Paper trading paper_trading=True ) ib_broker.connect() account = ib_broker.get_account() print(f"IB Account: ${account.equity:,.2f}") ``` **Configuration:** ```python # .env.example # Interactive Brokers IB_HOST=127.0.0.1 IB_PORT=7497 # 7497 for paper, 7496 for live IB_CLIENT_ID=1 ``` --- ### 3. Advanced Charting System **Value:** Professional-grade visualization **Effort:** 3-4 days **Impact:** Traders love charts **Implementation using Plotly:** ```python # tradingagents/visualization/charts.py import plotly.graph_objects as go from plotly.subplots import make_subplots import pandas as pd class TradingCharts: """Advanced charting for TradingAgents.""" @staticmethod def create_candlestick_with_signals( df: pd.DataFrame, signals: pd.DataFrame, indicators: Dict = None ): """Create interactive candlestick chart with trading signals.""" fig = make_subplots( rows=3, cols=1, shared_xaxes=True, vertical_spacing=0.03, row_heights=[0.6, 0.2, 0.2], subplot_titles=('Price & Signals', 'Volume', 'Indicators') ) # Candlestick fig.add_trace( go.Candlestick( x=df.index, open=df['open'], high=df['high'], low=df['low'], close=df['close'], name='Price' ), row=1, col=1 ) # Buy signals buy_signals = signals[signals['action'] == 'buy'] fig.add_trace( go.Scatter( x=buy_signals.index, y=buy_signals['price'], mode='markers', marker=dict( symbol='triangle-up', size=15, color='green' ), name='Buy Signal' ), row=1, col=1 ) # Sell signals sell_signals = signals[signals['action'] == 'sell'] fig.add_trace( go.Scatter( x=sell_signals.index, y=sell_signals['price'], mode='markers', marker=dict( symbol='triangle-down', size=15, color='red' ), name='Sell Signal' ), row=1, col=1 ) # Moving averages if indicators and 'sma_20' in indicators: fig.add_trace( go.Scatter( x=df.index, y=indicators['sma_20'], name='SMA 20', line=dict(color='orange', width=1) ), row=1, col=1 ) if indicators and 'sma_50' in indicators: fig.add_trace( go.Scatter( x=df.index, y=indicators['sma_50'], name='SMA 50', line=dict(color='blue', width=1) ), row=1, col=1 ) # Volume colors = ['red' if close < open else 'green' for close, open in zip(df['close'], df['open'])] fig.add_trace( go.Bar( x=df.index, y=df['volume'], marker_color=colors, name='Volume', showlegend=False ), row=2, col=1 ) # RSI if indicators and 'rsi' in indicators: fig.add_trace( go.Scatter( x=df.index, y=indicators['rsi'], name='RSI', line=dict(color='purple') ), row=3, col=1 ) # RSI zones fig.add_hline(y=70, line_dash="dash", line_color="red", row=3, col=1) fig.add_hline(y=30, line_dash="dash", line_color="green", row=3, col=1) # Layout fig.update_layout( title='TradingAgents Analysis', xaxis_rangeslider_visible=False, height=800, hovermode='x unified', template='plotly_dark' ) fig.update_xaxes(title_text="Date", row=3, col=1) fig.update_yaxes(title_text="Price", row=1, col=1) fig.update_yaxes(title_text="Volume", row=2, col=1) fig.update_yaxes(title_text="RSI", row=3, col=1) return fig @staticmethod def create_portfolio_dashboard(portfolio_data: Dict): """Create comprehensive portfolio dashboard.""" fig = make_subplots( rows=2, cols=2, subplot_titles=( 'Portfolio Value Over Time', 'Position Allocation', 'P&L by Position', 'Win Rate Analysis' ), specs=[ [{"type": "scatter"}, {"type": "pie"}], [{"type": "bar"}, {"type": "bar"}] ] ) # Portfolio equity curve fig.add_trace( go.Scatter( x=portfolio_data['dates'], y=portfolio_data['equity'], mode='lines', name='Portfolio Value', fill='tozeroy' ), row=1, col=1 ) # Position allocation pie fig.add_trace( go.Pie( labels=portfolio_data['positions']['symbols'], values=portfolio_data['positions']['values'], name='Allocation' ), row=1, col=2 ) # P&L by position colors = ['green' if pnl > 0 else 'red' for pnl in portfolio_data['positions']['pnl']] fig.add_trace( go.Bar( x=portfolio_data['positions']['symbols'], y=portfolio_data['positions']['pnl'], marker_color=colors, name='P&L' ), row=2, col=1 ) # Win rate fig.add_trace( go.Bar( x=['Wins', 'Losses'], y=[ portfolio_data['wins'], portfolio_data['losses'] ], marker_color=['green', 'red'], name='Trades' ), row=2, col=2 ) fig.update_layout( height=800, showlegend=True, template='plotly_dark' ) return fig # Integration with web UI @cl.on_message async def main(message: cl.Message): # ... elif command == "chart": await show_chart(parts) async def show_chart(parts): """Show interactive chart.""" if len(parts) < 2: await cl.Message(content="Usage: `chart TICKER`").send() return ticker = parts[1].upper() # Fetch data df = get_stock_data(ticker, days=90) signals = get_trading_signals(ticker) indicators = calculate_indicators(df) # Create chart fig = TradingCharts.create_candlestick_with_signals( df, signals, indicators ) # Send to user await cl.Message( content=f"📊 Chart for {ticker}", elements=[cl.Plotly(name="chart", figure=fig)] ).send() ``` --- ### 4. Strategy Backtesting UI **Value:** Visual strategy optimization **Effort:** 2-3 days **Impact:** Makes backtesting accessible **Implementation:** ```python # Add to web_app.py @cl.on_message async def main(message: cl.Message): # ... elif command == "backtest": await run_backtest_ui(parts) async def run_backtest_ui(parts): """Interactive backtesting interface.""" if len(parts) < 4: await cl.Message( content="""# 📊 Backtest Your Strategy Usage: `backtest TICKER START_DATE END_DATE` Example: `backtest NVDA 2023-01-01 2024-01-01` This will: 1. Run TradingAgents on historical data 2. Show performance metrics 3. Generate interactive charts 4. Compare to buy-and-hold """ ).send() return ticker = parts[1].upper() start_date = parts[2] end_date = parts[3] # Show progress progress_msg = await cl.Message( content=f"🔄 Running backtest for {ticker}...\n\n" "This may take a few minutes." ).send() try: # Run backtest from tradingagents.backtest import backtest_trading_agents results = await asyncio.to_thread( backtest_trading_agents, trading_graph=ta_graph, tickers=[ticker], start_date=start_date, end_date=end_date, initial_capital=100000.0 ) # Create visualizations equity_fig = create_equity_curve(results) metrics_fig = create_metrics_dashboard(results) # Send results await cl.Message( content=f"""# 📊 Backtest Results: {ticker} ## Performance Summary **Period:** {start_date} to {end_date} ### Returns - **Total Return:** {results.total_return:.2%} - **Annualized:** {results.annualized_return:.2%} - **Benchmark (Buy & Hold):** {results.benchmark_return:.2%} - **Alpha:** {results.alpha:.2%} ### Risk Metrics - **Sharpe Ratio:** {results.sharpe_ratio:.2f} - **Max Drawdown:** {results.max_drawdown:.2%} - **Volatility:** {results.volatility:.2%} ### Trading Stats - **Total Trades:** {results.total_trades} - **Win Rate:** {results.win_rate:.1%} - **Profit Factor:** {results.profit_factor:.2f} - **Average Win:** ${results.avg_win:,.2f} - **Average Loss:** ${results.avg_loss:,.2f} ## Charts """, elements=[ cl.Plotly(name="equity", figure=equity_fig), cl.Plotly(name="metrics", figure=metrics_fig) ] ).send() # Offer to save await cl.Message( content="💾 Save this report? Type `save report {ticker}_backtest`" ).send() except Exception as e: await cl.Message( content=f"❌ Backtest failed: {str(e)}\n\n" "Check your date range and ticker symbol." ).send() ``` --- ### 5. Multi-Ticker Portfolio Mode **Value:** Diversification support **Effort:** 2-3 days **Impact:** Professional portfolio management **Implementation:** ```python # tradingagents/portfolio/multi_ticker.py from typing import List, Dict import asyncio from decimal import Decimal class MultiTickerPortfolio: """Manage multiple tickers simultaneously.""" def __init__( self, tickers: List[str], allocation: Dict[str, float] = None, rebalance_frequency: str = "monthly" ): self.tickers = tickers self.allocation = allocation or self._equal_weight() self.rebalance_frequency = rebalance_frequency def _equal_weight(self) -> Dict[str, float]: """Equal weight allocation.""" weight = 1.0 / len(self.tickers) return {ticker: weight for ticker in self.tickers} async def analyze_all(self, date: str) -> Dict[str, any]: """Analyze all tickers in parallel.""" tasks = [ self._analyze_ticker(ticker, date) for ticker in self.tickers ] results = await asyncio.gather(*tasks) return { ticker: result for ticker, result in zip(self.tickers, results) } async def _analyze_ticker(self, ticker: str, date: str): """Analyze single ticker.""" _, signal = await ta_graph.propagate_async(ticker, date) return signal def calculate_portfolio_signals( self, signals: Dict[str, str] ) -> Dict[str, Decimal]: """ Calculate position sizes based on signals and allocation. Returns: Dict mapping ticker to target quantity """ positions = {} for ticker, signal in signals.items(): target_allocation = self.allocation[ticker] if signal == "BUY": # Increase position to target allocation positions[ticker] = self._calculate_target_shares( ticker, target_allocation ) elif signal == "SELL": # Reduce position positions[ticker] = Decimal(0) elif signal == "HOLD": # Maintain current position positions[ticker] = self._get_current_position(ticker) return positions def rebalance(self, portfolio_value: Decimal): """Rebalance portfolio to target allocations.""" for ticker, target_pct in self.allocation.items(): target_value = portfolio_value * Decimal(str(target_pct)) current_value = self._get_position_value(ticker) difference = target_value - current_value if abs(difference) > portfolio_value * Decimal("0.05"): # 5% threshold # Need to rebalance shares_to_trade = difference / self._get_current_price(ticker) yield ticker, shares_to_trade # Usage in web UI @cl.on_message async def main(message: cl.Message): # ... elif command == "portfolio-analyze": await analyze_portfolio(parts) async def analyze_portfolio(parts): """Analyze entire portfolio.""" # Get user's portfolio tickers = ["NVDA", "AAPL", "MSFT", "GOOGL", "TSLA"] # From config await cl.Message( content=f"🔍 Analyzing portfolio: {', '.join(tickers)}\n\n" "This will take 2-3 minutes..." ).send() # Analyze all in parallel portfolio = MultiTickerPortfolio(tickers) signals = await portfolio.analyze_all(date="2024-05-10") # Format results result = "# 📊 Portfolio Analysis Results\n\n" for ticker, signal in signals.items(): emoji = "🟢" if signal == "BUY" else "🔴" if signal == "SELL" else "🟡" result += f"{emoji} **{ticker}**: {signal}\n" result += "\n## Recommendations\n\n" # Calculate suggested trades positions = portfolio.calculate_portfolio_signals(signals) for ticker, target_qty in positions.items(): current_qty = get_current_position(ticker) difference = target_qty - current_qty if difference > 0: result += f"- Buy {difference} shares of {ticker}\n" elif difference < 0: result += f"- Sell {abs(difference)} shares of {ticker}\n" await cl.Message(content=result).send() ``` --- ### 6. Decision History Database **Value:** Learn from past decisions **Effort:** 2-3 days **Impact:** Enables analysis and improvement **Implementation:** ```python # tradingagents/history/decision_db.py import sqlite3 from datetime import datetime from typing import Dict, List import json class DecisionDatabase: """Store and analyze trading decisions.""" def __init__(self, db_path: str = "tradingagents_decisions.db"): self.db_path = db_path self._init_db() def _init_db(self): """Initialize database schema.""" conn = sqlite3.connect(self.db_path) cursor = conn.cursor() cursor.execute(""" CREATE TABLE IF NOT EXISTS decisions ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp TEXT NOT NULL, ticker TEXT NOT NULL, date TEXT NOT NULL, signal TEXT NOT NULL, confidence REAL, market_price REAL, decision_data TEXT, analyst_reports TEXT, execution_price REAL, execution_time TEXT, outcome TEXT, pnl REAL, created_at TEXT DEFAULT CURRENT_TIMESTAMP ) """) cursor.execute(""" CREATE INDEX IF NOT EXISTS idx_ticker_date ON decisions(ticker, date) """) cursor.execute(""" CREATE INDEX IF NOT EXISTS idx_signal ON decisions(signal) """) conn.commit() conn.close() def record_decision( self, ticker: str, date: str, signal: str, confidence: float, market_price: float, decision_data: Dict, analyst_reports: Dict ) -> int: """Record a trading decision.""" conn = sqlite3.connect(self.db_path) cursor = conn.cursor() cursor.execute(""" INSERT INTO decisions ( timestamp, ticker, date, signal, confidence, market_price, decision_data, analyst_reports ) VALUES (?, ?, ?, ?, ?, ?, ?, ?) """, ( datetime.now().isoformat(), ticker, date, signal, confidence, market_price, json.dumps(decision_data), json.dumps(analyst_reports) )) decision_id = cursor.lastrowid conn.commit() conn.close() return decision_id def update_outcome( self, decision_id: int, execution_price: float, execution_time: str, outcome: str, pnl: float ): """Update decision outcome.""" conn = sqlite3.connect(self.db_path) cursor = conn.cursor() cursor.execute(""" UPDATE decisions SET execution_price = ?, execution_time = ?, outcome = ?, pnl = ? WHERE id = ? """, (execution_price, execution_time, outcome, pnl, decision_id)) conn.commit() conn.close() def get_decision_history( self, ticker: str = None, signal: str = None, limit: int = 100 ) -> List[Dict]: """Query decision history.""" conn = sqlite3.connect(self.db_path) conn.row_factory = sqlite3.Row cursor = conn.cursor() query = "SELECT * FROM decisions WHERE 1=1" params = [] if ticker: query += " AND ticker = ?" params.append(ticker) if signal: query += " AND signal = ?" params.append(signal) query += " ORDER BY timestamp DESC LIMIT ?" params.append(limit) cursor.execute(query, params) rows = cursor.fetchall() conn.close() return [dict(row) for row in rows] def analyze_performance(self, ticker: str = None) -> Dict: """Analyze decision performance.""" conn = sqlite3.connect(self.db_path) cursor = conn.cursor() query = """ SELECT signal, COUNT(*) as total, AVG(confidence) as avg_confidence, SUM(CASE WHEN outcome = 'win' THEN 1 ELSE 0 END) as wins, SUM(CASE WHEN outcome = 'loss' THEN 1 ELSE 0 END) as losses, AVG(pnl) as avg_pnl, SUM(pnl) as total_pnl FROM decisions WHERE outcome IS NOT NULL """ if ticker: query += " AND ticker = ?" cursor.execute(query + " GROUP BY signal", (ticker,)) else: cursor.execute(query + " GROUP BY signal") results = cursor.fetchall() conn.close() analysis = {} for row in results: signal = row[0] analysis[signal] = { "total": row[1], "avg_confidence": row[2], "wins": row[3], "losses": row[4], "win_rate": row[3] / row[1] if row[1] > 0 else 0, "avg_pnl": row[5], "total_pnl": row[6] } return analysis # Integration decision_db = DecisionDatabase() # After analysis decision_id = decision_db.record_decision( ticker="NVDA", date="2024-05-10", signal="BUY", confidence=0.85, market_price=880.50, decision_data=final_state, analyst_reports={ "fundamentals": fundamentals_report, "news": news_report, "technical": technical_report } ) # After trade execution decision_db.update_outcome( decision_id=decision_id, execution_price=881.25, execution_time="2024-05-10T10:30:00", outcome="win", # or "loss" pnl=245.00 ) # Analyze performance performance = decision_db.analyze_performance(ticker="NVDA") print(f"NVDA BUY signals win rate: {performance['BUY']['win_rate']:.1%}") ``` --- *Continued in STRATEGIC_INITIATIVES.md →*