wiz-trader 0.3.0__py3-none-any.whl → 0.5.0__py3-none-any.whl

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.
wiz_trader/__init__.py CHANGED
@@ -3,6 +3,6 @@
3
3
  from .quotes import QuotesClient
4
4
  from .apis import WizzerClient
5
5
 
6
- __version__ = "0.3.0"
6
+ __version__ = "0.5.0"
7
7
 
8
8
  __all__ = ["QuotesClient", "WizzerClient"]
wiz_trader/apis/client.py CHANGED
@@ -21,12 +21,14 @@ class WizzerClient:
21
21
  base_url (str): Base URL of the Wizzer's API server.
22
22
  token (str): JWT token for authentication.
23
23
  log_level (str): Logging level. Options: "error", "info", "debug".
24
+ strategy_id (str): Default strategy ID to use if not provided in methods.
24
25
  """
25
26
 
26
27
  def __init__(
27
28
  self,
28
29
  base_url: Optional[str] = None,
29
30
  token: Optional[str] = None,
31
+ strategy_id: Optional[str] = None,
30
32
  log_level: str = "error" # default only errors
31
33
  ):
32
34
  # Configure logger based on log_level.
@@ -39,6 +41,8 @@ class WizzerClient:
39
41
  # System env vars take precedence over .env
40
42
  self.base_url = base_url or os.environ.get("WZ__API_BASE_URL")
41
43
  self.token = token or os.environ.get("WZ__TOKEN")
44
+ self.strategy_id = strategy_id or os.environ.get("WZ__STRATEGY_ID")
45
+
42
46
  if not self.token:
43
47
  raise ValueError("JWT token must be provided as an argument or in .env (WZ__TOKEN)")
44
48
  if not self.base_url:
@@ -52,6 +56,29 @@ class WizzerClient:
52
56
 
53
57
  logger.debug("Initialized WizzerClient with URL: %s", self.base_url)
54
58
 
59
+ def _get_strategy(self, strategy: Optional[Dict[str, str]] = None) -> Dict[str, str]:
60
+ """
61
+ Get strategy information, either from the provided parameter or from the default.
62
+
63
+ Args:
64
+ strategy (Optional[Dict[str, str]]): Strategy object with id, identifier, and name.
65
+
66
+ Returns:
67
+ Dict[str, str]: A strategy object with at least the id field.
68
+
69
+ Raises:
70
+ ValueError: If no strategy is provided and no default is set.
71
+ """
72
+ if strategy and "id" in strategy:
73
+ return strategy
74
+
75
+ if not self.strategy_id:
76
+ raise ValueError("Strategy ID must be provided either as a parameter or set in .env (WZ__STRATEGY_ID)")
77
+
78
+ return {"id": self.strategy_id}
79
+
80
+ # ===== DATA HUB METHODS =====
81
+
55
82
  def get_indices(self, trading_symbol: Optional[str] = None, exchange: Optional[str] = None) -> List[Dict[str, Any]]:
56
83
  """
57
84
  Get list of indices available on the exchange.
@@ -101,7 +128,8 @@ class WizzerClient:
101
128
  instruments: List[str],
102
129
  start_date: str,
103
130
  end_date: str,
104
- ohlcv: List[str]
131
+ ohlcv: List[str],
132
+ interval: str = "1d"
105
133
  ) -> List[Dict[str, Any]]:
