Files
Place-Order-Trading-Bot/enhanced_trailing_stop.py
T
cbazzaandClaude Opus 4.5 38950e0254
Deploy to Windows VPS / deploy (push) Has been cancelled
fix: Adjust trailing stop parameters for Gold (XAUUSD) trading
PROBLEM:
- Trailing stop values were optimized for Forex, not Gold
- breakeven_buffer_pips=5 → only $0.05 buffer for Gold (way too small!)
- min_distance_points=100 → only $1.00 minimum (too tight!)
- Trades were being stopped out with only ~$0.50 profit

SOLUTION (Gold-optimized):
- breakeven_buffer_pips: 5 → 300 ($3.00 buffer)
- min_distance_points: 100 → 500 ($5.00 minimum distance)
- atr_multiplier: 1.0 → 1.5 (more breathing room)

IMPACT:
- Trades now have proper room to develop
- Less premature stop-outs
- Better profit potential per trade

Updated in:
- enhanced_trailing_stop.py (class defaults + initialization)
- TradingBot_V1.6_Adaptive_Complete_CORRECTED.ipynb (Cell 78)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 08:33:00 +01:00

507 lines
19 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
📈 Enhanced Trailing Stop Management
Verbesserte Trailing Stops mit ATR-basierter Dynamic Trailing
IMPROVEMENTS:
1. ATR-based Trailing (nicht fix, sondern dynamisch)
2. Time-based Breakeven (nach X Stunden)
3. Profit-based Aggressive Trailing
4. Session-aware Trailing (Asian vs NY)
5. Multi-tier Profit Locking
"""
import MetaTrader5 as mt
from datetime import datetime, timedelta
from typing import Tuple, Optional, Dict
import logging
logger = logging.getLogger(__name__)
class EnhancedTrailingStopManager:
"""
Verbesserte Trailing Stop Logik
Features:
- Früher Breakeven (30% statt 50%)
- ATR-basiertes Trailing (dynamisch statt fix)
- Time-based Protection (nach 4h auf BE)
- Multi-tier Profit Locking (50%, 75%, 90%)
"""
def __init__(self,
# Breakeven Settings
breakeven_trigger_pct: float = 0.30, # ← Früher! (war 0.50)
breakeven_buffer_pips: int = 300, # ← +$3 für Gold (300 × 0.01)
# Profit Locking (Multi-tier)
tier1_trigger: float = 0.50, # Bei 50% zu TP
tier1_lock_pct: float = 0.25, # Lock 25% profit
tier2_trigger: float = 0.75, # Bei 75% zu TP
tier2_lock_pct: float = 0.50, # Lock 50% profit
tier3_trigger: float = 0.90, # Bei 90% zu TP
tier3_lock_pct: float = 0.75, # Lock 75% profit
# ATR-based Trailing
use_atr_trailing: bool = True,
atr_multiplier: float = 1.5, # Trail by 1.5 × ATR (mehr Spielraum)
# Time-based Protection
time_based_breakeven: bool = True,
hours_to_breakeven: float = 4.0, # Nach 4h → BE
# Session-aware
session_trailing_multipliers: Optional[Dict[str, float]] = None,
# Technical
min_distance_points: int = 500): # Min $5 für Gold (500 × 0.01)
"""
Args:
breakeven_trigger_pct: Bei wie viel % zu TP → Breakeven
breakeven_buffer_pips: Zusätzliche Pips über Breakeven
tier1/2/3_trigger: Multi-tier Trigger Points
tier1/2/3_lock_pct: Lock Amounts pro Tier
use_atr_trailing: ATR-basiertes Trailing nutzen
atr_multiplier: ATR Multiplikator für Trailing
time_based_breakeven: Time-based BE aktivieren
hours_to_breakeven: Stunden bis Auto-Breakeven
session_trailing_multipliers: Custom Multiplier pro Session
min_distance_points: Minimum Distanz (Anti-Stop-Hunting)
"""
self.breakeven_trigger = breakeven_trigger_pct
self.breakeven_buffer_pips = breakeven_buffer_pips
self.tier1_trigger = tier1_trigger
self.tier1_lock = tier1_lock_pct
self.tier2_trigger = tier2_trigger
self.tier2_lock = tier2_lock_pct
self.tier3_trigger = tier3_trigger
self.tier3_lock = tier3_lock_pct
self.use_atr_trailing = use_atr_trailing
self.atr_multiplier = atr_multiplier
self.time_based_be = time_based_breakeven
self.hours_to_be = hours_to_breakeven
self.session_multipliers = session_trailing_multipliers or {
'asian': 1.0, # Standard
'ny': 1.5, # Größer (mehr Volatilität)
'london': 1.2,
'overlap': 1.3
}
self.min_distance = min_distance_points
# Tracking
self.position_tiers = {} # ticket → current tier
logger.info("✅ Enhanced Trailing Stop Manager initialized")
logger.info(f" Breakeven: {breakeven_trigger_pct*100:.0f}% + {breakeven_buffer_pips} pips")
logger.info(f" Multi-tier: {tier1_trigger*100:.0f}%/{tier2_trigger*100:.0f}%/{tier3_trigger*100:.0f}%")
logger.info(f" ATR Trailing: {'✅' if use_atr_trailing else '❌'}")
logger.info(f" Time-based BE: {'✅' if time_based_breakeven else '❌'} ({hours_to_breakeven}h)")
# ==========================================
# MAIN LOGIC
# ==========================================
def should_update_trailing_stop(self,
position,
current_session: str = 'asian',
atr_value: Optional[float] = None) -> Tuple[bool, Optional[float], str]:
"""
Prüft ob Trailing Stop aktualisiert werden sollte
Args:
position: MT5 Position Object
current_session: Aktuelle Session (für session-aware trailing)
atr_value: Aktueller ATR (für ATR-based trailing)
Returns:
(should_update, new_sl_price, reason)
"""
try:
ticket = position.ticket
position_type = position.type # 0=BUY, 1=SELL
entry_price = position.price_open
current_sl = position.sl
tp = position.tp
entry_time = datetime.fromtimestamp(position.time)
# Current Price
symbol_info = mt.symbol_info_tick(position.symbol)
if not symbol_info:
return False, None, "No symbol info"
current_price = symbol_info.bid if position_type == 0 else symbol_info.ask
point = mt.symbol_info(position.symbol).point
# Calculate progress
if position_type == 0: # BUY
tp_distance = tp - entry_price
current_distance = current_price - entry_price
else: # SELL
tp_distance = entry_price - tp
current_distance = entry_price - current_price
if tp_distance <= 0:
return False, None, "Invalid TP distance"
progress_pct = current_distance / tp_distance
trade_age_hours = (datetime.now() - entry_time).total_seconds() / 3600
# ==========================================
# 1. TIME-BASED BREAKEVEN
# ==========================================
if self.time_based_be and trade_age_hours >= self.hours_to_be:
if current_distance > 0: # In profit
new_sl = entry_price + (self.breakeven_buffer_pips * point if position_type == 0 else -self.breakeven_buffer_pips * point)
if self._is_valid_sl_update(position_type, current_price, new_sl, current_sl, point):
return True, new_sl, f"Time-based BE after {trade_age_hours:.1f}h"
# ==========================================
# 2. EARLY BREAKEVEN (30% statt 50%)
# ==========================================
if progress_pct >= self.breakeven_trigger:
if position_type == 0: # BUY
new_sl = entry_price + (self.breakeven_buffer_pips * point)
else: # SELL
new_sl = entry_price - (self.breakeven_buffer_pips * point)
if self._is_valid_sl_update(position_type, current_price, new_sl, current_sl, point):
return True, new_sl, f"Early BE at {progress_pct*100:.1f}% (+{self.breakeven_buffer_pips} pips buffer)"
# ==========================================
# 3. MULTI-TIER PROFIT LOCKING
# ==========================================
# Get current tier
current_tier = self.position_tiers.get(ticket, 0)
# Tier 3 (90%)
if progress_pct >= self.tier3_trigger and current_tier < 3:
locked_profit = tp_distance * self.tier3_lock
if position_type == 0: # BUY
new_sl = entry_price + locked_profit
else: # SELL
new_sl = entry_price - locked_profit
# ATR-based trailing wenn verfügbar
if self.use_atr_trailing and atr_value:
session_mult = self.session_multipliers.get(current_session, 1.0)
atr_distance = atr_value * self.atr_multiplier * session_mult
if position_type == 0:
new_sl = max(new_sl, current_price - atr_distance)
else:
new_sl = min(new_sl, current_price + atr_distance)
if self._is_valid_sl_update(position_type, current_price, new_sl, current_sl, point):
self.position_tiers[ticket] = 3
return True, new_sl, f"Tier 3: Locking {self.tier3_lock*100:.0f}% profit at {progress_pct*100:.1f}%"
# Tier 2 (75%)
if progress_pct >= self.tier2_trigger and current_tier < 2:
locked_profit = tp_distance * self.tier2_lock
if position_type == 0: # BUY
new_sl = entry_price + locked_profit
else: # SELL
new_sl = entry_price - locked_profit
# ATR-based trailing
if self.use_atr_trailing and atr_value:
session_mult = self.session_multipliers.get(current_session, 1.0)
atr_distance = atr_value * self.atr_multiplier * session_mult
if position_type == 0:
new_sl = max(new_sl, current_price - atr_distance)
else:
new_sl = min(new_sl, current_price + atr_distance)
if self._is_valid_sl_update(position_type, current_price, new_sl, current_sl, point):
self.position_tiers[ticket] = 2
return True, new_sl, f"Tier 2: Locking {self.tier2_lock*100:.0f}% profit at {progress_pct*100:.1f}%"
# Tier 1 (50%)
if progress_pct >= self.tier1_trigger and current_tier < 1:
locked_profit = tp_distance * self.tier1_lock
if position_type == 0: # BUY
new_sl = entry_price + locked_profit
else: # SELL
new_sl = entry_price - locked_profit
if self._is_valid_sl_update(position_type, current_price, new_sl, current_sl, point):
self.position_tiers[ticket] = 1
return True, new_sl, f"Tier 1: Locking {self.tier1_lock*100:.0f}% profit at {progress_pct*100:.1f}%"
# ==========================================
# 4. AGGRESSIVE ATR TRAILING (wenn Tier 3)
# ==========================================
if current_tier >= 3 and self.use_atr_trailing and atr_value:
session_mult = self.session_multipliers.get(current_session, 1.0)
atr_distance = atr_value * 0.5 * session_mult # Tighter: 0.5 × ATR
if position_type == 0: # BUY
new_sl = current_price - atr_distance
else: # SELL
new_sl = current_price + atr_distance
if self._is_valid_sl_update(position_type, current_price, new_sl, current_sl, point):
return True, new_sl, f"Aggressive ATR trail (0.5 × ATR)"
return False, None, f"Progress {progress_pct*100:.1f}% (Tier {current_tier})"
except Exception as e:
logger.error(f"Error checking trailing stop: {e}")
return False, None, str(e)
# ==========================================
# HELPER FUNCTIONS
# ==========================================
def _is_valid_sl_update(self,
position_type: int,
current_price: float,
new_sl: float,
current_sl: float,
point: float) -> bool:
"""
Validiert SL Update
Checks:
- Minimum distance
- No backward movement
"""
# Check minimum distance
if position_type == 0: # BUY
distance_points = (current_price - new_sl) / point
else: # SELL
distance_points = (new_sl - current_price) / point
if distance_points < self.min_distance:
logger.debug(f"Distance too small: {distance_points:.0f} < {self.min_distance}")
return False
# Don't move SL backwards
if current_sl > 0:
if position_type == 0: # BUY
if new_sl <= current_sl:
logger.debug(f"Would move SL backwards: {new_sl} <= {current_sl}")
return False
else: # SELL
if new_sl >= current_sl:
logger.debug(f"Would move SL backwards: {new_sl} >= {current_sl}")
return False
return True
def update_stop_loss(self, position, new_sl: float) -> bool:
"""
Aktualisiert Stop-Loss für Position
Args:
position: MT5 Position
new_sl: Neuer Stop-Loss Preis
Returns:
Success
"""
try:
request = {
"action": mt.TRADE_ACTION_SLTP,
"position": position.ticket,
"symbol": position.symbol,
"sl": new_sl,
"tp": position.tp,
"magic": 234000,
"comment": "Enhanced Trailing"
}
result = mt.order_send(request)
if result.retcode == mt.TRADE_RETCODE_DONE:
logger.info(f"✅ Enhanced Trailing Stop updated for #{position.ticket}")
logger.info(f" Old SL: {position.sl:.5f}")
logger.info(f" New SL: {new_sl:.5f}")
logger.info(f" Buffer: {abs(new_sl - position.sl):.5f}")
return True
else:
logger.error(f"❌ Failed to update trailing stop: {result.comment}")
return False
except Exception as e:
logger.error(f"Error updating stop loss: {e}")
return False
def cleanup_closed_positions(self):
"""Entfernt geschlossene Positions aus Tier-Tracking"""
open_tickets = {pos.ticket for pos in mt.positions_get()}
closed_tickets = set(self.position_tiers.keys()) - open_tickets
for ticket in closed_tickets:
del self.position_tiers[ticket]
if closed_tickets:
logger.info(f"🧹 Cleaned up {len(closed_tickets)} closed position(s) from tier tracking")
# ==========================================
# INTEGRATION HELPER
# ==========================================
def create_enhanced_position_monitor(
trailing_manager: EnhancedTrailingStopManager,
rhythm_manager,
symbol: str = "XAUUSD"
):
"""
Factory für Enhanced Position Monitor
Args:
trailing_manager: EnhancedTrailingStopManager Instanz
rhythm_manager: AdaptiveRhythmManager (für Session)
symbol: Trading Symbol
Returns:
Monitor Function (für Scheduler)
"""
def enhanced_position_monitor():
"""
Überwacht Positionen mit Enhanced Trailing
Features:
- Session-aware Trailing
- ATR-based Dynamic Trailing
- Multi-tier Profit Locking
- Time-based Breakeven
"""
try:
positions = mt.positions_get(symbol=symbol)
if not positions:
return
# Get current session
session = rhythm_manager.get_current_session()
# Get current ATR
atr_value = None
try:
rates = mt.copy_rates_from_pos(symbol, mt.TIMEFRAME_M5, 0, 20)
if rates is not None:
import pandas as pd
df = pd.DataFrame(rates)
df['tr'] = df[['high', 'low', 'close']].apply(
lambda x: max(x['high'] - x['low'],
abs(x['high'] - x['close']),
abs(x['low'] - x['close'])),
axis=1
)
atr_value = df['tr'].rolling(14).mean().iloc[-1]
except Exception as e:
logger.debug(f"Could not calculate ATR: {e}")
logger.info(f"\n🔍 Enhanced Position Monitor - {len(positions)} position(s)")
atr_display = f"{atr_value:.5f}" if atr_value else "N/A"
logger.info(f" Session: {session.upper()} | ATR: {atr_display}")
for position in positions:
should_update, new_sl, reason = trailing_manager.should_update_trailing_stop(
position,
current_session=session,
atr_value=atr_value
)
if should_update:
logger.info(f"📈 Trailing Trigger for #{position.ticket}: {reason}")
trailing_manager.update_stop_loss(position, new_sl)
else:
logger.debug(f"⏸️ No update: {reason}")
# Cleanup
trailing_manager.cleanup_closed_positions()
except Exception as e:
logger.error(f"Error in enhanced position monitor: {e}")
return enhanced_position_monitor
# ==========================================
# USAGE EXAMPLE
# ==========================================
"""
INTEGRATION IN NOTEBOOK:
# Cell: Setup Enhanced Trailing Stop
from enhanced_trailing_stop import EnhancedTrailingStopManager, create_enhanced_position_monitor
# Initialize Manager
enhanced_trailing = EnhancedTrailingStopManager(
breakeven_trigger_pct=0.30, # Früher BE (30% statt 50%)
breakeven_buffer_pips=300, # +$3 über BE (300 points × 0.01 = $3 für Gold)
tier1_trigger=0.50, # Multi-tier Locking
tier1_lock_pct=0.25,
tier2_trigger=0.75,
tier2_lock_pct=0.50,
tier3_trigger=0.90,
tier3_lock_pct=0.75,
use_atr_trailing=True, # ATR-based Trailing
atr_multiplier=1.5, # Erhöht von 1.0 auf 1.5 für mehr Spielraum
time_based_breakeven=True, # Time-based BE
hours_to_breakeven=4.0,
min_distance_points=500, # Min $5 Abstand (500 × 0.01 = $5 für Gold)
session_trailing_multipliers={ # Session-aware
'asian': 1.0,
'ny': 1.5,
'london': 1.2,
'overlap': 1.3
}
)
print("✅ Enhanced Trailing Stop Manager activated!")
# Cell: Add to Scheduler
# Remove old trailing stop if exists
try:
scheduler.remove_job('advanced_position_management')
except:
pass
# Add enhanced version
enhanced_monitor = create_enhanced_position_monitor(
enhanced_trailing,
rhythm_manager,
symbol="XAUUSD"
)
scheduler.add_job(
func=enhanced_monitor,
trigger='interval',
minutes=1,
id='enhanced_trailing_stop'
)
print("✅ Enhanced Trailing Stop scheduler added (checks every 1 min)")
"""