🔧

How it works (without the math)

The optimizer builds stock portfolios based on your risk preference. Instead of guessing weights, it uses diversification, historical behavior, and realistic constraints to keep portfolios balanced and valid.

📈

Market data, not predictions

The optimizer uses multi-year historical behavior to understand how stocks tend to move relative to each other. It analyzes patterns in volatility, returns, and correlations over extended periods.

By relying on historical data rather than forecasts or daily news, the optimizer builds portfolios that are grounded in observable patterns that tend to persist over time, avoiding short-term noise and speculation.

⚖️

Risk is more than "aggressive vs conservative"

Risk affects multiple dimensions of your portfolio: volatility, concentration, and how much exposure you take to correlated stocks. It's not just about being aggressive or conservative.

Higher risk allows more concentration in fewer stocks and greater exposure to growth-oriented assets. Lower risk enforces more stability and diversification across a broader set of holdings.

The risk slider (1-10) controls how the optimizer balances these tradeoffs, giving you control over the fundamental structure of your portfolio.

🔗

Diversification and correlation

Diversification means not putting all your risk in stocks that move together. If you hold five tech stocks and they all drop 20% on the same day, you haven't really diversified.

Correlation is simply "how similarly two stocks behave." High correlation means when one goes up, the other tends to go up too. Low correlation means they move more independently.

High correlation reduces the benefit of holding both stocks. The optimizer tries to combine assets that don't all move the same way, spreading risk across different market behaviors. Some correlation is natural and even beneficial—the goal is to avoid over-concentration in highly correlated groups.

What this means for you: Owning stocks that don't all move together can reduce swings without needing to 'predict' the market.

🎯

Concentration limits keep portfolios realistic

No single stock or sector should dominate your portfolio unless you explicitly override the constraints. Caps prevent accidental "all-in" portfolios that put too much risk in one place.

These limits vary by risk level. Higher risk portfolios may allow more concentration in individual stocks, while lower risk portfolios enforce stricter diversification rules. The optimizer respects these limits while still finding the best balance of weights across your selected stocks.

What this means for you: You avoid accidental 'all-in' bets on one stock or one sector.

🏢

Sector Diversification

The optimizer actively manages sector exposure to prevent over-concentration in any single industry. Each stock is classified into a sector (like Technology, Healthcare, Financial Services, Energy, etc.), and the optimizer enforces limits on how much of your portfolio can be in each sector.

Maximum Sector Weight (General Cap)

The optimizer sets a maximum percentage that any single sector can occupy, which varies by your risk level:

  • Risk 1: 22% max per sector (strictest)
  • Risk 2: 28% max per sector
  • Risk 3: 32% max per sector
  • Risk 4: 38% max per sector
  • Risk 5-10: Gradually increases from 38% to 70%

Sector-Specific Limits

Some sectors have additional specific limits beyond the general cap:

  • Technology: 50% max (60% for risk 9-10)
  • Financial Services: 35% max
  • Energy: 20% max
  • Consumer Defensive: 70% max
  • Healthcare: 40% max

The stricter limit applies—so if the general cap is 38% but Tech has a 50% limit, Tech can go up to 38% at that risk level. If Tech has a 50% limit but risk level allows 60% per sector, Tech is still capped at 50%.

Minimum Sector Diversity (Low Risk Only)

For lower risk portfolios, the optimizer ensures you have exposure to multiple sectors:

  • Risk 1: Minimum 6 different sectors required
  • Risk 2: Minimum 5 different sectors required
  • Risk 3: Minimum 4 different sectors required
  • Risk 4: Minimum 3 different sectors required
  • Risk 5-10: No minimum requirement (allows sector concentration)

If your portfolio doesn't meet the minimum, the optimizer automatically adds high-quality stocks from missing sectors to ensure proper diversification.

How Sector Limits Are Enforced

When a sector exceeds its limit, the optimizer:

  1. Calculates total exposure: sums all weights of stocks in that sector
  2. Scales down: proportionally reduces all positions in the over-limit sector
  3. Redistributes: allocates the excess weight to sectors that are below their limits
  4. Renormalizes: ensures all weights still sum to 100%

What this means for you: You get automatic protection against sector concentration while still allowing higher-risk portfolios to take focused positions when appropriate.

⚙️

Optimization chooses weights, not just stocks

This isn't equal-weighting. The optimizer assigns weights based on your risk preference, stock characteristics, and diversification goals. Some stocks get more weight, others get less.

The optimizer balances multiple goals at once: managing risk, maintaining diversification, maximizing return potential, and considering quality signals. These goals sometimes conflict, and the optimizer finds the best compromise, creating a portfolio where each stock's weight reflects its role in achieving your overall risk-return profile.

🎯

How the Optimizer Works

The optimizer uses an iterative algorithm to build your portfolio step by step, starting from an empty portfolio and adding stocks one at a time based on their scores and how they fit with your risk preference.

The Optimization Process

  1. Scoring: Each stock is scored based on risk-adjusted returns, expected returns, quality, and how well it diversifies the current portfolio.
  2. Selection: The optimizer picks the highest-scoring stock that hasn't hit its maximum weight limit yet.
  3. Allocation: A small percentage (typically 2-5%) is allocated to that stock, with the exact amount adjusted based on how close the portfolio is to the target risk level.
  4. Constraint Enforcement: After each allocation, the optimizer checks and enforces all constraints:
    • Maximum weight per stock (varies by risk level)
    • Maximum weight per sector
    • Sector-specific limits (e.g., Tech capped at 50%)
    • Minimum sector diversity (for lower risk portfolios)
  5. Volatility Check: The optimizer monitors the portfolio's overall volatility. If adding more would exceed your target risk level, it stops adding new positions.
  6. Iteration: This process repeats until the portfolio reaches 100% allocation or hits the maximum number of positions (typically 10 stocks).

Constraint Relaxation

If the optimizer can't build a valid portfolio with strict constraints (for example, if you've selected only tech stocks but set a low risk level), it automatically tries progressively relaxed constraints:

  • Mild relaxation: Slightly higher sector limits and stock weights
  • Strong relaxation: More permissive limits while still maintaining diversification
  • Fallback methods: If needed, uses alternative allocation strategies like risk-parity or minimum variance approaches

This ensures you always get a valid portfolio, even with challenging stock selections or risk preferences.

Final Portfolio

