March 4, 2011
Linking the TDash Window with the Main Chart
The most important requirement for a Trading Dashboard is to be able to place orders by dragging price markers and have these prices reflected on your main chart. To accomplish this relationship, the Main Chart and TDash windows must be bi-directionally linked so that changing prices in one window are being tracked in the other.
If both the Main chart and Trading Dashboard window had an identical price range and window size, this could simply be done by sharing the price and pixel ranges using Static Variables. However, to make this work in a multi window layout where windows may not be aligned accurately, or when the TDash window is located on another monitor, is a little more complex.
The problem can be solved by aligning the upper edge of the windows with the upper edge of the AmiBroker window, and use this as the common reference to calculate prices and pixel values.
The code below demonstrates how the Y-Pixel position and prices, between the Trading Dashboard window and the main chart, can be made to track each other. To apply this technique in an actual application you would want to add graphical price markers that you can drag, start up initialization, and provide a fine-adjustment to set prices exactly. Some of this will be covered in the next post.
To test the code, create a two-window Layout, arrange them horizontally, apply the TDashLinkDemo code in the right window, and apply the MainChartLinkDemo code in the left window. Since this test code is not initialized at start-up, you need to click in the TDash window to set an initial price and make the price-line appear.
Click the left mouse button in the TDash window at a new price level to set the price-line to a different value. Click and hold the left mouse button down to drag the price to a new value. Note that the price-line in the main chart window tracks all changes. Price lines would be used to display pending orders and to enable you to set order prices with respect to real-time chart patterns.
When you release the left mouse button in the TDash window it locks in the current price. The only way to change the price is by clicking or dragging it in the TDash window.
If you drag the Y-axis in the main chart the corresponding price-line in the TDash window tracks this movement. This is needed to keep price markers in the TDash window in sync when the main chart y-axis changes.
In a multi-threading environment, where formulas execute asynchronously, we cannot assume that transient conditions saved in a Static Variable in one window will always be detected in another. To ensure reliable mouse-click detection in the Main chart program, the “~LeftButtonRelease” Static Variable, which is set in the control window, is reset in the main chart after it has been detected. This way no triggers will ever be missed.
The short video below illustrates how this works and what it looks like in AmiBroker.
// TDashLinkDemo function LinkWithMainChart() { MX = GetCursorXPosition( 1 ); MY = GetCursorYPosition( 1 ); OnTDash = !IsNull( MX ) AND !IsNull( MY ); // Is cursor in TDash? LeftClick = GetCursorMouseButtons() == 9 AND OnTDash; LeftDown = ( GetCursorMouseButtons() == 1 OR LeftClick ) AND OnTDash; PrevLeftDownState = Nz( StaticVarGet( "~LeftDown" ) ); LeftButtonRelease = LeftDown < PrevLeftDownState; StaticVarSet( "~LeftDown", LeftDown ); if ( LeftClick ) StaticVarSet( "~NowDragging", True ); else if ( LeftButtonRelease ) { StaticVarSet( "~NowDragging", False ); StaticVarSet( "~LeftButtonRelease", True ); } if ( Nz( StaticVarGet( "~NowDragging" ) ) ) StaticVarSet( "~TDashYPixels", MY ); } function DrawTDashPriceLine() { pxWidth = Status( "pxWidth" ); TDashYPixels = StaticVarGet( "~TDashYPixels" ); GfxSetBkMode( 1 ); GfxSelectPen( colorRed, 1, 1 ); GfxMoveTo( 0, TDashYPixels ); GfxLineTo( pxwidth, TDashYPixels ); } function TDashDisplayPrice() { MY = GetCursorYPosition( 1 ); TDashYPixles = StaticVarGet( "~TDashYPixels" ); MAinChartPrice = Nz( StaticVarGet( "~MainChartPrice" ) ); GfxSetTextAlign( 0 ) ; GfxSelectFont( "Lucida Console", 12, 600 ); GfxTextOut( "TDash price: $" + NumToStr( MAinChartPrice, 1.2, False ), 0, TDashYPixles + 5 ); GfxTextOut( "TDash Pixels: " + NumToStr( TDashYPixles, 1.0, False ), 0, TDashYPixles + 20 ); } RequestTimedRefresh( 0.1 ); GfxSetOverlayMode( 2); LinkWithMainChart(); DrawTDashPriceLine(); TDashDisplayPrice(); // Test only
// MainChartLinkDemo function LinkWithTDash() { pxWidth = Status( "pxWidth" ); Miny = Status( "axisminy" ); Maxy = Status( "axismaxy" ); Pricerange = MaxY - MinY; pxchartbottom = Status( "pxchartbottom" ); pxcharttop = Status( "pxcharttop" ); PxChartRange = Status( "pxchartheight" ); pxheight = Status( "pxheight" ); if ( Nz( StaticVarGet( "~LeftButtonRelease" ) ) ) { TDashYPixels = StaticVarGet( "~TDashYPixels" ); PricePerPixel = Pricerange / PxChartRange; MAinChartPrice = Maxy - ( PricePerPixel * ( TDashYPixels - 5 ) ); StaticVarSet( "~LeftButtonRelease", False ); StaticVarSet( "~MainChartPrice", MAinChartPrice ); } else if ( Nz( StaticVarGet( "~NowDragging" ) ) == 0 ) { MAinChartPrice = Nz( StaticVarGet( "~MainChartPrice" ) ); PixelPerprice = PxChartRange / Pricerange; PriceToPixelvalue = ( MaxY - MAinChartPrice ) * Pixelperprice + 5; StaticVarSet( "~TDashYPixels", PriceToPixelvalue ); } } function DrawTDashPriceLine() { pxWidth = Status( "pxWidth" ); TDashYPixels = StaticVarGet( "~TDashYPixels" ); GfxSetBkMode( 1 ); GfxSelectPen( colorRed, 1, 1 ); GfxMoveTo( 0, TDashYPixels ); GfxLineTo( pxwidth, TDashYPixels ); } function MainDisplayPrice() { pxWidth = Status( "pxWidth" ); TDashYPixels = StaticVarGet( "~TDashYPixels" ); MAinChartPrice = Nz( StaticVarGet( "~MainChartPrice" ) ); GfxSetTextAlign( 2 ) ; GfxSelectFont( "Lucida Console", 12, 600 ); GfxTextOut( " Main price: $" + NumToStr( MAinChartPrice, 1.2, False ), pxwidth, TDashYPixels + 5 ); GfxTextOut( "Main Pixels: " + NumToStr( TDashYPixels, 1.0, False ), pxwidth, TDashYPixels + 20 ); } RequestTimedRefresh( 0.1 ); GfxSetOverlayMode( 0 ); LinkWithTDash(); DrawTDashPriceLine(); MainDisplayPrice(); // Test only Plot( C, "", colorBlack, styleBar );
Filed by Herman at 12:04 am under Developing a RT Trading Dashboard
Comments Off on Linking the TDash Window with the Main Chart