Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading