Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
M
MBetterc
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Mbetter
MBetterc
Commits
b57de374
Commit
b57de374
authored
May 14, 2026
by
Your Name
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update extraction controller targeting
parent
2bcbdd45
Changes
3
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
832 additions
and
128 deletions
+832
-128
games_thread.py
mbetterclient/core/games_thread.py
+222
-69
test_extract_match_updated.py
test_extract_match_updated.py
+375
-59
test_extraction_accounting.py
test_extraction_accounting.py
+235
-0
No files found.
mbetterclient/core/games_thread.py
View file @
b57de374
This diff is collapsed.
Click to expand it.
test_extract_match_updated.py
View file @
b57de374
This diff is collapsed.
Click to expand it.
test_extraction_accounting.py
0 → 100644
View file @
b57de374
from
pathlib
import
Path
from
unittest.mock
import
patch
import
random
from
mbetterclient.core.games_thread
import
GamesThread
from
mbetterclient.core.message_bus
import
Message
,
MessageBus
,
MessageType
from
mbetterclient.database.manager
import
DatabaseManager
from
mbetterclient.database.models
import
(
BetDetailModel
,
GameConfigModel
,
MatchModel
,
MatchOutcomeModel
,
PersistentRedistributionAdjustmentModel
,
ResultOptionModel
,
ExtractionAssociationModel
,
)
def
_build_games_thread
(
tmp_path
:
Path
):
db_path
=
tmp_path
/
"accounting_test.db"
db_manager
=
DatabaseManager
(
str
(
db_path
))
assert
db_manager
.
initialize
()
message_bus
=
MessageBus
()
games_thread
=
GamesThread
(
"test_games_thread"
,
message_bus
,
db_manager
)
return
games_thread
,
db_manager
def
_seed_match_and_bets
(
db_manager
:
DatabaseManager
):
session
=
db_manager
.
get_session
()
try
:
cap_config
=
session
.
query
(
GameConfigModel
)
.
filter_by
(
config_key
=
'extraction_redistribution_cap'
)
.
first
()
if
cap_config
is
None
:
session
.
add
(
GameConfigModel
(
config_key
=
'extraction_redistribution_cap'
,
config_value
=
'70.0'
,
value_type
=
'float'
,
description
=
'Test cap'
))
else
:
cap_config
.
config_value
=
'70.0'
cap_config
.
value_type
=
'float'
if
session
.
query
(
ResultOptionModel
)
.
filter_by
(
result_name
=
'WIN1'
)
.
first
()
is
None
:
session
.
add
(
ResultOptionModel
(
result_name
=
'WIN1'
,
description
=
'Win 1'
,
is_active
=
True
,
sort_order
=
1
))
for
outcome_name
in
(
'WIN1'
,
'KO1'
):
exists
=
session
.
query
(
ExtractionAssociationModel
)
.
filter_by
(
outcome_name
=
outcome_name
,
extraction_result
=
'WIN1'
)
.
first
()
if
exists
is
None
:
session
.
add
(
ExtractionAssociationModel
(
outcome_name
=
outcome_name
,
extraction_result
=
'WIN1'
))
match
=
MatchModel
(
match_number
=
1
,
fighter1_township
=
'A'
,
fighter2_township
=
'B'
,
venue_kampala_township
=
'Kampala'
,
filename
=
'fixture.txt'
,
file_sha1sum
=
'fixture-sha1'
,
fixture_id
=
'fixture-1'
,
active_status
=
True
,
status
=
'bet'
)
session
.
add
(
match
)
session
.
flush
()
session
.
add_all
([
MatchOutcomeModel
(
match_id
=
match
.
id
,
column_name
=
'UNDER'
,
float_value
=
2.0
),
MatchOutcomeModel
(
match_id
=
match
.
id
,
column_name
=
'OVER'
,
float_value
=
2.5
),
MatchOutcomeModel
(
match_id
=
match
.
id
,
column_name
=
'WIN1'
,
float_value
=
3.0
),
MatchOutcomeModel
(
match_id
=
match
.
id
,
column_name
=
'KO1'
,
float_value
=
4.0
),
])
session
.
add_all
([
BetDetailModel
(
bet_id
=
'bet-under'
,
match_id
=
match
.
id
,
match_number
=
1
,
outcome
=
'UNDER'
,
amount
=
10.0
,
result
=
'pending'
),
BetDetailModel
(
bet_id
=
'bet-win1'
,
match_id
=
match
.
id
,
match_number
=
1
,
outcome
=
'WIN1'
,
amount
=
20.0
,
result
=
'pending'
),
BetDetailModel
(
bet_id
=
'bet-ko1'
,
match_id
=
match
.
id
,
match_number
=
1
,
outcome
=
'KO1'
,
amount
=
15.0
,
result
=
'pending'
),
])
session
.
commit
()
return
match
.
id
,
match
.
fixture_id
finally
:
session
.
close
()
def
test_match_start_uses_settled_winnings_for_adjustment
(
tmp_path
):
games_thread
,
db_manager
=
_build_games_thread
(
tmp_path
)
match_id
,
fixture_id
=
_seed_match_and_bets
(
db_manager
)
message
=
Message
(
type
=
MessageType
.
MATCH_START
,
sender
=
'test'
,
recipient
=
'test_games_thread'
,
data
=
{
'fixture_id'
:
fixture_id
,
'match_id'
:
match_id
}
)
with
patch
(
'mbetterclient.core.games_thread.extract_match'
,
return_value
=
(
'UNDER'
,
'WIN1'
,
0.0
,
'WIN1, KO1'
)):
with
patch
.
object
(
games_thread
,
'_send_play_video_match'
,
return_value
=
None
):
games_thread
.
_handle_match_start
(
message
)
session
=
db_manager
.
get_session
()
try
:
global_record
=
session
.
query
(
PersistentRedistributionAdjustmentModel
)
.
filter_by
(
date
=
'1970-01-01'
)
.
one
()
winning_bets
=
session
.
query
(
BetDetailModel
)
.
filter_by
(
match_id
=
match_id
,
result
=
'win'
)
.
all
()
actual_redistributed
=
sum
(
float
(
bet
.
win_amount
or
0.0
)
for
bet
in
winning_bets
)
assert
actual_redistributed
==
140.0
assert
global_record
.
total_redistributed
==
actual_redistributed
assert
global_record
.
total_payin
==
45.0
assert
global_record
.
accumulated_shortfall
==
(
45.0
*
0.70
)
-
actual_redistributed
finally
:
session
.
close
()
db_manager
.
close
()
def
_seed_simulation_match
(
session
,
fixture_id
:
str
,
match_number
:
int
,
under_amount
:
float
,
over_amount
:
float
,
win1_amount
:
float
,
ko1_amount
:
float
):
match
=
MatchModel
(
match_number
=
match_number
,
fighter1_township
=
f
'F{match_number}A'
,
fighter2_township
=
f
'F{match_number}B'
,
venue_kampala_township
=
'Kampala'
,
filename
=
f
'fixture-{match_number}.txt'
,
file_sha1sum
=
f
'fixture-sha1-{match_number}'
,
fixture_id
=
fixture_id
,
active_status
=
True
,
status
=
'bet'
)
session
.
add
(
match
)
session
.
flush
()
session
.
add_all
([
MatchOutcomeModel
(
match_id
=
match
.
id
,
column_name
=
'UNDER'
,
float_value
=
2.0
),
MatchOutcomeModel
(
match_id
=
match
.
id
,
column_name
=
'OVER'
,
float_value
=
2.0
),
MatchOutcomeModel
(
match_id
=
match
.
id
,
column_name
=
'WIN1'
,
float_value
=
2.0
),
MatchOutcomeModel
(
match_id
=
match
.
id
,
column_name
=
'KO1'
,
float_value
=
2.0
),
])
bet_rows
=
[]
for
index
,
(
outcome
,
amount
)
in
enumerate
((
(
'UNDER'
,
under_amount
),
(
'OVER'
,
over_amount
),
(
'WIN1'
,
win1_amount
),
(
'KO1'
,
ko1_amount
),
),
start
=
1
):
if
amount
<=
0
:
continue
bet_rows
.
append
(
BetDetailModel
(
bet_id
=
f
'bet-{match_number}-{index}'
,
match_id
=
match
.
id
,
match_number
=
match_number
,
outcome
=
outcome
,
amount
=
amount
,
result
=
'pending'
))
session
.
add_all
(
bet_rows
)
return
match
.
id
def
test_match_start_simulation_tracks_persisted_settled_totals
(
tmp_path
):
games_thread
,
db_manager
=
_build_games_thread
(
tmp_path
)
fixture_id
=
'fixture-sim'
rng
=
random
.
Random
(
7
)
rounds
=
120
total_payin
=
0.0
total_redistributed
=
0.0
session
=
db_manager
.
get_session
()
try
:
session
.
query
(
ExtractionAssociationModel
)
.
delete
()
session
.
query
(
ResultOptionModel
)
.
delete
()
session
.
add
(
ResultOptionModel
(
result_name
=
'WIN1'
,
description
=
'Win 1'
,
is_active
=
True
,
sort_order
=
1
))
session
.
add
(
ExtractionAssociationModel
(
outcome_name
=
'WIN1'
,
extraction_result
=
'WIN1'
))
session
.
add
(
ExtractionAssociationModel
(
outcome_name
=
'KO1'
,
extraction_result
=
'WIN1'
))
session
.
commit
()
finally
:
session
.
close
()
try
:
for
match_number
in
range
(
1
,
rounds
+
1
):
under_amount
=
rng
.
uniform
(
20.0
,
60.0
)
over_amount
=
rng
.
uniform
(
20.0
,
60.0
)
win1_amount
=
rng
.
uniform
(
20.0
,
60.0
)
ko1_amount
=
rng
.
uniform
(
20.0
,
60.0
)
session
=
db_manager
.
get_session
()
try
:
match_id
=
_seed_simulation_match
(
session
,
fixture_id
,
match_number
,
under_amount
,
over_amount
,
win1_amount
,
ko1_amount
,
)
session
.
commit
()
finally
:
session
.
close
()
message
=
Message
(
type
=
MessageType
.
MATCH_START
,
sender
=
'test'
,
recipient
=
'test_games_thread'
,
data
=
{
'fixture_id'
:
fixture_id
,
'match_id'
:
match_id
}
)
with
patch
.
object
(
games_thread
,
'_send_play_video_match'
,
return_value
=
None
):
games_thread
.
_handle_match_start
(
message
)
session
=
db_manager
.
get_session
()
try
:
winning_bets
=
session
.
query
(
BetDetailModel
)
.
filter_by
(
match_id
=
match_id
,
result
=
'win'
)
.
all
()
match_payin
=
sum
(
float
(
bet
.
amount
or
0.0
)
for
bet
in
session
.
query
(
BetDetailModel
)
.
filter_by
(
match_id
=
match_id
)
.
all
())
match_redistributed
=
sum
(
float
(
bet
.
win_amount
or
0.0
)
for
bet
in
winning_bets
)
total_payin
+=
match_payin
total_redistributed
+=
match_redistributed
finally
:
session
.
close
()
session
=
db_manager
.
get_session
()
try
:
global_record
=
session
.
query
(
PersistentRedistributionAdjustmentModel
)
.
filter_by
(
date
=
'1970-01-01'
)
.
one
()
assert
abs
(
global_record
.
total_payin
-
total_payin
)
<
1e-6
assert
abs
(
global_record
.
total_redistributed
-
total_redistributed
)
<
1e-6
assert
abs
(
global_record
.
accumulated_shortfall
-
((
total_payin
*
0.70
)
-
total_redistributed
)
)
<
1e-6
finally
:
session
.
close
()
finally
:
db_manager
.
close
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment