Responsible Gambling AI System (Detection of Problematic Gambling Behavior)
Problem gambling is a medical classification (ICD-11: Gambling Disorder). Operators are required to identify the signs and take action: limits, pauses, and self-exclusion. An AI system analyzes behavior in real time and detects patterns of control degradation a week before a player loses a critical amount.
Behavioral markers of problematic play
DSM-5 and PGSI indicators in digital form:
problem_gambling_markers = {
# Контроль над ставками
'bet_size_escalation': 'ставки растут быстрее баланса',
'chasing_losses': 'после серии проигрышей — немедленное увеличение ставки',
'session_overtime': 'сессия длится дольше обычной в 2+ раз',
'return_after_win': 'возврат в сессию сразу после вывода выигрыша',
# Паттерны времени
'late_night_sessions': 'игра после 2:00 — нарушение сна, импульсивность',
'daytime_work_hours': 'игра в рабочее время = приоритизация игры над работой',
'holiday_sessions': 'игра в праздники вместо социальной активности',
# Финансовые сигналы
'multiple_deposits_per_day': '3+ депозита за день',
'deposit_immediately_after_loss': 'депозит в течение 10 минут после проигрыша',
'withdrawal_cancellation': 'отмена запроса на вывод',
'max_deposit_frequency': 'достижение дневного лимита',
# Игровые паттерны
'rtp_deviation': 'ставит на игры с высоким RTP риска (volatility)',
'auto_spin_speed': 'максимальная скорость автоигры',
'side_bet_escalation': 'переход на более рискованные side bets'
}
Feature Engineering
Calculating Signs of Problematic Behavior:
import pandas as pd
import numpy as np
def compute_problem_gambling_features(player_id: str,
session_data: pd.DataFrame,
transaction_data: pd.DataFrame,
lookback_days: int = 30) -> dict:
recent_sessions = session_data[
(session_data['player_id'] == player_id) &
(session_data['start_time'] >= pd.Timestamp.now() - pd.Timedelta(days=lookback_days))
]
recent_tx = transaction_data[
(transaction_data['player_id'] == player_id) &
(transaction_data['timestamp'] >= pd.Timestamp.now() - pd.Timedelta(days=lookback_days))
]
# Сессионные паттерны
if len(recent_sessions) > 0:
session_durations = recent_sessions['duration_minutes']
avg_duration = session_durations.mean()
max_duration = session_durations.max()
overtime_sessions = (session_durations > avg_duration * 2).mean()
late_night_ratio = recent_sessions['start_time'].dt.hour.between(2, 5).mean()
# Скорость ставок внутри сессии
avg_bet_speed = recent_sessions['bets_per_minute'].mean()
else:
avg_duration = overtime_sessions = late_night_ratio = avg_bet_speed = 0
max_duration = 0
# Финансовые паттерны
deposits = recent_tx[recent_tx['type'] == 'deposit']
withdrawals = recent_tx[recent_tx['type'] == 'withdrawal']
withdrawal_cancels = recent_tx[recent_tx['type'] == 'withdrawal_cancelled']
multiple_deposits_days = (deposits.groupby(deposits['timestamp'].dt.date).size() >= 3).mean()
withdrawal_cancel_rate = len(withdrawal_cancels) / (len(withdrawals) + 1)
# Chasing losses: ставка после серии проигрышей
chasing_score = compute_chasing_score(recent_sessions)
# Тренд ставок
if len(recent_sessions) > 5:
x = np.arange(len(recent_sessions))
bet_slope = np.polyfit(x, recent_sessions['avg_bet_size'].values, 1)[0]
bet_escalation = bet_slope / (recent_sessions['avg_bet_size'].mean() + 1e-9)
else:
bet_escalation = 0
return {
'avg_session_duration_min': round(avg_duration, 1),
'overtime_sessions_ratio': round(overtime_sessions, 3),
'late_night_ratio': round(late_night_ratio, 3),
'multiple_deposit_days_ratio': round(multiple_deposits_days, 3),
'withdrawal_cancel_rate': round(withdrawal_cancel_rate, 3),
'chasing_score': round(chasing_score, 3),
'bet_escalation_rate': round(bet_escalation, 4),
'avg_bet_speed': round(avg_bet_speed, 2)
}
def compute_chasing_score(sessions: pd.DataFrame) -> float:
"""
Chasing losses: немедленное повышение ставки после проигрышной серии
"""
if len(sessions) < 5:
return 0.0
chasing_events = 0
for i in range(2, len(sessions)):
prev_balance_change = sessions.iloc[i-1].get('balance_change', 0)
curr_avg_bet = sessions.iloc[i].get('avg_bet_size', 0)
prev_avg_bet = sessions.iloc[i-2].get('avg_bet_size', 1)
# После проигрышной сессии ставка возросла на 50%+
if prev_balance_change < -10 and curr_avg_bet > prev_avg_bet * 1.5:
chasing_events += 1
return chasing_events / len(sessions)
Risk and Intervention Model
Scoring and intervention levels:
from lightgbm import LGBMClassifier
def assess_problem_gambling_risk(features: dict) -> dict:
"""
Три уровня риска → три вида интервенции.
"""
# Rule-based pre-screening (регуляторные триггеры)
hard_triggers = []
if features['late_night_ratio'] > 0.3:
hard_triggers.append('frequent_late_night')
if features['withdrawal_cancel_rate'] > 0.5:
hard_triggers.append('multiple_withdrawal_cancels')
if features['chasing_score'] > 0.4:
hard_triggers.append('chasing_losses')
if features['overtime_sessions_ratio'] > 0.3:
hard_triggers.append('session_overtime_pattern')
rule_risk = len(hard_triggers) / 4
# ML risk score (модель обучена на исторических данных игроков с подтверждённым GD)
# ml_score = model.predict_proba([feature_vector])[0][1]
ml_score = rule_risk # placeholder
combined_risk = 0.5 * rule_risk + 0.5 * ml_score
# Интервенции по уровням (UK Gambling Commission / UKGC guidelines)
if combined_risk > 0.75:
intervention = {
'level': 'mandatory',
'actions': ['pop_up_with_loss_reality_check', 'mandatory_cooling_off_24h',
'affordability_check_trigger'],
'message': 'Отображение истории потерь + предложение самоисключения'
}
elif combined_risk > 0.45:
intervention = {
'level': 'preventive',
'actions': ['reality_check_popup', 'deposit_limit_suggestion',
'gambling_support_info'],
'message': 'Информация о лимитах и ресурсах помощи'
}
else:
intervention = {'level': 'monitoring', 'actions': ['continue_monitoring']}
return {
'player_id': features.get('player_id'),
'risk_score': round(combined_risk, 3),
'risk_level': 'high' if combined_risk > 0.75 else ('medium' if combined_risk > 0.45 else 'low'),
'hard_triggers': hard_triggers,
'intervention': intervention
}
Compliance: UK Gambling Commission Single Customer View, UKGC LCCP Social Responsibility conditions. Federal Law 244 (Russian Federation) requires operators to have self-exclusion mechanisms. Integration with GAMSTOP (UK) and the self-exclusion registry.
Timeframe: Baseline risk score + intervention popup + regulatory audit log — 3-4 weeks. Machine learning model on labeled data, affordability checks, GAMSTOP API, and regulatory reporting — 2-3 months.







