Skip to content

Latest commit

 

History

History
876 lines (767 loc) · 40.7 KB

File metadata and controls

876 lines (767 loc) · 40.7 KB

Position Management System - Architecture Overview

📐 System Architecture

High-Level Architecture Diagram

┌─────────────────────────────────────────────────────────────────────────┐
│                           FRONTEND (React/TypeScript)                    │
│  ┌──────────────────┐  ┌──────────────────┐  ┌──────────────────┐     │
│  │  PositionsPage   │  │  Position Forms  │  │  CSV Upload UI   │     │
│  │   (UI Layer)     │  │  (Add/Edit)      │  │  (Import/Export) │     │
│  └────────┬─────────┘  └────────┬─────────┘  └────────┬─────────┘     │
│           │                     │                      │                │
│           └─────────────────────┴──────────────────────┘                │
│                                 │                                        │
│                    ┌────────────▼────────────┐                          │
│                    │   positionService.ts    │                          │
│                    │  (API Client Layer)     │                          │
│                    └────────────┬────────────┘                          │
└─────────────────────────────────┼─────────────────────────────────────┘
                                  │ HTTP/REST
                                  │
┌─────────────────────────────────▼─────────────────────────────────────┐
│                        BACKEND (FastAPI/Python)                        │
│                                                                         │
│  ┌──────────────────────────────────────────────────────────────┐    │
│  │                    API Layer (FastAPI)                        │    │
│  │  ┌────────────────────────────────────────────────────────┐  │    │
│  │  │              position_routes.py                         │  │    │
│  │  │  • POST /api/positions/stocks                          │  │    │
│  │  │  • GET  /api/positions/stocks                          │  │    │
│  │  │  • POST /api/positions/import/stocks                   │  │    │
│  │  │  • GET  /api/positions/export/stocks                   │  │    │
│  │  │  • GET  /api/positions/summary                         │  │    │
│  │  │  • POST /api/positions/enrich                          │  │    │
│  │  └────────────────────┬───────────────────────────────────┘  │    │
│  └───────────────────────┼──────────────────────────────────────┘    │
│                          │                                             │
│  ┌───────────────────────▼──────────────────────────────────────┐    │
│  │                  Service Layer                                │    │
│  │  ┌──────────────────┐  ┌──────────────────┐  ┌────────────┐ │    │
│  │  │ CSVPosition      │  │ Position         │  │ Position   │ │    │
│  │  │ Service          │  │ Enrichment       │  │ Context    │ │    │
│  │  │ (Import/Export)  │  │ Service          │  │ Service    │ │    │
│  │  │                  │  │ (Greeks/Metrics) │  │ (AI Agent) │ │    │
│  │  └────────┬─────────┘  └────────┬─────────┘  └─────┬──────┘ │    │
│  │           │                     │                   │         │    │
│  │           └─────────────────────┴───────────────────┘         │    │
│  │                                 │                              │    │
│  │                    ┌────────────▼────────────┐                │    │
│  │                    │   PositionManager       │                │    │
│  │                    │   (Core Storage)        │                │    │
│  │                    └────────────┬────────────┘                │    │
│  └─────────────────────────────────┼─────────────────────────────┘    │
│                                    │                                   │
│  ┌─────────────────────────────────▼─────────────────────────────┐   │
│  │              External Integrations                             │   │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────────┐   │   │
│  │  │  yfinance    │  │  Greeks      │  │  Black-Scholes   │   │   │
│  │  │  (Market     │  │  Calculator  │  │  (Option         │   │   │
│  │  │   Data)      │  │  (Greeks)    │  │   Pricing)       │   │   │
│  │  └──────────────┘  └──────────────┘  └──────────────────┘   │   │
│  └───────────────────────────────────────────────────────────────┘   │
│                                                                        │
│  ┌────────────────────────────────────────────────────────────────┐  │
│  │                    Data Persistence                             │  │
│  │  ┌──────────────────┐  ┌──────────────────────────────────┐   │  │
│  │  │ positions.json   │  │ conversation_memory.json         │   │  │
│  │  │ (Position Data)  │  │ (AI Conversation History)        │   │  │
│  │  └──────────────────┘  └──────────────────────────────────┘   │  │
│  └────────────────────────────────────────────────────────────────┘  │
│                                                                        │
│  ┌────────────────────────────────────────────────────────────────┐  │
│  │                    AI Agent Layer                               │  │
│  │  ┌──────────────────┐  ┌──────────────────────────────────┐   │  │
│  │  │ Recommendation   │  │ Multi-Agent System               │   │  │
│  │  │ Engine           │  │ (Technical, Fundamental,         │   │  │
│  │  │ (6 Scorers)      │  │  Sentiment, Risk, Earnings)      │   │  │
│  │  └──────────────────┘  └──────────────────────────────────┘   │  │
│  └────────────────────────────────────────────────────────────────┘  │
└────────────────────────────────────────────────────────────────────────┘

