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]
@validate_selected_methods(['login', 'place_order', 'modify_order', 'cancel_order', 'get_order_margin', 'historical_candles', 'quotes'])
class VortexAPI:
 155@validate_selected_methods(['login','place_order','modify_order','cancel_order','get_order_margin','historical_candles','quotes'])
 156class VortexAPI:
 157
 158    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:
 159        """
 160        Constructor method for VortexAPI class.
 161
 162        Args:
 163            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.
 164            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.
 165            base_url (str, optional): Base URL for the Vortex API. Defaults to "https://vortex-api.rupeezy.in/v2".
 166        """
 167        if api_key == None:
 168            if os.getenv("VORTEX_API_KEY") != None:
 169                api_key = os.getenv("VORTEX_API_KEY")
 170            else:
 171                raise ValueError("API key must be provided either as an argument or through the VORTEX_API_KEY environment variable.")
 172        
 173        if application_id == None:
 174            if os.getenv("VORTEX_APPLICATION_ID") != None:
 175                application_id = os.getenv("VORTEX_APPLICATION_ID")
 176            else:
 177                raise ValueError("Application ID must be provided either as an argument or through the VORTEX_APPLICATION_ID environment variable.")
 178        self.api_key = api_key
 179        self.application_id = application_id
 180
 181        if os.getenv("VORTEX_BASE_URL") != None:
 182            self.base_url = os.getenv("VORTEX_BASE_URL")
 183        else:
 184            self.base_url = base_url
 185            
 186        if os.getenv("VORTEX_ACCESS_TOKEN") != None:
 187            self.access_token = os.getenv("VORTEX_ACCESS_TOKEN")
 188        else:
 189            self.access_token = None
 190
 191        self.enable_logging = enable_logging
 192        if self.enable_logging:
 193            logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
 194    
 195    def _make_api_request(self, method: str, endpoint: str, data: dict = None, params=None) -> dict:
 196        """
 197        Private method to make HTTP requests to the Vortex API.
 198
 199        Args:
 200            method (str): HTTP method for the request (e.g. "GET", "POST", "PUT", "DELETE").
 201            endpoint (str): API endpoint for the request.
 202            data (dict, optional): Payload data for the request. Defaults to None.
 203
 204        Returns:
 205            dict: Dictionary containing the response data from the API.
 206        """
 207        if(self.access_token == None):
 208            op = {}
 209            op["status"]= "error"
 210            op["message"] = "please login first"
 211            return op
 212        bearer_token = f"Bearer {self.access_token}"
 213        headers = {"Content-Type": "application/json", "Authorization": bearer_token}
 214        url = self.base_url + endpoint
 215        if self.enable_logging:
 216            logging.debug(f"Making network call to {url}  , params: {params}, data: {data}, headers: {headers}")
 217        response = requests.request(method, url, headers=headers, json=data,params=params)
 218        if self.enable_logging:
 219            logging.debug(f"Response received from {url}  , body: {response.json()}")
 220        response.raise_for_status()
 221        return response.json()
 222    
 223    def _make_unauth_request(self, method: str, endpoint: str, data: dict = None, params: dict = None) -> dict:
 224        """
 225        Private method to make HTTP requests to the Vortex API.
 226
 227        Args:
 228            method (str): HTTP method for the request (e.g. "GET", "POST", "PUT", "DELETE").
 229            endpoint (str): API endpoint for the request.
 230            data (dict, optional): Payload data for the request. Defaults to None.
 231
 232        Returns:
 233            dict: Dictionary containing the response data from the API.
 234        """
 235        headers = {"Content-Type": "application/json", "x-api-key": self.api_key}
 236        url = self.base_url + endpoint
 237        if self.enable_logging:
 238            logging.debug(f"Making network call to {url}  , params: {params}, data: {data}, headers: {headers}")
 239        response = requests.request(method, url, headers=headers, json=data)
 240        response.raise_for_status()
 241        if self.enable_logging:
 242            logging.debug(f"Response received from {url}  , body: {response.json()}")
 243        return response.json()
 244    
 245    def login(self, client_code: str, password: str, totp: str)->dict:
 246        """
 247        Depricating Soon. Use SSO Login instead. Login using password and totp directly
 248        
 249        Documentation:
 250            https://vortex.rupeezy.in/docs/latest/authentication/
 251
 252        Args:
 253            client_code(str): Client Code of the account
 254            password(str): Password of the account
 255            totp(str): TOTP generated using third party apps like google authenticator etc. 
 256
 257        Returns:
 258            dict: JSON response containing the details of the user
 259        """
 260        endpoint = "/user/login"
 261        data = {
 262            "client_code": client_code,
 263            "password": password,
 264            "totp": totp,
 265            "application_id": self.application_id
 266        }
 267        res = self._make_unauth_request("POST", endpoint= endpoint, data=data)
 268        self._setup_client_code(login_object=res)
 269        return res
 270    
 271    def download_master(self) -> dict:
 272        """
 273        Download list of all available instruments and their details across all exchanges
 274
 275        Documentation:
 276            https://vortex.rupeezy.in/docs/latest/historical/#instrument-list
 277
 278        Returns:
 279            dict: CSV Array of all instruments. The first row contains headers
 280        """
 281        endpoint = "https://static.rupeezy.in/master.csv"
 282        with requests.Session() as s: 
 283            download = s.get(url=endpoint)
 284            decoded_content = download.content.decode('utf-8')
 285            cr = csv.reader(decoded_content.splitlines(), delimiter=',')
 286            my_list = list(cr)
 287            return my_list
 288    
 289    def place_order(self,exchange: Constants.ExchangeTypes, token: int, transaction_type: Constants.TransactionSides, product: Constants.ProductTypes, variety: Constants.VarietyTypes, 
 290                quantity: int, price: float, trigger_price: float, disclosed_quantity: int, validity: Constants.ValidityTypes) -> dict:
 291        """
 292        Place an order for a specific security
 293
 294        Documentation:
 295            https://vortex.rupeezy.in/docs/latest/order/#placing-an-order
 296
 297        Args:
 298            exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO]
 299            token (int): Security token of the scrip. It can be found in the scripmaster file
 300            transaction_type (Constants.TransactionSides): Possible values: [BUY, SELL]
 301            product (Constants.ProductTypes): Possible values: [INTRADAY, DELIVERY, MTF]. MTF product can only be used in NSE_EQ exchange.
 302            variety (Constants.VarietyTypes): Possible values: [RL, RL-MKT, SL, SL-MKT]. RL means regular orders, SL means Stop Loss order. 
 303                        MKT means that the trade will happen at market price
 304            quantity (int): For exchange NSE_FO, if you want to trade in 2 lots and lot size is 50, you should pass 100. 
 305                            In all other exchanges, you should pass just the number of lots. For example, in MCX_FO, 
 306                            if you want to trade 5 lots, you should pass just 5.
 307            price (float): Price should be an integer multiple of Tick Size. For example, IDEA's tick size is 0.05. 
 308                        So the price entered can be 9.5 or 9.65. It cannot be 9.67. 
 309                        In case of market orders, you should send the Last Trade Price received from the Quote API or Websocket API
 310            trigger_price (float): To be used for Stop loss orders. For BUY side SL orders, trigger_price should be 
 311                                lesser than price. for SELL side SL orders, trigger_price should be greater than price.
 312            disclosed_quantity (int): Can be any number lesser than or equal to quantity, including 0
 313            validity (Constants.ValidityTypes): Can be DAY for orders which are valid throughout the day, or IOC. 
 314                            IOC order will be cancelled if it is not traded immediately
 315        Returns:
 316            dict: JSON response containing the details of the placed order
 317
 318        Raises:
 319            HTTPError: If any HTTP error occurs during the API call
 320        """
 321
 322        endpoint = "/trading/orders/regular"
 323        if validity == Constants.ValidityTypes.FULL_DAY: 
 324            validity_days = 1 
 325            is_amo = False
 326        elif validity == Constants.ValidityTypes.IMMEDIATE_OR_CANCEL: 
 327            validity_days = 0 
 328            is_amo = False
 329        else: 
 330            validity_days = 1 
 331            is_amo = True 
 332
 333        data = {
 334            "exchange": exchange,
 335            "token": token,
 336            "transaction_type": transaction_type,
 337            "product": product,
 338            "variety": variety,
 339            "quantity": quantity,
 340            "price": price,
 341            "trigger_price": trigger_price,
 342            "disclosed_quantity": disclosed_quantity,
 343            "validity": validity,
 344            "validity_days": validity_days,
 345            "is_amo": is_amo
 346        }
 347        
 348        return self._make_api_request("POST", endpoint, data=data)
 349    
 350    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:
 351        """
 352        Method to modify an order using the Vortex API.
 353
 354        Documentation:
 355            https://vortex.rupeezy.in/docs/latest/order/#modifying-an-order
 356
 357        Args:
 358            exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO]
 359            order_id (str): The unique ID of the order to modify.
 360            variety (Constants.VarietyTypes): Possible values: [RL, RL-MKT, SL, SL-MKT]. RL means regular orders, SL means Stop Loss order. 
 361                    MKT means that the trade will happen at market price
 362            quantity (int): The new quantity for the order.
 363            traded_quantity (int): The quantity of the order that has already been traded.
 364            price (float): The new price for the order.
 365            trigger_price (float): The new trigger price for the order. Required for SL and SL-M orders.
 366            disclosed_quantity (int): The new quantity to be disclosed publicly.
 367            validity (Constants.ValidityTypes): The new validity for the order (e.g. DAY, IOC, GTD).
 368
 369        Returns:
 370            dict: Dictionary containing the response data from the API.
 371        """
 372
 373        endpoint = f"/trading/orders/regular/{order_id}"
 374        if validity == Constants.ValidityTypes.FULL_DAY: 
 375            validity_days = 1 
 376        elif validity == Constants.ValidityTypes.IMMEDIATE_OR_CANCEL: 
 377            validity_days = 0 
 378        else: 
 379            validity_days = 1 
 380
 381        data = {
 382            "variety": variety,
 383            "quantity": quantity,
 384            "traded_quantity": traded_quantity,
 385            "price": price,
 386            "trigger_price": trigger_price,
 387            "disclosed_quantity": disclosed_quantity,
 388            "validity": validity,
 389            "validity_days": validity_days
 390        }
 391        return self._make_api_request("PUT", endpoint, data=data)
 392    
 393    def cancel_order(self, order_id: str) -> dict:
 394        """
 395        Method to cancel an order using the Vortex API.
 396
 397        Documentation:
 398            https://vortex.rupeezy.in/docs/latest/order/#cancel-an-order
 399
 400        Args:
 401            exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO]
 402            order_id (str): The unique ID of the order to cancel.
 403
 404        Returns:
 405            dict: Dictionary containing the response data from the API.
 406        """
 407        
 408        endpoint = f"/trading/orders/regular/{order_id}"
 409        return self._make_api_request("DELETE", endpoint)
 410
 411    def orders(self,limit: int, offset: int) -> dict:
 412        """
 413        Method to get all orders.
 414
 415        Documentation:
 416            https://vortex.rupeezy.in/docs/latest/order/#fetching-order-book
 417
 418        Args:
 419            limit (int): Limit is the number of orders to be fetched. 
 420            offset (int): Offset should atleast be 1 
 421
 422        Returns:
 423            dict: Dictionary containing the response data from the API.
 424        """
 425        endpoint = f"/trading/orders?limit={limit}&offset={offset}"
 426        return self._make_api_request("GET", endpoint)
 427    
 428    def order_history(self,order_id: str) -> dict:
 429        """
 430        Method to get the order history of a particular order
 431
 432        Documentation:
 433            https://vortex.rupeezy.in/docs/latest/order/
 434
 435        Args:
 436            order_id (str): Order id for which history has to be fetched
 437
 438        Returns:
 439            dict: Dictionary containing the response data from the API.
 440        """
 441        endpoint = f"/trading/orders/{order_id}"
 442        return self._make_api_request("GET", endpoint)
 443
 444    def positions(self) -> dict:
 445        """
 446        Method to get the position book using the Vortex API.
 447
 448        Documentation:
 449            https://vortex.rupeezy.in/docs/latest/positions/#fetch-all-positions
 450
 451        Returns:
 452            dict: Dictionary containing the response data from the API.
 453        """
 454        endpoint = f"/trading/portfolio/positions"
 455        return self._make_api_request("GET", endpoint)
 456    
 457    def holdings(self) -> dict:
 458        """
 459        Method to get the holdings of the user using the Vortex API.
 460
 461        Documentation:    
 462            https://vortex.rupeezy.in/docs/latest/holdings/
 463
 464        Returns:
 465            dict: Dictionary containing the response data from the API.
 466        """
 467        endpoint = "/trading/portfolio/holdings"
 468        return self._make_api_request("GET", endpoint)
 469    
 470    def trades(self) -> dict:
 471        """
 472        Method to get today's trades of the user using the Vortex API.
 473
 474        Documentation:    
 475            https://vortex.rupeezy.in/docs/latest/positions/#get-trades
 476
 477        Returns:
 478            dict: Dictionary containing the response data from the API.
 479        """
 480        endpoint = "/trading/trades"
 481        return self._make_api_request("GET", endpoint)
 482    
 483    def funds(self) -> dict:
 484        """
 485        Method to get the funds of the user using the Vortex API.
 486
 487        Documentation:    
 488            https://vortex.rupeezy.in/docs/latest/user/#available-funds
 489
 490        Returns:
 491            dict: Dictionary containing the response data from the API.
 492        """
 493        endpoint = "/user/funds"
 494        return self._make_api_request("GET", endpoint)
 495    
 496    def get_order_margin(self, exchange: Constants.ExchangeTypes, token: int, transaction_type: Constants.TransactionSides, product: Constants.ProductTypes, variety: Constants.VarietyTypes, 
 497                     quantity: int, price: float,mode: Constants.OrderMarginModes, old_quantity: int = 0 , old_price: float = 0 ) -> dict:
 498        """
 499        Get the margin required for placing an order for a specific security.
 500
 501        Documentation:    
 502            https://vortex.rupeezy.in/docs/latest/margin/#order-margin
 503
 504        Args:
 505            exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO]
 506            token (int): Security token of the scrip. It can be found in the scripmaster file
 507            transaction_type (Constants.TransactionSides): Possible values: [BUY, SELL]
 508            product (Constants.ProductTypes): Possible values: [INTRADAY, DELIVERY, MTF]. MTF product can only be used in NSE_EQ exchange.
 509            variety (Constants.VarietyTypes): Possible values: [RL, RL-MKT, SL, SL-MKT]. RL means regular orders, SL means Stop Loss order. 
 510                        MKT means that the trade will happen at market price
 511            quantity (int): For exchange NSE_FO, if you want to trade in 2 lots and lot size is 50, you should pass 100. 
 512                            In all other exchanges, you should pass just the number of lots. For example, in MCX_FO, 
 513                            if you want to trade 5 lots, you should pass just 5.
 514            price (float): Price should be an integer multiple of Tick Size. For example, IDEA's tick size is 0.05. 
 515                        So the price entered can be 9.5 or 9.65. It cannot be 9.67. 
 516                        In case of market orders, you should send the Last Trade Price received from the Quote API or Websocket API
 517            mode (Constants.OrderMarginModes): Possible values: [NEW, MODIFY] , Whether you are trying to modify an existing order or placing a new order.            
 518            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
 519            old_price (float): Old Price in INR. Required if mode is MODIFY
 520
 521        Returns:
 522            dict: JSON response containing the details of the margin required to place the order
 523
 524        Raises:
 525            HTTPError: If any HTTP error occurs during the API call
 526        """
 527        
 528        endpoint = "/margins/order"
 529        
 530        data = {
 531            "exchange": exchange,
 532            "token": token,
 533            "transaction_type": transaction_type,
 534            "product": product,
 535            "variety": variety,
 536            "quantity": quantity,
 537            "price": price,
 538            "old_quantity": old_quantity,
 539            "old_price": old_price,
 540            "mode": mode,
 541        }
 542        return self._make_api_request("POST", endpoint, data=data)
 543    
 544    def brokerage_plan(self)-> dict: 
 545        """
 546        Get brokerage plan details of the user.
 547
 548        Documentation:    
 549            https://vortex.rupeezy.in/docs/latest/user/
 550
 551        Returns:
 552            dict: JSON response containing the details of the brokerage plan of the user
 553        """
 554        endpoint = "/user/profile/brokerage"
 555        return self._make_api_request("GET", endpoint, data=None,params=None)
 556    
 557    def quotes(self, instruments: list, mode: Constants.QuoteModes)-> dict: 
 558        """
 559        Gets quotes of up to 1000 instruments at a time. 
 560
 561        Documentation:    
 562            https://vortex.rupeezy.in/docs/latest/historical/#fetch-price-quotes
 563
 564        Args:
 565            instrument(list): List of instruments. The items should be like ( "NSE_EQ-22", "NSE_FO-1234")
 566            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.
 567
 568        Returns:
 569            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.
 570            Also, the order of output might be different than the order of input
 571        """
 572        endpoint = "/data/quotes"
 573        params = {"q": instruments,"mode": mode}
 574        return self._make_api_request("GET", endpoint, data=None,params=params)
 575    
 576    def historical_candles(self, exchange: Constants.ExchangeTypes, token: int, to: datetime.datetime , start: datetime.datetime, resolution: Constants.Resolutions): 
 577        """
 578        Gets historical candle data of a particular instrument. 
 579
 580        Documentation:    
 581            https://vortex.rupeezy.in/docs/latest/historical/#fetch-historical-candle-data
 582
 583        Args:
 584            exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO]
 585            token (int): Security token of the scrip. It can be found in the instruments master file: 
 586            to (datetime): datetime up till when you want to receive candles 
 587            start (datetime): datetime from when you want to receive candles 
 588            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"
 589        
 590        Returns:
 591            dict: JSON response containing the historical candles
 592        """
 593
 594        if not isinstance(token, int):
 595            raise TypeError("token must be an integer")
 596        if not isinstance(to,datetime.datetime): 
 597            raise TypeError("to must be a datetime")
 598        if not isinstance(start,datetime.datetime): 
 599            raise TypeError("start must be a datetime")
 600
 601
 602        endpoint = "/data/history"
 603        params = {"exchange": exchange,"token": token , "to": int(to.timestamp()), "from": int(start.timestamp()), "resolution": resolution}
 604        return self._make_api_request("GET", endpoint, data=None,params=params)
 605
 606    def login_url(self, callback_param: str) -> str:
 607        """
 608        Returns the login URL for the Vortex API.
 609
 610        Documentation:
 611            https://vortex.rupeezy.in/docs/latest/authentication/
 612
 613        Returns:
 614            str: The login URL for the Vortex API.
 615        """
 616
 617        return f"https://flow.rupeezy.in?applicationId={self.application_id}&cb_param={callback_param}"
 618    
 619    def exchange_token(self,auth_code: str) -> dict:
 620        """
 621        Exchange the auth code received from the login URL for an access token.
 622
 623        Documentation:
 624            https://vortex.rupeezy.in/docs/latest/authentication/
 625
 626        Args:
 627            auth_code (str): The authorization code received from the login URL.
 628
 629        Returns:
 630            dict: JSON response containing the details of the user
 631        """
 632
 633        endpoint = "/user/session"
 634        data = {
 635            "token": auth_code,
 636            "applicationId": self.application_id, 
 637            "checksum": self._sha256_hash(f"{self.application_id}{auth_code}{self.api_key}")
 638        }
 639        res = self._make_unauth_request("POST", endpoint= endpoint, data=data)
 640        self._setup_client_code(login_object=res)
 641        return res
 642
 643    def _sha256_hash(self,text: str) -> str:
 644        sha = hashlib.sha256()
 645        sha.update(text.encode('utf-8'))
 646        return sha.hexdigest()
 647
 648    def _setup_client_code(self, login_object: dict) -> bool:
 649        """
 650        Sets up access token after login
 651
 652        Args:
 653            login_object(dict): Login object received
 654
 655        Returns:
 656            (bool): Whether successful or not
 657        """
 658
 659        if (('data' in login_object ) and login_object["data"] != None and login_object["data"]["access_token"] != None):
 660            self.access_token = login_object["data"]["access_token"]
 661            return True
 662
 663        return False
 664
 665    def mf_holdings(self) -> dict:
 666        """
 667        Get the mutual fund holdings of the user.
 668
 669        Returns:
 670            dict: JSON response with the following structure::
 671
 672                {
 673                    "status": str,
 674                    "message": str,
 675                    "data": {
 676                        "OverallConfig": {
 677                            "OverAllXirr": float,
 678                            "MarketValueAmount": float,
 679                            "InvestedAmount": float,
 680                            "Returns": float,
 681                            "ReturnsPercentage": float,
 682                            "LastImportedAt": str or None,    # ISO datetime
 683                            "FundsImportStatus": str,
 684                            "OneDayReturns": float,
 685                            "OneDayReturnsPercentage": float,
 686                            "NavAsOn": str                    # ISO datetime
 687                        },
 688                        "IsinWiseData": {
 689                            "<ISIN>": {
 690                                "Name": str,
 691                                "MarketValueAmount": float,
 692                                "InvestedAmount": float,
 693                                "Returns": float,
 694                                "ReturnsPercentage": float,
 695                                "OneDayReturns": float,
 696                                "OneDayReturnsPercentage": float,
 697                                "IsinXirr": float,
 698                                "BseScheme": dict or None,
 699                                "CmotsScheme": dict or None,
 700                                "Folios": [
 701                                    {
 702                                        "xirr": float,
 703                                        "client_code": str,
 704                                        "dpam_id": int,
 705                                        "folio_number": str,
 706                                        "folio_xirr": float,
 707                                        "isin": str,
 708                                        "co_code": int,
 709                                        "name": str,
 710                                        "type": str,
 711                                        "units": float,
 712                                        "redeemable_units": float,
 713                                        "market_value_amount": float,
 714                                        "redeemable_amount": float,
 715                                        "invested_amount": float,
 716                                        "nav_value": float,
 717                                        "buy_price": float,
 718                                        "as_on": str or None,
 719                                        "hold_type": str,
 720                                        "is_demat": str,
 721                                        "one_day_returns": float,
 722                                        "one_day_returns_percentage": float
 723                                    }
 724                                ]
 725                            }
 726                        }
 727                    }
 728                }
 729        """
 730        endpoint = "/mf/holdings"
 731        return self._make_api_request("GET", endpoint)
 732
 733    def fund_details(self, isin: str) -> dict:
 734        """
 735        Get details of a mutual fund scheme by ISIN.
 736
 737        Args:
 738            isin (str): ISIN of the mutual fund scheme
 739
 740        Returns:
 741            dict: JSON response with the following structure::
 742
 743                {
 744                    "status": str,
 745                    "data": {
 746                        "assetAllocation": [
 747                            {
 748                                "Isin": str,
 749                                "AssetCode": int,
 750                                "AssetName": str,
 751                                "Holding_CurrentMonth": float,
 752                                "Holding_PrevMonth": float,
 753                                "CurrentMonth": str
 754                            }
 755                        ],
 756                        "sectorAllocation": [
 757                            {
 758                                "Isin": str,
 759                                "VALUE": float,
 760                                "PERC_HOLD": float,
 761                                "SECTOR": str,
 762                                "AsOnDate": str           # ISO datetime
 763                            }
 764                        ],
 765                        "holdingAllocation": [
 766                            {
 767                                "Isin": str,
 768                                "co_code": int,
 769                                "co_name": str,
 770                                "invdate": str,
 771                                "InvDate": str,           # ISO datetime
 772                                "Perc_hold": float,
 773                                "MktValue": float,
 774                                "TotalShares": float,
 775                                "AssetType": str,
 776                                "rating": str
 777                            }
 778                        ],
 779                        "cmotsDetails": {
 780                            "isin": str,
 781                            "sch_name": str,
 782                            "navrs": float,
 783                            "Navdate": str,
 784                            "FundManager": str,
 785                            "SchemeAUM": float,
 786                            "EXPRATIO": float,
 787                            "riskometervalue": str,
 788                            "BenchmarkName": str,
 789                            "Category": str,
 790                            "fund_rating": int or None,
 791                            ...
 792                        },
 793                        "bseSchemeDetails": {
 794                            "ISIN": str,
 795                            "SchemeCode": str,
 796                            "SchemeName": str,
 797                            "SchemeType": str,
 798                            "SchemePlan": str,
 799                            "PurchaseAllowed": str,
 800                            "RedemptionAllowed": str,
 801                            "SIPFlag": str,
 802                            "MinimumPurchaseAmount": float,
 803                            "MinimumRedemptionQty": float,
 804                            ...
 805                        }
 806                    }
 807                }
 808        """
 809        endpoint = "/mf/fund/details"
 810        params = {"isin": isin}
 811        return self._make_api_request("GET", endpoint, params=params)
 812
 813    def fund_navs(self, isin: str) -> dict:
 814        """
 815        Get historical NAV data for a mutual fund scheme.
 816
 817        Args:
 818            isin (str): ISIN of the mutual fund scheme
 819
 820        Returns:
 821            dict: JSON response with the following structure::
 822
 823                {
 824                    "status": str,
 825                    "data": [
 826                        {
 827                            "date": str,      # ISO datetime
 828                            "value": float    # NAV value
 829                        }
 830                    ]
 831                }
 832        """
 833        endpoint = "/mf/fund/navs"
 834        params = {"isin": isin}
 835        return self._make_api_request("GET", endpoint, params=params)
 836
 837    def portfolio_impact(self, isin: str, amount: float) -> dict:
 838        """
 839        Get the portfolio impact of adding a mutual fund scheme.
 840
 841        Args:
 842            isin (str): ISIN of the mutual fund scheme
 843            amount (float): Investment amount
 844
 845        Returns:
 846            dict: JSON response with the following structure::
 847
 848                {
 849                    "status": str,
 850                    "data": {
 851                        "New": {
 852                            "Returns": float,
 853                            "Risk": float
 854                        },
 855                        "Original": {
 856                            "Returns": float,
 857                            "Risk": float
 858                        }
 859                    }
 860                }
 861        """
 862        endpoint = "/mf/fund/portfolio-impact"
 863        params = {"isin": isin, "amount": amount}
 864        return self._make_api_request("GET", endpoint, params=params)
 865
 866    def fund_overlap(self, isin: str, amount: float) -> dict:
 867        """
 868        Get the fund overlap analysis for a mutual fund scheme against existing holdings.
 869
 870        Args:
 871            isin (str): ISIN of the mutual fund scheme
 872            amount (float): Investment amount
 873
 874        Returns:
 875            dict: JSON response with the following structure::
 876
 877                {
 878                    "status": str,
 879                    "data": {
 880                        "Value": float,
 881                        "Overlaps": [
 882                            {
 883                                "Isin": str,
 884                                "Holdings": [
 885                                    {
 886                                        "Name": str,
 887                                        "Value": float
 888                                    }
 889                                ]
 890                            }
 891                        ]
 892                    }
 893                }
 894        """
 895        endpoint = "/mf/fund/portfolio-overlap"
 896        params = {"isin": isin, "amount": amount}
 897        return self._make_api_request("GET", endpoint, params=params)
 898
 899    def sip_book(self) -> dict:
 900        """
 901        Get the SIP (Systematic Investment Plan) book of the user.
 902
 903        Returns:
 904            dict: JSON response with the following structure::
 905
 906                {
 907                    "status": str,
 908                    "data": [
 909                        {
 910                            "ID": int,
 911                            "CreatedAt": str,                     # ISO datetime
 912                            "UpdatedAt": str,                     # ISO datetime
 913                            "transactionCode": str,
 914                            "isin": str,
 915                            "amount": float,
 916                            "clientCode": str,
 917                            "schemeCode": str,
 918                            "remarks": str,
 919                            "startDate": str,                     # ISO datetime
 920                            "startDay": int,
 921                            "modifiedStartDate": str or None,     # ISO datetime
 922                            "mandateId": str,
 923                            "state": str,
 924                            "frequency": str,
 925                            "stepUp": bool,
 926                            "stepUpFrequency": str,
 927                            "stepUpPercentage": float,
 928                            "stepUpAmount": float,
 929                            "isAmcSip": bool,
 930                            "initialInvestmentAmount": float,
 931                            "buySellType": str,
 932                            "nextInstallmentDate": str or None,   # ISO datetime
 933                            "installmentNumber": int,
 934                            "schemeName": str,
 935                            "coCode": int,
 936                            "schemes_details": {
 937                                "bseSchemeDetails": dict,
 938                                "cmotsDetails": dict,
 939                                "nfoDetails": dict
 940                            }
 941                        }
 942                    ]
 943                }
 944        """
 945        endpoint = "/mf/purchases/synthetic/plan"
 946        return self._make_api_request("GET", endpoint)
 947
 948    def save_backtest_result(self, stats, name: str, symbol: str = "", description: str = "", tags: list = None) -> dict:
 949        """
 950        Save backtest results to Rupeezy for viewing on the developer portal.
 951
 952        Supports multiple backtesting libraries (auto-detected from the result type):
 953        - **backtesting.py**: pass the stats object from Backtest.run()
 954        - **vectorbt**: pass a vbt.Portfolio object
 955        - **backtrader**: pass the strategy from cerebro.run() (i.e. results[0])
 956
 957        Args:
 958            stats: The result object from any supported backtesting library.
 959            name (str): A label for this backtest run (e.g. "SMA Crossover v2").
 960            symbol (str, optional): Primary instrument symbol.
 961            description (str, optional): Notes about this run.
 962            tags (list[str], optional): Tags for filtering (e.g. ["intraday", "nifty"]).
 963
 964        Returns:
 965            dict: { "status": "success", "backtest_id": "bt_abc123", "url": "https://..." }
 966        """
 967        from .backtest import serialize_stats
 968        payload = serialize_stats(stats, name, symbol, description, tags or [])
 969        endpoint = "/strategies/backtests"
 970
 971        return self._make_api_request("POST", endpoint, data=payload)
 972
 973    def save_optimization_result(
 974        self,
 975        stats,
 976        heatmap,
 977        name: str,
 978        symbol: str = "",
 979        description: str = "",
 980        maximize="Sharpe Ratio",
 981        param_ranges: dict = None,
 982    ) -> dict:
 983        """
 984        Save optimization results to Rupeezy for viewing on the developer portal.
 985
 986        Supports multiple backtesting libraries (auto-detected from the result type):
 987        - **backtesting.py**: pass stats + heatmap from bt.optimize(return_heatmap=True)
 988        - **vectorbt**: pass Portfolio + metric Series from multi-param run
 989        - **backtrader**: pass results list from cerebro.run() after optstrategy()
 990
 991        Args:
 992            stats: The result object from any supported backtesting library.
 993            heatmap: The heatmap/metric Series (backtesting.py/vectorbt) or
 994                     metric extraction callable (backtrader).
 995            name (str): A label for this optimization run (e.g. "SMA Grid Search").
 996            symbol (str, optional): Primary instrument symbol (e.g. "NIFTY").
 997            description (str, optional): Notes about this optimization run.
 998            maximize: The metric that was optimized. Should match the `maximize`
 999                      argument passed to Backtest.optimize(). Can be a string
1000                      metric name (e.g. "Sharpe Ratio") or a callable.
1001                      Defaults to "Sharpe Ratio".
1002            param_ranges (dict, optional): Explicit parameter range definitions.
1003                Keys are parameter names, values are range() objects or lists.
1004                Example: {"sma_fast": range(5, 51, 5), "sma_slow": range(20, 201, 10)}
1005                If not provided, ranges are inferred from the heatmap index.
1006
1007        Returns:
1008            dict: {"status": "success", "optimization_id": "opt_xxx", "backtest_id": "bt_xxx"}
1009
1010        Example::
1011
1012            stats, heatmap = bt.optimize(
1013                sma_fast=range(5, 51, 5),
1014                sma_slow=range(20, 201, 10),
1015                maximize='Sharpe Ratio',
1016                return_heatmap=True,
1017            )
1018            client.save_optimization_result(
1019                stats=stats,
1020                heatmap=heatmap,
1021                name="SMA Crossover Grid Search",
1022                symbol="NIFTY",
1023                maximize='Sharpe Ratio',
1024                param_ranges={"sma_fast": range(5, 51, 5), "sma_slow": range(20, 201, 10)},
1025            )
1026        """
1027        is_maximize = True
1028        objective_metric = maximize
1029
1030        if isinstance(maximize, bool):
1031            is_maximize = maximize
1032            objective_metric = "Sharpe Ratio"
1033
1034        from .backtest import serialize_optimization
1035        payload = serialize_optimization(
1036            result=stats,
1037            heatmap=heatmap,
1038            name=name,
1039            symbol=symbol,
1040            description=description,
1041            objective_metric=objective_metric,
1042            maximize=is_maximize,
1043            param_ranges=param_ranges,
1044        )
1045        endpoint = "/strategies/optimizations"
1046        return self._make_api_request("POST", endpoint, data=payload)
VortexAPI( api_key: str = None, application_id: str = None, base_url: str = 'https://vortex-api.rupeezy.in/v2', enable_logging: bool = False)
158    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:
159        """
160        Constructor method for VortexAPI class.
161
162        Args:
163            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.
164            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.
165            base_url (str, optional): Base URL for the Vortex API. Defaults to "https://vortex-api.rupeezy.in/v2".
166        """
167        if api_key == None:
168            if os.getenv("VORTEX_API_KEY") != None:
169                api_key = os.getenv("VORTEX_API_KEY")
170            else:
171                raise ValueError("API key must be provided either as an argument or through the VORTEX_API_KEY environment variable.")
172        
173        if application_id == None:
174            if os.getenv("VORTEX_APPLICATION_ID") != None:
175                application_id = os.getenv("VORTEX_APPLICATION_ID")
176            else:
177                raise ValueError("Application ID must be provided either as an argument or through the VORTEX_APPLICATION_ID environment variable.")
178        self.api_key = api_key
179        self.application_id = application_id
180
181        if os.getenv("VORTEX_BASE_URL") != None:
182            self.base_url = os.getenv("VORTEX_BASE_URL")
183        else:
184            self.base_url = base_url
185            
186        if os.getenv("VORTEX_ACCESS_TOKEN") != None:
187            self.access_token = os.getenv("VORTEX_ACCESS_TOKEN")
188        else:
189            self.access_token = None
190
191        self.enable_logging = enable_logging
192        if self.enable_logging:
193            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".
def login(self, client_code: str, password: str, totp: str) -> dict:
245    def login(self, client_code: str, password: str, totp: str)->dict:
246        """
247        Depricating Soon. Use SSO Login instead. Login using password and totp directly
248        
249        Documentation:
250            https://vortex.rupeezy.in/docs/latest/authentication/
251
252        Args:
253            client_code(str): Client Code of the account
254            password(str): Password of the account
255            totp(str): TOTP generated using third party apps like google authenticator etc. 
256
257        Returns:
258            dict: JSON response containing the details of the user
259        """
260        endpoint = "/user/login"
261        data = {
262            "client_code": client_code,
263            "password": password,
264            "totp": totp,
265            "application_id": self.application_id
266        }
267        res = self._make_unauth_request("POST", endpoint= endpoint, data=data)
268        self._setup_client_code(login_object=res)
269        return res

