fix: ensure DB credentials are explicitly passed and verified (v1.5.3)
This commit is contained in:
@ -41,37 +41,56 @@ logger = logging.getLogger("PingPongBot")
|
|||||||
|
|
||||||
class DatabaseManager:
|
class DatabaseManager:
|
||||||
"""Minimal Database Manager for the bot"""
|
"""Minimal Database Manager for the bot"""
|
||||||
def __init__(self):
|
def __init__(self, host, port, database, user, password):
|
||||||
self.host = os.getenv('DB_HOST', '20.20.20.20')
|
self.host = host
|
||||||
self.port = int(os.getenv('DB_PORT', 5433))
|
self.port = int(port)
|
||||||
self.database = os.getenv('DB_NAME', 'btc_data')
|
self.database = database
|
||||||
self.user = os.getenv('DB_USER', 'btc_bot')
|
self.user = user
|
||||||
self.password = os.getenv('DB_PASSWORD', '')
|
self.password = password
|
||||||
self.pool = None
|
self.pool = None
|
||||||
|
|
||||||
async def connect(self):
|
async def connect(self):
|
||||||
self.pool = await asyncpg.create_pool(
|
try:
|
||||||
host=self.host, port=self.port, user=self.user,
|
self.pool = await asyncpg.create_pool(
|
||||||
password=self.password, database=self.database
|
host=self.host, port=self.port, user=self.user,
|
||||||
)
|
password=self.password, database=self.database,
|
||||||
logger.info("Connected to 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 def get_candles(self, symbol: str, interval: str, limit: int = 100):
|
||||||
async with self.pool.acquire() as conn:
|
if not self.pool:
|
||||||
rows = await conn.fetch('''
|
logger.error("Attempted to query DB before connecting")
|
||||||
SELECT time, open, high, low, close, volume
|
return []
|
||||||
FROM candles
|
try:
|
||||||
WHERE symbol = $1 AND interval = $2
|
async with self.pool.acquire() as conn:
|
||||||
ORDER BY time DESC LIMIT $3
|
rows = await conn.fetch('''
|
||||||
''', symbol, interval, limit)
|
SELECT time, open, high, low, close, volume
|
||||||
return [dict(r) for r in rows]
|
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:
|
class PingPongBot:
|
||||||
def __init__(self, config_path="config/ping_pong_config.yaml"):
|
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:
|
with open(config_path, 'r') as f:
|
||||||
self.config = yaml.safe_load(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_key = os.getenv("BYBIT_API_KEY") or os.getenv("API_KEY")
|
||||||
self.api_secret = os.getenv("BYBIT_API_SECRET") or os.getenv("API_SECRET")
|
self.api_secret = os.getenv("BYBIT_API_SECRET") or os.getenv("API_SECRET")
|
||||||
|
|
||||||
@ -85,7 +104,14 @@ class PingPongBot:
|
|||||||
timeout=10
|
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
|
# Base settings
|
||||||
self.base_coin = self.config['symbol'].upper().replace("USDT", "").replace("USDC", "") # e.g. BTC
|
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})")
|
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()}"
|
self.status_msg = f"Switching to {new_direction.upper()}"
|
||||||
|
|
||||||
|
# 1. Close all positions (Point III.3)
|
||||||
if self.direction is not None:
|
if self.direction is not None:
|
||||||
await self.close_all_positions()
|
await self.close_all_positions()
|
||||||
|
|
||||||
|
# 2. Swap Assets on Spot (Point II)
|
||||||
await self.swap_assets(new_direction)
|
await self.swap_assets(new_direction)
|
||||||
|
|
||||||
|
# 3. Update configuration
|
||||||
self.direction = new_direction
|
self.direction = new_direction
|
||||||
if self.direction == "long":
|
if self.direction == "long":
|
||||||
self.category = "inverse"
|
self.category = "inverse"
|
||||||
@ -202,7 +231,7 @@ class PingPongBot:
|
|||||||
self.symbol = f"{self.base_coin}USDC"
|
self.symbol = f"{self.base_coin}USDC"
|
||||||
|
|
||||||
logger.info(f"Bot configured for {self.direction.upper()} | Symbol: {self.symbol} | Category: {self.category}")
|
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 True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
@ -265,8 +294,8 @@ class PingPongBot:
|
|||||||
if ticker['retCode'] == 0:
|
if ticker['retCode'] == 0:
|
||||||
self.market_price = float(ticker['result']['list'][0]['lastPrice'])
|
self.market_price = float(ticker['result']['list'][0]['lastPrice'])
|
||||||
|
|
||||||
# settleCoin is only for linear perpetuals
|
# settleCoin is only for USDC linear perpetuals
|
||||||
settle_coin = "USDC" if self.category == "linear" else None
|
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)
|
pos = await asyncio.to_thread(self.session.get_positions, category=self.category, symbol=self.symbol, settleCoin=settle_coin)
|
||||||
if pos['retCode'] == 0:
|
if pos['retCode'] == 0:
|
||||||
active = [p for p in pos['result']['list'] if float(p.get('size', 0)) > 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")
|
self.console.print("="*60 + "\n")
|
||||||
|
|
||||||
async def run(self):
|
async def run(self):
|
||||||
await self.db.connect()
|
try:
|
||||||
await self.update_direction()
|
await self.db.connect()
|
||||||
|
await self.update_direction()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Startup Failure: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
last_exchange_update = 0
|
last_exchange_update = 0
|
||||||
while True:
|
while True:
|
||||||
|
|||||||
Reference in New Issue
Block a user