Zoom functions to check out signals on a chart

When developing a trading system you often want to skip back and forth on the chart, from signal to signal, or day to day, to see the price conditions surrounding your signal. I tried the new GuiButtons to accomplice that. Normally you would include this code at the end of your system's code but in this case but, to allow for easy testing, the code below will run as is.

Apply to an indicator pane and enable the Zoom functions in the Parameter window to show the buttons at the top of the chart. It should look like this:

image

Surely this code can be improved but it may give you a good start if you need something like this,
happy coding!
Herman

_SECTION_BEGIN( "DEMO SYSTEM" );
Plot( C, "C", colorWhite, styleBar );
Short = Cover = 0;
period = 20;
m = MA( Close, period );
Buy = Cross( Close, m );
Sell = Cross( m, Close );
PlotShapes( IIf( Buy, 	shapeSmallUpTriangle, shapeNone ), 5, 0, BuyPrice, 0 );
PlotShapes( IIf( Sell,	shapeSmallDownTriangle, shapeNone ), 4, 0, SellPrice, 0 );
_SECTION_END();


// All the code below can be placed saved to an include file
// This include shoude be included in your code AFTER your signals have been defined.
// #include <ZoomButtonsInclude.afl> 

procedure ZoomToIndex( FirstBarIndex, LastBarIndex )
{
    StaticVarSet( "FirstBarIndex", FirstBarIndex );
    StaticVarSet( "LastBarIndex", LastBarIndex );
    DT = DateTime();
    BI = BarIndex();
    LastDateTime = LastValue( ValueWhen( LastBarIndex == BI, DT ) );
    FirstDateTime = LastValue( ValueWhen( FirstBarIndex == BI, DT ) );
    LastDateTimestr = DateTimeToStr( LastDateTime );
    FirstDateTimestr = DateTimeToStr( FirstDateTime );
    AB = CreateObject( "Broker.Application" );
    AW = AB.ActiveWindow;
    AW.ZoomToRange( FirstDateTimestr, LastDateTimestr );
    //_TRACE( "~ FirstDateTimestr: " + FirstDateTimestr + ", LastDateTimestr: " + LastDateTimestr );
}
procedure ZoomToCursor( ZoomWidth )
{
    local ZoomWidth;
    BI = BarIndex();
    SBI = SelectedValue( BI );
    LBI = LastValue( BI );
    CursorIndex = Nz( StaticVarGet( "CursorIndex" ) );
    FirstBarIndex = Max( 0, SBI - ZoomWidth );
    LastBarIndex = Min( LBI, SBI + ZoomWidth );
    ZoomToIndex( FirstBarIndex, LastBarIndex );
}
procedure ZoomOut( ZoomWidth )
{
    local ZoomWidth;
    BI = BarIndex();
    LBI = LastValue( BI );
    LastVisiblebar = Status( "LastVisibleBar" );
    FirstVisibleBar = Status( "FirstVisibleBar" );
    FirstBarIndex = Max( 0, FirstVisibleBar - ZoomWidth );
    LastBarIndex = Min( LBI, LastVisibleBar + ZoomWidth );
    ZoomToIndex( FirstBarIndex, LastBarIndex );
}
procedure ZoomIn( ZoomWidth )
{
    local ZoomWidth;
    _TRACE( "##" );
    BI = BarIndex();
    LBI = LastValue( BI );
    LastVisiblebar = Status( "LastVisibleBar" );
    FirstVisibleBar = Status( "FirstVisibleBar" );
    FirstBarIndex = Max( 0, FirstVisibleBar + ZoomWidth );
    LastBarIndex = Min( LBI, LastVisibleBar - ZoomWidth );
    ZoomToIndex( FirstBarIndex, LastBarIndex );
}
procedure ZoomToNext( Event, ZoomWidth )
{
    local Event, Zoomwidth;
    EventNum = Cum( Event );
    BI = BarIndex();
    LBI = LastValue( BI );
    DT = DateTime();
    NextEventNum = Min( Nz( StaticVarGet( "EventNumber" ) ) + 1, LastValue( EventNum ) );
    NextEventIndex = LastValue( ValueWhen( EventNum == NextEventNum, BI ) );
    StaticVarSet( "EventNumber", Max( 1, NextEventNum ) );
    FirstBarIndex = Max( 0, NextEventIndex - ZoomWidth );
    LastBarIndex = Min( BarCount - 1, NextEventIndex + ZoomWidth );
    ZoomToIndex( FirstBarIndex, LastBarIndex );
    StaticVarSet( "FocusIndex", NextEventIndex );
}
procedure ZoomToPrev( Event, ZoomWidth )
{
    local Event, Zoomwidth;
    EventNum = Cum( Event );
    BI = BarIndex();
    LBI = LastValue( BI );
    LastEventNum = LastValue( EventNum );
    NextEventNum = Max( 1, Nz( StaticVarGet( "EventNumber" ) ) - 1 );
    NextEventIndex = LastValue( ValueWhen( EventNum == NextEventNum, BI, 1 ) );
    StaticVarSet( "EventNumber", NextEventNum );
    FirstBarIndex = Max( 0, NextEventIndex - ZoomWidth );
    LastBarIndex = Min( BarCount - 1, NextEventIndex + ZoomWidth );
    ZoomToIndex( FirstBarIndex, LastBarIndex );
    StaticVarSet( "FocusIndex", NextEventIndex );
}
procedure MarkFocus()
{
    EventNum = Nz( StaticVarGet( "EventNumber" ) );
    DT = DateTime();
    BI = BarIndex();
    LBI = LastValue( BI );
    FirstBarIndex = Nz( StaticVarGet( "FirstBarIndex" ) );
    FocusIndex = Min( LBI, Nz( StaticVarGet( "FocusIndex" ) ) + 1 );
    FocusDateStr = NumToStr( DT[FocusIndex], formatDateTime );
    ENStr = "Event " + NumToStr( EventNum[FocusIndex], 1.0, False ) +"\n|";
    PlotText( "Focus\n" + FocusDateStr + "\n" + ENStr, FocusIndex, 1.005 * H[FocusIndex], colorYellow );
}
procedure ZoomAllOut()
{
    BI = BarIndex();
    LBI = LastValue( BI );
    FirstBarIndex = 0;
    LastBarIndex = LBI;
    ZoomToIndex( FirstBarIndex, LastBarIndex );
}
procedure RightJustifyChart( ChartWidth )
{
    DT = DateTime();
    BI = BarIndex();
    FirstDateTime = LastValue( Nz( Ref( DT, -Max( 2, ChartWidth ) ) ) );
    FirstDateTimestr = DateTimeToStr( FirstDateTime );
    LastDateTimestr = DateTimeToStr( LastValue( DT ) );
    AB = CreateObject( "Broker.Application" );
    AW = AB.ActiveWindow;
    AW.ZoomToRange( FirstDateTimestr, LastDateTimestr );
}

