Skip to content

User Preferences API

⚙️ User Preferences Management

The User Preferences API provides comprehensive preference management for personalizing the Quantbot experience. Users can configure investment profiles, communication preferences, watchlists, and analysis settings through a robust set of endpoints.

Base URL

All preference endpoints are prefixed with:

/api/v1/preferences/

Authentication

All preference endpoints require user authentication. Include the Bearer token in the Authorization header:

Authorization: Bearer <your_jwt_token>

Data Models

UserPreferencesCreate

Request model for creating comprehensive user preferences.

{
  "experience_level": "intermediate",
  "investment_style": "long-term",
  "risk_tolerance": "moderate",
  "brokerage_platform": "fidelity",
  "investment_types": ["stocks", "etfs", "options"],
  "analysis_depth": "detailed",
  "information_sources": [
    {"type": "earnings", "priority": 1},
    {"type": "news", "priority": 2},
    {"type": "analyst", "priority": 3}
  ],
  "market_sectors": ["technology", "healthcare", "finance"],
  "geographic_focus": "us",
  "daily_summary_time": "morning",
  "alert_frequency": "daily",
  "esg_importance": "somewhat",
  "explanation_style": "key-points",
  "watchlist": ["AAPL", "MSFT", "GOOGL", "AMZN"],
  "privacy_level": "limited"
}

UserPreferencesUpdate

Request model for updating existing preferences (all fields optional).

{
  "risk_tolerance": "aggressive",
  "watchlist": ["AAPL", "MSFT", "TSLA", "NVDA", "META"],
  "alert_frequency": "real-time",
  "analysis_depth": "technical"
}

UserPreferencesResponse

Complete user preferences response format.

{
  "id": 123,
  "user_id": 456,
  "experience_level": "intermediate",
  "investment_style": "long-term",
  "risk_tolerance": "moderate",
  "brokerage_platform": "fidelity",
  "investment_types": ["stocks", "etfs", "options"],
  "analysis_depth": "detailed",
  "information_sources": [
    {"type": "earnings", "priority": 1},
    {"type": "news", "priority": 2},
    {"type": "analyst", "priority": 3}
  ],
  "market_sectors": ["technology", "healthcare", "finance"],
  "geographic_focus": "us",
  "daily_summary_time": "morning",
  "alert_frequency": "daily",
  "esg_importance": "somewhat",
  "explanation_style": "key-points",
  "watchlist": ["AAPL", "MSFT", "GOOGL", "AMZN"],
  "privacy_level": "limited",
  "created_at": "2025-01-15T10:30:00Z",
  "updated_at": "2025-01-15T14:30:00Z"
}

InformationSource

Information source preference with priority ranking.

{
  "type": "earnings",
  "priority": 1
}

Valid Types: earnings, news, analyst, social, technical, economic
Priority Range: 1-6 (1 = highest priority)

BulkPreferencesUpdate

Bulk update model for wizard-based preference setting.

{
  "step_data": {
    "essential": {
      "experience_level": "beginner",
      "investment_style": "long-term",
      "risk_tolerance": "conservative"
    },
    "portfolio": {
      "investment_types": ["stocks", "etfs"],
      "brokerage_platform": "robinhood"
    },
    "information": {
      "analysis_depth": "simple",
      "information_sources": [
        {"type": "news", "priority": 1},
        {"type": "earnings", "priority": 2}
      ]
    }
  },
  "complete": true
}

Endpoints

Get User Preferences

Retrieve the current user's preferences.

GET /api/v1/preferences/

Response

Status Code: 200 OK

{
  "id": 123,
  "user_id": 456,
  "experience_level": "intermediate",
  "investment_style": "long-term",
  "risk_tolerance": "moderate",
  "brokerage_platform": "fidelity",
  "investment_types": ["stocks", "etfs", "options"],
  "analysis_depth": "detailed",
  "information_sources": [
    {"type": "earnings", "priority": 1},
    {"type": "news", "priority": 2}
  ],
  "market_sectors": ["technology", "healthcare"],
  "geographic_focus": "us",
  "daily_summary_time": "morning",
  "alert_frequency": "daily",
  "esg_importance": "somewhat",
  "explanation_style": "key-points",
  "watchlist": ["AAPL", "MSFT", "GOOGL"],
  "privacy_level": "limited",
  "created_at": "2025-01-15T10:30:00Z",
  "updated_at": "2025-01-15T14:30:00Z"
}

Error Responses

404 Not Found - No preferences found for user

{
  "detail": "User preferences not found"
}


Create User Preferences

Create new preferences for the current user.

POST /api/v1/preferences/

Request Body

{
  "experience_level": "beginner",
  "investment_style": "long-term",
  "risk_tolerance": "conservative",
  "brokerage_platform": "robinhood",
  "investment_types": ["stocks", "etfs"],
  "analysis_depth": "simple",
  "information_sources": [
    {"type": "news", "priority": 1},
    {"type": "earnings", "priority": 2}
  ],
  "market_sectors": ["technology"],
  "geographic_focus": "us",
  "daily_summary_time": "evening",
  "alert_frequency": "daily",
  "esg_importance": "unsure",
  "explanation_style": "step-by-step",
  "watchlist": ["AAPL", "MSFT"],
  "privacy_level": "full"
}

Response

Status Code: 201 Created

{
  "id": 124,
  "user_id": 456,
  "experience_level": "beginner",
  "investment_style": "long-term",
  "risk_tolerance": "conservative",
  "brokerage_platform": "robinhood",
  "investment_types": ["stocks", "etfs"],
  "analysis_depth": "simple",
  "information_sources": [
    {"type": "news", "priority": 1},
    {"type": "earnings", "priority": 2}
  ],
  "market_sectors": ["technology"],
  "geographic_focus": "us",
  "daily_summary_time": "evening",
  "alert_frequency": "daily",
  "esg_importance": "unsure",
  "explanation_style": "step-by-step",
  "watchlist": ["AAPL", "MSFT"],
  "privacy_level": "full",
  "created_at": "2025-01-15T15:00:00Z",
  "updated_at": "2025-01-15T15:00:00Z"
}

Error Responses

409 Conflict - Preferences already exist for user

{
  "detail": "User preferences already exist"
}


Update User Preferences

Update existing preferences for the current user.

PUT /api/v1/preferences/

Request Body

{
  "risk_tolerance": "aggressive",
  "watchlist": ["AAPL", "TSLA", "NVDA", "AMD"],
  "alert_frequency": "real-time",
  "analysis_depth": "technical"
}

Response

Status Code: 200 OK

{
  "id": 123,
  "user_id": 456,
  "experience_level": "intermediate",
  "investment_style": "long-term",
  "risk_tolerance": "aggressive",
  "brokerage_platform": "fidelity",
  "investment_types": ["stocks", "etfs", "options"],
  "analysis_depth": "technical",
  "information_sources": [
    {"type": "earnings", "priority": 1},
    {"type": "news", "priority": 2}
  ],
  "market_sectors": ["technology", "healthcare"],
  "geographic_focus": "us",
  "daily_summary_time": "morning",
  "alert_frequency": "real-time",
  "esg_importance": "somewhat",
  "explanation_style": "key-points",
  "watchlist": ["AAPL", "TSLA", "NVDA", "AMD"],
  "privacy_level": "limited",
  "created_at": "2025-01-15T10:30:00Z",
  "updated_at": "2025-01-15T16:00:00Z"
}

Error Responses

404 Not Found - No preferences found to update

{
  "detail": "User preferences not found to update"
}


Delete User Preferences

Delete all preferences for the current user.

DELETE /api/v1/preferences/

Response

Status Code: 204 No Content


Get Smart Defaults

Get intelligent default preferences based on experience level.

GET /api/v1/preferences/defaults/{experience_level}

Path Parameters

Parameter Type Description
experience_level string User experience level: beginner, intermediate, or advanced

Response

Status Code: 200 OK

