Get quote/tick data

Are there any existing examples on how to pull quote data?

What exactly do you mean by pull quote data? Like set up a socket to receive live quote or replay quote data?

Yes, I am using C# and the demo provided has been very helpful. However, I have used other platforms in testing and it was very obvious how to get quote data. I cannot seem to find it here. Also, if they cap it, as I have read, it is probably a waste of time since I pull 1 million+ quotes a day with other brokers and they have no limitations.

I am not very familiar with c# but here is simplified way of doing it in TypeScript. Also here is a short write up from the Tradovate docs on the parameters for getChart that start a tick stream. The Tradovate javascript tutorial shows a way to get tick data too. You can reference these FAQ responses on limits: 1. Limit Requests and Data and 2. Data Size Limits.

It does not sound like there are hard limits.

import WebSocket, {MessageEvent, Data } from 'ws'

// Type for data received by Tick subscription
export type TickPacket = {
    id: number // Subscription ID, the same as historical/real-time subscription IDs from request response.
    eoh?: boolean // End-of-history used in historical data loads indicates that historical ticks are loaded and further packets will contain real-time ticks
    s: string // Source of packet data.
    td: string // Trade date YYYYMMDD.
    bp: number // Base price of the packet (integer number of contract tick sizes). Tick prices are calculated as relative from this one.
    bt: number // Base timestamp of the packet. Tick timestamps are calculated as relative from this value.
    ts: number // Tick size of the contract for which the tick chart is requested.
    tks: TickRaw[]
}

export type TickRaw = {
    id: number // Tick ID
    t: number // Tick relative timestamp. Actual tick timestamp is packet.bt + tick.t
    p: number // Tick relative price (in contract tick sizes). Actual tick price is packet.bp + tick.p
    s: number // Tick size (seems more proper name should be tick volume). Please don't confuse with contract tick size (packet.ts).
    b: number // Bid relative price (optional). Actual bid price is packet.bp + tick.b
    a: number // Ask relative price (optional).Actual ask price is packet.bp + tick.a
    bs: number // Bid size (optional).
    as: number // Ask size (optional).
}
// Id counter be passed every socket request
let requestId = 0

// the id to pass to md/cancelchart when done with tick stream
let cancelId: number

// reference to heartbeat interval to cancel interval when done with code.
let heartbeatInterval: NodeJS.Timer

// Receive an auth token
const token = getAccessToken() // I assume you have this logic

//Helper function to check if marketData Socket is connected
const isConnected = () => {
        return  marketDataSocket  && 
                marketDataSocket.readyState !== 0 && 
                marketDataSocket.readyState !== 2 && 
                marketDataSocket.readyState !== 3 && 
                marketDataSocket.readyState !== undefined
    }

//Heartbeat logic to be passed in to setInterval
const sendHeartbeat = () => {
    if (!isConnected()) {
        clearInterval(heartbeatInterval)
        return
    }
    marketDataSocket.send('[]')
}

// Helper function for parsing socket data
const prepareMessage = (raw: Data) => {
        const T = raw.slice(0, 1)
        let data = []
        if ((raw as string).length > 1) {
            data = JSON.parse((raw as string).slice(1))
        }
        return {T, data}
    }

// Once marketDataSocket is connected it will emit an 'o' open frame.
// On open frame connect with auth token and start heartbeat.
const onConnect = async (msg: MessageEvent) => {
    const {T} = prepareMessage(msg.data)
    if (T === 'o') {
        await marketDataSocket.send(`authorize\n${requestId}\n\n${token}`)   
        requestId++
        console.log('[MarketData]: connected.')
        
        marketDataSocket.removeEventListener('message', onConnect)
        heartbeatInterval = setInterval(sendHeartbeat, 2500)
    }
}

// Attach onConnect event listener to socket
marketDataSocket.addEventListener('message', onConnect)
// connect to market data web socket endpoint
const marketDataSocket  = new WebSocket('wss://md.tradovateapi.com/v1/websocket')

// Params for tick stream on ESU2023
const tickChartParams = {
   symbol: 'ESU3',
   chartDescription: {
       underlyingType: 'Tick',// Available values: Tick, DailyBar, MinuteBar, Custom, DOM
       elementSize: 1,
       elementSizeUnit: 'UnderlyingUnits', // Available values: Volume, Range, UnderlyingUnits, Renko, MomentumRange, PointAndFigure, OFARange
       withHistogram: false,
    },
    timeRange: {
        asMuchAsElements: 2
     }
}

// Tick event handler
const onTickData = (msg: MessageEvent) => {
    const {T, data} = prepareMessage(msg.data)
    if (T === 'a' && data && data.length > 0) {
        data.forEach((item: any) => {
             // initial response from getChart Request 
             // type guard for chart data, normally you wouldn't hard code 1 as id
             if(item.s === 200 && item.i  === 1){
                 cancelId = item.d.realtimeId
             }
             if(item.d && item.d.charts) {
                 item.d.charts.forEach((chart: TickPacket) => {
                     // manipulate data
                     console.log(chart)
                 })
             }
        })

    }
}

marketDataSocket.addEventListener('message', onTickData)
// request id updated to 1 
marketDataSocket.send(`md/getchart\n${requestId}\n\n${tickChartParams}`)
requestId++   


const cancelTickSubscription = () => { 
    const cancelBody = {subscriptionId: cancelId}
    marketDataSocket.send(`md/cancelchart\n${requestId}\n\n${cancelBody}`)
    clearInterval(heartbeatInterval)
}

// After 30 seconds cancel tick subscription and clear interval
setTimeout(()=>{
     cancelTickSubscription()
}, 30*1000)

The main issue with the above code is how the requestId counter is handled.

1 Like