This script is designed to monitor and record real-time price movements (specifically "ticks") for multiple financial instruments simultaneously. It automates the process of gathering market data and saving it into organized files on your computer for later use.
Core Functionality
1. Multi-Symbol Monitoring The script allows you to define a specific list of currency pairs or assets (for example, EURUSD, GBPUSD, etc.). Instead of only recording the chart you are currently looking at, it scans the market for all the instruments you have listed in your settings. It is capped at handling up to 32 different symbols at once.
2. Automated File Organization The script handles the "bookkeeping" of where data is saved. It automatically creates a folder structure based on:
- The Server Name: Ensuring data from different brokers/servers stays separate.
- The Current Date: It creates specific files for each month (e.g., a file for January, another for February).
- The Asset Name: Each symbol gets its own dedicated CSV file.
This means that as time passes and you switch servers or months change, the script automatically handles the creation of new files so your data remains organized and doesn't overwrite previous records.
3. Real-Time Data Logging The logic constantly "listens" to the market. Every time the price moves, the script captures:
- The exact timestamp (Date and Time).
- The current Bid price.
- The correct decimal precision for that specific asset.
To keep the logs clean, the script includes a built-in check to ensure it only records actual movements. If the price remains unchanged between updates, it skips the recording to prevent creating redundant, identical entries.
4. Connection and Stability Tracking The script is designed to be robust against internet interruptions:
- Connection Awareness: It monitors your connection to the broker. If the connection is lost, it can be configured to write a specific warning message into the files.
- Session Integrity: If the trading platform is stopped or restarted, the script can leave a "stopped" marker in the data file. This helps you identify exactly where the data stream was interrupted during later analysis.
Summary of Workflow
When you run this script, it prepares your list of symbols, verifies your connection, and opens the necessary files. It then enters a continuous loop: it checks the price of every asset on your list, verifies if the price has changed, and writes that new data into the corresponding monthly CSV file. It performs these actions hundreds of times per minute, ensuring a high-fidelity record of market activity.
//+------------------------------------------------------------------+
//| TickSave.mq4 |
//| Copyright © 2006, komposter |
//| mailto:komposterius@mail.ru |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, komposter"
#property link "mailto:komposterius@mail.ru"
extern string SymbolList = "EURUSD,GBPUSD,AUDUSD,USDCAD,USDJPY,USDCHF";
extern bool WriteWarnings = false;
string SymbolsArray[32], strComment; double preBid[32];
int FileHandle[32], SymbolsCount = 0;
#define strEXPERT_WAS_STOPED "--------------------------Expert was stoped"
#define strCONNECTION_LOST "--------------------------Connection lost "
#define strLEN 45
bool preIsConnected = true, nowIsConnected = true;
int init() { start(); return(0); }
int start()
{
string ServerName = AccountServer();
int CurYear = Year();
int CurMonth = Month();
// Èçâëåêàåì èç ñòðîêè SymbolList ñïèñîê ñèìâîëîâ
if ( !PrepareSymbolList() ) { return(-1); }
// Ïðîâåðÿåì ñîñòîÿíèå ñîåäèíåíèÿ
if ( !ConnectionCheck() ) { return(-1); }
// Îòêðûâàåì ôàéëû
if ( !OpenFiles() ) { return(-1); }
while ( !IsStopped() )
{
// Åñëè ïîìåíÿëñÿ ñåðâåð, ñðàçó ïðåêðàùàåì çàïèñü - äëÿ íîâîãî ñåðâåðà áóäåò ñîçäàíà ñâîÿ ïàïêà
if ( ServerName != AccountServer() ) { break; }
// Åñëè ïîìåíÿëñÿ ìåñÿö, ñðàçó ïðåêðàùàåì çàïèñü - äëÿ íîâîãî ìåñÿöà áóäåò ñîçäàí ñâîé ôàéë
if ( CurYear != Year() ) { break; }
if ( CurMonth != Month() ) { break; }
// Åñëè ïðîïàëà ñâÿçü,
if ( !IsConnected() )
{
// çàïèñûâàåì ïðåäóïðåæäåíèå âî âñå ôàéëû
WriteConnectionLost();
preIsConnected = false;
}
// Åñëè ñâÿçü åñòü,
else
{
// Çàïèñûâàåì ïîñòóïèâøèå òèêè
WriteTick();
preIsConnected = true;
}
Sleep(100);
}
// Çàêðûâàåì ôàéëû
CloseFiles();
Comment("");
return(0);
}
//+------------------------------------------------------------------+
//| Èçâëåêàåì èç ñòðîêè SymbolList ñïèñîê ñèìâîëîâ
//+------------------------------------------------------------------+
bool PrepareSymbolList()
{
int curchar = 0, len = StringLen( SymbolList ), curSymbol;
string cur_symbol = ""; SymbolsCount = 0;
//---- óñòàíàâëèâàåì óìîë÷àòåëüíûé ðàçìåð ìàññèâà ñèìâîëîâ
ArrayResize( SymbolsArray, 32 );
//---- ïåðåáèðàåì âñå ñèìâîëû â ñïèñêå ãðàôèêîâ
for ( int pos = 0; pos <= len; pos ++ )
{
curchar = StringGetChar( SymbolList, pos );
//---- åñëè òåêóùèé ñèìâîë - íå çàïÿòàÿ è íå ïîñëåäíèé ñèìâîë â ñòðîêå,
if ( curchar != ',' && pos != len )
{
//---- ýòî - îäèí èç ñèìâîëîâ èíñòðóìåíòà ãðàôèêà
cur_symbol = cur_symbol + CharToStr( curchar );
continue;
}
//---- åñëè òåêóùèé ñèìâîë çàïÿòàÿ, èëè ýòî - ïîñëåäíèé ñèìâîë â ñòðîêå,
else
{
//---- çíà÷èò, â ïåðåìåííîé cur_symbol - ïîëíîå èìÿ ñèìâîëà. Ïðîâåðÿåì åãî:
MarketInfo( cur_symbol, MODE_BID );
if ( GetLastError() == 4106 )
{
Alert( "Íåèçâåñòíûé ñèìâîë ", cur_symbol, "!!!" );
return(false);
}
//---- åñëè ñèìâîë ðåàëüíî ñóùåñòâóåò, ïðîâåðÿåì, íåò ëè òàêîãî ñèìîëà â íàøåì ñïèñêå:
bool Uniq = true;
for ( curSymbol = 0; curSymbol < SymbolsCount; curSymbol ++ )
{
if ( cur_symbol == SymbolsArray[curSymbol] )
{
Uniq = false;
break;
}
}
//---- åñëè òàêîãî ñèìîëà â íàøåì ñïèñêå íåò, çàïèñûâàåì åãî, è ñ÷èòàåì îáùåå êîëè÷åñòâî:
if ( Uniq )
{
SymbolsArray[SymbolsCount] = cur_symbol;
SymbolsCount ++;
if ( SymbolsCount > 31 )
{
Alert( "Ñëèøêîì ìíîãî ñèìâîëîâ! Îòêðûòü ìîæíî ìàêñèìóì 32 ôàéëà!" );
return(false);
}
}
//---- îáíóëÿåì çíà÷åíèå ïåðåìåííîé
cur_symbol = "";
}
}
//---- åñëè íè îäèí ñèìâîë íå áûë íàéäåí, âûõîäèì
if ( SymbolsCount <= 0 )
{
Alert( "Íå îïðåäåëåíî íè îäíîãî ñèìâîëà!!!" );
return(false);
}
//---- óñòàíàâëèâàåì ðàçìåð âñåõ ìàññèâîâ ïîä êîë-âî ñèìâîëîâ:
ArrayResize ( SymbolsArray , SymbolsCount );
ArrayResize ( preBid , SymbolsCount );
ArrayInitialize( preBid , -1 );
ArrayResize ( FileHandle , SymbolsCount );
ArrayInitialize( FileHandle , -1 );
//---- Âûâîäèì èíôîðìàöèþ:
string uniq_symbols_list = SymbolsArray[0];
for ( curSymbol = 1; curSymbol < SymbolsCount; curSymbol ++ )
{
if ( curSymbol == SymbolsCount - 1 )
{ uniq_symbols_list = uniq_symbols_list + " è " + SymbolsArray[curSymbol]; }
else
{ uniq_symbols_list = uniq_symbols_list + ", " + SymbolsArray[curSymbol]; }
}
strComment = StringConcatenate( AccountServer(), ": îáðàáàòûâàåòñÿ ", SymbolsCount, " ñèìâîë(-à,-îâ):\n", uniq_symbols_list, "\n" );
Comment( strComment );
return(true);
}
//+------------------------------------------------------------------+
//| Ïðîâåðÿåì ñîñòîÿíèå ñîåäèíåíèÿ
//+------------------------------------------------------------------+
bool ConnectionCheck()
{
while ( !IsConnected() )
{
Comment( AccountServer(), ": ÍÅÒ ÑÂßÇÈ Ñ ÑÅÐÂÅÐÎÌ!!!" );
if ( IsStopped() ) { return(false); }
Sleep(100);
}
return(true);
}
//+------------------------------------------------------------------+
//| Îòêðûâàåì ôàéëû, â êîòîðûå áóäåì çàïèñûâàòü òèêè
//+------------------------------------------------------------------+
bool OpenFiles()
{
int _GetLastError;
for ( int curSymbol = 0; curSymbol < SymbolsCount; curSymbol ++ )
{
string FileName = StringConcatenate( "[Ticks]\\", AccountServer(), "\\", SymbolsArray[curSymbol], "_", Year(), ".", strMonth(), ".csv" );
FileHandle[curSymbol] = FileOpen( FileName, FILE_READ | FILE_WRITE );
if ( FileHandle[curSymbol] < 0 )
{
_GetLastError = GetLastError();
Alert( "FileOpen( " + FileName + ", FILE_READ | FILE_WRITE ) - Error #", _GetLastError );
return(false);
}
if ( !FileSeek( FileHandle[curSymbol], 0, SEEK_END ) )
{
_GetLastError = GetLastError();
Alert( "FileSeek( " + FileHandle[curSymbol] + ", 0, SEEK_END ) - Error #", _GetLastError );
return(false);
}
if ( WriteWarnings )
{
if ( FileWrite( FileHandle[curSymbol], strEXPERT_WAS_STOPED ) < 0 )
{
_GetLastError = GetLastError();
Alert( "Ticks(" + Symbol() + ") - FileWrite() Error #", _GetLastError );
return(false);
}
FileFlush( FileHandle[curSymbol] );
}
preBid[curSymbol] = MarketInfo( SymbolsArray[curSymbol], MODE_BID );
}
return(true);
}
//+------------------------------------------------------------------+
//| Åñëè ïðîïàëà ñâÿçü, çàïèñûâàåì ïðåäóïðåæäåíèå âî âñå ôàéëû
//+------------------------------------------------------------------+
void WriteConnectionLost()
{
int _GetLastError;
if ( !preIsConnected ) { return(0); }
Comment( strComment, "ÍÅÒ ÑÂßÇÈ Ñ ÑÅÐÂÅÐÎÌ!!!" );
if ( !WriteWarnings ) { return(0); }
for ( int curSymbol = 0; curSymbol < SymbolsCount; curSymbol ++ )
{
if ( FileHandle[curSymbol] < 0 ) { continue; }
if ( !FileSeek( FileHandle[curSymbol], -strLEN, SEEK_END ) )
{
_GetLastError = GetLastError();
Alert( "FileSeek( " + FileHandle[curSymbol] + ", -strLEN, SEEK_END ) - Error #", _GetLastError );
continue;
}
if ( FileWrite( FileHandle[curSymbol], strCONNECTION_LOST ) < 0 )
{
_GetLastError = GetLastError();
Alert( "FileWrite() Error #", _GetLastError );
}
if ( FileWrite( FileHandle[curSymbol], strEXPERT_WAS_STOPED ) < 0 )
{
_GetLastError = GetLastError();
Alert( "FileWrite() Error #", _GetLastError );
}
FileFlush( FileHandle[curSymbol] );
}
}
//+------------------------------------------------------------------+
//| Çàïèñûâàåì ïîñòóïèâøèå òèêè
//+------------------------------------------------------------------+
void WriteTick()
{
int _GetLastError; double curBid; int curDigits;
Comment( strComment );
for ( int curSymbol = 0; curSymbol < SymbolsCount; curSymbol ++ )
{
if ( FileHandle[curSymbol] < 0 ) { continue; }
curBid = MarketInfo( SymbolsArray[curSymbol], MODE_BID );
curDigits = MarketInfo( SymbolsArray[curSymbol], MODE_DIGITS );
if ( NormalizeDouble( curBid - preBid[curSymbol], curDigits ) < 0.00000001 &&
NormalizeDouble( preBid[curSymbol] - curBid, curDigits ) < 0.00000001 ) { continue; }
preBid[curSymbol] = curBid;
if ( WriteWarnings )
{
if ( !FileSeek( FileHandle[curSymbol], -strLEN, SEEK_END ) )
{
_GetLastError = GetLastError();
Alert( "FileSeek( " + FileHandle[curSymbol] + ", -strLEN, SEEK_END ) - Error #", _GetLastError );
continue;
}
}
else
{
if ( !FileSeek( FileHandle[curSymbol], 0, SEEK_END ) )
{
_GetLastError = GetLastError();
Alert( "FileSeek( " + FileHandle[curSymbol] + ", 0, SEEK_END ) - Error #", _GetLastError );
continue;
}
}
if ( FileWrite( FileHandle[curSymbol], TimeToStr( TimeCurrent(), TIME_DATE | TIME_SECONDS ), DoubleToStr( curBid, curDigits ) ) < 0 )
{
_GetLastError = GetLastError();
Alert( "FileWrite() Error #", _GetLastError );
}
if ( WriteWarnings )
{
if ( FileWrite ( FileHandle[curSymbol], strEXPERT_WAS_STOPED ) < 0 )
{
_GetLastError = GetLastError();
Alert( "FileWrite() Error #", _GetLastError );
}
}
FileFlush( FileHandle[curSymbol] );
}
}
//+------------------------------------------------------------------+
//| Çàêðûâàåì âñå ôàéëû
//+------------------------------------------------------------------+
void CloseFiles()
{
for ( int curSymbol = 0; curSymbol < SymbolsCount; curSymbol ++ )
{
if ( FileHandle[curSymbol] > 0 )
{
FileClose( FileHandle[curSymbol] );
FileHandle[curSymbol] = -1;
}
}
}
string strMonth()
{
if ( Month() < 10 ) return( StringConcatenate( "0", Month() ) );
return(Month());
}
Comments