Our door onto OpticOdds. Scores, lists, and ticket grading are running. DraftKings combos are off. We do not take prices from OpticOdds yet. 22 Sep 2026.
Running
Grade a ticket
Inside our network, no login. Open a tunnel, then ask for the ticket. book is bet105 or bracco. live=true asks for the score while the game is still going. save=false returns the grade and does not store it.
kubectl -n drever-feeds port-forward svc/drever-feeds-optic-grade 8000:8000
curl 'http://127.0.0.1:8000/api/grade/bet105/TICKET_ID'
curl 'http://127.0.0.1:8000/api/grade/bet105/TICKET_ID?live=true'
curl 'http://127.0.0.1:8000/api/grade/bracco/TICKET_ID?save=false'
Inside the cluster the host is drever-feeds-optic-grade.drever-feeds.svc.cluster.local:8000. A bad book is 400. No legs is 404. Missing setup is 503. A failure talking to OpticOdds is 502.
/healthzIs the process up.
/api/grade/{book}/{ticket_id}One ticket, leg by leg, folded into one result.
How a grade is built
- grade_ticketgrade/grader.py Loads every leg, maps each one, asks OpticOdds once per leg, folds a ticket result, and saves it unless told not to.
- grade_from_coordinatesgrade/grader.py Grades one leg. Turns our market id into the name OpticOdds expects.
- fold_ticketgrade/grader.py One lost leg loses the ticket. An unmapped leg makes it ungradeable. A pending leg keeps it pending. A refunded leg drops out of a parlay. A half result on a parlay is partial.
- market_labelgrade/grader.py Our mappings store
moneyline. OpticOdds wants Moneyline.
- resolvegrade/mapping/mapper.py The same mapper the front end uses. Game, market, and selection name.
- LeagueResolvergrade/mapping/league_resolver.py Sport and league name to an OpticOdds league id.
- GradeReadClient.gradegrade/read_client.py Leagues, markets, games on the board, games that have started, and the grader.
- fetch_ticket_legsgrade/store.py Parsed legs from
clv.bet_ticker. Unparsed player props come back as unsupported.
- upsert_leg_gradegrade/store.py Saves each leg and the ticket. Pending can become Won or Lost later.
Running
Scores
A connection stays open to OpticOdds and writes each result as it arrives. The same event updates the match block: score, period, and clock. Injuries are asked for separately and attached to our player ids. There is no public address. These paths are on the pod.
/stream/statusWhich leagues share a connection, and how many events each has written.
/stream/fixturesMapped games, leagues on the live connection, and games we could not place.
/stream/results/{fixture_id}Latest result. The id is the OpticOdds game id.
/stream/results/kibl/{id}Same result, from our fixture id.
/stream/mblock/{fixture_id}Latest match block: score, clock, and game state.
/stream/mblock/kibl/{id}Same match block, from our fixture id.
/stream/injuries/{fixture_id}Injuries for that game, tied to our participant ids.
/stream/injuries/kibl/{id}Same injuries, from our fixture id.
A league is followed from 30 minutes before a mapped game starts until 8 hours after, and also when OpticOdds says a game in that league is live. Sports include soccer, basketball, football, baseball, tennis, hockey, and a long tail: golf, mixed martial arts, boxing, cricket, rugby, volleyball.
What does the work
- StreamController.runstream/controller.py Splits leagues across connections, at most ten each.
- ShardPlannerstream/controller.py Keeps a league on the same connection.
- ResultsWorkerstream/worker.py One live connection for a sport. A drop reconnects and replays from the last event.
- build_m_blockstream/mblock.py Match block from the same event. Live 6 hours, finished 15 minutes, unplayed 3 hours.
- ResultStorestream/store.py Writes the result, the match block, and the injuries together.
- InjuryPoller.runstream/injuries.py Asks for injuries and binds each row to our participant id.
- FixtureRegistrymapping/registry.py Reads the fixture record kibl-service keeps, including the OpticOdds id.
Running
Reference lists
Downloads OpticOdds’ own lists and stores them as they arrived. Teams and players cover soccer, basketball, football, baseball, and tennis. Leagues and markets cover every sport. A full download once a day, a smaller refresh every 30 minutes.
/readyzReady after the first full download. Until then it answers 503.
/catalog/statusHow many rows each list has, and when it was last pulled.
src:optic:sports
src:optic:leagues
src:optic:markets
src:optic:sportsbooks
src:optic:teams
src:optic:players
What does the work
- CatalogController.runcatalog/controller.py Full download at startup and once a day. Smaller refresh every 30 minutes.
- CatalogPullercatalog/pull.py Walks each list page by page. The same market id under several sports is stored once.
- CatalogStorecatalog/store.py Swaps the new list in one step. Each list expires after 14 days if the pod stops.
Off
DraftKings combos
Zero pods. The publish switch is unset, so nothing is pulled and nothing is sent to the odds wire. When it is on, the site is combos.danchrow.com, only on our network. A game is addressed by DraftKings’ own event id. Football only.
/todayGames whose start falls on today’s date in New York.
/currentEvery game this pod knows, soonest first.
/{source_event_id}Combos for one game. The number is DraftKings’ event id.
/openbook/combosEvery game, in the shape we would publish.
/combos/statusWhether publishing is on, and the counts.
What does the work
- CombosController.runcombos/controller.py Walks mapped football games, finds the DraftKings event, and keeps the cards. Publishes only when the switch is on.
- DkClientcombos/dk_client.py The only code that talks to DraftKings.
- parse_schedule / parse_comboscombos/dk_schedule.py Matches a game by team names and start time, then reads combo cards.
- OpticComboTranslator.translateopenbook_translate/optic.py A combo card becomes the messages we would publish. The event is the DraftKings event id.
- OpenBookPublishercombos/openbook.py Writes to
ob:odds:draftkings when the switch is on. The switch is off.
Not running
Calls we can make to OpticOdds
Listed in optic/endpoints.py. Scores, the lists, and the grader use them. A public pass-through at /optic/{key} is not running. Supplier address: https://api.opticodds.com/api/v3.
| Name | Path | Used for |
| sports, leagues, markets, sportsbooks, teams, players | reference | The daily lists. |
| fixtures | /fixtures | Needs sport and league. The grader also asks by start date. |
| fixtures_active | /fixtures/active | Finds which leagues are live. |
| odds, player_props, futures, parlay_odds | pricing | Nothing in production polls these. |
| results | /fixtures/results | The live path is the open connection. |
| injuries | /injuries | The scores copy polls this. |
| grader | /grader/odds | Needs the market name, such as Moneyline. The grade copy uses this. |