Fetching Market Data#

This guide outlines the different ways to fetch data about a chart and market.

Make sure you have set up the Sierra Chart custom study as shown in Hello, World! with the key helloworld.

Scope#

Through the four SCBridge methods covered in this guide, the following data can be fetched:

  • Price data

  • Volume

  • Price averages

  • Open interest

  • Number of trades

  • Bid/ask volume

  • Up/down volume

  • Bid/ask number of trades

  • Other sc.BaseData arrays

  • Volume by price

  • Time and sales

  • Market depth

  • Market depth pulling/stacking

Background Preamble#

There are two important forms that data will come in: the form of Snapshots and Incremental Updates.

When snapshot updates are sent, they contain only current information. On the other hand, incremental updates contain current information and all historical information not sent yet.

This concept will be elaborated on more later, but for now take the difference between how the snapshot MarketDepthResponse and the incremental TimeAndSalesResponse objects look as an example. As a pandas.DataFrame, MarketDepthResponse has no column for DateTime. It is not a historical collection of market depth data, it represents a single snapshot of what the market depth looks like right now. As a pandas.DataFrame, TimeAndSalesResponse has only two columns: DateTime and TimeAndSales. As opposed to the snapshot form of MarketDepthResponse, the TimeAndSalesResponse is a historical collection of data. Incremental data is simply a historical record of many snapshots.

Get and Subscribe#

Get methods are the simplest. You call them from the bridge and they return a response.

Let’s try calling get_chart_data(). This method can be used for a variety of purposes, it can:

  • Fetch price data (or any SCBaseData for that matter)

  • Fetch subgraph data from one or more studies

  • Fetch volume by price data

Let’s suppose we want to get the high and low price of the last 20 bars. In a new python shell:

>>> from trade29.sc import SCBridge
>>> from trade29.sc import constants
>>> bridge = SCBridge()
>>> price_data_to_fetch = [constants.SCBaseData.SC_HIGH, constants.SCBaseData.SC_LOW] # make a list of price data we want
>>> # we supply the get_chart_data method with the same key as the custom study
>>> ret = bridge.get_chart_data(key='helloworld', base_data=price_data_to_fetch, historical_bars=20)

You can try printing the resulting ChartDataResponse’s raw data by accessing the rdata property.

>>> print(ret.rdata)

All responses have their raw data accessible in dictionary form like this, but it is usually too messy to do much with. ChartDataResponse has a handy method as_df() that will return a much more digestible pandas DataFrame.

>>> df = ret.as_df()
>>> # pandas DataFrames are a very powerful data structure!
>>> df # print the DataFrame to the shell
             DateTime  BarIndex  IsBarClosed     High      Low
0 2024-06-06 17:33:00     20517         True  5361.25  5360.25
1 2024-06-06 17:34:00     20518         True  5361.50  5360.25
2 2024-06-06 17:35:00     20519         True  5361.25  5360.50
3 2024-06-06 17:36:00     20520         True  5362.75  5361.00
4 2024-06-06 17:37:00     20521         True  5363.50  5362.00
5 2024-06-06 17:38:00     20522         True  5363.25  5362.50
6 2024-06-06 17:39:00     20523         True  5363.25  5362.25
7 2024-06-06 17:40:00     20524         True  5362.75  5361.50
8 2024-06-06 17:41:00     20525         True  5361.75  5360.75
9 2024-06-06 17:42:00     20526        False  5361.25  5360.75

We can see we got the requested High and Low data.

This Get method is nice for pulling data for historical analysis, but lets suppose that we wanted a constant flow of current information, perhaps to implement some real time trading strategy. In this case, constantly calling get_chart_data() is unintuitive and wasteful. We only really need to get new data, but get_chart_data() just returns whatever we ask it for. So we would have to monitor when the live bar closes and time our Get requests ourselves. Instead we have the SCBridge’s Subscription methods, namely subscribe_to_chart_data(). This method is almost the exact same in functionality to its Get counterpart, but it gives new requested data whenever it’s available, dumping it to the SCBridge’s response queue. Most Get methods have a Subscription counterpart that works similarly. Here is a worked example of how to use a Subscription method in a script that fetches for the same information as we just did in the shell.

1from trade29.sc import commands, constants
2from trade29.sc import SCBridge
3
4bridge = SCBridge()
5
6# note how the parameters for the subscription version are the same as the get version
7chart_data_id = bridge.subscribe_to_chart_data(key='helloworld',
8                                               base_data=[constants.SCBaseData.SC_HIGH,
9                                                          constants.SCBaseData.SC_LOW])

We store the unique request id returned by the method. Now all new high and low price data will be sent to the bridge response queue. The response queue can be gotten with get_response_queue() and is an iterable python Queue.

