Skip to content

Cursor#16

Merged
chpeu merged 7 commits into
claude/switch-branch-011CV1vMmQctHeVpbrjjsRZ4from
cursor
Nov 11, 2025
Merged

Cursor#16
chpeu merged 7 commits into
claude/switch-branch-011CV1vMmQctHeVpbrjjsRZ4from
cursor

Conversation

@chpeu

@chpeu chpeu commented Nov 11, 2025

Copy link
Copy Markdown
Owner

PR Type

Enhancement, Bug fix


Description

  • Logging refactor and WebSocket integration: Replaced custom ColoredFormatter with standard logging and implemented WebSocketLogHandler to stream logs to frontend in real-time with ANSI color support

  • Position tracking improvements: Added opened_at ISO timestamp for countdown timers, implemented fixed-distance trailing stop (_update_trailing_stop_fixe()), and enhanced break-even trigger logic using new break_even_trigger configuration parameter

  • Slippage calculation enhancements: Improved slippage tracking with detailed logging, proper USDT conversion, and comprehensive analytics integration in close_position()

  • Position type handling fixes: Enhanced position_check_loop_callback() to properly handle string, dict, and object Position types with error handling

  • API response restructuring: Enhanced api_get_sessions_stats_global() with nested global_stats object and exposed Telegram notification configuration with individual type toggles

  • Telegram configuration management: Implemented update_telegram_config and test_telegram commands for dynamic settings management with 9 notification type controls

  • Configuration parameter additions: Added break_even_trigger, trailing_distance, and use_slippage_calculation parameters with proper validation and dynamic updates

  • TP/SL mode enhancements: Fixed tp_sl_mode handling to accept ESCALIER mode alongside existing modes with proper use_atr flag updates

  • Frontend UI improvements: Implemented global error popup with auto-hide, debug mode toggle with element inspection, dynamic bot phase tracking, and debounced TP/SL mode selector

  • Log viewer enhancements: Added ANSI color parsing, emoji extraction, and XLSX export functionality with styled headers

  • Position card redesign: Added dynamic duration countdown, intelligent TP/SL level calculation supporting FIXE/ESCALIER/ATR modes, and real-time trading config integration

  • Data consistency fixes: Fixed scalability data field mappings (spread, bookDepth, balanceScore), trade duration field consistency, and PnL calculations in trade history

  • Export functionality expansion: Migrated to Excel (XLSX) format with improved formatting and added new setup analysis export with 5 sheets (Trades, Configuration, TP-SL, Thresholds, Patterns)

  • Orderbook null-safety: Added null-safety checks and array bounds validation to prevent crashes when orderbook data is unavailable

  • Debug mode infrastructure: Added comprehensive data-debug-name attributes throughout frontend components for element inspection and testing


Diagram Walkthrough

flowchart LR
  A["Backend Logging"] -->|"WebSocketLogHandler"| B["WebSocket Stream"]
  B -->|"ANSI Colors"| C["Frontend LogViewer"]
  D["Position Manager"] -->|"opened_at, trailing_stop"| E["Position Card"]
  E -->|"Dynamic TP/SL Calc"| F["Frontend Display"]
  G["Trading Config"] -->|"break_even_trigger, trailing_distance"| D
  H["Telegram Config"] -->|"9 Notification Types"| I["NotificationSettings UI"]
  J["Trade Data"] -->|"net_pnl_usdt, slippage"| K["TradeHistory & Stats"]
  K -->|"XLSX Export"| L["Setup Analysis Report"]
  M["Bot Phase Events"] -->|"position_active, scan_*"| N["Dynamic Status Message"]
Loading

File Walkthrough

Relevant files
Enhancement
19 files
main.py
Logging refactor, WebSocket integration, position handling fixes

main.py

  • Simplified logging configuration by removing custom ColoredFormatter
    class and replacing with standard logging.basicConfig()
  • Added WebSocketLogHandler integration to send logs to frontend via
    WebSocket in init_instances()
  • Fixed position type checking in position_check_loop_callback() to
    handle string, dict, and object Position types with proper error
    handling
  • Enhanced api_get_sessions_stats_global() endpoint to restructure
    response format with global_stats nested object and removed redundant
    PnL fields
  • Added Telegram notification configuration exposure in API responses
    and WebSocket state with individual notification type toggles
  • Implemented update_telegram_config and test_telegram commands for
    dynamic Telegram settings management
  • Added break_even_trigger and trailing_distance configuration
    parameters with proper validation and logging
  • Fixed tp_sl_mode handling to accept ESCALIER mode alongside existing
    modes with proper use_atr flag updates
  • Added use_slippage_calculation configuration parameter with dynamic
    updates to both position_config and position_manager
+301/-113
logger.py
WebSocket log handler implementation for frontend               

utils/logger.py

  • Implemented new WebSocketLogHandler class to capture logs and emit
    them to frontend via WebSocket
  • Added ANSI color code support in WebSocketLogHandler with proper
    level-based coloring (DEBUG, INFO, WARNING, ERROR, CRITICAL)
  • Enhanced setup_logger() function to accept optional ws_manager
    parameter for WebSocket integration
  • Preserved emoji support in log messages while maintaining ANSI color
    formatting for frontend display
+84/-1   
position_check_loop.py
Position update events and stats calculation enhancements

core/callbacks/position_check_loop.py

  • Added opened_at ISO timestamp to position update events for frontend
    countdown timer functionality
  • Enhanced stats calculation with debug logging to verify trade PnL
    values from analytics database
  • Fixed rounding precision for total_pnl_usdt and total_pnl_pct to 4
    decimal places to preserve small values
  • Improved best/worst trade detection using net_pnl_usdt field for
    accurate performance metrics
+23/-2   
analyzer.py
Orderbook rejection logging and WebSocket integration       

core/analyzer.py

  • Changed orderbook rejection log from WARNING to INFO level for less
    critical notifications
  • Added WebSocket log emission for orderbook rejection events with
    proper async handling and fallback error management
  • Implemented try-catch wrapper around WebSocket log sending to prevent
    blocking analyzer execution
+28/-2   
+page.svelte
Global error popup, debug mode, bot phase tracking             

frontend/src/routes/+page.svelte

  • Implemented global error popup component with blinking animation and
    5-second auto-hide functionality
  • Added debug mode toggle in header with data-debug-name attributes for
    element inspection
  • Refactored TP/SL mode selector with debounce mechanism (2.5s delay) to
    prevent excessive config updates
  • Added bot phase tracking with events for position_active, scan_setups,
    scan_scalability, and arrêt states
  • Integrated PnLPercentChart component alongside existing PnLChart for
    percentage-based analytics
  • Simplified header layout with centered title and repositioned controls
    (ConnectionStatus left, debug toggle right)
  • Enhanced position and trade event handling with proper store updates
    and phase transitions
  • Added scalability scan event listeners for complete bot lifecycle
    tracking
+394/-77
LogViewer.svelte
Log viewer ANSI parsing and XLSX export enhancement           

frontend/src/lib/components/LogViewer.svelte

  • Moved error popup component to main +page.svelte for global display
    across all pages
  • Enhanced ANSI color code parsing with proper timestamp and level
    coloring while preserving message text
  • Improved emoji extraction with comprehensive Unicode range support for
    all emoji types
  • Added log export functionality using XLSX format with styled headers
    and configurable column widths
  • Fixed log message formatting to reconstruct [HH:MM:SS] LEVEL - message
    format with proper color application
  • Enhanced formatTime() to recognize and preserve pre-formatted HH:MM:SS
    timestamps
  • Added log-detail field support for additional log information display
