Skip to content

Commit

Permalink
Fitted first goalscorer
Browse files Browse the repository at this point in the history
  • Loading branch information
ekoutanov committed Nov 30, 2023
1 parent 95c3e12 commit 238b27a
Show file tree
Hide file tree
Showing 8 changed files with 416 additions and 188 deletions.
7 changes: 3 additions & 4 deletions benches/cri_interval.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
use criterion::{Criterion, criterion_group, criterion_main};

use brumby::interval;
use brumby::interval::{IntervalConfig, other_player};
use brumby::interval::IntervalConfig;

fn criterion_benchmark(c: &mut Criterion) {
fn run(intervals: u8) -> usize {
interval::explore_all(&IntervalConfig {
interval::explore(&IntervalConfig {
intervals,
home_prob: 0.25,
away_prob: 0.25,
common_prob: 0.25,
max_total_goals: u16::MAX,
home_scorers: other_player(),
away_scorers: other_player(),
scorers: vec![],
}).prospects.len()
}

Expand Down
46 changes: 42 additions & 4 deletions src/bin/soccer.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
use std::collections::HashMap;
use std::collections::{BTreeMap, HashMap};
use std::time::Instant;

use HAlign::Left;
use stanza::renderer::console::Console;
use stanza::renderer::Renderer;
use stanza::style::{HAlign, MinWidth, Styles};
use stanza::table::{Col, Row, Table};
use brumby::entity::{MarketType, OutcomeType, Over, Player, Score, Side};
use brumby::entity::Player::Named;
use brumby::interval::{explore, IntervalConfig, isolate};

use brumby::linear::matrix::Matrix;
use brumby::market::{Market, Overround, OverroundMethod, PriceBounds};
use brumby::opt::{hypergrid_search, HypergridSearchConfig, HypergridSearchOutcome};
use brumby::probs::SliceExt;
use brumby::scoregrid;
use brumby::scoregrid::{MarketType, OutcomeType, Over, Player, Score, Side};
use Player::Named;

const OVERROUND_METHOD: OverroundMethod = OverroundMethod::OddsRatio;
const SINGLE_PRICE_BOUNDS: PriceBounds = 1.04..=200.0;
const ZERO_INFLATION: f64 = 0.015;
const INTERVALS: usize = 10;
const INTERVALS: usize = 6;
const MAX_TOTAL_GOALS: u16 = 8;

type Odds = HashMap<OutcomeType, f64>;
Expand Down Expand Up @@ -219,6 +220,19 @@ pub fn main() {
);
// println!("scoregrid:\n{}sum: {}", scoregrid.verbose(), scoregrid.flatten().sum());

let mut first_goalscorer_probs = BTreeMap::new();
for (index, outcome) in first_gs.outcomes.iter().enumerate() {
match outcome {
OutcomeType::Player(player) => {
let player_search_outcome = fit_first_goalscorer(&search_outcome.optimal_values, player, first_gs.market.probs[index]);
println!("for player {player:?}, {player_search_outcome:?}");
first_goalscorer_probs.insert(player.clone(), player_search_outcome.optimal_values[0]);
}
OutcomeType::None => {},
_ => unreachable!()
}
}

let fitted_h2h = frame_prices(&scoregrid, &h2h.outcomes, &h2h.market.overround);
let fitted_h2h = LabelledMarket {
outcomes: h2h.outcomes.clone(),
Expand Down Expand Up @@ -317,6 +331,30 @@ fn fit_scoregrid(markets: &[&LabelledMarket]) -> HypergridSearchOutcome {
)
}

fn fit_first_goalscorer(optimal_scoring_probs: &[f64], player: &Player, expected_prob: f64) -> HypergridSearchOutcome {
hypergrid_search(
&HypergridSearchConfig {
max_steps: 100,
acceptable_residual: 1e-6,
bounds: vec![0.0001..=0.2].into(),
resolution: 4,
},
|values| true,
|values| {
let exploration = explore(&IntervalConfig {
intervals: INTERVALS as u8,
home_prob: optimal_scoring_probs[0],
away_prob: optimal_scoring_probs[1],
common_prob: optimal_scoring_probs[2],
max_total_goals: MAX_TOTAL_GOALS,
scorers: vec![(player.clone(), values[0])],
});
let isolated_prob = isolate(&MarketType::FirstGoalscorer, &OutcomeType::Player(player.clone()), &exploration.prospects);
((isolated_prob - expected_prob)/expected_prob).powi(2)
},
)
}

/// Intervals.
fn interval_scoregrid(interval_home_prob: f64, interval_away_prob: f64, interval_common_prob: f64) -> Matrix<f64> {
let dim = usize::min(MAX_TOTAL_GOALS as usize, INTERVALS) + 1;
Expand Down
62 changes: 62 additions & 0 deletions src/entity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Score {
pub home: u8,
pub away: u8,
}
impl Score {
pub fn new(home: u8, away: u8) -> Self {
Self { home, away }
}

pub fn nil_all() -> Self {
Self {
home: 0,
away: 0
}
}

pub fn total(&self) -> u16 {
(self.home + self.away) as u16
}
}

#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Over(pub u8);

#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Under(pub u8);

#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum MarketType {
HeadToHead,
TotalGoalsOverUnder(Over),
CorrectScore,
DrawNoBet,
AnytimeGoalscorer,
FirstGoalscorer,
PlayerShotsOnTarget(Over),
AnytimeAssist
}

#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum Side {
Home,
Away,
}

#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum Player {
Named(Side, String),
Other
}

#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum OutcomeType {
Win(Side),
Draw,
Under(u8),
Over(u8),
Score(Score),
Player(Player),
None,
}
Loading

0 comments on commit 238b27a

Please sign in to comment.