Spaces:
Running
on
Zero
feat: initial project setup with dependencies and core infrastructure
Browse filesSet up Portfolio Intelligence Platform with complete dependency management and core modules:
- Configure pyproject.toml with research-validated dependencies
- pydantic-ai v1.18.0 with native prompt caching
- fastmcp v2.13.0+ for MCP orchestration
- pyportfolioopt v1.5.6 (correct package name)
- quantitative finance libraries (riskfolio-lib, arch, xgboost, quantstats)
- All packages verified for Python 3.13 compatibility
- Create Gradio interface (app.py)
- Portfolio input with example portfolios
- Analysis output placeholder
- Clean, minimal UI ready for MCP integration
- Implement backend infrastructure
- config.py: Pydantic Settings for environment configuration
- database.py: Supabase PostgreSQL connection manager with demo mode
- mcp_router.py: MCP orchestration layer for 6 P0 servers
(Yahoo Finance, FMP, Trading-MCP, FRED, Portfolio Optimizer, Risk Analyzer)
- Establish project structure
- backend/agents/ for Pydantic AI agents
- backend/models/ for quantitative models
- backend/mcp_servers/ for custom MCP implementations
- tests/ directory for testing
All 270 packages installed successfully with uv sync
- app.py +89 -0
- backend/__init__.py +0 -0
- backend/agents/__init__.py +0 -0
- backend/config.py +70 -0
- backend/database.py +71 -0
- backend/mcp_router.py +130 -0
- backend/mcp_servers/__init__.py +0 -0
- backend/models/__init__.py +0 -0
- pyproject.toml +64 -2
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Portfolio Intelligence Platform - Gradio Interface.
|
| 2 |
+
|
| 3 |
+
Main application file for the hackathon demo.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import gradio as gr
|
| 7 |
+
from typing import List, Tuple
|
| 8 |
+
import os
|
| 9 |
+
from dotenv import load_dotenv
|
| 10 |
+
|
| 11 |
+
load_dotenv()
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def analyse_portfolio(portfolio_input: str) -> str:
|
| 15 |
+
"""Analyse portfolio and return AI insights.
|
| 16 |
+
|
| 17 |
+
Args:
|
| 18 |
+
portfolio_input: Portfolio holdings as text (e.g., "AAPL 50\nTSLA 25 shares")
|
| 19 |
+
|
| 20 |
+
Returns:
|
| 21 |
+
Analysis results with insights and recommendations
|
| 22 |
+
"""
|
| 23 |
+
# TODO: Integrate with MCP router and agents
|
| 24 |
+
return f"Analysis placeholder for:\n{portfolio_input}"
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def create_interface() -> gr.Blocks:
|
| 28 |
+
"""Create the main Gradio interface.
|
| 29 |
+
|
| 30 |
+
Returns:
|
| 31 |
+
Gradio Blocks interface
|
| 32 |
+
"""
|
| 33 |
+
with gr.Blocks(
|
| 34 |
+
title="Portfolio Intelligence Platform",
|
| 35 |
+
theme=gr.themes.Soft(),
|
| 36 |
+
fill_height=True
|
| 37 |
+
) as demo:
|
| 38 |
+
gr.Markdown("# 📊 Portfolio Intelligence Platform")
|
| 39 |
+
gr.Markdown("AI-powered portfolio analysis using MCP orchestration")
|
| 40 |
+
|
| 41 |
+
with gr.Row():
|
| 42 |
+
with gr.Column(scale=1):
|
| 43 |
+
gr.Markdown("## Enter Your Portfolio")
|
| 44 |
+
|
| 45 |
+
portfolio_input = gr.Textbox(
|
| 46 |
+
label="Portfolio Holdings",
|
| 47 |
+
placeholder="AAPL 50\nTSLA 25 shares\nNVDA $5000\nBTC 0.5",
|
| 48 |
+
lines=10,
|
| 49 |
+
info="Enter one holding per line"
|
| 50 |
+
)
|
| 51 |
+
|
| 52 |
+
analyse_btn = gr.Button("Analyse Portfolio", variant="primary")
|
| 53 |
+
|
| 54 |
+
# Example portfolios
|
| 55 |
+
gr.Examples(
|
| 56 |
+
examples=[
|
| 57 |
+
["AAPL 50\nTSLA 25 shares\nNVDA $5000\nBTC 0.5"],
|
| 58 |
+
["VOO 100 shares\nVTI 75 shares\nSCHD 50 shares"],
|
| 59 |
+
["VTI $25000\nVXUS $15000\nBND $15000\nGLD $5000"],
|
| 60 |
+
],
|
| 61 |
+
inputs=portfolio_input,
|
| 62 |
+
label="Example Portfolios"
|
| 63 |
+
)
|
| 64 |
+
|
| 65 |
+
with gr.Column(scale=2):
|
| 66 |
+
gr.Markdown("## Analysis Results")
|
| 67 |
+
|
| 68 |
+
output = gr.Markdown(
|
| 69 |
+
value="Enter your portfolio and click 'Analyse Portfolio' to get started.",
|
| 70 |
+
label="AI Insights"
|
| 71 |
+
)
|
| 72 |
+
|
| 73 |
+
# Event handlers
|
| 74 |
+
analyse_btn.click(
|
| 75 |
+
fn=analyse_portfolio,
|
| 76 |
+
inputs=portfolio_input,
|
| 77 |
+
outputs=output
|
| 78 |
+
)
|
| 79 |
+
|
| 80 |
+
return demo
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
if __name__ == "__main__":
|
| 84 |
+
demo = create_interface()
|
| 85 |
+
demo.launch(
|
| 86 |
+
server_name="0.0.0.0",
|
| 87 |
+
server_port=7860,
|
| 88 |
+
share=False
|
| 89 |
+
)
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Configuration module for Portfolio Intelligence Platform.
|
| 2 |
+
|
| 3 |
+
Loads environment variables and provides configuration settings.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import os
|
| 7 |
+
from typing import Optional
|
| 8 |
+
from pydantic import Field
|
| 9 |
+
from pydantic_settings import BaseSettings
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
class Settings(BaseSettings):
|
| 13 |
+
"""Application settings loaded from environment variables.
|
| 14 |
+
|
| 15 |
+
Attributes:
|
| 16 |
+
anthropic_api_key: Anthropic API key for Claude
|
| 17 |
+
supabase_url: Supabase project URL
|
| 18 |
+
supabase_key: Supabase anon key
|
| 19 |
+
fmp_api_key: Financial Modeling Prep API key
|
| 20 |
+
fred_api_key: FRED (Federal Reserve Economic Data) API key
|
| 21 |
+
environment: Application environment (development/production)
|
| 22 |
+
log_level: Logging level
|
| 23 |
+
"""
|
| 24 |
+
|
| 25 |
+
# AI/LLM Configuration
|
| 26 |
+
anthropic_api_key: str = Field(
|
| 27 |
+
default="",
|
| 28 |
+
validation_alias="ANTHROPIC_API_KEY"
|
| 29 |
+
)
|
| 30 |
+
|
| 31 |
+
# Database Configuration
|
| 32 |
+
supabase_url: Optional[str] = Field(
|
| 33 |
+
default=None,
|
| 34 |
+
validation_alias="SUPABASE_URL"
|
| 35 |
+
)
|
| 36 |
+
supabase_key: Optional[str] = Field(
|
| 37 |
+
default=None,
|
| 38 |
+
validation_alias="SUPABASE_KEY"
|
| 39 |
+
)
|
| 40 |
+
|
| 41 |
+
# Financial Data APIs
|
| 42 |
+
fmp_api_key: Optional[str] = Field(
|
| 43 |
+
default=None,
|
| 44 |
+
validation_alias="FMP_API_KEY"
|
| 45 |
+
)
|
| 46 |
+
fred_api_key: Optional[str] = Field(
|
| 47 |
+
default=None,
|
| 48 |
+
validation_alias="FRED_API_KEY"
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
# Application Settings
|
| 52 |
+
environment: str = Field(
|
| 53 |
+
default="development",
|
| 54 |
+
validation_alias="ENVIRONMENT"
|
| 55 |
+
)
|
| 56 |
+
log_level: str = Field(
|
| 57 |
+
default="INFO",
|
| 58 |
+
validation_alias="LOG_LEVEL"
|
| 59 |
+
)
|
| 60 |
+
|
| 61 |
+
class Config:
|
| 62 |
+
"""Pydantic config."""
|
| 63 |
+
|
| 64 |
+
env_file = ".env"
|
| 65 |
+
env_file_encoding = "utf-8"
|
| 66 |
+
case_sensitive = False
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
# Global settings instance
|
| 70 |
+
settings = Settings()
|
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Database module for Portfolio Intelligence Platform.
|
| 2 |
+
|
| 3 |
+
Handles Supabase PostgreSQL connections and operations.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
from typing import Optional
|
| 7 |
+
from supabase import create_client, Client
|
| 8 |
+
from backend.config import settings
|
| 9 |
+
import logging
|
| 10 |
+
|
| 11 |
+
logger = logging.getLogger(__name__)
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
class Database:
|
| 15 |
+
"""Database connection manager for Supabase PostgreSQL.
|
| 16 |
+
|
| 17 |
+
Attributes:
|
| 18 |
+
client: Supabase client instance
|
| 19 |
+
"""
|
| 20 |
+
|
| 21 |
+
def __init__(self):
|
| 22 |
+
"""Initialise database connection."""
|
| 23 |
+
self.client: Optional[Client] = None
|
| 24 |
+
|
| 25 |
+
if settings.supabase_url and settings.supabase_key:
|
| 26 |
+
try:
|
| 27 |
+
self.client = create_client(
|
| 28 |
+
settings.supabase_url,
|
| 29 |
+
settings.supabase_key
|
| 30 |
+
)
|
| 31 |
+
logger.info("Supabase client initialised successfully")
|
| 32 |
+
except Exception as e:
|
| 33 |
+
logger.warning(f"Failed to initialise Supabase client: {e}")
|
| 34 |
+
logger.info("Running in demo mode without database")
|
| 35 |
+
else:
|
| 36 |
+
logger.info("Supabase credentials not configured - running in demo mode")
|
| 37 |
+
|
| 38 |
+
def is_connected(self) -> bool:
|
| 39 |
+
"""Check if database connection is active.
|
| 40 |
+
|
| 41 |
+
Returns:
|
| 42 |
+
True if connected, False otherwise
|
| 43 |
+
"""
|
| 44 |
+
return self.client is not None
|
| 45 |
+
|
| 46 |
+
async def save_analysis(self, user_id: str, portfolio_data: dict, analysis_result: dict) -> bool:
|
| 47 |
+
"""Save portfolio analysis to database.
|
| 48 |
+
|
| 49 |
+
Args:
|
| 50 |
+
user_id: User identifier
|
| 51 |
+
portfolio_data: Portfolio holdings data
|
| 52 |
+
analysis_result: Analysis results from AI agents
|
| 53 |
+
|
| 54 |
+
Returns:
|
| 55 |
+
True if saved successfully, False otherwise
|
| 56 |
+
"""
|
| 57 |
+
if not self.is_connected():
|
| 58 |
+
logger.warning("Database not connected - skipping save")
|
| 59 |
+
return False
|
| 60 |
+
|
| 61 |
+
try:
|
| 62 |
+
# TODO: Implement actual database schema and insert logic
|
| 63 |
+
logger.info(f"Saving analysis for user {user_id}")
|
| 64 |
+
return True
|
| 65 |
+
except Exception as e:
|
| 66 |
+
logger.error(f"Failed to save analysis: {e}")
|
| 67 |
+
return False
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
# Global database instance
|
| 71 |
+
db = Database()
|
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""MCP Router for Portfolio Intelligence Platform.
|
| 2 |
+
|
| 3 |
+
Orchestrates MCP servers for financial data and quantitative analysis.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
from typing import Dict, List, Any, Optional
|
| 7 |
+
from fastmcp import FastMCP
|
| 8 |
+
import logging
|
| 9 |
+
|
| 10 |
+
logger = logging.getLogger(__name__)
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
class MCPRouter:
|
| 14 |
+
"""Router for orchestrating multiple MCP servers.
|
| 15 |
+
|
| 16 |
+
Manages connections to:
|
| 17 |
+
- P0 (Week 1): Yahoo Finance, FMP, Trading-MCP, FRED, Portfolio Optimizer, Risk Analyzer
|
| 18 |
+
- P1 (Week 2): Ensemble Predictor (if time permits)
|
| 19 |
+
"""
|
| 20 |
+
|
| 21 |
+
def __init__(self):
|
| 22 |
+
"""Initialise MCP router with configured servers."""
|
| 23 |
+
self.servers: Dict[str, Any] = {}
|
| 24 |
+
self._initialise_servers()
|
| 25 |
+
|
| 26 |
+
def _initialise_servers(self):
|
| 27 |
+
"""Initialise connections to MCP servers."""
|
| 28 |
+
# TODO: Implement actual MCP server connections
|
| 29 |
+
logger.info("Initialising MCP servers")
|
| 30 |
+
|
| 31 |
+
# Placeholder for P0 MCP servers
|
| 32 |
+
self.servers = {
|
| 33 |
+
"yahoo_finance": None, # Real-time pricing, historical data
|
| 34 |
+
"fmp": None, # Financial Modeling Prep - fundamentals
|
| 35 |
+
"trading_mcp": None, # Technical indicators (RSI, MACD, etc.)
|
| 36 |
+
"fred": None, # Macroeconomic data (GDP, unemployment, inflation)
|
| 37 |
+
"portfolio_optimizer": None, # HRP, Black-Litterman, Mean-Variance
|
| 38 |
+
"risk_analyzer": None, # VaR/CVaR calculations
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
logger.info(f"Initialised {len(self.servers)} MCP servers")
|
| 42 |
+
|
| 43 |
+
async def fetch_market_data(self, tickers: List[str]) -> Dict[str, Any]:
|
| 44 |
+
"""Fetch market data for given tickers.
|
| 45 |
+
|
| 46 |
+
Args:
|
| 47 |
+
tickers: List of stock/asset tickers
|
| 48 |
+
|
| 49 |
+
Returns:
|
| 50 |
+
Market data from Yahoo Finance and other sources
|
| 51 |
+
"""
|
| 52 |
+
# TODO: Implement actual MCP calls
|
| 53 |
+
logger.info(f"Fetching market data for {len(tickers)} tickers")
|
| 54 |
+
return {"status": "placeholder", "tickers": tickers}
|
| 55 |
+
|
| 56 |
+
async def fetch_fundamentals(self, tickers: List[str]) -> Dict[str, Any]:
|
| 57 |
+
"""Fetch fundamental data from Financial Modeling Prep.
|
| 58 |
+
|
| 59 |
+
Args:
|
| 60 |
+
tickers: List of stock tickers
|
| 61 |
+
|
| 62 |
+
Returns:
|
| 63 |
+
Fundamental data (P/E, margins, revenue, etc.)
|
| 64 |
+
"""
|
| 65 |
+
# TODO: Implement FMP MCP integration
|
| 66 |
+
logger.info(f"Fetching fundamentals for {len(tickers)} tickers")
|
| 67 |
+
return {"status": "placeholder", "tickers": tickers}
|
| 68 |
+
|
| 69 |
+
async def fetch_technical_indicators(self, tickers: List[str]) -> Dict[str, Any]:
|
| 70 |
+
"""Fetch technical indicators from Trading-MCP.
|
| 71 |
+
|
| 72 |
+
Args:
|
| 73 |
+
tickers: List of stock tickers
|
| 74 |
+
|
| 75 |
+
Returns:
|
| 76 |
+
Technical indicators (RSI, MACD, Bollinger Bands, etc.)
|
| 77 |
+
"""
|
| 78 |
+
# TODO: Implement Trading-MCP integration
|
| 79 |
+
logger.info(f"Fetching technical indicators for {len(tickers)} tickers")
|
| 80 |
+
return {"status": "placeholder", "tickers": tickers}
|
| 81 |
+
|
| 82 |
+
async def fetch_macro_data(self) -> Dict[str, Any]:
|
| 83 |
+
"""Fetch macroeconomic data from FRED.
|
| 84 |
+
|
| 85 |
+
Returns:
|
| 86 |
+
Macroeconomic indicators (GDP, unemployment, inflation, etc.)
|
| 87 |
+
"""
|
| 88 |
+
# TODO: Implement FRED MCP integration
|
| 89 |
+
logger.info("Fetching macroeconomic data")
|
| 90 |
+
return {"status": "placeholder"}
|
| 91 |
+
|
| 92 |
+
async def optimize_portfolio(
|
| 93 |
+
self,
|
| 94 |
+
historical_prices: Dict[str, List[float]],
|
| 95 |
+
risk_tolerance: str
|
| 96 |
+
) -> Dict[str, Any]:
|
| 97 |
+
"""Optimise portfolio allocation using quantitative models.
|
| 98 |
+
|
| 99 |
+
Args:
|
| 100 |
+
historical_prices: Historical price data for assets
|
| 101 |
+
risk_tolerance: User's risk tolerance (Conservative/Moderate/Aggressive)
|
| 102 |
+
|
| 103 |
+
Returns:
|
| 104 |
+
Optimised portfolio weights and metrics
|
| 105 |
+
"""
|
| 106 |
+
# TODO: Implement Portfolio Optimizer MCP
|
| 107 |
+
logger.info(f"Optimising portfolio with {risk_tolerance} risk tolerance")
|
| 108 |
+
return {"status": "placeholder", "method": "HRP + Black-Litterman"}
|
| 109 |
+
|
| 110 |
+
async def calculate_risk_metrics(
|
| 111 |
+
self,
|
| 112 |
+
historical_prices: Dict[str, List[float]],
|
| 113 |
+
portfolio_weights: Dict[str, float]
|
| 114 |
+
) -> Dict[str, Any]:
|
| 115 |
+
"""Calculate risk metrics for portfolio.
|
| 116 |
+
|
| 117 |
+
Args:
|
| 118 |
+
historical_prices: Historical price data
|
| 119 |
+
portfolio_weights: Current portfolio allocation
|
| 120 |
+
|
| 121 |
+
Returns:
|
| 122 |
+
Risk metrics (VaR, CVaR, volatility, etc.)
|
| 123 |
+
"""
|
| 124 |
+
# TODO: Implement Risk Analyzer MCP
|
| 125 |
+
logger.info("Calculating risk metrics")
|
| 126 |
+
return {"status": "placeholder", "metrics": ["VaR", "CVaR", "Volatility"]}
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
# Global MCP router instance
|
| 130 |
+
mcp_router = MCPRouter()
|
|
File without changes
|
|
File without changes
|
|
@@ -1,7 +1,69 @@
|
|
| 1 |
[project]
|
| 2 |
name = "portfolio-intelligence-platform"
|
| 3 |
version = "0.1.0"
|
| 4 |
-
description = "
|
| 5 |
readme = "README.md"
|
| 6 |
requires-python = ">=3.12"
|
| 7 |
-
dependencies = [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
[project]
|
| 2 |
name = "portfolio-intelligence-platform"
|
| 3 |
version = "0.1.0"
|
| 4 |
+
description = "AI-powered portfolio analysis platform with MCP orchestration"
|
| 5 |
readme = "README.md"
|
| 6 |
requires-python = ">=3.12"
|
| 7 |
+
dependencies = [
|
| 8 |
+
# AI Framework
|
| 9 |
+
"pydantic-ai==1.18.0",
|
| 10 |
+
"anthropic>=0.39.0",
|
| 11 |
+
"instructor>=1.6.4",
|
| 12 |
+
|
| 13 |
+
# Agent Orchestration
|
| 14 |
+
"langgraph>=0.1.0",
|
| 15 |
+
|
| 16 |
+
# MCP Framework
|
| 17 |
+
"fastmcp==2.13.0",
|
| 18 |
+
"mcp>=1.0.0",
|
| 19 |
+
|
| 20 |
+
# Frontend
|
| 21 |
+
"gradio==5.49.1",
|
| 22 |
+
|
| 23 |
+
# Backend
|
| 24 |
+
"fastapi>=0.104.0",
|
| 25 |
+
"uvicorn[standard]>=0.24.0",
|
| 26 |
+
"pydantic>=2.5.0",
|
| 27 |
+
|
| 28 |
+
# Database
|
| 29 |
+
"supabase>=2.9.0",
|
| 30 |
+
"psycopg2-binary>=2.9.9",
|
| 31 |
+
|
| 32 |
+
# Quantitative Finance (P0 - Deterministic Models)
|
| 33 |
+
# Research validated: Package name is 'pyportfolioopt', import as 'pypfopt'
|
| 34 |
+
"pyportfolioopt>=1.5.6",
|
| 35 |
+
"riskfolio-lib>=7.0.0",
|
| 36 |
+
"arch>=8.0.0",
|
| 37 |
+
"quantstats>=0.0.77",
|
| 38 |
+
|
| 39 |
+
# Data & Analysis
|
| 40 |
+
"pandas>=2.2.3",
|
| 41 |
+
"numpy>=2.0.0",
|
| 42 |
+
"yfinance>=0.2.40",
|
| 43 |
+
"scipy>=1.11.0",
|
| 44 |
+
|
| 45 |
+
# ML Models (P1 - Optional)
|
| 46 |
+
"torch>=2.0.0",
|
| 47 |
+
"xgboost>=3.1.0",
|
| 48 |
+
|
| 49 |
+
# Utilities
|
| 50 |
+
"python-dotenv>=1.0.0",
|
| 51 |
+
"httpx>=0.25.0",
|
| 52 |
+
"tenacity>=8.2.0",
|
| 53 |
+
]
|
| 54 |
+
|
| 55 |
+
[tool.uv]
|
| 56 |
+
dev-dependencies = [
|
| 57 |
+
"pytest>=7.4.0",
|
| 58 |
+
"pytest-asyncio>=0.21.0",
|
| 59 |
+
"ruff>=0.1.0",
|
| 60 |
+
"black>=23.11.0",
|
| 61 |
+
"mypy>=1.7.0",
|
| 62 |
+
]
|
| 63 |
+
|
| 64 |
+
[tool.hatch.build.targets.wheel]
|
| 65 |
+
packages = ["backend"]
|
| 66 |
+
|
| 67 |
+
[build-system]
|
| 68 |
+
requires = ["hatchling"]
|
| 69 |
+
build-backend = "hatchling.build"
|