Takes a list of stocks and quantities, connects to your broker, and automatically places the necessary buy/sell orders in one API call.
- Zerodha (Kite Connect)
- Fyers (API v3)
- AngelOne (SmartAPI)
- Groww (Partner API)
- Upstox (API v2)
app/
├── models/schemas.py # All data models
├── brokers/
│ ├── base.py # Broker interface (abstract class)
│ ├── registry.py # Broker lookup table
│ ├── zerodha.py # Zerodha adapter
│ ├── fyers.py # Fyers adapter
│ ├── angelone.py # AngelOne adapter
│ ├── groww.py # Groww adapter
│ └── upstox.py # Upstox adapter
├── core/engine.py # Main execution logic
├── notifications/notifier.py # Console, Webhook, WebSocket notifications
├── api/routes.py # API endpoints
└── main.py # App entry point
# Create virtual environment
python3.10 -m venv venv
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Start the API
uvicorn app.main:app --reload
# Start the frontend (separate terminal)
streamlit run frontend.pydocker-compose up --build| Method | URL | Description |
|---|---|---|
| GET | /api/v1/health | Health check |
| GET | /api/v1/examples | Example request payloads |
| POST | /api/v1/execute | Execute portfolio trades |
| WS | /api/v1/ws | Live notifications |
Send a target portfolio — engine figures out what to buy:
{
"broker": "zerodha",
"api_key": "your_key",
"api_secret": "your_secret",
"target_portfolio": {
"RELIANCE": 10,
"TCS": 5,
"INFY": 8
}
}Send explicit instructions — engine executes them directly:
{
"broker": "zerodha",
"api_key": "your_key",
"api_secret": "your_secret",
"instructions": [
{"symbol": "RELIANCE", "instruction": "SELL", "quantity": 3},
{"symbol": "TCS", "instruction": "BUY", "quantity": 5},
{"symbol": "INFY", "instruction": "REBALANCE", "quantity": 2}
]
}Request comes in
↓
Authenticate with broker
↓
First-time buy? → fetch current holdings → compute delta
Rebalancing? → use instructions directly
↓
Execute all orders concurrently
↓
Retry failed orders (up to 3 times)
↓
Send notifications (console + websocket + webhook)
↓
Return summary
- Console — always printed to terminal
- WebSocket — connect to
/api/v1/wsfor live updates - Webhook — pass
?webhook_url=https://your-url.comto the execute endpoint
- Create
app/brokers/newbroker.pywith your adapter class - Add the broker name to
BrokerNameenum inschemas.py - Add one line to
BROKER_REGISTRYinregistry.py
Zero changes needed anywhere else.
Adapter Pattern — each broker has its own adapter class implementing the same interface. The engine never talks to broker-specific code directly.
Concurrent Execution — all orders run simultaneously using asyncio.gather(). A 20-stock portfolio takes the same time as 1 order.
Retry with Backoff — failed orders are retried up to 3 times with increasing wait times (1.5s → 2.25s → 3.37s).
Separation of Concerns — routes handle HTTP, engine handles logic, adapters handle brokers, notifiers handle alerts. No file does more than one job.
- All broker calls are mocked for this assignment. Real SDK calls are shown in comments inside each adapter file.
- Brokers require real credentials and browser-based OAuth login for production use.