Basics#
A series of simple examples are provided showing how to retrieve, filter, aggregate and join datasets, using OneTick Cloud sample databases.
Directed Graphs & Chains#
Directed Graphs and Chains are constructed from a series of nodes.
Nodes are python objects accessed through the onetick.query_webapi
library.
A Chain is a simple linkage between nodes. Chains can be reused to build graphs.
A Directed Graph can be more than a Chain supporting joining and branching.
In both cases, nodes can be linked with the >>
syntax.
def trades():
# Defined Nodes
pt = otq.Passthrough().tick_type('TRD')
a = otq.AddField(field='VALUE',value='PRICE*SIZE')
w = otq.WhereClause(where='SIZE > 1')
# Link Nodes as a Chain
chain = otq.Chainlet(pt,a,w)
# Create Graph from the Chain
graph = otq.Graph(chain)
return graph
def trades():
# Defined Nodes
pt = otq.Passthrough().tick_type('TRD')
a = otq.AddField(field='VALUE',value='PRICE*SIZE')
w = otq.WhereClause(where='SIZE > 1')
# Link Nodes as a Directed Graph
graph = otq.Graph(pt >> a >> w)
return graph
Data Retrieval#
Directed Graphs are executed using the run
method, passing in the server location, access token, and retrieval details.
An access token is generated using the get_access_token
method.
http_address = "https://rest.cloud.onetick.com"
access_token_url = "https://cloud-auth.parent.onetick.com/realms/OMD/protocol/openid-connect/token"
# Replace [client id] and [client_secret] with values retrieved from your profile
client_id = "[client_id]"
client_secret = "[client_secret]"
access_token = otq.get_access_token(access_token_url, client_id, client_secret)
result = otq.run(query,
http_address=rest_url,access_token=access_token,
output_mode="pandas",
start=datetime(2024,1,3,9,30,0),
end = datetime(2024,1,3,9,31,0),
timezone='America/New_York',
symbols='US_COMP_SAMPLE::CSCO'
)
Data can be retrieved by selecting.
Database
Table (tick_type).
Symbol or Symbols
Time Range
All four must be provided for results to be retrieved. Typically the directed graph includes the reference to the table to be retrieved,
while the otq.run
method is used to specify the database, symbol, and time range, along with the http_address
and access_token
.
def trades():
pt = otq.Passthrough().tick_type('TRD')
graph = otq.Graph(pt)
return graph
result = otq.run(trades,
http_address=rest_url,access_token=access_token,
output_mode="pandas",
start=datetime(2024,1,3,9,30,0),
end = datetime(2024,1,3,9,31,0),
timezone='America/New_York',
symbols='US_COMP_SAMPLE::CSCO' # Specifies the [Database]::[Symbol]
)
Sample Databases & Tables#
The full list of 200+ Global Equities, Futures, Options & Indices databases is available in OneTick Cloud
The list of sample databases are additionally included below:
Database |
Description |
Available Tables |
---|---|---|
CA_COMP_SAMPLE |
Consolidated Trades & Quotes Across All Canadian Venues |
QTE, NBBO, STAT, TRD |
CA_COMP_SAMPLE_BARS |
Consolidated Canadian Trade & Quote 1 Minute Bars |
QTE_1M, TRD_1M |
EU_COMP_SAMPLE |
Consolidated Trades & Quotes Across All European Venues |
QTE, STAT, TRD |
EU_COMP_SAMPLE_BARS |
Consolidated European Trade & Quote 1 Minute Bars |
QTE_1M, TRD_1M |
LSE_SAMPLE |
London Stock Exchange Trades, Quotes & Book Depth |
DAY, IND, MKT, PRL_FULL, QTE, STAT, TRD |
LSE_SAMPLE_BARS |
LSE Trade & Quote 1 Minute Bars |
QTE_1M, TRD_1M, DAY |
TDI_FUT_SAMPLE |
Global Futures Trades & Quotes |
QTE, STAT, TRD |
TDI_FUT_SAMPLE_BARS |
Global Futures Trades & Quote 1 Minute Bars |
QTE_1M, TRD_1M |
US_COMP_SAMPLE |
Consolidated Trades & Quotes Across All US Venues |
QTE, STAT, TRD |
SYMBOL_UNIVERSE |
Symbol Universe across all available Venues |
STAT |
OQD_MKT_CAL |
Market Holidays & Trading Hours |
MKTCAL |
Data is stored in standardized tables
Table |
Description |
---|---|
DAY |
End of Day Record typically covering Closing Price & Open Interest for Derivatives Markets |
IND |
Indicative Prices occuring during Auction phases |
QTE |
Quote Events |
STAT |
Static Reference Data for the Instrument |
TRD |
Trade Events |
NBBO |
National Best Bid & Offer Quotes |
PRL |
Book Depth - Market By Level |
PRL_FULL |
Book Depth - Market by Order |
MKTCAL |
Market Holiday & Trading Hours |
TRD_1M |
1 Minute Trade Bar |
QTE_1M |
1 Minute Quote Bar |
Retrieving a Single Symbol#
A Symbol can be retrieved through passing a string value to the otq.run
symbols
property.
result = otq.run(query,
http_address=rest_url,access_token=access_token,
output_mode="pandas",
start=datetime(2024,1,3,9,30,0),
end = datetime(2024,1,3,9,31,0),
timezone='America/New_York',
symbols=['US_COMP_SAMPLE::CSCO']
)
Retrieving Multiple Symbols#
Multiple symbols can be retrieved through passing in a list of symbols into the otq.run
symbols
property.
result = otq.run(query,
http_address=rest_url,access_token=access_token,
output_mode="pandas",
start=datetime(2024,1,3,9,30,0),
end = datetime(2024,1,3,9,31,0),
timezone='America/New_York',
symbols=['US_COMP_SAMPLE::CSCO','US_COMP_SAMPLE::MSFT']
)
A dictionary of Pandas dataframes will be returned. One for each symbol specified in the input list.
Defining the Database in the Graph#
The Database can be prefixed in the graph, allowing shorter symbol names. The tick_type
is set to the Database and Table. (e.g. [database]::[table]
.
def trades():
pt = otq.Passthrough().tick_type('US_COMP_SAMPLE::TRD')
graph = otq.Graph(pt)
return graph
result = otq.run(trades,
http_address=rest_url,access_token=access_token,
output_mode="pandas",
start=datetime(2024,1,3,9,30,0),
end = datetime(2024,1,3,9,31,0),
timezone='America/New_York',
symbols=['CSCO','MSFT']
)
Producing a single output dataset across Symbols#
A single Pandas dataframe can be generated by binding symbols to a Merge
object in the Directed Graph.
Nodes before the Merge
are run per symbol, while nodes after performed across symbols. The single output is sorted by Timestamp.
In this case the symbols
attribute of the run
method should not be specified or set to None
.
def trades():
pt = otq.Passthrough().tick_type('US_COMP_SAMPLE::TRD')
merge = otq.Merge().symbols(['CSCO','MSFT'])
graph = otq.Graph(pt >> merge)
return graph
result = otq.run(trades,
http_address=http_address,
access_token=access_token,
output_mode="pandas",
start=datetime(2024,1,3,9,30,0),
end = datetime(2024,1,3,9,40,0),
timezone='America/New_York',
symbols=None
)
Retrieving All Fields#
A directed graph uses the otq.Passthrough
object. The tick_type attribute is specified to retrieve records from the selected table.
def trades():
pt = otq.Passthrough().tick_type('TRD')
graph = otq.Graph(pt)
return graph
Retrieving Specific Fields#
Specific Fields can be retrieved by specifying the fields
attribute of the Passthrough node in the directed graph.
def trades():
pt = otq.Passthrough(fields='PRICE,SIZE').tick_type('TRD')
graph = otq.Graph(pt)
return graph
Adding Calculated Fields#
Additional fields can be added through the AddField node in the directed graph.
Multiple nodes in a graph can be chained together with >>
. e.g. pt >> add_value
def trades():
pt = otq.Passthrough(fields='PRICE,SIZE').tick_type('TRD')
add_value = otq.AddField(field='TRADED_VALUE',value='PRICE*SIZE')
graph = otq.Graph(pt >> add_value)
return graph
Adding Filters#
Results can be filtered through a WhereClause node in the directed graph.
def trades():
pt = otq.Passthrough(fields='PRICE,SIZE,EXCHANGE').tick_type('TRD')
add_value = otq.AddField(field='TRADED_VALUE',value='PRICE*SIZE')
filter_on = otq.WhereClause(where='EXCHANGE="N" and SIZE > 100')
graph = otq.Graph(pt >> add_value >> filter_on)
return graph
By default the filter is applied, and only matches to the filter are returned. If non-matches are required the attribute discard_on_match
can be set to True
.
def trades():
pt = otq.Passthrough(fields='PRICE,SIZE,EXCHANGE').tick_type('TRD')
add_value = otq.AddField(field='TRADED_VALUE',value='PRICE*SIZE')
filter_out = otq.WhereClause(discard_on_match=True,where='EXCHANGE="N" and SIZE > 100')
graph = otq.Graph(pt >> add_value >> filter_out)
return graph
Aggregating Across Results#
Results can be aggregated by specifying an a dictionary of aggregation methods using ComputeFields
, and then applying them in the Compute
object along with the desired grouping, bucket period and method.
def agg_stats():
trd_in= otq.Passthrough(fields='PRICE,SIZE').tick_type('TRD')
comp_fields = otq.ComputeFields({
mean_price':otq.Average(In='PRICE'),
stddev_price':otq.Stddev(In='PRICE'),
median_price':otq.Median(In='PRICE'),
max_price':otq.Max(In='PRICE'),
min_price':otq.Min(In='PRICE'),
twa_price':otq.TwAverage(In='PRICE'),
vwap_price':otq.Vwap(price_field_name='PRICE',size_field_name='SIZE'),
count_price':otq.Count()
})
comp = otq.Compute(compute=comp_fields,append_output_field_name=False)
graph = otq.Graph(trd_in >> comp)
return graph
Additionally results can be grouped by adding the group_by
attribute to the Compute
object.
def agg_stats():
trd_in= otq.Passthrough(fields='PRICE,SIZE').tick_type('TRD')
comp_fields = otq.ComputeFields({
mean_price':otq.Average(In='PRICE'),
stddev_price':otq.Stddev(In='PRICE'),
median_price':otq.Median(In='PRICE'),
max_price':otq.Max(In='PRICE'),
min_price':otq.Min(In='PRICE'),
twa_price':otq.TwAverage(In='PRICE'),
vwap_price':otq.Vwap(price_field_name='PRICE',size_field_name='SIZE'),
count_price':otq.Count()
})
comp = otq.Compute(compute=comp_fields,group_by='EXCHANGE',append_output_field_name=False)
graph = otq.Graph(trd_in >> comp)
return graph
And results can be grouped by time period the bucket_interval
attribute to the Compute
object.
def agg_stats():
trd_in= otq.Passthrough(fields='PRICE,SIZE').tick_type('TRD')
comp_fields = otq.ComputeFields({
mean_price':otq.Average(In='PRICE'),
stddev_price':otq.Stddev(In='PRICE'),
median_price':otq.Median(In='PRICE'),
max_price':otq.Max(In='PRICE'),
min_price':otq.Min(In='PRICE'),
twa_price':otq.TwAverage(In='PRICE'),
vwap_price':otq.Vwap(price_field_name='PRICE',size_field_name='SIZE'),
count_price':otq.Count()
})
comp = otq.Compute(compute=comp_fields,bucket_interval=60,append_output_field_name=False)
graph = otq.Graph(trd_in >> comp)
return graph
Limiting Results#
Results can be limited by adding the Limit
object to the graph.
def trades():
pt = otq.Passthrough(fields='PRICE,SIZE,EXCHANGE').tick_type('TRD')
first_n = otq.Limit(tick_limit=1000)
graph = otq.Graph(pt >> first_n)
return graph
Logic Re-use#
Chainlets can be used to store common directed graph patterns. Both Chainlets and Graphs can be made of multiple input chainlets.
def retrieve_quotes_part1():
qte = otq.Passthrough(fields="BID_PRICE,ASK_PRICE,BID_SIZE,ASK_SIZE").set_tick_types(['QTE'])
mid = otq.AddField(field="MID_PRICE",value="(BID_PRICE + ASK_PRICE)/2")
chain = otq.Chainlet(qte,mid)
return chain
def retrieve_quotes_part2():
spread = otq.AddField(field="SPREAD",value="ASK_PRICE-BID_PRICE")
qte_output = otq.Passthrough()
qte_output.set_node_name('qte')
chain = otq.Chainlet(spread,qte_output)
return chain
def retrieve_quotes():
# Creating a new chainlet from two input chains
chain = otq.Chainlet(retrieve_quotes_part1(),retrieve_quotes_part2())
return chain
def retrieve_trades():
trd = otq.Passthrough(fields="PRICE,SIZE").set_tick_types(['TRD'])
tradedvalue = otq.AddField(field="VALUE",value="PRICE*SIZE")
trd_output = otq.Passthrough()
trd_output.set_node_name('trd')
chain = otq.Chainlet(trd,tradedvalue,trd_output)
return chain
def retrieve_enriched_trades():
# Building Directed Graph Nodes from pre-defined Chainlets
qte_output = retrieve_quotes()
trd_output = retrieve_trades()
jbt = otq.JoinByTime(leading_sources='qte',add_source_prefix=False)
out = otq.Passthrough(fields="trd.TIMESTAMP,qte.TIMESTAMP",drop_fields=True)
# Defining the Graph by linking nodes together
trd_output >> jbt
qte_output >> jbt
jbt >> out
# Output the Graph object
graph = otq.Graph(out)
return graph