{
  "experience_level": "beginner",
  "investment_style": "long-term",
  "risk_tolerance": "conservative",
  "brokerage_platform": null,
  "investment_types": ["stocks", "etfs"],
  "analysis_depth": "simple",
  "information_sources": [
    {"type": "news", "priority": 1},
    {"type": "earnings", "priority": 2},
    {"type": "analyst", "priority": 3}
  ],
  "market_sectors": ["technology", "healthcare", "finance"],
  "geographic_focus": "us",
  "daily_summary_time": "evening",
  "alert_frequency": "daily",
  "esg_importance": "unsure",
  "explanation_style": "step-by-step",
  "watchlist": [],
  "privacy_level": "full"
}

Error Responses

400 Bad Request - Invalid experience level

{
  "detail": "Invalid experience level. Must be: beginner, intermediate, or advanced"
}


Get Preference Choices

Get all available choices for preference fields.

GET /api/v1/preferences/choices

Response

Status Code: 200 OK

{
  "experience_level": ["beginner", "intermediate", "advanced"],
  "investment_style": ["long-term", "active", "swing", "day"],
  "risk_tolerance": ["conservative", "moderate", "aggressive"],
  "investment_types": ["stocks", "etfs", "mutual_funds", "bonds", "options", "futures", "crypto", "real_estate"],
  "analysis_depth": ["simple", "detailed", "technical"],
  "market_sectors": ["technology", "healthcare", "finance", "energy", "consumer_discretionary", "consumer_staples", "industrials", "materials", "utilities", "real_estate", "telecommunications"],
  "geographic_focus": ["us", "us-international", "global"],
  "daily_summary_time": ["morning", "lunch", "evening", "night", "convenient"],
  "alert_frequency": ["real-time", "hourly", "daily", "weekly"],
  "esg_importance": ["very", "somewhat", "not", "unsure"],
  "explanation_style": ["step-by-step", "key-points", "bottom-line-first"],
  "privacy_level": ["full", "limited", "minimal"],
  "information_source_types": ["earnings", "news", "analyst", "social", "technical", "economic"],
  "brokerage_platforms": ["fidelity", "schwab", "vanguard", "etrade", "td_ameritrade", "robinhood", "webull", "interactive_brokers", "merrill", "other"]
}

Bulk Update from Wizard

Update preferences from wizard step data.

POST /api/v1/preferences/wizard

Request Body

{
  "step_data": {
    "essential": {
      "experience_level": "intermediate",
      "investment_style": "active",
      "risk_tolerance": "moderate"
    },
    "portfolio": {
      "investment_types": ["stocks", "etfs", "options"],
      "brokerage_platform": "fidelity"
    },
    "information": {
      "analysis_depth": "detailed",
      "information_sources": [
        {"type": "earnings", "priority": 1},
        {"type": "technical", "priority": 2},
        {"type": "news", "priority": 3}
      ],
      "market_sectors": ["technology", "healthcare"]
    },
    "communication": {
      "daily_summary_time": "morning",
      "alert_frequency": "hourly"
    },
    "advanced": {
      "esg_importance": "somewhat",
      "explanation_style": "key-points",
      "privacy_level": "limited"
    }
  },
  "complete": true
}

Response

Status Code: 200 OK

Returns the complete updated preferences in UserPreferencesResponse format.


Get or Create with Defaults

Get existing preferences or create with smart defaults.

GET /api/v1/preferences/or-create/{experience_level}

Path Parameters

Parameter Type Description
experience_level string Experience level for defaults: beginner, intermediate, or advanced

Response

Status Code: 200 OK

Returns existing preferences if they exist, otherwise creates new preferences with intelligent defaults and returns them.


Update Watchlist

Update only the user's stock watchlist.

PATCH /api/v1/preferences/watchlist

Request Body

["AAPL", "MSFT", "GOOGL", "AMZN", "TSLA", "NVDA", "META"]

Response

Status Code: 200 OK

Returns the complete updated preferences with the new watchlist.

Validation Rules

  • Maximum 50 symbols
  • Valid ticker format: 1-5 uppercase letters
  • No duplicates allowed
  • Automatic uppercase conversion

Error Responses

400 Bad Request - Validation error

{
  "detail": "Watchlist cannot exceed 50 symbols"
}

400 Bad Request - Invalid tickers

{
  "detail": "Invalid ticker symbols: ['INVALID123', 'toolong']"
}

Preference Categories

Core Investment Profile

  • Experience Level: beginner, intermediate, advanced
  • Investment Style: long-term, active, swing, day
  • Risk Tolerance: conservative, moderate, aggressive

Portfolio Information

  • Investment Types: Multiple selection from stocks, ETFs, options, etc.
  • Brokerage Platform: User's primary trading platform
  • Market Sectors: Preferred sectors for focus and analysis

Analysis & Information

  • Analysis Depth: simple, detailed, technical
  • Information Sources: Prioritized list of preferred data sources
  • Geographic Focus: us, us-international, global

Communication & Alerts

  • Daily Summary Time: morning, lunch, evening, night, convenient
  • Alert Frequency: real-time, hourly, daily, weekly
  • Explanation Style: step-by-step, key-points, bottom-line-first

Advanced Settings

  • ESG Importance: very, somewhat, not, unsure
  • Privacy Level: full, limited, minimal
  • Watchlist: Personal stock ticker symbol list

Integration Examples

Python Example

import requests
from typing import Dict, List, Any, Optional

class QuantbotPreferencesClient:
    def __init__(self, base_url: str, access_token: str):
        self.base_url = base_url
        self.headers = {
            "Authorization": f"Bearer {access_token}",
            "Content-Type": "application/json"
        }

    def get_preferences(self) -> Dict[str, Any]:
        """Get current user preferences"""
        response = requests.get(
            f"{self.base_url}/api/v1/preferences/",
            headers=self.headers
        )
        response.raise_for_status()
        return response.json()

    def create_preferences(self, preferences: Dict[str, Any]) -> Dict[str, Any]:
        """Create new user preferences"""
        response = requests.post(
            f"{self.base_url}/api/v1/preferences/",
            headers=self.headers,
            json=preferences
        )
        response.raise_for_status()
        return response.json()

    def update_preferences(self, updates: Dict[str, Any]) -> Dict[str, Any]:
        """Update existing preferences"""
        response = requests.put(
            f"{self.base_url}/api/v1/preferences/",
            headers=self.headers,
            json=updates
        )
        response.raise_for_status()
        return response.json()

    def get_smart_defaults(self, experience_level: str) -> Dict[str, Any]:
        """Get intelligent defaults for experience level"""
        response = requests.get(
            f"{self.base_url}/api/v1/preferences/defaults/{experience_level}",
            headers=self.headers
        )
        response.raise_for_status()
        return response.json()

    def get_preference_choices(self) -> Dict[str, List[str]]:
        """Get available choices for all preference fields"""
        response = requests.get(
            f"{self.base_url}/api/v1/preferences/choices",
            headers=self.headers
        )
        response.raise_for_status()
        return response.json()

    def update_watchlist(self, watchlist: List[str]) -> Dict[str, Any]:
        """Update only the watchlist"""
        response = requests.patch(
            f"{self.base_url}/api/v1/preferences/watchlist",
            headers=self.headers,
            json=watchlist
        )
        response.raise_for_status()
        return response.json()

    def bulk_update_from_wizard(self, step_data: Dict[str, Any], complete: bool = True) -> Dict[str, Any]:
        """Bulk update from wizard steps"""
        response = requests.post(
            f"{self.base_url}/api/v1/preferences/wizard",
            headers=self.headers,
            json={
                "step_data": step_data,
                "complete": complete
            }
        )
        response.raise_for_status()
        return response.json()

# Usage examples
prefs_client = QuantbotPreferencesClient("http://localhost:8000", "your_access_token")

# Get available choices for form building
choices = prefs_client.get_preference_choices()
print("📋 Available investment types:", choices["investment_types"])

# Get smart defaults for a beginner
defaults = prefs_client.get_smart_defaults("beginner")
print(f"🎯 Beginner defaults: {defaults['risk_tolerance']} risk, {defaults['analysis_depth']} analysis")