_SECTION_BEGIN( "ZOOMING" );
ZoomOn = ParamToggle( "ZoomFunction", "OFF,ON", 0 );
ZoomIncrement = Param( "Zoom Increment", 10, 1, 1000, 2 );
ZoomWidth = Param( "Zoom Width", 100, 2, 1000, 1 );
height = Param( "Zoom Buttons Height", 30, 10, 100, 1 );
y = Param( "Zoom Buttons Vertical Position", 0, 0, 2000, 1 );
x = Param( "Zoom Buttons Horizontal Position", 0, 0, 2000, 1 );
_SECTION_END();

if( ZoomOn )
{
    if( typeof( Buy ) == "undefined" ) Buy = 0;

    if( typeof( Short ) == "undefined" ) Short = 0;

    RequestTimedRefresh( 1 );
    SetBarsRequired( sbrall, sbrall );
    GuiSetFont( "Lucida Console", 10 );

    NumButtons = 9;
    xi = ( Status( "pxchartright" ) - x ) / NumButtons;
    GuiButton( "> BUY", 2, x, y, xi, height, 7 );
    GuiButton( "< BUY", 3, x = x + xi, y, xi, height, 7 );
    GuiButton( "> SHORT", 4, x = x + xi, y, xi, height, 7 );
    GuiButton( "< SHORT", 5, x = x + xi, y, xi, height, 7 );
    GuiButton( "> DAY", 6, x = x + xi, y, xi, height, 7 );
    GuiButton( "< DAY", 7, x = x + xi, y, xi, height, 7 );
    GuiButton( "IN", 8, x = x + xi, y, xi, height, 7 );
    GuiButton( "OUT", 9, x = x + xi, y, xi, height, 7 );
    GuiButton( "JUSTIFY >", 10, x = x + xi, y, xi, height, 7 );
    GuiSetColors( 2, 10, 2, colorYellow, colorBlack, colorYellow, colorWhite, colorBlue, colorblue, colorBlack, colorYellow, colorYellow );
//  idFrom, idTo, border , clrText     clrBack     clrBorder     clrSelText  clrSelBack clrSelBorder clrHoverText clrHoverBack clrHoverBorder clrDisText clrDisBack clrDisBorder


    if( GuiGetEvent( 0, 1 ) == 1 )
    {
        PrevZoomWidth = Nz( StaticVarGet( "ZoomWidth" ) );
        ZoomChange = PrevZoomWidth != ZoomWidth;
        StaticVarSet( "ZoomWidth", ZoomWidth );
        DN = DateNum();
        BarInRange 	= Status( "BarInRange" );
        NewDay 		= DN != Ref( DN, -1 ) AND BarInRange;
        FirstVisibleBar = Status( "FirstVisibleBar" );
        Lastvisiblebar = Status( "LastVisibleBar" );
        BI = BarIndex();
        SBI = SelectedValue( BI );
        LBI = LastValue( BI );
        str = GuiGetEvent( 0, 2 );
        id = GuiGetEvent( 0, 0 );
        StaticVarSet( "CursorIndex", SBI );
        StaticVarSet( "FocusIndex", SBI - 1 );
        CurrentRange = LastVisiblebar - FirstVisibleBar;
        VisibleCenter = int( ( LastVisibleBar + FirstVisibleBar ) / 2 );
        FirstBarIndex = Nz( StaticVarGet( "FirstBarIndex" ) );
        LastBarIndex = Nz( StaticVarGet( "LastBarIndex" ) );

        for( i = 2; i <= 10; i++ )
        {
            if( id == i )
            {
                switch( id )
                {
                    case 2:
                        event = Buy;
                        ZoomToNext( Event, ZoomWidth );
                        break;

                    case 3:
                        event = Buy;
                        ZoomToPrev( Event, ZoomWidth );
                        break;

                    case 4:
                        event = Short;
                        ZoomToNext( Event, ZoomWidth );
                        break;

                    case 5:
                        event = Short;
                        ZoomToPrev( Event, ZoomWidth );
                        break;

                    case 6:
                        event = NewDay;
                        ZoomToNext( Event, ZoomWidth );
                        break;

                    case 7:
                        event = NewDay;
                        ZoomToPrev( Event, ZoomWidth );
                        break;

                    case 8:
                        ZoomIn( ZoomWidth );
                        break;

                    case 9:
                        ZoomOut( ZoomWidth );
                        break;

                    case 10:
                        RightJustifyChart( ZoomWidth );
                        break;

                    default:
                        break;
                }

                playsound( "C:\\Program Files\\Amibroker\\Sounds\\Button.wav" );
            }
        }
    }

    MArkFocus();
}
2 Likes

