Examples

Orders

Basic example showing order placement and getting order status from orderbook.

# -*- coding: utf-8 -*-
###############################################################################
# MIT License                                                                 #
###############################################################################
# Copyright (c) 2023 Definedge Securities Broking Pvt. Ltd.                   #
###############################################################################
# Permission is hereby granted, free of charge, to any person obtaining a     #
# copy of this software and associated documentation files (the "Software"),  #
# to deal in the Software without restriction, including without limitation   #
# the rights to use, copy, modify, merge, publish, distribute, sublicense,    #
# and/or sell copies of the Software, and to permit persons to whom the       #
# Software is furnished to do so, subject to the following conditions:        #
#                                                                             #
# The above copyright notice and this permission notice shall be included in  #
# all copies or substantial portions of the Software.                         #
#                                                                             #
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  #
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,    #
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER      #
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING     #
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER         #
# DEALINGS IN THE SOFTWARE.                                                   #
###############################################################################

"""
This example shows how to use the IntegrateOrders class to connect to
the Integrate Orders API and place a market order, get an order's status
using order_id and get the order book. This example also shows how to
login to Integrate and save the session keys in a .env file, so that
you don't have to login again and again.
"""

from logging import INFO, basicConfig, info
from os import environ
from typing import Any

from dotenv import (  # pip install python-dotenv
    find_dotenv,
    load_dotenv,
    set_key,
)

from integrate import ConnectToIntegrate, IntegrateOrders

basicConfig(level=INFO)
dotenv_file: str = find_dotenv()
load_dotenv(dotenv_file)


def main() -> None:
    """
    Main function
    """
    try:
        # Get the API token and secret from environment variables.
        api_token: str = environ["INTEGRATE_API_TOKEN"]
        api_secret: str = environ["INTEGRATE_API_SECRET"]
    except KeyError:
        raise KeyError(
            "Please set INTEGRATE_API_TOKEN and INTEGRATE_API_SECRET in .env file."
        )

    # Initialise the connection.
    conn = ConnectToIntegrate()
    # Login to Integrate.
    try:
        uid: str = environ["INTEGRATE_UID"]
        actid: str = environ["INTEGRATE_ACTID"]
        api_session_key: str = environ["INTEGRATE_API_SESSION_KEY"]
        ws_session_key: str = environ["INTEGRATE_WS_SESSION_KEY"]
        conn.set_session_keys(uid, actid, api_session_key, ws_session_key)
        # Please note that the session keys are valid for 24 hours. After that you
        # will have to login again. The logic to handle this is left to the user.
    except KeyError:
        conn.login(
            api_token=api_token,
            api_secret=api_secret,
        )
        (uid, actid, api_session_key, ws_session_key) = conn.get_session_keys()
        environ["INTEGRATE_UID"] = uid
        environ["INTEGRATE_ACTID"] = actid
        environ["INTEGRATE_API_SESSION_KEY"] = api_session_key
        environ["INTEGRATE_WS_SESSION_KEY"] = ws_session_key
        set_key(dotenv_file, "INTEGRATE_UID", uid)
        set_key(dotenv_file, "INTEGRATE_ACTID", actid)
        set_key(dotenv_file, "INTEGRATE_API_SESSION_KEY", api_session_key)
        set_key(dotenv_file, "INTEGRATE_WS_SESSION_KEY", ws_session_key)
        info("Login successful.")

    io = IntegrateOrders(conn)

    # Get account balance and cash margin.
    info(io.limits())

    try:
        order: dict[str, Any] = io.place_order(
            exchange=conn.EXCHANGE_TYPE_NSE,
            order_type=conn.ORDER_TYPE_BUY,
            price=0,
            price_type=conn.PRICE_TYPE_MARKET,
            product_type=conn.PRODUCT_TYPE_INTRADAY,
            quantity=1,
            tradingsymbol="SBIN-EQ",
        )
        info(f"Order placed: {order}")

        # Get status of a single order.
        info(io.order(order_id=order["order_id"]))
    except Exception as e:
        info(f"Order placement failed: {e}")

    # Get order book.
    info(io.orders())


if __name__ == "__main__":
    main()

Margins

Basic example showing getting margin requirements for a basket of orders.

# -*- coding: utf-8 -*-
###############################################################################
# MIT License                                                                 #
###############################################################################
# Copyright (c) 2023 Definedge Securities Broking Pvt. Ltd.                   #
###############################################################################
# Permission is hereby granted, free of charge, to any person obtaining a     #
# copy of this software and associated documentation files (the "Software"),  #
# to deal in the Software without restriction, including without limitation   #
# the rights to use, copy, modify, merge, publish, distribute, sublicense,    #
# and/or sell copies of the Software, and to permit persons to whom the       #
# Software is furnished to do so, subject to the following conditions:        #
#                                                                             #
# The above copyright notice and this permission notice shall be included in  #
# all copies or substantial portions of the Software.                         #
#                                                                             #
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  #
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,    #
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER      #
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING     #
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER         #
# DEALINGS IN THE SOFTWARE.                                                   #
###############################################################################

"""
This example shows how to use the IntegrateOrders class to connect to
the Integrate Orders API and get the margin requirements for a basket
of securities.
"""

from logging import INFO, basicConfig, info
from typing import Any

from integrate import ConnectToIntegrate, IntegrateOrders

basicConfig(level=INFO)


def main() -> None:
    """
    Main function
    """
    # Initialise the connection and login.
    conn = ConnectToIntegrate()
    conn.login(  # nosec: B106
        api_token="YOUR_API_TOKEN",
        api_secret="YOUR_API_SECRET",
    )

    io = IntegrateOrders(conn)

    # Get margin requirements for a basket of securities.
    orders: list[dict[str, Any]] = [
        {
            "exchange": io.c2i.EXCHANGE_TYPE_NSE,
            "tradingsymbol": "SBIN-EQ",
            "quantity": 50,
            "price": 0,
            "product_type": io.c2i.PRODUCT_TYPE_INTRADAY,
            "order_type": io.c2i.ORDER_TYPE_BUY,
            "price_type": io.c2i.PRICE_TYPE_MARKET,
        },
        {
            "exchange": io.c2i.EXCHANGE_TYPE_NSE,
            "tradingsymbol": "TCS-EQ",
            "quantity": 10,
            "price": 0,
            "product_type": io.c2i.PRODUCT_TYPE_CNC,
            "order_type": io.c2i.ORDER_TYPE_BUY,
            "price_type": io.c2i.PRICE_TYPE_MARKET,
        },
    ]

    info(io.margins(orders=orders))


if __name__ == "__main__":
    main()

Data

Basic example showing how to get historical data, quotes and security information.

# -*- coding: utf-8 -*-
###############################################################################
# MIT License                                                                 #
###############################################################################
# Copyright (c) 2023 Definedge Securities Broking Pvt. Ltd.                   #
###############################################################################
# Permission is hereby granted, free of charge, to any person obtaining a     #
# copy of this software and associated documentation files (the "Software"),  #
# to deal in the Software without restriction, including without limitation   #
# the rights to use, copy, modify, merge, publish, distribute, sublicense,    #
# and/or sell copies of the Software, and to permit persons to whom the       #
# Software is furnished to do so, subject to the following conditions:        #
#                                                                             #
# The above copyright notice and this permission notice shall be included in  #
# all copies or substantial portions of the Software.                         #
#                                                                             #
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  #
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,    #
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER      #
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING     #
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER         #
# DEALINGS IN THE SOFTWARE.                                                   #
###############################################################################

"""
This example shows how to use the IntegrateData class to connect to
the Integrate Data API and fetch quotes, security information and
historical data for a symbol.
"""

from datetime import datetime, timedelta
from logging import INFO, basicConfig, info
from typing import Any, Generator

from integrate import ConnectToIntegrate, IntegrateData

basicConfig(level=INFO)


def main() -> None:
    """
    Main function
    """
    # Initialise the connection and login.
    conn = ConnectToIntegrate()
    conn.login(  # nosec: B106
        api_token="YOUR_API_TOKEN",
        api_secret="YOUR_API_SECRET",
    )

    ic = IntegrateData(conn)

    # Get quote for NSE:SBIN-EQ
    info(ic.quotes(exchange=conn.EXCHANGE_TYPE_NSE, trading_symbol="SBIN-EQ"))

    # Get security information for NSE:SBIN-EQ
    info(
        ic.security_information(
            exchange=conn.EXCHANGE_TYPE_NSE, trading_symbol="SBIN-EQ"
        )
    )

    today: datetime = datetime.today()
    yesterday: datetime = today - timedelta(days=1)

    # Get historical data for NSE:SBIN-EQ
    history: Generator[dict[str, Any], None, None] = ic.historical_data(
        exchange=conn.EXCHANGE_TYPE_NSE,
        trading_symbol="SBIN-EQ",
        timeframe=conn.TIMEFRAME_TYPE_MIN,
        start=yesterday,
        end=today,
    )

    for data in history:
        info(data)


if __name__ == "__main__":
    main()

WebSocket

Basic example showing how to use the WebSocket API.

