overtime-live-trading-utils 2.1.44 → 2.1.45-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.
@@ -1,10 +1,7 @@
1
1
  import * as oddslib from 'oddslib';
2
- import {
3
- DIFF_BETWEEN_BOOKMAKERS_MESSAGE,
4
- ZERO_ODDS_AFTER_SPREAD_ADJUSTMENT,
5
- ZERO_ODDS_MESSAGE,
6
- } from '../constants/errors';
2
+ import { ZERO_ODDS_AFTER_SPREAD_ADJUSTMENT } from '../constants/errors';
7
3
  import { OddsObject } from '../types/odds';
4
+ import { LastPolledArray } from '../types/sports';
8
5
  import { createChildMarkets, getParentOdds } from './odds';
9
6
  import { getLeagueInfo } from './sports';
10
7
  import { adjustAddedSpread } from './spread';
@@ -30,8 +27,10 @@ export const processMarket = (
30
27
  spreadData: any,
31
28
  isDrawAvailable: any,
32
29
  defaultSpreadForLiveMarkets: any,
33
- maxPercentageDiffBetwenOdds: any,
34
- leagueMap: any
30
+ maxPercentageDiffBetwenOdds: number,
31
+ leagueMap: any,
32
+ lastPolledData: LastPolledArray,
33
+ maxAllowedProviderDataStaleDelay: number
35
34
  ) => {
36
35
  const sportSpreadData = spreadData.filter((data: any) => data.sportId === String(market.leagueId));
37
36
  const leagueInfo = getLeagueInfo(market.leagueId, leagueMap);
@@ -43,7 +42,10 @@ export const processMarket = (
43
42
  apiResponseWithOdds,
44
43
  market.leagueId,
45
44
  defaultSpreadForLiveMarkets,
46
- maxPercentageDiffBetwenOdds
45
+ maxPercentageDiffBetwenOdds,
46
+ leagueInfo,
47
+ lastPolledData,
48
+ maxAllowedProviderDataStaleDelay
47
49
  );
48
50
 
49
51
  const oddsAfterSpread = adjustAddedSpread(moneylineOdds.odds, leagueInfo, market.typeId);
@@ -78,42 +80,41 @@ export const processMarket = (
78
80
  });
79
81
  }
80
82
 
81
- if ([ZERO_ODDS_MESSAGE, DIFF_BETWEEN_BOOKMAKERS_MESSAGE].includes(moneylineOdds.errorMessage || '')) {
82
- market.childMarkets = [];
83
- } else {
84
- const childMarkets = createChildMarkets(
85
- apiResponseWithOdds,
86
- sportSpreadData,
87
- market.leagueId,
88
- liveOddsProviders,
89
- defaultSpreadForLiveMarkets,
90
- leagueMap
91
- );
92
-
93
- const packedChildMarkets = childMarkets.map((childMarket: any) => {
94
- const preparedMarket = { ...market, ...childMarket };
95
- const oddsAfterSpread = adjustAddedSpread(preparedMarket.odds, leagueInfo, preparedMarket.typeId);
96
- if (preparedMarket.odds.length > 0) {
97
- preparedMarket.odds = oddsAfterSpread.map((probability) => {
98
- if (probability == 0) {
99
- return {
100
- american: 0,
101
- decimal: 0,
102
- normalizedImplied: 0,
103
- };
104
- }
83
+ const childMarkets = createChildMarkets(
84
+ apiResponseWithOdds,
85
+ sportSpreadData,
86
+ market.leagueId,
87
+ liveOddsProviders,
88
+ defaultSpreadForLiveMarkets,
89
+ leagueMap,
90
+ lastPolledData,
91
+ maxAllowedProviderDataStaleDelay,
92
+ maxPercentageDiffBetwenOdds
93
+ );
105
94
 
95
+ const packedChildMarkets = childMarkets.map((childMarket: any) => {
96
+ const preparedMarket = { ...market, ...childMarket };
97
+ const oddsAfterSpread = adjustAddedSpread(preparedMarket.odds, leagueInfo, preparedMarket.typeId);
98
+ if (preparedMarket.odds.length > 0) {
99
+ preparedMarket.odds = oddsAfterSpread.map((probability) => {
100
+ if (probability == 0) {
106
101
  return {
107
- american: oddslib.from('impliedProbability', probability).to('moneyline'),
108
- decimal: Number(oddslib.from('impliedProbability', probability).to('decimal').toFixed(10)),
109
- normalizedImplied: probability,
102
+ american: 0,
103
+ decimal: 0,
104
+ normalizedImplied: 0,
110
105
  };
111
- });
112
- }
113
- return preparedMarket;
114
- });
115
- market.childMarkets = packedChildMarkets;
116
- }
106
+ }
107
+
108
+ return {
109
+ american: oddslib.from('impliedProbability', probability).to('moneyline'),
110
+ decimal: Number(oddslib.from('impliedProbability', probability).to('decimal').toFixed(10)),
111
+ normalizedImplied: probability,
112
+ };
113
+ });
114
+ }
115
+ return preparedMarket;
116
+ });
117
+ market.childMarkets = packedChildMarkets;
117
118
 
