mirror of
https://github.com/softwaredevelop/mql5.git
synced 2026-07-27 20:47:44 +00:00
218 lines
18 KiB
Plaintext
218 lines
18 KiB
Plaintext
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| 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 <Trade\SymbolInfo.mqh>
|
||
|
|
|
||
|
|
//--- 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);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
�
|