- Describing resources using the #resource directive
- Shared use of resources of different MQL programs
- Resource variables
- Connecting custom indicators as resources
- Dynamic resource creation: ResourceCreate
- Deleting dynamic resources: ResourceFree
- Reading and modifying resource data: ResourceReadImage
- Saving images to a file: ResourceSave
- Fonts and text output to graphic resources
- Application of graphic resources in trading
Application of graphic resources in trading
Of course, beautifying is not the primary purpose of the resources. Let's see how to create a useful tool based on them. We will also eliminate one more omission: so far we have used resources only inside OBJ_BITMAP_LABEL objects, which are positioned in screen coordinates. However, graphic resources can also be embedded in OBJ_BITMAP objects with reference to quote coordinates: prices and time.
Earlier in the book, we have seen the IndDeltaVolume.mq5 indicator which calculates the delta volume (tick or real) for each bar. In addition to this representation of the delta volume, there is another one that is no less popular with users: the market profile. This is the distribution of volumes in the context of price levels. Such a histogram can be built for the entire window, for a given depth (for example, within a day), or for a single bar.
It is the last option that we implement in the form of a new indicator DeltaVolumeProfile.mq5. We have already considered the main technical details of the tick history request within the framework of the above indicator, so now we will focus mainly on the graphical component.
Flag ShowSplittedDelta in the input variable will control how volumes are displayed: broken down by buy/sell directions or collapsed.
input bool ShowSplittedDelta = true; |
There will be no buffers in the indicator. It will calculate and display a histogram for a specific bar at the user's request, and specifically, by clicking on this bar. Thus, we will use the OnChartEvent handler. In this handler, we get screen coordinates, recalculate them into price and time, and call some helper function RequestData, which starts the calculation.
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
|
To fill it, we need the DeltaVolumeProfile class, which is built to be similar to the class CalcDeltaVolume from IndDeltaVolume.mq5.
The new class describes variables that take into account the volume calculation method (tickType), the type of price on which the chart is built (barType), mode from the ShowSplittedDelta input variable (will be placed in a member variable delta), as well as a prefix for generated objects on the chart.
class DeltaVolumeProfile
|
The tick type can be changed to the TRADE_TICKS value only for trading instruments for which real volumes are available. By default, the INFO_TICKS mode is enabled, which works on all instruments.
Ticks for a particular bar are requested by the createProfileBar method.
int createProfileBar(const int i)
|
Direct analysis of ticks and calculation of volumes is performed in the protected method calcProfile. In it, first of all, we find out the price range of the bar and its size in pixels.
void calcProfile(const int b, const datetime time, const MqlTick &ticks[])
|
Based on this information, we create an OBJ_BITMAP object, allocate an array for the image, and create a resource. The background of the whole picture is empty (transparent). Each object is anchored by the upper midpoint to the High price of its bar and has a width of one bar.
uint data[];
|
This is followed by the calculation of volumes in ticks of the passed array. The number of price levels is equal to the height of the bar in pixels (h). Usually, it is less than the price range in points, and therefore the pixels act as a kind of basket for calculating statistics. If on a small timeframe, the range of points is smaller than the size in pixels, the histogram will be visually sparse. Volumes of purchases and sales are accumulated separately in plus and minus arrays.
long plus[], minus[], max = 0;
|
To normalize the histogram, we find the maximum value.
if(delta)
|
Finally, the resulting statistics are output to the graphics buffer data and sent to the resource. Buy volumes are displayed in blue, and sell volumes are shown in red. If the net mode is enabled, then the amount is displayed in green.
for(int i = 0; i < h; i++)
|
Now we can return to the RequestData function: its task is to call the createProfileBar method and handle errors (if any).
void RequestData(const int b, const datetime time, const int count = 0)
|
The only error-handling strategy is to try requesting the ticks again because they might not have had time to load. For this purpose, the function sends a custom TRY_AGAIN message to the chart and processes it itself.
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
|
We repeat this process no more than 5 times, because the tick history can have a limited depth, and it makes no sense to load the computer for no reason.
The DeltaVolumeProfile class also has the mechanism for processing the message CHARTEVENT_CHART_CHANGE in order to redraw existing objects in case of changing the size or scale of the chart. Details can be found in the source code.
The result of the indicator is shown in the following image.
Displaying per-bar histograms of separate volumes in graphic resources
Note that the histograms are not displayed immediately after drawing the indicator: you have to click on the bar to calculate its histogram.