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.
= reactive.value(True)
run_once
@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(=sb_rvs['historical_data'],
historical_data=ib_socket,
hd_socket=sb.Contract({
contract'symbol': "AAPL",
'secType': "STK",
'exchange': "SMART",
'currency': "USD",
}),="3 D",
durationStr="1 hour"
barSizeSetting
)
# Do the same, but for the S&P 500 Index
sb.start_historical_data_subscription(=sb_rvs['historical_data'],
historical_data=ib_socket,
hd_socket=sb.Contract({
contract'symbol': 'SPX',
'secType': 'IND',
'currency': 'USD',
'exchange': 'CBOE'
}),="3 D",
durationStr="1 hour"
barSizeSetting
)
# 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.
= sb.sb_app(
app =a_server_function,
server_fn='127.0.0.1',
host=7497,
port=10742,
client_id=True
verbose
)
# run the app.
app.run()
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:
- Defines a Shiny server function
- Sets a reactive variable named
run_once
- 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. - 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!) - 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
:
- 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']
sb_rvs['historical_data']
is a dictionary that contains the data retrieved by each query. That dictionary is keyed by the integer-valuedsubscription_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, add1
to that, and treat the result as thesubscription_id
, beginning with1
if no previous subscriptions are found for the current session.- You must define the
contract
for which you want data using theContract
constructor, which is provided by the ShinyBroker package.
Run the code below
- View your Shiny app in a browser
- Navigate to the Market Data panel
- 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!