🔄 Data Flow Diagrams

1. CSV Import Flow

User Action: Upload CSV File
         │
         ▼
┌────────────────────┐
│  Frontend UI       │
│  (File Upload)     │
└─────────┬──────────┘
          │ FormData with file
          ▼
┌────────────────────────────────┐
│  API: POST /import/stocks      │
│  position_routes.py            │
└─────────┬──────────────────────┘
          │ CSV content (string)
          ▼
┌────────────────────────────────┐
│  CSVPositionService            │
│  • Parse CSV                   │
│  • Validate each row           │
│  • Check data types            │
└─────────┬──────────────────────┘
          │ Validated position data
          ▼
┌────────────────────────────────┐
│  PositionManager               │
│  • add_stock_position()        │
│  • add_option_position()       │
│  • save_positions()            │
└─────────┬──────────────────────┘
          │ Write to disk
          ▼
┌────────────────────────────────┐
│  data/positions.json           │
│  {                             │
│    "stocks": {...},            │
│    "options": {...}            │
│  }                             │
└─────────┬──────────────────────┘
          │ Trigger enrichment
          ▼
┌────────────────────────────────┐
│  PositionEnrichmentService     │
│  • Fetch real-time prices      │
│  • Calculate Greeks            │
│  • Compute P&L                 │
└─────────┬──────────────────────┘
          │ Enriched positions
          ▼
┌────────────────────────────────┐
│  Response to Frontend          │
│  {                             │
│    "success": 3,               │
│    "failed": 0,                │
│    "position_ids": [...]       │
│  }                             │
└────────────────────────────────┘

2. Position Enrichment Flow

Trigger: User clicks "Refresh Data" OR Auto-enrichment on create
         │
         ▼
┌────────────────────────────────┐
│  API: POST /positions/enrich   │
│  position_routes.py            │
└─────────┬──────────────────────┘
          │
          ▼
┌────────────────────────────────┐
│  PositionEnrichmentService     │
│  enrich_all_positions()        │
└─────────┬──────────────────────┘
          │
          ├─────────────────────────────────┐
          │                                 │
          ▼                                 ▼
┌──────────────────────┐        ┌──────────────────────┐
│  For Each Stock:     │        │  For Each Option:    │
│                      │        │                      │
│  1. Fetch from       │        │  1. Fetch from       │
│     yfinance         │        │     yfinance         │
│     ├─ Current price │        │     ├─ Underlying    │
│     ├─ PE ratio      │        │     ├─ Option chain  │
│     ├─ Dividend      │        │     ├─ IV            │
│     └─ Market cap    │        │     └─ Last price    │
│                      │        │                      │
│  2. Calculate        │        │  2. Calculate        │
│     ├─ P&L ($)       │        │     ├─ P&L ($)       │
│     ├─ P&L (%)       │        │     ├─ P&L (%)       │
│     └─ Status        │        │     ├─ Greeks (BS)   │
│                      │        │     ├─ Intrinsic val │
│                      │        │     ├─ Break-even    │
│                      │        │     └─ Risk level    │
└──────────┬───────────┘        └──────────┬───────────┘
           │                               │
           └───────────┬───────────────────┘
                       │
                       ▼
           ┌────────────────────────┐
           │  PositionManager       │
           │  save_positions()      │
           └────────────────────────┘
                       │
                       ▼
           ┌────────────────────────┐
           │  data/positions.json   │
           │  (Updated with         │
           │   enriched data)       │
           └────────────────────────┘