Depricating Soon. Use SSO Login instead. Login using password and totp directly

Documentation:

https://vortex.rupeezy.in/docs/latest/authentication/

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

def download_master(self) -> dict:
271    def download_master(self) -> dict:
272        """
273        Download list of all available instruments and their details across all exchanges
274
275        Documentation:
276            https://vortex.rupeezy.in/docs/latest/historical/#instrument-list
277
278        Returns:
279            dict: CSV Array of all instruments. The first row contains headers
280        """
281        endpoint = "https://static.rupeezy.in/master.csv"
282        with requests.Session() as s: 
283            download = s.get(url=endpoint)
284            decoded_content = download.content.decode('utf-8')
285            cr = csv.reader(decoded_content.splitlines(), delimiter=',')
286            my_list = list(cr)
287            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

def place_order( self, exchange: vortex_api.Constants.ExchangeTypes, token: int, transaction_type: vortex_api.Constants.TransactionSides, product: vortex_api.Constants.ProductTypes, variety: vortex_api.Constants.VarietyTypes, quantity: int, price: float, trigger_price: float, disclosed_quantity: int, validity: vortex_api.Constants.ValidityTypes) -> dict:
289    def place_order(self,exchange: Constants.ExchangeTypes, token: int, transaction_type: Constants.TransactionSides, product: Constants.ProductTypes, variety: Constants.VarietyTypes, 
290                quantity: int, price: float, trigger_price: float, disclosed_quantity: int, validity: Constants.ValidityTypes) -> dict:
291        """
292        Place an order for a specific security
293
294        Documentation:
295            https://vortex.rupeezy.in/docs/latest/order/#placing-an-order
296
297        Args:
298            exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO]
299            token (int): Security token of the scrip. It can be found in the scripmaster file
300            transaction_type (Constants.TransactionSides): Possible values: [BUY, SELL]
301            product (Constants.ProductTypes): Possible values: [INTRADAY, DELIVERY, MTF]. MTF product can only be used in NSE_EQ exchange.
302            variety (Constants.VarietyTypes): Possible values: [RL, RL-MKT, SL, SL-MKT]. RL means regular orders, SL means Stop Loss order. 
303                        MKT means that the trade will happen at market price
304            quantity (int): For exchange NSE_FO, if you want to trade in 2 lots and lot size is 50, you should pass 100. 
305                            In all other exchanges, you should pass just the number of lots. For example, in MCX_FO, 
306                            if you want to trade 5 lots, you should pass just 5.
307            price (float): Price should be an integer multiple of Tick Size. For example, IDEA's tick size is 0.05. 
308                        So the price entered can be 9.5 or 9.65. It cannot be 9.67. 
309                        In case of market orders, you should send the Last Trade Price received from the Quote API or Websocket API
310            trigger_price (float): To be used for Stop loss orders. For BUY side SL orders, trigger_price should be 
311                                lesser than price. for SELL side SL orders, trigger_price should be greater than price.
312            disclosed_quantity (int): Can be any number lesser than or equal to quantity, including 0
313            validity (Constants.ValidityTypes): Can be DAY for orders which are valid throughout the day, or IOC. 
314                            IOC order will be cancelled if it is not traded immediately
315        Returns:
316            dict: JSON response containing the details of the placed order
317
318        Raises:
319            HTTPError: If any HTTP error occurs during the API call
320        """
321
322        endpoint = "/trading/orders/regular"
323        if validity == Constants.ValidityTypes.FULL_DAY: 
324            validity_days = 1 
325            is_amo = False
326        elif validity == Constants.ValidityTypes.IMMEDIATE_OR_CANCEL: 
327            validity_days = 0 
328            is_amo = False
329        else: 
330            validity_days = 1 
331            is_amo = True 
332
333        data = {
334            "exchange": exchange,
335            "token": token,
336            "transaction_type": transaction_type,
337            "product": product,
338            "variety": variety,
339            "quantity": quantity,
340            "price": price,
341            "trigger_price": trigger_price,
342            "disclosed_quantity": disclosed_quantity,
343            "validity": validity,
344            "validity_days": validity_days,
345            "is_amo": is_amo
346        }
347        
348        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
def modify_order( self, order_id: str, variety: vortex_api.Constants.VarietyTypes, quantity: int, traded_quantity: int, price: float, trigger_price: float, disclosed_quantity: int, validity: vortex_api.Constants.ValidityTypes) -> dict:
350    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:
351        """
352        Method to modify an order using the Vortex API.
353
354        Documentation:
355            https://vortex.rupeezy.in/docs/latest/order/#modifying-an-order
356
357        Args:
358            exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO]
359            order_id (str): The unique ID of the order to modify.
360            variety (Constants.VarietyTypes): Possible values: [RL, RL-MKT, SL, SL-MKT]. RL means regular orders, SL means Stop Loss order. 
361                    MKT means that the trade will happen at market price
362            quantity (int): The new quantity for the order.
363            traded_quantity (int): The quantity of the order that has already been traded.
364            price (float): The new price for the order.
365            trigger_price (float): The new trigger price for the order. Required for SL and SL-M orders.
366            disclosed_quantity (int): The new quantity to be disclosed publicly.
367            validity (Constants.ValidityTypes): The new validity for the order (e.g. DAY, IOC, GTD).
368
369        Returns:
370            dict: Dictionary containing the response data from the API.
371        """
372
373        endpoint = f"/trading/orders/regular/{order_id}"
374        if validity == Constants.ValidityTypes.FULL_DAY: 
375            validity_days = 1 
376        elif validity == Constants.ValidityTypes.IMMEDIATE_OR_CANCEL: 
377            validity_days = 0 
378        else: 
379            validity_days = 1 
380
381        data = {
382            "variety": variety,
383            "quantity": quantity,
384            "traded_quantity": traded_quantity,
385            "price": price,
386            "trigger_price": trigger_price,
387            "disclosed_quantity": disclosed_quantity,
388            "validity": validity,
389            "validity_days": validity_days
390        }
391        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.

def cancel_order(self, order_id: str) -> dict:
393    def cancel_order(self, order_id: str) -> dict:
394        """
395        Method to cancel an order using the Vortex API.
396
397        Documentation:
398            https://vortex.rupeezy.in/docs/latest/order/#cancel-an-order
399
400        Args:
401            exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO]
402            order_id (str): The unique ID of the order to cancel.
403
404        Returns:
405            dict: Dictionary containing the response data from the API.
406        """
407        
408        endpoint = f"/trading/orders/regular/{order_id}"
409        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.

def orders(self, limit: int, offset: int) -> dict:
411    def orders(self,limit: int, offset: int) -> dict:
412        """
413        Method to get all orders.
414
415        Documentation:
416            https://vortex.rupeezy.in/docs/latest/order/#fetching-order-book
417
418        Args:
419            limit (int): Limit is the number of orders to be fetched. 
420            offset (int): Offset should atleast be 1 
421
422        Returns:
423            dict: Dictionary containing the response data from the API.
424        """
425        endpoint = f"/trading/orders?limit={limit}&offset={offset}"
426        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.

def order_history(self, order_id: str) -> dict:
428    def order_history(self,order_id: str) -> dict:
429        """
430        Method to get the order history of a particular order
431
432        Documentation:
433            https://vortex.rupeezy.in/docs/latest/order/
434
435        Args:
436            order_id (str): Order id for which history has to be fetched
437
438        Returns:
439            dict: Dictionary containing the response data from the API.
440        """
441        endpoint = f"/trading/orders/{order_id}"
442        return self._make_api_request("GET", endpoint)

Method to get the order history of a particular order

Documentation:

https://vortex.rupeezy.in/docs/latest/order/

Arguments:
  • order_id (str): Order id for which history has to be fetched
Returns:

dict: Dictionary containing the response data from the API.

def positions(self) -> dict:
444    def positions(self) -> dict:
445        """
446        Method to get the position book using the Vortex API.
447
448        Documentation:
449            https://vortex.rupeezy.in/docs/latest/positions/#fetch-all-positions
450
451        Returns:
452            dict: Dictionary containing the response data from the API.
453        """
454        endpoint = f"/trading/portfolio/positions"
455        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.

def holdings(self) -> dict:
457    def holdings(self) -> dict:
458        """
459        Method to get the holdings of the user using the Vortex API.
460
461        Documentation:    
462            https://vortex.rupeezy.in/docs/latest/holdings/
463
464        Returns:
465            dict: Dictionary containing the response data from the API.
466        """
467        endpoint = "/trading/portfolio/holdings"
468        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.

def trades(self) -> dict:
470    def trades(self) -> dict:
471        """
472        Method to get today's trades of the user using the Vortex API.
473
474        Documentation:    
475            https://vortex.rupeezy.in/docs/latest/positions/#get-trades
476
477        Returns:
478            dict: Dictionary containing the response data from the API.
479        """
480        endpoint = "/trading/trades"
481        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.

def funds(self) -> dict:
483    def funds(self) -> dict:
484        """
485        Method to get the funds of the user using the Vortex API.
486
487        Documentation:    
488            https://vortex.rupeezy.in/docs/latest/user/#available-funds
489
490        Returns:
491            dict: Dictionary containing the response data from the API.
492        """
493        endpoint = "/user/funds"
494        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.

def get_order_margin( self, exchange: vortex_api.Constants.ExchangeTypes, token: int, transaction_type: vortex_api.Constants.TransactionSides, product: vortex_api.Constants.ProductTypes, variety: vortex_api.Constants.VarietyTypes, quantity: int, price: float, mode: vortex_api.Constants.OrderMarginModes, old_quantity: int = 0, old_price: float = 0) -> dict:
496    def get_order_margin(self, exchange: Constants.ExchangeTypes, token: int, transaction_type: Constants.TransactionSides, product: Constants.ProductTypes, variety: Constants.VarietyTypes, 
497                     quantity: int, price: float,mode: Constants.OrderMarginModes, old_quantity: int = 0 , old_price: float = 0 ) -> dict:
498        """
499        Get the margin required for placing an order for a specific security.
500
501        Documentation:    
502            https://vortex.rupeezy.in/docs/latest/margin/#order-margin
503
504        Args:
505            exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO]
506            token (int): Security token of the scrip. It can be found in the scripmaster file
507            transaction_type (Constants.TransactionSides): Possible values: [BUY, SELL]
508            product (Constants.ProductTypes): Possible values: [INTRADAY, DELIVERY, MTF]. MTF product can only be used in NSE_EQ exchange.
509            variety (Constants.VarietyTypes): Possible values: [RL, RL-MKT, SL, SL-MKT]. RL means regular orders, SL means Stop Loss order. 
510                        MKT means that the trade will happen at market price
511            quantity (int): For exchange NSE_FO, if you want to trade in 2 lots and lot size is 50, you should pass 100. 
512                            In all other exchanges, you should pass just the number of lots. For example, in MCX_FO, 
513                            if you want to trade 5 lots, you should pass just 5.
514            price (float): Price should be an integer multiple of Tick Size. For example, IDEA's tick size is 0.05. 
515                        So the price entered can be 9.5 or 9.65. It cannot be 9.67. 
516                        In case of market orders, you should send the Last Trade Price received from the Quote API or Websocket API
517            mode (Constants.OrderMarginModes): Possible values: [NEW, MODIFY] , Whether you are trying to modify an existing order or placing a new order.            
518            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
519            old_price (float): Old Price in INR. Required if mode is MODIFY
520
521        Returns:
522            dict: JSON response containing the details of the margin required to place the order
523
524        Raises:
525            HTTPError: If any HTTP error occurs during the API call
526        """
527        
528        endpoint = "/margins/order"
529        
530        data = {
531            "exchange": exchange,
532            "token": token,
533            "transaction_type": transaction_type,
534            "product": product,
535            "variety": variety,
536            "quantity": quantity,
537            "price": price,
538            "old_quantity": old_quantity,
539            "old_price": old_price,
540            "mode": mode,
541        }
542        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
def brokerage_plan(self) -> dict:
544    def brokerage_plan(self)-> dict: 
545        """
546        Get brokerage plan details of the user.
547
548        Documentation:    
549            https://vortex.rupeezy.in/docs/latest/user/
550
551        Returns:
552            dict: JSON response containing the details of the brokerage plan of the user
553        """
554        endpoint = "/user/profile/brokerage"
555        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

def quotes( self, instruments: list, mode: vortex_api.Constants.QuoteModes) -> dict:
557    def quotes(self, instruments: list, mode: Constants.QuoteModes)-> dict: 
558        """
559        Gets quotes of up to 1000 instruments at a time. 
560
561        Documentation:    
562            https://vortex.rupeezy.in/docs/latest/historical/#fetch-price-quotes
563
564        Args:
565            instrument(list): List of instruments. The items should be like ( "NSE_EQ-22", "NSE_FO-1234")
566            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.
567
568        Returns:
569            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.
570            Also, the order of output might be different than the order of input
571        """
572        endpoint = "/data/quotes"
573        params = {"q": instruments,"mode": mode}
574        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

def historical_candles( self, exchange: vortex_api.Constants.ExchangeTypes, token: int, to: datetime.datetime, start: datetime.datetime, resolution: vortex_api.Constants.Resolutions):
576    def historical_candles(self, exchange: Constants.ExchangeTypes, token: int, to: datetime.datetime , start: datetime.datetime, resolution: Constants.Resolutions): 
577        """
578        Gets historical candle data of a particular instrument. 
579
580        Documentation:    
581            https://vortex.rupeezy.in/docs/latest/historical/#fetch-historical-candle-data
582
583        Args:
584            exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO]
585            token (int): Security token of the scrip. It can be found in the instruments master file: 
586            to (datetime): datetime up till when you want to receive candles 
587            start (datetime): datetime from when you want to receive candles 
588            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"
589        
590        Returns:
591            dict: JSON response containing the historical candles
592        """
593
594        if not isinstance(token, int):
595            raise TypeError("token must be an integer")
596        if not isinstance(to,datetime.datetime): 
597            raise TypeError("to must be a datetime")
598        if not isinstance(start,datetime.datetime): 
599            raise TypeError("start must be a datetime")
600
601
602        endpoint = "/data/history"
603        params = {"exchange": exchange,"token": token , "to": int(to.timestamp()), "from": int(start.timestamp()), "resolution": resolution}
604        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

def login_url(self, callback_param: str) -> str:
606    def login_url(self, callback_param: str) -> str:
607        """
608        Returns the login URL for the Vortex API.
609
610        Documentation:
611            https://vortex.rupeezy.in/docs/latest/authentication/
612
613        Returns:
614            str: The login URL for the Vortex API.
615        """
616
617        return f"https://flow.rupeezy.in?applicationId={self.application_id}&cb_param={callback_param}"

Returns the login URL for the Vortex API.

Documentation:

https://vortex.rupeezy.in/docs/latest/authentication/

Returns:

str: The login URL for the Vortex API.

def exchange_token(self, auth_code: str) -> dict:
619    def exchange_token(self,auth_code: str) -> dict:
620        """
621        Exchange the auth code received from the login URL for an access token.
622
623        Documentation:
624            https://vortex.rupeezy.in/docs/latest/authentication/
625
626        Args:
627            auth_code (str): The authorization code received from the login URL.
628
629        Returns:
630            dict: JSON response containing the details of the user
631        """
632
633        endpoint = "/user/session"
634        data = {
635            "token": auth_code,
636            "applicationId": self.application_id, 
637            "checksum": self._sha256_hash(f"{self.application_id}{auth_code}{self.api_key}")
638        }
639        res = self._make_unauth_request("POST", endpoint= endpoint, data=data)
640        self._setup_client_code(login_object=res)
641        return res

Exchange the auth code received from the login URL for an access token.

Documentation:

https://vortex.rupeezy.in/docs/latest/authentication/

Arguments:
  • auth_code (str): The authorization code received from the login URL.
Returns:

dict: JSON response containing the details of the user

def mf_holdings(self) -> dict:
665    def mf_holdings(self) -> dict:
666        """
667        Get the mutual fund holdings of the user.
668
669        Returns:
670            dict: JSON response with the following structure::
671
672                {
673                    "status": str,
674                    "message": str,
675                    "data": {
676                        "OverallConfig": {
677                            "OverAllXirr": float,
678                            "MarketValueAmount": float,
679                            "InvestedAmount": float,
680                            "Returns": float,
681                            "ReturnsPercentage": float,
682                            "LastImportedAt": str or None,    # ISO datetime
683                            "FundsImportStatus": str,
684                            "OneDayReturns": float,
685                            "OneDayReturnsPercentage": float,
686                            "NavAsOn": str                    # ISO datetime
687                        },
688                        "IsinWiseData": {
689                            "<ISIN>": {
690                                "Name": str,
691                                "MarketValueAmount": float,
692                                "InvestedAmount": float,
693                                "Returns": float,
694                                "ReturnsPercentage": float,
695                                "OneDayReturns": float,
696                                "OneDayReturnsPercentage": float,
697                                "IsinXirr": float,
698                                "BseScheme": dict or None,
699                                "CmotsScheme": dict or None,
700                                "Folios": [
701                                    {
702                                        "xirr": float,
703                                        "client_code": str,
704                                        "dpam_id": int,
705                                        "folio_number": str,
706                                        "folio_xirr": float,
707                                        "isin": str,
708                                        "co_code": int,
709                                        "name": str,
710                                        "type": str,
711                                        "units": float,
712                                        "redeemable_units": float,
713                                        "market_value_amount": float,
714                                        "redeemable_amount": float,
715                                        "invested_amount": float,
716                                        "nav_value": float,
717                                        "buy_price": float,
718                                        "as_on": str or None,
719                                        "hold_type": str,
720                                        "is_demat": str,
721                                        "one_day_returns": float,
722                                        "one_day_returns_percentage": float
723                                    }
724                                ]
725                            }
726                        }
727                    }
728                }
729        """
730        endpoint = "/mf/holdings"
731        return self._make_api_request("GET", endpoint)