# Create comprehensive preferences
new_preferences = {
    "experience_level": "intermediate",
    "investment_style": "long-term",
    "risk_tolerance": "moderate",
    "brokerage_platform": "fidelity",
    "investment_types": ["stocks", "etfs", "options"],
    "analysis_depth": "detailed",
    "information_sources": [
        {"type": "earnings", "priority": 1},
        {"type": "news", "priority": 2},
        {"type": "analyst", "priority": 3}
    ],
    "market_sectors": ["technology", "healthcare"],
    "geographic_focus": "us",
    "daily_summary_time": "morning",
    "alert_frequency": "daily",
    "esg_importance": "somewhat",
    "explanation_style": "key-points",
    "watchlist": ["AAPL", "MSFT", "GOOGL"],
    "privacy_level": "limited"
}

try:
    created_prefs = prefs_client.create_preferences(new_preferences)
    print(f"✅ Created preferences for user {created_prefs['user_id']}")
except requests.HTTPError as e:
    if e.response.status_code == 409:
        print("📝 Preferences already exist, updating instead...")
        updated_prefs = prefs_client.update_preferences({
            "risk_tolerance": "aggressive",
            "alert_frequency": "real-time"
        })
        print(f"✏️ Updated preferences: {updated_prefs['risk_tolerance']} risk")

# Quick watchlist update
new_watchlist = ["AAPL", "MSFT", "GOOGL", "AMZN", "TSLA", "NVDA"]
updated_prefs = prefs_client.update_watchlist(new_watchlist)
print(f"📈 Updated watchlist: {len(updated_prefs['watchlist'])} symbols")

# Wizard-style bulk update
wizard_data = {
    "essential": {
        "experience_level": "advanced",
        "investment_style": "active",
        "risk_tolerance": "aggressive"
    },
    "information": {
        "analysis_depth": "technical",
        "information_sources": [
            {"type": "technical", "priority": 1},
            {"type": "earnings", "priority": 2}
        ]
    },
    "communication": {
        "alert_frequency": "real-time",
        "daily_summary_time": "morning"
    }
}

wizard_prefs = prefs_client.bulk_update_from_wizard(wizard_data)
print(f"🧙‍♂️ Wizard update completed: {wizard_prefs['experience_level']} level")

TypeScript Example

interface UserPreferences {
  id?: number;
  user_id?: number;
  experience_level: string;
  investment_style: string;
  risk_tolerance: string;
  brokerage_platform?: string;
  investment_types: string[];
  analysis_depth: string;
  information_sources: InformationSource[];
  market_sectors: string[];
  geographic_focus: string;
  daily_summary_time: string;
  alert_frequency: string;
  esg_importance?: string;
  explanation_style: string;
  watchlist: string[];
  privacy_level: string;
  created_at?: string;
  updated_at?: string;
}

interface InformationSource {
  type: string;
  priority: number;
}

interface WizardStepData {
  [stepName: string]: Record<string, any>;
}

class QuantbotPreferencesAPI {
  constructor(private baseURL: string, private accessToken: string) {}

  private get headers() {
    return {
      'Authorization': `Bearer ${this.accessToken}`,
      'Content-Type': 'application/json'
    };
  }

  async getPreferences(): Promise<UserPreferences> {
    const response = await fetch(`${this.baseURL}/api/v1/preferences/`, {
      method: 'GET',
      headers: this.headers
    });

    if (!response.ok) {
      throw new Error(`Failed to get preferences: ${response.statusText}`);
    }

    return await response.json();
  }

  async createPreferences(preferences: Partial<UserPreferences>): Promise<UserPreferences> {
    const response = await fetch(`${this.baseURL}/api/v1/preferences/`, {
      method: 'POST',
      headers: this.headers,
      body: JSON.stringify(preferences)
    });

    if (!response.ok) {
      const error = await response.json();
      throw new Error(`Failed to create preferences: ${error.detail}`);
    }

    return await response.json();
  }