3. AI Agent Integration Flow

User Query: "Should I hold my AAPL calls?"
         │
         ▼
┌────────────────────────────────┐
│  Frontend / API Request        │
└─────────┬──────────────────────┘
          │
          ▼
┌────────────────────────────────┐
│  PositionContextService        │
│  create_agent_context()        │
└─────────┬──────────────────────┘
          │
          ├─────────────────────────────────┐
          │                                 │
          ▼                                 ▼
┌──────────────────────┐        ┌──────────────────────┐
│  Get Conversation    │        │  Get Position Data   │
│  History             │        │                      │
│  ├─ Last 10 messages │        │  ├─ Portfolio summary│
│  ├─ User queries     │        │  ├─ AAPL positions   │
│  └─ Agent responses  │        │  ├─ Enriched metrics │
│                      │        │  └─ Greeks, P&L      │
└──────────┬───────────┘        └──────────┬───────────┘
           │                               │
           └───────────┬───────────────────┘
                       │
                       ▼
           ┌────────────────────────┐
           │  Format Context        │
           │  for AI Agent          │
           │                        │
           │  # Recent Conversation │
           │  User: ...             │
           │                        │
           │  # Portfolio Summary   │
           │  Total Value: $X       │
           │                        │
           │  # AAPL Positions      │
           │  - Stock: 100 @ $150   │
           │  - Call: 20 @ $5.75    │
           │    Delta: 0.65         │
           │    Days: 36            │
           └────────────────────────┘
                       │
                       ▼
           ┌────────────────────────┐
           │  Pass to AI Agent      │
           │  (Recommendation       │
           │   Engine / Multi-Agent)│
           └────────────────────────┘
                       │
                       ▼
           ┌────────────────────────┐
           │  Agent analyzes with   │
           │  position context:     │
           │  • Current P&L         │
           │  • Greeks              │
           │  • Risk level          │
           │  • Days to expiry      │
           │  • Market conditions   │
           └────────────────────────┘
                       │
                       ▼
           ┌────────────────────────┐
           │  Agent Response        │
           │  "Based on your AAPL   │
           │   calls (Delta 0.65,   │
           │   36 days left), I     │
           │   recommend..."        │
           └────────────────────────┘
                       │
                       ▼
           ┌────────────────────────┐
           │  Log Interaction       │
           │  to Conversation       │
           │  Memory                │
           └────────────────────────┘

💻 Code Examples

Example 1: Complete CSV Import Flow

# 1. User uploads CSV file via frontend
# Frontend: positionService.ts
async importPositions(type: 'stocks' | 'options', file: File) {
    const formData = new FormData();
    formData.append('file', file);
    
    const response = await fetch(
        `${API_BASE_URL}/api/positions/import/${type}`,
        { method: 'POST', body: formData }
    );
    
    return response.json();
}

# 2. API receives request
# Backend: position_routes.py
@router.post("/import/stocks", response_model=CSVImportResponse)
async def import_stock_positions(
    file: UploadFile = File(...),
    replace_existing: bool = Query(False)
):
    # Read file content
    content = await file.read()
    csv_content = content.decode('utf-8')
    
    # Import positions
    results = csv_service.import_stock_positions(
        csv_content, 
        replace_existing
    )
    
    # Enrich imported positions
    if results['success'] > 0:
        enrichment_service.enrich_all_positions()
    
    return CSVImportResponse(**results)

