Skip to content

Commit

Permalink
Simplified stateless query spec
Browse files Browse the repository at this point in the history
  • Loading branch information
ekoutanov committed Jan 9, 2024
1 parent 116cb48 commit 622217a
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 298 deletions.
53 changes: 18 additions & 35 deletions brumby-soccer/src/bin/soc_prices.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::HashMap;
use std::collections::{BTreeMap, HashMap};
use std::env;
use std::error::Error;
use std::fs::File;
Expand All @@ -14,6 +14,7 @@ use stanza::renderer::Renderer;
use stanza::style::Styles;
use stanza::table::{Cell, Content, Row, Table};
use tracing::{debug, info, warn};
use brumby::derived_price::DerivedPrice;

use brumby::hash_lookup::HashLookup;
use brumby::market::{Market, OverroundMethod, PriceBounds};
Expand All @@ -30,6 +31,7 @@ use brumby_soccer::model::score_fitter::ScoreFitter;

const OVERROUND_METHOD: OverroundMethod = OverroundMethod::OddsRatio;
const SINGLE_PRICE_BOUNDS: PriceBounds = 1.001..=301.0;
const MULTI_PRICE_BOUNDS: PriceBounds = 1.001..=1001.0;
const INTERVALS: u8 = 18;
const INCREMENTAL_OVERROUND: f64 = 0.01;
const MAX_TOTAL_GOALS: u16 = 8;
Expand Down Expand Up @@ -277,24 +279,16 @@ async fn main() -> Result<(), Box<dyn Error>> {
// let relatedness =
// compute_relatedness_coefficient(&selections, model.offers(), derivation.probability);
let scaling_exponent = compute_scaling_exponent(derivation.relatedness);
let scaled_price = derivation.quotation.price
/ derivation
.quotation
.overround()
.powf(scaling_exponent - 1.0);
let scaled_price = scale_price(&derivation.quotation, scaling_exponent);
info!("selections: {selections:?}, quotation: {:?}, overround: {:.3}, relatedness: {:.3}, redundancies: {:?}, scaling_exponent: {scaling_exponent:?}, scaled_price: {scaled_price:.3}, took: {elapsed:?}",
derivation.quotation, derivation.quotation.overround(), derivation.relatedness, derivation.redundancies);
let mut total_fringes = 0;
let mut unattainable_fringes = 0;
for (offer, fringe_vec) in derivation.fringes {
info!("fringe offer: {offer:?}");
for (offer, fringe_vec) in derivation.fringes.into_iter().collect::<BTreeMap<_, _>>() {
info!("\nfringe offer: {offer:?}");
for fringe in fringe_vec {
let scaling_exponent = compute_scaling_exponent(fringe.relatedness);
let scaled_price = fringe.quotation.price
/ fringe
.quotation
.overround()
.powf(scaling_exponent - 1.0);
let scaled_price = scale_price(&fringe.quotation, scaling_exponent);
total_fringes += 1;
if fringe.quotation.probability == 0.0 {
unattainable_fringes += 1;
Expand All @@ -307,28 +301,17 @@ async fn main() -> Result<(), Box<dyn Error>> {
Ok(())
}

// fn compute_unrelated_probability(
// selections: &[(OfferType, Outcome)],
// offers: &FxHashMap<OfferType, Offer>,
// ) -> f64 {
// selections
// .iter()
// .map(|(offer_type, outcome)| {
// let offer = offers.get(offer_type).unwrap();
// let outcome_index = offer.outcomes.index_of(outcome).unwrap();
// offer.market.probs[outcome_index]
// })
// .product()
// }

// fn compute_relatedness_coefficient(
// selections: &[(OfferType, Outcome)],
// offers: &FxHashMap<OfferType, Offer>,
// related_prob: f64,
// ) -> f64 {
// let unrelated_prob = compute_unrelated_probability(selections, offers);
// unrelated_prob / related_prob
// }
fn scale_price(quotation: &DerivedPrice, scaling_exponent: f64) -> f64 {
if quotation.price.is_finite() {
let scaled_price = quotation.price
/ quotation
.overround()
.powf(scaling_exponent - 1.0);
f64::max(*MULTI_PRICE_BOUNDS.start(), f64::min(scaled_price, *MULTI_PRICE_BOUNDS.end()))
} else {
quotation.price
}
}

fn compute_scaling_exponent(relatedness: f64) -> f64 {
0.5 * f64::log10(100.0 * relatedness)
Expand Down
34 changes: 16 additions & 18 deletions brumby-soccer/src/interval/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,14 @@ use crate::interval::{Expansions, Prospect, Prospects};

mod anytime_assist;
mod anytime_goalscorer;
mod asian_handicap;
mod correct_score;
mod first_goalscorer;
mod head_to_head;
mod win_draw;
mod total_goals;

#[derive(Debug)]
pub enum QuerySpec {
None,
PassThrough(OfferType, Outcome),
Stateless,
PlayerLookup(usize),
NoFirstGoalscorer,
NoAnytimeGoalscorer,
Expand All @@ -24,10 +22,10 @@ pub enum QuerySpec {
#[must_use]
pub fn requirements(offer_type: &OfferType) -> Expansions {
match offer_type {
OfferType::HeadToHead(period, _) => head_to_head::requirements(period),
OfferType::HeadToHead(period, _) => win_draw::requirements(period),
OfferType::TotalGoals(period, _) => total_goals::requirements(period),
OfferType::CorrectScore(period) => correct_score::requirements(period),
OfferType::AsianHandicap(period, _) => asian_handicap::requirements(period),
OfferType::AsianHandicap(period, _) => win_draw::requirements(period),
OfferType::DrawNoBet(_) => unimplemented!(),
OfferType::FirstGoalscorer => first_goalscorer::requirements(),
OfferType::AnytimeGoalscorer => anytime_goalscorer::requirements(),
Expand All @@ -43,10 +41,10 @@ pub fn prepare(
player_lookup: &HashLookup<Player>,
) -> QuerySpec {
match offer_type {
OfferType::HeadToHead(_, _) => head_to_head::prepare(offer_type, outcome),
OfferType::TotalGoals(_, _) => total_goals::prepare(offer_type, outcome),
OfferType::CorrectScore(_) => correct_score::prepare(offer_type, outcome),
OfferType::AsianHandicap(_, _) => asian_handicap::prepare(offer_type, outcome),
OfferType::HeadToHead(_, _) => win_draw::prepare(),
OfferType::TotalGoals(_, _) => total_goals::prepare(),
OfferType::CorrectScore(_) => correct_score::prepare(),
OfferType::AsianHandicap(_, _) => win_draw::prepare(),
OfferType::DrawNoBet(_) => unimplemented!(),
OfferType::FirstGoalscorer => first_goalscorer::prepare(outcome, player_lookup),
OfferType::AnytimeGoalscorer => anytime_goalscorer::prepare(outcome, player_lookup),
Expand All @@ -56,12 +54,12 @@ pub fn prepare(
}

#[must_use]
pub fn filter(offer_type: &OfferType, query: &QuerySpec, prospect: &Prospect) -> bool {
pub fn filter(offer_type: &OfferType, outcome: &Outcome, query: &QuerySpec, prospect: &Prospect) -> bool {
match offer_type {
OfferType::HeadToHead(_, _) => head_to_head::filter(query, prospect),
OfferType::TotalGoals(_, _) => total_goals::filter(query, prospect),
OfferType::CorrectScore(_) => correct_score::filter(query, prospect),
OfferType::AsianHandicap(_, _) => asian_handicap::filter(query, prospect),
OfferType::HeadToHead(period, _) => win_draw::filter(period, outcome, prospect),
OfferType::TotalGoals(period, _) => total_goals::filter(period, outcome, prospect),
OfferType::CorrectScore(period) => correct_score::filter(period, outcome, prospect),
OfferType::AsianHandicap(period, _) => win_draw::filter(period, outcome, prospect),
OfferType::DrawNoBet(_) => unimplemented!(),
OfferType::AnytimeGoalscorer => anytime_goalscorer::filter(query, prospect),
OfferType::FirstGoalscorer => first_goalscorer::filter(query, prospect),
Expand All @@ -80,7 +78,7 @@ pub fn isolate(
let query = prepare(offer_type, outcome, player_lookup);
prospects
.iter()
.filter(|(prospect, _)| filter(offer_type, &query, prospect))
.filter(|(prospect, _)| filter(offer_type, outcome, &query, prospect))
.map(|(_, prob)| prob)
.sum()
}
Expand All @@ -94,15 +92,15 @@ pub fn isolate_set(
let queries = selections
.iter()
.map(|(offer_type, outcome)| {
(offer_type, prepare(offer_type, outcome, player_lookup))
(offer_type, outcome, prepare(offer_type, outcome, player_lookup))
})
.collect::<Vec<_>>();
prospects
.iter()
.filter(|(prospect, _)| {
!queries
.iter()
.any(|(offer_type, query)| !filter(offer_type, query, prospect))
.any(|(offer_type, outcome, query)| !filter(offer_type, outcome, query, prospect))
})
.map(|(_, prospect_prob)| prospect_prob)
.sum()
Expand Down
183 changes: 0 additions & 183 deletions brumby-soccer/src/interval/query/asian_handicap.rs

This file was deleted.

12 changes: 6 additions & 6 deletions brumby-soccer/src/interval/query/correct_score.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,22 @@ pub(crate) fn requirements(period: &Period) -> Expansions {

#[inline]
#[must_use]
pub(crate) fn prepare(offer_type: &OfferType, outcome: &Outcome) -> QuerySpec {
QuerySpec::PassThrough(offer_type.clone(), outcome.clone())
pub(crate) fn prepare() -> QuerySpec {
QuerySpec::Stateless
}

#[inline]
#[must_use]
pub(crate) fn filter(query: &QuerySpec, prospect: &Prospect) -> bool {
match query {
QuerySpec::PassThrough(OfferType::CorrectScore(period), Outcome::Score(score)) => {
pub(crate) fn filter(period: &Period, outcome: &Outcome, prospect: &Prospect) -> bool {
match outcome {
Outcome::Score(score) => {
let (home_goals, away_goals) = match period {
Period::FirstHalf => (prospect.ht_score.home, prospect.ht_score.away),
Period::SecondHalf => { let h2_score = prospect.h2_score(); (h2_score.home, h2_score.away) },
Period::FullTime => (prospect.ft_score.home, prospect.ft_score.away),
};
score.home == home_goals && score.away == away_goals
}
_ => panic!("{query:?} unsupported"),
_ => panic!("{outcome:?} unsupported"),
}
}
Loading

0 comments on commit 622217a

Please sign in to comment.