fix: enhanced_trailing_stop, dynamic_threshold_optimizer, signal_cache
enhanced_trailing_stop.py: - mt -> mt5 (all occurrences) - Add pandas + timezone imports at file top - Fix UTC bug: datetime.fromtimestamp(..., tz=timezone.utc).replace(tzinfo=None) - Fetch symbol_info once per call, reuse for point (was called twice) - cleanup_closed_positions: handle None from positions_get() - Remove pandas import from inside function body dynamic_threshold_optimizer.py: - Fix SQL injection: replace f-string session filter with parameterized query (?) - Add logging module, replace all print() with logger calls - Use context manager (with sqlite3.connect()) to prevent connection leak on exception - save_thresholds_to_config: add try/except with logger.error signal_cache.py: - Fix bare except -> except Exception in _cleanup_old_entries Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -12,10 +12,13 @@ FEATURES:
|
||||
|
||||
import sqlite3
|
||||
import pandas as pd
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, Optional, Tuple
|
||||
import json
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DynamicThresholdOptimizer:
|
||||
"""
|
||||
@@ -58,10 +61,9 @@ class DynamicThresholdOptimizer:
|
||||
'overlap': 70
|
||||
}
|
||||
|
||||
print(f"✅ Dynamic Threshold Optimizer initialized")
|
||||
print(f" Lookback: {lookback_trades} trades")
|
||||
print(f" Target Win Rate: {target_win_rate*100:.1f}%")
|
||||
print(f" Range: {min_threshold}% - {max_threshold}%")
|
||||
logger.info(f"Dynamic Threshold Optimizer initialized — "
|
||||
f"lookback={lookback_trades}, target_wr={target_win_rate*100:.0f}%, "
|
||||
f"range={min_threshold}%-{max_threshold}%")
|
||||
|
||||
def get_recent_performance(self, session: Optional[str] = None) -> Dict:
|
||||
"""
|
||||
@@ -74,10 +76,7 @@ class DynamicThresholdOptimizer:
|
||||
Dict mit Performance-Metriken
|
||||
"""
|
||||
try:
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
|
||||
# Query für letzte N Trades
|
||||
query = f"""
|
||||
base_query = """
|
||||
SELECT
|
||||
confidence,
|
||||
session,
|
||||
@@ -86,14 +85,15 @@ class DynamicThresholdOptimizer:
|
||||
FROM trades
|
||||
WHERE status = 'closed'
|
||||
"""
|
||||
|
||||
params: list = []
|
||||
if session:
|
||||
query += f" AND session = '{session}'"
|
||||
base_query += " AND session = ?"
|
||||
params.append(session)
|
||||
base_query += " ORDER BY exit_time DESC LIMIT ?"
|
||||
params.append(self.lookback_trades)
|
||||
|
||||
query += f" ORDER BY exit_time DESC LIMIT {self.lookback_trades}"
|
||||
|
||||
df = pd.read_sql_query(query, conn)
|
||||
conn.close()
|
||||
with sqlite3.connect(self.db_path) as conn:
|
||||
df = pd.read_sql_query(base_query, conn, params=params)
|
||||
|
||||
if df.empty:
|
||||
return {
|
||||
@@ -105,10 +105,10 @@ class DynamicThresholdOptimizer:
|
||||
}
|
||||
|
||||
trades = len(df)
|
||||
wins = df['win'].sum()
|
||||
wins = int(df['win'].sum())
|
||||
win_rate = wins / trades if trades > 0 else 0.0
|
||||
avg_confidence = df['confidence'].mean()
|
||||
total_profit = df['net_profit'].sum()
|
||||
avg_confidence = float(df['confidence'].mean())
|
||||
total_profit = float(df['net_profit'].sum())
|
||||
|
||||
return {
|
||||
'trades': trades,
|
||||
@@ -121,7 +121,7 @@ class DynamicThresholdOptimizer:
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error getting performance: {e}")
|
||||
logger.error(f"Error getting performance: {e}")
|
||||
return {
|
||||
'trades': 0,
|
||||
'win_rate': 0.0,
|
||||
@@ -322,10 +322,12 @@ class DynamicThresholdOptimizer:
|
||||
}
|
||||
}
|
||||
|
||||
with open(config_file, 'w') as f:
|
||||
json.dump(config, f, indent=2)
|
||||
|
||||
print(f"✅ Thresholds saved to: {config_file}")
|
||||
try:
|
||||
with open(config_file, 'w') as f:
|
||||
json.dump(config, f, indent=2)
|
||||
logger.info(f"Thresholds saved to: {config_file}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to save thresholds: {e}")
|
||||
|
||||
|
||||
# ==========================================
|
||||
@@ -344,9 +346,9 @@ def auto_optimize_thresholds(optimizer: DynamicThresholdOptimizer,
|
||||
Returns:
|
||||
Optimization Results
|
||||
"""
|
||||
print(f"\n{'='*70}")
|
||||
print(f"🔄 AUTO-OPTIMIZATION STARTED - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print(f"{'='*70}\n")
|
||||
logger.info(f"\n{'='*70}")
|
||||
logger.info(f"🔄 AUTO-OPTIMIZATION STARTED - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
logger.info(f"{'='*70}\n")
|
||||
|
||||
results = optimizer.optimize_all_sessions()
|
||||
|
||||
@@ -357,16 +359,16 @@ def auto_optimize_thresholds(optimizer: DynamicThresholdOptimizer,
|
||||
|
||||
change_emoji = "🔽" if info['change'] < 0 else ("🔼" if info['change'] > 0 else "➡️")
|
||||
|
||||
print(f"{session.upper():8s}: {info['old_threshold']}% → {info['new_threshold']}% "
|
||||
logger.info(f"{session.upper():8s}: {info['old_threshold']}% → {info['new_threshold']}% "
|
||||
f"{change_emoji} | WR: {info['win_rate']*100:.1f}% ({info['recent_trades']} trades)")
|
||||
|
||||
if apply_changes:
|
||||
optimizer.save_thresholds_to_config()
|
||||
print("\n✅ Changes applied and saved!")
|
||||
logger.info("\n✅ Changes applied and saved!")
|
||||
else:
|
||||
print("\n⚠️ Dry-run mode - changes NOT applied")
|
||||
logger.info("\n⚠️ Dry-run mode - changes NOT applied")
|
||||
|
||||
print(f"\n{'='*70}\n")
|
||||
logger.info(f"\n{'='*70}\n")
|
||||
|
||||
return results
|
||||
|
||||
@@ -434,4 +436,4 @@ print("✅ Auto-optimization scheduled (daily at midnight)")
|
||||
if __name__ == "__main__":
|
||||
# Test
|
||||
optimizer = DynamicThresholdOptimizer()
|
||||
print(optimizer.generate_report())
|
||||
logger.info(optimizer.generate_report())
|
||||
|
||||
Reference in New Issue
Block a user