# 3. CSV Service validates and imports
# Backend: csv_position_service.py
def import_stock_positions(self, csv_content: str, replace_existing: bool):
    results = {'success': 0, 'failed': 0, 'errors': [], 'position_ids': []}
    
    reader = csv.DictReader(io.StringIO(csv_content))
    
    for row_num, row in enumerate(reader, start=2):
        # Validate row
        is_valid, error_msg = self.validate_stock_row(row, row_num)
        if not is_valid:
            results['failed'] += 1
            results['errors'].append(error_msg)
            continue
        
        # Add position
        try:
            position_id = self.position_manager.add_stock_position(
                symbol=row['symbol'].upper(),
                quantity=int(row['quantity']),
                entry_price=float(row['entry_price']),
                # ... other fields
            )
            results['success'] += 1
            results['position_ids'].append(position_id)
        except Exception as e:
            results['failed'] += 1
            results['errors'].append(f"Row {row_num}: {str(e)}")
    
    return results

# 4. Position Manager stores data
# Backend: position_manager.py
def add_stock_position(self, symbol, quantity, entry_price, **kwargs):
    position_id = f"STK_{symbol}_{datetime.now().strftime('%Y%m%d%H%M%S')}"
    
    position = StockPosition(
        symbol=symbol.upper(),
        quantity=quantity,
        entry_price=entry_price,
        position_id=position_id,
        **kwargs
    )
    
    self.stock_positions[position_id] = position
    self.save_positions()  # Write to data/positions.json
    
    return position_id

Example 2: Position Enrichment with Greeks

# Backend: position_enrichment_service.py
def enrich_option_position(self, position: OptionPosition) -> OptionPosition:
    # 1. Get underlying stock data
    market_data = self.get_stock_data(position.symbol)
    underlying_price = market_data.get('current_price')
    hv = market_data.get('historical_volatility', 0.3)
    
    # 2. Get option chain data from yfinance
    option_data = self.get_option_chain_data(
        position.symbol,
        position.expiration_date,
        position.strike,
        position.option_type
    )
    
    # 3. If no option data, estimate using Black-Scholes
    if not option_data and underlying_price:
        bs_price = black_scholes.black_scholes_price(
            option_type=position.option_type,
            underlying_price=underlying_price,
            strike=position.strike,
            time_to_expiry=position.time_to_expiry(),
            volatility=hv,
            risk_free_rate=self.get_risk_free_rate()
        )
        option_data = {
            'last_price': bs_price,
            'implied_volatility': hv
        }
    
    # 4. Calculate metrics
    position.calculate_metrics(market_data, option_data)
    
    # 5. Calculate Greeks
    if position.implied_volatility and underlying_price:
        greeks = self.calculate_option_greeks(
            underlying_price=underlying_price,
            strike=position.strike,
            time_to_expiry=position.time_to_expiry(),
            volatility=position.implied_volatility,
            option_type=position.option_type
        )
        
        position.delta = greeks.get('delta')
        position.gamma = greeks.get('gamma')
        position.theta = greeks.get('theta')
        position.vega = greeks.get('vega')
        position.rho = greeks.get('rho')
    
    # 6. Calculate probability of profit
    if position.delta:
        if position.option_type.lower() == 'call':
            position.probability_of_profit = abs(position.delta) * 100
        else:
            position.probability_of_profit = (1 - abs(position.delta)) * 100
    
    return position

Example 3: AI Agent Accessing Position Context