106
134
  """
107
135
  Get historical OHLCV data for specified instruments.
@@ -111,6 +139,7 @@ class WizzerClient:
111
139
  start_date (str): Start date in YYYY-MM-DD format.
112
140
  end_date (str): End date in YYYY-MM-DD format.
113
141
  ohlcv (List[str]): List of OHLCV fields to retrieve (open, high, low, close, volume).
142
+ interval (str, optional): Data interval. Options: "1d" (daily, default), "1M" (monthly - last trading day of month).
114
143
 
115
144
  Returns:
116
145
  List[Dict[str, Any]]: Historical data for requested instruments.
@@ -120,28 +149,442 @@ class WizzerClient:
120
149
  "instruments": instruments,
121
150
  "startDate": start_date,
122
151
  "endDate": end_date,
123
- "ohlcv": ohlcv
152
+ "ohlcv": ohlcv,
153
+ "interval": interval
124
154
  }
125
155
 
126
156
  logger.debug("Fetching historical OHLCV with data: %s", data)
127
157
  response = self._make_request("POST", endpoint, json=data)
128
158
  return response
129
159
 
160
+ # ===== ORDER MANAGEMENT METHODS =====
161
+
162
+ def place_order(
163
+ self,
164
+ exchange: str,
165
+ trading_symbol: str,
166
+ transaction_type: str,
167
+ quantity: int,
168
+ order_type: str = "MARKET",
169
+ product: str = "CNC",
170
+ price: float = 0,
171
+ trigger_price: float = 0,
172
+ disclosed_qty: int = 0,
173
+ validity: str = "DAY",
174
+ variety: str = "REGULAR",
175
+ stoploss: float = 0,
176
+ target: float = 0,
177
+ segment: Optional[str] = None,
178
+ exchange_token: Optional[int] = None,
179
+ broker: str = None,
180
+ strategy: Optional[Dict[str, str]] = None
181
+ ) -> Dict[str, Any]:
182
+ """
183
+ Place a regular order.
184
+
185
+ Args:
186
+ exchange (str): Exchange code (e.g., "NSE", "BSE").
187
+ trading_symbol (str): Symbol of the instrument.
188
+ transaction_type (str): "BUY" or "SELL".
189
+ quantity (int): Number of shares to trade.
190
+ order_type (str, optional): Order type (e.g., "MARKET", "LIMIT"). Defaults to "MARKET".
191
+ product (str, optional): Product code (e.g., "CNC" for delivery). Defaults to "CNC".
192
+ price (float, optional): Price for limit orders. Defaults to 0.
193
+ trigger_price (float, optional): Trigger price for stop orders. Defaults to 0.
194
+ disclosed_qty (int, optional): Disclosed quantity. Defaults to 0.
195
+ validity (str, optional): Order validity (e.g., "DAY", "IOC"). Defaults to "DAY".
196
+ variety (str, optional): Order variety. Defaults to "REGULAR".
197
+ stoploss (float, optional): Stop loss price. Defaults to 0.
198
+ target (float, optional): Target price. Defaults to 0.
199
+ segment (Optional[str], optional): Market segment. If None, determined from exchange.
200
+ exchange_token (Optional[int], optional): Exchange token for the instrument.
201
+ broker (str, optional): Broker code.
202
+ strategy (Optional[Dict[str, str]], optional): Strategy information. If None, uses default.
203
+
204
+ Returns:
205
+ Dict[str, Any]: Order response containing orderId.
206
+ """
207
+ endpoint = "/orders"
208
+
209
+ # Determine segment if not provided
210
+ if not segment:
211
+ segment = f"{exchange}CM"
212
+
213
+ # Get strategy information
214
+ strategy_info = self._get_strategy(strategy)
215
+
216
+ data = {
217
+ "exchange": exchange,
218
+ "tradingSymbol": trading_symbol,
219
+ "transactionType": transaction_type,
220
+ "qty": quantity,
221
+ "orderType": order_type,
222
+ "product": product,
223
+ "price": price,
224
+ "triggerPrice": trigger_price,
225
+ "disclosedQty": disclosed_qty,
226
+ "validity": validity,
227
+ "variety": variety,
228
+ "stoploss": stoploss,
229
+ "target": target,
230
+ "segment": segment,
231
+ "strategy": strategy_info
232
+ }
233
+
234
+ # Add exchange token if provided
235
+ if exchange_token:
236
+ data["exchangeToken"] = exchange_token
237
+
238
+ logger.debug("Placing order: %s", data)
239
+ return self._make_request("POST", endpoint, json=data)
240
+
241
+ def modify_order(
242
+ self,
243
+ order_id: str,
244
+ **params
245
+ ) -> Dict[str, Any]:
246
+ """
247
+ Modify an existing order.
248
+
249
+ Args:
250
+ order_id (str): Order ID to modify.
251
+ **params: Parameters to update in the order.
252
+
253
+ Returns:
254
+ Dict[str, Any]: Order response containing orderId.
255
+ """
256
+ endpoint = f"/orders/{order_id}"
257
+
258
+ logger.debug("Modifying order %s with params: %s", order_id, params)
259
+ return self._make_request("PATCH", endpoint, json=params)
260
+
261
+ def cancel_order(self, order_id: str) -> Dict[str, Any]:
262
+ """
263
+ Cancel an existing order.
264
+
265
+ Args:
266
+ order_id (str): Order ID to cancel.
267
+
268
+ Returns:
269
+ Dict[str, Any]: Response with the cancelled order ID.
270
+ """
271
+ endpoint = f"/orders/{order_id}"
272
+
273
+ logger.debug("Cancelling order: %s", order_id)
274
+ return self._make_request("DELETE", endpoint)
275
+
276
+ def get_positions(self) -> List[Dict[str, Any]]:
277
+ """
278
+ Get current portfolio positions.
279
+
280
+ Returns:
281
+ List[Dict[str, Any]]: List of positions.
282
+ """
283
+ endpoint = "/portfolios/positions"
284
+
285
+ logger.debug("Fetching positions")
286
+ return self._make_request("GET", endpoint)
287
+
288
+ def get_holdings(self, portfolios: Optional[str] = "default") -> List[Dict[str, Any]]:
289
+ """
290
+ Get current holdings.
291
+
292
+ Args:
293
+ portfolios (str, optional): Portfolio name. Defaults to "default".
294
+
295
+ Returns:
296
+ List[Dict[str, Any]]: List of holdings.
297
+ """
298
+ endpoint = "/portfolios/holdings"
299
+ params = {"portfolios": portfolios}
300
+
301
+ logger.debug("Fetching holdings for portfolio: %s", portfolios)
302
+ return self._make_request("GET", endpoint, params=params)
303
+
304
+ # ===== BASKET MANAGEMENT METHODS =====
305
+
306
+ def create_basket(
307
+ self,
308
+ name: str,
309
+ instruments: List[Dict[str, Any]],
310
+ weightage_scheme: str = "equi_weighted",
311
+ capital: Optional[Dict[str, float]] = None,
312
+ instrument_types: Optional[List[str]] = None,
313
+ trading_symbol: Optional[str] = None
314
+ ) -> Dict[str, Any]:
315
+ """
316
+ Create a new basket.
317
+
318
+ Args:
319
+ name (str): Name of the basket.
320
+ instruments (List[Dict[str, Any]]): List of instruments with weightage and shares.
321
+ weightage_scheme (str, optional): Weightage scheme. Defaults to "equi_weighted".
322
+ capital (Optional[Dict[str, float]], optional): Capital allocation. Defaults to {"minValue": 0, "actualValue": 0}.
323
+ instrument_types (Optional[List[str]], optional): Types of instruments. Defaults to ["EQLC"].
324
+
325
+ Returns:
326
+ Dict[str, Any]: Basket information.
327
+ """
328
+ endpoint = "/baskets"
329
+
330
+ # Set defaults
331
+ if capital is None:
332
+ capital = {"minValue": 0, "actualValue": 0}
333
+
334
+ data = {
335
+ "name": name,
336
+ "weightageScheme": weightage_scheme,
337
+ "instruments": instruments,
338
+ "capital": capital,
339
+ "instrumentTypes": instrument_types
340
+ }
341
+
342
+ logger.debug("Creating basket: %s", data)
343
+ return self._make_request("POST", endpoint, json=data)
344
+
345
+ def get_baskets(self) -> List[Dict[str, Any]]:
346
+ """
347
+ Get all baskets.
348
+
349
+ Returns:
350
+ List[Dict[str, Any]]: List of baskets.
351
+ """
352
+ endpoint = "/baskets"
353
+
354
+ logger.debug("Fetching baskets")
355
+ return self._make_request("GET", endpoint)
356
+
357
+ def get_basket(self, basket_id: str) -> Dict[str, Any]:
358
+ """
359
+ Get a specific basket by ID.
360
+
361
+ Args:
362
+ basket_id (str): Basket ID.
363
+
364
+ Returns:
365
+ Dict[str, Any]: Basket information.
366
+ """
367
+ endpoint = f"/baskets/{basket_id}"
368
+
369
+ logger.debug("Fetching basket: %s", basket_id)
370
+ return self._make_request("GET", endpoint)
371
+
372
+ def get_basket_instruments(self, basket_id: str) -> List[Dict[str, Any]]:
373
+ """
374
+ Get instruments in a basket.
375
+
376
+ Args:
377
+ basket_id (str): Basket ID.
378
+
379
+ Returns:
380
+ List[Dict[str, Any]]: List of instruments in the basket.
381
+ """
382
+ endpoint = f"/baskets/{basket_id}/instruments"
383
+
384
+ logger.debug("Fetching instruments for basket: %s", basket_id)
385
+ return self._make_request("GET", endpoint)
386
+
387
+ def place_basket_order(
388
+ self,
389
+ trading_symbol: str,
390
+ transaction_type: str,
391
+ quantity: float,
392
+ price: float = 0,
393
+ order_type: str = "MARKET",
394
+ product: str = "CNC",
395
+ validity: str = "DAY",
396
+ exchange_token: Optional[int] = None,
397
+ trigger_price: float = 0,
398
+ stoploss: float = 0,
399
+ target: float = 0,
400
+ broker: str = "wizzer",
401
+ variety: str = "REGULAR",
402
+ strategy: Optional[Dict[str, str]] = None,
403
+ disclosed_qty: int = 0,
404
+ sl_applied_level: Optional[str] = None
405
+ ) -> Dict[str, Any]:
406
+ """
407
+ Place a basket order.
408
+
409
+ Args:
410
+ trading_symbol (str): Basket trading symbol (e.g., "/BASKET_NAME").
411
+ transaction_type (str): "BUY" or "SELL".
412
+ quantity (float): Quantity/units of the basket.
413
+ price (float, optional): Price for limit orders. Defaults to 0.
414
+ order_type (str, optional): Order type. Defaults to "MARKET".
415
+ product (str, optional): Product code. Defaults to "CNC".
416
+ validity (str, optional): Order validity. Defaults to "DAY".
417
+ exchange_token (Optional[int], optional): Exchange token for the basket.
418
+ trigger_price (float, optional): Trigger price. Defaults to 0.
419
+ stoploss (float, optional): Stop loss price. Defaults to 0.
420
+ target (float, optional): Target price. Defaults to 0.
421
+ broker (str, optional): Broker code. Defaults to "wizzer".
422
+ variety (str, optional): Order variety. Defaults to "REGULAR".
423
+ strategy (Optional[Dict[str, str]], optional): Strategy information. If None, uses default.
424
+ disclosed_qty (int, optional): Disclosed quantity. Defaults to 0.
425
+ sl_applied_level (Optional[str], optional): Stop loss applied level (e.g., "basket").
426
+
427
+ Returns:
428
+ Dict[str, Any]: Order response containing orderId.
429
+ """
430
+ endpoint = "/orders/basket"
431
+
432
+ # Get strategy information
433
+ strategy_info = self._get_strategy(strategy)
434
+
435
+ data = {
436
+ "tradingSymbol": trading_symbol,
437
+ "exchange": "WZR",
438
+ "transactionType": transaction_type,
439
+ "qty": quantity,
440
+ "price": price,
441
+ "orderType": order_type,
442
+ "product": product,
443
+ "validity": validity,
444
+ "triggerPrice": trigger_price,
445
+ "stoploss": stoploss,
446
+ "target": target,
447
+ "broker": broker,
448
+ "variety": variety,
449
+ "strategy": strategy_info,
450
+ "segment": "WZREQ",
451
+ "disclosedQty": disclosed_qty
452
+ }
453
+
454
+ # Add exchange token if provided
455
+ if exchange_token:
456
+ data["exchangeToken"] = exchange_token
457
+
458
+ # Add stop loss level if provided
459
+ if sl_applied_level:
460
+ data["slAppliedLevel"] = sl_applied_level
461
+
462
+ logger.debug("Placing basket order: %s", data)
463
+ return self._make_request("POST", endpoint, json=data)
464
+
465
+ def place_basket_exit_order(
466
+ self,
467
+ trading_symbol: str,
468
+ exchange: str,
469
+ transaction_type: str,
470
+ quantity: float,
471
+ exchange_token: int,
472
+ **kwargs
473
+ ) -> Dict[str, Any]:
474
+ """
475
+ Place a basket exit order.
476
+
477
+ Args:
478
+ trading_symbol (str): Basket trading symbol.
479
+ exchange (str): Exchange code (usually "WZR" for baskets).
480
+ transaction_type (str): "BUY" or "SELL" (usually "SELL" for exit).
481
+ quantity (float): Quantity/units of the basket.
482
+ exchange_token (int): Exchange token for the basket.
483
+ **kwargs: Additional parameters for the order.
484
+
485
+ Returns:
486
+ Dict[str, Any]: Order response containing orderId.
487
+ """
488
+ endpoint = "/orders/basket/exit"
489
+
490
+ # Build base data
491
+ data = {
492
+ "tradingSymbol": trading_symbol,
493
+ "exchange": exchange,
494
+ "transactionType": transaction_type,
495
+ "qty": quantity,
496
+ "exchangeToken": exchange_token,
497
+ **kwargs
498
+ }
499
+
500
+ # Set strategy if not in kwargs
501
+ if "strategy" not in kwargs:
502
+ data["strategy"] = self._get_strategy(None)
503
+
504
+ # Set defaults if not in kwargs
505
+ defaults = {
506
+ "orderType": "MARKET",
507
+ "product": "CNC",
508
+ "validity": "DAY",
509
+ "disclosedQty": 0,
510
+ "price": 0,
511
+ "variety": "REGULAR",
512
+ "stoploss": 0,
513
+ "broker": "wizzer",
514
+ "triggerPrice": 0,
515
+ "target": 0,
516
+ "segment": "WZREQ"
517
+ }
518
+
519
+ for key, value in defaults.items():
520
+ if key not in data:
521
+ data[key] = value
522
+
523
+ logger.debug("Placing basket exit order: %s", data)
524
+ return self._make_request("POST", endpoint, json=data)
525
+
526
+ def modify_basket_order(
527
+ self,
528
+ order_id: str,
529
+ **params
530
+ ) -> Dict[str, Any]:
531
+ """
532
+ Modify an existing basket order.
533
+
534
+ Args:
535
+ order_id (str): Order ID to modify.
536
+ **params: Parameters to update in the order.
537
+
538
+ Returns:
539
+ Dict[str, Any]: Order response containing orderId.
540
+ """
541
+ endpoint = f"/orders/basket/{order_id}"
542
+
543
+ logger.debug("Modifying basket order %s with params: %s", order_id, params)
544
+ return self._make_request("PATCH", endpoint, json=params)
545
+
546
+ def rebalance_basket(
547
+ self,
548
+ trading_symbol: str,
549
+ instruments: List[str]
550
+ ) -> Dict[str, Any]:
551
+ """
552
+ Rebalance a basket with new instruments.
553
+
554
+ Args:
555
+ trading_symbol (str): Basket trading symbol.
556
+ instruments (List[str]): List of instrument identifiers for the new basket composition.
557
+
558
+ Returns:
559
+ Dict[str, Any]: Rebalance response.
560
+ """
561
+ endpoint = "/baskets/rebalance"
562
+
563
+ data = {
564
+ "tradingSymbol": trading_symbol,
565
+ "instruments": instruments
566
+ }
567
+
568
+ logger.debug("Rebalancing basket %s with instruments: %s", trading_symbol, instruments)
569
+ return self._make_request("POST", endpoint, json=data)
570
+
130
571
  def _make_request(
131
572
  self,
132
573
  method: str,
133
574
  endpoint: str,
134
575
  params: Optional[Dict[str, str]] = None,
135
- json: Optional[Dict[str, Any]] = None
576
+ json: Optional[Dict[str, Any]] = None,
577
+ headers: Optional[Dict[str, str]] = None
136
578
  ) -> Any:
137
579
  """
