MQL 4
MQL 4
MQL4 Reference
MetaQuotes Language 4 (MQL4) is a built-in language for
programming trading strategies. This language is
developed by MetaQuotes Software Corp. based on their
long experience in the creation of online trading
platforms. Using this language, you can create your own
Expert Advisors that make trading management
automated and are perfectly suitable for implementing
your own trading strategies. Besides, using MQL4 you can
create your own technical indicators (custom indicators),
scripts and libraries.
MQL4 contains a large number of functions necessary for
analyzing current and previously received quotes, and has
built-in basic indicators and functions for managing trade
orders and controlling them. The MetaEditor (text editor)
that highlights different constructions of MQL4 language is
used for writing the program code. It helps users to
orientate themselves in the expert system text quite
easily.
The brief guide contains functions, operations, reserved
words, and other language constructions divided into
categories, and allows finding the description of every
used element of the language.
Programs written in MetaQuotes Language 4 have
different features and purposes:
Expert Advisor is a mechanical trading system linked
up to a certain chart. An Expert Advisor starts to run
when an event happens that can be handled by it:
events of initialization and deinitialization, event of a
new tick receipt, a timer event, depth of market
changing event, chart event and custom events. An
Expert Advisor can both inform you about a possibility
to trade and automatically trade on an account sending
orders directly to a trade server. Expert Advisors are
stored in terminal_directory\MQL4\Experts.
Custom Indicator is a technical indicator written
independently in addition to those already integrated
into the client terminal. Like built-in indicators, they
cannot trade automatically and are intended for
implementing of analytical functions only.
Custom indicators are stored in
terminal_directory\MQL4\Indicators
Script is a program intended for a single execution of
some actions. Unlike Expert Advisors, scripts do not
process any actions, except for the start event (this
requires the OnStart handler function in a script).
Scripts are stored in terminal_directory\MQL4\Scripts
Library is a set of custom functions intended for
storing and distributing frequently used blocks of
custom programs. Libraries cannot start executing by
themselves.
Libraries are stored in
terminal_directory\MQL4\Libraries
Include File is a source text of the most frequently
used blocks of custom programs. Such files can be
included into the source texts of Expert Advisors,
scripts, custom indicators, and libraries at the
compiling stage. The use of included files is more
preferable than the use of libraries because of
additional burden occurring at calling library functions.
Include files can be stored in the same directory as a
source file - in this case the #include directive with
double quotes is used. Another place to store include
files is terminal_directory\MQL4\Include, in this case
the #include directive is used with angle brackets.
© 2000-2023, MetaQuotes Ltd
MQL4 Reference / MQL5 features
MQL5 charts
The new generation platform has two times more
timeframes (21 vs 9), as well as the precise time scale. Now
graphical objects are not necessarily linked to bars. Object
anchors can be placed in any position between the chart
bars. Moreover, when switching between timeframes, the
accurate positioning of the control points of the object is
preserved. New built-in indicators and analytical tools have
also been added.
The new OBJ_CHART graphical object is most notable in
terms of the complex technical analysis. It allows creating
an unlimited number of nested charts, set all the necessary
properties (color scheme, timeframe, symbol) and even
impose indicators on them. Thus, a usual price chart can be
turned into a complex analytical tool by quickly switching
between symbols and timeframes in a single mouse click.
If you use several monitors for trading, then you will
certainly appreciate another advantage of the new platform
floating chart windows. Any symbol chart can now be
detached from the terminal window and moved to the
necessary monitor. An example of such a chart is shown in
the image. Add indicators and an EA with the graphical
panel to a floating chart to get a real trading control center.
Floating windows can also be moved and resized from MQL5
programs using the chart properties (CHART_IS_DOCKED and
others).
The third distinctive feature of the fifth generation platform
is the ability to create custom symbols or synthetic indices.
To do that, simply enter the calculation formula or
download files with minute bars or tick history. You can also
work with custom symbols using MQL5 language. The
appropriate functions allow you to automate collecting and
preparing history data, open charts and update them in real
time, as well as test your EAs in the strategy tester using
custom symbols.
Explore MQL5 language features and take your programming
skills to the next level.
MQL4 Reference / MQL5 features / Indicators
MQL5 indicators
In the new terminal, the number of built-in technical
indicators has been increased from 30 to 38, while the
number of drawing styles of custom indicators has been
increased 3 times from 6 to 18. Now custom indicators are
able to use up to 512 indicator buffers. A separate color on
each bar can be specified for color styles.
MQL4 Reference / MQL5 features / MQL5 functions / Common
Functions
Common Functions
General-purpose functions not included into any
specialized group are listed here.
Function Action
Displays a message in a separate
Alert
window
CheckPointer Returns the type of the object pointer
Outputs a comment in the left top
Comment
corner of the chart
Transforms the data from array with
CryptEncode
the specified method
Performs the inverse transformation of
CryptDecode
the data from array
DebugBreak Program breakpoint in debugging
Stops Expert Advisor and unloads it
ExpertRemove
from the chart
GetPointer Returns the object pointer
Returns the number of milliseconds
GetTickCount that have elapsed since the system was
started
Returns the number of microseconds
GetMicrosecondCount that have elapsed since the start of
MQL5 program
Creates, displays a message box and
MessageBox
manages it
Function Action
Returns the number of seconds in the
PeriodSeconds
period
PlaySound Plays a sound file
Print Displays a message in the log
Formats and prints the sets of symbols
PrintFormat and values in a log file in accordance
with a preset format
Sets the value of a predetermined
ResetLastError
variable _LastError to zero
Creates an image resource based on a
ResourceCreate
data set
Deletes dynamically created resource
ResourceFree
(freeing the memory allocated for it)
Reads data from the graphical resource
ResourceReadImage created by ResourceCreate() function
or saved in EX5 file during compilation
ResourceSave Saves a resource into the specified file
Sets the predefined variable _LastError
SetUserError into the value equal to
ERR_USER_ERROR_FIRST + user_error
Sets the code that returns the terminal
SetReturnError process when completing the
operation.
Suspends execution of the current
Sleep Expert Advisor or script within a
specified interval
Commands the terminal to complete
TerminalClose
operation
Function Action
Sets the mode of displaying/hiding
TesterHideIndicators
indicators used in an EA
It returns the value of a specified
TesterStatistics statistic calculated based on testing
results
Gives program operation completion
TesterStop
command when testing
Emulates the operation of money
TesterWithdrawal
withdrawal in the process of testing
Returns a Unicode character by a
TranslateKey
virtual key code
Resets a variable passed to it by
reference. The variable can be of any
ZeroMemory
type, except for classes and structures
that have constructors.
MQL4 Reference / MQL5 features / MQL5 functions / Array Functions
Conversion Functions
This is a group of functions that provide conversion of
data from one format into another.
Function Action
Converting a symbol code into a one-
CharToString
character string
Converting a numeric value to a text
DoubleToString
line with a specified accuracy
Converting an enumeration value of any
EnumToString
type to string
Rounding of a floating point number to
NormalizeDouble
a specified accuracy
Converting a string containing a symbol
StringToDouble representation of number into number
of double type
Converting a string containing a symbol
StringToInteger representation of number into number
of int type
Converting a string containing time or
StringToTime date in "[Link] [hh:mi]" format
into datetime type
Converting a value containing time in
TimeToString seconds elapsed since 01.01.1970 into a
string of "[Link] hh:mi" format
Converting int into a string of preset
IntegerToString
length
Function Action
Converting symbol code (unicode) into
ShortToString
one-symbol string
ShortArrayToString Copying array part into a string
Symbol-wise copying a string to a
StringToShortArray
selected part of array of ushort type
Converting symbol code (ansi) into one-
CharArrayToString
symbol array
Symbol-wise copying a string converted
StringToCharArray from Unicode to ANSI, to a selected
place of array of uchar type
CharArrayToStruct Copy uchar type array to POD structure
StructToCharArray Copy POD structure to uchar type array
Converting color type to uint type to
ColorToARGB receive ARGB representation of the
color.
Converting color value into string as
ColorToString
"R,G,B"
Converting "R,G,B" string or string with
StringToColor
color name into color type value
Converting number into string
StringFormat
according to preset format
MQL4 Reference / MQL5 features / MQL5 functions / Math Functions
Mathematical Functions
A set of mathematical and trigonometric functions.
Function Action
MathAbs Returns absolute value (modulus) of the
specified numeric value
MathArccos Returns the arc cosine of x in radians
MathArcsin Returns the arc sine of x in radians
MathArctan Returns the arc tangent of x in radians
MathCeil Returns integer numeric value closest
from above
MathCos Returns the cosine of a number
MathExp Returns exponent of a number
MathFloor Returns integer numeric value closest
from below
MathLog Returns natural logarithm
MathLog10 Returns the logarithm of a number by
base 10
MathMax Returns the maximal value of the two
numeric values
MathMin Returns the minimal value of the two
numeric values
MathMod Returns the real remainder after the
division of two numbers
MathPow Raises the base to the specified power
Function Action
MathRand Returns a pseudorandom value within
the range of 0 to 32767
MathRound Rounds of a value to the nearest
integer
MathSin Returns the sine of a number
MathSqrt Returns a square root
MathSrand Sets the starting point for generating a
series of pseudorandom integers
MathTan Returns the tangent of a number
MathIsValidNumber Checks the correctness of a real
number
MathExpm1 Returns the value of the expression
MathExp(x)-1
MathLog1p Returns the value of the expression
MathLog(1+x)
MathArccosh Returns the hyperbolic arccosine
MathArcsinh Returns the hyperbolic arcsine
MathArctanh Returns the hyperbolic arctangent
MathCosh Returns the hyperbolic cosine
MathSinh Returns the hyperbolic sine
MathTanh Returns the hyperbolic tangent
MathSwap Change the order of bytes in the
ushort/uint/ushort types value
MQL4 Reference / MQL5 features / MQL5 functions / String Functions
String Functions
This is a group of functions intended for working with data
of the string type.
Function Action
StringAdd Adds a string to the end of another
string
StringBufferLen Returns the size of buffer allocated for
the string
StringCompare Compares two strings and returns 1 if
the first string is greater than the
second; 0 - if the strings are equal; -1
(minus 1) - if the first string is less than
the second one
StringConcatenate Forms a string of parameters passed
StringFill Fills out a specified string by selected
symbols
StringFind Search for a substring in a string
StringGetCharacter Returns the value of a number located
in the specified string position
StringInit Initializes string by specified symbols
and provides the specified string length
StringLen Returns the number of symbols in a
string
StringSetLength Sets a specified length (in characters)
for a string
Function Action
StringReplace Replaces all the found substrings of a
string by a set sequence of symbols
StringReserve Reserves the buffer of a specified size
for a string in memory.
StringSetCharacter Returns a copy of a string with a
changed value of a symbol in a
specified position
StringSplit Gets substrings by a specified separator
from the specified string, returns the
number of substrings obtained
StringSubstr Extracts a substring from a text string
starting from a specified position
StringToLower Transforms all symbols of a selected
string to lowercase
StringToUpper Transforms all symbols of a selected
string into capitals
StringTrimLeft Cuts line feed characters, spaces and
tabs in the left part of the string
StringTrimRight Cuts line feed characters, spaces and
tabs in the right part of the string
MQL4 Reference / MQL5 features / MQL5 functions / Date and Time
Account Information
Functions that return parameters of the current account.
Function Action
AccountInfoDouble Returns a value of double type of the
corresponding account property
AccountInfoInteger Returns a value of integer type (bool,
int or long) of the corresponding
account property
AccountInfoString Returns a value string type
corresponding account property
MQL4 Reference / MQL5 features / MQL5 functions / Checkup
State Checking
Functions that return parameters of the current state of
the client terminal
Function Action
GetLastError Returns the last error
IsStopped Returns true, if an mql5 program has
been commanded to stop its operation
UninitializeReason Returns the code of the reason for
deinitialization
TerminalInfoInteger Returns an integer value of a
corresponding property of the mql5
program environment
TerminalInfoDouble Returns a double value of a
corresponding property of the mql5
program environment
TerminalInfoString Returns a string value of a
corresponding property of the mql5
program environment
MQLInfoInteger Returns an integer value of a
corresponding property of a running
mql5 program
MQLInfoString Returns a string value of a
corresponding property of a running
mql5 program
Symbol Returns the name of a symbol of the
current chart
Function Action
Period Returns the current chart timeframe
Digits Returns the number of decimal digits
determining the accuracy of the price
value of the current chart symbol
Point Returns the point size of the current
symbol in the quote currency
MQL4 Reference / MQL5 features / MQL5 functions / Event Handling
Event Handling
The MQL5 language provides handling of certain
predefined events. The functions for handling these
events should be defined in an MQL5 program: function
name, return type, a set of parameters (if any) and their
types should strictly correspond to the description of an
event handling function.
The client terminal event handler uses the return and
parameter types to identify functions processing an event.
If a certain function has some parameters or a return type
not corresponding to the descriptions below, such a
function cannot be used for handling an event.
Function Action
The function is called when the Start
OnStart event occurs to perform actions set in
the script
The function is called in indicators and
OnInit EAs when the Init event occurs to
initialize a launched MQL5 program
The function is called in indicators and
OnDeinit EAs when the Deinit event occurs to de-
initialize a launched MQL5 program
The function is called in EAs when the
OnTick NewTick event occurs to handle a new
quote
Function Action
The function is called in indicators
OnCalculate when the Calculate event occurs to
handle price data changes
The function is called in indicators and
EAs during the Timer periodic event
OnTimer
generated by the terminal at fixed time
intervals
The function is called in EAs during the
OnTrade Trade event generated at the end of a
trading operation on a trade server
The function is called in EAs when the
TradeTransaction event occurs to
OnTradeTransaction
process a trade request execution
results
The function is called in EAs when the
OnBookEvent BookEvent event occurs to process
changes in the market depth
The function is called in indicators and
EAs when the ChartEvent event occurs
OnChartEvent
to process chart changes made by a
user or an MQL5 program
The function is called in EAs when the
Tester event occurs to perform
OnTester
necessary actions after testing an EA on
history data
The function is called in EAs when the
TesterInit event occurs to perform
OnTesterInit
necessary actions before optimization
in the strategy tester
Function Action
The function is called in EAs when the
OnTesterDeinit TesterDeinit event occurs after EA
optimization in the strategy tester
The function is called in EAs when the
TesterPass even occurs to handle an
OnTesterPass
arrival of a new data frame during EA
optimization in the strategy tester
MQL4 Reference / MQL5 features / MQL5 functions / Economic
Calendar
MQL4 Reference / MQL5 features / MQL5 functions / Custom Symbols
Custom symbols
Functions for creating and editing the custom symbol
properties.
When connecting the terminal to a certain trade server, a
user is able to work with time series of the financial
symbols provided by a broker. Available financial symbols
are displayed as a list in the Market Watch window. A
separate group of functions allows receiving data on the
symbol properties, trading sessions and market depth
updates.
The group of functions described in this section allows
creating custom symbols. To do this, users are able to
apply the trade server's existing symbols, text files or
external data sources.
Function Action
Create a custom symbol with
CustomSymbolCreate the specified name in the
specified group
Delete a custom symbol with
CustomSymbolDelete
the specified name
Set the integer type property
CustomSymbolSetInteger
value for a custom symbol
Set the real type property
CustomSymbolSetDouble
value for a custom symbol
Set the string type property
CustomSymbolSetString
value for a custom symbol
Function Action
Set the margin rates
depending on the order type
CustomSymbolSetMarginRate
and direction for a custom
symbol
Set the start and end time of
the specified quotation
CustomSymbolSetSessionQuote
session for the specified
symbol and week day
Set the start and end time of
the specified trading session
CustomSymbolSetSessionTrade
for the specified symbol and
week day
Delete all bars from the price
CustomRatesDelete history of the custom symbol
in the specified time interval
Fully replace the price history
of the custom symbol within
CustomRatesReplace the specified time interval
with the data from
the MqlRates type array
Add missing bars to the
custom symbol history and
CustomRatesUpdate replace existing data with the
ones from the MqlRates type
array
Adds data from an array of
the MqlTick type to the price
history of a custom symbol.
CustomTicksAdd
The custom symbol must be
selected in the Market Watch
window
Function Action
Delete all ticks from the price
CustomTicksDelete history of the custom symbol
in the specified time interval
Fully replace the price history
of the custom symbol within
CustomTicksReplace the specified time interval
with the data from
the MqlTick type array
Passes the status of the Depth
CustomBookAdd
of Market for a custom symbol
MQL4 Reference / MQL5 features / MQL5 functions / Chart
Operations
Chart Operations
Functions for setting chart properties (ChartSetInteger,
ChartSetDouble, ChartSetString) are asynchronous and are
used for sending update commands to a chart. If these
functions are executed successfully, the command is
included in the common queue of the chart events. Chart
property changes are implemented along with handling of
the events queue of this chart.
Function Action
Applies a specific template from a
ChartApplyTemplate
specified file to the chart
Saves current chart settings in a
ChartSaveTemplate
template with a specified name
Returns the number of a subwindow
ChartWindowFind
where an indicator is drawn
Converts the coordinates of a chart
ChartTimePriceToXY from the time/price representation to
the X and Y coordinates
Converts the X and Y coordinates on a
ChartXYToTimePrice
chart to the time and price values
Opens a new chart with the specified
ChartOpen
symbol and period
ChartClose Closes the specified chart
Returns the ID of the first chart of the
ChartFirst
client terminal
Function Action
Returns the chart ID of the chart next
ChartNext
to the specified one
Returns the symbol name of the
ChartSymbol
specified chart
Returns the period value of the
ChartPeriod
specified chart
Calls a forced redrawing of a specified
ChartRedraw
chart
Sets the double value for a
ChartSetDouble corresponding property of the
specified chart
Sets the integer value (datetime, int,
color, bool or char) for a
ChartSetInteger
corresponding property of the
specified chart
Sets the string value for a
ChartSetString corresponding property of the
specified chart
Returns the double value property of
ChartGetDouble
the specified chart
Returns the integer value property of
ChartGetInteger
the specified chart
Returns the string value property of
ChartGetString
the specified chart
Performs shift of the specified chart
by the specified number of bars
ChartNavigate
relative to the specified position in
the chart
ChartID Returns the ID of the current chart
Function Action
Adds an indicator with the specified
ChartIndicatorAdd
handle into a specified chart window
Removes an indicator with a specified
ChartIndicatorDelete
name from the specified chart window
Returns the handle of the indicator
ChartIndicatorGet with the specified short name in the
specified chart window
Returns the short name of the
indicator by the number in the
ChartIndicatorName
indicators list on the specified chart
window
Returns the number of all indicators
ChartIndicatorsTotal
applied to the specified chart window.
Returns the number (index) of the
ChartWindowOnDropped chart subwindow the Expert Advisor or
script has been dropped to
Returns the price coordinate of the
ChartPriceOnDropped chart point the Expert Advisor or
script has been dropped to
Returns the time coordinate of the
ChartTimeOnDropped chart point the Expert Advisor or
script has been dropped to
Returns the X coordinate of the chart
ChartXOnDropped point the Expert Advisor or script has
been dropped to
Returns the Y coordinate of the chart
ChartYOnDropped point the Expert Advisor or script has
been dropped to
Function Action
Changes the symbol value and a
ChartSetSymbolPeriod
period of the specified chart
Provides a screenshot of the chart of
its current state in a GIF, PNG or BMP
ChartScreenShot
format depending on specified
extension
MQL4 Reference / MQL5 features / MQL5 functions / Trade Functions
Trade Functions
This is the group of functions intended for managing
trading activities. Trading functions can be called only if
in the properties of the Expert Advisor or script the "Allow
live trading" checkbox is enabled.
Trading can be allowed or prohibited depending on various
factors described in the Trade Permission section.
Function Action
Calculates the margin required for
OrderCalcMargin the specified order type, in the
deposit currency
Calculates the profit based on the
OrderCalcProfit parameters passed, in the deposit
currency
Checks if there are enough funds to
OrderCheck execute the required trade
operation.
OrderSend Sends trade requests to a server
Asynchronously sends trade requests
OrderSendAsync without waiting for the trade
response of the trade server
PositionsTotal Returns the number of open positions
Returns the symbol corresponding to
PositionGetSymbol
the open position
Chooses an open position for further
PositionSelect
working with it
Function Action
Selects a position to work with by the
PositionSelectByTicket
ticket number specified in it
Returns the requested property of an
PositionGetDouble
open position (double)
Returns the requested property of an
PositionGetInteger
open position (datetime or int)
Returns the requested property of an
PositionGetString
open position (string)
Returns the ticket of the position
PositionGetTicket with the specified index in the list of
open positions
OrdersTotal Returns the number of orders
Return the ticket of a corresponding
OrderGetTicket
order
Selects a order for further working
OrderSelect
with it
Returns the requested property of
OrderGetDouble
the order (double)
Returns the requested property of
OrderGetInteger
the order (datetime or int)
Returns the requested property of
OrderGetString
the order (string)
Retrieves the history of transactions
HistorySelect and orders for the specified period of
the server time
Requests the history of deals with a
HistorySelectByPosition
specified position identifier.
Function Action
Selects an order in the history for
HistoryOrderSelect
further working with it
Returns the number of orders in the
HistoryOrdersTotal
history
Return order ticket of a
HistoryOrderGetTicket
corresponding order in the history
Returns the requested property of an
HistoryOrderGetDouble
order in the history (double)
Returns the requested property of an
HistoryOrderGetInteger
order in the history (datetime or int)
Returns the requested property of an
HistoryOrderGetString
order in the history (string)
Selects a deal in the history for
HistoryDealSelect further calling it through appropriate
functions
Returns the number of deals in the
HistoryDealsTotal
history
Returns a ticket of a corresponding
HistoryDealGetTicket
deal in the history
Returns the requested property of a
HistoryDealGetDouble
deal in the history (double)
Returns the requested property of a
HistoryDealGetInteger
deal in the history (datetime or int)
Returns the requested property of a
HistoryDealGetString
deal in the history (string)
MQL4 Reference / MQL5 features / MQL5 functions / Trade Signals
Trade Signals
This is the group of functions intended for managing trade
signals. The functions allow:
get information about trade signals, available for
copying,
get and set the signal copy settings,
subscribe and unsubscribe to the signal copying using
MQL5 language functions.
Function Action
SignalBaseGetDouble Returns the value of double type
property for selected signal
SignalBaseGetInteger Returns the value of integer type
property for selected signal
SignalBaseGetString Returns the value of string type
property for selected signal
SignalBaseSelect Selects a signal from signals, available
in terminal for further working with it
SignalBaseTotal Returns the total amount of signals,
available in terminal
SignalInfoGetDouble Returns the value of double type
property of signal copy settings
SignalInfoGetInteger Returns the value of integer type
property of signal copy settings
SignalInfoGetString Returns the value of string type
property of signal copy settings
Function Action
SignalInfoSetDouble Sets the value of double type property
of signal copy settings
SignalInfoSetInteger Sets the value of integer type property
of signal copy settings
SignalSubscribe Subscribes to the trading signal
SignalUnsubscribe Cancels subscription
MQL4 Reference / MQL5 features / MQL5 functions / Network
Functions
Network functions
MQL5 programs can exchange data with remote servers,
as well as send push notifications, emails and data via
FTP.
Add an explicit message to the MQL5 program to notify a
user of the need for additional configuration. You can do
that via #property description, Alert or Print.
Function Action
Create a socket with specified flags
SocketCreate
and return its handle
SocketClose Close a socket
Connect to the server with timeout
SocketConnect
control
Checks if the socket is currently
SocketIsConnected
connected
Get a number of bytes that can be
SocketIsReadable
read from a socket
Check whether data can be written
SocketIsWritable
to a socket at the current time
Set timeouts for receiving and
SocketTimeouts sending data for a socket system
object
SocketRead Read data from a socket
SocketSend Write data to a socket
Function Action
Initiate secure TLS (SSL) connection
SocketTlsHandshake to a specified host via TLS Handshake
protocol
Get data on the certificate used to
SocketTlsCertificate
secure network connection
Read data from secure TLS
SocketTlsRead
connection
Read all available data from secure
SocketTlsReadAvailable
TLS connection
SocketTlsSend Send data via secure TLS connection
Send an HTTP request to a specified
WebRequest
server
Send a file to an address specified on
SendFTP
the FTP tab
Send an email to an address specified
SendMail in the Email tab of the options
window
Send push notifications to mobile
SendNotification terminals whose MetaQuotes IDs are
specified in the Notifications tab
MQL4 Reference / MQL5 features / MQL5 functions / Global Variables
of the Terminal
File Functions
This is a group of functions for working with files. File
functions allow working with so-called "named pipes". To
do this, simply call FileOpen() function with appropriate
parameters.
Function Action
Starts the search of files in a directory
FileFindFirst
in accordance with the specified filter
Continues the search started by the
FileFindNext
FileFindFirst() function
FileFindClose Closes search handle
Opens a file with a specified name and
FileOpen
flag
FileDelete Deletes a specified file
Writes to a disk all data remaining in
FileFlush
the input/output file buffer
FileGetInteger Gets an integer property of a file
Defines the end of a file in the process
FileIsEnding
of reading
Defines the end of a line in a text file
FileIsLineEnding
in the process of reading
FileClose Closes a previously opened file
FileIsExist Checks the existence of a file
Copies the original file from a local or
FileCopy
shared folder to another file
Function Action
FileMove Moves or renames a file
Reads arrays of any type except for
FileReadArray
string from the file of the BIN type
Reads from the file of the CSV type a
string from the current position till a
FileReadBool delimiter (or till the end of a text line)
and converts the read string to a value
of bool type
Reads from the file of the CSV type a
string of one of the formats:
FileReadDatetime "[Link] HH:MM:SS", "[Link]"
or "HH:MM:SS" - and converts it into a
datetime value
Reads a double value from the current
FileReadDouble
position of the file pointer
Reads a float value from the current
FileReadFloat
position of the file pointer
Reads int, short or char value from the
FileReadInteger
current position of the file pointer
Reads a long type value from the
FileReadLong
current position of the file pointer
Reads from the file of the CSV type a
string from the current position till a
FileReadNumber delimiter (or til the end of a text line)
and converts the read string into
double value
Reads a string from the current position
FileReadString
of a file pointer from a file
Function Action
Reads the contents from a binary file
into a structure passed as a parameter,
FileReadStruct
from the current position of the file
pointer
Moves the position of the file pointer
FileSeek by a specified number of bytes relative
to the specified position
Returns the size of a corresponding
FileSize
open file
Returns the current position of the file
FileTell
pointer of a corresponding open file
FileWrite Writes data to a file of CSV or TXT type
Writes arrays of any type except for
FileWriteArray
string into a file of BIN type
Writes value of the double type from
FileWriteDouble the current position of a file pointer
into a binary file
Writes value of the float type from the
FileWriteFloat current position of a file pointer into a
binary file
Writes value of the int type from the
FileWriteInteger current position of a file pointer into a
binary file
Writes value of the long type from the
FileWriteLong current position of a file pointer into a
binary file
Writes the value of a string parameter
FileWriteString into a BIN or TXT file starting from the
current position of the file pointer
Function Action
Writes the contents of a structure
passed as a parameter into a binary
FileWriteStruct
file, starting from the current position
of the file pointer
Reads all data of a specified binary file
FileLoad into a passed array of numeric types or
simple structures
Writes to a binary file all elements of
FileSave
an array passed as a parameter
FolderCreate Creates a folder in the Files directory
Removes a selected directory. If the
FolderDelete folder is not empty, then it can't be
removed
FolderClean Deletes all files in the specified folder
Custom Indicators
This is the group functions used in the creation of custom
indicators. These functions can't be used when writing
Expert Advisors and Scripts.
Function Action
SetIndexBuffer Binds the specified indicator buffer with
one-dimensional dynamic array of the
double type
IndicatorSetDouble Sets the value of an indicator property
of the double type
IndicatorSetInteger Sets the value of an indicator property
of the int type
IndicatorSetString Sets the value of an indicator property
of the string type
PlotIndexSetDouble Sets the value of an indicator line
property of the type double
PlotIndexSetInteger Sets the value of an indicator line
property of the int type
PlotIndexSetString Sets the value of an indicator line
property of the string type
PlotIndexGetInteger Returns the value of an indicator line
property of the integer type
Object Functions
This is the group of functions intended for working with
graphic objects relating to any specified chart.
The functions defining the properties of graphical objects,
as well as ObjectCreate() and ObjectMove() operations for
creating and moving objects along the chart are actually
used for sending commands to the chart. If these
functions are executed successfully, the command is
included in the common queue of the chart events. Visual
changes in the properties of graphical objects are
implemented when handling the queue of the chart
events.
Thus, do not expect an immediate visual update of
graphical objects after calling these functions. Generally,
the graphical objects on the chart are updated
automatically by the terminal following the change events
- a new quote arrival, resizing the chart window, etc. Use
ChartRedraw() function to forcefully update the graphical
objects.
Function Action
Creates an object of the specified
ObjectCreate
type in a specified chart
Returns the name of an object of the
ObjectName corresponding type in the specified
chart (specified chart subwindow)
Function Action
Removes the object with the
specified name from the specified
ObjectDelete
chart (from the specified chart
subwindow)
Removes all objects of the specified
ObjectsDeleteAll type from the specified chart (from
the specified chart subwindow)
Searches for an object with the
ObjectFind
specified ID by the name
Returns the time value for the
ObjectGetTimeByValue
specified object price value
Returns the price value of an object
ObjectGetValueByTime
for the specified time
Changes the coordinates of the
ObjectMove
specified object anchor point
Returns the number of objects of the
ObjectsTotal specified type in the specified chart
(specified chart subwindow)
Returns the double value of the
ObjectGetDouble
corresponding object property
Returns the integer value of the
ObjectGetInteger
corresponding object property
Returns the string value of the
ObjectGetString
corresponding object property
Sets the value of the corresponding
ObjectSetDouble
object property
Sets the value of the corresponding
ObjectSetInteger
object property
Function Action
Sets the value of the corresponding
ObjectSetString
object property
Sets the font for displaying the text
TextSetFont using drawing methods (Arial 20 used
by default)
Transfers the text to the custom array
TextOut (buffer) designed for creation of a
graphical resource
Returns the string's width and height
TextGetSize
at the current font settings
MQL4 Reference / MQL5 features / MQL5 functions / Working with
Optimization Results
Event Functions
This group contains functions for working with custom
events and timer events. Besides this group, there are
special functions for handling predefined events.
Function Action
EventSetMillisecondTimer Launches event generator of the
high-resolution timer with a period
less than 1 second for the current
chart
EventSetTimer Starts the timer event generator
with the specified periodicity for
the current chart
EventKillTimer Stops the generation of events by
the timer in the current chart
EventChartCustom Generates a custom event for the
specified chart
MQL4 Reference / MQL5 features / MQL5 functions / Working with
OpenCL
MQL4 Reference / Language Basics
Language Basics
The MetaQuotes Language 4 (MQL4) is an object-oriented
high-level programming language intended for writing
automated trading strategies, custom technical indicators
for the analysis of various financial markets. It allows not
only to write a variety of expert systems, designed to
operate in real time, but also create their own graphical
tools to help you make trade decisions.
MQL4 is based on the concept of the popular programming
language C++. The language has enumerations, structures,
classes and event handling. By increasing the number of
embedded main types, the interaction of executable
programs in MQL4 with other applications through dll is
now as easy as possible. MQL4 syntax is similar to the
syntax of C++, and this makes it easy to translate into it
programs from modern programming languages.
To help you study the MQL4 language, all topics are
grouped into the following sections:
Syntax
Data Types
Operations and Expressions
Operators
Functions
Variables
Preprocessor
Object-Oriented Programming
Updated MQL4
MQL4 Reference / Language Basics / Syntax
Syntax
As to the syntax, THE MQL4 language for programming
trading strategies is very much similar to the C++
programming language, except for some features:
no address arithmetic;
no goto operator;
an anonymous enumeration can't be declared;
no multiple inheritance.
See also
Enumerations, Structures and Classes, Inheritance
MQL4 Reference / Language Basics / Syntax / Comments
Comments
Multi-line comments start with the /* pair of symbols and
end with the */ one. Such kind of comments cannot be
nested. Single-line comments begin with the // pair of
symbols and end with the newline character, they can be
nested in other multi-line comments. Comments are
allowed everywhere where the spaces are allowed, they
can have any number of spaces in them.
Examples:
//--- Single-line comment /* Multi-
line // Nested single-line comment
comment
*/
MQL4 Reference / Language Basics / Syntax / Identifiers
Identifiers
Identifiers are used as names of variables and functions.
The length of the identifier can not exceed 63 characters.
Characters allowed to be written in an identifier: figures
0-9, the Latin uppercase and lowercase letters a-z and A-
Z, recognized as different characters, the underscore
character (_).The first character can not be a digit.
The identifier must not coincide with reserved word.
Examples:
NAME1 namel Total_5 Paper
See also
Variables, Functions
MQL4 Reference / Language Basics / Syntax / Reserved Words
Reserved Words
The following identifiers are recorded as reserved words,
each of them corresponds to a certain action, and cannot
be used in another meaning:
Data Types
bool enum struct
char float uchar
class int uint
color long ulong
datetime short ushort
double string void
Access Specificators
const private protected
public virtual
Memory Classes
extern input static
Operators
break dynamic_cast return
case else sizeof
break dynamic_cast return
continue for switch
default if while
delete new
do operator
Other
false #define #property
this #import template
true #include typename
strict
MQL4 Reference / Language Basics / Data Types
Data Types
Any program operates with data. Data can be of different
types depending on their purposes. For example, integer
data are used to access to array components. Price data
belong to those of double precision with floating point.
This is related to the fact that no special data type for
price data is provided in MQL4.
Data of different types are processed with different rates.
Integer data are processed at the fastest. To process the
double precision data, a special co-processor is used.
However, because of complexity of internal
representation of data with floating point, they are
processed slower than the integer ones.
String data are processed at the longest because of
dynamic computer memory allocation/reallocation.
The basic data types are:
integers (char, short, int, long, uchar, ushort, uint,
ulong);
logical (bool);
literals (ushort);
strings (string);
floating-point numbers (double, float);
color (color);
date and time (datetime);
enumerations (enum).
Complex data types are:
structures;
classes.
In terms of OOP complex data types are called abstract
data types.
The color and datetime types make sense only to
facilitate visualization and input of parameters defined
from outside - from the table of Expert Advisor or custom
indicator properties (the Inputs tab). Data of color and
datetime types are represented as integers. Integer types
and floating-point types are called arithmetic (numeric)
types.
Only implicit type casting is used in expressions, unless
the explicit casting is specified.
See also
Typecasting
MQL4 Reference / Language Basics / Data Types / Integer Types
Integer Types
In MQL4 integers are represented by eleven types. Some
types can be used together with other ones, if required by
the program logic, but in this case it's necessary to
remember the rules of typecasting.
The table below lists the characteristics of each type.
Besides, the last column features a type in C++
corresponding to each type.
Type Size Minimum Maximum Value C++
in Value Analog
Bytes
char 1 -128 127 char
uchar 1 0 255 unsigned
char, BYTE
bool 1 0(false) 1(true) bool
short 2 -32 768 32 767 short,
wchar_t
ushort 2 0 65 535 unsigned
short,
WORD
int 4 - 2 147 483 2 147 483 647 int
648
uint 4 0 4 294 967 295 unsigned
int,
DWORD
Type Size Minimum Maximum Value C++
in Value Analog
Bytes
color 4 -1 16 777 215 int,
COLORREF
long 8 -9 223 372 9 223 372 036 __int64
036 854 775 854 775 807
808
ulong 8 0 18 446 744 073 unsigned
709 551 615 __int64
datetime 8 0 32 535 244 799 __time64_t
(1970.01.01 (3000.12.31
[Link]) [Link])
uchar
The uchar integer type also occupies 1 byte of memory, as
well as the char type, but unlike it uchar is intended only for
positive values. The minimum value is zero, the maximum
value is 255. The first letter u in the name of the uchar type
is the abbreviation for unsigned.
short
The size of the short type is 2 bytes (16 bits) and,
accordingly, it allows expressing the range of values equal to
2 to the power 16: 2^16 = 65 [Link] the short type is a
signed one, and contains both positive and negative values,
the range of values is between -32 768 and 32 767.
ushort
The unsigned short type is the type ushort, which also has a
size of 2 bytes. The minimum value is 0, the maximum value
is 65 535.
int
The size of the int type is 4 bytes (32 bits). The minimal
value is -2 147 483 648, the maximal one is 2 147 483 647.
uint
The unsigned integer type is uint. It takes 4 bytes of memory
and allows expressing integers from 0 to 4 294 967 295.
long
The size of the long type is 8 bytes (64 bits). The minimum
value is -9 223 372 036 854 775 808, the maximum value is 9
223 372 036 854 775 807.
ulong
The ulong type also occupies 8 bytes and can store values
from 0 to 18 446 744 073 709 551 615.
Examples:
char ch=12; short sh=-5000;
int in=2445777;
Since the unsigned integer types are not designed for storing
negative values, the attempt to set a negative value can lead
to unexpected consequences. Such a simple script will lead
to an infinite loop:
//--- Infinite loop
void OnStart()
{
uchar u_ch;
for(char ch=-128;ch<128;ch++)
{
u_ch=ch;
Print("ch = ",ch," u_ch = ",u_ch);
}
}
for(char ch=-128;ch<=127;ch++)
{
u_ch=ch;
Print("ch = ",ch," u_ch = ",u_ch);
if(ch==127) break;
}
}
Result:
ch= -128 u_ch= 128
ch= -127 u_ch= 129
ch= -126 u_ch= 130
ch= -125 u_ch= 131
ch= -124 u_ch= 132
ch= -123 u_ch= 133
ch= -122 u_ch= 134
ch= -121 u_ch= 135
ch= -120 u_ch= 136
ch= -119 u_ch= 137
ch= -118 u_ch= 138
ch= -117 u_ch= 139
ch= -116 u_ch= 140
ch= -115 u_ch= 141
ch= -114 u_ch= 142
ch= -113 u_ch= 143
ch= -112 u_ch= 144
ch= -111 u_ch= 145
...
Examples:
//--- Negative values can not be stored in unsigned types
uchar u_ch=-120;
ushort u_sh=-5000;
uint u_in=-401280;
See also
Typecasting
MQL4 Reference / Language Basics / Data Types / Integer Types / Character Constants
Character Constants
Characters as elements of a string in MQL4 are indexes in the Unicode character set.
They are hexadecimal values that can be cast into integers, and that can be manipulated
by integer operations like addition and subtraction.
Any single character in quotation marks or a hexadecimal ASCII code of a character as
'\x10' is a character constant and is of ushort type. For example, a record of '0' type is a
numerical value 30, that corresponds to the index of zero in the table of characters.
Example:
void OnStart() {
//--- define character constants
int symbol_0='0';
int symbol_9=symbol_0+9; // get symbol '9'
//--- output values of constants
printf("In a decimal form: symbol_0 = %d, symbol_9 = %d",symbol_0,symbol_9);
printf("In a hexadecimal form: symbol_0 = 0x%x, symbol_9 = 0x%x",symbol_0,symbol_
//--- enter constants into a string
string test="";
StringSetCharacter(test,0,symbol_0);
StringSetCharacter(test,1,symbol_9);
//--- this is what they look like in a string
Print(test);
}
A backslash is a control character for a compiler when dealing with constant strings and
character constants in a source text of a program. Some symbols, for example a single
quote ('), double quotes ("), backslash (\) and control characters can be represented as a
combination of symbols that start with a backslash (\), according to the below table:
Character name Mnemonic code or Record in Numeric value
image MQL4
new line (line LF '\n' 10
feed)
horizontal tab HT '\t' 9
carriage return CR '\r' 13
backslash \ '\\' 92
single quote ' '\'' 39
double quote " '\"' 34
hexadecimal code hhhh '\xhhhh' 1 to 4 hexadecimal characters
decimal code d '\d' decimal number from 0 to
65535
As it was mentioned above, the value of a character constant (or variable) is an index in
the table of characters. Index being an integer, it can be written in different ways.
void OnStart()
{
//---
int a=0xAE; // the code of ® corresponds to the '\xAE' literal
int b=0x24; // the code of $ corresponds to the '\x24' literal
int c=0xA9; // the code of © corresponds to the '\xA9' literal
int d=0x263A; // the code of ☺ corresponds to the '\x263A' literal
//--- show values
Print(a,b,c,d);
//--- add a character to the string
string test="";
StringSetCharacter(test,0,a);
Print(test);
//--- replace a character in a string
StringSetCharacter(test,0,b);
Print(test);
//--- replace a character in a string
StringSetCharacter(test,0,c);
Print(test);
//--- replace a character in a string
StringSetCharacter(test,0,d);
Print(test);
//--- codes of suits
int a1=0x2660;
int b1=0x2661;
int c1=0x2662;
int d1=0x2663;
//--- add a character of spades
StringSetCharacter(test,1,a1);
Print(test);
//--- add a character of hearts
StringSetCharacter(test,2,b1);
Print(test);
//--- add a character of diamonds
StringSetCharacter(test,3,c1);
Print(test);
//--- add a character of clubs
StringSetCharacter(test,4,d1);
Print(test);
//--- Example of character literals in a string
test="Queen\x2660Ace\x2662";
printf("%s",test);
}
The internal representation of a character literal is the ushort type. Character constants
can accept values from 0 to 65535.
See also
StringSetCharacter(), StringGetCharacter(), ShortToString(), ShortArrayToString(),
StringToShortArray()
MQL4 Reference / Language Basics / Data Types / Integer Types / Datetime Type
Datetime Type
The datetime type is intended for storing the date and time as the number of seconds
elapsed since January 01, 1970. This type occupies 8 bytes of memory.
Constants of the date and time can be represented as a literal string, which consists of 6
parts showing the numerical value of the year, month, day (or day, month, year), hours,
minutes and seconds. The constant is enclosed in single quotation marks and starts with
the D character.
Values range from 1 January, 1970 to 31 December, 3000. Either date (year , month, day)
or time (hours, minutes, seconds), or all together can be omitted.
With literal date specification, it is desirable that you specify year, month and day.
Otherwise the compiler returns a warning about an incomplete entry.
Examples:
datetime NY=D'2015.01.01 00:00'; // Time of beginning of year 2015 datetime d1=D'1
datetime d2=D'19.07.1980 [Link]'; // Equal to D'1980.07.19 [Link]';
datetime d3=D'19.07.1980 12'; // Equal to D'1980.07.19 [Link]'
datetime d4=D'01.01.2004'; // Equal to D'01.01.2004 [Link]'
datetime compilation_date=__DATE__; // Compilation date
datetime compilation_date_time=__DATETIME__; // Compilation date and time
datetime compilation_time=__DATETIME__-__DATE__;// Compilation time
//--- Examples of declarations after which compiler warnings will be returned
datetime warning1=D'[Link]'; // Equal to D'[date of compilation] [Link]'
datetime warning2=D''; // Equal to __DATETIME__
See also
Structure of the Date Type, Date and Time, TimeToString, StringToTime
MQL4 Reference / Language Basics / Data Types / Integer Types /
Color Type
Color Type
The color type is intended for storing information about
color and occupies 4 bytes in memory. The first byte is
ignored, the remaining 3 bytes contain the RGB-
components.
Color constants can be represented in three ways:
literally, by integers, or by name (for named Web-colors
only).
Literal representation consists of three parts representing
numerical rate values of the three main color
components: red, green, blue. The constant starts with C
and is enclosed in single quotes. Numerical rate values of
a color component lie in the range from 0 to 255.
Integer-valued representation is written in a form of
hexadecimal or a decimal number. A hexadecimal number
looks like 0x00BBGGRR, where RR is the rate of the red
color component, GG - of the green one, and BB - of the
blue one. Decimal constants are not directly reflected in
the RGB. They represent a decimal value of the
hexadecimal integer representation.
Specific colors reflect the so-called Web-colors set.
Examples:
//--- Literals C'128,128,128' // Gray
C'0x00,0x00,0xFF' // Blue
//color names
clrRed // Red
clrYellow // Yellow
clrBlack // Black
//--- Integral representations
0xFFFFFF // White
16777215 // White
0x008000 // Green
32768 // Green
See also
Web Colors, ColorToString, StringToColor, Typecasting
MQL4 Reference / Language Basics / Data Types / Integer Types /
Bool Type
Bool Type
The bool type is intended to store the logical values of
true or false, numeric representation of them is 1 or 0,
respectively.
Examples:
bool a = true; bool b = false;
bool c = 1;
i=0;
if(i) Print("i = ",i," and has the true value");
else Print("i = ",i," and has the false value");
d=0.0;
if(d) Print("d = ",d," and has the true value");
else Print("d = ",d," and has the false value");
See also
Boolean Operations, Precedence Rules
MQL4 Reference / Language Basics / Data Types / Integer Types /
Enumerations
Enumerations
Data of the enum type belong to a certain limited set of
data. Defining the enumeration type:
enum name of enumerable type {
list of values
};
Notes
Unlike C++, the size of the internal representation of
the enumerated type in MQL4 is always equal to 4
bytes. That is, sizeof(months) returns the value 4.
Unlike C++, an anonymous enumeration can't be
declared in MQL4. That is, a unique name must be
always specified after the enum keyword.
See also
Typecasting
MQL4 Reference / Language Basics / Data Types / Real Types (double, float)
The double name means that the accuracy of these numbers is twice the accuracy of the
float type numbers. In most cases, the double type is the most convenient one. In many
cases the limited precision of float numbers is not enough. The reason why the float type
is still used is saving the memory (this is important for large arrays of real numbers).
Floating-point constants consist of an integer part, a point (.) and the fractional part.
The integer and fractional parts are sequences of decimal digits.
Examples:
double a=12.111; double b=-956.1007;
float c =0.0001;
float d =16;
There is a scientific way of writing real constants, often this method of recording is more
compact than the traditional one.
Example:
double c1=1.12123515e-25;
double c2=0.000000000000000000000000112123515; // 24 zero after the decimal point
Print("1. c1 =",DoubleToString(c1,16));
// Result: 1. c1 = 0.0000000000000000
Print("2. c1 =",DoubleToString(c1,-16));
// Result: 2. c1 = 1.1212351499999999e-025
Print("3. c2 =",DoubleToString(c2,-16));
// Result: 3. c2 = 1.1212351499999999e-025
It should be remembered that real numbers are stored in memory with some limited
accuracy in the binary system, while generally the decimal notation is used. That's why
many numbers that are precisely represented in the decimal system can be written only
as an infinite fraction in the binary system.
For example, numbers 0.3 and 0.7 are represented in the computer as infinite fractions,
while the number of 0.25 is stored exactly, because it represents the power of two.
In this regard, it is strongly recommended not to compare two real numbers for equality,
because such a comparison is not correct.
Example:
void OnStart()
{
//---
double three=3.0;
double x,y,z;
x=1/three;
y=4/three;
z=5/three;
if(x+y==z) Print("1/3 + 4/3 == 5/3");
else Print("1/3 + 4/3 != 5/3");
// Result: 1/3 + 4/3 != 5/3
}
If you still need to compare the equality of two real numbers, then you can do this in
two different ways. The first way is to compare the difference between two numbers
with some small quantity that specifies the accuracy of comparison.
Example:
bool EqualDoubles(double d1,double d2,double epsilon)
{
if(epsilon<0) epsilon=-epsilon;
//---
if(d1-d2>epsilon) return false;
if(d1-d2<-epsilon) return false;
//---
return true;
}
void OnStart()
{
double d_val=0.7;
float f_val=0.7;
if(EqualDoubles(d_val,f_val,0.000000000000001)) Print(d_val," equals ",f_val);
else Print("Different: d_val = ",DoubleToString(d_val,16),
" f_val = ",DoubleToString(f_val,16));
// Result: Different: d_val= 0.7000000000000000 f_val= 0.6999999880790710
}
Note that the value of epsilon in the above example can not be less than the predefined
constant DBL_EPSILON. The value of this constant is 2.2204460492503131e-016. The
constant corresponding to the float type is FLT_EPSILON = 1.192092896e-07. The
meaning of these values is the following: it is the lowest value that satisfies the
condition 1.0 + DBL_EPSILON! = 1.0 (for numbers of float type 1.0 + FLT_EPSILON! =
1.0).
The second way offers comparing the normalized difference of two real numbers with
zero. It's meaningless to compare the difference of normalized numbers with a zero,
because any mathematical operation with normalized numbers gives a non-normalized
result.
Example:
bool CompareDoubles(double number1,double number2)
{
if(NormalizeDouble(number1-number2,8)==0) return(true);
else return(false);
}
void OnStart()
{
double d_val=0.3;
float f_val=0.3;
if(CompareDoubles(d_val,f_val)) Print(d_val," equals ",f_val);
else Print("Different: d_val = ",DoubleToString(d_val,16),
" f_val = ",DoubleToString(f_val,16));
// Result: Different: d_val= 0.3000000000000000 f_val= 0.3000000119209290
}
Some operations of the mathematical co-processor can result in the invalid real number,
which can't be used in mathematical operations and operations of comparison, because
the result of operations with invalid real numbers is undefined. For example, when
trying to calculate the arcsine of 2, the result is the negative infinity.
Example:
double abnormal = MathArcsin(2.0);
Print("MathArcsin(2.0) =",abnormal);
// Result: MathArcsin(2.0) = -1.#IND
Besides the minus infinity there is the plus infinity and NaN (not a number). To
determine that this number is invalid, you can use MathIsValidNumber(). According to
the IEEE standard, they have a special machine representation. For example, plus
infinity for the double type has the bit representation of 0x7FF0 0000 0000 0000.
Examples:
struct str1
{
double d;
};
struct str2
{
long l;
};
//--- Start
str1 s1;
str2 s2;
//---
s1.d=MathArcsin(2.0); // Get the invalid number -1.#IND
s2=s1;
printf("1. %f %I64X",s1.d,s2.l);
//---
s2.l=0xFFFF000000000000; // invalid number -1.#QNAN
s1=s2;
printf("2. %f %I64X",s1.d,s2.l);
//---
s2.l=0x7FF7000000000000; // greatest non-number SNaN
s1=s2;
printf("3. %f %I64X",s1.d,s2.l);
//---
s2.l=0x7FF8000000000000; // smallest non-number QNaN
s1=s2;
printf("4. %f %I64X",s1.d,s2.l);
//---
s2.l=0x7FFF000000000000; // greatest non-number QNaN
s1=s2;
printf("5. %f %I64X",s1.d,s2.l);
//---
s2.l=0x7FF0000000000000; // Positive infinity 1.#INF and smallest non-number S
s1=s2;
printf("6. %f %I64X",s1.d,s2.l);
//---
s2.l=0xFFF0000000000000; // Negative infinity -1.#INF
s1=s2;
printf("7. %f %I64X",s1.d,s2.l);
//---
s2.l=0x8000000000000000; // Negative zero -0.0
s1=s2;
printf("8. %f %I64X",s1.d,s2.l);
//---
s2.l=0x3FE0000000000000; // 0.5
s1=s2;
printf("9. %f %I64X",s1.d,s2.l);
//---
s2.l=0x3FF0000000000000; // 1.0
s1=s2;
printf("10. %f %I64X",s1.d,s2.l);
//---
s2.l=0x7FEFFFFFFFFFFFFF; // Greatest normalized number (MAX_DBL)
s1=s2;
printf("11. %.16e %I64X",s1.d,s2.l);
//---
s2.l=0x0010000000000000; // Smallest positive normalized (MIN_DBL)
s1=s2;
printf("12. %.16e %.16I64X",s1.d,s2.l);
//---
s1.d=0.7; // Show that the number of 0.7 - endless fraction
s2=s1;
printf("13. %.16e %.16I64X",s1.d,s2.l);
/*
1. -1.#IND00 FFF8000000000000
2. -1.#QNAN0 FFFF000000000000
3. 1.#SNAN0 7FF7000000000000
4. 1.#QNAN0 7FF8000000000000
5. 1.#QNAN0 7FFF000000000000
6. 1.#INF00 7FF0000000000000
7. -1.#INF00 FFF0000000000000
8. -0.000000 8000000000000000
9. 0.500000 3FE0000000000000
10. 1.000000 3FF0000000000000
11. 1.7976931348623157e+308 7FEFFFFFFFFFFFFF
12. 2.2250738585072014e-308 0010000000000000
13. 6.9999999999999996e-001 3FE6666666666666
*/
See also
DoubleToString, NormalizeDouble, Numeric Type Constants
MQL4 Reference / Language Basics / Data Types / String Type
String Type
The string type is used for storing text strings. A text string is a sequence of characters
in the Unicode format with the final zero at the end of it. A string constant can be
assigned to a string variable. A string constant is a sequence of Unicode characters
enclosed in double quotes: "This is a string constant".
If you need to include a double quote (") into a string, the backslash character (\) must
be put before it. Any special character constants can be written in a string, if the
backslash character (\) is typed before them.
Examples:
string svar="This is a character string"; string svar2=StringSubstr(svar,0,4);
Print("Copyright symbol\t\x00A9");
FileWrite(handle,"This string contains a new line symbols \n");
string MT4path="C:\\Program Files\\MetaTrader 4";
To make the source code readable, long constant strings can be split into parts without
addition operation. During compilation, these parts will be combined into one long
string:
//--- Declare a long constant string
string HTML_head="<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"
" \"[Link]
"<html xmlns=\"[Link]
"<head>\n"
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=u
"<title>Trade Operations Report</title>\n"
"</head>";
//--- Output the constant string into log
Print(HTML_head);
}
See also
Conversion Functions, String Functions, FileOpen(), FileReadString(), FileWriteString()
MQL4 Reference / Language Basics / Data Types / Structures, Classes and Interfaces
If you want to do another alignment in the structure, use auxiliary members, "fillers" to
the right size.
Example:
struct trade_settings
{
uchar slippage; // value of the permissible slippage-size 1 byte
char reserved1; // skip 1 byte
short reserved2; // skip 2 bytes
int reserved4; // another 4 bytes are skipped. ensure alignment of the bound
double take; // values of the price of profit fixing
double stop; // price value of the protective stop
};
Such a description of aligned structures is necessary only for transferring to imported dll-
functions.
Attention: This example illustrates incorrectly designed data. It would be better first to
declare the take and stop large data of the double type, and then declare the slippage
member of the uchar type. In this case, the internal representation of data will always
be the same regardless of the value specified in #pragma pack().
If a structure contains variables of the string type and/or object of a dynamic array, the
compiler assigns an implicit constructor to such a structure. This constructor resets all
the structure members of string type and correctly initializes objects of the dynamic
array.
Simple Structures
Structures that do not contain strings or objects of dynamic arrays are called simple
structures; variables of such structures can be freely copied to each other, even if they
are different structures. Variables of simple structures, as well as their array can be
passed as parameters to functions imported from DLL.
Access to Structure Members
The name of a structure becomes a new data type, so you can declare variables of this
type. The structure can be declared only once within a project. The structure members
are accessed using thepoint operation (.).
Example:
struct trade_settings
{
double take; // values of the profit fixing price
double stop; // value of the protective stop price
uchar slippage; // value of the acceptable slippage
};
//--- create up and initialize a variable of the trade_settings type
trade_settings my_set={0.0,0.0,5};
if (input_TP>0) my_set.take=input_TP;
Classes
Classes differ from structures in the following:
the keyword class is used in declaration;
by default, all class members have access specifier private, unless otherwise
indicated. Data-members of the structure have the default type of access as public,
unless otherwise indicated;
class objects always have a table of virtual functions, even if there are no virtual
functions declared in the class. Structures cannot have virtual functions;
the new operator can be applied to class objects; this operator cannot be applied to
structures;
classes can be inherited only from classes, structures can be inherited only from
structures.
Classes and structures can have an explicit constructor and destructor. If your
constructor is explicitly defined, the initialization of a structure or class variable using
the initializing sequence is impossible.
Example:
struct trade_settings
{
double take; // values of the profit fixing price
double stop; // value of the protective stop price
uchar slippage; // value of the acceptable slippage
//--- Constructor
trade_settings() { take=0.0; stop=0.0; slippage=5; }
//--- Destructor
~trade_settings() { Print("This is the end"); }
};
//--- Compiler will generate an error message that initialization is impossible
trade_settings my_set={0.0,0.0,5};
A constructor can be declared in the class description and then its body can be defined.
For example, two constructors of MyDateClass can be defined the following way:
//+------------------------------------------------------------------+
//| Default constructor |
//+------------------------------------------------------------------+
MyDateClass::MyDateClass(void)
{
//---
MqlDateTime mdt;
datetime t=TimeCurrent(mdt);
m_year=[Link];
m_month=[Link];
m_day=[Link];
m_hour=[Link];
m_minute=[Link];
m_second=[Link];
Print(__FUNCTION__);
}
//+------------------------------------------------------------------+
//| Parametric constructor |
//+------------------------------------------------------------------+
MyDateClass::MyDateClass(int h,int m,int s)
{
MqlDateTime mdt;
datetime t=TimeCurrent(mdt);
m_year=[Link];
m_month=[Link];
m_day=[Link];
m_hour=h;
m_minute=m;
m_second=s;
Print(__FUNCTION__);
}
In the default constructor, all members of the class are filled using the TimeCurrent()
function. In the parametric constructor only hour values are filled in. Other members of
the class (m_year, m_month and m_day) will be automatically initialized with the
current date.
The default constructor has a special purpose when initializing an array of objects of its
class. The constructor, all parameters of which have default values, is not a default
constructor. Here is an example:
//+------------------------------------------------------------------+
//| Class with a default constructor |
//+------------------------------------------------------------------+
class CFoo
{
datetime m_call_time; // Time of the last object call
public:
//--- Constructor with a parameter that has a default value is not a default const
CFoo(const datetime t=0){m_call_time=t;};
//--- Copy constructor
CFoo(const CFoo &foo){m_call_time=foo.m_call_time;};
string ToString(){return(TimeToString(m_call_time,TIME_DATE|TIME_SECONDS));};
};
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
// CFoo foo; // This variant cannot be used - a default constructor is not set
//--- Possible options to create the CFoo object
CFoo foo1(TimeCurrent()); // An explicit call of a parametric constructor
CFoo foo2(); // An explicit call of a parametric constructor with
CFoo foo3=D'2009.09.09'; // An implicit call of a parametric constructor
CFoo foo40(foo1); // An explicit call of a copy constructor
CFoo foo41=foo1; // An implicit call of a copy constructor
CFoo foo5; // An explicit call of a default constructor (if the
// then a parametric constructor with a default valu
//--- Possible options to receive CFoo pointers
CFoo *pfoo6=new CFoo(); // Dynamic creation of an object and receiving of a
CFoo *pfoo7=new CFoo(TimeCurrent());// Another option of dynamic object creation
CFoo *pfoo8=GetPointer(foo1); // Now pfoo8 points to object foo1
CFoo *pfoo9=pfoo7; // pfoo9 and pfoo7 point to one and the same object
// CFoo foo_array[3]; // This option cannot be used - a default constructo
//--- Show the value of m_call_time
Print("foo1.m_call_time=",[Link]());
Print("foo2.m_call_time=",[Link]());
Print("foo3.m_call_time=",[Link]());
Print("foo4.m_call_time=",[Link]());
Print("foo5.m_call_time=",[Link]());
Print("pfoo6.m_call_time=",[Link]());
Print("pfoo7.m_call_time=",[Link]());
Print("pfoo8.m_call_time=",[Link]());
Print("pfoo9.m_call_time=",[Link]());
//--- Delete dynamically created arrays
delete pfoo6;
delete pfoo7;
//delete pfoo8; // You do not need to delete pfoo8 explicitly, since it points to
//delete pfoo9; // You do not need to delete pfoo9 explicitly. since it points to
}
or
//CFoo foo_dyn_array[]; // This variant cannot be used - a default constructor is
then the compiler will return an error for them "default constructor is not defined".
If a class has a user-defined constructor, the default constructor is not generated by the
compiler. This means that if a parametric constructor is declared in a class, but a default
constructor is not declared, you can not declare the arrays of objects of this class. The
compiler will return an error for this script:
//+------------------------------------------------------------------+
//| Class without a default constructor |
//+------------------------------------------------------------------+
class CFoo
{
string m_name;
public:
CFoo(string name) { m_name=name;}
};
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- Get the "default constructor is not defined" error during compilation
CFoo badFoo[5];
}
In this example, the CFoo class has a declared parametric constructor - in such cases,
the compiler does not create a default constructor automatically during compilation. At
the same time when you declare an array of objects, it is assumed that all objects
should be created and initialized automatically. During auto-initialization of an object, it
is necessary to call a default constructor, but since the default constructor is not
explicitly declared and not automatically generated by the compiler, it is impossible to
create such an object. For this reason, the compiler generates an error at the
compilation stage.
There is a special syntax to initialize an object using a constructor. Constructor
initializers (special constructions for initialization) for the members of a struct or class
can be specified in the initialization list.
An initialization list is a list of initializers separated by commas, which comes after the
colon after the list of parameters of a constructor and precedes the body (goes before
an opening brace). There are several requirements:
Initialization lists can be used only in constructors;
Parent members cannot be initialized in the initialization list;
The initialization list must be followed by a definition (implementation) of a function.
Here is an example of several constructors for initializing class members.
//+------------------------------------------------------------------+
//| Class for storing the name of a character |
//+------------------------------------------------------------------+
class CPerson
{
string m_first_name; // First name
string m_second_name; // Second name
public:
//--- An empty default constructor
CPerson() {Print(__FUNCTION__);};
//--- A parametric constructor
CPerson(string full_name);
//--- A constructor with an initialization list
CPerson(string surname,string name): m_second_name(surname), m_f
void PrintName(){PrintFormat("Name=%s Surname=%s",m_first_name,m_second_name);};
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CPerson::CPerson(string full_name)
{
int pos=StringFind(full_name," ");
if(pos>=0)
{
m_first_name=StringSubstr(full_name,0,pos);
m_second_name=StringSubstr(full_name,pos+1);
}
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- Get an error "default constructor is not defined"
CPerson people[5];
CPerson Tom="Tom Sawyer"; // Tom Sawyer
CPerson Huck("Huckleberry","Finn"); // Huckleberry Finn
CPerson *Pooh = new CPerson("Winnie","Pooh"); // Winnie the Pooh
//--- Output values
[Link]();
[Link]();
[Link]();
In the initialization list, members can go in any order, but all members of the class will
be initialized according to the order of their announcement. This means that in the third
constructor, first the m_first_name member will be initialized, as it is announced first,
and only after it m_second_name is initialized. This should be taken into account in
cases where the initialization of some members of the class depends on the values in
other class members.
If a default constructor is not declared in the base class, and at the same time one or
more constructors with parameters are declared, you should always call one of the base
class constructors in the initialization list. It goes through the comma as ordinary
members of the list and will be called first during object initialization, no matter where
in the initialization list it is located.
//+------------------------------------------------------------------+
//| Base class |
//+------------------------------------------------------------------+
class CFoo
{
string m_name;
public:
//--- A constructor with an initialization list
CFoo(string name) : m_name(name) { Print(m_name);}
};
//+------------------------------------------------------------------+
//| Class derived from CFoo |
//+------------------------------------------------------------------+
class CBar : CFoo
{
CFoo m_member; // A class member is an object of the parent
public:
//--- A default constructor in the initialization list calls the constructor of a
CBar(): m_member(_Symbol), CFoo("CBAR") {Print(__FUNCTION__);}
};
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
CBar bar;
}
In this example, when creating the bar object, a default constructor CBar() will be
called, in which first a constructor for the parent CFoo is called, and then comes a
constructor for the m_member class member.
A destructor is a special function that is called automatically when a class object is
destroyed. The name of the destructor is written as a class name with a tilde (~).
Strings, dynamic arrays and objects, requiring deinitialization, will be de-initialized
anyway, regardless of the destructor presence or absence. If there is a destructor, these
actions will be performed after calling the destructor.
Destructors are always virtual, regardless of whether they are declared with the virtual
keyword or not.
Defining Class Methods
Class function-methods can be defined both inside the class and outside the class
declaration. If the method is defined within a class, then its body comes right after the
method declaration.
Example:
class CTetrisShape
{
protected:
int m_type;
int m_xpos;
int m_ypos;
int m_xsize;
int m_ysize;
int m_prev_turn;
int m_turn;
int m_right_border;
public:
void CTetrisShape();
void SetRightBorder(int border) { m_right_border=border; }
void SetYPos(int ypos) { m_ypos=ypos; }
void SetXPos(int xpos) { m_xpos=xpos; }
int GetYPos() { return(m_ypos); }
int GetXPos() { return(m_xpos); }
int GetYSize() { return(m_ysize); }
int GetXSize() { return(m_xsize); }
int GetType() { return(m_type); }
void Left() { m_xpos-=SHAPE_SIZE; }
void Right() { m_xpos+=SHAPE_SIZE; }
void Rotate() { m_prev_turn=m_turn; if(++m_turn>3)
virtual void Draw() { return; }
virtual bool CheckDown(int& pad_array[]);
virtual bool CheckLeft(int& side_row[]);
virtual bool CheckRight(int& side_row[]);
};
Functions from SetRightBorder(int border) to Draw() are declared and defined directly
inside the CTetrisShape class.
The CTetrisShape() constructor and methods CheckDown(int& pad_array[]),
CheckLeft(int& side_row[]) and CheckRight(int& side_row[]) are only declared inside the
class, but not defined yet. Definitions of these functions will be further in the code. In
order to define the method outside the class, the scope resolution operator is used, the
class name is used as the scope.
Example:
//+------------------------------------------------------------------+
//| Constructor of the basic class |
//+------------------------------------------------------------------+
void CTetrisShape::CTetrisShape()
{
m_type=0;
m_ypos=0;
m_xpos=0;
m_xsize=SHAPE_SIZE;
m_ysize=SHAPE_SIZE;
m_prev_turn=0;
m_turn=0;
m_right_border=0;
}
//+------------------------------------------------------------------+
//| Checking ability to move down (for the stick and cube) |
//+------------------------------------------------------------------+
bool CTetrisShape::CheckDown(int& pad_array[])
{
int i,xsize=m_xsize/SHAPE_SIZE;
//---
for(i=0; i<xsize; i++)
{
if(m_ypos+m_ysize>=pad_array[i]) return(false);
}
//---
return(true);
}
Any class members and methods declared after the specifier public: (and before the
next access specifier) are available in any reference to the class object by the program.
In this example these are the following members: functions CTetrisField(), Init(),
Deinit(), Down(), Left(), Right(), Rotate() and Drop().
Any members that are declared after the access specifier to the elements private: (and
before the next access specifier) are available only to members-functions of this class.
Specifiers of access to elements always end with a colon (:) and can appear in the class
definition many times.
Access to the members of the basis class can be redefined during inheritance in derived
classes.
Modifier 'final'
The use of the 'final' modifier during class declaration prohibits further inheritance from
this class. If the class interface requires no further modifications, or modifications are
not allowed for security reasons, declare this class with the 'final' modifier. In addition,
all the members of the class will also be implicitly considered final.
class CFoo final
{
//--- Class body
};
If you try to inherit form a class with the 'final' modifier as shown in the above example,
the compiler will return an error:
cannot inherit from 'CFoo' as it has been declared as 'final'
see declaration of 'CFoo'
Unions (union)
Union is a special data type consisting of several variables sharing the same memory
area. Therefore, the union provides the ability to interpret the same bit sequence in two
(or more) different ways. Union declaration is similar to structure declaration and starts
with the union keyword.
union LongDouble
{
long long_value;
double double_value;
};
Unlike the structure, various union members belong to the same memory area. In this
example, the union of LongDouble is declared with long and double type values sharing
the same memory area. Please note that it is impossible to make the union store a long
integer value and a double real value simultaneously (unlike a structure), since
long_value and double_value variables overlap (in memory). On the other hand, an MQL5
program is able to process data containing in the union as an integer (long) or real
(double) value at any time. Therefore, the union allows receiving two (or more) options
for representing the same data sequence.
During the union declaration, the compiler automatically allocates the memory area
sufficient to store the largest type (by volume) in the variable union. The same syntax is
used for accessing the union element as for the structures point operator.
union LongDouble
{
long long_value;
double double_value;
};
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//---
LongDouble lb;
//--- get and display the invalid -nan(ind) number
lb.double_value=MathArcsin(2.0);
printf("1. double=%f integer=%I64X",lb.double_value,lb.long_value)
//--- largest normalized value (DBL_MAX)
lb.long_value=0x7FEFFFFFFFFFFFFF;
printf("2. double=%.16e integer=%I64X",lb.double_value,lb.long_value);
//--- smallest positive normalized (DBL_MIN)
lb.long_value=0x0010000000000000;
printf("3. double=%.16e integer=%.16I64X",lb.double_value,lb.long_value);
}
/* Execution result
1. double=-nan(ind) integer=FFF8000000000000
2. double=1.7976931348623157e+308 integer=7FEFFFFFFFFFFFFF
3. double=2.2250738585072014e-308 integer=0010000000000000
*/
Since the unions allow the program to interpret the same memory data in different
ways, they are often used when an unusual type conversion is required.
The unions cannot be involved in the inheritance, and they also cannot have static
members due to their very nature. In all other aspects, the union behaves like a
structure with all its members having a zero offset. The following types cannot be the
union members:
dynamic arrays
strings
pointers to objects and functions
class objects
structure objects having constructors or destructors
structure objects having members from the points 1-5
Similar to classes, the union is capable of having constructors and destructors, as well as
methods. By default, the union members are of public access type. In order to create
private elements, use the private keyword. All these possibilities are displayed in the
example illustrating how to convert a color of the color type to ARGB as does the
ColorToARGB() function.
//+------------------------------------------------------------------+
//| Union for color(BGR) conversion to ARGB |
//+------------------------------------------------------------------+
union ARGB
{
uchar argb[4];
color clr;
//--- constructors
ARGB(color col,uchar a=0){Color(col,a);};
~ARGB(){};
//--- public methods
public:
uchar Alpha(){return(argb[3]);};
void Alpha(const uchar alpha){argb[3]=alpha;};
color Color(){ return(color(clr));};
//--- private methods
private:
//+------------------------------------------------------------------+
//| set the alpha channel value and color |
//+------------------------------------------------------------------+
void Color(color col,uchar alpha)
{
//--- set color to clr member
clr=col;
//--- set the Alpha component value - opacity level
argb[3]=alpha;
//--- interchange the bytes of R and B components (Red and Blue)
uchar t=argb[0];argb[0]=argb[2];argb[2]=t;
};
};
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 0x55 means 55/255=21.6 % (0% - fully transparent)
uchar alpha=0x55;
//--- color type is represented as 0x00BBGGRR
color test_color=clrDarkOrange;
//--- values of bytes from the ARGB union are accepted here
uchar argb[];
PrintFormat("0x%.8X - here is how the 'color' type look like for %s, BGR=(%s)",
test_color,ColorToString(test_color,true),ColorToString(test_color));
//--- ARGB type is represented as 0x00RRGGBB, RR and BB components are swapped
ARGB argb_color(test_color);
//--- copy the bytes array
ArrayCopy(argb,argb_color.argb);
//--- here is how it looks in ARGB representation
PrintFormat("0x%.8X - ARGB representation with the alpha channel=0x%.2x, ARGB=(%d,
argb_color.clr,argb_color.Alpha(),argb[3],argb[2],argb[1],argb[0]);
//--- add opacity level
argb_color.Alpha(alpha);
//--- try defining ARGB as 'color' type
Print("ARGB as color=(",argb_color.clr,") alpha channel=",argb_color.Alpha());
//--- copy the bytes array
ArrayCopy(argb,argb_color.argb);
//--- here is how it looks in ARGB representation
PrintFormat("0x%.8X - ARGB representation with the alpha channel=0x%.2x, ARGB=(%d,
argb_color.clr,argb_color.Alpha(),argb[3],argb[2],argb[1],argb[0]);
//--- check with the ColorToARGB() function results
PrintFormat("0x%.8X - result of ColorToARGB(%s,0x%.2x)",ColorToARGB(test_color,alp
ColorToString(test_color,true),alpha);
}
/* Execution result
0x00008CFF - here is how the color type looks for clrDarkOrange, BGR=(255,140,0)
0x00FF8C00 - ARGB representation with the alpha channel=0x00, ARGB=(0,255,140,0)
ARGB as color=(0,140,255) alpha channel=85
0x55FF8C00 - ARGB representation with the alpha channel=0x55, ARGB=(85,255,140,0)
0x55FF8C00 - result of ColorToARGB(clrDarkOrange,0x55)
*/
Interfaces
An interface allows determining specific functionality, which a class can then implement.
In fact, an interface is a class that cannot contain any members, and may not have a
constructor and/or a destructor. All methods declared in an interface are purely virtual,
even without an explicit definition.
An interface is defined using the "interface" keyword. Example:
//--- Basic interface for describing animals
interface IAnimal
{
//--- The methods of the interface have public access by default
void Sound(); // The sound produced by the animal
};
//+------------------------------------------------------------------+
//| The CCat class is inherited from the IAnimal interface |
//+------------------------------------------------------------------+
class CCat : public IAnimal
{
public:
CCat() { Print("Cat was born"); }
~CCat() { Print("Cat is dead"); }
//--- Implementing the Sound method of the IAnimal interface
void Sound(){ Print("meou"); }
};
//+------------------------------------------------------------------+
//| The CDog class is inherited from the IAnimal interface |
//+------------------------------------------------------------------+
class CDog : public IAnimal
{
public:
CDog() { Print("Dog was born"); }
~CDog() { Print("Dog is dead"); }
//--- Implementing the Sound method of the IAnimal interface
void Sound(){ Print("guaf"); }
};
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- An array of pointers to objects of the IAnimal type
IAnimal *animals[2];
//--- Creating child classes of IAnimal and saving pointers to them into an array
animals[0]=new CCat;
animals[1]=new CDog;
//--- Calling the Sound() method of the basic IAnimal interface for each child
for(int i=0;i<ArraySize(animals);++i)
animals[i].Sound();
//--- Deleting objects
for(int i=0;i<ArraySize(animals);++i)
delete animals[i];
//--- Execution result
/*
Cat was born
Dog was born
meou
guaf
Cat is dead
Dog is dead
*/
}
Like with abstract classes, an interface object cannot be created without inheritance.
An interface can only be inherited from other interfaces and can be a parent for a class.
An interface is always publicly visible.
An interface cannot be declared within a class or structure declaration, but a pointer to
the interface can be saved in a variable of type void *. Generally speaking, a pointer to
an object of any class can be saved into a variable of type void *. In order to convert a
void * pointer to a pointer to an object of a particular class, use the dynamic_cast
operator. If conversion is not possible, the result of the dynamic_cast operation will be
NULL.
See also
Object-Oriented Programming
MQL4 Reference / Language Basics / Data Types / Dynamic Array Object
Static Arrays
When all significant array dimensions are explicitly specified, the compiler pre-allocates
the necessary memory size. Such an array is called static. Nevertheless, the compiler
allocates additional memory for the object of a dynamic array, which (object) is
associated with the pre-allocated static buffer (memory part for storing the array).
Creating a dynamic array object is due to the possible need to pass this static array as a
parameter to some function.
Examples:
double stat_array[5]; // 1-dimensional static array
some_function(stat_array);
...
bool some_function(double& array[])
{
if(ArrayResize(array,100)<0) return(false);
...
return(true);
}
Arrays in Structures
When a static array is declared as a member of a structure, a dynamic array object is
not created. This is done to ensure compatibility of data structures used in the Windows
API.
However, static arrays that are declared as members of structures can also be passed to
MQL5 functions. In this case, when passing the parameter, a temporary object of a
dynamic array will be created. Such an object is linked with the static array - member of
structure.
See also
Array Functions, Initialization of Variables, Visibility Scope and Lifetime of Variables,
Creating and Deleting Objects
MQL4 Reference / Language Basics / Data Types / Typecasting
Typecasting
Casting Numeric Types
Often a necessity occurs to convert one numeric type into another. Not all numeric types
can be converted into another. Here is the scheme of allowed casting:
Solid lines with arrows indicate changes that are performed almost without any loss of
information. Instead of the char type, the bool type can be used (both take 1 byte of
memory), instead of type int, the color type can be used (4 bytes), instead of the long
type, datetime can be used (take 8 bytes). The four dashed grey lines, also arrowed,
denote conversions, when the loss of precision can occur. For example, the number of
digits in an integer equal to 123456789 (int) is higher than the number of digits that can
be represented by float.
int n=123456789; float f=n; // the content of f is equal to 1.234567892E8
Print("n = ",n," f = ",f);
// result n= 123456789 f= 123456792.00000
A number converted into float has the same order, but is less accurate. Conversions,
contrary to black arrows, can be performed with possible data loss. Conversions between
char and uchar, short and ushort, int and uint, long and ulong (conversions to both
sides), may lead to the loss of data.
As a result of converting floating point values to integer type, the fractional part is
always deleted. If you want to round off a float to the nearest whole number (which in
many cases is more useful), you should use MathRound().
Example:
//--- Gravitational acceleration
double g=9.8;
double round_g=(int)g;
double math_round_g=MathRound(g);
Print("round_g = ",round_g);
Print("math_round_g = ",math_round_g);
/*
Result:
round_g = 9
math_round_g = 10
*/
If two values are combined by a binary operator, before the operation execution the
operand of a lower type is converted to the higher type in accordance with the priority
given in the below scheme:
The data types char, uchar, short, and ushort unconditionally are converted to the int
type.
Examples:
char c1=3;
//--- First example
double d2=c1/2+0.3;
Print("c1/2 + 0.3 = ",d2);
// Result: c1/2+0.3 = 1.3
The calculated expression consists of two operations. In the first example, the variable
c1 of the char type is converted to a temporary variable of the int type, because the
second operand in the division operation, the constant 2, is of the higher type int. As a
result of the integer division 3/2 we get the value 1, which is of the int type.
In the second operation of the first example, the second operand is the constant 0.3,
which is of the double type, so the result of the first operation is converted into a
temporary variable of the double type with a value of 1.0.
In the second example the variable of the char type c1 is converted to a temporary
variable of the double type, because the second operand in the division operation, the
constant 2.0, is of the double type; no further conversions are made.
Typecasting of Numeric Types
In the expressions of the MQL4 language both explicit and implicit typecasting can be
used. The explicit typecasting is written as follows:
var_1 = (type)var_2;
An expression or function execution result can be used as the var_2 variable. The
function style notation of the explicit typecasting is also possible:
var_1 = type(var_2);
Before the division operation is performed, the c1 variable is explicitly cast to the
double type. Now the integer constant 2 is cast to the value 2.0 of the double type,
because as a result of converting the first operand has taken the double type. In fact,
the explicit typecasting is a unary operation.
Besides, when trying to cast types, the result may go beyond the permissible range. In
this case, the truncation occurs. For example:
char c;
uchar u;
c=400;
u=400;
Print("c = ",c); // Result c=-112
Print("u = ",u); // Result u=144
Before operations (except for the assignment ones) are performed, the data are
converted into the maximum priority type. Before assignment operations are performed,
the data are cast into the target type.
Examples:
int i=1/2; // no types casting, the result is 0
Print("i = 1/2 ",i);
double x=1/2; // the expression of the int type is cast to the double targe
Print("x = 1/2; ",x); // the result is 0.0
When converting long/ulong type into double, precision may be lost in case the integer
value is greater than 9223372036854774784 or less than -9223372036854774784.
void OnStart()
{
long l_max=LONG_MAX;
long l_min=LONG_MIN+1;
//--- define the highest integer value, which does not lose accuracy when being cast
while(l_max!=long((double)l_max))
l_max--;
//--- define the lowest integer value, which does not lose accuracy when being cast t
while(l_min!=long((double)l_min))
l_min++;
//--- derive the found interval for integer values
PrintFormat("When casting an integer value to double, it must be "
"within [%I64d, %I64d] interval",l_min,l_max);
//--- now, let's see what happens if the value falls out of this interval
PrintFormat("l_max+1=%I64d, double(l_max+1)=%.f, ulong(double(l_max+1))=%I64d",
l_max+1,double(l_max+1),long(double(l_max+1)));
PrintFormat("l_min-1=%I64d, double(l_min-1)=%.f, ulong(double(l_min-1))=%I64d",
l_min-1,double(l_min-1),long(double(l_min-1)));
//--- receive the following result
// When casting an integer value to double, it should be within [-9223372036854774784
// l_max+1=9223372036854774785, double(l_max+1)=9223372036854774800, ulong(double(l_m
// l_min-1=-9223372036854774785, double(l_min-1)=-9223372036854774800, ulong(double(l
}
Typecasting for the String Type
The string type has the highest priority among simple types. Therefore, if one of
operands of an operation is of the string type, the second operand will be cast to a string
automatically. Note that for a string, a single dyadic two-place operation of addition is
possible. The explicit casting of string to any numeric type is allowed.
Examples:
string s1=1.0/8; // the expression is cast to the double type,
Print("s1 = 1.0/8; ",s1); // then is to the target type of string,
// result is "0.12500000" (a string containing 10 characters)
string str1="true";
string str2="0,255,0";
string str3="2009.06.01";
string str4="1.2345e2";
Print(bool(str1));
Print(color(str2));
Print(datetime(str3));
Print(double(str4));
Typecasting of Simple Structure Types
Data of the simple structures type can be assigned to each other only if all the members
of both structures are of numeric types. In this case both operands of the assignment
operation (left and right) must be of the structures type. The member-wise casting is not
performed, a simple copying is done. If the structures are of different sizes, the number
of bytes of the smaller size is copied. Thus the absence of union in MQL4 is
compensated.
Examples:
struct str1
{
double d;
};
//---
struct str2
{
long l;
};
//---
struct str3
{
int low_part;
int high_part;
};
//---
struct str4
{
string s;
};
//+------------------------------------------------------------------+
void OnStart()
{
str1 s1;
str2 s2;
str3 s3;
str4 s4;
//---
s1.d=MathArcsin(2.0); // get the invalid number -1. # IND
s2=s1;
printf("1. %f %I64X",s1.d,s2.l);
//---
s3=s2;
printf("2. high part of long %.8X low part of long %.8X",
s3.high_part,s3.low_part);
//---
s4.s="some constant string";
s3=s4;
printf("3. buffer len is %d constant string address is 0x%.8X",
s3.low_part,s3.high_part);
}
Another example illustrates the method of organizing a custom function for receiving
RGB (Red, Green, Blue) representation from the color type. Create two structures of the
same size but with different contents. For convenience, let's add a function returning
the RGB representation of a color as a string.
#property script_show_inputs
input color testColor=clrBlue;// set color for testing
//--- structure for representing color as RGB
struct RGB
{
uchar blue; // blue component of color
uchar green; // green component of color
uchar red; // red component of color
uchar empty; // this byte is not used
string toString(); // function for receiving a string
};
//--- function for showing color as a string
string RGB::toString(void)
{
string out="("+(string)red+":"+(string)green+":"+(string)blue+")";
return out;
}
//--- structure for storing of the built-in color type
struct builtColor
{
color c;
};
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- a variable for storing in RGB
RGB colorRGB;
//--- variable for storing the color type
builtColor test;
test.c=testColor;
//--- casting two structures by copying contents
colorRGB=test;
Print("color ",test.c,"=",[Link]());
//---
}
Typecasting of Base Class Pointers to Pointers of Derivative Classes
Objects of the open generated class can also be viewed as objects of the corresponding
base class. This leads to some interesting consequences. For example, despite the fact
that objects of different classes, generated by a single base class, may differ
significantly from each other, we can create a linked list (List) of them, as we view them
as objects of the base type. But the converse is not true: the base class objects are not
automatically objects of a derived class.
You can use the explicit casting to convert the base class pointers to the pointers of a
derived class. But you must be fully confident in the admissibility of such a
transformation, because otherwise a critical runtime error will occur and the mql4
program will be stopped.
Dynamic typecasting using dynamic_cast operator
Dynamic typecasting is performed using dynamic_cast operator that can be applied only
to pointers to classes. Type validation is performed at runtime. This means that the
compiler does not check the data type applied for typecasting when dynamic_cast
operator is used. If a pointer is converted to a data type which is not the actual type of
an object, the result is NULL.
dynamic_cast <type-id> ( expression )
The type-id parameter in angle brackets should point to a previously defined class type.
Unlike C++, expression operand type can be of any value except for void.
Example:
class CBar { };
class CFoo : public CBar { };
void OnStart()
{
CBar bar;
//--- dynamic casting of *bar pointer type to *foo pointer is allowed
CFoo *foo = dynamic_cast<CFoo *>(&bar); // no critical error
Print(foo); // foo=NULL
//--- an attempt to explicitly cast a Bar type object reference to a Foo type object
foo=(CFoo *)&bar; // critical runtime error
Print(foo); // this string is not executed
}
See also
Data Types
MQL4 Reference / Language Basics / Data Types / Void Type and NULL Constant
Also NULL can be compared to pointers to objects created with the new operator.
See also
Variables, Functions
MQL4 Reference / Language Basics / Data Types / User-defined Types
User-defined types
The typedef keyword in C++ allows creating user-defined data types. To do this, simply
specify a new data type name for an already existing data type. The new data type is
not created. A new name for the existing type is defined instead. User-defined types
make applications more flexible: sometimes, it is enough to change typedef instructions
using substitution macros (#define). User-defined types also improve code readability
since it is possible to apply custom names to standard data types using typedef. The
general format of the entry for creating a user-defined type:
typedef type new_name;
Here, type means any acceptable data type, while new_name is a new name of the type.
A new name is set only as an addition (not as a replacement) to an existing type name.
MQL5 allows creating pointers to functions using typedef.
where after typedef, the function signature (number and type of input parameters, as
well as a type of a result returned by the function) is set. Below is a simple example of
creating and applying a pointer to a function:
//--- declare a pointer to a function that accepts two int parameters typedef int
//--- TFunc is a type, and it is possible to declare the variable pointer to the func
TFunc func_ptr; // pointer to the function
//--- declare the functions corresponding to the TFunc description
int sub(int x,int y) { return(x-y); } // subtract one number from another
int add(int x,int y) { return(x+y); } // addition of two numbers
int neg(int x) { return(~x); } // invert bits in the variable
//--- the func_ptr variable may store the function address to declare it later
func_ptr=sub;
Print(func_ptr(10,5));
func_ptr=add;
Print(func_ptr(10,5));
func_ptr=neg; // error: neg does not have int (int,int) type
Print(func_ptr(10)); // error: two parameters needed
In this example, the func_ptr variable may receive the sub and add functions since they
have two inputs each of int type as defined in the TFunc pointer to the function. On the
contrary, the neg function cannot be assigned to the func_ptr pointer since its signature
is different.
Arranging event models in the user interface
Pointers to functions allow you to easily create processing of events when creating a user
interface. First, define a pointer to the TAction function to be called by pressing the
button and create three functions according to the TAction description.
//--- create a custom function type
typedef int(*TAction)(string,int);
//+------------------------------------------------------------------+
//| Open the file |
//+------------------------------------------------------------------+
int Open(string name,int id)
{
PrintFormat("%s function called (name=%s id=%d)",__FUNCTION__,name,id);
return(1);
}
//+------------------------------------------------------------------+
//| Save the file |
//+------------------------------------------------------------------+
int Save(string name,int id)
{
PrintFormat("%s function called (name=%s id=%d)",__FUNCTION__,name,id);
return(2);
}
//+------------------------------------------------------------------+
//| Close the file |
//+------------------------------------------------------------------+
int Close(string name,int id)
{
PrintFormat("%s function called (name=%s id=%d)",__FUNCTION__,name,id);
return(3);
}
Then, create the MyButton class from CButton, where we should add the TAction pointer
to the function.
//+------------------------------------------------------------------+
//| Create the button class with the events processing function |
//+------------------------------------------------------------------+
class MyButton: public CButton
{
private:
TAction m_action; // chart events handler
public:
MyButton(void){}
~MyButton(void){}
//--- constructor specifying the button text and the pointer to the events handlin
MyButton(string text, TAction act)
{
Text(text);
m_action=act;
}
//--- set the custom function called from the OnEvent() events handler
void SetAction(TAction act){m_action=act;}
//--- standard chart events handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,con
{
if(m_action!=NULL && lparam==Id())
{
//--- call the custom m_action() handler
m_action(sparam,(int)lparam);
return(true);
}
else
//--- return the result of calling the handler from the CButton parent class
return(CButton::OnEvent(id,lparam,dparam,sparam));
}
};
Create the CControlsDialog derivative class from CAppDialog, add the m_buttons array to
it for storing the buttons of the MyButton type, as well as the AddButton(MyButton
&button) and CreateButtons() methods.
//+------------------------------------------------------------------+
//| CControlsDialog class |
//| Objective: graphical panel for managing the application |
//+------------------------------------------------------------------+
class CControlsDialog : public CAppDialog
{
private:
CArrayObj m_buttons; // button array
public:
CControlsDialog(void){};
~CControlsDialog(void){};
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const
//--- add the button
bool AddButton(MyButton &button){return(m_buttons.Add(GetPointer(butt
protected:
//--- create the buttons
bool CreateButtons(void);
};
//+------------------------------------------------------------------+
//| Create the CControlsDialog object on the chart |
//+------------------------------------------------------------------+
bool CControlsDialog::Create(const long chart,const string name,const int subwin,cons
{
if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
return(CreateButtons());
//---
}
//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+
//--- indents and gaps
#define INDENT_LEFT (11) // indent from left (with allow
#define INDENT_TOP (11) // indent from top (with allowa
#define CONTROLS_GAP_X (5) // gap by X coordinate
#define CONTROLS_GAP_Y (5) // gap by Y coordinate
//--- for buttons
#define BUTTON_WIDTH (100) // size by X coordinate
#define BUTTON_HEIGHT (20) // size by Y coordinate
//--- for the indication area
#define EDIT_HEIGHT (20) // size by Y coordinate
//+------------------------------------------------------------------+
//| Create and add buttons to the CControlsDialog panel |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateButtons(void)
{
//--- calculate buttons coordinates
int x1=INDENT_LEFT;
int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y);
int x2;
int y2=y1+BUTTON_HEIGHT;
//--- add buttons objects together with pointers to functions
AddButton(new MyButton("Open",Open));
AddButton(new MyButton("Save",Save));
AddButton(new MyButton("Close",Close));
//--- create the buttons graphically
for(int i=0;i<m_buttons.Total();i++)
{
MyButton *b=(MyButton*)m_buttons.At(i);
x1=INDENT_LEFT+i*(BUTTON_WIDTH+CONTROLS_GAP_X);
x2=x1+BUTTON_WIDTH;
if(,m_subwin,x1,y1,x2,y2))
{
PrintFormat("Failed to create button %s %d",[Link](),i);
return(false);
}
//--- add each button to the CControlsDialog container
if(!Add(b))
return(false);
}
//--- succeed
return(true);
}
Now, we can develop the program using the CControlsDialog control panel having 3
buttons: Open, Save and Close. When clicking a button, the appropriate function in the
form of the TAction pointer is called.
//--- declare the object on the global level to automatically create it when launchin
CControlsDialog MyDialog;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- now, create the object on the chart
if()
return(INIT_FAILED);
//--- launch the application
[Link]();
//--- application successfully initialized
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- clear comments when the application shuts down
Comment("");
//--- destroy dialog
[Link](reason);
}
//+------------------------------------------------------------------+
//| Expert chart event function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, // event ID
const long& lparam, // event parameter of the long type
const double& dparam, // event parameter of the double type
const string& sparam) // event parameter of the string type
{
//--- call the handler from the parent class (here it is CAppDialog) for the chart ev
[Link](id,lparam,dparam,sparam);
}
The launched application's appearance and button clicking results are provided on the
screenshot.
The full source code of the program
//+------------------------------------------------------------------+
//| Panel_Buttons.mq5 |
//| Copyright 2017, MetaQuotes Software Corp. |
//| [Link] |
//+------------------------------------------------------------------+
See also
Variables, Functions
MQL4 Reference / Language Basics / Data Types / Object Pointers
Object Pointers
In MQL4, there is a possibility to dynamically create objects of complex type. This is
done by the new operator, which returns a descriptor of the created object. Descriptor
is 8 bytes large. Syntactically, object descriptors in MQL4 are similar to pointers in C++.
Examples:
MyObject* hobject= new MyObject();
In contrast to C++, the hobject variable from example above is not a pointer to memory,
but rather an object descriptor. Furthermore, in MQL5 all objects in function parameters
must be passed by reference. Below are examples of passing objects as function
parameters:
class Foo {
public:
string m_name;
int m_id;
static int s_counter;
//--- constructors and desctructors
Foo(void){Setup("noname");};
Foo(string name){Setup(name);};
~Foo(void){};
//--- initializes object of type Foo
void Setup(string name)
{
m_name=name;
s_counter++;
m_id=s_counter;
}
};
int Foo::s_counter=0;
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- declare an object as variable with its automatic creation
Foo foo1;
//--- variant of passing an object by reference
PrintObject(foo1);
//--- declare a pointer to an object and create it using the 'new' operator
Foo *foo2=new Foo("foo2");
//--- variant of passing a pointer to an object by reference
PrintObject(foo2); // pointer to an object is converted automatically by compiler
See also
Variables, Initialization of Variables, Visibility Scope and Lifetime of Variables, Creating
and Deleting Objects
MQL4 Reference / Language Basics / Data Types / References: Modifier & and Keyword this
public:
void setArray(double &array[]);
};
//+------------------------------------------------------------------+
//| filling the array |
//+------------------------------------------------------------------+
void CDemoClass::setArray(double &array[])
{
if(ArraySize(array)>0)
{
ArrayResize(m_array,ArraySize(array));
ArrayCopy(m_array, array);
}
}
Keyword this
A variable of class type (object) can be passed both by reference and by
pointer. As well as reference, the pointer allows having access to an
object. After the object pointer is declared, the new operator should be
applied to it to create and initialize it.
The reserved word this is intended for obtaining the reference of the
object to itself, which is available inside class or structure methods. this
always references to the object, in the method of which it is used, and the
expression GetPointer(this) gives the pointer of the object, whose member
is the function, in which call of GetPointer() is performed. In MQL4
functions can't return objects, but they can return the object pointer.
Thus, if we need a function to return an object, we can return the pointer
of this object in the form of GetPointer(this). Let's add function
getDemoClass() that returns pointer of the object of this class, into the
description of CDemoClass.
class CDemoClass
{
private:
double m_array[];
public:
void setArray(double &array[]);
CDemoClass *getDemoClass();
};
//+------------------------------------------------------------------+
//| filling the array |
//+------------------------------------------------------------------+
void CDemoClass::setArray(double &array[])
{
if(ArraySize(array)>0)
{
ArrayResize(m_array,ArraySize(array));
ArrayCopy(m_array,array);
}
}
//+------------------------------------------------------------------+
//| returns its own pointer |
//+------------------------------------------------------------------+
CDemoClass *CDemoClass::getDemoClass(void)
{
return(GetPointer(this));
}
Structures don't have pointers, operators new and delete can't be applied
to them, GetPointer(this) can't be used.
See also
Object Pointers, Creating and Deleting Objects, Visibility Scope and
Lifetime of Variables
MQL4 Reference / Language Basics / Operations and Expressions
Operation symbols are used in expressions and have sense when appropriate operands
are given to them. Punctuation marks are emphasized, as well. These are parentheses,
braces, comma, colon, and semicolon.
Operation symbols, punctuation marks, and spaces are used to separate language
elements from each other.
This section contains the description of the following topics:
Expressions
Arithmetic Operations
Assignment Operations
Operations of Relation
Boolean Operations
Bitwise Operations
Other Operations
Priorities and Operations Order
MQL4 Reference / Language Basics / Operations and Expressions / Expressions
Expressions
An expression consists of one or more operands and operation symbols. An expression
can be written in several lines.
Examples:
a++; b = 10; // several expressions are located in one line //--- one express
x = (y * z) /
(w + 2) + 127;
Arithmetic Operations
Arithmetic operations include additive and multiplicative operations:
Sum of variables i = j + 2; Difference of variables
Changing the sign x = - x;
Product of variables z = 3 * x;
Division quotient i = j / 5;
Remainder of division minutes = time % 60;
Adding 1 to the variable value i++;
Adding 1 to the variable value ++i;
Subtracting 1 from the variable value k--;
Subtracting 1 from the variable value --k;
Increment and decrement operations are applied only to variables, they can't be applied
to constants. The prefix increment (++i) and decrement (--k) are applied to the variable
right before this variable is used in an expression.
Post-increment (i++) and post-decrement (k--) are applied to the variable right after this
variable is used in an expression.
Important Notice
int i=5;
int k = i++ + ++i;
Computational problems may occur while moving the above expression from one
programming environment to another one (for example, from Borland C++ to MQL4). In
general, the order of computations depends on the compiler implementation. In
practice, there are two ways to implement the post-decrement (post-increment):
1. The post-decrement (post-increment) is applied to the variable after calculating the
whole expression.
2. The post-decrement (post-increment) is applied to the variable immediately at the
operation.
Currently the first way of post-decrement (post-increment) calculation is implemented
in MQL4. But even knowing this peculiarity, it is not recommended to experiment with its
use.
Examples:
int a=3;
a++; // valid expression
int b=(a++)*3; // invalid expression
See also
Precedence Rules
MQL4 Reference / Language Basics / Operations and Expressions / Assignment Operations
Assignment Operations
The value of the expression that includes the given operation is the value of the left
operand after assignment:
Assigning the value of x to the y variable y = x;
Bitwise operations can be applied to integers only. When performing the operation of the
logical shift of the y representation to the right/left by x bits, the 5 smallest binary
digits of the x value are used, the highest ones are dropped, i.e. the shift is made to 0-
31 bits.
By %= operation (y value by module of x), the result sign is equal to the sign of divided
number.
The assignment operator can be used several times in an expression . In this case the
processing of the expression is performed from left to right:
y=x=3;
First, the variable x will be assigned the value 3, then the y variable will be assigned the
value of x, i.e. also 3.
See also
Precedence Rules
MQL4 Reference / Language Basics / Operations and Expressions / Operations of Relation
Operations of Relation
Boolean FALSE is represented with an integer zero value, while the boolean TRUE is
represented by any non-zero value.
The value of expressions containing operations of relation or logical operations is FALSE
(0) or TRUE (1).
True if a is equal to b a == b; True if a is not equal to b
True if a is less than b a < b;
True if a is greater than b a > b;
True if a is less than or equal to b a <= b;
True if a is greater than or equal to b a >= b;
The equality of two real numbers can't be compared. In most cases, two seemingly
identical numbers can be unequal because of different values in the 15th decimal place.
In order to correctly compare two real numbers, compare the normalized difference of
these numbers with zero.
Example:
bool CompareDoubles(double number1,double number2)
{
if(NormalizeDouble(number1-number2,8)==0) return(true);
else return(false);
}
void OnStart()
{
double first=0.3;
double second=3.0;
double third=second-2.7;
if(first!=third)
{
if(CompareDoubles(first,third))
printf("%.16f and %.16f are equal",first,third);
}
}
// Result: 0.3000000000000000 0.2999999999999998 are equal
See also
Precedence Rules
MQL4 Reference / Language Basics / Operations and Expressions / Boolean Operations
Boolean Operations
Logical Negation NOT (!)
Operand of the logical negation (!) must be of arithmetic type. The result is TRUE (1), if
the operand value is FALSE (0); and it is equal to FALSE (0), if the operand differs from
FALSE (0).
if(!a) Print("not 'a'");
See also
Precedence Rules
MQL4 Reference / Language Basics / Operations and Expressions /
Bitwise Operations
Bitwise Operations
Complement to One
Complement of the variable value up to one. The value of
the expression contains 1 in all digits where the variable
value contains 0, and 0 in all digits where the variable
contains 1.
b = ~n;
Example:
char a='a',b; b=~a;
Print("a = ",a, " b = ",b);
// The result will be:
// a = 97 b = -98
Right Shift
The binary representation of x is shifted to the right by y
digits. If the value to shift is of the unsigned type, the
logical right shift is made, i.e. the freed left-side bits will
be filled with zeroes.
If the value to shift is of a sign type, the arithmetic right
shift is made, i.e. the freed left-side digits will be filled
with the value of a sign bit (if the number is positive, the
value of the sign bit is 0; if the number is negative, the
value of the sign bit is 1).
x = x >> y;
Example:
char a='a',b='b';
Print("Before: a = ",a, " b = ",b);
//--- shift to the right
b=a>>1;
Print("After: a = ",a, " b = ",b);
// The result will be:
// Before: a = 97 b = 98
// After: a = 97 b = 48
Left Shift
The binary representation of x is shifted to the left by y
digits, the freed right-side digits are filled with zeros.
x = x << y;
Example:
char a='a',b='b';
Print("Before: a = ",a, " b = ",b);
//--- shift to the left
b=a<<1;
Print("After: a = ",a, " b = ",b);
// The result will be:
// Before: a = 97 b = 98
// After: a = 97 b = -62
Example:
char a='a',b='b';
//--- AND operation
char c=a&b;
Print("a = ",a," b = ",b);
Print("a & b = ",c);
// The result will be:
// a = 97 b = 98
// a & b = 96
Bitwise OR Operation
The bitwise OR operation of binary representations of x
and y. The value of the expression contains 1 in all digits
where x or y does not contain 0, and it contains 0 in all
other digits.
b = x | y;
Example:
char a='a',b='b';
//--- OR operation
char c=a|b;
Print("a = ",a," b = ",b);
Print("a | b = ",c);
// The result will be:
// a = 97 b = 98
// a | b = 99
Example:
char a='a', b='b';
//--- Excluding OR operation
char c=a^b;
Print("a = ",a," b = ",b);
Print("a ^ b = ",c);
// The result will be:
// a = 97 b = 98
// a ^ b = 3
Other operations
Indexing ( [] )
When addressing the i-th element of the array, the expression value is the
value of a variable with the serial number i.
Example:
array[i] = 3; // Assign the value of 3 to i-th element of the array.
Comma Operation ( , )
Expressions separated by commas are executed from left to right. All side
effects of the left expression calculation can appear before the right
expression is calculated. The result type and value coincide with those of the
right expression. The list of parameters to be passed (see above) can be
considered as an example.
Example:
for(i=0,j=99; i<100; i++,j--) Print(array[i][j]);
Dot Operator ( . )
For the direct access to the public members of structures and classes the dot
operation is used. Syntax:
Variable_name_of_structure_type.Member_name
Example:
struct SessionTime
{
string sessionName;
int startHour;
int startMinutes;
int endHour;
int endMinutes;
} st;
[Link]="Asian";
[Link]=0;
[Link]=0;
[Link]=9;
[Link]=0;
If there is no scope name, this is the explicit direction to use the global
scope. If there is no scope resolution operation, the function is sought in the
nearest scope. If there is no function in the local scope, the search is
conducted in the global scope.
The scope resolution operation is also used to define function-class member.
type Class_name::Function_name(parameters_description)
{
// function body
}
Use of several functions of the same name from different execution contexts
in a program may cause ambiguity. The priority order of function calls
without explicit scope specification is the following:
1. Class methods. If no function with the specified name is set in the class,
move to the next level.
2. MQL4 functions. If the language does not have such a function, move to
the next level.
3. User defined global functions. If no function with the specified name is
found, move to the next level.
4. Imported functions. If no function with the specified name is found, the
compiler returns an error.
To avoid the ambiguity of function calls, always explicitly specify the
function scope using the scope resolution operation.
Example:
#property script_show_inputs
#import "[Link]"
int GetLastError(void);
#import
class CCheckContext
{
int m_id;
public:
CCheckContext() { m_id=1234; }
protected:
int GetLastError() { return(m_id); }
};
class CCheckContext2 : public CCheckContext
{
int m_id2;
public:
CCheckContext2() { m_id2=5678; }
void Print();
protected:
int GetLastError() { return(m_id2); }
};
void CCheckContext2::Print()
{
::Print("Terminal GetLastError",::GetLastError());
::Print("kernel32 GetLastError",kernel32::GetLastError());
::Print("parent GetLastError",CCheckContext::GetLastError());
::Print("our GetLastError",GetLastError());
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//---
CCheckContext2 test;
[Link]();
}
//+------------------------------------------------------------------+
Precedence Rules
Each group of operations in the table has the same
priority. The higher the priority of operations is, the
higher it is position of the group in the table. The
precedence rules determine the grouping of operations
and operands.
Attention: Precedence of operations in the MQL4
language corresponds to the priority adopted in C++.
Operation Desciption Execution
Order
() Function Call From left to
[] Referencing to an array right
. element
Referencing to a structure
element
! Logical negation Right to left
~ Bitwise negation (complement)
++ Sign changing
-- Increment by one
(type) Decrement by one
sizeof Typecasting
Determining size in bytes
* Multiplication From left to
/ Division right
% Module division
+ Addition From left to
Subtraction right
Operation Desciption Execution
Order
<< Left shift From left to
>> Right shift right
< Less than From left to
<= Less than or equal right
> Greater than
>= Greater than or equal
== Equal From left to
!= Not equal right
& Bitwise AND operation From left to
right
^ Bitwise exclusive OR From left to
right
| Bitwise OR operation From left to
right
&& Logical AND operation From left to
right
|| Logical OR operation From left to
right
?: Conditional Operator Right to left
Operation Desciption Execution
Order
= Assignment Right to left
*= Multiplication with assignment
/= Division with assignment
%= Module with assignment
+= Addition with assignment
-= Subtraction with assignment
<<= Left shift with assignment
>>= Right shift with assignment
&= Bitwise AND with assignment
^= Exclusive OR with assignment
|= Bitwise OR with assignment
, Comma From left to
right
Operators
Language operators describe some algorithmic operations that
must be executed to accomplish a task. The program body is a
sequence of such operators. Operators following one by one are
separated by semicolons.
Operator Description
Compound One or more operators of any type, enclosed in
operator {} curly braces {}
Expression Any expression that ends with a semicolon (;)
operator (;)
return operator Terminates the current function and returns
control to the calling program
if-else conditional Is used when it's necessary to make a choice
operator
?: conditional A simple analog of the if-else conditional
operator operator
switch selection Passes control to the operator, which corresponds
operator to the expression value
while loop Performs an operator until the expression
operator checked becomes false. The expression is
checked before each iteration
for loop operator Performs an operator until the expression
checked becomes false. The expression is
checked before each iteration
do-while loop Performs an operator until the expression
operator checked becomes false. The end condition is
checked, after each loop. The loop body is
always executed at least once.
Operator Description
break operator Terminates the execution of the nearest
attached external operator switch, while, do-
while or for
continue operator Passes control to the beginning of the nearest
external loop operator while, do-while or for
new operator Creates an object of the appropriate size and
returns a descriptor of the created object.
delete operator Deletes the object created by the new operator
See also
Initialization of Variables, Visibility Scope and Lifetime of
Variables, Creating and Deleting Objects
MQL4 Reference / Language Basics / Operators / Compound Operator
Compound Operator
A compound operator (a block) consists of one or more
operators of any type, enclosed in braces {}. The closing
brace must not be followed by a semicolon (;).
Example:
if(x==0) {
Print("invalid position x = ",x);
return;
}
See also
Initialization of Variables, Visibility Scope and Lifetime
of Variables, Creating and Deleting Objects
MQL4 Reference / Language Basics / Operators / Expression Operator
Expression Operator
Any expression followed by a semicolon (;) is the operator.
Here are some examples of expression operators.
Assignment Operator
Identifier = expression;
x=3; y=x=3;
bool equal=(x==y);
Empty Operator
Consists only of a semicolon (;) and is used to denote an
empty body of a control operator.
See also
Initialization of Variables, Visibility Scope and Lifetime
of Variables, Creating and Deleting Objects
MQL4 Reference / Language Basics / Operators / Return Operator
Return Operator
The return operator terminates the current function
execution and returns control to the calling program. The
expression calculation result is returned to the calling
function. The expression can contain an assignment
operator.
Example:
int CalcSum(int x, int y) {
return(x+y);
}
See also
Initialization of Variables, Visibility Scope and Lifetime
of Variables, Creating and Deleting Objects
MQL4 Reference / Language Basics / Operators / Ternary Operator ?:
Ternary Operator ?:
The general form of the ternary operator is as follows:
expression1 ? expression2 : expression3
For the first operand - "expression1" - any expression that results in a bool type value
can be used. If the result is true, then the operator set by the second operand, i.e.
"expression2" is executed.
If the first operand is false, the third operand - "expression3" is performed. The second
and third operands, i.e. "expression2" and "expression3" should return values of one type
and should not be of void type. The result of the conditional operator execution is the
result of expression2 or result of the expression3, depending on the result of
expression1.
//--- normalize difference between open and close prices for a day range double true_r
bool Expression1=true;
double Expression2=M_PI;
string Expression3="3.1415926";
void OnStart()
{
func(Expression2);
func(Expression3);
// Result:
// double argument: 3.141592653589793
// string argument: 3.1415926
// string argument: 3.141592653589793
// string argument: 3.1415926
See also
Initialization of Variables, Visibility Scope and Lifetime of Variables, Creating and
Deleting Objects
MQL4 Reference / Language Basics / Operators / Switch Operator
Switch Operator
Compares the expression value with constants in all the
case variants and passes control to the operator that
corresponds to the expression value. Each variant of case
can be marked with an integer constant, a literal constant
or a constant expression. The constant expression can't
contain variables or function calls. Expression of the
switch operator must be of integer type.
switch(expression) {
case constant: operators
case constant: operators
...
default: operators
}
See also
Initialization of Variables, Visibility Scope and Lifetime
of Variables, Creating and Deleting Objects
MQL4 Reference / Language Basics / Operators / Loop Operator while
See also
Initialization of Variables, Visibility Scope and Lifetime
of Variables, Creating and Deleting Objects
MQL4 Reference / Language Basics / Operators / Loop Operator for
See also
Initialization of Variables, Visibility Scope and Lifetime
of Variables, Creating and Deleting Objects
MQL4 Reference / Language Basics / Operators / Loop Operator do while
See also
Initialization of Variables, Visibility Scope and Lifetime of Variables, Creating
and Deleting Objects
MQL4 Reference / Language Basics / Operators / Break Operator
Break Operator
The break operator terminates the execution of the nearest nested
outward switch, while, do-while or for operator. The control is passed to
the operator that follows the terminated one. One of the purposes of
this operator is to finish the looping execution when a certain value is
assigned to a variable.
Example:
//--- searching for the first zero element for(i=0;i<array_size;i++)
if(array[i]==0)
break;
See also
Initialization of Variables, Visibility Scope and Lifetime of Variables,
Creating and Deleting Objects
MQL4 Reference / Language Basics / Operators / Continue Operator
Continue Operator
The continue operator passes control to the beginning of
the nearest outward loop while, do-while or for operator,
the next iteration being called. The purpose of this
operator is opposite to that of break operator.
Example:
//--- Sum of all nonzero elements int func(int array[])
{
int array_size=ArraySize(array);
int sum=0;
for(int i=0;i<array_size; i++)
{
if(a[i]==0) continue;
sum+=a[i];
}
return(sum);
}
See also
Initialization of Variables, Visibility Scope and Lifetime of
Variables, Creating and Deleting Objects
MQL4 Reference / Language Basics / Operators / Object Create Operator new
See also
Initialization of Variables, Visibility Scope and Lifetime
of Variables, Creating and Deleting Objects
MQL4 Reference / Language Basics / Functions
Functions
Every task can be divided into subtasks, each of which can either be directly
represented in the form of a code, or divided into smaller sub-tasks. This method is
called stepwise refinement. Functions are used for writing the code of sub-tasks to
be solved. The code that describes what a function does is called function definition:
function_header {
instructions
}
All that is before the first brace is the header of the function definition, and what is
between braces is the body of the function definition. The function header includes a
description of the return value type, name (identifier) and formal parameters. The
number of parameters passed to the function is limited and cannot exceed 64.
The function can be called from other parts of the program as many times as
necessary. In fact, the return type, function identifier and parameter types
constitute the function prototype.
Function prototype is the function declaration, but not its definition. Due to the
explicit declaration of the return type and a list of argument types, the strict type
checking and implicit typecasting are possible during function calls. Very often
function declarations are used in classes to improve the code readability.
The function definition must exactly match its declaration. Each declared function
must be defined.
Example:
double // return value type
linfunc (double a, double b) // function name and parameter list
{
// composite operator
return (a + b); // return value
}
The return operator can return the value of an expression located in this operator. If
necessary, the expression value is converted to the function result type. What can be
returned: simple types, simple structures, object pointers. With the return operator
you can't return any arrays, class objects, variables of compound structure type.
A function that returns no value should be described as that of void type.
Example:
void errmesg(string s)
{
Print("error: "+s);
}
Parameters passed to the function can have default values, which are defined by
constants of that type.
Example:
int somefunc(double a,
double d=0.0001,
int n=5,
bool b=true,
string s="passed string")
{
Print("Required parameter a = ",a);
Print("Pass the following parameters: d = ",d," n = ",n," b = ",b," s = ",s);
return(0);
}
If any of parameters has a default value, all subsequent parameters must also have
default values.
Example of incorrect declaration:
int somefunc(double a,
double d=0.0001, // default value 0.0001 declared
int n, // default value is not specified !
bool b, // default value is not specified !
string s="passed string")
{
}
See also
Overload, Virtual Functions, Polymorphism
MQL4 Reference / Language Basics / Functions / Function Call
Function Call
If a name that has not been described before, appears in the expression and is followed
by the left parenthesis, it is contextually considered as the name of a function.
function_name (x1, x2,..., xn)
Arguments (formal parameters) are passed by value, i.e. each expression x1,..., xn is
calculated, and the value is passed to the function. The order of expressions calculation
and the order of values loading are not guaranteed. During the execution, the system
checks the number and type of arguments passed to the function. Such way of
addressing to the function is called a value call.
Function call is an expression, the value of which is the value returned by the function.
The function type described above must correspond with the type of the return value.
The function can be declared or described in any part of the program on the global
scope, i.e., outside other functions. The function cannot be declared or described inside
of another function.
Examples:
int start() {
double some_array[4]={0.3, 1.4, 2.5, 3.6};
double a=linfunc(some_array, 10.5, 8);
//...
}
double linfunc(double x[], double a, double b)
{
return (a*x[0] + b);
}
At calling of a function with default parameters, the list of parameters to be passed can
be limited, but not before the first default parameter.
Examples:
void somefunc(double init,
double sec=0.0001, //set default values
int level=10);
//...
somefunc(); // Wrong call. The first parameter must be presented
somefunc(3.14); // Correct call
somefunc(3.14,0.0002); // Correct call
somefunc(3.14,0.0002,10); // Correct call
When calling a function, one may not skip parameters, even those having default values:
somefunc(3.14, , 10); // Wrong call -> the second parameter was skipped.
Use of several functions of the same name from different execution contexts in a
program may cause ambiguity. To avoid the ambiguity of function calls, always explicitly
specify the function scope using scope resolution operation.
See also
Overload, Virtual Functions, Polymorphism
MQL4 Reference / Language Basics / Functions / Passing Parameters
Passing Parameters
There are two methods, by which the machine language can pass arguments to a
subprogram (function). The first method is to send a parameter by value. This method
copies the argument value into a formal function parameter. Therefore, any changes in
this parameter within the function have no influence on the corresponding call
argument.
//+------------------------------------------------------------------+ //| Passing par
//+------------------------------------------------------------------+
double FirstMethod(int i,int j)
{
double res;
//---
i*=2;
j/=2;
res=i+j;
//---
return(res);
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//---
int a=14,b=8;
Print("a and b before call:",a," ",b);
double d=FirstMethod(a,b);
Print("a and b after call:",a," ",b);
}
//--- Result of script execution
// a and b before call: 14 8
// a and b after call: 14 8
The second method is to pass by reference. In this case, reference to a parameter (not
its value) is passed to a function parameter. Inside the function, it is used to refer to the
actual parameter specified in the call. This means that the parameter changes will
affect the argument used to call the function.
//+------------------------------------------------------------------+
//| Passing parameters by reference |
//+------------------------------------------------------------------+
double SecondMethod(int &i,int &j)
{
double res;
//---
i*=2;
j/=2;
res=i+j;
//---
return(res);
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//---
int a=14,b=8;
Print("a and b before call:",a," ",b);
double d=SecondMethod(a,b);
Print("a and b after call:",a," ",b);
}
//+------------------------------------------------------------------+
//--- result of script execution
// a and b before call: 14 8
// a and b after call: 28 4
MQL4 uses both methods, with one exception: arrays, structure type variables and class
objects are always passed by reference. In order to avoid changes in actual parameters
(arguments passed at function call) use the access specifier const. When trying to
change the contents of a variable declared with the const specifier, the compiler will
generate an error.
Note
It should be noted that parameters are passed to a function in reversed order, i.e., first
the last parameter is calculated and passed, and then the last but one, etc. The last
calculated and passed parameter is the one that stands first after opening parenthesis.
Example:
void OnStart()
{
//---
int a[]={0,1,2};
int i=0;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void func(int par1,int par2,string comment)
{
Print(comment,": par1 = ",par1," par2 = ",par2);
}
In first call (see example above) the i variable is first used in strings concatenation:
"First call (i = "+string(i)+")"
Here its value doesn't change. Then the i variable is used in calculation of the a[i++]
array element, i.e. when array element with index i is accessed, the i variable is
incremented. And only after that the first parameter with changed value of i variable is
calculated.
In the second call the same value of i (calculated on the first phase of function calling) is
used when calculating all three parameters. Only after the first parameters is calculated
the i variable is changed again.
See also
Visibility Scope and Lifetime of Variables, Overload, Virtual Functions, Polymorphism
MQL4 Reference / Language Basics / Functions / Function Overloading
Function Overloading
Usually the function name tends to reflect its main purpose. As a rule, readable
programs contain various well selected identifiers. Sometimes different functions are
used for the same purposes. Let's consider, for example, a function that calculates the
average value of an array of double precision numbers and the same function, but
operating with an array of integers. Both are convenient to be called AverageFromArray:
//+------------------------------------------------------------------+ //| The calcula
//+------------------------------------------------------------------+
double AverageFromArray(const double & array[],int size)
{
if(size<=0) return 0.0;
double sum=0.0;
double aver;
//---
for(int i=0;i<size;i++)
{
sum+=array[i]; // Summation for the double
}
aver=sum/size; // Just divide the sum by the number
//---
Print("Calculation of the average for an array of double type");
return aver;
}
//+------------------------------------------------------------------+
//| The calculation of average for an array of int type |
//+------------------------------------------------------------------+
double AverageFromArray(const int & array[],int size)
{
if(size<=0) return 0.0;
double aver=0.0;
int sum=0;
//---
for(int i=0;i<size;i++)
{
sum+=array[i]; // Summation for the int
}
aver=(double)sum/size;// Give the amount of type double, and divide
//---
Print("Calculation of the average for an array of int type");
return aver;
}
Each function contains the message output via the Print() function;
Print("Calculation of the average for an array of int type");
The compiler selects a necessary function in accordance with the types of arguments and
their quantity. The rule, according to which the choice is made, is called the signature
matching algorithm. A signature is a list of types used in the function declaration.
Example:
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//---
int a[5]={1,2,3,4,5};
double b[5]={1.1,2.2,3.3,4.4,5.5};
double int_aver=AverageFromArray(a,5);
double double_aver=AverageFromArray(b,5);
Print("int_aver = ",int_aver," double_aver = ",double_aver);
}
//--- Result of the script
// Calculate the average for an array of int type
// Calculate the average for an array of double type
// int_aver= 3.00000000 double_aver= 3.30000000
Function overloading is a process of creating several functions with the same name, but
different parameters. This means that in overloaded variants of a function, the number
of arguments and/or their type must be different. A specific function variant is selected
based on the correspondence of the list of arguments when calling the function, to the
list of parameters in the function declaration.
When an overloaded function is called, the compiler must have an algorithm to select
the appropriate function. The algorithm that performs this choice depends on castings of
what types are present. The best correspondence must be unique. An overloaded
function must be the best match among all the other variants for at least one argument.
At the same time it must match for all other arguments not worse than other variants.
Below is a matching algorithm for each argument.
See also
Overload, Virtual Functions, Polymorphism
MQL4 Reference / Language Basics / Functions / Operation Overloading
Operation Overloading
For ease of code reading and writing, overloading of some operations is allowed.
Overloading operator is written using the keyword operator. The following operators can
be overloaded:
binary +,-,/,*,%,<<,>>,==,!=,<,>,<=,>=,=,+=,-=,/=,*=,%=,&=,|=,^=,
<<=,>>=,&&,||,&,|,^
unary +,-,++,--,!,~
assignment operator =
indexing operator []
Operation overloading allows the use of the operating notation (written in the form of
simple expressions) for complex objects - structures and classes. Writing expressions
using overloaded operations simplifies the view of the source code, because a more
complex implementation is hidden.
For example, consider complex numbers, which consist of real and imaginary parts. They
are widely used in mathematics. The MQL4 language has no data type to represent
complex numbers, but it is possible to create a new data type in the form of a structure
or class. Declare the complex structure and define four methods that implement four
arithmetic operations:
//+------------------------------------------------------------------+ //| A structure
//+------------------------------------------------------------------+
struct complex
{
double re; // Real part
double im; // Imaginary part
//--- Constructors
complex():re(0.0),im(0.0) { }
complex(const double r):re(r),im(0.0) { }
complex(const double r,const double i):re(r),im(i) { }
complex(const complex &o):re([Link]),im([Link]) { }
//--- Arithmetic operations
complex Add(const complex &l,const complex &r) const; // Addition
complex Sub(const complex &l,const complex &r) const; // Subtraction
complex Mul(const complex &l,const complex &r) const; // Multiplication
complex Div(const complex &l,const complex &r) const; // Division
};
Now, in our code we can declare variables representing complex numbers, and work with
them.
For example:
void OnStart()
{
//--- Declare and initialize variables of a complex type
complex a(2,4),b(-4,-2);
PrintFormat("a=%.2f+i*%.2f, b=%.2f+i*%.2f",[Link],[Link],[Link],[Link]);
//--- Sum up two numbers
complex z;
z=[Link](a,b);
PrintFormat("a+b=%.2f+i*%.2f",[Link],[Link]);
//--- Multiply two numbers
z=[Link](a,b);
PrintFormat("a*b=%.2f+i*%.2f",[Link],[Link]);
//--- Divide two numbers
z=[Link](a,b);
PrintFormat("a/b=%.2f+i*%.2f",[Link],[Link]);
//---
}
But it would be more convenient to use usual operators "+", "-", "*" and "/" for ordinary
arithmetic operations with complex numbers.
Keyword operator is used for defining a member function that performs type conversion.
Unary and binary operations for class object variables can be overloaded as non-static
member functions. They implicitly act on the class object.
Most binary operations can be overloaded like regular functions that take one or both
arguments as a class variable or a pointer to an object of this class. For our type
complex, overloading in the declaration will look like this:
//--- Operators
complex operator+(const complex &r) const { return(Add(this,r)); }
complex operator-(const complex &r) const { return(Sub(this,r)); }
complex operator*(const complex &r) const { return(Mul(this,r)); }
complex operator/(const complex &r) const { return(Div(this,r)); }
z=a*b;
PrintFormat("a*b=%.2f+i*%.2f",[Link],[Link]);
//--- Divide two numbers
z=a/b;
PrintFormat("a/b=%.2f+i*%.2f",[Link],[Link]);
//---
}
//+------------------------------------------------------------------+
//| A structure for operations with complex numbers |
//+------------------------------------------------------------------+
struct complex
{
double re; // Real part
double im; // Imaginary part
//--- Constructors
complex():re(0.0),im(0.0) { }
complex(const double r):re(r),im(0.0) { }
complex(const double r,const double i):re(r),im(i) { }
complex(const complex &o):re([Link]),im([Link]) { }
//--- Arithmetic operations
complex Add(const complex &l,const complex &r) const; // Addition
complex Sub(const complex &l,const complex &r) const; // Subtraction
complex Mul(const complex &l,const complex &r) const; // Multiplication
complex Div(const complex &l,const complex &r) const; // Division
//--- Binary operators
complex operator+(const complex &r) const { return(Add(this,r)); }
complex operator-(const complex &r) const { return(Sub(this,r)); }
complex operator*(const complex &r) const { return(Mul(this,r)); }
complex operator/(const complex &r) const { return(Div(this,r)); }
};
//+------------------------------------------------------------------+
//| Addition |
//+------------------------------------------------------------------+
complex complex::Add(const complex &l,const complex &r) const
{
complex res;
//---
[Link]=[Link]+[Link];
[Link]=[Link]+[Link];
//--- Result
return res;
}
//+------------------------------------------------------------------+
//| Subtraction |
//+------------------------------------------------------------------+
complex complex::Sub(const complex &l,const complex &r) const
{
complex res;
//---
[Link]=[Link];
[Link]=[Link];
//--- Result
return res;
}
//+------------------------------------------------------------------+
//| Multiplication |
//+------------------------------------------------------------------+
complex complex::Mul(const complex &l,const complex &r) const
{
complex res;
//---
[Link]=[Link]*[Link]*[Link];
[Link]=[Link]*[Link]+[Link]*[Link];
//--- Result
return res;
}
//+------------------------------------------------------------------+
//| Division |
//+------------------------------------------------------------------+
complex complex::Div(const complex &l,const complex &r) const
{
//--- Empty complex number
complex res(EMPTY_VALUE,EMPTY_VALUE);
//--- Check for zero
if([Link]==0 && [Link]==0)
{
Print(__FUNCTION__+": number is zero");
return(res);
}
//--- Auxiliary variables
double e;
double f;
//--- Selecting calculation variant
if(MathAbs([Link])<MathAbs([Link]))
{
e = [Link]/[Link];
f = [Link]+[Link]*e;
[Link]=([Link]+[Link]*e)/f;
[Link]=([Link]*e)/f;
}
else
{
e = [Link]/[Link];
f = [Link]+[Link]*e;
[Link]=([Link]+[Link]*e)/f;
[Link]=(-[Link]+[Link]*e)/f;
}
//--- Result
return res;
}
Most unary operations for classes can be overloaded as ordinary functions that accept a
single class object argument or a pointer to it. Add overloading of unary operations "-"
and "!".
//+------------------------------------------------------------------+
//| Structure for operations with complex numbers |
//+------------------------------------------------------------------+
struct complex
{
double re; // Real part
double im; // Imaginary part
...
//--- Unary operators
complex operator-() const; // Unary minus
bool operator!() const; // Negation
};
...
//+------------------------------------------------------------------+
//| Overloading the "unary minus" operator |
//+------------------------------------------------------------------+
complex complex::operator-() const
{
complex res;
//---
[Link]=-re;
[Link]=-im;
//--- Result
return res;
}
//+------------------------------------------------------------------+
//| Overloading the "logical negation" operator |
//+------------------------------------------------------------------+
bool complex::operator!() const
{
//--- Are the real and imaginary parts of the complex number equal to zero?
return (re!=0 && im!=0);
}
Now we can check the value of a complex number for zero and get a negative value:
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- Declare and initialize variables of type complex
complex a(2,4),b(-4,-2);
PrintFormat("a=%.2f+i*%.2f, b=%.2f+i*%.2f",[Link],[Link],[Link],[Link]);
//--- Divide the two numbers
complex z=a/b;
PrintFormat("a/b=%.2f+i*%.2f",[Link],[Link]);
//--- A complex number is equal to zero by default (in the default constructor re==0
complex zero;
Print("!zero=",!zero);
//--- Assign a negative value
zero=-z;
PrintFormat("z=%.2f+i*%.2f, zero=%.2f+i*%.2f",[Link],[Link], [Link],[Link]);
PrintFormat("-zero=%.2f+i*%.2f",-[Link],-[Link]);
//--- Check for zero once again
Print("!zero=",!zero);
//---
}
Note that we did not have to overload the assignment operator "=", as structures of
simple types can be directly copied one into each other. Thus, we can now write a code
for calculations involving complex numbers in the usual manner.
Overloading of the indexing operator allows to obtain the values of the arrays enclosed
in an object, in a simple and familiar way, and it also contributes to a better readability
of the source code. For example, we need to provide access to a symbol in the string at
the specified position. A string in MQL4 is a separate type string, which is not an array of
symbols, but with the help of an overloaded indexing operation we can provide a simple
and transparent work in the generated CString class:
//+------------------------------------------------------------------+
//| Class to access symbols in string as in array of symbols |
//+------------------------------------------------------------------+
class CString
{
string m_string;
public:
CString(string str=NULL):m_string(str) { }
ushort operator[] (int x) { return(StringGetCharacter(m_string,x)); }
};
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- An array for receiving symbols from a string
int x[]={ 19,4,18,19,27,14,15,4,17,0,19,14,17,27,26,28,27,5,14,
17,27,2,11,0,18,18,27,29,30,19,17,8,13,6 };
CString str("abcdefghijklmnopqrstuvwxyz[ ]CS");
string res;
//--- Make up a phrase using symbols from the str variable
for(int i=0,n=ArraySize(x);i<n;i++)
{
res+=ShortToString(str[x[i]]);
}
//--- Show the result
Print(res);
}
Another example of overloading of the indexing operation is operations with matrices.
The matrix represents a two-dimensional dynamic array, the array size is not defined in
advance. Therefore, you cannot declare an array of form array[][] without specifying the
size of the second dimension, and then pass this array as a parameter. A possible solution
is a special class CMatrix, which contains an array of CRow class objects.
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- Operations of addition and multiplication of matrices
CMatrix A(3),B(3),C();
//--- Prepare an array for rows
double a1[3]={1,2,3}, a2[3]={2,3,1}, a3[3]={3,1,2};
double b1[3]={3,2,1}, b2[3]={1,3,2}, b3[3]={2,1,3};
//--- Fill the matrices
A[0]=a1; A[1]=a2; A[2]=a3;
B[0]=b1; B[1]=b2; B[2]=b3;
//--- Output the matrices in the Experts log
Print("---- Elements of matrix A");
Print([Link]());
Print("---- Elements of matrix B");
Print([Link]());
//--- Now we show how to get values in the style of dynamic arrays matrix[i][j]
Print("Output the values of matrix C elementwise");
//--- Go through the matrix rows - CRow objects - in a loop
for(int i=0;i<3;i++)
{
string com="| ";
//--- Form rows from the matrix for the value
for(int j=0;j<3;j++)
{
//--- Get the matrix element by the number of the row and column
double element=C[i][j];// [i] - Access to CRow in the array m_rows[] ,
// [j] - Overloaded operator of indexing in CRow
com=com+StringFormat("a(%d,%d)=%G ; ",i,j,element);
}
com+="|";
//--- Output the values of the row
Print(com);
}
}
//+------------------------------------------------------------------+
//| Class "Row" |
//+------------------------------------------------------------------+
class CRow
{
private:
double m_array[];
public:
//--- Constructors and a destructor
CRow(void) { ArrayResize(m_array,0); }
CRow(const CRow &r) { this=r; }
CRow(const double &array[]);
~CRow(void){};
//--- Number of elements in the row
int Size(void) const { return(ArraySize(m_array));}
//--- Returns a string with values
string String(void) const;
//--- Indexing operator
double operator[](int i) const { return(m_array[i]); }
//--- Assignment operators
void operator=(const double &array[]); // An array
void operator=(const CRow & r); // Another CRow object
double operator*(const CRow &o); // CRow object for multiplica
};
//+------------------------------------------------------------------+
//| Constructor for initializing a row with an array |
//+------------------------------------------------------------------+
void CRow::CRow(const double &array[])
{
int size=ArraySize(array);
//--- If the array is not empty
if(size>0)
{
ArrayResize(m_array,size);
//--- Fill with values
for(int i=0;i<size;i++)
m_array[i]=array[i];
}
//---
}
//+------------------------------------------------------------------+
//| Assignment operation for the array |
//+------------------------------------------------------------------+
void CRow::operator=(const double &array[])
{
int size=ArraySize(array);
if(size==0) return;
//--- Fill the array with values
ArrayResize(m_array,size);
for(int i=0;i<size;i++) m_array[i]=array[i];
//---
}
//+------------------------------------------------------------------+
//| Assignment operation for CRow |
//+------------------------------------------------------------------+
void CRow::operator=(const CRow &r)
{
int size=[Link]();
if(size==0) return;
//--- Fill the array with values
ArrayResize(m_array,size);
for(int i=0;i<size;i++) m_array[i]=r[i];
//---
}
//+------------------------------------------------------------------+
//| Operator of multiplication by another row |
//+------------------------------------------------------------------+
double CRow::operator*(const CRow &o)
{
double res=0;
//--- Verifications
int size=Size();
if(size!=[Link]() || size==0)
{
Print(__FUNCSIG__,": Failed to multiply two matrices, their sizes are different
return(res);
}
//--- Multiply arrays elementwise and add the products
for(int i=0;i<size;i++)
res+=m_array[i]*o[i];
//--- Result
return(res);
}
//+------------------------------------------------------------------+
//| Returns a formatted string representation |
//+------------------------------------------------------------------+
string CRow::String(void) const
{
string out="";
//--- If the size of the array is greater than zero
int size=ArraySize(m_array);
//--- We work only with a non-zero number of array elements
if(size>0)
{
out="{";
for(int i=0;i<size;i++)
{
//--- Collect the values to a string
out+=StringFormat(" %G;",m_array[i]);
}
out+=" }";
}
//--- Result
return(out);
}
//+------------------------------------------------------------------+
//| Class "Matrix" |
//+------------------------------------------------------------------+
class CMatrix
{
private:
CRow m_rows[];
public:
//--- Constructors and a destructor
CMatrix(void);
CMatrix(int rows) { ArrayResize(m_rows,rows); }
~CMatrix(void){};
//--- Get the matrix sizes
int Rows() const { return(ArraySize(m_rows)); }
int Cols() const { return(Rows()>0? m_rows[0].Size():0); }
//--- Returns the value of the column in the form of a CRow row
CRow GetColumnAsRow(const int col_index) const;
//--- Returns a string with the matrix values
string String(void) const;
//--- The indexing operator returns a string by its number
CRow *operator[](int i) const { return(GetPointer(m_rows[i])); }
//--- Addition operator
CMatrix operator+(const CMatrix &m);
//--- Multiplication operator
CMatrix operator*(const CMatrix &m);
//--- Assignment operator
CMatrix *operator=(const CMatrix &m);
};
//+------------------------------------------------------------------+
//| Default constructor, create and array of rows of zero size |
//+------------------------------------------------------------------+
CMatrix::CMatrix(void)
{
//--- The zero number of rows in the matrix
ArrayResize(m_rows,0);
//---
}
//+------------------------------------------------------------------+
//| Returns the column value in the form of CRow |
//+------------------------------------------------------------------+
CRow CMatrix::GetColumnAsRow(const int col_index) const
{
//--- A variable to get the values from the column
CRow row();
//--- The number of rows in the matrix
int rows=Rows();
//--- If the number of rows is greater than zero, execute the operation
if(rows>0)
{
//--- An array to receive the values of the column with index col_index
double array[];
ArrayResize(array,rows);
//--- Filling the array
for(int i=0;i<rows;i++)
{
//--- Check the number of the column for row i - it may exceed the boundarie
if(col_index>=this[i].Size())
{
Print(__FUNCSIG__,": Error! Column number ",col_index,"> row size ",i);
break; // row will be uninitialized object
}
array[i]=this[i][col_index];
}
//--- Create a CRow row based on the array values
row=array;
}
//--- Result
return(row);
}
//+------------------------------------------------------------------+
//| Addition of two matrices |
//+------------------------------------------------------------------+
CMatrix CMatrix::operator+(const CMatrix &m)
{
//--- The number of rows and columns in the passed matrix
int cols=[Link]();
int rows=[Link]();
//--- The matrix to receive the addition results
CMatrix res(rows);
//--- The sizes of the matrix must match
if(cols!=Cols() || rows!=Rows())
{
//--- Addition impossible
Print(__FUNCSIG__,": Failed to add two matrices, their sizes are different");
return(res);
}
//--- Auxiliary array
double arr[];
ArrayResize(arr,cols);
//--- Go through rows to add
for(int i=0;i<rows;i++)
{
//--- Write the results of addition of matrix strings in the array
for(int k=0;k<cols;k++)
{
arr[k]=this[i][k]+m[i][k];
}
//--- Place the array to the matrix row
res[i]=arr;
}
//--- return the result of addition of matrices
return(res);
}
//+------------------------------------------------------------------+
//| Multiplication of two matrices |
//+------------------------------------------------------------------+
CMatrix CMatrix::operator*(const CMatrix &m)
{
//--- Number of columns of the first matrix, number of rows passed in the matrix
int cols1=Cols();
int rows2=[Link]();
int rows1=Rows();
int cols2=[Link]();
//--- Matrix to receive the addition result
CMatrix res(rows1);
//--- Matrices should be coordinated
if(cols1!=rows2)
{
//--- Multiplication impossible
Print(__FUNCSIG__,": Failed to multiply two matrices, format is not compatible
"- number of columns in the first factor should be equal to the number of
return(res);
}
//--- Auxiliary array
double arr[];
ArrayResize(arr,cols1);
//--- Fill the rows in the multiplication matrix
for(int i=0;i<rows1;i++)// Go through rows
{
//--- Reset the receiving array
ArrayInitialize(arr,0);
//--- Go through elements in the row
for(int k=0;k<cols1;k++)
{
//--- Take values of column k of the matrix m in the for of CRow
CRow column=[Link](k);
//--- Multiply two rows and write the result of scalar multiplication of vec
arr[k]=this[i]*column;
}
//--- place array arr[] in the i-th row of the matrix
res[i]=arr;
}
//--- Return the product of two matrices
return(res);
}
//+------------------------------------------------------------------+
//| Assignment operation |
//+------------------------------------------------------------------+
CMatrix *CMatrix::operator=(const CMatrix &m)
{
//--- Find and set the number of rows
int rows=[Link]();
ArrayResize(m_rows,rows);
//--- Fill our rows with the values of rows of the passed matrix
for(int i=0;i<rows;i++) this[i]=m[i];
//---
return(GetPointer(this));
}
//+------------------------------------------------------------------+
//| String representation of the matrix |
//+------------------------------------------------------------------+
string CMatrix::String(void) const
{
string out="";
int rows=Rows();
//--- Form string by string
for(int i=0;i<rows;i++)
{
out=out+this[i].String()+"\r\n";
}
//--- Result
return(out);
}
See also
Overloading, Arithmetic Operations, Function Overloading, Precedence Rules
MQL4 Reference / Language Basics / Functions / Description of External Functions
With the help of import, it is easy to describe functions that are called from external
DLL or compiled EX4 libraries. EX4 libraries are compiled ex4 files, which have the
library property. Only function described with the export modifier can be imported from
EX4 libraries.
Please keep in mind that DLL and EX4 libraries should have different names (regardless
of the directories they are located in) if they are imported together. All imported
functions have the scope resolution corresponding to the library's "file name".
Use of several functions of the same name from different execution contexts in a
program may cause ambiguity. To avoid the ambiguity of function calls, always explicitly
specify the function scope using the scope resolution operation.
Example:
#import "[Link]"
int GetLastError();
#import "lib.ex4"
int GetLastError();
#import
class CFoo
{
public:
int GetLastError() { return(12345); }
void func()
{
Print(GetLastError()); // call of the class method
Print(::GetLastError()); // call of the MQL5 function
Print(kernel32::GetLastError()); // call of the DLL library function from kerne
Print(lib::GetLastError()); // call of the EX4 library function from lib.e
}
};
void OnStart()
{
CFoo foo;
[Link]();
}
See also
Overload, Virtual Functions, Polymorphism
MQL4 Reference / Language Basics / Functions / Exporting Functions
Exporting Functions
A function declared in a mql4 program with the export
postmodifier can be used in another mql4 program. Such a
function is called exportable, and it can be called from
other programs after compilation.
int Function() export {
}
For the OnStart() function, the int return type can be specified.
OnInit
The OnInit() function is the Init event handler. It must be of void or int type, with no
parameters:
void OnInit();
The OnInit() function of the void type always denotes successful initialization.
OnDeinit
The OnDeinit() function is called during deinitialization and is the Deinit event handler. It
must be declared as the void type and should have one parameter of the const int type,
which contains the code of deinitialization reason. If a different type is declared, the
compiler will generate a warning, but the function will not be called.
void OnDeinit(const int reason);
The Deinit event is generated for Expert Advisors and indicators in the following cases:
before reinitialization due to the change of a symbol or chart period, to which the
mql4 program is attached;
before reinitialization due to the change of input parameters;
before unloading the mql4 program.
OnTick
The NewTick event is generated for Expert Advisors only when a new tick for a symbol
is received, to the chart of which the Expert Advisor is attached. It's useless to define
the OnTick() function in a custom indicator or script, because the NewTick event is not
generated for them.
The Tick event is generated only for Expert Advisors, but this does not mean that Expert
Advisors required the OnTick() function, since not only NewTick events are generated for
Expert Advisors, but also events of Timer, BookEvent and ChartEvent are generated. It
must be declared as the void type, with no parameters:
void OnTick();
OnTimer
The OnTimer() function is called when the Timer event occurs, which is generated by the
system timer only for Expert Advisors and indicators - it can't be used in scripts. The
frequency of the event occurrence is set when subscribing to notifications about this
event to be received by the EventSetTimer() function.
You can unsubscribe from receiving timer events for a particular Expert Advisor using the
EventKillTimer() function. The function must be defined with the void type, with no
parameters:
void OnTimer();
The function is called right before the call of OnDeinit() and has the same type of the
return value - double. OnTester() can be used only in the testing of Expert Advisors. Its
main purpose is to calculate a certain value that is used as the Custom max criterion in
the genetic optimization of input parameters.
In the genetic optimization descending sorting is applied to results within one
generation. I.e. from the point of view of the optimization criterion, the best results are
those with largest values (for the Custom max optimization criterion values returned by
the OnTester function are taken into account). In such a sorting, the worst values are
positioned at the end and further thrown off and do not participate in the forming of the
next generation.
OnChartEvent
OnChartEvent() is the handler of a group of ChartEvent events:
CHARTEVENT_KEYDOWN event of a keystroke, when the chart window is focused;
CHARTEVENT_MOUSE_MOVE mouse move events and mouse click events (if
CHART_EVENT_MOUSE_MOVE=true is set for the chart);
CHARTEVENT_OBJECT_CREATE event of graphical object creation (if
CHART_EVENT_OBJECT_CREATE=true is set for the chart);
CHARTEVENT_OBJECT_CHANGE event of change of an object property via the
properties dialog;
CHARTEVENT_OBJECT_DELETE event of graphical object deletion (if
CHART_EVENT_OBJECT_DELETE=true is set for the chart);
CHARTEVENT_CLICK event of a mouse click on the chart;
CHARTEVENT_OBJECT_CLICK event of a mouse click in a graphical object belonging to
the chart;
CHARTEVENT_OBJECT_DRAG event of a graphical object move using the mouse;
CHARTEVENT_OBJECT_ENDEDIT event of the finished text editing in the entry box of
the LabelEdit graphical object;
CHARTEVENT_CHART_CHANGE event of chart changes;
CHARTEVENT_CUSTOM+n ID of the user event, where n is in the range from 0 to
65535.
CHARTEVENT_CUSTOM_LAST the last acceptable ID of a custom event
(CHARTEVENT_CUSTOM +65535).
The function can be called only in Expert Advisors and indicators. The function should be
of void type with 4 parameters:
void OnChartEvent(const int id, // Event ID const long& lpar
const double& dparam, // Parameter of type double event
const string& sparam // Parameter of type string events
);
For each type of event, the input parameters of the OnChartEvent() function have
definite values that are required for the processing of this event. The events and values
passed through these parameters are listed in the table below.
Event Value of the id parameter Value of the lparam Value
parameter dpara
Event of a keystroke CHARTEVENT_KEYDOWN code of a pressed Repea
key numb
the
repea
of the
down
Mouse events (if property CHARTEVENT_MOUSE_MOVE the X coordinate the Y
CHART_EVENT_MOUSE_MOVE=true is
set for the chart)
Parameters of open[], high[], low[] and close[] contain arrays with open prices, high and
low prices and close prices of the current time frame. The time[] parameter contains an
array with open time values, the spread[] parameter has an array containing the history
of spreads (if any spread is provided for the traded security). The parameters of
volume[] and tick_volume[] contain the history of trade and tick volume, respectively.
To determine the indexing direction of time[], open[], high[], low[], close[],
tick_volume[], volume[] and spread[], call ArrayGetAsSeries(). In order not to depend on
default values, you should unconditionally call the ArraySetAsSeries() function for those
arrays, which are expected to work with.
The first rates_total parameter contains the number of bars, available to the indicator
for calculation, and corresponds to the number of bars available in the chart.
We should note the connection between the return value of OnCalculate() and the
second input parameter prev_calculated. During the function call, the prev_calculated
parameter contains a value returned by OnCalculate() during previous call. This allows
for economical algorithms for calculating the custom indicator in order to avoid
repeated calculations for those bars that haven't changed since the previous run of this
function.
For this, it is usually enough to return the value of the rates_total parameter, which
contains the number of bars in the current function call. If since the last call of
OnCalculate() price data has changed (a deeper history downloaded or history blanks
filled), the value of the input parameter prev_calculated will be set to zero by the
terminal.
To understand it better, it would be useful to start the indicator, which code is attached
below.
Indicator Example:
#property indicator_chart_window
#property indicator_buffers 1
//---- plot Line
#property indicator_label1 "Line"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrDarkBlue
#property indicator_style1 STYLE_SOLID
#property indicator_width1 1
//--- indicator buffers
double LineBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
SetIndexBuffer(0,LineBuffer,INDICATOR_DATA);
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime& time[],
const double& open[],
const double& high[],
const double& low[],
const double& close[],
const long& tick_volume[],
const long& volume[],
const int& spread[])
{
//--- Get the number of bars available for the current symbol and chart period
int bars=Bars(Symbol(),0);
Print("Bars = ",bars,", rates_total = ",rates_total,", prev_calculated = ",prev_c
Print("time[0] = ",time[0]," time[rates_total-1] = ",time[rates_total-1]);
//--- return value of prev_calculated for next call
return(rates_total);
}
See also
Running Programs, Client Terminal Events, Working with Events
MQL4 Reference / Language Basics / Variables
Variables
Declaring Variables
Variables must be declared before they are used. Unique names are used to
identify variables. To declare a variable, you must specify its type and a unique
name. Declaration of variable is not an operator.
Simple types are:
char, short, int, long, uchar, ushort, uint, ulong integers;
color integer representing the RGB-color;
datetime the date and time, an unsigned integer containing the number of
seconds since 0 hour January 1, 1970;
bool boolean values true and false;
double double-precision floating point number;
float single-precision floating point number;
string character strings.
Examples:
string szInfoBox; int nOrders;
double dSymbolPrice;
bool bLog;
datetime tBegin_Data = D'2004.01.01 00:00';
color cModify_Color = C'0x44,0xB9,0xE6';
You can't declare variables of the structure type until you declare the structure.
Arrays
Array is the indexed sequence of identical-type data:
int a[50]; // One-dimensional array of 50 integers.
double m[7][50]; // Two-dimensional array of seven arrays,
// each of them consisting of 50 numbers.
MyTime t[100]; // Array containing elements such as MyTime
Only an integer can be an array index. No more than four-dimensional arrays are
allowed. Numbering of array elements starts with 0. The last element of a one-
dimensional array has the number which is 1 less than the array size. This means
that call for the last element of an array consisting of 50 integers will appear as
a[49]. The same concerns multidimensional arrays: A dimension is indexed from 0
to the dimension size-1. The last element of a two-dimensional array from the
example will appear as m[6][49].
Static arrays can't be represented as timeseries, i.e., the ArraySetAsSeries()
function, which sets access to array elements from the end to beginning, can't be
applied to them. If you want to provide access to an array the same as in
timeseries, use the dynamic array object.
If there is an attempt to access out of the array range, the executing subsystem
will generate a critical error and the program will be stopped.
Access Specifiers
Access specifiers define how the compiler can access variables, members of
structures or classes.
The const specifier declares a variable as a constant, and does not allow to
change this variable during runtime. A single initialization of a variable is allowed
when declaring it.
Example:
int OnCalculate (const int rates_total, // size of input time series
const int prev_calculated, // bars handled in previous call
const datetime& time[], // Time
const double& open[], // Open
const double& high[], // High
const double& low[], // Low
const double& close[], // Close
const long& tick_volume[], // Tick Volume
const long& volume[], // Real Volume
const int& spread[] // Spread
);
Local Variables
A variable declared inside a function is local. The scope of
a local variable is limited to the function range inside
which it is declared. Local variable can be initialized by
outcome of any expression. Every call of the function
initializes a local variable. Local variables are stored in
memory area of the corresponding function.
Example:
int somefunc() {
int ret_code=0;
...
return(ret_code);
}
Stack
In every MQL4 program, a special memory area called
stack is allocated for storing local function variables that
are created automatically. One stack is allocated for all
functions. The default stack size is 256 kb, the stack size
can be managed using the #property stacksize compiler
directive.
Static local variables are stored in the same place where
other static and global variables are stored - in a special
memory area, which exists separately from the stack.
Dynamically created variables also use a memory area
separate from the stack.
With each function call, a place on the stack is allocated
for internal non-static variables. After exiting the function,
the memory is available for use again.
If from the first function the second one is called, then the
second function occupies the required size from the
remaining stack memory for its variables. Thus, when using
included functions, stack memory will be sequentially
occupied for each function. This may lead to a shortage of
memory during one of the function calls, such a situation is
called stack overflow.
Therefore, for large local data you should better use
dynamic memory - when entering a function, allocate the
memory, which is required for local needs, in the system
(new, ArrayResize()), and when exiting the function,
release the memory (delete, ArrayFree()).
See also
Data Types, Encapsulation and Extensibility of
Types,Initialization of Variables, Visibility Scope and
Lifetime of Variables, Creating and Deleting Objects
MQL4 Reference / Language Basics / Variables / Formal Parameters
Formal Parameters
Parameters passed to the function are local. The scope is
the function block. Formal parameters must have names
differing from those of external variables and local
variables defined within one function. Some values can be
assigned to formal parameters in the function block. If a
formal parameter is declared with the const modifier, its
value can't be changed within the function.
Example:
void func(const int & x[], double y, bool z) {
if(y>0.0 && !z)
Print(x[0]);
...
}
Static Variables
The storage class of static defines a static variable. The static modifier is indicated
before the data type.
Example:
int somefunc() {
static int flag=10;
...
return(flag);
}
Global Variables
Global variables are created by placing their declarations
outside function descriptions. Global variables are defined
at the same level as functions, i.e., they are not local in
any block.
Example:
int GlobalFlag=10; // Global variable int OnStart()
{
...
}
Input Variables
The input storage class defines the external variable. The input modifier
is indicated before the data type. A variable with the input modifier can't
be changed inside mql4-programs, such variables can be accessed for
reading only. Values of input variables can be changed only by a user from
the program properties window. External variables are always
reinitialized immediately before the OnInit() is called.
Example:
//--- input parameters input int MA_Period=13;
input int MA_Shift=0;
input ENUM_MA_METHOD MA_Method=MODE_SMMA;
There is another way to set how your input parameter will look like in the
Inputs tab. For this, place a string comment after the description of an
input parameter in the same line. In this way you can make names of
input parameters more understandable for users.
Example:
//--- input parameters
input int InpMAPeriod=13; // Smoothing period
input int InpMAShift=0; // Line horizontal shift
input ENUM_MA_METHOD InpMAMethod=MODE_SMMA; // Smoothing method
Note: Arrays and variables of complex types can't act as input variables.
Note: The length of a string comment for Input variables cannot exceed
63 characters.
Passing Parameters When Calling Custom Indicators from
MQL4 Programs
Custom Indicators are called using the iCustom() function. After the name
of the custom indicator, parameters should go in a strict accordance with
the declaration of input variables of this custom indicator. If indicated
parameters are less than input variables declared in the called custom
indicator, the missing parameters are filled with values specified during
the declaration of variables.
If the custom indicator uses the OnCalculate function of the first type
(i.e., the indicator is calculated using the same array of data), then one
of ENUM_APPLIED_PRICE values or handle of another indicator should be
used as the last parameter when calling such a custom indicator. All
parameters corresponding to input variables must be clearly indicated.
Enumerations as input Parameters
Not only built-in enumerations provided in MQL4, but also user defined
variables can be used as input variables (input parameters for mql4
programs). For example, we can create the dayOfWeek enumeration,
describing days of the week, and use the input variable to specify a
particular day of the week, not as a number, but in a more common way.
Example:
#property script_show_inputs
//--- day of week
enum dayOfWeek
{
S=0, // Sunday
M=1, // Monday
T=2, // Tuesday
W=3, // Wednesday
Th=4, // Thursday
Fr=5, // Friday,
St=6, // Saturday
};
//--- input parameters
input dayOfWeek swapday=W;
Extern variables
The extern storage class defines the external variable. The extern modifier is
indicated before the data type.
//--- extern parameters extern int MA_Period=13;
extern int MA_Shift=0;
extern ENUM_MA_METHOD MA_Method=MODE_SMMA;
Strict compilation mode with the output of the input parameters window is set in
this script. Therefore, the values set in the string comments instead of ExtVar and
InpVar variable names are displayed in Variable field.
Note: Arrays and variables of complex types can't act as extern variables.
Note: The length of a string comment for extern variables cannot exceed 63
characters.
See also
Input Variables, Data Types, Encapsulation and Extensibility of Types, Initialization
of Variables, Visibility Scope and Lifetime of Variables, Creating and Deleting
Objects
MQL4 Reference / Language Basics / Variables / Initialization of Variables
Initialization of Variables
Any variable can be initialized during definition. If a variable is not initialized
explicitly, the value stored in this variable can be any. Implicit initialization is not
used.
Global and static variables can be initialized only by a constant of the
corresponding type or a constant expression. Local variables can be initialized by
any expression, not just a constant.
Initialization of global and static variables is performed only once. Initialization of
local variables is made every time you call the corresponding functions.
Examples:
int n = 1; string s = "hello";
double f[] = { 0.0, 0.236, 0.382, 0.5, 0.618, 1.0 };
int a[4][4] = { {1, 1, 1, 1}, {2, 2, 2, 2}, {3, 3, 3, 3}, {4, 4, 4, 4 } };
//--- from tetris
int right[4]={WIDTH_IN_PIXELS+VERT_BORDER,WIDTH_IN_PIXELS+VERT_BORDER,
WIDTH_IN_PIXELS+VERT_BORDER,WIDTH_IN_PIXELS+VERT_BORDER};
//--- initialization of all fields of the structure with zero values
MqlTradeRequest request={0};
List of values of the array elements must be enclosed in curly brackets. Missed
initializing sequences are considered equal to 0. The initializing sequence must
have at least one value: this value is initialized to the first element of the
corresponding structure or array, missing elements are considered equal to zero.
If the size of the initialized array is not specified, it is determined by a compiler,
based on the size of the initialization sequence. Multi-dimensional arrays cannot
be initialized by a one-dimensional sequence (a sequence without additional curly
brackets), except for the case, when only one initializing element is specified
(zero, as a rule).
Arrays (including those announced at the local level) can be initialized only by
constants.
Examples:
struct str3
{
int low_part;
int high_part;
};
struct str10
{
str3 s3;
double d1[10];
int i3;
};
void OnStart()
{
str10 s10_1={{1,0},{1.0,2.1,3.2,4.4,5.3,6.1,7.8,8.7,9.2,10.0},100};
str10 s10_2={{1,0},{0},100};
str10 s10_3={{1,0},{1.0}};
//---
Print("1. s10_1.d1[5] = ",s10_1.d1[5]);
Print("2. s10_2.d1[5] = ",s10_2.d1[5]);
Print("3. s10_3.d1[5] = ",s10_3.d1[5]);
Print("4. s10_3.d1[0] = ",s10_3.d1[0]);
}
For structure type variable partial initialization is allowed, as well as for static
arrays (with an implicitly set size). You can initialize one or more first elements of
a structure or array, the other elements will be initialized with zeroes in this case.
See also
Data Types, Encapsulation and Extensibility of Types, Visibility Scope and
Lifetime of Variables, Creating and Deleting Objects
MQL4 Reference / Language Basics / Variables / Visibility Scope and Lifetime of Variables
for(i=limit;i<rates_total;i++)
{
sum=0;
for(int j=0; j<MA_Period; j++) sum+=(MA_Period-j)*price[i-j];
LineBuffer[i]=sum/weightsum;
}
//---
}
Pay attention to the variable i, declared in line
for(int i=begin; i<limit; i++)
{
int k=i-begin+1;
weightsum+=k;
firstValue+=k*price[i];
}
Its scope is only the for loop; outside of this loop there is another variable with the same
name, declared at the beginning of the function. In addition, the k variable is declared
in the loop body, its scope is the loop body.
Local variables can be declared with the access specifier static. In this case, the
compiler has a variable in the global pool of memory. Therefore, the lifetime of a static
variable is equal to the lifetime of the program. Here the scope of such a variable is
limited to the block in which it is declared.
See also
Data Types, Encapsulation and Extensibility of Types,Initialization of Variables, Creating
and Deleting Objects
MQL4 Reference / Language Basics / Variables / Creating and
Deleting Objects
See also
Data Types, Encapsulation and Extensibility of
Types,Initialization of Variables, Visibility Scope and
Lifetime of Variables
MQL4 Reference / Language Basics / Preprocessor
Preprocessor
Preprocessor is a special subsystem of the MQL4 compiler
that is intended for preparation of the program source
code immediately before the program is compiled.
Preprocessor allows enhancement of the source code
readability. The code can be structured by including of
specific files containing source codes of mql4-programs.
The possibility to assign mnemonic names to specific
constants contributes to enhancement of the code
readability.
Preprocessor also allows determining specific parameters
of mql4-programs:
Declare constants
Set program properties
Include files in program text
Import functions
Conditional compilation
If the # symbol is used as the first character in a line of
the program, this line is considered as a preprocessor
directive. A preprocessor directive ends with a line feed
character.
MQL4 Reference / Language Basics / Preprocessor / Macro substitution (#define)
The #define directive substitutes expression for all further found entries of identifier in
the source text. The identifier is replaced only if it is a separate token. The identifier is
not replaced if it is part of a comment, part of a string, or part of another longer
identifier.
The constant identifier is governed by the same rules as variable names. The value can
be of any type:
#define ABC 100
#define PI 3.14
#define COMPANY_NAME "MetaQuotes Software Corp."
...
void ShowCopyright()
{
Print("Copyright 2001-2013, ",COMPANY_NAME);
Print("[Link]
}
expression can consist of several tokens, such as keywords, constants, constant and non-
constant expressions. expression ends with the end of the line and can't be transferred
to the next line.
Example:
#define TWO 2
#define THREE 3
#define INCOMPLETE TWO+THREE
#define COMPLETE (TWO+THREE)
void OnStart()
{
Print("2 + 3*2 = ",INCOMPLETE*2);
Print("(2 + 3)*2 = ",COMPLETE*2);
}
// Result
// 2 + 3*2 = 8
// (2 + 3)*2 = 10
Parametric Form #define
With the parametric form, all the subsequent found entries of identifier will be replaced
by expression taking into account the actual parameters. For example:
// example with two parameters a and b
#define A 2+3
#define B 5-1
#define MUL(a, b) ((a)*(b))
double c=MUL(A,B);
Print("c=",c);
/*
expression double c=MUL(A,B);
is equivalent to double c=((2+3)*(5-1));
*/
// Result
// c=20
double c=MUL(A,B);
Print("c=",c);
/*
expression double c=MUL(A,B);
is equivalent to double c=2+3*5-1;
*/
// Result
// c=16
The #undef directive
The #undef directive cancels declaration of the macro substitution, defined before.
Example:
#define MACRO
void func1()
{
#ifdef MACRO
Print("MACRO is defined in ",__FUNCTION__);
#else
Print("MACRO is not defined in ",__FUNCTION__);
#endif
}
#undef MACRO
void func2()
{
#ifdef MACRO
Print("MACRO is defined in ",__FUNCTION__);
#else
Print("MACRO is not defined in ",__FUNCTION__);
#endif
}
void OnStart()
{
func1();
func2();
}
/* Result:
MACRO is defined in func1
MACRO is not defined in func2
*/
See also
Identifiers, Character Constants
MQL4 Reference / Language Basics / Preprocessor / Program Properties (#property)
The compiler will write declared values in the configuration of the module executed.
Constant Type Description
strict Compiler directive for strict compilation mode (see
Updated MQL4)
icon string Path to the file of an image that will be used as an icon of
the EX4 program. Path specification rules are the same as
for resources. The property must be specified in the main
module with the MQL4 source code. The icon file must be
in the ICO format.
link string Link to the company website
copyright string The company name
version string Program version, maximum 31 characters
description string Brief text description of a MQL4-program. Several
description can be present, each of them describes one
line of the text. The total length of all description can not
exceed 511 characters including line feed.
stacksize int MQL4 program stack size. The stack of sufficient size is
necessary when executing function recursive calls.
When launching a script or an Expert Advisor on the chart,
the stack of at least 8 MB is allocated. In case of
indicators, the stack size is always fixed and equal to 1
MB.
When a program is launched in the strategy tester, the
stack of 8 MB is always allocated for it.
library A library; no start function is assigned, functions with the
export modifier can be imported in other MQL4-programs
indicator_chart_window Show the indicator in the chart window
indicator_separate_window Show the indicator in a separate window
indicator_height int Fixed height of the indicator subwindow in pixels
(property INDICATOR_HEIGHT)
indicator_buffers int Number of buffers for indicator calculation
indicator_minimum double The bottom scaling limit for a separate indicator window
indicator_maximum double The top scaling limit for a separate indicator window
Constant Type Description
indicator_labelN string Sets a label for the N-th graphic series displayed in
DataWindow
indicator_colorN color The color for displaying line N, where N is the number of
graphic series; numbering starts from 1
indicator_widthN int Line thickness in graphic series, where N is the number of
graphic series; numbering starts from 1
indicator_styleN int Line style in graphic series, specified by the values of
ENUM_LINE_STYLE. N is the number of graphic series;
numbering starts from 1
indicator_typeN int Type of indicator drawing style. N is the number of
graphic series; numbering starts from 1
indicator_levelN double Horizontal level of N in a separate indicator window
indicator_levelcolor color Color of horizontal levels of the indicator
indicator_levelwidth int Thickness of horizontal levels of the indicator
indicator_levelstyle int Style of horizontal levels of the indicator
script_show_confirm Display a confirmation window before running the script
script_show_inputs Display a window with the properties before running the
script and disable this confirmation window
tester_file string File name from <terminal_data_folder>\MQL4\Files\ to be
sent to a virtual server
tester_indicator string Indicator file name from
<terminal_data_folder>\MQL4\Indicators\ to be sent to a
virtual server
tester_library string Library file name from
<terminal_data_folder>\MQL4\Libraries\ to be sent to a
virtual server
Examples:
#include <[Link]>
#include "[Link]"
Imported functions can have any names. Functions having the same names
but from different modules can be imported at the same time. Imported
functions can have names that coincide with the names of built-in functions.
Operation of scope resolution defines which of the functions should be
called.
The order of searching for a file specified after the #import keyword is
described in Call of Imported Functions.
Since the imported functions are outside the compiled module, the compiler
can not verify the validity of passed parameters. Therefore, to avoid run-
time errors, one must accurately describe the composition and order of
parameters passed to imported functions. Parameters passed to imported
functions (both from EX4, and from the DLL-module) can have default
values.
The following can't be used for parameters in imported functions:
pointers (*);
links to objects that contain dynamic arrays and/or pointers.
Classes, string arrays or complex objects that contain strings and/or dynamic
arrays of any types cannot be passed as a parameter to functions imported
from DLL.
Examples:
#import "[Link]"
int MessageBoxW(uint hWnd,string lpText,string lpCaption,uint uType);
#import "stdlib.ex4"
string ErrorDescription(int error_code);
int RGB(int red_value,int green_value,int blue_value);
bool CompareDoubles(double number1,double number2);
string DoubleToStrMorePrecision(double number,int precision);
string IntegerToHexString(int integer_number);
#import "[Link]"
int GetIntValue(int);
double GetDoubleValue(double);
string GetStringValue(string);
double GetArrayItemValue(double &arr[],int,int);
bool SetArrayItemValue(double &arr[],int,int,double);
double GetRatesItemValue(double &rates[][6],int,int,int);
#import
#ifndef identifier
// the code located here is compiled if identifier is not currently defined by #de
#endif
Any of the conditional compilation directives can be followed by any number of lines
possibly containing #else directive and ending with #endif. If the verified condition is
true, the lines between #else and #endif are ignored. If the verified condition is not
fulfilled, all lines between checking and #else directive (or #endif directive if the former
is absent) are ignored.
Example:
#ifndef TestMode
#define TestMode
#endif
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
#ifdef TestMode
Print("Test mode");
#else
Print("Normal mode");
#endif
}
Depending on the program type and compilation mode, the standard macros are defined
the following way:
__MQL4__ macro is defined when compiling *.mq4 file, __MQL5__ macro is defined
when compiling *.mq5 one.
_DEBUG macro is defined when compiling in debug mode.
_RELEASE macro is defined when compiling in release mode.
Example:
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
#ifdef __MQL5__
#ifdef _DEBUG
Print("Hello from MQL5 compiler [DEBUG]");
#else
#ifdef _RELEASE
Print("Hello from MQL5 compiler [RELEASE]");
#endif
#endif
#else
#ifdef __MQL4__
#ifdef _DEBUG
Print("Hello from MQL4 compiler [DEBUG]");
#else
#ifdef _RELEASE
Print("Hello from MQL4 compiler [RELEASE]");
#endif
#endif
#endif
#endif
}
MQL4 Reference / Language Basics / Object-Oriented Programming
Object-Oriented Programming
Object-oriented programming (OOP) is programming
primarily focused on data, while data and behavior are
being inseparably linked. Data and behavior together
constitute a class, while objects are class instances.
The components of the object-oriented approach are:
Encapsulation and type extensibility
Inheritance
Polymorphism
Overloading
Virtual functions
OOP considers computation as modeling of behavior. The
modeled item is the object represented by computational
abstractions. Suppose we want to write a well known
game "Tetris". To do this, we must learn how to model the
appearance of random shapes composed of four squares
joined together by edges. Also we need to regulate the
falling speed of shapes, define operations of rotation and
shift of shapes. Moving of shapes on the screen is limited
by the well's boundaries, this requirement must also be
modeled. Besides that, filled rows of cubes must be
destroyed and achieved points must be counted.
Thus, this easy-to-understand game requires the creation
of several models - shape model, well model, shape
movement model and so on. All these models are
abstractions, represented by calculations in the computer.
To describe these models, the concept of Abstract Data
Type, ADT (or complex data type) is used. Strictly
speaking, the model of the "shapes" motion in the DOM is
not a data type, but it is a set of operations on the
"shape" data type, using the restrictions of the "well" data
type.
Objects are class variables. Object-oriented programming
allows you to easily create and use ADT. Object-oriented
programming uses the inheritance mechanism. The
benefit of inheritance is in the fact that it allows
obtaining derivative types from data types already
defined by a user.
For example, to create Tetris shapes, it's convenient to
create a base class Shape first. The other classes
representing all seven possible shape types can be derived
on its basis. Behavior of shapes is defined in the base
class, while implementation of behavior of each separate
shape is defined in derivative classes.
In OOP objects are responsible for their behavior. ADT
developer should include a code to describe any behavior
that would normally be expected from the corresponding
objects. The fact that the object itself is responsible for
its behavior, greatly simplifies the task of programming
for the user of this object.
If we want to draw a shape on the screen, we need to
know where the center will be and how to draw it. If a
separate shape knows how to draw itself, the programmer
should send a "draw" message when using such a shape.
The MQL4 Language is a C++ like, and it also has the
encapsulation mechanism for the implementation of ADT.
On the one hand encapsulation combines the internal
details of the implementation of a particular type, and on
the other hand it combines externally accessible functions
that can influence objects of this type. Implementation
details may be inaccessible for a program that uses this
type.
The concept of OOP has a set of related concepts,
including the following:
Simulation of actions from the real world
User-defined data types
Hiding the implementation details
Possibility of the code reuse through inheritance
Interpretation of function calls during execution
Some of these concepts are rather vague, some are
abstract, others are general.
MQL4 Reference / Language Basics / Object-Oriented Programming / Encapsulation and Extensibility of
Types
This approach offers several advantages. First, by function name we can understand
what it does - sets or gets the value of a class member. Secondly, perhaps in the
future we will need to change the type of the m_name variable in the CPerson class
or in any of its derivative classes.
In this case, we'll need just to change the implementation of functions SetName()
and GetName(), while objects of the CPerson class will be available for using in a
program without any code changes because the user will not even know that the
data type of m_name has changed.
Example:
struct Name
{
string first_name; // name
string last_name; // last name
};
class CPerson
{
protected:
Name m_name; // name
public:
void SetName(string n);
string GetName(){return(m_name.first_name+" "+m_name.last_name);}
private:
string GetFirstName(string full_name);
string GetLastName(string full_name);
};
void CPerson::SetName(string n)
{
m_name.first_name=GetFirstName(n);
m_name.last_name=GetLastName(n);
}
See also
Data Types
MQL4 Reference / Language Basics / Object-Oriented Programming / Inheritance
Inheritance
The characteristic feature of OOP is the encouragement of code reuse through
inheritance. A new class is made from the existing, which is called the base class. The
derived class uses the members of the base class, but can also modify and supplement
them.
Many types are variations of the existing types. It is often tedious to develop a new code
for each of them. In addition, the new code implies new errors. The derived class
inherits the description of the base class, thus any re-development and re-testing of
code is unnecessary. The inheritance relationships are hierarchical.
Hierarchy is a method that allows to copy the elements in all their diversity and
complexity. It introduces the objects classification. For example, the periodic table of
elements has gases. They possess to properties inherent to all periodic elements.
Inert gases constitute the next important subclass. The hierarchy is that the inert gas,
such as argon is a gas, and gas, in its turn, is part of the system. Such a hierarchy allows
to interpret behaviour of inert gases easily. We know that their atoms contain protons
and electrons, that is true for all other elements.
We know that they are in a gaseous state at room temperature, like all the gases. We
know that no gas from inert gas subclass enters usual chemical reaction with other
elements, and it is a property of all inert gases.
Consider an example of the inheritance of geometric shapes. To describe the whole
variety of simple shapes (circle, triangle, rectangle, square etc.), the best way is to
create a base class (ADT), which is the ancestor of all the derived classes.
Let's create a base class CShape, which contains just the most common members
describing the shape. These members describe properties that are characteristic of any
shape - the type of the shape and main anchor point coordinates.
Example:
//--- The base class Shape class CShape
{
protected:
int m_type; // Shape type
int m_xpos; // X - coordinate of the base point
int m_ypos; // Y - coordinate of the base point
public:
CShape(){m_type=0; m_xpos=0; m_ypos=0;} // constructor
void SetXPos(int x){m_xpos=x;} // set X
void SetYPos(int y){m_ypos=y;} // set Y
};
Next, create new classes derived from the base class, in which we will add necessary
fields, each specifying a certain class. For the Circle shape it is necessary to add a
member that contains the radius value. The Square shape is characterized by the side
value. Therefore, derived classes, inherited from the base class CShape will be declared
as follows:
//--- The derived class circle
class CCircle : public CShape // After a colon we define the base class
{ // from which inheritance is made
private:
int m_radius; // circle radius
public:
CCircle(){m_type=1;}// constructor, type 1
};
public:
CSquare(){m_type=2;} // constructor, type 2
};
It should be noted that while object is created the base class constructor is called first,
and then the constructor of the derived class is called. When an object is destroyed first
the destructor of the derived class is called, and then a base class destructor is called.
Thus, by declaring the most general members in the base class, we can add an additional
members in derived classes, which specify a particular class. Inheritance allows creating
powerful code libraries that can be reused many times.
The syntax for creating a derived class from an already existing one is as follows:
class class_name :
(public | protected | private) opt base_class_name
{
class members declaration
};
One of aspects of the derived class is the visibility (openness) of its members successors
(heirs). The public, protected and private keywords are used to indicate the extent, to
which members of the base class will be available for the derived one. The public
keyword after a colon in the header of a derived class indicates that the protected and
public members of the base class CShape should be inherited as protected and public
members of the derived class CCircle.
The private class members of the base class are not available for the derived class. The
public inheritance also means that derived classes (CCircle and CSquare) are CShapes.
That is, the Square (CSquare) is a shape (CShape), but the shape does not necessarily
have to be a square.
The derived class is a modification of the base class, it inherits the protected and public
members of the base class. The constructors and destructors of the base class cannot be
inherited. In addition to members of the base class, new members are added in a
derivative class.
The derived class may include the implementation of member functions, different from
the base class. It has nothing common with an overload, when the meaning of the same
function name may be different for different signatures.
In protected inheritance, public and protected members of base class become protected
members of derived class. In private inheritance, the public and protected members of
base class become private members of the derived class.
In protected and private inheritance, the relation that "the object of a derivative class is
object of a base class" is not true. The protected and private inheritance types are rare,
and each of them needs to be used carefully.
It should be understood that the type of inheritance (public, protected or private) does
not affect the ways of accessing the members of base classes in the hierarchy of
inheritance from a derived class. With any type of inheritance, only base class
members declared with public and protected access specifiers will be available out of
the derived classes. Let's consider it in the following example:
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link "[Link]
#property version "1.00"
//+------------------------------------------------------------------+
//| Example class with a few access types |
//+------------------------------------------------------------------+
class CBaseClass
{
private: //--- The private member is not available from derived classes
int m_member;
protected: //--- The protected method is available from the base class and
int Member(){return(m_member);}
public: //--- Class constructor is available to all members of classes
CBaseClass(){m_member=5;return;};
private: //--- A private method for assigning a value to m_member
void Member(int value) { m_member=value;};
};
//+------------------------------------------------------------------+
//| Derived class with errors |
//+------------------------------------------------------------------+
class CDerived: public CBaseClass // specification of public inheritance can be omitt
{
public:
void Func() // In the derived class, define a function with calls to base class me
{
//--- An attempt to modify a private member of the base class
m_member=0; // Error, the private member of the base class is not availa
Member(0); // Error, the private method of the base class is not availa
//--- Reading the member of the base class
Print(m_member); // Error, the private member of the base class is not availa
Print(Member()); // No error, protected method is available from the base cla
}
};
In the above example, CBaseClass has only a public method the constructor. Constructors
are called automatically when creating a class object. Therefore, the private member
m_member and the protected methods Member() cannot be called from the outside. But
in case of public inheritance, the Member() method of the base class will be available
from the derived classes.
In case of protected inheritance, all the members of the base class with public and
protected access become protected. It means that if public data members and methods
of the base class were accessible from the outside, with protected inheritance they are
available only from the classes of the derived class and its further derivatives.
//+------------------------------------------------------------------+
//| Example class with a few access types |
//+------------------------------------------------------------------+
class CBaseMathClass
{
private: //--- The private member is not available from derived classes
double m_Pi;
public: //--- Getting and setting a value for m_Pi
void SetPI(double v){m_Pi=v;return;};
double GetPI(){return m_Pi;};
public: // The class constructor is available to all members
CBaseMathClass() {SetPI(3.14); PrintFormat("%s",__FUNCTION__);}
};
//+------------------------------------------------------------------+
//| A derived class, in which m_Pi cannot be modified |
//+------------------------------------------------------------------+
class CProtectedChildClass: protected CBaseMathClass // Protected inheritance
{
private:
double m_radius;
public: //--- Public methods in the derived class
void SetRadius(double r){m_radius=r; return;};
double GetCircleLength(){return GetPI()*m_radius;};
};
//+------------------------------------------------------------------+
//| Script starting function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- When creating a derived class, the constructor of the base class will be called
CProtectedChildClass pt;
//--- Specify radius
[Link](10);
PrintFormat("Length=%G",[Link]());
//--- If we uncomment the line below, we will get an error at the stage of compilatio
// [Link](3);
//--- Now declare a variable of the base class and try to set the Pi constant equal t
CBaseMathClass bc;
[Link](10);
//--- Here is the result
PrintFormat("[Link]()=%G",[Link]());
}
The example shows that methods SetPI() and GetPi() in the base class CBaseMathClass
are open and available for calling from any place of the program. But at the same time,
for CProtectedChildClass which is derived from it these methods can be called only from
the methods of the CProtectedChildClass class or its derived classes.
In case of private inheritance, all the members of the basic class with the public and
protected access become private, and calling them becomes impossible in further
inheritance.
MQL4 has no multiple inheritance.
See also
Structures and Classes
MQL4 Reference / Language Basics / Object-Oriented Programming / Polymorphism
Polymorphism
Polymorphism is an opportunity for different classes of objects, related through
inheritance, to respond in various ways when calling the same function element. It helps
to create a universal mechanism describing the behavior of not only the base class, but
also descendant classes.
Let's continue to develop a base class CShape, and define a member function GetArea(),
designed to calculate the area of a shape. In all the descendant classes, produced by
inheritance from the base class, we redefine this function in accordance with rules of
calculating the area of a particular shape.
For a square (class CSquare), the area is calculated through its sides, for a circle (class
CCircle), area is expressed through its radius etc. We can create an array to store
objects of CShape type, in which both objects of a base class and those of all descendant
classes can be stored. Further we can call the same function for each element of the
array.
Example:
//--- Base class class CShape
{
protected:
int m_type; // Shape type
int m_xpos; // X - coordinate of the base point
int m_ypos; // Y - coordinate of the base point
public:
void CShape(){m_type=0;}; // constructor, type=0
int GetType(){return(m_type);};// returns type of the shape
virtual
double GetArea(){return (0); }// returns area of the shape
};
Now, all of the derived classes have a member function getArea(), which returns a zero
value. The implementation of this function in each descendant will vary.
//--- The derived class Circle
class CCircle : public CShape // After a colon we define the base class
{ // from which inheritance is made
private:
double m_radius; // circle radius
public:
void CCircle(){m_type=1;}; // constructor, type=1
void SetRadius(double r){m_radius=r;};
virtual double GetArea(){return (3.14*m_radius*m_radius);}// circle area
};
public:
void CSquare(){m_type=2;}; // constructor, type=1
void SetSide(double s){m_square_side=s;};
virtual double GetArea(){return (m_square_side*m_square_side);}// square area
};
For calculating the area of the square and circle, we need the corresponding values of
m_radius and m_square_side, so we have added the functions SetRadius() and SetSide()
in the declaration of the corresponding class.
It is assumed that object of different types (CCircle and CSquare) derived from one base
type CShape are used in our program. Polymorphism allows creating an array of objects
of the base CShape class, but when declaring this array, these objects are yet unknown
and their type is undefined.
The decision on what type of object will be contained in each element of the array will
be taken directly during program execution. This involves the dynamic creation of
objects of the appropriate classes, and hence the necessity to use object pointers
instead of objects.
The new operator is used for dynamic creation of objects. Each such object must be
individually and explicitly deleted using the delete operator. Therefore we will declare
an array of pointers of CShape type, and create an object of a proper type for each
element (new Class_Name), as shown in the following script example:
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- Declare an array of object pointers of the base type
CShape *shapes[5]; // An array of pointers to CShape object
//--- Create another CCircle object and write down its pointer in shapes[1]
circle=new CCircle();
shapes[1]=circle;
[Link](5);
//--- Create a CSquare object and write down its pointer to shapes[3]
CSquare *square=new CSquare();
[Link](5);
shapes[3]=square;
//--- Create a CSquare object and write down its pointer to shapes[4]
square=new CSquare();
[Link](10);
shapes[4]=square;
Please note that when deleting an object using the delete operator, the type of its
pointer must be checked. Only objects with the POINTER_DYNAMIC pointer can be
deleted using delete. For pointers of other type, an error will be returned.
But besides the redefining of functions during inheritance, polymorphism also includes
the implementation of one and the same functions with different sets of parameters
within a class. This means that the class may have several functions with the same name
but with a different type and/or set of parameters. In this case, polymorphism is
implemented through the function overload.
MQL4 Reference / Language Basics / Object-Oriented Programming /
Overload
Overload
Within one class it is possible to define two or more
methods that use the same name, but have different
numbers of parameters. When this occurs, methods are
called overloaded and such a process is referred to as
method overloading.
Method overloading is one of ways of polymorphism
realization. Overloading of methods is performed
according to the same rules as the function overloading.
If the called function has no exact match, the compiler
searches for a suitable function on three levels
sequentially:
1. search within class methods.
2. search within the base class methods, consistently
from the nearest ancestor to the very first.
3. search among other functions.
If there is no exact correspondence at all levels, but
several suitable functions at different levels have been
found, the function found at the least level is used.
Within one level, there can't be more than one suitable
function.
See also
Function Overloading
MQL4 Reference / Language Basics / Object-Oriented Programming / Virtual Functions
Virtual Functions
The virtual keyword is the function specifier, which provides a mechanism to select
dynamically at runtime an appropriate function-member among the functions of basic
and derived classes. Structures cannot have virtual functions. It can be used to change
the declarations for function-members only.
The virtual function, like an ordinary function, must have an executable body. When
called, its semantic is the same as that of other functions.
A virtual function may be overridden in a derived class. The choice of what function
definition should be called for a virtual function is made dynamically (at runtime). A
typical case is when a base class contains a virtual function, and derived classes have
their own versions of this function.
The pointer to the base class can indicate either a base class object or the object of a
derived class. The choice of the member-function to call will be performed at runtime
and will depend on the type of the object, not the type of the pointer. If there is no
member of a derived type, the virtual function of the base class is used by default.
Destructors are always virtual, regardless of whether they are declared with the virtual
keyword or not.
Attention: it is not recommended to call virtual methods from constructors and
desctructors, because the result is undefined in this case.
Let's consider the use of virtual functions on the example of Tetris.mq5. The base class
CTetrisShape with the virtual function Draw is defined in the included file
[Link].
//+------------------------------------------------------------------+ class CTetrisSh
{
protected:
int m_type;
int m_xpos;
int m_ypos;
int m_xsize;
int m_ysize;
int m_prev_turn;
int m_turn;
int m_right_border;
public:
void CTetrisShape();
void SetRightBorder(int border) { m_right_border=border; }
void SetYPos(int ypos) { m_ypos=ypos; }
void SetXPos(int xpos) { m_xpos=xpos; }
int GetYPos() { return(m_ypos); }
int GetXPos() { return(m_xpos); }
int GetYSize() { return(m_ysize); }
int GetXSize() { return(m_xsize); }
int GetType() { return(m_type); }
void Left() { m_xpos-=SHAPE_SIZE; }
void Right() { m_xpos+=SHAPE_SIZE; }
void Rotate() { m_prev_turn=m_turn; if(++m_turn>3)
virtual void Draw() { return; }
virtual bool CheckDown(int& pad_array[]);
virtual bool CheckLeft(int& side_row[]);
virtual bool CheckRight(int& side_row[]);
};
Further, for each derived class, this function is implemented in accordance with
characteristics of a descendant class. For example, the first shape CTetrisShape1 has its
own implementation of the Draw() function:
class CTetrisShape1 : public CTetrisShape
{
public:
//--- shape drawing
virtual void Draw()
{
int i;
string name;
//---
if(m_turn==0 || m_turn==2)
{
//--- horizontal
for(i=0; i<4; i++)
{
name=SHAPE_NAME+(string)i;
ObjectSetInteger(0,name,OBJPROP_XDISTANCE,m_xpos+i*SHAPE_SIZE);
ObjectSetInteger(0,name,OBJPROP_YDISTANCE,m_ypos);
}
}
else
{
//--- vertical
for(i=0; i<4; i++)
{
name=SHAPE_NAME+(string)i;
ObjectSetInteger(0,name,OBJPROP_XDISTANCE,m_xpos);
ObjectSetInteger(0,name,OBJPROP_YDISTANCE,m_ypos+i*SHAPE_SIZE);
}
}
}
}
The Square shape is described by class CTetrisShape6 and has its own implementation of
the Draw() method:
class CTetrisShape6 : public CTetrisShape
{
public:
//--- Shape drawing
virtual void Draw()
{
int i;
string name;
//---
for(i=0; i<2; i++)
{
name=SHAPE_NAME+(string)i;
ObjectSetInteger(0,name,OBJPROP_XDISTANCE,m_xpos+i*SHAPE_SIZE);
ObjectSetInteger(0,name,OBJPROP_YDISTANCE,m_ypos);
}
for(i=2; i<4; i++)
{
name=SHAPE_NAME+(string)i;
ObjectSetInteger(0,name,OBJPROP_XDISTANCE,m_xpos+(i-2)*SHAPE_SIZE);
ObjectSetInteger(0,name,OBJPROP_YDISTANCE,m_ypos+SHAPE_SIZE);
}
}
};
Depending on the class, to which the created object belongs, it calls the virtual function
of this or that derived class.
void CTetrisField::NewShape()
{
//--- creating one of the 7 possible shapes randomly
int nshape=rand()%7;
switch(nshape)
{
case 0: m_shape=new CTetrisShape1; break;
case 1: m_shape=new CTetrisShape2; break;
case 2: m_shape=new CTetrisShape3; break;
case 3: m_shape=new CTetrisShape4; break;
case 4: m_shape=new CTetrisShape5; break;
case 5: m_shape=new CTetrisShape6; break;
case 6: m_shape=new CTetrisShape7; break;
}
//--- draw
m_shape.Draw();
//---
}
MQL4 Reference / Language Basics / Object-Oriented Programming / Static Members of a Class
where class_name is the name of the class, and variable is the name of the class
member.
As you see, to access the static member of a class, context resolution operator :: is
used. When you access a static member within class methods, the context operator is
optional.
Static member of a class has to be explicitly initialized with desired value. For this it
must be declared and initialized in global scope. The sequence of static members
initialization will correspond to the sequence of their declaration in global scope.
For example, we have a class CParser used for parsing the text, and we need to count
the total number of processed words and characters. We only need to declare the
necessary class members as static and initialize them at the global level. Then all
instances of the class will use common counters of words and characters.
//+------------------------------------------------------------------+ //| Class "Text
//+------------------------------------------------------------------+
class CParser
{
public:
static int s_words;
static int s_symbols;
//--- Constructor and destructor
CParser(void);
~CParser(void){};
};
...
//--- Initialization of static members of the Parser class at the global level
int CParser::s_words=0;
int CParser::s_symbols=0;
A static class member can be declared with the const keyword. Such static constants
must be initialized at the global level with the const keyword:
//+------------------------------------------------------------------+
//| Class "Stack" for storing processed data |
//+------------------------------------------------------------------+
class CStack
{
public:
CStack(void);
~CStack(void){};
...
private:
static const int s_max_length; // Maximum stack capacity
};
Pointer this
The keyword this denotes an implicitly declared pointer to itself to a specific instance of
the class, in the context of which the method is executed. It can be used only in non-
static methods of the class. Pointer this is an implicit non-static member of any class.
In static functions you can access only static members/methods of a class.
Static Methods
In MQL4 member functions of type static can be used. The static modifier must precede
the return type of a function in the declaration inside a class.
class CStack
{
public:
//--- Constructor and destructor
CStack(void){};
~CStack(void){};
//--- Maximum stack capacity
static int Capacity();
private:
int m_length; // The number of elements in the stack
static const int s_max_length; // Maximum stack capacity
};
//+------------------------------------------------------------------+
//| Returns the maximum number of elements to store in the stack |
//+------------------------------------------------------------------+
int CStack::Capacity(void)
{
return(s_max_length);
}
//--- Initialization of the static constant of the CStack class
const int CStack::s_max_length=1000;
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- declare CStack type variable
CStack stack;
//--- call the object's static method
Print("CStack.s_max_length=",[Link]());
//--- it can also be called the following way, as the method is static and does not r
Print("CStack.s_max_length=",CStack::Capacity());
}
A method with the const modifier is called constant and cannot modify implicit members
of its class. Declaration of constant functions of a class and constant parameters is
called const-correctness control. Through this control you can be sure that the compiler
will ensure the consistency of values of objects and will return an error during
compilation if there is something wrong.
The const modifier is placed after the list of arguments inside a class declaration.
Definition outside a class should also include the const modifier:
//+------------------------------------------------------------------+
//| Class "Rectangle" |
//+------------------------------------------------------------------+
class CRectangle
{
private:
double m_width; // Width
double m_height; // Height
public:
//--- Constructors and destructor
CRectangle(void):m_width(0),m_height(0){};
CRectangle(const double w,const double h):m_width(w),m_height(h)
~CRectangle(void){};
//--- Calculating the area
double Square(void) const;
static double Square(const double w,const double h);// { return(w*h); }
};
//+------------------------------------------------------------------+
//| Returns the area of the "Rectangle" object |
//+------------------------------------------------------------------+
double CRectangle::Square(void) const
{
return(Square(m_width,m_height));
}
//+------------------------------------------------------------------+
//| Returns the product of two variables |
//+------------------------------------------------------------------+
static double CRectangle::Square(const double w,const double h)
{
return(w*h);
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- Create a rectangle rect with the sides equal to 5 and 6
CRectangle rect(5,6);
//--- Find the rectangle area using a constant method
PrintFormat("[Link]()=%.2f",[Link]());
//--- Find the product of numbers using the static method of class CRectangle
PrintFormat("CRectangle::Square(2.0,1.5)=%f",CRectangle::Square(2.0,1.5));
}
An additional argument in favor of using the constancy control is the fact that in this
case, the compiler generates a special optimization, for example, places a constant
object in read-only memory.
A static function cannot be determined with the const modifier, because this modifier
ensures the constancy of the instance members when calling this function. But, as
mentioned above, the static function cannot access non-static class members.
See also
Static Variables, Variables, References. Modifier & and Keyword this
MQL4 Reference / Language Basics / Object-Oriented Programming / Function Templates
Function Templates
Overloaded functions are commonly used to perform similar operations on
various data types. ArraySize() is a simple example of such function in
MQL4. It returns size of any type of array. In fact, this system function is
overloaded and the entire implementation of such an overload is hidden
from MQL4 application developers:
int ArraySize( void& array[] // checked array
);
ArraySize() function can be displayed the following way for MqlRates type
array for working with quotations in historical data format:
int ArraySize(
MqlRates& array[] // array filled with MqlRates type values
);
Thus, it is very convenient to use the same function for working with
different types. However, all preliminary work should be carried out the
necessary function should be overloaded for all data types it should
correctly work with.
There is a convenient solution. If similar operations should be executed for
each data type, it is possible to use function templates. In this case, a
programmer needs to write only one function template description. When
describing the template in such a way, we should specify only some formal
parameter instead of some definite data type the function should work
with. The compiler will automatically generate various functions for the
appropriate handling of each type based on the types of the arguments used
when calling the function.
Function template definition starts with the template keyword followed by
the list of formal parameters in angle brackets. Each formal parameter is
preceded by the typename keyword. Formal parameter types are built-in or
user-defined types. They are used:
to specify the types of function arguments,
to specify the types of function's return value,
to declare the variables inside the function definition
Number of template parameters cannot exceed eight. Each formal
parameter in the template definition should appear in the list of function
parameters at least once. Each name of the formal parameter should be
unique.
Below is an example of a function template for searching the highest value
in the array of any numeric type (integer and real numbers):
template<typename T>
T ArrayMax(T &arr[])
{
uint size=ArraySize(arr);
if(size==0) return(0);
T max=arr[0];
for(uint n=1;n<size;n++)
if(max<arr[n]) max=arr[n];
//---
return(max);
}
This template defines the function that finds the highest value in the
passed array and returns this value as a result. Keep in mind that the
ArrayMaximum() function built in MQL4 returns only the highest value index
that can be used to find the value itself. For example:
//--- create an array
double array[];
int size=50;
ArrayResize(array,size);
//--- fill with random values
for(int i=0;i<size;i++)
{
array[i]=MathRand();
}
we now can use only one line, in which the returned result has the same
type as the array passed into function:
//--- find the highest value
double max=ArrayMax(array);
In this case, the type of result returned by the ArrayMax() function will
automatically match the type of array.
Use the typename keyword to get the argument type as a string in order to
create general purpose methods of working with various data types. Let's
consider a specific example of the function that returns data type as a
string:
#include <Trade\[Link]>
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OnStart()
{
//---
CTrade trade;
double d_value=M_PI;
int i_value=INT_MAX;
Print("d_value: type=",GetTypeName(d_value), ", value=", d_value);
Print("i_value: type=",GetTypeName(i_value), ", value=", i_value);
Print("trade: type=",GetTypeName(trade));
//---
}
//+------------------------------------------------------------------+
//| Type is returned as a line |
//+------------------------------------------------------------------+
template<typename T>
string GetTypeName(const T &t)
{
//--- return the type as a line
return(typename(T));
//---
}
Function templates can also be used for class methods, for example:
class CFile
{
...
public:
...
template<typename T>
uint WriteStruct(T &data);
};
template<typename T>
uint CFile::WriteStruct(T &data)
{
...
return(FileWriteStruct(m_handle,data));
}
Function templates should not be declared with export, virtual and #import
keywords.
Template function overload
A template function overload may be necessary sometimes. For example,
we have a template function that writes the value of the second parameter
to the first one using typecasting. MQL5 does not allow typecasting string to
bool. We can do that ourselves let's create an overload of a template
function. For example:
//+------------------------------------------------------------------+
//| Template function |
//+------------------------------------------------------------------+
template<typename T1,typename T2>
string Assign(T1 &var1,T2 var2)
{
var1=(T1)var2;
return(__FUNCSIG__);
}
//+------------------------------------------------------------------+
//| Special overload for bool+string |
//+------------------------------------------------------------------+
string Assign(bool &var1,string var2)
{
var1=(StringCompare(var2,"true",false) || StringToInteger(var2)!=0);
return(__FUNCSIG__);
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
int i;
bool b;
Print(Assign(i,"test"));
Print(Assign(b,"test"));
}
As a result of the code execution, we can see that the Assign() template
function has been used for the int+string pair, while the overloaded version
has already been used for the bool+string pair during the second call.
string Assign<int,string>(int&,string)
string Assign(bool&,string)
See also
Overload
MQL4 Reference / Language Basics / Object-Oriented Programming / Class Templates
Template advantages
Function templates are used when you need to perform similar operations on various
data types, for example, searching for a maximum element in the array. The main
advantage of applying the templates is that you do not have to code a separate overload
for each type. Instead of declaring multiple overloads of each type
double ArrayMax(double array[]) {
...
}
int ArrayMax(int array[])
{
...
}
uint ArrayMax(uint array[])
{
...
}
long ArrayMax(long array[])
{
...
}
datetime ArrayMax(datetime array[])
{
...
}
Here, the T formal parameter specifying a type of used data is replaced with an actually
applied type during compilation, i.e. the compiler automatically generates a separate
function for each type double, datetime, etc. MQL5 also allows you to develop class
templates using all the advantages of the approach.
Class templates
A class template is declared using the template keyword followed by angle brackets<>
enumerating the list of formal parameters with the typename keyword. This entry
informs the compiler that it deals with a generic class with the T formal parameter
defining a real variable type when implementing a class. For example, let's create a
vector class for storing an array with T type elements:
#define TOSTR(x) #x+" " // macro for displaying an object name
//+------------------------------------------------------------------+
//| Vector class for storing T-type elements |
//+------------------------------------------------------------------+
template <typename T>
class TArray
{
protected:
T m_array[];
public:
//--- constructor creates an array for 10 elements by default
void TArray(void){ArrayResize(m_array,10);}
//--- constructor for creating a vector with a specified array size
void TArray(int size){ArrayResize(m_array,size);}
//--- return a type and amount of data stored in the TArray type object
string Type(void){return(typename(m_array[0])+":"+(string)ArraySize(m_array));};
};
Next, let's apply different methods to create three TArray objects in the program for
working with various types
void OnStart()
{
TArray<double> double_array; // vector has a default size of 10
TArray<int> int_array(15); // vector has a size of 15
TArray<string> *string_array; // pointer to TArray<string> vector
//--- create a dynamic object
string_array=new TArray<string>(20);
//--- display an object name, data type and vector size in the Journal
PrintFormat("%s (%s)",TOSTR(double_array),double_array.Type());
PrintFormat("%s (%s)",TOSTR(int_array),int_array.Type());
PrintFormat("%s (%s)",TOSTR(string_array),string_array.Type());
//--- remove a dynamic object before completing the program
delete(string_array);
}
Now, we have 3 vectors with different data types: double, int and string.
Class templates are well suited for developing containers objects designed for
encapsulating other objects of any type. Container objects are collections already
containing objects of one certain type. Usually, working with stored data is instantly
built into the container.
For example, you can create a class template that does not allow accessing an element
outside the array, thus avoiding the "out of range" critical error.
//+------------------------------------------------------------------+
//| Class for a free access to an array element |
//+------------------------------------------------------------------+
template<typename T>
class TSafeArray
{
protected:
T m_array[];
public:
//--- default constructor
void TSafeArray(void){}
//--- constructor for creating the array of a specified size
void TSafeArray(int size){ArrayResize(m_array,size);}
//--- array size
int Size(void){return(ArraySize(m_array));}
//--- change the array size
int Resize(int size,int reserve){return(ArrayResize(m_array,size,res
//--- release the array
void Erase(void){ZeroMemory(m_array);}
//--- operator for accessing the array element by index
T operator[](int index);
//--- assignment operator for receiving all elements from the array at once
void operator=(const T &array[]); // T type array
};
//+------------------------------------------------------------------+
//| Receiving an element by index |
//+------------------------------------------------------------------+
template<typename T>
T TSafeArray::operator[](int index)
{
static T invalid_value;
//---
int max=ArraySize(m_array)-1;
if(index<0 || index>=ArraySize(m_array))
{
PrintFormat("%s index %d is not in range (0-%d)!",__FUNCTION__,index,max);
return(invalid_value);
}
//---
return(m_array[index]);
}
//+------------------------------------------------------------------+
//| Assigning for the array |
//+------------------------------------------------------------------+
template<typename T>
void TSafeArray::operator=(const T &array[])
{
int size=ArraySize(array);
ArrayResize(m_array,size);
//--- T type should support the copying operator
for(int i=0;i<size;i++)
m_array[i]=array[i];
//---
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
int copied,size=15;
MqlRates rates[];
//--- copy the array of quotes
if((copied=CopyRates(_Symbol,_Period,0,size,rates))!=size)
{
PrintFormat("CopyRates(%s,%s,0,%d) returned %d error code",
_Symbol,EnumToString(_Period),size,GetLastError());
return;
}
//--- create a container and insert the MqlRates value array to it
TSafeArray<MqlRates> safe_rates;
safe_rates=rates;
//--- index within the array
int index=3;
PrintFormat("Close[%d]=%G",index,safe_rates[index].close);
//--- index outside the array
index=size;
PrintFormat("Close[%d]=%G",index,safe_rates[index].close);
}
Please note that template declaration should also be used when describing methods
outside the class declaration:
template<typename T>
T TSafeArray::operator[](int index)
{
...
}
template<typename T>
void TSafeArray::operator=(const T &array[])
{
...
}
Class and function templates allow you to define multiple comma-separated formal
parameters, for example, Map collection for storing "key value" pairs:
template<typename Key, template Value>
class TMap
{
...
}
See also
Function templates, Overload
MQL4 Reference / Language Basics / Object-Oriented Programming / Abstract Classes
Here Sound() is a pure virtual function, because it is declared with the specifier of the
pure virtual function PURE (=0).
Pure virtual functions are only the virtual functions for which the PURE specifier is set:
(=NULL) or (=0). Example of abstract class declaration and use:
class CAnimal
{
public:
virtual void Sound()=NULL; // PURE method, should be overridden in the der
};
//--- Derived from an abstract class
class CCat : public CAnimal
{
public:
virtual void Sound() { Print("Myau"); } // PURE is overridden, CCat is not a
};
Restrictions on abstract classes
If the constructor for an abstract class calls a pure virtual function (either directly or
indirectly), the result is undefined.
//+------------------------------------------------------------------+
//| An abstract base class |
//+------------------------------------------------------------------+
class CAnimal
{
public:
//--- A pure virtual function
virtual void Sound(void)=NULL;
//--- Function
void CallSound(void) { Sound(); }
//--- Constructor
CAnimal()
{
//--- An explicit call of the virtual method
Sound();
//--- An implicit call (using a third function)
CallSound();
//--- A constructor and/or destructor always calls its own functions,
//--- even if they are virtual and overridden by a called function in a derived
//--- If the called function is pure virtual,
//--- its call will cause a critical runtime error: "pure virtual function call"
}
};
However, constructors and destructors for abstract classes can call other member
functions.
MQL4 Reference / Language Basics / Updated MQL4
Also the new function format can be used for virtual copying, when there is no actual
copying, and accessing the copied values you actually access the price data.
int ArrayCopyRates(
MqlRates& rates_array[], // MqlRates array, passed by reference
string symbol=NULL, // symbol
int timeframe=0 // timeframe
);
To provide compatibility with old MQL4 programs, the previous call format is also
preserved, but now it leads to actual copying of data into a double-type array.
int ArrayCopyRates(
void& dest_array[][], // destination array, passed by reference
string symbol=NULL, // symbol
int timeframe=0 // timeframe
);
This means that when the values in the time series change (new bars are added,
restructuring, the last bar's Close price is uodated), you must re-copy the required data
into the dest_array[][]. The receiver array will be automatically allocated for the
required number of copied bars, even if it was declared statically.
Changed RateInfo history data storage format. RateInfo structure was presented as
follows in the old version:
struct RateInfo
{
unsigned int ctm; // bar open date
double open; // Open price
double low; // Low price
double high; // High price
double close; // Close price
double vol; // volume
};
In the new format, RateInfo structure features fields for storing spread and trading
volume:
//--- Standard quote presentation in the new terminal version
struct RateInfo
{
INT64 ctm; // open date and time
double open; // Open price (absolute value)
double high; // Low price
double low; // High price
double close; // Close price
UINT64 vol; // tick volume
INT32 spread; // spread
UINT64 real; // trade volume
};
Thus, if MQL4 programs contain DLLs for passing/accepting price data, the
corresponding functions in the source codes should be rewritten and recompiled
considering format changes to ensure proper operation.
Old EX4 applications and DLLs based on old RateInfo format will not work in the new
terminal. Conversion to the new format is required.
In file operations, the number of simultaneously opened files can now reach 64 ones,
while there could be no more than 32 ones in the old MQL4. Until recently, the files
were always opened in FILE_SHARE_READ or FILE_SHARE_WRITE mode. Now, the
necessary opening mode should be specified explicitly.
For FileWrite(), FileWriteArray(), FileWriteDouble(), FileWriteInteger() and
FileWriteString() functions the type of returned value has been changed from int to
uint. The functions return the number of bytes, actually written or 0 in case of error
(in old version of MQL4 the negative number is returned in case of error).
Working with functions, scope of variables and memory release in local arrays has also
been changed. Since the number of changes is large enough, the new #property strict
property has been introduced to provide maximum compatibility with the previous
approach to developing MQL4 programs. When creating new MQL4 application using
MQL wizard, this property is always added to the template.
The string representation of datetime type depends on compilation mode:
datetime date=D'2014.03.05 [Link]';
string str="mydate="+date;
//--- str="mydate=1394034418" - old compiler/new compiler without #property strict
//--- str="mydate=2014.03.05 [Link]" - new compiler with #property strict
The table below contains the differences between MQL4, new MQL4 without using strict
and new MQL4 with specified strict compilation mode:
#property strict
When compiling libraries in the strict mode, the export modifier should be added for
each exported function, otherwise the function will not be accessible from outside.
The table of differences between compilers:
Old MQL4 compiler New MQL4 compiler New MQL4 with #property
strict
Old MQL4 compiler New MQL4 compiler New MQL4 with #property
strict
init(), start() and deinit() init(), start() and deinit() Ditto
entry points may have any have been remained intact for
parameters and any return compatibility,
type while new OnInit(), OnStart(),
OnCalculate(), OnTick(),
OnTimer(), OnChartEvent(),
OnTester() and OnDeinit()
should strictly correspond to
their signatures
The result of the return from The result of the return from If a non-zero value is returned
init() function is not analyzed init() and OnInit() functions is from OnInit(), the operation of
by the runtime subsystem not analyzed by the runtime an Expert Advisor or an
subsystem indicator is stopped, the
program is unloaded
Virtually any variable names Variable names cannot have Ditto
(except for the reserved special characters and points.
words) are possible, including The list of the reserved words
special characters and points has been expanded. Thus,
such widespread words as
short, long, const, etc. cannot
be used as names
Variable scope is from Ditto Variable scope is from
declaration (even in the declaration to the end of the
nested block) to the function block, in which the variable is
end declared
Implicit initialization of all Ditto Only global variables are
the variables (both global and initialized. In local variables,
local ones) by zero only strings are initialized
implicitly
Local arrays are not released Local arrays are released Local arrays are released when
when exiting the function when exiting the function exiting {} block
"Array out of range" does not Ditto, except for the arrays of "Array out of range" is a
cause a critical error structures and classes, for critical error causing the
which this error is critical one program to stop
No structures and classes Structures and classes are Ditto
present. Additional data types
are implemented
Strings are single-byte. Strings are unicode ones. Ditto
datetime is a 32-bit integer datetime is a 64-bit integer
Predefined Volume variable is Predefined Volume variable is
of double type of long type
Old MQL4 compiler New MQL4 compiler New MQL4 with #property
strict
ArrayCopyRates() performs ArrayCopyRates() performs Ditto
virtual copying to double[][6] virtual copying to MqlRates[]
array array. Copying to double[][6]
array has remained intact for
the sake of compatibility,
however, that copying is real,
not virtual.
The functions may not return Ditto Functions of any type should
values even if they have a return a value
type. To do this, return(0) is
automatically inserted by the
compiler in the function end
The number of The number of simultaneously Ditto
simultaneously opened files is opened files is 64
32
The files are always opened FILE_SHARE_READ and/or Ditto
in FILE_SHARE_READ, FILE_SHARE_WRITE should be
FILE_SHARE_WRITE mode ** specified explicitly
The names of extern The names of extern and String comments instead of
variables are displayed for input variables are displayed extern and input variable
scripts in the input for scripts in show_inputs names are displayed for scripts
parameters window mode in the input parameters in show_inputs mode in the
window input parameters window
* Please pay special attention to "Array out of range" error - many old custom indicators
will display this error in strict mode of the new compiler when launched on the chart.
It is recommended to find the cause and eliminate it.
** In the new MQL4 and MQL5, FILE_SHARE_READ and FILE_SHARE_WRITE flags are
responsible for the files shared use mode. There were no such files in the old MQL4.
Changes in File Structure
In the previous builds of MetaTrader 4 client terminal (509 and older), all MQL4
applications were stored in the following subdirectories of
<terminal_installation_folder>\experts\ root directory:
\experts - Expert Advisors (trading robots),
\experts\indicators - custom indicators,
\experts\scripts - scripts (MQL4 applications for a single run on the chart),
\include - source code MQH and MQ4 files implemented into other programs,
\libraries - libraries in the form of MQ4 source codes and EX4 executable files
compiled from them. They are used for the dynamic call of the functions contained
there by other MQL4 programs,
\files - special "file sandbox". MQL4 applications are allowed to execute file
operations only within this directory.
In the new MQL4 version, the file structure for storing the source codes has changed.
Now, all MQL4 applications should be located in the appropriate folders of
<data_folder>\MQL4\ directory:
\Experts - Expert Advisors (trading robots),
\Indicators - custom indicators,
\Scripts - scripts (MQL4 applications for a single run on the chart),
\Include - source code MQH and MQ4 files implemented into other programs,
\Libraries - libraries in the form of MQ4 source codes and EX4 executable files
compiled from them. They are used for the dynamic call of the functions contained
there by other MQL4 programs,
\Images - image files for using in resources,
\Files - special "file sandbox". MQL4 applications are allowed to execute file
operations only within this directory.
When updating MetaTrader 4 terminal from build 509 to the newer version, all MQ4,
MQH and EX4 files from standard root directories of the previous version are
automatically copied and relocated to the appropriate folders. Subfolders additionally
created by a user, as well as files contained there are not processed. They should be
relocated to the new place manually if necessary.
No files or folders are deleted during the update! All file copy operations including used file
paths are fixed in the terminal Journal during the update.
No automatic re-compilation of the old EX4 files to the new version is performed
during the update. Users are free to decide what source codes should be compiled to
the new EX4 version. All old EX4 will work in the new MetaTrader 4 terminal. EX4
libraries compiled by the new compiler can be called only from the EX4 programs that
have also been compiled in the new version.
In some cases, you may need to edit the path in #include for included files (if relative
paths have changed) in the source files. Please note that MetaEditor's root directory is
now <data_folder>\MQL4\. All programs should be located in the correct subdirectories.
You can find the data folder (<data_folder>) for each copy of MetaTrader 4 terminal on
your computer via the terminal menu or in MetaEditor: File - Open Data Folder.
MQL4 Reference / Constants, Enumerations and Structures
Chart Constants
Constants describing various properties of charts are divided into the
following groups:
Types of events events that occur when working with charts;
Chart timeframes standard built-in periods;
Properties of chart identifiers that are used as parameters of chart
functions;
Positioning constants - value of a parameter of the ChartNavigate()
function;
Displaying charts - setting the chart appearance.
What's new in MQL5
The new generation platform has two times more timeframes (21 vs
9). It also features new graphical objects and analytical tools. Object
anchors can be placed in any position between the chart bars up to a
minute. Moreover, when switching between timeframes, the accurate
positioning of the control points of the object is preserved.
You can set any chart properties directly from an MQL5 program. The
number of properties has been increased. CHART_SHOW and
CHART_IS_DOCKED are among the most notable ones. They allow
moving any chart beyond the terminal turning it into a full-fledged
separate trading panel. Disable the display of unnecessary areas on
the chart and place OBJ_CHART objects, indicators and an EA on it to
get your own trading control center with all the necessary technical
analysis tools.
The table shows the new properties allowing you to fully manage a
symbol chart.
Property
ID Description
Type
Property
ID Description
Type
Price chart drawing. If false,
drawing any price chart
attributes is disabled and all
chart border indents are
eliminated, including time and
price scales, quick navigation
bar, Calendar event labels,
trade labels, indicator and bar
CHART_SHOW tooltips, indicator subwindows, bool
volume histograms, etc.
Disabling the drawing is a
perfect solution for creating a
custom program interface using
the graphical resources.
The graphical objects are
always drawn regardless of the
CHART_SHOW property value.
Identifying "Chart"
(OBJ_CHART) object returns
CHART_IS_OBJECT bool r/o
true for a graphical object.
Returns false for a real chart
bool
Show chart on top of other
CHART_CONTEXT_MENU (default
charts
is 'true')
Enabling/disabling access to
the context menu using the
right click.
When bool
CHART_CROSSHAIR_TOOL CHART_CONTEXT_MENU=false, (default
only the chart context menu is is 'true')
disabled. The context menu of
objects on the chart remains
available.
Enabling/disabling access to
CHART_MOUSE_SCROLL the Crosshair tool using the bool
middle click.
Property
ID Description
Type
Scrolling the chart horizontally
using the left mouse button.
Vertical scrolling is also
available if the value of any
following properties is set to
bool
true: CHART_SCALEFIX,
CHART_EVENT_MOUSE_WHEEL (default
CHART_SCALEFIX_11 or
is 'true')
CHART_SCALE_PT_PER_BAR
When
CHART_MOUSE_SCROLL=false,
chart scrolling with the mouse
wheel is unavailable
Sending messages about mouse
wheel events
CHART_EVENT_MOUSE_MOVE bool
(CHARTEVENT_MOUSE_WHEEL)
to all mql5 programs on a chart
Send notifications of mouse
move and mouse click events
CHART_EVENT_OBJECT_CREATE bool
(CHARTEVENT_MOUSE_MOVE)
to all mql5 programs on a chart
Send a notification of an event
of new object creation
CHART_EVENT_OBJECT_DELETE bool
(CHARTEVENT_OBJECT_CREATE)
to all mql5-programs on a chart
Allow managing the chart using
a keyboard ("Home", "End",
"PageUp", "+", "-", "Up arrow",
etc.). Setting
CHART_KEYBOARD_CONTROL to
CHART_KEYBOARD_CONTROL bool
false disables chart scrolling
and scaling while leaving intact
the ability to receive the keys
pressing events in
OnChartEvent().
Display textual descriptions of
CHART_SHOW_OBJECT_DESCR objects (not available for all bool
objects)
Property
ID Description
Type
Showing the "One click trading"
CHART_SHOW_ONE_CLICK bool
panel on a chart
CHART_IS_MAXIMIZED Chart window is maximized bool
CHART_IS_MINIMIZED Chart window is minimized bool
The chart window is docked. If
set to false, the chart can be
CHART_IS_DOCKED bool
dragged outside the terminal
area
The left coordinate of the
CHART_FLOAT_LEFT undocked chart window int
relative to the virtual screen
The top coordinate of the
CHART_FLOAT_TOP undocked chart window int
relative to the virtual screen
The right coordinate of the
CHART_FLOAT_RIGHT undocked chart window int
relative to the virtual screen
The bottom coordinate of the
CHART_FLOAT_BOTTOM undocked chart window int
relative to the virtual screen
MQL4 Reference / Constants, Enumerations and Structures / Chart Constants / Types of Chart Events
For each type of event, the input parameters of the OnChartEvent() function have
definite values that are required for the processing of this event. The events and values
passed through this parameters are listed in the below table.
Event Value of the id parameter Value of the lparam Value
parameter dpara
Event of a keystroke CHARTEVENT_KEYDOWN code of a pressed Repea
key numb
the
repea
of the
down
Mouse events (if CHARTEVENT_MOUSE_MOVE the X coordinate the Y
CHART_EVENT_MOUSE_MOVE=true is
set for the chart)
Event Value of the id parameter Value of the lparam Value
parameter dpara
event of graphical object creation CHARTEVENT_OBJECT_CREATE
(if
CHART_EVENT_OBJECT_CREATE=true
is set for the chart)
Event of change of an object CHARTEVENT_OBJECT_CHANGE
property via the properties dialog
Example:
#define KEY_NUMPAD_5 12 #define KEY_LEFT 37
#define KEY_UP 38
#define KEY_RIGHT 39
#define KEY_DOWN 40
#define KEY_NUMLOCK_DOWN 98
#define KEY_NUMLOCK_LEFT 100
#define KEY_NUMLOCK_5 101
#define KEY_NUMLOCK_RIGHT 102
#define KEY_NUMLOCK_UP 104
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
Print("The Expert Advisor with name ",MQLInfoString(MQL_PROGRAM_NAME)," is running
//--- enable object create events
ChartSetInteger(ChartID(),CHART_EVENT_OBJECT_CREATE,true);
//--- enable object delete events
ChartSetInteger(ChartID(),CHART_EVENT_OBJECT_DELETE,true);
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, // Event identifier
const long& lparam, // Event parameter of long type
const double& dparam, // Event parameter of double type
const string& sparam) // Event parameter of string type
{
//--- the left mouse button has been pressed on the chart
if(id==CHARTEVENT_CLICK)
{
Print("The coordinates of the mouse click on the chart are: x = ",lparam," y =
}
//--- the mouse has been clicked on the graphic object
if(id==CHARTEVENT_OBJECT_CLICK)
{
Print("The mouse has been clicked on the object with name '"+sparam+"'");
}
//--- the key has been pressed
if(id==CHARTEVENT_KEYDOWN)
{
switch(int(lparam))
{
case KEY_NUMLOCK_LEFT: Print("The KEY_NUMLOCK_LEFT has been pressed"); br
case KEY_LEFT: Print("The KEY_LEFT has been pressed"); br
case KEY_NUMLOCK_UP: Print("The KEY_NUMLOCK_UP has been pressed"); br
case KEY_UP: Print("The KEY_UP has been pressed"); br
case KEY_NUMLOCK_RIGHT: Print("The KEY_NUMLOCK_RIGHT has been pressed"); br
case KEY_RIGHT: Print("The KEY_RIGHT has been pressed"); br
case KEY_NUMLOCK_DOWN: Print("The KEY_NUMLOCK_DOWN has been pressed"); br
case KEY_DOWN: Print("The KEY_DOWN has been pressed"); br
case KEY_NUMPAD_5: Print("The KEY_NUMPAD_5 has been pressed"); br
case KEY_NUMLOCK_5: Print("The KEY_NUMLOCK_5 has been pressed"); br
default: Print("Some not listed key has been pressed");
}
ChartRedraw();
}
//--- the object has been deleted
if(id==CHARTEVENT_OBJECT_DELETE)
{
Print("The object with name ",sparam," has been deleted");
}
//--- the object has been created
if(id==CHARTEVENT_OBJECT_CREATE)
{
Print("The object with name ",sparam," has been created");
}
//--- the object has been moved or its anchor point coordinates has been changed
if(id==CHARTEVENT_OBJECT_DRAG)
{
Print("The anchor point coordinates of the object with name ",sparam," has been
}
//--- the text in the Edit of object has been changed
if(id==CHARTEVENT_OBJECT_ENDEDIT)
{
Print("The text in the Edit field of the object with name ",sparam," has been c
}
}
Example:
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
void OnInit()
{
//--- enable CHART_EVENT_MOUSE_MOVE messages
ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,1);
}
//+------------------------------------------------------------------+
//| MouseState |
//+------------------------------------------------------------------+
string MouseState(uint state)
{
string res;
res+="\nML: " +(((state& 1)== 1)?"DN":"UP"); // mouse left
res+="\nMR: " +(((state& 2)== 2)?"DN":"UP"); // mouse right
res+="\nMM: " +(((state&16)==16)?"DN":"UP"); // mouse middle
res+="\nMX: " +(((state&32)==32)?"DN":"UP"); // mouse first X key
res+="\nMY: " +(((state&64)==64)?"DN":"UP"); // mouse second X key
res+="\nSHIFT: "+(((state& 4)== 4)?"DN":"UP"); // shift key
res+="\nCTRL: " +(((state& 8)== 8)?"DN":"UP"); // control key
return(res);
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &
{
if(id==CHARTEVENT_MOUSE_MOVE)
Comment("POINT: ",(int)lparam,",",(int)dparam,"\n",MouseState((uint)sparam));
}
See also
Event Handling Functions, Working with events
MQL4 Reference / Constants, Enumerations and Structures / Chart
Constants / Chart Timeframes
Chart Timeframes
All predefined timeframes of charts have unique
identifiers. The PERIOD_CURRENT identifier means the
current period of a chart, at which a mql4-program is
running.
ENUM_TIMEFRAMES
ID Value Description
PERIOD_CURRENT 0 Current timeframe
PERIOD_M1 1 1 minute
PERIOD_M5 5 5 minutes
PERIOD_M15 15 15 minutes
PERIOD_M30 30 30 minutes
PERIOD_H1 60 1 hour
PERIOD_H4 240 4 hours
PERIOD_D1 1440 1 day
PERIOD_W1 10080 1 week
PERIOD_MN1 43200 1 month
Chart Properties
Identifiers of ENUM_CHART_PROPERTY enumerations are used as parameters of
functions for working with charts. The abbreviation of r/o in the "Property Type"
column means that this property is read-only and cannot be changed. The w/o
abbreviation in the "Property Type" column means that this property is write-only and
it cannot be received. When accessing certain properties, it's necessary to specify an
additional parameter-modifier (modifier), which serves to indicate the number of
chart subwindows. 0 means the main window.
For functions ChartSetInteger() and ChartGetInteger()
ENUM_CHART_PROPERTY_INTEGER
ID Description Property Type
CHART_BRING_TO_TOP Show chart on top of other bool w/o
charts
CHART_MOUSE_SCROLL Scrolling the chart horizontally bool
using the left mouse button.
Vertical scrolling is also
available if the value of any
following properties is set to
true: CHART_SCALEFIX,
CHART_SCALEFIX_11 or
CHART_SCALE_PT_PER_BAR
CHART_EVENT_MOUSE_MOVE Send notifications of mouse bool
move and mouse click events
(CHARTEVENT_MOUSE_MOVE)
to all mql4 programs on a chart
CHART_EVENT_OBJECT_CREATE Send a notification of an event bool
of new object creation
(CHARTEVENT_OBJECT_CREATE)
to all mql4-programs on a chart
CHART_EVENT_OBJECT_DELETE Send a notification of an event bool
of object deletion
(CHARTEVENT_OBJECT_DELETE)
to all mql4-programs on a chart
CHART_MODE Chart type (candlesticks, bars enum ENUM_CHART_MODE
or line)
CHART_FOREGROUND Price chart in the foreground bool
CHART_SHIFT Mode of price chart indent from bool
the right border
CHART_AUTOSCROLL Mode of automatic moving to bool
the right border of the chart
ID Description Property Type
CHART_QUICK_NAVIGATION Allow the chart to intercept bool
Space and Enter key strokes to
activate the quick navigation
bar. The quick navigation bar
automatically appears at the
bottom of the chart after
double-clicking the mouse or
pressing Space/Enter. It allows
you to quickly change a symbol,
timeframe and first visible bar
date.
CHART_SCALE Scale int from 0 to 5
CHART_SCALEFIX Fixed scale mode bool
CHART_SCALEFIX_11 Scale 1:1 mode bool
CHART_SCALE_PT_PER_BAR Scale to be specified in points bool
per bar
CHART_SHOW_OHLC Show OHLC values in the upper bool
left corner
CHART_SHOW_BID_LINE Display Bid values as a bool
horizontal line in a chart
CHART_SHOW_ASK_LINE Display Ask values as a bool
horizontal line in a chart
CHART_SHOW_LAST_LINE Display Last values as a bool
horizontal line in a chart
CHART_SHOW_PERIOD_SEP Display vertical separators bool
between adjacent periods
CHART_SHOW_GRID Display grid in the chart bool
CHART_SHOW_VOLUMES Display volume in the chart enum
ENUM_CHART_VOLUME_MODE
CHART_SHOW_OBJECT_DESCR Display textual descriptions of bool
objects (not available for all
objects)
CHART_VISIBLE_BARS The number of bars on the int r/o
chart that can be displayed
CHART_WINDOWS_TOTAL The total number of chart int r/o
windows, including indicator
subwindows
CHART_WINDOW_IS_VISIBLE Visibility of subwindows bool r/o modifier -
subwindow number
CHART_WINDOW_HANDLE Chart window handle (HWND) int r/o
ID Description Property Type
CHART_WINDOW_YDISTANCE The distance between the int r/o modifier -
upper frame of the indicator subwindow number
subwindow and the upper
frame of the main chart
window, along the vertical Y
axis, in pixels. In case of a
mouse event, the cursor
coordinates are passed in terms
of the coordinates of the main
chart window, while the
coordinates of graphical
objects in an indicator
subwindow are set relative to
the upper left corner of the
subwindow.
The value is required for
converting the absolute
coordinates of the main chart
to the local coordinates of a
subwindow for correct work
with the graphical objects,
whose coordinates are set
relative to the upper left
corner of the subwindow
frame.
CHART_FIRST_VISIBLE_BAR Number of the first visible bar int r/o
in the chart. Indexing of bars is
the same as for timeseries.
CHART_WIDTH_IN_BARS Chart width in bars int r/o
CHART_WIDTH_IN_PIXELS Chart width in pixels int r/o
CHART_HEIGHT_IN_PIXELS Chart height in pixels int modifier - subwindow
number
CHART_COLOR_BACKGROUND Chart background color color
CHART_COLOR_FOREGROUND Color of axes, scales and OHLC color
line
CHART_COLOR_GRID Grid color color
CHART_COLOR_VOLUME Color of volumes and order color
opening levels
CHART_COLOR_CHART_UP Color for the up bar, shadows color
and body borders of bull
candlesticks
CHART_COLOR_CHART_DOWN Color for the down bar, color
shadows and body borders of
bear candlesticks
ID Description Property Type
CHART_COLOR_CHART_LINE Line chart color and color of color
"Doji" Japanese candlesticks
CHART_COLOR_CANDLE_BULL Body color of a bull candlestick color
CHART_COLOR_CANDLE_BEAR Body color of a bear color
candlestick
CHART_COLOR_BID Bid price level color color
CHART_COLOR_ASK Ask price level color color
CHART_COLOR_LAST Line color of the last executed color
deal price (Last)
CHART_COLOR_STOP_LEVEL Color of stop order levels (Stop color
Loss and Take Profit)
CHART_SHOW_TRADE_LEVELS Displaying trade levels in the bool
chart (levels of open orders,
Stop Loss, Take Profit and
pending orders)
CHART_DRAG_TRADE_LEVELS Permission to drag trading bool
levels on a chart with a mouse.
The drag mode is enabled by
default (true value)
CHART_SHOW_DATE_SCALE Showing the time scale on a bool
chart
CHART_SHOW_PRICE_SCALE Showing the price scale on a bool
chart
CHART_IS_OFFLINE Flag, indicating that chart bool r/o
opened in offline mode
Example:
int chartMode=ChartGetInteger(0,CHART_MODE); switch(chartMode)
{
case(CHART_BARS): Print("CHART_BARS"); break;
case(CHART_CANDLES): Print("CHART_CANDLES");break;
default:Print("CHART_LINE");
}
bool shifted=ChartGetInteger(0,CHART_SHIFT);
if(shifted) Print("CHART_SHIFT = true");
else Print("CHART_SHIFT = false");
bool autoscroll=ChartGetInteger(0,CHART_AUTOSCROLL);
if(autoscroll) Print("CHART_AUTOSCROLL = true");
else Print("CHART_AUTOSCROLL = false");
int chartHandle=ChartGetInteger(0,CHART_WINDOW_HANDLE);
Print("CHART_WINDOW_HANDLE = ",chartHandle);
int windows=ChartGetInteger(0,CHART_WINDOWS_TOTAL);
Print("CHART_WINDOWS_TOTAL = ",windows);
if(windows>1)
{
for(int i=0;i<windows;i++)
{
int height=ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS,i);
double priceMin=ChartGetDouble(0,CHART_PRICE_MIN,i);
double priceMax=ChartGetDouble(0,CHART_PRICE_MAX,i);
Print(i+": CHART_HEIGHT_IN_PIXELS = ",height," pixels");
Print(i+": CHART_PRICE_MIN = ",priceMin);
Print(i+": CHART_PRICE_MAX = ",priceMax);
}
}
See also
Examples of Working with the Chart
MQL4 Reference / Constants, Enumerations and Structures / Chart Constants /
Positioning Constants
Positioning Constants
Three identifiers from the ENUM_CHART_POSITION list are the
possible values of the position parameter for the ChartNavigate()
function.
ENUM_CHART_POSITION
ID Description
CHART_BEGIN Chart beginning (the oldest prices)
CHART_CURRENT_POS Current position
CHART_END Chart end (the latest prices)
Example:
long handle=ChartOpen("EURUSD",PERIOD_H12); if(handle!=0)
{
ChartSetInteger(handle,CHART_AUTOSCROLL,false);
ChartSetInteger(handle,CHART_SHIFT,true);
ChartSetInteger(handle,CHART_MODE,CHART_LINE);
ResetLastError();
bool res=ChartNavigate(handle,CHART_END,150);
if(!res) Print("Navigate failed. Error = ",GetLastError());
ChartRedraw();
}
MQL4 Reference / Constants, Enumerations and Structures / Chart Constants / Chart
Representation
Chart Representation
Price charts can be displayed in three ways:
as bars;
as candlesticks;
as a line.
The specific way of displaying the price chart is set by the function
ChartSetInteger(chart_handle,CHART_MODE, chart_mode), where
chart_mode is one of the values of the ENUM_CHART_MODE
enumeration.
ENUM_CHART_MODE
ID Description
CHART_BARS Display as a sequence of bars
CHART_CANDLES Display as Japanese candlesticks
CHART_LINE Display as a line drawn by Close prices
Example:
//--- Get the handle of the current chart long handle=ChartID();
if(handle>0) // If it succeeded, additionally customize
{
//--- Disable autoscroll
ChartSetInteger(handle,CHART_AUTOSCROLL,false);
//--- Set the indent of the right border of the chart
ChartSetInteger(handle,CHART_SHIFT,true);
//--- Display as candlesticks
ChartSetInteger(handle,CHART_MODE,CHART_CANDLES);
//--- Scroll by 100 bars from the beginning of history
ChartNavigate(handle,CHART_CURRENT_POS,100);
//--- Set the tick volume display mode
ChartSetInteger(handle,CHART_SHOW_VOLUMES,CHART_VOLUME_TICK);
}
See also
ChartOpen, ChartID
MQL4 Reference / Constants, Enumerations and Structures / Chart Constants / Examples of Working with the
Chart
CHART_MOUSE_SCROLL is a property for scrolling the chart using left mouse button.
//+--------------------------------------------------------------------------+
//| The function defines if scrolling the chart using left mouse button is |
//| enabled. |
//+--------------------------------------------------------------------------+
bool ChartMouseScrollGet(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_MOUSE_SCROLL,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+--------------------------------------------------------------------+
//| The function enables/disables scrolling the chart using left mouse |
//| button. |
//+--------------------------------------------------------------------+
bool ChartMouseScrollSet(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_MOUSE_SCROLL,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_EVENT_MOUSE_MOVE is a property of sending messages concerning move
events and mouse clicks to mql4 applications (CHARTEVENT_MOUSE_MOVE).
//+------------------------------------------------------------------+
//| Check if messages concerning move events and mouse clicks |
//| are sent to all mql4 applications on the chart. |
//+------------------------------------------------------------------+
bool ChartEventMouseMoveGet(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_EVENT_MOUSE_MOVE,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+------------------------------------------------------------------------------+
//| The function enables/disables the mode of sending messages concerning move |
//| events and mouse clicks to mql4 applications on the |
//| chart. |
//+------------------------------------------------------------------------------+
bool ChartEventMouseMoveSet(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_EVENT_MOUSE_MOVE,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_EVENT_OBJECT_CREATE is a property of sending messages concerning the
event of a graphic object creation to mql4 applications
(CHARTEVENT_OBJECT_CREATE).
//+---------------------------------------------------------------------+
//| Check if messages concerning the event of a graphic object creation |
//| are sent to all mql4 applications on the chart. |
//+---------------------------------------------------------------------+
bool ChartEventObjectCreateGet(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_EVENT_OBJECT_CREATE,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+--------------------------------------------------------------------------+
//| The function enables/disables the mode of sending messages concerning |
//| the event of a graphic object creation to all mql4 applications on the |
//| chart. |
//+--------------------------------------------------------------------------+
bool ChartEventObjectCreateSet(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_EVENT_OBJECT_CREATE,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_EVENT_OBJECT_DELETE is a property of sending messages concerning the
event of a graphic object deletion to mql4 applications
(CHARTEVENT_OBJECT_DELETE).
//+---------------------------------------------------------------------+
//| Check if messages concerning the event of a graphic object deletion |
//| are sent to all mql4 applications on the chart. |
//+---------------------------------------------------------------------+
bool ChartEventObjectDeleteGet(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_EVENT_OBJECT_DELETE,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+--------------------------------------------------------------------------+
//| The function enables/disables the mode of sending messages concerning |
//| the event of a graphic object deletion to all mql4 applications on the |
//| chart. |
//+--------------------------------------------------------------------------+
bool ChartEventObjectDeleteSet(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_EVENT_OBJECT_DELETE,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_MODE type of the chart (candlesticks, bars or line).
//+------------------------------------------------------------------+
//| Get chart display type (candlesticks, bars or |
//| line). |
//+------------------------------------------------------------------+
ENUM_CHART_MODE ChartModeGet(const long chart_ID=0)
{
//--- prepare the variable to get the property value
long result=WRONG_VALUE;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_MODE,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((ENUM_CHART_MODE)result);
}
//+------------------------------------------------------------------+
//| Set chart display type (candlesticks, bars or |
//| line). |
//+------------------------------------------------------------------+
bool ChartModeSet(const long value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_MODE,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_FOREGROUND is a property of displaying a price chart in the foreground.
//+------------------------------------------------------------------+
//| The function defines if a price chart is displayed in the |
//| foreground. |
//+------------------------------------------------------------------+
bool ChartForegroundGet(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_FOREGROUND,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+---------------------------------------------------------------------------+
//| The function enables/disables the mode of displaying a price chart on the |
//| foreground. |
//+---------------------------------------------------------------------------+
bool ChartForegroundSet(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_FOREGROUND,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_SHIFT mode of shift of the price chart from the right border.
//+----------------------------------------------------------------------------------
//| The function defines if the mode of shift of the price chart from the right borde
//| is enabled.
//+----------------------------------------------------------------------------------
bool ChartShiftGet(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_SHIFT,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+--------------------------------------------------------------------------+
//| The function enables/disables the mode of displaying a price chart with |
//| a shift from the right border. |
//+--------------------------------------------------------------------------+
bool ChartShiftSet(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_SHIFT,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_AUTOSCROLL the mode of automatic shift to the right border of the chart.
//+---------------------------------------------------------------------+
//| The function defines if the mode of the autoscroll |
//| of the chart to the right in case of new ticks' arrival is enabled. |
//+---------------------------------------------------------------------+
bool ChartAutoscrollGet(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_AUTOSCROLL,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| The function enables/disables the mode of the autoscroll |
//| of the chart to the right in case of new ticks' arrival. |
//+------------------------------------------------------------------+
bool ChartAutoscrollSet(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_AUTOSCROLL,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_SCALE chart scale property.
//+------------------------------------------------------------------+
//| Get chart scale (from 0 to 5). |
//+------------------------------------------------------------------+
int ChartScaleGet(const long chart_ID=0)
{
//--- prepare the variable to get the property value
long result=-1;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_SCALE,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((int)result);
}
//+------------------------------------------------------------------+
//| Set chart scale (from 0 to 5). |
//+------------------------------------------------------------------+
bool ChartScaleSet(const long value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_SCALE,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_SCALEFIX the mode of fixed chart scale.
//+------------------------------------------------------------------+
//| The function defines if the fixed scale mode is enabled. |
//+------------------------------------------------------------------+
bool ChartScaleFixGet(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_SCALEFIX,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| The function enables/disables the fixed scale mode. |
//+------------------------------------------------------------------+
bool ChartScaleFixSet(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_SCALEFIX,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_SCALEFIX_11 1:1 chart scale mode.
//+------------------------------------------------------------------+
//| The function defines if "1:1" scale is enabled. |
//+------------------------------------------------------------------+
bool ChartScaleFix11Get(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_SCALEFIX_11,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| The function enables/disables "1:1" scale mode |
//+------------------------------------------------------------------+
bool ChartScaleFix11Set(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_SCALEFIX_11,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_SCALE_PT_PER_BAR the mode of specifying the chart scale in points per bar.
//+------------------------------------------------------------------------------+
//| The function defines if the mode of specifying the chart scale in points per |
//| bar is enabled. |
//+------------------------------------------------------------------------------+
bool ChartScalePerBarGet(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_SCALE_PT_PER_BAR,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+----------------------------------------------------------------------------------
//| The function enables/disables the mode of specifying the chart scale in points pe
//| bar.
//+----------------------------------------------------------------------------------
bool ChartScalePerBarSet(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_SCALE_PT_PER_BAR,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_SHOW_OHLC the property of displaying OHLC values in the upper left corner.
//+------------------------------------------------------------------+
//| The function defines if the mode of displaying OHLC values |
//| in the upper left corner is enabled. |
//+------------------------------------------------------------------+
bool ChartShowOHLCGet(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_SHOW_OHLC,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+--------------------------------------------------------------------------+
//| The function enables/disables the mode of displaying OHLC values in the |
//| upper left corner of the chart. |
//+--------------------------------------------------------------------------+
bool ChartShowOHLCSet(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_SHOW_OHLC,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_SHOW_BID_LINE the property of displaying Bid value as a horizontal line on
the chart.
//+-----------------------------------------------------------------------------+
//| The function defines if the mode of displaying Bid value line on the chart |
//| is enabled. |
//+-----------------------------------------------------------------------------+
bool ChartShowBidLineGet(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_SHOW_BID_LINE,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+--------------------------------------------------------------------+
//| The function enables/disables the mode of displaying Bid line on a |
//| chart. |
//+--------------------------------------------------------------------+
bool ChartShowBidLineSet(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_SHOW_BID_LINE,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_SHOW_ASK_LINE the property of displaying Ask value as a horizontal line on
a chart.
//+-----------------------------------------------------------------------+
//| The function defines if the mode of displaying Ask value line on the |
//| chart. |
//+-----------------------------------------------------------------------+
bool ChartShowAskLineGet(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_SHOW_ASK_LINE,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+-----------------------------------------------------------------------+
//| The function enables/disables the mode of displaying Ask line on the |
//| chart. |
//+-----------------------------------------------------------------------+
bool ChartShowAskLineSet(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_SHOW_ASK_LINE,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_SHOW_LAST_LINE the property of displaying Last value as a horizontal line
on a chart.
//+---------------------------------------------------------------------------------+
//| The function defines if the mode of displaying the line for the last performed |
//| deal's price is enabled. |
//+---------------------------------------------------------------------------------+
bool ChartShowLastLineGet(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_SHOW_LAST_LINE,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+----------------------------------------------------------------------------------
//| The function enables/disables the mode of displaying the line for the last perfor
//| deal's price.
//+----------------------------------------------------------------------------------
bool ChartShowLastLineSet(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_SHOW_LAST_LINE,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_SHOW_PERIOD_SEP the property of displaying vertical separators between
adjacent periods.
//+------------------------------------------------------------------+
//| The function defines if the mode of displaying vertical |
//| separators between adjacent periods is enabled. |
//+------------------------------------------------------------------+
bool ChartShowPeriodSeparatorGet(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_SHOW_PERIOD_SEP,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| The function enables/disables the mode of displaying vertical |
//| separators between adjacent periods. |
//+------------------------------------------------------------------+
bool ChartShowPeriodSepapatorSet(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_SHOW_PERIOD_SEP,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_SHOW_GRID the property of displaying the chart grid.
//+------------------------------------------------------------------+
//| The function defines if the chart grid is displayed. |
//+------------------------------------------------------------------+
bool ChartShowGridGet(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_SHOW_GRID,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| The function enables/disables the chart grid. |
//+------------------------------------------------------------------+
bool ChartShowGridSet(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set the property value
if(!ChartSetInteger(chart_ID,CHART_SHOW_GRID,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_SHOW_VOLUMES the property of displaying the volumes on a chart.
//+------------------------------------------------------------------------+
//| The function defines if the volumes are displayed on a chart (are not |
//| displayed, tick ones are displayed, actual ones are displayed). |
//+------------------------------------------------------------------------+
ENUM_CHART_VOLUME_MODE ChartShowVolumesGet(const long chart_ID=0)
{
//--- prepare the variable to get the property value
long result=WRONG_VALUE;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_SHOW_VOLUMES,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((ENUM_CHART_VOLUME_MODE)result);
}
//+------------------------------------------------------------------+
//| The function sets the mode of displaying the volumes on a chart. |
//+------------------------------------------------------------------+
bool ChartShowVolumesSet(const long value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_SHOW_VOLUMES,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_SHOW_OBJECT_DESCR the property of graphical object pop-up descriptions.
//+-------------------------------------------------------------------+
//| The function defines if pop-up descriptions |
//| of graphical objects are displayed when hovering mouse over them. |
//+-------------------------------------------------------------------+
bool ChartShowObjectDescriptionGet(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_SHOW_OBJECT_DESCR,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+--------------------------------------------------------------------------+
//| The function enables/disables the mode of displaying pop-up descriptions |
//| of graphical objects when hovering mouse over them. |
//+--------------------------------------------------------------------------+
bool ChartShowObjectDescriptionSet(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_SHOW_OBJECT_DESCR,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_VISIBLE_BARS defines the number of bars on a chart that are available for
display.
//+-----------------------------------------------------------------------+
//| The function receives the number of bars that are displayed (visible) |
//| in the chart window. |
//+-----------------------------------------------------------------------+
int ChartVisibleBars(const long chart_ID=0)
{
//--- prepare the variable to get the property value
long result=-1;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_VISIBLE_BARS,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((int)result);
}
CHART_WINDOWS_TOTAL defines the total number of chart windows including
indicator subwindows.
//+--------------------------------------------------------------------------+
//| The function gets the total number of chart windows including indicator |
//| subwindows. |
//+--------------------------------------------------------------------------+
int ChartWindowsTotal(const long chart_ID=0)
{
//--- prepare the variable to get the property value
long result=-1;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_WINDOWS_TOTAL,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((int)result);
}
CHART_WINDOW_IS_VISIBLE defines the subwindow's visibility.
//+------------------------------------------------------------------+
//| The function defines if the current chart window or subwindow |
//| is visible. |
//+------------------------------------------------------------------+
bool ChartWindowsIsVisible(bool &result,const long chart_ID=0,const int sub_window=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_WINDOW_IS_VISIBLE,sub_window,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
CHART_WINDOW_HANDLE returns the chart handle.
//+------------------------------------------------------------------+
//| The function gets the chart handle |
//+------------------------------------------------------------------+
int ChartWindowsHandle(const long chart_ID=0)
{
//--- prepare the variable to get the property value
long result=-1;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_WINDOW_HANDLE,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((int)result);
}
CHART_WINDOW_YDISTANCE defines the distance in pixels between the upper frame
of the indicator subwindow and the upper frame of the chart's main window.
//+------------------------------------------------------------------+
//| The function gets the distance in pixels between the upper frame |
//| of the subwindow and the upper frame of the chart's main window. |
//+------------------------------------------------------------------+
int ChartWindowsYDistance(const long chart_ID=0,const int sub_window=0)
{
//--- prepare the variable to get the property value
long result=-1;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_WINDOW_YDISTANCE,sub_window,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((int)result);
}
CHART_FIRST_VISIBLE_BAR returns the number of the first visible bar on the chart
(bar indexing corresponds to the time series).
//+----------------------------------------------------------------------------+
//| The function receives the number of the first visible bar on the chart. |
//| Indexing is performed like in time series, last bars have smaller indices. |
//+----------------------------------------------------------------------------+
int ChartFirstVisibleBar(const long chart_ID=0)
{
//--- prepare the variable to get the property value
long result=-1;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_WINDOW_YDISTANCE,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((int)result);
}
CHART_WIDTH_IN_BARS returns the chart width in bars.
//+------------------------------------------------------------------+
//| The function receives the chart width in bars. |
//+------------------------------------------------------------------+
int ChartWidthInBars(const long chart_ID=0)
{
//--- prepare the variable to get the property value
long result=-1;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_WIDTH_IN_BARS,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((int)result);
}
CHART_WIDTH_IN_PIXELS returns the chart width in pixels.
//+------------------------------------------------------------------+
//| The function receives the chart width in pixels. |
//+------------------------------------------------------------------+
int ChartWidthInPixels(const long chart_ID=0)
{
//--- prepare the variable to get the property value
long result=-1;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_WIDTH_IN_PIXELS,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((int)result);
}
CHART_HEIGHT_IN_PIXELS chart height property in pixels.
//+------------------------------------------------------------------+
//| The function receives the chart height value in pixels. |
//+------------------------------------------------------------------+
int ChartHeightInPixelsGet(const long chart_ID=0,const int sub_window=0)
{
//--- prepare the variable to get the property value
long result=-1;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_HEIGHT_IN_PIXELS,sub_window,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((int)result);
}
//+------------------------------------------------------------------+
//| The function sets the chart height value in pixels. |
//+------------------------------------------------------------------+
bool ChartHeightInPixelsSet(const int value,const long chart_ID=0,const int sub_windo
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_HEIGHT_IN_PIXELS,sub_window,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_COLOR_BACKGROUND - chart background color.
//+------------------------------------------------------------------+
//| The function receives chart background color. |
//+------------------------------------------------------------------+
color ChartBackColorGet(const long chart_ID=0)
{
//--- prepare the variable to receive the color
long result=clrNONE;
//--- reset the error value
ResetLastError();
//--- receive chart background color
if(!ChartGetInteger(chart_ID,CHART_COLOR_BACKGROUND,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((color)result);
}
//+------------------------------------------------------------------+
//| The function sets chart background color. |
//+------------------------------------------------------------------+
bool ChartBackColorSet(const color clr,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set the chart background color
if(!ChartSetInteger(chart_ID,CHART_COLOR_BACKGROUND,clr))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_COLOR_FOREGROUND color of axes, scale and OHLC line.
//+------------------------------------------------------------------+
//| The function receives the color of axes, scale and OHLC line. |
//+------------------------------------------------------------------+
color ChartForeColorGet(const long chart_ID=0)
{
//--- prepare the variable to receive the color
long result=clrNONE;
//--- reset the error value
ResetLastError();
//--- receive the color of axes, scale and OHLC line
if(!ChartGetInteger(chart_ID,CHART_COLOR_FOREGROUND,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((color)result);
}
//+------------------------------------------------------------------+
//| The function sets the color of axes, scale and OHLC line. |
//+------------------------------------------------------------------+
bool ChartForeColorSet(const color clr,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set the color of axes, scale and OHLC line
if(!ChartSetInteger(chart_ID,CHART_COLOR_FOREGROUND,clr))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_COLOR_GRID chart grid color.
//+------------------------------------------------------------------+
//| The function receives chart grid color. |
//+------------------------------------------------------------------+
color ChartGridColorGet(const long chart_ID=0)
{
//--- prepare the variable to receive the color
long result=clrNONE;
//--- reset the error value
ResetLastError();
//--- receive chart grid color
if(!ChartGetInteger(chart_ID,CHART_COLOR_GRID,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((color)result);
}
//+------------------------------------------------------------------+
//| The function sets chart grid color. |
//+------------------------------------------------------------------+
bool ChartGridColorSet(const color clr,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set chart grid color
if(!ChartSetInteger(chart_ID,CHART_COLOR_GRID,clr))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_COLOR_VOLUME - color of volumes and order opening levels.
//+------------------------------------------------------------------+
//| The function receives color of volumes and market entry |
//| levels. |
//+------------------------------------------------------------------+
color ChartVolumeColorGet(const long chart_ID=0)
{
//--- prepare the variable to receive the color
long result=clrNONE;
//--- reset the error value
ResetLastError();
//--- receive color of volumes and market entry levels
if(!ChartGetInteger(chart_ID,CHART_COLOR_VOLUME,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((color)result);
}
//+------------------------------------------------------------------+
//| The function sets the color of volumes and market entry |
//| levels. |
//+------------------------------------------------------------------+
bool ChartVolumeColorSet(const color clr,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set color of volumes and market entry levels
if(!ChartSetInteger(chart_ID,CHART_COLOR_VOLUME,clr))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_COLOR_CHART_UP color of up bar, its shadow and border of a bullish
candlestick's body.
//+------------------------------------------------------------------+
//| The function receives color of up bar, its shadow and |
//| border of a bullish candlestick's body. |
//+------------------------------------------------------------------+
color ChartUpColorGet(const long chart_ID=0)
{
//--- prepare the variable to receive the color
long result=clrNONE;
//--- reset the error value
ResetLastError();
//--- receive the color of up bar, its shadow and border of bullish candlestick's bod
if(!ChartGetInteger(chart_ID,CHART_COLOR_CHART_UP,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((color)result);
}
//+------------------------------------------------------------------+
//| The function sets color of up bar, its shadow and |
//| border of a bullish candlestick's body. |
//+------------------------------------------------------------------+
bool ChartUpColorSet(const color clr,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set the color of up bar, its shadow and border of body of a bullish candlestick
if(!ChartSetInteger(chart_ID,CHART_COLOR_CHART_UP,clr))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_COLOR_CHART_DOWN color of down bar, its shadow and border of bearish
candlestick's body.
//+------------------------------------------------------------------+
//| The function receives color of up bar, its shadow and |
//| border of a bearish candlestick's body. |
//+------------------------------------------------------------------+
color ChartDownColorGet(const long chart_ID=0)
{
//--- prepare the variable to receive the color
long result=clrNONE;
//--- reset the error value
ResetLastError();
//--- receive the color of down bar, its shadow and border of bearish candlestick's b
if(!ChartGetInteger(chart_ID,CHART_COLOR_CHART_DOWN,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((color)result);
}
//+------------------------------------------------------------------+
//| The function sets color of down bar, its shadow and |
//| border of a bearish candlestick's body. |
//+------------------------------------------------------------------+
bool ChartDownColorSet(const color clr,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set the color of down bar, its shadow and border of bearish candlestick's body
if(!ChartSetInteger(chart_ID,CHART_COLOR_CHART_DOWN,clr))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_COLOR_CHART_LINE color of the chart line and Doji candlesticks.
//+------------------------------------------------------------------------+
//| The function receives color of the chart line and Doji candlesticks. |
//+------------------------------------------------------------------------+
color ChartLineColorGet(const long chart_ID=0)
{
//--- prepare the variable to receive the color
long result=clrNONE;
//--- reset the error value
ResetLastError();
//--- receive color of the chart line and Doji candlesticks
if(!ChartGetInteger(chart_ID,CHART_COLOR_CHART_LINE,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((color)result);
}
//+------------------------------------------------------------------+
//| The function sets the color of the chart line and Doji |
//| candlesticks. |
//+------------------------------------------------------------------+
bool ChartLineColorSet(const color clr,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set color of the chart line and Doji candlesticks
if(!ChartSetInteger(chart_ID,CHART_COLOR_CHART_LINE,clr))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_COLOR_CANDLE_BULL color of bullish candlestick's body.
//+------------------------------------------------------------------+
//| The function receives color of bullish candlestick's body. |
//+------------------------------------------------------------------+
color ChartBullColorGet(const long chart_ID=0)
{
//--- prepare the variable to receive the color
long result=clrNONE;
//--- reset the error value
ResetLastError();
//--- receive the color of bullish candlestick's body
if(!ChartGetInteger(chart_ID,CHART_COLOR_CANDLE_BULL,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((color)result);
}
//+------------------------------------------------------------------+
//| The function sets color of bullish candlestick's body. |
//+------------------------------------------------------------------+
bool ChartBullColorSet(const color clr,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set the color of bullish candlestick's body
if(!ChartSetInteger(chart_ID,CHART_COLOR_CANDLE_BULL,clr))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_COLOR_CANDLE_BEAR color of bearish candlestick's body.
//+------------------------------------------------------------------+
//| The function receives color of bearish candlestick's body. |
//+------------------------------------------------------------------+
color ChartBearColorGet(const long chart_ID=0)
{
//--- prepare the variable to receive the color
long result=clrNONE;
//--- reset the error value
ResetLastError();
//--- receive the color of bearish candlestick's body
if(!ChartGetInteger(chart_ID,CHART_COLOR_CANDLE_BEAR,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((color)result);
}
//+------------------------------------------------------------------+
//| The function sets color of bearish candlestick's body. |
//+------------------------------------------------------------------+
bool ChartBearColorSet(const color clr,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set the color of bearish candlestick's body
if(!ChartSetInteger(chart_ID,CHART_COLOR_CANDLE_BEAR,clr))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_COLOR_BID Bid price line color.
//+------------------------------------------------------------------+
//| The function receives the color of Bid line. |
//+------------------------------------------------------------------+
color ChartBidColorGet(const long chart_ID=0)
{
//--- prepare the variable to receive the color
long result=clrNONE;
//--- reset the error value
ResetLastError();
//--- receive the color of Bid price line
if(!ChartGetInteger(chart_ID,CHART_COLOR_BID,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((color)result);
}
//+------------------------------------------------------------------+
//| The function sets the color of Bid line. |
//+------------------------------------------------------------------+
bool ChartBidColorSet(const color clr,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set the color of Bid price line
if(!ChartSetInteger(chart_ID,CHART_COLOR_BID,clr))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_COLOR_ASK Ask price line color.
//+------------------------------------------------------------------+
//| The function receives the color of Ask line. |
//+------------------------------------------------------------------+
color ChartAskColorGet(const long chart_ID=0)
{
//--- prepare the variable to receive the color
long result=clrNONE;
//--- reset the error value
ResetLastError();
//--- receive the color of Ask price line
if(!ChartGetInteger(chart_ID,CHART_COLOR_ASK,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((color)result);
}
//+------------------------------------------------------------------+
//| The function sets the color of Ask line. |
//+------------------------------------------------------------------+
bool ChartAskColorSet(const color clr,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set the color of Ask price line
if(!ChartSetInteger(chart_ID,CHART_COLOR_ASK,clr))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_COLOR_LAST color of the last performed deal's price line (Last).
//+----------------------------------------------------------------------+
//| The function receives color of the last performed deal's price line. |
//+----------------------------------------------------------------------+
color ChartLastColorGet(const long chart_ID=0)
{
//--- prepare the variable to receive the color
long result=clrNONE;
//--- reset the error value
ResetLastError();
//--- receive color of the last performed deal's price line (Last)
if(!ChartGetInteger(chart_ID,CHART_COLOR_LAST,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((color)result);
}
//+------------------------------------------------------------------+
//| The function sets color of the last performed deal's price |
//| line. |
//+------------------------------------------------------------------+
bool ChartLastColorSet(const color clr,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set color of the last performed deal's price line (Last)
if(!ChartSetInteger(chart_ID,CHART_COLOR_LAST,clr))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_COLOR_STOP_LEVEL stop order level color (Stop Loss and Take Profit).
//+--------------------------------------------------------------------+
//| The function receives colors of Stop Loss and Take Profit levels. |
//+--------------------------------------------------------------------+
color ChartStopLevelColorGet(const long chart_ID=0)
{
//--- prepare the variable to receive the color
long result=clrNONE;
//--- reset the error value
ResetLastError();
//--- receive the color of stop order levels (Stop Loss and Take Profit)
if(!ChartGetInteger(chart_ID,CHART_COLOR_STOP_LEVEL,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return((color)result);
}
//+------------------------------------------------------------------+
//| The function sets Stop Loss and Take Profit level colors. |
//+------------------------------------------------------------------+
bool ChartStopLevelColorSet(const color clr,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set the color of stop order levels (Stop Loss and Take Profit)
if(!ChartSetInteger(chart_ID,CHART_COLOR_STOP_LEVEL,clr))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_SHOW_TRADE_LEVELS property of displaying trade levels on the chart (levels
of open orders, Stop Loss, Take Profit and pending orders).
//+---------------------------------------------------------------------+
//| The function defines if trading levels are displayed on the chart. |
//+---------------------------------------------------------------------+
bool ChartShowTradeLevelsGet(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_SHOW_TRADE_LEVELS,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| The function enables/disables trading levels display mode. |
//+------------------------------------------------------------------+
bool ChartShowTradeLevelsSet(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_SHOW_TRADE_LEVELS,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_DRAG_TRADE_LEVELS property of enabling the ability to drag trading levels
on a chart using mouse.
//+---------------------------------------------------------------------------+
//| The function defines if dragging trading levels on a chart using mouse |
//| is allowed. |
//+---------------------------------------------------------------------------+
bool ChartDragTradeLevelsGet(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_DRAG_TRADE_LEVELS,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| The function enables/disables the mode of dragging trade levels |
//| on the chart using mouse. |
//+------------------------------------------------------------------+
bool ChartDragTradeLevelsSet(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_DRAG_TRADE_LEVELS,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_SHOW_DATE_SCALE property of displaying the time scale on a chart.
//+--------------------------------------------------------------------+
//| The function defines if the time scale is displayed on the chart. |
//+--------------------------------------------------------------------+
bool ChartShowDateScaleGet(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_SHOW_DATE_SCALE,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+-----------------------------------------------------------------------------+
//| The function enables/disables the mode of displaying the time scale on a |
//| chart. |
//+-----------------------------------------------------------------------------+
bool ChartShowDateScaleSet(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_SHOW_DATE_SCALE,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_SHOW_PRICE_SCALE property of displaying the price scale on a chart.
//+--------------------------------------------------------------------+
//| The function defines if the price scale is displayed on the chart. |
//+--------------------------------------------------------------------+
bool ChartShowPriceScaleGet(bool &result,const long chart_ID=0)
{
//--- prepare the variable to get the property value
long value;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetInteger(chart_ID,CHART_SHOW_PRICE_SCALE,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- store the value of the chart property in memory
result=value;
//--- successful execution
return(true);
}
//+----------------------------------------------------------------------------+
//| The function enables/disables the mode of displaying the price scale on a |
//| chart. |
//+----------------------------------------------------------------------------+
bool ChartShowPriceScaleSet(const bool value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetInteger(chart_ID,CHART_SHOW_PRICE_SCALE,0,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_SHIFT_SIZE shift size of the zero bar from the right border in percentage
values.
//+---------------------------------------------------------------------------+
//| The function receives shift size of the zero bar from the right border |
//| of the chart in percentage values (from 10% up to 50%). |
//+---------------------------------------------------------------------------+
double ChartShiftSizeGet(const long chart_ID=0)
{
//--- prepare the variable to get the result
double result=EMPTY_VALUE;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetDouble(chart_ID,CHART_SHIFT_SIZE,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return(result);
}
//+----------------------------------------------------------------------------------
//| The function sets the shift size of the zero bar from the right
//| border of the chart in percentage values (from 10% up to 50%). To enable the shif
//| mode, CHART_SHIFT property value should be set to
//| true.
//+----------------------------------------------------------------------------------
bool ChartShiftSizeSet(const double value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetDouble(chart_ID,CHART_SHIFT_SIZE,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_IS_OFFLINE checks offline mode of the chart.
//+------------------------------------------------------------------+
//| The function checks offline mode of the chart |
//+------------------------------------------------------------------+
bool CheckChartOffline(const long chart_ID=0)
{
bool offline=ChartGetInteger(chart_ID,CHART_IS_OFFLINE);
return(offline);
}
CHART_FIXED_POSITION chart fixed position from the left border in percentage
value.
//+--------------------------------------------------------------------------+
//| The function receives the location of the chart fixed position from the |
//| left border in percentage value. |
//+--------------------------------------------------------------------------+
double ChartFixedPositionGet(const long chart_ID=0)
{
//--- prepare the variable to get the result
double result=EMPTY_VALUE;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetDouble(chart_ID,CHART_FIXED_POSITION,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return(result);
}
//+---------------------------------------------------------------------+
//| The function sets the location of the chart fixed position from the |
//| left border in percentage value. To view the location of the |
//| chart fixed position, the value of |
//| CHART_AUTOSCROLL property should be set to false. |
//+---------------------------------------------------------------------+
bool ChartFixedPositionSet(const double value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetDouble(chart_ID,CHART_FIXED_POSITION,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_FIXED_MAX property of the chart's fixed maximum.
//+------------------------------------------------------------------+
//| The function receives the value of chart's fixed maximum. |
//+------------------------------------------------------------------+
double ChartFixedMaxGet(const long chart_ID=0)
{
//--- prepare the variable to get the result
double result=EMPTY_VALUE;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetDouble(chart_ID,CHART_FIXED_MAX,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return(result);
}
//+------------------------------------------------------------------+
//| The function sets the value of chart's fixed maximum. |
//| To change the value of the property, |
//| CHART_SCALEFIX property value should be preliminarily set to |
//| true. |
//+------------------------------------------------------------------+
bool ChartFixedMaxSet(const double value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetDouble(chart_ID,CHART_FIXED_MAX,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_FIXED_MIN property of the chart's fixed minimum.
//+------------------------------------------------------------------+
//| The function receives the value of chart's fixed minimum. |
//+------------------------------------------------------------------+
double ChartFixedMinGet(const long chart_ID=0)
{
//--- prepare the variable to get the result
double result=EMPTY_VALUE;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetDouble(chart_ID,CHART_FIXED_MIN,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return(result);
}
//+------------------------------------------------------------------+
//| The function sets the value of chart's fixed minimum. |
//| To change the value of the property, |
//| CHART_SCALEFIX property value should be preliminarily set to |
//| true. |
//+------------------------------------------------------------------+
bool ChartFixedMinSet(const double value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetDouble(chart_ID,CHART_FIXED_MIN,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_POINTS_PER_BAR value of scale in points per bar.
//+---------------------------------------------------------------------------+
//| The function receives the value of the chart scale in points per bar. |
//+---------------------------------------------------------------------------+
double ChartPointsPerBarGet(const long chart_ID=0)
{
//--- prepare the variable to get the result
double result=EMPTY_VALUE;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetDouble(chart_ID,CHART_POINTS_PER_BAR,0,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return(result);
}
//+----------------------------------------------------------------------+
//| The function sets the value of the chart scale in points per bar. |
//| To view the result of this property's value change, |
//| the value of |
//| CHART_SCALE_PT_PER_BAR property should be preliminarily set to true. |
//+----------------------------------------------------------------------+
bool ChartPointsPerBarSet(const double value,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetDouble(chart_ID,CHART_POINTS_PER_BAR,value))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
CHART_PRICE_MIN returns the value of the chart minimum.
//+---------------------------------------------------------------------------------+
//| The function receives the value of the chart minimum in the main window or a |
//| subwindow. |
//+---------------------------------------------------------------------------------+
double ChartPriceMin(const long chart_ID=0,const int sub_window=0)
{
//--- prepare the variable to get the result
double result=EMPTY_VALUE;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetDouble(chart_ID,CHART_PRICE_MIN,sub_window,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return(result);
}
CHART_PRICE_MAX returns the value of the chart maximum.
//+--------------------------------------------------------------------------------+
//| The function receives the value of the chart maximum in the main window or a |
//| subwindow. |
//+--------------------------------------------------------------------------------+
double ChartPriceMax(const long chart_ID=0,const int sub_window=0)
{
//--- prepare the variable to get the result
double result=EMPTY_VALUE;
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetDouble(chart_ID,CHART_PRICE_MAX,sub_window,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
}
//--- return the value of the chart property
return(result);
}
CHART_COMMENT comment on the chart.
//+----------------------------------------------------------------------+
//| The function receives comment in the upper left corner of the chart. |
//+----------------------------------------------------------------------+
bool ChartCommentGet(string &result,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- receive the property value
if(!ChartGetString(chart_ID,CHART_COMMENT,result))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| The function sets comment in the upper left corner of the |
//| chart. |
//+------------------------------------------------------------------+
bool ChartCommentSet(const string str,const long chart_ID=0)
{
//--- reset the error value
ResetLastError();
//--- set property value
if(!ChartSetString(chart_ID,CHART_COMMENT,str))
{
//--- display the error message in Experts journal
Print(__FUNCTION__+", Error Code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
Panel for chart properties
//--- connect the library of control elements
#include <ChartObjects\[Link]>
//--- predefined constants
#define X_PROPERTY_NAME_1 10 // х coordinate of the property name in the first co
#define X_PROPERTY_VALUE_1 225 // х coordinate of the property value in the first c
#define X_PROPERTY_NAME_2 345 // х coordinate of the property name in the second a
#define X_PROPERTY_VALUE_2 550 // х coordinate of the property value in the second
#define X_BUTTON_1 285 // х coordinate of the button in the first column
#define X_BUTTON_2 700 // х coordinate of the button in the second column
#define Y_PROPERTY_1 30 // y coordinate of the beginning of the first and se
#define Y_PROPERTY_2 286 // y coordinate of the beginning of the third column
#define Y_DISTANCE 16 // y axial distance between the lines
#define LAST_PROPERTY_NUMBER 111 // number of the last graphical property
//--- input parameters
input color InpFirstColor=clrDodgerBlue; // Color of odd lines
input color InpSecondColor=clrGoldenrod; // Color of even lines
//--- variables and arrays
CChartObjectLabel ExtLabelsName[]; // labels for displaying property names
CChartObjectLabel ExtLabelsValue[]; // labels for displaying property values
CChartObjectButton ExtButtons[]; // buttons
int ExtNumbers[]; // property indices
string ExtNames[]; // property names
uchar ExtDataTypes[]; // property data types (integer, double, string)
uint ExtGroupTypes[]; // array that stores the data on belonging of pr
uchar ExtDrawTypes[]; // array that stores the data on the type of pro
double ExtMaxValue[]; // maximum property values that are possible whe
double ExtMinValue[]; // minimum property values that are possible whe
double ExtStep[]; // steps for changing properties
int ExtCount; // total number of all properties
color ExtColors[2]; // array of colors for displaying lines
string ExtComments[2]; // array of comments (for CHART_COMMENT property
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- display a comment on the chart
Comment("SomeComment");
//--- store colors in the array to be able to switch between them later
ExtColors[0]=InpFirstColor;
ExtColors[1]=InpSecondColor;
//--- store comments in the array to be able to switch between them later
ExtComments[0]="FirstComment";
ExtComments[1]="SecondComment";
//--- prepare and display the control panel for managing chart properties
if(!PrepareControls())
return(INIT_FAILED);
//--- successful execution
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Deinitialization function of the expert |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- remove the comment on the chart
Comment("");
}
//+------------------------------------------------------------------+
//| Handler of a chart event |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
//--- check the event of clicking the chart object
if(id==CHARTEVENT_OBJECT_CLICK)
{
//--- divide the object name by separator
string obj_name[];
StringSplit(sparam,'_',obj_name);
//--- check if the object is a button
if(obj_name[0]=="Button")
{
//--- receive button index
int index=(int)StringToInteger(obj_name[1]);
//--- unpress the button
ExtButtons[index].State(false);
//--- set the new value of the property depending on its type
if(ExtDataTypes[index]=='I')
ChangeIntegerProperty(index);
if(ExtDataTypes[index]=='D')
ChangeDoubleProperty(index);
if(ExtDataTypes[index]=='S')
ChangeStringProperty(index);
}
}
//--- re-draw property values
RedrawProperties();
ChartRedraw();
}
//+------------------------------------------------------------------+
//| Change the integer property of the chart |
//+------------------------------------------------------------------+
void ChangeIntegerProperty(const int index)
{
//--- receive the current property value
long value=ChartGetInteger(0,(ENUM_CHART_PROPERTY_INTEGER)ExtNumbers[index]);
//--- define the following property value
switch(ExtDrawTypes[index])
{
case 'C':
value=GetNextColor((color)value);
break;
default:
value=(long)GetNextValue((double)value,index);
break;
}
//--- set the new property value
ChartSetInteger(0,(ENUM_CHART_PROPERTY_INTEGER)ExtNumbers[index],0,value);
}
//+------------------------------------------------------------------+
//| Change double property of the chart |
//+------------------------------------------------------------------+
void ChangeDoubleProperty(const int index)
{
//--- receive the current property value
double value=ChartGetDouble(0,(ENUM_CHART_PROPERTY_DOUBLE)ExtNumbers[index]);
//--- define the following property value
value=GetNextValue(value,index);
//--- set the new property value
ChartSetDouble(0,(ENUM_CHART_PROPERTY_DOUBLE)ExtNumbers[index],value);
}
//+------------------------------------------------------------------+
//| Change string property of the chart |
//+------------------------------------------------------------------+
void ChangeStringProperty(const int index)
{
//--- static variable for switching inside ExtComments array
static uint comment_index=1;
//--- change index for receiving another comment
comment_index=1-comment_index;
//--- set the new property value
ChartSetString(0,(ENUM_CHART_PROPERTY_STRING)ExtNumbers[index],ExtComments[comment
}
//+------------------------------------------------------------------+
//| Define the next property value |
//+------------------------------------------------------------------+
double GetNextValue(const double value,const int index)
{
if(value+ExtStep[index]<=ExtMaxValue[index])
return(value+ExtStep[index]);
else
return(ExtMinValue[index]);
}
//+------------------------------------------------------------------+
//| Receive the next color for color type property |
//+------------------------------------------------------------------+
color GetNextColor(const color clr)
{
//--- return the following color value
switch(clr)
{
case clrWhite: return(clrRed);
case clrRed: return(clrGreen);
case clrGreen: return(clrBlue);
case clrBlue: return(clrBlack);
default: return(clrWhite);
}
}
//+------------------------------------------------------------------+
//| Re-draw property values |
//+------------------------------------------------------------------+
void RedrawProperties(void)
{
//--- property value text
string text;
long value;
//--- loop of the number of properties
for(int i=0;i<ExtCount;i++)
{
text="";
switch(ExtDataTypes[i])
{
case 'I':
//--- receive the current property value
if(!ChartGetInteger(0,(ENUM_CHART_PROPERTY_INTEGER)ExtNumbers[i],0,value)
break;
//--- integer property text
switch(ExtDrawTypes[i])
{
//--- color property
case 'C':
text=(string)((color)value);
break;
//--- boolean property
case 'B':
text=(string)((bool)value);
break;
//--- ENUM_CHART_MODE enumeration property
case 'M':
text=EnumToString((ENUM_CHART_MODE)value);
break;
//--- ENUM_CHART_VOLUME_MODE enumeration property
case 'V':
text=EnumToString((ENUM_CHART_VOLUME_MODE)value);
break;
//--- int type number
default:
text=IntegerToString(value);
break;
}
break;
case 'D':
//--- double property text
text=DoubleToString(ChartGetDouble(0,(ENUM_CHART_PROPERTY_DOUBLE)ExtNumbe
break;
case 'S':
//--- string property text
text=ChartGetString(0,(ENUM_CHART_PROPERTY_STRING)ExtNumbers[i]);
break;
}
//--- display property value
ExtLabelsValue[i].Description(text);
}
}
//+------------------------------------------------------------------+
//| Create the panel for managing chart properties |
//+------------------------------------------------------------------+
bool PrepareControls(void)
{
//--- allocate memory for arrays with a reserve
MemoryAllocation(LAST_PROPERTY_NUMBER+1);
//--- variables
int i=0; // loop variable
int col_1=0; // number of properties in the first column
int col_2=0; // number of properties in the second column
int col_3=0; // number of properties in the third column
//--- current number of properties - 0
ExtCount=0;
//--- looking for properties in the loop
while(i<=LAST_PROPERTY_NUMBER)
{
//--- store the current number of the property
ExtNumbers[ExtCount]=i;
//--- increase the value of the loop variable
i++;
//--- check if there is a property with such a number
if(CheckNumber(ExtNumbers[ExtCount],ExtNames[ExtCount],ExtDataTypes[ExtCount],E
{
//--- create control elements for the property
switch(ExtGroupTypes[ExtCount])
{
case 1:
//--- create labels and a button for the property
if(!ShowProperty(ExtCount,0,X_PROPERTY_NAME_1,X_PROPERTY_VALUE_1,X_BUT
return(false);
//--- number of the elements in the first column has increased
col_1++;
break;
case 2:
//--- create labels and a button for the property
if(!ShowProperty(ExtCount,1,X_PROPERTY_NAME_2,X_PROPERTY_VALUE_2,X_BUT
return(false);
//--- number of the elements in the second column has increased
col_2++;
break;
case 3:
//--- create only labels for the property
if(!ShowProperty(ExtCount,2,X_PROPERTY_NAME_2,X_PROPERTY_VALUE_2,0,Y_P
return(false);
//--- number of the elements in the third column has increased
col_3++;
break;
}
//--- define maximum and minimum property value and step
GetMaxMinStep(ExtNumbers[ExtCount],ExtMaxValue[ExtCount],ExtMinValue[ExtCoun
//--- increase the number of properties
ExtCount++;
}
}
//--- free the memory not used by arrays
MemoryAllocation(ExtCount);
//--- re-draw property values
RedrawProperties();
ChartRedraw();
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Allocate memory for arrays |
//+------------------------------------------------------------------+
void MemoryAllocation(const int size)
{
ArrayResize(ExtLabelsName,size);
ArrayResize(ExtLabelsValue,size);
ArrayResize(ExtButtons,size);
ArrayResize(ExtNumbers,size);
ArrayResize(ExtNames,size);
ArrayResize(ExtDataTypes,size);
ArrayResize(ExtGroupTypes,size);
ArrayResize(ExtDrawTypes,size);
ArrayResize(ExtMaxValue,size);
ArrayResize(ExtMinValue,size);
ArrayResize(ExtStep,size);
}
//+------------------------------------------------------------------+
//| Check if the property index belongs to the one of |
//| ENUM_CHART_PROPERTIES enumerations |
//+------------------------------------------------------------------+
bool CheckNumber(const int ind,string &name,uchar &data_type,uint &group_type,uchar &
{
//--- check if the property is of integer type
ResetLastError();
name=EnumToString((ENUM_CHART_PROPERTY_INTEGER)ind);
if(_LastError==0)
{
data_type='I'; // property from ENUM_CHART_PROPERTY_INTEGE
GetTypes(ind,group_type,draw_type); // define property display parameters
return(true);
}
//--- check if the property is of double type
ResetLastError();
name=EnumToString((ENUM_CHART_PROPERTY_DOUBLE)ind);
if(_LastError==0)
{
data_type='D'; // property from ENUM_CHART_PROPERTY_DOUBLE
GetTypes(ind,group_type,draw_type); // define property display parameters
return(true);
}
//--- check if the property is of string type
ResetLastError();
name=EnumToString((ENUM_CHART_PROPERTY_STRING)ind);
if(_LastError==0)
{
data_type='S'; // property from ENUM_CHART_PROPERTY_STRING
GetTypes(ind,group_type,draw_type); // define property display parameters
return(true);
}
//--- property does not belong to any enumeration
return(false);
}
//+------------------------------------------------------------------+
//| Define the group the property should be stored in, |
//| as well as its display type |
//+------------------------------------------------------------------+
void GetTypes(const int property_number,uint &group_type,uchar &draw_type)
{
//--- check if the property belongs to the third group
//--- third group properties are displayed in the second column starting from CHART_B
if(CheckThirdGroup(property_number,group_type,draw_type))
return;
//--- check if the property belongs to the second group
//--- second group properties are displayed at the beginning of the second column
if(CheckSecondGroup(property_number,group_type,draw_type))
return;
//--- if you find yourself here, the property belongs to the first group (first colum
CheckFirstGroup(property_number,group_type,draw_type);
}
//+----------------------------------------------------------------------+
//| The function checks if the property belongs to the third group and |
//| defines its display type in case of a positive answer |
//+----------------------------------------------------------------------+
bool CheckThirdGroup(const int property_number,uint &group_type,uchar &draw_type)
{
//--- check if the property belongs to the third group
switch(property_number)
{
//--- boolean properties
case CHART_WINDOW_IS_VISIBLE:
draw_type='B';
break;
//--- integer properties
case CHART_VISIBLE_BARS:
case CHART_WINDOWS_TOTAL:
case CHART_WINDOW_HANDLE:
case CHART_WINDOW_YDISTANCE:
case CHART_FIRST_VISIBLE_BAR:
case CHART_WIDTH_IN_BARS:
case CHART_WIDTH_IN_PIXELS:
draw_type='I';
break;
//--- double properties
case CHART_PRICE_MIN:
case CHART_PRICE_MAX:
draw_type='D';
break;
//--- in fact, this property is a command of displaying the chart on top of
//--- there is no need to apply this panel, as the window will always be
//--- on top of other ones before we use it
case CHART_BRING_TO_TOP:
draw_type=' ';
break;
//--- property does not belong to the third group
default:
return(false);
}
//--- property belongs to the third group
group_type=3;
return(true);
}
//+----------------------------------------------------------------------+
//| The function checks if the property belongs to the second group and |
//| defines its display type in case of a positive answer |
//+----------------------------------------------------------------------+
bool CheckSecondGroup(const int property_number,uint &group_type,uchar &draw_type)
{
//--- check if the property belongs to the second group
switch(property_number)
{
//--- ENUM_CHART_MODE type property
case CHART_MODE:
draw_type='M';
break;
//--- ENUM_CHART_VOLUME_MODE type property
case CHART_SHOW_VOLUMES:
draw_type='V';
break;
//--- string property
case CHART_COMMENT:
draw_type='S';
break;
//--- color property
case CHART_COLOR_BACKGROUND:
case CHART_COLOR_FOREGROUND:
case CHART_COLOR_GRID:
case CHART_COLOR_VOLUME:
case CHART_COLOR_CHART_UP:
case CHART_COLOR_CHART_DOWN:
case CHART_COLOR_CHART_LINE:
case CHART_COLOR_CANDLE_BULL:
case CHART_COLOR_CANDLE_BEAR:
case CHART_COLOR_BID:
case CHART_COLOR_ASK:
case CHART_COLOR_LAST:
case CHART_COLOR_STOP_LEVEL:
draw_type='C';
break;
//--- property does not belong to the second group
default:
return(false);
}
//--- property belongs to the second group
group_type=2;
return(true);
}
//+-----------------------------------------------------------------------+
//| This function is called only if it is already known that |
//| the property does not belong to the second and third property groups |
//+-----------------------------------------------------------------------+
void CheckFirstGroup(const int property_number,uint &group_type,uchar &draw_type)
{
//--- the property belongs to the first group
group_type=1;
//--- define property display type
switch(property_number)
{
//--- integer properties
case CHART_SCALE:
case CHART_HEIGHT_IN_PIXELS:
draw_type='I';
return;
//--- double properties
case CHART_SHIFT_SIZE:
case CHART_FIXED_POSITION:
case CHART_FIXED_MAX:
case CHART_FIXED_MIN:
case CHART_POINTS_PER_BAR:
draw_type='D';
return;
//--- only boolean properties have remained
default:
draw_type='B';
return;
}
}
//+------------------------------------------------------------------+
//| Create a label and a button for the property |
//+------------------------------------------------------------------+
bool ShowProperty(const int ind,const int type,const int x1,const int x2,
const int xb,const int y,const bool btn)
{
//--- static array for switching inside ExtColors color array
static uint color_index[3]={1,1,1};
//--- change index for receiving another color
color_index[type]=1-color_index[type];
//--- display labels and a button (if btn=true) for the property
if(!LabelCreate(ExtLabelsName[ind],"name_"+(string)ind,ExtNames[ind],ExtColors[col
return(false);
if(!LabelCreate(ExtLabelsValue[ind],"value_"+(string)ind,"",ExtColors[color_index[
return(false);
if(btn && !ButtonCreate(ExtButtons[ind],(string)ind,xb,y+1))
return(false);
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Create a label |
//+------------------------------------------------------------------+
bool LabelCreate(CChartObjectLabel &lbl,const string name,const string text,
const color clr,const int x,const int y)
{
if() return(false);
if() return(false);
if() return(false);
if() return(false);
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Create the button |
//+------------------------------------------------------------------+
bool ButtonCreate(CChartObjectButton &btn,const string name,
const int x,const int y)
{
if() return(false);
if() return(false);
if() return(false);
if() return(false);
if() return(false);
if() return(false);
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Define maximum and minimum property value and step |
//+------------------------------------------------------------------+
void GetMaxMinStep(const int property_number,double &max,double &min,double &step)
{
double value;
//--- set values depending on the property type
switch(property_number)
{
case CHART_SCALE:
max=5;
min=0;
step=1;
break;
case CHART_MODE:
case CHART_SHOW_VOLUMES:
max=2;
min=0;
step=1;
break;
case CHART_SHIFT_SIZE:
max=50;
min=10;
step=2.5;
break;
case CHART_FIXED_POSITION:
max=90;
min=0;
step=15;
break;
case CHART_POINTS_PER_BAR:
max=19;
min=1;
step=3;
break;
case CHART_FIXED_MAX:
value=ChartGetDouble(0,CHART_FIXED_MAX);
max=value*1.25;
min=value;
step=value/32;
break;
case CHART_FIXED_MIN:
value=ChartGetDouble(0,CHART_FIXED_MIN);
max=value;
min=value*0.75;
step=value/32;
break;
case CHART_HEIGHT_IN_PIXELS:
max=700;
min=520;
step=30;
break;
//--- default values
default:
max=1;
min=0;
step=1;
}
}
MQL4 Reference / Constants, Enumerations and Structures / Objects Constants
Object Constants
There are 40 graphical objects that can be created and displayed
in the price chart. All constants for working with objects are
divided into 9 groups:
Object types Identifiers of graphical objects;
Object properties setting and getting properties of graphical
objects;
Methods of object binding constants of object positioning in the
chart;
Binding corner setting the corner relative to which an object is
positioned on chart;
Visibility of objects setting timeframes in which an object is
visible;
Gann objects trend constants for Gann fan and Gann grid;
Web colors constants of predefined web colors;
Wingdings codes of characters of the Wingdings font.
What's new in MQL5
Added new objects and analytical tools. The most notable of them
is the OBJ_CHART graphical object which is actually a full-fledged
chart. It allows creating an unlimited number of nested charts, set
all the necessary properties (color scheme, timeframe, symbol)
and even impose indicators on them.
Added new properties allowing you to manage a chart object
location and visibility more accurately.
ID Description Property Type
ID Description Property Type
Fill an object with
color (for
OBJ_RECTANGLE,
OBJ_TRIANGLE,
OBJ_ELLIPSE,
OBJ_CHANNEL,
OBJPROP_FILL bool
OBJ_STDDEVCHANNEL,
OBJ_REGRESSION)
OBJ_ELLIPSE,
OBJ_CHANNEL,
OBJ_STDDEVCHANNEL,
OBJ_REGRESSION)
OBJPROP_SELECTABLE Object availability bool
Time of object
OBJPROP_CREATETIME datetime r/o
creation
OBJPROP_RAY_LEFT Ray goes to the left bool
Location of the anchor
ENUM_ARROW_ANCHOR
OBJPROP_ANCHOR point of a graphical
ENUM_ANCHOR_POINT
object
Button state (pressed
OBJPROP_STATE bool
/ depressed))
ID of the "Chart"
object (OBJ_CHART).
It allows working with
the properties of this
OBJPROP_CHART_ID object like with a long r/o
normal chart using the
functions described in
Chart Operations, but
there some exceptions
Timeframe for the
OBJPROP_PERIOD ENUM_TIMEFRAMES
Chart object
Displaying the time
OBJPROP_DATE_SCALE scale for the Chart bool
object
ID Description Property Type
Displaying the price
OBJPROP_PRICE_SCALE scale for the Chart bool
object
The scale for the int value in the range
OBJPROP_CHART_SCALE
Chart object 0-5
MQL4 Reference / Constants, Enumerations and Structures / Objects
Constants / Object Types
Object Types
When a graphical object is created using the
ObjectCreate() function, it's necessary to specify the type
of object being created, which can be one of the values
of the ENUM_OBJECT enumeration. Object type identifiers
are used in ObjectCreate(), ObjectsDeleteAll() and
ObjectType() functions.
Further specifications of object properties are possible
using functions for working with graphical objects.
ENUM_OBJECT
ID Description
OBJ_VLINE Vertical Line
OBJ_HLINE Horizontal Line
OBJ_TREND Trend Line
OBJ_TRENDBYANGLE Trend Line By Angle
OBJ_CYCLES Cycle Lines
OBJ_CHANNEL Equidistant Channel
OBJ_STDDEVCHANNEL Standard Deviation Channel
OBJ_REGRESSION Linear Regression Channel
OBJ_PITCHFORK Andrews Pitchfork
OBJ_GANNLINE Gann Line
OBJ_GANNFAN Gann Fan
OBJ_GANNGRID Gann Grid
ID Description
OBJ_FIBO Fibonacci Retracement
OBJ_FIBOTIMES Fibonacci Time Zones
OBJ_FIBOFAN Fibonacci Fan
OBJ_FIBOARC Fibonacci Arcs
OBJ_FIBOCHANNEL Fibonacci Channel
OBJ_EXPANSION Fibonacci Expansion
OBJ_RECTANGLE Rectangle
OBJ_TRIANGLE Triangle
OBJ_ELLIPSE Ellipse
OBJ_ARROW_THUMB_UP Thumbs Up
OBJ_ARROW_THUMB_DOWN Thumbs Down
OBJ_ARROW_UP Arrow Up
OBJ_ARROW_DOWN Arrow Down
OBJ_ARROW_STOP Stop Sign
OBJ_ARROW_CHECK Check Sign
OBJ_ARROW_LEFT_PRICE Left Price Label
OBJ_ARROW_RIGHT_PRICE Right Price Label
OBJ_ARROW_BUY Buy Sign
OBJ_ARROW_SELL Sell Sign
OBJ_ARROW Arrow
OBJ_TEXT Text
OBJ_LABEL Label
OBJ_BUTTON Button
ID Description
OBJ_BITMAP Bitmap
OBJ_BITMAP_LABEL Bitmap Label
OBJ_EDIT Edit
OBJ_EVENT The "Event" object
corresponding to an event in
the economic calendar
OBJ_RECTANGLE_LABEL The "Rectangle label" object
for creating and designing
the custom graphical
interface.
MQL4 Reference / Constants, Enumerations and Structures / Objects Constants / Object Types / OBJ_VLINE
OBJ_VLINE
Vertical Line.
Example
The following script creates and moves the vertical line on the chart. Special functions
have been developed to create and change graphical object's properties. You can use
these functions "as is" in your own applications.
#property strict //--- description
#property description "Script draws \"Vertical Line\" graphical object."
#property description "Anchor point date is set in percentage of"
#property description "the chart window width in bars."
//--- display window of the input parameters during the script's launch
#property script_show_inputs
//--- input parameters of the script
input string InpName="VLine"; // Line name
input int InpDate=25; // Event date, %
input color InpColor=clrRed; // Line color
input ENUM_LINE_STYLE InpStyle=STYLE_DASH; // Line style
input int InpWidth=1; // Line width
input bool InpBack=false; // Background line
input bool InpSelection=true; // Highlight to move
input bool InpHidden=true; // Hidden in the object list
input long InpZOrder=0; // Priority for mouse click
//+------------------------------------------------------------------+
//| Create the vertical line |
//+------------------------------------------------------------------+
bool VLineCreate(const long chart_ID=0, // chart's ID
const string name="VLine", // line name
const int sub_window=0, // subwindow index
datetime time=0, // line time
const color clr=clrRed, // line color
const ENUM_LINE_STYLE style=STYLE_SOLID, // line style
const int width=1, // line width
const bool back=false, // in the background
const bool selection=true, // highlight to move
const bool hidden=true, // hidden in the object lis
const long z_order=0) // priority for mouse click
{
//--- if the line time is not set, draw it via the last bar
if(!time)
time=TimeCurrent();
//--- reset the error value
ResetLastError();
//--- create a vertical line
if(!ObjectCreate(chart_ID,name,OBJ_VLINE,sub_window,time,0))
{
Print(__FUNCTION__,
": failed to create a vertical line! Error code = ",GetLastError());
return(false);
}
//--- set line color
ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- set line display style
ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
//--- set line width
ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
//--- display in the foreground (false) or background (true)
ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- enable (true) or disable (false) the mode of moving the line by mouse
//--- when creating a graphical object using ObjectCreate function, the object cannot
//--- highlighted and moved by default. Inside this method, selection parameter
//--- is true by default making it possible to highlight and move the object
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- hide (true) or display (false) graphical object name in the object list
ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- set the priority for receiving the event of a mouse click in the chart
ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Move the vertical line |
//+------------------------------------------------------------------+
bool VLineMove(const long chart_ID=0, // chart's ID
const string name="VLine", // line name
datetime time=0) // line time
{
//--- if line time is not set, move the line to the last bar
if(!time)
time=TimeCurrent();
//--- reset the error value
ResetLastError();
//--- move the vertical line
if(!ObjectMove(chart_ID,name,0,time,0))
{
Print(__FUNCTION__,
": failed to move the vertical line! Error code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Delete the vertical line |
//+------------------------------------------------------------------+
bool VLineDelete(const long chart_ID=0, // chart's ID
const string name="VLine") // line name
{
//--- reset the error value
ResetLastError();
//--- delete the vertical line
if(!ObjectDelete(chart_ID,name))
{
Print(__FUNCTION__,
": failed to delete the vertical line! Error code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- check correctness of the input parameters
if(InpDate<0 || InpDate>100)
{
Print("Error! Incorrect values of input parameters!");
return;
}
//--- number of visible bars in the chart window
int bars=(int)ChartGetInteger(0,CHART_VISIBLE_BARS);
//--- array for storing the date values to be used
//--- for setting and changing line anchor point's coordinates
datetime date[];
//--- memory allocation
ArrayResize(date,bars);
//--- fill the array of dates
ResetLastError();
if(CopyTime(Symbol(),Period(),0,bars,date)==-1)
{
Print("Failed to copy time values! Error code = ",GetLastError());
return;
}
//--- define points for drawing the line
int d=InpDate*(bars-1)/100;
//--- create a vertical line
if(!VLineCreate(0,InpName,0,date[d],InpColor,InpStyle,InpWidth,InpBack,
InpSelection,InpHidden,InpZOrder))
return;
//--- redraw the chart and wait for 1 second
ChartRedraw();
Sleep(1000);
//--- now, move the line
//--- loop counter
int h_steps=bars/2;
//--- move the line
for(int i=0;i<h_steps;i++)
{
//--- use the following value
if(d<bars-1)
d+=1;
//--- move the point
if(!VLineMove(0,InpName,date[d]))
return;
//--- check if the script's operation has been forcefully disabled
if(IsStopped())
return;
//--- redraw the chart
ChartRedraw();
// 0.03 seconds of delay
Sleep(30);
}
//--- 1 second of delay
Sleep(1000);
//--- delete the channel from the chart
VLineDelete(0,InpName);
ChartRedraw();
//--- 1 second of delay
Sleep(1000);
//---
}
MQL4 Reference / Constants, Enumerations and Structures / Objects Constants / Object Types / OBJ_HLINE
OBJ_HLINE
Horizontal Line.
Example
The following script creates and moves the horizontal line on the chart. Special
functions have been developed to create and change graphical object's properties. You
can use these functions "as is" in your own applications.
#property strict //--- description
#property description "Script draws \"Horizontal Line\" graphical object."
#property description "Anchor point price is set in percentage of the height of"
#property description "the chart window."
//--- display window of the input parameters during the script's launch
#property script_show_inputs
//--- input parameters of the script
input string InpName="HLine"; // Line name
input int InpPrice=25; // Line price, %
input color InpColor=clrRed; // Line color
input ENUM_LINE_STYLE InpStyle=STYLE_DASH; // Line style
input int InpWidth=1; // Line width
input bool InpBack=false; // Background line
input bool InpSelection=true; // Highlight to move
input bool InpHidden=true; // Hidden in the object list
input long InpZOrder=0; // Priority for mouse click
//+------------------------------------------------------------------+
//| Create the horizontal line |
//+------------------------------------------------------------------+
bool HLineCreate(const long chart_ID=0, // chart's ID
const string name="HLine", // line name
const int sub_window=0, // subwindow index
double price=0, // line price
const color clr=clrRed, // line color
const ENUM_LINE_STYLE style=STYLE_SOLID, // line style
const int width=1, // line width
const bool back=false, // in the background
const bool selection=true, // highlight to move
const bool hidden=true, // hidden in the object lis
const long z_order=0) // priority for mouse click
{
//--- if the price is not set, set it at the current Bid price level
if(!price)
price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
//--- reset the error value
ResetLastError();
//--- create a horizontal line
if(!ObjectCreate(chart_ID,name,OBJ_HLINE,sub_window,0,price))
{
Print(__FUNCTION__,
": failed to create a horizontal line! Error code = ",GetLastError());
return(false);
}
//--- set line color
ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- set line display style
ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
//--- set line width
ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
//--- display in the foreground (false) or background (true)
ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- enable (true) or disable (false) the mode of moving the line by mouse
//--- when creating a graphical object using ObjectCreate function, the object cannot
//--- highlighted and moved by default. Inside this method, selection parameter
//--- is true by default making it possible to highlight and move the object
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- hide (true) or display (false) graphical object name in the object list
ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- set the priority for receiving the event of a mouse click in the chart
ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Move horizontal line |
//+------------------------------------------------------------------+
bool HLineMove(const long chart_ID=0, // chart's ID
const string name="HLine", // line name
double price=0) // line price
{
//--- if the line price is not set, move it to the current Bid price level
if(!price)
price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
//--- reset the error value
ResetLastError();
//--- move a horizontal line
if(!ObjectMove(chart_ID,name,0,0,price))
{
Print(__FUNCTION__,
": failed to move the horizontal line! Error code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Delete a horizontal line |
//+------------------------------------------------------------------+
bool HLineDelete(const long chart_ID=0, // chart's ID
const string name="HLine") // line name
{
//--- reset the error value
ResetLastError();
//--- delete a horizontal line
if(!ObjectDelete(chart_ID,name))
{
Print(__FUNCTION__,
": failed to delete a horizontal line! Error code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- check correctness of the input parameters
if(InpPrice<0 || InpPrice>100)
{
Print("Error! Incorrect values of input parameters!");
return;
}
//--- price array size
int accuracy=1000;
//--- array for storing the price values to be used
//--- for setting and changing line anchor point's coordinates
double price[];
//--- memory allocation
ArrayResize(price,accuracy);
//--- fill the array of prices
//--- find the highest and lowest values of the chart
double max_price=ChartGetDouble(0,CHART_PRICE_MAX);
double min_price=ChartGetDouble(0,CHART_PRICE_MIN);
//--- define a change step of a price and fill the array
double step=(max_price-min_price)/accuracy;
for(int i=0;i<accuracy;i++)
price[i]=min_price+i*step;
//--- define points for drawing the line
int p=InpPrice*(accuracy-1)/100;
//--- create a horizontal line
if(!HLineCreate(0,InpName,0,price[p],InpColor,InpStyle,InpWidth,InpBack,
InpSelection,InpHidden,InpZOrder))
{
return;
}
//--- redraw the chart and wait for 1 second
ChartRedraw();
Sleep(1000);
//--- now, move the line
//--- loop counter
int v_steps=accuracy/2;
//--- move the line
for(int i=0;i<v_steps;i++)
{
//--- use the following value
if(p<accuracy-1)
p+=1;
//--- move the point
if(!HLineMove(0,InpName,price[p]))
return;
//--- check if the script's operation has been forcefully disabled
if(IsStopped())
return;
//--- redraw the chart
ChartRedraw();
}
//--- 1 second of delay
Sleep(1000);
//--- delete from the chart
HLineDelete(0,InpName);
ChartRedraw();
//--- 1 second of delay
Sleep(1000);
//---
}
MQL4 Reference / Constants, Enumerations and Structures / Objects Constants / Object Types / OBJ_TREND
OBJ_TREND
Trend Line.
Note
For Trend Line, it is possible to specify the mode of continuation of its display to the
right (OBJPROP_RAY_RIGHT property).
Example
The following script creates and moves the trend line on the chart. Special functions
have been developed to create and change graphical object's properties. You can use
these functions "as is" in your own applications.
#property strict //--- description
#property description "Script draws \"Trend Line\" graphical object."
#property description "Anchor point coordinates are set in percentage of"
#property description "the chart window size."
//--- display window of the input parameters during the script's launch
#property script_show_inputs
//--- input parameters of the script
input string InpName="Trend"; // Line name
input int InpDate1=35; // 1 st point's date, %
input int InpPrice1=60; // 1 st point's price, %
input int InpDate2=65; // 2 nd point's date, %
input int InpPrice2=40; // 2 nd point's price, %
input color InpColor=clrRed; // Line color
input ENUM_LINE_STYLE InpStyle=STYLE_DASH; // Line style
input int InpWidth=1; // Line width
input bool InpBack=false; // Background line
input bool InpSelection=true; // Highlight to move
input bool InpRayRight=false; // Line's continuation to the right
input bool InpHidden=true; // Hidden in the object list
input long InpZOrder=0; // Priority for mouse click
//+------------------------------------------------------------------+
//| Create a trend line by the given coordinates |
//+------------------------------------------------------------------+
bool TrendCreate(const long chart_ID=0, // chart's ID
const string name="TrendLine", // line name
const int sub_window=0, // subwindow index
datetime time1=0, // first point time
double price1=0, // first point price
datetime time2=0, // second point time
double price2=0, // second point price
const color clr=clrRed, // line color
const ENUM_LINE_STYLE style=STYLE_SOLID, // line style
const int width=1, // line width
const bool back=false, // in the background
const bool selection=true, // highlight to move
const bool ray_right=false, // line's continuation to t
const bool hidden=true, // hidden in the object lis
const long z_order=0) // priority for mouse click
{
//--- set anchor points' coordinates if they are not set
ChangeTrendEmptyPoints(time1,price1,time2,price2);
//--- reset the error value
ResetLastError();
//--- create a trend line by the given coordinates
if(!ObjectCreate(chart_ID,name,OBJ_TREND,sub_window,time1,price1,time2,price2))
{
Print(__FUNCTION__,
": failed to create a trend line! Error code = ",GetLastError());
return(false);
}
//--- set line color
ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- set line display style
ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
//--- set line width
ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
//--- display in the foreground (false) or background (true)
ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- enable (true) or disable (false) the mode of moving the line by mouse
//--- when creating a graphical object using ObjectCreate function, the object cannot
//--- highlighted and moved by default. Inside this method, selection parameter
//--- is true by default making it possible to highlight and move the object
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- enable (true) or disable (false) the mode of continuation of the line's display
ObjectSetInteger(chart_ID,name,OBJPROP_RAY_RIGHT,ray_right);
//--- hide (true) or display (false) graphical object name in the object list
ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- set the priority for receiving the event of a mouse click in the chart
ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Move trend line anchor point |
//+------------------------------------------------------------------+
bool TrendPointChange(const long chart_ID=0, // chart's ID
const string name="TrendLine", // line name
const int point_index=0, // anchor point index
datetime time=0, // anchor point time coordinate
double price=0) // anchor point price coordinate
{
//--- if point position is not set, move it to the current bar having Bid price
if(!time)
time=TimeCurrent();
if(!price)
price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
//--- reset the error value
ResetLastError();
//--- move trend line's anchor point
if(!ObjectMove(chart_ID,name,point_index,time,price))
{
Print(__FUNCTION__,
": failed to move the anchor point! Error code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| The function deletes the trend line from the chart. |
//+------------------------------------------------------------------+
bool TrendDelete(const long chart_ID=0, // chart's ID
const string name="TrendLine") // line name
{
//--- reset the error value
ResetLastError();
//--- delete a trend line
if(!ObjectDelete(chart_ID,name))
{
Print(__FUNCTION__,
": failed to delete a trend line! Error code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Check the values of trend line's anchor points and set default |
//| values for empty ones |
//+------------------------------------------------------------------+
void ChangeTrendEmptyPoints(datetime &time1,double &price1,
datetime &time2,double &price2)
{
//--- if the first point's time is not set, it will be on the current bar
if(!time1)
time1=TimeCurrent();
//--- if the first point's price is not set, it will have Bid value
if(!price1)
price1=SymbolInfoDouble(Symbol(),SYMBOL_BID);
//--- if the second point's time is not set, it is located 9 bars left from the secon
if(!time2)
{
//--- array for receiving the open time of the last 10 bars
datetime temp[10];
CopyTime(Symbol(),Period(),time1,10,temp);
//--- set the second point 9 bars left from the first one
time2=temp[0];
}
//--- if the second point's price is not set, it is equal to the first point's one
if(!price2)
price2=price1;
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- check correctness of the input parameters
if(InpDate1<0 || InpDate1>100 || InpPrice1<0 || InpPrice1>100 ||
InpDate2<0 || InpDate2>100 || InpPrice2<0 || InpPrice2>100)
{
Print("Error! Incorrect values of input parameters!");
return;
}
//--- number of visible bars in the chart window
int bars=(int)ChartGetInteger(0,CHART_VISIBLE_BARS);
//--- price array size
int accuracy=1000;
//--- arrays for storing the date and price values to be used
//--- for setting and changing line anchor points' coordinates
datetime date[];
double price[];
//--- memory allocation
ArrayResize(date,bars);
ArrayResize(price,accuracy);
//--- fill the array of dates
ResetLastError();
if(CopyTime(Symbol(),Period(),0,bars,date)==-1)
{
Print("Failed to copy time values! Error code = ",GetLastError());
return;
}
//--- fill the array of prices
//--- find the highest and lowest values of the chart
double max_price=ChartGetDouble(0,CHART_PRICE_MAX);
double min_price=ChartGetDouble(0,CHART_PRICE_MIN);
//--- define a change step of a price and fill the array
double step=(max_price-min_price)/accuracy;
for(int i=0;i<accuracy;i++)
price[i]=min_price+i*step;
//--- define points for drawing the line
int d1=InpDate1*(bars-1)/100;
int d2=InpDate2*(bars-1)/100;
int p1=InpPrice1*(accuracy-1)/100;
int p2=InpPrice2*(accuracy-1)/100;
//--- create a trend line
if(!TrendCreate(0,InpName,0,date[d1],price[p1],date[d2],price[p2],InpColor,InpStyl
InpWidth,InpBack,InpSelection,InpRayRight,InpHidden,InpZOrder))
{
return;
}
//--- redraw the chart and wait for 1 second
ChartRedraw();
Sleep(1000);
//--- now, move the line's anchor points
//--- loop counter
int v_steps=accuracy/5;
//--- move the first anchor point vertically
for(int i=0;i<v_steps;i++)
{
//--- use the following value
if(p1>1)
p1-=1;
//--- move the point
if(!TrendPointChange(0,InpName,0,date[d1],price[p1]))
return;
//--- check if the script's operation has been forcefully disabled
if(IsStopped())
return;
//--- redraw the chart
ChartRedraw();
}
//--- move the second anchor point vertically
for(int i=0;i<v_steps;i++)
{
//--- use the following value
if(p2<accuracy-1)
p2+=1;
//--- move the point
if(!TrendPointChange(0,InpName,1,date[d2],price[p2]))
return;
//--- check if the script's operation has been forcefully disabled
if(IsStopped())
return;
//--- redraw the chart
ChartRedraw();
}
//--- half a second of delay
Sleep(500);
//--- loop counter
int h_steps=bars/2;
//--- move both anchor points horizontally at the same time
for(int i=0;i<h_steps;i++)
{
//--- use the following values
if(d1<bars-1)
d1+=1;
if(d2>1)
d2-=1;
//--- shift the points
if(!TrendPointChange(0,InpName,0,date[d1],price[p1]))
return;
if(!TrendPointChange(0,InpName,1,date[d2],price[p2]))
return;
//--- check if the script's operation has been forcefully disabled
if(IsStopped())
return;
//--- redraw the chart
ChartRedraw();
// 0.03 seconds of delay
Sleep(30);
}
//--- 1 second of delay
Sleep(1000);
//--- delete a trend line
TrendDelete(0,InpName);
ChartRedraw();
//--- 1 second of delay
Sleep(1000);
//---
}
MQL4 Reference / Constants, Enumerations and Structures / Objects Constants / Object Types /
OBJ_TRENDBYANGLE
OBJ_TRENDBYANGLE
Trend Line By Angle.
Note
For Trend Line By Angle, it is possible to specify the mode of continuation of its display
to the right (OBJPROP_RAY_RIGHT property).
Both angle and the second anchor point's coordinates can be used to set the slope of
the line.
Example
The following script creates and moves the trend line on the chart. Special functions
have been developed to create and change graphical object's properties. You can use
these functions "as is" in your own applications.
#property strict //--- description
#property description "Script draws \"Trend Line By Angle\" graphical object."
#property description "Anchor point coordinates are set in percentage of the size of"
#property description "the chart window."
//--- display window of the input parameters during the script's launch
#property script_show_inputs
//--- input parameters of the script
input string InpName="Trend"; // Line name
input int InpDate1=50; // 1 st point's date, %
input int InpPrice1=75; // 1 st point's price, %
input int InpAngle=0; // Line's slope angle
input color InpColor=clrRed; // Line color
input ENUM_LINE_STYLE InpStyle=STYLE_DASH; // Line style
input int InpWidth=1; // Line width
input bool InpBack=false; // Background line
input bool InpSelection=true; // Highlight to move
input bool InpRayRight=true; // Line's continuation to the right
input bool InpHidden=true; // Hidden in the object list
input long InpZOrder=0; // Priority for mouse click
//+------------------------------------------------------------------+
//| Create a trend line by angle |
//+------------------------------------------------------------------+
bool TrendByAngleCreate(const long chart_ID=0, // chart's ID
const string name="TrendLine", // line name
const int sub_window=0, // subwindow index
datetime time=0, // point time
double price=0, // point price
const double angle=45.0, // slope angle
const color clr=clrRed, // line color
const ENUM_LINE_STYLE style=STYLE_SOLID, // line style
const int width=1, // line width
const bool back=false, // in the background
const bool selection=true, // highlight to move
const bool ray_right=true, // line's continuati
const bool hidden=true, // hidden in the obj
const long z_order=0) // priority for mous
{
//--- create the second point to facilitate dragging the trend line by mouse
datetime time2=0;
double price2=0;
//--- set anchor points' coordinates if they are not set
ChangeTrendEmptyPoints(time,price,time2,price2);
//--- reset the error value
ResetLastError();
//--- create a trend line using 2 points
if(!ObjectCreate(chart_ID,name,OBJ_TRENDBYANGLE,sub_window,time,price,time2,price2
{
Print(__FUNCTION__,
": failed to create a trend line! Error code = ",GetLastError());
return(false);
}
//--- change trend line's slope angle; when changing the angle, coordinates of the se
//--- point of the line are redefined automatically according to the angle's new valu
ObjectSetDouble(chart_ID,name,OBJPROP_ANGLE,angle);
//--- set line color
ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- set line style
ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
//--- set line width
ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
//--- display in the foreground (false) or background (true)
ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- enable (true) or disable (false) the mode of moving the line by mouse
//--- when creating a graphical object using ObjectCreate function, the object cannot
//--- highlighted and moved by default. Inside this method, selection parameter
//--- is true by default making it possible to highlight and move the object
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- enable (true) or disable (false) the mode of continuation of the line's display
ObjectSetInteger(chart_ID,name,OBJPROP_RAY_RIGHT,ray_right);
//--- hide (true) or display (false) graphical object name in the object list
ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- set the priority for receiving the event of a mouse click in the chart
ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Change trend line anchor point's coordinates |
//+------------------------------------------------------------------+
bool TrendPointChange(const long chart_ID=0, // chart's ID
const string name="TrendLine", // line name
datetime time=0, // anchor point time coordinate
double price=0) // anchor point price coordinate
{
//--- if point position is not set, move it to the current bar having Bid price
if(!time)
time=TimeCurrent();
if(!price)
price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
//--- reset the error value
ResetLastError();
//--- move trend line's anchor point
if(!ObjectMove(chart_ID,name,0,time,price))
{
Print(__FUNCTION__,
": failed to move the anchor point! Error code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Change trend line's slope angle |
//+------------------------------------------------------------------+
bool TrendAngleChange(const long chart_ID=0, // chart's ID
const string name="TrendLine", // trend line name
const double angle=45) // trend line's slope angle
{
//--- reset the error value
ResetLastError();
//--- change trend line's slope angle
if(!ObjectSetDouble(chart_ID,name,OBJPROP_ANGLE,angle))
{
Print(__FUNCTION__,
": failed to change the line's slope angle! Error code = ",GetLastError()
return(false);
}
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Delete the trend line |
//+------------------------------------------------------------------+
bool TrendDelete(const long chart_ID=0, // chart's ID
const string name="TrendLine") // line name
{
//--- reset the error value
ResetLastError();
//--- delete a trend line
if(!ObjectDelete(chart_ID,name))
{
Print(__FUNCTION__,
": failed to delete a trend line! Error code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Check the values of trend line's anchor points and set default |
//| values for empty ones |
//+------------------------------------------------------------------+
void ChangeTrendEmptyPoints(datetime &time1,double &price1,
datetime &time2,double &price2)
{
//--- if the first point's time is not set, it will be on the current bar
if(!time1)
time1=TimeCurrent();
//--- if the first point's price is not set, it will have Bid value
if(!price1)
price1=SymbolInfoDouble(Symbol(),SYMBOL_BID);
//--- set coordinates of the second, auxiliary point
//--- the second point will be 9 bars left and have the same price
datetime second_point_time[10];
CopyTime(Symbol(),Period(),time1,10,second_point_time);
time2=second_point_time[0];
price2=price1;
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- check correctness of the input parameters
if(InpDate1<0 || InpDate1>100 || InpPrice1<0 || InpPrice1>100)
{
Print("Error! Incorrect values of input parameters!");
return;
}
//--- number of visible bars in the chart window
int bars=(int)ChartGetInteger(0,CHART_VISIBLE_BARS);
//--- price array size
int accuracy=1000;
//--- arrays for storing the date and price values to be used
//--- for setting and changing line anchor points' coordinates
datetime date[];
double price[];
//--- memory allocation
ArrayResize(date,bars);
ArrayResize(price,accuracy);
//--- fill the array of dates
ResetLastError();
if(CopyTime(Symbol(),Period(),0,bars,date)==-1)
{
Print("Failed to copy time values! Error code = ",GetLastError());
return;
}
//--- fill the array of prices
//--- find the highest and lowest values of the chart
double max_price=ChartGetDouble(0,CHART_PRICE_MAX);
double min_price=ChartGetDouble(0,CHART_PRICE_MIN);
//--- define a change step of a price and fill the array
double step=(max_price-min_price)/accuracy;
for(int i=0;i<accuracy;i++)
price[i]=min_price+i*step;
//--- define points for drawing the line
int d1=InpDate1*(bars-1)/100;
int p1=InpPrice1*(accuracy-1)/100;
//--- create a trend line
if(!TrendByAngleCreate(0,InpName,0,date[d1],price[p1],InpAngle,InpColor,InpStyle,
InpWidth,InpBack,InpSelection,InpRayRight,InpHidden,InpZOrder))
{
return;
}
//--- redraw the chart and wait for 1 second
ChartRedraw();
Sleep(1000);
//--- now, move and rotate the line
//--- loop counter
int v_steps=accuracy/2;
//--- move the anchor point and change the line's slope angle
for(int i=0;i<v_steps;i++)
{
//--- use the following value
if(p1>1)
p1-=1;
//--- move the point
if(!TrendPointChange(0,InpName,date[d1],price[p1]))
return;
if(!TrendAngleChange(0,InpName,18*(i+1)))
return;
//--- check if the script's operation has been forcefully disabled
if(IsStopped())
return;
//--- redraw the chart
ChartRedraw();
}
//--- 1 second of delay
Sleep(1000);
//--- delete from the chart
TrendDelete(0,InpName);
ChartRedraw();
//--- 1 second of delay
Sleep(1000);
//---
}
MQL4 Reference / Constants, Enumerations and Structures / Objects Constants / Object Types / OBJ_CYCLES
OBJ_CYCLES
Cycle Lines.
Note
The distance between the lines is set by time coordinates of two anchor points of the
object.
Example
The following script creates and moves cycle lines on the chart. Special functions have
been developed to create and change graphical object's properties. You can use these
functions "as is" in your own applications.
#property strict //--- description
#property description "Script creates cycle lines on the chart."
#property description "Anchor point coordinates are set in percentage"
#property description "percentage of the chart window size."
//--- display window of the input parameters during the script's launch
#property script_show_inputs
//--- input parameters of the script
input string InpName="Cycles"; // Object name
input int InpDate1=10; // 1 st point's date, %
input int InpPrice1=45; // 1 st point's price, %
input int InpDate2=20; // 2 nd point's date, %
input int InpPrice2=55; // 2 nd point's price, %
input color InpColor=clrRed; // Color of cycle lines
input ENUM_LINE_STYLE InpStyle=STYLE_DOT; // Style of cycle lines
input int InpWidth=1; // Width of cycle lines
input bool InpBack=false; // Background object
input bool InpSelection=true; // Highlight to move
input bool InpHidden=true; // Hidden in the object list
input long InpZOrder=0; // Priority for mouse click
//+------------------------------------------------------------------+
//| Create cycle lines |
//+------------------------------------------------------------------+
bool CyclesCreate(const long chart_ID=0, // chart's ID
const string name="Cycles", // object name
const int sub_window=0, // subwindow index
datetime time1=0, // first point time
double price1=0, // first point price
datetime time2=0, // second point time
double price2=0, // second point price
const color clr=clrRed, // color of cycle lines
const ENUM_LINE_STYLE style=STYLE_SOLID, // style of cycle lines
const int width=1, // width of cycle lines
const bool back=false, // in the background
const bool selection=true, // highlight to move
const bool hidden=true, // hidden in the object li
const long z_order=0) // priority for mouse clic
{
//--- set anchor points' coordinates if they are not set
ChangeCyclesEmptyPoints(time1,price1,time2,price2);
//--- reset the error value
ResetLastError();
//--- create cycle lines by the given coordinates
if(!ObjectCreate(chart_ID,name,OBJ_CYCLES,sub_window,time1,price1,time2,price2))
{
Print(__FUNCTION__,
": failed to create cycle lines! Error code = ",GetLastError());
return(false);
}
//--- set color of the lines
ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- set display style of the lines
ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
//--- set width of the lines
ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
//--- display in the foreground (false) or background (true)
ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- enable (true) or disable (false) the mode of moving the lines by mouse
//--- when creating a graphical object using ObjectCreate function, the object cannot
//--- highlighted and moved by default. Inside this method, selection parameter
//--- is true by default making it possible to highlight and move the object
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- hide (true) or display (false) graphical object name in the object list
ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- set the priority for receiving the event of a mouse click in the chart
ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Move the anchor point |
//+------------------------------------------------------------------+
bool CyclesPointChange(const long chart_ID=0, // chart's ID
const string name="Cycles", // object name
const int point_index=0, // anchor point index
datetime time=0, // anchor point time coordinate
double price=0) // anchor point price coordinate
{
//--- if point position is not set, move it to the current bar having Bid price
if(!time)
time=TimeCurrent();
if(!price)
price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
//--- reset the error value
ResetLastError();
//--- move the anchor point
if(!ObjectMove(chart_ID,name,point_index,time,price))
{
Print(__FUNCTION__,
": failed to move the anchor point! Error code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Delete the cycle lines |
//+------------------------------------------------------------------+
bool CyclesDelete(const long chart_ID=0, // chart's ID
const string name="Cycles") // object name
{
//--- reset the error value
ResetLastError();
//--- delete cycle lines
if(!ObjectDelete(chart_ID,name))
{
Print(__FUNCTION__,
": failed to delete cycle lines! Error code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+-----------------------------------------------------------------------+
//| Check the values of cycle lines' anchor points and set default values |
//| values for empty ones |
//+-----------------------------------------------------------------------+
void ChangeCyclesEmptyPoints(datetime &time1,double &price1,
datetime &time2,double &price2)
{
//--- if the first point's time is not set, it will be on the current bar
if(!time1)
time1=TimeCurrent();
//--- if the first point's price is not set, it will have Bid value
if(!price1)
price1=SymbolInfoDouble(Symbol(),SYMBOL_BID);
//--- if the second point's time is not set, it is located 9 bars left from the secon
if(!time2)
{
//--- array for receiving the open time of the last 10 bars
datetime temp[10];
CopyTime(Symbol(),Period(),time1,10,temp);
//--- set the second point 9 bars left from the first one
time2=temp[0];
}
//--- if the second point's price is not set, it is equal to the first point's one
if(!price2)
price2=price1;
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- check correctness of the input parameters
if(InpDate1<0 || InpDate1>100 || InpPrice1<0 || InpPrice1>100 ||
InpDate2<0 || InpDate2>100 || InpPrice2<0 || InpPrice2>100)
{
Print("Error! Incorrect values of input parameters!");
return;
}
//--- number of visible bars in the chart window
int bars=(int)ChartGetInteger(0,CHART_VISIBLE_BARS);
//--- price array size
int accuracy=1000;
//--- arrays for storing the date and price values to be used
//--- for setting and changing the coordinates of cycle lines' anchor points
datetime date[];
double price[];
//--- memory allocation
ArrayResize(date,bars);
ArrayResize(price,accuracy);
//--- fill the array of dates
ResetLastError();
if(CopyTime(Symbol(),Period(),0,bars,date)==-1)
{
Print("Failed to copy time values! Error code = ",GetLastError());
return;
}
//--- fill the array of prices
//--- find the highest and lowest values of the chart
double max_price=ChartGetDouble(0,CHART_PRICE_MAX);
double min_price=ChartGetDouble(0,CHART_PRICE_MIN);
//--- define a change step of a price and fill the array
double step=(max_price-min_price)/accuracy;
for(int i=0;i<accuracy;i++)
price[i]=min_price+i*step;
//--- define points for drawing cycle lines
int d1=InpDate1*(bars-1)/100;
int d2=InpDate2*(bars-1)/100;
int p1=InpPrice1*(accuracy-1)/100;
int p2=InpPrice2*(accuracy-1)/100;
//--- create a trend line
if(!CyclesCreate(0,InpName,0,date[d1],price[p1],date[d2],price[p2],InpColor,
InpStyle,InpWidth,InpBack,InpSelection,InpHidden,InpZOrder))
{
return;
}
//--- redraw the chart and wait for 1 second
ChartRedraw();
Sleep(1000);
//--- now, move the anchor points
//--- loop counter
int h_steps=bars/5;
//--- move the second anchor point
for(int i=0;i<h_steps;i++)
{
//--- use the following value
if(d2<bars-1)
d2+=1;
//--- move the point
if(!CyclesPointChange(0,InpName,1,date[d2],price[p2]))
return;
//--- check if the script's operation has been forcefully disabled
if(IsStopped())
return;
//--- redraw the chart
ChartRedraw();
// 0.05 seconds of delay
Sleep(50);
}
//--- 1 second of delay
Sleep(1000);
//--- loop counter
h_steps=bars/4;
//--- move the first anchor point
for(int i=0;i<h_steps;i++)
{
//--- use the following value
if(d1<bars-1)
d1+=1;
//--- move the point
if(!CyclesPointChange(0,InpName,0,date[d1],price[p1]))
return;
//--- check if the script's operation has been forcefully disabled
if(IsStopped())
return;
//--- redraw the chart
ChartRedraw();
// 0.05 seconds of delay
Sleep(50);
}
//--- 1 second of delay
Sleep(1000);
//--- delete the object from the chart
CyclesDelete(0,InpName);
ChartRedraw();
//--- 1 second of delay
Sleep(1000);
//---
}
MQL4 Reference / Constants, Enumerations and Structures / Objects Constants / Object Types / OBJ_CHANNEL
OBJ_CHANNEL
Equidistant Channel
Note
For an equidistant channel, it is possible to specify the mode of its continuation to the
right (OBJPROP_RAY_RIGHT property). The mode of filling the channel with color can
also be set.
Example
The following script creates and moves an equidistant channel on the chart. Special
functions have been developed to create and change graphical object's properties. You
can use these functions "as is" in your own applications.
#property strict //--- description
#property description "Script draws \"Equidistant Channel\" graphical object."
#property description "Anchor point coordinates are set in percentage of the size of"
#property description "the chart window."
//--- display window of the input parameters during the script's launch
#property script_show_inputs
//--- input parameters of the script
input string InpName="Channel"; // Channel name
input int InpDate1=25; // 1 st point's date, %
input int InpPrice1=60; // 1 st point's price, %
input int InpDate2=65; // 2 nd point's date, %
input int InpPrice2=80; // 2 nd point's price, %
input int InpDate3=30; // 3 rd point's date, %
input int InpPrice3=40; // 3 rd point's date, %
input color InpColor=clrRed; // Channel color
input ENUM_LINE_STYLE InpStyle=STYLE_DASH; // Style of channel lines
input int InpWidth=1; // Channel line width
input bool InpBack=false; // Background channel
input bool InpFill=false; // Filling the channel with color
input bool InpSelection=true; // Highlight to move
input bool InpRayRight=false; // Channel's continuation to the right
input bool InpHidden=true; // Hidden in the object list
input long InpZOrder=0; // Priority for mouse click
//+------------------------------------------------------------------+
//| Create an equidistant channel by the given coordinates |
//+------------------------------------------------------------------+
bool ChannelCreate(const long chart_ID=0, // chart's ID
const string name="Channel", // channel name
const int sub_window=0, // subwindow index
datetime time1=0, // first point time
double price1=0, // first point price
datetime time2=0, // second point time
double price2=0, // second point price
datetime time3=0, // third point time
double price3=0, // third point price
const color clr=clrRed, // channel color
const ENUM_LINE_STYLE style=STYLE_SOLID, // style of channel lines
const int width=1, // width of channel lines
const bool fill=false, // filling the channel wi
const bool back=false, // in the background
const bool selection=true, // highlight to move
const bool ray_right=false, // channel's continuation
const bool hidden=true, // hidden in the object l
const long z_order=0) // priority for mouse cli
{
//--- set anchor points' coordinates if they are not set
ChangeChannelEmptyPoints(time1,price1,time2,price2,time3,price3);
//--- reset the error value
ResetLastError();
//--- create a channel by the given coordinates
if(!ObjectCreate(chart_ID,name,OBJ_CHANNEL,sub_window,time1,price1,time2,price2,ti
{
Print(__FUNCTION__,
": failed to create an equidistant channel! Error code = ",GetLastError()
return(false);
}
//--- set channel color
ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- set style of the channel lines
ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
//--- set width of the channel lines
ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
//--- display in the foreground (false) or background (true)
ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- enable (true) or disable (false) the mode of highlighting the channel for movin
//--- when creating a graphical object using ObjectCreate function, the object cannot
//--- highlighted and moved by default. Inside this method, selection parameter
//--- is true by default making it possible to highlight and move the object
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- enable (true) or disable (false) the mode of continuation of the channel's disp
ObjectSetInteger(chart_ID,name,OBJPROP_RAY_RIGHT,ray_right);
//--- hide (true) or display (false) graphical object name in the object list
ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- set the priority for receiving the event of a mouse click in the chart
ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Move the channel's anchor point |
//+------------------------------------------------------------------+
bool ChannelPointChange(const long chart_ID=0, // chart's ID
const string name="Channel", // channel name
const int point_index=0, // anchor point index
datetime time=0, // anchor point time coordinate
double price=0) // anchor point price coordinate
{
//--- if point position is not set, move it to the current bar having Bid price
if(!time)
time=TimeCurrent();
if(!price)
price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
//--- reset the error value
ResetLastError();
//--- move the anchor point
if(!ObjectMove(chart_ID,name,point_index,time,price))
{
Print(__FUNCTION__,
": failed to move the anchor point! Error code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Delete the channel |
//+------------------------------------------------------------------+
bool ChannelDelete(const long chart_ID=0, // chart's ID
const string name="Channel") // channel name
{
//--- reset the error value
ResetLastError();
//--- delete the channel
if(!ObjectDelete(chart_ID,name))
{
Print(__FUNCTION__,
": failed to delete the channel! Error code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+-------------------------------------------------------------------------+
//| Check the values of the channel's anchor points and set default values |
//| for empty ones |
//+-------------------------------------------------------------------------+
void ChangeChannelEmptyPoints(datetime &time1,double &price1,datetime &time2,
double &price2,datetime &time3,double &price3)
{
//--- if the second (right) point's time is not set, it will be on the current bar
if(!time2)
time2=TimeCurrent();
//--- if the second point's price is not set, it will have Bid value
if(!price2)
price2=SymbolInfoDouble(Symbol(),SYMBOL_BID);
//--- if the first (left) point's time is not set, it is located 9 bars left from the
if(!time1)
{
//--- array for receiving the open time of the last 10 bars
datetime temp[10];
CopyTime(Symbol(),Period(),time2,10,temp);
//--- set the first point 9 bars left from the second one
time1=temp[0];
}
//--- if the first point's price is not set, move it 300 points higher than the secon
if(!price1)
price1=price2+300*SymbolInfoDouble(Symbol(),SYMBOL_POINT);
//--- if the third point's time is not set, it coincides with the first point's one
if(!time3)
time3=time1;
//--- if the third point's price is not set, it is equal to the second point's one
if(!price3)
price3=price2;
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- check correctness of the input parameters
if(InpDate1<0 || InpDate1>100 || InpPrice1<0 || InpPrice1>100 ||
InpDate2<0 || InpDate2>100 || InpPrice2<0 || InpPrice2>100 ||
InpDate3<0 || InpDate3>100 || InpPrice3<0 || InpPrice3>100)
{
Print("Error! Incorrect values of input parameters!");
return;
}
//--- number of visible bars in the chart window
int bars=(int)ChartGetInteger(0,CHART_VISIBLE_BARS);
//--- price array size
int accuracy=1000;
//--- arrays for storing the date and price values to be used
//--- for setting and changing channel anchor points' coordinates
datetime date[];
double price[];
//--- memory allocation
ArrayResize(date,bars);
ArrayResize(price,accuracy);
//--- fill the array of dates
ResetLastError();
if(CopyTime(Symbol(),Period(),0,bars,date)==-1)
{
Print("Failed to copy time values! Error code = ",GetLastError());
return;
}
//--- fill the array of prices
//--- find the highest and lowest values of the chart
double max_price=ChartGetDouble(0,CHART_PRICE_MAX);
double min_price=ChartGetDouble(0,CHART_PRICE_MIN);
//--- define a change step of a price and fill the array
double step=(max_price-min_price)/accuracy;
for(int i=0;i<accuracy;i++)
price[i]=min_price+i*step;
//--- define points for drawing the channel
int d1=InpDate1*(bars-1)/100;
int d2=InpDate2*(bars-1)/100;
int d3=InpDate3*(bars-1)/100;
int p1=InpPrice1*(accuracy-1)/100;
int p2=InpPrice2*(accuracy-1)/100;
int p3=InpPrice3*(accuracy-1)/100;
//--- create the equidistant channel
if(!ChannelCreate(0,InpName,0,date[d1],price[p1],date[d2],price[p2],date[d3],price
InpStyle,InpWidth,InpFill,InpBack,InpSelection,InpRayRight,InpHidden,InpZOrder)
{
return;
}
//--- redraw the chart and wait for 1 second
ChartRedraw();
Sleep(1000);
//--- now, move the channel's anchor points
//--- loop counter
int h_steps=bars/6;
//--- move the second anchor point
for(int i=0;i<h_steps;i++)
{
//--- use the following value
if(d2<bars-1)
d2+=1;
//--- move the point
if(!ChannelPointChange(0,InpName,1,date[d2],price[p2]))
return;
//--- check if the script's operation has been forcefully disabled
if(IsStopped())
return;
//--- redraw the chart
ChartRedraw();
// 0.05 seconds of delay
Sleep(50);
}
//--- 1 second of delay
Sleep(1000);
//--- move the first anchor point
for(int i=0;i<h_steps;i++)
{
//--- use the following value
if(d1>1)
d1-=1;
//--- move the point
if(!ChannelPointChange(0,InpName,0,date[d1],price[p1]))
return;
//--- check if the script's operation has been forcefully disabled
if(IsStopped())
return;
//--- redraw the chart
ChartRedraw();
// 0.05 seconds of delay
Sleep(50);
}
//--- 1 second of delay
Sleep(1000);
//--- loop counter
int v_steps=accuracy/10;
//--- move the third anchor point
for(int i=0;i<v_steps;i++)
{
//--- use the following value
if(p3>1)
p3-=1;
//--- move the point
if(!ChannelPointChange(0,InpName,2,date[d3],price[p3]))
return;
//--- check if the script's operation has been forcefully disabled
if(IsStopped())
return;
//--- redraw the chart
ChartRedraw();
}
//--- 1 second of delay
Sleep(1000);
//--- delete the channel from the chart
ChannelDelete(0,InpName);
ChartRedraw();
//--- 1 second of delay
Sleep(1000);
//---
}
MQL4 Reference / Constants, Enumerations and Structures / Objects Constants / Object Types /
OBJ_STDDEVCHANNEL
OBJ_STDDEVCHANNEL
Standard Deviation Channel.
Note
For Standard Deviation Channel, it is possible to specify the mode of continuation of its
display to the right (OBJPROP_RAY_RIGHT property). The mode of filling the channel
with color can also be set.
OBJPROP_DEVIATION property is used to change the value of the channel deviation.
Example
The following script creates and moves Standard Deviation Channel on the chart.
Special functions have been developed to create and change graphical object's
properties. You can use these functions "as is" in your own applications.
#property strict //--- description
#property description "Script draws \"Standard Deviation Channel\" graphical object."
#property description "Anchor point coordinates are set in percentage of the size of"
#property description "the chart window."
//--- display window of the input parameters during the script's launch
#property script_show_inputs
//--- input parameters of the script
input string InpName="StdDevChannel"; // Channel name
input int InpDate1=10; // 1 st point's date, %
input int InpDate2=40; // 2 nd point's date, %
input double InpDeviation=1.0; // Deviation
input color InpColor=clrRed; // Channel color
input ENUM_LINE_STYLE InpStyle=STYLE_DASHDOTDOT; // Style of channel lines
input int InpWidth=1; // Width of channel lines
input bool InpFill=false; // Filling the channel with color
input bool InpBack=false; // Background channel
input bool InpSelection=true; // Highlight to move
input bool InpRayRight=false; // Channel's continuation to the rig
input bool InpHidden=true; // Hidden in the object list
input long InpZOrder=0; // Priority for mouse click
//+------------------------------------------------------------------+
//| Create standard deviation channel by the given coordinates |
//+------------------------------------------------------------------+
bool StdDevChannelCreate(const long chart_ID=0, // chart's ID
const string name="Channel", // channel name
const int sub_window=0, // subwindow index
datetime time1=0, // first point time
datetime time2=0, // second point tim
const double deviation=1.0, // deviation
const color clr=clrRed, // channel color
const ENUM_LINE_STYLE style=STYLE_SOLID, // style of channel
const int width=1, // width of channel
const bool fill=false, // filling the chan
const bool back=false, // in the backgroun
const bool selection=true, // highlight to mov
const bool ray_right=false, // channel's contin
const bool hidden=true, // hidden in the ob
const long z_order=0) // priority for mou
{
//--- set anchor points' coordinates if they are not set
ChangeChannelEmptyPoints(time1,time2);
//--- reset the error value
ResetLastError();
//--- create a channel by the given coordinates
if(!ObjectCreate(chart_ID,name,OBJ_STDDEVCHANNEL,sub_window,time1,0,time2,0))
{
Print(__FUNCTION__,
": failed to create standard deviation channel! Error code = ",GetLastErr
return(false);
}
//--- set deviation value affecting the channel width
ObjectSetDouble(chart_ID,name,OBJPROP_DEVIATION,deviation);
//--- set channel color
ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- set style of the channel lines
ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
//--- set width of the channel lines
ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
//--- display in the foreground (false) or background (true)
ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- enable (true) or disable (false) the mode of highlighting the channel for movin
//--- when creating a graphical object using ObjectCreate function, the object cannot
//--- highlighted and moved by default. Inside this method, selection parameter
//--- is true by default making it possible to highlight and move the object
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- enable (true) or disable (false) the mode of continuation of the channel's disp
ObjectSetInteger(chart_ID,name,OBJPROP_RAY_RIGHT,ray_right);
//--- hide (true) or display (false) graphical object name in the object list
ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- set the priority for receiving the event of a mouse click in the chart
ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Move the channel's anchor point |
//+------------------------------------------------------------------+
bool StdDevChannelPointChange(const long chart_ID=0, // chart's ID
const string name="Channel", // channel name
const int point_index=0, // anchor point index
datetime time=0) // anchor point time coord
{
//--- if point time is not set, move the point to the current bar
if(!time)
time=TimeCurrent();
//--- reset the error value
ResetLastError();
//--- move the anchor point
if(!ObjectMove(chart_ID,name,point_index,time,0))
{
Print(__FUNCTION__,
": failed to move the anchor point! Error code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Change the channel's deviation |
//+------------------------------------------------------------------+
bool StdDevChannelDeviationChange(const long chart_ID=0, // chart's ID
const string name="Channel", // channel name
const double deviation=1.0) // deviation
{
//--- reset the error value
ResetLastError();
//--- change trend line's slope angle
if(!ObjectSetDouble(chart_ID,name,OBJPROP_DEVIATION,deviation))
{
Print(__FUNCTION__,
": failed to change channel deviation! Error code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Delete the channel |
//+------------------------------------------------------------------+
bool StdDevChannelDelete(const long chart_ID=0, // chart's ID
const string name="Channel") // channel name
{
//--- reset the error value
ResetLastError();
//--- delete the channel
if(!ObjectDelete(chart_ID,name))
{
Print(__FUNCTION__,
": failed to delete the channel! Error code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+-------------------------------------------------------------------------+
//| Check the values of the channel's anchor points and set default values |
//| for empty ones |
//+-------------------------------------------------------------------------+
void ChangeChannelEmptyPoints(datetime &time1,datetime &time2)
{
//--- if the second point's time is not set, it will be on the current bar
if(!time2)
time2=TimeCurrent();
//--- if the first point's time is not set, it is located 9 bars left from the second
if(!time1)
{
//--- array for receiving the open time of the last 10 bars
datetime temp[10];
CopyTime(Symbol(),Period(),time2,10,temp);
//--- set the first point 9 bars left from the second one
time1=temp[0];
}
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- check correctness of the input parameters
if(InpDate1<0 || InpDate1>100 ||
InpDate2<0 || InpDate2>100)
{
Print("Error! Incorrect values of input parameters!");
return;
}
//--- number of visible bars in the chart window
int bars=(int)ChartGetInteger(0,CHART_VISIBLE_BARS);
//--- price array size
int accuracy=1000;
//--- arrays for storing the date and price values to be used
//--- for setting and changing channel anchor points' coordinates
datetime date[];
double price[];
//--- memory allocation
ArrayResize(date,bars);
ArrayResize(price,accuracy);
//--- fill the array of dates
ResetLastError();
if(CopyTime(Symbol(),Period(),0,bars,date)==-1)
{
Print("Failed to copy time values! Error code = ",GetLastError());
return;
}
//--- fill the array of prices
//--- find the highest and lowest values of the chart
double max_price=ChartGetDouble(0,CHART_PRICE_MAX);
double min_price=ChartGetDouble(0,CHART_PRICE_MIN);
//--- define a change step of a price and fill the array
double step=(max_price-min_price)/accuracy;
for(int i=0;i<accuracy;i++)
price[i]=min_price+i*step;
//--- define points for drawing the channel
int d1=InpDate1*(bars-1)/100;
int d2=InpDate2*(bars-1)/100;
//--- create standard deviation channel
if(!StdDevChannelCreate(0,InpName,0,date[d1],date[d2],InpDeviation,InpColor,InpSty
InpWidth,InpFill,InpBack,InpSelection,InpRayRight,InpHidden,InpZOrder))
{
return;
}
//--- redraw the chart and wait for 1 second
ChartRedraw();
Sleep(1000);
//--- now, move the channel horizontally to the right and expand it
//--- loop counter
int h_steps=bars/2;
//--- move the channel
for(int i=0;i<h_steps;i++)
{
//--- use the following values
if(d1<bars-1)
d1+=1;
if(d2<bars-1)
d2+=1;
//--- move the anchor points
if(!StdDevChannelPointChange(0,InpName,0,date[d1]))
return;
if(!StdDevChannelPointChange(0,InpName,1,date[d2]))
return;
//--- check if the script's operation has been forcefully disabled
if(IsStopped())
return;
//--- redraw the chart
ChartRedraw();
// 0.05 seconds of delay
Sleep(50);
}
//--- 1 second of delay
Sleep(1000);
//--- loop counter
double v_steps=InpDeviation*2;
//--- expand the channel
for(double i=InpDeviation;i<v_steps;i+=10.0/accuracy)
{
if(!StdDevChannelDeviationChange(0,InpName,i))
return;
//--- check if the script's operation has been forcefully disabled
if(IsStopped())
return;
//--- redraw the chart
ChartRedraw();
}
//--- 1 second of delay
Sleep(1000);
//--- delete the channel from the chart
StdDevChannelDelete(0,InpName);
ChartRedraw();
//--- 1 second of delay
Sleep(1000);
//---
}
MQL4 Reference / Constants, Enumerations and Structures / Objects Constants / Object Types /
OBJ_REGRESSION
OBJ_REGRESSION
Linear Regression Channel.
Note
For Linear Regression Channel, it is possible to specify the mode of continuation of its
display to the right (OBJPROP_RAY_RIGHT property). The mode of filling the channel
with color can also be set.
Example
The following script creates and moves Linear Regression Channel on the chart. Special
functions have been developed to create and change graphical object's properties. You
can use these functions "as is" in your own applications.
#property strict //--- description
#property description "Script draws \"Linear Regression Channel\" graphical object."
#property description "Anchor point coordinates are set in percentage of the size of"
#property description "the chart window."
//--- display window of the input parameters during the script's launch
#property script_show_inputs
//--- input parameters of the script
input string InpName="Regression"; // Channel name
input int InpDate1=10; // 1 st point's date, %
input int InpDate2=40; // 2 nd point's date, %
input color InpColor=clrRed; // Channel color
input ENUM_LINE_STYLE InpStyle=STYLE_DASH; // Style of channel lines
input int InpWidth=1; // Width of channel lines
input bool InpFill=false; // Filling the channel with color
input bool InpBack=false; // Background channel
input bool InpSelection=true; // Highlight to move
input bool InpRayRight=false; // Channel's continuation to the right
input bool InpHidden=true; // Hidden in the object list
input long InpZOrder=0; // Priority for mouse click
//+------------------------------------------------------------------+
//| Create Linear Regression Channel by the given coordinates |
//+------------------------------------------------------------------+
bool RegressionCreate(const long chart_ID=0, // chart's ID
const string name="Regression", // channel name
const int sub_window=0, // subwindow index
datetime time1=0, // first point time
datetime time2=0, // second point time
const color clr=clrRed, // channel color
const ENUM_LINE_STYLE style=STYLE_SOLID, // style of channel li
const int width=1, // width of channel li
const bool fill=false, // filling the channel
const bool back=false, // in the background
const bool selection=true, // highlight to move
const bool ray_right=false, // channel's continuat
const bool hidden=true, // hidden in the objec
const long z_order=0) // priority for mouse
{
//--- set anchor points' coordinates if they are not set
ChangeRegressionEmptyPoints(time1,time2);
//--- reset the error value
ResetLastError();
//--- create a channel by the given coordinates
if(!ObjectCreate(chart_ID,name,OBJ_REGRESSION,sub_window,time1,0,time2,0))
{
Print(__FUNCTION__,
": failed to create linear regression channel! Error code = ",GetLastErro
return(false);
}
//--- set channel color
ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- set style of the channel lines
ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
//--- set width of the channel lines
ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
//--- display in the foreground (false) or background (true)
ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- enable (true) or disable (false) the mode of highlighting the channel for movin
//--- when creating a graphical object using ObjectCreate function, the object cannot
//--- highlighted and moved by default. Inside this method, selection parameter
//--- is true by default making it possible to highlight and move the object
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- enable (true) or disable (false) the mode of continuation of the channel's disp
ObjectSetInteger(chart_ID,name,OBJPROP_RAY_RIGHT,ray_right);
//--- hide (true) or display (false) graphical object name in the object list
ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- set the priority for receiving the event of a mouse click in the chart
ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Move the channel's anchor point |
//+------------------------------------------------------------------+
bool RegressionPointChange(const long chart_ID=0, // chart's ID
const string name="Channel", // channel name
const int point_index=0, // anchor point index
datetime time=0) // anchor point time coordina
{
//--- if point time is not set, move the point to the current bar
if(!time)
time=TimeCurrent();
//--- reset the error value
ResetLastError();
//--- move the anchor point
if(!ObjectMove(chart_ID,name,point_index,time,0))
{
Print(__FUNCTION__,
": failed to move the anchor point! Error code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Delete the channel |
//+------------------------------------------------------------------+
bool RegressionDelete(const long chart_ID=0, // chart's ID
const string name="Channel") // channel name
{
//--- reset the error value
ResetLastError();
//--- delete the channel
if(!ObjectDelete(chart_ID,name))
{
Print(__FUNCTION__,
": failed to delete the channel! Error code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+-------------------------------------------------------------------------+
//| Check the values of the channel's anchor points and set default values |
//| for empty ones |
//+-------------------------------------------------------------------------+
void ChangeRegressionEmptyPoints(datetime &time1,datetime &time2)
{
//--- if the second point's time is not set, it will be on the current bar
if(!time2)
time2=TimeCurrent();
//--- if the first point's time is not set, it is located 9 bars left from the second
if(!time1)
{
//--- array for receiving the open time of the last 10 bars
datetime temp[10];
CopyTime(Symbol(),Period(),time2,10,temp);
//--- set the first point 9 bars left from the second one
time1=temp[0];
}
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- check correctness of the input parameters
if(InpDate1<0 || InpDate1>100 ||
InpDate2<0 || InpDate2>100)
{
Print("Error! Incorrect values of input parameters!");
return;
}
//--- number of visible bars in the chart window
int bars=(int)ChartGetInteger(0,CHART_VISIBLE_BARS);
//--- price array size
int accuracy=1000;
//--- arrays for storing the date and price values to be used
//--- for setting and changing channel anchor points' coordinates
datetime date[];
double price[];
//--- memory allocation
ArrayResize(date,bars);
ArrayResize(price,accuracy);
//--- fill the array of dates
ResetLastError();
if(CopyTime(Symbol(),Period(),0,bars,date)==-1)
{
Print("Failed to copy time values! Error code = ",GetLastError());
return;
}
//--- fill the array of prices
//--- find the highest and lowest values of the chart
double max_price=ChartGetDouble(0,CHART_PRICE_MAX);
double min_price=ChartGetDouble(0,CHART_PRICE_MIN);
//--- define a change step of a price and fill the array
double step=(max_price-min_price)/accuracy;
for(int i=0;i<accuracy;i++)
price[i]=min_price+i*step;
//--- define points for drawing the channel
int d1=InpDate1*(bars-1)/100;
int d2=InpDate2*(bars-1)/100;
//--- create linear regression channel
if(!RegressionCreate(0,InpName,0,date[d1],date[d2],InpColor,InpStyle,InpWidth,
InpFill,InpBack,InpSelection,InpRayRight,InpHidden,InpZOrder))
{
return;
}
//--- redraw the chart and wait for 1 second
ChartRedraw();
Sleep(1000);
//--- now, the channel horizontally to the right
//--- loop counter
int h_steps=bars/2;
//--- move the channel
for(int i=0;i<h_steps;i++)
{
//--- use the following values
if(d1<bars-1)
d1+=1;
if(d2<bars-1)
d2+=1;
//--- move the anchor points
if(!RegressionPointChange(0,InpName,0,date[d1]))
return;
if(!RegressionPointChange(0,InpName,1,date[d2]))
return;
//--- check if the script's operation has been forcefully disabled
if(IsStopped())
return;
//--- redraw the chart
ChartRedraw();
// 0.05 seconds of delay
Sleep(50);
}
//--- 1 second of delay
Sleep(1000);
//--- delete the channel from the chart
RegressionDelete(0,InpName);
ChartRedraw();
//--- 1 second of delay
Sleep(1000);
//---
}
MQL4 Reference / Constants, Enumerations and Structures / Objects Constants / Object Types / OBJ_PITCHFORK
OBJ_PITCHFORK
Andrews Pitchfork.
Note
For Andrews Pitchfork, it is possible to specify the mode of continuation of its display
to the right (OBJPROP_RAY_RIGHT property).
You can also specify the number of line-levels, their values and color.
Example
The following script creates and moves Andrews Pitchfork on the chart. Special
functions have been developed to create and change graphical object's properties. You
can use these functions "as is" in your own applications.
#property strict //--- description
#property description "Script draws \"Andrews Pitchfork\" graphical object."
#property description "Anchor point coordinates are set in percentage of"
#property description "the chart window size."
//--- display window of the input parameters during the script's launch
#property script_show_inputs
//--- input parameters of the script
input string InpName="Pitchfork"; // Pitchfork name
input int InpDate1=14; // 1 st point's date, %
input int InpPrice1=40; // 1 st point's price, %
input int InpDate2=18; // 2 nd point's date, %
input int InpPrice2=50; // 2 nd point's price, %
input int InpDate3=18; // 3 rd point's date, %
input int InpPrice3=30; // 3 rd point's price, %
input color InpColor=clrRed; // Pitchfork color
input ENUM_LINE_STYLE InpStyle=STYLE_SOLID; // Style of pitchfork lines
input int InpWidth=1; // Width of pitchfork lines
input bool InpBack=false; // Background pitchfork
input bool InpSelection=true; // Highlight to move
input bool InpRayRight=false; // Pitchfork's continuation to the right
input bool InpHidden=true; // Hidden in the object list
input long InpZOrder=0; // Priority for mouse click
//+------------------------------------------------------------------+
//| Create Andrews' Pitchfork by the given coordinates |
//+------------------------------------------------------------------+
bool PitchforkCreate(const long chart_ID=0, // chart's ID
const string name="Pitchfork", // pitchfork name
const int sub_window=0, // subwindow index
datetime time1=0, // first point time
double price1=0, // first point price
datetime time2=0, // second point time
double price2=0, // second point price
datetime time3=0, // third point time
double price3=0, // third point price
const color clr=clrRed, // color of pitchfork l
const ENUM_LINE_STYLE style=STYLE_SOLID, // style of pitchfork l
const int width=1, // width of pitchfork l
const bool back=false, // in the background
const bool selection=true, // highlight to move
const bool ray_right=false, // pitchfork's continua
const bool hidden=true, // hidden in the object
const long z_order=0) // priority for mouse c
{
//--- set anchor points' coordinates if they are not set
ChangeChannelEmptyPoints(time1,price1,time2,price2,time3,price3);
//--- reset the error value
ResetLastError();
//--- create Andrews' Pitchfork by the given coordinates
if(!ObjectCreate(chart_ID,name,OBJ_PITCHFORK,sub_window,time1,price1,time2,price2,
{
Print(__FUNCTION__,
": failed to create \"Andrews' Pitchfork\"! Error code = ",GetLastError()
return(false);
}
//--- set color
ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- set the line style
ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
//--- set width of the lines
ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
//--- display in the foreground (false) or background (true)
ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- enable (true) or disable (false) the mode of highlighting the pitchfork for mov
//--- when creating a graphical object using ObjectCreate function, the object cannot
//--- highlighted and moved by default. Inside this method, selection parameter
//--- is true by default making it possible to highlight and move the object
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- enable (true) or disable (false) the mode of continuation of the pitchfork's di
ObjectSetInteger(chart_ID,name,OBJPROP_RAY_RIGHT,ray_right);
//--- hide (true) or display (false) graphical object name in the object list
ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- set the priority for receiving the event of a mouse click in the chart
ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Move Andrews' Pitchfork anchor point |
//+------------------------------------------------------------------+
bool PitchforkPointChange(const long chart_ID=0, // chart's ID
const string name="Pitchfork", // channel name
const int point_index=0, // anchor point index
datetime time=0, // anchor point time coordin
double price=0) // anchor point price coordi
{
//--- if point position is not set, move it to the current bar having Bid price
if(!time)
time=TimeCurrent();
if(!price)
price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
//--- reset the error value
ResetLastError();
//--- move the anchor point
if(!ObjectMove(chart_ID,name,point_index,time,price))
{
Print(__FUNCTION__,
": failed to move the anchor point! Error code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Delete Andrews Pitchfork |
//+------------------------------------------------------------------+
bool PitchforkDelete(const long chart_ID=0, // chart's ID
const string name="Pitchfork") // channel name
{
//--- reset the error value
ResetLastError();
//--- delete the channel
if(!ObjectDelete(chart_ID,name))
{
Print(__FUNCTION__,
": failed to delete \"Andrews' Pitchfork\"! Error code = ",GetLastError()
return(false);
}
//--- successful execution
return(true);
}
//+----------------------------------------------------------------------+
//| Check the values of Andrews' Pitchfork anchor points and set default |
//| values for empty ones |
//+----------------------------------------------------------------------+
void ChangeChannelEmptyPoints(datetime &time1,double &price1,datetime &time2,
double &price2,datetime &time3,double &price3)
{
//--- if the second (upper right) point's time is not set, it will be on the current
if(!time2)
time2=TimeCurrent();
//--- if the second point's price is not set, it will have Bid value
if(!price2)
price2=SymbolInfoDouble(Symbol(),SYMBOL_BID);
//--- if the first (left) point's time is not set, it is located 9 bars left from the
if(!time1)
{
//--- array for receiving the open time of the last 10 bars
datetime temp[10];
CopyTime(Symbol(),Period(),time2,10,temp);
//--- set the first point 9 bars left from the second one
time1=temp[0];
}
//--- if the first point's price is not set, move it 200 points below the second one
if(!price1)
price1=price2-200*SymbolInfoDouble(Symbol(),SYMBOL_POINT);
//--- if the third point's time is not set, it coincides with the second point's one
if(!time3)
time3=time2;
//--- if the third point's price is not set, move it 200 points lower than the first
if(!price3)
price3=price1-200*SymbolInfoDouble(Symbol(),SYMBOL_POINT);
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- check correctness of the input parameters
if(InpDate1<0 || InpDate1>100 || InpPrice1<0 || InpPrice1>100 ||
InpDate2<0 || InpDate2>100 || InpPrice2<0 || InpPrice2>100 ||
InpDate3<0 || InpDate3>100 || InpPrice3<0 || InpPrice3>100)
{
Print("Error! Incorrect values of input parameters!");
return;
}
//--- number of visible bars in the chart window
int bars=(int)ChartGetInteger(0,CHART_VISIBLE_BARS);
//--- price array size
int accuracy=1000;
//--- arrays for storing the date and price values to be used
//--- for setting and changing the coordinates of Andrews' Pitchfork anchor points
datetime date[];
double price[];
//--- memory allocation
ArrayResize(date,bars);
ArrayResize(price,accuracy);
//--- fill the array of dates
ResetLastError();
if(CopyTime(Symbol(),Period(),0,bars,date)==-1)
{
Print("Failed to copy time values! Error code = ",GetLastError());
return;
}
//--- fill the array of prices
//--- find the highest and lowest values of the chart
double max_price=ChartGetDouble(0,CHART_PRICE_MAX);
double min_price=ChartGetDouble(0,CHART_PRICE_MIN);
//--- define a change step of a price and fill the array
double step=(max_price-min_price)/accuracy;
for(int i=0;i<accuracy;i++)
price[i]=min_price+i*step;
//--- define points for drawing Andrews' Pitchfork
int d1=InpDate1*(bars-1)/100;
int d2=InpDate2*(bars-1)/100;
int d3=InpDate3*(bars-1)/100;
int p1=InpPrice1*(accuracy-1)/100;
int p2=InpPrice2*(accuracy-1)/100;
int p3=InpPrice3*(accuracy-1)/100;
//--- create the pitchfork
if(!PitchforkCreate(0,InpName,0,date[d1],price[p1],date[d2],price[p2],date[d3],pri
InpColor,InpStyle,InpWidth,InpBack,InpSelection,InpRayRight,InpHidden,InpZOrder
{
return;
}
//--- redraw the chart and wait for