From 8b076106dce00a9f94dae6c3f35f90bb27d4e959 Mon Sep 17 00:00:00 2001 From: Gemini CLI Date: Thu, 5 Mar 2026 23:26:59 +0100 Subject: [PATCH] fix: ensure DB credentials are explicitly passed and verified (v1.5.3) --- src/strategies/ping_pong_bot.py | 85 +++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 26 deletions(-) diff --git a/src/strategies/ping_pong_bot.py b/src/strategies/ping_pong_bot.py index 3fdf1bb..ca31e00 100644 --- a/src/strategies/ping_pong_bot.py +++ b/src/strategies/ping_pong_bot.py @@ -41,37 +41,56 @@ logger = logging.getLogger("PingPongBot") class DatabaseManager: """Minimal Database Manager for the bot""" - def __init__(self): - self.host = os.getenv('DB_HOST', '20.20.20.20') - self.port = int(os.getenv('DB_PORT', 5433)) - self.database = os.getenv('DB_NAME', 'btc_data') - self.user = os.getenv('DB_USER', 'btc_bot') - self.password = os.getenv('DB_PASSWORD', '') + def __init__(self, host, port, database, user, password): + self.host = host + self.port = int(port) + self.database = database + self.user = user + self.password = password self.pool = None async def connect(self): - self.pool = await asyncpg.create_pool( - host=self.host, port=self.port, user=self.user, - password=self.password, database=self.database - ) - logger.info("Connected to Database") + try: + self.pool = await asyncpg.create_pool( + host=self.host, port=self.port, user=self.user, + password=self.password, database=self.database, + min_size=1, max_size=10 + ) + # Test connection + async with self.pool.acquire() as conn: + res = await conn.fetchval("SELECT 1") + if res == 1: + logger.info(f"Database connection verified at {self.host}:{self.port}") + else: + raise Exception("Database test query failed") + except Exception as e: + logger.error(f"DATABASE CONNECTION FAILED: {e}") + raise async def get_candles(self, symbol: str, interval: str, limit: int = 100): - async with self.pool.acquire() as conn: - rows = await conn.fetch(''' - SELECT time, open, high, low, close, volume - FROM candles - WHERE symbol = $1 AND interval = $2 - ORDER BY time DESC LIMIT $3 - ''', symbol, interval, limit) - return [dict(r) for r in rows] + if not self.pool: + logger.error("Attempted to query DB before connecting") + return [] + try: + async with self.pool.acquire() as conn: + rows = await conn.fetch(''' + SELECT time, open, high, low, close, volume + FROM candles + WHERE symbol = $1 AND interval = $2 + ORDER BY time DESC LIMIT $3 + ''', symbol, interval, limit) + return [dict(r) for r in rows] + except Exception as e: + logger.error(f"DB Query Error for {symbol} {interval}: {e}") + return [] class PingPongBot: def __init__(self, config_path="config/ping_pong_config.yaml"): - self.version = "1.5.2" + self.version = "1.5.3" with open(config_path, 'r') as f: self.config = yaml.safe_load(f) + # Explicitly load from ENV to ensure they are available self.api_key = os.getenv("BYBIT_API_KEY") or os.getenv("API_KEY") self.api_secret = os.getenv("BYBIT_API_SECRET") or os.getenv("API_SECRET") @@ -85,7 +104,14 @@ class PingPongBot: timeout=10 ) - self.db = DatabaseManager() + # Initialize DB with explicit credentials + self.db = DatabaseManager( + host=os.getenv('DB_HOST', '20.20.20.20'), + port=os.getenv('DB_PORT', 5433), + database=os.getenv('DB_NAME', 'btc_data'), + user=os.getenv('DB_USER', 'btc_bot'), + password=os.getenv('DB_PASSWORD', '') + ) # Base settings self.base_coin = self.config['symbol'].upper().replace("USDT", "").replace("USDC", "") # e.g. BTC @@ -188,11 +214,14 @@ class PingPongBot: logger.info(f"DIRECTION CHANGE: {self.direction} -> {new_direction} (Price: {current_price:.2f}, MA44: {self.ma_44_val:.2f})") self.status_msg = f"Switching to {new_direction.upper()}" + # 1. Close all positions (Point III.3) if self.direction is not None: await self.close_all_positions() + # 2. Swap Assets on Spot (Point II) await self.swap_assets(new_direction) + # 3. Update configuration self.direction = new_direction if self.direction == "long": self.category = "inverse" @@ -202,7 +231,7 @@ class PingPongBot: self.symbol = f"{self.base_coin}USDC" logger.info(f"Bot configured for {self.direction.upper()} | Symbol: {self.symbol} | Category: {self.category}") - self.last_candle_time = None + self.last_candle_time = None # Force indicator recalculation return True return False @@ -265,8 +294,8 @@ class PingPongBot: if ticker['retCode'] == 0: self.market_price = float(ticker['result']['list'][0]['lastPrice']) - # settleCoin is only for linear perpetuals - settle_coin = "USDC" if self.category == "linear" else None + # settleCoin is only for USDC linear perpetuals + settle_coin = "USDC" if (self.category == "linear" and "USDC" in self.symbol) else None pos = await asyncio.to_thread(self.session.get_positions, category=self.category, symbol=self.symbol, settleCoin=settle_coin) if pos['retCode'] == 0: active = [p for p in pos['result']['list'] if float(p.get('size', 0)) > 0] @@ -376,8 +405,12 @@ class PingPongBot: self.console.print("="*60 + "\n") async def run(self): - await self.db.connect() - await self.update_direction() + try: + await self.db.connect() + await self.update_direction() + except Exception as e: + logger.error(f"Startup Failure: {e}") + return last_exchange_update = 0 while True: