vortex_api
Vortex API client for Python -- Visit Api Center. Astha Credit & Securities Pvt. Ltd. (c) 2023
License
Rupeezy's Vortex Python library is licensed under the MIT License
The library
Vortex APIs are meant for clients who want to execute orders based on their own strategy programatically and for partners to build their own applications. These apis provide a fast and secure way to place trades, manage positions and access real time market data.
The python client provides an abstraction over these APIs in order to seamlessly write applications and atrategies without the hassle of managing the apis.
Getting started
#!python
from vortex_api import VortexAPI
client = VortexAPI("your api secret","your application id")
#For client login using SSO
client.login_url(callback_param="hi)
# Place order
client.place_order(client.EXCHANGE_NSE_EQUITY,22,client.TRANSACTION_TYPE_BUY,client.PRODUCT_DELIVERY,client.VARIETY_REGULAR_LIMIT_ORDER,1,1700,0,0,"DAY",1,True)
#Get order book
client.orders(limit=20,offset=1)
1""" 2Vortex API client for Python -- [Visit Api Center](https://vortex.rupeezy.in). 3Astha Credit & Securities Pvt. Ltd. (c) 2023 4 5License 6------- 7Rupeezy's Vortex Python library is licensed under the MIT License 8 9The library 10----------- 11Vortex APIs are meant for clients who want to execute orders based on their own strategy programatically and for partners to build their own applications. 12These apis provide a fast and secure way to place trades, manage positions and access real time market data. 13 14The python client provides an abstraction over these APIs in order to seamlessly write applications and atrategies without 15the hassle of managing the apis. 16 17Getting started 18--------------- 19 #!python 20 from vortex_api import VortexAPI 21 22 client = VortexAPI("your api secret","your application id") 23 24 #For client login using SSO 25 client.login_url(callback_param="hi) 26 27 # Place order 28 29 client.place_order(client.EXCHANGE_NSE_EQUITY,22,client.TRANSACTION_TYPE_BUY,client.PRODUCT_DELIVERY,client.VARIETY_REGULAR_LIMIT_ORDER,1,1700,0,0,"DAY",1,True) 30 31 #Get order book 32 client.orders(limit=20,offset=1) 33 34""" 35from __future__ import unicode_literals, absolute_import 36from vortex_api.api import VortexAPI,Constants 37from vortex_api.vortex_feed import VortexFeed 38__all__ = [VortexAPI,Constants,VortexFeed]
152@validate_selected_methods(['login','place_order','modify_order','cancel_order','get_order_margin','historical_candles','quotes']) 153class VortexAPI: 154 155 def __init__(self, api_key: str = None , application_id: str = None, base_url: str = "https://vortex-api.rupeezy.in/v2",enable_logging: bool=False) -> None: 156 """ 157 Constructor method for VortexAPI class. 158 159 Args: 160 api_key (str, optional): API key for the Vortex API. You can either pass it as an argument or set it as an environment variable named VORTEX_API_KEY. 161 application_id (str, optional): Application ID for the Vortex API. You can either pass it as an argument or set it as an environment variable named VORTEX_APPLICATION_ID. 162 base_url (str, optional): Base URL for the Vortex API. Defaults to "https://vortex-api.rupeezy.in/v2". 163 """ 164 if api_key == None: 165 if os.getenv("VORTEX_API_KEY") != None: 166 api_key = os.getenv("VORTEX_API_KEY") 167 else: 168 raise ValueError("API key must be provided either as an argument or through the VORTEX_API_KEY environment variable.") 169 170 if application_id == None: 171 if os.getenv("VORTEX_APPLICATION_ID") != None: 172 application_id = os.getenv("VORTEX_APPLICATION_ID") 173 else: 174 raise ValueError("Application ID must be provided either as an argument or through the VORTEX_APPLICATION_ID environment variable.") 175 self.api_key = api_key 176 self.application_id = application_id 177 self.base_url = base_url 178 if os.getenv("VORTEX_ACCESS_TOKEN") != None: 179 self.access_token = os.getenv("VORTEX_ACCESS_TOKEN") 180 else: 181 self.access_token = None 182 183 self.enable_logging = enable_logging 184 if self.enable_logging: 185 logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') 186 187 def _make_api_request(self, method: str, endpoint: str, data: dict = None, params=None) -> dict: 188 """ 189 Private method to make HTTP requests to the Vortex API. 190 191 Args: 192 method (str): HTTP method for the request (e.g. "GET", "POST", "PUT", "DELETE"). 193 endpoint (str): API endpoint for the request. 194 data (dict, optional): Payload data for the request. Defaults to None. 195 196 Returns: 197 dict: Dictionary containing the response data from the API. 198 """ 199 if(self.access_token == None): 200 op = {} 201 op["status"]= "error" 202 op["message"] = "please login first" 203 return op 204 bearer_token = f"Bearer {self.access_token}" 205 headers = {"Content-Type": "application/json", "Authorization": bearer_token} 206 url = self.base_url + endpoint 207 if self.enable_logging: 208 logging.debug(f"Making network call to {url} , params: {params}, data: {data}, headers: {headers}") 209 response = requests.request(method, url, headers=headers, json=data,params=params) 210 if self.enable_logging: 211 logging.debug(f"Response received from {url} , body: {response.json()}") 212 response.raise_for_status() 213 return response.json() 214 215 def _make_unauth_request(self, method: str, endpoint: str, data: dict = None, params: dict = None) -> dict: 216 """ 217 Private method to make HTTP requests to the Vortex API. 218 219 Args: 220 method (str): HTTP method for the request (e.g. "GET", "POST", "PUT", "DELETE"). 221 endpoint (str): API endpoint for the request. 222 data (dict, optional): Payload data for the request. Defaults to None. 223 224 Returns: 225 dict: Dictionary containing the response data from the API. 226 """ 227 headers = {"Content-Type": "application/json", "x-api-key": self.api_key} 228 url = self.base_url + endpoint 229 if self.enable_logging: 230 logging.debug(f"Making network call to {url} , params: {params}, data: {data}, headers: {headers}") 231 response = requests.request(method, url, headers=headers, json=data) 232 response.raise_for_status() 233 if self.enable_logging: 234 logging.debug(f"Response received from {url} , body: {response.json()}") 235 return response.json() 236 237 def login(self, client_code: str, password: str, totp: str)->dict: 238 """ 239 Depricating Soon. Use SSO Login instead. Login using password and totp directly 240 241 Documentation: 242 https://vortex.rupeezy.in/docs/latest/authentication/ 243 244 Args: 245 client_code(str): Client Code of the account 246 password(str): Password of the account 247 totp(str): TOTP generated using third party apps like google authenticator etc. 248 249 Returns: 250 dict: JSON response containing the details of the user 251 """ 252 endpoint = "/user/login" 253 data = { 254 "client_code": client_code, 255 "password": password, 256 "totp": totp, 257 "application_id": self.application_id 258 } 259 res = self._make_unauth_request("POST", endpoint= endpoint, data=data) 260 self._setup_client_code(login_object=res) 261 return res 262 263 def download_master(self) -> dict: 264 """ 265 Download list of all available instruments and their details across all exchanges 266 267 Documentation: 268 https://vortex.rupeezy.in/docs/latest/historical/#instrument-list 269 270 Returns: 271 dict: CSV Array of all instruments. The first row contains headers 272 """ 273 endpoint = "https://static.rupeezy.in/master.csv" 274 with requests.Session() as s: 275 download = s.get(url=endpoint) 276 decoded_content = download.content.decode('utf-8') 277 cr = csv.reader(decoded_content.splitlines(), delimiter=',') 278 my_list = list(cr) 279 return my_list 280 281 def place_order(self,exchange: Constants.ExchangeTypes, token: int, transaction_type: Constants.TransactionSides, product: Constants.ProductTypes, variety: Constants.VarietyTypes, 282 quantity: int, price: float, trigger_price: float, disclosed_quantity: int, validity: Constants.ValidityTypes) -> dict: 283 """ 284 Place an order for a specific security 285 286 Documentation: 287 https://vortex.rupeezy.in/docs/latest/order/#placing-an-order 288 289 Args: 290 exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO] 291 token (int): Security token of the scrip. It can be found in the scripmaster file 292 transaction_type (Constants.TransactionSides): Possible values: [BUY, SELL] 293 product (Constants.ProductTypes): Possible values: [INTRADAY, DELIVERY, MTF]. MTF product can only be used in NSE_EQ exchange. 294 variety (Constants.VarietyTypes): Possible values: [RL, RL-MKT, SL, SL-MKT]. RL means regular orders, SL means Stop Loss order. 295 MKT means that the trade will happen at market price 296 quantity (int): For exchange NSE_FO, if you want to trade in 2 lots and lot size is 50, you should pass 100. 297 In all other exchanges, you should pass just the number of lots. For example, in MCX_FO, 298 if you want to trade 5 lots, you should pass just 5. 299 price (float): Price should be an integer multiple of Tick Size. For example, IDEA's tick size is 0.05. 300 So the price entered can be 9.5 or 9.65. It cannot be 9.67. 301 In case of market orders, you should send the Last Trade Price received from the Quote API or Websocket API 302 trigger_price (float): To be used for Stop loss orders. For BUY side SL orders, trigger_price should be 303 lesser than price. for SELL side SL orders, trigger_price should be greater than price. 304 disclosed_quantity (int): Can be any number lesser than or equal to quantity, including 0 305 validity (Constants.ValidityTypes): Can be DAY for orders which are valid throughout the day, or IOC. 306 IOC order will be cancelled if it is not traded immediately 307 Returns: 308 dict: JSON response containing the details of the placed order 309 310 Raises: 311 HTTPError: If any HTTP error occurs during the API call 312 """ 313 314 endpoint = "/trading/orders/regular" 315 if validity == Constants.ValidityTypes.FULL_DAY: 316 validity_days = 1 317 is_amo = False 318 elif validity == Constants.ValidityTypes.IMMEDIATE_OR_CANCEL: 319 validity_days = 0 320 is_amo = False 321 else: 322 validity_days = 1 323 is_amo = True 324 325 data = { 326 "exchange": exchange, 327 "token": token, 328 "transaction_type": transaction_type, 329 "product": product, 330 "variety": variety, 331 "quantity": quantity, 332 "price": price, 333 "trigger_price": trigger_price, 334 "disclosed_quantity": disclosed_quantity, 335 "validity": validity, 336 "validity_days": validity_days, 337 "is_amo": is_amo 338 } 339 340 return self._make_api_request("POST", endpoint, data=data) 341 342 def modify_order(self, order_id: str, variety: Constants.VarietyTypes, quantity: int, traded_quantity: int, price: float, trigger_price: float, disclosed_quantity: int, validity: Constants.ValidityTypes) -> dict: 343 """ 344 Method to modify an order using the Vortex API. 345 346 Documentation: 347 https://vortex.rupeezy.in/docs/latest/order/#modifying-an-order 348 349 Args: 350 exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO] 351 order_id (str): The unique ID of the order to modify. 352 variety (Constants.VarietyTypes): Possible values: [RL, RL-MKT, SL, SL-MKT]. RL means regular orders, SL means Stop Loss order. 353 MKT means that the trade will happen at market price 354 quantity (int): The new quantity for the order. 355 traded_quantity (int): The quantity of the order that has already been traded. 356 price (float): The new price for the order. 357 trigger_price (float): The new trigger price for the order. Required for SL and SL-M orders. 358 disclosed_quantity (int): The new quantity to be disclosed publicly. 359 validity (Constants.ValidityTypes): The new validity for the order (e.g. DAY, IOC, GTD). 360 361 Returns: 362 dict: Dictionary containing the response data from the API. 363 """ 364 365 endpoint = f"/trading/orders/regular/{order_id}" 366 if validity == Constants.ValidityTypes.FULL_DAY: 367 validity_days = 1 368 elif validity == Constants.ValidityTypes.IMMEDIATE_OR_CANCEL: 369 validity_days = 0 370 else: 371 validity_days = 1 372 373 data = { 374 "variety": variety, 375 "quantity": quantity, 376 "traded_quantity": traded_quantity, 377 "price": price, 378 "trigger_price": trigger_price, 379 "disclosed_quantity": disclosed_quantity, 380 "validity": validity, 381 "validity_days": validity_days 382 } 383 return self._make_api_request("PUT", endpoint, data=data) 384 385 def cancel_order(self, order_id: str) -> dict: 386 """ 387 Method to cancel an order using the Vortex API. 388 389 Documentation: 390 https://vortex.rupeezy.in/docs/latest/order/#cancel-an-order 391 392 Args: 393 exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO] 394 order_id (str): The unique ID of the order to cancel. 395 396 Returns: 397 dict: Dictionary containing the response data from the API. 398 """ 399 400 endpoint = f"/trading/orders/regular/{order_id}" 401 return self._make_api_request("DELETE", endpoint) 402 403 def orders(self,limit: int, offset: int) -> dict: 404 """ 405 Method to get all orders. 406 407 Documentation: 408 https://vortex.rupeezy.in/docs/latest/order/#fetching-order-book 409 410 Args: 411 limit (int): Limit is the number of orders to be fetched. 412 offset (int): Offset should atleast be 1 413 414 Returns: 415 dict: Dictionary containing the response data from the API. 416 """ 417 endpoint = f"/trading/orders?limit={limit}&offset={offset}" 418 return self._make_api_request("GET", endpoint) 419 420 def order_history(self,order_id: str) -> dict: 421 """ 422 Method to get the order history of a particular order 423 424 Documentation: 425 https://vortex.rupeezy.in/docs/latest/order/ 426 427 Args: 428 order_id (str): Order id for which history has to be fetched 429 430 Returns: 431 dict: Dictionary containing the response data from the API. 432 """ 433 endpoint = f"/trading/orders/{order_id}" 434 return self._make_api_request("GET", endpoint) 435 436 def positions(self) -> dict: 437 """ 438 Method to get the position book using the Vortex API. 439 440 Documentation: 441 https://vortex.rupeezy.in/docs/latest/positions/#fetch-all-positions 442 443 Returns: 444 dict: Dictionary containing the response data from the API. 445 """ 446 endpoint = f"/trading/portfolio/positions" 447 return self._make_api_request("GET", endpoint) 448 449 def holdings(self) -> dict: 450 """ 451 Method to get the holdings of the user using the Vortex API. 452 453 Documentation: 454 https://vortex.rupeezy.in/docs/latest/holdings/ 455 456 Returns: 457 dict: Dictionary containing the response data from the API. 458 """ 459 endpoint = "/trading/portfolio/holdings" 460 return self._make_api_request("GET", endpoint) 461 462 def trades(self) -> dict: 463 """ 464 Method to get today's trades of the user using the Vortex API. 465 466 Documentation: 467 https://vortex.rupeezy.in/docs/latest/positions/#get-trades 468 469 Returns: 470 dict: Dictionary containing the response data from the API. 471 """ 472 endpoint = "/trading/trades" 473 return self._make_api_request("GET", endpoint) 474 475 def funds(self) -> dict: 476 """ 477 Method to get the funds of the user using the Vortex API. 478 479 Documentation: 480 https://vortex.rupeezy.in/docs/latest/user/#available-funds 481 482 Returns: 483 dict: Dictionary containing the response data from the API. 484 """ 485 endpoint = "/user/funds" 486 return self._make_api_request("GET", endpoint) 487 488 def get_order_margin(self, exchange: Constants.ExchangeTypes, token: int, transaction_type: Constants.TransactionSides, product: Constants.ProductTypes, variety: Constants.VarietyTypes, 489 quantity: int, price: float,mode: Constants.OrderMarginModes, old_quantity: int = 0 , old_price: float = 0 ) -> dict: 490 """ 491 Get the margin required for placing an order for a specific security. 492 493 Documentation: 494 https://vortex.rupeezy.in/docs/latest/margin/#order-margin 495 496 Args: 497 exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO] 498 token (int): Security token of the scrip. It can be found in the scripmaster file 499 transaction_type (Constants.TransactionSides): Possible values: [BUY, SELL] 500 product (Constants.ProductTypes): Possible values: [INTRADAY, DELIVERY, MTF]. MTF product can only be used in NSE_EQ exchange. 501 variety (Constants.VarietyTypes): Possible values: [RL, RL-MKT, SL, SL-MKT]. RL means regular orders, SL means Stop Loss order. 502 MKT means that the trade will happen at market price 503 quantity (int): For exchange NSE_FO, if you want to trade in 2 lots and lot size is 50, you should pass 100. 504 In all other exchanges, you should pass just the number of lots. For example, in MCX_FO, 505 if you want to trade 5 lots, you should pass just 5. 506 price (float): Price should be an integer multiple of Tick Size. For example, IDEA's tick size is 0.05. 507 So the price entered can be 9.5 or 9.65. It cannot be 9.67. 508 In case of market orders, you should send the Last Trade Price received from the Quote API or Websocket API 509 mode (Constants.OrderMarginModes): Possible values: [NEW, MODIFY] , Whether you are trying to modify an existing order or placing a new order. 510 old_quantity (int): For NSE_FO segments, old_quantity is lots * lot_size. For all others, enter just the number of lots. Required if mode is MODIFY 511 old_price (float): Old Price in INR. Required if mode is MODIFY 512 513 Returns: 514 dict: JSON response containing the details of the margin required to place the order 515 516 Raises: 517 HTTPError: If any HTTP error occurs during the API call 518 """ 519 520 endpoint = "/margins/order" 521 522 data = { 523 "exchange": exchange, 524 "token": token, 525 "transaction_type": transaction_type, 526 "product": product, 527 "variety": variety, 528 "quantity": quantity, 529 "price": price, 530 "old_quantity": old_quantity, 531 "old_price": old_price, 532 "mode": mode, 533 } 534 return self._make_api_request("POST", endpoint, data=data) 535 536 def brokerage_plan(self)-> dict: 537 """ 538 Get brokerage plan details of the user. 539 540 Documentation: 541 https://vortex.rupeezy.in/docs/latest/user/ 542 543 Returns: 544 dict: JSON response containing the details of the brokerage plan of the user 545 """ 546 endpoint = "/user/profile/brokerage" 547 return self._make_api_request("GET", endpoint, data=None,params=None) 548 549 def quotes(self, instruments: list, mode: Constants.QuoteModes)-> dict: 550 """ 551 Gets quotes of up to 1000 instruments at a time. 552 553 Documentation: 554 https://vortex.rupeezy.in/docs/latest/historical/#fetch-price-quotes 555 556 Args: 557 instrument(list): List of instruments. The items should be like ( "NSE_EQ-22", "NSE_FO-1234") 558 mode(Constants.QuoteModes): Quote mode. Can be ["ltp","ohlcv", "full"]. LTP quotes just give the last trade price, ohlc give open, high, low, close and volume, full mode also gives depth. 559 560 Returns: 561 dict: JSON response containing quotes. It is possible that not all the symbol identifiers you passed had a quote available. Those inputs will be missing from the response. 562 Also, the order of output might be different than the order of input 563 """ 564 endpoint = "/data/quotes" 565 params = {"q": instruments,"mode": mode} 566 return self._make_api_request("GET", endpoint, data=None,params=params) 567 568 def historical_candles(self, exchange: Constants.ExchangeTypes, token: int, to: datetime.datetime , start: datetime.datetime, resolution: Constants.Resolutions): 569 """ 570 Gets historical candle data of a particular instrument. 571 572 Documentation: 573 https://vortex.rupeezy.in/docs/latest/historical/#fetch-historical-candle-data 574 575 Args: 576 exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO] 577 token (int): Security token of the scrip. It can be found in the instruments master file: 578 to (datetime): datetime up till when you want to receive candles 579 start (datetime): datetime from when you want to receive candles 580 resolution (Constants.Resolutions): resoulution of the candle. can be "1", "2", "3", "4", "5", "10", "15", "30", "45", "60", "120", "180", "240", "1D", "1W", "1M" 581 582 Returns: 583 dict: JSON response containing the historical candles 584 """ 585 586 if not isinstance(token, int): 587 raise TypeError("token must be an integer") 588 if not isinstance(to,datetime.datetime): 589 raise TypeError("to must be a datetime") 590 if not isinstance(start,datetime.datetime): 591 raise TypeError("start must be a datetime") 592 593 594 endpoint = "/data/history" 595 params = {"exchange": exchange,"token": token , "to": int(to.timestamp()), "from": int(start.timestamp()), "resolution": resolution} 596 return self._make_api_request("GET", endpoint, data=None,params=params) 597 598 def login_url(self, callback_param: str) -> str: 599 """ 600 Returns the login URL for the Vortex API. 601 602 Documentation: 603 https://vortex.rupeezy.in/docs/latest/authentication/ 604 605 Returns: 606 str: The login URL for the Vortex API. 607 """ 608 609 return f"https://flow.rupeezy.in?applicationId={self.application_id}&cb_param={callback_param}" 610 611 def exchange_token(self,auth_code: str) -> dict: 612 """ 613 Exchange the auth code received from the login URL for an access token. 614 615 Documentation: 616 https://vortex.rupeezy.in/docs/latest/authentication/ 617 618 Args: 619 auth_code (str): The authorization code received from the login URL. 620 621 Returns: 622 dict: JSON response containing the details of the user 623 """ 624 625 endpoint = "/user/session" 626 data = { 627 "token": auth_code, 628 "applicationId": self.application_id, 629 "checksum": self._sha256_hash(f"{self.application_id}{auth_code}{self.api_key}") 630 } 631 res = self._make_unauth_request("POST", endpoint= endpoint, data=data) 632 self._setup_client_code(login_object=res) 633 return res 634 635 def _sha256_hash(self,text: str) -> str: 636 sha = hashlib.sha256() 637 sha.update(text.encode('utf-8')) 638 return sha.hexdigest() 639 640 def _setup_client_code(self, login_object: dict) -> bool: 641 """ 642 Sets up access token after login 643 644 Args: 645 login_object(dict): Login object received 646 647 Returns: 648 (bool): Whether successful or not 649 """ 650 651 if (('data' in login_object ) and login_object["data"] != None and login_object["data"]["access_token"] != None): 652 self.access_token = login_object["data"]["access_token"] 653 return True 654 655 return False 656 657 def save_backtest_result(self, stats, name: str, symbol: str = "", description: str = "", tags: list = None) -> dict: 658 """ 659 Save backtest results to Rupeezy for viewing on the developer portal. 660 661 Supports multiple backtesting libraries (auto-detected from the result type): 662 - **backtesting.py**: pass the stats object from Backtest.run() 663 - **vectorbt**: pass a vbt.Portfolio object 664 - **backtrader**: pass the strategy from cerebro.run() (i.e. results[0]) 665 666 Args: 667 stats: The result object from any supported backtesting library. 668 name (str): A label for this backtest run (e.g. "SMA Crossover v2"). 669 symbol (str, optional): Primary instrument symbol. 670 description (str, optional): Notes about this run. 671 tags (list[str], optional): Tags for filtering (e.g. ["intraday", "nifty"]). 672 673 Returns: 674 dict: { "status": "success", "backtest_id": "bt_abc123", "url": "https://..." } 675 """ 676 from .backtest import serialize_stats 677 payload = serialize_stats(stats, name, symbol, description, tags or []) 678 endpoint = "/strategies/backtests" 679 680 return self._make_api_request("POST", endpoint, data=payload) 681 682 def save_optimization_result( 683 self, 684 stats, 685 heatmap, 686 name: str, 687 symbol: str = "", 688 description: str = "", 689 maximize="Sharpe Ratio", 690 param_ranges: dict = None, 691 ) -> dict: 692 """ 693 Save optimization results to Rupeezy for viewing on the developer portal. 694 695 Supports multiple backtesting libraries (auto-detected from the result type): 696 - **backtesting.py**: pass stats + heatmap from bt.optimize(return_heatmap=True) 697 - **vectorbt**: pass Portfolio + metric Series from multi-param run 698 - **backtrader**: pass results list from cerebro.run() after optstrategy() 699 700 Args: 701 stats: The result object from any supported backtesting library. 702 heatmap: The heatmap/metric Series (backtesting.py/vectorbt) or 703 metric extraction callable (backtrader). 704 name (str): A label for this optimization run (e.g. "SMA Grid Search"). 705 symbol (str, optional): Primary instrument symbol (e.g. "NIFTY"). 706 description (str, optional): Notes about this optimization run. 707 maximize: The metric that was optimized. Should match the `maximize` 708 argument passed to Backtest.optimize(). Can be a string 709 metric name (e.g. "Sharpe Ratio") or a callable. 710 Defaults to "Sharpe Ratio". 711 param_ranges (dict, optional): Explicit parameter range definitions. 712 Keys are parameter names, values are range() objects or lists. 713 Example: {"sma_fast": range(5, 51, 5), "sma_slow": range(20, 201, 10)} 714 If not provided, ranges are inferred from the heatmap index. 715 716 Returns: 717 dict: {"status": "success", "optimization_id": "opt_xxx", "backtest_id": "bt_xxx"} 718 719 Example:: 720 721 stats, heatmap = bt.optimize( 722 sma_fast=range(5, 51, 5), 723 sma_slow=range(20, 201, 10), 724 maximize='Sharpe Ratio', 725 return_heatmap=True, 726 ) 727 client.save_optimization_result( 728 stats=stats, 729 heatmap=heatmap, 730 name="SMA Crossover Grid Search", 731 symbol="NIFTY", 732 maximize='Sharpe Ratio', 733 param_ranges={"sma_fast": range(5, 51, 5), "sma_slow": range(20, 201, 10)}, 734 ) 735 """ 736 is_maximize = True 737 objective_metric = maximize 738 739 if isinstance(maximize, bool): 740 is_maximize = maximize 741 objective_metric = "Sharpe Ratio" 742 743 from .backtest import serialize_optimization 744 payload = serialize_optimization( 745 result=stats, 746 heatmap=heatmap, 747 name=name, 748 symbol=symbol, 749 description=description, 750 objective_metric=objective_metric, 751 maximize=is_maximize, 752 param_ranges=param_ranges, 753 ) 754 endpoint = "/strategies/optimizations" 755 return self._make_api_request("POST", endpoint, data=payload)
155 def __init__(self, api_key: str = None , application_id: str = None, base_url: str = "https://vortex-api.rupeezy.in/v2",enable_logging: bool=False) -> None: 156 """ 157 Constructor method for VortexAPI class. 158 159 Args: 160 api_key (str, optional): API key for the Vortex API. You can either pass it as an argument or set it as an environment variable named VORTEX_API_KEY. 161 application_id (str, optional): Application ID for the Vortex API. You can either pass it as an argument or set it as an environment variable named VORTEX_APPLICATION_ID. 162 base_url (str, optional): Base URL for the Vortex API. Defaults to "https://vortex-api.rupeezy.in/v2". 163 """ 164 if api_key == None: 165 if os.getenv("VORTEX_API_KEY") != None: 166 api_key = os.getenv("VORTEX_API_KEY") 167 else: 168 raise ValueError("API key must be provided either as an argument or through the VORTEX_API_KEY environment variable.") 169 170 if application_id == None: 171 if os.getenv("VORTEX_APPLICATION_ID") != None: 172 application_id = os.getenv("VORTEX_APPLICATION_ID") 173 else: 174 raise ValueError("Application ID must be provided either as an argument or through the VORTEX_APPLICATION_ID environment variable.") 175 self.api_key = api_key 176 self.application_id = application_id 177 self.base_url = base_url 178 if os.getenv("VORTEX_ACCESS_TOKEN") != None: 179 self.access_token = os.getenv("VORTEX_ACCESS_TOKEN") 180 else: 181 self.access_token = None 182 183 self.enable_logging = enable_logging 184 if self.enable_logging: 185 logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
Constructor method for VortexAPI class.
Arguments:
- api_key (str, optional): API key for the Vortex API. You can either pass it as an argument or set it as an environment variable named VORTEX_API_KEY.
- application_id (str, optional): Application ID for the Vortex API. You can either pass it as an argument or set it as an environment variable named VORTEX_APPLICATION_ID.
- base_url (str, optional): Base URL for the Vortex API. Defaults to "https://vortex-api.rupeezy.in/v2".
237 def login(self, client_code: str, password: str, totp: str)->dict: 238 """ 239 Depricating Soon. Use SSO Login instead. Login using password and totp directly 240 241 Documentation: 242 https://vortex.rupeezy.in/docs/latest/authentication/ 243 244 Args: 245 client_code(str): Client Code of the account 246 password(str): Password of the account 247 totp(str): TOTP generated using third party apps like google authenticator etc. 248 249 Returns: 250 dict: JSON response containing the details of the user 251 """ 252 endpoint = "/user/login" 253 data = { 254 "client_code": client_code, 255 "password": password, 256 "totp": totp, 257 "application_id": self.application_id 258 } 259 res = self._make_unauth_request("POST", endpoint= endpoint, data=data) 260 self._setup_client_code(login_object=res) 261 return res
Depricating Soon. Use SSO Login instead. Login using password and totp directly
Documentation:
Arguments:
- client_code(str): Client Code of the account
- password(str): Password of the account
- totp(str): TOTP generated using third party apps like google authenticator etc.
Returns:
dict: JSON response containing the details of the user
263 def download_master(self) -> dict: 264 """ 265 Download list of all available instruments and their details across all exchanges 266 267 Documentation: 268 https://vortex.rupeezy.in/docs/latest/historical/#instrument-list 269 270 Returns: 271 dict: CSV Array of all instruments. The first row contains headers 272 """ 273 endpoint = "https://static.rupeezy.in/master.csv" 274 with requests.Session() as s: 275 download = s.get(url=endpoint) 276 decoded_content = download.content.decode('utf-8') 277 cr = csv.reader(decoded_content.splitlines(), delimiter=',') 278 my_list = list(cr) 279 return my_list
Download list of all available instruments and their details across all exchanges
Documentation:
https://vortex.rupeezy.in/docs/latest/historical/#instrument-list
Returns:
dict: CSV Array of all instruments. The first row contains headers
281 def place_order(self,exchange: Constants.ExchangeTypes, token: int, transaction_type: Constants.TransactionSides, product: Constants.ProductTypes, variety: Constants.VarietyTypes, 282 quantity: int, price: float, trigger_price: float, disclosed_quantity: int, validity: Constants.ValidityTypes) -> dict: 283 """ 284 Place an order for a specific security 285 286 Documentation: 287 https://vortex.rupeezy.in/docs/latest/order/#placing-an-order 288 289 Args: 290 exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO] 291 token (int): Security token of the scrip. It can be found in the scripmaster file 292 transaction_type (Constants.TransactionSides): Possible values: [BUY, SELL] 293 product (Constants.ProductTypes): Possible values: [INTRADAY, DELIVERY, MTF]. MTF product can only be used in NSE_EQ exchange. 294 variety (Constants.VarietyTypes): Possible values: [RL, RL-MKT, SL, SL-MKT]. RL means regular orders, SL means Stop Loss order. 295 MKT means that the trade will happen at market price 296 quantity (int): For exchange NSE_FO, if you want to trade in 2 lots and lot size is 50, you should pass 100. 297 In all other exchanges, you should pass just the number of lots. For example, in MCX_FO, 298 if you want to trade 5 lots, you should pass just 5. 299 price (float): Price should be an integer multiple of Tick Size. For example, IDEA's tick size is 0.05. 300 So the price entered can be 9.5 or 9.65. It cannot be 9.67. 301 In case of market orders, you should send the Last Trade Price received from the Quote API or Websocket API 302 trigger_price (float): To be used for Stop loss orders. For BUY side SL orders, trigger_price should be 303 lesser than price. for SELL side SL orders, trigger_price should be greater than price. 304 disclosed_quantity (int): Can be any number lesser than or equal to quantity, including 0 305 validity (Constants.ValidityTypes): Can be DAY for orders which are valid throughout the day, or IOC. 306 IOC order will be cancelled if it is not traded immediately 307 Returns: 308 dict: JSON response containing the details of the placed order 309 310 Raises: 311 HTTPError: If any HTTP error occurs during the API call 312 """ 313 314 endpoint = "/trading/orders/regular" 315 if validity == Constants.ValidityTypes.FULL_DAY: 316 validity_days = 1 317 is_amo = False 318 elif validity == Constants.ValidityTypes.IMMEDIATE_OR_CANCEL: 319 validity_days = 0 320 is_amo = False 321 else: 322 validity_days = 1 323 is_amo = True 324 325 data = { 326 "exchange": exchange, 327 "token": token, 328 "transaction_type": transaction_type, 329 "product": product, 330 "variety": variety, 331 "quantity": quantity, 332 "price": price, 333 "trigger_price": trigger_price, 334 "disclosed_quantity": disclosed_quantity, 335 "validity": validity, 336 "validity_days": validity_days, 337 "is_amo": is_amo 338 } 339 340 return self._make_api_request("POST", endpoint, data=data)
Place an order for a specific security
Documentation:
https://vortex.rupeezy.in/docs/latest/order/#placing-an-order
Arguments:
- exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO]
- token (int): Security token of the scrip. It can be found in the scripmaster file
- transaction_type (Constants.TransactionSides): Possible values: [BUY, SELL]
- product (Constants.ProductTypes): Possible values: [INTRADAY, DELIVERY, MTF]. MTF product can only be used in NSE_EQ exchange.
- variety (Constants.VarietyTypes): Possible values: [RL, RL-MKT, SL, SL-MKT]. RL means regular orders, SL means Stop Loss order. MKT means that the trade will happen at market price
- quantity (int): For exchange NSE_FO, if you want to trade in 2 lots and lot size is 50, you should pass 100. In all other exchanges, you should pass just the number of lots. For example, in MCX_FO, if you want to trade 5 lots, you should pass just 5.
- price (float): Price should be an integer multiple of Tick Size. For example, IDEA's tick size is 0.05. So the price entered can be 9.5 or 9.65. It cannot be 9.67. In case of market orders, you should send the Last Trade Price received from the Quote API or Websocket API
- trigger_price (float): To be used for Stop loss orders. For BUY side SL orders, trigger_price should be lesser than price. for SELL side SL orders, trigger_price should be greater than price.
- disclosed_quantity (int): Can be any number lesser than or equal to quantity, including 0
- validity (Constants.ValidityTypes): Can be DAY for orders which are valid throughout the day, or IOC. IOC order will be cancelled if it is not traded immediately
Returns:
dict: JSON response containing the details of the placed order
Raises:
- HTTPError: If any HTTP error occurs during the API call
342 def modify_order(self, order_id: str, variety: Constants.VarietyTypes, quantity: int, traded_quantity: int, price: float, trigger_price: float, disclosed_quantity: int, validity: Constants.ValidityTypes) -> dict: 343 """ 344 Method to modify an order using the Vortex API. 345 346 Documentation: 347 https://vortex.rupeezy.in/docs/latest/order/#modifying-an-order 348 349 Args: 350 exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO] 351 order_id (str): The unique ID of the order to modify. 352 variety (Constants.VarietyTypes): Possible values: [RL, RL-MKT, SL, SL-MKT]. RL means regular orders, SL means Stop Loss order. 353 MKT means that the trade will happen at market price 354 quantity (int): The new quantity for the order. 355 traded_quantity (int): The quantity of the order that has already been traded. 356 price (float): The new price for the order. 357 trigger_price (float): The new trigger price for the order. Required for SL and SL-M orders. 358 disclosed_quantity (int): The new quantity to be disclosed publicly. 359 validity (Constants.ValidityTypes): The new validity for the order (e.g. DAY, IOC, GTD). 360 361 Returns: 362 dict: Dictionary containing the response data from the API. 363 """ 364 365 endpoint = f"/trading/orders/regular/{order_id}" 366 if validity == Constants.ValidityTypes.FULL_DAY: 367 validity_days = 1 368 elif validity == Constants.ValidityTypes.IMMEDIATE_OR_CANCEL: 369 validity_days = 0 370 else: 371 validity_days = 1 372 373 data = { 374 "variety": variety, 375 "quantity": quantity, 376 "traded_quantity": traded_quantity, 377 "price": price, 378 "trigger_price": trigger_price, 379 "disclosed_quantity": disclosed_quantity, 380 "validity": validity, 381 "validity_days": validity_days 382 } 383 return self._make_api_request("PUT", endpoint, data=data)
Method to modify an order using the Vortex API.
Documentation:
https://vortex.rupeezy.in/docs/latest/order/#modifying-an-order
Arguments:
- exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO]
- order_id (str): The unique ID of the order to modify.
- variety (Constants.VarietyTypes): Possible values: [RL, RL-MKT, SL, SL-MKT]. RL means regular orders, SL means Stop Loss order. MKT means that the trade will happen at market price
- quantity (int): The new quantity for the order.
- traded_quantity (int): The quantity of the order that has already been traded.
- price (float): The new price for the order.
- trigger_price (float): The new trigger price for the order. Required for SL and SL-M orders.
- disclosed_quantity (int): The new quantity to be disclosed publicly.
- validity (Constants.ValidityTypes): The new validity for the order (e.g. DAY, IOC, GTD).
Returns:
dict: Dictionary containing the response data from the API.
385 def cancel_order(self, order_id: str) -> dict: 386 """ 387 Method to cancel an order using the Vortex API. 388 389 Documentation: 390 https://vortex.rupeezy.in/docs/latest/order/#cancel-an-order 391 392 Args: 393 exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO] 394 order_id (str): The unique ID of the order to cancel. 395 396 Returns: 397 dict: Dictionary containing the response data from the API. 398 """ 399 400 endpoint = f"/trading/orders/regular/{order_id}" 401 return self._make_api_request("DELETE", endpoint)
Method to cancel an order using the Vortex API.
Documentation:
https://vortex.rupeezy.in/docs/latest/order/#cancel-an-order
Arguments:
- exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO]
- order_id (str): The unique ID of the order to cancel.
Returns:
dict: Dictionary containing the response data from the API.
403 def orders(self,limit: int, offset: int) -> dict: 404 """ 405 Method to get all orders. 406 407 Documentation: 408 https://vortex.rupeezy.in/docs/latest/order/#fetching-order-book 409 410 Args: 411 limit (int): Limit is the number of orders to be fetched. 412 offset (int): Offset should atleast be 1 413 414 Returns: 415 dict: Dictionary containing the response data from the API. 416 """ 417 endpoint = f"/trading/orders?limit={limit}&offset={offset}" 418 return self._make_api_request("GET", endpoint)
Method to get all orders.
Documentation:
https://vortex.rupeezy.in/docs/latest/order/#fetching-order-book
Arguments:
- limit (int): Limit is the number of orders to be fetched.
- offset (int): Offset should atleast be 1
Returns:
dict: Dictionary containing the response data from the API.
420 def order_history(self,order_id: str) -> dict: 421 """ 422 Method to get the order history of a particular order 423 424 Documentation: 425 https://vortex.rupeezy.in/docs/latest/order/ 426 427 Args: 428 order_id (str): Order id for which history has to be fetched 429 430 Returns: 431 dict: Dictionary containing the response data from the API. 432 """ 433 endpoint = f"/trading/orders/{order_id}" 434 return self._make_api_request("GET", endpoint)
Method to get the order history of a particular order
Documentation:
Arguments:
- order_id (str): Order id for which history has to be fetched
Returns:
dict: Dictionary containing the response data from the API.
436 def positions(self) -> dict: 437 """ 438 Method to get the position book using the Vortex API. 439 440 Documentation: 441 https://vortex.rupeezy.in/docs/latest/positions/#fetch-all-positions 442 443 Returns: 444 dict: Dictionary containing the response data from the API. 445 """ 446 endpoint = f"/trading/portfolio/positions" 447 return self._make_api_request("GET", endpoint)
Method to get the position book using the Vortex API.
Documentation:
https://vortex.rupeezy.in/docs/latest/positions/#fetch-all-positions
Returns:
dict: Dictionary containing the response data from the API.
449 def holdings(self) -> dict: 450 """ 451 Method to get the holdings of the user using the Vortex API. 452 453 Documentation: 454 https://vortex.rupeezy.in/docs/latest/holdings/ 455 456 Returns: 457 dict: Dictionary containing the response data from the API. 458 """ 459 endpoint = "/trading/portfolio/holdings" 460 return self._make_api_request("GET", endpoint)
Method to get the holdings of the user using the Vortex API.
Documentation:
https://vortex.rupeezy.in/docs/latest/holdings/
Returns:
dict: Dictionary containing the response data from the API.
462 def trades(self) -> dict: 463 """ 464 Method to get today's trades of the user using the Vortex API. 465 466 Documentation: 467 https://vortex.rupeezy.in/docs/latest/positions/#get-trades 468 469 Returns: 470 dict: Dictionary containing the response data from the API. 471 """ 472 endpoint = "/trading/trades" 473 return self._make_api_request("GET", endpoint)
Method to get today's trades of the user using the Vortex API.
Documentation:
https://vortex.rupeezy.in/docs/latest/positions/#get-trades
Returns:
dict: Dictionary containing the response data from the API.
475 def funds(self) -> dict: 476 """ 477 Method to get the funds of the user using the Vortex API. 478 479 Documentation: 480 https://vortex.rupeezy.in/docs/latest/user/#available-funds 481 482 Returns: 483 dict: Dictionary containing the response data from the API. 484 """ 485 endpoint = "/user/funds" 486 return self._make_api_request("GET", endpoint)
Method to get the funds of the user using the Vortex API.
Documentation:
https://vortex.rupeezy.in/docs/latest/user/#available-funds
Returns:
dict: Dictionary containing the response data from the API.
488 def get_order_margin(self, exchange: Constants.ExchangeTypes, token: int, transaction_type: Constants.TransactionSides, product: Constants.ProductTypes, variety: Constants.VarietyTypes, 489 quantity: int, price: float,mode: Constants.OrderMarginModes, old_quantity: int = 0 , old_price: float = 0 ) -> dict: 490 """ 491 Get the margin required for placing an order for a specific security. 492 493 Documentation: 494 https://vortex.rupeezy.in/docs/latest/margin/#order-margin 495 496 Args: 497 exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO] 498 token (int): Security token of the scrip. It can be found in the scripmaster file 499 transaction_type (Constants.TransactionSides): Possible values: [BUY, SELL] 500 product (Constants.ProductTypes): Possible values: [INTRADAY, DELIVERY, MTF]. MTF product can only be used in NSE_EQ exchange. 501 variety (Constants.VarietyTypes): Possible values: [RL, RL-MKT, SL, SL-MKT]. RL means regular orders, SL means Stop Loss order. 502 MKT means that the trade will happen at market price 503 quantity (int): For exchange NSE_FO, if you want to trade in 2 lots and lot size is 50, you should pass 100. 504 In all other exchanges, you should pass just the number of lots. For example, in MCX_FO, 505 if you want to trade 5 lots, you should pass just 5. 506 price (float): Price should be an integer multiple of Tick Size. For example, IDEA's tick size is 0.05. 507 So the price entered can be 9.5 or 9.65. It cannot be 9.67. 508 In case of market orders, you should send the Last Trade Price received from the Quote API or Websocket API 509 mode (Constants.OrderMarginModes): Possible values: [NEW, MODIFY] , Whether you are trying to modify an existing order or placing a new order. 510 old_quantity (int): For NSE_FO segments, old_quantity is lots * lot_size. For all others, enter just the number of lots. Required if mode is MODIFY 511 old_price (float): Old Price in INR. Required if mode is MODIFY 512 513 Returns: 514 dict: JSON response containing the details of the margin required to place the order 515 516 Raises: 517 HTTPError: If any HTTP error occurs during the API call 518 """ 519 520 endpoint = "/margins/order" 521 522 data = { 523 "exchange": exchange, 524 "token": token, 525 "transaction_type": transaction_type, 526 "product": product, 527 "variety": variety, 528 "quantity": quantity, 529 "price": price, 530 "old_quantity": old_quantity, 531 "old_price": old_price, 532 "mode": mode, 533 } 534 return self._make_api_request("POST", endpoint, data=data)
Get the margin required for placing an order for a specific security.
Documentation:
https://vortex.rupeezy.in/docs/latest/margin/#order-margin
Arguments:
- exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO]
- token (int): Security token of the scrip. It can be found in the scripmaster file
- transaction_type (Constants.TransactionSides): Possible values: [BUY, SELL]
- product (Constants.ProductTypes): Possible values: [INTRADAY, DELIVERY, MTF]. MTF product can only be used in NSE_EQ exchange.
- variety (Constants.VarietyTypes): Possible values: [RL, RL-MKT, SL, SL-MKT]. RL means regular orders, SL means Stop Loss order. MKT means that the trade will happen at market price
- quantity (int): For exchange NSE_FO, if you want to trade in 2 lots and lot size is 50, you should pass 100. In all other exchanges, you should pass just the number of lots. For example, in MCX_FO, if you want to trade 5 lots, you should pass just 5.
- price (float): Price should be an integer multiple of Tick Size. For example, IDEA's tick size is 0.05. So the price entered can be 9.5 or 9.65. It cannot be 9.67. In case of market orders, you should send the Last Trade Price received from the Quote API or Websocket API
- mode (Constants.OrderMarginModes): Possible values: [NEW, MODIFY] , Whether you are trying to modify an existing order or placing a new order.
- old_quantity (int): For NSE_FO segments, old_quantity is lots * lot_size. For all others, enter just the number of lots. Required if mode is MODIFY
- old_price (float): Old Price in INR. Required if mode is MODIFY
Returns:
dict: JSON response containing the details of the margin required to place the order
Raises:
- HTTPError: If any HTTP error occurs during the API call
536 def brokerage_plan(self)-> dict: 537 """ 538 Get brokerage plan details of the user. 539 540 Documentation: 541 https://vortex.rupeezy.in/docs/latest/user/ 542 543 Returns: 544 dict: JSON response containing the details of the brokerage plan of the user 545 """ 546 endpoint = "/user/profile/brokerage" 547 return self._make_api_request("GET", endpoint, data=None,params=None)
Get brokerage plan details of the user.
Documentation:
https://vortex.rupeezy.in/docs/latest/user/
Returns:
dict: JSON response containing the details of the brokerage plan of the user
549 def quotes(self, instruments: list, mode: Constants.QuoteModes)-> dict: 550 """ 551 Gets quotes of up to 1000 instruments at a time. 552 553 Documentation: 554 https://vortex.rupeezy.in/docs/latest/historical/#fetch-price-quotes 555 556 Args: 557 instrument(list): List of instruments. The items should be like ( "NSE_EQ-22", "NSE_FO-1234") 558 mode(Constants.QuoteModes): Quote mode. Can be ["ltp","ohlcv", "full"]. LTP quotes just give the last trade price, ohlc give open, high, low, close and volume, full mode also gives depth. 559 560 Returns: 561 dict: JSON response containing quotes. It is possible that not all the symbol identifiers you passed had a quote available. Those inputs will be missing from the response. 562 Also, the order of output might be different than the order of input 563 """ 564 endpoint = "/data/quotes" 565 params = {"q": instruments,"mode": mode} 566 return self._make_api_request("GET", endpoint, data=None,params=params)
Gets quotes of up to 1000 instruments at a time.
Documentation:
https://vortex.rupeezy.in/docs/latest/historical/#fetch-price-quotes
Arguments:
- instrument(list): List of instruments. The items should be like ( "NSE_EQ-22", "NSE_FO-1234")
- mode(Constants.QuoteModes): Quote mode. Can be ["ltp","ohlcv", "full"]. LTP quotes just give the last trade price, ohlc give open, high, low, close and volume, full mode also gives depth.
Returns:
dict: JSON response containing quotes. It is possible that not all the symbol identifiers you passed had a quote available. Those inputs will be missing from the response. Also, the order of output might be different than the order of input
568 def historical_candles(self, exchange: Constants.ExchangeTypes, token: int, to: datetime.datetime , start: datetime.datetime, resolution: Constants.Resolutions): 569 """ 570 Gets historical candle data of a particular instrument. 571 572 Documentation: 573 https://vortex.rupeezy.in/docs/latest/historical/#fetch-historical-candle-data 574 575 Args: 576 exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO] 577 token (int): Security token of the scrip. It can be found in the instruments master file: 578 to (datetime): datetime up till when you want to receive candles 579 start (datetime): datetime from when you want to receive candles 580 resolution (Constants.Resolutions): resoulution of the candle. can be "1", "2", "3", "4", "5", "10", "15", "30", "45", "60", "120", "180", "240", "1D", "1W", "1M" 581 582 Returns: 583 dict: JSON response containing the historical candles 584 """ 585 586 if not isinstance(token, int): 587 raise TypeError("token must be an integer") 588 if not isinstance(to,datetime.datetime): 589 raise TypeError("to must be a datetime") 590 if not isinstance(start,datetime.datetime): 591 raise TypeError("start must be a datetime") 592 593 594 endpoint = "/data/history" 595 params = {"exchange": exchange,"token": token , "to": int(to.timestamp()), "from": int(start.timestamp()), "resolution": resolution} 596 return self._make_api_request("GET", endpoint, data=None,params=params)
Gets historical candle data of a particular instrument.
Documentation:
https://vortex.rupeezy.in/docs/latest/historical/#fetch-historical-candle-data
Arguments:
- exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO]
- token (int): Security token of the scrip. It can be found in the instruments master file:
- to (datetime): datetime up till when you want to receive candles
- start (datetime): datetime from when you want to receive candles
- resolution (Constants.Resolutions): resoulution of the candle. can be "1", "2", "3", "4", "5", "10", "15", "30", "45", "60", "120", "180", "240", "1D", "1W", "1M"
Returns:
dict: JSON response containing the historical candles
598 def login_url(self, callback_param: str) -> str: 599 """ 600 Returns the login URL for the Vortex API. 601 602 Documentation: 603 https://vortex.rupeezy.in/docs/latest/authentication/ 604 605 Returns: 606 str: The login URL for the Vortex API. 607 """ 608 609 return f"https://flow.rupeezy.in?applicationId={self.application_id}&cb_param={callback_param}"
Returns the login URL for the Vortex API.
Documentation:
Returns:
str: The login URL for the Vortex API.
611 def exchange_token(self,auth_code: str) -> dict: 612 """ 613 Exchange the auth code received from the login URL for an access token. 614 615 Documentation: 616 https://vortex.rupeezy.in/docs/latest/authentication/ 617 618 Args: 619 auth_code (str): The authorization code received from the login URL. 620 621 Returns: 622 dict: JSON response containing the details of the user 623 """ 624 625 endpoint = "/user/session" 626 data = { 627 "token": auth_code, 628 "applicationId": self.application_id, 629 "checksum": self._sha256_hash(f"{self.application_id}{auth_code}{self.api_key}") 630 } 631 res = self._make_unauth_request("POST", endpoint= endpoint, data=data) 632 self._setup_client_code(login_object=res) 633 return res
Exchange the auth code received from the login URL for an access token.
Documentation:
Arguments:
- auth_code (str): The authorization code received from the login URL.
Returns:
dict: JSON response containing the details of the user
657 def save_backtest_result(self, stats, name: str, symbol: str = "", description: str = "", tags: list = None) -> dict: 658 """ 659 Save backtest results to Rupeezy for viewing on the developer portal. 660 661 Supports multiple backtesting libraries (auto-detected from the result type): 662 - **backtesting.py**: pass the stats object from Backtest.run() 663 - **vectorbt**: pass a vbt.Portfolio object 664 - **backtrader**: pass the strategy from cerebro.run() (i.e. results[0]) 665 666 Args: 667 stats: The result object from any supported backtesting library. 668 name (str): A label for this backtest run (e.g. "SMA Crossover v2"). 669 symbol (str, optional): Primary instrument symbol. 670 description (str, optional): Notes about this run. 671 tags (list[str], optional): Tags for filtering (e.g. ["intraday", "nifty"]). 672 673 Returns: 674 dict: { "status": "success", "backtest_id": "bt_abc123", "url": "https://..." } 675 """ 676 from .backtest import serialize_stats 677 payload = serialize_stats(stats, name, symbol, description, tags or []) 678 endpoint = "/strategies/backtests" 679 680 return self._make_api_request("POST", endpoint, data=payload)
Save backtest results to Rupeezy for viewing on the developer portal.
Supports multiple backtesting libraries (auto-detected from the result type):
- backtesting.py: pass the stats object from Backtest.run()
- vectorbt: pass a vbt.Portfolio object
- backtrader: pass the strategy from cerebro.run() (i.e. results[0])
Arguments:
- stats: The result object from any supported backtesting library.
- name (str): A label for this backtest run (e.g. "SMA Crossover v2").
- symbol (str, optional): Primary instrument symbol.
- description (str, optional): Notes about this run.
- tags (list[str], optional): Tags for filtering (e.g. ["intraday", "nifty"]).
Returns:
dict: { "status": "success", "backtest_id": "bt_abc123", "url": "https://..." }
682 def save_optimization_result( 683 self, 684 stats, 685 heatmap, 686 name: str, 687 symbol: str = "", 688 description: str = "", 689 maximize="Sharpe Ratio", 690 param_ranges: dict = None, 691 ) -> dict: 692 """ 693 Save optimization results to Rupeezy for viewing on the developer portal. 694 695 Supports multiple backtesting libraries (auto-detected from the result type): 696 - **backtesting.py**: pass stats + heatmap from bt.optimize(return_heatmap=True) 697 - **vectorbt**: pass Portfolio + metric Series from multi-param run 698 - **backtrader**: pass results list from cerebro.run() after optstrategy() 699 700 Args: 701 stats: The result object from any supported backtesting library. 702 heatmap: The heatmap/metric Series (backtesting.py/vectorbt) or 703 metric extraction callable (backtrader). 704 name (str): A label for this optimization run (e.g. "SMA Grid Search"). 705 symbol (str, optional): Primary instrument symbol (e.g. "NIFTY"). 706 description (str, optional): Notes about this optimization run. 707 maximize: The metric that was optimized. Should match the `maximize` 708 argument passed to Backtest.optimize(). Can be a string 709 metric name (e.g. "Sharpe Ratio") or a callable. 710 Defaults to "Sharpe Ratio". 711 param_ranges (dict, optional): Explicit parameter range definitions. 712 Keys are parameter names, values are range() objects or lists. 713 Example: {"sma_fast": range(5, 51, 5), "sma_slow": range(20, 201, 10)} 714 If not provided, ranges are inferred from the heatmap index. 715 716 Returns: 717 dict: {"status": "success", "optimization_id": "opt_xxx", "backtest_id": "bt_xxx"} 718 719 Example:: 720 721 stats, heatmap = bt.optimize( 722 sma_fast=range(5, 51, 5), 723 sma_slow=range(20, 201, 10), 724 maximize='Sharpe Ratio', 725 return_heatmap=True, 726 ) 727 client.save_optimization_result( 728 stats=stats, 729 heatmap=heatmap, 730 name="SMA Crossover Grid Search", 731 symbol="NIFTY", 732 maximize='Sharpe Ratio', 733 param_ranges={"sma_fast": range(5, 51, 5), "sma_slow": range(20, 201, 10)}, 734 ) 735 """ 736 is_maximize = True 737 objective_metric = maximize 738 739 if isinstance(maximize, bool): 740 is_maximize = maximize 741 objective_metric = "Sharpe Ratio" 742 743 from .backtest import serialize_optimization 744 payload = serialize_optimization( 745 result=stats, 746 heatmap=heatmap, 747 name=name, 748 symbol=symbol, 749 description=description, 750 objective_metric=objective_metric, 751 maximize=is_maximize, 752 param_ranges=param_ranges, 753 ) 754 endpoint = "/strategies/optimizations" 755 return self._make_api_request("POST", endpoint, data=payload)
Save optimization results to Rupeezy for viewing on the developer portal.
Supports multiple backtesting libraries (auto-detected from the result type):
- backtesting.py: pass stats + heatmap from bt.optimize(return_heatmap=True)
- vectorbt: pass Portfolio + metric Series from multi-param run
- backtrader: pass results list from cerebro.run() after optstrategy()
Arguments:
- stats: The result object from any supported backtesting library.
- heatmap: The heatmap/metric Series (backtesting.py/vectorbt) or metric extraction callable (backtrader).
- name (str): A label for this optimization run (e.g. "SMA Grid Search").
- symbol (str, optional): Primary instrument symbol (e.g. "NIFTY").
- description (str, optional): Notes about this optimization run.
- maximize: The metric that was optimized. Should match the
maximizeargument passed to Backtest.optimize(). Can be a string metric name (e.g. "Sharpe Ratio") or a callable. Defaults to "Sharpe Ratio". - param_ranges (dict, optional): Explicit parameter range definitions. Keys are parameter names, values are range() objects or lists. Example: {"sma_fast": range(5, 51, 5), "sma_slow": range(20, 201, 10)} If not provided, ranges are inferred from the heatmap index.
Returns:
dict: {"status": "success", "optimization_id": "opt_xxx", "backtest_id": "bt_xxx"}
Example::
stats, heatmap = bt.optimize(
sma_fast=range(5, 51, 5),
sma_slow=range(20, 201, 10),
maximize='Sharpe Ratio',
return_heatmap=True,
)
client.save_optimization_result(
stats=stats,
heatmap=heatmap,
name="SMA Crossover Grid Search",
symbol="NIFTY",
maximize='Sharpe Ratio',
param_ranges={"sma_fast": range(5, 51, 5), "sma_slow": range(20, 201, 10)},
)
11class Constants: 12 """ 13 Constants used in the API 14 """ 15 class ExchangeTypes(str,Enum): 16 """ 17 Constants for exchanges 18 """ 19 NSE_FO = "NSE_FO" 20 BSE_FO = "BSE_FO" 21 NSE_EQUITY = "NSE_EQ" 22 BSE_EQUITY = "BSE_EQ" 23 NSE_CURRENCY = "NSE_CD" 24 MCX = "MCX_FO" 25 26 def __str__(self): 27 return str(self.value) 28 class VarietyTypes(str,Enum): 29 """ 30 Constants for varieties 31 """ 32 REGULAR_LIMIT_ORDER = "RL" 33 REGULAR_MARKET_ORDER = "RL-MKT" 34 STOP_LIMIT_ORDER = "SL" 35 STOP_MARKET_ORDER = "SL-MKT" 36 37 def __str__(self): 38 return str(self.value) 39 class ProductTypes(str,Enum): 40 """ 41 Constants for product types 42 """ 43 INTRADAY = "INTRADAY" 44 DELIVERY = "DELIVERY" 45 MTF = "MTF" 46 47 def __str__(self): 48 return str(self.value) 49 class ValidityTypes(str,Enum): 50 """ 51 Constants for validity types 52 """ 53 FULL_DAY = "DAY" 54 IMMEDIATE_OR_CANCEL = "IOC" 55 AFTER_MARKET = "AMO" 56 57 def __str__(self): 58 return str(self.value) 59 class TransactionSides(str,Enum): 60 """ 61 Constants for transaction sides 62 """ 63 BUY = "BUY" 64 SELL = "SELL" 65 def __str__(self): 66 return str(self.value) 67 class QuoteModes(str,Enum): 68 """ 69 Constants for quote modes 70 """ 71 LTP = "ltp" 72 FULL = "full" 73 OHLCV = "ohlcv" 74 def __str__(self): 75 return str(self.value) 76 class OrderMarginModes(str,Enum): 77 """ 78 Constants for order margin modes 79 """ 80 NEW_ORDER = "NEW" 81 MODIFY_ORDER = "MODIFY" 82 83 def __str__(self): 84 return str(self.value) 85 class Resolutions(str,Enum): 86 """ 87 Constants for resolutions 88 """ 89 MIN_1 = "1" 90 MIN_2 = "2" 91 MIN_3 = "3" 92 MIN_4 = "4" 93 MIN_5 = "5" 94 MIN_10 = "10" 95 MIN_15 = "15" 96 MIN_30 = "30" 97 MIN_45 = "45" 98 MIN_60 = "60" 99 MIN_120 = "120" 100 MIN_180 = "180" 101 MIN_240 = "240" 102 DAY = "1D" 103 WEEK = "1W" 104 MONTH = "1M" 105 106 def __str__(self): 107 return str(self.value)
Constants used in the API
15 class ExchangeTypes(str,Enum): 16 """ 17 Constants for exchanges 18 """ 19 NSE_FO = "NSE_FO" 20 BSE_FO = "BSE_FO" 21 NSE_EQUITY = "NSE_EQ" 22 BSE_EQUITY = "BSE_EQ" 23 NSE_CURRENCY = "NSE_CD" 24 MCX = "MCX_FO" 25 26 def __str__(self): 27 return str(self.value)
Constants for exchanges
Inherited Members
- enum.Enum
- name
- value
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
28 class VarietyTypes(str,Enum): 29 """ 30 Constants for varieties 31 """ 32 REGULAR_LIMIT_ORDER = "RL" 33 REGULAR_MARKET_ORDER = "RL-MKT" 34 STOP_LIMIT_ORDER = "SL" 35 STOP_MARKET_ORDER = "SL-MKT" 36 37 def __str__(self): 38 return str(self.value)
Constants for varieties
Inherited Members
- enum.Enum
- name
- value
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
39 class ProductTypes(str,Enum): 40 """ 41 Constants for product types 42 """ 43 INTRADAY = "INTRADAY" 44 DELIVERY = "DELIVERY" 45 MTF = "MTF" 46 47 def __str__(self): 48 return str(self.value)
Constants for product types
Inherited Members
- enum.Enum
- name
- value
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
49 class ValidityTypes(str,Enum): 50 """ 51 Constants for validity types 52 """ 53 FULL_DAY = "DAY" 54 IMMEDIATE_OR_CANCEL = "IOC" 55 AFTER_MARKET = "AMO" 56 57 def __str__(self): 58 return str(self.value)
Constants for validity types
Inherited Members
- enum.Enum
- name
- value
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
59 class TransactionSides(str,Enum): 60 """ 61 Constants for transaction sides 62 """ 63 BUY = "BUY" 64 SELL = "SELL" 65 def __str__(self): 66 return str(self.value)
Constants for transaction sides
Inherited Members
- enum.Enum
- name
- value
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
67 class QuoteModes(str,Enum): 68 """ 69 Constants for quote modes 70 """ 71 LTP = "ltp" 72 FULL = "full" 73 OHLCV = "ohlcv" 74 def __str__(self): 75 return str(self.value)
Constants for quote modes
Inherited Members
- enum.Enum
- name
- value
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
76 class OrderMarginModes(str,Enum): 77 """ 78 Constants for order margin modes 79 """ 80 NEW_ORDER = "NEW" 81 MODIFY_ORDER = "MODIFY" 82 83 def __str__(self): 84 return str(self.value)
Constants for order margin modes
Inherited Members
- enum.Enum
- name
- value
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
85 class Resolutions(str,Enum): 86 """ 87 Constants for resolutions 88 """ 89 MIN_1 = "1" 90 MIN_2 = "2" 91 MIN_3 = "3" 92 MIN_4 = "4" 93 MIN_5 = "5" 94 MIN_10 = "10" 95 MIN_15 = "15" 96 MIN_30 = "30" 97 MIN_45 = "45" 98 MIN_60 = "60" 99 MIN_120 = "120" 100 MIN_180 = "180" 101 MIN_240 = "240" 102 DAY = "1D" 103 WEEK = "1W" 104 MONTH = "1M" 105 106 def __str__(self): 107 return str(self.value)
Constants for resolutions
Inherited Members
- enum.Enum
- name
- value
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
The WebSocket client for connecting to vortex's live price and order streaming service
239 def __init__(self, access_token: str=None, websocket_endpoint="wss://wire.rupeezy.in/ws",reconnect=True, reconnect_max_tries=RECONNECT_MAX_TRIES, reconnect_max_delay=RECONNECT_MAX_DELAY, 240 connect_timeout=CONNECT_TIMEOUT, debug = False) -> None: 241 self._maximum_reconnect_max_tries = self.RECONNECT_MAX_TRIES 242 self._minimum_reconnect_max_delay = 0 243 if reconnect == False: 244 self.reconnect_max_tries = 0 245 elif reconnect_max_tries > self._maximum_reconnect_max_tries: 246 log.warning("`reconnect_max_tries` can not be more than {val}. Setting to highest possible value - {val}.".format( 247 val=self._maximum_reconnect_max_tries)) 248 self.reconnect_max_tries = self._maximum_reconnect_max_tries 249 else: 250 self.reconnect_max_tries = reconnect_max_tries 251 252 if reconnect_max_delay < self._minimum_reconnect_max_delay: 253 log.warning("`reconnect_max_delay` can not be less than {val}. Setting to lowest possible value - {val}.".format( 254 val=self._minimum_reconnect_max_delay)) 255 self.reconnect_max_delay = self._minimum_reconnect_max_delay 256 else: 257 self.reconnect_max_delay = reconnect_max_delay 258 259 self.connect_timeout = connect_timeout 260 if access_token == None: 261 if os.getenv("VORTEX_ACCESS_TOKEN") != None: 262 access_token = os.getenv("VORTEX_ACCESS_TOKEN") 263 else: 264 raise ValueError("Access token must be provided either as an argument or through the VORTEX_ACCESS_TOKEN environment variable.") 265 266 self.socket_url = websocket_endpoint+"?auth_token="+access_token 267 self.access_token = access_token 268 self.socket_token = self.__getSocketToken__(self.access_token) 269 270 self.debug = debug 271 # self.on_price_update = None 272 self.on_price_update = None 273 self.on_open = None 274 self.on_close = None 275 self.on_error = None 276 self.on_connect = None 277 self.on_message = None 278 self.on_reconnect = None 279 self.on_noreconnect = None 280 self.on_order_update = None 281 self.subscribed_tokens = {} 282 pass
306 def connect(self, threaded=False, disable_ssl_verification=False): 307 """ 308 Establish a websocket connection. 309 - `disable_ssl_verification` disables building ssl context 310 """ 311 # Init WebSocket client factory 312 self._create_connection(self.socket_url, 313 useragent=self._user_agent()) 314 315 # Set SSL context 316 context_factory = None 317 if self.factory.isSecure and not disable_ssl_verification: 318 from urllib.parse import urlparse 319 hostname = urlparse(self.socket_url).hostname 320 context_factory = ssl.optionsForClientTLS(hostname) 321 322 # Establish WebSocket connection to a server 323 connectWS(self.factory, contextFactory=context_factory, timeout=self.connect_timeout) 324 325 if self.debug: 326 twisted_log.startLogging(sys.stdout) 327 328 # Run in seperate thread of blocking 329 opts = {} 330 # Run when reactor is not running 331 if not reactor.running: 332 if threaded: 333 # Signals are not allowed in non main thread by twisted so suppress it. 334 opts["installSignalHandlers"] = False 335 self.websocket_thread = threading.Thread(target=reactor.run, kwargs=opts) 336 self.websocket_thread.daemon = True 337 self.websocket_thread.start() 338 else: 339 reactor.run(**opts) 340 else: 341 print(reactor.running)
Establish a websocket connection.
disable_ssl_verificationdisables building ssl context
343 def is_connected(self): 344 """Check if WebSocket connection is established.""" 345 if self.ws and self.ws.state == self.ws.STATE_OPEN: 346 return True 347 else: 348 return False
Check if WebSocket connection is established.
355 def close(self, code=None, reason=None): 356 """Close the WebSocket connection.""" 357 self.stop_retry() 358 self._close(code, reason)
Close the WebSocket connection.
360 def stop(self): 361 """Stop the event loop. Should be used if main thread has to be closed in `on_close` method. 362 Reconnection mechanism cannot happen past this method 363 """ 364 reactor.stop()
Stop the event loop. Should be used if main thread has to be closed in on_close method.
Reconnection mechanism cannot happen past this method
366 def stop_retry(self): 367 """Stop auto retry when it is in progress.""" 368 if self.factory: 369 self.factory.stopTrying()
Stop auto retry when it is in progress.
371 def subscribe(self, exchange: str,token: int,mode: str)->bool: 372 """ 373 Subscribe to a list of instrument_tokens. 374 - `instrument_tokens` is list of instrument instrument_tokens to subscribe 375 """ 376 try: 377 self.ws.sendMessage(six.b(json.dumps({"message_type": self._message_subscribe, "exchange": exchange,"token": token,"mode": mode}))) 378 379 try: 380 self.subscribed_tokens[exchange][token] = mode 381 except KeyError: 382 self.subscribed_tokens[exchange] = {} 383 self.subscribed_tokens[exchange][token] = mode 384 385 return True 386 except Exception as e: 387 self._close(reason="Error while subscribe: {}".format(str(e))) 388 raise
Subscribe to a list of instrument_tokens.
instrument_tokensis list of instrument instrument_tokens to subscribe
390 def unsubscribe(self, exchange: str,token: int)->bool: 391 """ 392 Unsubscribe the given list of instrument_tokens. 393 - `instrument_tokens` is list of instrument_tokens to unsubscribe. 394 """ 395 try: 396 self.ws.sendMessage(six.b(json.dumps({"message_type": self._message_unsubscribe, "exchange": exchange,"token": token}))) 397 398 try: 399 del(self.subscribed_tokens[exchange][token]) 400 except KeyError: 401 pass 402 403 return True 404 except Exception as e: 405 self._close(reason="Error while unsubscribe: {}".format(str(e))) 406 raise
Unsubscribe the given list of instrument_tokens.
instrument_tokensis list of instrument_tokens to unsubscribe.
408 def resubscribe(self): 409 """Resubscribe to all current subscribed tokens.""" 410 modes = {} 411 412 for exchange in self.subscribed_tokens: 413 for token in self.subscribed_tokens[exchange]: 414 self.subscribe(exchange=exchange, token=token,mode=self.subscribed_tokens[exchange][token])
Resubscribe to all current subscribed tokens.