Initial commit - MIDAS App educação financeira para apostadores (FastAPI + Next.js)
This commit is contained in:
79
backend/app/services/risk_engine.py
Normal file
79
backend/app/services/risk_engine.py
Normal file
@@ -0,0 +1,79 @@
|
||||
from datetime import datetime, timedelta
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select, func
|
||||
from app.models.bet import Bet
|
||||
from app.models.bankroll import Bankroll
|
||||
|
||||
async def calculate_risk_score(user_id, db: AsyncSession) -> dict:
|
||||
score = 0
|
||||
factors = []
|
||||
now = datetime.utcnow()
|
||||
|
||||
# 1. Horário noturno (22h-5h) +15
|
||||
hour = now.hour
|
||||
if hour >= 22 or hour < 5:
|
||||
score += 15
|
||||
factors.append("Apostando em horário noturno")
|
||||
|
||||
# 2. Valor crescente +25
|
||||
recent = await db.execute(
|
||||
select(Bet).where(Bet.user_id == user_id).order_by(Bet.created_at.desc()).limit(5)
|
||||
)
|
||||
recent_bets = recent.scalars().all()
|
||||
if len(recent_bets) >= 3:
|
||||
amounts = [float(b.amount) for b in recent_bets[:3]]
|
||||
if amounts[0] > amounts[1] > amounts[2]:
|
||||
score += 25
|
||||
factors.append("Valores de aposta crescentes")
|
||||
|
||||
# 3. Recuperação (aposta logo após loss) +30
|
||||
if len(recent_bets) >= 2:
|
||||
last = recent_bets[0]
|
||||
prev = recent_bets[1]
|
||||
if prev.result == "loss" and last.created_at and prev.created_at:
|
||||
diff = (last.created_at - prev.created_at).total_seconds()
|
||||
if diff < 1800: # 30 min
|
||||
score += 30
|
||||
factors.append("Tentativa de recuperação após perda")
|
||||
|
||||
# 4. Frequência alta (>5 apostas em 24h) +20
|
||||
day_ago = now - timedelta(hours=24)
|
||||
count_result = await db.execute(
|
||||
select(func.count()).select_from(Bet).where(Bet.user_id == user_id, Bet.created_at >= day_ago)
|
||||
)
|
||||
bet_count = count_result.scalar() or 0
|
||||
if bet_count > 5:
|
||||
score += 20
|
||||
factors.append(f"Alta frequência: {bet_count} apostas em 24h")
|
||||
|
||||
# 5. Limite estourado +25
|
||||
br_result = await db.execute(select(Bankroll).where(Bankroll.user_id == user_id))
|
||||
bankroll = br_result.scalar_one_or_none()
|
||||
if bankroll and float(bankroll.month_spent) > float(bankroll.monthly_budget):
|
||||
score += 25
|
||||
factors.append("Limite mensal ultrapassado")
|
||||
|
||||
# 6. Emoção negativa +15
|
||||
if recent_bets and recent_bets[0].emotion in ["😤", "😰", "tilt", "ansioso", "frustrado"]:
|
||||
score += 15
|
||||
factors.append("Emoção negativa detectada")
|
||||
|
||||
# 7. Sequência de perdas +20
|
||||
loss_streak = 0
|
||||
for b in recent_bets:
|
||||
if b.result == "loss":
|
||||
loss_streak += 1
|
||||
else:
|
||||
break
|
||||
if loss_streak >= 3:
|
||||
score += 20
|
||||
factors.append(f"Sequência de {loss_streak} perdas consecutivas")
|
||||
|
||||
if score <= 30:
|
||||
level = "green"
|
||||
elif score <= 60:
|
||||
level = "yellow"
|
||||
else:
|
||||
level = "red"
|
||||
|
||||
return {"score": score, "level": level, "factors": factors}
|
||||
Reference in New Issue
Block a user