Initial Commit.
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
# Working with databases
|
||||
|
||||
The functions for working with databases apply the popular and easy-to-use [SQLite](https://www.sqlite.org/index.html) engine. The convenient feature of this engine is that the entire database is located in a single file on a user PC's hard disk.
|
||||
|
||||
The functions allow for convenient creation of tables, adding data to them, performing modifications and sampling using simple SQL requests:
|
||||
|
||||
- receiving trading history and quotes from any formats,
|
||||
- saving optimization and test results,
|
||||
- preparing and exchanging data with other analysis packages,
|
||||
- storing MQL5 application settings and status.
|
||||
|
||||
Queries allow using [statistical](/en/docs/database#math) and [mathematical](/en/docs/database#stats) functions.
|
||||
|
||||
The functions for working with databases allow you to replace the most repetitive large data array handling operations with SQL requests, so that it is often possible to use the [DatabaseExecute](/en/docs/database/databaseexecute)/[DatabasePrepare](/en/docs/database/databaseprepare) calls instead of programming complex loops and comparisons. Use the [DatabaseReadBind](/en/docs/database/databasereadbind) function to conveniently obtain query results in a ready-made structure. The function allows reading all record fields at once within a single call.
|
||||
|
||||
To accelerate reading, writing and modification, a database can be opened/created in RAM with the DATABASE_OPEN_MEMORY flag, although such a database is available only to a specific application and is not shared. When working with databases located on the hard disk, bulk data inserts/changes should be wrapped in transactions using [DatabaseTransactionBegin](/en/docs/database/databasetransactionbegin)/DatabaseTransactionCommit/DatabaseTransactionRollback. This accelerates the process hundreds of times.
|
||||
|
||||
To start working with the functions, read the article [SQLite: Native handling of SQL databases in MQL5](https://www.mql5.com/en/articles/7463).
|
||||
|
||||
| Function | Action |
|
||||
| --- | --- |
|
||||
| DatabaseOpen | Opens or creates a database in a specified file |
|
||||
| DatabaseClose | Closes a database |
|
||||
| DatabaseImport | Imports data from a file into a table |
|
||||
| DatabaseExport | Exports a table or an SQL request execution result to a CSV file |
|
||||
| DatabasePrint | Prints a table or an SQL request execution result in the Experts journal |
|
||||
| DatabaseTableExists | Checks the presence of the table in a database |
|
||||
| DatabaseExecute | Executes a request to a specified database |
|
||||
| DatabasePrepare | Creates a handle of a request, which can then be executed using DatabaseRead() |
|
||||
| DatabaseReset | Resets a request, like after calling DatabasePrepare() |
|
||||
| DatabaseBind | Sets a parameter value in a request |
|
||||
| DatabaseBindArray | Sets an array as a parameter value |
|
||||
| DatabaseRead | Moves to the next entry as a result of a request |
|
||||
| DatabaseReadBind | Moves to the next record and reads data into the structure from it |
|
||||
| DatabaseFinalize | Removes a request created in DatabasePrepare() |
|
||||
| DatabaseTransactionBegin | Starts transaction execution |
|
||||
| DatabaseTransactionCommit | Completes transaction execution |
|
||||
| DatabaseTransactionRollback | Rolls back transactions |
|
||||
| DatabaseColumnsCount | Gets the number of fields in a request |
|
||||
| DatabaseColumnName | Gets a field name by index |
|
||||
| DatabaseColumnType | Gets a field type by index |
|
||||
| DatabaseColumnSize | Gets a field size in bytes |
|
||||
| DatabaseColumnText | Gets a field value as a string from the current record |
|
||||
| DatabaseColumnInteger | Gets the int type value from the current record |
|
||||
| DatabaseColumnLong | Gets the long type value from the current record |
|
||||
| DatabaseColumnDouble | Gets the double type value from the current record |
|
||||
| DatabaseColumnBlob | Gets a field value as an array from the current record |
|
||||
|
||||
Statistical functions:
|
||||
|
||||
- mode – [mode](https://en.wikipedia.org/wiki/Mode_(statistics))
|
||||
- median – [median](https://en.wikipedia.org/wiki/Median) (50th percentile)
|
||||
- percentile_25 – 25th [percentile](https://en.wikipedia.org/wiki/Quantile)
|
||||
- percentile_75
|
||||
- percentile_90
|
||||
- percentile_95
|
||||
- percentile_99
|
||||
- stddev or stddev_samp — sample standard deviation
|
||||
- stddev_pop — population standard deviation
|
||||
- variance or var_samp — sample variance
|
||||
- var_pop — population variance
|
||||
|
||||
Mathematical functions
|
||||
|
||||
- [acos(X)](https://sqlite.org/lang_mathfunc.html#acos) – arccosine in radians
|
||||
- [acosh(X)](https://sqlite.org/lang_mathfunc.html#acosh) – hyperbolic arccosine
|
||||
- [asin(X)](https://sqlite.org/lang_mathfunc.html#asin) – arcsine in radians
|
||||
- [asinh(X)](https://sqlite.org/lang_mathfunc.html#asinh) – hyperbolic arcsine
|
||||
- [atan(X)](https://sqlite.org/lang_mathfunc.html#atan) – arctangent in radians
|
||||
- [atan2(X,Y)](https://sqlite.org/lang_mathfunc.html#atan2) – arctangent in radians of the X/Y ratio
|
||||
- [atanh(X)](https://sqlite.org/lang_mathfunc.html#atanh) – hyperbolic arctangent
|
||||
- [ceil(X)](https://sqlite.org/lang_mathfunc.html#ceil) – rounding up to an integer
|
||||
- [ceiling(X)](https://sqlite.org/lang_mathfunc.html#ceil) – rounding up to an integer
|
||||
- [cos(X)](https://sqlite.org/lang_mathfunc.html#cos) – angle cosine in radians
|
||||
- [cosh(X)](https://sqlite.org/lang_mathfunc.html#cosh) – hyperbolic cosine
|
||||
- [degrees(X)](https://sqlite.org/lang_mathfunc.html#degrees) – convert radians into the angle
|
||||
- [exp(X)](https://sqlite.org/lang_mathfunc.html#exp) – exponent
|
||||
- [floor(X)](https://sqlite.org/lang_mathfunc.html#floor) – rounding down to an integer
|
||||
- [ln(X)](https://sqlite.org/lang_mathfunc.html#ln) – natural logarithm
|
||||
- [log(B,X)](https://sqlite.org/lang_mathfunc.html#log) – logarithm to the indicated base
|
||||
- [log(X)](https://sqlite.org/lang_mathfunc.html#log) – decimal logarithm
|
||||
- [log10(X)](https://sqlite.org/lang_mathfunc.html#log) – decimal logarithm
|
||||
- [log2(X)](https://sqlite.org/lang_mathfunc.html#log2) – logarithm to base 2
|
||||
- [mod(X,Y)](https://sqlite.org/lang_mathfunc.html#mod) – remainder of division
|
||||
- [pi()](https://sqlite.org/lang_mathfunc.html#pi) – approximate Pi
|
||||
- [pow(X,Y)](https://sqlite.org/lang_mathfunc.html#pow) – power by the indicated base
|
||||
- [power(X,Y)](https://sqlite.org/lang_mathfunc.html#pow) – power by the indicated base
|
||||
- [radians(X)](https://sqlite.org/lang_mathfunc.html#radians) – convert the angle into radians
|
||||
- [sin(X)](https://sqlite.org/lang_mathfunc.html#sin) – angle sine in radians
|
||||
- [sinh(X)](https://sqlite.org/lang_mathfunc.html#sinh) – hyperbolic sine
|
||||
- [sqrt(X)](https://sqlite.org/lang_mathfunc.html#sqrt) – square root
|
||||
- [tan(X)](https://sqlite.org/lang_mathfunc.html#tan) – angle tangent in radians
|
||||
- [tanh(X)](https://sqlite.org/lang_mathfunc.html#tanh) – hyperbolic tangent
|
||||
- [trunc(X)](https://sqlite.org/lang_mathfunc.html#trunc) – truncate to an integer closest to 0
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
select
|
||||
count(*) as book_count,
|
||||
cast(avg(parent) as integer) as mean,
|
||||
cast(median(parent) as integer) as median,
|
||||
mode(parent) as mode,
|
||||
percentile_90(parent) as p90,
|
||||
percentile_95(parent) as p95,
|
||||
percentile_99(parent) as p99
|
||||
from moz_bookmarks;
|
||||
|
||||
```
|
||||
@@ -0,0 +1,60 @@
|
||||
# DatabaseOpen
|
||||
|
||||
Opens or creates a database in a specified file.
|
||||
|
||||
```
|
||||
int DatabaseOpen(
|
||||
string filename, // file name
|
||||
uint flags // combination of flags
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
filename
|
||||
|
||||
[in] File name relative to the "MQL5\Files" folder.
|
||||
|
||||
flags
|
||||
|
||||
[in] Combination of flags from the [ENUM_DATABASE_OPEN_FLAGS](/en/docs/database/databaseopen#enum_database_open_flags) enumeration.
|
||||
|
||||
Return Value
|
||||
|
||||
If executed successfully, the function returns the database handle, which is then used to access the database. Otherwise, it returns [INVALID_HANDLE](/en/docs/constants/namedconstants/otherconstants). To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_INTERNAL_ERROR (4001) – critical runtime error;
|
||||
- ERR_WRONG_INTERNAL_PARAMETER (4002) - internal error, while accessing the "MQL5\Files" folder;
|
||||
- ERR_INVALID_PARAMETER (4003) – path to the database file contains an empty string, or an incompatible combination of flags is set;
|
||||
- ERR_NOT_ENOUGH_MEMORY (4004) - insufficient memory;
|
||||
- ERR_WRONG_FILENAME (5002) - wrong database file name;
|
||||
- ERR_TOO_LONG_FILENAME (5003) - absolute path to the database file exceeds the maximum length;
|
||||
- ERR_DATABASE_TOO_MANY_OBJECTS (5122) - exceeded the maximum acceptable number of Database objects;
|
||||
- ERR_DATABASE_CONNECT (5123) - database connection error;
|
||||
|
||||
- ERR_DATABASE_MISUSE (5621) - incorrect use of the SQLite library.
|
||||
|
||||
Note
|
||||
|
||||
If the filename parameter features NULL or the empty string "", a temporary file is created on the disk. It is automatically deleted after closing the database connection.
|
||||
|
||||
If the filename parameter features ":memory:", the database is created in the memory and is automatically deleted after the connection to it is closed.
|
||||
|
||||
If the flags parameter features none of the DATABASE_OPEN_READONLY or DATABASE_OPEN_READWRITE flags, the DATABASE_OPEN_READWRITE flag is used.
|
||||
|
||||
If the file extension is not specified, ".sqlite" is used.
|
||||
|
||||
ENUM_DATABASE_OPEN_FLAGS
|
||||
|
||||
| ID | Description |
|
||||
| --- | --- |
|
||||
| DATABASE_OPEN_READONLY | Read only |
|
||||
| DATABASE_OPEN_READWRITE | Open for reading and writing |
|
||||
| DATABASE_OPEN_CREATE | Create the file on a disk if necessary |
|
||||
| DATABASE_OPEN_MEMORY | Create a database in RAM |
|
||||
| DATABASE_OPEN_COMMON | The file is in the common folder of all terminals |
|
||||
|
||||
See also
|
||||
|
||||
[DatabaseClose](/en/docs/database/databaseclose)
|
||||
@@ -0,0 +1,30 @@
|
||||
# DatabaseClose
|
||||
|
||||
Closes a database.
|
||||
|
||||
```
|
||||
void DatabaseClose(
|
||||
int database // database handle received in DatabaseOpen
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
database
|
||||
|
||||
[in] Database handle received in [DatabaseOpen()](/en/docs/database/databaseopen).
|
||||
|
||||
Return Value
|
||||
|
||||
None.
|
||||
|
||||
Note
|
||||
|
||||
After calling DatabaseClose, all [handles of requests ](/en/docs/database/databaseprepare) to the database are automatically removed and become invalid.
|
||||
|
||||
If the handle is invalid, the function sets the ERR_DATABASE_INVALID_HANDLE error. You can check the error using GetLastError().
|
||||
|
||||
See also
|
||||
|
||||
[DatabaseOpen](/en/docs/database/databaseopen), [DatabasePrepare](/en/docs/database/databaseprepare)
|
||||
@@ -0,0 +1,135 @@
|
||||
# DatabaseImport
|
||||
|
||||
Imports data from a file into a table.
|
||||
|
||||
```
|
||||
long DatabaseImport(
|
||||
int database, // database handle received in DatabaseOpen
|
||||
const string table, // name of a table to insert data
|
||||
const string filename, // name of a file to import data
|
||||
uint flags, // combination of flags
|
||||
const string separator, // data separator
|
||||
ulong skip_rows, // how many initial strings to skip
|
||||
const string skip_comments // string of characters defining comments
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
database
|
||||
|
||||
[in] Database handle received in [DatabaseOpen()](/en/docs/database/databaseopen).
|
||||
|
||||
table
|
||||
|
||||
[in] Name of a table the data from a file is to be added to.
|
||||
|
||||
filename
|
||||
|
||||
[in] CSV file or ZIP archive for reading data. The name may contain subdirectories and is set relative to the MQL5\Files folder.
|
||||
|
||||
flags
|
||||
|
||||
[in] Combination of flags from the [ENUM_DATABASE_IMPORT_FLAGS](/en/docs/database/databaseimport#enum_database_import_flags) enumeration.
|
||||
|
||||
separator
|
||||
|
||||
[in] Data separator in CSV file.
|
||||
|
||||
skip_rows
|
||||
|
||||
[in] Number of initial strings to be skipped when reading data from the file.
|
||||
|
||||
skip_comments
|
||||
|
||||
[in] String of characters for designating strings as comments. If any character from skip_comments is detected at the beginning of a string, such a string is considered a comment and is not imported.
|
||||
|
||||
Return Value
|
||||
|
||||
Return the number of imported strings or -1 in case of an error. To get the error code, use [GetLastError()](/en/docs/check/getlasterror), the possible responses are:
|
||||
|
||||
- ERR_INVALID_PARAMETER (4003) – no table name specified (empty string or NULL);
|
||||
- ERR_DATABASE_INTERNAL (5120) – internal database error;
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) - invalid database handle.
|
||||
|
||||
Note
|
||||
|
||||
If there is no table named table, it is generated automatically. Names and field types in the created table are defined automatically based on the file data.
|
||||
|
||||
If there is no table named table, it is generated automatically. Names and field types in the created table are defined automatically based on the file data.
|
||||
|
||||
ENUM_DATABASE_IMPORT_FLAGS
|
||||
|
||||
| ID | Description |
|
||||
| --- | --- |
|
||||
| DATABASE_IMPORT_HEADER | The first line contains the names of the table fields |
|
||||
| DATABASE_IMPORT_CRLF | CRLF (the default is LF) is considered a string break |
|
||||
| DATABASE_IMPORT_APPEND | Add data to the end of an existing table |
|
||||
| DATABASE_IMPORT_QUOTED_STRINGS | String values enclosed in double quotes |
|
||||
| DATABASE_IMPORT_COMMON_FOLDER | The file is stored in the common folder of all client terminals \Terminal\Common\File. |
|
||||
|
||||
Example of reading the table from the file created by the code from the [DatabaseExport](/en/docs/database/databaseexport) example:
|
||||
|
||||
```
|
||||
//+------------------------------------------------------------------+
|
||||
//| Script program start function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnStart()
|
||||
{
|
||||
string csv_filename;
|
||||
//--- get the names of text files for downloading from the common folder of the client terminals
|
||||
string filenames[];
|
||||
if(FileSelectDialog("Select a CSV file to download a table", NULL,
|
||||
"Text files (*.csv)|*.csv",
|
||||
FSD_WRITE_FILE|FSD_COMMON_FOLDER, filenames, "data.csv")>0)
|
||||
{
|
||||
//--- display the name of each selected file
|
||||
if(ArraySize(filenames)==1)
|
||||
csv_filename=filenames[0];
|
||||
else
|
||||
{
|
||||
Print("Unknown error while selecting file. Error code ", GetLastError());
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("CSV file not selected");
|
||||
return;
|
||||
}
|
||||
//--- create or open a database
|
||||
string db_filename="test.sqlite";
|
||||
int db=DatabaseOpen(db_filename, DATABASE_OPEN_READWRITE|DATABASE_OPEN_CREATE);
|
||||
//--- check if the TEST table exists
|
||||
if(DatabaseTableExists(db, "TEST"))
|
||||
{
|
||||
//--- remove the TEST table
|
||||
if(!DatabaseExecute(db, "DROP TABLE IF EXISTS TEST"))
|
||||
{
|
||||
Print("Failed to drop the TEST table with code ", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
}
|
||||
//--- import entries from the file to the TEST table
|
||||
long imported=DatabaseImport(db, "TEST", csv_filename, DATABASE_IMPORT_HEADER|DATABASE_IMPORT_COMMON_FOLDER|DATABASE_IMPORT_APPEND, ";", 0, NULL);
|
||||
if(imported>0)
|
||||
{
|
||||
Print(imported," lines imported in table TEST");
|
||||
DatabasePrint(db,"SELECT * FROM TEST",DATABASE_PRINT_NO_INDEX);
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("DatabaseImport() failed. Error ",GetLastError());
|
||||
}
|
||||
//--- close the database file and inform of that
|
||||
DatabaseClose(db);
|
||||
PrintFormat("Database: %s closed", db_filename);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
See also
|
||||
|
||||
[DatabaseOpen](/en/docs/database/databaseopen), [DatabasePrint](/en/docs/database/databaseprint)
|
||||
@@ -0,0 +1,272 @@
|
||||
# DatabaseExport
|
||||
|
||||
Exports a table or an SQL request execution result to a CSV file. The file is created in the UTF-8 encoding.
|
||||
|
||||
```
|
||||
long DatabaseExport(
|
||||
int database, // database handle received in DatabaseOpen
|
||||
const string table_or_sql, // a table name or an SQL request
|
||||
const string filename, // a name of a CSV file for data export
|
||||
uint flags, // combination of flags
|
||||
const string separator // data separator in the CSV file
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
database
|
||||
|
||||
[in] Database handle received in [DatabaseOpen()](/en/docs/database/databaseopen).
|
||||
|
||||
table_or_sql
|
||||
|
||||
[in] A name of a table or a text of an SQL request whose results are to be exported to a specified file.
|
||||
|
||||
filename
|
||||
|
||||
[in] A file name for data export. The path is set relative to the MQL5\Files folder.
|
||||
|
||||
flags
|
||||
|
||||
[in] Combination of flags from the [ENUM_DATABASE_EXPORT_FLAGS](/en/docs/database/databaseexport) enumeration.
|
||||
|
||||
separator
|
||||
|
||||
[in] Data separator. If NULL is specified, the '\t' tabulation character is used as a separator. An empty string "" is considered a valid separator but the obtained CSV file cannot be read as a table – it is considered as a set of strings.
|
||||
|
||||
Return Value
|
||||
|
||||
Return the number of exported entries or a negative value in case of an error. To get the error code, use [GetLastError()](/en/docs/check/getlasterror), the possible responses are:
|
||||
|
||||
- ERR_INTERNAL_ERROR (4001) – critical runtime error;
|
||||
- ERR_INVALID_PARAMETER (4003) – path to the database file contains an empty string, or an incompatible combination of flags is set;
|
||||
- ERR_NOT_ENOUGH_MEMORY (4004) - insufficient memory;
|
||||
- ERR_FUNCTION_NOT_ALLOWED(4014) – specified pipe is not allowed;
|
||||
- ERR_PROGRAM_STOPPED(4022) – operation canceled (MQL program stopped);
|
||||
- ERR_WRONG_FILENAME (5002) - invalid file name;
|
||||
- ERR_TOO_LONG_FILENAME (5003) - absolute path to the file exceeds the maximum length;
|
||||
- ERR_CANNOT_OPEN_FILE(5004) – unable to open the file for writing;
|
||||
- ERR_FILE_WRITEERROR(5026) – unable to write to the file;
|
||||
- ERR_DATABASE_INTERNAL (5120) – internal database error;
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) - invalid database handle;
|
||||
- ERR_DATABASE_QUERY_PREPARE(5125) – request generation error;
|
||||
- ERR_DATABASE_QUERY_NOT_READONLY – read-only request is allowed.
|
||||
|
||||
Note
|
||||
|
||||
If request results are exported, the SQL request should begin with "SELECT" or "select". In other words, the SQL request cannot alter the database status, otherwise DatabaseExport() fails with an error.
|
||||
|
||||
Database string values may contain the conversion character ('\r' or '\r\n' ), as well as the value separator character set in the separator parameter. In this case, be sure to use the DATABASE_EXPORT_QUOTED_STRINGS flag in the 'flags' parameter. If this flag is present, all displayed strings are enclosed in double quotes. If a string contains a double quote, it is replaced by two double quotes.
|
||||
|
||||
ENUM_DATABASE_EXPORT_FLAGS
|
||||
|
||||
| ID | Description |
|
||||
| --- | --- |
|
||||
| DATABASE_EXPORT_HEADER | Display field names in the first string |
|
||||
| DATABASE_EXPORT_INDEX | Display string indices |
|
||||
| DATABASE_EXPORT_NO_BOM | Do not insert BOM mark at the beginning of the file (BOM is inserted by default) |
|
||||
| DATABASE_EXPORT_CRLF | Use CRLF for string break (the default is LF) |
|
||||
| DATABASE_EXPORT_APPEND | Add data to the end of an existing file (by default, the file is overwritten). If the file does not exist, it will be created. |
|
||||
| DATABASE_EXPORT_QUOTED_STRINGS | Display string values in double quotes. |
|
||||
| DATABASE_EXPORT_COMMON_FOLDER | A CSV file is created in the common folder of all client terminals \Terminal\Common\File. |
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
input int InpRates=100;
|
||||
//+------------------------------------------------------------------+
|
||||
//| Script program start function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnStart()
|
||||
{
|
||||
MqlRates rates[];
|
||||
//--- remember the start time before receiving bars
|
||||
ulong start=GetMicrosecondCount();
|
||||
//--- request the last 100 bars on H1
|
||||
if(CopyRates(Symbol(), PERIOD_H1, 1, InpRates, rates)<InpRates)
|
||||
{
|
||||
Print("CopyRates() failed,, Error ", GetLastError());
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- how many bars were received and how much time it took to receive them
|
||||
PrintFormat("%s: CopyRates received %d bars in %d ms ",
|
||||
_Symbol, ArraySize(rates), (GetMicrosecondCount()-start)/1000);
|
||||
}
|
||||
//--- set the file name for storing the database
|
||||
string filename=_Symbol+"_"+EnumToString(PERIOD_H1)+"_"+TimeToString(TimeCurrent())+".sqlite";
|
||||
StringReplace(filename, ":", "-"); // ":" character is not allowed in file names
|
||||
//--- open/create the database in the common terminal folder
|
||||
int db=DatabaseOpen(filename, DATABASE_OPEN_READWRITE|DATABASE_OPEN_CREATE|DATABASE_OPEN_COMMON);
|
||||
if(db==INVALID_HANDLE)
|
||||
{
|
||||
Print("Database: ", filename, " open failed with code ", GetLastError());
|
||||
return;
|
||||
}
|
||||
else
|
||||
Print("Database: ", filename, " opened successfully");
|
||||
|
||||
//--- check if the RATES table exists
|
||||
if(DatabaseTableExists(db, "RATES"))
|
||||
{
|
||||
//--- remove the RATES table
|
||||
if(!DatabaseExecute(db, "DROP TABLE IF EXISTS RATES"))
|
||||
{
|
||||
Print("Failed to drop the RATES table with code ", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
}
|
||||
//--- create the RATES table
|
||||
if(!DatabaseExecute(db, "CREATE TABLE RATES("
|
||||
"SYMBOL CHAR(10),"
|
||||
"TIME INT NOT NULL,"
|
||||
"OPEN REAL,"
|
||||
"HIGH REAL,"
|
||||
"LOW REAL,"
|
||||
"CLOSE REAL,"
|
||||
"TICK_VOLUME INT,"
|
||||
"SPREAD INT,"
|
||||
"REAL_VOLUME INT);"))
|
||||
{
|
||||
Print("DB: ", filename, " create table RATES with code ", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
//--- display the list of all fields in the RATES table
|
||||
if(DatabasePrint(db, "PRAGMA TABLE_INFO(RATES)", 0)<0)
|
||||
{
|
||||
PrintFormat("DatabasePrint(\"PRAGMA TABLE_INFO(RATES)\") failed, error code=%d at line %d", GetLastError(), __LINE__);
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
//--- create a parametrized request to add bars to the RATES table
|
||||
string sql="INSERT INTO RATES (SYMBOL,TIME,OPEN,HIGH,LOW,CLOSE,TICK_VOLUME,SPREAD,REAL_VOLUME)"
|
||||
" VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9)"; // request parameters
|
||||
int request=DatabasePrepare(db, sql);
|
||||
if(request==INVALID_HANDLE)
|
||||
{
|
||||
PrintFormat("DatabasePrepare() failed with code=%d", GetLastError());
|
||||
Print("SQL request: ", sql);
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
//--- set the value of the first request parameter
|
||||
DatabaseBind(request, 0, _Symbol);
|
||||
//--- remember the start time before adding bars to the RATES table
|
||||
start=GetMicrosecondCount();
|
||||
DatabaseTransactionBegin(db);
|
||||
int total=ArraySize(rates);
|
||||
bool request_error=false;
|
||||
for(int i=0; i<total; i++)
|
||||
{
|
||||
//--- set the values of the remaining parameters before adding the entry
|
||||
ResetLastError();
|
||||
if(!DatabaseBind(request, 1, rates[i].time))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed with code=%d", GetLastError());
|
||||
PrintFormat("Bar #%d line=%d", i+1, __LINE__);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
//--- if the previous DatabaseBind() call was successful, set the next parameter
|
||||
if(!request_error && !DatabaseBind(request, 2, rates[i].open))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed with code=%d", GetLastError());
|
||||
PrintFormat("Bar #%d line=%d", i+1, __LINE__);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
if(!request_error && !DatabaseBind(request, 3, rates[i].high))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed with code=%d", GetLastError());
|
||||
PrintFormat("Bar #%d line=%d", i+1, __LINE__);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
if(!request_error && !DatabaseBind(request, 4, rates[i].low))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed with code=%d", GetLastError());
|
||||
PrintFormat("Bar #%d line=%d", i+1, __LINE__);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
if(!request_error && !DatabaseBind(request, 5, rates[i].close))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed with code=%d", GetLastError());
|
||||
PrintFormat("Bar #%d line=%d", i+1, __LINE__);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
if(!request_error && !DatabaseBind(request, 6, rates[i].tick_volume))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed with code=%d", GetLastError());
|
||||
PrintFormat("Bar #%d line=%d", i+1, __LINE__);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
if(!request_error && !DatabaseBind(request, 7, rates[i].spread))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed with code=%d", GetLastError());
|
||||
PrintFormat("Bar #%d line=%d", i+1, __LINE__);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
if(!request_error && !DatabaseBind(request, 8, rates[i].real_volume))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed with code=%d", GetLastError());
|
||||
PrintFormat("Bar #%d line=%d", i+1, __LINE__);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
|
||||
//--- execute a request for inserting the entry and check for an error
|
||||
if(!request_error && !DatabaseRead(request) && (GetLastError()!=ERR_DATABASE_NO_MORE_DATA))
|
||||
{
|
||||
PrintFormat("DatabaseRead() failed with code=%d", GetLastError());
|
||||
DatabaseFinalize(request);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
//--- reset the request before the next parameter update
|
||||
if(!request_error && !DatabaseReset(request))
|
||||
{
|
||||
PrintFormat("DatabaseReset() failed with code=%d", GetLastError());
|
||||
DatabaseFinalize(request);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
} //--- done going through all the bars
|
||||
|
||||
//--- transactions status
|
||||
if(request_error)
|
||||
{
|
||||
PrintFormat("Table RATES: failed to add %d bars ", ArraySize(rates));
|
||||
DatabaseTransactionRollback(db);
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
DatabaseTransactionCommit(db);
|
||||
PrintFormat("Table RATES: added %d bars in %d ms",
|
||||
ArraySize(rates), (GetMicrosecondCount()-start)/1000);
|
||||
}
|
||||
//--- save the RATES table to a CSV file
|
||||
string csv_filename=Symbol()+".csv";
|
||||
long saved=DatabaseExport(db, "SELECT * FROM RATES", csv_filename, DATABASE_EXPORT_HEADER|DATABASE_EXPORT_INDEX|DATABASE_EXPORT_COMMON_FOLDER, ";");
|
||||
if(saved>0)
|
||||
Print("Table RATES saved in ", Symbol(), ".csv");
|
||||
else
|
||||
Print("DatabaseExport() failed. Error ", GetLastError());
|
||||
//--- close the database file and inform of that
|
||||
DatabaseClose(db);
|
||||
PrintFormat("Database: %s created and closed", filename);
|
||||
|
||||
```
|
||||
|
||||
See also
|
||||
|
||||
[DatabasePrint](/en/docs/database/databaseprint), [DatabaseImport](/en/docs/database/databaseimport)
|
||||
@@ -0,0 +1,231 @@
|
||||
# DatabasePrint
|
||||
|
||||
Prints a table or an SQL request execution result in the Experts journal.
|
||||
|
||||
```
|
||||
long DatabasePrint(
|
||||
int database, // database handle received in DatabaseOpen
|
||||
const string table_or_sql, // a table or an SQL request
|
||||
uint flags // combination of flags
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
database
|
||||
|
||||
[in] Database handle received in [DatabaseOpen()](/en/docs/database/databaseopen).
|
||||
|
||||
table_or_sql
|
||||
|
||||
[in] A name of a table or a text of an SQL request whose results are displayed in the Experts journal.
|
||||
|
||||
flags
|
||||
|
||||
[in] Combination of flags defining the output formatting. The flags are defined as follows:
|
||||
|
||||
DATABASE_PRINT_NO_HEADER – do not display table column names (field names)
|
||||
|
||||
DATABASE_PRINT_NO_INDEX – do not display string indices
|
||||
|
||||
DATABASE_PRINT_NO_FRAME – do not display a frame separating a header and data
|
||||
|
||||
DATABASE_PRINT_STRINGS_RIGHT – align strings to the right.
|
||||
|
||||
If flags=0, the columns and the strings are displayed, the header and the data are separated by the frame, while the strings are aligned to the left.
|
||||
|
||||
Return Value
|
||||
|
||||
Return the number of exported strings or -1 in case of an error. To get the error code, use [GetLastError()](/en/docs/check/getlasterror), the possible responses are:
|
||||
|
||||
- ERR_INTERNAL_ERROR (4001) – critical runtime error;
|
||||
- ERR_NOT_ENOUGH_MEMORY (4004) - insufficient memory;
|
||||
- ERR_DATABASE_INTERNAL (5120) – internal database error;
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) - invalid database handle;
|
||||
|
||||
Note
|
||||
|
||||
If the journal displays request results, the SQL request should begin with "SELECT" or "select". In other words, the SQL request cannot alter the database status, otherwise DatabasePrint() fails with an error.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
//+------------------------------------------------------------------+
|
||||
//| Script program start function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnStart()
|
||||
{
|
||||
string filename="departments.sqlite";
|
||||
//--- create or open the database in the common terminal folder
|
||||
int db=DatabaseOpen(filename, DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE |DATABASE_OPEN_COMMON);
|
||||
if(db==INVALID_HANDLE)
|
||||
{
|
||||
Print("DB: ", filename, " open failed with code ", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
//--- create the COMPANY table
|
||||
if(!CreataTableCompany(db))
|
||||
{
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
//--- create the DEPARTMENT table
|
||||
if(!CreataTableDepartment(db))
|
||||
{
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
|
||||
//--- display the list of all fields in the COMPANY and DEPARTMENT tables
|
||||
PrintFormat("Try to print request \"PRAGMA TABLE_INFO(COMPANY);PRAGMA TABLE_INFO(DEPARTMENT)\"");
|
||||
if(DatabasePrint(db, "PRAGMA TABLE_INFO(COMPANY);PRAGMA TABLE_INFO(DEPARTMENT)", 0)<0)
|
||||
{
|
||||
PrintFormat("DatabasePrint(\"PRAGMA TABLE_INFO()\") failed, error code=%d", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
//--- display the COMPANY table in the log
|
||||
PrintFormat("Try to print request \"SELECT * from COMPANY\"");
|
||||
if(DatabasePrint(db, "SELECT * from COMPANY", 0)<0)
|
||||
{
|
||||
Print("DatabasePrint failed with code ", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
//--- request text for combining the COMPANY and DEPARTMENT tables
|
||||
string request="SELECT EMP_ID, NAME, DEPT FROM COMPANY LEFT OUTER JOIN DEPARTMENT "
|
||||
"ON COMPANY.ID = DEPARTMENT.EMP_ID";
|
||||
//--- display the table combining result
|
||||
PrintFormat("Try to print request \"SELECT EMP_ID, NAME, DEPT FROM COMPANY LEFT OUTER JOIN DEPARTMENT\"");
|
||||
if(DatabasePrint(db, request, 0)<0)
|
||||
{
|
||||
Print("DatabasePrint failed with code ", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
//--- close the database
|
||||
DatabaseClose(db);
|
||||
}
|
||||
/*
|
||||
Conclusion:
|
||||
Try to print request "PRAGMA TABLE_INFO(COMPANY);PRAGMA TABLE_INFO(DEPARTMENT)"
|
||||
#| cid name type notnull dflt_value pk
|
||||
-+-------------------------------------------
|
||||
1| 0 ID INT 1 1
|
||||
2| 1 NAME TEXT 1 0
|
||||
3| 2 AGE INT 1 0
|
||||
4| 3 ADDRESS CHAR(50) 0 0
|
||||
5| 4 SALARY REAL 0 0
|
||||
#| cid name type notnull dflt_value pk
|
||||
-+------------------------------------------
|
||||
1| 0 ID INT 1 1
|
||||
2| 1 DEPT CHAR(50) 1 0
|
||||
3| 2 EMP_ID INT 1 0
|
||||
Try to print request "SELECT * from COMPANY"
|
||||
#| ID NAME AGE ADDRESS SALARY
|
||||
-+--------------------------------
|
||||
1| 1 Paul 32 California 25000.0
|
||||
2| 2 Allen 25 Texas 15000.0
|
||||
3| 3 Teddy 23 Norway 20000.0
|
||||
4| 4 Mark 25 Rich-Mond 65000.0
|
||||
5| 5 David 27 Texas 85000.0
|
||||
6| 6 Kim 22 South-Hall 45000.0
|
||||
7| 7 James 24 Houston 10000.0
|
||||
Try to print request "SELECT EMP_ID, NAME, DEPT FROM COMPANY LEFT OUTER JOIN DEPARTMENT"
|
||||
#| EMP_ID NAME DEPT
|
||||
-+-------------------------
|
||||
1| 1 Paul IT Billing
|
||||
2| 2 Allen Engineering
|
||||
3| Teddy
|
||||
4| Mark
|
||||
5| David
|
||||
6| Kim
|
||||
7| 7 James Finance
|
||||
*/
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create the COMPANY table |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CreateTableCompany(int database)
|
||||
{
|
||||
//--- if the COMPANY table exists, delete it
|
||||
if(DatabaseTableExists(database, "COMPANY"))
|
||||
{
|
||||
//--- delete the table
|
||||
if(!DatabaseExecute(database, "DROP TABLE COMPANY"))
|
||||
{
|
||||
Print("Failed to drop table COMPANY with code ", GetLastError());
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
//--- create the COMPANY table
|
||||
if(!DatabaseExecute(database, "CREATE TABLE COMPANY("
|
||||
"ID INT PRIMARY KEY NOT NULL,"
|
||||
"NAME TEXT NOT NULL,"
|
||||
"AGE INT NOT NULL,"
|
||||
"ADDRESS CHAR(50),"
|
||||
"SALARY REAL );"))
|
||||
{
|
||||
Print("DB: create table COMPANY failed with code ", GetLastError());
|
||||
return(false);
|
||||
}
|
||||
|
||||
//--- enter data to the COMPANY table
|
||||
if(!DatabaseExecute(database, "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (1, 'Paul', 32, 'California', 25000.00); "
|
||||
"INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (2, 'Allen', 25, 'Texas', 15000.00); "
|
||||
"INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (3, 'Teddy', 23, 'Norway', 20000.00); "
|
||||
"INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (4, 'Mark', 25, 'Rich-Mond', 65000.00); "
|
||||
"INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (5, 'David', 27, 'Texas', 85000.0); "
|
||||
"INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (6, 'Kim', 22, 'South-Hall', 45000.0); "
|
||||
"INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (7, 'James', 24, 'Houston', 10000.00); "))
|
||||
{
|
||||
Print("COMPANY insert failed with code ", GetLastError());
|
||||
return(false);
|
||||
}
|
||||
//--- success
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create the DEPARTMENT table |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CreateTableDepartment(int database)
|
||||
{
|
||||
//--- if the DEPARTMENT table exists, delete it
|
||||
if(DatabaseTableExists(database, "DEPARTMENT"))
|
||||
{
|
||||
//--- delete the table
|
||||
if(!DatabaseExecute(database, "DROP TABLE DEPARTMENT"))
|
||||
{
|
||||
Print("Failed to drop table DEPARTMENT with code ", GetLastError());
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
//--- create the DEPARTMENT table
|
||||
if(!DatabaseExecute(database, "CREATE TABLE DEPARTMENT ("
|
||||
"ID INT PRIMARY KEY NOT NULL,"
|
||||
"DEPT CHAR(50) NOT NULL,"
|
||||
"EMP_ID INT NOT NULL);"))
|
||||
{
|
||||
Print("DB: create table DEPARTMENT failed with code ", GetLastError());
|
||||
return(false);
|
||||
}
|
||||
|
||||
//--- enter data to the DEPARTMENT table
|
||||
if(!DatabaseExecute(database, "INSERT INTO DEPARTMENT (ID,DEPT,EMP_ID) VALUES (1, 'IT Billing', 1); "
|
||||
"INSERT INTO DEPARTMENT (ID,DEPT,EMP_ID) VALUES (2, 'Engineering', 2); "
|
||||
"INSERT INTO DEPARTMENT (ID,DEPT,EMP_ID) VALUES (3, 'Finance', 7);"))
|
||||
{
|
||||
Print("DEPARTMENT insert failed with code ", GetLastError());
|
||||
return(false);
|
||||
}
|
||||
//--- success
|
||||
return(true);
|
||||
}
|
||||
//+-------------------------------------------------------------------
|
||||
|
||||
```
|
||||
|
||||
See also
|
||||
|
||||
[DatabaseExport](/en/docs/database/databaseexport), [DatabaseImport](/en/docs/database/databaseimport)
|
||||
@@ -0,0 +1,36 @@
|
||||
# DatabaseTableExists
|
||||
|
||||
Checks the presence of the table in a database.
|
||||
|
||||
```
|
||||
bool DatabaseTableExists(
|
||||
int database, // database handle received in DatabaseOpen
|
||||
string table // table name
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
database
|
||||
|
||||
[in] Database handle received in [DatabaseOpen()](/en/docs/database/databaseopen).
|
||||
|
||||
table
|
||||
|
||||
[in] Table name.
|
||||
|
||||
Return Value
|
||||
|
||||
Return true if successful, otherwise false. To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_INVALID_PARAMETER (4003) – no table name specified (empty string or NULL);
|
||||
- ERR_WRONG_STRING_PARAMETER (5040) – error converting a request into a UTF-8 string;
|
||||
- ERR_DATABASE_INTERNAL (5120) – internal database error;
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) - invalid database handle;
|
||||
- ERR_DATABASE_EXECUTE (5124) - request execution error;
|
||||
- ERR_DATABASE_NO_MORE_DATA (5126) - no table exists (not an error, normal completion).
|
||||
|
||||
See also
|
||||
|
||||
[DatabasePrepare](/en/docs/database/databaseprepare), [DatabaseFinalize](/en/docs/database/databasefinalize)
|
||||
@@ -0,0 +1,557 @@
|
||||
# DatabaseExecute
|
||||
|
||||
Executes a request to a specified database.
|
||||
|
||||
```
|
||||
bool DatabaseExecute(
|
||||
int database, // database handle received in DatabaseOpen
|
||||
string sql // SQL request
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
database
|
||||
|
||||
[in] Database handle received in [DatabaseOpen()](/en/docs/database/databaseopen).
|
||||
|
||||
sql
|
||||
|
||||
[in] SQL request.
|
||||
|
||||
Return Value
|
||||
|
||||
Return true if successful, otherwise false. To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_INTERNAL_ERROR (4001) – critical runtime error;
|
||||
- ERR_INVALID_PARAMETER (4003) – sql parameter contains an empty string;
|
||||
- ERR_NOT_ENOUGH_MEMORY (4004) – insufficient memory;
|
||||
- ERR_WRONG_STRING_PARAMETER (5040) – error converting a request into a UTF-8 string;
|
||||
- ERR_DATABASE_INTERNAL (5120) – internal database error;
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) – invalid database handle;
|
||||
- ERR_DATABASE_EXECUTE (5124) – request execution error.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
//--- symbol statistics
|
||||
struct Symbol_Stats
|
||||
{
|
||||
string name; // symbol name
|
||||
int trades; // number of trades for the symbol
|
||||
double gross_profit; // total profit for the symbol
|
||||
double gross_loss; // total loss for the symbol
|
||||
double total_commission; // total commission for the symbol
|
||||
double total_swap; // total swaps for the symbol
|
||||
double total_profit; // total profit excluding swaps and commissions
|
||||
double net_profit; // net profit taking into account swaps and commissions
|
||||
int win_trades; // number of profitable trades
|
||||
int loss_trades; // number of losing trades
|
||||
double expected_payoff; // expected payoff for the trade excluding swaps and commissions
|
||||
double win_percent; // percentage of winning trades
|
||||
double loss_percent; // percentage of losing trades
|
||||
double average_profit; // average profit
|
||||
double average_loss; // average loss
|
||||
double profit_factor; // profit factor
|
||||
};
|
||||
|
||||
//--- Magic Number statistics
|
||||
struct Magic_Stats
|
||||
{
|
||||
long magic; // EA's Magic Number
|
||||
int trades; // number of trades for the symbol
|
||||
double gross_profit; // total profit for the symbol
|
||||
double gross_loss; // total loss for the symbol
|
||||
double total_commission; // total commission for the symbol
|
||||
double total_swap; // total swaps for the symbol
|
||||
double total_profit; // total profit excluding swaps and commissions
|
||||
double net_profit; // net profit taking into account swaps and commissions
|
||||
int win_trades; // number of profitable trades
|
||||
int loss_trades; // number of losing trades
|
||||
double expected_payoff; // expected payoff for the trade excluding swaps and commissions
|
||||
double win_percent; // percentage of winning trades
|
||||
double loss_percent; // percentage of losing trades
|
||||
double average_profit; // average profit
|
||||
double average_loss; // average loss
|
||||
double profit_factor; // profit factor
|
||||
};
|
||||
|
||||
//--- entry hour statistics
|
||||
struct Hour_Stats
|
||||
{
|
||||
char hour_in; // market entry hour
|
||||
int trades; // number of trades in this entry hour
|
||||
double volume; // volume of trades in this entry hour
|
||||
double gross_profit; // total profit in this entry hour
|
||||
double gross_loss; // total loss in this entry hour
|
||||
double net_profit; // net profit taking into account swaps and commissions
|
||||
int win_trades; // number of profitable trades
|
||||
int loss_trades; // number of losing trades
|
||||
double expected_payoff; // expected payoff for the trade excluding swaps and commissions
|
||||
double win_percent; // percentage of winning trades
|
||||
double loss_percent; // percentage of losing trades
|
||||
double average_profit; // average profit
|
||||
double average_loss; // average loss
|
||||
double profit_factor; // profit factor
|
||||
};
|
||||
|
||||
int ExtDealsTotal=0;;
|
||||
//+------------------------------------------------------------------+
|
||||
//| Script program start function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnStart()
|
||||
{
|
||||
//--- create the file name
|
||||
string filename=IntegerToString(AccountInfoInteger(ACCOUNT_LOGIN))+"_stats.sqlite";
|
||||
//--- open/create the database in the common terminal folder
|
||||
int db=DatabaseOpen(filename, DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE | DATABASE_OPEN_COMMON);
|
||||
if(db==INVALID_HANDLE)
|
||||
{
|
||||
Print("DB: ", filename, " open failed with code ", GetLastError());
|
||||
return;
|
||||
}
|
||||
//--- create the DEALS table
|
||||
if(!CreateTableDeals(db))
|
||||
{
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
PrintFormat("Deals in the trading history: %d ", ExtDealsTotal);
|
||||
|
||||
//--- get trading statistics per symbols
|
||||
int request=DatabasePrepare(db, "SELECT r.*,"
|
||||
" (case when r.trades != 0 then (r.gross_profit+r.gross_loss)/r.trades else 0 end) as expected_payoff,"
|
||||
" (case when r.trades != 0 then r.win_trades*100.0/r.trades else 0 end) as win_percent,"
|
||||
" (case when r.trades != 0 then r.loss_trades*100.0/r.trades else 0 end) as loss_percent,"
|
||||
" r.gross_profit/r.win_trades as average_profit,"
|
||||
" r.gross_loss/r.loss_trades as average_loss,"
|
||||
" (case when r.gross_loss!=0.0 then r.gross_profit/(-r.gross_loss) else 0 end) as profit_factor "
|
||||
"FROM "
|
||||
" ("
|
||||
" SELECT SYMBOL,"
|
||||
" sum(case when entry =1 then 1 else 0 end) as trades,"
|
||||
" sum(case when profit > 0 then profit else 0 end) as gross_profit,"
|
||||
" sum(case when profit < 0 then profit else 0 end) as gross_loss,"
|
||||
" sum(swap) as total_swap,"
|
||||
" sum(commission) as total_commission,"
|
||||
" sum(profit) as total_profit,"
|
||||
" sum(profit+swap+commission) as net_profit,"
|
||||
" sum(case when profit > 0 then 1 else 0 end) as win_trades,"
|
||||
" sum(case when profit < 0 then 1 else 0 end) as loss_trades "
|
||||
" FROM DEALS "
|
||||
" WHERE SYMBOL <> '' and SYMBOL is not NULL "
|
||||
" GROUP BY SYMBOL"
|
||||
" ) as r");
|
||||
if(request==INVALID_HANDLE)
|
||||
{
|
||||
Print("DB: ", filename, " request failed with code ", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
Symbol_Stats stats[], symbol_stats;
|
||||
ArrayResize(stats, ExtDealsTotal);
|
||||
int i=0;
|
||||
//--- get records from request results
|
||||
for(; DatabaseReadBind(request, symbol_stats) ; i++)
|
||||
{
|
||||
stats[i].name=symbol_stats.name;
|
||||
stats[i].trades=symbol_stats.trades;
|
||||
stats[i].gross_profit=symbol_stats.gross_profit;
|
||||
stats[i].gross_loss=symbol_stats.gross_loss;
|
||||
stats[i].total_commission=symbol_stats.total_commission;
|
||||
stats[i].total_swap=symbol_stats.total_swap;
|
||||
stats[i].total_profit=symbol_stats.total_profit;
|
||||
stats[i].net_profit=symbol_stats.net_profit;
|
||||
stats[i].win_trades=symbol_stats.win_trades;
|
||||
stats[i].loss_trades=symbol_stats.loss_trades;
|
||||
stats[i].expected_payoff=symbol_stats.expected_payoff;
|
||||
stats[i].win_percent=symbol_stats.win_percent;
|
||||
stats[i].loss_percent=symbol_stats.loss_percent;
|
||||
stats[i].average_profit=symbol_stats.average_profit;
|
||||
stats[i].average_loss=symbol_stats.average_loss;
|
||||
stats[i].profit_factor=symbol_stats.profit_factor;
|
||||
}
|
||||
ArrayResize(stats, i);
|
||||
Print("Trade statistics by Symbol");
|
||||
ArrayPrint(stats);
|
||||
Print("");
|
||||
//--- delete the request
|
||||
DatabaseFinalize(request);
|
||||
|
||||
//--- get trading statistics for Expert Advisors by Magic Numbers
|
||||
request=DatabasePrepare(db, "SELECT r.*,"
|
||||
" (case when r.trades != 0 then (r.gross_profit+r.gross_loss)/r.trades else 0 end) as expected_payoff,"
|
||||
" (case when r.trades != 0 then r.win_trades*100.0/r.trades else 0 end) as win_percent,"
|
||||
" (case when r.trades != 0 then r.loss_trades*100.0/r.trades else 0 end) as loss_percent,"
|
||||
" r.gross_profit/r.win_trades as average_profit,"
|
||||
" r.gross_loss/r.loss_trades as average_loss,"
|
||||
" (case when r.gross_loss!=0.0 then r.gross_profit/(-r.gross_loss) else 0 end) as profit_factor "
|
||||
"FROM "
|
||||
" ("
|
||||
" SELECT MAGIC,"
|
||||
" sum(case when entry =1 then 1 else 0 end) as trades,"
|
||||
" sum(case when profit > 0 then profit else 0 end) as gross_profit,"
|
||||
" sum(case when profit < 0 then profit else 0 end) as gross_loss,"
|
||||
" sum(swap) as total_swap,"
|
||||
" sum(commission) as total_commission,"
|
||||
" sum(profit) as total_profit,"
|
||||
" sum(profit+swap+commission) as net_profit,"
|
||||
" sum(case when profit > 0 then 1 else 0 end) as win_trades,"
|
||||
" sum(case when profit < 0 then 1 else 0 end) as loss_trades "
|
||||
" FROM DEALS "
|
||||
" WHERE SYMBOL <> '' and SYMBOL is not NULL "
|
||||
" GROUP BY MAGIC"
|
||||
" ) as r");
|
||||
if(request==INVALID_HANDLE)
|
||||
{
|
||||
Print("DB: ", filename, " request failed with code ", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
Magic_Stats EA_stats[], magic_stats;
|
||||
ArrayResize(EA_stats, ExtDealsTotal);
|
||||
i=0;
|
||||
//--- print
|
||||
for(; DatabaseReadBind(request, magic_stats) ; i++)
|
||||
{
|
||||
EA_stats[i].magic=magic_stats.magic;
|
||||
EA_stats[i].trades=magic_stats.trades;
|
||||
EA_stats[i].gross_profit=magic_stats.gross_profit;
|
||||
EA_stats[i].gross_loss=magic_stats.gross_loss;
|
||||
EA_stats[i].total_commission=magic_stats.total_commission;
|
||||
EA_stats[i].total_swap=magic_stats.total_swap;
|
||||
EA_stats[i].total_profit=magic_stats.total_profit;
|
||||
EA_stats[i].net_profit=magic_stats.net_profit;
|
||||
EA_stats[i].win_trades=magic_stats.win_trades;
|
||||
EA_stats[i].loss_trades=magic_stats.loss_trades;
|
||||
EA_stats[i].expected_payoff=magic_stats.expected_payoff;
|
||||
EA_stats[i].win_percent=magic_stats.win_percent;
|
||||
EA_stats[i].loss_percent=magic_stats.loss_percent;
|
||||
EA_stats[i].average_profit=magic_stats.average_profit;
|
||||
EA_stats[i].average_loss=magic_stats.average_loss;
|
||||
EA_stats[i].profit_factor=magic_stats.profit_factor;
|
||||
}
|
||||
ArrayResize(EA_stats, i);
|
||||
Print("Trade statistics by Magic Number");
|
||||
ArrayPrint(EA_stats);
|
||||
Print("");
|
||||
//--- delete the request
|
||||
DatabaseFinalize(request);
|
||||
|
||||
//--- make sure that hedging system for open position management is used on the account
|
||||
if((ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE)!=ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
|
||||
{
|
||||
//--- deals cannot be transformed to trades using a simple method through transactions, therefore complete operation
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
|
||||
//--- now create the TRADES table based on the DEALS table
|
||||
if(!CreateTableTrades(db))
|
||||
{
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
//--- fill in the TRADES table using an SQL query based on DEALS table data
|
||||
if(DatabaseTableExists(db, "DEALS"))
|
||||
//--- populate the TRADES table
|
||||
if(!DatabaseExecute(db, "INSERT INTO TRADES(TIME_IN,HOUR_IN,TICKET,TYPE,VOLUME,SYMBOL,PRICE_IN,TIME_OUT,PRICE_OUT,COMMISSION,SWAP,PROFIT) "
|
||||
"SELECT "
|
||||
" d1.time as time_in,"
|
||||
" d1.hour as hour_in,"
|
||||
" d1.position_id as ticket,"
|
||||
" d1.type as type,"
|
||||
" d1.volume as volume,"
|
||||
" d1.symbol as symbol,"
|
||||
" d1.price as price_in,"
|
||||
" d2.time as time_out,"
|
||||
" d2.price as price_out,"
|
||||
" d1.commission+d2.commission as commission,"
|
||||
" d2.swap as swap,"
|
||||
" d2.profit as profit "
|
||||
"FROM DEALS d1 "
|
||||
"INNER JOIN DEALS d2 ON d1.position_id=d2.position_id "
|
||||
"WHERE d1.entry=0 AND d2.entry=1 "))
|
||||
{
|
||||
Print("DB: fillng the table TRADES failed with code ", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
//--- get trading statistics by market entry hours
|
||||
request=DatabasePrepare(db, "SELECT r.*,"
|
||||
" (case when r.trades != 0 then (r.gross_profit+r.gross_loss)/r.trades else 0 end) as expected_payoff,"
|
||||
" (case when r.trades != 0 then r.win_trades*100.0/r.trades else 0 end) as win_percent,"
|
||||
" (case when r.trades != 0 then r.loss_trades*100.0/r.trades else 0 end) as loss_percent,"
|
||||
" r.gross_profit/r.win_trades as average_profit,"
|
||||
" r.gross_loss/r.loss_trades as average_loss,"
|
||||
" (case when r.gross_loss!=0.0 then r.gross_profit/(-r.gross_loss) else 0 end) as profit_factor "
|
||||
"FROM "
|
||||
" ("
|
||||
" SELECT HOUR_IN,"
|
||||
" count() as trades,"
|
||||
" sum(volume) as volume,"
|
||||
" sum(case when profit > 0 then profit else 0 end) as gross_profit,"
|
||||
" sum(case when profit < 0 then profit else 0 end) as gross_loss,"
|
||||
" sum(profit) as net_profit,"
|
||||
" sum(case when profit > 0 then 1 else 0 end) as win_trades,"
|
||||
" sum(case when profit < 0 then 1 else 0 end) as loss_trades "
|
||||
" FROM TRADES "
|
||||
" WHERE SYMBOL <> '' and SYMBOL is not NULL "
|
||||
" GROUP BY HOUR_IN"
|
||||
" ) as r");
|
||||
if(request==INVALID_HANDLE)
|
||||
{
|
||||
Print("DB: ", filename, " request failed with code ", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
Hour_Stats hours_stats[], h_stats;
|
||||
ArrayResize(hours_stats, ExtDealsTotal);
|
||||
i=0;
|
||||
//--- print
|
||||
for(; DatabaseReadBind(request, h_stats) ; i++)
|
||||
{
|
||||
hours_stats[i].hour_in=h_stats.hour_in;
|
||||
hours_stats[i].trades=h_stats.trades;
|
||||
hours_stats[i].volume=h_stats.volume;
|
||||
hours_stats[i].gross_profit=h_stats.gross_profit;
|
||||
hours_stats[i].gross_loss=h_stats.gross_loss;
|
||||
hours_stats[i].net_profit=h_stats.net_profit;
|
||||
hours_stats[i].win_trades=h_stats.win_trades;
|
||||
hours_stats[i].loss_trades=h_stats.loss_trades;
|
||||
hours_stats[i].expected_payoff=h_stats.expected_payoff;
|
||||
hours_stats[i].win_percent=h_stats.win_percent;
|
||||
hours_stats[i].loss_percent=h_stats.loss_percent;
|
||||
hours_stats[i].average_profit=h_stats.average_profit;
|
||||
hours_stats[i].average_loss=h_stats.average_loss;
|
||||
hours_stats[i].profit_factor=h_stats.profit_factor;
|
||||
}
|
||||
ArrayResize(hours_stats, i);
|
||||
Print("Trade statistics by entry hour");
|
||||
ArrayPrint(hours_stats);
|
||||
Print("");
|
||||
//--- delete the request
|
||||
DatabaseFinalize(request);
|
||||
|
||||
//--- close database
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
Deals in the trading history: 2771
|
||||
Trade statistics by Symbol
|
||||
[name] [trades] [gross_profit] [gross_loss] [total_commission] [total_swap] [total_profit] [net_profit] [win_trades] [loss_trades] [expected_payoff] [win_percent] [loss_percent] [average_profit] [average_loss] [profit_factor]
|
||||
[0] "AUDUSD" 112 503.20000 -568.00000 -8.83000 -24.64000 -64.80000 -98.27000 70 42 -0.57857 62.50000 37.50000 7.18857 -13.52381 0.88592
|
||||
[1] "EURCHF" 125 607.71000 -956.85000 -11.77000 -45.02000 -349.14000 -405.93000 54 71 -2.79312 43.20000 56.80000 11.25389 -13.47676 0.63512
|
||||
[2] "EURJPY" 127 1078.49000 -1057.83000 -10.61000 -45.76000 20.66000 -35.71000 64 63 0.16268 50.39370 49.60630 16.85141 -16.79095 1.01953
|
||||
[3] "EURUSD" 233 1685.60000 -1386.80000 -41.00000 -83.76000 298.80000 174.04000 127 106 1.28240 54.50644 45.49356 13.27244 -13.08302 1.21546
|
||||
[4] "GBPCHF" 125 1881.37000 -1424.72000 -22.60000 -51.56000 456.65000 382.49000 80 45 3.65320 64.00000 36.00000 23.51712 -31.66044 1.32052
|
||||
[5] "GBPJPY" 127 1943.43000 -1776.67000 -18.84000 -52.46000 166.76000 95.46000 76 51 1.31307 59.84252 40.15748 25.57145 -34.83667 1.09386
|
||||
[6] "GBPUSD" 121 1668.50000 -1438.20000 -7.96000 -49.93000 230.30000 172.41000 77 44 1.90331 63.63636 36.36364 21.66883 -32.68636 1.16013
|
||||
[7] "USDCAD" 99 405.28000 -475.47000 -8.68000 -31.68000 -70.19000 -110.55000 51 48 -0.70899 51.51515 48.48485 7.94667 -9.90563 0.85238
|
||||
[8] "USDCHF" 206 1588.32000 -1241.83000 -17.98000 -65.92000 346.49000 262.59000 131 75 1.68199 63.59223 36.40777 12.12458 -16.55773 1.27902
|
||||
[9] "USDJPY" 107 464.73000 -730.64000 -35.12000 -34.24000 -265.91000 -335.27000 50 57 -2.48514 46.72897 53.27103 9.29460 -12.81825 0.63606
|
||||
|
||||
Trade statistics by Magic Number
|
||||
[magic] [trades] [gross_profit] [gross_loss] [total_commission] [total_swap] [total_profit] [net_profit] [win_trades] [loss_trades] [expected_payoff] [win_percent] [loss_percent] [average_profit] [average_loss] [profit_factor]
|
||||
[0] 100 242 2584.80000 -2110.00000 -33.36000 -93.53000 474.80000 347.91000 143 99 1.96198 59.09091 40.90909 18.07552 -21.31313 1.22502
|
||||
[1] 200 254 3021.92000 -2834.50000 -29.45000 -98.22000 187.42000 59.75000 140 114 0.73787 55.11811 44.88189 21.58514 -24.86404 1.06612
|
||||
[2] 300 250 2489.08000 -2381.57000 -34.37000 -96.58000 107.51000 -23.44000 134 116 0.43004 53.60000 46.40000 18.57522 -20.53078 1.04514
|
||||
[3] 400 224 1272.50000 -1283.00000 -24.43000 -64.80000 -10.50000 -99.73000 131 93 -0.04687 58.48214 41.51786 9.71374 -13.79570 0.99182
|
||||
[4] 500 198 1141.23000 -1051.91000 -27.66000 -63.36000 89.32000 -1.70000 116 82 0.45111 58.58586 41.41414 9.83819 -12.82817 1.08491
|
||||
[5] 600 214 1317.10000 -1396.03000 -34.12000 -68.48000 -78.93000 -181.53000 116 98 -0.36883 54.20561 45.79439 11.35431 -14.24520 0.94346
|
||||
|
||||
Trade statistics by entry hour
|
||||
[hour_in] [trades] [volume] [gross_profit] [gross_loss] [net_profit] [win_trades] [loss_trades] [expected_payoff] [win_percent] [loss_percent] [average_profit] [average_loss] [profit_factor]
|
||||
[ 0] 0 50 5.00000 336.51000 -747.47000 -410.96000 21 29 -8.21920 42.00000 58.00000 16.02429 -25.77483 0.45020
|
||||
[ 1] 1 20 2.00000 102.56000 -57.20000 45.36000 12 8 2.26800 60.00000 40.00000 8.54667 -7.15000 1.79301
|
||||
[ 2] 2 6 0.60000 38.55000 -14.60000 23.95000 5 1 3.99167 83.33333 16.66667 7.71000 -14.60000 2.64041
|
||||
[ 3] 3 38 3.80000 173.84000 -200.15000 -26.31000 22 16 -0.69237 57.89474 42.10526 7.90182 -12.50938 0.86855
|
||||
[ 4] 4 60 6.00000 361.44000 -389.40000 -27.96000 27 33 -0.46600 45.00000 55.00000 13.38667 -11.80000 0.92820
|
||||
[ 5] 5 32 3.20000 157.43000 -179.89000 -22.46000 20 12 -0.70187 62.50000 37.50000 7.87150 -14.99083 0.87515
|
||||
[ 6] 6 18 1.80000 95.59000 -162.33000 -66.74000 11 7 -3.70778 61.11111 38.88889 8.69000 -23.19000 0.58886
|
||||
[ 7] 7 14 1.40000 38.48000 -134.30000 -95.82000 9 5 -6.84429 64.28571 35.71429 4.27556 -26.86000 0.28652
|
||||
[ 8] 8 42 4.20000 368.48000 -322.30000 46.18000 24 18 1.09952 57.14286 42.85714 15.35333 -17.90556 1.14328
|
||||
[ 9] 9 118 11.80000 1121.62000 -875.21000 246.41000 72 46 2.08822 61.01695 38.98305 15.57806 -19.02630 1.28154
|
||||
[10] 10 206 20.60000 2280.59000 -2021.80000 258.79000 115 91 1.25626 55.82524 44.17476 19.83122 -22.21758 1.12800
|
||||
[11] 11 138 13.80000 1377.02000 -994.18000 382.84000 84 54 2.77420 60.86957 39.13043 16.39310 -18.41074 1.38508
|
||||
[12] 12 152 15.20000 1247.56000 -1463.80000 -216.24000 84 68 -1.42263 55.26316 44.73684 14.85190 -21.52647 0.85227
|
||||
[13] 13 64 6.40000 778.27000 -516.22000 262.05000 36 28 4.09453 56.25000 43.75000 21.61861 -18.43643 1.50763
|
||||
[14] 14 62 6.20000 536.93000 -427.47000 109.46000 38 24 1.76548 61.29032 38.70968 14.12974 -17.81125 1.25606
|
||||
[15] 15 50 5.00000 699.92000 -413.00000 286.92000 28 22 5.73840 56.00000 44.00000 24.99714 -18.77273 1.69472
|
||||
[16] 16 88 8.80000 778.55000 -514.00000 264.55000 51 37 3.00625 57.95455 42.04545 15.26569 -13.89189 1.51469
|
||||
[17] 17 76 7.60000 533.92000 -1019.46000 -485.54000 44 32 -6.38868 57.89474 42.10526 12.13455 -31.85813 0.52373
|
||||
[18] 18 52 5.20000 237.17000 -246.78000 -9.61000 24 28 -0.18481 46.15385 53.84615 9.88208 -8.81357 0.96106
|
||||
[19] 19 52 5.20000 407.67000 -150.36000 257.31000 30 22 4.94827 57.69231 42.30769 13.58900 -6.83455 2.71129
|
||||
[20] 20 18 1.80000 65.92000 -89.09000 -23.17000 9 9 -1.28722 50.00000 50.00000 7.32444 -9.89889 0.73993
|
||||
[21] 21 10 1.00000 41.86000 -32.38000 9.48000 7 3 0.94800 70.00000 30.00000 5.98000 -10.79333 1.29277
|
||||
[22] 22 14 1.40000 45.55000 -83.72000 -38.17000 6 8 -2.72643 42.85714 57.14286 7.59167 -10.46500 0.54408
|
||||
[23] 23 2 0.20000 1.20000 -1.90000 -0.70000 1 1 -0.35000 50.00000 50.00000 1.20000 -1.90000 0.63158
|
||||
*/
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Creates the DEALS table |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CreateTableDeals(int database)
|
||||
{
|
||||
//--- if the DEALS table already exists, delete it
|
||||
if(!DeleteTable(database, "DEALS"))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
//--- check if the table exists
|
||||
if(!DatabaseTableExists(database, "DEALS"))
|
||||
//--- create the table
|
||||
if(!DatabaseExecute(database, "CREATE TABLE DEALS("
|
||||
"ID INT KEY NOT NULL,"
|
||||
"ORDER_ID INT NOT NULL,"
|
||||
"POSITION_ID INT NOT NULL,"
|
||||
"TIME INT NOT NULL,"
|
||||
"TYPE INT NOT NULL,"
|
||||
"ENTRY INT NOT NULL,"
|
||||
"SYMBOL CHAR(10),"
|
||||
"VOLUME REAL,"
|
||||
"PRICE REAL,"
|
||||
"PROFIT REAL,"
|
||||
"SWAP REAL,"
|
||||
"COMMISSION REAL,"
|
||||
"MAGIC INT,"
|
||||
"HOUR INT,"
|
||||
"REASON INT);"))
|
||||
{
|
||||
Print("DB: create the DEALS table failed with code ", GetLastError());
|
||||
return(false);
|
||||
}
|
||||
//--- request the entire trading history
|
||||
datetime from_date=0;
|
||||
datetime to_date=TimeCurrent();
|
||||
//--- request the history of deals in the specified interval
|
||||
HistorySelect(from_date, to_date);
|
||||
ExtDealsTotal=HistoryDealsTotal();
|
||||
//--- add deals to the table
|
||||
if(!InsertDeals(database))
|
||||
return(false);
|
||||
//--- the table has been successfully created
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deletes a table with the specified name from the database |
|
||||
//+------------------------------------------------------------------+
|
||||
bool DeleteTable(int database, string table_name)
|
||||
{
|
||||
if(!DatabaseExecute(database, "DROP TABLE IF EXISTS "+table_name))
|
||||
{
|
||||
Print("Failed to drop the DEALS table with code ", GetLastError());
|
||||
return(false);
|
||||
}
|
||||
//--- the table has been successfully deleted
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds deals to the database table |
|
||||
//+------------------------------------------------------------------+
|
||||
bool InsertDeals(int database)
|
||||
{
|
||||
//--- Auxiliary variables
|
||||
ulong deal_ticket; // deal ticket
|
||||
long order_ticket; // the ticket of the order by which the deal was executed
|
||||
long position_ticket; // ID of the position to which the deal belongs
|
||||
datetime time; // deal execution time
|
||||
long type ; // deal type
|
||||
long entry ; // deal direction
|
||||
string symbol; // the symbol fro which the deal was executed
|
||||
double volume; // operation volume
|
||||
double price; // price
|
||||
double profit; // financial result
|
||||
double swap; // swap
|
||||
double commission; // commission
|
||||
long magic; // Magic number (Expert Advisor ID)
|
||||
long reason; // deal execution reason or source
|
||||
char hour; // deal execution hour
|
||||
MqlDateTime time_strusture;
|
||||
//--- go through all deals and add them to the database
|
||||
bool failed=false;
|
||||
int deals=HistoryDealsTotal();
|
||||
// --- lock the database before executing transactions
|
||||
DatabaseTransactionBegin(database);
|
||||
for(int i=0; i<deals; i++)
|
||||
{
|
||||
deal_ticket= HistoryDealGetTicket(i);
|
||||
order_ticket= HistoryDealGetInteger(deal_ticket, DEAL_ORDER);
|
||||
position_ticket=HistoryDealGetInteger(deal_ticket, DEAL_POSITION_ID);
|
||||
time= (datetime)HistoryDealGetInteger(deal_ticket, DEAL_TIME);
|
||||
type= HistoryDealGetInteger(deal_ticket, DEAL_TYPE);
|
||||
entry= HistoryDealGetInteger(deal_ticket, DEAL_ENTRY);
|
||||
symbol= HistoryDealGetString(deal_ticket, DEAL_SYMBOL);
|
||||
volume= HistoryDealGetDouble(deal_ticket, DEAL_VOLUME);
|
||||
price= HistoryDealGetDouble(deal_ticket, DEAL_PRICE);
|
||||
profit= HistoryDealGetDouble(deal_ticket, DEAL_PROFIT);
|
||||
swap= HistoryDealGetDouble(deal_ticket, DEAL_SWAP);
|
||||
commission= HistoryDealGetDouble(deal_ticket, DEAL_COMMISSION);
|
||||
magic= HistoryDealGetInteger(deal_ticket, DEAL_MAGIC);
|
||||
reason= HistoryDealGetInteger(deal_ticket, DEAL_REASON);
|
||||
TimeToStruct(time, time_strusture);
|
||||
hour= (char)time_strusture.hour;
|
||||
//--- add each deal to the table using the following request
|
||||
string request_text=StringFormat("INSERT INTO DEALS (ID,ORDER_ID,POSITION_ID,TIME,TYPE,ENTRY,SYMBOL,VOLUME,PRICE,PROFIT,SWAP,COMMISSION,MAGIC,REASON,HOUR)"
|
||||
"VALUES (%d, %d, %d, %d, %d, %d, '%s', %G, %G, %G, %G, %G, %d, %d,%d)",
|
||||
deal_ticket, order_ticket, position_ticket, time, type, entry, symbol, volume, price, profit, swap, commission, magic, reason, hour);
|
||||
if(!DatabaseExecute(database, request_text))
|
||||
{
|
||||
PrintFormat("%s: failed to insert deal #%d with code %d", __FUNCTION__, deal_ticket, GetLastError());
|
||||
PrintFormat("i=%d: deal #%d %s", i, deal_ticket, symbol);
|
||||
failed=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//--- check for transaction execution errors
|
||||
if(failed)
|
||||
{
|
||||
//--- roll back all transactions and unlock the database
|
||||
DatabaseTransactionRollback(database);
|
||||
PrintFormat("%s: DatabaseExecute() failed with code ", __FUNCTION__, GetLastError());
|
||||
return(false);
|
||||
}
|
||||
//--- all transactions have been performed successfully - record changes and unlock the database
|
||||
DatabaseTransactionCommit(database);
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Creates the TRADES table |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CreateTableTrades(int database)
|
||||
{
|
||||
//--- if the TRADES table already exists, delete it
|
||||
if(!DeleteTable(database, "TRADES"))
|
||||
return(false);
|
||||
//--- check if the table exists
|
||||
if(!DatabaseTableExists(database, "TRADES"))
|
||||
//--- create the table
|
||||
if(!DatabaseExecute(database, "CREATE TABLE TRADES("
|
||||
"TIME_IN INT NOT NULL,"
|
||||
"HOUR_IN INT NOT NULL,"
|
||||
"TICKET INT NOT NULL,"
|
||||
"TYPE INT NOT NULL,"
|
||||
"VOLUME REAL,"
|
||||
"SYMBOL CHAR(10),"
|
||||
"PRICE_IN REAL,"
|
||||
"TIME_OUT INT NOT NULL,"
|
||||
"PRICE_OUT REAL,"
|
||||
"COMMISSION REAL,"
|
||||
"SWAP REAL,"
|
||||
"PROFIT REAL);"))
|
||||
{
|
||||
Print("DB: create the TRADES table failed with code ", GetLastError());
|
||||
return(false);
|
||||
}
|
||||
//--- the table has been successfully created
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
```
|
||||
|
||||
See also
|
||||
|
||||
[DatabasePrepare](/en/docs/database/databaseprepare), [DatabaseFinalize](/en/docs/database/databasefinalize)
|
||||
@@ -0,0 +1,409 @@
|
||||
# DatabasePrepare
|
||||
|
||||
Creates a handle of a request, which can then be executed using [DatabaseRead()](/en/docs/database/databaseread).
|
||||
|
||||
```
|
||||
int DatabasePrepare(
|
||||
int database, // database handle received in DatabaseOpen
|
||||
string sql, // SQL request
|
||||
... // request parameters
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
database
|
||||
|
||||
[in] Database handle received in [DatabaseOpen()](/en/docs/database/databaseopen).
|
||||
|
||||
sql
|
||||
|
||||
[in] SQL request that may contain automatically substituted parameters named ?1,?2,...
|
||||
|
||||
...
|
||||
|
||||
[in] Automatically substituted request parameters.
|
||||
|
||||
Return Value
|
||||
|
||||
If successful, the function returns a handle for the SQL request. Otherwise, it returns [INVALID_HANDLE](/en/docs/constants/namedconstants/otherconstants). To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_INVALID_PARAMETER (4003) – path to the database file contains an empty string, or an incompatible combination of flags is set;
|
||||
- ERR_NOT_ENOUGH_MEMORY (4004) - insufficient memory;
|
||||
- ERR_WRONG_STRING_PARAMETER (5040) – error converting a request into a UTF-8 string;
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) - invalid database handle;
|
||||
- ERR_DATABASE_TOO_MANY_OBJECTS (5122) - exceeded the maximum acceptable number of Database objects;
|
||||
- ERR_DATABASE_PREPARE (5125) - request generation error.
|
||||
|
||||
Note
|
||||
|
||||
The DatabasePrepare() function does not perform a request to a database. Its purpose is to verify the request parameters and return the handle for executing the SQL request based on the verification results. The request itself is set during the [DatabaseRead()](/en/docs/database/databaseread) first call.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
//--- Structure to store the deal
|
||||
struct Deal
|
||||
{
|
||||
ulong ticket; // DEAL_TICKET
|
||||
long order_ticket; // DEAL_ORDER
|
||||
long position_ticket; // DEAL_POSITION_ID
|
||||
datetime time; // DEAL_TIME
|
||||
char type; // DEAL_TYPE
|
||||
char entry; // DEAL_ENTRY
|
||||
string symbol; // DEAL_SYMBOL
|
||||
double volume; // DEAL_VOLUME
|
||||
double price; // DEAL_PRICE
|
||||
double profit; // DEAL_PROFIT
|
||||
double swap; // DEAL_SWAP
|
||||
double commission; // DEAL_COMMISSION
|
||||
long magic; // DEAL_MAGIC
|
||||
char reason; // DEAL_REASON
|
||||
};
|
||||
//--- Structure to store the trade: the order of members corresponds to the position in the terminal
|
||||
struct Trade
|
||||
{
|
||||
datetime time_in; // entry time
|
||||
ulong ticket; // position ID
|
||||
char type; // buy or sell
|
||||
double volume; // volume
|
||||
string symbol; // symbol
|
||||
double price_in; // entry price
|
||||
datetime time_out; // exit time
|
||||
double price_out; // exit price
|
||||
double commission; // entry and exit commission
|
||||
double swap; // swap
|
||||
double profit; // profit or loss
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Script program start function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnStart()
|
||||
{
|
||||
//--- create the file name
|
||||
string filename=IntegerToString(AccountInfoInteger(ACCOUNT_LOGIN))+"_trades.sqlite";
|
||||
//--- open/create the database in the common terminal folder
|
||||
int db=DatabaseOpen(filename, DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE | DATABASE_OPEN_COMMON);
|
||||
if(db==INVALID_HANDLE)
|
||||
{
|
||||
Print("DB: ", filename, " open failed with code ", GetLastError());
|
||||
return;
|
||||
}
|
||||
//--- create the DEALS table
|
||||
if(!CreateTableDeals(db))
|
||||
{
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
//--- request the entire trading history
|
||||
datetime from_date=0;
|
||||
datetime to_date=TimeCurrent();
|
||||
//--- request the history of deals in the specified interval
|
||||
HistorySelect(from_date, to_date);
|
||||
int deals_total=HistoryDealsTotal();
|
||||
PrintFormat("Deals in the trading history: %d ", deals_total);
|
||||
//--- add deals to the table
|
||||
if(!InsertDeals(db))
|
||||
return;
|
||||
//--- show the first 10 deals
|
||||
Deal deals[], deal;
|
||||
ArrayResize(deals, 10);
|
||||
int request=DatabasePrepare(db, "SELECT * FROM DEALS");
|
||||
if(request==INVALID_HANDLE)
|
||||
{
|
||||
Print("DB: ", filename, " request failed with code ", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
int i;
|
||||
for(i=0; DatabaseReadBind(request, deal); i++)
|
||||
{
|
||||
if(i>=10)
|
||||
break;
|
||||
deals[i].ticket=deal.ticket;
|
||||
deals[i].order_ticket=deal.order_ticket;
|
||||
deals[i].position_ticket=deal.position_ticket;
|
||||
deals[i].time=deal.time;
|
||||
deals[i].type=deal.type;
|
||||
deals[i].entry=deal.entry;
|
||||
deals[i].symbol=deal.symbol;
|
||||
deals[i].volume=deal.volume;
|
||||
deals[i].price=deal.price;
|
||||
deals[i].profit=deal.profit;
|
||||
deals[i].swap=deal.swap;
|
||||
deals[i].commission=deal.commission;
|
||||
deals[i].magic=deal.magic;
|
||||
deals[i].reason=deal.reason;
|
||||
}
|
||||
//--- print the deals
|
||||
if(i>0)
|
||||
{
|
||||
ArrayResize(deals, i);
|
||||
PrintFormat("The first %d deals:", i);
|
||||
ArrayPrint(deals);
|
||||
}
|
||||
|
||||
//--- delete request after use
|
||||
DatabaseFinalize(request);
|
||||
|
||||
//--- make sure that hedging system for open position management is used on the account
|
||||
if((ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE)!=ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
|
||||
{
|
||||
//--- deals cannot be transformed to trades using a simple method through transactions, therefore complete operation
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
|
||||
//--- now create the TRADES table based on the DEALS table
|
||||
if(!CreateTableTrades(db))
|
||||
{
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
//--- fill in the TRADES table using an SQL query based on DEALS table data
|
||||
ulong start=GetMicrosecondCount();
|
||||
if(DatabaseTableExists(db, "DEALS"))
|
||||
//--- populate the TRADES table
|
||||
if(!DatabaseExecute(db, "INSERT INTO TRADES(TIME_IN,TICKET,TYPE,VOLUME,SYMBOL,PRICE_IN,TIME_OUT,PRICE_OUT,COMMISSION,SWAP,PROFIT) "
|
||||
"SELECT "
|
||||
" d1.time as time_in,"
|
||||
" d1.position_id as ticket,"
|
||||
" d1.type as type,"
|
||||
" d1.volume as volume,"
|
||||
" d1.symbol as symbol,"
|
||||
" d1.price as price_in,"
|
||||
" d2.time as time_out,"
|
||||
" d2.price as price_out,"
|
||||
" d1.commission+d2.commission as commission,"
|
||||
" d2.swap as swap,"
|
||||
" d2.profit as profit "
|
||||
"FROM DEALS d1 "
|
||||
"INNER JOIN DEALS d2 ON d1.position_id=d2.position_id "
|
||||
"WHERE d1.entry=0 AND d2.entry=1 "))
|
||||
{
|
||||
Print("DB: fillng the TRADES table failed with code ", GetLastError());
|
||||
return;
|
||||
}
|
||||
ulong transaction_time=GetMicrosecondCount()-start;
|
||||
|
||||
//--- show the first 10 deals
|
||||
Trade trades[], trade;
|
||||
ArrayResize(trades, 10);
|
||||
request=DatabasePrepare(db, "SELECT * FROM TRADES");
|
||||
if(request==INVALID_HANDLE)
|
||||
{
|
||||
Print("DB: ", filename, " request failed with code ", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
for(i=0; DatabaseReadBind(request, trade); i++)
|
||||
{
|
||||
if(i>=10)
|
||||
break;
|
||||
trades[i].time_in=trade.time_in;
|
||||
trades[i].ticket=trade.ticket;
|
||||
trades[i].type=trade.type;
|
||||
trades[i].volume=trade.volume;
|
||||
trades[i].symbol=trade.symbol;
|
||||
trades[i].price_in=trade.price_in;
|
||||
trades[i].time_out=trade.time_out;
|
||||
trades[i].price_out=trade.price_out;
|
||||
trades[i].commission=trade.commission;
|
||||
trades[i].swap=trade.swap;
|
||||
trades[i].profit=trade.profit;
|
||||
}
|
||||
//--- print trades
|
||||
if(i>0)
|
||||
{
|
||||
ArrayResize(trades, i);
|
||||
PrintFormat("\r\nThe first %d trades:", i);
|
||||
ArrayPrint(trades);
|
||||
PrintFormat("Filling the TRADES table took %.2f milliseconds",double(transaction_time)/1000);
|
||||
}
|
||||
//--- delete request after use
|
||||
DatabaseFinalize(request);
|
||||
|
||||
//--- close the database
|
||||
DatabaseClose(db);
|
||||
}
|
||||
/*
|
||||
Results:
|
||||
Deals in the trading history: 2741
|
||||
The first 10 deals:
|
||||
[ticket] [order_ticket] [position_ticket] [time] [type] [entry] [symbol] [volume] [price] [profit] [swap] [commission] [magic] [reason]
|
||||
[0] 34429573 0 0 2019.09.05 22:39:59 2 0 "" 0.00000 0.00000 2000.00000 0.0000 0.00000 0 0
|
||||
[1] 34432127 51447238 51447238 2019.09.06 06:00:03 0 0 "USDCAD" 0.10000 1.32320 0.00000 0.0000 -0.16000 500 3
|
||||
[2] 34432128 51447239 51447239 2019.09.06 06:00:03 1 0 "USDCHF" 0.10000 0.98697 0.00000 0.0000 -0.16000 500 3
|
||||
[3] 34432450 51447565 51447565 2019.09.06 07:00:00 0 0 "EURUSD" 0.10000 1.10348 0.00000 0.0000 -0.18000 400 3
|
||||
[4] 34432456 51447571 51447571 2019.09.06 07:00:00 1 0 "AUDUSD" 0.10000 0.68203 0.00000 0.0000 -0.11000 400 3
|
||||
[5] 34432879 51448053 51448053 2019.09.06 08:00:00 1 0 "USDCHF" 0.10000 0.98701 0.00000 0.0000 -0.16000 600 3
|
||||
[6] 34432888 51448064 51448064 2019.09.06 08:00:00 0 0 "USDJPY" 0.10000 106.96200 0.00000 0.0000 -0.16000 600 3
|
||||
[7] 34435147 51450470 51450470 2019.09.06 10:30:00 1 0 "EURUSD" 0.10000 1.10399 0.00000 0.0000 -0.18000 100 3
|
||||
[8] 34435152 51450476 51450476 2019.09.06 10:30:00 0 0 "GBPUSD" 0.10000 1.23038 0.00000 0.0000 -0.20000 100 3
|
||||
[9] 34435154 51450479 51450479 2019.09.06 10:30:00 1 0 "EURJPY" 0.10000 118.12000 0.00000 0.0000 -0.18000 200 3
|
||||
|
||||
The first 10 trades:
|
||||
[time_in] [ticket] [type] [volume] [symbol] [price_in] [time_out] [price_out] [commission] [swap] [profit]
|
||||
[0] 2019.09.06 06:00:03 51447238 0 0.10000 "USDCAD" 1.32320 2019.09.06 18:00:00 1.31761 -0.32000 0.00000 -42.43000
|
||||
[1] 2019.09.06 06:00:03 51447239 1 0.10000 "USDCHF" 0.98697 2019.09.06 18:00:00 0.98641 -0.32000 0.00000 5.68000
|
||||
[2] 2019.09.06 07:00:00 51447565 0 0.10000 "EURUSD" 1.10348 2019.09.09 03:30:00 1.10217 -0.36000 -1.31000 -13.10000
|
||||
[3] 2019.09.06 07:00:00 51447571 1 0.10000 "AUDUSD" 0.68203 2019.09.09 03:30:00 0.68419 -0.22000 0.03000 -21.60000
|
||||
[4] 2019.09.06 08:00:00 51448053 1 0.10000 "USDCHF" 0.98701 2019.09.06 18:00:01 0.98640 -0.32000 0.00000 6.18000
|
||||
[5] 2019.09.06 08:00:00 51448064 0 0.10000 "USDJPY" 106.96200 2019.09.06 18:00:01 106.77000 -0.32000 0.00000 -17.98000
|
||||
[6] 2019.09.06 10:30:00 51450470 1 0.10000 "EURUSD" 1.10399 2019.09.06 14:30:00 1.10242 -0.36000 0.00000 15.70000
|
||||
[7] 2019.09.06 10:30:00 51450476 0 0.10000 "GBPUSD" 1.23038 2019.09.06 14:30:00 1.23040 -0.40000 0.00000 0.20000
|
||||
[8] 2019.09.06 10:30:00 51450479 1 0.10000 "EURJPY" 118.12000 2019.09.06 14:30:00 117.94100 -0.36000 0.00000 16.73000
|
||||
[9] 2019.09.06 10:30:00 51450480 0 0.10000 "GBPJPY" 131.65300 2019.09.06 14:30:01 131.62500 -0.40000 0.00000 -2.62000
|
||||
Filling the TRADES table took 12.51 milliseconds
|
||||
*/
|
||||
//+------------------------------------------------------------------+
|
||||
//| Creates the DEALS table |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CreateTableDeals(int database)
|
||||
{
|
||||
//--- if the DEALS table already exists, delete it
|
||||
if(!DeleteTable(database, "DEALS"))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
//--- check if the table exists
|
||||
if(!DatabaseTableExists(database, "DEALS"))
|
||||
//--- create the table
|
||||
if(!DatabaseExecute(database, "CREATE TABLE DEALS("
|
||||
"ID INT KEY NOT NULL,"
|
||||
"ORDER_ID INT NOT NULL,"
|
||||
"POSITION_ID INT NOT NULL,"
|
||||
"TIME INT NOT NULL,"
|
||||
"TYPE INT NOT NULL,"
|
||||
"ENTRY INT NOT NULL,"
|
||||
"SYMBOL CHAR(10),"
|
||||
"VOLUME REAL,"
|
||||
"PRICE REAL,"
|
||||
"PROFIT REAL,"
|
||||
"SWAP REAL,"
|
||||
"COMMISSION REAL,"
|
||||
"MAGIC INT,"
|
||||
"REASON INT );"))
|
||||
{
|
||||
Print("DB: create the DEALS table failed with code ", GetLastError());
|
||||
return(false);
|
||||
}
|
||||
//--- the table has been successfully created
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deletes a table with the specified name from the database |
|
||||
//+------------------------------------------------------------------+
|
||||
bool DeleteTable(int database, string table_name)
|
||||
{
|
||||
if(!DatabaseExecute(database, "DROP TABLE IF EXISTS "+table_name))
|
||||
{
|
||||
Print("Failed to drop the DEALS table with code ", GetLastError());
|
||||
return(false);
|
||||
}
|
||||
//--- the table has been successfully deleted
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds deals to the database table |
|
||||
//+------------------------------------------------------------------+
|
||||
bool InsertDeals(int database)
|
||||
{
|
||||
//--- Auxiliary variables
|
||||
ulong deal_ticket; // deal ticket
|
||||
long order_ticket; // the ticket of the order by which the deal was executed
|
||||
long position_ticket; // ID of the position to which the deal belongs
|
||||
datetime time; // deal execution time
|
||||
long type ; // deal type
|
||||
long entry ; // deal direction
|
||||
string symbol; // the symbol fro which the deal was executed
|
||||
double volume; // operation volume
|
||||
double price; // price
|
||||
double profit; // financial result
|
||||
double swap; // swap
|
||||
double commission; // commission
|
||||
long magic; // Magic number (Expert Advisor ID)
|
||||
long reason; // deal execution reason or source
|
||||
//--- go through all deals and add them to the database
|
||||
bool failed=false;
|
||||
int deals=HistoryDealsTotal();
|
||||
// --- lock the database before executing transactions
|
||||
DatabaseTransactionBegin(database);
|
||||
for(int i=0; i<deals; i++)
|
||||
{
|
||||
deal_ticket= HistoryDealGetTicket(i);
|
||||
order_ticket= HistoryDealGetInteger(deal_ticket, DEAL_ORDER);
|
||||
position_ticket=HistoryDealGetInteger(deal_ticket, DEAL_POSITION_ID);
|
||||
time= (datetime)HistoryDealGetInteger(deal_ticket, DEAL_TIME);
|
||||
type= HistoryDealGetInteger(deal_ticket, DEAL_TYPE);
|
||||
entry= HistoryDealGetInteger(deal_ticket, DEAL_ENTRY);
|
||||
symbol= HistoryDealGetString(deal_ticket, DEAL_SYMBOL);
|
||||
volume= HistoryDealGetDouble(deal_ticket, DEAL_VOLUME);
|
||||
price= HistoryDealGetDouble(deal_ticket, DEAL_PRICE);
|
||||
profit= HistoryDealGetDouble(deal_ticket, DEAL_PROFIT);
|
||||
swap= HistoryDealGetDouble(deal_ticket, DEAL_SWAP);
|
||||
commission= HistoryDealGetDouble(deal_ticket, DEAL_COMMISSION);
|
||||
magic= HistoryDealGetInteger(deal_ticket, DEAL_MAGIC);
|
||||
reason= HistoryDealGetInteger(deal_ticket, DEAL_REASON);
|
||||
//--- add each deal to the table using the following request
|
||||
string request_text=StringFormat("INSERT INTO DEALS (ID,ORDER_ID,POSITION_ID,TIME,TYPE,ENTRY,SYMBOL,VOLUME,PRICE,PROFIT,SWAP,COMMISSION,MAGIC,REASON)"
|
||||
"VALUES (%d, %d, %d, %d, %d, %d, '%s', %G, %G, %G, %G, %G, %d, %d)",
|
||||
deal_ticket, order_ticket, position_ticket, time, type, entry, symbol, volume, price, profit, swap, commission, magic, reason);
|
||||
if(!DatabaseExecute(database, request_text))
|
||||
{
|
||||
PrintFormat("%s: failed to insert deal #%d with code %d", __FUNCTION__, deal_ticket, GetLastError());
|
||||
PrintFormat("i=%d: deal #%d %s", i, deal_ticket, symbol);
|
||||
failed=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//--- check for transaction execution errors
|
||||
if(failed)
|
||||
{
|
||||
//--- roll back all transactions and unlock the database
|
||||
DatabaseTransactionRollback(database);
|
||||
PrintFormat("%s: DatabaseExecute() failed with code %d", __FUNCTION__, GetLastError());
|
||||
return(false);
|
||||
}
|
||||
//--- all transactions have been performed successfully - record changes and unlock the database
|
||||
DatabaseTransactionCommit(database);
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Creates the TRADES table |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CreateTableTrades(int database)
|
||||
{
|
||||
//--- if the TRADES table already exists, delete it
|
||||
if(!DeleteTable(database, "TRADES"))
|
||||
return(false);
|
||||
//--- check if the table exists
|
||||
if(!DatabaseTableExists(database, "TRADES"))
|
||||
//--- create the table
|
||||
if(!DatabaseExecute(database, "CREATE TABLE TRADES("
|
||||
"TIME_IN INT NOT NULL,"
|
||||
"TICKET INT NOT NULL,"
|
||||
"TYPE INT NOT NULL,"
|
||||
"VOLUME REAL,"
|
||||
"SYMBOL CHAR(10),"
|
||||
"PRICE_IN REAL,"
|
||||
"TIME_OUT INT NOT NULL,"
|
||||
"PRICE_OUT REAL,"
|
||||
"COMMISSION REAL,"
|
||||
"SWAP REAL,"
|
||||
"PROFIT REAL);"))
|
||||
{
|
||||
Print("DB: create the TRADES table failed with code ", GetLastError());
|
||||
return(false);
|
||||
}
|
||||
//--- the table has been successfully created
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
```
|
||||
|
||||
See also
|
||||
|
||||
[DatabaseExecute](/en/docs/database/databaseexecute), [DatabaseFinalize](/en/docs/database/databasefinalize)
|
||||
@@ -0,0 +1,290 @@
|
||||
# DatabaseReset
|
||||
|
||||
Resets a request, like after calling [DatabasePrepare()](/en/docs/database/databaseprepare).
|
||||
|
||||
```
|
||||
int DatabaseReset(
|
||||
int request // request handle received in DatabasePrepare
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
request
|
||||
|
||||
[in] The handle of the request obtained in [DatabasePrepare()](/en/docs/database/databaseprepare).
|
||||
|
||||
Return Value
|
||||
|
||||
Return true if successful, otherwise false. To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) - invalid database handle;
|
||||
- SQLite error codes starting with ERR_DATABASE_ERROR(5601).
|
||||
|
||||
Note
|
||||
|
||||
The DatabaseReset() function is intended for multiple execution of a request with different parameter values. For example, when adding data to the table in bulk using the INSERT command, a custom set of field values should be formed for each entry.
|
||||
|
||||
Unlike [DatabasePrepare()](/en/docs/database/databaseprepare), the DatabaseReset() call does not compile the string with SQL commands into a new request, therefore DatabaseReset() is executed much faster than DatabasePrepare().
|
||||
|
||||
DatabaseReset() is used together with the [DatabaseBind()](/en/docs/database/databasebind) functions and/or [DatabaseBindArray()](/en/docs/database/databasebindarray) if the request parameter values should be changed after executing [DatabaseRead()](/en/docs/database/databaseread). This means that before setting new values of the request parameters (before the block of DatabaseBind/DatabaseBindArray calls), DatabaseReset() should be called to reset it. The parametrized request itself should be created using [DatabasePrepare()](/en/docs/database/databaseprepare).
|
||||
|
||||
Just like DatabasePrepare(), DatabaseReset() does not make a database request. A direct request execution is performed when calling [DatabaseRead()](/en/docs/database/databaseread) or [DatabaseReadBind()](/en/docs/database/databasereadbind).
|
||||
|
||||
DatabaseReset() call does not lead to resetting parameter values in the request if they were set by calling DatabaseBind()/DatabaseBindArray(), i.e. the parameters retain their values. Thus, the value of only a single parameter can be changed. There is no need to set all request parameters anew after calling DatabaseReset().
|
||||
|
||||
A handle of a request removed using [DatabaseFinalize()](/en/docs/database/databasefinalize) cannot be passed to DatabaseReset(). This will result in an error.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
//+------------------------------------------------------------------+
|
||||
//| Script program start function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnStart()
|
||||
{
|
||||
//--- create or open a database
|
||||
string filename="symbols.sqlite";
|
||||
int db=DatabaseOpen(filename, DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE);
|
||||
if(db==INVALID_HANDLE)
|
||||
{
|
||||
Print("DB: ", filename, " open failed with code ", GetLastError());
|
||||
return;
|
||||
}
|
||||
else
|
||||
Print("Database: ", filename, " opened successfully");
|
||||
//--- if the SYMBOLS table exists, delete it
|
||||
if(DatabaseTableExists(db, "SYMBOLS"))
|
||||
{
|
||||
//--- delete the table
|
||||
if(!DatabaseExecute(db, "DROP TABLE SYMBOLS"))
|
||||
{
|
||||
Print("Failed to drop table SYMBOLS with code ", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
}
|
||||
//--- create the SYMBOLS table
|
||||
if(!DatabaseExecute(db, "CREATE TABLE SYMBOLS("
|
||||
"NAME TEXT NOT NULL,"
|
||||
"DESCRIPTION TEXT ,"
|
||||
"PATH TEXT ,"
|
||||
"SPREAD INT ,"
|
||||
"POINT REAL NOT NULL,"
|
||||
"DIGITS INT NOT NULL,"
|
||||
"JSON BLOB );"))
|
||||
{
|
||||
Print("DB: ", filename, " create table failed with code ", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
//--- display the list of all fields in the SYMBOLS table
|
||||
if(DatabasePrint(db, "PRAGMA TABLE_INFO(SYMBOLS)", 0)<0)
|
||||
{
|
||||
PrintFormat("DatabasePrint(\"PRAGMA TABLE_INFO(SYMBOLS)\") failed, error code=%d at line %d", GetLastError(), __LINE__);
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
|
||||
//--- create a parametrized request to add symbols to the SYMBOLS table
|
||||
string sql="INSERT INTO SYMBOLS (NAME,DESCRIPTION,PATH,SPREAD,POINT,DIGITS,JSON)"
|
||||
" VALUES (?1,?2,?3,?4,?5,?6,?7);"; // request parameters
|
||||
int request=DatabasePrepare(db, sql);
|
||||
if(request==INVALID_HANDLE)
|
||||
{
|
||||
PrintFormat("DatabasePrepare() failed with code=%d", GetLastError());
|
||||
Print("SQL request: ", sql);
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
|
||||
//--- go through all the symbols and add them to the SYMBOLS table
|
||||
int symbols=SymbolsTotal(false);
|
||||
bool request_error=false;
|
||||
DatabaseTransactionBegin(db);
|
||||
for(int i=0; i<symbols; i++)
|
||||
{
|
||||
//--- set the values of the parameters before adding a symbol
|
||||
ResetLastError();
|
||||
string symbol=SymbolName(i, false);
|
||||
if(!DatabaseBind(request, 0, symbol))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed at line %d with code=%d", __LINE__, GetLastError());
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
//--- if the previous DatabaseBind() call was successful, set the next parameter
|
||||
if(!DatabaseBind(request, 1, SymbolInfoString(symbol, SYMBOL_DESCRIPTION)))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed at line %d with code=%d", __LINE__, GetLastError());
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
if(!DatabaseBind(request, 2, SymbolInfoString(symbol, SYMBOL_PATH)))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed at line %d with code=%d", __LINE__, GetLastError());
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
if(!DatabaseBind(request, 3, SymbolInfoInteger(symbol, SYMBOL_SPREAD)))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed at line %d with code=%d", __LINE__, GetLastError());
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
if(!DatabaseBind(request, 4, SymbolInfoDouble(symbol, SYMBOL_POINT)))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed at line %d with code=%d", __LINE__, GetLastError());
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
if(!DatabaseBind(request, 5, SymbolInfoInteger(symbol, SYMBOL_DIGITS)))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed at line %d with code=%d", __LINE__, GetLastError());
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
if(!DatabaseBind(request, 6, GetSymBolAsJson(symbol)))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed at line %d with code=%d", __LINE__, GetLastError());
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
|
||||
//--- execute a request for inserting the entry and check for an error
|
||||
if(!DatabaseRead(request)&&(GetLastError()!=ERR_DATABASE_NO_MORE_DATA))
|
||||
{
|
||||
PrintFormat("DatabaseRead() failed with code=%d", GetLastError());
|
||||
DatabaseFinalize(request);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
PrintFormat("%d: added %s", i+1, symbol);
|
||||
//--- reset the request before the next parameter update
|
||||
if(!DatabaseReset(request))
|
||||
{
|
||||
PrintFormat("DatabaseReset() failed with code=%d", GetLastError());
|
||||
DatabaseFinalize(request);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
} //--- done going through all the symbols
|
||||
|
||||
//--- transactions status
|
||||
if(request_error)
|
||||
{
|
||||
PrintFormat("Table SYMBOLS: failed to add %d symbols", symbols);
|
||||
DatabaseTransactionRollback(db);
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
DatabaseTransactionCommit(db);
|
||||
PrintFormat("Table SYMBOLS: added %d symbols",symbols);
|
||||
}
|
||||
|
||||
//--- save the SYMBOLS table to a CSV file
|
||||
string csv_filename="symbols.csv";
|
||||
if(DatabaseExport(db, "SELECT * FROM SYMBOLS", csv_filename,
|
||||
DATABASE_EXPORT_HEADER|DATABASE_EXPORT_INDEX|DATABASE_EXPORT_QUOTED_STRINGS, ";"))
|
||||
Print("Database: table SYMBOLS saved in ", csv_filename);
|
||||
else
|
||||
Print("Database: DatabaseExport(\"SELECT * FROM SYMBOLS\") failed with code", GetLastError());
|
||||
|
||||
//--- close the database file and inform of that
|
||||
DatabaseClose(db);
|
||||
PrintFormat("Database: %s created and closed", filename);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Return a symbol specification as JSON |
|
||||
//+------------------------------------------------------------------+
|
||||
string GetSymBolAsJson(string symbol)
|
||||
{
|
||||
//--- indents
|
||||
string indent1=Indent(1);
|
||||
string indent2=Indent(2);
|
||||
string indent3=Indent(3);
|
||||
//---
|
||||
int digits=(int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
|
||||
string json="{"+
|
||||
"\n"+indent1+"\"ConfigSymbols\":["+
|
||||
"\n"+indent2+"{"+
|
||||
"\n"+indent3+"\"Symbol\":\""+symbol+"\","+
|
||||
"\n"+indent3+"\"Path\":\""+SymbolInfoString(symbol, SYMBOL_PATH)+"\","+
|
||||
"\n"+indent3+"\"CurrencyBase\":\""+SymbolInfoString(symbol, SYMBOL_CURRENCY_BASE)+"\","+
|
||||
"\n"+indent3+"\"CurrencyProfit\":\""+SymbolInfoString(symbol, SYMBOL_CURRENCY_PROFIT)+"\","+
|
||||
"\n"+indent3+"\"CurrencyMargin\":\""+SymbolInfoString(symbol, SYMBOL_CURRENCY_MARGIN)+"\","+
|
||||
"\n"+indent3+"\"ColorBackground\":\""+ColorToString((color)SymbolInfoInteger(symbol, SYMBOL_BACKGROUND_COLOR))+"\","+
|
||||
"\n"+indent3+"\"Digits\":\""+IntegerToString(SymbolInfoInteger(symbol, SYMBOL_DIGITS))+"\","+
|
||||
"\n"+indent3+"\"Point\":\""+DoubleToString(SymbolInfoDouble(symbol, SYMBOL_POINT), digits)+"\","+
|
||||
"\n"+indent3+"\"TickBookDepth\":\""+IntegerToString(SymbolInfoInteger(symbol, SYMBOL_TICKS_BOOKDEPTH))+"\","+
|
||||
"\n"+indent3+"\"ChartMode\":\""+IntegerToString(SymbolInfoInteger(symbol, SYMBOL_CHART_MODE))+"\","+
|
||||
"\n"+indent3+"\"TradeMode\":\""+IntegerToString(SymbolInfoInteger(symbol, SYMBOL_TRADE_EXEMODE))+"\","+
|
||||
"\n"+indent3+"\"TradeCalcMode\":\""+IntegerToString(SymbolInfoInteger(symbol, SYMBOL_TRADE_CALC_MODE))+"\","+
|
||||
"\n"+indent3+"\"OrderMode\":\""+IntegerToString(SymbolInfoInteger(symbol, SYMBOL_ORDER_MODE))+"\","+
|
||||
"\n"+indent3+"\"CalculationMode\":\""+IntegerToString(SymbolInfoInteger(symbol, SYMBOL_TRADE_CALC_MODE))+"\","+
|
||||
"\n"+indent3+"\"ExecutionMode\":\""+IntegerToString(SymbolInfoInteger(symbol, SYMBOL_TRADE_EXEMODE))+"\","+
|
||||
"\n"+indent3+"\"ExpirationMode\":\""+IntegerToString(SymbolInfoInteger(symbol, SYMBOL_EXPIRATION_MODE))+"\","+
|
||||
"\n"+indent3+"\"FillFlags\":\""+IntegerToString(SymbolInfoInteger(symbol, SYMBOL_FILLING_MODE))+"\","+
|
||||
"\n"+indent3+"\"ExpirFlags\":\""+IntegerToString(SymbolInfoInteger(symbol, SYMBOL_EXPIRATION_MODE))+"\","+
|
||||
"\n"+indent3+"\"Spread\":\""+IntegerToString(SymbolInfoInteger(symbol, SYMBOL_SPREAD))+"\","+
|
||||
"\n"+indent3+"\"TickValue\":\""+StringFormat("%G", (SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE)))+"\","+
|
||||
"\n"+indent3+"\"TickSize\":\""+StringFormat("%G", (SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE)))+"\","+
|
||||
"\n"+indent3+"\"ContractSize\":\""+StringFormat("%G",(SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE)))+"\","+
|
||||
"\n"+indent3+"\"StopsLevel\":\""+IntegerToString(SymbolInfoInteger(symbol, SYMBOL_TRADE_STOPS_LEVEL))+"\","+
|
||||
"\n"+indent3+"\"VolumeMin\":\""+StringFormat("%G",(SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN)))+"\","+
|
||||
"\n"+indent3+"\"VolumeMax\":\""+StringFormat("%G",(SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX)))+"\","+
|
||||
"\n"+indent3+"\"VolumeStep\":\""+StringFormat("%G",(SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP)))+"\","+
|
||||
"\n"+indent3+"\"VolumeLimit\":\""+StringFormat("%G",(SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP)))+"\","+
|
||||
"\n"+indent3+"\"SwapMode\":\""+IntegerToString(SymbolInfoInteger(symbol, SYMBOL_SWAP_MODE))+"\","+
|
||||
"\n"+indent3+"\"SwapLong\":\""+StringFormat("%G",(SymbolInfoDouble(symbol, SYMBOL_SWAP_LONG)))+"\","+
|
||||
"\n"+indent3+"\"SwapShort\":\""+StringFormat("%G",(SymbolInfoDouble(symbol, SYMBOL_SWAP_SHORT)))+"\","+
|
||||
"\n"+indent3+"\"Swap3Day\":\""+IntegerToString(SymbolInfoInteger(symbol, SYMBOL_SWAP_ROLLOVER3DAYS))+"\""+
|
||||
"\n"+indent2+"}"+
|
||||
"\n"+indent1+"]"+
|
||||
"\n}";
|
||||
return(json);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Form an indent made of spaces |
|
||||
//+------------------------------------------------------------------+
|
||||
string Indent(const int number, const int characters=3)
|
||||
{
|
||||
int length=number*characters;
|
||||
string indent=NULL;
|
||||
StringInit(indent, length, ' ');
|
||||
return indent;
|
||||
}
|
||||
/*
|
||||
Result:
|
||||
Database: symbols.sqlite opened successfully
|
||||
#| cid name type notnull dflt_value pk
|
||||
-+-------------------------------------------
|
||||
1| 0 NAME TEXT 1 0
|
||||
2| 1 DESCRIPTION TEXT 0 0
|
||||
3| 2 PATH TEXT 0 0
|
||||
4| 3 SPREAD INT 0 0
|
||||
5| 4 POINT REAL 1 0
|
||||
6| 5 DIGITS INT 1 0
|
||||
7| 6 JSON BLOB 0 0
|
||||
1: added EURUSD
|
||||
2: added GBPUSD
|
||||
3: added USDCHF
|
||||
...
|
||||
82: added USDCOP
|
||||
83: added USDARS
|
||||
84: added USDCLP
|
||||
Table SYMBOLS: added 84 symbols
|
||||
Database: table SYMBOLS saved in symbols.csv
|
||||
Database: symbols.sqlite created and closed
|
||||
*/
|
||||
|
||||
|
||||
```
|
||||
|
||||
See also
|
||||
|
||||
[DatabasePrepare](/en/docs/database/databaseprepare), [DatabaseBind](/en/docs/database/databasebind), [DatabaseBindArray](/en/docs/database/databasebindarray), [DatabaseFinalize](/en/docs/database/databasefinalize)
|
||||
@@ -0,0 +1,250 @@
|
||||
# DatabaseBind
|
||||
|
||||
Sets a parameter value in a request.
|
||||
|
||||
```
|
||||
bool DatabaseBind(
|
||||
int request, // the handle of a request created in DatabasePrepare
|
||||
int index, // the parameter index in the request
|
||||
T value // the value of a simple type parameter
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
request
|
||||
|
||||
[in] The handle of a request created in [DatabasePrepare()](/en/docs/database/databaseprepare).
|
||||
|
||||
index
|
||||
|
||||
[in] The parameter index in the request a value should be set for. The numbering starts with zero.
|
||||
|
||||
value
|
||||
|
||||
[in] The value to be set. Extended types: bool, char, uchar, short, ushart, int, uint, color, datetime, long, ulong, float, double, string.
|
||||
|
||||
Return Value
|
||||
|
||||
Returns true if successful, otherwise - false. To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_INVALID_PARAMETER (4003) – unsupported type;
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) - invalid database handle;
|
||||
- ERR_DATABASE_NOT_READY (5128) - cannot use the function to make a request at the moment. The request is being executed or already complete. [DatabaseReset()](/en/docs/database/databasereset) should be called.
|
||||
|
||||
Note
|
||||
|
||||
The function is used in case an SQL request contains "?" or "?N" parameterizable values where N means the parameter index (starting from one). At the same time, parameters indexing in DatabaseBind() starts from zero.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
INSERT INTO table VALUES (?,?,?)
|
||||
SELECT * FROM table WHERE id=?
|
||||
|
||||
```
|
||||
|
||||
The function may be called immediately after a parametrized request is created in [DatabasePrepare()](/en/docs/database/databaseprepare) or after the request is reset using [DatabaseReset()](/en/docs/database/databasereset).
|
||||
|
||||
Use this function together with [DatabaseReset()](/en/docs/database/databasereset) to execute the request as many times as needed with different parameter values.
|
||||
|
||||
The function is designed to work with simple type parameters. If a parameter should be checked against an array, use the [DatabaseBindArray()](/en/docs/database/databasebindarray) function.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
//+------------------------------------------------------------------+
|
||||
//| Script program start function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnStart()
|
||||
{
|
||||
MqlTick ticks[];
|
||||
//--- remember the start time before receiving the ticks
|
||||
uint start=GetTickCount();
|
||||
//--- request the tick history per day
|
||||
ulong to=TimeCurrent()*1000;
|
||||
ulong from=to-PeriodSeconds(PERIOD_D1)*1000;
|
||||
if(CopyTicksRange(_Symbol, ticks, COPY_TICKS_ALL, from, to)==-1)
|
||||
{
|
||||
PrintFormat("%s: CopyTicksRange(%s - %s) failed, error=%d",
|
||||
_Symbol, TimeToString(datetime(from/1000)), TimeToString(datetime(to/1000)), _LastError);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- how many ticks were received and how much time it took to receive them
|
||||
PrintFormat("%s: CopyTicksRange received %d ticks in %d ms (from %s to %s)",
|
||||
_Symbol, ArraySize(ticks), GetTickCount()-start,
|
||||
TimeToString(datetime(from/1000)), TimeToString(datetime(to/1000)));
|
||||
}
|
||||
|
||||
//--- set the file name for storing the database
|
||||
string filename=_Symbol+" "+TimeToString(datetime(from/1000))+" - "+TimeToString(datetime(to/1000))+".sqlite";
|
||||
StringReplace(filename, ":", "."); // ":" character is not allowed in file names
|
||||
//--- open/create the database in the common terminal folder
|
||||
int db=DatabaseOpen(filename, DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE | DATABASE_OPEN_COMMON);
|
||||
if(db==INVALID_HANDLE)
|
||||
{
|
||||
Print("Database: ", filename, " open failed with code ", GetLastError());
|
||||
return;
|
||||
}
|
||||
else
|
||||
Print("Database: ", filename, " opened successfully");
|
||||
|
||||
//--- create the TICKS table
|
||||
if(!DatabaseExecute(db, "CREATE TABLE TICKS("
|
||||
"SYMBOL CHAR(10),"
|
||||
"TIME INT NOT NULL,"
|
||||
"BID REAL,"
|
||||
"ASK REAL,"
|
||||
"LAST REAL,"
|
||||
"VOLUME INT,"
|
||||
"TIME_MSC INT,"
|
||||
"VOLUME_REAL REAL);"))
|
||||
{
|
||||
Print("DB: ", filename, " create table TICKS failed with code ", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
//--- display the list of all fields in the TICKS table
|
||||
if(DatabasePrint(db, "PRAGMA TABLE_INFO(TICKS)", 0)<0)
|
||||
{
|
||||
PrintFormat("DatabasePrint(\"PRAGMA TABLE_INFO(TICKS)\") failed, error code=%d at line %d", GetLastError(), __LINE__);
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
//--- create a parametrized request to add ticks to the TICKS table
|
||||
string sql="INSERT INTO TICKS (SYMBOL,TIME,BID,ASK,LAST,VOLUME,TIME_MSC,VOLUME_REAL)"
|
||||
" VALUES (?1,?2,?3,?4,?5,?6,?7,?8)"; // request parameters
|
||||
int request=DatabasePrepare(db, sql);
|
||||
if(request==INVALID_HANDLE)
|
||||
{
|
||||
PrintFormat("DatabasePrepare() failed with code=%d", GetLastError());
|
||||
Print("SQL request: ", sql);
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
//--- set the value of the first request parameter
|
||||
DatabaseBind(request, 0, _Symbol);
|
||||
//--- remember the start time before adding ticks to the TICKS table
|
||||
start=GetTickCount();
|
||||
DatabaseTransactionBegin(db);
|
||||
int total=ArraySize(ticks);
|
||||
bool request_error=false;
|
||||
for(int i=0; i<total; i++)
|
||||
{
|
||||
//--- set the values of the remaining parameters before adding the entry
|
||||
ResetLastError();
|
||||
if(!DatabaseBind(request, 1, ticks[i].time))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed with code=%d", GetLastError());
|
||||
PrintFormat("Tick #%d line=%d", i+1, __LINE__);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
//--- if the previous DatabaseBind() call was successful, set the next parameter
|
||||
if(!request_error && !DatabaseBind(request, 2, ticks[i].bid))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed with code=%d", GetLastError());
|
||||
PrintFormat("Tick #%d line=%d", i+1, __LINE__);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
if(!request_error && !DatabaseBind(request, 3, ticks[i].ask))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed with code=%d", GetLastError());
|
||||
PrintFormat("Tick #%d line=%d", i+1, __LINE__);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
if(!request_error && !DatabaseBind(request, 4, ticks[i].last))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed with code=%d", GetLastError());
|
||||
PrintFormat("Tick #%d line=%d", i+1, __LINE__);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
if(!request_error && !DatabaseBind(request, 5, ticks[i].volume))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed with code=%d", GetLastError());
|
||||
PrintFormat("Tick #%d line=%d", i+1, __LINE__);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
if(!request_error && !DatabaseBind(request, 6, ticks[i].time_msc))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed with code=%d", GetLastError());
|
||||
PrintFormat("Tick #%d line=%d", i+1, __LINE__);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
if(!request_error && !DatabaseBind(request, 7, ticks[i].volume_real))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed with code=%d", GetLastError());
|
||||
PrintFormat("Tick #%d line=%d", i+1, __LINE__);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
|
||||
//--- execute a request for inserting the entry and check for an error
|
||||
if(!request_error && !DatabaseRead(request) && (GetLastError()!=ERR_DATABASE_NO_MORE_DATA))
|
||||
{
|
||||
PrintFormat("DatabaseRead() failed with code=%d", GetLastError());
|
||||
DatabaseFinalize(request);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
//--- reset the request before the next parameter update
|
||||
if(!request_error && !DatabaseReset(request))
|
||||
{
|
||||
PrintFormat("DatabaseReset() failed with code=%d", GetLastError());
|
||||
DatabaseFinalize(request);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
} //--- done going through all the ticks
|
||||
|
||||
//--- transactions status
|
||||
if(request_error)
|
||||
{
|
||||
PrintFormat("Table TICKS: failed to add %d ticks ", ArraySize(ticks));
|
||||
DatabaseTransactionRollback(db);
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
DatabaseTransactionCommit(db);
|
||||
PrintFormat("Table TICKS: added %d ticks in %d ms",
|
||||
ArraySize(ticks), GetTickCount()-start);
|
||||
}
|
||||
|
||||
//--- close the database file and inform of that
|
||||
DatabaseClose(db);
|
||||
PrintFormat("Database: %s created and closed", filename);
|
||||
}
|
||||
/*
|
||||
Result:
|
||||
EURUSD: CopyTicksRange received 268061 ticks in 47 ms (from 2020.03.18 12:40 to 2020.03.19 12:40)
|
||||
Database: EURUSD 2020.03.18 12.40 - 2020.03.19 12.40.sqlite opened successfully
|
||||
#| cid name type notnull dflt_value pk
|
||||
-+-----------------------------------------------
|
||||
1| 0 SYMBOL CHAR(10) 0 0
|
||||
2| 1 TIME INT 1 0
|
||||
3| 2 BID REAL 0 0
|
||||
4| 3 ASK REAL 0 0
|
||||
5| 4 LAST REAL 0 0
|
||||
6| 5 VOLUME INT 0 0
|
||||
7| 6 TIME_MSC INT 0 0
|
||||
8| 7 VOLUME_REAL REAL 0 0
|
||||
Table TICKS: added 268061 ticks in 797 ms
|
||||
Database: EURUSD 2020.03.18 12.40 - 2020.03.19 12.40.sqlite created and closed
|
||||
OnCalculateCorrelation=0.87 2020.03.19 13:00: EURUSD vs GBPUSD PERIOD_M30
|
||||
*/
|
||||
|
||||
```
|
||||
|
||||
See also
|
||||
|
||||
[DatabasePrepare](/en/docs/database/databaseprepare), [DatabaseReset](/en/docs/database/databasereset), [DatabaseRead](/en/docs/database/databaseread), [DatabaseBindArray](/en/docs/database/databasebindarray)
|
||||
@@ -0,0 +1,232 @@
|
||||
# DatabaseBindArray
|
||||
|
||||
Sets an array as a parameter value.
|
||||
|
||||
```
|
||||
bool DatabaseBind(
|
||||
int request, // the handle of a request created in DatabasePrepare
|
||||
int index, // the parameter index in the request
|
||||
T& array[] // parameter value as an array
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
request
|
||||
|
||||
[in] The handle of a request created in [DatabasePrepare()](/en/docs/database/databaseprepare).
|
||||
|
||||
index
|
||||
|
||||
[in] The parameter index in the request a value should be set for. The numbering starts with zero.
|
||||
|
||||
array[]
|
||||
|
||||
[in] The array to be set as a request parameter value.
|
||||
|
||||
Return Value
|
||||
|
||||
Returns true if successful, otherwise - false. To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_INVALID_PARAMETER (4003) – unsupported type;
|
||||
- ERR_ARRAY_BAD_SIZE (4011) - array size in bytes exceeds INT_MAX;
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) - invalid database handle;
|
||||
- ERR_DATABASE_NOT_READY (5128) - cannot use the function to make a request at the moment (the request is being executed or already complete, DatabaseReset should be called).
|
||||
|
||||
Note
|
||||
|
||||
The function is used in case an SQL request contains "?" or "?N" parameterizable values where N means the parameter index (starting from one). At the same time, parameters indexing in DatabaseBindArray() starts from zero.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
INSERT INTO table VALUES (?,?,?)
|
||||
|
||||
```
|
||||
|
||||
The function may be called immediately after a parametrized request is created in [DatabasePrepare()](/en/docs/database/databaseprepare) or after the request is reset using [DatabaseReset()](/en/docs/database/databasereset).
|
||||
|
||||
Use this function together with [DatabaseReset()](/en/docs/database/databasereset) to execute the request as many times as needed with different parameter values.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
//+------------------------------------------------------------------+
|
||||
//| Script program start function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnStart()
|
||||
{
|
||||
//--- open the dialog for selecting files with the DAT extension
|
||||
string selected_files[];
|
||||
if(!FileSelectDialog("Select files to download", NULL,
|
||||
"Data files (*.dat)|*.dat|All files (*.*)|*.*",
|
||||
FSD_ALLOW_MULTISELECT, selected_files, "tester.dat")>0)
|
||||
{
|
||||
Print("Files not selected. Exit");
|
||||
return;
|
||||
}
|
||||
//--- get the size of files
|
||||
ulong filesize[];
|
||||
int filehandle[];
|
||||
int files=ArraySize(selected_files);
|
||||
ArrayResize(filesize, files);
|
||||
ZeroMemory(filesize);
|
||||
ArrayResize(filehandle, files);
|
||||
double total_size=0;
|
||||
for(int i=0; i<files; i++)
|
||||
{
|
||||
filehandle[i]=FileOpen(selected_files[i], FILE_READ|FILE_BIN);
|
||||
if(filehandle[i]!=INVALID_HANDLE)
|
||||
{
|
||||
filesize[i]=FileSize(filehandle[i]);
|
||||
//PrintFormat("%d, %s handle=%d %d bytes", i, selected_files[i], filehandle[i], filesize[i]);
|
||||
total_size+=(double)filesize[i];
|
||||
}
|
||||
}
|
||||
//--- check the common size of files
|
||||
if(total_size==0)
|
||||
{
|
||||
PrintFormat("Total files size is 0. Exit");
|
||||
return;
|
||||
}
|
||||
|
||||
//--- create or open the database in the common terminal folder
|
||||
string filename="dat_files.sqlite";
|
||||
int db=DatabaseOpen(filename, DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE);
|
||||
if(db==INVALID_HANDLE)
|
||||
{
|
||||
Print("DB: ", filename, " open failed with code ", GetLastError());
|
||||
return;
|
||||
}
|
||||
else
|
||||
Print("Database: ", filename, " opened successfully");
|
||||
//--- if the FILES table exists, delete it
|
||||
if(DatabaseTableExists(db, "FILES"))
|
||||
{
|
||||
//--- delete the table
|
||||
if(!DatabaseExecute(db, "DROP TABLE FILES"))
|
||||
{
|
||||
Print("Failed to drop table FILES with code ", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
}
|
||||
//--- create the FILES table
|
||||
if(!DatabaseExecute(db, "CREATE TABLE FILES("
|
||||
"NAME TEXT NOT NULL,"
|
||||
"SIZE INT NOT NULL,"
|
||||
"PERCENT_SIZE REAL NOT NULL,"
|
||||
"DATA BLOB NOT NULL);"))
|
||||
{
|
||||
Print("DB: failed to create table FILES with code ", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
//--- display the list of all fields in the FILES table
|
||||
if(DatabasePrint(db, "PRAGMA TABLE_INFO(FILES)", 0)<0)
|
||||
{
|
||||
PrintFormat("DatabasePrint(\"PRAGMA TABLE_INFO(FILES)\") failed, error code=%d at line %d", GetLastError(), __LINE__);
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
|
||||
//--- create a parametrized request to add files to the FILES table
|
||||
string sql="INSERT INTO FILES (NAME,SIZE,PERCENT_SIZE,DATA)"
|
||||
" VALUES (?1,?2,?3,?4);"; // request parameters
|
||||
int request=DatabasePrepare(db, sql);
|
||||
if(request==INVALID_HANDLE)
|
||||
{
|
||||
PrintFormat("DatabasePrepare() failed with code=%d", GetLastError());
|
||||
Print("SQL request: ", sql);
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
|
||||
//--- go through all the files and add them to the FILES table
|
||||
bool request_error=false;
|
||||
DatabaseTransactionBegin(db);
|
||||
int count=0;
|
||||
uint size;
|
||||
for(int i=0; i<files; i++)
|
||||
{
|
||||
if(filehandle[i]!=INVALID_HANDLE)
|
||||
{
|
||||
char data[];
|
||||
size=FileReadArray(filehandle[i], data);
|
||||
if(size==0)
|
||||
{
|
||||
PrintFormat("FileReadArray(%s) failed with code %d", selected_files[i], GetLastError());
|
||||
continue;
|
||||
}
|
||||
|
||||
count++;
|
||||
//--- set the values of the parameters before adding the file to the table
|
||||
if(!DatabaseBind(request, 0, selected_files[i]))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed at line %d with code=%d", __LINE__, GetLastError());
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
if(!DatabaseBind(request, 1, size))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed at line %d with code=%d", __LINE__, GetLastError());
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
if(!DatabaseBind(request, 2, double(size)*100./total_size))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed at line %d with code=%d", __LINE__, GetLastError());
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
if(!DatabaseBindArray(request, 3, data))
|
||||
{
|
||||
PrintFormat("DatabaseBind() failed at line %d with code=%d", __LINE__, GetLastError());
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
//--- execute a request for inserting the entry and check for an error
|
||||
if(!DatabaseRead(request)&&(GetLastError()!=ERR_DATABASE_NO_MORE_DATA))
|
||||
{
|
||||
PrintFormat("DatabaseRead() failed with code=%d", GetLastError());
|
||||
DatabaseFinalize(request);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
PrintFormat("%d. %s: %d bytes", count, selected_files[i],size);
|
||||
//--- reset the request before the next parameter update
|
||||
if(!DatabaseReset(request))
|
||||
{
|
||||
PrintFormat("DatabaseReset() failed with code=%d", GetLastError());
|
||||
DatabaseFinalize(request);
|
||||
request_error=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- transactions status
|
||||
if(request_error)
|
||||
{
|
||||
PrintFormat("Table FILES: failed to add %d files", count);
|
||||
DatabaseTransactionRollback(db);
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
DatabaseTransactionCommit(db);
|
||||
PrintFormat("Table FILES: added %d files", count);
|
||||
}
|
||||
|
||||
//--- close the database file and inform of that
|
||||
DatabaseClose(db);
|
||||
PrintFormat("Database: %s created and closed", filename);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
See also
|
||||
|
||||
[DatabasePrepare](/en/docs/database/databaseprepare), [DatabaseReset](/en/docs/database/databasereset), [DatabaseRead](/en/docs/database/databaseread), [DatabaseBind](/en/docs/database/databasebind)
|
||||
@@ -0,0 +1,31 @@
|
||||
# DatabaseRead
|
||||
|
||||
Moves to the next entry as a result of a request.
|
||||
|
||||
```
|
||||
bool DatabaseRead(
|
||||
int request // request handle received in DatabasePrepare
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
request
|
||||
|
||||
[in] Request handle received in [DatabasePrepare()](/en/docs/database/databaseprepare).
|
||||
|
||||
Return Value
|
||||
|
||||
Return true if successful, otherwise false. To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_INVALID_PARAMETER (4003) – no table name specified (empty string or NULL);
|
||||
- ERR_WRONG_STRING_PARAMETER (5040) – error converting a request into a UTF-8 string;
|
||||
- ERR_DATABASE_INTERNAL (5120) – internal database error;
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) – invalid database handle;
|
||||
- ERR_DATABASE_EXECUTE (5124) – request execution error;
|
||||
- ERR_DATABASE_NO_MORE_DATA (5126) – no table exists (not an error, normal completion).
|
||||
|
||||
See also
|
||||
|
||||
[DatabasePrepare](/en/docs/database/databaseprepare), [DatabaseReadBind](/en/docs/database/databasereadbind)
|
||||
@@ -0,0 +1,169 @@
|
||||
# DatabaseReadBind
|
||||
|
||||
Moves to the next record and reads data into the structure from it.
|
||||
|
||||
```
|
||||
bool DatabaseReadBind(
|
||||
int request, // the handle of a request created in DatabasePrepare
|
||||
void& struct_object // the reference to the structure for reading the record
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
request
|
||||
|
||||
[in] The handle of a request created in [DatabasePrepare()](/en/docs/database/databaseprepare).
|
||||
|
||||
struct_object
|
||||
|
||||
[out] The reference to the structure the data from the current record is to be read to. The structure should only have numerical types and/or strings (arrays are not allowed) as members and cannot be a descendant.
|
||||
|
||||
Return Value
|
||||
|
||||
Return true if successful, otherwise false. To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_INVALID_PARAMETER (4003) – no table name specified (empty string or NULL);
|
||||
- ERR_WRONG_STRING_PARAMETER (5040) – error converting a request into a UTF-8 string;
|
||||
- ERR_DATABASE_INTERNAL (5120) – internal database error;
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) – invalid database handle;
|
||||
- ERR_DATABASE_EXECUTE (5124) – request execution error;
|
||||
- ERR_DATABASE_NO_MORE_DATA (5126) – no table exists (not an error, normal completion).
|
||||
|
||||
Note
|
||||
|
||||
A number of fields in the struct_object structure should not exceed [DatabaseColumnsCount()](/en/docs/database/databasecolumnscount). If the number of fields in the struct_object structure is less than the number of fields in the record, the partial reading is performed. The remaining data can be explicitly obtained using the corresponding [DatabaseColumnText()](/en/docs/database/databasecolumntext), [DatabaseColumnInteger()](/en/docs/database/databasecolumninteger) and other functions.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
struct Person
|
||||
{
|
||||
int id;
|
||||
string name;
|
||||
int age;
|
||||
string address;
|
||||
double salary;
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Script program start function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnStart()
|
||||
{
|
||||
int db;
|
||||
string filename="company.sqlite";
|
||||
//--- open
|
||||
db=DatabaseOpen(filename, DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE |DATABASE_OPEN_COMMON);
|
||||
if(db==INVALID_HANDLE)
|
||||
{
|
||||
Print("DB: ", filename, " open failed with code ", GetLastError());
|
||||
return;
|
||||
}
|
||||
//--- if the table COMPANY exists then drop the table
|
||||
if(DatabaseTableExists(db, "COMPANY"))
|
||||
{
|
||||
//--- delete the table
|
||||
if(!DatabaseExecute(db, "DROP TABLE COMPANY"))
|
||||
{
|
||||
Print("Failed to drop table COMPANY with code ", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
}
|
||||
//--- create table
|
||||
if(!DatabaseExecute(db, "CREATE TABLE COMPANY("
|
||||
"ID INT PRIMARY KEY NOT NULL,"
|
||||
"NAME TEXT NOT NULL,"
|
||||
"AGE INT NOT NULL,"
|
||||
"ADDRESS CHAR(50),"
|
||||
"SALARY REAL );"))
|
||||
{
|
||||
Print("DB: ", filename, " create table failed with code ", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
|
||||
//--- insert data
|
||||
if(!DatabaseExecute(db, "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (1, 'Paul', 32, 'California', 25000.00 ); "
|
||||
"INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (2, 'Allen', 25, 'Texas', 15000.00 ); "
|
||||
"INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (3, 'Teddy', 23, 'Norway', 20000.00 );"
|
||||
"INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (4, 'Mark', 25, 'Rich-Mond ', 65000.00 );"))
|
||||
{
|
||||
Print("DB: ", filename, " insert failed with code ", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
|
||||
//--- prepare the request
|
||||
int request=DatabasePrepare(db, "SELECT * FROM COMPANY WHERE SALARY>15000");
|
||||
if(request==INVALID_HANDLE)
|
||||
{
|
||||
Print("DB: ", filename, " request failed with code ", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
//--- print records
|
||||
Person person;
|
||||
Print("Persons with salary > 15000:");
|
||||
for(int i=0; DatabaseReadBind(request, person); i++)
|
||||
Print(i, ": ", person.id, " ", person.name, " ", person.age, " ", person.address, " ", person.salary);
|
||||
//--- delete request after use
|
||||
DatabaseFinalize(request);
|
||||
|
||||
Print("Some statistics:");
|
||||
//--- prepare new request about total salary
|
||||
request=DatabasePrepare(db, "SELECT SUM(SALARY) FROM COMPANY");
|
||||
if(request==INVALID_HANDLE)
|
||||
{
|
||||
Print("DB: ", filename, " request failed with code ", GetLastError());
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
while(DatabaseRead(request))
|
||||
{
|
||||
double total_salary;
|
||||
DatabaseColumnDouble(request, 0, total_salary);
|
||||
Print("Total salary=", total_salary);
|
||||
}
|
||||
//--- delete request after use
|
||||
DatabaseFinalize(request);
|
||||
|
||||
//--- prepare new request about average salary
|
||||
request=DatabasePrepare(db, "SELECT AVG(SALARY) FROM COMPANY");
|
||||
if(request==INVALID_HANDLE)
|
||||
{
|
||||
Print("DB: ", filename, " request failed with code ", GetLastError());
|
||||
ResetLastError();
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
while(DatabaseRead(request))
|
||||
{
|
||||
double aver_salary;
|
||||
DatabaseColumnDouble(request, 0, aver_salary);
|
||||
Print("Average salary=", aver_salary);
|
||||
}
|
||||
//--- delete request after use
|
||||
DatabaseFinalize(request);
|
||||
|
||||
//--- close database
|
||||
DatabaseClose(db);
|
||||
}
|
||||
//+-------------------------------------------------------------------
|
||||
/*
|
||||
Output:
|
||||
Persons with salary > 15000:
|
||||
0: 1 Paul 32 California 25000.0
|
||||
1: 3 Teddy 23 Norway 20000.0
|
||||
2: 4 Mark 25 Rich-Mond 65000.0
|
||||
Some statistics:
|
||||
Total salary=125000.0
|
||||
Average salary=31250.0
|
||||
*/
|
||||
|
||||
```
|
||||
|
||||
See also
|
||||
|
||||
[DatabasePrepare](/en/docs/database/databaseprepare), [DatabaseRead](/en/docs/database/databaseread)
|
||||
@@ -0,0 +1,28 @@
|
||||
# DatabaseFinalize
|
||||
|
||||
Removes a request created in [DatabasePrepare(](/en/docs/database/databaseprepare)).
|
||||
|
||||
```
|
||||
void DatabaseFinalize(
|
||||
int request // request handle received in DatabasePrepare
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
request
|
||||
|
||||
[in] Request handle received in DatabasePrepare().
|
||||
|
||||
Return Value
|
||||
|
||||
None.
|
||||
|
||||
Note
|
||||
|
||||
If the handle is invalid, the function sets the ERR_DATABASE_INVALID_HANDLE error. You can check the error using GetLastError().
|
||||
|
||||
See also
|
||||
|
||||
[DatabasePrepare](/en/docs/database/databaseprepare), [DatabaseExecute](/en/docs/database/databaseexecute)
|
||||
@@ -0,0 +1,234 @@
|
||||
# DatabaseTransactionBegin
|
||||
|
||||
Starts transaction execution.
|
||||
|
||||
```
|
||||
bool DatabaseTransactionBegin(
|
||||
int database // database handle received in DatabaseOpen
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
database
|
||||
|
||||
[in] Database handle received in [DatabaseOpen()](/en/docs/database/databaseopen).
|
||||
|
||||
Return true if successful, otherwise false. To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_INTERNAL_ERROR (4001) – critical runtime error;
|
||||
- ERR_INVALID_PARAMETER (4003) – sql parameter contains an empty string;
|
||||
- ERR_NOT_ENOUGH_MEMORY (4004) – insufficient memory;
|
||||
- ERR_WRONG_STRING_PARAMETER (5040) – error converting a request into a UTF-8 string;
|
||||
- ERR_DATABASE_INTERNAL (5120) – internal database error;
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) – invalid database handle;
|
||||
- ERR_DATABASE_EXECUTE (5124) – request execution error.
|
||||
|
||||
Note
|
||||
|
||||
The DatabaseTransactionBegin() function should be called before a transaction execution. Any transaction should start with calling DatabaseTransactionBegin() and end with calling DatabaseTransactionCommit().
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
//+------------------------------------------------------------------+
|
||||
//| Script program start function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnStart()
|
||||
{
|
||||
//--- create the file name
|
||||
string filename=AccountInfoString(ACCOUNT_SERVER) +"_"+IntegerToString(AccountInfoInteger(ACCOUNT_LOGIN))+".sqlite";
|
||||
//--- open/create the database in the common terminal folder
|
||||
int db=DatabaseOpen(filename, DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE | DATABASE_OPEN_COMMON);
|
||||
if(db==INVALID_HANDLE)
|
||||
{
|
||||
Print("DB: ", filename, " open failed with code ", GetLastError());
|
||||
return;
|
||||
}
|
||||
//--- if the DEALS table already exists, delete it
|
||||
if(!DeleteTable(db, "DEALS"))
|
||||
{
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
//--- create the DEALS table
|
||||
if(!CreateTableDeals(db))
|
||||
{
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
//--- request the entire trading history
|
||||
datetime from_date=0;
|
||||
datetime to_date=TimeCurrent();
|
||||
//--- request the history of deals in the specified interval
|
||||
HistorySelect(from_date, to_date);
|
||||
int deals_total=HistoryDealsTotal();
|
||||
PrintFormat("Deals in the trading history: %d ", deals_total);
|
||||
|
||||
//--- measure the transaction execution speed using DatabaseTransactionBegin/DatabaseTransactionCommit
|
||||
ulong start=GetMicrosecondCount();
|
||||
bool fast_transactions=true;
|
||||
InsertDeals(db, fast_transactions);
|
||||
double fast_transactions_time=double(GetMicrosecondCount()-start)/1000;
|
||||
PrintFormat("Transations WITH DatabaseTransactionBegin/DatabaseTransactionCommit: time=%.1f milliseconds", fast_transactions_time);
|
||||
|
||||
//--- delete the DEALS table, and then create it again
|
||||
if(!DeleteTable(db, "DEALS"))
|
||||
{
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
//--- create a new DEALS table
|
||||
if(!CreateTableDeals(db))
|
||||
{
|
||||
DatabaseClose(db);
|
||||
return;
|
||||
}
|
||||
|
||||
//--- test again, this time without using DatabaseTransactionBegin/DatabaseTransactionCommit
|
||||
fast_transactions=false;
|
||||
start=GetMicrosecondCount();
|
||||
InsertDeals(db, fast_transactions);
|
||||
double slow_transactions_time=double(GetMicrosecondCount()-start)/1000;
|
||||
PrintFormat("Transations WITHOUT DatabaseTransactionBegin/DatabaseTransactionCommit: time=%.1f milliseconds", slow_transactions_time);
|
||||
//--- report gain in time
|
||||
PrintFormat("Use of DatabaseTransactionBegin/DatabaseTransactionCommit provided acceleration by %.1f times", double(slow_transactions_time)/fast_transactions_time);
|
||||
//--- close the database
|
||||
DatabaseClose(db);
|
||||
}
|
||||
/*
|
||||
Results:
|
||||
Deals in the trading history: 2737
|
||||
Transations WITH DatabaseTransactionBegin/DatabaseTransactionCommit: time=48.5 milliseconds
|
||||
Transations WITHOUT DatabaseTransactionBegin/DatabaseTransactionCommit: time=25818.9 milliseconds
|
||||
Use of DatabaseTransactionBegin/DatabaseTransactionCommit provided acceleration by 532.8 times
|
||||
*/
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deletes a table with the specified name from the database |
|
||||
//+------------------------------------------------------------------+
|
||||
bool DeleteTable(int database, string table_name)
|
||||
{
|
||||
if(!DatabaseExecute(database, "DROP TABLE IF EXISTS "+table_name))
|
||||
{
|
||||
Print("Failed to drop table with code ", GetLastError());
|
||||
return(false);
|
||||
}
|
||||
//--- the table has been successfully deleted
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Creates the DEALS table |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CreateTableDeals(int database)
|
||||
{
|
||||
//--- check if the table exists
|
||||
if(!DatabaseTableExists(database, "DEALS"))
|
||||
//--- create the table
|
||||
if(!DatabaseExecute(database, "CREATE TABLE DEALS("
|
||||
"ID INT KEY NOT NULL,"
|
||||
"ORDER_ID INT NOT NULL,"
|
||||
"POSITION_ID INT NOT NULL,"
|
||||
"TIME INT NOT NULL,"
|
||||
"TYPE INT NOT NULL,"
|
||||
"ENTRY INT NOT NULL,"
|
||||
"SYMBOL CHAR(10),"
|
||||
"VOLUME REAL,"
|
||||
"PRICE REAL,"
|
||||
"PROFIT REAL,"
|
||||
"SWAP REAL,"
|
||||
"COMMISSION REAL,"
|
||||
"MAGIC INT,"
|
||||
"REASON INT );"))
|
||||
{
|
||||
Print("DB: create the table DEALS failed with code ", GetLastError());
|
||||
return(false);
|
||||
}
|
||||
//--- the table has been successfully created
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds deals to the database table |
|
||||
//+------------------------------------------------------------------+
|
||||
bool InsertDeals(int database, bool begintransaction=true)
|
||||
{
|
||||
//--- Auxiliary variables
|
||||
ulong deal_ticket; // deal ticket
|
||||
long order_ticket; // the ticket of the order by which the deal was executed
|
||||
long position_ticket; // ID of the position to which the deal belongs
|
||||
datetime time; // deal execution time
|
||||
long type ; // deal type
|
||||
long entry ; // deal direction
|
||||
string symbol; // the symbol fro which the deal was executed
|
||||
double volume; // operation volume
|
||||
double price; // price
|
||||
double profit; // financial result
|
||||
double swap; // swap
|
||||
double commission; // commission
|
||||
long magic; // Magic number
|
||||
long reason; // deal execution reason or source
|
||||
//--- go through all deals and add to the database
|
||||
bool failed=false;
|
||||
int deals=HistoryDealsTotal();
|
||||
//--- if fast transaction performance method is used
|
||||
if(begintransaction)
|
||||
{
|
||||
// --- lock the database before executing transactions
|
||||
DatabaseTransactionBegin(database);
|
||||
}
|
||||
for(int i=0; i<deals; i++)
|
||||
{
|
||||
deal_ticket= HistoryDealGetTicket(i);
|
||||
order_ticket= HistoryDealGetInteger(deal_ticket, DEAL_ORDER);
|
||||
position_ticket=HistoryDealGetInteger(deal_ticket, DEAL_POSITION_ID);
|
||||
time= (datetime)HistoryDealGetInteger(deal_ticket, DEAL_TIME);
|
||||
type= HistoryDealGetInteger(deal_ticket, DEAL_TYPE);
|
||||
entry= HistoryDealGetInteger(deal_ticket, DEAL_ENTRY);
|
||||
symbol= HistoryDealGetString(deal_ticket, DEAL_SYMBOL);
|
||||
volume= HistoryDealGetDouble(deal_ticket, DEAL_VOLUME);
|
||||
price= HistoryDealGetDouble(deal_ticket, DEAL_PRICE);
|
||||
profit= HistoryDealGetDouble(deal_ticket, DEAL_PROFIT);
|
||||
swap= HistoryDealGetDouble(deal_ticket, DEAL_SWAP);
|
||||
commission= HistoryDealGetDouble(deal_ticket, DEAL_COMMISSION);
|
||||
magic= HistoryDealGetInteger(deal_ticket, DEAL_MAGIC);
|
||||
reason= HistoryDealGetInteger(deal_ticket, DEAL_REASON);
|
||||
//--- add each deal using the following request
|
||||
string request_text=StringFormat("INSERT INTO DEALS (ID,ORDER_ID,POSITION_ID,TIME,TYPE,ENTRY,SYMBOL,VOLUME,PRICE,PROFIT,SWAP,COMMISSION,MAGIC,REASON)"
|
||||
"VALUES (%d, %d, %d, %d, %d, %d, '%s', %G, %G, %G, %G, %G, %d, %d)",
|
||||
deal_ticket, order_ticket, position_ticket, time, type, entry, symbol, volume, price, profit, swap, commission, magic, reason);
|
||||
if(!DatabaseExecute(database, request_text))
|
||||
{
|
||||
PrintFormat("%s: failed to insert deal #%dwith code %d", __FUNCTION__, deal_ticket, GetLastError());
|
||||
PrintFormat("i=%d: deal #%d %s", i, deal_ticket, symbol);
|
||||
failed=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//--- check for transaction execution errors
|
||||
if(failed)
|
||||
{
|
||||
//--- if fast transaction performance method is used
|
||||
if(begintransaction)
|
||||
{
|
||||
//--- roll back all transactions and unlock the database
|
||||
DatabaseTransactionRollback(database);
|
||||
}
|
||||
Print("%s: DatabaseExecute() failed with code ", __FUNCTION__, GetLastError());
|
||||
return(false);
|
||||
}
|
||||
//--- if fast transaction performance method is used
|
||||
if(begintransaction)
|
||||
{
|
||||
//--- all transactions have been performed successfully - record changes and unlock the database
|
||||
DatabaseTransactionCommit(database);
|
||||
}
|
||||
//--- successful completion
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
```
|
||||
|
||||
See also
|
||||
|
||||
[DatabaseExecute](/en/docs/database/databaseexecute),[ DatabasePrepare](/en/docs/database/databaseprepare), [DatabaseTransactionCommit](/en/docs/database/databasetransactioncommit), [DatabaseTransactionRollback](/en/docs/database/databasetransactionrollback)
|
||||
@@ -0,0 +1,34 @@
|
||||
# DatabaseTransactionCommit
|
||||
|
||||
Completes transaction execution.
|
||||
|
||||
```
|
||||
bool DatabaseTransactionCommit(
|
||||
int database // database handle received in DatabaseOpen
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
database
|
||||
|
||||
[in] Database handle received in [DatabaseOpen()](/en/docs/database/databaseopen).
|
||||
|
||||
Return true if successful, otherwise false. To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_INTERNAL_ERROR (4001) – critical runtime error;
|
||||
- ERR_INVALID_PARAMETER (4003) – sql parameter contains an empty string;
|
||||
- ERR_NOT_ENOUGH_MEMORY (4004) – insufficient memory;
|
||||
- ERR_WRONG_STRING_PARAMETER (5040) – error converting a request into a UTF-8 string;
|
||||
- ERR_DATABASE_INTERNAL (5120) – internal database error;
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) – invalid database handle;
|
||||
- ERR_DATABASE_EXECUTE (5124) – request execution error.
|
||||
|
||||
Note
|
||||
|
||||
The DatabaseTransactionCommit() function completes all transactions executed after calling the [DatabaseBeginTransaction()](/en/docs/database/databasetransactionbegin) function. Any transaction should start with calling DatabaseTransactionBegin() and end with calling DatabaseTransactionCommit() for successful completion.
|
||||
|
||||
See also
|
||||
|
||||
[DatabaseExecute](/en/docs/database/databaseexecute),[ DatabasePrepare](/en/docs/database/databaseprepare), [DatabaseTransactionBegin](/en/docs/database/databasetransactionbegin), [DatabaseTransactionRollback](/en/docs/database/databasetransactionrollback)
|
||||
@@ -0,0 +1,34 @@
|
||||
# DatabaseTransactionRollback
|
||||
|
||||
Rolls back transactions.
|
||||
|
||||
```
|
||||
bool DatabaseTransactionRollback(
|
||||
int database // database handle received in DatabaseOpen
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
database
|
||||
|
||||
[in] Database handle received in [DatabaseOpen()](/en/docs/database/databaseopen).
|
||||
|
||||
Return true if successful, otherwise false. To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_INTERNAL_ERROR (4001) – critical runtime error;
|
||||
- ERR_INVALID_PARAMETER (4003) – sql parameter contains an empty string;
|
||||
- ERR_NOT_ENOUGH_MEMORY (4004) – insufficient memory;
|
||||
- ERR_WRONG_STRING_PARAMETER (5040) – error converting a request into a UTF-8 string;
|
||||
- ERR_DATABASE_INTERNAL (5120) – internal database error;
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) – invalid database handle;
|
||||
- ERR_DATABASE_EXECUTE (5124) – request execution error.
|
||||
|
||||
Note
|
||||
|
||||
DatabaseTransactionRollback() call cancels all transactions executed after calling the DatabaseTransactionBegin() function. The DatabaseTransactionRollback() function is necessary for rolling back changes in a database in case errors occur when executing a transaction.
|
||||
|
||||
See also
|
||||
|
||||
[DatabaseExecute](/en/docs/database/databaseexecute),[ DatabasePrepare](/en/docs/database/databaseprepare), [DatabaseTransactionBegin](/en/docs/database/databasetransactionbegin), [DatabaseTransactionCommit](/en/docs/database/databasetransactioncommit)
|
||||
@@ -0,0 +1,30 @@
|
||||
# DatabaseColumnsCount
|
||||
|
||||
Gets the number of fields in a request.
|
||||
|
||||
```
|
||||
int DatabaseColumnsCount(
|
||||
int request // request handle received in DatabasePrepare
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
request
|
||||
|
||||
[in] Request handle received in [DatabasePrepare()](/en/docs/database/databaseprepare).
|
||||
|
||||
Return Value
|
||||
|
||||
Number of fields or -1 in case of an error. To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) - invalid request handle.
|
||||
|
||||
Note
|
||||
|
||||
There is no need to call the [DatabaseRead()](/en/docs/database/databaseread) function to get the number of fields of a request created in DatabasePrepare(). For the remaining DatabaseColumnXXX() functions, DatabaseRead() should be preliminarily called.
|
||||
|
||||
See also
|
||||
|
||||
[DatabasePrepare](/en/docs/database/databaseprepare), [DatabaseFinalize](/en/docs/database/databasefinalize), [DatabaseClose](/en/docs/database/databaseclose)
|
||||
@@ -0,0 +1,41 @@
|
||||
# DatabaseColumnName
|
||||
|
||||
Gets a field name by index.
|
||||
|
||||
```
|
||||
bool DatabaseColumnName(
|
||||
int request, // request handle received in DatabasePrepare
|
||||
int column, // field index in the request
|
||||
string& name // the reference to the variable for receiving the field name
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
request
|
||||
|
||||
[in] Request handle received in [DatabasePrepare()](/en/docs/database/databaseprepare).
|
||||
|
||||
column
|
||||
|
||||
[in] Field index in the request. Field numbering starts from zero and cannot exceed [DatabaseColumnsCount()](/en/docs/database/databasecolumnscount) - 1.
|
||||
|
||||
name
|
||||
|
||||
[out] Variable for writing the field name.
|
||||
|
||||
Return Value
|
||||
|
||||
Return true if successful, otherwise false. To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) – invalid request handle;
|
||||
- ERR_DATABASE_NO_MORE_DATA (5126) – 'column' index exceeds DatabaseColumnsCount() -1.
|
||||
|
||||
Note
|
||||
|
||||
The value can be obtained only if at least one [DatabaseRead()](/en/docs/database/databaseread) call has been preliminarily made for 'request'.
|
||||
|
||||
See also
|
||||
|
||||
[DatabasePrepare](/en/docs/database/databaseprepare), [DatabaseColumnsCount](/en/docs/database/databasecolumnscount), [DatabaseColumnType](/en/docs/database/databasecolumntype)
|
||||
@@ -0,0 +1,47 @@
|
||||
# DatabaseColumnType
|
||||
|
||||
Gets a field type by index.
|
||||
|
||||
```
|
||||
ENUM_DATABASE_FIELD_TYPE DatabaseColumnType(
|
||||
int request, // request handle received in DatabasePrepare
|
||||
int column // field index in the request
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
request
|
||||
|
||||
[in] Request handle received in [DatabasePrepare()](/en/docs/database/databaseprepare).
|
||||
|
||||
column
|
||||
|
||||
[in] Field index in the request. Field numbering starts from zero and cannot exceed [DatabaseColumnsCount()](/en/docs/database/databasecolumnscount) - 1.
|
||||
|
||||
Return Value
|
||||
|
||||
Return the field type from the [ENUM_DATABASE_FIELD_TYPE](/en/docs/database/databasecolumntype#enum_database_field_type) enumeration. To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) – invalid request handle;
|
||||
- ERR_DATABASE_NO_MORE_DATA (5126) – 'column' index exceeds DatabaseColumnsCount() -1.
|
||||
|
||||
Note
|
||||
|
||||
The value can be obtained only if at least one [DatabaseRead()](/en/docs/database/databaseread) call has been preliminarily made for 'request'.
|
||||
|
||||
ENUM_DATABASE_FIELD_TYPE
|
||||
|
||||
| ID | Description |
|
||||
| --- | --- |
|
||||
| DATABASE_FIELD_TYPE_INVALID | Error getting type, the error code can be obtained using int GetLastError() |
|
||||
| DATABASE_FIELD_TYPE_INTEGER | Integer type |
|
||||
| DATABASE_FIELD_TYPE_FLOAT | Real type |
|
||||
| DATABASE_FIELD_TYPE_TEXT | String type |
|
||||
| DATABASE_FIELD_TYPE_BLOB | Binary type |
|
||||
| DATABASE_FIELD_TYPE_NULL | Special NULL type |
|
||||
|
||||
See also
|
||||
|
||||
[DatabasePrepare](/en/docs/database/databaseprepare), [DatabaseColumnsCount](/en/docs/database/databasecolumnscount), [DatabaseColumnName](/en/docs/database/databasecolumnname)
|
||||
@@ -0,0 +1,36 @@
|
||||
# DatabaseColumnSize
|
||||
|
||||
Gets a field size in bytes.
|
||||
|
||||
```
|
||||
int DatabaseColumnSize(
|
||||
int request, // request handle received in DatabasePrepare
|
||||
int column // field index in the request
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
request
|
||||
|
||||
[in] Request handle received in [DatabasePrepare()](/en/docs/database/databaseprepare).
|
||||
|
||||
column
|
||||
|
||||
[in] Field index in the request. Field numbering starts from zero and cannot exceed [DatabaseColumnsCount()](/en/docs/database/databasecolumnscount) - 1.
|
||||
|
||||
Return Value
|
||||
|
||||
If successful, the field size in bytes is returned, otherwise -1. To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) – invalid request handle;
|
||||
- ERR_DATABASE_NO_MORE_DATA (5126) – 'column' index exceeds DatabaseColumnsCount() -1.
|
||||
|
||||
Note
|
||||
|
||||
The value can be obtained only if at least one [DatabaseRead()](/en/docs/database/databaseread) call has been preliminarily made for 'request'.
|
||||
|
||||
See also
|
||||
|
||||
[DatabasePrepare](/en/docs/database/databaseprepare), [DatabaseColumnBlob](/en/docs/database/databasecolumnblob), [DatabaseColumnsCount](/en/docs/database/databasecolumnscount), [DatabaseColumnName](/en/docs/database/databasecolumnname), [DatabaseColumnType](/en/docs/database/databasecolumntype)
|
||||
@@ -0,0 +1,43 @@
|
||||
# DatabaseColumnText
|
||||
|
||||
Gets a field value as a string from the current record.
|
||||
|
||||
```
|
||||
bool DatabaseColumnText(
|
||||
int request, // request handle received in DatabasePrepare
|
||||
int column, // field index in the request
|
||||
string& value // the reference to the variable for receiving the value
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
request
|
||||
|
||||
[in] Request handle received in [DatabasePrepare()](/en/docs/database/databaseprepare).
|
||||
|
||||
column
|
||||
|
||||
[in] Field index in the request. Field numbering starts from zero and cannot exceed [DatabaseColumnsCount()](/en/docs/database/databasecolumnscount) - 1.
|
||||
|
||||
value
|
||||
|
||||
[out] Reference to the variable for writing the field value.
|
||||
|
||||
Return Value
|
||||
|
||||
Return true if successful, otherwise false. To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) – invalid request handle;
|
||||
- ERR_DATABASE_NO_MORE_DATA (5126) – 'column' index exceeds DatabaseColumnsCount() -1.
|
||||
|
||||
Note
|
||||
|
||||
The value can be obtained only if at least one [DatabaseRead()](/en/docs/database/databaseread) call has been preliminarily made for 'request'.
|
||||
|
||||
To read the value from the next record, call [DatabaseRead()](/en/docs/database/databaseread) preliminarily.
|
||||
|
||||
See also
|
||||
|
||||
[DatabasePrepare](/en/docs/database/databaseprepare), [DatabaseColumnsCount](/en/docs/database/databasecolumnscount), [DatabaseColumnType](/en/docs/database/databasecolumntype), [DatabaseColumnName](/en/docs/database/databasecolumnname)
|
||||
@@ -0,0 +1,43 @@
|
||||
# DatabaseColumnInteger
|
||||
|
||||
Gets the int type value from the current record.
|
||||
|
||||
```
|
||||
bool DatabaseColumnInteger(
|
||||
int request, // request handle received in DatabasePrepare
|
||||
int column, // field index in the request
|
||||
int& value // the reference to the variable for receiving the value
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
request
|
||||
|
||||
[in] Request handle received in [DatabasePrepare()](/en/docs/database/databaseprepare).
|
||||
|
||||
column
|
||||
|
||||
[in] Field index in the request. Field numbering starts from zero and cannot exceed [DatabaseColumnsCount()](/en/docs/database/databasecolumnscount) - 1.
|
||||
|
||||
value
|
||||
|
||||
[out] Reference to the variable for writing the field value.
|
||||
|
||||
Return Value
|
||||
|
||||
Return true if successful, otherwise false. To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) – invalid request handle;
|
||||
- ERR_DATABASE_NO_MORE_DATA (5126) – 'column' index exceeds DatabaseColumnsCount() -1.
|
||||
|
||||
Note
|
||||
|
||||
The value can be obtained only if at least one [DatabaseRead()](/en/docs/database/databaseread) call has been preliminarily made for 'request'.
|
||||
|
||||
To read the value from the next record, call [DatabaseRead()](/en/docs/database/databaseread) preliminarily.
|
||||
|
||||
See also
|
||||
|
||||
[DatabasePrepare](/en/docs/database/databaseprepare), [DatabaseColumnsCount](/en/docs/database/databasecolumnscount), [DatabaseColumnType](/en/docs/database/databasecolumntype), [DatabaseColumnName](/en/docs/database/databasecolumnname)
|
||||
@@ -0,0 +1,43 @@
|
||||
# DatabaseColumnLong
|
||||
|
||||
Gets the long type value from the current record.
|
||||
|
||||
```
|
||||
bool DatabaseColumnLong(
|
||||
int request, // request handle received in DatabasePrepare
|
||||
int column, // field index in the request
|
||||
long& value // the reference to the variable for receiving the value
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
request
|
||||
|
||||
[in] Request handle received in [DatabasePrepare()](/en/docs/database/databaseprepare).
|
||||
|
||||
column
|
||||
|
||||
[in] Field index in the request. Field numbering starts from zero and cannot exceed [DatabaseColumnsCount()](/en/docs/database/databasecolumnscount) - 1.
|
||||
|
||||
value
|
||||
|
||||
[out] Reference to the variable for writing the field value.
|
||||
|
||||
Return Value
|
||||
|
||||
Return true if successful, otherwise false. To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) – invalid request handle;
|
||||
- ERR_DATABASE_NO_MORE_DATA (5126) – 'column' index exceeds DatabaseColumnsCount() -1.
|
||||
|
||||
Note
|
||||
|
||||
The value can be obtained only if at least one [DatabaseRead()](/en/docs/database/databaseread) call has been preliminarily made for 'request'.
|
||||
|
||||
To read the value from the next record, call [DatabaseRead()](/en/docs/database/databaseread) preliminarily.
|
||||
|
||||
See also
|
||||
|
||||
[DatabasePrepare](/en/docs/database/databaseprepare), [DatabaseColumnsCount](/en/docs/database/databasecolumnscount), [DatabaseColumnType](/en/docs/database/databasecolumntype), [DatabaseColumnName](/en/docs/database/databasecolumnname)
|
||||
@@ -0,0 +1,43 @@
|
||||
# DatabaseColumnDouble
|
||||
|
||||
Gets the double type value from the current record.
|
||||
|
||||
```
|
||||
bool DatabaseColumnDouble(
|
||||
int request, // request handle received in DatabasePrepare
|
||||
int column, // field index in the request
|
||||
double& value // the reference to the variable for receiving the value
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
request
|
||||
|
||||
[in] Request handle received in [DatabasePrepare()](/en/docs/database/databaseprepare).
|
||||
|
||||
column
|
||||
|
||||
[in] Field index in the request. Field numbering starts from zero and cannot exceed [DatabaseColumnsCount()](/en/docs/database/databasecolumnscount) - 1.
|
||||
|
||||
value
|
||||
|
||||
[out] Reference to the variable for writing the field value.
|
||||
|
||||
Return Value
|
||||
|
||||
Return true if successful, otherwise false. To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) – invalid request handle;
|
||||
- ERR_DATABASE_NO_MORE_DATA (5126) – 'column' index exceeds DatabaseColumnsCount() -1.
|
||||
|
||||
Note
|
||||
|
||||
The value can be obtained only if at least one [DatabaseRead()](/en/docs/database/databaseread) call has been preliminarily made for 'request'.
|
||||
|
||||
To read the value from the next record, call [DatabaseRead()](/en/docs/database/databaseread) preliminarily.
|
||||
|
||||
See also
|
||||
|
||||
[DatabasePrepare](/en/docs/database/databaseprepare), [DatabaseColumnsCount](/en/docs/database/databasecolumnscount), [DatabaseColumnType](/en/docs/database/databasecolumntype), [DatabaseColumnName](/en/docs/database/databasecolumnname)
|
||||
@@ -0,0 +1,43 @@
|
||||
# DatabaseColumnBlob
|
||||
|
||||
Gets a field value as an array from the current record.
|
||||
|
||||
```
|
||||
bool DatabaseColumnBlob(
|
||||
int request, // request handle received in DatabasePrepare
|
||||
int column, // field index in the request
|
||||
void& data[] // the reference to the variable for receiving the value
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
Parameters
|
||||
|
||||
request
|
||||
|
||||
[in] Request handle received in [DatabasePrepare()](/en/docs/database/databaseprepare).
|
||||
|
||||
column
|
||||
|
||||
[in] Field index in the request. Field numbering starts from zero and cannot exceed [DatabaseColumnsCount()](/en/docs/database/databasecolumnscount) - 1.
|
||||
|
||||
data[]
|
||||
|
||||
[out] Reference to the array for writing the field value.
|
||||
|
||||
Return Value
|
||||
|
||||
Return true if successful, otherwise false. To get the error code, use GetLastError(), the possible responses are:
|
||||
|
||||
- ERR_DATABASE_INVALID_HANDLE (5121) – invalid request handle;
|
||||
- ERR_DATABASE_NO_MORE_DATA (5126) – 'column' index exceeds DatabaseColumnsCount() -1.
|
||||
|
||||
Note
|
||||
|
||||
The value can be obtained only if at least one [DatabaseRead()](/en/docs/database/databaseread) call has been preliminarily made for 'request'.
|
||||
|
||||
To read the value from the next record, call [DatabaseRead()](/en/docs/database/databaseread) preliminarily.
|
||||
|
||||
See also
|
||||
|
||||
[DatabasePrepare](/en/docs/database/databaseprepare), [DatabaseColumnSize](/en/docs/database/databasecolumnsize), [DatabaseColumnsCount](/en/docs/database/databasecolumnscount), [DatabaseColumnType](/en/docs/database/databasecolumntype), [DatabaseColumnName](/en/docs/database/databasecolumnname)
|
||||
Reference in New Issue
Block a user