EuNEx / shared /config.py
RayMelius's picture
v0.9.3: Add .env support with auto-loader in shared config
7d19948
"""
EuNEx shared configuration β€” centralized settings for all Python services.
"""
import os
# Load .env from project root if python-dotenv is available
try:
from dotenv import load_dotenv
load_dotenv(os.path.join(os.path.dirname(__file__), "..", ".env"))
except ImportError:
_env_path = os.path.join(os.path.dirname(__file__), "..", ".env")
if os.path.isfile(_env_path):
with open(_env_path) as _f:
for _line in _f:
_line = _line.strip()
if _line and not _line.startswith("#") and "=" in _line:
_k, _, _v = _line.partition("=")
os.environ.setdefault(_k.strip(), _v.strip())
# ── Service ports ──────────────────────────────────────────────────
DASHBOARD_PORT = int(os.environ.get("EUNEX_DASHBOARD_PORT", 8090))
FIX_PORT = int(os.environ.get("EUNEX_FIX_PORT", 9001))
CH_PORT = int(os.environ.get("EUNEX_CH_PORT", 8091))
# ── Service URLs (for inter-service communication) ─────────────────
DASHBOARD_URL = os.environ.get("EUNEX_DASHBOARD_URL", f"http://localhost:{DASHBOARD_PORT}")
CH_URL = os.environ.get("EUNEX_CH_URL", f"http://localhost:{CH_PORT}")
# ── Database paths ─────────────────────────────────────────────────
DATA_DIR = os.environ.get("EUNEX_DATA_DIR", os.path.join(os.path.dirname(__file__), "..", "data"))
DASHBOARD_DB = os.path.join(DATA_DIR, "dashboard.db")
CH_DB = os.path.join(DATA_DIR, "clearing_house.db")
# ── Kafka ──────────────────────────────────────────────────────────
KAFKA_BROKERS = os.environ.get("EUNEX_KAFKA_BROKERS", "localhost:9092")
KAFKA_TOPIC_ORDERS = "eunex.orders"
KAFKA_TOPIC_TRADES = "eunex.trades"
KAFKA_TOPIC_SNAPSHOTS = "eunex.market-data"
KAFKA_TOPIC_CONTROL = "eunex.control"
# ── Symbols ────────────────────────────────────────────────────────
SYMBOLS = {
1: {"name": "AAPL", "segment": "EQU", "startPrice": 154.0, "tickSize": 0.01, "lotSize": 1},
2: {"name": "MSFT", "segment": "EQU", "startPrice": 324.0, "tickSize": 0.01, "lotSize": 1},
3: {"name": "GOOGL", "segment": "EQU", "startPrice": 141.0, "tickSize": 0.01, "lotSize": 1},
4: {"name": "TSLA", "segment": "EQU", "startPrice": 375.0, "tickSize": 0.01, "lotSize": 1},
5: {"name": "NVDA", "segment": "EQU", "startPrice": 201.0, "tickSize": 0.01, "lotSize": 1},
6: {"name": "AMD", "segment": "EQU", "startPrice": 320.0, "tickSize": 0.01, "lotSize": 1},
7: {"name": "ENX", "segment": "EQU", "startPrice": 146.0, "tickSize": 0.01, "lotSize": 1},
}
# ── Simulation ─────────────────────────────────────────────────────
SIM_INTERVAL = int(os.environ.get("EUNEX_SIM_INTERVAL", 30))
SIM_ORDERS_PER_ROUND = int(os.environ.get("EUNEX_SIM_ORDERS", 4))
# ── Clearing House ─────────────────────────────────────────────────
CH_MEMBERS = {
f"MBR{i:02d}": {"capital": 100_000.0} for i in range(1, 11)
}
CH_AI_INTERVAL = int(os.environ.get("EUNEX_CH_AI_INTERVAL", 30))
CH_OBLIGATION_MIN_SECURITIES = 20
# ── AI strategies per member ───────────────────────────────────────
CH_DEFAULT_STRATEGIES = {
"MBR01": "momentum", "MBR02": "momentum", "MBR03": "momentum",
"MBR04": "mean_revert", "MBR05": "mean_revert", "MBR06": "mean_revert",
"MBR07": "random", "MBR08": "random", "MBR09": "random",
"MBR10": "random",
}