118
119
  return market;
119
120
  };
package/src/utils/odds.ts CHANGED
@@ -1,11 +1,16 @@
1
1
  import * as oddslib from 'oddslib';
2
2
  import { MarketType, MarketTypeMap } from 'overtime-utils';
3
3
  import { DRAW, MIN_ODDS_FOR_DIFF_CHECKING, MONEYLINE_TYPE_ID, ZERO } from '../constants/common';
4
- import { NO_MARKETS_FOR_LEAGUE_ID } from '../constants/errors';
4
+ import { LAST_POLLED_TOO_OLD, NO_MARKETS_FOR_LEAGUE_ID } from '../constants/errors';
5
5
  import { MoneylineTypes } from '../enums/sports';
6
6
  import { HomeAwayTeams, Odds, OddsObject } from '../types/odds';
7
- import { ChildMarket, LeagueConfigInfo } from '../types/sports';
8
- import { checkOddsFromBookmakers } from './bookmakers';
7
+ import { ChildMarket, LastPolledArray, LeagueConfigInfo } from '../types/sports';
8
+ import {
9
+ checkOddsFromBookmakers,
10
+ checkOddsFromBookmakersForChildMarkets,
11
+ getPrimaryAndSecondaryBookmakerForTypeId,
12
+ isLastPolledForBookmakersValid,
13
+ } from './bookmakers';
9
14
  import { getLeagueInfo } from './sports';
10
15
  import { adjustSpreadOnOdds, getSpreadData } from './spread';
11
16
 