# Backend: position_context_service.py
def create_agent_context(
    self,
    conversation_id: str,
    include_summary: bool = True,
    include_positions: bool = False,
    symbol: str = None
) -> str:
    context_parts = []
    
    # 1. Add conversation history
    recent_messages = self.conversation_memory.get_conversation(
        conversation_id, 
        limit=10
    )
    if recent_messages:
        context_parts.append("# Recent Conversation\n")
        for msg in recent_messages[-5:]:
            role = msg['role'].capitalize()
            content = msg['content'][:200]
            context_parts.append(f"**{role}**: {content}\n")
    
    # 2. Add portfolio summary
    if include_summary:
        summary = self.enrichment_service.get_enriched_portfolio_summary()
        context_parts.append(f"""
# Portfolio Summary

**Total Positions**: {summary['total_stocks']} stocks, {summary['total_options']} options
**Total Value**: ${summary.get('total_current_value', 0):,.2f}
**Total P&L**: ${summary.get('total_pnl', 0):,.2f} ({summary.get('total_pnl_pct', 0):.2f}%)
""")
    
    # 3. Add detailed positions
    if include_positions:
        if symbol:
            positions = self.position_manager.get_positions_by_symbol(symbol)
        else:
            positions = {
                'stocks': self.position_manager.get_all_stock_positions(),
                'options': self.position_manager.get_all_option_positions()
            }
        
        # Format positions for agent
        for pos in positions['options']:
            self.enrichment_service.enrich_option_position(pos)
            context_parts.append(f"""
### {pos.symbol} ${pos.strike} {pos.option_type.upper()}
- **P&L**: ${pos.unrealized_pnl:.2f} ({pos.unrealized_pnl_pct:.2f}%)
- **Delta**: {pos.delta:.3f}, **Theta**: {pos.theta:.3f}
- **Days to Expiry**: {pos.days_to_expiry()}
- **Risk Level**: {pos.get_risk_level()}
""")
    
    return "\n".join(context_parts)

# Usage in recommendation engine
from src.agents.position_context_service import PositionContextService

context_service = PositionContextService()

# Create context for agent
context = context_service.create_agent_context(
    conversation_id="user_123_session_1",
    include_summary=True,
    include_positions=True,
    symbol="AAPL"
)

# Pass to recommendation engine
recommendation = recommendation_engine.analyze_with_context(
    symbol="AAPL",
    context=context
)

# Log interaction
context_service.log_agent_interaction(
    conversation_id="user_123_session_1",
    user_query="Should I hold my AAPL calls?",
    agent_response=recommendation,
    positions_accessed=["OPT_AAPL_CALL_180_20251121"]
)

🔗 Component Integration Details

CSV Position Service ↔ Position Manager

# csv_position_service.py
class CSVPositionService:
    def __init__(self, position_manager: PositionManager):
        self.position_manager = position_manager  # Dependency injection
    
    def import_stock_positions(self, csv_content: str):
        # Validates CSV, then calls position_manager
        position_id = self.position_manager.add_stock_position(...)
        return results

Position Manager ↔ Position Enrichment Service

# position_enrichment_service.py
class PositionEnrichmentService:
    def __init__(self, position_manager: PositionManager):
        self.position_manager = position_manager
    
    def enrich_all_positions(self):
        # Gets positions from manager
        for position in self.position_manager.get_all_stock_positions():
            self.enrich_stock_position(position)
        
        # Saves back to manager
        self.position_manager.save_positions()

Position Context Service ↔ All Services

# position_context_service.py
class PositionContextService:
    def __init__(
        self,
        position_manager: PositionManager = None,
        enrichment_service: PositionEnrichmentService = None,
        conversation_memory: ConversationMemory = None
    ):
        self.position_manager = position_manager or PositionManager()
        self.enrichment_service = enrichment_service or \
            PositionEnrichmentService(self.position_manager)
        self.conversation_memory = conversation_memory or ConversationMemory()

API Routes ↔ All Services

# position_routes.py
from ..data.position_manager import PositionManager
from ..data.csv_position_service import CSVPositionService
from ..data.position_enrichment_service import PositionEnrichmentService

# Initialize services (singleton pattern)
position_manager = PositionManager()
csv_service = CSVPositionService(position_manager)
enrichment_service = PositionEnrichmentService(position_manager)

@router.post("/import/stocks")
async def import_stock_positions(file: UploadFile):
    # Uses csv_service
    results = csv_service.import_stock_positions(csv_content)
    
    # Uses enrichment_service
    if results['success'] > 0:
        enrichment_service.enrich_all_positions()
    
    return results