Hello Herman. Thanks for the interesting code :slight_smile:

I have one performance related question. Why do you force additional chart refreshes using: --> RequestTimedRefresh( 1 ); ? I don’t think it’s necessary - the code seems to be working fine without it. If it’s because of GuiButtons, you don’t need any regular refreshes.

Regards

Hi Milosz,

I copied the zooming code from another program and it got included. It is
not there for the GuiButtons.

I may use this code with programs that use timers and display functions
that need to be refreshed often, even without RT data or mouse movement.
Actually I mostly use 0.1 sec refreshes as I like to display my timers with
0.1 sec accuracy.

I never experienced any problems using RequestTimedRefresh( 0.1 ) so I
don’t bother to check each program I load to see if it really needs it.

best regards,
Herman

Doing so puts unnecessary load on CPU (as large as 10x too much). The result may be decreased responsiveness of entire computer.
I am strongly against frivolous use of 0.1 second refreshes everywhere without very good reason to do so. That is why it is hidden in registry.

Really providing programmable platform is a support nightmare.

1 Like

Thank you, yes I am aware of it and always keep an eye on the Performance
Monitor, load factor, and afl execution time. I usually have lots of spare.

Also, when finalizing a formula I may remove the timed refresh to see if
things work the same.

best regards,
Herman

Interesting information, thanks