A sophisticated investment portfolio generator that combines quiz-based user profiling with AI-powered portfolio recommendations and professional PDF report generation.
Portfolio Generator is a Python application that:
- Captures investor preferences through structured quiz inputs
- Generates AI-enhanced portfolios using Google Gemini API
- Fetches portfolio data from the Paasa API
- Renders professional reports as HTML and PDF with performance charts
This project follows a clean architecture with clear separation of concerns: data retrieval, AI enhancement, and presentation layers.
- Quiz Parser: Converts user quiz responses into structured investor profiles
- Portfolio Mapping: Maps risk profiles to appropriate portfolio types (Preservation, Balanced, Growth)
- API Integration: Integrates with Paasa API for real portfolio data
- AI Enhancement: Uses Google Gemini to enhance and personalize portfolio recommendations
- Report Generation: Creates professional 2-page PDF reports with:
- Investor profile summary
- Investment methodology
- Portfolio holdings table
- Performance charts (portfolio vs S&P 500)
- Key performance metrics
- Preservation Portfolio (ID: 1) - Conservative, capital protection focus
- Balanced Portfolio (ID: 2) - Moderate growth with risk management
- Growth Portfolio (ID: 3) - Aggressive growth strategy
- Python 3.x - Core application language
- Google Genai SDK - AI-powered portfolio enhancements
- Requests - HTTP client for API calls
- python-dotenv - Environment variable management
- xhtml2pdf (pisa) - HTML to PDF conversion
- Matplotlib - Performance chart generation
- NumPy - Numerical computations
- HTML5 - Report template structure
- CSS3 - Professional styling and layouts
- JavaScript - Interactive elements
SDKs/
โโโ main.py # Entry point and orchestration
โโโ data_provider.py # API calls and data retrieval
โโโ renderer.py # Report generation (HTML/PDF)
โโโ requirements.txt # Python dependencies
โโโ .env # API keys (not in repo)
โ
โโโ templates/
โ โโโ portfolio_template.html # HTML report template
โ โโโ styles.css # Report styling
โ โโโ script.js # Interactive features
โ
โโโ utils/
โ โโโ accumulating_etfs.json # ETF database (4000+ securities)
โ
โโโ output/
โ โโโ portfolio_1/
โ โ โโโ portfolio_data.json # Parsed portfolio data
โ โ โโโ portfolio_report.pdf # Generated report
โ โโโ portfolio_N/ # Additional portfolios
โ
โโโ README.md # This file
- Python 3.8 or higher
- pip (Python package manager)
- API credentials (see below)
pip install -r requirements.txtCreate a .env file in the project root directory:
# Google Gemini API Key
GEMINI_API_KEY=your_google_genai_api_key_here
# Paasa API Bearer Token
PAASA_BEARER_TOKEN=your_paasa_bearer_token_hereNote: Never commit the .env file to version control.
The utils/accumulating_etfs.json file contains 4000+ ETFs. This database is used for:
- ETF name lookups
- Category classification
- Holdings validation
python main.pyThe application accepts quiz results in the following format:
Investment Goals: Grow with caution
Withdraw Expectation: In 6-10 years
Scenario Question Answer: I'll do nothing
Portfolio Committed Capital: $5,000.00
Preferred Topics: World (all regions), Emerging markets, Asia-Pacific, Latin America, Healthcare, Technology, Industrials, Nuclear Energy, Electric Vehicles, Biotech, Corporate Bonds, Total Bond Market, Palladium, Uranium, Water
The parser recognizes key phrases to determine investor profile:
Conservative Indicators:
- "avoid losing"
- "grow with caution"
- "sell everything"
- "sell some"
Aggressive Indicators:
- "grow aggressively"
- "buy more"
Time Horizons:
- Short: 0-3 years
- Medium: 3-10 years
- Long: 10+ years
For each generated portfolio, the application creates:
{
"user_name": "John Doe",
"user_email": "[email protected]",
"portfolio_id": 2,
"risk_level": "Balanced",
"investment_horizon": "6-10 years",
"holdings": [
{
"ticker": "IWDA.L",
"name": "iShares Core MSCI World UCITS ETF",
"weight": 40,
"category": "Global Equities"
}
],
"methodology": {...}
}A professional 2-page report including:
- Page 1: Profile, methodology, holdings table
- Page 2: Performance charts, metrics, recommendations
Responsibility: Application orchestration and user interaction
Key Functions:
parse_user_input()- Converts quiz strings to structured profilesget_next_portfolio_number()- Manages output folder numberingmain()- Orchestrates the entire flow
Responsibility: Data retrieval and enhancement
Key Functions:
get_portfolio_id()- Maps user profile to portfolio typefetch_from_api()- Calls Paasa API with authenticationenhance_with_gemini()- Uses Google Gemini to personalize recommendationsget_portfolio_data()- Main orchestration function
Responsibility: Report generation
Key Functions:
generate_performance_chart()- Creates matplotlib chart as base64render_portfolio_to_html()- Injects data into HTML templaterender_portfolio()- Main function: HTML โ PDF conversiongenerate_pdf_from_html()- Uses xhtml2pdf for conversion
Endpoint: https://api-stage.paasa.com/api/portfolio/v1/analyze
Method: GET
Parameters:
{
'portfolioId': int, # 1, 2, or 3
'fromTemplates': 'true'
}Headers:
{
'Authorization': f'Bearer {token}',
'Accept': 'application/json',
'build-version': '44',
'x-internal-client-token': INTERNAL_TOKEN,
'app-version': '6.0.2'
}Purpose: Enhance portfolio recommendations with personalized insights
Typical Use:
- Generate investment methodology descriptions
- Create personalized recommendations based on user preferences
- Enhance holdings descriptions with market context
The renderer creates comparison charts showing:
- User Portfolio Performance (blue line) - Actual portfolio returns
- S&P 500 Benchmark (red dashed line) - Market benchmark
Features:
- Dynamic sampling (max 80 data points for clarity)
- Matplotlib-based rendering
- Base64 encoding for HTML embedding
- Responsive sizing for PDF layout
1. User runs: python main.py
โ
2. System prompts for quiz input
โ
3. User pastes quiz results and presses Enter
โ
4. parse_user_input() extracts: goal, risk, time horizon, etc.
โ
5. get_portfolio_id() maps to portfolio (1, 2, or 3)
โ
6. fetch_from_api() retrieves holdings from Paasa
โ
7. enhance_with_gemini() personalizes recommendations
โ
8. render_portfolio() generates HTML with charts
โ
9. xhtml2pdf converts to PDF
โ
10. Output saved to: output/portfolio_N/
- portfolio_data.json
- portfolio_report.pdf
| Variable | Required | Description |
|---|---|---|
GEMINI_API_KEY |
Yes | Google Genai API key |
PAASA_BEARER_TOKEN |
Yes | Paasa API authentication token |
| Variable | Value | Purpose |
|---|---|---|
BASE_DIR |
Script directory | Project root |
OUTPUT_DIR |
{BASE_DIR}/output |
Generated reports |
TEMPLATES_DIR |
{BASE_DIR}/templates |
HTML templates |
Issue: GEMINI_API_KEY not found
- Solution: Ensure
.envfile exists in project root with valid API key
Issue: Bearer token invalid
- Solution: Verify
PAASA_BEARER_TOKENis current and has proper permissions
Issue: PDF generation fails
- Solution: Ensure
xhtml2pdfis installed:pip install xhtml2pdf
Issue: Chart not appearing in PDF
- Solution: Check matplotlib backend is set to 'Agg' (already configured)
User Quiz Input
โ
parse_user_input() โ Structured Profile
โ
get_portfolio_id() โ Portfolio Type (1/2/3)
โ
fetch_from_api() โ API Holdings
โ
enhance_with_gemini() โ Personalized Recommendations
โ
generate_performance_chart() โ Chart Image (Base64)
โ
render_portfolio_to_html() โ HTML with Data
โ
generate_pdf_from_html() โ PDF Report
โ
Output: portfolio_data.json + portfolio_report.pdf
| Package | Version | Purpose |
|---|---|---|
google-genai |
Latest | Google Gemini API client |
python-dotenv |
Latest | Environment variable management |
xhtml2pdf |
Latest | HTML to PDF conversion |
requests |
Latest | HTTP requests |
matplotlib |
Latest | Chart generation |
numpy |
Latest | Numerical operations |
Proprietary - Paasa Inc.
For issues or questions:
- Check the Troubleshooting section above
- Verify all API keys are correctly configured
- Ensure all dependencies are installed:
pip install -r requirements.txt
-
Separation of Concerns
- Data layer (
data_provider.py) - independent of presentation - Rendering layer (
renderer.py) - agnostic to data source - Orchestration (
main.py) - coordinates components
- Data layer (
-
Clean API Integration
- External APIs abstracted in dedicated functions
- Error handling for network failures
- Configurable authentication via environment variables
-
Extensibility
- Easy to add new portfolio types by extending portfolio ID mapping
- Template changes don't require code modifications
- ETF database is JSON-based for easy updates
Potential improvements for future versions:
- Web UI for quiz input
- Email report delivery
- Portfolio backtesting and analytics
- Real-time market data integration
- Multi-currency support
- Advanced visualization options
Last Updated: December 2025