📊 API Request/Response Flow

Complete Request Trace: Import CSV

1. FRONTEND REQUEST
   ┌─────────────────────────────────────┐
   │ User clicks "Import CSV"            │
   │ Selects file: stock_positions.csv  │
   └─────────────────┬───────────────────┘
                     │
   ┌─────────────────▼───────────────────┐
   │ positionService.ts                  │
   │ importPositions('stocks', file)     │
   │                                     │
   │ FormData:                           │
   │   file: <File object>               │
   └─────────────────┬───────────────────┘
                     │ HTTP POST
                     │ multipart/form-data
2. API ENDPOINT      │
   ┌─────────────────▼───────────────────┐
   │ POST /api/positions/import/stocks   │
   │ position_routes.py                  │
   │                                     │
   │ async def import_stock_positions(   │
   │     file: UploadFile,               │
   │     replace_existing: bool = False  │
   │ )                                   │
   └─────────────────┬───────────────────┘
                     │
3. READ FILE         │
   ┌─────────────────▼───────────────────┐
   │ content = await file.read()         │
   │ csv_content = content.decode('utf-8')│
   │                                     │
   │ CSV Content:                        │
   │ "symbol,quantity,entry_price,...    │
   │  AAPL,100,150.50,..."               │
   └─────────────────┬───────────────────┘
                     │
4. CSV SERVICE       │
   ┌─────────────────▼───────────────────┐
   │ csv_service.import_stock_positions( │
   │     csv_content,                    │
   │     replace_existing                │
   │ )                                   │
   │                                     │
   │ • Parse CSV with csv.DictReader     │
   │ • Validate each row                 │
   │ • Check data types                  │
   └─────────────────┬───────────────────┘
                     │
5. POSITION MANAGER  │
   ┌─────────────────▼───────────────────┐
   │ For each valid row:                 │
   │ position_manager.add_stock_position(│
   │     symbol='AAPL',                  │
   │     quantity=100,                   │
   │     entry_price=150.50              │
   │ )                                   │
   │                                     │
   │ • Create StockPosition object       │
   │ • Generate position_id              │
   │ • Add to self.stock_positions dict  │
   └─────────────────┬───────────────────┘
                     │
6. SAVE TO DISK      │
   ┌─────────────────▼───────────────────┐
   │ position_manager.save_positions()   │
   │                                     │
   │ Write to: data/positions.json       │
   │ {                                   │
   │   "stocks": {                       │
   │     "STK_AAPL_20251016...": {       │
   │       "symbol": "AAPL",             │
   │       "quantity": 100,              │
   │       "entry_price": 150.50         │
   │     }                               │
   │   }                                 │
   │ }                                   │
   └─────────────────┬───────────────────┘
                     │
7. ENRICHMENT        │
   ┌─────────────────▼───────────────────┐
   │ enrichment_service.enrich_all_      │
   │ positions()                         │
   │                                     │
   │ For each position:                  │
   │ • Fetch from yfinance               │
   │ • Calculate Greeks                  │
   │ • Compute P&L                       │
   │ • Update position object            │
   │ • Save back to positions.json       │
   └─────────────────┬───────────────────┘
                     │
8. API RESPONSE      │
   ┌─────────────────▼───────────────────┐
   │ return CSVImportResponse(           │
   │     success=3,                      │
   │     failed=0,                       │
   │     errors=[],                      │
   │     position_ids=[                  │
   │         "STK_AAPL_...",             │
   │         "STK_NVDA_...",             │
   │         "STK_MSFT_..."              │
   │     ]                               │
   │ )                                   │
   └─────────────────┬───────────────────┘
                     │ HTTP 200 OK
                     │ application/json
9. FRONTEND RESPONSE │
   ┌─────────────────▼───────────────────┐
   │ positionService.ts receives:        │
   │ {                                   │
   │   success: 3,                       │
   │   failed: 0,                        │
   │   errors: [],                       │
   │   position_ids: [...]               │
   │ }                                   │
   └─────────────────┬───────────────────┘
                     │
