Fix SLG formula drift in extracted rating models

The extracted batting and pitching models used malformed SLG equations that double-counted and omitted outcomes, skewing slash lines. Align formulas with canonical weighting and add regression tests to prevent recurrence.

Co-Authored-By: Claude GPT-5.3-Codex <noreply@anthropic.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Cal Corum 2026-02-26 07:47:15 -06:00
parent 39c652e55c
commit 2bf3a6cee7
3 changed files with 96 additions and 4 deletions

View File

@ -269,8 +269,9 @@ class BattingCardRatingsModel(pydantic.BaseModel):
self.avg = mround(self.total_hits() / 108, prec=5, base=0.00001)
self.obp = mround((self.total_hits() + self.hbp + self.walk) / 108, prec=5, base=0.00001)
self.slg = mround((
self.homerun * 4 + self.triple * 3 + self.single_center + self.single_two + self.single_two +
(self.double_two + self.double_three + self.double_two + self.bp_homerun) * 2 + self.bp_single / 2) / 108, prec=5, base=0.00001)
self.homerun * 4 + self.bp_homerun * 2 + self.triple * 3 + self.double_three * 2 +
self.double_two * 2 + self.double_pull * 2 + self.single_two + self.single_one +
self.single_center + self.bp_single / 2) / 108, prec=5, base=0.00001)
def custom_to_dict(self):
self.calculate_rate_stats()

View File

@ -89,8 +89,9 @@ class PitchingCardRatingsModel(pydantic.BaseModel):
self.avg = mround(self.total_hits() / 108, prec=5, base=0.00001)
self.obp = mround((self.total_hits() + self.hbp + self.walk) / 108, prec=5, base=0.00001)
self.slg = mround((
self.homerun * 4 + self.triple * 3 + self.single_center + self.single_two + self.single_two +
(self.double_two + self.double_three + self.double_two + self.bp_homerun) * 2 + self.bp_single / 2) / 108, prec=5, base=0.00001)
self.homerun * 4 + self.bp_homerun * 2 + self.triple * 3 + self.double_three * 2 +
self.double_two * 2 + self.double_cf * 2 + self.single_two + self.single_one +
self.single_center + self.bp_single / 2) / 108, prec=5, base=0.00001)
def custom_to_dict(self):
self.calculate_rate_stats()

View File

@ -0,0 +1,90 @@
from batters.models import BattingCardRatingsModel
from pitchers.models import PitchingCardRatingsModel
from creation_helpers import mround
def test_batting_model_slg_formula_matches_canonical_weights():
ratings = BattingCardRatingsModel(
battingcard_id=1,
bat_hand='R',
vs_hand='R',
hard_rate=0.3,
med_rate=0.3,
soft_rate=0.3,
pull_rate=0.3,
center_rate=0.3,
slap_rate=0.3,
homerun=1,
bp_homerun=2,
triple=3,
double_three=4,
double_two=5,
double_pull=6,
single_two=7,
single_one=8,
single_center=9,
bp_single=10,
)
ratings.calculate_rate_stats()
expected = mround(
(
ratings.homerun * 4
+ ratings.bp_homerun * 2
+ ratings.triple * 3
+ ratings.double_three * 2
+ ratings.double_two * 2
+ ratings.double_pull * 2
+ ratings.single_two
+ ratings.single_one
+ ratings.single_center
+ ratings.bp_single / 2
) / 108,
prec=5,
base=0.00001,
)
assert ratings.slg == expected
def test_pitching_model_slg_formula_matches_canonical_weights():
ratings = PitchingCardRatingsModel(
pitchingcard_id=1,
pit_hand='R',
vs_hand='R',
hard_rate=0.3,
med_rate=0.3,
soft_rate=0.3,
homerun=1,
bp_homerun=2,
triple=3,
double_three=4,
double_two=5,
double_cf=6,
single_two=7,
single_one=8,
single_center=9,
bp_single=10,
)
ratings.calculate_rate_stats()
expected = mround(
(
ratings.homerun * 4
+ ratings.bp_homerun * 2
+ ratings.triple * 3
+ ratings.double_three * 2
+ ratings.double_two * 2
+ ratings.double_cf * 2
+ ratings.single_two
+ ratings.single_one
+ ratings.single_center
+ ratings.bp_single / 2
) / 108,
prec=5,
base=0.00001,
)
assert ratings.slg == expected