Skip to content

Commit 15c48e2

Browse files
committed
Use the same date across the entire request
We can now filter rates based on their date compared to server time in the bucketing utils
1 parent 3a082f2 commit 15c48e2

File tree

8 files changed

+227
-39
lines changed

8 files changed

+227
-39
lines changed

src/v3/getRates.ts

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,12 @@ const queryProviders = async (
8686

8787
const updateProviders = async (
8888
providers: RateProvider[],
89-
rates: UpdateRatesParams
89+
rates: UpdateRatesParams,
90+
rightNow: Date
9091
): Promise<void> => {
9192
for (const p of providers) {
9293
if (p.updateRates != null) {
93-
p.updateRates(rates).catch(err => {
94+
p.updateRates(rates, rightNow).catch(err => {
9495
console.error(`Error updating rates from ${p.providerId}`, err)
9596
})
9697
}
@@ -152,20 +153,28 @@ export const getRates: GetRatesFunc = async (params, rightNow) => {
152153
)
153154

154155
// Update redis with db and api data
155-
updateProviders(memoryProviders, {
156-
targetFiat,
157-
crypto: new Map([...dbResults.foundCrypto, ...apiResults.foundCrypto]),
158-
fiat: new Map([...dbResults.foundFiat, ...apiResults.foundFiat])
159-
}).catch(e => {
156+
updateProviders(
157+
memoryProviders,
158+
{
159+
targetFiat,
160+
crypto: new Map([...dbResults.foundCrypto, ...apiResults.foundCrypto]),
161+
fiat: new Map([...dbResults.foundFiat, ...apiResults.foundFiat])
162+
},
163+
rightNow
164+
).catch(e => {
160165
console.error('Error updating memoryproviders', e)
161166
})
162167

163168
// Update db with api data
164-
updateProviders(dbProviders, {
165-
targetFiat,
166-
crypto: apiResults.foundCrypto,
167-
fiat: apiResults.foundFiat
168-
}).catch(e => {
169+
updateProviders(
170+
dbProviders,
171+
{
172+
targetFiat,
173+
crypto: apiResults.foundCrypto,
174+
fiat: apiResults.foundFiat
175+
},
176+
rightNow
177+
).catch(e => {
169178
console.error('Error updating dbproviders', e)
170179
})
171180

src/v3/providers/coinmarketcap/coinmarketcap.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -249,11 +249,11 @@ const getCurrentRates = async (ids: Set<string>): Promise<NumberMap> => {
249249
}
250250
const getHistoricalRates = async (
251251
ids: Set<string>,
252-
date: string
252+
date: string,
253+
rightNow: Date
253254
): Promise<NumberMap> => {
254255
const out: NumberMap = {}
255-
const now = new Date()
256-
const days = daysBetween(new Date(date), now)
256+
const days = daysBetween(new Date(date), rightNow)
257257

258258
// If we're querying a date more than 3 months in the past, use
259259
// daily average
@@ -329,7 +329,7 @@ export const coinmarketcap: RateProvider = {
329329
)
330330
} else {
331331
promises.push(
332-
getHistoricalRates(ids, date).then(results => {
332+
getHistoricalRates(ids, date, rightNow).then(results => {
333333
allResults.set(date, results)
334334
})
335335
)

src/v3/providers/couch.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,15 @@ export const couch: RateProvider = {
8383
requestedRates: out.requestedRates
8484
}
8585
},
86-
getFiatRates: async ({ targetFiat, requestedRates }) => {
86+
getFiatRates: async ({ targetFiat, requestedRates }, rightNow) => {
8787
if (targetFiat !== 'USD') {
8888
return {
8989
foundRates: new Map(),
9090
requestedRates
9191
}
9292
}
9393

94-
const rateBuckets = reduceRequestedFiatRates(requestedRates)
94+
const rateBuckets = reduceRequestedFiatRates(requestedRates, rightNow)
9595

9696
const allResults: RateBuckets = new Map()
9797

@@ -130,16 +130,19 @@ export const couch: RateProvider = {
130130
requestedRates: out.requestedRates
131131
}
132132
},
133-
updateRates: async (params: UpdateRatesParams): Promise<void> => {
133+
updateRates: async (
134+
params: UpdateRatesParams,
135+
rightNow: Date
136+
): Promise<void> => {
134137
if (params.targetFiat !== 'USD') {
135138
return
136139
}
137140
if (params.crypto.size === 0 && params.fiat.size === 0) {
138141
return
139142
}
140143

141-
const cryptoRateBuckets = groupCryptoRatesByTime(params.crypto)
142-
const fiatRateBuckets = groupFiatRatesByTime(params.fiat)
144+
const cryptoRateBuckets = groupCryptoRatesByTime(params.crypto, rightNow)
145+
const fiatRateBuckets = groupFiatRatesByTime(params.fiat, rightNow)
143146

144147
const ids = new Set<string>([
145148
...cryptoRateBuckets.keys(),

src/v3/providers/currencyconverter.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,21 +65,20 @@ const fetchCurrencyConverter = async (
6565
export const currencyconverter: RateProvider = {
6666
providerId: 'currencyconverter',
6767
type: 'api',
68-
getFiatRates: async ({ targetFiat, requestedRates }) => {
68+
getFiatRates: async ({ targetFiat, requestedRates }, rightNow) => {
6969
if (apiKey == null) {
7070
return {
7171
foundRates: new Map(),
7272
requestedRates
7373
}
7474
}
7575

76-
const rateBuckets = reduceRequestedFiatRates(requestedRates)
76+
const rateBuckets = reduceRequestedFiatRates(requestedRates, rightNow)
7777

78-
const currentDate = new Date()
7978
const allResults: RateBuckets = new Map()
8079
const promises: Array<Promise<void>> = []
8180
rateBuckets.forEach((ids, date) => {
82-
if (isCurrentFiat(new Date(date), currentDate)) {
81+
if (isCurrentFiat(new Date(date), rightNow)) {
8382
promises.push(
8483
fetchCurrencyConverter(targetFiat, Array.from(ids)).then(results => {
8584
allResults.set(date, results)

src/v3/providers/redis.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,15 @@ export const redis: RateProvider = {
8181
requestedRates: out.requestedRates
8282
}
8383
},
84-
getFiatRates: async ({ targetFiat, requestedRates }) => {
84+
getFiatRates: async ({ targetFiat, requestedRates }, rightNow) => {
8585
if (targetFiat !== 'USD') {
8686
return {
8787
foundRates: new Map(),
8888
requestedRates
8989
}
9090
}
9191

92-
const rateBuckets = reduceRequestedFiatRates(requestedRates)
92+
const rateBuckets = reduceRequestedFiatRates(requestedRates, rightNow)
9393

9494
const allResults: RateBuckets = new Map()
9595
for (const [date, fiatPairs] of rateBuckets.entries()) {
@@ -115,7 +115,10 @@ export const redis: RateProvider = {
115115
requestedRates: out.requestedRates
116116
}
117117
},
118-
updateRates: async (params: UpdateRatesParams): Promise<void> => {
118+
updateRates: async (
119+
params: UpdateRatesParams,
120+
rightNow: Date
121+
): Promise<void> => {
119122
if (params.targetFiat !== 'USD') {
120123
return
121124
}
@@ -124,13 +127,13 @@ export const redis: RateProvider = {
124127
return
125128
}
126129

127-
const cryptoRateBuckets = groupCryptoRatesByTime(params.crypto)
130+
const cryptoRateBuckets = groupCryptoRatesByTime(params.crypto, rightNow)
128131
for (const [date, cryptoRates] of cryptoRateBuckets.entries()) {
129132
const cryptoRedisKey = `rates_data:${date}:crypto`
130133
await hsetAsync(cryptoRedisKey, cryptoRates)
131134
}
132135

133-
const fiatRateBuckets = groupFiatRatesByTime(params.fiat)
136+
const fiatRateBuckets = groupFiatRatesByTime(params.fiat, rightNow)
134137
for (const [date, fiatRates] of fiatRateBuckets.entries()) {
135138
const fiatRedisKey = `rates_data:${date}:fiat`
136139
await hsetAsync(fiatRedisKey, fiatRates)

src/v3/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ export interface RateProvider {
102102
foundRates: FiatRateMap
103103
requestedRates: FiatRateMap
104104
}>
105-
updateRates?: (params: UpdateRatesParams) => Promise<void>
105+
updateRates?: (params: UpdateRatesParams, rightNow: Date) => Promise<void>
106106
engines?: Array<{
107107
frequency: Frequency
108108
engine: RateEngine

src/v3/utils.ts

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,20 @@ export const createTokenId = (
110110
}
111111
}
112112

113+
// Ignore requests with a future time with an allowance for clients that are close enough
114+
const isFutureTime = ({
115+
rateDate,
116+
rightNow,
117+
fuzzFactor = 0
118+
}: {
119+
rateDate: Date
120+
rightNow: Date
121+
fuzzFactor?: number
122+
}): boolean => {
123+
const fuzzyFutureThreshold = new Date(rightNow.getTime() + fuzzFactor)
124+
return rateDate > fuzzyFutureThreshold
125+
}
126+
113127
// These functions reduce requested rates into buckets based on the date that
114128
// the providers can handle efficiently. The rates returned by the providers
115129
// can then be rematched with the requested rates
@@ -121,6 +135,16 @@ export const reduceRequestedCryptoRates = (
121135
const buckets: DateBuckets = new Map()
122136

123137
requestedRates.forEach(rate => {
138+
if (
139+
isFutureTime({
140+
rateDate: rate.isoDate,
141+
rightNow,
142+
fuzzFactor: ONE_MINUTE
143+
})
144+
) {
145+
return
146+
}
147+
124148
const rateTime = rate.isoDate.getTime()
125149

126150
// Current rates (< five minutes old) use minute precision and historical rates use five minutes
@@ -193,11 +217,22 @@ export const expandReturnedCryptoRates = (
193217
}
194218

195219
export const reduceRequestedFiatRates = (
196-
requestedRates: FiatRateMap
220+
requestedRates: FiatRateMap,
221+
rightNow: Date
197222
): DateBuckets => {
198223
const buckets: DateBuckets = new Map()
199224

200225
requestedRates.forEach(rate => {
226+
if (
227+
isFutureTime({
228+
rateDate: rate.isoDate,
229+
rightNow,
230+
fuzzFactor: ONE_MINUTE
231+
})
232+
) {
233+
return
234+
}
235+
201236
const rateTime = rate.isoDate.getTime()
202237

203238
// Floor to the start of the interval bucket
@@ -243,14 +278,24 @@ export const expandReturnedFiatRates = (
243278
// This function breaks apart the requested rates into buckets of the given interval.
244279
type UpdateBuckets = Map<string, Record<string, number>>
245280
export const groupCryptoRatesByTime = (
246-
requestedRates: CryptoRateMap
281+
requestedRates: CryptoRateMap,
282+
rightNow: Date
247283
): UpdateBuckets => {
248284
const buckets: UpdateBuckets = new Map()
249285
const rightNowMs = new Date().getTime()
250286

251287
requestedRates.forEach(cryptoRate => {
252288
if (cryptoRate.rate == null) return
253289

290+
if (
291+
isFutureTime({
292+
rateDate: cryptoRate.isoDate,
293+
rightNow
294+
})
295+
) {
296+
return
297+
}
298+
254299
const rateTime = cryptoRate.isoDate.getTime()
255300

256301
// Current rates (< five minutes old) use minute precision and historical rates use five minutes
@@ -269,13 +314,23 @@ export const groupCryptoRatesByTime = (
269314
}
270315

271316
export const groupFiatRatesByTime = (
272-
requestedRates: FiatRateMap
317+
requestedRates: FiatRateMap,
318+
rightNow: Date
273319
): UpdateBuckets => {
274320
const buckets: UpdateBuckets = new Map()
275321

276322
requestedRates.forEach(fiatRate => {
277323
if (fiatRate.rate == null) return
278324

325+
if (
326+
isFutureTime({
327+
rateDate: fiatRate.isoDate,
328+
rightNow
329+
})
330+
) {
331+
return
332+
}
333+
279334
const rateTime = fiatRate.isoDate.getTime()
280335

281336
// Floor to the start of the interval bucket

0 commit comments

Comments
 (0)