"""
Configuration — all settings from environment variables.
Single source of truth for the entire bot.
"""
import os
from dotenv import load_dotenv
# Load .env file (from project root)
load_dotenv(os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env"), override=True)
# === BYBIT API ===
BYBIT_API_KEY = os.environ.get("BYBIT_API_KEY", "")
BYBIT_API_SECRET = os.environ.get("BYBIT_API_SECRET", "")
BYBIT_TESTNET = os.environ.get("BYBIT_TESTNET", "false").lower() == "true"
# === TELEGRAM ===
TELEGRAM_BOT_TOKEN = os.environ.get("TELEGRAM_BOT_TOKEN", "")
TELEGRAM_CHAT_ID = int(os.environ.get("TELEGRAM_CHAT_ID", "0"))
# === POSITION SIZING ===
TRADE_SIZE_USDT = float(os.environ.get("TRADE_SIZE_USDT", "20")) # $20 per trade (Zvwap, no DCA)
MAX_LEVERAGE = int(os.environ.get("MAX_LEVERAGE", "3"))
MAX_OPEN_POSITIONS = int(os.environ.get("MAX_OPEN_POSITIONS", "6"))
# === RISK MANAGEMENT ===
MAX_DAILY_LOSS_USDT = float(os.environ.get("MAX_DAILY_LOSS_USDT", "50")) # $50 daily loss limit
MAX_TOTAL_EXPOSURE_PCT = float(os.environ.get("MAX_TOTAL_EXPOSURE_PCT", "50"))
# === FEES (Bybit Linear USDT Perps) ===
TAKER_FEE_PCT = 0.055 # 0.055%
MAKER_FEE_PCT = 0.02 # 0.02%
# === GENERAL ===
LOG_LEVEL = os.environ.get("LOG_LEVEL", "INFO")
PRICE_CHECK_INTERVAL = int(os.environ.get("PRICE_CHECK_INTERVAL", "3"))
# === PATHS ===
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DATA_DIR = os.path.join(PROJECT_ROOT, "data")
def validate():
"""Validate required config. Raises ValueError if missing."""
errors = []
if not BYBIT_API_KEY:
errors.append("BYBIT_API_KEY is not set")
if not BYBIT_API_SECRET:
errors.append("BYBIT_API_SECRET is not set")
if not TELEGRAM_BOT_TOKEN:
errors.append("TELEGRAM_BOT_TOKEN is not set")
if not TELEGRAM_CHAT_ID:
errors.append("TELEGRAM_CHAT_ID is not set")
if errors:
raise ValueError("Config errors:\n " + "\n ".join(errors))