Metadata-Version: 2.4
Name: pypsx
Version: 2.5.1
Summary: Pakistan Stock Exchange (PSX) Trading SDK for Paper Trading and Backtesting
Author: PyPSX Team
License: Proprietary
Project-URL: Homepage, https://pypsx.com
Keywords: trading,stock,psx,pakistan,simulation,backtesting,algorithmic-trading
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: Other/Proprietary License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Office/Business :: Financial :: Investment
Classifier: Topic :: Scientific/Engineering :: Mathematics
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: pydantic>=2.0.0
Requires-Dist: httpx>=0.24.0
Requires-Dist: sqlalchemy>=2.0.0
Requires-Dist: pandas<3.0.0,>=1.5.0
Requires-Dist: numpy<2.4.0,>=1.24.0
Requires-Dist: ta>=0.11.0
Requires-Dist: tzdata>=2024.1
Requires-Dist: fastapi>=0.110.0
Requires-Dist: uvicorn>=0.23.0
Requires-Dist: psycopg2-binary>=2.9.0
Requires-Dist: websockets>=12.0
Requires-Dist: python-dateutil>=2.8.0
Requires-Dist: requests>=2.31.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
Requires-Dist: black>=23.0.0; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"
Provides-Extra: jupyter
Requires-Dist: nest-asyncio>=1.5.0; extra == "jupyter"

# PyPSX SDK

API-first trading infrastructure for the Pakistan Stock Exchange.

## Installation

```bash
pip install pypsx
```

## Try it in a notebook

[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1ac6yt0dlTzpBR16qS_-ltYuImVyyr2PG?usp=sharing)

## One-liners — no client to construct

```python
import pypsx

df = pypsx.download("OGDC", period="1y")
result = pypsx.backtest("dual_sma_momentum", "OGDC", period="1y", initial_cash=1_000_000)
quote = pypsx.get_quote("OGDC")
depth = pypsx.get_market_depth("OGDC")
```

These read `PYPSX_API_KEY_ID`/`PYPSX_API_SECRET_KEY` from the environment automatically. For order placement, positions, and account state, use `TradingClient` below.

## Quick Start

Start with paper trading. It is the safety-first way to test your strategy, validate your order flow, and watch your dashboard update in real time before risking real capital.

```python
import os
from dotenv import load_dotenv
from pypsx import TradingClient

load_dotenv()

client = TradingClient(
    api_key=os.getenv("PYPSX_API_KEY_ID"),
    secret_key=os.getenv("PYPSX_API_SECRET_KEY"),
    paper=True,
)

account = client.get_account()
print(f"Connected! Current Balance: PKR {account.cash}")

order = client.place_manual_order(
    symbol="OGDC",
    side="BUY",
    quantity=10,
    order_type="MARKET",
)

print("Submitted:", order["order_id"], order["status"])
```

You can also load keys directly from environment variables:

```python
from pypsx import TradingClient

client = TradingClient.from_env(paper=True)
```

### Your First Trade

**Step 1:** Generate a paper key in the PyPSX dashboard.  
**Step 2:** Copy the script above into `my_bot.py`.  
**Step 3:** Set your own `PYPSX_API_KEY_ID` and `PYPSX_API_SECRET_KEY` in `.env`.  
**Step 4:** Run `python my_bot.py` while the market is open.  
**Step 5:** Watch orders, fills, and positions appear in the dashboard automatically.

## The Power of PyPSX

PyPSX gives algorithmic traders a clean Python interface for the Pakistan Stock Exchange without exposing them to exchange plumbing.

### Paper Trading

PyPSX currently operates in paper trading mode: simulated orders, no real
money.

### Real-Time Trading Experience

With PyPSX you can:

- Read positions, orders, and account state from Python
- Submit orders with a simple REST interface
- See fills reflected in the web dashboard without manual refresh
- Build bots around trading logic instead of exchange protocol handling

### Developer's Promise

PyPSX handles the operational complexity of PSX integration, including request authentication, endpoint routing, and exchange connectivity. You focus on signal generation, risk rules, and execution logic. We handle the FIX-side complexity behind the API.

## Authentication

### How To Get Your Keys

1. Sign in to the PyPSX dashboard.
2. Open `Settings`.
3. Select the account you want to trade.
4. Click `Generate Paper Key` or `Generate Live Key`.
5. Copy the `Public Key ID` and `Secret Key`.

### How The SDK Uses Them

Use the credentials directly in `TradingClient(...)`:

```python
from pypsx import TradingClient

client = TradingClient(
    api_key=os.getenv("PYPSX_API_KEY_ID"),
    secret_key=os.getenv("PYPSX_API_SECRET_KEY"),
    paper=True,
)
```

Under the hood, the SDK automatically sends:

```http
PYPSX-API-KEY-ID: <your-public-key-id>
PYPSX-API-SECRET-KEY: <your-secret-key>
```

If you are building against the API without the Python SDK, send those same headers yourself.

## API Reference

