Building a Sovereign Portfolio Risk Calculator: Why We Ditched the Backend

Building a Sovereign Portfolio Risk Calculator: Why We Ditched the Backend

Backer posted Originally published at www.pocketportfolio.app 4 min read

Building a Sovereign Portfolio Risk Calculator: Why We Ditched the Backend

Client-side financial modeling. React risk calculator. TypeScript finance tooling.
This post is about why we deliberately killed the backend for portfolio risk analysis — and why that decision matters if you care about privacy, performance, and ownership.


The Problem: Risk Analysis Behind Paywalls

Most portfolio risk tools follow the same playbook:

  • Mandatory signups
  • Server-side data processing
  • Cloud databases full of sensitive financial history
  • Monthly subscriptions for basic metrics

We wanted the opposite.

We wanted a tool that:

  • Works instantly with no login
  • Runs entirely via sovereign computation
  • Processes data locally in the browser
  • Provides real, actionable risk metrics
  • Acts as a public preview of our core engine ahead of launch

This post breaks down how we built the Portfolio Risk Calculator, a zero-login, privacy-first tool that computes portfolio Beta entirely client-side.

Try it live:
Portfolio Risk Calculator →

Launch note: We are going live in 24 hours. This calculator is a public preview of the engine behind Pocket Portfolio.


Sovereign Computation (The Core Idea)

This tool is built around a single principle:

The logic travels to the data — the data never travels to the logic.

Your browser is the compute boundary.

There is:

  • No backend portfolio processing
  • No server-side storage
  • No account system
  • No tracking

This is not “client-heavy.”
This is sovereign computation.


Architecture Overview

The Risk Calculator is a pure client-side React component that:

  1. Accepts comma-separated ticker symbols
  2. Fetches public asset metadata only (Beta, sector, industry)
  3. Computes portfolio Beta locally using TypeScript
  4. Classifies risk visually
  5. Discards everything on refresh

Nothing is persisted. Nothing is uploaded.

Tech Stack

  • Next.js 15 (App Router)
  • TypeScript
  • Client-side computation only
  • Public market metadata APIs
  • No backend portfolio logic

API Privacy (Pre-Empting the Smart Question)

“If you call an API with my tickers, doesn’t the provider know my portfolio?”

Good question. Here’s the precise answer.

What we send:

  • Batched ticker symbols only (e.g. 20–30 at a time)

What we never send:

  • Position sizes
  • Trade history
  • Net worth
  • Identity
  • Portfolio composition

Batching introduces anonymity-through-noise.
Even the API provider cannot infer who you are or what you own.

This is fundamentally different from server-side portfolio tracking.


Core Implementation

1. The Client Component

The calculator is a 'use client' page — intentionally.

'use client';

import { useState } from 'react';
import { fetchAssetProfiles } from '../../services/enrichmentService';
import { AssetProfile } from '../../types/analytics';

export default function RiskCalculatorPage() {
  const [input, setInput] = useState('');
  const [loading, setLoading] = useState(false);
  const [result, setResult] = useState<{
    score: number;
    label: string;
    profiles: AssetProfile[];
  } | null>(null);
  const [error, setError] = useState<string | null>(null);
}

Why client-side?

  • Immediate feedback
  • Zero trust assumptions
  • No global state required
  • No backend failure modes

2. Risk Analysis Logic

const analyzeRisk = async () => {
  const tickers = input
    .split(',')
    .map(t => t.trim().toUpperCase())
    .filter(Boolean);

  const profiles = await fetchAssetProfiles(tickers);

  const validProfiles = Object.values(profiles)
    .filter(p => p.beta !== 0 && p.ticker !== 'CASH');

  const totalBeta = validProfiles.reduce(
    (sum, p) => sum + (p.beta ?? 1),
    0
  );

  const avgBeta = totalBeta / validProfiles.length;

  let label = '⚖️ Balanced Growth';
  if (avgBeta > 1.3) label = ' High Risk / Aggressive';
  if (avgBeta < 0.8) label = '️ Low Risk / Defensive';

  setResult({ score: avgBeta, label, profiles: validProfiles });
};

Why Equal Weight?

This tool is a snapshot, not a full portfolio engine.

  • Users may not know position sizes
  • Simplicity beats false precision
  • Zero-friction entry point

Important bridge:
The full Pocket Portfolio app runs the same privacy-first engine, but applies weighted Beta math using your actual holdings — still entirely local.


Data Fetching with Fallback Strategy

export async function fetchAssetProfiles(
  tickers: string[]
): Promise<Record<string, AssetProfile>> {
  const results: Record<string, AssetProfile> = { ...PROFILE_CACHE };

  const uncached = tickers
    .map(t => t.split('.')[0])
    .filter(t => !results[t]);

  if (uncached.length && FMP_KEY) {
    await Promise.all(
      chunkArray(uncached, 30).map(async batch => {
        try {
          const res = await fetch(
            `${BASE_URL}/profile/${batch.join(',')}?apikey=${FMP_KEY}`
          );
          if (!res.ok) return;

          const data = await res.json();
          data.forEach((item: any) => {
            results[item.symbol] = {
              ticker: item.symbol,
              name: item.companyName ?? item.symbol,
              sector: item.sector ?? 'Other',
              industry: item.industry ?? 'Other',
              beta: item.beta ?? 1,
              geo: item.currency ?? 'US',
            };
          });
        } catch {}
      })
    );
  }

  return results;
}

Why this matters:

  • Cache-first
  • Offline-tolerant
  • API failures don’t break UX
  • Always returns a result

Beta Math (Quick Refresher)

Equal Weight Formula

Portfolio Beta = (B₁ + B₂ + … + Bₙ) / n

Example

  • NVDA (1.7)
  • TSLA (2.3)
  • AAPL (1.2)

Average = 1.73 → High Risk


Privacy-First by Construction

What we do NOT do

  • ❌ No tracking
  • ❌ No cookies
  • ❌ No storage
  • ❌ No user accounts

What we DO

  • ✅ Local computation only
  • ✅ Public metadata only
  • ✅ Zero persistence
  • ✅ GDPR-safe by default

Data Flow

User Input
 → Client Parsing
 → Public Metadata Fetch
 → Local Calculation
 → Display Result
 → Memory Cleared

Why This Exists (The Wedge)

Most developers don’t wake up wanting a portfolio tracker.

They wake up angry that:

  • Their exports are messy
  • Their scripts break
  • Their data is hostage

This calculator solves that problem.

And once you trust the engine, the next step is obvious.


Launch Call to Action

We are launching tomorrow.

If you believe finance software should:

  • Respect user sovereignty
  • Avoid data hoarding
  • Run locally by default

Support the launch on Product Hunt:
Product Hunt → Pocket Portfolio

Use the free tool:
Risk Calculator →


Key Takeaways

  1. Client-side finance is viable
  2. Sovereign computation scales
  3. Privacy is an architectural choice
  4. Free tools can still be honest
  5. Infrastructure beats dashboards

Next Steps

Developers

  • Clone the repo
  • Inspect /app/tools/risk-calculator/page.tsx
  • Submit PRs

Users

  • Try the calculator
  • Join the Founders Club
  • Own your data

About Pocket Portfolio

Pocket Portfolio is a local-first portfolio tracker that turns Google Drive into your personal database.

No servers.
No signups.
No lock-in.

Try it free →


2 Comments

1 vote
0

More Posts

Sovereign Intelligence: The Complete 25,000 Word Blueprint (Download)

Pocket Portfolioverified - Apr 1

How I Built a React Portfolio in 7 Days That Landed ₹1.2L in Freelance Work

Dharanidharan - Feb 9

I’m a Senior Dev and I’ve Forgotten How to Think Without a Prompt

Karol Modelskiverified - Mar 19

TypeScript Complexity Has Finally Reached the Point of Total Absurdity

Karol Modelskiverified - Apr 23

The Privacy Gap: Why sending financial ledgers to OpenAI is broken

Pocket Portfolioverified - Feb 23
chevron_left

Related Jobs

View all jobs →

Commenters (This Week)

3 comments
2 comments

Contribute meaningful comments to climb the leaderboard and earn badges!