10response_queue = bridge.get_response_queue()
11
12while True:
13
14    response = response_queue.get()
15
16    chart_data_df = response.as_df()
17
18    chart_data_df
19
20    # do something with chart data

The two other subscribe functions of interest are subscribe_to_time_and_sales() and subscribe_to_market_depth(). Let’s try getting time and sales data. First we would go back and add a line to also subscribe to time and sales.

 1from trade29.sc import constants
 2from trade29.sc import SCBridge
 3
 4bridge = SCBridge()
 5
 6# note how the parameters for the subscription version are the same as the get version
 7chart_data_id = bridge.subscribe_to_chart_data(key='helloworld',
 8                                               base_data=[constants.SCBaseData.SC_HIGH,
 9                                                          constants.SCBaseData.SC_LOW])
10
11tns_id = bridge.subscribe_to_time_and_sales(key='helloworld')

Now time and sales data will also be sent to the response queue. However, since both chart data and time and sales data come through the same queue, we need some way to filter the responses for the different types of responses. That’s what saving the request ids is for. Every response has the property request_id. Let’s simply print what type of data we have and the DataFrames

12response_queue = bridge.get_response_queue()
13
14while True:
15
16    response = response_queue.get()
17
18    if response.request_id == chart_data_id:
19        print('I have price data!')
20        response.as_df()
21        # if low, buy, if high, sell
22
23
24    elif response.request_id == tns_id:
25        print('I have time and sales data!')
26        response.as_df()
27        # do something with tns data

Both of the Subscription methods we used so far are incrementally updated. By looking at the printout, we can see that the first response includes a big dump of historical data, and subsequent responses return all historical information since the last response.

Now lets try out a SCBridge method that just gives snapshots: subscribe_to_market_depth(). Let’s remove the other subscriptions so we can more clearly see what’s going on.

 1from trade29.sc import constants
 2from trade29.sc import SCBridge
 3
 4bridge = SCBridge()
 5
 6market_depth_id = bridge.subscribe_to_market_depth(key='helloworld', include_pulling_stacking=True)
 7
 8response_queue = bridge.get_response_queue()
 9
10while True:
11
12    response = response_queue.get()
13
14    if response.request_id == market_depth_id:
15        print('I have market depth data!')
16        response.as_df()

We added a subscription for market depth, and told it to include data on pulling-stacking. Then we simply print out the DataFrame. Running the script, you can see now that each response only includes a snapshot of a single moment in time, as opposed to the incremental historical records of the previous examples.

Getting Subgraph Data#

The get_chart_data() and subscribe_to_chart_data() methods can get alot more than just price data through their parameters. They can even get subgraph data! In the chart you are working with, add a study. I added Bollinger Bands. Note how in the study window each study has an ID. In my case the Bollinger Bands study is ID 2.

../_images/figure1.png

Now note how in the Study Settings window under the Subgraphs tab each subgraph has an ID. In the Bollinger Bands study the lower band is ID 3.

../_images/figure2.png

Now that we know the IDs we want to fetch, in a new Python shell:

>>> from trade29.sc import SCBridge, SubgraphQuery
>>> from trade29.sc import constants
>>> bridge = SCBridge()
>>> # get_chart_data wants a list of SubgraphQuery
>>> sg_to_fetch = [SubgraphQuery(study_id=2, subgraphs=[3])]
>>> ret = bridge.get_chart_data(key='helloworld', sg_data=sg_to_fetch)
>>> ret.as_df()
             DateTime  BarIndex  IsBarClosed  ID2.SG3
0 2024-06-06 17:52:00     19156         True  5359.02
1 2024-06-06 17:53:00     19157         True  5359.00
2 2024-06-06 17:54:00     19158         True  5358.75
3 2024-06-06 17:55:00     19159         True  5358.45
4 2024-06-06 17:56:00     19160         True  5358.45
5 2024-06-06 17:57:00     19161         True  5358.51
6 2024-06-06 17:58:00     19162         True  5358.82
7 2024-06-06 17:59:00     19163         True  5359.07
8 2024-06-06 18:00:00     19164         True  5359.28
9 2024-06-06 18:01:00     19165        False  5359.57

We can now see a column in the DataFrame for the lower band.

The constructor for SubgraphQuery takes a list of integers for its subgraphs parameter. This makes it very easy to fetch more than one subgraph of interest:

>>> sg_to_fetch = [SubgraphQuery(study_id=2, subgraphs=range(1, 4))]
>>> ret = bridge.get_chart_data(key='helloworld', sg_data=sg_to_fetch)
>>> ret.as_df()
             DateTime  BarIndex  IsBarClosed  ID2.SG1  ID2.SG2  ID2.SG3
