Creating GFX Chart-Overlays (v3)

Important note: The AmiBroker 5.09.0 Beta introduced the following new GFX functions:

Status(“pxchartleft”) – returns x-coordinate of top-left corner of chart area
Status(“pxcharttop”) – returns y-coordinate of top-left corner of chart area
Status(“pxchartright”) – returns x-coordinate of bottom-right corner of chart area
Status(“pxchartbottom”) – returns y-coordinate of bottom-right corner of chart area
Status(“pxchartwidth”) – returns width chart area (right-left)
Status(“pxchartheight”) – returns width chart area (bottom-top)

Since this release appeared after this post was published these functions are not used in the examples below. This post has been left unchanged for educational purposes. For examples using the new functions please see the 5.09.0 Read Me file.

=====

Creating an exact chart overlay using GFX functions can be a daunting task for the non-professional programmer. The solutions presented here were derived through experimentation; if there is a better way, please make a comment. Once the pixel layout is fully understood, GFX becomes an extremely powerful tool and may just give you an additional trading edge. The first and most important step in using GFX functions is to understand how pixels make up your display. In AmiBroker the width and height of your charting pane can be retrieved using the following two functions:

pxwidth Status("pxwidth");
pxheight Status("pxheight");

Horizontal pixels count left to right, 1 to pxwidth; vertical pixels count top to bottom, 1 to pxheight. The area covered by these two numbers is shown in Yellow below. For a high resolution monitor this area may cover about 2000 (H) x 1000 (V) pixels. This pixel area includes the areas used by the X and Y axis, and the blank top and bottom margins.

pixelarea.png

Next is the standard charting area, which is the area where your price charts are located. This area excludes the surrounding blank margins and the areas used for axis labeling. If you want to keep your overlay within the standard chart boundaries, you have to place your images within the above boundaries. This area is highlighted in Blue in the image below:

chartingarea.png

The boundaries for this area can be determined by running the example code listed in Finding Pixel Boundaries. Eight parameters must be known to create pixel overlays:

pxwidth Status"pxwidth" );
pxheight Status"pxheight" );
pxLeftArea Param"Left Blank Margin"50100); // Constant
pxRightArea Param"Right Axis Area"930200); // Depends on font
pxTopArea Param"Top Blank Margin"50100); // Constant
pxDateArea Param"Date Axis Area"110100); // Depends on font
pxBottomArea Param"Bottom Blank Margin"50100); // Constant
DateaxisOn ParamToggle"Date Axis""HIDE|SHOW");

Since adding date labels to your DateTime axis changes the size of your pixel plotting area, you need to compensate for this:

if( DateaxisOn ) 
    {
    pxBottomArea pxDateArea pxBottomArea;
    SetChartOptions(2,chartShowDates);
    }
else 
    {
    SetChartOptions(3,chartShowDates);
    }

The pixel plotting area’s width and height can now be calculated:

pxPaneWidth pxwidth pxLeftAreapxRightArea;
pxPaneHeight pxHeight pxTopAreapxBottomArea;

The dimension of the Blue area shown earlier changes when you resize AmiBroker, open additional windows or panes, change the fonts in your axis, or turn On/Off date labels. When this happens you will have to recalibrate the boundaries. To convert prices to pixels, so that you can create an exact overlay, you also need to define the width and height of your regular chart pane. These are expressed in DateTime and Price units. They will change when you zoom your chart. When you have at least one price plot displayed, so that the values for miny and maxy are defined, you can calculate these boundaries as follows:

Miny Status("axisminy");
Maxy Status("axismaxy");
YRange MaxY MinY
BarsVisible Status("BarVisible");
NumBarsVisible Cum(BarsVisible);

You now have all the information needed to calculate the Pixels/Price and Pixels/Bar conversion factors:

PixelsPerBar     pxPaneWidth NumBarsVisible;
PixelsPerPrice pxPaneHeight YRange;