  async updatePreferences(updates: Partial<UserPreferences>): Promise<UserPreferences> {
    const response = await fetch(`${this.baseURL}/api/v1/preferences/`, {
      method: 'PUT',
      headers: this.headers,
      body: JSON.stringify(updates)
    });

    if (!response.ok) {
      const error = await response.json();
      throw new Error(`Failed to update preferences: ${error.detail}`);
    }

    return await response.json();
  }

  async getSmartDefaults(experienceLevel: string): Promise<UserPreferences> {
    const response = await fetch(
      `${this.baseURL}/api/v1/preferences/defaults/${experienceLevel}`,
      {
        method: 'GET',
        headers: this.headers
      }
    );

    if (!response.ok) {
      throw new Error(`Failed to get defaults: ${response.statusText}`);
    }

    return await response.json();
  }

  async getPreferenceChoices(): Promise<Record<string, string[]>> {
    const response = await fetch(`${this.baseURL}/api/v1/preferences/choices`, {
      method: 'GET',
      headers: this.headers
    });

    if (!response.ok) {
      throw new Error(`Failed to get choices: ${response.statusText}`);
    }

    return await response.json();
  }

  async updateWatchlist(watchlist: string[]): Promise<UserPreferences> {
    const response = await fetch(`${this.baseURL}/api/v1/preferences/watchlist`, {
      method: 'PATCH',
      headers: this.headers,
      body: JSON.stringify(watchlist)
    });

    if (!response.ok) {
      const error = await response.json();
      throw new Error(`Failed to update watchlist: ${error.detail}`);
    }

    return await response.json();
  }

  async bulkUpdateFromWizard(stepData: WizardStepData, complete: boolean = true): Promise<UserPreferences> {
    const response = await fetch(`${this.baseURL}/api/v1/preferences/wizard`, {
      method: 'POST',
      headers: this.headers,
      body: JSON.stringify({
        step_data: stepData,
        complete
      })
    });

    if (!response.ok) {
      const error = await response.json();
      throw new Error(`Failed to update from wizard: ${error.detail}`);
    }

    return await response.json();
  }

  async deletePreferences(): Promise<void> {
    const response = await fetch(`${this.baseURL}/api/v1/preferences/`, {
      method: 'DELETE',
      headers: this.headers
    });

    if (!response.ok) {
      throw new Error(`Failed to delete preferences: ${response.statusText}`);
    }
  }
}

// Usage examples
const prefsAPI = new QuantbotPreferencesAPI('http://localhost:8000', 'your_access_token');

// Comprehensive preference management
async function setupUserPreferences() {
  try {
    // Get available choices for form validation
    const choices = await prefsAPI.getPreferenceChoices();
    console.log('📋 Available risk levels:', choices.risk_tolerance);

    // Try to get existing preferences
    let preferences: UserPreferences;
    try {
      preferences = await prefsAPI.getPreferences();
      console.log('📖 Found existing preferences');
    } catch (error) {
      // Create new preferences with smart defaults
      const defaults = await prefsAPI.getSmartDefaults('intermediate');

      const newPreferences: Partial<UserPreferences> = {
        ...defaults,
        brokerage_platform: 'fidelity',
        watchlist: ['AAPL', 'MSFT', 'GOOGL', 'AMZN'],
        market_sectors: ['technology', 'healthcare']
      };

      preferences = await prefsAPI.createPreferences(newPreferences);
      console.log('✅ Created new preferences with defaults');
    }

    // Update specific preferences
    const updates = await prefsAPI.updatePreferences({
      risk_tolerance: 'aggressive',
      alert_frequency: 'real-time',
      analysis_depth: 'technical'
    });

    console.log('✏️ Updated preferences:', {
      risk: updates.risk_tolerance,
      alerts: updates.alert_frequency,
      analysis: updates.analysis_depth
    });

    // Update watchlist separately
    const newWatchlist = ['AAPL', 'MSFT', 'NVDA', 'TSLA', 'AMD', 'GOOGL'];
    const watchlistUpdate = await prefsAPI.updateWatchlist(newWatchlist);
    console.log(`📈 Updated watchlist: ${watchlistUpdate.watchlist.length} symbols`);

    return preferences;

  } catch (error) {
    console.error('❌ Preference setup failed:', error);
    throw error;
  }
}

