The Stock Market Portfolio project is a web application that helps users manage and track their investments efficiently. Built using the MERN stack, it offers a scalable and responsive solution for modern financial management.
Prerequisites
Ensure you have the required technologies and tools installed to build and run the MERN-based application.
Create Stock Market Portfolio App
Follow this approach to build a dynamic stock portfolio management application.
- The database stores a list of stock data fetched by the server.
- Users can also manually add stock data via API requests.
- The frontend includes two routes: one for all stocks and another for watchlisted stocks.
- Users can add favorite stocks to a watchlist.
- Stock prices are displayed in green if increasing and red if decreasing.
Steps to Create the Project
Follow these steps to build a full-stack stock market portfolio application using the MERN stack.
Step 1: Create a folder for the project backend and initialized the Express Application.
mkdir stock-market-portfolio
cd stock-market-portfolio
npm init -yStep 2: Install Express and other required packages:
npm install express mongoose body-parser corsFolder Structure:

Dependencies (Backend):
"dependencies": {
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"express": "^4.18.2",
"mongoose": "^8.0.4"
}Example: Create a file named server.js and add the following code.
const express = require("express");
const mongoose = require("mongoose");
const cors = require("cors");
const bodyParser = require("body-parser");
const app = express();
const PORT = process.env.PORT || 5000;
app.use(cors());
app.use(bodyParser.json());
const uri = "Your Mongo URI";
mongoose
.connect(uri)
.then(() => console.log("MongoDB connected"))
.catch((err) => {
console.error("MongoDB connection error:", err);
process.exit(1);
});
const stockSchema = new mongoose.Schema({
company: String,
description: String,
initial_price: Number,
price_2002: Number,
price_2007: Number,
symbol: String,
});
const Stock = mongoose.model("Stock", stockSchema, "stocks");
const watchlistSchema = new mongoose.Schema({
stockId: { type: mongoose.Schema.Types.ObjectId, ref: "Stock" },
addedAt: { type: Date, default: Date.now },
});
const Watchlist = mongoose.model("Watchlist", watchlistSchema);
app.get("/api/stocks", async (req, res) => {
try {
const stocks = await Stock.find();
res.json(stocks);
} catch (error) {
res.status(500).json({ error: "Internal Server Error" });
}
});
app.get("/api/watchlist", async (req, res) => {
try {
const list = await Watchlist.find().populate("stockId");
res.json(list);
} catch (error) {
res.status(500).json({ error: "Internal Server Error" });
}
});
app.post("/api/watchlist", async (req, res) => {
try {
const { stockId } = req.body;
const exists = await Watchlist.findOne({ stockId });
if (exists) return res.json({ message: "Already in watchlist" });
const item = new Watchlist({ stockId });
await item.save();
res.json({ message: "Added to watchlist" });
} catch (error) {
res.status(500).json({ error: "Internal Server Error" });
}
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Step 3: Open the MongoDB atlas or compass and insert the following JSON file in the "stocks" collection.
"https://gist.github.com/stevekinney/f96d5800852e91282f46#file-stocks-json".Step 4: Create the Frontend (React.js) by running the below command.
npx create-react-app stock-market-frontend
cd stock-market-frontendStep 5: Install the required dependencies.
npm install axiosDependencies (Frontend):
"dependencies": {
"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
"@mui/material": "^5.15.4",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.6.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.21.2",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}Example: Write the given code in the respective files.
/* src/App.css */
body {
font-family: 'Arial', sans-serif;
background-color: #d9d7ca;
margin: 0;
padding: 0;
}
.App {
text-align: center;
padding: 20px;
}
h1 {
color: #1f454d;
}
h2 {
color: #3c8d93;
margin-top: 30px;
}
ul {
list-style-type: none;
padding: 0;
}
li {
background-color: #3c8d93;
color: #d9d7ca;
padding: 10px;
margin: 10px 0;
border-radius: 5px;
display: flex;
justify-content: space-between;
align-items: center;
}
button {
background-color: #1f454d;
color: #d9d7ca;
border: none;
padding: 8px;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s ease;
}
button:hover {
background-color: #3c8d93;
}
/* Navigation bar styles */
nav {
background-color: #1f454d;
padding: 15px 0;
}
nav a {
color: #d9d7ca;
text-decoration: none;
margin: 0 20px;
font-size: 18px;
transition: color 0.3s ease;
}
nav a:hover {
color: #3c8d93;
}
// src/App.js
import React, { useState, useEffect } from "react";
import {
BrowserRouter as Router,
Routes,
Route,
NavLink,
Navigate,
} from "react-router-dom";
import "./App.css";
function computeColor(stock) {
if (!stock) return "black";
const current = stock.initial_price;
const compare = stock.price_2007;
if (typeof current === "number" && typeof compare === "number") {
return current >= compare ? "green" : "red";
}
return "black";
}
const Stocks = ({ addToWatchlist }) => {
const [stocks, setStocks] = useState([]);
useEffect(() => {
fetch("http://localhost:5000/api/stocks")
.then((res) => res.json())
.then((data) => setStocks(data))
.catch((error) => console.error("Error fetching stocks:", error));
}, []);
return (
<div className="App" style={{ padding: 16 }}>
<h1>Stock Market MERN App</h1>
<h2>Stocks</h2>
<ul>
{stocks.map((stock) => (
<li key={stock._id || stock.symbol} style={{ marginBottom: 8 }}>
<strong>{stock.company}</strong> ({stock.symbol}) -
<span style={{ color: computeColor(stock), marginLeft: 8 }}>
${stock.initial_price ?? "N/A"}
</span>
<button
style={{ marginLeft: 12 }}
onClick={() => addToWatchlist(stock)}
>
Add to My Watchlist
</button>
</li>
))}
</ul>
</div>
);
};
const Watchlist = ({ watchlist }) => {
return (
<div className="App" style={{ padding: 16 }}>
<h1>Stock Market MERN App</h1>
<h2>My Watchlist</h2>
{watchlist.length === 0 ? (
<p>No items in watchlist.</p>
) : (
<ul>
{watchlist.map((item) => {
const stock = item.stockId || item;
return (
<li key={item._id} style={{ marginBottom: 8 }}>
<strong>{stock.company}</strong> ({stock.symbol}) -
<span style={{ marginLeft: 8 }}>
${stock.initial_price ?? "N/A"}
</span>
</li>
);
})}
</ul>
)}
</div>
);
};
function App() {
const [watchlist, setWatchlist] = useState([]);
const loadWatchlist = () => {
fetch("http://localhost:5000/api/watchlist")
.then((res) => res.json())
.then((data) => setWatchlist(data))
.catch((err) => console.error("Error loading watchlist:", err));
};
useEffect(() => {
loadWatchlist();
}, []);
const addToWatchlist = (stock) => {
fetch("http://localhost:5000/api/watchlist", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ stockId: stock._id }),
})
.then((res) => res.json())
.then((data) => {
alert(data.message || "Action completed");
loadWatchlist();
})
.catch((error) => {
console.error("Error adding to watchlist:", error);
alert("Failed to add to watchlist");
});
};
return (
<Router>
<nav style={{ padding: 12 }}>
<NavLink to="/stocks" style={{ marginRight: 12 }}>
Stocks
</NavLink>
<NavLink to="/watchlist">Watchlist</NavLink>
</nav>
<Routes>
<Route path="/" element={<Navigate to="/stocks" replace />} />
<Route path="/stocks" element={<Stocks addToWatchlist={addToWatchlist} />} />
<Route path="/watchlist" element={<Watchlist watchlist={watchlist} />} />
</Routes>
</Router>
);
}
export default App;
Step 6: Start backend server
cd stock-market-portfolio
npm startStep 7: Start frontend
cd stock-market-frontend
npm startOutput: