summaryrefslogtreecommitdiff
path: root/shared/src
diff options
context:
space:
mode:
Diffstat (limited to 'shared/src')
-rw-r--r--shared/src/shared/config.py40
1 files changed, 33 insertions, 7 deletions
diff --git a/shared/src/shared/config.py b/shared/src/shared/config.py
index b6b9d69..0f1c66e 100644
--- a/shared/src/shared/config.py
+++ b/shared/src/shared/config.py
@@ -1,14 +1,15 @@
"""Shared configuration settings for the trading platform."""
+from pydantic import SecretStr, field_validator
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
- alpaca_api_key: str = ""
- alpaca_api_secret: str = ""
+ alpaca_api_key: SecretStr = SecretStr("")
+ alpaca_api_secret: SecretStr = SecretStr("")
alpaca_paper: bool = True # Use paper trading by default
- redis_url: str = "redis://localhost:6379"
- database_url: str = "postgresql://trading:trading@localhost:5432/trading"
+ redis_url: SecretStr = SecretStr("redis://localhost:6379")
+ database_url: SecretStr = SecretStr("postgresql://trading:trading@localhost:5432/trading")
db_pool_size: int = 20
db_max_overflow: int = 10
db_pool_recycle: int = 3600
@@ -30,20 +31,45 @@ class Settings(BaseSettings):
risk_max_consecutive_losses: int = 5
risk_loss_pause_minutes: int = 60
dry_run: bool = True
- telegram_bot_token: str = ""
+ telegram_bot_token: SecretStr = SecretStr("")
telegram_chat_id: str = ""
telegram_enabled: bool = False
log_format: str = "json"
health_port: int = 8080
metrics_auth_token: str = "" # If set, /health and /metrics require Bearer token
+ # API security
+ api_auth_token: SecretStr = SecretStr("")
+ cors_origins: str = "http://localhost:3000"
# News collector
- finnhub_api_key: str = ""
+ finnhub_api_key: SecretStr = SecretStr("")
news_poll_interval: int = 300
sentiment_aggregate_interval: int = 900
# Stock selector
selector_final_time: str = "15:30"
selector_max_picks: int = 3
# LLM
- anthropic_api_key: str = ""
+ anthropic_api_key: SecretStr = SecretStr("")
anthropic_model: str = "claude-sonnet-4-20250514"
model_config = {"env_file": ".env", "env_file_encoding": "utf-8", "extra": "ignore"}
+
+ @field_validator("risk_max_position_size")
+ @classmethod
+ def validate_position_size(cls, v: float) -> float:
+ if v <= 0 or v > 1:
+ raise ValueError("risk_max_position_size must be between 0 and 1 (exclusive)")
+ return v
+
+ @field_validator("health_port")
+ @classmethod
+ def validate_health_port(cls, v: int) -> int:
+ if v < 1024 or v > 65535:
+ raise ValueError("health_port must be between 1024 and 65535")
+ return v
+
+ @field_validator("log_level")
+ @classmethod
+ def validate_log_level(cls, v: str) -> str:
+ valid = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"}
+ if v.upper() not in valid:
+ raise ValueError(f"log_level must be one of {valid}")
+ return v.upper()