| Method | What it does | Returns |
| --- | --- | --- |
| `get_account(account_id=None)` | Account snapshot: `cash`, `equity`, `buying_power`, `can_trade` (attribute access supported) | `dict` |
| `get_portfolio_valuation()` | Returns the latest equity, cash, positions value, and pricing snapshot | `dict` |
| `get_positions()` | Returns open positions for the selected paper trading account | `list[dict]` |
| `get_orders(limit=...)` | Returns recent orders and their current state | `list[dict]` |
| `place_manual_order(...)` | Submits a market or priced order through the selected environment | `dict` |
| `get_symbols()` | Fetches available market symbols | `list[dict]` |
| `get_intraday(symbol, days=...)` | Retrieves recent intraday market data for a symbol | `list[dict]` |
| `get_historical(symbol, start=..., end=...)` | Retrieves historical daily bars for strategy research and analysis | `list[dict]` |
| `get_historical_intraday(symbols, start=..., end=..., interval=...)` | Retrieves multi-interval OHLCV candles (1m/5m/15m/1h) | `list[dict]` |
| `get_portfolio(bot_id=None)` | Raw portfolio dict for the current bot/account scope | `dict` |
| `get_account_config(account_id=None)` | Account-level configuration | `dict` |
| `get_fundamentals(symbol)` | `pe_ratio`, `dividend_yield`, `market_cap`, `free_float`, etc. for a symbol | `dict` |
| `get_dividends(symbol)` | Dividend history: `year`, `amount`, `ex_date`, `payment_date`, `record_date` | `list[dict]` |
| `get_commission_rate()` | The account's commission rate percentage (cached after first call) | `float` |
| `add_funds(amount, account_id=None, bot_id=None)` | Add paper cash to an account | `dict` |
| `get_performance(bot_id=None, limit=100)` | Historical performance snapshots for a bot | `dict` |
| `get_trades(bot_id=None, limit=100)` | Executed trade history for a bot | `dict` |
| `get_logs(bot_id=None, limit=200)` | Bot run logs | `dict` |
| `list_bots()` | List all bots registered under the account | `list[dict]` |
| `create_bot(bot_id, bot_label=None, strategy_name=None, symbols=None, cycle_minutes=None)` | Register a new cloud bot | `dict` |
| `place_bracket_order(symbol, side, quantity, stop_loss_price, take_profit_price, entry_type="MARKET", ...)` | Entry order plus a linked stop-loss/take-profit exit pair | `dict` |
| `place_oco_order(symbol, quantity, stop_loss_price, take_profit_price, ...)` | Attach a linked stop-loss/take-profit pair to an existing position | `dict` |
| `place_stop_order(symbol, quantity, trigger_price, limit_price=None, ...)` | Standalone stop order | `dict` |
| `get_order_executions(since=None, limit=1000)` | Raw fill/execution records for the current bot scope | `list[dict]` |
| `close()` | Closes the underlying HTTP client cleanly | `None` |

## Examples

### Paper Trading

```python
import os
from pypsx import TradingClient

client = TradingClient(
    api_key=os.getenv("PYPSX_API_KEY_ID"),
    secret_key=os.getenv("PYPSX_API_SECRET_KEY"),
    paper=True,
)

valuation = client.get_portfolio_valuation()
positions = client.get_positions()
orders = client.get_orders(limit=25)

print("Equity:", valuation["equity"])
print("Positions:", len(positions))
print("Orders:", len(orders))
```

### Simple Bot Pattern

```python
from pypsx import TradingClient

SYMBOL = "OGDC"

client = TradingClient(
    api_key="PK_xxxxxxxxxxxx",
    secret_key="your_secret_key",
    paper=True,
)

positions = client.get_positions()
already_holding = any(
    position["symbol"] == SYMBOL and float(position["qty"]) > 0
    for position in positions
)

if not already_holding:
    client.place_manual_order(
        symbol=SYMBOL,
        side="BUY",
        quantity=10,
        order_type="MARKET",
    )
```

## Best Practices

- Use `.env` files or a secrets manager for credentials. Do not hardcode production keys into source control.
- Start every new strategy with `paper=True`.
- Treat paper trading as your pre-flight checklist before switching to live.
- Run execution scripts when the market is open so fills, liquidity, and dashboard feedback reflect real conditions.
- Add explicit guards in your code for position sizing, duplicate orders, and risk limits.
- Close clients cleanly with `client.close()` in longer-running scripts or services.

## Raw HTTP Example

If you are not using the SDK, this is the equivalent request format:

```bash
curl -X POST "$PYPSX_API_BASE_URL/orders" \
  -H "Content-Type: application/json" \
  -H "PYPSX-API-KEY-ID: $PYPSX_API_KEY_ID" \
  -H "PYPSX-API-SECRET-KEY: $PYPSX_API_SECRET_KEY" \
  -d "{\"symbol\":\"OGDC\",\"side\":\"BUY\",\"quantity\":10,\"order_type\":\"MARKET\",\"mode\":\"PAPER\",\"commission_rate\":0.02}"
```

Set `commission_rate` only when you want to override the default fee behavior for a specific order. The value is a percentage, so `0.02` means `0.02%`.

## Additional Examples

- `examples/pypsx_client_example.py`
- `examples/example_bot.py`
