Skip to main content

System Architecture

Overview

TradeEntry is a full-stack web application built with a decoupled frontend/backend architecture.

┌───────────────────────────────────────────┐
│ Browser (User) │
│ React 18 + TypeScript │
│ Vite + Tailwind + ShadCN │
└──────────────────┬────────────────────────┘
│ HTTP / REST
┌──────────────────▼────────────────────────┐
│ FastAPI (Python 3.11+) │
│ Uvicorn ASGI server │
│ SQLAlchemy (async) │
│ Pydantic v2 models │
└──────────────────┬────────────────────────┘
│ psycopg2 / asyncpg
┌──────────────────▼────────────────────────┐
│ PostgreSQL 14+ │
│ NSE EOD tables (EQ + FO) │
│ Trade journal tables │
└───────────────────────────────────────────┘

Core Components

Frontend (/frontend)

ComponentTechnology
FrameworkReact 18 + TypeScript
Build ToolVite
UI LibraryShadCN / Radix UI + Tailwind CSS
StateReact Hooks (useState, useCallback, useRef)
HTTP ClientAxios (src/services/api.js)
ChartingLightweight Charts

Backend (/backend)

ComponentTechnology
FrameworkFastAPI
ASGI ServerUvicorn
ORMSQLAlchemy (async) + psycopg2 (sync tasks)
Task QueueFastAPI BackgroundTasks
Data Processingpandas, numpy
NSE DataCustom nseeod package

Data Pipeline (/backend/nseeod)

The nseeod package handles all NSE data ingestion:

NSE Website


BhavProcessor.run_update()
├── NseEodEqUpdater.update() → scr_nseeq_eod table
├── NseEodFoUpdater.update() → scr_nsefo_eod table
└── bhav.generateamiformat() → .txt AMI export files

Key Design Decisions

  1. Background Tasks over Celery — Simple BackgroundTasks used for bhav downloads to avoid Redis/Celery infrastructure complexity.
  2. File-based Status (stats.json) — Progress and logs written to stats.json for polling by the frontend, since WebSocket was not required.
  3. Separate AMI Path — AmiBroker export files stored separately from CSV/bhav copies to allow independent cleanup.
  4. Direct psycopg2 for Bulk Queries — Used alongside SQLAlchemy async for time-series queries that benefit from raw cursor performance.

Security Notes

  • All AMI filenames validated with re.compile(r"^\d{8}\.txt$") before serving.
  • Path traversal prevented via os.path.basename() normalization.
  • No authentication implemented yet (planned for v2.0).

See Deployment Notes for production setup.