pypsx 2.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,36 @@
1
+ # pypsx SDK Package Manifest
2
+ # This file controls what gets included in the PyPI distribution.
3
+ # For closed-source distribution: only compiled binaries + .pyi stubs are shipped.
4
+
5
+ include README.md
6
+ include LICENSE
7
+
8
+ # Include stub files and py.typed marker (required for IDE autocomplete)
9
+ recursive-include pypsx *.pyi
10
+ recursive-include pypsx py.typed
11
+
12
+ # Keep dashboard assets (HTML/CSS/JS for the local dashboard UI)
13
+ recursive-include pypsx/dashboard/assets *
14
+
15
+ # Include cache SQL schema
16
+ recursive-include pypsx/data/cache *.sql
17
+
18
+ # Exclude all .py implementation files so source code is not leaked, then
19
+ # re-include only what setup.py's EXCLUDE_STEMS keeps as plain Python.
20
+ # These re-includes MUST come after this exclude -- MANIFEST.in processes
21
+ # include/exclude directives in file order, so anything included earlier
22
+ # gets silently undone here otherwise.
23
+ recursive-exclude pypsx *.py
24
+ recursive-include pypsx __init__.py
25
+ include pypsx/utils/enums.py
26
+ include pypsx/utils/exceptions.py
27
+
28
+ # Exclude development/build artefacts
29
+ prune examples
30
+ prune tests
31
+ prune scripts
32
+ prune build
33
+ prune dist
34
+ prune *.egg-info
35
+ recursive-exclude . *.log *.db *.sqlite *.pyc
36
+ exclude .*
pypsx-2.4.0/PKG-INFO ADDED
@@ -0,0 +1,305 @@
1
+ Metadata-Version: 2.4
2
+ Name: pypsx
3
+ Version: 2.4.0
4
+ Summary: Pakistan Stock Exchange (PSX) Trading SDK for Paper Trading and Backtesting
5
+ Author: PyPSX Team
6
+ License: Proprietary
7
+ Project-URL: Homepage, https://github.com/yourusername/pypsx
8
+ Project-URL: Documentation, https://github.com/yourusername/pypsx/blob/main/README.md
9
+ Project-URL: Repository, https://github.com/yourusername/pypsx
10
+ Keywords: trading,stock,psx,pakistan,simulation,backtesting,algorithmic-trading
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Financial and Insurance Industry
14
+ Classifier: License :: Other/Proprietary License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Classifier: Topic :: Office/Business :: Financial :: Investment
21
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ Requires-Dist: pydantic>=2.0.0
25
+ Requires-Dist: httpx>=0.24.0
26
+ Requires-Dist: sqlalchemy>=2.0.0
27
+ Requires-Dist: pandas<2.3.3,>=1.5.0
28
+ Requires-Dist: numpy<2.3.0,>=1.24.0
29
+ Requires-Dist: ta>=0.11.0
30
+ Requires-Dist: tzdata>=2024.1
31
+ Requires-Dist: fastapi>=0.110.0
32
+ Requires-Dist: uvicorn>=0.23.0
33
+ Requires-Dist: psycopg2-binary>=2.9.0
34
+ Requires-Dist: websockets>=12.0
35
+ Requires-Dist: python-dateutil>=2.8.0
36
+ Requires-Dist: requests>=2.31.0
37
+ Provides-Extra: dev
38
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
39
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
40
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
41
+ Requires-Dist: black>=23.0.0; extra == "dev"
42
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
43
+ Provides-Extra: jupyter
44
+ Requires-Dist: nest-asyncio>=1.5.0; extra == "jupyter"
45
+
46
+ # PyPSX SDK
47
+
48
+ API-first trading infrastructure for the Pakistan Stock Exchange.
49
+
50
+ ## Installation
51
+
52
+ ```bash
53
+ pip install pypsx
54
+ ```
55
+
56
+ ## Try it in a notebook
57
+
58
+ [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1ac6yt0dlTzpBR16qS_-ltYuImVyyr2PG?usp=sharing)
59
+
60
+ ## One-liners — no client to construct
61
+
62
+ ```python
63
+ import pypsx
64
+
65
+ df = pypsx.download("OGDC", period="1y")
66
+ result = pypsx.backtest("dual_sma_momentum", "OGDC", period="1y", initial_cash=1_000_000)
67
+ quote = pypsx.get_quote("OGDC")
68
+ depth = pypsx.get_market_depth("OGDC")
69
+ ```
70
+
71
+ These read `PYPSX_API_KEY_ID`/`PYPSX_API_SECRET_KEY` from the environment automatically. For order placement, positions, and account state, use `TradingClient` below.
72
+
73
+ ## Quick Start
74
+
75
+ 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.
76
+
77
+ ```python
78
+ import os
79
+ from dotenv import load_dotenv
80
+ from pypsx import TradingClient
81
+
82
+ load_dotenv()
83
+
84
+ client = TradingClient(
85
+ api_key=os.getenv("PYPSX_API_KEY_ID"),
86
+ secret_key=os.getenv("PYPSX_API_SECRET_KEY"),
87
+ paper=True,
88
+ )
89
+
90
+ account = client.get_account()
91
+ print(f"Connected! Current Balance: PKR {account.cash}")
92
+
93
+ order = client.place_manual_order(
94
+ symbol="OGDC",
95
+ side="BUY",
96
+ quantity=10,
97
+ order_type="MARKET",
98
+ )
99
+
100
+ print("Submitted:", order["order_id"], order["status"])
101
+ ```
102
+
103
+ You can also load keys directly from environment variables:
104
+
105
+ ```python
106
+ from pypsx import TradingClient
107
+
108
+ client = TradingClient.from_env(paper=True)
109
+ ```
110
+
111
+ ### Your First Trade
112
+
113
+ **Step 1:** Generate a paper key in the PyPSX dashboard.
114
+ **Step 2:** Copy the script above into `my_bot.py`.
115
+ **Step 3:** Set your own `PYPSX_API_KEY_ID` and `PYPSX_API_SECRET_KEY` in `.env`.
116
+ **Step 4:** Run `python my_bot.py` while the market is open.
117
+ **Step 5:** Watch orders, fills, and positions appear in the dashboard automatically.
118
+
119
+ ## The Power of PyPSX
120
+
121
+ PyPSX gives algorithmic traders a clean Python interface for the Pakistan Stock Exchange without exposing them to exchange plumbing.
122
+
123
+ ### Paper And Live Modes
124
+
125
+ The SDK automatically routes traffic based on one flag:
126
+
127
+ - `paper=True` sends requests to the paper trading environment at `https://paper-api.pypsx.com`
128
+ - `paper=False` sends requests to the live trading environment at `https://api.pypsx.com`
129
+
130
+ This keeps your code identical across testing and production. Change the credentials, switch the flag, and keep your trading logic the same.
131
+
132
+ ### Real-Time Trading Experience
133
+
134
+ With PyPSX you can:
135
+
136
+ - Read positions, orders, and account state from Python
137
+ - Submit orders with a simple REST interface
138
+ - See fills reflected in the web dashboard without manual refresh
139
+ - Build bots around trading logic instead of exchange protocol handling
140
+
141
+ ### Developer's Promise
142
+
143
+ 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.
144
+
145
+ ## Authentication
146
+
147
+ ### How To Get Your Keys
148
+
149
+ 1. Sign in to the PyPSX dashboard.
150
+ 2. Open `Settings`.
151
+ 3. Select the account you want to trade.
152
+ 4. Click `Generate Paper Key` or `Generate Live Key`.
153
+ 5. Copy the `Public Key ID` and `Secret Key`.
154
+
155
+ ### How The SDK Uses Them
156
+
157
+ Use the credentials directly in `TradingClient(...)`:
158
+
159
+ ```python
160
+ from pypsx import TradingClient
161
+
162
+ client = TradingClient(
163
+ api_key=os.getenv("PYPSX_API_KEY_ID"),
164
+ secret_key=os.getenv("PYPSX_API_SECRET_KEY"),
165
+ paper=True,
166
+ )
167
+ ```
168
+
169
+ Under the hood, the SDK automatically sends:
170
+
171
+ ```http
172
+ PYPSX-API-KEY-ID: <your-public-key-id>
173
+ PYPSX-API-SECRET-KEY: <your-secret-key>
174
+ ```
175
+
176
+ If you are building against the API without the Python SDK, send those same headers yourself.
177
+
178
+ ## API Reference
179
+
180
+ | Method | What it does | Returns |
181
+ | --- | --- | --- |
182
+ | `get_account_config()` | Fetches trading permissions and account-level configuration | `dict` |
183
+ | `get_portfolio_valuation()` | Returns the latest equity, cash, positions value, and pricing snapshot | `dict` |
184
+ | `get_positions()` | Returns open positions for the selected paper or live account | `list[dict]` |
185
+ | `get_orders(limit=...)` | Returns recent orders and their current state | `list[dict]` |
186
+ | `place_manual_order(...)` | Submits a market or priced order through the selected environment | `dict` |
187
+ | `get_symbols()` | Fetches available market symbols | `list[dict]` |
188
+ | `get_intraday(symbol, days=...)` | Retrieves recent intraday market data for a symbol | `list[dict]` |
189
+ | `get_historical(symbol, start=..., end=...)` | Retrieves historical daily bars for strategy research and analysis | `list[dict]` |
190
+ | `get_historical_intraday(symbols, start=..., end=..., interval=...)` | Retrieves multi-interval OHLCV candles (1m/5m/15m/1h) | `list[dict]` |
191
+ | `get_portfolio(bot_id=None)` | Raw portfolio dict for the current bot/account scope | `dict` |
192
+ | `get_account_config(account_id=None)` | Account-level configuration | `dict` |
193
+ | `get_fundamentals(symbol)` | `pe_ratio`, `dividend_yield`, `market_cap`, `free_float`, etc. for a symbol | `dict` |
194
+ | `get_dividends(symbol)` | Dividend history: `year`, `amount`, `ex_date`, `payment_date`, `record_date` | `list[dict]` |
195
+ | `get_commission_rate()` | The account's commission rate percentage (cached after first call) | `float` |
196
+ | `add_funds(amount, account_id=None, bot_id=None)` | Add paper cash to an account | `dict` |
197
+ | `get_performance(bot_id=None, limit=100)` | Historical performance snapshots for a bot | `list[dict]` |
198
+ | `get_trades(bot_id=None, limit=100)` | Executed trade history for a bot | `list[dict]` |
199
+ | `get_logs(bot_id=None, limit=200)` | Bot run logs | `list[dict]` |
200
+ | `list_bots()` | List all bots registered under the account | `list[dict]` |
201
+ | `create_bot(bot_id, bot_label=None, strategy_name=None, symbols=None, cycle_minutes=None)` | Register a new cloud bot | `dict` |
202
+ | `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` |
203
+ | `place_oco_order(symbol, quantity, stop_loss_price, take_profit_price, ...)` | Attach a linked stop-loss/take-profit pair to an existing position | `dict` |
204
+ | `place_stop_order(symbol, quantity, trigger_price, limit_price=None, ...)` | Standalone stop order | `dict` |
205
+ | `get_order_executions(since=None, limit=1000)` | Raw fill/execution records for the current bot scope | `list[dict]` |
206
+ | `close()` | Closes the underlying HTTP client cleanly | `None` |
207
+
208
+ ## Examples
209
+
210
+ ### Paper Trading
211
+
212
+ ```python
213
+ from pypsx import TradingClient
214
+
215
+ client = TradingClient(
216
+ api_key=os.getenv("PYPSX_API_KEY_ID"),
217
+ secret_key=os.getenv("PYPSX_API_SECRET_KEY"),
218
+ paper=True,
219
+ )
220
+
221
+ valuation = client.get_portfolio_valuation()
222
+ positions = client.get_positions()
223
+ orders = client.get_orders(limit=25)
224
+
225
+ print("Equity:", valuation["equity"])
226
+ print("Positions:", len(positions))
227
+ print("Orders:", len(orders))
228
+ ```
229
+
230
+ ### Live Trading
231
+
232
+ ```python
233
+ from pypsx import TradingClient
234
+
235
+ client = TradingClient(
236
+ api_key="PK-LIVE-ABC123456789",
237
+ secret_key="pypsx-secret-live-replace-me",
238
+ paper=False,
239
+ )
240
+
241
+ order = client.place_manual_order(
242
+ symbol="OGDC",
243
+ side="BUY",
244
+ quantity=100,
245
+ order_type="MARKET",
246
+ )
247
+
248
+ print(order)
249
+ ```
250
+
251
+ ### Simple Bot Pattern
252
+
253
+ ```python
254
+ from pypsx import TradingClient
255
+
256
+ SYMBOL = "OGDC"
257
+
258
+ client = TradingClient(
259
+ api_key="PK-PAPER-123456",
260
+ secret_key="pypsx-secret-paper-replace-me",
261
+ paper=True,
262
+ )
263
+
264
+ positions = client.get_positions()
265
+ already_holding = any(
266
+ position["symbol"] == SYMBOL and float(position["qty"]) > 0
267
+ for position in positions
268
+ )
269
+
270
+ if not already_holding:
271
+ client.place_manual_order(
272
+ symbol=SYMBOL,
273
+ side="BUY",
274
+ quantity=10,
275
+ order_type="MARKET",
276
+ )
277
+ ```
278
+
279
+ ## Best Practices
280
+
281
+ - Use `.env` files or a secrets manager for credentials. Do not hardcode production keys into source control.
282
+ - Start every new strategy with `paper=True`.
283
+ - Treat paper trading as your pre-flight checklist before switching to live.
284
+ - Run execution scripts when the market is open so fills, liquidity, and dashboard feedback reflect real conditions.
285
+ - Add explicit guards in your code for position sizing, duplicate orders, and risk limits.
286
+ - Close clients cleanly with `client.close()` in longer-running scripts or services.
287
+
288
+ ## Raw HTTP Example
289
+
290
+ If you are not using the SDK, this is the equivalent request format:
291
+
292
+ ```bash
293
+ curl -X POST "https://paper-api.pypsx.com/orders" \
294
+ -H "Content-Type: application/json" \
295
+ -H "PYPSX-API-KEY-ID: $PYPSX_API_KEY_ID" \
296
+ -H "PYPSX-API-SECRET-KEY: $PYPSX_API_SECRET_KEY" \
297
+ -d "{\"symbol\":\"OGDC\",\"side\":\"BUY\",\"quantity\":10,\"order_type\":\"MARKET\",\"mode\":\"PAPER\",\"commission_rate\":0.02}"
298
+ ```
299
+
300
+ 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%`.
301
+
302
+ ## Additional Examples
303
+
304
+ - `examples/pypsx_client_example.py`
305
+ - `examples/example_bot.py`
pypsx-2.4.0/README.md ADDED
@@ -0,0 +1,260 @@
1
+ # PyPSX SDK
2
+
3
+ API-first trading infrastructure for the Pakistan Stock Exchange.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install pypsx
9
+ ```
10
+
11
+ ## Try it in a notebook
12
+
13
+ [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1ac6yt0dlTzpBR16qS_-ltYuImVyyr2PG?usp=sharing)
14
+
15
+ ## One-liners — no client to construct
16
+
17
+ ```python
18
+ import pypsx
19
+
20
+ df = pypsx.download("OGDC", period="1y")
21
+ result = pypsx.backtest("dual_sma_momentum", "OGDC", period="1y", initial_cash=1_000_000)
22
+ quote = pypsx.get_quote("OGDC")
23
+ depth = pypsx.get_market_depth("OGDC")
24
+ ```
25
+
26
+ These read `PYPSX_API_KEY_ID`/`PYPSX_API_SECRET_KEY` from the environment automatically. For order placement, positions, and account state, use `TradingClient` below.
27
+
28
+ ## Quick Start
29
+
30
+ 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.
31
+
32
+ ```python
33
+ import os
34
+ from dotenv import load_dotenv
35
+ from pypsx import TradingClient
36
+
37
+ load_dotenv()
38
+
39
+ client = TradingClient(
40
+ api_key=os.getenv("PYPSX_API_KEY_ID"),
41
+ secret_key=os.getenv("PYPSX_API_SECRET_KEY"),
42
+ paper=True,
43
+ )
44
+
45
+ account = client.get_account()
46
+ print(f"Connected! Current Balance: PKR {account.cash}")
47
+
48
+ order = client.place_manual_order(
49
+ symbol="OGDC",
50
+ side="BUY",
51
+ quantity=10,
52
+ order_type="MARKET",
53
+ )
54
+
55
+ print("Submitted:", order["order_id"], order["status"])
56
+ ```
57
+
58
+ You can also load keys directly from environment variables:
59
+
60
+ ```python
61
+ from pypsx import TradingClient
62
+
63
+ client = TradingClient.from_env(paper=True)
64
+ ```
65
+
66
+ ### Your First Trade
67
+
68
+ **Step 1:** Generate a paper key in the PyPSX dashboard.
69
+ **Step 2:** Copy the script above into `my_bot.py`.
70
+ **Step 3:** Set your own `PYPSX_API_KEY_ID` and `PYPSX_API_SECRET_KEY` in `.env`.
71
+ **Step 4:** Run `python my_bot.py` while the market is open.
72
+ **Step 5:** Watch orders, fills, and positions appear in the dashboard automatically.
73
+
74
+ ## The Power of PyPSX
75
+
76
+ PyPSX gives algorithmic traders a clean Python interface for the Pakistan Stock Exchange without exposing them to exchange plumbing.
77
+
78
+ ### Paper And Live Modes
79
+
80
+ The SDK automatically routes traffic based on one flag:
81
+
82
+ - `paper=True` sends requests to the paper trading environment at `https://paper-api.pypsx.com`
83
+ - `paper=False` sends requests to the live trading environment at `https://api.pypsx.com`
84
+
85
+ This keeps your code identical across testing and production. Change the credentials, switch the flag, and keep your trading logic the same.
86
+
87
+ ### Real-Time Trading Experience
88
+
89
+ With PyPSX you can:
90
+
91
+ - Read positions, orders, and account state from Python
92
+ - Submit orders with a simple REST interface
93
+ - See fills reflected in the web dashboard without manual refresh
94
+ - Build bots around trading logic instead of exchange protocol handling
95
+
96
+ ### Developer's Promise
97
+
98
+ 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.
99
+
100
+ ## Authentication
101
+
102
+ ### How To Get Your Keys
103
+
104
+ 1. Sign in to the PyPSX dashboard.
105
+ 2. Open `Settings`.
106
+ 3. Select the account you want to trade.
107
+ 4. Click `Generate Paper Key` or `Generate Live Key`.
108
+ 5. Copy the `Public Key ID` and `Secret Key`.
109
+
110
+ ### How The SDK Uses Them
111
+
112
+ Use the credentials directly in `TradingClient(...)`:
113
+
114
+ ```python
115
+ from pypsx import TradingClient
116
+
117
+ client = TradingClient(
118
+ api_key=os.getenv("PYPSX_API_KEY_ID"),
119
+ secret_key=os.getenv("PYPSX_API_SECRET_KEY"),
120
+ paper=True,
121
+ )
122
+ ```
123
+
124
+ Under the hood, the SDK automatically sends:
125
+
126
+ ```http
127
+ PYPSX-API-KEY-ID: <your-public-key-id>
128
+ PYPSX-API-SECRET-KEY: <your-secret-key>
129
+ ```
130
+
131
+ If you are building against the API without the Python SDK, send those same headers yourself.
132
+
133
+ ## API Reference
134
+
135
+ | Method | What it does | Returns |
136
+ | --- | --- | --- |
137
+ | `get_account_config()` | Fetches trading permissions and account-level configuration | `dict` |
138
+ | `get_portfolio_valuation()` | Returns the latest equity, cash, positions value, and pricing snapshot | `dict` |
139
+ | `get_positions()` | Returns open positions for the selected paper or live account | `list[dict]` |
140
+ | `get_orders(limit=...)` | Returns recent orders and their current state | `list[dict]` |
141
+ | `place_manual_order(...)` | Submits a market or priced order through the selected environment | `dict` |
142
+ | `get_symbols()` | Fetches available market symbols | `list[dict]` |
143
+ | `get_intraday(symbol, days=...)` | Retrieves recent intraday market data for a symbol | `list[dict]` |
144
+ | `get_historical(symbol, start=..., end=...)` | Retrieves historical daily bars for strategy research and analysis | `list[dict]` |
145
+ | `get_historical_intraday(symbols, start=..., end=..., interval=...)` | Retrieves multi-interval OHLCV candles (1m/5m/15m/1h) | `list[dict]` |
146
+ | `get_portfolio(bot_id=None)` | Raw portfolio dict for the current bot/account scope | `dict` |
147
+ | `get_account_config(account_id=None)` | Account-level configuration | `dict` |
148
+ | `get_fundamentals(symbol)` | `pe_ratio`, `dividend_yield`, `market_cap`, `free_float`, etc. for a symbol | `dict` |
149
+ | `get_dividends(symbol)` | Dividend history: `year`, `amount`, `ex_date`, `payment_date`, `record_date` | `list[dict]` |
150
+ | `get_commission_rate()` | The account's commission rate percentage (cached after first call) | `float` |
151
+ | `add_funds(amount, account_id=None, bot_id=None)` | Add paper cash to an account | `dict` |
152
+ | `get_performance(bot_id=None, limit=100)` | Historical performance snapshots for a bot | `list[dict]` |
153
+ | `get_trades(bot_id=None, limit=100)` | Executed trade history for a bot | `list[dict]` |
154
+ | `get_logs(bot_id=None, limit=200)` | Bot run logs | `list[dict]` |
155
+ | `list_bots()` | List all bots registered under the account | `list[dict]` |
156
+ | `create_bot(bot_id, bot_label=None, strategy_name=None, symbols=None, cycle_minutes=None)` | Register a new cloud bot | `dict` |
157
+ | `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` |
158
+ | `place_oco_order(symbol, quantity, stop_loss_price, take_profit_price, ...)` | Attach a linked stop-loss/take-profit pair to an existing position | `dict` |
159
+ | `place_stop_order(symbol, quantity, trigger_price, limit_price=None, ...)` | Standalone stop order | `dict` |
160
+ | `get_order_executions(since=None, limit=1000)` | Raw fill/execution records for the current bot scope | `list[dict]` |
161
+ | `close()` | Closes the underlying HTTP client cleanly | `None` |
162
+
163
+ ## Examples
164
+
165
+ ### Paper Trading
166
+
167
+ ```python
168
+ from pypsx import TradingClient
169
+
170
+ client = TradingClient(
171
+ api_key=os.getenv("PYPSX_API_KEY_ID"),
172
+ secret_key=os.getenv("PYPSX_API_SECRET_KEY"),
173
+ paper=True,
174
+ )
175
+
176
+ valuation = client.get_portfolio_valuation()
177
+ positions = client.get_positions()
178
+ orders = client.get_orders(limit=25)
179
+
180
+ print("Equity:", valuation["equity"])
181
+ print("Positions:", len(positions))
182
+ print("Orders:", len(orders))
183
+ ```
184
+
185
+ ### Live Trading
186
+
187
+ ```python
188
+ from pypsx import TradingClient
189
+
190
+ client = TradingClient(
191
+ api_key="PK-LIVE-ABC123456789",
192
+ secret_key="pypsx-secret-live-replace-me",
193
+ paper=False,
194
+ )
195
+
196
+ order = client.place_manual_order(
197
+ symbol="OGDC",
198
+ side="BUY",
199
+ quantity=100,
200
+ order_type="MARKET",
201
+ )
202
+
203
+ print(order)
204
+ ```
205
+
206
+ ### Simple Bot Pattern
207
+
208
+ ```python
209
+ from pypsx import TradingClient
210
+
211
+ SYMBOL = "OGDC"
212
+
213
+ client = TradingClient(
214
+ api_key="PK-PAPER-123456",
215
+ secret_key="pypsx-secret-paper-replace-me",
216
+ paper=True,
217
+ )
218
+
219
+ positions = client.get_positions()
220
+ already_holding = any(
221
+ position["symbol"] == SYMBOL and float(position["qty"]) > 0
222
+ for position in positions
223
+ )
224
+
225
+ if not already_holding:
226
+ client.place_manual_order(
227
+ symbol=SYMBOL,
228
+ side="BUY",
229
+ quantity=10,
230
+ order_type="MARKET",
231
+ )
232
+ ```
233
+
234
+ ## Best Practices
235
+
236
+ - Use `.env` files or a secrets manager for credentials. Do not hardcode production keys into source control.
237
+ - Start every new strategy with `paper=True`.
238
+ - Treat paper trading as your pre-flight checklist before switching to live.
239
+ - Run execution scripts when the market is open so fills, liquidity, and dashboard feedback reflect real conditions.
240
+ - Add explicit guards in your code for position sizing, duplicate orders, and risk limits.
241
+ - Close clients cleanly with `client.close()` in longer-running scripts or services.
242
+
243
+ ## Raw HTTP Example
244
+
245
+ If you are not using the SDK, this is the equivalent request format:
246
+
247
+ ```bash
248
+ curl -X POST "https://paper-api.pypsx.com/orders" \
249
+ -H "Content-Type: application/json" \
250
+ -H "PYPSX-API-KEY-ID: $PYPSX_API_KEY_ID" \
251
+ -H "PYPSX-API-SECRET-KEY: $PYPSX_API_SECRET_KEY" \
252
+ -d "{\"symbol\":\"OGDC\",\"side\":\"BUY\",\"quantity\":10,\"order_type\":\"MARKET\",\"mode\":\"PAPER\",\"commission_rate\":0.02}"
253
+ ```
254
+
255
+ 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%`.
256
+
257
+ ## Additional Examples
258
+
259
+ - `examples/pypsx_client_example.py`
260
+ - `examples/example_bot.py`
@@ -0,0 +1,96 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel", "Cython>=3.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pypsx"
7
+ version = "2.4.0"
8
+ description = "Pakistan Stock Exchange (PSX) Trading SDK for Paper Trading and Backtesting"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = {text = "Proprietary"}
12
+ authors = [
13
+ {name = "PyPSX Team"}
14
+ ]
15
+ keywords = ["trading", "stock", "psx", "pakistan", "simulation", "backtesting", "algorithmic-trading"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Developers",
19
+ "Intended Audience :: Financial and Insurance Industry",
20
+ "License :: Other/Proprietary License",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Topic :: Software Development :: Libraries :: Python Modules",
26
+ "Topic :: Office/Business :: Financial :: Investment",
27
+ "Topic :: Scientific/Engineering :: Mathematics",
28
+ ]
29
+
30
+ # Core runtime dependencies for the SDK
31
+ dependencies = [
32
+ "pydantic>=2.0.0",
33
+ "httpx>=0.24.0",
34
+ "sqlalchemy>=2.0.0",
35
+ "pandas>=1.5.0,<2.3.3",
36
+ "numpy>=1.24.0,<2.3.0",
37
+ "ta>=0.11.0",
38
+ "tzdata>=2024.1",
39
+ "fastapi>=0.110.0",
40
+ "uvicorn>=0.23.0",
41
+ "psycopg2-binary>=2.9.0",
42
+ "websockets>=12.0",
43
+ "python-dateutil>=2.8.0",
44
+ "requests>=2.31.0",
45
+ ]
46
+
47
+ [project.optional-dependencies]
48
+ # Development dependencies (for SDK development)
49
+ dev = [
50
+ "pytest>=7.0.0",
51
+ "pytest-cov>=4.0.0",
52
+ "pytest-asyncio>=0.21.0",
53
+ "black>=23.0.0",
54
+ "ruff>=0.1.0",
55
+ ]
56
+ # Jupyter/Colab support (recommended for notebook environments)
57
+ jupyter = [
58
+ "nest-asyncio>=1.5.0",
59
+ ]
60
+
61
+ [project.urls]
62
+ Homepage = "https://github.com/yourusername/pypsx"
63
+ Documentation = "https://github.com/yourusername/pypsx/blob/main/README.md"
64
+ Repository = "https://github.com/yourusername/pypsx"
65
+
66
+ [tool.setuptools.packages.find]
67
+ where = ["."]
68
+ include = ["pypsx*", "examples*"]
69
+ exclude = [
70
+ "tests*",
71
+ "logs*",
72
+ "user_data*",
73
+ "scripts*",
74
+ "test bots*",
75
+ "pypsx.egg-info*",
76
+ "*.egg-info*",
77
+ ]
78
+
79
+ # Ship .pyi stub files, py.typed marker, and assets alongside compiled binaries.
80
+ # Without "*.pyi" here, pip install will NOT include stubs and IDE autocomplete breaks.
81
+ [tool.setuptools.package-data]
82
+ "*" = ["*.pyi", "py.typed"]
83
+ "pypsx.data.cache" = ["*.sql"]
84
+ "pypsx.dashboard.assets" = ["*"]
85
+
86
+ # CLI entry points for SDK
87
+ [project.scripts]
88
+ pypsx-paper = "pypsx.cli.paper_trading:main"
89
+
90
+ [tool.black]
91
+ line-length = 100
92
+ target-version = ['py38']
93
+
94
+ [tool.ruff]
95
+ line-length = 100
96
+ target-version = "py38"