Query and Display Market Data – ShinyBroker

# Query and Display Market Data

So you’ve installed Shinybroker and gotten the hello world example to work. Congrats! Now it’s time to actually build an app that uses some of the features.

This example will introduce you, in steps, to using ShinyBroker to write an app that will calculate beta between two assets, display that information, and use it to trade. Each step below adds a layer of functionality to the app. You can use this example to learn how to:

- access & use the ShinyBroker reactive variables in `sb_rvs`
- implement some initial setup logic to fetch data from IBKR
- process your data and display it

Coming Soon: live updating data, dynamic contract entry, positions, order placement, and finally– a video walkthrough of all this :)

### Step 1: `sb_rvs` and setup logic

We’re interested in calculating beta between two assets, so first we’re going to need to pull price data from IBKR in order to make the calculation.

We can accomplish this task with the code below, which operates as follows:

1. Defines a Shiny server function
2. Sets a reactive variable named `run_once`
3. Defines a setup function named `make_historical_data_queries` that fetches data for Apple & the S&P 500 index. Don’t worry, in later steps we’ll add the ability to dynamically pick what two assets you want, but for now we’ll hard-code the logic for Apple and SPX.
4. Creates an `app` object from the server function that connects to a running instance of TWS (don’t forget run TWS or else it can’t connect!)
5. Runs the app.

#### The Design Pattern

The server function, appropriately named `a_server_function`, first sets the value of a reactive variable named `run_once` to `True`. That design pattern is needed because `start_historical_data_subscription` can only be called within a reactive context, and also because when the shiny app loads, the reactive variables in `a_server_function` will be registered, set, and detected by the setup function `make_historical_data_queries` only after ShinyBroker has connected to TWS. In other words, by the time `run_once` is set, detected by `make_historical_data_queries`, and triggers the data fetching logic, you can be sure that the socket connection to IBKR (which takes place in the ShinyBroker backend) is set up and ready for use.

#### The setup function

Once triggered, `make_historical_data_queries` makes two calls to `start_historical_data_subscription`, a function provided by the ShinyBroker library. Even though in this case we’re performing a static, one-time data query, the word “subscription” appears in the function’s name because it can be called by setting the `keepUpToDate` parameter to `True`. Doing so results in the historical data being kept up-to-date with live market data as it becomes available, and we’ll do exactly this in a later step.

For now, you should understand three things about `start_historical_data_subscription`:

1. The data it fetches is written to the reactive variable named ‘historical_data’. Because this is a native ShinyBroker reactive variable, you can always access it with `sb_rvs['historical_data']`
2. `sb_rvs['historical_data']` is a dictionary that contains the data retrieved by each query. That dictionary is keyed by the integer-valued `subscription_id` you pass to it. If you don’t pass a subscription id, as in the code below, then ShinyBroker will just find the maximum subscription id already used in a historical data query for that session, add `1` to that, and treat the result as the `subscription_id`, beginning with `1` if no previous subscriptions are found for the current session.
3. You must define the `contract` for which you want data using the `Contract` constructor, which is provided by the ShinyBroker package.

##### Run the code below

1. View your Shiny app in a browser
2. Navigate to the Market Data panel
3. Open the “Historical Data” accordion panel …and you should see an output of the historical data fetched by your query! Once you’ve successfully accomplished that, you can move on to the next step!

    import select
    import shinybroker as sb
    from shiny import Inputs, Outputs, Session, reactive

    # Declare a server function...
    #   ...just like you would when making an ordinary Shiny app.
    # remember that your server functions must always include the five inputs that
    #   appear in the signature below.
    def a_server_function(
            input: Inputs, output: Outputs, session: Session, ib_socket, sb_rvs
    ):
        # Only set this variable once. Reactive functions that depend upon it will
        #   run when the app is initialized, after the socket has been connected
        #   and properly set up by ShinyBroker.
        run_once = reactive.value(True)

        @reactive.effect
        @reactive.event(run_once)
        def make_historical_data_queries():

            # Fetch the hourly trade data for AAPL for the past 3 days.
            sb.start_historical_data_subscription(
                historical_data=sb_rvs['historical_data'],
                hd_socket=ib_socket,
                contract=sb.Contract({
                    'symbol': "AAPL",
                    'secType': "STK",
                    'exchange': "SMART",
                    'currency': "USD",
                }),
                durationStr="3 D",
                barSizeSetting="1 hour"
            )

            # Do the same, but for the S&P 500 Index
            sb.start_historical_data_subscription(
                historical_data=sb_rvs['historical_data'],
                hd_socket=ib_socket,
                contract=sb.Contract({
                    'symbol': 'SPX',
                    'secType': 'IND',
                    'currency': 'USD',
                    'exchange': 'CBOE'
                }),
                durationStr="3 D",
                barSizeSetting="1 hour"
            )

    # create an app object using your server function
    # Adjust your connection parameters if not using the default TWS paper trader,
    #   or if you want a different client id, etc.
    app = sb.sb_app(
        server_fn=a_server_function,
        host='127.0.0.1',
        port=7497,
        client_id=10742,
        verbose=True
    )

    # run the app.
    app.run()