How jbocciadev/papertrader works
Purpose and deployment shape
PaperTrader is a paper-trading application split into three deployable services: a market-data service, a trading engine, and a server-rendered web application. Containerization and multi-service orchestration are defined in docker-compose.yml, with per-service images in market-service/Dockerfile, trading-service/Dockerfile, and web-server/Dockerfile.
Service entry points
• Market service: Node.js entry point at market-service/app.js; its package/runtime boundary is defined by market-service/package.json.
• Trading service: Python application starts at trading-service/main.py; gRPC serving is separated into trading-service/app/grpc_server.py.
• Web server: Python web entry point is web-server/app/main.py, serving application pages and static browser assets.
Market-data ingestion boundary
The market service is the external-market integration boundary. The README states it queries Finnhub using cURL-style quote requests and accepts ticker selection through the TICKERS environment variable. This isolates third-party quote retrieval from trading and UI concerns.
Grounding: market-service/app.js, market-service/package.json, market-service/Dockerfile.
Trading engine and RPC contract
The trading service owns trade-processing behavior and exposes it through gRPC. Its engine implementation is in trading-service/app/engine.py, while server-side request handling is in trading-service/app/grpc_server.py. The cross-service API is defined centrally in protos/engine.proto; generated Python bindings are checked into trading-service/app/engine_pb2.py and trading-service/app/engine_pb2_grpc.py.
Primary control flow is expected to cross this boundary as: caller submits an engine RPC → gRPC server dispatches to the engine → engine reads/writes trading state → response returns over the protobuf contract.
Persistence and trading state
The trading service maintains its own persistence layer and domain models, keeping business state behind the engine boundary. Database setup/access and initialization are separated from engine logic.
Grounding: trading-service/app/database.py, trading-service/app/models.py, trading-service/app/init_db.py.
SQLite is the intended development/test database, with PostgreSQL identified as the prospective deployment database. Database implementation details should therefore preserve portability across those backends.
Web application and browser boundary
The web server is a server-rendered Python application with landing, registration, login, dashboard, and profile views. It has its own models and database layer, suggesting web/account-facing state is managed separately from the trading-service persistence boundary.
Grounding: web-server/app/main.py, web-server/app/models.py, web-server/app/database.py.
The browser-facing dashboard consumes static JavaScript for holdings and ticker streaming, while HTML templates remain on the server-rendered side.
Grounding: web-server/app/templates/dashboard.html, web-server/app/static/js/holdings.js, web-server/app/static/js/ticker-stream.js.
Key integration and operational concerns
The web server contains generated gRPC client bindings (web-server/app/engine_pb2.py, web-server/app/engine_pb2_grpc.py), indicating it is the likely RPC client of the trading engine. The protobuf file is the compatibility-critical contract between them.
Environment configuration includes ticker selection and a development TLS workaround (NODE_TLS_REJECT_UNAUTHORIZED=0). The latter is explicitly non-production-safe and should be replaced by valid certificate handling. The application currently permits trades outside US market hours; market-hours enforcement is a future production policy boundary rather than a current engine constraint.
Main entry points: main.py Server-rendered web app · grpc_server.py gRPC server · docker-compose.yml Service orchestration · engine.py Trade engine
Components 20
Deployment
- Service orchestration · Runs the three deployable services.
docker-compose.yml
Market data
- Market image
market-service/Dockerfile - Quote ingestion · Retrieves selected ticker quotes from the external market API.
market-service/app.js - Node runtime
market-service/package.json
Trading engine
- Engine RPC contract · Compatibility-critical cross-service API.
protos/engine.proto - gRPC server · Dispatches engine RPCs to trading behavior.
trading-service/app/grpc_server.py - Trade engine · Owns trade-processing behavior and trading state access.
trading-service/app/engine.py - Trading models
trading-service/app/models.py - Trading persistence · Portable persistence targeting SQLite development and future PostgreSQL.
trading-service/app/database.py - Database initialization
trading-service/app/init_db.py - Trading process
trading-service/main.py
Web application
- Server-rendered web app · Serves landing, account, dashboard, and profile pages.
web-server/app/main.py - Account models
web-server/app/models.py - Account persistence · Separate web and account-facing state boundary.
web-server/app/database.py - Engine gRPC client
web-server/app/engine_pb2_grpc.py - Dashboard template
web-server/app/templates/dashboard.html - Holdings client
web-server/app/static/js/holdings.js - Ticker stream client
web-server/app/static/js/ticker-stream.js
Other components
- Finnhub
- Browser
Connections 22
- Service orchestration → Market image: builds
- Service orchestration → Trading process: runs
- Service orchestration → Server-rendered web app: runs
- Market image → Quote ingestion: packages
- Node runtime → Quote ingestion: defines runtime
- Quote ingestion → Finnhub: quote requests
- Trading process → gRPC server: starts
- Engine RPC contract → gRPC server: defines RPCs
- gRPC server → Trade engine: dispatches
- Trade engine → Trading models: uses
- Trade engine → Trading persistence: reads and writes
- Database initialization → Trading persistence: initializes
- Server-rendered web app → Account models: uses
- Server-rendered web app → Account persistence: reads and writes
- Server-rendered web app → Engine gRPC client: submits engine RPCs
- Engine gRPC client → Engine RPC contract: implements
- Engine gRPC client → gRPC server: gRPC calls
- Server-rendered web app → Dashboard template: renders
- Dashboard template → Holdings client: loads
- Dashboard template → Ticker stream client: loads
- Browser → Server-rendered web app: HTTP requests
- Server-rendered web app → Browser: pages and assets