0 2024-06-06 17:52:00     19156         True  5361.43  5360.23  5359.02
1 2024-06-06 17:53:00     19157         True  5361.55  5360.28  5359.00
2 2024-06-06 17:54:00     19158         True  5362.02  5360.38  5358.75
3 2024-06-06 17:55:00     19159         True  5362.60  5360.52  5358.45
4 2024-06-06 17:56:00     19160         True  5362.70  5360.57  5358.45
5 2024-06-06 17:57:00     19161         True  5362.76  5360.63  5358.51
6 2024-06-06 17:58:00     19162         True  5362.70  5360.76  5358.82
7 2024-06-06 17:59:00     19163         True  5362.63  5360.85  5359.07
8 2024-06-06 18:00:00     19164         True  5362.61  5360.94  5359.28
9 2024-06-06 18:01:00     19165        False  5362.50  5361.03  5359.57

Note how the sg_data parameter of get_chart_data() is a list too, so it is very easy to fetch more than one subgraph at a time. Add a new study to the chart. I added a Simple Moving Average; its ID is 3 and it has one subgraph with ID 1. In the shell same as last time, but adding a new SubgraphQuery to the list:

>>> sg_to_fetch = [SubgraphQuery(study_id=2, subgraphs=range(1, 4)),
>>>                SubgraphQuery(study_id=3, subgraphs=[1])]
>>> ret = bridge.get_chart_data(key='helloworld', sg_data=sg_to_fetch)
>>> ret.as_df()
             DateTime  BarIndex  IsBarClosed  ID2.SG1  ID2.SG2  ID2.SG3  ID3.SG1
0 2024-06-06 17:52:00     19156         True  5361.43  5360.23  5359.02  5360.23
1 2024-06-06 17:53:00     19157         True  5361.55  5360.28  5359.00  5360.33
2 2024-06-06 17:54:00     19158         True  5362.02  5360.38  5358.75  5360.45
3 2024-06-06 17:55:00     19159         True  5362.60  5360.52  5358.45  5360.63
4 2024-06-06 17:56:00     19160         True  5362.70  5360.57  5358.45  5360.63
5 2024-06-06 17:57:00     19161         True  5362.76  5360.63  5358.51  5360.73
6 2024-06-06 17:58:00     19162         True  5362.70  5360.76  5358.82  5360.83
7 2024-06-06 17:59:00     19163         True  5362.63  5360.85  5359.07  5360.92
8 2024-06-06 18:00:00     19164         True  5362.61  5360.94  5359.28  5361.02
9 2024-06-06 18:01:00     19165        False  5362.50  5361.03  5359.57  5361.08

Fetching Volume by Price#

get_chart_data() can also fetch volume by price data. In a Python shell:

>>> from trade29.sc import SCBridge
>>> bridge = SCBridge()
>>> ret = bridge.get_chart_data(key='helloworld', include_volume_by_price=True)
>>> ret.as_df()
             DateTime  BarIndex  IsBarClosed                                      VolumeByPrice
0 2024-06-06 17:52:00     19156         True       Price  AskVol  BidVol  TotalVolume  NumOf...
1 2024-06-06 17:53:00     19157         True       Price  AskVol  BidVol  TotalVolume  NumOf...
2 2024-06-06 17:54:00     19158         True       Price  AskVol  BidVol  TotalVolume  NumOf...
3 2024-06-06 17:55:00     19159         True       Price  AskVol  BidVol  TotalVolume  NumOf...
4 2024-06-06 17:56:00     19160         True       Price  AskVol  BidVol  TotalVolume  NumOf...
5 2024-06-06 17:57:00     19161         True       Price  AskVol  BidVol  TotalVolume  NumOf...
6 2024-06-06 17:58:00     19162         True       Price  AskVol  BidVol  TotalVolume  NumOf...
7 2024-06-06 17:59:00     19163         True       Price  AskVol  BidVol  TotalVolume  NumOf...
8 2024-06-06 18:00:00     19164         True       Price  AskVol  BidVol  TotalVolume  NumOf...
9 2024-06-06 18:01:00     19165        False       Price  AskVol  BidVol  TotalVolume  NumOf...
# volume by price is its own DataFrame, print out the most recent one:
>>> ret['VolumeByPrice'][9]
     Price  AskVol  BidVol  TotalVolume  NumOfTrades
0  5360.00       0       5            5            4
1  5360.25      65      64          129           95
2  5360.50      44     138          182          111
3  5360.75      66      72          138           98
4  5361.00      11      33           44           33
5  5361.25       2       0            2            2