Skip to content

Commit 74360b8

Browse files
authored
finalto: Support overrides for stock symbols (#3898)
* finalto: Support overrides for stock symbols * Add changeset
1 parent b7921cc commit 74360b8

File tree

8 files changed

+149
-19
lines changed

8 files changed

+149
-19
lines changed

.changeset/healthy-islands-stare.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@chainlink/finalto-adapter': minor
3+
---
4+
5+
Add support for stock assets
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export { endpoint as forex } from './forex'
1+
export { endpoint as quote } from './quote'

packages/sources/finalto/src/endpoint/forex.ts renamed to packages/sources/finalto/src/endpoint/quote.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import {
2-
ForexPriceEndpoint,
2+
PriceEndpoint,
33
priceEndpointInputParametersDefinition,
44
} from '@chainlink/external-adapter-framework/adapter'
5-
import { InputParameters } from '@chainlink/external-adapter-framework/validation'
65
import { SingleNumberResultResponse } from '@chainlink/external-adapter-framework/util'
6+
import { InputParameters } from '@chainlink/external-adapter-framework/validation'
77
import { config } from '../config'
8-
import { wsTransport } from '../transport/forex'
8+
import { wsTransport } from '../transport/quote'
99

1010
export const inputParameters = new InputParameters(
1111
{
@@ -25,9 +25,9 @@ export type BaseEndpointTypes = {
2525
Settings: typeof config.settings
2626
}
2727

28-
export const endpoint = new ForexPriceEndpoint({
29-
name: 'forex',
30-
aliases: ['fx', 'commodities'],
28+
export const endpoint = new PriceEndpoint({
29+
name: 'quote',
30+
aliases: ['forex', 'fx', 'commodities', 'stock'],
3131
transport: wsTransport,
3232
inputParameters,
3333
})

packages/sources/finalto/src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import { expose, ServerInstance } from '@chainlink/external-adapter-framework'
22
import { PriceAdapter } from '@chainlink/external-adapter-framework/adapter'
33
import { config } from './config'
4-
import { forex } from './endpoint'
54
import includes from './config/includes.json'
5+
import { quote } from './endpoint'
66

77
export const adapter = new PriceAdapter({
8-
defaultEndpoint: forex.name,
8+
defaultEndpoint: quote.name,
99
name: 'FINALTO',
1010
config,
11-
endpoints: [forex],
11+
endpoints: [quote],
1212
includes,
1313
})
1414

packages/sources/finalto/src/transport/forex.ts renamed to packages/sources/finalto/src/transport/quote.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { WebsocketReverseMappingTransport } from '@chainlink/external-adapter-framework/transports'
2-
import { BaseEndpointTypes } from '../endpoint/forex'
32
import { makeLogger } from '@chainlink/external-adapter-framework/util'
43
import { v4 as uuidv4 } from 'uuid'
4+
import { BaseEndpointTypes } from '../endpoint/quote'
55

66
const logger = makeLogger('FinaltoWSTransport')
77

@@ -35,6 +35,14 @@ const getSubscriptionId = (symbol: string): string => {
3535
return subscriptionIdMap[symbol]
3636
}
3737

38+
const buildSymbol = ({ base, quote }: { base: string; quote: string }): string => {
39+
if (base.includes('.')) {
40+
// e.g. "AAPL.xnas"
41+
return base
42+
}
43+
return `${base}${quote}`.toUpperCase()
44+
}
45+
3846
// DP returns the date info in an unparseable format like 20240112-11:11:11.111
3947
const parseDate = (dateLike: string): number => {
4048
const year = dateLike.substring(0, 4)
@@ -106,7 +114,9 @@ export const wsTransport: WebsocketReverseMappingTransport<WsTransportTypes, str
106114
]
107115
}
108116

109-
const result = (Number(bidInfo.Px) + Number(askInfo.Px)) / 2
117+
const bid = Number(bidInfo.Px)
118+
const ask = Number(askInfo.Px)
119+
const result = (bid + ask) / 2
110120

111121
return [
112122
{
@@ -115,6 +125,9 @@ export const wsTransport: WebsocketReverseMappingTransport<WsTransportTypes, str
115125
result,
116126
data: {
117127
result,
128+
bid,
129+
mid: result,
130+
ask,
118131
},
119132
timestamps: {
120133
providerIndicatedTimeUnixMs: parseDate(message.SendTime),
@@ -126,7 +139,7 @@ export const wsTransport: WebsocketReverseMappingTransport<WsTransportTypes, str
126139
},
127140
builders: {
128141
subscribeMessage: (params) => {
129-
const symbol = `${params.base}${params.quote}`.toUpperCase()
142+
const symbol = buildSymbol(params)
130143
wsTransport.setReverseMapping(symbol, params)
131144
const id = getSubscriptionId(symbol)
132145
return {
@@ -140,7 +153,7 @@ export const wsTransport: WebsocketReverseMappingTransport<WsTransportTypes, str
140153
}
141154
},
142155
unsubscribeMessage: (params) => {
143-
const symbol = `${params.base}${params.quote}`.toUpperCase()
156+
const symbol = buildSymbol(params)
144157
const id = getSubscriptionId(symbol)
145158
delete subscriptionIdMap[symbol]
146159
return {

packages/sources/finalto/test/integration/__snapshots__/adapter.test.ts.snap

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,51 @@
33
exports[`websocket forex endpoint should return success 1`] = `
44
{
55
"data": {
6+
"ask": 6.82543,
7+
"bid": 6.82427,
8+
"mid": 6.82485,
69
"result": 6.82485,
710
},
811
"result": 6.82485,
912
"statusCode": 200,
1013
"timestamps": {
11-
"providerDataReceivedUnixMs": 1022,
14+
"providerDataReceivedUnixMs": 3042,
15+
"providerDataStreamEstablishedUnixMs": 1010,
16+
"providerIndicatedTimeUnixMs": 1704951160198,
17+
},
18+
}
19+
`;
20+
21+
exports[`websocket stock endpoint should return success 1`] = `
22+
{
23+
"data": {
24+
"ask": 200.88,
25+
"bid": 200.84,
26+
"mid": 200.86,
27+
"result": 200.86,
28+
},
29+
"result": 200.86,
30+
"statusCode": 200,
31+
"timestamps": {
32+
"providerDataReceivedUnixMs": 3042,
33+
"providerDataStreamEstablishedUnixMs": 1010,
34+
"providerIndicatedTimeUnixMs": 1704951160198,
35+
},
36+
}
37+
`;
38+
39+
exports[`websocket stock endpoint should return success with base override 1`] = `
40+
{
41+
"data": {
42+
"ask": 461.96,
43+
"bid": 461.92,
44+
"mid": 461.94,
45+
"result": 461.94,
46+
},
47+
"result": 461.94,
48+
"statusCode": 200,
49+
"timestamps": {
50+
"providerDataReceivedUnixMs": 3042,
1251
"providerDataStreamEstablishedUnixMs": 1010,
1352
"providerIndicatedTimeUnixMs": 1704951160198,
1453
},

packages/sources/finalto/test/integration/adapter.test.ts

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { WebSocketClassProvider } from '@chainlink/external-adapter-framework/transports'
22
import {
3-
TestAdapter,
4-
setEnvVariables,
53
mockWebSocketProvider,
64
MockWebsocketServer,
5+
setEnvVariables,
6+
TestAdapter,
77
} from '@chainlink/external-adapter-framework/util/testing-utils'
88
import FakeTimers from '@sinonjs/fake-timers'
99
import { mockWebsocketServer } from './fixtures'
@@ -20,6 +20,23 @@ describe('websocket', () => {
2020
endpoint: 'forex',
2121
}
2222

23+
const dataStock = {
24+
base: 'AAPL.xnas',
25+
quote: 'USD',
26+
endpoint: 'stock',
27+
}
28+
29+
const dataStockWithOverride = {
30+
base: 'MSFT',
31+
quote: 'USD',
32+
overrides: {
33+
finalto: {
34+
MSFT: 'MSFT.xnas',
35+
},
36+
},
37+
endpoint: 'stock',
38+
}
39+
2340
beforeAll(async () => {
2441
oldEnv = JSON.parse(JSON.stringify(process.env))
2542
process.env['WS_API_ENDPOINT'] = wsEndpoint
@@ -36,7 +53,9 @@ describe('websocket', () => {
3653

3754
// Send initial request to start background execute and wait for cache to be filled with results
3855
await testAdapter.request(dataForex)
39-
await testAdapter.waitForCache(1)
56+
await testAdapter.request(dataStock)
57+
await testAdapter.request(dataStockWithOverride)
58+
await testAdapter.waitForCache(2)
4059
})
4160

4261
afterAll(async () => {
@@ -67,4 +86,16 @@ describe('websocket', () => {
6786
expect(response.statusCode).toEqual(400)
6887
})
6988
})
89+
90+
describe('stock endpoint', () => {
91+
it('should return success', async () => {
92+
const response = await testAdapter.request(dataStock)
93+
expect(response.json()).toMatchSnapshot()
94+
})
95+
96+
it('should return success with base override', async () => {
97+
const response = await testAdapter.request(dataStockWithOverride)
98+
expect(response.json()).toMatchSnapshot()
99+
})
100+
})
70101
})

packages/sources/finalto/test/integration/fixtures.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export const mockWebsocketServer = (URL: string): MockWebsocketServer => {
1212
}),
1313
)
1414
}
15-
return socket.send(
15+
socket.send(
1616
JSON.stringify({
1717
MsgSeqNum: '12',
1818
MsgType: 'SymbolPrices',
@@ -33,6 +33,48 @@ export const mockWebsocketServer = (URL: string): MockWebsocketServer => {
3333
Symbol: 'GBPUSD',
3434
}),
3535
)
36+
socket.send(
37+
JSON.stringify({
38+
MsgSeqNum: '12',
39+
MsgType: 'SymbolPrices',
40+
Prices: [
41+
{
42+
Px: '200.84',
43+
Type: 'B',
44+
Vol: '1000000',
45+
},
46+
{
47+
Px: '200.88',
48+
Type: 'O',
49+
Vol: '1000000',
50+
},
51+
],
52+
SendTime: '20240111-05:32:40.198',
53+
SubID: parsed.SubID,
54+
Symbol: 'AAPL.xnas',
55+
}),
56+
)
57+
socket.send(
58+
JSON.stringify({
59+
MsgSeqNum: '12',
60+
MsgType: 'SymbolPrices',
61+
Prices: [
62+
{
63+
Px: '461.92',
64+
Type: 'B',
65+
Vol: '1000000',
66+
},
67+
{
68+
Px: '461.96',
69+
Type: 'O',
70+
Vol: '1000000',
71+
},
72+
],
73+
SendTime: '20240111-05:32:40.198',
74+
SubID: parsed.SubID,
75+
Symbol: 'MSFT.xnas',
76+
}),
77+
)
3678
})
3779
})
3880

0 commit comments

Comments
 (0)