# -*- coding: utf-8 -*-
###############################################################################
# MIT License                                                                 #
###############################################################################
# Copyright (c) 2023 Definedge Securities Broking Pvt. Ltd.                   #
###############################################################################
# Permission is hereby granted, free of charge, to any person obtaining a     #
# copy of this software and associated documentation files (the "Software"),  #
# to deal in the Software without restriction, including without limitation   #
# the rights to use, copy, modify, merge, publish, distribute, sublicense,    #
# and/or sell copies of the Software, and to permit persons to whom the       #
# Software is furnished to do so, subject to the following conditions:        #
#                                                                             #
# The above copyright notice and this permission notice shall be included in  #
# all copies or substantial portions of the Software.                         #
#                                                                             #
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  #
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,    #
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER      #
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING     #
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER         #
# DEALINGS IN THE SOFTWARE.                                                   #
###############################################################################

"""
This example shows how to use the IntegrateWebSocket class to connect to
the Integrate WebSocket API and subscribe to ticks, order updates and
bid-ask depth updates. The websocket connection is blocking, so you have
to use the callbacks to manage the connection.
"""

from logging import INFO, basicConfig, info
from typing import Union

from integrate import ConnectToIntegrate, IntegrateWebSocket

basicConfig(level=INFO)

# Initialise the connection and login.
conn = ConnectToIntegrate()
conn.login(  # nosec: B106
    api_token="YOUR_API_TOKEN",
    api_secret="YOUR_API_SECRET",
)

# List of symbols (TCS and TATAMOTORS here) to subscribe to.
symbols: list[tuple[str, str]] = [
    (conn.EXCHANGE_TYPE_NSE, "TCS-EQ"),
    (conn.EXCHANGE_TYPE_NSE, "TATAMOTORS-EQ"),
]
# Tokens of the above symbols.
tokens: list[tuple[str, str]] = []


def get_token_for_symbol(exchange: str, symbol: str) -> tuple[str, str]:
    """
    Get the token for a symbol from the symbols file.
    """
    if exchange not in conn.exchange_types:
        raise ValueError("Invalid exchange type")

    token: Union[str, None] = next(
        (
            i["token"]
            for i in conn.symbols
            if i["segment"] == exchange and i["trading_symbol"] == symbol
        ),
        None,
    )
    if token:
        return (exchange, token)
    else:
        raise Exception(f"Token not found for {symbol} in symbols file")


def on_login(iws: IntegrateWebSocket) -> None:
    """
    Callback called when the WebSocket connection is established and the login is successful.
    """
    for exchange, symbol in symbols:
        tokens.append(get_token_for_symbol(exchange, symbol))
    info(tokens)
    # Subscribe to a list of symbols. You can have different lists for different subscriptions.
    iws.subscribe(conn.SUBSCRIPTION_TYPE_TICK, tokens)
    iws.subscribe(conn.SUBSCRIPTION_TYPE_DEPTH, tokens)


def on_tick_update(iws: IntegrateWebSocket, tick: dict[str, str]) -> None:
    """
    Callback to receive tick updates.
    """
    info(f"Ticks: {tick}")


def on_order_update(iws: IntegrateWebSocket, order: dict[str, str]) -> None:
    """
    Callback called when an order update is received.
    """
    info(f"Order update : {order}")


def on_depth_update(iws: IntegrateWebSocket, depth: dict[str, str]) -> None:
    """
    Callback to receive bid-ask depth updates.
    """
    info(f"Depth update : {depth}")


def on_exception(iws: IntegrateWebSocket, e: Exception) -> None:
    """
    Callback to run on Python exceptions.
    """
    info(f"Exception : {e}")
    # Below will close the WebSocket connection.
    iws.close_on_exception("Closing connection due to exception")


def on_close(iws: IntegrateWebSocket, code: int, reason: str) -> None:
    """
    Callback to run on WebSocket close. Calling iws.stop() here is required to
    exit the program by stopping the event loop.
    """
    info(f"Closed : {code} {reason}")
    # Below will stop the event loop and the program will exit.
    iws.stop()


def main() -> None:
    """
    Main function
    """
    iws = IntegrateWebSocket(conn)

    # Assign the callbacks.
    iws.on_login = on_login  # type: ignore
    iws.on_tick_update = on_tick_update  # type: ignore
    iws.on_order_update = on_order_update  # type: ignore
    iws.on_depth_update = on_depth_update  # type: ignore
    iws.on_exception = on_exception  # type: ignore
    iws.on_close = on_close  # type: ignore

    # Blocking WebSocket connection below. Nothing after this will run.
    # You have to use the callbacks for further management.
    # If you receive an SSL Error after login, then replace the below line with:
    # iws.connect(ssl_verify=False)
    iws.connect()