Once the optimizer finishes, it finalizes the portfolio by:

  • Ensuring exactly 10 positions (or fewer if there aren't enough suitable stocks)
  • Normalizing all weights to sum to exactly 100%
  • Verifying all constraints are satisfied
  • Computing final portfolio metrics (volatility, expected return, Sharpe ratio, etc.)

What this means for you: The optimizer handles all the complex math and constraint checking automatically, so you can focus on your risk preference and stock selection.

Why the portfolio always stays valid

Weights always sum to 100%. This isn't just a display rule—it's a fundamental constraint that the optimizer enforces at every step.

When you edit one weight, the optimizer automatically rebalances the rest to maintain the 100% total. This happens instantly, keeping your portfolio valid even as you make adjustments. The optimizer prevents invalid states, so you can't accidentally create a portfolio that doesn't add up or violates the risk and concentration limits you've set.

What this means for you: You can experiment freely without breaking the portfolio math.

📊

What the metrics mean

Expected Return

A long-term estimate based on historical behavior. It represents the average return you might expect over time, not a guarantee for any specific period.

Volatility

How much the portfolio tends to fluctuate. Higher volatility means larger swings up and down. Lower volatility means more stable, predictable movement.

Quality Score

A stability and consistency signal based on the underlying stocks. Higher quality scores indicate more reliable, established companies with consistent performance patterns.

Sharpe Ratio

Risk-adjusted efficiency. It measures how much return you get per unit of risk. Higher Sharpe ratios indicate better risk-adjusted performance.

⚠️ These are estimates, not guarantees. Past performance does not predict future results.

🚫

What the optimizer does not do

  • ×Does not guarantee returns
  • ×Does not provide personalized financial advice
  • ×Does not time the market
  • ×Does not predict news-driven moves
💡

Key idea

The optimizer helps you build portfolios that balance risk, diversification, and return potential based on historical patterns. It's a systematic approach to portfolio construction, not a crystal ball for market timing or stock picking.

Advanced Technical Guide

For developers and advanced users: detailed technical architecture, data processing pipeline, and scoring methodology.

Overview

StockRisker is a portfolio risk assessment and optimization tool that evaluates individual securities (stocks and ETFs) and constructs optimal portfolios based on quantitative metrics. The system processes raw financial data from multiple sources, normalizes it, computes risk-adjusted scores, and uses these scores for portfolio construction.

Core Principles

  1. Risk-Adjusted Scoring: All securities are evaluated on a risk-adjusted basis, not just raw returns
  2. Instrument-Aware Processing: Stocks and ETFs are scored using different metrics appropriate to their structure
  3. Robust Fallbacks: Missing data is handled gracefully with neutral fallback values (0.5) to prevent scoring failures
  4. Computed Risk Metrics: Risk metrics are computed from historical returns, never taken directly from data sources
  5. Unit Consistency: All financial metrics are normalized to decimal format internally for consistent calculations

Data Sources & Collection

Primary Data Sources

  1. Financial Data APIs
    • Historical price data (5+ years)
    • Fundamental metrics (valuation, growth, profitability, balance sheet)
    • Dividend history and yields
    • ETF-specific metadata (expense ratios, AUM, fund details)
    • Analyst recommendations and price targets
    • Earnings estimates
  2. Computed Metrics
    • Risk metrics (volatility, beta, Sharpe ratio, alpha, tracking error)
    • Correlation with benchmark (SPY)
    • Momentum indicators
    • Returns calculations

Data Collection Process

The data collection pipeline follows this workflow:

  1. Fetch Historical Prices: Retrieve 5+ years of daily price data (adjusted close)
  2. Fetch Fundamentals: Extract all available fundamental metrics from financial data APIs
  3. Fetch Dividends: Get dividend history and compute yield
  4. Normalize Units: Convert all percentage-based fields to decimal format
  5. Compute Risk Metrics: Calculate volatility, beta, Sharpe, alpha, tracking error from historical returns
  6. Store Raw + Normalized: Keep both raw values (for debugging) and normalized values (for scoring)

Data Processing Pipeline

Stage 1: Data Fetching

Data is fetched from financial data APIs, parsed and validated, normalized to consistent units, and stored with metadata.

Stage 2: Risk Calculation

Risk metrics are computed:

  • Price data is aligned to ensure stock and benchmark prices have matching dates
  • Returns are computed (daily and cumulative)
  • Risk metrics are calculated: volatility, beta, Sharpe ratio, alpha, tracking error
  • Risk components are normalized to a 0-1 scale for comparison

Stage 3: Scoring

The scoring engine classifies instruments (ETF vs stock), routes to the appropriate scoring function, computes component scores, combines them with weights, and handles missing data gracefully.

Data Flow

Financial Data APIs
    ↓
Data Fetching
  - Fetch data
  - Normalize
  - Store JSON
    ↓
Risk Calculation
  - Compute risk
  - Calculate metrics
    ↓
Scoring Engine
  - Classify (ETF/Stock)
  - Score
  - Combine
    ↓
Portfolio Optimizer
  - Rank
  - Optimize
  - Generate

Scoring Architecture

Equity Scoring

Equity scores are composed of four main dimensions:

  1. Risk-Adjusted Score (40% weight in final)

    Based on volatility, beta, tracking error, Sharpe ratio, and danger metrics. Higher = less risk / better.

  2. Expected Return Score (30% weight)

    Combines growth potential, sustainability, income, analyst sentiment, and value.

  3. Quality Score (20% weight)

    Measures business quality through profitability, value, growth, and debt.

  4. Diversification Bonus (10% weight)

    Portfolio-level metric (0 for individual stock scoring).

Final Equity Score Formula:

Final Score = 0.40 × Risk-Adjusted Score + 0.30 × Expected Return Score + 0.20 × Quality Score + 0.10 × Diversification Bonus

ETF Scoring

ETF scores use a different methodology optimized for fund characteristics:

  1. ETF Risk-Adjusted Score (55% weight) - Uses volatility, beta, tracking error, Sharpe ratio, plus ETF-specific danger
  2. ETF Return Score (20% weight) - Based on backward-looking returns (3Y/5Y averages, YTD)
  3. ETF Income Score (15% weight) - Dividend yield with yield trap detection
  4. ETF Cost Score (5% weight) - Expense ratio (lower = better)
  5. ETF Liquidity Score (5% weight) - Composite of spread, dollar volume, and AUM

Final ETF Score Formula:

Final ETF Score = 0.55 × Risk-Adjusted Score + 0.20 × Return Score + 0.15 × Income Score + 0.05 × Cost Score + 0.05 × Liquidity Score

For complete formula details, see the Scoring Formulas Reference.

Instrument Classification

The system automatically detects instrument type using metadata from data sources:

  • quoteType === "ETF": Routes to ETF scoring path
  • quoteType === "EQUITY" (or missing): Routes to equity scoring path

Key Differences:

  • ETFs: Skip stock-specific metrics, use ETF-specific metrics (expense ratio, AUM, fund returns), use ETF danger (drawdown/alpha)
  • Equities: Use traditional fundamental analysis metrics, compute stock danger from short interest, debt, float

Sector Diversification System

Sector Resolution

Sectors are resolved directly from stock metadata:

  1. Stock metadata (from stocks.json) - Primary source, all stocks have sector data
  2. "Other" - Default fallback if sector is missing (should not occur in normal operation)

Sector names from stock data (e.g., "Technology") are normalized to internal classifications (e.g., "Tech") to match sector limits. All sector data is stored in the stock metadata files, ensuring consistency and eliminating the need for hardcoded mappings.

Maximum Sector Weight Function

The general maximum sector weight is calculated by risk level:

getMaxSectorWeight(risk):
  Risk 1: 22%
  Risk 2: 28%
  Risk 3: 32%
  Risk 4: 38%
  Risk 5-10: Linear interpolation from 38% to 70%

This is enforced via enforceMaxSectorWeight() before sector-specific limits.

Sector-Specific Limits

Defined in SECTOR_LIMITS constant:

SECTOR_LIMITS = {
  Tech: 0.50,              // 50% (60% if risk >= 9)
  Financials: 0.35,
  Energy: 0.20,
  ConsumerDefensive: 0.70,
  Healthcare: 0.40,
  Meme: 0.05,
  Junk: 0.00,
  Crypto: 0.10
}

Enforced via enforceSectorLimits(). The stricter limit applies (general cap vs sector-specific).

Sector Diversity Requirements

For low risk levels (1-4), minimum sector counts are enforced:

enforceSectorDiversity():
  Risk 1: minSectors = 6
  Risk 2: minSectors = 5
  Risk 3: minSectors = 4
  Risk 4: minSectors = 3
  Risk 5-10: No enforcement

If minimum not met, optimizer adds high-quality stocks from missing sectors.

Sector Exposure Calculation

The computeSectorExposure() function calculates total weight per sector:

for each stock:
  sector = classifyStockSector(stock)
  weight = weights[stock.ticker]
  exposure[sector] += weight

Returns: { sector: totalWeight, ... }

Enforcement Algorithm

When a sector exceeds its limit in enforceSectorLimits():

  1. Compute exposure for all sectors
  2. For each over-limit sector: scaleFactor = limit / exposure
  3. Multiply all stocks in that sector by scaleFactor
  4. Redistribute excess weight to sectors below limit
  5. Renormalize weights to sum to 1.0

Unit Normalization & Data Consistency

Financial data APIs may return data in inconsistent units (percent vs decimal). The system normalizes all values to decimal format before storage.

Field TypeSource FormatNormalization RuleStored As
Yield / Fee FieldsPercent (e.g., 12.58 = 12.58%)If abs(value) > threshold → divide by 100Decimal (e.g., 0.1258)
Return FieldsMixed (percent or decimal)If abs(value) > 1.0 → divide by 100Decimal
Change-Percent FieldsMixed (percent or decimal)If abs(value) >= 1.0 → divide by 100Decimal
Risk MetricsAlready decimalNo conversion neededDecimal

Risk Calculation

All risk metrics are computed from historical price data, never taken directly from data sources.

Volatility

Annualized standard deviation of daily returns

stdDev(dailyReturns) × √252

Beta

Sensitivity to market movements

Covariance(stock, market) / Variance(market)

Sharpe Ratio

Risk-adjusted return

(Return - RiskFreeRate) / Volatility

Alpha

Excess return after accounting for market risk

Return - (RiskFreeRate + Beta × MarketReturn)

Final Score Composition

Equity Final Score

0.40 × Risk-Adjusted Score +
0.30 × Expected Return Score +
0.20 × Quality Score +
0.10 × Diversification Bonus

Scores range from 0.0 to 1.0. Higher = better investment opportunity (risk-adjusted).

ETF Final Score

0.55 × Risk-Adjusted Score +
0.20 × Return Score +
0.15 × Income Score +
0.05 × Cost Score +
0.05 × Liquidity Score

Heavier weight on risk (55%) reflects importance of risk management for ETFs.

Ready to try it?

Build your portfolio based on your risk preference.

Build my portfolio

Educational purposes only. Not financial advice.