10. UI UPDATE        │
   ┌─────────────────▼───────────────────┐
   │ PositionsPage.tsx                   │
   │ • Show success snackbar             │
   │ • Reload positions list             │
   │ • Update portfolio summary          │
   └─────────────────────────────────────┘

📁 File Dependencies

Module Import Graph

src/api/main.py
├── imports: src/api/position_routes.py
│   ├── imports: src/data/position_manager.py
│   ├── imports: src/data/csv_position_service.py
│   │   └── imports: src/data/position_manager.py
│   └── imports: src/data/position_enrichment_service.py
│       ├── imports: src/data/position_manager.py
│       ├── imports: src/analytics/greeks_calculator.py
│       └── imports: src/analytics/black_scholes.py
│
└── imports: src/agents/position_context_service.py
    ├── imports: src/data/position_manager.py
    └── imports: src/data/position_enrichment_service.py

frontend/src/pages/PositionsPage.tsx
└── imports: frontend/src/services/positionService.ts

Detailed Dependency Tree

# src/api/main.py
from .position_routes import router as position_router
app.include_router(position_router)

# src/api/position_routes.py
from ..data.position_manager import PositionManager
from ..data.csv_position_service import CSVPositionService
from ..data.position_enrichment_service import PositionEnrichmentService

# src/data/csv_position_service.py
from .position_manager import PositionManager, StockPosition, OptionPosition

# src/data/position_enrichment_service.py
from .position_manager import PositionManager, StockPosition, OptionPosition
from ..analytics.greeks_calculator import GreeksCalculator
from ..analytics import black_scholes

# src/agents/position_context_service.py
from ..data.position_manager import PositionManager
from ..data.position_enrichment_service import PositionEnrichmentService

🎯 Integration with Playwright (Browser Automation)

Note on Playwright Integration

The Position Management System is independent of Playwright. Playwright was used in the Chase integration attempt (which we moved away from), but the current system uses:

  1. yfinance for market data (not Playwright)
  2. FastAPI for API endpoints (not Playwright)
  3. React for frontend (not Playwright)
  4. CSV files for data import/export (not Playwright)

Playwright is NOT required for this system to work.

However, if you want to use Playwright for testing the frontend UI, here's how:

# test_ui_with_playwright.py
from playwright.sync_api import sync_playwright

def test_position_import_ui():
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        page = browser.new_page()
        
        # Navigate to positions page
        page.goto("http://localhost:3000/positions")
        
        # Click import button
        page.click('button:has-text("Import CSV")')
        
        # Upload file
        page.set_input_files('input[type="file"]', 'stock_positions.csv')
        
        # Click import
        page.click('button:has-text("Import")')
        
        # Wait for success message
        page.wait_for_selector('text=Successfully imported')
        
        browser.close()

🔄 Conversation Memory Flow

# Example: Multi-conversation tracking

# Session 1: User asks about AAPL
context_service.log_agent_interaction(
    conversation_id="user_123_session_1",
    user_query="What's my AAPL position?",
    agent_response="You have 100 shares at $150.50, up 65%",
    positions_accessed=["STK_AAPL_20251015120000"]
)

# Session 2: User asks follow-up (different day)
context = context_service.create_agent_context(
    conversation_id="user_123_session_1",  # Same conversation_id
    include_summary=True
)

# Context includes previous conversation:
# """
# # Recent Conversation
# **User**: What's my AAPL position?
# **Assistant**: You have 100 shares at $150.50, up 65%
# **User**: Should I sell now?
# """

# Agent has full context from previous session

Where to find results:

  • Architecture Diagram: See ASCII diagrams above
  • Data Flow: See flow diagrams for CSV import, enrichment, AI integration
  • Code Examples: See practical snippets for each integration point
  • API Flow: See complete request/response trace
  • Dependencies: See module import graph
  • Playwright Note: System works without Playwright (uses yfinance instead)