overtime-live-trading-utils 3.0.2 → 4.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/main.js +1 -1
- package/package.json +1 -1
- package/src/constants/odds.ts +19 -0
- package/src/tests/unit/bookmakers.test.ts +25 -14
- package/src/tests/unit/markets.test.ts +51 -14
- package/src/tests/unit/odds.test.ts +19 -10
- package/src/tests/unit/spread.test.ts +22 -12
- package/src/tests/utils/helper.ts +8 -0
- package/src/types/odds.ts +19 -16
- package/src/utils/bookmakers.ts +57 -59
- package/src/utils/markets.ts +11 -7
- package/src/utils/odds.ts +43 -20
package/src/utils/markets.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as oddslib from 'oddslib';
|
|
2
2
|
import { ZERO_ODDS_AFTER_SPREAD_ADJUSTMENT } from '../constants/errors';
|
|
3
|
-
import { OddsObject } from '../types/odds';
|
|
3
|
+
import { Anchor, OddsObject } from '../types/odds';
|
|
4
4
|
import { LastPolledArray } from '../types/sports';
|
|
5
5
|
import { createChildMarkets, getParentOdds } from './odds';
|
|
6
6
|
import { getLeagueInfo } from './sports';
|
|
@@ -16,8 +16,10 @@ import { adjustAddedSpread } from './spread';
|
|
|
16
16
|
* @param {Array} spreadData - Spread data for odds.
|
|
17
17
|
* @param {Boolean} isDrawAvailable - Is it two or three-positional sport
|
|
18
18
|
* @param {Number} defaultSpreadForLiveMarkets - Default spread for live markets
|
|
19
|
-
* @param {
|
|
20
|
-
* @param {
|
|
19
|
+
* @param {Object} leagueMap - League map for additional league information
|
|
20
|
+
* @param {LastPolledArray} lastPolledData - Array containing last polled timestamps for bookmakers
|
|
21
|
+
* @param {Number} maxAllowedProviderDataStaleDelay - Maximum allowed delay for provider data to be considered fresh
|
|
22
|
+
* @param {Map<string, number>} playersMap - Map of player OO IDs to our internal player ID
|
|
21
23
|
* @returns {Promise<Object|null>} A promise that resolves to the processed event object or null if the event is invalid or mapping fails.
|
|
22
24
|
*/
|
|
23
25
|
export const processMarket = (
|
|
@@ -27,10 +29,11 @@ export const processMarket = (
|
|
|
27
29
|
spreadData: any,
|
|
28
30
|
isDrawAvailable: any,
|
|
29
31
|
defaultSpreadForLiveMarkets: any,
|
|
30
|
-
|
|
32
|
+
anchors: Anchor[],
|
|
31
33
|
leagueMap: any,
|
|
32
34
|
lastPolledData: LastPolledArray,
|
|
33
|
-
maxAllowedProviderDataStaleDelay: number
|
|
35
|
+
maxAllowedProviderDataStaleDelay: number,
|
|
36
|
+
playersMap: Map<string, number>
|
|
34
37
|
) => {
|
|
35
38
|
const sportSpreadData = spreadData.filter((data: any) => data.sportId === String(market.leagueId));
|
|
36
39
|
const leagueInfo = getLeagueInfo(market.leagueId, leagueMap);
|
|
@@ -42,7 +45,7 @@ export const processMarket = (
|
|
|
42
45
|
apiResponseWithOdds,
|
|
43
46
|
market.leagueId,
|
|
44
47
|
defaultSpreadForLiveMarkets,
|
|
45
|
-
|
|
48
|
+
anchors,
|
|
46
49
|
leagueInfo,
|
|
47
50
|
lastPolledData,
|
|
48
51
|
maxAllowedProviderDataStaleDelay
|
|
@@ -89,7 +92,8 @@ export const processMarket = (
|
|
|
89
92
|
leagueMap,
|
|
90
93
|
lastPolledData,
|
|
91
94
|
maxAllowedProviderDataStaleDelay,
|
|
92
|
-
|
|
95
|
+
anchors,
|
|
96
|
+
playersMap
|
|
93
97
|
);
|
|
94
98
|
|
|
95
99
|
const packedChildMarkets = childMarkets.map((childMarket: any) => {
|
package/src/utils/odds.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as oddslib from 'oddslib';
|
|
2
2
|
import { MarketType, MarketTypeMap } from 'overtime-utils';
|
|
3
|
-
import { DRAW,
|
|
3
|
+
import { DRAW, MONEYLINE_TYPE_ID, ZERO } from '../constants/common';
|
|
4
4
|
import { LAST_POLLED_TOO_OLD, NO_MARKETS_FOR_LEAGUE_ID } from '../constants/errors';
|
|
5
5
|
import { MoneylineTypes } from '../enums/sports';
|
|
6
|
-
import { HomeAwayTeams, Odds, OddsObject } from '../types/odds';
|
|
6
|
+
import { Anchor, HomeAwayTeams, Odds, OddsObject } from '../types/odds';
|
|
7
7
|
import { ChildMarket, LastPolledArray, LeagueConfigInfo } from '../types/sports';
|
|
8
8
|
import {
|
|
9
9
|
checkOddsFromBookmakers,
|
|
@@ -128,7 +128,7 @@ export const getParentOdds = (
|
|
|
128
128
|
oddsApiObject: OddsObject,
|
|
129
129
|
sportId: string,
|
|
130
130
|
defaultSpreadForLiveMarkets: number,
|
|
131
|
-
|
|
131
|
+
anchors: Anchor[],
|
|
132
132
|
leagueInfo: LeagueConfigInfo[],
|
|
133
133
|
lastPolledData: LastPolledArray,
|
|
134
134
|
maxAllowedProviderDataStaleDelay: number
|
|
@@ -164,13 +164,7 @@ export const getParentOdds = (
|
|
|
164
164
|
);
|
|
165
165
|
|
|
166
166
|
// CHECKING AND COMPARING ODDS FOR THE GIVEN BOOKMAKERS
|
|
167
|
-
const oddsObject = checkOddsFromBookmakers(
|
|
168
|
-
moneylineOddsMap,
|
|
169
|
-
bookmakers,
|
|
170
|
-
isTwoPositionalSport,
|
|
171
|
-
maxPercentageDiffBetwenOdds,
|
|
172
|
-
MIN_ODDS_FOR_DIFF_CHECKING
|
|
173
|
-
);
|
|
167
|
+
const oddsObject = checkOddsFromBookmakers(moneylineOddsMap, bookmakers, isTwoPositionalSport, anchors);
|
|
174
168
|
|
|
175
169
|
if (oddsObject.errorMessage) {
|
|
176
170
|
return {
|
|
@@ -214,7 +208,8 @@ export const createChildMarkets: (
|
|
|
214
208
|
leagueMap: any,
|
|
215
209
|
lastPolledData: LastPolledArray,
|
|
216
210
|
maxAllowedProviderDataStaleDelay: number,
|
|
217
|
-
|
|
211
|
+
anchors: Anchor[],
|
|
212
|
+
playersMap: Map<string, number>
|
|
218
213
|
) => ChildMarket[] = (
|
|
219
214
|
apiResponseWithOdds,
|
|
220
215
|
spreadDataForSport,
|
|
@@ -224,7 +219,8 @@ export const createChildMarkets: (
|
|
|
224
219
|
leagueMap,
|
|
225
220
|
lastPolledData,
|
|
226
221
|
maxAllowedProviderDataStaleDelay,
|
|
227
|
-
|
|
222
|
+
anchors,
|
|
223
|
+
playersMap
|
|
228
224
|
) => {
|
|
229
225
|
const [spreadOdds, totalOdds, moneylineOdds, correctScoreOdds, doubleChanceOdds, ggOdds, childMarkets]: any[] = [
|
|
230
226
|
[],
|
|
@@ -242,14 +238,14 @@ export const createChildMarkets: (
|
|
|
242
238
|
};
|
|
243
239
|
|
|
244
240
|
if (leagueInfo.length > 0) {
|
|
245
|
-
const allChildOdds =
|
|
241
|
+
const allChildOdds = filterOdds(apiResponseWithOdds.odds, leagueInfo, playersMap);
|
|
246
242
|
const checkedChildOdds = checkOddsFromBookmakersForChildMarkets(
|
|
247
243
|
allChildOdds,
|
|
248
244
|
leagueInfo,
|
|
249
245
|
liveOddsProviders,
|
|
250
246
|
lastPolledData,
|
|
251
247
|
maxAllowedProviderDataStaleDelay,
|
|
252
|
-
|
|
248
|
+
anchors
|
|
253
249
|
);
|
|
254
250
|
checkedChildOdds.forEach((odd) => {
|
|
255
251
|
if (odd.type === 'Total') {
|
|
@@ -269,7 +265,7 @@ export const createChildMarkets: (
|
|
|
269
265
|
|
|
270
266
|
const homeAwayFormattedOdds = [
|
|
271
267
|
...groupAndFormatSpreadOdds(spreadOdds, commonData),
|
|
272
|
-
...groupAndFormatTotalOdds(totalOdds, commonData),
|
|
268
|
+
...groupAndFormatTotalOdds(totalOdds, commonData), // playerProps are handled inside this function
|
|
273
269
|
...groupAndFormatMoneylineOdds(moneylineOdds, commonData),
|
|
274
270
|
...groupAndFormatGGOdds(ggOdds),
|
|
275
271
|
...groupAndFormatDoubleChanceOdds(doubleChanceOdds, commonData),
|
|
@@ -284,13 +280,29 @@ export const createChildMarkets: (
|
|
|
284
280
|
);
|
|
285
281
|
|
|
286
282
|
homeAwayOddsWithSpreadAdjusted.forEach((data) => {
|
|
287
|
-
|
|
283
|
+
let childMarket = {
|
|
288
284
|
leagueId: Number(data.sportId),
|
|
289
285
|
typeId: Number(data.typeId),
|
|
290
286
|
type: MarketTypeMap[data.typeId as MarketType]?.key || '',
|
|
291
287
|
line: Number(data.line || 0),
|
|
292
288
|
odds: data.odds,
|
|
289
|
+
playerProps: {
|
|
290
|
+
playerId: 0,
|
|
291
|
+
playerName: '',
|
|
292
|
+
},
|
|
293
|
+
isPlayerPropsMarket: false,
|
|
293
294
|
};
|
|
295
|
+
if (data.playerProps) {
|
|
296
|
+
childMarket = {
|
|
297
|
+
...childMarket,
|
|
298
|
+
playerProps: {
|
|
299
|
+
playerId: playersMap.get(data.playerProps.playerId.toString()) || 0, // convert from opticOdds playerId to our internal playerId
|
|
300
|
+
playerName: data.playerProps.playerName,
|
|
301
|
+
},
|
|
302
|
+
isPlayerPropsMarket: true,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
|
|
294
306
|
const leagueInfoByTypeId = leagueInfo.find((league) => Number(league.typeId) === Number(data.typeId));
|
|
295
307
|
const minOdds = leagueInfoByTypeId?.minOdds; // minimum odds configured for child market (e.g. 0.95 implied probability)
|
|
296
308
|
const maxOdds = leagueInfoByTypeId?.maxOdds; // maximum odds configured for child market (e.g. 0.05 implied probability)
|
|
@@ -343,7 +355,7 @@ export const createChildMarkets: (
|
|
|
343
355
|
* @param {string} oddsProvider - The main odds provider to filter by.
|
|
344
356
|
* @returns {Array} The filtered odds array.
|
|
345
357
|
*/
|
|
346
|
-
export const
|
|
358
|
+
export const filterOdds = (oddsArray: Odds, leagueInfos: LeagueConfigInfo[], playersMap: Map<string, number>): any => {
|
|
347
359
|
const allChildMarketsTypes = leagueInfos
|
|
348
360
|
.filter(
|
|
349
361
|
(leagueInfo) =>
|
|
@@ -353,7 +365,10 @@ export const filterOddsByMarketNameBookmaker = (oddsArray: Odds, leagueInfos: Le
|
|
|
353
365
|
.map((leagueInfo) => leagueInfo.marketName.toLowerCase());
|
|
354
366
|
return oddsArray.reduce((acc: any, odd: any) => {
|
|
355
367
|
if (allChildMarketsTypes.includes(odd.marketName.toLowerCase())) {
|
|
356
|
-
const { points, marketName, selection, selectionLine, sportsBookName } = odd;
|
|
368
|
+
const { points, marketName, selection, selectionLine, sportsBookName, playerId } = odd;
|
|
369
|
+
if (playerId && !playersMap.has(playerId)) {
|
|
370
|
+
return acc;
|
|
371
|
+
}
|
|
357
372
|
const key = `${sportsBookName.toLowerCase()}_${marketName.toLowerCase()}_${points}_${selection}_${selectionLine}`;
|
|
358
373
|
acc[key] = {
|
|
359
374
|
...odd,
|
|
@@ -440,6 +455,13 @@ export const groupAndFormatTotalOdds = (oddsArray: any[], commonData: HomeAwayTe
|
|
|
440
455
|
acc[key].typeId = odd.typeId;
|
|
441
456
|
acc[key].type = odd.type;
|
|
442
457
|
acc[key].sportId = odd.sportId;
|
|
458
|
+
|
|
459
|
+
if (odd.playerId) {
|
|
460
|
+
acc[key].playerProps = {
|
|
461
|
+
playerId: odd.playerId, // Player ID from OpticOdds, this will be converted to our internal playerId later
|
|
462
|
+
playerName: odd.selection,
|
|
463
|
+
};
|
|
464
|
+
}
|
|
443
465
|
}
|
|
444
466
|
|
|
445
467
|
return acc;
|
|
@@ -447,8 +469,8 @@ export const groupAndFormatTotalOdds = (oddsArray: any[], commonData: HomeAwayTe
|
|
|
447
469
|
|
|
448
470
|
// Format the grouped odds into the desired output
|
|
449
471
|
const formattedOdds = Object.entries(groupedOdds as any).reduce((acc: any, [key, value]) => {
|
|
450
|
-
const [_marketName, selection,
|
|
451
|
-
const line = parseFloat(
|
|
472
|
+
const [_marketName, selection, points] = key.split('_');
|
|
473
|
+
const line = parseFloat(points);
|
|
452
474
|
|
|
453
475
|
// if we have away team in total odds we know the market is team total and we need to increase typeId by one.
|
|
454
476
|
// if this is false typeId is already mapped correctly
|
|
@@ -460,6 +482,7 @@ export const groupAndFormatTotalOdds = (oddsArray: any[], commonData: HomeAwayTe
|
|
|
460
482
|
typeId: !isAwayTeam ? (value as any).typeId : Number((value as any).typeId) + 1,
|
|
461
483
|
sportId: (value as any).sportId,
|
|
462
484
|
type: (value as any).type,
|
|
485
|
+
playerProps: (value as any).playerProps,
|
|
463
486
|
});
|
|
464
487
|
}
|
|
465
488
|
return acc;
|