more quiet logging

This commit is contained in:
Dobromir Popov 2025-03-19 04:32:19 +02:00
parent 1a1c410922
commit dc532f8795
3 changed files with 209 additions and 27 deletions

View File

@ -2,6 +2,11 @@ https://github.com/mexcdevelop/mexc-api-sdk/blob/main/README.md#test-new-order
python mexc_tick_visualizer.py --symbol BTC/USDT --interval 1.0 --candle 60
python main.py --mode live --symbol ETH/USDT --timeframe 1m --use-websocket
python main.py --mode live --symbol BTC/USDT --timeframe 1m --use-websocket --dashboard
# http://localhost:8060
& 'C:\Users\popov\miniforge3\python.exe' 'c:\Users\popov\.cursor\extensions\ms-python.debugpy-2024.6.0-win32-x64\bundled\libs\debugpy\adapter/../..\debugpy\launcher' '51766' '--' 'main.py' '--mode' 'live' '--demo' 'false' '--symbol' 'ETH/USDT' '--timeframe' '1m' '--leverage' '50'

229
main.py
View File

@ -48,6 +48,22 @@ logging.basicConfig(
)
logger = logging.getLogger("trading_bot")
# Look for WebSocket specific logger
websocket_logger = logging.getLogger('websocket') # or similar name
websocket_logger.setLevel(logging.INFO) # Change this from DEBUG to INFO
# Add this somewhere after the logger is defined
class WebSocketFilter(logging.Filter):
def filter(self, record):
# Filter out DEBUG messages from WebSocket-related modules
if record.levelno == logging.DEBUG and ('websocket' in record.name or
'protocol' in record.name or
'realtime' in record.name):
return False
return True
logger.addFilter(WebSocketFilter())
# Load environment variables
load_dotenv()
MEXC_API_KEY = os.getenv('MEXC_API_KEY')
@ -287,8 +303,15 @@ class PricePredictionModel(nn.Module):
return total_loss / epochs
class TradingEnvironment:
"""Trading environment for reinforcement learning with enhanced features"""
def __init__(self, initial_balance=INITIAL_BALANCE, window_size=30, demo=True):
"""Initialize the trading environment"""
"""Initialize trading environment
Args:
initial_balance: Starting account balance
window_size: Number of candles in the state window
demo: Whether to run in demo mode
"""
self.initial_balance = initial_balance
self.balance = initial_balance
self.window_size = window_size
@ -310,6 +333,13 @@ class TradingEnvironment:
self.current_step = 0
self.current_price = 0
# Risk management parameters (adjusted for more aggressive trading)
self.stop_loss_pct = STOP_LOSS_PERCENT * 0.8 # Tighter stop loss (80% of original)
self.take_profit_pct = TAKE_PROFIT_PERCENT * 1.5 # Higher take profit (150% of original)
self.trailing_stop_activated = False
self.trailing_stop_distance = 0
self.max_position_size_pct = 0.8 # Use up to 80% of balance for position size
# For tracking signals for visualization
self.trade_signals = []
@ -473,6 +503,9 @@ class TradingEnvironment:
}
return next_state, 0, done, info
# Adapt trading parameters to current market conditions
self.adapt_trading_parameters_to_market()
# Store current price before taking action
self.current_price = self.data[self.current_step]['close']
@ -985,8 +1018,9 @@ class TradingEnvironment:
self.position = 'long'
self.entry_price = self.current_price
self.position_size = self.calculate_position_size()
self.stop_loss = self.entry_price * (1 - STOP_LOSS_PERCENT/100)
self.take_profit = self.entry_price * (1 + TAKE_PROFIT_PERCENT/100)
# Use the adjusted risk parameters
self.stop_loss = self.entry_price * (1 - self.stop_loss_pct/100)
self.take_profit = self.entry_price * (1 + self.take_profit_pct/100)
# Check if this is an optimal buy point (bottom)
current_idx = len(self.features['price']) - 1
@ -1059,8 +1093,8 @@ class TradingEnvironment:
self.entry_price = self.current_price
self.entry_index = len(self.features['price']) - 1
self.position_size = self.calculate_position_size()
self.stop_loss = self.entry_price * (1 - STOP_LOSS_PERCENT/100)
self.take_profit = self.entry_price * (1 + TAKE_PROFIT_PERCENT/100)
self.stop_loss = self.entry_price * (1 - self.stop_loss_pct/100)
self.take_profit = self.entry_price * (1 + self.take_profit_pct/100)
# Check if this is an optimal buy point
if hasattr(self, 'optimal_bottoms') and self.entry_index in self.optimal_bottoms:
@ -1074,8 +1108,9 @@ class TradingEnvironment:
self.position = 'short'
self.entry_price = self.current_price
self.position_size = self.calculate_position_size()
self.stop_loss = self.entry_price * (1 + STOP_LOSS_PERCENT/100)
self.take_profit = self.entry_price * (1 - TAKE_PROFIT_PERCENT/100)
# Use the adjusted risk parameters
self.stop_loss = self.entry_price * (1 + self.stop_loss_pct/100)
self.take_profit = self.entry_price * (1 - self.take_profit_pct/100)
# Check if this is an optimal sell point (top)
current_idx = len(self.features['price']) - 1
@ -1138,8 +1173,8 @@ class TradingEnvironment:
self.position = 'short'
self.entry_price = self.current_price
self.position_size = self.calculate_position_size()
self.stop_loss = self.entry_price * (1 + STOP_LOSS_PERCENT/100)
self.take_profit = self.entry_price * (1 - TAKE_PROFIT_PERCENT/100)
self.stop_loss = self.entry_price * (1 + self.stop_loss_pct/100)
self.take_profit = self.entry_price * (1 - self.take_profit_pct/100)
# Check if this is an optimal sell point
current_idx = len(self.features['price']) - 1
@ -1387,26 +1422,19 @@ class TradingEnvironment:
logger.info(f"Identified {len(bottoms)} optimal buy points and {len(tops)} optimal sell points")
def calculate_position_size(self):
"""Calculate position size based on current balance and risk parameters"""
# Use a fixed percentage of balance for each trade
risk_percent = 5.0 # Risk 5% of balance per trade
"""Calculate position size based on current balance and risk parameters
# Calculate position size with leverage
position_size = self.balance * (risk_percent / 100) * MAX_LEVERAGE
Returns:
float: Position size in quote currency
"""
# More aggressive position sizing
risk_amount = self.balance * (self.max_position_size_pct * random.uniform(0.7, 1.0))
# Apply a safety factor to avoid liquidation
safety_factor = 0.8
position_size *= safety_factor
# In futures trading, adjust for leverage
if hasattr(self, 'leverage') and self.leverage > 1:
risk_amount = min(risk_amount * self.leverage, self.balance * 10) # Limit max risk
# Ensure minimum position size
min_position = 10.0 # Minimum position size in USD
position_size = max(position_size, min(min_position, self.balance * 0.5))
# Ensure position size doesn't exceed balance * leverage
max_position = self.balance * MAX_LEVERAGE
position_size = min(position_size, max_position)
return position_size
return risk_amount
def calculate_fees(self, position_size):
"""Calculate trading fees for a given position size"""
@ -1639,6 +1667,105 @@ class TradingEnvironment:
logger.error(f"Trade execution failed: {e}")
return None
def is_volatile_market(self):
"""Detect if the market is currently in a volatile state with significant price movements
Returns:
bool: True if market is volatile, False otherwise
"""
if len(self.features['price']) < 20:
return False
# Calculate recent price volatility
recent_prices = self.features['price'][-20:]
returns = np.diff(recent_prices) / recent_prices[:-1]
volatility = np.std(returns) * 100 # Convert to percentage
# Calculate volume increase
recent_volumes = self.features['volume'][-10:]
avg_volume_prev = np.mean(self.features['volume'][-20:-10])
avg_volume_recent = np.mean(recent_volumes)
volume_increase = avg_volume_recent / avg_volume_prev if avg_volume_prev > 0 else 1.0
# Calculate ATR if available
atr_high = False
if len(self.features['atr']) > 5:
recent_atr = self.features['atr'][-1]
avg_atr = np.mean(self.features['atr'][-20:-1])
atr_ratio = recent_atr / avg_atr if avg_atr > 0 else 1.0
atr_high = atr_ratio > 1.5
# Check if price moved significantly in either direction recently
price_range_percent = (max(recent_prices) - min(recent_prices)) / min(recent_prices) * 100
# Market is volatile if any of these conditions are met
volatile = (
volatility > 0.5 or # High standard deviation of returns
volume_increase > 1.8 or # Volume spike
price_range_percent > 1.5 or # Large price range
atr_high # High ATR relative to average
)
if volatile:
logger.info(f"Volatile market detected - Volatility: {volatility:.2f}%, Volume increase: {volume_increase:.2f}x, Price range: {price_range_percent:.2f}%")
return volatile
def adapt_trading_parameters_to_market(self):
"""Dynamically adjust trading parameters based on market conditions
Returns:
None
"""
# Check market conditions
is_volatile = self.is_volatile_market()
is_trending_up = self.is_uptrend()
is_trending_down = self.is_downtrend()
# Base parameters
base_stop_loss = STOP_LOSS_PERCENT
base_take_profit = TAKE_PROFIT_PERCENT
base_position_size = 0.5 # 50% of max
# Adjust based on market conditions
if is_volatile:
# In volatile markets, use tighter stops but higher take profits
self.stop_loss_pct = base_stop_loss * 0.7 # Tighter stop
self.take_profit_pct = base_take_profit * 1.8 # Higher target
self.max_position_size_pct = base_position_size * 1.3 # More aggressive sizing
elif is_trending_up:
# In uptrends, use looser stops for longs, tighter for shorts
if self.position == 'long' or self.position == 'flat':
self.stop_loss_pct = base_stop_loss * 0.9
self.take_profit_pct = base_take_profit * 1.6
self.max_position_size_pct = base_position_size * 1.2
else:
# More conservative for shorts in uptrend
self.stop_loss_pct = base_stop_loss * 0.7
self.take_profit_pct = base_take_profit * 1.2
self.max_position_size_pct = base_position_size * 0.8
elif is_trending_down:
# In downtrends, use looser stops for shorts, tighter for longs
if self.position == 'short' or self.position == 'flat':
self.stop_loss_pct = base_stop_loss * 0.9
self.take_profit_pct = base_take_profit * 1.6
self.max_position_size_pct = base_position_size * 1.2
else:
# More conservative for longs in downtrend
self.stop_loss_pct = base_stop_loss * 0.7
self.take_profit_pct = base_take_profit * 1.2
self.max_position_size_pct = base_position_size * 0.8
else:
# In sideways/uncertain markets, be more balanced
self.stop_loss_pct = base_stop_loss * 0.8
self.take_profit_pct = base_take_profit * 1.3
self.max_position_size_pct = base_position_size
# Log the adaptation
logger.debug(f"Adapted trading parameters - Stop loss: {self.stop_loss_pct:.2f}%, Take profit: {self.take_profit_pct:.2f}%, Max position size: {self.max_position_size_pct*100:.1f}%")
# Ensure GPU usage if available
def get_device():
"""Get the best available device (CUDA GPU or CPU)"""
@ -2787,6 +2914,12 @@ async def process_websocket_ticks(websocket, env, agent=None, demo=True, timefra
trades_count = 0
step_counter = 0
# For tracking sudden price movements
last_prices = []
price_movement_threshold = 0.5 # 0.5% movement threshold
volume_spike_threshold = 2.0 # 2x average volume
recent_volumes = []
try:
logger.info("Starting WebSocket tick processing...")
@ -2808,6 +2941,50 @@ async def process_websocket_ticks(websocket, env, agent=None, demo=True, timefra
logger.warning(f"Invalid tick data received: {tick}")
continue
# Track price movement for significant changes
last_prices.append(price)
if len(last_prices) > 20:
last_prices.pop(0)
# Track volumes for volume spikes
recent_volumes.append(volume)
if len(recent_volumes) > 20:
recent_volumes.pop(0)
# Check for significant price movement
if len(last_prices) >= 5:
price_change_pct = abs(price - last_prices[0]) / last_prices[0] * 100
avg_volume = np.mean(recent_volumes[:-1]) if len(recent_volumes) > 1 else volume
volume_ratio = volume / avg_volume if avg_volume > 0 else 1.0
# Log significant movements
if price_change_pct > price_movement_threshold:
logger.info(f"Significant price movement detected: {price_change_pct:.2f}% change")
if volume_ratio > volume_spike_threshold:
logger.info(f"Volume spike detected: {volume_ratio:.2f}x average volume")
# Force more frequent trading decisions on significant movements
if (price_change_pct > price_movement_threshold or volume_ratio > volume_spike_threshold) and agent is not None and current_candle is not None:
# Create a temporary candle with current data
temp_candle = current_candle.copy()
temp_candle['close'] = price # Update with latest price
# Add to environment temporarily
env.add_data(temp_candle)
# Get action
state = env.get_state()
# Force exploitation (no exploration) during significant movements
action = agent.select_action(state, training=False)
# Execute action in environment
next_state, reward, done, info = env.step(action)
# Log trading activity
action_name = "HOLD" if action == 0 else "BUY" if action == 1 else "SELL" if action == 2 else "CLOSE"
logger.info(f"Significant movement action: {action_name}, Price: ${price:.2f}, Balance: ${env.balance:.2f}")
# Convert timestamp to datetime
tick_time = datetime.datetime.fromtimestamp(timestamp / 1000)

View File

@ -20,7 +20,7 @@ from datetime import datetime, timedelta
# Configure logging with more detailed format
logging.basicConfig(
level=logging.DEBUG, # Changed to DEBUG for more detailed logs
level=logging.INFO, # Changed to DEBUG for more detailed logs
format='%(asctime)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s',
handlers=[
logging.StreamHandler(),