138
- Make an HTTP request to the DataHub API.
580
+ Make an HTTP request to the API.
139
581
 
140
582
  Args:
141
583
  method (str): HTTP method (GET, POST, etc.)
142
584
  endpoint (str): API endpoint path.
143
585
  params (Optional[Dict[str, str]]): Query parameters for GET requests.
144
586
  json (Optional[Dict[str, Any]]): JSON payload for POST requests.
587
+ headers (Optional[Dict[str, str]]): Custom headers to override the defaults.
145
588
 
146
589
  Returns:
147
590
  Any: Parsed JSON response.
@@ -150,13 +593,14 @@ class WizzerClient:
150
593
  requests.RequestException: If the request fails.
151
594
  """
152
595
  url = f"{self.base_url}{endpoint}"
596
+ request_headers = headers if headers else self.headers
153
597
 
154
598
  try:
155
599
  logger.debug("%s request to %s", method, url)
156
600
  response = requests.request(
157
601
  method=method,
158
602
  url=url,
159
- headers=self.headers,
603
+ headers=request_headers,
160
604
  params=params,
161
605
  json=json
162
606
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: wiz_trader
3
- Version: 0.3.0
3
+ Version: 0.5.0
4
4
  Summary: A Python SDK for connecting to the Wizzer.
5
5
  Home-page: https://bitbucket.org/wizzer-tech/quotes_sdk.git
6
6
  Author: Pawan Wagh
@@ -0,0 +1,9 @@
1
+ wiz_trader/__init__.py,sha256=_X0Mp5qJUiQ5GyZsECsIXaZ-IjzF2L2Hmpxkn4zLHXI,181
2
+ wiz_trader/apis/__init__.py,sha256=ItWKMOl4omiW0g2f-M7WRW3v-dss_ULd9vYnFyIIT9o,132
3
+ wiz_trader/apis/client.py,sha256=EfBLHI-4cfWdrVhtKdL3rzeKheIIxGKwSFrjUE_hfWU,19131
4
+ wiz_trader/quotes/__init__.py,sha256=RF9g9CNP6bVWlmCh_ad8krm3-EWOIuVfLp0-H9fAeEM,108
5
+ wiz_trader/quotes/client.py,sha256=fUHTMGDauGF9cjsFsVAzoOwqSgD555_TLoNqmnFhLdQ,6203
6
+ wiz_trader-0.5.0.dist-info/METADATA,sha256=35gVWkB7nVy-u1n0vrAgKJQvsaxz4hgfRdymJ4yxLjc,4281
7
+ wiz_trader-0.5.0.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
8
+ wiz_trader-0.5.0.dist-info/top_level.txt,sha256=lnYS_g8LlA6ryKYnvY8xIQ6K2K-xzOsd-99AWgnW6VY,11
9
+ wiz_trader-0.5.0.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- wiz_trader/__init__.py,sha256=uaaA0AMX89NXCanP1Fr54bKu4VvU9X_8Af6Q5dvoqkU,181
2
- wiz_trader/apis/__init__.py,sha256=ItWKMOl4omiW0g2f-M7WRW3v-dss_ULd9vYnFyIIT9o,132
3
- wiz_trader/apis/client.py,sha256=SxjFqKRbE1vsMKB82fks_Zap779t8ArxmCKhBktOCFk,5292
4
- wiz_trader/quotes/__init__.py,sha256=RF9g9CNP6bVWlmCh_ad8krm3-EWOIuVfLp0-H9fAeEM,108
5
- wiz_trader/quotes/client.py,sha256=fUHTMGDauGF9cjsFsVAzoOwqSgD555_TLoNqmnFhLdQ,6203
6
- wiz_trader-0.3.0.dist-info/METADATA,sha256=O5GuhJR91LUVt9VHYbDuzLckzVdAnG8k36HmHvBs82o,4281
7
- wiz_trader-0.3.0.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
8
- wiz_trader-0.3.0.dist-info/top_level.txt,sha256=lnYS_g8LlA6ryKYnvY8xIQ6K2K-xzOsd-99AWgnW6VY,11
9
- wiz_trader-0.3.0.dist-info/RECORD,,