+170/-267
SessionSelector.svelte
Debug mode attribute additions                                                     

frontend/src/lib/components/SessionSelector.svelte

  • Added comprehensive data-debug-name attributes throughout component
    for debug mode element inspection
  • Maintained existing session management functionality with improved
    debug traceability
+46/-36 
WinLossChart.svelte
Debug mode attribute additions                                                     

frontend/src/lib/components/WinLossChart.svelte

  • Added data-debug-name attributes to all major DOM elements for debug
    mode support
  • Preserved existing chart rendering and statistics display
    functionality
+16/-16 
VariablesPanel.svelte
Add break-even and trailing stop parameters with debug attributes

frontend/src/lib/components/VariablesPanel.svelte

  • Added two new configuration parameters break_even_trigger and
    trailing_distance to default config with values 0.3 and 0.15
  • Removed WebSocket config_updated listener from onMount hook and
    simplified tab change detection logic
  • Refactored config loading to check !completeConfig instead of tracking
    previousSubTab state
  • Added extensive data-debug-name attributes throughout the template for
    debugging/testing purposes
  • Added UI controls for the new break_even_trigger and trailing_distance
    parameters in FIXE mode section
  • Enhanced WebSocket config update handler to explicitly update
    break_even_trigger and trailing_distance and refresh completeConfig
    when on current tab
+541/-462
ExportPanel.svelte
Add setup analysis export option with debug attributes     

frontend/src/lib/components/ExportPanel.svelte

  • Imported new exportSetupAnalysis function from export utilities
  • Added new export option card for "Analyse des Setups/Trade" with setup
    analysis export functionality
  • Updated CSV export button label from "Export CSV" to "Export Excel"
    with description mentioning .xlsx format
  • Added comprehensive data-debug-name attributes to all UI elements for
    debugging/testing
+61/-43 
BotControls.svelte
Implement dynamic bot status messaging with phase tracking

frontend/src/lib/components/BotControls.svelte

  • Imported botPhase store and getPhaseMessage function for dynamic
    status messaging
  • Imported activePosition store to track active trading positions
  • Added computed statusMessage that prioritizes position active status,
    bot phase, scanner state, and fallback to stopped state
  • Replaced static conditional status text with dynamic statusMessage
    variable
  • Added data-debug-name attributes to all UI elements for
    debugging/testing
+30/-12 
Tabs.svelte
Add debug attributes to tab component elements                     

frontend/src/lib/components/Tabs.svelte

  • Added data-debug-name attributes to tab container, header, buttons,
    icons, and labels for debugging/testing
  • Used dynamic naming convention with tab IDs to uniquely identify each
    tab element
+5/-4     
PositionCard.svelte
Dynamic position tracking with intelligent TP/SL calculation

frontend/src/lib/components/PositionCard.svelte

  • Added dynamic position duration countdown with live updates every
    second
  • Implemented trading config loading via WebSocket to calculate next
    TP/SL levels
  • Added support for multiple TP/SL modes (FIXE, TP_MULTI/ESCALIER, ATR)
    with intelligent level calculation
  • Refactored TP/SL display to show next target PnL and position size
    instead of escalier levels grid
  • Added comprehensive debug attributes (data-debug-name) throughout
    template for testing
  • Improved duration display styling with dedicated label and value
    sections
+280/-212
NotificationSettings.svelte
Telegram notification settings with granular type controls

frontend/src/lib/components/NotificationSettings.svelte

  • Added Telegram notification configuration UI with 9 notification type
    toggles
  • Implemented loadTelegramConfig() to fetch Telegram settings from
    backend via WebSocket
  • Added saveTelegramConfig() and testTelegram() functions for managing
    Telegram notifications
  • Created conditional UI sections showing Telegram setup instructions
    when disabled
  • Added real-time config update listener for bidirectional
    synchronization
  • Replaced old static Telegram info with interactive settings panel
+343/-70
SettingsPanel.svelte
Simplified settings panel to frontend-only configuration 

frontend/src/lib/components/SettingsPanel.svelte

  • Removed backend synchronization logic for trading parameters
    (sl_percent, tp_percent, trailing_trigger_pnl)
  • Removed loadBackendConfig() and syncWithBackend() functions
  • Removed WebSocket listeners for config updates
  • Simplified component to manage only frontend-local settings
  • Removed Scanner and UI settings sections, keeping only Trading section
+25/-346
PnLPercentChart.svelte
New cumulative PnL percentage visualization chart               

frontend/src/lib/components/PnLPercentChart.svelte

  • Created new chart component displaying cumulative PnL percentage curve
  • Implemented real-time chart updates from trade history store
  • Added dynamic color coding (green for positive, red for negative)
  • Configured Chart.js with custom styling matching application theme
  • Included responsive design with mobile breakpoint
+222/-0 
StatsPanel.svelte
Enhanced stats display with percentage metrics and debug attributes

frontend/src/lib/components/StatsPanel.svelte

  • Added data-debug-name attributes to all stat boxes and values
  • Changed best/worst trade display from USDT to percentage format
  • Improved semantic naming for debugging and testing
+26/-26 
ScannerPanel.svelte
Improved scanner panel layout and added debug attributes 

frontend/src/lib/components/ScannerPanel.svelte

  • Added data-debug-name attributes to all pair cards and metrics
  • Fixed grid layout from fixed minmax to flexible 1fr for better
    responsiveness
  • Improved semantic naming for debugging
+26/-26 
export.js
Enhanced export functionality with Excel format and setup analysis

frontend/src/lib/utils/export.js

  • Migrated CSV export to Excel (XLSX) format with improved formatting
  • Added column width configuration and header styling for better
    readability
  • Implemented new exportSetupAnalysis() function exporting 5 sheets
    (Trades, Configuration, TP-SL, Thresholds, Patterns)
  • Added complete trading configuration export from backend API
  • Improved numeric precision with proper decimal handling
  • Added comprehensive parameter documentation in configuration sheets
+253/-11
Bug fix
4 files
position_manager.py
Trailing stop refactor, slippage calculation improvements

core/position_manager.py

  • Added opened_at ISO timestamp field to Position.to_dict() for frontend
    countdown timer support
  • Implemented _update_trailing_stop_fixe() method for fixed-distance
    trailing stop in FIXE mode
  • Enhanced check_position() to use break_even_trigger from
    TRADING_CONFIG for first partial TP trigger threshold
  • Fixed trailing stop activation logic to trigger after first partial TP
    or when PnL exceeds break_even_trigger
  • Improved slippage calculation with detailed logging and proper USDT
    conversion from percentage
  • Enhanced close_position() to calculate net_pnl_pct accounting for
    total costs (fees + slippage)
  • Added comprehensive slippage tracking in analytics logging with both
    percentage and USDT values
  • Fixed _estimate_slippage() logging to use INFO level for visibility
    and added validation for invalid spread/depth values
+149/-32
scanner_loop.py
Scalability data field name corrections                                   

core/callbacks/scanner_loop.py

  • Fixed scalability data mapping to use correct field names from scanner
    output (spread, bookDepth, balanceScore, bidVol, askVol)
  • Added NaN validation for spread values to prevent invalid data
    propagation
  • Corrected field name mappings: spread_pctspread, depthbookDepth,
    balancebalanceScore
+11/-5   
analytics_database.py
Trade duration field consistency fix                                         

core/analytics_database.py

  • Added fallback logic in get_trades() to ensure duration_seconds field
    is present when duration exists
  • Improved trade data consistency by aliasing duration to
    duration_seconds if needed
+8/-1     
TradeHistory.svelte
Fixed PnL calculations and improved data format handling 

frontend/src/lib/components/TradeHistory.svelte

  • Fixed sessionPnL calculation to use net_pnl_usdt directly (includes
    slippage/fees)
  • Fixed sessionPnLPct to return total instead of average percentage
  • Enhanced slippage display with fallback logic to handle multiple data
    formats
  • Improved PnL Net calculation by subtracting slippage from net PnL
    percentage
  • Added robust duration calculation with priority-based fallback chain
  • Added comprehensive debug attributes throughout table structure
+93/-43 
Formatting
4 files
GlobalStats.svelte
Added debug attributes for testing and debugging                 

frontend/src/lib/components/GlobalStats.svelte

  • Added data-debug-name attributes to all stat cards and content
    sections
  • Improved testability and debugging capabilities with semantic naming
+50/-50 
VolumeChart.svelte
Added debug attributes to volume chart component                 

frontend/src/lib/components/VolumeChart.svelte

  • Added data-debug-name attributes to chart container, header, and
    controls
  • Improved semantic naming for testing and debugging
+13/-13 
PnLChart.svelte
Added debug attributes to PnL chart component                       

frontend/src/lib/components/PnLChart.svelte

  • Added data-debug-name attributes to chart container, header, and
    wrapper
  • Improved semantic naming for debugging
+6/-6     
ConnectionStatus.svelte
Added debug attributes to connection status component       

frontend/src/lib/components/ConnectionStatus.svelte

  • Added data-debug-name attributes to connection status elements
  • Improved semantic naming for testing
+3/-3     
Additional files
7 files
.env.example +23/-13 
package.json +2/-1     
botPhase.js +36/-0   
debug.js +24/-0   
logs.js +2/-2     
stats.js +59/-29 
debugTooltip.js +208/-0 

@chpeu chpeu merged commit 590e679 into claude/switch-branch-011CV1vMmQctHeVpbrjjsRZ4 Nov 11, 2025
@qodo-code-review

Copy link
Copy Markdown

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Sensitive log exposure

Description: Logging to WebSocket from a root logger via a custom handler may forward sensitive
operational details to all connected clients, potentially exposing internal errors and
system state to unauthorized frontends.
main.py [1064-1077]

Referred Code
# 🔥 FIX: Configurer le logger avec WebSocket handler pour envoyer les logs au frontend
try:
    from utils.logger import WebSocketLogHandler
    root_logger = logging.getLogger()
    # Vérifier si le handler WebSocket existe déjà
    has_ws_handler = any(isinstance(h, WebSocketLogHandler) for h in root_logger.handlers)
    if not has_ws_handler and ws_manager:
        ws_handler = WebSocketLogHandler()
        ws_handler.set_ws_manager(ws_manager)
        ws_handler.setLevel(logging.INFO)
        # Ne pas formater (garder le message brut avec emojis)
        ws_handler.setFormatter(logging.Formatter('%(message)s'))
        root_logger.addHandler(ws_handler)
        logger.info("✅ WebSocket log handler configuré")
Insecure config change

Description: The 'update_telegram_config' command updates environment variables at runtime and reloads
the config, enabling remote toggling of notification settings without
authentication/authorization checks, which could be abused to disable alerts or change
behavior.
main.py [3029-3090]

Referred Code
# 🔥 NOUVEAU: Mettre à jour la configuration Telegram
from config import (
    TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID, TELEGRAM_ENABLED,
    TELEGRAM_NOTIFY_POSITION_OPENED, TELEGRAM_NOTIFY_POSITION_CLOSED,
    TELEGRAM_NOTIFY_TP_ESCALIER, TELEGRAM_NOTIFY_EARLY_INVALIDATION,
    TELEGRAM_NOTIFY_ERROR, TELEGRAM_NOTIFY_RECONNECTION,
    TELEGRAM_NOTIFY_DAILY_SUMMARY, TELEGRAM_NOTIFY_RECOVERY_MODE,
    TELEGRAM_NOTIFY_SETUP_REJECTED
)
import os
updated = {}

