App tokens and market data
Describes stx-python 0.8.0, the current release.
An app token is your app acting as itself: no member, no sign-in, no consent screen. It reads the market and event catalog and streams the market data channels, which is how an app shows markets and prices to people who have not connected an STX account. It comes from the client_credentials grant, so it needs a client secret (a Web app or Server-to-server app). See App tokens for the protocol.
App tokens need an exchange that offers them; What you can do lists which do. In Ontario an app reads public market data only, with the market_data and events scopes.
An app client
Section titled “An app client”from stx import oauth
app = oauth.OAuthClient.discover( client_id="stxapp_client_g2XU2Kyg3EJoOhC9sndPe2bPvZENsbkkFkzCQFgkWHa0emOUt", client_secret=CLIENT_SECRET, region="us", env="demo",)
with app.app_client("market_data events") as catalog: for market in catalog.markets(status="open", trading=True, limit=3): print(market.symbol, market.title)Sample output:
STXMLB-26OCT182000LADMIL-GAMELAD MLB Playoff LAD @ MILSTXMLB-26OCT182000LADMIL-GAMEMIL MLB Playoff LAD @ MILSTXMLB-26OCT192000LADMIL-GAMELAD MLB Playoff LAD @ MILapp_client(scope) returns an STX client whose requests carry an app token. The SDK mints the token on first use, keeps it until 60 seconds before it expires, mints a new one then, and once more if the exchange answers 401. Every client built for the same scope shares one token. The token request and its answer look like this:
tokens = app.client_credentials("market_data events")print(tokens.scope, tokens.token_type, tokens.expires_in, tokens.refresh_token)market_data events bearer 3600 NoneAn app token has no refresh token: the SDK simply mints another.
What an app token can call
Section titled “What an app token can call”| Scope | Calls |
|---|---|
market_data |
markets(), iter_markets(), market(), and the market data channels: orderbook, ticker, trades, markets, market_stats, market_updates, market |
events |
events(), iter_events(), event_players(), market_types() |
markets.write |
create_markets(), granted by STX on request. See Create markets |
Member calls (balance(), place_order()…) are refused with STXForbiddenException: an app token has no member. A scope your app does not hold is refused with oauth.STXOAuthException (invalid_scope), and a scope the exchange does not offer at all with STXNotAvailableError (scope:<name>).
Stream market data
Section titled “Stream market data”With oauth.AsyncOAuthClient, the app client’s socket streams the market data channels with the app token:
import asyncio
from stx import oauth
async def main(): app = await oauth.AsyncOAuthClient.discover( client_id=CLIENT_ID, client_secret=CLIENT_SECRET, region="us", env="demo" ) async with app, app.app_client("market_data") as catalog: page = await catalog.markets(status="open", trading=True, limit=1) async with catalog.websocket() as ws: channel = await ws.market(page.items[0].market_id) market = (await channel.wait_snapshot())["reply"] print(market["symbol"], market["last_traded_price"], market["max_price"], market["event_brief"]) await ws.ticker(on_message=lambda msg: print(msg.event, msg.payload)) await ws.run_forever()
asyncio.run(main())Sample output:
STXMLB-26OCT182000LADMIL-GAMELAD 0.4000 1.0000 Oct 18 at 08:00 PM EDTws.market(market_id) is one market in full: the join reply is every market field plus ob, its aggregated book, then market_update carries the fields that change and order_book_update a fresh book about every 200 ms. Prices are dollar strings, as everywhere in the SDK. The socket mints a fresh app token on every reconnect. Every channel is in WebSockets.
A token you already have
Section titled “A token you already have”An access token from anywhere (your own OAuth code, another service) can be used directly, without refresh:
from stx import STX
with STX(region="us", env="demo", access_token=token) as client: print(client.markets(limit=1).items[0].symbol)
