feat: add is_trading filter to symbols API + hardcode secret paths + backfill script

- API /api/v1/symbols: add is_trading query param + is_trading field in response
- config.py: set default DB_PASSWORD_FILE=/run/secrets/db_pw.txt and ENCRYPTION_KEY_FILE=/run/secrets/enc_key.txt
- scripts/backfill_candles.py: new script to fetch 500 historical candles per symbol/timeframe for all is_trading=true symbols
- Cleared 2.88M non-trading candles from DB
This commit is contained in:
2026-07-04 04:28:54 +00:00
parent 0e77c055ba
commit 8839df93f3
4 changed files with 165 additions and 3 deletions
+6 -1
View File
@@ -21,11 +21,12 @@ router = APIRouter(prefix="/symbols", tags=["symbols"])
async def list_symbols(
exchange: Optional[str] = Query(None, description="Filter by exchange name"),
active_only: bool = Query(True, description="Only return active symbols"),
is_trading: Optional[bool] = Query(None, description="Filter by trading status (top-100 bases)"),
limit: int = Query(50, ge=1, le=1000, description="Max symbols to return"),
offset: int = Query(0, ge=0, description="Offset for pagination"),
db: AsyncSession = Depends(get_db_session),
) -> list[SymbolResponse]:
"""Return symbols with pagination, optionally filtered by exchange and/or active status."""
"""Return symbols with pagination, optionally filtered by exchange, active status, and trading flag."""
query = select(Symbol).options(joinedload(Symbol.exchange))
if exchange:
@@ -34,6 +35,8 @@ async def list_symbols(
)
if active_only:
query = query.where(Symbol.is_active == True) # noqa: E712
if is_trading is not None:
query = query.where(Symbol.is_trading == is_trading)
query = query.limit(limit).offset(offset)
result = await db.execute(query)
@@ -47,6 +50,7 @@ async def list_symbols(
base=s.base,
quote=s.quote,
is_active=s.is_active,
is_trading=s.is_trading,
)
for s in symbols
]
@@ -82,6 +86,7 @@ async def search_symbols(
base=s.base,
quote=s.quote,
is_active=s.is_active,
is_trading=s.is_trading,
)
for s in symbols
]
+2 -2
View File
@@ -18,7 +18,7 @@ class Settings(BaseSettings):
# to override whatever password is embedded in DATABASE_URL. Keeps
# DB credentials out of plain env vars, consistent with how JWT keys
# are already handled.
DB_PASSWORD_FILE: str = ""
DB_PASSWORD_FILE: str = "/run/secrets/db_pw.txt"
# JWT
JWT_PRIVATE_KEY_PATH: str = "/run/secrets/jwt_private.pem"
@@ -30,7 +30,7 @@ class Settings(BaseSettings):
# Encryption
ENCRYPTION_KEY: str = ""
# If set, ENCRYPTION_KEY is read from this file (Docker secret) instead.
ENCRYPTION_KEY_FILE: str = ""
ENCRYPTION_KEY_FILE: str = "/run/secrets/enc_key.txt"
# Redis (shared cache across backend-api / backend-scheduler processes).
# Optional: if unreachable, callers fall back to per-process in-memory
+1
View File
@@ -11,6 +11,7 @@ class SymbolResponse(BaseModel):
base: str
quote: str
is_active: bool = True
is_trading: bool = False
class SymbolSearchResponse(BaseModel):