Skip to content

Repository files navigation

PSX Investor

A tiny, local tool for disciplined monthly investing on the Pakistan Stock Exchange. Enter how much you want to invest, and it pulls live PSX prices and tells you exactly how many whole shares of each holding to buy to hit your target weights.

Built for a Shariah-compliant / KMI30 portfolio, but the holdings and weights are fully editable, so you can point it at any set of PSX symbols.

Python FastAPI License: MIT

Features

  • Live prices from the PSX data portal (intraday, with end-of-day + cached fallback).
  • Buy plan: enter an amount, get shares-to-buy, cost, leftover cash, and actual vs. target weight per holding.
  • Editable portfolio: change tickers and weights in the browser; saved to data/portfolio.json.
  • Purchase history & positions: record what you actually bought (shares + fill price, prefilled from the plan), then see accumulated holdings, average cost, market value, and unrealized P/L at live prices.
  • Leftover optimizer (optional): spends residual cash on the most-underweight names.
  • Resilient: if a price can't be fetched, it falls back to the last good value and flags it as stale instead of breaking.
  • No Node build: one self-contained HTML page served by a Python backend.

Quickstart

git clone https://github.com/humzakt/psx-investor.git
cd psx-investor
bash run.sh

Then open http://localhost:8787.

run.sh creates a virtualenv, installs dependencies, and starts the server. After the first run you can also start it with:

source .venv/bin/activate
uvicorn app.main:app --port 8787

How it works

browser  ->  GET /api/plan?amount=50000
             |
             FastAPI (app/main.py)
             |-> load_portfolio()      data/portfolio.json
             |-> psx.get_prices()      dps.psx.com.pk  (async, cached, fallback)
             |-> build_plan()          floor(amount * weight / price)
             <-  JSON: rows + totals

The PSX endpoints send no CORS headers, so the Python backend acts as the proxy. See docs/DECISIONS.md for the architecture rationale and AGENTS.md for a contributor/agent guide.

API

Method Path Purpose
GET /api/plan?amount=&optimize=&refresh= Full buy plan
GET /api/prices?refresh= Latest prices for portfolio tickers
GET /api/portfolio Current holdings + weights
PUT /api/portfolio Save edited holdings + weights
GET /api/transactions Purchase history (newest first)
POST /api/transactions Record a batch of purchases
DELETE /api/transactions/{id} Delete one purchase
GET /api/positions?refresh= Accumulated positions valued at live prices
GET /api/health Health check

Interactive docs at /docs.

Configure your portfolio

The app ships with a generic example allocation in data/portfolio.example.json. To use your own:

  • In the app: click Edit weights, adjust tickers/weights, and Save.
  • Or by file: copy the example to data/portfolio.json and edit it:
    cp data/portfolio.example.json data/portfolio.json

Config resolution order (first found wins): private/portfolio.json -> data/portfolio.json -> data/portfolio.example.json. Your data/portfolio.json is git-ignored, so your real allocation is never committed. (The author keeps their personal config and thesis in a separate private repo mounted at private/.)

Your purchase history (transactions.json) is treated the same way: it resolves private/ -> data/ (both git-ignored, no example), so nothing you record is ever committed to the public repo.

Disclaimer

This is not financial advice. It is a personal, educational decision-support tool. Prices come from unofficial endpoints and may be delayed or wrong. It never places trades. Do your own research and consult a licensed advisor before investing.

License

MIT

About

Local FastAPI tool: pulls live PSX prices and turns a monthly PKR amount into a whole-share buy plan for a Shariah/KMI30 portfolio (editable weights).

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages