{"id":1734,"date":"2008-03-20T20:10:00","date_gmt":"2008-03-20T20:10:00","guid":{"rendered":"http:\/\/www.amibroker.org\/userkb\/2008\/03\/20\/creating-gfx-chart-overlays\/"},"modified":"2008-05-01T18:13:31","modified_gmt":"2008-05-01T18:13:31","slug":"creating-gfx-chart-overlays","status":"publish","type":"post","link":"http:\/\/www.amibroker.org\/editable_userkb\/2008\/03\/20\/creating-gfx-chart-overlays\/","title":{"rendered":"Creating GFX Chart-Overlays (v3)"},"content":{"rendered":"

Important note<\/strong>: The AmiBroker 5.09.0 Beta<\/a> introduced the following new GFX functions:<\/p>\n

Status(“pxchartleft”) – returns x-coordinate of top-left corner of chart area
\nStatus(“pxcharttop”) – returns y-coordinate of top-left corner of chart area
\nStatus(“pxchartright”) – returns x-coordinate of bottom-right corner of chart area
\nStatus(“pxchartbottom”) – returns y-coordinate of bottom-right corner of chart area
\nStatus(“pxchartwidth”) – returns width chart area (right-left)
\nStatus(“pxchartheight”) – returns width chart area (bottom-top)<\/p>\n

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<\/a> file.<\/p>\n

=====<\/p>\n

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:<\/p>\n

pxwidth <\/span>= <\/span>Status<\/span>(<\/span>"pxwidth"<\/span>);\r<\/span>pxheight <\/span>= <\/span>Status<\/span>(<\/span>"pxheight"<\/span>);<\/span><\/pre>\n

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.<\/p>\n

\npixelarea.png<\/a><\/p>\n

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:<\/p>\n

\nchartingarea.png<\/a><\/p>\n

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

pxwidth <\/span>= <\/span>Status<\/span>( <\/span>"pxwidth" <\/span>);\r<\/span>pxheight <\/span>= <\/span>Status<\/span>( <\/span>"pxheight" <\/span>);\r<\/span>pxLeftArea <\/span>= <\/span>Param<\/span>( <\/span>"Left Blank Margin"<\/span>, <\/span>5<\/span>, <\/span>0<\/span>, <\/span>100<\/span>, <\/span>1 <\/span>); <\/span>\/\/ Constant\r<\/span>pxRightArea <\/span>= <\/span>Param<\/span>( <\/span>"Right Axis Area"<\/span>, <\/span>93<\/span>, <\/span>0<\/span>, <\/span>200<\/span>, <\/span>1 <\/span>); <\/span>\/\/ Depends on font\r<\/span>pxTopArea <\/span>= <\/span>Param<\/span>( <\/span>"Top Blank Margin"<\/span>, <\/span>5<\/span>, <\/span>0<\/span>, <\/span>100<\/span>, <\/span>1 <\/span>); <\/span>\/\/ Constant\r<\/span>pxDateArea <\/span>= <\/span>Param<\/span>( <\/span>"Date Axis Area"<\/span>, <\/span>11<\/span>, <\/span>0<\/span>, <\/span>100<\/span>, <\/span>1 <\/span>); <\/span>\/\/ Depends on font\r<\/span>pxBottomArea <\/span>= <\/span>Param<\/span>( <\/span>"Bottom Blank Margin"<\/span>, <\/span>5<\/span>, <\/span>0<\/span>, <\/span>100<\/span>, <\/span>1 <\/span>); <\/span>\/\/ Constant\r<\/span>DateaxisOn <\/span>= <\/span>ParamToggle<\/span>( <\/span>"Date Axis"<\/span>, <\/span>"HIDE|SHOW"<\/span>, <\/span>1 <\/span>);<\/span><\/pre>\n

Since adding date labels to your DateTime axis changes the size of your pixel plotting area, you need to compensate for this:<\/p>\n

<\/span>if( <\/span>DateaxisOn <\/span>) \r    {\r    <\/span>pxBottomArea <\/span>= <\/span>pxDateArea <\/span>+ <\/span>pxBottomArea<\/span>;\r    <\/span>SetChartOptions<\/span>(<\/span>2<\/span>,<\/span>chartShowDates<\/span>);\r    }\relse \r    {\r    <\/span>SetChartOptions<\/span>(<\/span>3<\/span>,<\/span>chartShowDates<\/span>);\r    }<\/span><\/pre>\n

The pixel plotting area’s width and height can now be calculated:<\/p>\n

pxPaneWidth <\/span>= <\/span>pxwidth <\/span>- <\/span>pxLeftArea<\/span>- <\/span>pxRightArea<\/span>;\r<\/span>pxPaneHeight <\/span>= <\/span>pxHeight <\/span>- <\/span>pxTopArea<\/span>- <\/span>pxBottomArea<\/span>;<\/span><\/pre>\n

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:<\/p>\n

Miny <\/span>= <\/span>Status<\/span>(<\/span>"axisminy"<\/span>);\r<\/span>Maxy <\/span>= <\/span>Status<\/span>(<\/span>"axismaxy"<\/span>);\r<\/span>YRange <\/span>= <\/span>MaxY <\/span>- <\/span>MinY\rBarsVisible <\/span>= <\/span>Status<\/span>(<\/span>"BarVisible"<\/span>);\r<\/span>NumBarsVisible <\/span>= <\/span>Cum<\/span>(<\/span>BarsVisible<\/span>);<\/span><\/pre>\n

You now have all the information needed to calculate the Pixels\/Price and Pixels\/Bar conversion factors:<\/p>\n

PixelsPerBar     <\/span>= <\/span>pxPaneWidth <\/span>\/ <\/span>NumBarsVisible<\/span>;\r<\/span>PixelsPerPrice <\/span>= <\/span>pxPaneHeight <\/span>\/ <\/span>YRange<\/span>;<\/span><\/pre>\n

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.<\/p>\n

\npricechartoverlay1.png<\/a><\/p>\n

\npricechartoverlayparam.png<\/a><\/p>\n

<\/span>function <\/span>gfxPlotHLine<\/span>( <\/span>YPixels<\/span>, <\/span>Color <\/span>)\r{\r    global <\/span>pxwidth<\/span>;\r    <\/span>GfxSelectPen<\/span>( <\/span>Color <\/span>) ;\r    <\/span>GfxMoveTo<\/span>( <\/span>0<\/span>, <\/span>YPixels <\/span>);\r    <\/span>GfxLineTo<\/span>( <\/span>pxwidth<\/span>, <\/span>YPixels <\/span>);\r}\r \rfunction <\/span>gfxPlotVLine<\/span>( <\/span>XPixels<\/span>, <\/span>Color <\/span>)\r{\r    global <\/span>pxheight<\/span>;\r    <\/span>GfxSelectPen<\/span>( <\/span>Color <\/span>) ;\r    <\/span>GfxMoveTo<\/span>( <\/span>XPixels<\/span>, <\/span>0 <\/span>);\r    <\/span>GfxLineTo<\/span>( <\/span>XPixels<\/span>, <\/span>pxheight <\/span>);\r}\r \rfunction <\/span>GetVisualBarIndex<\/span>( )\r{\r    <\/span>lvb <\/span>= <\/span>Status<\/span>( <\/span>"lastvisiblebar" <\/span>);\r    <\/span>fvb <\/span>= <\/span>Status<\/span>( <\/span>"firstvisiblebar" <\/span>);\r    <\/span>bi <\/span>= <\/span>BarIndex<\/span>();\r    <\/span>StaticVarSet<\/span>( <\/span>"NumberbarsVisible"<\/span>, <\/span>Lvb <\/span>- <\/span>fvb <\/span>+ <\/span>1 <\/span>);\r    return <\/span>bi <\/span>- <\/span>bi<\/span>[ <\/span>0 <\/span>] - <\/span>fvb<\/span>;\r}\r\rfunction <\/span>GetYPixels<\/span>( <\/span>Y <\/span>)\r    {\r    global <\/span>PixelsPerPrice<\/span>, <\/span>pxTopArea<\/span>, <\/span>MaxY<\/span>; \r    return (<\/span>MaxY <\/span>- <\/span>Y<\/span>) * <\/span>PixelsPerPrice <\/span>+ <\/span>pxTopArea<\/span>;\r    }\r\rfunction <\/span>GetXPixels<\/span>( <\/span>X <\/span>)\r    {\r    global <\/span>PixelsPerBar<\/span>, <\/span>pxLeftArea<\/span>;\r    return <\/span>X <\/span>* <\/span>PixelsPerBar <\/span>+ <\/span>pxLeftArea<\/span>;\r    }\r \r<\/span>GraphXSpace <\/span>= <\/span>5<\/span>;\r<\/span>SetChartOptions<\/span>( <\/span>0<\/span>, <\/span>chartHideQuoteMarker <\/span>);\r\r<\/span>pxwidth <\/span>= <\/span>Status<\/span>( <\/span>"pxwidth" <\/span>);\r<\/span>pxheight <\/span>= <\/span>Status<\/span>( <\/span>"pxheight" <\/span>);\r\r<\/span>\/\/ These Parameters will change depending on screen layout\/fonts\r<\/span>pxRightArea <\/span>= <\/span>Param<\/span>( <\/span>"Right Axis Area"<\/span>, <\/span>93<\/span>, <\/span>0<\/span>, <\/span>200<\/span>, <\/span>1 <\/span>); <\/span>\/\/ Depends on font\r<\/span>pxDateArea <\/span>= <\/span>Param<\/span>( <\/span>"Date Axis Area"<\/span>, <\/span>11<\/span>, <\/span>0<\/span>, <\/span>100<\/span>, <\/span>1 <\/span>); <\/span>\/\/ Depends on font\r<\/span>DateaxisOn <\/span>= <\/span>ParamToggle<\/span>( <\/span>"Date Axis"<\/span>, <\/span>"HIDE|SHOW"<\/span>, <\/span>1 <\/span>);\r\r<\/span>\/\/ These Parameters appear constant and can probably be hardcoded\r<\/span>pxLeftArea <\/span>= <\/span>Param<\/span>( <\/span>"Left Blank Margin"<\/span>, <\/span>5<\/span>, <\/span>0<\/span>, <\/span>100<\/span>, <\/span>1 <\/span>); <\/span>\/\/ Constant\r<\/span>pxTopArea <\/span>= <\/span>Param<\/span>( <\/span>"Top Blank Margin"<\/span>, <\/span>5<\/span>, <\/span>0<\/span>, <\/span>100<\/span>, <\/span>1 <\/span>); <\/span>\/\/ Constant\r<\/span>pxBottomArea <\/span>= <\/span>Param<\/span>( <\/span>"Bottom Blank Margin"<\/span>, <\/span>5<\/span>, <\/span>0<\/span>, <\/span>100<\/span>, <\/span>1 <\/span>); <\/span>\/\/ Constant\r \r<\/span>if ( <\/span>DateaxisOn <\/span>) <\/span>\/\/ Size of bottom boundary depends on whether dates are shown\r<\/span>{\r    <\/span>pxBottomArea <\/span>= <\/span>pxDateArea <\/span>+ <\/span>pxBottomArea<\/span>;\r    <\/span>SetChartOptions<\/span>( <\/span>2<\/span>, <\/span>chartShowDates <\/span>);\r}\relse\r    <\/span>SetChartOptions<\/span>( <\/span>3<\/span>, <\/span>chartShowDates <\/span>);\r \r<\/span>\/\/ Test Plots to help line up boundary lines\r<\/span>Color <\/span>= <\/span>colorWhite<\/span>;\r<\/span>gfxPlotVLine<\/span>( <\/span>pxLeftArea<\/span>, <\/span>color <\/span>);\r<\/span>gfxPlotVLine<\/span>( <\/span>pxwidth <\/span>- <\/span>pxRightArea<\/span>, <\/span>color <\/span>);\r<\/span>gfxPlotHLine<\/span>( <\/span>pxTopArea<\/span>, <\/span>color <\/span>);\r<\/span>gfxPlotHLine<\/span>( <\/span>pxHeight <\/span>- <\/span>pxBottomArea<\/span>, <\/span>color <\/span>);\r \r<\/span>\/\/ Calculate Pane width and height\r<\/span>pxPaneWidth <\/span>= <\/span>pxwidth <\/span>- <\/span>pxLeftArea <\/span>- <\/span>pxRightArea<\/span>;\r<\/span>pxPaneHeight <\/span>= <\/span>pxHeight <\/span>- <\/span>pxTopArea <\/span>- <\/span>pxBottomArea<\/span>;\r \r<\/span>\/\/ clalculate charting area width and height\r<\/span>Plot<\/span>( <\/span>C<\/span>, <\/span>""<\/span>, <\/span>1<\/span>, <\/span>styleDots <\/span>);\r<\/span>Miny <\/span>= <\/span>Status<\/span>( <\/span>"axisminy" <\/span>);\r<\/span>Maxy <\/span>= <\/span>Status<\/span>( <\/span>"axismaxy" <\/span>);\r<\/span>YRange <\/span>= <\/span>MaxY <\/span>- <\/span>MinY<\/span>;\r<\/span>VisBarIndex <\/span>=  <\/span>GetVisualBarIndex<\/span>( );\r<\/span>NumBarsVisible <\/span>= <\/span>StaticVarGet<\/span>( <\/span>"NumberbarsVisible" <\/span>);\r\r<\/span>\/\/ calculate conversion factors\r<\/span>PixelsPerBar     <\/span>= <\/span>pxPaneWidth <\/span>\/ <\/span>NumBarsVisible<\/span>;\r<\/span>PixelsPerPrice <\/span>= <\/span>pxPaneHeight <\/span>\/ <\/span>YRange<\/span>;\r\r<\/span>\/\/ For verification: Overlay pixel on price plot\r<\/span>FVB <\/span>= <\/span>Status<\/span>( <\/span>"firstvisiblebar" <\/span>);\r<\/span>LVB <\/span>= <\/span>Status<\/span>( <\/span>"lastvisiblebar" <\/span>);\r<\/span>GfxSelectPen<\/span>( <\/span>colorRed <\/span>);\rfor ( <\/span>b <\/span>= <\/span>FVB <\/span>+ <\/span>1<\/span>; <\/span>b <\/span><= <\/span>LVB <\/span>AND <\/span>b <\/span>< <\/span>BarCount<\/span>; <\/span>b<\/span>++ )\r{\r    <\/span>PrevPixelY <\/span>= <\/span>GetYPixels<\/span>( <\/span>C<\/span>[<\/span>b<\/span>-<\/span>1<\/span>] );\r    <\/span>PixelY <\/span>= <\/span>GetYPixels<\/span>( <\/span>C<\/span>[<\/span>b<\/span>] );\r \r    <\/span>PrevPixelX <\/span>= <\/span>GetXPixels<\/span>( <\/span>VisBarIndex<\/span>[<\/span>b<\/span>-<\/span>1<\/span>] );\r    <\/span>PixelX <\/span>= <\/span>GetXPixels<\/span>( <\/span>VisBarIndex<\/span>[<\/span>b<\/span>] );\r \r    <\/span>GfxMoveTo<\/span>( <\/span>PrevPixelX<\/span>, <\/span>PrevPixelY <\/span>);\r    <\/span>GfxLineTo<\/span>( <\/span>PixelX<\/span>, <\/span>PixelY <\/span>);\r}<\/span><\/pre>\n

Edited by Al Venosa.<\/p>\n","protected":false},"excerpt":{"rendered":"

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 […]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[138],"tags":[],"_links":{"self":[{"href":"http:\/\/www.amibroker.org\/editable_userkb\/wp-json\/wp\/v2\/posts\/1734"}],"collection":[{"href":"http:\/\/www.amibroker.org\/editable_userkb\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.amibroker.org\/editable_userkb\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.amibroker.org\/editable_userkb\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.amibroker.org\/editable_userkb\/wp-json\/wp\/v2\/comments?post=1734"}],"version-history":[{"count":0,"href":"http:\/\/www.amibroker.org\/editable_userkb\/wp-json\/wp\/v2\/posts\/1734\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.amibroker.org\/editable_userkb\/wp-json\/wp\/v2\/media?parent=1734"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.amibroker.org\/editable_userkb\/wp-json\/wp\/v2\/categories?post=1734"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.amibroker.org\/editable_userkb\/wp-json\/wp\/v2\/tags?post=1734"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}