overtime-live-trading-utils 4.0.3-rc.0 → 4.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/mock/MockLeagueMap.ts +0 -16
- package/src/tests/unit/bookmakers.test.ts +10 -173
- package/src/tests/unit/markets.test.ts +24 -17
- package/src/tests/unit/odds.test.ts +12 -9
- package/src/tests/unit/spread.test.ts +13 -11
- package/src/tests/utils/helper.ts +3 -10
- package/src/utils/bookmakers.ts +1 -31
- package/src/utils/markets.ts +2 -4
- package/src/utils/odds.ts +5 -8
- package/src/tests/mock/OpticOddsMock/MockNBAPlayerPropsAdjustment.ts +0 -476
- package/src/tests/mock/OpticOddsMock/MockRedisNbaPlayerPropsAdjustment.ts +0 -22
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "overtime-live-trading-utils",
|
|
3
|
-
"version": "4.0.3
|
|
3
|
+
"version": "4.0.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "main.js",
|
|
6
6
|
"scripts": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@types/node": "^20.8.10",
|
|
16
16
|
"oddslib": "^2.1.1",
|
|
17
|
-
"overtime-utils": "^0.1.
|
|
17
|
+
"overtime-utils": "^0.1.72",
|
|
18
18
|
"react": "^17.0.1"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
@@ -145,21 +145,6 @@ const PlayerAssist: LeagueConfigInfo[] = [
|
|
|
145
145
|
},
|
|
146
146
|
];
|
|
147
147
|
|
|
148
|
-
const PlayerAssistWithSecondaryBookmaker: LeagueConfigInfo[] = [
|
|
149
|
-
baseLeagueInfoNba,
|
|
150
|
-
{
|
|
151
|
-
sportId: 4,
|
|
152
|
-
enabled: 'true',
|
|
153
|
-
marketName: 'Player Assists',
|
|
154
|
-
typeId: 11039,
|
|
155
|
-
type: 'Total',
|
|
156
|
-
maxOdds: 0.25,
|
|
157
|
-
minOdds: 0.75,
|
|
158
|
-
primaryBookmaker: 'superbet',
|
|
159
|
-
secondaryBookmaker: 'draftkings',
|
|
160
|
-
},
|
|
161
|
-
];
|
|
162
|
-
|
|
163
148
|
const teamTotal2: LeagueConfigInfo = {
|
|
164
149
|
sportId: 9806,
|
|
165
150
|
enabled: 'true',
|
|
@@ -237,5 +222,4 @@ export const LeagueMocks = {
|
|
|
237
222
|
leagueInfoDisabledCorrectScoreAndDoubleChance,
|
|
238
223
|
leaguInfoDifferentPrimaryBookmaker,
|
|
239
224
|
PlayerAssist,
|
|
240
|
-
PlayerAssistWithSecondaryBookmaker,
|
|
241
225
|
};
|
|
@@ -11,19 +11,10 @@ import {
|
|
|
11
11
|
MockOnlyMoneylineWithDifferentSportsbook,
|
|
12
12
|
} from '../mock/MockOpticSoccer';
|
|
13
13
|
import { mockSoccer } from '../mock/MockSoccerRedis';
|
|
14
|
-
import {
|
|
15
|
-
MockPlayerPropsWithLowPoints,
|
|
16
|
-
MockPlayerPropsWithNegativeOnePointDiff,
|
|
17
|
-
MockPlayerPropsWithNoMatchingLine,
|
|
18
|
-
MockPlayerPropsWithOnePointDiff,
|
|
19
|
-
MockPlayerPropsWithTwoPointDiff,
|
|
20
|
-
} from '../mock/OpticOddsMock/MockNBAPlayerPropsAdjustment';
|
|
21
|
-
import { MockRedisNbaPlayerPropsAdjustment } from '../mock/OpticOddsMock/MockRedisNbaPlayerPropsAdjustment';
|
|
22
14
|
import {
|
|
23
15
|
getLastPolledDataForBookmakers,
|
|
24
16
|
getPlayersMap,
|
|
25
17
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
26
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK,
|
|
27
18
|
} from '../utils/helper';
|
|
28
19
|
|
|
29
20
|
const lastPolledData = getLastPolledDataForBookmakers();
|
|
@@ -42,8 +33,7 @@ describe('Bookmakers', () => {
|
|
|
42
33
|
LeagueMocks.leagueInfoEnabledSpeadAndTotals,
|
|
43
34
|
lastPolledData,
|
|
44
35
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
45
|
-
playersMap
|
|
46
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
36
|
+
playersMap
|
|
47
37
|
);
|
|
48
38
|
|
|
49
39
|
const hasOdds = market.odds.some(
|
|
@@ -67,8 +57,7 @@ describe('Bookmakers', () => {
|
|
|
67
57
|
LeagueMocks.leagueInfoOnlyParent,
|
|
68
58
|
lastPolledData,
|
|
69
59
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
70
|
-
playersMap
|
|
71
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
60
|
+
playersMap
|
|
72
61
|
);
|
|
73
62
|
|
|
74
63
|
const hasOdds = market.odds.some(
|
|
@@ -92,8 +81,7 @@ describe('Bookmakers', () => {
|
|
|
92
81
|
LeagueMocks.leagueInfoEnabledSpeadAndTotals,
|
|
93
82
|
lastPolledData,
|
|
94
83
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
95
|
-
playersMap
|
|
96
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
84
|
+
playersMap
|
|
97
85
|
);
|
|
98
86
|
|
|
99
87
|
const hasOdds = market.odds.some(
|
|
@@ -113,12 +101,12 @@ describe('Bookmakers', () => {
|
|
|
113
101
|
mapOpticOddsApiFixtureOdds([freshMockOpticSoccer])[0],
|
|
114
102
|
['bovada', 'draftkings'],
|
|
115
103
|
true,
|
|
104
|
+
|
|
116
105
|
ODDS_THRESHOLD_ANCHORS,
|
|
117
106
|
LeagueMocks.leagueInfoEnabledSpeadAndTotals,
|
|
118
107
|
lastPolledData,
|
|
119
108
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
120
|
-
playersMap
|
|
121
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
109
|
+
playersMap
|
|
122
110
|
);
|
|
123
111
|
|
|
124
112
|
expect(market.childMarkets.length).toBe(2);
|
|
@@ -132,12 +120,12 @@ describe('Bookmakers', () => {
|
|
|
132
120
|
mapOpticOddsApiFixtureOdds([freshMockOpticSoccer])[0],
|
|
133
121
|
['bovada', 'draftkings'],
|
|
134
122
|
true,
|
|
123
|
+
|
|
135
124
|
ODDS_THRESHOLD_ANCHORS,
|
|
136
125
|
LeagueMocks.leaguInfoDifferentPrimaryBookmaker,
|
|
137
126
|
lastPolledData,
|
|
138
127
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
139
|
-
playersMap
|
|
140
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
128
|
+
playersMap
|
|
141
129
|
);
|
|
142
130
|
|
|
143
131
|
expect(market.childMarkets.length).toBe(3);
|
|
@@ -150,13 +138,14 @@ describe('Bookmakers', () => {
|
|
|
150
138
|
freshMockSoccer,
|
|
151
139
|
mapOpticOddsApiFixtureOdds([freshMockOpticSoccer])[0],
|
|
152
140
|
['bovada', 'draftkings'],
|
|
141
|
+
|
|
153
142
|
true,
|
|
143
|
+
|
|
154
144
|
ODDS_THRESHOLD_ANCHORS,
|
|
155
145
|
LeagueMocks.leagueInfoEnabledSpeadAndTotals,
|
|
156
146
|
lastPolledData,
|
|
157
147
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
158
|
-
playersMap
|
|
159
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
148
|
+
playersMap
|
|
160
149
|
);
|
|
161
150
|
|
|
162
151
|
expect(market.childMarkets.length).toBe(1);
|
|
@@ -188,155 +177,3 @@ describe('Bookmakers', () => {
|
|
|
188
177
|
expect(__test__.shouldBlockOdds(OUR_ODDS, OTHER_ODDS, THRESHOLDS)).toBe(true);
|
|
189
178
|
});
|
|
190
179
|
});
|
|
191
|
-
|
|
192
|
-
describe('Bookmakers - Player Props Point Adjustment', () => {
|
|
193
|
-
it('Should find matching line when secondary bookmaker has 1 point higher', () => {
|
|
194
|
-
const freshMockRedis = JSON.parse(JSON.stringify(MockRedisNbaPlayerPropsAdjustment));
|
|
195
|
-
const freshMockOptic = JSON.parse(JSON.stringify(MockPlayerPropsWithOnePointDiff));
|
|
196
|
-
|
|
197
|
-
const market = processMarket(
|
|
198
|
-
freshMockRedis,
|
|
199
|
-
mapOpticOddsApiFixtureOdds([freshMockOptic])[0],
|
|
200
|
-
['superbet', 'draftkings'],
|
|
201
|
-
true,
|
|
202
|
-
ODDS_THRESHOLD_ANCHORS,
|
|
203
|
-
LeagueMocks.PlayerAssistWithSecondaryBookmaker,
|
|
204
|
-
lastPolledData,
|
|
205
|
-
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
206
|
-
playersMap,
|
|
207
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
208
|
-
);
|
|
209
|
-
|
|
210
|
-
// Should have child markets for player props
|
|
211
|
-
expect(market.childMarkets.length).toBeGreaterThan(0);
|
|
212
|
-
// Check that the player props were matched despite the 1 point difference
|
|
213
|
-
const playerPropsMarket = market.childMarkets.find((child: any) => child.playerProps?.playerId == 54321);
|
|
214
|
-
expect(playerPropsMarket).toBeDefined();
|
|
215
|
-
expect(playerPropsMarket.playerProps.playerName).toContain('James Harden');
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
it('Should find matching line when secondary bookmaker has 1 point lower', () => {
|
|
219
|
-
const freshMockRedis = JSON.parse(JSON.stringify(MockRedisNbaPlayerPropsAdjustment));
|
|
220
|
-
const freshMockOptic = JSON.parse(JSON.stringify(MockPlayerPropsWithNegativeOnePointDiff));
|
|
221
|
-
|
|
222
|
-
const market = processMarket(
|
|
223
|
-
freshMockRedis,
|
|
224
|
-
mapOpticOddsApiFixtureOdds([freshMockOptic])[0],
|
|
225
|
-
['superbet', 'draftkings'],
|
|
226
|
-
true,
|
|
227
|
-
ODDS_THRESHOLD_ANCHORS,
|
|
228
|
-
LeagueMocks.PlayerAssistWithSecondaryBookmaker,
|
|
229
|
-
lastPolledData,
|
|
230
|
-
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
231
|
-
playersMap,
|
|
232
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
233
|
-
);
|
|
234
|
-
|
|
235
|
-
// Should have child markets for player props
|
|
236
|
-
expect(market.childMarkets.length).toBeGreaterThan(0);
|
|
237
|
-
|
|
238
|
-
// Check that the player props were matched despite the -1 point difference
|
|
239
|
-
const playerPropsMarket = market.childMarkets.find((child: any) => child.playerProps?.playerId === 77889);
|
|
240
|
-
expect(playerPropsMarket).toBeDefined();
|
|
241
|
-
expect(playerPropsMarket.playerProps.playerName).toContain('LeBron James');
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
it('Should find matching line when secondary bookmaker has 2 points higher', () => {
|
|
245
|
-
const freshMockRedis = JSON.parse(JSON.stringify(MockRedisNbaPlayerPropsAdjustment));
|
|
246
|
-
const freshMockOptic = JSON.parse(JSON.stringify(MockPlayerPropsWithTwoPointDiff));
|
|
247
|
-
|
|
248
|
-
const market = processMarket(
|
|
249
|
-
freshMockRedis,
|
|
250
|
-
mapOpticOddsApiFixtureOdds([freshMockOptic])[0],
|
|
251
|
-
['superbet', 'draftkings'],
|
|
252
|
-
true,
|
|
253
|
-
ODDS_THRESHOLD_ANCHORS,
|
|
254
|
-
LeagueMocks.PlayerAssistWithSecondaryBookmaker,
|
|
255
|
-
lastPolledData,
|
|
256
|
-
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
257
|
-
playersMap,
|
|
258
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
259
|
-
);
|
|
260
|
-
|
|
261
|
-
// Should have child markets for player props
|
|
262
|
-
expect(market.childMarkets.length).toBeGreaterThan(0);
|
|
263
|
-
|
|
264
|
-
// Check that the player props were matched despite the 2 point difference
|
|
265
|
-
const playerPropsMarket = market.childMarkets.find((child: any) => child.playerProps?.playerId === 99001);
|
|
266
|
-
expect(playerPropsMarket).toBeDefined();
|
|
267
|
-
expect(playerPropsMarket.playerProps.playerName).toContain('Stephen Curry');
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
it('Should NOT find matching line when difference is too large (beyond step range)', () => {
|
|
271
|
-
const freshMockRedis = JSON.parse(JSON.stringify(MockRedisNbaPlayerPropsAdjustment));
|
|
272
|
-
const freshMockOptic = JSON.parse(JSON.stringify(MockPlayerPropsWithNoMatchingLine));
|
|
273
|
-
|
|
274
|
-
const market = processMarket(
|
|
275
|
-
freshMockRedis,
|
|
276
|
-
mapOpticOddsApiFixtureOdds([freshMockOptic])[0],
|
|
277
|
-
['superbet', 'draftkings'],
|
|
278
|
-
true,
|
|
279
|
-
ODDS_THRESHOLD_ANCHORS,
|
|
280
|
-
LeagueMocks.PlayerAssistWithSecondaryBookmaker,
|
|
281
|
-
lastPolledData,
|
|
282
|
-
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
283
|
-
playersMap,
|
|
284
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
285
|
-
);
|
|
286
|
-
|
|
287
|
-
// Check that the player props were NOT matched (5 point difference is too large for 25.5 points)
|
|
288
|
-
const playerPropsMarket = market.childMarkets.find((child: any) => child.playerProps?.playerId === 44556);
|
|
289
|
-
expect(playerPropsMarket).toBeUndefined();
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
it('Should find matching line with low point values using appropriate step calculation', () => {
|
|
293
|
-
const freshMockRedis = JSON.parse(JSON.stringify(MockRedisNbaPlayerPropsAdjustment));
|
|
294
|
-
const freshMockOptic = JSON.parse(JSON.stringify(MockPlayerPropsWithLowPoints));
|
|
295
|
-
|
|
296
|
-
const market = processMarket(
|
|
297
|
-
freshMockRedis,
|
|
298
|
-
mapOpticOddsApiFixtureOdds([freshMockOptic])[0],
|
|
299
|
-
['superbet', 'draftkings'],
|
|
300
|
-
true,
|
|
301
|
-
ODDS_THRESHOLD_ANCHORS,
|
|
302
|
-
LeagueMocks.PlayerAssistWithSecondaryBookmaker,
|
|
303
|
-
lastPolledData,
|
|
304
|
-
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
305
|
-
playersMap,
|
|
306
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
307
|
-
);
|
|
308
|
-
|
|
309
|
-
// Should have child markets for player props
|
|
310
|
-
expect(market.childMarkets.length).toBeGreaterThan(0);
|
|
311
|
-
|
|
312
|
-
// Check that the player props were matched with low points (10.5 vs 11.5)
|
|
313
|
-
const playerPropsMarket = market.childMarkets.find((child: any) => child.playerProps?.playerId === 11223);
|
|
314
|
-
expect(playerPropsMarket).toBeDefined();
|
|
315
|
-
expect(playerPropsMarket.playerProps.playerName).toContain('Anthony Davis');
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
it('Should work correctly with only primary bookmaker (no adjustment needed)', () => {
|
|
319
|
-
const freshMockRedis = JSON.parse(JSON.stringify(MockRedisNbaPlayerPropsAdjustment));
|
|
320
|
-
const freshMockOptic = JSON.parse(JSON.stringify(MockPlayerPropsWithOnePointDiff));
|
|
321
|
-
|
|
322
|
-
const market = processMarket(
|
|
323
|
-
freshMockRedis,
|
|
324
|
-
mapOpticOddsApiFixtureOdds([freshMockOptic])[0],
|
|
325
|
-
['superbet'], // Only primary bookmaker
|
|
326
|
-
true,
|
|
327
|
-
ODDS_THRESHOLD_ANCHORS,
|
|
328
|
-
LeagueMocks.PlayerAssist, // Config without secondary bookmaker
|
|
329
|
-
lastPolledData,
|
|
330
|
-
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
331
|
-
playersMap,
|
|
332
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
333
|
-
);
|
|
334
|
-
|
|
335
|
-
// Should still have child markets for player props
|
|
336
|
-
expect(market.childMarkets.length).toBeGreaterThan(0);
|
|
337
|
-
|
|
338
|
-
// Check that the player props were included (no adjustment logic needed)
|
|
339
|
-
const playerPropsMarket = market.childMarkets.find((child: any) => child.playerProps?.playerId === 54321);
|
|
340
|
-
expect(playerPropsMarket).toBeDefined();
|
|
341
|
-
});
|
|
342
|
-
});
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
getLastPolledDataForBookmakers,
|
|
12
12
|
getPlayersMap,
|
|
13
13
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
14
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK,
|
|
15
14
|
} from '../utils/helper';
|
|
16
15
|
|
|
17
16
|
const lastPolledData = getLastPolledDataForBookmakers();
|
|
@@ -27,13 +26,14 @@ describe('Markets', () => {
|
|
|
27
26
|
freshMockSoccer,
|
|
28
27
|
mapOpticOddsApiFixtureOdds([freshMockOpticSoccer])[0],
|
|
29
28
|
['draftkings'],
|
|
29
|
+
|
|
30
30
|
true,
|
|
31
|
+
|
|
31
32
|
ODDS_THRESHOLD_ANCHORS,
|
|
32
33
|
LeagueMocks.leagueInfoOnlyParent,
|
|
33
34
|
lastPolledData,
|
|
34
35
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
35
|
-
playersMap
|
|
36
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
36
|
+
playersMap
|
|
37
37
|
);
|
|
38
38
|
|
|
39
39
|
expect(market.childMarkets).toHaveLength(0);
|
|
@@ -46,13 +46,14 @@ describe('Markets', () => {
|
|
|
46
46
|
freshMockSoccer,
|
|
47
47
|
mapOpticOddsApiFixtureOdds([freshMockOpticSoccer])[0],
|
|
48
48
|
['draftkings'],
|
|
49
|
+
|
|
49
50
|
true,
|
|
51
|
+
|
|
50
52
|
ODDS_THRESHOLD_ANCHORS,
|
|
51
53
|
LeagueMocks.leagueInfoMockDisabledChilds,
|
|
52
54
|
lastPolledData,
|
|
53
55
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
54
|
-
playersMap
|
|
55
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
56
|
+
playersMap
|
|
56
57
|
);
|
|
57
58
|
|
|
58
59
|
expect(market.childMarkets).toHaveLength(0);
|
|
@@ -65,13 +66,14 @@ describe('Markets', () => {
|
|
|
65
66
|
freshMockSoccer,
|
|
66
67
|
mapOpticOddsApiFixtureOdds([freshMockOpticSoccer])[0],
|
|
67
68
|
['draftkings'],
|
|
69
|
+
|
|
68
70
|
true,
|
|
71
|
+
|
|
69
72
|
ODDS_THRESHOLD_ANCHORS,
|
|
70
73
|
LeagueMocks.leagueInfoEnabledSpreadDisabledTotals,
|
|
71
74
|
lastPolledData,
|
|
72
75
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
73
|
-
playersMap
|
|
74
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
76
|
+
playersMap
|
|
75
77
|
);
|
|
76
78
|
|
|
77
79
|
const containsSpread = market.childMarkets.some((child: any) => child.type === 'spread');
|
|
@@ -88,13 +90,14 @@ describe('Markets', () => {
|
|
|
88
90
|
freshMockSoccer,
|
|
89
91
|
mapOpticOddsApiFixtureOdds([freshMockOpticSoccer])[0],
|
|
90
92
|
['draftkings'],
|
|
93
|
+
|
|
91
94
|
true,
|
|
95
|
+
|
|
92
96
|
ODDS_THRESHOLD_ANCHORS,
|
|
93
97
|
LeagueMocks.leagueInfoEnabledSpeadAndTotals,
|
|
94
98
|
lastPolledData,
|
|
95
99
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
96
|
-
playersMap
|
|
97
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
100
|
+
playersMap
|
|
98
101
|
);
|
|
99
102
|
|
|
100
103
|
const containsSpread = market.childMarkets.some((child: any) => child.type === 'spread');
|
|
@@ -111,13 +114,14 @@ describe('Markets', () => {
|
|
|
111
114
|
freshMockSoccer,
|
|
112
115
|
mapOpticOddsApiFixtureOdds([freshMockOpticSoccer])[0],
|
|
113
116
|
['draftkings'],
|
|
117
|
+
|
|
114
118
|
true,
|
|
119
|
+
|
|
115
120
|
ODDS_THRESHOLD_ANCHORS,
|
|
116
121
|
LeagueMocks.leagueInfoEnabledAll,
|
|
117
122
|
lastPolledData,
|
|
118
123
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
119
|
-
playersMap
|
|
120
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
124
|
+
playersMap
|
|
121
125
|
);
|
|
122
126
|
|
|
123
127
|
const containsSpread = market.childMarkets.some((child: any) => child.type === 'spread');
|
|
@@ -166,13 +170,14 @@ describe('Markets', () => {
|
|
|
166
170
|
freshMockSoccer,
|
|
167
171
|
mapOpticOddsApiFixtureOdds([freshMockOpticSoccer])[0],
|
|
168
172
|
['draftkings'],
|
|
173
|
+
|
|
169
174
|
true,
|
|
175
|
+
|
|
170
176
|
ODDS_THRESHOLD_ANCHORS,
|
|
171
177
|
LeagueMocks.leagueInfoOnlyParentDiffSportId,
|
|
172
178
|
lastPolledData,
|
|
173
179
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
174
|
-
playersMap
|
|
175
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
180
|
+
playersMap
|
|
176
181
|
);
|
|
177
182
|
|
|
178
183
|
expect(warnSpy).toHaveBeenCalled();
|
|
@@ -189,13 +194,14 @@ describe('Markets', () => {
|
|
|
189
194
|
freshMockSoccer,
|
|
190
195
|
mapOpticOddsApiFixtureOdds([freshMockOpticSoccer])[0],
|
|
191
196
|
['bovada', 'draftkings'], // this will be ignored as primaryBookmaker is defined in LeagueMap
|
|
197
|
+
|
|
192
198
|
true,
|
|
199
|
+
|
|
193
200
|
ODDS_THRESHOLD_ANCHORS,
|
|
194
201
|
LeagueMocks.PlayerAssist, // league map with player props configured
|
|
195
202
|
lastPolledData,
|
|
196
203
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
197
|
-
playersMap
|
|
198
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
204
|
+
playersMap
|
|
199
205
|
);
|
|
200
206
|
|
|
201
207
|
market.childMarkets.forEach((child: any) => {
|
|
@@ -212,13 +218,14 @@ describe('Markets', () => {
|
|
|
212
218
|
freshMockSoccer,
|
|
213
219
|
mapOpticOddsApiFixtureOdds([freshMockOpticSoccer])[0],
|
|
214
220
|
['bovada', 'draftkings'], // this will be ignored as primaryBookmaker is defined in LeagueMap
|
|
221
|
+
|
|
215
222
|
true,
|
|
223
|
+
|
|
216
224
|
ODDS_THRESHOLD_ANCHORS,
|
|
217
225
|
LeagueMocks.PlayerAssist, // league map with player props configured
|
|
218
226
|
lastPolledData,
|
|
219
227
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
220
|
-
playersMap
|
|
221
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
228
|
+
playersMap
|
|
222
229
|
);
|
|
223
230
|
|
|
224
231
|
market.childMarkets.forEach((child: any) => {
|
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
getLastPolledDataForBookmakers,
|
|
15
15
|
getPlayersMap,
|
|
16
16
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
17
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK,
|
|
18
17
|
} from '../utils/helper';
|
|
19
18
|
|
|
20
19
|
const lastPolledData = getLastPolledDataForBookmakers();
|
|
@@ -28,13 +27,14 @@ describe('Odds', () => {
|
|
|
28
27
|
freshMockSoccer,
|
|
29
28
|
mapOpticOddsApiFixtureOdds([freshMockOpticSoccer])[0],
|
|
30
29
|
['draftkings'],
|
|
30
|
+
|
|
31
31
|
true,
|
|
32
|
+
|
|
32
33
|
ODDS_THRESHOLD_ANCHORS,
|
|
33
34
|
LeagueMocks.leagueInfoOnlyParent,
|
|
34
35
|
lastPolledData,
|
|
35
36
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
36
|
-
playersMap
|
|
37
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
37
|
+
playersMap
|
|
38
38
|
);
|
|
39
39
|
|
|
40
40
|
const hasOdds = market.odds.some(
|
|
@@ -51,13 +51,14 @@ describe('Odds', () => {
|
|
|
51
51
|
freshMockSoccer,
|
|
52
52
|
mapOpticOddsApiFixtureOdds([freshMockOpticSoccer])[0],
|
|
53
53
|
['draftkings'],
|
|
54
|
+
|
|
54
55
|
true,
|
|
56
|
+
|
|
55
57
|
ODDS_THRESHOLD_ANCHORS,
|
|
56
58
|
LeagueMocks.leagueInfoEnabledSpeadAndTotals,
|
|
57
59
|
lastPolledData,
|
|
58
60
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
59
|
-
playersMap
|
|
60
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
61
|
+
playersMap
|
|
61
62
|
);
|
|
62
63
|
|
|
63
64
|
const hasOdds = market.odds.some(
|
|
@@ -76,13 +77,14 @@ describe('Odds', () => {
|
|
|
76
77
|
freshMockSoccer,
|
|
77
78
|
mapOpticOddsApiFixtureOdds([freshMockOpticSoccer])[0],
|
|
78
79
|
['draftkings'],
|
|
80
|
+
|
|
79
81
|
true,
|
|
82
|
+
|
|
80
83
|
ODDS_THRESHOLD_ANCHORS,
|
|
81
84
|
LeagueMocks.leagueInfoEnabledSpeadAndTotals,
|
|
82
85
|
lastPolledData,
|
|
83
86
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
84
|
-
playersMap
|
|
85
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
87
|
+
playersMap
|
|
86
88
|
);
|
|
87
89
|
|
|
88
90
|
const hasChildMarkets = market.childMarkets.length > 0;
|
|
@@ -96,13 +98,14 @@ describe('Odds', () => {
|
|
|
96
98
|
freshMockSoccer,
|
|
97
99
|
mapOpticOddsApiFixtureOdds([freshMockOpticSoccer])[0],
|
|
98
100
|
['draftkings'],
|
|
101
|
+
|
|
99
102
|
true,
|
|
103
|
+
|
|
100
104
|
ODDS_THRESHOLD_ANCHORS,
|
|
101
105
|
LeagueMocks.leagueInfoEnabledSpeadAndTotals,
|
|
102
106
|
lastPolledData,
|
|
103
107
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
104
|
-
playersMap
|
|
105
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
108
|
+
playersMap
|
|
106
109
|
);
|
|
107
110
|
|
|
108
111
|
expect(market.childMarkets).toHaveLength(0);
|
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
getLastPolledDataForBookmakers,
|
|
10
10
|
getPlayersMap,
|
|
11
11
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
12
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK,
|
|
13
12
|
} from '../utils/helper';
|
|
14
13
|
|
|
15
14
|
const lastPolledData = getLastPolledDataForBookmakers();
|
|
@@ -28,8 +27,7 @@ describe('Spread configuration', () => {
|
|
|
28
27
|
LeagueMocks.leagueInfoEnabledSpeadAndTotals,
|
|
29
28
|
lastPolledData,
|
|
30
29
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
31
|
-
playersMap
|
|
32
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
30
|
+
playersMap
|
|
33
31
|
);
|
|
34
32
|
|
|
35
33
|
const hasOdds = market.odds.some(
|
|
@@ -50,13 +48,14 @@ describe('Spread configuration', () => {
|
|
|
50
48
|
freshMockSoccer,
|
|
51
49
|
mapOpticOddsApiFixtureOdds([freshMockOpticSoccer])[0],
|
|
52
50
|
['draftkings'],
|
|
51
|
+
|
|
53
52
|
true,
|
|
53
|
+
|
|
54
54
|
ODDS_THRESHOLD_ANCHORS,
|
|
55
55
|
LeagueMocks.leagueInfoOnlyParent,
|
|
56
56
|
lastPolledData,
|
|
57
57
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
58
|
-
playersMap
|
|
59
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
58
|
+
playersMap
|
|
60
59
|
)
|
|
61
60
|
)
|
|
62
61
|
);
|
|
@@ -67,13 +66,14 @@ describe('Spread configuration', () => {
|
|
|
67
66
|
freshMockSoccer,
|
|
68
67
|
mapOpticOddsApiFixtureOdds([freshMockOpticSoccer])[0],
|
|
69
68
|
['draftkings'],
|
|
69
|
+
|
|
70
70
|
true,
|
|
71
|
+
|
|
71
72
|
ODDS_THRESHOLD_ANCHORS,
|
|
72
73
|
LeagueMocks.leagueInfoOnlyParentWithSpreadAdded,
|
|
73
74
|
lastPolledData,
|
|
74
75
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
75
|
-
playersMap
|
|
76
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
76
|
+
playersMap
|
|
77
77
|
)
|
|
78
78
|
)
|
|
79
79
|
);
|
|
@@ -104,13 +104,14 @@ describe('Spread configuration', () => {
|
|
|
104
104
|
freshMockSoccer,
|
|
105
105
|
mapOpticOddsApiFixtureOdds([freshMockOpticSoccer])[0],
|
|
106
106
|
['draftkings'],
|
|
107
|
+
|
|
107
108
|
true,
|
|
109
|
+
|
|
108
110
|
ODDS_THRESHOLD_ANCHORS,
|
|
109
111
|
LeagueMocks.leagueInfoOnlyParent,
|
|
110
112
|
lastPolledData,
|
|
111
113
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
112
|
-
playersMap
|
|
113
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
114
|
+
playersMap
|
|
114
115
|
)
|
|
115
116
|
)
|
|
116
117
|
);
|
|
@@ -121,13 +122,14 @@ describe('Spread configuration', () => {
|
|
|
121
122
|
freshMockSoccer,
|
|
122
123
|
mapOpticOddsApiFixtureOdds([freshMockOpticSoccer])[0],
|
|
123
124
|
['draftkings'],
|
|
125
|
+
|
|
124
126
|
true,
|
|
127
|
+
|
|
125
128
|
ODDS_THRESHOLD_ANCHORS,
|
|
126
129
|
LeagueMocks.leagueInfoOnlyParentWithSpreadAdded,
|
|
127
130
|
lastPolledData,
|
|
128
131
|
MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
|
|
129
|
-
playersMap
|
|
130
|
-
MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK
|
|
132
|
+
playersMap
|
|
131
133
|
)
|
|
132
134
|
)
|
|
133
135
|
);
|
|
@@ -10,17 +10,10 @@ export const getLastPolledDataForBookmakers = () => {
|
|
|
10
10
|
|
|
11
11
|
export const getPlayersMap = () => {
|
|
12
12
|
const playersMap: Map<string, number> = new Map<string, number>();
|
|
13
|
-
playersMap
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
.set('674851E026BC', 98765)
|
|
17
|
-
.set('CC707B1EADE5', 54321)
|
|
18
|
-
.set('JKL012', 11223)
|
|
19
|
-
.set('GHI789', 44556)
|
|
20
|
-
.set('ABC123', 77889)
|
|
21
|
-
.set('DEF456', 99001);
|
|
13
|
+
playersMap.set('0C07D14CC5DC', 13234);
|
|
14
|
+
playersMap.set('AD91EA260284', 56789);
|
|
15
|
+
playersMap.set('674851E026BC', 98765);
|
|
22
16
|
return playersMap;
|
|
23
17
|
};
|
|
24
|
-
export const MAX_PERCENTAGE_DIFF_FOR_PP_LINES_MOCK = 10; // 10%, used for tests, the production value is from env variable
|
|
25
18
|
|
|
26
19
|
export const MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST = 30000; // 30 seconds
|
package/src/utils/bookmakers.ts
CHANGED
|
@@ -156,8 +156,7 @@ export const checkOddsFromBookmakersForChildMarkets = (
|
|
|
156
156
|
oddsProviders: string[],
|
|
157
157
|
lastPolledData: LastPolledArray,
|
|
158
158
|
maxAllowedProviderDataStaleDelay: number,
|
|
159
|
-
anchors: Anchor[]
|
|
160
|
-
percentageDiffForPPLines: number
|
|
159
|
+
anchors: Anchor[]
|
|
161
160
|
): OddsWithLeagueInfo => {
|
|
162
161
|
const formattedOdds = Object.entries(odds as any).reduce((acc: any, [key, value]: [string, any]) => {
|
|
163
162
|
const [sportsBookName, marketName, points, selection, selectionLine] = key.split('_');
|
|
@@ -184,7 +183,6 @@ export const checkOddsFromBookmakersForChildMarkets = (
|
|
|
184
183
|
}
|
|
185
184
|
} else {
|
|
186
185
|
if (sportsBookName.toLowerCase() === primaryBookmaker) {
|
|
187
|
-
if (value.playerId && !value.isMain) return acc; // Skip if not main for player props
|
|
188
186
|
const secondaryBookmakerObject =
|
|
189
187
|
odds[
|
|
190
188
|
`${secondaryBookmaker}_${marketName.toLowerCase()}_${points}_${selection}_${selectionLine}`
|
|
@@ -196,24 +194,6 @@ export const checkOddsFromBookmakersForChildMarkets = (
|
|
|
196
194
|
}
|
|
197
195
|
|
|
198
196
|
acc.push(value);
|
|
199
|
-
} else {
|
|
200
|
-
// if its player props and we didnt find the correct line, try adjusting points by steps defined and search again
|
|
201
|
-
if (value.playerId) {
|
|
202
|
-
const steps = getStepsForPointAdjustment(Number(points), percentageDiffForPPLines);
|
|
203
|
-
for (const step of steps) {
|
|
204
|
-
const adjustedPoints = (Number(points) + step).toString();
|
|
205
|
-
|
|
206
|
-
const secondaryBookmakerObject =
|
|
207
|
-
odds[
|
|
208
|
-
`${secondaryBookmaker}_${marketName.toLowerCase()}_${adjustedPoints}_${selection}_${selectionLine}`
|
|
209
|
-
];
|
|
210
|
-
|
|
211
|
-
if (secondaryBookmakerObject) {
|
|
212
|
-
acc.push(value);
|
|
213
|
-
break;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
197
|
}
|
|
218
198
|
}
|
|
219
199
|
}
|
|
@@ -316,15 +296,5 @@ const shouldBlockOdds = (ourOdds: number, otherOdds: number, anchors: Anchor[])
|
|
|
316
296
|
return otherOdds < requiredOther;
|
|
317
297
|
};
|
|
318
298
|
|
|
319
|
-
const getStepsForPointAdjustment = (points: number, percentageDiffForPPLines: number): number[] => {
|
|
320
|
-
const stepsDelta = Math.round((points * percentageDiffForPPLines) / 100); // Example logic: 10% of the points value
|
|
321
|
-
const steps: number[] = [];
|
|
322
|
-
for (let index = 1; index <= stepsDelta; index++) {
|
|
323
|
-
steps.push(-index, index);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
return steps;
|
|
327
|
-
};
|
|
328
|
-
|
|
329
299
|
// Export only when running tests
|
|
330
300
|
export const __test__ = { getRequiredOtherOdds, shouldBlockOdds };
|