@@ -123,10 +128,33 @@ export const getParentOdds = (
123
128
  oddsApiObject: OddsObject,
124
129
  sportId: string,
125
130
  defaultSpreadForLiveMarkets: number,
126
- maxPercentageDiffBetwenOdds: number
131
+ maxPercentageDiffBetwenOdds: number,
132
+ leagueInfo: LeagueConfigInfo[],
133
+ lastPolledMap: LastPolledArray,
134
+ maxAllowedProviderDataStaleDelay: number
127
135
  ) => {
128
136
  const commonData = { homeTeam: oddsApiObject.homeTeam, awayTeam: oddsApiObject.awayTeam };
129
137
 
138
+ const { primaryBookmaker, secondaryBookmaker } = getPrimaryAndSecondaryBookmakerForTypeId(
139
+ liveOddsProviders,
140
+ leagueInfo,
141
+ 0 // typeId for moneyline
142
+ );
143
+
144
+ const isValidLastPolled = isLastPolledForBookmakersValid(
145
+ lastPolledMap,
146
+ maxAllowedProviderDataStaleDelay,
147
+ primaryBookmaker,
148
+ secondaryBookmaker
149
+ );
150
+
151
+ if (!isValidLastPolled) {
152
+ return {
153
+ odds: isTwoPositionalSport ? [0, 0] : [0, 0, 0],
154
+ errorMessage: LAST_POLLED_TOO_OLD,
155
+ };
156
+ }
157
+
130
158
  // EXTRACTING ODDS FROM THE RESPONSE PER MARKET NAME AND BOOKMAKER
131
159
  const moneylineOddsMap = filterOddsByMarketNameTeamNameBookmaker(
132
160
  oddsApiObject.odds,
@@ -184,14 +212,20 @@ export const createChildMarkets: (
184
212
  leagueId: number,
185
213
  liveOddsProviders: any,
186
214
  defaultSpreadForLiveMarkets: any,
187
- leagueMap: any
215
+ leagueMap: any,
216
+ lastPolledData: LastPolledArray,
217
+ maxAllowedProviderDataStaleDelay: number,
218
+ maxImpliedPercentageDifference: number
188
219
  ) => ChildMarket[] = (
189
220
  apiResponseWithOdds,
190
221
  spreadDataForSport,
191
222
  leagueId,
192
223
  liveOddsProviders,
193
224
  defaultSpreadForLiveMarkets,
194
- leagueMap
225
+ leagueMap,
226
+ lastPolledData,
227
+ maxAllowedProviderDataStaleDelay,
228
+ maxImpliedPercentageDifference
195
229
  ) => {
196
230
  const [spreadOdds, totalOdds, moneylineOdds, correctScoreOdds, doubleChanceOdds, ggOdds, childMarkets]: any[] = [
197
231
  [],
@@ -209,14 +243,16 @@ export const createChildMarkets: (
209
243
  };
210
244
 
211
245
  if (leagueInfo.length > 0) {
212
- // TODO ADD ODDS COMPARISON BETWEEN BOOKMAKERS
213
- const allChildOdds = filterOddsByMarketNameBookmaker(
214
- apiResponseWithOdds.odds,
246
+ const allChildOdds = filterOddsByMarketNameBookmaker(apiResponseWithOdds.odds, leagueInfo);
247
+ const checkedChildOdds = checkOddsFromBookmakersForChildMarkets(
248
+ allChildOdds,
215
249
  leagueInfo,
216
- liveOddsProviders[0]
250
+ liveOddsProviders,
251
+ lastPolledData,
252
+ maxAllowedProviderDataStaleDelay,
253
+ maxImpliedPercentageDifference
217
254
  );
218
-
219
- allChildOdds.forEach((odd) => {
255
+ checkedChildOdds.forEach((odd) => {
220
256
  if (odd.type === 'Total') {
221
257
  if (Math.abs(Number(odd.points) % 1) === 0.5) totalOdds.push(odd);
222
258
  } else if (odd.type === 'Spread') {
@@ -241,6 +277,7 @@ export const createChildMarkets: (
241
277
  ];
242
278
  const otherFormattedOdds = [...groupAndFormatCorrectScoreOdds(correctScoreOdds, commonData)];
243
279
 
280
+ // odds are converted to implied probability inside adjustSpreadOnChildOdds
244
281
  const homeAwayOddsWithSpreadAdjusted = adjustSpreadOnChildOdds(
245
282
  homeAwayFormattedOdds,
246
283
  spreadDataForSport,
@@ -256,18 +293,20 @@ export const createChildMarkets: (
256
293
  odds: data.odds,
257
294
  };
258
295
  const leagueInfoByTypeId = leagueInfo.find((league) => Number(league.typeId) === Number(data.typeId));
259
- const minOdds = leagueInfoByTypeId?.minOdds;
260
- const maxOdds = leagueInfoByTypeId?.maxOdds;
261
- if (
262
- !(
263
- minOdds &&
264
- maxOdds &&
265
- (data.odds[0] >= minOdds ||
266
- data.odds[0] <= maxOdds ||
267
- data.odds[1] >= minOdds ||
268
- data.odds[1] <= maxOdds)
269
- )
270
- ) {
296
+ const minOdds = leagueInfoByTypeId?.minOdds; // minimum odds configured for child market (e.g. 0.95 implied probability)
297
+ const maxOdds = leagueInfoByTypeId?.maxOdds; // maximum odds configured for child market (e.g. 0.05 implied probability)
298
+
299
+ if (minOdds && maxOdds) {
300
+ let conditionToAddChildMarket = true;
301
+ data.odds.forEach((odd: number) => {
302
+ if (odd >= minOdds || odd <= maxOdds) {
303
+ conditionToAddChildMarket = false;
304
+ }
305
+ });
306
+ if (conditionToAddChildMarket) {
307
+ childMarkets.push(childMarket);
308
+ }
309
+ } else {
271
310
  childMarkets.push(childMarket);
272
311
  }
273
312
  });
@@ -305,11 +344,7 @@ export const createChildMarkets: (
305
344
  * @param {string} oddsProvider - The main odds provider to filter by.
306
345
  * @returns {Array} The filtered odds array.
307
346
  */
308
- export const filterOddsByMarketNameBookmaker = (
309
- oddsArray: Odds,
310
- leagueInfos: LeagueConfigInfo[],
311
- oddsProvider: string
312
- ): any[] => {
347
+ export const filterOddsByMarketNameBookmaker = (oddsArray: Odds, leagueInfos: LeagueConfigInfo[]): any => {
313
348
  const allChildMarketsTypes = leagueInfos
314
349
  .filter(
315
350
  (leagueInfo) =>
@@ -317,20 +352,20 @@ export const filterOddsByMarketNameBookmaker = (
317
352
  leagueInfo.enabled === 'true'
318
353
  )
319
354
  .map((leagueInfo) => leagueInfo.marketName.toLowerCase());
320
- return oddsArray
321
- .filter(
322
- (odd) =>
323
- allChildMarketsTypes.includes(odd.marketName.toLowerCase()) &&
324
- odd.sportsBookName.toLowerCase() == oddsProvider.toLowerCase()
325
- )
326
- .map((odd) => {
327
- return {
355
+ return oddsArray.reduce((acc: any, odd: any) => {
356
+ if (allChildMarketsTypes.includes(odd.marketName.toLowerCase())) {
357
+ const { points, marketName, selection, selectionLine, sportsBookName } = odd;
358
+ const key = `${sportsBookName.toLowerCase()}_${marketName.toLowerCase()}_${points}_${selection}_${selectionLine}`;
359
+ acc[key] = {
328
360
  ...odd,
329
361
  ...leagueInfos.find(
330
362
  (leagueInfo) => leagueInfo.marketName.toLowerCase() === odd.marketName.toLowerCase()
331
363
  ), // using .find() for team totals means that we will always assign 10017 as typeID at this point
332
364
  };
333
- });
365
+ }
366
+
367
+ return acc;
368
+ }, {}) as any;
334
369
  };
335
370
 
336
371
  /**
package/tsconfig.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "compilerOptions": {
3
3
  "module": "esnext",
4
4
  "esModuleInterop": true,
5
- "target": "es5",
5
+ "target": "ESNext",
6
6
  "lib": [
7
7
  "dom",
8
8
  "dom.iterable",