Skip to content

Commit

Permalink
Feat/STRUCT-2627 tiingo iex update (#3635)
Browse files Browse the repository at this point in the history
* STRUCT-2627 update tiingo iex transport with new payload

* add changeset
  • Loading branch information
mmcallister-cll authored Jan 14, 2025
1 parent 0bede17 commit da65fb1
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 127 deletions.
5 changes: 5 additions & 0 deletions .changeset/light-maps-scream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@chainlink/tiingo-adapter': minor
---

Update IEX endpoint with new payload
70 changes: 21 additions & 49 deletions packages/sources/tiingo/src/transport/iex-ws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,7 @@ import { TiingoWebsocketTransport } from './utils'
interface Message {
service: string
messageType: string
data: [
string,
string,
number,
string,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
]
}

const dateIndex = 1
const tickerIndex = 3

const priceIndexMap = {
lastTrade: 9,
quote: 6,
}

const updateTypeMap = {
lastTrade: 'T',
quote: 'Q',
data: [string, string, number]
}

type WsTransportTypes = BaseEndpointTypes & {
Expand All @@ -44,10 +14,14 @@ type WsTransportTypes = BaseEndpointTypes & {
}
}

const dateIndex = 0
const tickerIndex = 1
const priceIndex = 2

/*
Tiingo EA currently does not receive asset prices during off-market hours. When a heartbeat message is received during these hours,
we update the TTL of cache entries that EA is requested to provide a price during off-market hours.
*/
*/
const updateTTL = async (transport: WebSocketTransport<WsTransportTypes>, ttl: number) => {
const params = await transport.subscriptionSet.getAll()
transport.responseCache.writeTTL(transport.name, params, ttl)
Expand All @@ -69,32 +43,24 @@ export const wsTransport: TiingoWebsocketTransport<WsTransportTypes> =
return []
}

const updateType = message.data[0]
// Expects Last Trade (T) or Quote (Q) messages
if (
!message?.data?.length ||
message.messageType !== 'A' ||
(updateType !== updateTypeMap.lastTrade && updateType !== updateTypeMap.quote)
) {
if (!message?.data?.length || message.messageType !== 'A') {
return []
}

let result: number
if (updateType === updateTypeMap.lastTrade) {
result = message.data[priceIndexMap.lastTrade] as number
} else {
result = message.data[priceIndexMap.quote] as number
}
const dateString = message.data[dateIndex]
const ticker = message.data[tickerIndex]
const result = message.data[priceIndex]

return [
{
params: { base: message.data[tickerIndex] },
params: { base: ticker },
response: {
data: {
result,
},
result,
timestamps: {
providerIndicatedTimeUnixMs: new Date(message.data[dateIndex]).getTime(),
providerIndicatedTimeUnixMs: new Date(dateString).getTime(),
},
},
},
Expand All @@ -107,14 +73,20 @@ export const wsTransport: TiingoWebsocketTransport<WsTransportTypes> =
return {
eventName: 'subscribe',
authorization: wsTransport.apiKey,
eventData: { thresholdLevel: 5, tickers: [params.base] },
eventData: {
thresholdLevel: 6,
tickers: [params.base],
},
}
},
unsubscribeMessage: (params) => {
return {
eventName: 'unsubscribe',
authorization: wsTransport.apiKey,
eventData: { thresholdLevel: 5, tickers: [params.base] },
eventData: {
thresholdLevel: 6,
tickers: [params.base],
},
}
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,47 +92,32 @@ exports[`websocket forex endpoint should return success 1`] = `
}
`;

exports[`websocket iex endpoint Q request should return success 1`] = `
exports[`websocket iex endpoint iex A request should return success 1`] = `
{
"data": {
"result": 170.285,
"result": 232.66,
},
"result": 170.285,
"result": 232.66,
"statusCode": 200,
"timestamps": {
"providerDataReceivedUnixMs": 3038,
"providerDataStreamEstablishedUnixMs": 3030,
"providerIndicatedTimeUnixMs": 1645032916595,
},
}
`;

exports[`websocket iex endpoint T request should return success 1`] = `
{
"data": {
"result": 106.21,
},
"result": 106.21,
"statusCode": 200,
"timestamps": {
"providerDataReceivedUnixMs": 3038,
"providerDataStreamEstablishedUnixMs": 3030,
"providerIndicatedTimeUnixMs": 1645032916595,
"providerIndicatedTimeUnixMs": 1736885388216,
},
}
`;

exports[`websocket iex endpoint should update the ttl after heartbeat is received 1`] = `
{
"data": {
"result": 170.285,
"result": 232.66,
},
"result": 170.285,
"result": 232.66,
"statusCode": 200,
"timestamps": {
"providerDataReceivedUnixMs": 3038,
"providerDataStreamEstablishedUnixMs": 3030,
"providerIndicatedTimeUnixMs": 1645032916595,
"providerIndicatedTimeUnixMs": 1736885388216,
},
}
`;
15 changes: 2 additions & 13 deletions packages/sources/tiingo/test/integration/adapter-ws.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
import { WebSocketClassProvider } from '@chainlink/external-adapter-framework/transports'
import FakeTimers from '@sinonjs/fake-timers'
import * as lwbaTransport from '../../src/transport/crypto-lwba'
import * as lwbaEndpoint from '../../src/endpoint/crypto-lwba'

describe('websocket', () => {
let mockWsServerCrypto: MockWebsocketServer | undefined
Expand All @@ -39,11 +38,6 @@ describe('websocket', () => {
base: 'aapl',
transport: 'ws',
}
const priceDataAmzn = {
endpoint: 'iex',
base: 'amzn',
transport: 'ws',
}
const priceDataForex = {
endpoint: 'forex',
base: 'eur',
Expand Down Expand Up @@ -75,9 +69,8 @@ describe('websocket', () => {
await testAdapter.request(priceData)
await testAdapter.request(spreadData)
await testAdapter.request(priceDataAapl)
await testAdapter.request(priceDataAmzn)
await testAdapter.request(priceDataForex)
await testAdapter.waitForCache(5)
await testAdapter.waitForCache(4)
})

afterAll(async () => {
Expand Down Expand Up @@ -137,14 +130,10 @@ describe('websocket', () => {
})

describe('iex endpoint', () => {
it('Q request should return success', async () => {
it('iex A request should return success', async () => {
const response = await testAdapter.request(priceDataAapl)
expect(response.json()).toMatchSnapshot()
})
it('T request should return success', async () => {
const response = await testAdapter.request(priceDataAmzn)
expect(response.json()).toMatchSnapshot()
})

it('should update the ttl after heartbeat is received', async () => {
// The cache ttl is 150 seconds. Mocked heartbeat message is sent after 10s after connection which should
Expand Down
46 changes: 3 additions & 43 deletions packages/sources/tiingo/test/integration/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,49 +413,10 @@ export const mockCryptoLwbaWebSocketServer = (URL: string): MockWebsocketServer
}

export const mockIexWebSocketServer = (URL: string): MockWebsocketServer => {
const wsResponseQ = {
const wsResponseIexA = {
messageType: 'A',
service: 'iex',
data: [
'Q',
'2022-02-16T12:35:16.595244526-05:00',
1645032916595244500,
'aapl',
399,
170.28,
170.285,
170.29,
100,
null,
null,
0,
0,
null,
null,
null,
],
}
const wsResponseT = {
messageType: 'A',
service: 'iex',
data: [
'T',
'2022-02-16T12:35:16.595244526-05:00',
1645032916595244500,
'amzn',
null,
null,
null,
null,
null,
106.21,
null,
null,
0,
0,
0,
0,
],
data: ['2025-01-14T15:09:48.216010528-05:00', 'aapl', 232.66],
}
const wsResponseHeartbeat = {
response: { code: 200, message: 'HeartBeat' },
Expand All @@ -466,8 +427,7 @@ export const mockIexWebSocketServer = (URL: string): MockWebsocketServer => {
let counter = 0
socket.on('message', () => {
if (counter++ === 0) {
socket.send(JSON.stringify(wsResponseQ))
socket.send(JSON.stringify(wsResponseT))
socket.send(JSON.stringify(wsResponseIexA))
setTimeout(() => {
socket.send(JSON.stringify(wsResponseHeartbeat))
}, 10000)
Expand Down

0 comments on commit da65fb1

Please sign in to comment.