# Mettre à jour les types de notifications Telegram
notify_types = {
    'TELEGRAM_NOTIFY_POSITION_OPENED': 'TELEGRAM_NOTIFY_POSITION_OPENED',
    'TELEGRAM_NOTIFY_POSITION_CLOSED': 'TELEGRAM_NOTIFY_POSITION_CLOSED',
    'TELEGRAM_NOTIFY_TP_ESCALIER': 'TELEGRAM_NOTIFY_TP_ESCALIER',
    'TELEGRAM_NOTIFY_EARLY_INVALIDATION': 'TELEGRAM_NOTIFY_EARLY_INVALIDATION',
    'TELEGRAM_NOTIFY_ERROR': 'TELEGRAM_NOTIFY_ERROR',
    'TELEGRAM_NOTIFY_RECONNECTION': 'TELEGRAM_NOTIFY_RECONNECTION',
    'TELEGRAM_NOTIFY_DAILY_SUMMARY': 'TELEGRAM_NOTIFY_DAILY_SUMMARY',


 ... (clipped 41 lines)
Information leakage

Description: Emitting log entries to WebSocket based on analysis results may leak trading strategy
details (ratios, thresholds, rejection reasons) to all connected clients.
analyzer.py [681-704]

Referred Code
try:
    from core.websocket_manager import get_websocket_manager
    from datetime import datetime
    import asyncio
    ws_mgr = get_websocket_manager()
    if ws_mgr:
        try:
            loop = asyncio.get_running_loop()
            async def send_log():
                # Format identique à add_log dans main.py
                entry = {
                    'timestamp': datetime.now().strftime('%H:%M:%S'),
                    'level': 'INFO',  # 🔥 FIX: INFO au lieu de WARNING
                    'message': f"ℹ️ Setup {best_setup['direction']} rejeté",
                    'detail': f"{symbol}: Orderbook défavorable (ratio={orderbook_check['ratio']:.2f}, required={required_str})",
                    'raw_message': f"Setup {best_setup['direction']} rejeté"
                }
                await ws_mgr.emit('log', entry)
            loop.create_task(send_log())
        except RuntimeError:
            # Pas de loop en cours, ignorer (le log est déjà dans logger.info)


 ... (clipped 3 lines)
Sensitive log exposure

Description: Detailed INFO/WARNING logs about slippage parameters and calculations could reveal order
sizes and market depth data to any client receiving logs via WebSocket.
position_manager.py [594-603]

Referred Code
Returns:
    Slippage estimé en %
"""
# 🔥 INFO: Log pour vérifier les paramètres (changer de debug à info pour visibilité)
logger.info(f"💹 _estimate_slippage: order_size={order_size}, spread_pct={spread_pct}, depth={depth}, balance_score={balance_score}")

if spread_pct <= 0 or depth <= 0:
    logger.warning(f"💹 _estimate_slippage: Retourne 0.0 car spread_pct={spread_pct} ou depth={depth} <= 0")
    return 0.0
Log message injection

Description: The global error popup renders raw log messages after only basic ANSI stripping, which
could allow HTML/markup injection in the UI if log messages contain untrusted content.
+page.svelte [461-481]

Referred Code
</script>

<!-- 🔥 FIX: Popup d'erreur global (affiché sur toutes les pages) -->
{#if showErrorPopup && $criticalErrorLogs.length > 0}
	{@const latestError = $criticalErrorLogs[$criticalErrorLogs.length - 1]}
	<div class="error-popup" class:blinking={showErrorPopup}>
		<div class="error-popup-content">
			<div class="error-popup-header">
				<span class="error-icon">🚨</span>
				<h3>Erreur détectée</h3>
				<button class="close-popup-btn" on:click={acknowledgeError}>✕</button>
			</div>
			<div class="error-popup-message">
				<span class="error-time">{formatTime(latestError.timestamp)}</span>
				<span class="error-level">[{latestError.level}]</span>
				<span class="error-text">{stripAnsiCodes(latestError.message)}</span>
			</div>
			<button class="acknowledge-btn" on:click={acknowledgeError}>Acquitter</button>
		</div>
	</div>
{/if}
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Audit coverage: The PR adds and routes many informational logs (including WebSocket log handler) but does
not clearly ensure that critical actions like position open/close, config changes, and
Telegram config updates are consistently logged with user/context identifiers and outcomes
across all new paths.

Referred Code
    else:
        raise ValueError('Aucune position active')

elif command == 'update_telegram_config':
    # 🔥 NOUVEAU: Mettre à jour la configuration Telegram
    from config import (
        TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID, TELEGRAM_ENABLED,
        TELEGRAM_NOTIFY_POSITION_OPENED, TELEGRAM_NOTIFY_POSITION_CLOSED,
        TELEGRAM_NOTIFY_TP_ESCALIER, TELEGRAM_NOTIFY_EARLY_INVALIDATION,
        TELEGRAM_NOTIFY_ERROR, TELEGRAM_NOTIFY_RECONNECTION,
        TELEGRAM_NOTIFY_DAILY_SUMMARY, TELEGRAM_NOTIFY_RECOVERY_MODE,
        TELEGRAM_NOTIFY_SETUP_REJECTED
    )
    import os
    updated = {}

    # Mettre à jour les types de notifications Telegram
    notify_types = {
        'TELEGRAM_NOTIFY_POSITION_OPENED': 'TELEGRAM_NOTIFY_POSITION_OPENED',
        'TELEGRAM_NOTIFY_POSITION_CLOSED': 'TELEGRAM_NOTIFY_POSITION_CLOSED',
        'TELEGRAM_NOTIFY_TP_ESCALIER': 'TELEGRAM_NOTIFY_TP_ESCALIER',


 ... (clipped 65 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Error handling: While additional edge checks were added (e.g., None orderbook, safe dict access), several
new async logging and WebSocket emits lack retries/fallbacks and some exceptions are only
logged without remediation, which may require verification in integrated context.

Referred Code
# Récupérer orderbook
orderbook = await client.fetch_order_book(symbol, limit=5)

# 🔥 FIX: Vérifier que orderbook n'est pas None et contient bids/asks
if orderbook is None:
    # 🔥 FIX: Ne pas logger ici car WebSocketLogHandler capture déjà logger.error et envoie au frontend
    # Le log sera envoyé automatiquement via WebSocketLogHandler
    return {'valid': False, 'spread_pct': 999, 'max_allowed': 0.03, 'quality': 'ERROR'}

bids = orderbook.get('bids', []) if orderbook else []
asks = orderbook.get('asks', []) if orderbook else []

best_bid = bids[0][0] if bids and len(bids) > 0 and len(bids[0]) > 0 else 0
best_ask = asks[0][0] if asks and len(asks) > 0 and len(asks[0]) > 0 else 0

if best_bid == 0 or best_ask == 0:
    return {'valid': False, 'spread_pct': 999, 'max_allowed': 0.03, 'quality': 'UNKNOWN'}

mid_price = (best_bid + best_ask) / 2
spread_pct = ((best_ask - best_bid) / mid_price) * 100



 ... (clipped 41 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status:
User exposure: Errors and info logs (with detailed internal context and emojis) are forwarded to the
frontend via WebSocket which could be user-facing; verify that only internal users see
these logs and that user-facing surfaces do not expose sensitive internals.

Referred Code
# 🔥 FIX: Configurer le logger avec WebSocket handler pour envoyer les logs au frontend
try:
    from utils.logger import WebSocketLogHandler
    root_logger = logging.getLogger()
    # Vérifier si le handler WebSocket existe déjà
    has_ws_handler = any(isinstance(h, WebSocketLogHandler) for h in root_logger.handlers)
    if not has_ws_handler and ws_manager:
        ws_handler = WebSocketLogHandler()
        ws_handler.set_ws_manager(ws_manager)
        ws_handler.setLevel(logging.INFO)
        # Ne pas formater (garder le message brut avec emojis)
        ws_handler.setFormatter(logging.Formatter('%(message)s'))
        root_logger.addHandler(ws_handler)
        logger.info("✅ WebSocket log handler configuré")
except Exception as e:
    logger.debug(f"Impossible de configurer WebSocket log handler: {e}")

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Sensitive logs: New logs include detailed trading metrics and possibly environment-driven settings; ensure
no secrets (e.g., tokens, chat IDs) or sensitive identifiers are logged when forwarding to
the frontend via WebSocket.

Referred Code
)

# Calculer slippage si applicable
# 🔥 FIX: _estimate_slippage retourne un pourcentage (%)
slippage_pct = 0.0
# 🔥 INFO: Log pour vérifier les conditions (changer de debug à info pour visibilité)
logger.info(f"💹 Calcul slippage: use_slippage_calculation={self.config.use_slippage_calculation}, "
           f"scalability_data={'présent' if self.active_position.scalability_data else 'absent'}")

if self.config.use_slippage_calculation and self.active_position.scalability_data:
    spread_pct = self.active_position.scalability_data.get('spread_pct', 0.0)
    depth = self.active_position.scalability_data.get('depth', 0.0)
    balance = self.active_position.scalability_data.get('balance', 1.0)

    logger.info(f"💹 Données scalabilité: spread_pct={spread_pct}, depth={depth}, balance={balance}, size={self.active_position.size}")

    slippage_pct = self._estimate_slippage(
        order_size=self.active_position.size,
        spread_pct=spread_pct,
        depth=depth,
        balance_score=balance,


 ... (clipped 125 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Input validation: The new 'update_telegram_config' command updates environment variables based on
client-provided params without explicit validation or authorization checks in the shown
diff; verify upstream authentication/authorization and value sanitization.

Referred Code
elif command == 'update_telegram_config':
    # 🔥 NOUVEAU: Mettre à jour la configuration Telegram
    from config import (
        TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID, TELEGRAM_ENABLED,
        TELEGRAM_NOTIFY_POSITION_OPENED, TELEGRAM_NOTIFY_POSITION_CLOSED,
        TELEGRAM_NOTIFY_TP_ESCALIER, TELEGRAM_NOTIFY_EARLY_INVALIDATION,
        TELEGRAM_NOTIFY_ERROR, TELEGRAM_NOTIFY_RECONNECTION,
        TELEGRAM_NOTIFY_DAILY_SUMMARY, TELEGRAM_NOTIFY_RECOVERY_MODE,
        TELEGRAM_NOTIFY_SETUP_REJECTED
    )
    import os
    updated = {}

    # Mettre à jour les types de notifications Telegram
    notify_types = {
        'TELEGRAM_NOTIFY_POSITION_OPENED': 'TELEGRAM_NOTIFY_POSITION_OPENED',
        'TELEGRAM_NOTIFY_POSITION_CLOSED': 'TELEGRAM_NOTIFY_POSITION_CLOSED',
        'TELEGRAM_NOTIFY_TP_ESCALIER': 'TELEGRAM_NOTIFY_TP_ESCALIER',
        'TELEGRAM_NOTIFY_EARLY_INVALIDATION': 'TELEGRAM_NOTIFY_EARLY_INVALIDATION',
        'TELEGRAM_NOTIFY_ERROR': 'TELEGRAM_NOTIFY_ERROR',
        'TELEGRAM_NOTIFY_RECONNECTION': 'TELEGRAM_NOTIFY_RECONNECTION',


 ... (clipped 42 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review

Copy link
Copy Markdown

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Log flooding risk

Description: The WebSocket log handler is added to the root logger without preventing duplicate
attachments across reloads or ensuring handler thread-safety, which can lead to unbounded
memory usage and potential log flooding to clients if init_instances is called multiple
times.
main.py [1064-1077]

Referred Code
# 🔥 FIX: Configurer le logger avec WebSocket handler pour envoyer les logs au frontend
try:
    from utils.logger import WebSocketLogHandler
    root_logger = logging.getLogger()
    # Vérifier si le handler WebSocket existe déjà
    has_ws_handler = any(isinstance(h, WebSocketLogHandler) for h in root_logger.handlers)
    if not has_ws_handler and ws_manager:
        ws_handler = WebSocketLogHandler()
        ws_handler.set_ws_manager(ws_manager)
        ws_handler.setLevel(logging.INFO)
        # Ne pas formater (garder le message brut avec emojis)
        ws_handler.setFormatter(logging.Formatter('%(message)s'))
        root_logger.addHandler(ws_handler)
        logger.info("✅ WebSocket log handler configuré")
Unvalidated input usage

Description: Slippage is computed from unvalidated scalability_data fields and logged back to users,
but no bounds checking on spread/depth allows attacker-controlled or NaN values from
upstream to skew net PnL and potentially trigger incorrect trading decisions.
position_manager.py [888-934]

Referred Code
)

# Calculer slippage si applicable
# 🔥 FIX: _estimate_slippage retourne un pourcentage (%)
slippage_pct = 0.0
# 🔥 INFO: Log pour vérifier les conditions (changer de debug à info pour visibilité)
logger.info(f"💹 Calcul slippage: use_slippage_calculation={self.config.use_slippage_calculation}, "
           f"scalability_data={'présent' if self.active_position.scalability_data else 'absent'}")

if self.config.use_slippage_calculation and self.active_position.scalability_data:
    spread_pct = self.active_position.scalability_data.get('spread_pct', 0.0)
    depth = self.active_position.scalability_data.get('depth', 0.0)
    balance = self.active_position.scalability_data.get('balance', 1.0)

    logger.info(f"💹 Données scalabilité: spread_pct={spread_pct}, depth={depth}, balance={balance}, size={self.active_position.size}")

    slippage_pct = self._estimate_slippage(
        order_size=self.active_position.size,
        spread_pct=spread_pct,
        depth=depth,
        balance_score=balance,


 ... (clipped 26 lines)
XSS via logs

Description: The error popup displays log messages with only a simple ANSI escape removal and no HTML
escaping, which could allow HTML injection if log messages contain markup delivered via
WebSocket.
+page.svelte [460-1258]

Referred Code
	}
</script>

<!-- 🔥 FIX: Popup d'erreur global (affiché sur toutes les pages) -->
{#if showErrorPopup && $criticalErrorLogs.length > 0}
	{@const latestError = $criticalErrorLogs[$criticalErrorLogs.length - 1]}
	<div class="error-popup" class:blinking={showErrorPopup}>
		<div class="error-popup-content">
			<div class="error-popup-header">
				<span class="error-icon">🚨</span>
				<h3>Erreur détectée</h3>
				<button class="close-popup-btn" on:click={acknowledgeError}>✕</button>
			</div>
			<div class="error-popup-message">
				<span class="error-time">{formatTime(latestError.timestamp)}</span>
				<span class="error-level">[{latestError.level}]</span>
				<span class="error-text">{stripAnsiCodes(latestError.message)}</span>
			</div>
			<button class="acknowledge-btn" on:click={acknowledgeError}>Acquitter</button>
		</div>
	</div>


 ... (clipped 778 lines)
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Action logging: While logging infrastructure was added and some warnings/info are sent to frontend, newly
added critical actions (e.g., Telegram config changes, TP/SL mode changes, position close
slippage adjustments) are not consistently logged with user identity and outcome details,
making audit trails potentially incomplete.

Referred Code
# 🔥 TP/SL Mode
if 'tp_sl_mode' in params:
    mode = str(params['tp_sl_mode']).upper()
    # 🔥 FIX: Accepter aussi 'ESCALIER' comme mode valide
    if mode in ['FIXE', 'ATR', 'TP_MULTI', 'ESCALIER']:
        TRADING_CONFIG['tp_sl_mode'] = mode
        # 🔥 FIX: Ne pas appeler init_instances() car cela réinitialise tout, utiliser directement position_config et position_manager
        if position_config:
            position_config.use_atr = (mode == 'ATR' or mode == 'TP_MULTI' or mode == 'ESCALIER')
        # 🔥 FIX: Mettre à jour aussi position_manager.config.use_atr si position_manager existe
        if position_manager:
            position_manager.config.use_atr = (mode == 'ATR' or mode == 'TP_MULTI' or mode == 'ESCALIER')
        updated['tp_sl_mode'] = mode
        logger.info(f"✅ Mode TP/SL mis à jour: {mode} (use_atr={position_config.use_atr if position_config else 'N/A'})")

if 'tp_percent' in params:
    val = float(params['tp_percent'])
    TRADING_CONFIG['tp_percent'] = val
    if position_config:
        position_config.fixed_tp_pct = val
    updated['tp_percent'] = val


 ... (clipped 486 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status:
Generic naming: The inline proxy class named PositionProxy and variables like ws_handler, ws_mgr, e, and d
in several added blocks provide limited semantic clarity and may hinder self-documentation
without surrounding context.

Referred Code
# Calculer PnL pour affichage
position = position_manager.active_position
if position:
    # 🔥 FIX: Vérifier que position est un objet Position et non un dict ou string
    if isinstance(position, str):
        # Si position est une chaîne, essayer de la parser en dict
        import json
        try:
            position_dict = json.loads(position)
            # Utiliser les valeurs du dict pour calculer PnL
            pnl = position_manager.pnl_calculator.calculate_pnl_percent(
                entry=position_dict.get('entry', 0),
                current_price=current_price,
                direction=position_dict.get('direction', 'LONG')
            )
            pnl_usdt = position_manager.pnl_calculator.calculate_pnl_usdt(
                position=position_dict,
                current_price=current_price
            )
            # Créer un objet position-like pour le reste du code
            class PositionProxy:


 ... (clipped 50 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Error context: Error handling logs a generic error message for spread checks but does not include
symbol/orderbook context beyond the exception string nor retries/fallbacks, which may
limit actionable debugging in production.

Referred Code
    return result

except Exception as e:
    error_msg = f"❌ Erreur check spread {symbol}: {e}"
    # 🔥 FIX: logger.error est capturé par WebSocketLogHandler et envoyé au frontend automatiquement
    # Pas besoin d'envoyer manuellement via websocket_manager.emit (cela créerait un doublon)
    logger.error(error_msg)
    return {'valid': False, 'spread_pct': 999, 'max_allowed': 0.03, 'quality': 'ERROR'}

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Env exposure: The new update_telegram_config command mutates environment variables and logs settings
updates; ensure that secrets like TELEGRAM_BOT_TOKEN/CHAT_ID are never logged or echoed to
clients via websockets.

Referred Code
    else:
        raise ValueError('Aucune position active')

elif command == 'update_telegram_config':
    # 🔥 NOUVEAU: Mettre à jour la configuration Telegram
    from config import (
        TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID, TELEGRAM_ENABLED,
        TELEGRAM_NOTIFY_POSITION_OPENED, TELEGRAM_NOTIFY_POSITION_CLOSED,
        TELEGRAM_NOTIFY_TP_ESCALIER, TELEGRAM_NOTIFY_EARLY_INVALIDATION,
        TELEGRAM_NOTIFY_ERROR, TELEGRAM_NOTIFY_RECONNECTION,
        TELEGRAM_NOTIFY_DAILY_SUMMARY, TELEGRAM_NOTIFY_RECOVERY_MODE,
        TELEGRAM_NOTIFY_SETUP_REJECTED
    )
    import os
    updated = {}

    # Mettre à jour les types de notifications Telegram
    notify_types = {
        'TELEGRAM_NOTIFY_POSITION_OPENED': 'TELEGRAM_NOTIFY_POSITION_OPENED',
        'TELEGRAM_NOTIFY_POSITION_CLOSED': 'TELEGRAM_NOTIFY_POSITION_CLOSED',
        'TELEGRAM_NOTIFY_TP_ESCALIER': 'TELEGRAM_NOTIFY_TP_ESCALIER',


 ... (clipped 45 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Param validation: Several websocket command handlers accept params (e.g., tp_sl_mode, trailing_distance,
Telegram flags) with minimal validation and no authentication context visible in the diff,
which may risk improper configuration or injection if upstream checks are absent.

Referred Code
# 🔥 TP/SL Mode
if 'tp_sl_mode' in params:
    mode = str(params['tp_sl_mode']).upper()
    # 🔥 FIX: Accepter aussi 'ESCALIER' comme mode valide
    if mode in ['FIXE', 'ATR', 'TP_MULTI', 'ESCALIER']:
        TRADING_CONFIG['tp_sl_mode'] = mode
        # 🔥 FIX: Ne pas appeler init_instances() car cela réinitialise tout, utiliser directement position_config et position_manager
        if position_config:
            position_config.use_atr = (mode == 'ATR' or mode == 'TP_MULTI' or mode == 'ESCALIER')
        # 🔥 FIX: Mettre à jour aussi position_manager.config.use_atr si position_manager existe
        if position_manager:
            position_manager.config.use_atr = (mode == 'ATR' or mode == 'TP_MULTI' or mode == 'ESCALIER')
        updated['tp_sl_mode'] = mode
        logger.info(f"✅ Mode TP/SL mis à jour: {mode} (use_atr={position_config.use_atr if position_config else 'N/A'})")

if 'tp_percent' in params:
    val = float(params['tp_percent'])
    TRADING_CONFIG['tp_percent'] = val
    if position_config:
        position_config.fixed_tp_pct = val
    updated['tp_percent'] = val


 ... (clipped 486 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review

Copy link
Copy Markdown

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Fix data corruption instead of patching

Instead of adding complex logic in main.py to handle
position_manager.active_position being a string or dictionary, find and fix the
root cause of this data type inconsistency. This will ensure active_position is
always a Position object, simplifying the code and preventing potential bugs.

Examples:

main.py [860-926]
                # 🔥 FIX: Vérifier que position est un objet Position et non un dict ou string
                if isinstance(position, str):
                    # Si position est une chaîne, essayer de la parser en dict
                    import json
                    try:
                        position_dict = json.loads(position)
                        # Utiliser les valeurs du dict pour calculer PnL
                        pnl = position_manager.pnl_calculator.calculate_pnl_percent(
                            entry=position_dict.get('entry', 0),
                            current_price=current_price,

 ... (clipped 57 lines)

Solution Walkthrough:

Before:

async def position_check_loop_callback():
    position = position_manager.active_position
    if position:
        # Check if position is a string, dict, or object
        if isinstance(position, str):
            # ... parse json from string ...
            # ... calculate pnl from dict ...
            # ... create a PositionProxy object ...
            position = PositionProxy(position_dict)
        elif isinstance(position, dict):
            # ... calculate pnl from dict ...
            # ... create a PositionProxy object ...
            position = PositionProxy(position)
        else: # It's a Position object
            # ... calculate pnl from object attributes ...
        
        # ... rest of the logic using `position` ...

After:

# In the part of the code where `position_manager.active_position` is set or retrieved,
# ensure it is always instantiated as a `Position` object.
# This removes the need for type checking in the callback.

async def position_check_loop_callback():
    position = position_manager.active_position # This is now guaranteed to be a Position object or None
    if position:
        # Position is a normal Position object
        pnl = position_manager.pnl_calculator.calculate_pnl_percent(
            entry=position.entry,
            current_price=current_price,
            direction=position.direction
        )
        # ... other calculations using position attributes ...
        
        # ... rest of the logic using `position` ...
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a critical issue where a workaround is implemented instead of fixing the root cause of data type inconsistency for position_manager.active_position, which has a high impact on code quality and maintainability.

High
Possible issue
Fix incorrect net PnL calculation

Correct the net_pnl_pct calculation to derive it from the final net_pnl_usdt and
position size, preventing an issue where trading fees were effectively
subtracted twice.

core/position_manager.py [926-933]

-# 🔥 FIX: Calculer net_pnl_pct en tenant compte des coûts (fees + slippage)
-# Le PnL net en % doit être ajusté pour refléter les coûts réels
-gross_pnl_pct = pnl_data['pnl_pct']
-total_costs_pct = (total_costs / self.active_position.size) * 100 if self.active_position.size > 0 else 0
-net_pnl_pct = gross_pnl_pct - total_costs_pct
-
 # 🔥 FIX: net_pnl_usdt doit être calculé après déduction du slippage USDT
 net_pnl_usdt = pnl_data['net_pnl'] - slippage_usdt
 
+# 🔥 FIX: Calculer net_pnl_pct à partir de net_pnl_usdt pour assurer la cohérence
+# et éviter de compter les frais deux fois.
+net_pnl_pct = (net_pnl_usdt / self.active_position.size) * 100 if self.active_position.size > 0 else 0
+
  • Apply / Chat
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a critical bug in the net_pnl_pct calculation that would lead to incorrect financial metrics by double-counting fees, and it provides the correct formula.

High
Avoid reloading modules for configuration

Replace the use of importlib.reload(config) with a safer method of updating
configuration by directly modifying the config module's attributes and
explicitly propagating those changes.

main.py [3028-3090]

 elif command == 'update_telegram_config':
     # 🔥 NOUVEAU: Mettre à jour la configuration Telegram
-    from config import (
-        TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID, TELEGRAM_ENABLED,
-        TELEGRAM_NOTIFY_POSITION_OPENED, TELEGRAM_NOTIFY_POSITION_CLOSED,
-        TELEGRAM_NOTIFY_TP_ESCALIER, TELEGRAM_NOTIFY_EARLY_INVALIDATION,
-        TELEGRAM_NOTIFY_ERROR, TELEGRAM_NOTIFY_RECONNECTION,
-        TELEGRAM_NOTIFY_DAILY_SUMMARY, TELEGRAM_NOTIFY_RECOVERY_MODE,
-        TELEGRAM_NOTIFY_SETUP_REJECTED
-    )
-    import os
+    import config
     updated = {}
     
     # Mettre à jour les types de notifications Telegram
     notify_types = {
-        'TELEGRAM_NOTIFY_POSITION_OPENED': 'TELEGRAM_NOTIFY_POSITION_OPENED',
-        'TELEGRAM_NOTIFY_POSITION_CLOSED': 'TELEGRAM_NOTIFY_POSITION_CLOSED',
-        'TELEGRAM_NOTIFY_TP_ESCALIER': 'TELEGRAM_NOTIFY_TP_ESCALIER',
-        'TELEGRAM_NOTIFY_EARLY_INVALIDATION': 'TELEGRAM_NOTIFY_EARLY_INVALIDATION',
-        'TELEGRAM_NOTIFY_ERROR': 'TELEGRAM_NOTIFY_ERROR',
-        'TELEGRAM_NOTIFY_RECONNECTION': 'TELEGRAM_NOTIFY_RECONNECTION',
-        'TELEGRAM_NOTIFY_DAILY_SUMMARY': 'TELEGRAM_NOTIFY_DAILY_SUMMARY',
-        'TELEGRAM_NOTIFY_RECOVERY_MODE': 'TELEGRAM_NOTIFY_RECOVERY_MODE',
-        'TELEGRAM_NOTIFY_SETUP_REJECTED': 'TELEGRAM_NOTIFY_SETUP_REJECTED'
+        'TELEGRAM_NOTIFY_POSITION_OPENED': 'position_opened',
+        'TELEGRAM_NOTIFY_POSITION_CLOSED': 'position_closed',
+        'TELEGRAM_NOTIFY_TP_ESCALIER': 'tp_escalier_level',
+        'TELEGRAM_NOTIFY_EARLY_INVALIDATION': 'early_invalidation',
+        'TELEGRAM_NOTIFY_ERROR': 'error',
+        'TELEGRAM_NOTIFY_RECONNECTION': 'reconnection',
+        'TELEGRAM_NOTIFY_DAILY_SUMMARY': 'daily_summary',
+        'TELEGRAM_NOTIFY_RECOVERY_MODE': 'recovery_mode',
+        'TELEGRAM_NOTIFY_SETUP_REJECTED': 'setup_rejected'
     }
     
     # Mettre à jour chaque type de notification
-    for key, env_key in notify_types.items():
+    for key, manager_key in notify_types.items():
         if key in params:
             value = bool(params[key])
-            os.environ[env_key] = 'true' if value else 'false'
+            # Mettre à jour l'attribut sur le module config directement
+            setattr(config, key, value)
             updated[key] = value
             logger.info(f"✅ {key} mis à jour: {value}")
     
-    # Recharger la config depuis les variables d'environnement
-    from importlib import reload
-    import config
-    reload(config)
-    
     # Mettre à jour notification_manager si disponible
     if notification_manager:
-        from config import (
-            TELEGRAM_NOTIFY_POSITION_OPENED, TELEGRAM_NOTIFY_POSITION_CLOSED,
-            TELEGRAM_NOTIFY_TP_ESCALIER, TELEGRAM_NOTIFY_EARLY_INVALIDATION,
-            TELEGRAM_NOTIFY_ERROR, TELEGRAM_NOTIFY_RECONNECTION,
-            TELEGRAM_NOTIFY_DAILY_SUMMARY, TELEGRAM_NOTIFY_RECOVERY_MODE,
-            TELEGRAM_NOTIFY_SETUP_REJECTED
-        )
-        # 🔥 FIX: Mettre à jour les paramètres avec les nouvelles valeurs depuis params
-        notification_manager.telegram_notify_settings.update({
-            'position_opened': params.get('TELEGRAM_NOTIFY_POSITION_OPENED', TELEGRAM_NOTIFY_POSITION_OPENED),
-            'position_closed': params.get('TELEGRAM_NOTIFY_POSITION_CLOSED', TELEGRAM_NOTIFY_POSITION_CLOSED),
-            'tp_escalier_level': params.get('TELEGRAM_NOTIFY_TP_ESCALIER', TELEGRAM_NOTIFY_TP_ESCALIER),
-            'early_invalidation': params.get('TELEGRAM_NOTIFY_EARLY_INVALIDATION', TELEGRAM_NOTIFY_EARLY_INVALIDATION),
-            'error': params.get('TELEGRAM_NOTIFY_ERROR', TELEGRAM_NOTIFY_ERROR),
-            'reconnection': params.get('TELEGRAM_NOTIFY_RECONNECTION', TELEGRAM_NOTIFY_RECONNECTION),
-            'daily_summary': params.get('TELEGRAM_NOTIFY_DAILY_SUMMARY', TELEGRAM_NOTIFY_DAILY_SUMMARY),
-            'recovery_mode': params.get('TELEGRAM_NOTIFY_RECOVERY_MODE', TELEGRAM_NOTIFY_RECOVERY_MODE),
-            'setup_rejected': params.get('TELEGRAM_NOTIFY_SETUP_REJECTED', TELEGRAM_NOTIFY_SETUP_REJECTED)
-        })
+        for key, manager_key in notify_types.items():
+            if key in updated:
+                notification_manager.telegram_notify_settings[manager_key] = updated[key]
+        
         logger.info(f"✅ Notification Manager mis à jour: {notification_manager.telegram_notify_settings}")
     
     return {'updated': updated, 'success': True}
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies the use of importlib.reload() as a dangerous anti-pattern for runtime configuration and proposes a much safer, more robust architectural solution, preventing potential state inconsistencies.

Medium
Ensure data is refreshed on tab activation

Modify the reactive statement to call loadCompleteConfig() every time the
'current' tab is activated, not just the first time, to prevent displaying stale
data.

frontend/src/lib/components/VariablesPanel.svelte [147-150]

 	// Charger la config complète quand on active l'onglet
-	$: if (activeSubTab === 'current' && !completeConfig && !loadingCompleteConfig) {
+	$: if (activeSubTab === 'current' && !loadingCompleteConfig) {
 		loadCompleteConfig();
 	}
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly points out that the current logic prevents data refresh on subsequent visits to the tab, which can lead to displaying stale data. The proposed change ensures data is always re-fetched, which is a significant correctness improvement.

Medium
Correct trailing stop PnL calculation

Correct the trailing stop targetPnL calculation. The target PnL should be
calculated based on the dynamic_sl price, not the current_price.

frontend/src/lib/components/PositionCard.svelte [96-184]

 $: nextTpInfo = (() => {
 ...
 			// Après le 1er TP : utiliser trailing_distance (dynamique en fonction du prix actuel)
 			// Le trailing stop est actif, donc le prochain TP sera déclenché quand le trailing stop est touché
-			// Le PnL objectif est calculé dynamiquement : PnL actuel - trailing_distance (car le trailing suit le prix)
-			if ($activePosition.current_price && $activePosition.entry) {
-				const currentPnL = $activePosition.direction === 'LONG' 
-					? (($activePosition.current_price - $activePosition.entry) / $activePosition.entry) * 100
-					: (($activePosition.entry - $activePosition.current_price) / $activePosition.entry) * 100;
-				
-				// Le trailing_distance est la distance entre le prix actuel et le trailing stop
-				// Le prochain TP sera déclenché quand le prix revient au trailing stop
-				// Donc le PnL objectif est le PnL actuel moins trailing_distance
-				const trailingDistance = tradingConfig.trailing_distance || 0.1;
-				const targetPnL = Math.max(0, currentPnL - trailingDistance);
+			// Le PnL objectif est le PnL au niveau du SL dynamique
+			if ($activePosition.dynamic_sl && $activePosition.entry) {
+				const targetPnL = $activePosition.direction === 'LONG'
+					? (($activePosition.dynamic_sl - $activePosition.entry) / $activePosition.entry) * 100
+					: (($activePosition.entry - $activePosition.dynamic_sl) / $activePosition.entry) * 100;
 ...
 			}
 ...
 })();

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a logical flaw in the targetPnL calculation for trailing stops and provides a correct implementation, which significantly improves the accuracy of the displayed trading information.

Medium
Prevent race conditions on save

Prevent a race condition in saveTelegramConfig by adding a guard to ensure only
one save operation can be in progress at a time.

frontend/src/lib/components/NotificationSettings.svelte [100-116]

 	async function saveTelegramConfig() {
+		if (saveLoading) return;
 		saveLoading = true;
 		try {
 			const result = await sendCommandViaWS('update_telegram_config', telegramNotifySettings);
 			if (result && result.success) {
 				telegramNotifySettings = { ...telegramNotifySettings, ...result.updated };
-				alert('✅ Configuration Telegram sauvegardée avec succès');
+				// Using a less intrusive notification is better than an alert
+				console.log('✅ Configuration Telegram sauvegardée avec succès');
 			} else {
 				alert('❌ Erreur lors de la sauvegarde');
 			}
 		} catch (err) {
 			console.error('Erreur sauvegarde Telegram:', err);
 			alert(`❌ Erreur: ${err.message || 'Impossible de sauvegarder'}`);
 		} finally {
 			saveLoading = false;
 		}
 	}
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a potential race condition when saving Telegram settings and proposes a valid solution by adding a loading guard, which improves the robustness of the feature.

Medium
General
Refactor complex type-checking logic

Refactor the repetitive type-checking for the position variable by normalizing
it into a consistent format at the start of the block, thus removing duplicated
code.

main.py [860-926]

-# 🔥 FIX: Vérifier que position est un objet Position et non un dict ou string
-if isinstance(position, str):
-    # Si position est une chaîne, essayer de la parser en dict
-    import json
-    try:
+from types import SimpleNamespace
+import json
+
+position_obj = None
+position_dict = {}
+
+try:
+    if isinstance(position, str):
         position_dict = json.loads(position)
-        # Utiliser les valeurs du dict pour calculer PnL
-        pnl = position_manager.pnl_calculator.calculate_pnl_percent(
-            entry=position_dict.get('entry', 0),
-            current_price=current_price,
-            direction=position_dict.get('direction', 'LONG')
-        )
-        pnl_usdt = position_manager.pnl_calculator.calculate_pnl_usdt(
-            position=position_dict,
-            current_price=current_price
-        )
-        # Créer un objet position-like pour le reste du code
-        class PositionProxy:
-            def __init__(self, d):
-                self.symbol = d.get('symbol', '')
-                self.direction = d.get('direction', 'LONG')
-                self.entry = d.get('entry', 0)
-                self.sl = d.get('sl', 0)
-                self.tp = d.get('tp', 0)
-                self.size = d.get('size', 0)
-                self.break_even_set = d.get('break_even_set', False)
-                self.partial_tp_sold = d.get('partial_tp_sold', False)
-        position = PositionProxy(position_dict)
-    except Exception as parse_err:
-        logger.error(f"❌ Erreur parsing position (string): {parse_err}")
+    elif isinstance(position, dict):
+        position_dict = position
+    elif hasattr(position, 'to_dict'): # Assumes it's a Position object
+        position_dict = position.to_dict()
+        position_obj = position # Keep original object
+    else:
+        logger.error(f"❌ Type de position inconnu: {type(position)}")
         return
-elif isinstance(position, dict):
-    # Si position est déjà un dict, utiliser directement
-    pnl = position_manager.pnl_calculator.calculate_pnl_percent(
-        entry=position.get('entry', 0),
-        current_price=current_price,
-        direction=position.get('direction', 'LONG')
-    )
-    pnl_usdt = position_manager.pnl_calculator.calculate_pnl_usdt(
-        position=position,
-        current_price=current_price
-    )
-    # Créer un objet position-like pour le reste du code
-    class PositionProxy:
-        def __init__(self, d):
-            self.symbol = d.get('symbol', '')
-            self.direction = d.get('direction', 'LONG')
-            self.entry = d.get('entry', 0)
-            self.sl = d.get('sl', 0)
-            self.tp = d.get('tp', 0)
-            self.size = d.get('size', 0)
-            self.break_even_set = d.get('break_even_set', False)
-            self.partial_tp_sold = d.get('partial_tp_sold', False)
-    position = PositionProxy(position)
-else:
-    # Position est un objet Position normal
-    pnl = position_manager.pnl_calculator.calculate_pnl_percent(
-        entry=position.entry,
-        current_price=current_price,
-        direction=position.direction
-    )
-    # 🔥 FIX: Calculer PnL USDT avec pnl_calculator (incluant TP partiel automatiquement)
-    position_dict = position.to_dict() if hasattr(position, 'to_dict') else {}
-    pnl_usdt = position_manager.pnl_calculator.calculate_pnl_usdt(
-        position=position_dict,
-        current_price=current_price
-    )
+except Exception as parse_err:
+    logger.error(f"❌ Erreur parsing position: {parse_err}")
+    return
 
+if not position_obj:
+    # Create a proxy object for consistent attribute access if we started with str/dict
+    position_obj = SimpleNamespace(**position_dict)
+
+# Now, calculate PnL using the consistent dictionary
+pnl = position_manager.pnl_calculator.calculate_pnl_percent(
+    entry=position_dict.get('entry', 0),
+    current_price=current_price,
+    direction=position_dict.get('direction', 'LONG')
+)
+pnl_usdt = position_manager.pnl_calculator.calculate_pnl_usdt(
+    position=position_dict,
+    current_price=current_price
+)
+
+# Use position_obj for the rest of the code that needs attribute access
+position = position_obj
+
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion provides a good refactoring that eliminates code duplication and simplifies complex logic, significantly improving code quality and maintainability.

Low
Remove redundant configuration update logic

Remove the redundant if blocks that explicitly update break_even_trigger and
trailing_distance, as this logic is already covered by the preceding forEach
loop.

frontend/src/lib/components/VariablesPanel.svelte [574-580]

 					Object.keys(data.updated).forEach(key => {
 						if (key in newConfig) {
 							newConfig[key] = data.updated[key];
 						}
 					});
-					// 🔥 FIX: S'assurer que break_even_trigger et trailing_distance sont bien mis à jour depuis le backend
-					if (data.updated.break_even_trigger !== undefined && data.updated.break_even_trigger !== null) {
-						newConfig.break_even_trigger = data.updated.break_even_trigger;
-					}
-					if (data.updated.trailing_distance !== undefined && data.updated.trailing_distance !== null) {
-						newConfig.trailing_distance = data.updated.trailing_distance;
-					}

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies that the explicit updates for break_even_trigger and trailing_distance are redundant, as they are already handled by the preceding loop. Removing this duplicated code improves maintainability.

Low
  • More

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant