overtime-live-trading-utils 3.0.2-rc.2 → 3.0.3
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 +2 -2
- package/src/tests/unit/bookmakers.test.ts +14 -25
- package/src/tests/unit/markets.test.ts +14 -51
- package/src/tests/unit/odds.test.ts +10 -19
- package/src/tests/unit/spread.test.ts +12 -22
- package/src/tests/utils/helper.ts +0 -8
- package/src/types/odds.ts +16 -19
- package/src/utils/bookmakers.ts +64 -73
- package/src/utils/markets.ts +7 -11
- package/src/utils/odds.ts +20 -43
- package/src/constants/odds.ts +0 -19
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 {
|
|
3
|
+
import { 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,10 +16,8 @@ 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 {
|
|
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
|
|
19
|
+
* @param {Number} maxPercentageDiffBetwenOdds - Maximum allowed percentage difference between same position odds from different providers
|
|
20
|
+
* @param {Boolean} isTestnet - Flag showing should we process for testnet or mainnet
|
|
23
21
|
* @returns {Promise<Object|null>} A promise that resolves to the processed event object or null if the event is invalid or mapping fails.
|
|
24
22
|
*/
|
|
25
23
|
export const processMarket = (
|
|
@@ -29,11 +27,10 @@ export const processMarket = (
|
|
|
29
27
|
spreadData: any,
|
|
30
28
|
isDrawAvailable: any,
|
|
31
29
|
defaultSpreadForLiveMarkets: any,
|
|
32
|
-
|
|
30
|
+
maxPercentageDiffBetwenOdds: number,
|
|
33
31
|
leagueMap: any,
|
|
34
32
|
lastPolledData: LastPolledArray,
|
|
35
|
-
maxAllowedProviderDataStaleDelay: number
|
|
36
|
-
playersMap: Map<string, number>
|
|
33
|
+
maxAllowedProviderDataStaleDelay: number
|
|
37
34
|
) => {
|
|
38
35
|
const sportSpreadData = spreadData.filter((data: any) => data.sportId === String(market.leagueId));
|
|
39
36
|
const leagueInfo = getLeagueInfo(market.leagueId, leagueMap);
|
|
@@ -45,7 +42,7 @@ export const processMarket = (
|
|
|
45
42
|
apiResponseWithOdds,
|
|
46
43
|
market.leagueId,
|
|
47
44
|
defaultSpreadForLiveMarkets,
|
|
48
|
-
|
|
45
|
+
maxPercentageDiffBetwenOdds,
|
|
49
46
|
leagueInfo,
|
|
50
47
|
lastPolledData,
|
|
51
48
|
maxAllowedProviderDataStaleDelay
|
|
@@ -92,8 +89,7 @@ export const processMarket = (
|
|
|
92
89
|
leagueMap,
|
|
93
90
|
lastPolledData,
|
|
94
91
|
maxAllowedProviderDataStaleDelay,
|
|
95
|
-
|
|
96
|
-
playersMap
|
|
92
|
+
maxPercentageDiffBetwenOdds
|
|
97
93
|
);
|
|
98
94
|
|
|
99
95
|
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, MONEYLINE_TYPE_ID, ZERO } from '../constants/common';
|
|
3
|
+
import { DRAW, MIN_ODDS_FOR_DIFF_CHECKING, 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 {
|
|
6
|
+
import { 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
|
+
maxPercentageDiffBetwenOdds: number,
|
|
132
132
|
leagueInfo: LeagueConfigInfo[],
|
|
133
133
|
lastPolledData: LastPolledArray,
|
|
134
134
|
maxAllowedProviderDataStaleDelay: number
|
|
@@ -164,7 +164,13 @@ export const getParentOdds = (
|
|
|
164
164
|
);
|
|
165
165
|
|
|
166
166
|
// CHECKING AND COMPARING ODDS FOR THE GIVEN BOOKMAKERS
|
|
167
|
-
const oddsObject = checkOddsFromBookmakers(
|
|
167
|
+
const oddsObject = checkOddsFromBookmakers(
|
|
168
|
+
moneylineOddsMap,
|
|
169
|
+
bookmakers,
|
|
170
|
+
isTwoPositionalSport,
|
|
171
|
+
maxPercentageDiffBetwenOdds,
|
|
172
|
+
MIN_ODDS_FOR_DIFF_CHECKING
|
|
173
|
+
);
|
|
168
174
|
|
|
169
175
|
if (oddsObject.errorMessage) {
|
|
170
176
|
return {
|
|
@@ -208,8 +214,7 @@ export const createChildMarkets: (
|
|
|
208
214
|
leagueMap: any,
|
|
209
215
|
lastPolledData: LastPolledArray,
|
|
210
216
|
maxAllowedProviderDataStaleDelay: number,
|
|
211
|
-
|
|
212
|
-
playersMap: Map<string, number>
|
|
217
|
+
maxImpliedPercentageDifference: number
|
|
213
218
|
) => ChildMarket[] = (
|
|
214
219
|
apiResponseWithOdds,
|
|
215
220
|
spreadDataForSport,
|
|
@@ -219,8 +224,7 @@ export const createChildMarkets: (
|
|
|
219
224
|
leagueMap,
|
|
220
225
|
lastPolledData,
|
|
221
226
|
maxAllowedProviderDataStaleDelay,
|
|
222
|
-
|
|
223
|
-
playersMap
|
|
227
|
+
maxImpliedPercentageDifference
|
|
224
228
|
) => {
|
|
225
229
|
const [spreadOdds, totalOdds, moneylineOdds, correctScoreOdds, doubleChanceOdds, ggOdds, childMarkets]: any[] = [
|
|
226
230
|
[],
|
|
@@ -238,14 +242,14 @@ export const createChildMarkets: (
|
|
|
238
242
|
};
|
|
239
243
|
|
|
240
244
|
if (leagueInfo.length > 0) {
|
|
241
|
-
const allChildOdds =
|
|
245
|
+
const allChildOdds = filterOddsByMarketNameBookmaker(apiResponseWithOdds.odds, leagueInfo);
|
|
242
246
|
const checkedChildOdds = checkOddsFromBookmakersForChildMarkets(
|
|
243
247
|
allChildOdds,
|
|
244
248
|
leagueInfo,
|
|
245
249
|
liveOddsProviders,
|
|
246
250
|
lastPolledData,
|
|
247
251
|
maxAllowedProviderDataStaleDelay,
|
|
248
|
-
|
|
252
|
+
maxImpliedPercentageDifference
|
|
249
253
|
);
|
|
250
254
|
checkedChildOdds.forEach((odd) => {
|
|
251
255
|
if (odd.type === 'Total') {
|
|
@@ -265,7 +269,7 @@ export const createChildMarkets: (
|
|
|
265
269
|
|
|
266
270
|
const homeAwayFormattedOdds = [
|
|
267
271
|
...groupAndFormatSpreadOdds(spreadOdds, commonData),
|
|
268
|
-
...groupAndFormatTotalOdds(totalOdds, commonData),
|
|
272
|
+
...groupAndFormatTotalOdds(totalOdds, commonData),
|
|
269
273
|
...groupAndFormatMoneylineOdds(moneylineOdds, commonData),
|
|
270
274
|
...groupAndFormatGGOdds(ggOdds),
|
|
271
275
|
...groupAndFormatDoubleChanceOdds(doubleChanceOdds, commonData),
|
|
@@ -280,29 +284,13 @@ export const createChildMarkets: (
|
|
|
280
284
|
);
|
|
281
285
|
|
|
282
286
|
homeAwayOddsWithSpreadAdjusted.forEach((data) => {
|
|
283
|
-
|
|
287
|
+
const childMarket = {
|
|
284
288
|
leagueId: Number(data.sportId),
|
|
285
289
|
typeId: Number(data.typeId),
|
|
286
290
|
type: MarketTypeMap[data.typeId as MarketType]?.key || '',
|
|
287
291
|
line: Number(data.line || 0),
|
|
288
292
|
odds: data.odds,
|
|
289
|
-
playerProps: {
|
|
290
|
-
playerId: 0,
|
|
291
|
-
playerName: '',
|
|
292
|
-
},
|
|
293
|
-
isPlayerPropsMarket: false,
|
|
294
293
|
};
|
|
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
|
-
|
|
306
294
|
const leagueInfoByTypeId = leagueInfo.find((league) => Number(league.typeId) === Number(data.typeId));
|
|
307
295
|
const minOdds = leagueInfoByTypeId?.minOdds; // minimum odds configured for child market (e.g. 0.95 implied probability)
|
|
308
296
|
const maxOdds = leagueInfoByTypeId?.maxOdds; // maximum odds configured for child market (e.g. 0.05 implied probability)
|
|
@@ -355,7 +343,7 @@ export const createChildMarkets: (
|
|
|
355
343
|
* @param {string} oddsProvider - The main odds provider to filter by.
|
|
356
344
|
* @returns {Array} The filtered odds array.
|
|
357
345
|
*/
|
|
358
|
-
export const
|
|
346
|
+
export const filterOddsByMarketNameBookmaker = (oddsArray: Odds, leagueInfos: LeagueConfigInfo[]): any => {
|
|
359
347
|
const allChildMarketsTypes = leagueInfos
|
|
360
348
|
.filter(
|
|
361
349
|
(leagueInfo) =>
|
|
@@ -365,10 +353,7 @@ export const filterOdds = (oddsArray: Odds, leagueInfos: LeagueConfigInfo[], pla
|
|
|
365
353
|
.map((leagueInfo) => leagueInfo.marketName.toLowerCase());
|
|
366
354
|
return oddsArray.reduce((acc: any, odd: any) => {
|
|
367
355
|
if (allChildMarketsTypes.includes(odd.marketName.toLowerCase())) {
|
|
368
|
-
const { points, marketName, selection, selectionLine, sportsBookName
|
|
369
|
-
if (playerId && !playersMap.has(playerId)) {
|
|
370
|
-
return acc;
|
|
371
|
-
}
|
|
356
|
+
const { points, marketName, selection, selectionLine, sportsBookName } = odd;
|
|
372
357
|
const key = `${sportsBookName.toLowerCase()}_${marketName.toLowerCase()}_${points}_${selection}_${selectionLine}`;
|
|
373
358
|
acc[key] = {
|
|
374
359
|
...odd,
|
|
@@ -455,13 +440,6 @@ export const groupAndFormatTotalOdds = (oddsArray: any[], commonData: HomeAwayTe
|
|
|
455
440
|
acc[key].typeId = odd.typeId;
|
|
456
441
|
acc[key].type = odd.type;
|
|
457
442
|
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
|
-
}
|
|
465
443
|
}
|
|
466
444
|
|
|
467
445
|
return acc;
|
|
@@ -469,8 +447,8 @@ export const groupAndFormatTotalOdds = (oddsArray: any[], commonData: HomeAwayTe
|
|
|
469
447
|
|
|
470
448
|
// Format the grouped odds into the desired output
|
|
471
449
|
const formattedOdds = Object.entries(groupedOdds as any).reduce((acc: any, [key, value]) => {
|
|
472
|
-
const [_marketName, selection,
|
|
473
|
-
const line = parseFloat(
|
|
450
|
+
const [_marketName, selection, selectionLine] = key.split('_');
|
|
451
|
+
const line = parseFloat(selectionLine);
|
|
474
452
|
|
|
475
453
|
// if we have away team in total odds we know the market is team total and we need to increase typeId by one.
|
|
476
454
|
// if this is false typeId is already mapped correctly
|
|
@@ -482,7 +460,6 @@ export const groupAndFormatTotalOdds = (oddsArray: any[], commonData: HomeAwayTe
|
|
|
482
460
|
typeId: !isAwayTeam ? (value as any).typeId : Number((value as any).typeId) + 1,
|
|
483
461
|
sportId: (value as any).sportId,
|
|
484
462
|
type: (value as any).type,
|
|
485
|
-
playerProps: (value as any).playerProps,
|
|
486
463
|
});
|
|
487
464
|
}
|
|
488
465
|
return acc;
|
package/src/constants/odds.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
// For each ourOdds, this is the minimum otherOdds we require to NOT block
|
|
2
|
-
// USED FOR TESTS ONLY, real anchors are passed from risk repo
|
|
3
|
-
export const ODDS_THRESHOLD_ANCHORS = [
|
|
4
|
-
{ our: 1.05, otherMin: 1.03 },
|
|
5
|
-
{ our: 1.1, otherMin: 1.06 },
|
|
6
|
-
{ our: 1.2, otherMin: 1.15 },
|
|
7
|
-
{ our: 1.3, otherMin: 1.25 },
|
|
8
|
-
{ our: 1.4, otherMin: 1.33 },
|
|
9
|
-
{ our: 1.5, otherMin: 1.4 },
|
|
10
|
-
|
|
11
|
-
{ our: 2.0, otherMin: 1.85 },
|
|
12
|
-
{ our: 2.5, otherMin: 2.25 },
|
|
13
|
-
{ our: 3.0, otherMin: 2.5 },
|
|
14
|
-
{ our: 4.0, otherMin: 3.5 },
|
|
15
|
-
|
|
16
|
-
{ our: 8.0, otherMin: 6.5 },
|
|
17
|
-
{ our: 10.0, otherMin: 8.0 },
|
|
18
|
-
{ our: 100.0, otherMin: 70.0 },
|
|
19
|
-
];
|