Replace hardcoded DB credentials with environment-driven configuration.
Centralize DB settings in ingestion config, remove embedded secrets from ingestion helpers, and add an idempotent PostgreSQL bootstrap script to create role/database and apply schema safely. Made-with: Cursor
This commit is contained in:
@@ -1,14 +0,0 @@
|
||||
DB_CONFIG = {
|
||||
"host": "localhost",
|
||||
"port": 5432,
|
||||
"database": "options_db",
|
||||
"user": "quant_user",
|
||||
"password": "strong_password",
|
||||
}
|
||||
|
||||
PIPELINE_CONFIG = {
|
||||
"symbols": [
|
||||
"SPY"
|
||||
# Example: "SPY"
|
||||
]
|
||||
}
|
||||
@@ -1,13 +1,15 @@
|
||||
import psycopg2
|
||||
import pandas as pd
|
||||
|
||||
conn = psycopg2.connect(
|
||||
dbname="options_db",
|
||||
user="quant_user",
|
||||
password="strong_password",
|
||||
host="144.91.73.49",
|
||||
port="5432"
|
||||
)
|
||||
from option_pricing.src.data.ingestion.db_connect import db_engine
|
||||
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT * FROM underlyings;")
|
||||
print(cursor.fetchall())
|
||||
|
||||
def fetch_underlyings() -> pd.DataFrame:
|
||||
"""
|
||||
Fetch all entries from the underlyings table using configured DB credentials.
|
||||
"""
|
||||
engine = db_engine()
|
||||
return pd.read_sql("SELECT * FROM underlyings;", engine)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(fetch_underlyings())
|
||||
3
src/data/ingestion/config/__init__.py
Normal file
3
src/data/ingestion/config/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from .settings import DB_CONFIG, PIPELINE_CONFIG
|
||||
|
||||
__all__ = ["DB_CONFIG", "PIPELINE_CONFIG"]
|
||||
31
src/data/ingestion/config/settings.py
Normal file
31
src/data/ingestion/config/settings.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import os
|
||||
|
||||
|
||||
def _get_env_int(name: str, default: int) -> int:
|
||||
raw = os.getenv(name)
|
||||
if raw is None:
|
||||
return default
|
||||
try:
|
||||
return int(raw)
|
||||
except ValueError as exc:
|
||||
raise ValueError(f"Environment variable {name} must be an integer, got '{raw}'") from exc
|
||||
|
||||
|
||||
def _get_env_list(name: str, default: list[str]) -> list[str]:
|
||||
raw = os.getenv(name)
|
||||
if not raw:
|
||||
return default
|
||||
return [x.strip() for x in raw.split(",") if x.strip()]
|
||||
|
||||
|
||||
DB_CONFIG = {
|
||||
"host": os.getenv("DB_HOST", "localhost"),
|
||||
"port": _get_env_int("DB_PORT", 5432),
|
||||
"database": os.getenv("DB_NAME", "options_db"),
|
||||
"user": os.getenv("DB_USER", "quant_user"),
|
||||
"password": os.getenv("DB_PASSWORD", ""),
|
||||
}
|
||||
|
||||
PIPELINE_CONFIG = {
|
||||
"symbols": _get_env_list("PIPELINE_SYMBOLS", ["SPY"]),
|
||||
}
|
||||
13
src/data/ingestion/db_connect.py
Normal file
13
src/data/ingestion/db_connect.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from sqlalchemy import create_engine
|
||||
from option_pricing.src.data.ingestion.config.settings import DB_CONFIG
|
||||
|
||||
def build_db_url() -> str:
|
||||
return (
|
||||
f"postgresql+psycopg2://{DB_CONFIG['user']}:{DB_CONFIG['password']}"
|
||||
f"@{DB_CONFIG['host']}:{DB_CONFIG['port']}/{DB_CONFIG['database']}"
|
||||
)
|
||||
|
||||
def db_engine():
|
||||
db_url = build_db_url()
|
||||
engine = create_engine(db_url, future=True)
|
||||
return engine
|
||||
@@ -1,16 +1,14 @@
|
||||
from datetime import datetime, timedelta
|
||||
import pandas as pd
|
||||
import yfinance as yf
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
from db_connect import db_engine
|
||||
|
||||
# --- CONFIG ---
|
||||
TICKERS = ["UBS", "^GSPC"]
|
||||
DAYS_BACK = 21 # ~3 weeks
|
||||
TABLE_NAME = "prices"
|
||||
|
||||
DB_URI = "postgresql://quant_user:strong_password@localhost:5432/options_db"
|
||||
|
||||
|
||||
def fetch_data(tickers, start_date, end_date):
|
||||
data = yf.download(
|
||||
tickers,
|
||||
@@ -64,7 +62,7 @@ def main():
|
||||
raw = fetch_data(TICKERS, start_date, end_date)
|
||||
df = transform_data(raw)
|
||||
|
||||
engine = create_engine(DB_URI)
|
||||
engine = db_engine()
|
||||
load_to_postgres(df, engine)
|
||||
|
||||
print("Ingestion complete.")
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
from datetime import datetime, timezone
|
||||
from decimal import Decimal, InvalidOperation
|
||||
|
||||
import pandas as pd
|
||||
import yfinance as yf
|
||||
from sqlalchemy import create_engine, text
|
||||
from sqlalchemy import text
|
||||
|
||||
from config.settings import DB_CONFIG, PIPELINE_CONFIG
|
||||
from option_pricing.src.data.ingestion.config import DB_CONFIG, PIPELINE_CONFIG
|
||||
from db_connect import db_engine
|
||||
|
||||
|
||||
def build_db_url() -> str:
|
||||
@@ -269,8 +269,7 @@ def ingest_symbol(symbol: str, engine):
|
||||
|
||||
|
||||
def main():
|
||||
db_url = build_db_url()
|
||||
engine = create_engine(db_url, future=True)
|
||||
engine = db_engine()
|
||||
|
||||
for symbol in PIPELINE_CONFIG["symbols"]:
|
||||
ingest_symbol(symbol, engine)
|
||||
|
||||
Reference in New Issue
Block a user