// Wizard-based setup
async function setupFromWizard() {
  const wizardData: WizardStepData = {
    essential: {
      experience_level: 'advanced',
      investment_style: 'active',
      risk_tolerance: 'aggressive'
    },
    portfolio: {
      investment_types: ['stocks', 'options', 'futures'],
      brokerage_platform: 'interactive_brokers'
    },
    information: {
      analysis_depth: 'technical',
      information_sources: [
        { type: 'technical', priority: 1 },
        { type: 'earnings', priority: 2 },
        { type: 'news', priority: 3 }
      ],
      market_sectors: ['technology', 'finance']
    },
    communication: {
      daily_summary_time: 'morning',
      alert_frequency: 'real-time'
    },
    advanced: {
      esg_importance: 'not',
      explanation_style: 'bottom-line-first',
      privacy_level: 'minimal'
    }
  };

  try {
    const preferences = await prefsAPI.bulkUpdateFromWizard(wizardData, true);
    console.log('🧙‍♂️ Wizard setup completed successfully');
    console.log(`🎯 Profile: ${preferences.experience_level} ${preferences.investment_style} investor`);
    console.log(`⚡ Alerts: ${preferences.alert_frequency} ${preferences.analysis_depth} analysis`);

    return preferences;
  } catch (error) {
    console.error('❌ Wizard setup failed:', error);
    throw error;
  }
}

Smart Defaults System

The preferences API includes an intelligent defaults system that provides appropriate starting configurations based on user experience level:

Beginner Defaults

  • Risk Tolerance: Conservative
  • Analysis Depth: Simple explanations
  • Investment Types: Stocks and ETFs only
  • Alert Frequency: Daily summaries
  • Explanation Style: Step-by-step guidance

Intermediate Defaults

  • Risk Tolerance: Moderate
  • Analysis Depth: Detailed analysis
  • Investment Types: Stocks, ETFs, and options
  • Alert Frequency: Daily with real-time for major events
  • Explanation Style: Key points summary

Advanced Defaults

  • Risk Tolerance: Aggressive
  • Analysis Depth: Technical analysis
  • Investment Types: Full range including futures and crypto
  • Alert Frequency: Real-time alerts
  • Explanation Style: Bottom-line first approach

Validation Rules

Watchlist Validation

  • Maximum 50 ticker symbols
  • 1-5 uppercase letters only
  • No duplicate symbols allowed
  • Automatic uppercase conversion

Information Sources

  • Each type can only appear once
  • Priority values must be unique (1-6)
  • All priorities within valid range

Investment Types

  • Must be from approved list
  • Multiple selections allowed
  • Validated against current market offerings

Experience Level Progression

  • Users can update experience level over time
  • System suggests preference updates when level changes
  • Smart migration of existing settings

Security Considerations

Data Privacy

  • User Isolation: Each user can only access their own preferences
  • Privacy Levels: Users control how much data is shared with analytics
  • Audit Trail: All preference changes are logged with timestamps

Validation & Sanitization

  • Input Validation: All preference values validated against allowed choices
  • SQL Injection Prevention: All database queries use parameterized statements
  • XSS Protection: All user inputs sanitized before storage

Error Handling

Common Error Responses

400 Bad Request - Validation error

{
  "detail": "Invalid ticker symbols: ['INVALID123']"
}

401 Unauthorized - Authentication required

{
  "detail": "Could not validate credentials"
}

404 Not Found - Preferences not found

{
  "detail": "User preferences not found"
}

409 Conflict - Preferences already exist

{
  "detail": "User preferences already exist"
}

422 Unprocessable Entity - Invalid request format

{
  "detail": [
    {
      "loc": ["body", "risk_tolerance"],
      "msg": "string does not match regex",
      "type": "value_error.str.regex"
    }
  ]
}

  • Users API - User account management and profile information
  • Chat API - Personalized chat responses based on preferences
  • Authentication API - Required for all preference operations