fix: refine base_coin extraction to support BTCUSD and fix DB queries (v1.5.4)
This commit is contained in:
@ -86,7 +86,7 @@ class DatabaseManager:
|
|||||||
|
|
||||||
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.3"
|
self.version = "1.5.4"
|
||||||
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)
|
||||||
|
|
||||||
@ -113,12 +113,18 @@ class PingPongBot:
|
|||||||
password=os.getenv('DB_PASSWORD', '')
|
password=os.getenv('DB_PASSWORD', '')
|
||||||
)
|
)
|
||||||
|
|
||||||
# Base settings
|
# Base settings - Improved extraction
|
||||||
self.base_coin = self.config['symbol'].upper().replace("USDT", "").replace("USDC", "") # e.g. BTC
|
raw_symbol = self.config['symbol'].upper()
|
||||||
|
# Remove common suffixes to get base coin (e.g., BTCUSD -> BTC, BTCUSDT -> BTC)
|
||||||
|
self.base_coin = raw_symbol.replace("USDT", "").replace("USDC", "").replace("USD", "")
|
||||||
|
|
||||||
self.db_symbol = self.base_coin
|
self.db_symbol = self.base_coin
|
||||||
self.interval = str(self.config['interval'])
|
self.interval = str(self.config['interval'])
|
||||||
|
# Map interval to DB format: '30' -> '30m'
|
||||||
self.db_interval = self.interval + "m" if self.interval.isdigit() else self.interval
|
self.db_interval = self.interval + "m" if self.interval.isdigit() else self.interval
|
||||||
|
|
||||||
|
logger.info(f"Bot v{self.version} Initialized | DB Symbol: {self.db_symbol} | DB Interval: {self.db_interval}")
|
||||||
|
|
||||||
# Dynamic Strategy State
|
# Dynamic Strategy State
|
||||||
self.direction = None # 'long' or 'short'
|
self.direction = None # 'long' or 'short'
|
||||||
self.category = None # 'linear' or 'inverse'
|
self.category = None # 'linear' or 'inverse'
|
||||||
@ -145,7 +151,6 @@ class PingPongBot:
|
|||||||
self.console = Console()
|
self.console = Console()
|
||||||
|
|
||||||
# Fixed Parameters from Config
|
# Fixed Parameters from Config
|
||||||
self.tp_pct = float(self.config.get('take_profit_pct', 1.5)) / 100.0
|
|
||||||
self.partial_exit_pct = float(self.config.get('partial_exit_pct', 0.15))
|
self.partial_exit_pct = float(self.config.get('partial_exit_pct', 0.15))
|
||||||
self.min_val_usd = float(self.config.get('min_position_value_usd', 15.0))
|
self.min_val_usd = float(self.config.get('min_position_value_usd', 15.0))
|
||||||
self.pos_size_margin = float(self.config.get('pos_size_margin', 20.0))
|
self.pos_size_margin = float(self.config.get('pos_size_margin', 20.0))
|
||||||
@ -186,13 +191,12 @@ class PingPongBot:
|
|||||||
async def update_direction(self):
|
async def update_direction(self):
|
||||||
"""Logic Point I: 1D MA44 check and Point II: Asset/Perp selection"""
|
"""Logic Point I: 1D MA44 check and Point II: Asset/Perp selection"""
|
||||||
try:
|
try:
|
||||||
logger.info("Checking direction based on SMA(44, 1D)...")
|
logger.info(f"Checking direction based on SMA(44, 1D) for {self.db_symbol}...")
|
||||||
# Increase limit to ensure we get enough data even with potential gaps
|
|
||||||
candles_1d = await self.db.get_candles(self.db_symbol, "1d", limit=100)
|
candles_1d = await self.db.get_candles(self.db_symbol, "1d", limit=100)
|
||||||
|
|
||||||
if not candles_1d or len(candles_1d) < 44:
|
if not candles_1d or len(candles_1d) < 44:
|
||||||
got = len(candles_1d) if candles_1d else 0
|
got = len(candles_1d) if candles_1d else 0
|
||||||
logger.warning(f"Not enough 1D data for MA44. Got {got} candles for {self.db_symbol}.")
|
logger.warning(f"Not enough 1D data for MA44. Got {got} candles for {self.db_symbol} / 1d.")
|
||||||
self.status_msg = f"Error: Need 44 1D candles (Got {got})"
|
self.status_msg = f"Error: Need 44 1D candles (Got {got})"
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -214,14 +218,11 @@ 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"
|
||||||
@ -231,7 +232,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 # Force indicator recalculation
|
self.last_candle_time = None
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
@ -276,7 +277,6 @@ class PingPongBot:
|
|||||||
usdc_bal = coins.get("USDC", 0)
|
usdc_bal = coins.get("USDC", 0)
|
||||||
if usdc_bal > 1.0:
|
if usdc_bal > 1.0:
|
||||||
logger.info(f"Spot: Buying {self.base_coin} with {usdc_bal} USDC")
|
logger.info(f"Spot: Buying {self.base_coin} with {usdc_bal} USDC")
|
||||||
# Spot Market Buy using orderAmount (spending USDC)
|
|
||||||
await asyncio.to_thread(self.session.place_order,
|
await asyncio.to_thread(self.session.place_order,
|
||||||
category="spot", symbol=spot_symbol, side="Buy", orderType="Market",
|
category="spot", symbol=spot_symbol, side="Buy", orderType="Market",
|
||||||
qty=str(usdc_bal), marketUnit="quote"
|
qty=str(usdc_bal), marketUnit="quote"
|
||||||
@ -316,7 +316,6 @@ class PingPongBot:
|
|||||||
last, prev = df.iloc[-1], df.iloc[-2]
|
last, prev = df.iloc[-1], df.iloc[-2]
|
||||||
rsi_cfg, hurst_cfg = self.config['rsi'], self.config['hurst']
|
rsi_cfg, hurst_cfg = self.config['rsi'], self.config['hurst']
|
||||||
|
|
||||||
# Signals defined by crossover
|
|
||||||
l_open = (rsi_cfg['enabled_for_open'] and prev['rsi'] < rsi_cfg['oversold'] and last['rsi'] >= rsi_cfg['oversold']) or \
|
l_open = (rsi_cfg['enabled_for_open'] and prev['rsi'] < rsi_cfg['oversold'] and last['rsi'] >= rsi_cfg['oversold']) or \
|
||||||
(hurst_cfg['enabled_for_open'] and prev['close'] > prev['hurst_lower'] and last['close'] <= last['hurst_lower'])
|
(hurst_cfg['enabled_for_open'] and prev['close'] > prev['hurst_lower'] and last['close'] <= last['hurst_lower'])
|
||||||
l_close = (rsi_cfg['enabled_for_close'] and prev['rsi'] > rsi_cfg['overbought'] and last['rsi'] <= rsi_cfg['overbought']) or \
|
l_close = (rsi_cfg['enabled_for_close'] and prev['rsi'] > rsi_cfg['overbought'] and last['rsi'] <= rsi_cfg['overbought']) or \
|
||||||
|
|||||||
Reference in New Issue
Block a user