overtime-live-trading-utils 2.1.33 → 2.1.35
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/CLAUDE.md +26 -19
- package/main.js +1 -1
- package/package.json +1 -1
- package/resolution_live_markets.md +93 -88
- package/src/tests/mock/MockOpticOddsEvents.ts +144 -0
- package/src/tests/unit/resolution.test.ts +471 -71
- package/src/types/resolution.ts +25 -25
- package/src/utils/resolution.ts +43 -22
- package/src/utils/sportPeriodMapping.ts +36 -0
- package/tsconfig.json +3 -7
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
# Live Market Resolution - TypeId-Based Implementation Plan
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
|
+
|
|
4
5
|
Enhance the resolution utilities to support checking if specific market types (identified by `typeId`) can be resolved based on which periods are complete in a live game.
|
|
5
6
|
|
|
6
7
|
## Problem Statement
|
|
8
|
+
|
|
7
9
|
The current `canResolveMarketForGameIdAndSport` function only checks if periods are complete, but doesn't answer the key question: **"Can I resolve market type 10021 (e.g., 1st Quarter Winner) right now?"**
|
|
8
10
|
|
|
9
11
|
For live trading, we need to know which specific markets can be resolved based on:
|
|
12
|
+
|
|
10
13
|
1. Which periods have been completed
|
|
11
14
|
2. The market type (typeId)
|
|
12
15
|
3. Whether the game is still live or fully completed
|
|
@@ -14,12 +17,14 @@ For live trading, we need to know which specific markets can be resolved based o
|
|
|
14
17
|
## Understanding TypeIds
|
|
15
18
|
|
|
16
19
|
TypeIds identify specific market types:
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
20
|
+
|
|
21
|
+
- `10021` - 1st period/quarter/half markets (various bet types)
|
|
22
|
+
- `10022` - 2nd period markets
|
|
23
|
+
- `10031` - 1st period totals
|
|
24
|
+
- `0`, `10001`, `10002` - Full game markets (should NOT resolve during live games)
|
|
21
25
|
|
|
22
26
|
Example from codebase:
|
|
27
|
+
|
|
23
28
|
```typescript
|
|
24
29
|
{
|
|
25
30
|
sportId: 9806,
|
|
@@ -32,6 +37,7 @@ Example from codebase:
|
|
|
32
37
|
## Solution Design
|
|
33
38
|
|
|
34
39
|
### 1. Sport-Specific Period-to-TypeId Mappings
|
|
40
|
+
|
|
35
41
|
Created three separate mappings for different sport period structures:
|
|
36
42
|
|
|
37
43
|
```typescript
|
|
@@ -70,13 +76,15 @@ const FULL_GAME_TYPE_IDS = [0, 10001, 10002, 10003, 10004, 10010, 10011, 10012];
|
|
|
70
76
|
```
|
|
71
77
|
|
|
72
78
|
**Key Insight**: TypeId 10051 (1st half) resolves at different periods depending on sport type:
|
|
73
|
-
|
|
74
|
-
-
|
|
75
|
-
-
|
|
79
|
+
|
|
80
|
+
- Soccer (HALVES): Period 1
|
|
81
|
+
- NFL (QUARTERS): Period 2 (after both quarters 1 & 2)
|
|
82
|
+
- MLB (INNINGS): Period 5 (after first 5 innings)
|
|
76
83
|
|
|
77
84
|
### 2. Updated Function Signature
|
|
78
85
|
|
|
79
86
|
**Before:**
|
|
87
|
+
|
|
80
88
|
```typescript
|
|
81
89
|
canResolveMarketForGameIdAndSport(
|
|
82
90
|
gameId: string,
|
|
@@ -86,6 +94,7 @@ canResolveMarketForGameIdAndSport(
|
|
|
86
94
|
```
|
|
87
95
|
|
|
88
96
|
**After:**
|
|
97
|
+
|
|
89
98
|
```typescript
|
|
90
99
|
// Single typeId overload
|
|
91
100
|
canResolveMarketsForEvent(
|
|
@@ -122,7 +131,7 @@ function selectMappingForSportType(sportType: SportPeriodType) {
|
|
|
122
131
|
export function canResolveMarketsForEvent(
|
|
123
132
|
event: OpticOddsEvent,
|
|
124
133
|
typeIdOrTypeIds: number | number[],
|
|
125
|
-
sportType: SportPeriodType,
|
|
134
|
+
sportType: SportPeriodType, // REQUIRED - must specify sport type
|
|
126
135
|
sportName?: string
|
|
127
136
|
): boolean | number[] {
|
|
128
137
|
// Get completed periods
|
|
@@ -143,7 +152,7 @@ export function canResolveMarketsForEvent(
|
|
|
143
152
|
|
|
144
153
|
for (const period of periodData.completedPeriods) {
|
|
145
154
|
const typeIdsForPeriod = mapping[period] || [];
|
|
146
|
-
typeIdsForPeriod.forEach(id => resolvableTypeIds.add(id));
|
|
155
|
+
typeIdsForPeriod.forEach((id) => resolvableTypeIds.add(id));
|
|
147
156
|
}
|
|
148
157
|
|
|
149
158
|
// Full game typeIds can only be resolved when game is completed
|
|
@@ -163,7 +172,7 @@ export function canResolveMarketsForEvent(
|
|
|
163
172
|
|
|
164
173
|
// Batch typeIds check
|
|
165
174
|
if (typeIds !== undefined) {
|
|
166
|
-
return typeIds.filter(id => {
|
|
175
|
+
return typeIds.filter((id) => {
|
|
167
176
|
// Exclude full game typeIds during live games
|
|
168
177
|
if (!isCompleted && FULL_GAME_TYPE_IDS.includes(id)) {
|
|
169
178
|
return false;
|
|
@@ -173,76 +182,80 @@ export function canResolveMarketsForEvent(
|
|
|
173
182
|
}
|
|
174
183
|
|
|
175
184
|
return false;
|
|
176
|
-
}
|
|
185
|
+
}
|
|
177
186
|
```
|
|
178
187
|
|
|
179
188
|
### 4. Why Sport Parameter is Needed
|
|
180
189
|
|
|
181
190
|
Different sports have different period structures:
|
|
182
|
-
|
|
183
|
-
-
|
|
184
|
-
-
|
|
185
|
-
-
|
|
186
|
-
-
|
|
191
|
+
|
|
192
|
+
- **Soccer**: 2 halves (periods 1-2)
|
|
193
|
+
- **NFL/NBA**: 4 quarters (periods 1-4)
|
|
194
|
+
- **MLB**: 9+ innings (periods 1-9)
|
|
195
|
+
- **NHL**: 3 periods (periods 1-3)
|
|
196
|
+
- **Tennis**: Sets (periods 1-5)
|
|
187
197
|
|
|
188
198
|
The sport parameter allows future customization where period-to-typeId mappings could be sport-specific. For example:
|
|
189
|
-
|
|
190
|
-
-
|
|
191
|
-
-
|
|
199
|
+
|
|
200
|
+
- Soccer might map period 1 → "1st Half" markets
|
|
201
|
+
- Basketball might map period 1 → "1st Quarter" markets
|
|
202
|
+
- Both use period 1, but represent different market types
|
|
192
203
|
|
|
193
204
|
## Implementation Steps
|
|
194
205
|
|
|
195
206
|
### Phase 1: Add Sport-Specific Mappings ✅ COMPLETED
|
|
196
|
-
|
|
197
|
-
-
|
|
198
|
-
-
|
|
199
|
-
-
|
|
200
|
-
-
|
|
201
|
-
-
|
|
207
|
+
|
|
208
|
+
- [x] Add `SportPeriodType` enum to `src/types/resolution.ts`
|
|
209
|
+
- [x] Add `HALVES_PERIOD_TYPE_ID_MAPPING` to `src/types/resolution.ts`
|
|
210
|
+
- [x] Add `QUARTERS_PERIOD_TYPE_ID_MAPPING` to `src/types/resolution.ts`
|
|
211
|
+
- [x] Add `INNINGS_PERIOD_TYPE_ID_MAPPING` to `src/types/resolution.ts`
|
|
212
|
+
- [x] Add `FULL_GAME_TYPE_IDS` to `src/types/resolution.ts`
|
|
213
|
+
- [x] Export all constants and enum
|
|
202
214
|
|
|
203
215
|
### Phase 2: Update Resolution Function ✅ COMPLETED
|
|
204
|
-
|
|
205
|
-
-
|
|
206
|
-
-
|
|
207
|
-
-
|
|
208
|
-
-
|
|
216
|
+
|
|
217
|
+
- [x] Update `canResolveMarketsForEvent` function signature to accept `sportType` parameter
|
|
218
|
+
- [x] Implement sport-type-based mapping selection logic
|
|
219
|
+
- [x] Update function overloads for clean API (no undefined placeholders)
|
|
220
|
+
- [x] Handle full game typeIds exclusion during live games
|
|
221
|
+
- [x] Keep backward compatibility with existing functions
|
|
209
222
|
|
|
210
223
|
### Phase 3: Add Tests ✅ COMPLETED
|
|
211
|
-
|
|
212
|
-
-
|
|
213
|
-
-
|
|
214
|
-
-
|
|
215
|
-
-
|
|
216
|
-
-
|
|
217
|
-
-
|
|
218
|
-
-
|
|
224
|
+
|
|
225
|
+
- [x] Test single typeId resolution
|
|
226
|
+
- [x] Test batch typeIds resolution
|
|
227
|
+
- [x] Test that full game typeIds are NOT resolved during live games
|
|
228
|
+
- [x] Test with real event data (Soccer, NFL, MLB)
|
|
229
|
+
- [x] Test edge cases (no completed periods, game in overtime, etc.)
|
|
230
|
+
- [x] Add sport-specific tests for typeId 10051 (1st half) with HALVES, QUARTERS, INNINGS
|
|
231
|
+
- [x] Add sport-specific tests for typeId 10052 (2nd half)
|
|
232
|
+
- [x] Test default behavior (QUARTERS_BASED when no sportType provided)
|
|
219
233
|
|
|
220
234
|
### Phase 4: Update Exports ✅ COMPLETED
|
|
221
|
-
|
|
222
|
-
-
|
|
223
|
-
-
|
|
224
|
-
-
|
|
225
|
-
-
|
|
226
|
-
-
|
|
235
|
+
|
|
236
|
+
- [x] Export `SportPeriodType` enum from index.ts
|
|
237
|
+
- [x] Export `HALVES_PERIOD_TYPE_ID_MAPPING` from index.ts
|
|
238
|
+
- [x] Export `QUARTERS_PERIOD_TYPE_ID_MAPPING` from index.ts
|
|
239
|
+
- [x] Export `INNINGS_PERIOD_TYPE_ID_MAPPING` from index.ts
|
|
240
|
+
- [x] Export `FULL_GAME_TYPE_IDS` from index.ts
|
|
241
|
+
- [x] Keep existing exports for backward compatibility
|
|
227
242
|
|
|
228
243
|
### Phase 5: Testing & Validation ✅ COMPLETED
|
|
229
|
-
|
|
230
|
-
-
|
|
231
|
-
-
|
|
232
|
-
-
|
|
244
|
+
|
|
245
|
+
- [x] Run full test suite
|
|
246
|
+
- [x] Verify all 85 tests pass
|
|
247
|
+
- [x] Test with real OpticOdds API responses (Soccer, NFL, MLB)
|
|
248
|
+
- [x] Verify TypeScript compilation succeeds
|
|
233
249
|
|
|
234
250
|
## Example Usage
|
|
235
251
|
|
|
236
252
|
### Single TypeId Check
|
|
253
|
+
|
|
237
254
|
```typescript
|
|
238
255
|
import { canResolveMarketsForEvent, SportPeriodType } from 'overtime-live-trading-utils';
|
|
239
256
|
|
|
240
257
|
// Check NFL (quarters-based) - Can we resolve "1st Quarter Winner" market (typeId 10021)?
|
|
241
|
-
const canResolve = canResolveMarketsForEvent(
|
|
242
|
-
nflEvent,
|
|
243
|
-
10021,
|
|
244
|
-
SportPeriodType.QUARTERS_BASED
|
|
245
|
-
);
|
|
258
|
+
const canResolve = canResolveMarketsForEvent(nflEvent, 10021, SportPeriodType.QUARTERS_BASED);
|
|
246
259
|
|
|
247
260
|
if (canResolve) {
|
|
248
261
|
// Resolve the 1st quarter market
|
|
@@ -251,52 +264,40 @@ if (canResolve) {
|
|
|
251
264
|
```
|
|
252
265
|
|
|
253
266
|
### Sport-Specific TypeId 10051 (1st Half) Resolution
|
|
267
|
+
|
|
254
268
|
```typescript
|
|
255
269
|
// Soccer (halves-based): Resolves after period 1
|
|
256
|
-
const soccerCanResolve = canResolveMarketsForEvent(
|
|
257
|
-
soccerEvent,
|
|
258
|
-
10051,
|
|
259
|
-
SportPeriodType.HALVES_BASED
|
|
260
|
-
); // true if period 1 complete
|
|
270
|
+
const soccerCanResolve = canResolveMarketsForEvent(soccerEvent, 10051, SportPeriodType.HALVES_BASED); // true if period 1 complete
|
|
261
271
|
|
|
262
272
|
// NFL (quarters-based): Resolves after period 2
|
|
263
|
-
const nflCanResolve = canResolveMarketsForEvent(
|
|
264
|
-
nflEvent,
|
|
265
|
-
10051,
|
|
266
|
-
SportPeriodType.QUARTERS_BASED
|
|
267
|
-
); // true if period 2 complete
|
|
273
|
+
const nflCanResolve = canResolveMarketsForEvent(nflEvent, 10051, SportPeriodType.QUARTERS_BASED); // true if period 2 complete
|
|
268
274
|
|
|
269
275
|
// MLB (innings-based): Resolves after period 5
|
|
270
|
-
const mlbCanResolve = canResolveMarketsForEvent(
|
|
271
|
-
mlbEvent,
|
|
272
|
-
10051,
|
|
273
|
-
SportPeriodType.INNINGS_BASED
|
|
274
|
-
); // true if period 5 complete
|
|
276
|
+
const mlbCanResolve = canResolveMarketsForEvent(mlbEvent, 10051, SportPeriodType.INNINGS_BASED); // true if period 5 complete
|
|
275
277
|
```
|
|
276
278
|
|
|
277
279
|
### Batch TypeIds Check
|
|
280
|
+
|
|
278
281
|
```typescript
|
|
279
282
|
// Which of these markets can we resolve right now for an NFL game?
|
|
280
283
|
const marketTypeIds = [10021, 10022, 10031, 10001];
|
|
281
|
-
const resolvableMarkets = canResolveMarketsForEvent(
|
|
282
|
-
nflEvent,
|
|
283
|
-
marketTypeIds,
|
|
284
|
-
SportPeriodType.QUARTERS_BASED
|
|
285
|
-
);
|
|
284
|
+
const resolvableMarkets = canResolveMarketsForEvent(nflEvent, marketTypeIds, SportPeriodType.QUARTERS_BASED);
|
|
286
285
|
|
|
287
286
|
// Returns: [10021, 10031] if only period 1 is complete
|
|
288
287
|
// Full game typeId 10001 is excluded during live games
|
|
289
|
-
resolvableMarkets.forEach(typeId => resolveMarket(typeId));
|
|
288
|
+
resolvableMarkets.forEach((typeId) => resolveMarket(typeId));
|
|
290
289
|
```
|
|
291
290
|
|
|
292
291
|
### Function Overloads (TypeScript)
|
|
292
|
+
|
|
293
293
|
The function uses TypeScript overloads for clean API:
|
|
294
|
+
|
|
294
295
|
```typescript
|
|
295
296
|
// Single typeId → returns boolean
|
|
296
297
|
function canResolveMarketsForEvent(
|
|
297
298
|
event: OpticOddsEvent,
|
|
298
299
|
typeId: number,
|
|
299
|
-
sportType: SportPeriodType,
|
|
300
|
+
sportType: SportPeriodType, // REQUIRED
|
|
300
301
|
sportName?: string
|
|
301
302
|
): boolean;
|
|
302
303
|
|
|
@@ -304,7 +305,7 @@ function canResolveMarketsForEvent(
|
|
|
304
305
|
function canResolveMarketsForEvent(
|
|
305
306
|
event: OpticOddsEvent,
|
|
306
307
|
typeIds: number[],
|
|
307
|
-
sportType: SportPeriodType,
|
|
308
|
+
sportType: SportPeriodType, // REQUIRED
|
|
308
309
|
sportName?: string
|
|
309
310
|
): number[];
|
|
310
311
|
```
|
|
@@ -312,25 +313,29 @@ function canResolveMarketsForEvent(
|
|
|
312
313
|
## Testing Strategy
|
|
313
314
|
|
|
314
315
|
### Test Cases
|
|
316
|
+
|
|
315
317
|
1. **Period 1 Complete (Live Soccer 2nd Half)**
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
318
|
+
|
|
319
|
+
- Input: Soccer event in 2nd half, period 1 complete
|
|
320
|
+
- TypeIds: [10021, 10022, 10001]
|
|
321
|
+
- Expected: [10021] (only 1st half markets resolvable)
|
|
319
322
|
|
|
320
323
|
2. **Periods 1-4 Complete (NFL Overtime)**
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
+
|
|
325
|
+
- Input: NFL event in overtime, all 4 quarters complete
|
|
326
|
+
- TypeIds: [10021, 10022, 10023, 10024, 10001]
|
|
327
|
+
- Expected: [10021, 10022, 10023, 10024] (all quarter markets, but not full game)
|
|
324
328
|
|
|
325
329
|
3. **Game Completed**
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
330
|
+
|
|
331
|
+
- Input: Completed game with all periods
|
|
332
|
+
- TypeIds: [10021, 10001]
|
|
333
|
+
- Expected: [10021, 10001] (all markets including full game)
|
|
329
334
|
|
|
330
335
|
4. **No Periods Complete**
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
336
|
+
- Input: Live game in 1st period
|
|
337
|
+
- TypeIds: [10021, 10022]
|
|
338
|
+
- Expected: [] (no markets resolvable yet)
|
|
334
339
|
|
|
335
340
|
## Benefits
|
|
336
341
|
|
|
@@ -516,3 +516,147 @@ export const MockNFLCompletedWithOvertime = {
|
|
|
516
516
|
clock: null,
|
|
517
517
|
},
|
|
518
518
|
};
|
|
519
|
+
|
|
520
|
+
export const MockNBACompletedEvent = {
|
|
521
|
+
sport: {
|
|
522
|
+
id: 'basketball',
|
|
523
|
+
name: 'Basketball',
|
|
524
|
+
numerical_id: 4,
|
|
525
|
+
},
|
|
526
|
+
league: {
|
|
527
|
+
id: 'nba',
|
|
528
|
+
name: 'NBA',
|
|
529
|
+
numerical_id: 355,
|
|
530
|
+
},
|
|
531
|
+
fixture: {
|
|
532
|
+
id: '202511053DEE59D4',
|
|
533
|
+
numerical_id: 402396,
|
|
534
|
+
game_id: '10459-24860-2025-11-04',
|
|
535
|
+
start_date: '2025-11-05T03:00:00Z',
|
|
536
|
+
home_competitors: [
|
|
537
|
+
{
|
|
538
|
+
id: 'DFC9A735A4D7',
|
|
539
|
+
name: 'Golden State Warriors',
|
|
540
|
+
numerical_id: 21801,
|
|
541
|
+
base_id: 14357,
|
|
542
|
+
abbreviation: 'GSW',
|
|
543
|
+
logo: 'https://cdn.opticodds.com/team-logos/basketball/14357.png',
|
|
544
|
+
},
|
|
545
|
+
],
|
|
546
|
+
away_competitors: [
|
|
547
|
+
{
|
|
548
|
+
id: '9BF9A5FD18B1',
|
|
549
|
+
name: 'Phoenix Suns',
|
|
550
|
+
numerical_id: 21815,
|
|
551
|
+
base_id: 14371,
|
|
552
|
+
abbreviation: 'PHX',
|
|
553
|
+
logo: 'https://cdn.opticodds.com/team-logos/basketball/14371.png',
|
|
554
|
+
},
|
|
555
|
+
],
|
|
556
|
+
home_team_display: 'Golden State Warriors',
|
|
557
|
+
away_team_display: 'Phoenix Suns',
|
|
558
|
+
status: 'completed',
|
|
559
|
+
is_live: false,
|
|
560
|
+
season_type: 'Regular Season',
|
|
561
|
+
season_year: '2025',
|
|
562
|
+
season_week: '45',
|
|
563
|
+
venue_name: 'Chase Center',
|
|
564
|
+
venue_location: 'San Francisco, CA, USA',
|
|
565
|
+
venue_neutral: false,
|
|
566
|
+
},
|
|
567
|
+
scores: {
|
|
568
|
+
home: {
|
|
569
|
+
total: 118.0,
|
|
570
|
+
periods: {
|
|
571
|
+
period_1: 33.0,
|
|
572
|
+
period_2: 35.0,
|
|
573
|
+
period_3: 24.0,
|
|
574
|
+
period_4: 26.0,
|
|
575
|
+
},
|
|
576
|
+
aggregate: null,
|
|
577
|
+
},
|
|
578
|
+
away: {
|
|
579
|
+
total: 107.0,
|
|
580
|
+
periods: {
|
|
581
|
+
period_1: 19.0,
|
|
582
|
+
period_2: 30.0,
|
|
583
|
+
period_3: 34.0,
|
|
584
|
+
period_4: 24.0,
|
|
585
|
+
},
|
|
586
|
+
aggregate: null,
|
|
587
|
+
},
|
|
588
|
+
},
|
|
589
|
+
in_play: {
|
|
590
|
+
period: '4',
|
|
591
|
+
clock: null,
|
|
592
|
+
},
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
export const MockNBALiveAtHalftime = {
|
|
596
|
+
sport: {
|
|
597
|
+
id: 'basketball',
|
|
598
|
+
name: 'Basketball',
|
|
599
|
+
numerical_id: 4,
|
|
600
|
+
},
|
|
601
|
+
league: {
|
|
602
|
+
id: 'nba',
|
|
603
|
+
name: 'NBA',
|
|
604
|
+
numerical_id: 355,
|
|
605
|
+
},
|
|
606
|
+
fixture: {
|
|
607
|
+
id: '202511053DEE59D4',
|
|
608
|
+
numerical_id: 402396,
|
|
609
|
+
game_id: '10459-24860-2025-11-04',
|
|
610
|
+
start_date: '2025-11-05T03:00:00Z',
|
|
611
|
+
home_competitors: [
|
|
612
|
+
{
|
|
613
|
+
id: 'DFC9A735A4D7',
|
|
614
|
+
name: 'Golden State Warriors',
|
|
615
|
+
numerical_id: 21801,
|
|
616
|
+
base_id: 14357,
|
|
617
|
+
abbreviation: 'GSW',
|
|
618
|
+
logo: 'https://cdn.opticodds.com/team-logos/basketball/14357.png',
|
|
619
|
+
},
|
|
620
|
+
],
|
|
621
|
+
away_competitors: [
|
|
622
|
+
{
|
|
623
|
+
id: '9BF9A5FD18B1',
|
|
624
|
+
name: 'Phoenix Suns',
|
|
625
|
+
numerical_id: 21815,
|
|
626
|
+
base_id: 14371,
|
|
627
|
+
abbreviation: 'PHX',
|
|
628
|
+
logo: 'https://cdn.opticodds.com/team-logos/basketball/14371.png',
|
|
629
|
+
},
|
|
630
|
+
],
|
|
631
|
+
home_team_display: 'Golden State Warriors',
|
|
632
|
+
away_team_display: 'Phoenix Suns',
|
|
633
|
+
status: 'half',
|
|
634
|
+
is_live: true,
|
|
635
|
+
season_type: 'Regular Season',
|
|
636
|
+
season_year: '2025',
|
|
637
|
+
season_week: '45',
|
|
638
|
+
venue_name: 'Chase Center',
|
|
639
|
+
venue_location: 'San Francisco, CA, USA',
|
|
640
|
+
venue_neutral: false,
|
|
641
|
+
},
|
|
642
|
+
scores: {
|
|
643
|
+
home: {
|
|
644
|
+
total: 68.0,
|
|
645
|
+
periods: {
|
|
646
|
+
period_1: 33.0,
|
|
647
|
+
period_2: 35.0,
|
|
648
|
+
},
|
|
649
|
+
},
|
|
650
|
+
away: {
|
|
651
|
+
total: 49.0,
|
|
652
|
+
periods: {
|
|
653
|
+
period_1: 19.0,
|
|
654
|
+
period_2: 30.0,
|
|
655
|
+
},
|
|
656
|
+
},
|
|
657
|
+
},
|
|
658
|
+
in_play: {
|
|
659
|
+
period: 'half',
|
|
660
|
+
clock: null,
|
|
661
|
+
},
|
|
662
|
+
};
|