A full-stack paper-trading platform built with React, Vite, Node.js, Express, and SQLite.
TradeNet lets users create a local account, manage virtual funds, track a portfolio, and place simulated buy/sell orders. It can also retrieve current US stock quotes through Twelve Data when an API key is configured.
Educational project only. TradeNet does not execute real brokerage orders, handle real money, or provide investment advice.
- User signup and login
- Password hashing and session-based authentication
- Virtual starting balance
- Paper buy and sell orders
- Holdings and portfolio tracking
- Order history
- Daily positions
- Virtual fund deposits and withdrawals
- Support request system
- SQLite persistence
- Optional current US stock quotes
- Market-data caching and fallback prices
- Responsive React dashboard
- Local development and production-style modes
- React
- Vite
- JavaScript
- CSS
- Node.js
- Express
- SQLite
- Twelve Data API
- npm
- Git
- GitHub
- VS Code
Screenshots can be added here once they are committed to the repository.
screenshots/
├── home.png
├── dashboard.png
├── holdings.png
└── orders.png
Example:
Make sure you have:
- Node.js 24 or newer
- npm
- Git
- Optional Twelve Data API key
Check your Node version:
node --versionClone the repository:
git clone https://github.com/shivek16/TradeNet.gitEnter the project:
cd TradeNetInstall dependencies:
npm ciCreate your local environment file:
Copy-Item .env.example .envOpen it in VS Code:
code .envAdd your Twelve Data API key:
TWELVE_DATA_API_KEY=YOUR_PRIVATE_API_KEY
MARKET_CACHE_MS=65000Never commit your real .env file.
The repository includes .env.example so other developers can see which environment variables are required without exposing private credentials.
Start TradeNet:
npm run devThe frontend will run at:
http://127.0.0.1:5173/
The backend API runs at:
http://127.0.0.1:3002/
Vite proxies frontend /api requests to the Express backend.
Build the frontend:
npm run buildThen start Express:
npm startOpen:
http://127.0.0.1:3002/
In this mode, Express serves both the frontend build and API from the same origin.
TradeNet currently supports these demonstration US symbols:
| Symbol | Company |
|---|---|
| AAPL | Apple |
| MSFT | Microsoft |
| NVDA | NVIDIA |
| AMZN | Amazon |
| GOOGL | Alphabet |
| META | Meta Platforms |
| TSLA | Tesla |
When a Twelve Data API key is configured, the backend requests updated market quotes and caches them to reduce API usage.
The dashboard shows these market-data states:
LIVE— all requested symbols have fresh provider timestamps and are not reported closedPARTIAL— some symbols are live and others are cached/sampleSAMPLE— no API key is configured;DELAYED,CLOSEDandUNAVAILABLEdistinguish other states
Buy/sell orders always use the latest quote selected by the backend, not a price supplied by the browser. When an API key is configured, new paper orders pause if the quote is stale, unavailable, or the provider reports the market closed. Sample-price trading is only available when no key is configured. Retried completed orders retain their original fill.
Availability and freshness of market data depend on the Twelve Data plan and exchange access.
Trades are simulated.
When a buy or sell order is placed:
- The frontend sends the order request to the backend.
- The backend determines the execution price.
- The user's virtual cash and holdings are updated.
- The order is saved in SQLite.
- The dashboard refreshes the portfolio.
The browser does not directly control the execution price.
Buy/sell orders always use the latest quote selected by the backend, not a price supplied by the browser. When an API key is configured, new paper orders pause if the quote is stale, unavailable, or the provider reports the market closed. Sample-price trading is only available when no key is configured. Retried completed orders retain their original fill.
TradeNet uses a local SQLite database:
data/trading.sqlite
It is automatically created when the backend starts.
Stored account data includes:
- Users
- Sessions
- Virtual cash
- Holdings
- Orders
- Transactions
- Support requests
The local data/ directory is excluded from Git.
To completely reset your local TradeNet data, stop the server and delete the data directory.
This permanently removes local accounts and portfolio data.
TradeNet/
│
├── backend/
│ ├── market.js
│ ├── seed.json
│ └── server.js
│
├── dashboard/
│ └── src/
│ └── Dashboard.jsx
│
├── frontend/
│ └── src/
│ ├── api.js
│ ├── main.jsx
│ └── styles.css
│
├── scripts/
│ └── dev.js
│
├── tests/
│ └── api.test.js
│
├── .env.example
├── .gitignore
├── index.html
├── package.json
├── package-lock.json
├── vite.config.js
└── README.md
npm run devnpm run buildnpm startnpm testnpm run checknpm run check runs the project tests and production build.
Run:
npm run devThen use one of these addresses:
http://127.0.0.1:5173/
or
http://localhost:5173/
The backend probably failed to start.
Check the terminal for the actual backend error.
You can also verify that the market service exists:
Test-Path .\backend\market.jsExpected:
True
Make sure .env exists:
Get-ChildItem -Force .envThen check that your Twelve Data key has been added.
Restart TradeNet after changing .env:
npm run devStop the running development process with:
Ctrl + C
Then start it again:
npm run devTradeNet includes several protections appropriate for a local educational project:
- Password hashing
- HTTP-only sessions
- Origin validation for mutation requests
- Backend-controlled trade execution prices
- Private
.envconfiguration - SQLite account separation
This project has not been designed or audited for real-money brokerage use or public financial infrastructure.
TradeNet is an independent educational project.
It is not affiliated with Zerodha, Twelve Data, NASDAQ, NYSE, or any brokerage or exchange.
Stock prices may be delayed, cached, simulated, or unavailable depending on API configuration.
Nothing in this project should be considered financial or investment advice.
Shivek
GitHub: @shivek16
This project can be licensed under the MIT License for educational and portfolio use.
The Overview dashboard now includes a candlestick chart and separate volume bars, a stock selector, 1m/5m/15m/1H/1D timeframes, hover OHLC readout, zoom, history navigation and buy/sell shortcuts. No additional dependencies are required.
History is fetched server-side from Twelve Data /time_series, in UTC, and displayed in Eastern Time for intraday bars. The server caches each symbol/interval for 65 seconds and shares requests between clients. History contains up to 200 provider bars. New ticks update the active candle and selected stock valuation. Stream-built candles are provisional, based on ticks actually received; history refresh reconciles them. Missing intervals are not invented. Volume is refreshed from provider history, not manufactured from price ticks; a new streaming candle shows volume as pending until supplied by history.
One server-side Twelve Data WebSocket is shared across viewers. An authenticated EventSource connection relays only the selected symbol to each browser. Keys never appear in client JavaScript or events. Idle subscriptions are removed. Reconnects are automatic. Symbols not covered by the streaming subscription continue to use periodic history requests. A connection alone is not labeled STREAMING: a recent timestamped tick must actually arrive.
Your provider plan controls symbol coverage, history access, latency, and API/WebSocket credits. The app does not unlock access the plan does not include. Seven watchlist quotes plus a new chart request can consume a basic plan's minute allowance. Rapidly switching timeframes can trigger rate limits; the UI displays the failure and retries later. No automatic paid upgrade is performed. Free/limited plans may not provide tick streaming for the chosen stock.
Official provider documentation:
- https://support.twelvedata.com/en/articles/5620516-how-to-stream-the-data
- https://support.twelvedata.com/en/articles/5194610-websocket-faq
Stop the old server first. Copy the updated source into the project directory while keeping your existing .env and data directory. Neither is included in the distributable ZIP. Then run npm ci followed by npm run dev, and open http://127.0.0.1:5173/ . The separate dist build can also be served with npm start.
Previously owned symbols remain supported when loading an existing database even if removed from the default watchlist. Quote cache freshness is tracked per symbol, and concurrent quote requests wait on their shared provider request.
npm run check includes market-specific tests for concurrent quotes, stale/partial responses, missing keys, history parsing/caching, candle aggregation, stream routing and cleanup, authenticated chart endpoints and blocking stale-price orders. Tests use controlled provider fixtures, not your real API account.