if __name__ == "__main__":
    main()

Daemonized WebSocket

Basic example showing how to use the WebSocket API in a daemonized process.

# -*- coding: utf-8 -*-
###############################################################################
# MIT License                                                                 #
###############################################################################
# Copyright (c) 2023 Definedge Securities Broking Pvt. Ltd.                   #
###############################################################################
# Permission is hereby granted, free of charge, to any person obtaining a     #
# copy of this software and associated documentation files (the "Software"),  #
# to deal in the Software without restriction, including without limitation   #
# the rights to use, copy, modify, merge, publish, distribute, sublicense,    #
# and/or sell copies of the Software, and to permit persons to whom the       #
# Software is furnished to do so, subject to the following conditions:        #
#                                                                             #
# The above copyright notice and this permission notice shall be included in  #
# all copies or substantial portions of the Software.                         #
#                                                                             #
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  #
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,    #
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER      #
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING     #
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER         #
# DEALINGS IN THE SOFTWARE.                                                   #
###############################################################################

"""
This example shows how to use the IntegrateWebSocket class to connect to
the Integrate WebSocket API and subscribe to ticks, order updates and
bid-ask depth updates in a daemonized process.
"""

from logging import INFO, basicConfig, info

from integrate import ConnectToIntegrate, IntegrateWebSocket

basicConfig(level=INFO)


def on_login(iws: IntegrateWebSocket) -> None:
    """
    Callback called when the WebSocket connection is established
    and the login is successful.
    """
    # Subscribe to a list of symbols (TCS and TATAMOTORS here).
    tokens: list[tuple[str, str]] = [
        (iws.c2i.EXCHANGE_TYPE_NSE, "11536"),
        (iws.c2i.EXCHANGE_TYPE_NSE, "3456"),
    ]
    iws.subscribe(iws.c2i.SUBSCRIPTION_TYPE_TICK, tokens)
    iws.subscribe(iws.c2i.SUBSCRIPTION_TYPE_ORDER, tokens)
    iws.subscribe(iws.c2i.SUBSCRIPTION_TYPE_DEPTH, tokens)


def on_tick_update(iws: IntegrateWebSocket, tick: dict[str, str]) -> None:
    """
    Callback called when a tick update is received.
    """
    info(f"Ticks: {tick}")


def on_order_update(iws: IntegrateWebSocket, order: dict[str, str]) -> None:
    """
    Callback called when an order update is received.
    """
    info(f"Order update : {order}")


def on_depth_update(iws: IntegrateWebSocket, depth: dict[str, str]) -> None:
    """
    Callback called when a bid-ask depth update is received.
    """
    info(f"Depth update : {depth}")


def on_acknowledgement(iws: IntegrateWebSocket, ack: dict[str, str]) -> None:
    """
    Callback called when an acknowledgement is received.
    """
    info(f"Ack : {ack}")


def on_exception(iws: IntegrateWebSocket, e: Exception) -> None:
    """
    Callback to run on Python exceptions.
    """
    info(f"Exception : {e}")
    # Below will close the WebSocket connection.
    # iws.close_on_exception("Closing connection due to exception")


def on_close(iws: IntegrateWebSocket, code: int, reason: str) -> None:
    """
    Callback to run on WebSocket close.
    """
    info(f"Closed : {code} {reason}")
    # Below will stop the event loop and the program will exit.
    # iws.stop()


def main() -> None:
    """
    Main function.
    """
    # Initialise the connection and login.
    conn = ConnectToIntegrate()
    conn.login(  # nosec: B106
        api_token="YOUR_API_TOKEN",
        api_secret="YOUR_API_SECRET",
    )
    iws = IntegrateWebSocket(conn)

    # Assign the callbacks to the IntegrateWebSocket object.
    iws.on_login = on_login  # type: ignore
    iws.on_tick_update = on_tick_update  # type: ignore
    iws.on_order_update = on_order_update  # type: ignore
    iws.on_depth_update = on_depth_update  # type: ignore
    iws.on_acknowledgement = on_acknowledgement  # type: ignore
    iws.on_exception = on_exception  # type: ignore
    iws.on_close = on_close  # type: ignore

    # Non-Blocking WebSocket connection below (daemonize=True).
    # If you receive an SSL Error after login, then replace the below line with:
    # iws.connect(daemonize=True, ssl_verify=False)
    iws.connect(daemonize=True)

    # To keep the main thread running, an infinite loop as below should be
    # running. Else, the main thread and thus the daemon thread would exit.
    while True:
        try:
            pass
        except KeyboardInterrupt:
            break


if __name__ == "__main__":
    main()