Putting it all together in a demo program (listed at the end of this post) produces the price-chart overlay shown below. The regular price plot is plotted using dots, so that the overlay is clearly visible. When you plot both traces in lines, you will see minor deviations that are probably due to rounding to the nearest pixel. The pixel price plot is shown in Red. The purpose of this exercise is to learn to work with pixels and be able to produce an exact overlay on the price chart. The Param window below the charts shows typical parameters; they will likely be different for your screen layout.

pricechartoverlay1.png

pricechartoverlayparam.png

function gfxPlotHLineYPixelsColor )
{
    global pxwidth;
    GfxSelectPenColor ) ;
    GfxMoveTo0YPixels );
    GfxLineTopxwidthYPixels );
}
 
function gfxPlotVLineXPixelsColor )
{
    global pxheight;
    GfxSelectPenColor ) ;
    GfxMoveToXPixels);
    GfxLineToXPixelspxheight );
}
 
function GetVisualBarIndex( )
{
    lvb Status"lastvisiblebar" );
    fvb Status"firstvisiblebar" );
    bi BarIndex();
    StaticVarSet"NumberbarsVisible"Lvb fvb );
    return bi bi] - fvb;
}

function GetYPixels)
    {
    global PixelsPerPricepxTopAreaMaxY; 
    return (MaxY Y) * PixelsPerPrice pxTopArea;
    }

function GetXPixels)
    {
    global PixelsPerBarpxLeftArea;
    return PixelsPerBar pxLeftArea;
    }
 
GraphXSpace 5;
SetChartOptions0chartHideQuoteMarker );

pxwidth Status"pxwidth" );
pxheight Status"pxheight" );

// These Parameters will change depending on screen layout/fonts
pxRightArea Param"Right Axis Area"930200); // Depends on font
pxDateArea Param"Date Axis Area"110100); // Depends on font
DateaxisOn ParamToggle"Date Axis""HIDE|SHOW");

// These Parameters appear constant and can probably be hardcoded
pxLeftArea Param"Left Blank Margin"50100); // Constant
pxTopArea Param"Top Blank Margin"50100); // Constant
pxBottomArea Param"Bottom Blank Margin"50100); // Constant
 
if ( DateaxisOn // Size of bottom boundary depends on whether dates are shown
{
    pxBottomArea pxDateArea pxBottomArea;
    SetChartOptions2chartShowDates );
}
else
    SetChartOptions3chartShowDates );
 
// Test Plots to help line up boundary lines
Color colorWhite;
gfxPlotVLinepxLeftAreacolor );
gfxPlotVLinepxwidth pxRightAreacolor );
gfxPlotHLinepxTopAreacolor );
gfxPlotHLinepxHeight pxBottomAreacolor );
 
// Calculate Pane width and height
pxPaneWidth pxwidth pxLeftArea pxRightArea;
pxPaneHeight pxHeight pxTopArea pxBottomArea;
 
// clalculate charting area width and height
PlotC""1styleDots );
Miny Status"axisminy" );
Maxy Status"axismaxy" );
YRange MaxY MinY;
VisBarIndex =  GetVisualBarIndex( );
NumBarsVisible StaticVarGet"NumberbarsVisible" );

// calculate conversion factors
PixelsPerBar     pxPaneWidth NumBarsVisible;
PixelsPerPrice pxPaneHeight YRange;

// For verification: Overlay pixel on price plot
FVB Status"firstvisiblebar" );
LVB Status"lastvisiblebar" );
GfxSelectPencolorRed );
for ( FVB 1<= LVB AND BarCountb++ )
{
    PrevPixelY GetYPixelsC[b-1] );
    PixelY GetYPixelsC[b] );
 
    PrevPixelX GetXPixelsVisBarIndex[b-1] );
    PixelX GetXPixelsVisBarIndex[b] );
 
    GfxMoveToPrevPixelXPrevPixelY );
    GfxLineToPixelXPixelY );
}

Edited by Al Venosa.

Comments are closed.