Replay Sessions Q&A

I had a conversation with @Rob_Hoskins about replay sessions that deserves a topic. Rob had asked me about a bug he had found, but the more important part of the conversation followed:

Q:

A: Yes it’s completely possible, check out this section of the API docs:
https://api.tradovate.com/#section/Request-Examples/Market-Replay
You’ll want to use it with a websocket, so use the wss://replay.tradovateapi.com/v1/websocket address.

Q:

A: That’s correct, the API is split into domains based on the function you’re looking to utilize. You would gain access using the typical https://demo... or https://live... URLs and use the wss://replay... URL with a websocket for replay related calls. As for market data, that’s a lot of what replay is all about. Using a websocket that has been configured for a replay session (by using the replay wss URL and initializing the clock using the replay/initializeClock endpoint), you send a market data request just like you would with a websocket looking at the md endpoint md/subscribeQuote or md/subscribeDOM etc.

Q:

A: In order to use the pre-made socket classes I built you’ll need to do some re-configuring. The gist is that you’ll use the replay URL in a websocket to make an md/subscribeQuote call.

It may work if you just change the MarketDataSocket’s URL to the replay URL instead of the market data URL, given that you’re not already using that implementation. If you are actively using the md socket for something else then you could always just extend the TradovateSocket again. Basically you’d copy paste all the market data socket’s implementation and change the base URL to the replay URL.

Q:

A: Yes, technically each time you call initializeClock you set a new session for your user. That session is unique to your user, so its the same session when you see it from the UI and the API. Until you call initializeClock again, you’ll have the same session on both UI and API.

Q:

A: The replay session is reset every time you call initializeClock, so you can’t save old sessions, but you could keep track of the parameters you used and re-run them. And the time-horizon entitlements come into play - you need to purchase more history if you want to go way back in time, or replay a large amount of time.

Please feel free to add any other Replay related questions to this thread!

Hello everyone.

After we initialize a market replay via replay/initializeclock endpoint, the api documentation says:

" To maintain the clock synchronization between the server-side ‘replay’ clock and client one, the server pushes periodical clock synch event messages like that:

a[{"e":"clock","d":"{\"t\":\"2019-08-26T16:43:08.599Z\",\"s\":20}"}]

d field contains a text representation of JSON entity with the next fields:

  • t : the current replay timestamp
  • s : the current replay speed "

How exactly can we listen to this event message?

Thanks.

You have to use a WebSocket for market replay. It comes through the WebSocket like any other message. I typically use it with the API to determine whether or not I’ve reached the end of a backtesting period, or to see if my replay speed has changed to 0 (after a long replay session you may need to do this). The a is the frame type which means it has an array of data. So usually I’ll split the data portion of the message:

const mySocket = new WebSocket('wss://replay.tradovateapi.com/v1/websocket')

mySocket.onmessage = msg => {
    const [T, data] = prepareMsg(msg.data)
    switch(T) {
        case 'a': {
            handleAFrame(data)
            break
        }
    }
}

function handleAFrame(data) {
    if(data.e && data.e === 'clock') {
        const { t, s } = data.d
        //compare timestamp t to backtest end timestamp
        //check speed s against 0 or a set replay speed
    }
}

function prepareMsg(rawData) {
    const type = rawData.slice(0,1)
    const data = JSON.parse(rawData.slice(1))
    return [type, data]
}
1 Like

The current provided implimentation of the TradovateSocket (example-api-js/TradovateSocket.js at main · tradovate/example-api-js · GitHub) does not match contractID’s when you subscribe to a quote with an @ at the start, as the subscribe method only resolves the contractID for the symbol if it does not start with @:

const realtimeId = response?.d?.realtimeId || response?.d?.subscriptionId;
	if (body?.symbol && !body.symbol.startsWith('@')) {
		const contractRes = await tvGet('/contract/find', { name: body.symbol });
		contractId = contractRes?.id || null;
		if (!contractId) {
			contractId = await tvGet('/contract/suggest', { name: body.symbol })[0].id;
		}
	}

Any advice on how to use @based symbols, and correctly match up the data coming back from the socket (it only returns contractID, not symbol)

Not sure if this is completely related to the above discussions. But as the topic title was pretty generic I thought it was a good place to drop this question.

I just started messing around with the API. In going through the 3 part tutorial I ran across something with replay that I’m not understanding. I took the priceDisplay strategy and simply added a field that outputs the timestamp value in addition to the contract and price. When I ran the code, I noticed that it never seems to stop running. The timestamps confirm that I’m seeing ticks from outside the window for the replay. So, what’s going on? Is the window acting only as a “start” time and the end is ignored? Is it something in the config options I’m not understanding (side note: an explanation of what exactly each of the parameters in the examples represents/controls would be greatly appreciated)? Anywhere in particular I should be looking?

TIA

Try adding this to the strategy’s next function in the switch statement. You can import onReplayComplete from ../common/onReplayComplete

switch(event) {
//...
    case TdEvent.ReplayComplete: {
        return onReplayComplete(prevState, payload)
    }

    default: {
        return this.catchReplaySessionsDefault(prevState, [event, payload]) || { 
            state: prevState,
                effects: [
                    { event: 'displayPrice/draw' }
                ]
            }       
    }
}

If it catches a replay session or if the replay session is over it should react.

Ahhh, OK. So, the replay session starts at the specified point in time and then runs. It eventually sends an ReplyComplete event when the end time is reached. But if the code doesn’t look for that it will just run indefinitely?

thanks!

Yes, if you don’t set it up for backtesting it won’t recognize when to restart the time frames.

Great. Thanks… Now I’m trying to run the same example with MinuteBars instead of Ticks (leaving all other inputs the same). But all I get are undefined values back. Any ideas?

Is there any reason a replay session should end after 4 hrs (even if it’s set to run longer than that)? I’m using minute bars if it matters…

Is it dropping your connection or is it changing your replay session to have an 's' value of 0? You’ll see when the server responds with 'clock' type events from the Replay Socket some JSON that looks like this { "s": 400, "t": "2022-04-25Z..." }

I’m not certain. I’ll have to try and add some logging. I’m using the example-api-trading-strategy code and some other code I was provided. Neither errors out or provides any other feedback. The code seems to keep running, I’m just not (apparently) receiving additional quote/price data.