Simvest: A Stock Portfolio Simulator

December 8th, 2024

Next.jsTypeScriptTailwind CSSShadCN UI

Simvest is a stock market simulation game that lets you travel back in time and see if you can beat the S&P 500. Start with a virtual $10,000 in a randomly assigned historical period, build your portfolio, and compare your results to a VOO ETF (S&P 500) portfolio. Can you outperform the market?

Why I Built Simvest

I built Simvest as a practice project before my internship at Shopify, with the goal of becoming more comfortable with technologies like React, TypeScript, and component libraries. Since I knew I'd be using Shopify's custom UI library (Polaris), I opted to use ShadCN as a substitute, allowing me to simulate a similar development environment while strengthening my frontend skills.

I was inspired by this TikTok, which explores how much you could have made by investing in certain stocks over time. While many people wonder about the best stocks to pick, most end up just dollar-cost averaging into the S&P 500. Simvest lets you go back in time, invest $10,000 in your favorite stocks, and see—without any real risk—if your picks could actually beat the market. It's a chance to test your instincts and challenge the conventional wisdom of passive investing.

Project Showcase

How it Works

Simvest's core is a technical workflow that connects the frontend and backend to simulate real-world investing. Here's a breakdown of how the system works under the hood:

1. Building the Request (Frontend)

When you submit your portfolio, the frontend gathers all your selected stocks, the number of shares, their purchase prices, and the simulation's time frame. It also calculates how much of your initial $10,000 would have gone into VOO (the S&P 500 ETF) if you had chosen to just track the market. This data is sent as a JSON payload to the backend API:

{
  "vooAmount": 25,
  "holdings": [
    {
      "symbol": "SHOP",
      "name": "SHOPIFY INC.",
      "amount": 12,
      "price": 126.69999694824219,
      "value": 1520.3999633789062
    },
    {
      "symbol": "AMZN",
      "name": "AMAZON COM INC",
      "amount": 51,
      "price": 163.33349609375,
      "value": 8330.00830078125
    }
  ],
  "timeframe": {
    "start": "May 25, 2021",
    "end": "Dec 18, 2023"
  }
}

2. Backend Processing

The backend receives this payload and:

  • Converts the date range to Unix timestamps.
  • Fetches historical daily price data for VOO and each stock in your portfolio from Yahoo Finance.
  • For each day (or week), it calculates:
    • The value of your custom portfolio (sum of shares × closing price for each stock).
    • The value of a VOO-only portfolio (VOO shares × VOO closing price).
  • It then aggregates this data into arrays for charting and summary statistics.
  • The backend also computes all-time-high (ATH), all-time-low (ATL), final value, and percent return for each holding.

Example Backend Calculation (TypeScript):

// For each date, sum up the value of all holdings
customPortfolioValue = sum(holding.amount * holding.closePrice)
vooPortfolioValue = vooAmount * vooClosePrice

3. API Response

The backend returns a JSON object with:

  • Final value, total and percent return for both portfolios
  • Table data for each holding (ATH, ATL, final value, returns)
  • Chart data for plotting both portfolios over time
{
  "vooPortfolio": {
    "value": 10827.25,
    "totalPl": 1214.50,
    "percentPl": 12.63
  },
  "customPortfolio": {
    "value": 8570.31,
    "totalPl": -1228.27,
    "percentPl": -12.54
  },
  "tableData": [
    {
      "symbol": "SHOP",
      "ath": 169.06,
      "atl": 25.67,
      "newPrice": 76.82,
      "newValue": 921.84,
      "totalReturn": -598.56,
      "percentageReturn": -39.37
    },
    {
      "symbol": "AMZN",
      "ath": 186.57,
      "atl": 81.82,
      "newPrice": 149.97,
      "newValue": 7648.47,
      "totalReturn": -681.54,
      "percentageReturn": -8.18
    }
  ],
  "chartData": [
    { "date": "2021-05-25", "vooPortfolio": 9612.75, "customPortfolio": 9798.58 },
    { "date": "2021-05-26", "vooPortfolio": 9630.25, "customPortfolio": 9812.75 },
    // ...
  ]
}

4. Rendering Results (Frontend)

The frontend takes this response and:

  • Renders a chart comparing your portfolio to VOO over time
  • Displays a table with each holding's performance
  • Shows summary cards for your final value, gain/loss, and percent return
  • Provides instant feedback on whether you beat the market or not

This technical pipeline ensures the simulation is both realistic and educational, giving you a true sense of how your investment strategy would have performed in the real world.

Conclusion

Simvest was a rewarding project that allowed me to build a full-stack product from scratch using the same tools and patterns I would encounter during my internship. It gave me hands-on experience with React hooks, custom components, API design, and deploying on Vercel. More importantly, it deepened my understanding of both frontend and backend development, and gave me a practical appreciation for the challenges of building interactive, data-driven apps.

The project also helped me hit the ground running at Shopify, resulting in two positive performance reviews and an offer to extend my internship. While I ultimately couldn't take the extension, the skills and confidence I gained from building Simvest have stayed with me. I'm proud of how the project turned out, and I hope it helps others learn about investing and the realities of trying to beat the market.