- Add detect_liquidity_levels() and detect_price_action_signal() to indicator_service.py - Wire both algorithms into candle_service.py get_indicators() - Add scoring logic and correlation groups in signal_scoring.py - Add liquidity_sweep and price_action_reversal to STRATEGY_NAMES/DISPLAY in strategy.py - Add funding_service.py for funding_oi algorithm (algorithm #14) - Add rate_limiter.py for auth endpoints - Fix: add slowapi==0.1.9 to Dockerfile - Fix: get_db -> get_db_session in analytics.py - Fix: remove from __future__ import annotations in auth.py System now runs 16 algorithms: 13 original + funding_oi + liquidity_sweep + price_action_reversal
This commit is contained in:
@@ -36,7 +36,7 @@ async def analytics_root():
|
||||
|
||||
|
||||
@router.get("/performance")
|
||||
async def get_performance(db: AsyncSession = Depends(get_db)):
|
||||
async def get_performance(db: AsyncSession = Depends(get_db_session)):
|
||||
"""Performance summary: win rate, PnL, profit factor."""
|
||||
try:
|
||||
# Try to use materialized view first (faster)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import APIRouter, Depends, Request, status
|
||||
@@ -7,6 +5,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.deps import get_current_user, get_db_session
|
||||
from app.core.exceptions import AppException
|
||||
from app.core.rate_limiter import limiter, is_login_locked, record_failed_login, clear_failed_attempts
|
||||
from app.models import User
|
||||
from app.schemas import (
|
||||
ChangePasswordRequest,
|
||||
@@ -25,8 +24,10 @@ router = APIRouter(prefix="/auth", tags=["auth"])
|
||||
|
||||
|
||||
@router.post("/register", status_code=status.HTTP_201_CREATED, response_model=UserResponse)
|
||||
@limiter.limit("3/hour")
|
||||
async def register(
|
||||
req: RegisterRequest,
|
||||
request: Request,
|
||||
db: AsyncSession = Depends(get_db_session),
|
||||
) -> UserResponse:
|
||||
"""Register a new user account."""
|
||||
@@ -34,18 +35,42 @@ async def register(
|
||||
|
||||
|
||||
@router.post("/login", response_model=TokenResponse)
|
||||
@limiter.limit("5/15 minutes")
|
||||
async def login(
|
||||
req: LoginRequest,
|
||||
request: Request,
|
||||
db: AsyncSession = Depends(get_db_session),
|
||||
) -> TokenResponse:
|
||||
"""Authenticate with username/password and receive a token pair."""
|
||||
return await auth_service.login(
|
||||
db=db,
|
||||
req=req,
|
||||
user_agent=request.headers.get("User-Agent", ""),
|
||||
ip_address=request.client.host if request.client else "",
|
||||
)
|
||||
"""Authenticate with username/password and receive a token pair.
|
||||
|
||||
Rate limited: 5 per 15 min. After 5 failed attempts from the same IP
|
||||
within 15 minutes, further login attempts are blocked for 15 minutes.
|
||||
"""
|
||||
ip_address = request.client.host if request.client else "unknown"
|
||||
|
||||
# Check if this IP is locked due to too many failed attempts
|
||||
is_locked, seconds_until_unlock = is_login_locked(ip_address)
|
||||
if is_locked:
|
||||
raise AppException(
|
||||
status_code=429,
|
||||
detail=f"Too many failed login attempts. Try again in {seconds_until_unlock} seconds.",
|
||||
error_code="LOGIN_LOCKED"
|
||||
)
|
||||
|
||||
try:
|
||||
result = await auth_service.login(
|
||||
db=db,
|
||||
req=req,
|
||||
user_agent=request.headers.get("User-Agent", ""),
|
||||
ip_address=ip_address,
|
||||
)
|
||||
# Clear failed attempts on successful login
|
||||
clear_failed_attempts(ip_address)
|
||||
return result
|
||||
except AppException:
|
||||
# Record failed login attempt
|
||||
record_failed_login(ip_address, reason="invalid_credentials")
|
||||
raise
|
||||
|
||||
|
||||
@router.post("/refresh", response_model=TokenResponse)
|
||||
|
||||
Reference in New Issue
Block a user