fix: session_filter_patch, advanced_position_management, loss_protection_manager
session_filter_patch.py: - Fix mutable default arguments (config=None + internal assignment) - Read confidence threshold from config (95) instead of hardcoded 60 - Read debug flag from config instead of hardcoding True - Rename datetime parameter to avoid shadowing the module (_datetime import) - Clamp optimal_interval to max 59 to avoid % modulo issues - Cache now = _datetime.now() to avoid double call advanced_position_management.py: - mt -> mt5 alias (21 replacements) - should_update_trailing_stop: fetch symbol_info.point once, reuse for both checks - close_partial_position: fetch mt5.symbol_info_tick once instead of twice - check_and_update_positions: add mt5.terminal_info() guard loss_protection_manager.py: - Fix critical bug: .seconds -> .total_seconds() in news cache check (.seconds resets at 1h boundary, causing stale cache to appear fresh) - _fetch_economic_calendar: activate via news_filter_simple integration, document that it was previously a no-op - record_trade: document approximate balance tracking limitation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,7 @@ Performance Optimization Features:
|
||||
3. Partial Take Profit
|
||||
"""
|
||||
|
||||
import MetaTrader5 as mt
|
||||
import MetaTrader5 as mt5
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Tuple, Optional, Dict
|
||||
@@ -102,7 +102,7 @@ class AdaptivePositionSizer:
|
||||
risk_amount = balance * adjusted_risk
|
||||
|
||||
# Symbol Info
|
||||
symbol_info = mt.symbol_info(symbol)
|
||||
symbol_info = mt5.symbol_info(symbol)
|
||||
if not symbol_info:
|
||||
logger.error(f"Symbol info not available for {symbol}")
|
||||
return 0.10 # Minimum
|
||||
@@ -180,7 +180,7 @@ class TrailingStopManager:
|
||||
tp = position.tp
|
||||
|
||||
# Current Price
|
||||
symbol_info = mt.symbol_info_tick(position.symbol)
|
||||
symbol_info = mt5.symbol_info_tick(position.symbol)
|
||||
if not symbol_info:
|
||||
return False, None, "No symbol info"
|
||||
|
||||
@@ -200,20 +200,21 @@ class TrailingStopManager:
|
||||
# Progress to TP
|
||||
progress_pct = current_distance / tp_distance
|
||||
|
||||
# Fetch symbol point once for all distance checks below
|
||||
sym_point = mt5.symbol_info(position.symbol).point
|
||||
|
||||
# Check Break-Even Trigger
|
||||
if progress_pct >= self.breakeven_trigger:
|
||||
new_sl = entry_price
|
||||
|
||||
# Verify minimum distance
|
||||
if position_type == 0: # BUY
|
||||
sl_distance_points = (current_price - new_sl) / mt.symbol_info(position.symbol).point
|
||||
sl_distance_points = (current_price - new_sl) / sym_point
|
||||
else: # SELL
|
||||
sl_distance_points = (new_sl - current_price) / mt.symbol_info(position.symbol).point
|
||||
sl_distance_points = (new_sl - current_price) / sym_point
|
||||
|
||||
if sl_distance_points < self.min_distance:
|
||||
return False, None, f"Distance too small: {sl_distance_points:.0f} points"
|
||||
|
||||
# Don't move SL backwards
|
||||
if position_type == 0: # BUY
|
||||
if current_sl > 0 and new_sl <= current_sl:
|
||||
return False, None, "Would move SL backwards"
|
||||
@@ -232,11 +233,10 @@ class TrailingStopManager:
|
||||
locked_profit = tp_distance * self.profit_lock_amount
|
||||
new_sl = entry_price - locked_profit
|
||||
|
||||
# Verify minimum distance
|
||||
if position_type == 0: # BUY
|
||||
sl_distance_points = (current_price - new_sl) / mt.symbol_info(position.symbol).point
|
||||
sl_distance_points = (current_price - new_sl) / sym_point
|
||||
else: # SELL
|
||||
sl_distance_points = (new_sl - current_price) / mt.symbol_info(position.symbol).point
|
||||
sl_distance_points = (new_sl - current_price) / sym_point
|
||||
|
||||
if sl_distance_points < self.min_distance:
|
||||
return False, None, f"Distance too small: {sl_distance_points:.0f} points"
|
||||
@@ -270,7 +270,7 @@ class TrailingStopManager:
|
||||
"""
|
||||
try:
|
||||
request = {
|
||||
"action": mt.TRADE_ACTION_SLTP,
|
||||
"action": mt5.TRADE_ACTION_SLTP,
|
||||
"position": position.ticket,
|
||||
"symbol": position.symbol,
|
||||
"sl": new_sl,
|
||||
@@ -279,9 +279,9 @@ class TrailingStopManager:
|
||||
"comment": "Trailing Stop"
|
||||
}
|
||||
|
||||
result = mt.order_send(request)
|
||||
result = mt5.order_send(request)
|
||||
|
||||
if result.retcode == mt.TRADE_RETCODE_DONE:
|
||||
if result.retcode == mt5.TRADE_RETCODE_DONE:
|
||||
logger.info(f"✅ Trailing Stop updated for #{position.ticket}")
|
||||
logger.info(f" Old SL: {position.sl:.5f}")
|
||||
logger.info(f" New SL: {new_sl:.5f}")
|
||||
@@ -366,7 +366,7 @@ class PartialTakeProfitManager:
|
||||
"""
|
||||
try:
|
||||
# Current Price
|
||||
symbol_info = mt.symbol_info_tick(position.symbol)
|
||||
symbol_info = mt5.symbol_info_tick(position.symbol)
|
||||
if not symbol_info:
|
||||
return False, "No symbol info"
|
||||
|
||||
@@ -405,17 +405,20 @@ class PartialTakeProfitManager:
|
||||
close_volume = round(position.volume * close_pct, 2)
|
||||
|
||||
# Minimum volume check
|
||||
symbol_info = mt.symbol_info(position.symbol)
|
||||
symbol_info = mt5.symbol_info(position.symbol)
|
||||
if close_volume < symbol_info.volume_min:
|
||||
logger.warning(f"Close volume {close_volume} < minimum {symbol_info.volume_min}")
|
||||
return False
|
||||
|
||||
# Close request
|
||||
close_type = mt.ORDER_TYPE_SELL if position.type == 0 else mt.ORDER_TYPE_BUY
|
||||
close_price = mt.symbol_info_tick(position.symbol).bid if position.type == 0 else mt.symbol_info_tick(position.symbol).ask
|
||||
close_type = mt5.ORDER_TYPE_SELL if position.type == 0 else mt5.ORDER_TYPE_BUY
|
||||
tick = mt5.symbol_info_tick(position.symbol)
|
||||
if not tick:
|
||||
logger.error(f"Could not get tick for {position.symbol}")
|
||||
return False
|
||||
close_price = tick.bid if position.type == 0 else tick.ask
|
||||
|
||||
request = {
|
||||
"action": mt.TRADE_ACTION_DEAL,
|
||||
"action": mt5.TRADE_ACTION_DEAL,
|
||||
"position": position.ticket,
|
||||
"symbol": position.symbol,
|
||||
"volume": close_volume,
|
||||
@@ -424,13 +427,13 @@ class PartialTakeProfitManager:
|
||||
"deviation": 20,
|
||||
"magic": 234000,
|
||||
"comment": f"Partial TP1 ({close_pct*100:.0f}%)",
|
||||
"type_time": mt.ORDER_TIME_GTC,
|
||||
"type_filling": mt.ORDER_FILLING_IOC,
|
||||
"type_time": mt5.ORDER_TIME_GTC,
|
||||
"type_filling": mt5.ORDER_FILLING_IOC,
|
||||
}
|
||||
|
||||
result = mt.order_send(request)
|
||||
result = mt5.order_send(request)
|
||||
|
||||
if result.retcode == mt.TRADE_RETCODE_DONE:
|
||||
if result.retcode == mt5.TRADE_RETCODE_DONE:
|
||||
logger.info(f"✅ Partial close executed for #{position.ticket}")
|
||||
logger.info(f" Closed: {close_volume:.2f} lots ({close_pct*100:.0f}%)")
|
||||
logger.info(f" Remaining: {position.volume - close_volume:.2f} lots")
|
||||
@@ -486,7 +489,11 @@ class AdvancedPositionManager:
|
||||
symbol: Symbol zum Checken
|
||||
"""
|
||||
try:
|
||||
positions = mt.positions_get(symbol=symbol)
|
||||
if not mt5.terminal_info():
|
||||
logger.error("MT5 not initialized — skipping position management")
|
||||
return
|
||||
|
||||
positions = mt5.positions_get(symbol=symbol)
|
||||
|
||||
if not positions:
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user