Get the mutual fund holdings of the user.

Returns:

dict: JSON response with the following structure::

{
    "status": str,
    "message": str,
    "data": {
        "OverallConfig": {
            "OverAllXirr": float,
            "MarketValueAmount": float,
            "InvestedAmount": float,
            "Returns": float,
            "ReturnsPercentage": float,
            "LastImportedAt": str or None,    # ISO datetime
            "FundsImportStatus": str,
            "OneDayReturns": float,
            "OneDayReturnsPercentage": float,
            "NavAsOn": str                    # ISO datetime
        },
        "IsinWiseData": {
            "<ISIN>": {
                "Name": str,
                "MarketValueAmount": float,
                "InvestedAmount": float,
                "Returns": float,
                "ReturnsPercentage": float,
                "OneDayReturns": float,
                "OneDayReturnsPercentage": float,
                "IsinXirr": float,
                "BseScheme": dict or None,
                "CmotsScheme": dict or None,
                "Folios": [
                    {
                        "xirr": float,
                        "client_code": str,
                        "dpam_id": int,
                        "folio_number": str,
                        "folio_xirr": float,
                        "isin": str,
                        "co_code": int,
                        "name": str,
                        "type": str,
                        "units": float,
                        "redeemable_units": float,
                        "market_value_amount": float,
                        "redeemable_amount": float,
                        "invested_amount": float,
                        "nav_value": float,
                        "buy_price": float,
                        "as_on": str or None,
                        "hold_type": str,
                        "is_demat": str,
                        "one_day_returns": float,
                        "one_day_returns_percentage": float
                    }
                ]
            }
        }
    }
}
def fund_details(self, isin: str) -> dict:
733    def fund_details(self, isin: str) -> dict:
734        """
735        Get details of a mutual fund scheme by ISIN.
736
737        Args:
738            isin (str): ISIN of the mutual fund scheme
739
740        Returns:
741            dict: JSON response with the following structure::
742
743                {
744                    "status": str,
745                    "data": {
746                        "assetAllocation": [
747                            {
748                                "Isin": str,
749                                "AssetCode": int,
750                                "AssetName": str,
751                                "Holding_CurrentMonth": float,
752                                "Holding_PrevMonth": float,
753                                "CurrentMonth": str
754                            }
755                        ],
756                        "sectorAllocation": [
757                            {
758                                "Isin": str,
759                                "VALUE": float,
760                                "PERC_HOLD": float,
761                                "SECTOR": str,
762                                "AsOnDate": str           # ISO datetime
763                            }
764                        ],
765                        "holdingAllocation": [
766                            {
767                                "Isin": str,
768                                "co_code": int,
769                                "co_name": str,
770                                "invdate": str,
771                                "InvDate": str,           # ISO datetime
772                                "Perc_hold": float,
773                                "MktValue": float,
774                                "TotalShares": float,
775                                "AssetType": str,
776                                "rating": str
777                            }
778                        ],
779                        "cmotsDetails": {
780                            "isin": str,
781                            "sch_name": str,
782                            "navrs": float,
783                            "Navdate": str,
784                            "FundManager": str,
785                            "SchemeAUM": float,
786                            "EXPRATIO": float,
787                            "riskometervalue": str,
788                            "BenchmarkName": str,
789                            "Category": str,
790                            "fund_rating": int or None,
791                            ...
792                        },
793                        "bseSchemeDetails": {
794                            "ISIN": str,
795                            "SchemeCode": str,
796                            "SchemeName": str,
797                            "SchemeType": str,
798                            "SchemePlan": str,
799                            "PurchaseAllowed": str,
800                            "RedemptionAllowed": str,
801                            "SIPFlag": str,
802                            "MinimumPurchaseAmount": float,
803                            "MinimumRedemptionQty": float,
804                            ...
805                        }
806                    }
807                }
808        """
809        endpoint = "/mf/fund/details"
810        params = {"isin": isin}
811        return self._make_api_request("GET", endpoint, params=params)

Get details of a mutual fund scheme by ISIN.

Arguments:
  • isin (str): ISIN of the mutual fund scheme
Returns:

dict: JSON response with the following structure::

{
    "status": str,
    "data": {
        "assetAllocation": [
            {
                "Isin": str,
                "AssetCode": int,
                "AssetName": str,
                "Holding_CurrentMonth": float,
                "Holding_PrevMonth": float,
                "CurrentMonth": str
            }
        ],
        "sectorAllocation": [
            {
                "Isin": str,
                "VALUE": float,
                "PERC_HOLD": float,
                "SECTOR": str,
                "AsOnDate": str           # ISO datetime
            }
        ],
        "holdingAllocation": [
            {
                "Isin": str,
                "co_code": int,
                "co_name": str,
                "invdate": str,
                "InvDate": str,           # ISO datetime
                "Perc_hold": float,
                "MktValue": float,
                "TotalShares": float,
                "AssetType": str,
                "rating": str
            }
        ],
        "cmotsDetails": {
            "isin": str,
            "sch_name": str,
            "navrs": float,
            "Navdate": str,
            "FundManager": str,
            "SchemeAUM": float,
            "EXPRATIO": float,
            "riskometervalue": str,
            "BenchmarkName": str,
            "Category": str,
            "fund_rating": int or None,
            ...
        },
        "bseSchemeDetails": {
            "ISIN": str,
            "SchemeCode": str,
            "SchemeName": str,
            "SchemeType": str,
            "SchemePlan": str,
            "PurchaseAllowed": str,
            "RedemptionAllowed": str,
            "SIPFlag": str,
            "MinimumPurchaseAmount": float,
            "MinimumRedemptionQty": float,
            ...
        }
    }
}
def fund_navs(self, isin: str) -> dict:
813    def fund_navs(self, isin: str) -> dict:
814        """
815        Get historical NAV data for a mutual fund scheme.
816
817        Args:
818            isin (str): ISIN of the mutual fund scheme
819
820        Returns:
821            dict: JSON response with the following structure::
822
823                {
824                    "status": str,
825                    "data": [
826                        {
827                            "date": str,      # ISO datetime
828                            "value": float    # NAV value
829                        }
830                    ]
831                }
832        """
833        endpoint = "/mf/fund/navs"
834        params = {"isin": isin}
835        return self._make_api_request("GET", endpoint, params=params)

Get historical NAV data for a mutual fund scheme.

Arguments:
  • isin (str): ISIN of the mutual fund scheme
Returns:

dict: JSON response with the following structure::

{
    "status": str,
    "data": [
        {
            "date": str,      # ISO datetime
            "value": float    # NAV value
        }
    ]
}
def portfolio_impact(self, isin: str, amount: float) -> dict:
837    def portfolio_impact(self, isin: str, amount: float) -> dict:
838        """
839        Get the portfolio impact of adding a mutual fund scheme.
840
841        Args:
842            isin (str): ISIN of the mutual fund scheme
843            amount (float): Investment amount
844
845        Returns:
846            dict: JSON response with the following structure::
847
848                {
849                    "status": str,
850                    "data": {
851                        "New": {
852                            "Returns": float,
853                            "Risk": float
854                        },
855                        "Original": {
856                            "Returns": float,
857                            "Risk": float
858                        }
859                    }
860                }
861        """
862        endpoint = "/mf/fund/portfolio-impact"
863        params = {"isin": isin, "amount": amount}
864        return self._make_api_request("GET", endpoint, params=params)

Get the portfolio impact of adding a mutual fund scheme.

Arguments:
  • isin (str): ISIN of the mutual fund scheme
  • amount (float): Investment amount
Returns:

dict: JSON response with the following structure::

{
    "status": str,
    "data": {
        "New": {
            "Returns": float,
            "Risk": float
        },
        "Original": {
            "Returns": float,
            "Risk": float
        }
    }
}
def fund_overlap(self, isin: str, amount: float) -> dict:
866    def fund_overlap(self, isin: str, amount: float) -> dict:
867        """
868        Get the fund overlap analysis for a mutual fund scheme against existing holdings.
869
870        Args:
871            isin (str): ISIN of the mutual fund scheme
872            amount (float): Investment amount
873
874        Returns:
875            dict: JSON response with the following structure::
876
877                {
878                    "status": str,
879                    "data": {
880                        "Value": float,
881                        "Overlaps": [
882                            {
883                                "Isin": str,
884                                "Holdings": [
885                                    {
886                                        "Name": str,
887                                        "Value": float
888                                    }
889                                ]
890                            }
891                        ]
892                    }
893                }
894        """
895        endpoint = "/mf/fund/portfolio-overlap"
896        params = {"isin": isin, "amount": amount}
897        return self._make_api_request("GET", endpoint, params=params)

Get the fund overlap analysis for a mutual fund scheme against existing holdings.

Arguments:
  • isin (str): ISIN of the mutual fund scheme
  • amount (float): Investment amount
Returns:

dict: JSON response with the following structure::

{
    "status": str,
    "data": {
        "Value": float,
        "Overlaps": [
            {
                "Isin": str,
                "Holdings": [
                    {
                        "Name": str,
                        "Value": float
                    }
                ]
            }
        ]
    }
}
def sip_book(self) -> dict:
899    def sip_book(self) -> dict:
900        """
901        Get the SIP (Systematic Investment Plan) book of the user.
902
903        Returns:
904            dict: JSON response with the following structure::
905
906                {
907                    "status": str,
908                    "data": [
909                        {
910                            "ID": int,
911                            "CreatedAt": str,                     # ISO datetime
912                            "UpdatedAt": str,                     # ISO datetime
913                            "transactionCode": str,
914                            "isin": str,
915                            "amount": float,
916                            "clientCode": str,
917                            "schemeCode": str,
918                            "remarks": str,
919                            "startDate": str,                     # ISO datetime
920                            "startDay": int,
921                            "modifiedStartDate": str or None,     # ISO datetime
922                            "mandateId": str,
923                            "state": str,
924                            "frequency": str,
925                            "stepUp": bool,
926                            "stepUpFrequency": str,
927                            "stepUpPercentage": float,
928                            "stepUpAmount": float,
929                            "isAmcSip": bool,
930                            "initialInvestmentAmount": float,
931                            "buySellType": str,
932                            "nextInstallmentDate": str or None,   # ISO datetime
933                            "installmentNumber": int,
934                            "schemeName": str,
935                            "coCode": int,
936                            "schemes_details": {
937                                "bseSchemeDetails": dict,
938                                "cmotsDetails": dict,
939                                "nfoDetails": dict
940                            }
941                        }
942                    ]
943                }
944        """
945        endpoint = "/mf/purchases/synthetic/plan"
946        return self._make_api_request("GET", endpoint)

