//+------------------------------------------------------------------+ //| SymbolScannerPanel.mq5 | //| Copyright 2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.04" // Final, corrected version based on SymbolInfo.mqh #property script_show_inputs #include //--- Input Parameters for Filtering --- input string InpSymbolsToScan = ""; input string InpSymbolSeparator = ","; input string InpFilterPathContains = ""; input bool InpFilterMarketWatch = true; input double InpFilterMinVolMin = 0.0; input double InpFilterMaxVolMin = 1000000.0; input double InpFilterMinVolStep = 0.0; input double InpFilterMaxVolStep = 1000000.0; input bool InpFilterOnlyETFs = false; input bool InpFilterExtendedHours= false; input string InpKeywordExtHours = "(Extended Hours)"; //--- A structure to hold all necessary data for a symbol --- struct SymbolData { string name; string path; string description; string industry_name; int spread; double point; double tick_value; double tick_value_profit; double tick_value_loss; double tick_size; double volume_min; double volume_step; double swap_long; double swap_short; }; //--- Forward declarations --- bool GetSymbolsToScan(string &symbols_array[]); bool SymbolPassesFilters(const SymbolData &data); void PrintSymbolData(const SymbolData &data); void PrintHeader(); void PrintFilterCriteria(); //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { Print("--- Symbol Scanner Panel Started ---"); PrintFilterCriteria(); Print("---------------------------------"); string symbols_to_scan[]; if(!GetSymbolsToScan(symbols_to_scan)) { Print("No symbols to scan. Exiting."); return; } int found_count = 0; PrintHeader(); CSymbolInfo symbol_info; SymbolData current_symbol_data; for(int i = 0; i < ArraySize(symbols_to_scan); i++) { string symbol_name = symbols_to_scan[i]; StringTrimLeft(symbol_name); StringTrimRight(symbol_name); if(StringLen(symbol_name) == 0) continue; if(!symbol_info.Name(symbol_name)) continue; if(!symbol_info.RefreshRates()) continue; // --- Data Gathering in the main loop using existing CSymbolInfo methods --- current_symbol_data.name = symbol_info.Name(); current_symbol_data.path = symbol_info.Path(); current_symbol_data.description = symbol_info.Description(); // For Industry Name, there is no direct method, so we use InfoString symbol_info.InfoString(SYMBOL_INDUSTRY_NAME, current_symbol_data.industry_name); current_symbol_data.spread = symbol_info.Spread(); current_symbol_data.point = symbol_info.Point(); current_symbol_data.tick_value = symbol_info.TickValue(); current_symbol_data.tick_value_profit = symbol_info.TickValueProfit(); current_symbol_data.tick_value_loss = symbol_info.TickValueLoss(); current_symbol_data.tick_size = symbol_info.TickSize(); // For Volume Min/Step, the methods are LotsMin/LotsStep current_symbol_data.volume_min = symbol_info.LotsMin(); current_symbol_data.volume_step = symbol_info.LotsStep(); current_symbol_data.swap_long = symbol_info.SwapLong(); current_symbol_data.swap_short = symbol_info.SwapShort(); if(SymbolPassesFilters(current_symbol_data)) { found_count++; PrintSymbolData(current_symbol_data); } } Print("--------------------------------------------------------------------------------------------------------------------------------------------------------"); PrintFormat("Scanner Completed. Found %d matching symbols.", found_count); Print("---------------------------------"); } //+------------------------------------------------------------------+ //| Checks if a symbol's data meets all the filter criteria | //+------------------------------------------------------------------+ bool SymbolPassesFilters(const SymbolData &data) { if(InpFilterMarketWatch && !SymbolInfoInteger(data.name, SYMBOL_SELECT)) return false; if(StringLen(InpFilterPathContains) > 0 && StringFind(data.path, InpFilterPathContains) == -1) return false; if(data.volume_min < InpFilterMinVolMin || data.volume_min > InpFilterMaxVolMin) return false; if(data.volume_step < InpFilterMinVolStep || data.volume_step > InpFilterMaxVolStep) return false; if(InpFilterOnlyETFs && data.industry_name != "Exchange Traded Fund") return false; if(InpFilterExtendedHours && StringFind(data.description, InpKeywordExtHours) == -1) return false; return true; } //+------------------------------------------------------------------+ //| Prints a formatted row of data for a single symbol | //+------------------------------------------------------------------+ void PrintSymbolData(const SymbolData &data) { PrintFormat("%-15s | %-8s | %-8s | %-10s | %-10s | %-10s | %-10s | %-10s | %-10s | %-10s | %-10s | %-20s", data.name, (string)data.spread, DoubleToString(data.point, -1), DoubleToString(data.tick_value, 2), DoubleToString(data.tick_value_profit, 2), DoubleToString(data.tick_value_loss, 2), DoubleToString(data.tick_size, -1), DoubleToString(data.volume_min, -1), DoubleToString(data.volume_step, -1), DoubleToString(data.swap_long, 2), DoubleToString(data.swap_short, 2), data.path); } // --- Other helper functions (GetSymbolsToScan, PrintHeader, PrintFilterCriteria) --- bool GetSymbolsToScan(string &symbols_array[]) { string symbols_input_copy = InpSymbolsToScan; StringTrimLeft(symbols_input_copy); StringTrimRight(symbols_input_copy); if(StringLen(symbols_input_copy) > 0) { StringSplit(symbols_input_copy, StringGetCharacter(InpSymbolSeparator, 0), symbols_array); PrintFormat("%d symbols provided by user.", ArraySize(symbols_array)); } else { int total_server_symbols = SymbolsTotal(false); if(total_server_symbols == 0) return false; ArrayResize(symbols_array, total_server_symbols); for(int j = 0; j < total_server_symbols; j++) { symbols_array[j] = SymbolName(j, false); } Print("No specific symbols provided. Scanning all available server symbols."); } return(ArraySize(symbols_array) > 0); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void PrintHeader() { PrintFormat("%-15s | %-8s | %-8s | %-10s | %-10s | %-10s | %-10s | %-10s | %-10s | %-10s | %-10s | %-20s", "Symbol", "Spread", "Point", "TickValue", "TV_Profit", "TV_Loss", "TickSize", "Vol_Min", "Vol_Step", "Swap_Long", "Swap_Short", "Path"); Print("--------------------------------------------------------------------------------------------------------------------------------------------------------"); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void PrintFilterCriteria() { PrintFormat("Filter Criteria:"); PrintFormat(" Symbols to Scan: '%s'", InpSymbolsToScan); PrintFormat(" Path Contains: '%s'", InpFilterPathContains); PrintFormat(" Only Market Watch Selected: %s", (string)InpFilterMarketWatch); PrintFormat(" Min Volume (Min): %g - %g", InpFilterMinVolMin, InpFilterMaxVolMin); PrintFormat(" Volume Step: %g - %g", InpFilterMinVolStep, InpFilterMaxVolStep); PrintFormat(" Only ETFs: %s", (string)InpFilterOnlyETFs); PrintFormat(" Only Extended Hours: %s (Keyword: '%s')", (string)InpFilterExtendedHours, InpKeywordExtHours); } //+------------------------------------------------------------------+