Files

167 lines
6.8 KiB
Python
Raw Permalink Normal View History

2025-12-16 22:02:15 +01:00
"""
Adaptive Rhythm Manager - Extracted from Notebook
Manages adaptive trading intervals based on volatility and session
"""
import MetaTrader5 as mt5
2025-12-16 22:02:15 +01:00
import pandas as pd
import pandas_ta as ta
from datetime import datetime, time, timezone
2025-12-16 22:02:15 +01:00
import logging
logger = logging.getLogger(__name__)
class AdaptiveRhythmManager:
"""
Adaptive Trading Rhythm Manager
Verwaltet adaptiven Trading-Rhythmus basierend auf:
- Marktvolatilität (ATR)
- Trading-Session (Asian/London/NY/Overlap)
- Marktregime
"""
def __init__(self, symbol="XAUUSD"):
self.symbol = symbol
self.current_interval = 5
# Zeitintervalle in Minuten
self.intervals = {
'fast': 5, # Hohe Volatilität, aktive Sessions
'medium': 15, # Moderate Volatilität, Standard
'slow': 30 # Niedrige Volatilität, ruhige Sessions
}
# ATR-Schwellenwerte für XAUUSD (Gold)
self.atr_thresholds = {
'high': 15.0, # Hohe Volatilität
'medium': 8.0, # Moderate Volatilität
'low': 5.0 # Niedrige Volatilität
}
# Session-Zeiten (UTC)
self.sessions = {
'asian': (time(0, 0), time(8, 0)), # 00:00-08:00 UTC
'london': (time(8, 0), time(16, 0)), # 08:00-16:00 UTC
'ny': (time(13, 0), time(21, 0)), # 13:00-21:00 UTC
'overlap': (time(13, 0), time(16, 0)) # London-NY Overlap
}
def get_current_session(self):
"""Ermittelt die aktuelle Trading-Session"""
now_utc = datetime.now(timezone.utc).time()
2025-12-16 22:02:15 +01:00
# Overlap hat höchste Priorität
if self.sessions['overlap'][0] <= now_utc <= self.sessions['overlap'][1]:
return 'overlap'
elif self.sessions['london'][0] <= now_utc < self.sessions['london'][1]:
return 'london'
elif self.sessions['ny'][0] <= now_utc < self.sessions['ny'][1]:
return 'ny'
return 'asian'
def get_volatility_level(self, atr_value):
"""Klassifiziert die Volatilität basierend auf ATR"""
if atr_value >= self.atr_thresholds['high']:
return 'high'
elif atr_value >= self.atr_thresholds['medium']:
return 'medium'
return 'low'
def get_market_data(self):
"""Hole Marktdaten für ATR-Analyse"""
try:
rates = mt5.copy_rates_from_pos(self.symbol, mt5.TIMEFRAME_H1, 0, 50)
2025-12-16 22:02:15 +01:00
if rates is None:
return None
# mt5 may return a structured numpy array or DataFrame depending on version
df = rates if isinstance(rates, pd.DataFrame) else pd.DataFrame(rates)
2025-12-16 22:02:15 +01:00
df['time'] = pd.to_datetime(df['time'], unit='s')
df.set_index('time', inplace=True)
if len(df) < 14:
logger.warning(f"Not enough data for ATR calculation: {len(df)} bars")
return None
2025-12-16 22:02:15 +01:00
df['atr'] = ta.atr(df['high'], df['low'], df['close'], length=14)
return df
except Exception as e:
logger.error(f"Fehler beim Laden der Marktdaten: {e}")
return None
def calculate_optimal_interval(self):
"""Berechnet optimales Trading-Intervall"""
session = self.get_current_session()
df = self.get_market_data()
if df is None:
return self.current_interval
current_atr = df['atr'].iloc[-1]
volatility = self.get_volatility_level(current_atr)
optimal_interval = self._determine_interval(session, volatility)
# Logge Änderungen
if optimal_interval != self.current_interval:
logger.info(f"🔄 Rhythmus-Änderung: {self.current_interval}m → {optimal_interval}m")
logger.info(f" Session: {session}, Volatilität: {volatility} (ATR: {current_atr:.2f})")
self.current_interval = optimal_interval
return optimal_interval
def _determine_interval(self, session, volatility):
"""
Intervall-Entscheidungs-Matrix:
Session │ Hohe Vol │ Mittlere Vol │ Niedrige Vol
───────────┼──────────┼──────────────┼─────────────
Overlap │ 5min │ 15min │ 15min
London/NY │ 5min │ 15min │ 30min
Asian │ 15min │ 30min │ 30min
"""
if session == 'overlap':
return self.intervals['fast'] if volatility == 'high' else self.intervals['medium']
elif session in ['london', 'ny']:
if volatility == 'high':
return self.intervals['fast']
elif volatility == 'medium':
return self.intervals['medium']
return self.intervals['slow']
else: # asian
return self.intervals['medium'] if volatility == 'high' else self.intervals['slow']
def shutdown(self):
"""Trennt MT5-Verbindung sauber"""
mt5.shutdown()
logger.info("AdaptiveRhythmManager: MT5 disconnected")
2025-12-16 22:02:15 +01:00
def get_status_report(self):
"""Erstellt Status-Report"""
session = self.get_current_session()
df = self.get_market_data()
if df is not None:
current_atr = df['atr'].iloc[-1]
volatility = self.get_volatility_level(current_atr)
else:
current_atr = 0
volatility = 'unknown'
return f"""
╔════════════════════════════════════════════════════════╗
║ ADAPTIVE RHYTHM STATUS - {datetime.now(timezone.utc).strftime('%H:%M:%S UTC')}
2025-12-16 22:02:15 +01:00
╠════════════════════════════════════════════════════════╣
║ Aktuelles Intervall: {self.current_interval:>2} Minuten ║
║ Trading Session: {session.upper():<15}
║ Volatilitätslevel: {volatility.upper():<15}
║ ATR (H1): {current_atr:>6.2f}
╠════════════════════════════════════════════════════════╣
║ INTERVALL-SCHEMA: ║
║ • Overlap (13-16 UTC): 5-15 Min (aktivste Phase) ║
║ • London/NY: 5-30 Min (volatilitätsabh.) ║
║ • Asian Session: 15-30 Min (ruhigere Phase) ║
╚════════════════════════════════════════════════════════╝
"""