Get the SIP (Systematic Investment Plan) book of the user.

Returns:

dict: JSON response with the following structure::

{
    "status": str,
    "data": [
        {
            "ID": int,
            "CreatedAt": str,                     # ISO datetime
            "UpdatedAt": str,                     # ISO datetime
            "transactionCode": str,
            "isin": str,
            "amount": float,
            "clientCode": str,
            "schemeCode": str,
            "remarks": str,
            "startDate": str,                     # ISO datetime
            "startDay": int,
            "modifiedStartDate": str or None,     # ISO datetime
            "mandateId": str,
            "state": str,
            "frequency": str,
            "stepUp": bool,
            "stepUpFrequency": str,
            "stepUpPercentage": float,
            "stepUpAmount": float,
            "isAmcSip": bool,
            "initialInvestmentAmount": float,
            "buySellType": str,
            "nextInstallmentDate": str or None,   # ISO datetime
            "installmentNumber": int,
            "schemeName": str,
            "coCode": int,
            "schemes_details": {
                "bseSchemeDetails": dict,
                "cmotsDetails": dict,
                "nfoDetails": dict
            }
        }
    ]
}
def save_backtest_result( self, stats, name: str, symbol: str = '', description: str = '', tags: list = None) -> dict:
948    def save_backtest_result(self, stats, name: str, symbol: str = "", description: str = "", tags: list = None) -> dict:
949        """
950        Save backtest results to Rupeezy for viewing on the developer portal.
951
952        Supports multiple backtesting libraries (auto-detected from the result type):
953        - **backtesting.py**: pass the stats object from Backtest.run()
954        - **vectorbt**: pass a vbt.Portfolio object
955        - **backtrader**: pass the strategy from cerebro.run() (i.e. results[0])
956
957        Args:
958            stats: The result object from any supported backtesting library.
959            name (str): A label for this backtest run (e.g. "SMA Crossover v2").
960            symbol (str, optional): Primary instrument symbol.
961            description (str, optional): Notes about this run.
962            tags (list[str], optional): Tags for filtering (e.g. ["intraday", "nifty"]).
963
964        Returns:
965            dict: { "status": "success", "backtest_id": "bt_abc123", "url": "https://..." }
966        """
967        from .backtest import serialize_stats
968        payload = serialize_stats(stats, name, symbol, description, tags or [])
969        endpoint = "/strategies/backtests"
970
971        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://..." }

def save_optimization_result( self, stats, heatmap, name: str, symbol: str = '', description: str = '', maximize='Sharpe Ratio', param_ranges: dict = None) -> dict:
 973    def save_optimization_result(
 974        self,
 975        stats,
 976        heatmap,
 977        name: str,
 978        symbol: str = "",
 979        description: str = "",
 980        maximize="Sharpe Ratio",
 981        param_ranges: dict = None,
 982    ) -> dict:
 983        """
 984        Save optimization results to Rupeezy for viewing on the developer portal.
 985
 986        Supports multiple backtesting libraries (auto-detected from the result type):
 987        - **backtesting.py**: pass stats + heatmap from bt.optimize(return_heatmap=True)
 988        - **vectorbt**: pass Portfolio + metric Series from multi-param run
 989        - **backtrader**: pass results list from cerebro.run() after optstrategy()
 990
 991        Args:
 992            stats: The result object from any supported backtesting library.
 993            heatmap: The heatmap/metric Series (backtesting.py/vectorbt) or
 994                     metric extraction callable (backtrader).
 995            name (str): A label for this optimization run (e.g. "SMA Grid Search").
 996            symbol (str, optional): Primary instrument symbol (e.g. "NIFTY").
 997            description (str, optional): Notes about this optimization run.
 998            maximize: The metric that was optimized. Should match the `maximize`
 999                      argument passed to Backtest.optimize(). Can be a string
1000                      metric name (e.g. "Sharpe Ratio") or a callable.
1001                      Defaults to "Sharpe Ratio".
1002            param_ranges (dict, optional): Explicit parameter range definitions.
1003                Keys are parameter names, values are range() objects or lists.
1004                Example: {"sma_fast": range(5, 51, 5), "sma_slow": range(20, 201, 10)}
1005                If not provided, ranges are inferred from the heatmap index.
1006
1007        Returns:
1008            dict: {"status": "success", "optimization_id": "opt_xxx", "backtest_id": "bt_xxx"}
1009
1010        Example::
1011
1012            stats, heatmap = bt.optimize(
1013                sma_fast=range(5, 51, 5),
1014                sma_slow=range(20, 201, 10),
1015                maximize='Sharpe Ratio',
1016                return_heatmap=True,
1017            )
1018            client.save_optimization_result(
1019                stats=stats,
1020                heatmap=heatmap,
1021                name="SMA Crossover Grid Search",
1022                symbol="NIFTY",
1023                maximize='Sharpe Ratio',
1024                param_ranges={"sma_fast": range(5, 51, 5), "sma_slow": range(20, 201, 10)},
1025            )
1026        """
1027        is_maximize = True
1028        objective_metric = maximize
1029
1030        if isinstance(maximize, bool):
1031            is_maximize = maximize
1032            objective_metric = "Sharpe Ratio"
1033
1034        from .backtest import serialize_optimization
1035        payload = serialize_optimization(
1036            result=stats,
1037            heatmap=heatmap,
1038            name=name,
1039            symbol=symbol,
1040            description=description,
1041            objective_metric=objective_metric,
1042            maximize=is_maximize,
1043            param_ranges=param_ranges,
1044        )
1045        endpoint = "/strategies/optimizations"
1046        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 maximize argument 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)},
)
class Constants:
 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        NSE_EQ = "NSE_EQ"
 23        BSE_EQUITY = "BSE_EQ"
 24        BSE_EQ = "NSE_EQ"
 25        NSE_CURRENCY = "NSE_CD"
 26        NSE_CD = "NSE_CD"
 27        MCX = "MCX_FO"
 28
 29        def __str__(self):
 30            return str(self.value)
 31    class VarietyTypes(str,Enum): 
 32        """
 33        Constants for varieties
 34        """
 35        REGULAR_LIMIT_ORDER = "RL"
 36        REGULAR_MARKET_ORDER = "RL-MKT"
 37        STOP_LIMIT_ORDER = "SL"
 38        STOP_MARKET_ORDER = "SL-MKT"
 39
 40        def __str__(self):
 41            return str(self.value)
 42    class ProductTypes(str,Enum): 
 43        """
 44        Constants for product types
 45        """
 46        INTRADAY = "INTRADAY"
 47        DELIVERY = "DELIVERY"
 48        MTF = "MTF"
 49
 50        def __str__(self):
 51            return str(self.value)
 52    class ValidityTypes(str,Enum): 
 53        """
 54        Constants for validity types
 55        """
 56        FULL_DAY = "DAY"
 57        IMMEDIATE_OR_CANCEL = "IOC"
 58        AFTER_MARKET = "AMO"
 59
 60        def __str__(self):
 61            return str(self.value)
 62    class TransactionSides(str,Enum): 
 63        """
 64        Constants for transaction sides
 65        """
 66        BUY = "BUY"
 67        SELL = "SELL"
 68        def __str__(self):
 69            return str(self.value)
 70    class QuoteModes(str,Enum): 
 71        """
 72        Constants for quote modes
 73        """
 74        LTP = "ltp"
 75        FULL = "full"
 76        OHLCV = "ohlcv"
 77        def __str__(self):
 78            return str(self.value)
 79    class OrderMarginModes(str,Enum): 
 80        """
 81        Constants for order margin modes
 82        """
 83        NEW_ORDER = "NEW"
 84        MODIFY_ORDER = "MODIFY"
 85
 86        def __str__(self):
 87            return str(self.value)
 88    class Resolutions(str,Enum): 
 89        """
 90        Constants for resolutions
 91        """
 92        MIN_1 = "1"
 93        MIN_2 = "2"
 94        MIN_3 = "3"
 95        MIN_4 = "4"
 96        MIN_5 = "5"
 97        MIN_10 = "10"
 98        MIN_15 = "15"
 99        MIN_30 = "30"
100        MIN_45 = "45"
101        MIN_60 = "60"
102        MIN_120 = "120"
103        MIN_180 = "180"
104        MIN_240 = "240"
105        DAY = "1D"
106        WEEK = "1W"
107        MONTH = "1M"
108
109        def __str__(self):
110            return str(self.value)

Constants used in the API

class Constants.ExchangeTypes(builtins.str, enum.Enum):
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        NSE_EQ = "NSE_EQ"
23        BSE_EQUITY = "BSE_EQ"
24        BSE_EQ = "NSE_EQ"
25        NSE_CURRENCY = "NSE_CD"
26        NSE_CD = "NSE_CD"
27        MCX = "MCX_FO"
28
29        def __str__(self):
30            return str(self.value)

Constants for exchanges

NSE_FO = <ExchangeTypes.NSE_FO: 'NSE_FO'>
BSE_FO = <ExchangeTypes.BSE_FO: 'BSE_FO'>
NSE_EQUITY = <ExchangeTypes.NSE_EQUITY: 'NSE_EQ'>
NSE_EQ = <ExchangeTypes.NSE_EQUITY: 'NSE_EQ'>
BSE_EQUITY = <ExchangeTypes.BSE_EQUITY: 'BSE_EQ'>
BSE_EQ = <ExchangeTypes.NSE_EQUITY: 'NSE_EQ'>
NSE_CURRENCY = <ExchangeTypes.NSE_CURRENCY: 'NSE_CD'>
NSE_CD = <ExchangeTypes.NSE_CURRENCY: 'NSE_CD'>
MCX = <ExchangeTypes.MCX: 'MCX_FO'>
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
class Constants.VarietyTypes(builtins.str, enum.Enum):
31    class VarietyTypes(str,Enum): 
32        """
33        Constants for varieties
34        """
35        REGULAR_LIMIT_ORDER = "RL"
36        REGULAR_MARKET_ORDER = "RL-MKT"
37        STOP_LIMIT_ORDER = "SL"
38        STOP_MARKET_ORDER = "SL-MKT"
39
40        def __str__(self):
41            return str(self.value)

Constants for varieties

REGULAR_LIMIT_ORDER = <VarietyTypes.REGULAR_LIMIT_ORDER: 'RL'>
REGULAR_MARKET_ORDER = <VarietyTypes.REGULAR_MARKET_ORDER: 'RL-MKT'>
STOP_LIMIT_ORDER = <VarietyTypes.STOP_LIMIT_ORDER: 'SL'>
STOP_MARKET_ORDER = <VarietyTypes.STOP_MARKET_ORDER: 'SL-MKT'>
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
class Constants.ProductTypes(builtins.str, enum.Enum):
42    class ProductTypes(str,Enum): 
43        """
44        Constants for product types
45        """
46        INTRADAY = "INTRADAY"
47        DELIVERY = "DELIVERY"
48        MTF = "MTF"
49
50        def __str__(self):
51            return str(self.value)

Constants for product types

INTRADAY = <ProductTypes.INTRADAY: 'INTRADAY'>
DELIVERY = <ProductTypes.DELIVERY: 'DELIVERY'>
MTF = <ProductTypes.MTF: 'MTF'>
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
class Constants.ValidityTypes(builtins.str, enum.Enum):
52    class ValidityTypes(str,Enum): 
53        """
54        Constants for validity types
55        """
56        FULL_DAY = "DAY"
57        IMMEDIATE_OR_CANCEL = "IOC"
58        AFTER_MARKET = "AMO"
59
60        def __str__(self):
61            return str(self.value)

Constants for validity types

FULL_DAY = <ValidityTypes.FULL_DAY: 'DAY'>
IMMEDIATE_OR_CANCEL = <ValidityTypes.IMMEDIATE_OR_CANCEL: 'IOC'>
AFTER_MARKET = <ValidityTypes.AFTER_MARKET: 'AMO'>
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
class Constants.TransactionSides(builtins.str, enum.Enum):
62    class TransactionSides(str,Enum): 
63        """
64        Constants for transaction sides
65        """
66        BUY = "BUY"
67        SELL = "SELL"
68        def __str__(self):
69            return str(self.value)

Constants for transaction sides

BUY = <TransactionSides.BUY: 'BUY'>
SELL = <TransactionSides.SELL: 'SELL'>
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
class Constants.QuoteModes(builtins.str, enum.Enum):
70    class QuoteModes(str,Enum): 
71        """
72        Constants for quote modes
73        """
74        LTP = "ltp"
75        FULL = "full"
76        OHLCV = "ohlcv"
77        def __str__(self):
78            return str(self.value)

Constants for quote modes

LTP = <QuoteModes.LTP: 'ltp'>
FULL = <QuoteModes.FULL: 'full'>
OHLCV = <QuoteModes.OHLCV: 'ohlcv'>
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
class Constants.OrderMarginModes(builtins.str, enum.Enum):
79    class OrderMarginModes(str,Enum): 
80        """
81        Constants for order margin modes
82        """
83        NEW_ORDER = "NEW"
84        MODIFY_ORDER = "MODIFY"
85
86        def __str__(self):
87            return str(self.value)

Constants for order margin modes

NEW_ORDER = <OrderMarginModes.NEW_ORDER: 'NEW'>
MODIFY_ORDER = <OrderMarginModes.MODIFY_ORDER: 'MODIFY'>
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
class Constants.Resolutions(builtins.str, enum.Enum):
 88    class Resolutions(str,Enum): 
 89        """
 90        Constants for resolutions
 91        """
 92        MIN_1 = "1"
 93        MIN_2 = "2"
 94        MIN_3 = "3"
 95        MIN_4 = "4"
 96        MIN_5 = "5"
 97        MIN_10 = "10"
 98        MIN_15 = "15"
 99        MIN_30 = "30"
100        MIN_45 = "45"
101        MIN_60 = "60"
102        MIN_120 = "120"
103        MIN_180 = "180"
104        MIN_240 = "240"
105        DAY = "1D"
106        WEEK = "1W"
107        MONTH = "1M"
108
109        def __str__(self):
110            return str(self.value)

Constants for resolutions

MIN_1 = <Resolutions.MIN_1: '1'>
MIN_2 = <Resolutions.MIN_2: '2'>
MIN_3 = <Resolutions.MIN_3: '3'>
MIN_4 = <Resolutions.MIN_4: '4'>
MIN_5 = <Resolutions.MIN_5: '5'>
MIN_10 = <Resolutions.MIN_10: '10'>
MIN_15 = <Resolutions.MIN_15: '15'>
MIN_30 = <Resolutions.MIN_30: '30'>
MIN_45 = <Resolutions.MIN_45: '45'>
MIN_60 = <Resolutions.MIN_60: '60'>
MIN_120 = <Resolutions.MIN_120: '120'>
MIN_180 = <Resolutions.MIN_180: '180'>
MIN_240 = <Resolutions.MIN_240: '240'>
DAY = <Resolutions.DAY: '1D'>
WEEK = <Resolutions.WEEK: '1W'>
MONTH = <Resolutions.MONTH: '1M'>
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
class VortexFeed:

The WebSocket client for connecting to vortex's live price and order streaming service

VortexFeed( access_token: str = None, websocket_endpoint='wss://wire.rupeezy.in/ws', reconnect=True, reconnect_max_tries=50, reconnect_max_delay=60, connect_timeout=30, debug=False)
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        if os.getenv("VORTEX_FEED_BASE_URL") != None:
267            self.socket_url = os.getenv("VORTEX_FEED_BASE_URL") + "?auth_token=" + access_token
268        else:
269            self.socket_url = websocket_endpoint+"?auth_token="+access_token
270
271        self.access_token = access_token
272        self.socket_token = self.__getSocketToken__(self.access_token)
273
274        self.debug = debug
275        # self.on_price_update = None
276        self.on_price_update = None
277        self.on_open = None
278        self.on_close = None
279        self.on_error = None
280        self.on_connect = None
281        self.on_message = None
282        self.on_reconnect = None
283        self.on_noreconnect = None
284        self.on_order_update = None
285        self.subscribed_tokens = {}
286        pass
def connect(self, threaded=False, disable_ssl_verification=False):
310    def connect(self, threaded=False, disable_ssl_verification=False):
311        """
312        Establish a websocket connection.
313        - `disable_ssl_verification` disables building ssl context
314        """
315        # Init WebSocket client factory
316        self._create_connection(self.socket_url,
317                                useragent=self._user_agent())
318
319        # Set SSL context
320        context_factory = None
321        if self.factory.isSecure and not disable_ssl_verification:
322            from urllib.parse import urlparse
323            hostname = urlparse(self.socket_url).hostname
324            context_factory = ssl.optionsForClientTLS(hostname)
325
326        # Establish WebSocket connection to a server
327        connectWS(self.factory, contextFactory=context_factory, timeout=self.connect_timeout)
328
329        if self.debug:
330            twisted_log.startLogging(sys.stdout)
331
332        # Run in seperate thread of blocking
333        opts = {}
334        # Run when reactor is not running
335        if not reactor.running:
336            if threaded:
337                # Signals are not allowed in non main thread by twisted so suppress it.
338                opts["installSignalHandlers"] = False
339                self.websocket_thread = threading.Thread(target=reactor.run, kwargs=opts)
340                self.websocket_thread.daemon = True
341                self.websocket_thread.start()
342            else:
343                reactor.run(**opts)
344        else: 
345            print(reactor.running)

Establish a websocket connection.

  • disable_ssl_verification disables building ssl context
def is_connected(self):
347    def is_connected(self):
348        """Check if WebSocket connection is established."""
349        if self.ws and self.ws.state == self.ws.STATE_OPEN:
350            return True
351        else:
352            return False

Check if WebSocket connection is established.

def close(self, code=None, reason=None):
359    def close(self, code=None, reason=None):
360        """Close the WebSocket connection."""
361        self.stop_retry()
362        self._close(code, reason)

Close the WebSocket connection.

def stop(self):
364    def stop(self):
365        """Stop the event loop. Should be used if main thread has to be closed in `on_close` method.
366        Reconnection mechanism cannot happen past this method
367        """
368        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

def stop_retry(self):
370    def stop_retry(self):
371        """Stop auto retry when it is in progress."""
372        if self.factory:
373            self.factory.stopTrying()

Stop auto retry when it is in progress.

def subscribe(self, exchange: str, token: int, mode: str) -> bool:
375    def subscribe(self, exchange: str,token: int,mode: str)->bool:
376        """
377        Subscribe to a list of instrument_tokens.
378        - `instrument_tokens` is list of instrument instrument_tokens to subscribe
379        """
380        try:
381            self.ws.sendMessage(six.b(json.dumps({"message_type": self._message_subscribe, "exchange": exchange,"token": token,"mode": mode})))     
382
383            try: 
384                self.subscribed_tokens[exchange][token] = mode
385            except KeyError: 
386                self.subscribed_tokens[exchange] = {}
387                self.subscribed_tokens[exchange][token] = mode
388
389            return True
390        except Exception as e:
391            self._close(reason="Error while subscribe: {}".format(str(e)))
392            raise

Subscribe to a list of instrument_tokens.

  • instrument_tokens is list of instrument instrument_tokens to subscribe
def unsubscribe(self, exchange: str, token: int) -> bool:
394    def unsubscribe(self, exchange: str,token: int)->bool:
395        """
396        Unsubscribe the given list of instrument_tokens.
397        - `instrument_tokens` is list of instrument_tokens to unsubscribe.
398        """
399        try:
400            self.ws.sendMessage(six.b(json.dumps({"message_type": self._message_unsubscribe, "exchange": exchange,"token": token})))            
401
402            try: 
403                del(self.subscribed_tokens[exchange][token])
404            except KeyError: 
405                pass 
406
407            return True
408        except Exception as e:
409            self._close(reason="Error while unsubscribe: {}".format(str(e)))
410            raise

Unsubscribe the given list of instrument_tokens.

  • instrument_tokens is list of instrument_tokens to unsubscribe.
def resubscribe(self):
412    def resubscribe(self):
413        """Resubscribe to all current subscribed tokens."""
414        modes = {}
415
416        for exchange in self.subscribed_tokens: 
417            for token in self.subscribed_tokens[exchange]: 
418                self.subscribe(exchange=exchange, token=token,mode=self.subscribed_tokens[exchange][token])

Resubscribe to all current subscribed tokens.