Alert-driven Bar-Replay. Auto - syncing charts with Buy/Sell signals

This topic is similar to: Bar replay - go to specific time

Strangely enough, there were no replies to trunda's post - perhaps the subject wasn't clear enough or the idea wasn't elaborated on sufficiently.

Bar-Replay is probably the most powerful learning tool we in our toolbox, however, most people shy away from using it because it takes too much time to step over the countless bars before a trading opportunity occurs.

I find Bar-Replay indispensable and would like to implement a skip-to-alert feature that would, for example using a ParamTrigger(), allow me to fast-forward to an alert condition defined in afl (similar to a Buy signal).

If you are an intraday trader and trade just once a day on the average, this feature would allow you to Bar-Replay several months of data in just an hour or so - instead of going cross-eyed by watching charts scroll by for several days.

I hesitate to suggest this feature as I suspect it can only be implemented by Tomasz and I am sure he has more important things to work on.

But perhaps I am missing something and someone has either solved it or has some ideas on how to go about it.

Anyone?

2 Likes

@Beaver this does not seem an easy task.

Just some randoms ideas if you have some (probably a lot of) time to spend on this.

Implement it as a state machine (with a low time refresh).

Use GUI buttons to transit from different states, bar by bar replay, pause, find next signal, etc.
Use OLE to interact both with the AmiBroker active chart (using the OLE range functions developed in the past to zoom and move along the timeline), plus the WShell SendKeys function to send Keyboards command to AB (like it was done in this other OLE example)

// Initialize all the OLE Object ONCE
WSHShell = CreateObject( "WScript.Shell" );
WSHShell.AppActivate( "AmiBroker" );
// send this command from the state machine when in "replay" state
WSHShell.Sendkeys( "{RIGHT}" );

In the end, it may not work as expected, or some unforeseen issues may make it unpractical, but at least you have something to think about.

As usual, I tend to over-complicate things... Let's hope someone else will provide a better approach!

1 Like

Thanks beppe,

OLE has always been a challenge for me so I don't think I would get very far with this.

I should mention that this needs to only work for a single symbol database. Possible, and not completely thought through, solutions that crossed my mind are:

  1. Somehow trick AB into thinking there is no data beyond the alert - perhaps by nulling all data past the alert - and then add on one bar at a time until there is an alert.

  2. Use zoom functions to step the data one bar at a time.

  3. Create a simple bar-replay system that shifts all data arrays so that the next alert becomes the last bar.

  4. Modify the database. Remove and add back in data.

Thanks for your reply!

1 Like

Hi @SpinTrader,

Just sharing another perspective using AutoHotKey. AHK can be used to create macros for almost anything within Windows environment. I literally use it for many stuffs like creating excel charts/reports, automating redundant tedious tasks etc. - makes life lot easy.

IMO using AHK for this project would be simpler but not easy, since, AHK and AB need to walk hand-in-hand. Sometime back I succeeded doing that - Passing variables from AFL to AHK but the task was pretty easy compared to this one. Gosh, I am stuck on other stuffs, once free will certainly look onto this. Sounds lot of fun!

Below I am using the "Active Window Info" spy feature of SciTE4AutoHotkey (AHK's editor) to identify the Controls of "Bar Replay" window. Notice the Absolute, Relative and Client Mouse Position along with the ClassNN and its Text under Mouse position. These values can be called to take external control over any application and automate manual efforts.

AHK

So what I am suggesting is that once a GFX button on the chart is clicked. It will invoke AHK to hit shortcut keys automatically to open "Bar Replay" window (using the shortcut which was previously specified in AB's customize keyboard shortcuts) and then automatically scroll through the ClassNN msctls_trackbar321 until the next signal is found wherein it should stop scrolling unless the user clicks on the GFX button again to scroll to the next signal.

P.S. AHK and its editor - SciTE4AutoHotkey are all open source.

3 Likes

@Beaver,
If the motive is to watch only (historical) alerts by skipping/jumping directly to the alerts one after other ,what i need BarReplay for ? Wouldn't Exploration do a better job ? listing all the alerts and more info displayed neatly in rows n columns in whichever way i prefer.

IMHO, BarReplay is to watch /study how the Chart /Prices behaved /what lead to/ circumstances/causes /events PRIOR to the ALERT.

P.S. : And of course, to catch a Bad/Repainting AFL red handed , BarReplay comes handy.:smile::smile:

I mean, BarReplay is the tool to Vissualize/ReEnact all the drama that enacted before the Event Alert .

1 Like

Thanks, Lennon, this might indeed work and I checked out the AHK website.

If, and I couldn't find this info right away, we can start an AHK script from afl than this might work:

  1. Click a button or ParamTrigger to look for the next alert

  2. When it finds an alert it launches AHK

  3. AHK open the Bar-Replay window

  4. AHK sets the next Bar-Replay Starting date (End date is last bar) and clicks Run

  5. After making our trade we would close Bar-Replay and go back to 1

The big question I have is step 2 above. Can an AHK script be launched from afl, perhaps using ShellExec?

I would like to suggest adding a Skip to Alert button to the Bar-Replay window, perhaps Tomasz may consider this. Is there still a place to suggest new features?

1 Like

Thanks SpinTrader for looking into it.

ShellExecute. Caveat is that AB's ShellExecute does not run an external application as admin. To resolve this (if admin rights are required) we could simply ShellExecute a JS that would call the AHK script with admin rights.

For example:
Lets say Lmt_Win_Btn.ahk contains a set of event instructions to be orchestrated on a different application or a window within the same application.

Lmt_Win_Btn.js calling AHK as Admin:

var oShell = new ActiveXObject("Shell.Application");
oShell.ShellExecute( "C:\\Program Files\\AmiBroker\\OrderInterface\\Lmt_Win_Btn.ahk", "", "", "runas", 1 );

Lmt_Win_Btn.js called from AB chart:

if( CrsrInLmtWinBtnArea & MouseJustClicked )
 {
	 Price = 0;
	 Trigger = 0;
		 
	 OrderInterface( Call, Tkr, Quantity, Price, Trigger );
	 ShellExecute( "C:\\Program Files\\AmiBroker\\OrderInterface\\JS_Shortcuts\\Lmt_Win_Btn.js", "", "", 1 );
}

I think in this case going by .js route won't be necessary. ShellExecute from AB would suffice.

I would like to do is the following:

  1. ShellExecute AHK script which will run an exploration and save the trade dates onto a txt/csv file;
  2. Then invoke BarReplay window and wait until it automatically identifies and duplicates the start/end dates from the previously ran exploration;
  3. Trigger Auto BarReplay once done - I mean slide the bar, by looping in tandem with the current BarIndex and the trade dates txt saved previously
  4. Scrolling of the slider stops whence the next trade date / datetime is found in static4 which was tallied from the trade dates txt

Its doable and simple but not easy as we would need to collaborate the orchestra.

Feedback Center

P.S. Using AHK gives many readymade solutions to intercommunication of applications in Windows environment. Its just automating the manual events (clicks, keystrokes, drag/drop, etc..) Having that said, it does not cliche OLE control calls and one need to use alternatives when the OLE is restricting - and AHK serves to be one.

3 Likes

Thanks very much for giving this some thought.

Your examples go over my head a bit and I need some time to digest your reply. Also, let's see what other replies appear, perhaps a simpler solution surfaces.

Your idea of saving the Alert DateTimes to a file might lead to other ideas. Even manually copying the dates to the Bar-Replay window could be considered.

The problem here is that the Bar-Replay window does not allow a starting bar by time. Hence, if you trade once a day intraday there would be no time savings. This suggests some data-array manipulation may be required to obtain intraday functioning.

BTW, thanks for the link! Since this would enhance the appeal and usefulness of Bar-Replay I posted a suggestion on the feedback site.

1 Like

@Beaver you can also try a simpler solution first.

If the main problem is auto scrolling to Buy/Sell signals, you can use already inbuilt in AmiBroker functionality for that. If you run a Scan, let's say as sophisticated as this one :wink: :

Buy = ROC(C, 1) >= 1;
Sell = ROC(C, 1) <= -1;

PlotShapes(Buy*shapeDownTriangle, colorGreen, 0, H);
PlotShapes(Sell*shapeDownTriangle, colorRed, 0, H);
Plot(C, "Price", colorDefault, styleCandle);

... and click on the results pane with a right mouse button and select "Show current trade arrow" or just double click the line while holding SHIFT key pressed down, the chart will be automatically scrolled to this signal! This could be the whole solution! You have both - the list with all the signals and you can momentarily see selected signal on the chart!

Arrows%201

It is important to enable showing trading arrows (for instance in the chart's properties):

Arrows%202


If you want to replicate other Bar replay functionalities it could be possible for example using ZoomToRange and SetBarsRequired(n, FutureBars = 0) used at the end of the code! (not at the begining) to overwritte the default number of bars in use and force AmiBroker not to see/use any bars after the last visible candle (or signal in this case). You just need to scroll (using ZoomToRange) the chart so as the signal is the last visible candle (just like in Bar replay). It should be possible, because I've noticed, that after syncing, the bar with the signal is always 21st from the left.

Making a separate list with all the signals and then exploring them is another possibility.

Currently I don't have time to code this idea (I have already planned some outdoor activities for Saturday :wink: ), but you can try to put them into life on your own!

... But I also think, that adding such functionality to the Bar replay is a good idea!

Regards

5 Likes

On a side note:

... so you can not control Bar Replay from the outside.


When I wrote using ZoomToRange I meant using OLE for that so it all happens automatically. Some examples:

http://www.amibroker.org/userkb/2007/06/28/zoom-to-range-applications/
http://www.amibroker.com/kb/2015/10/05/how-to-browse-charts-in-selected-date-range/

2 Likes

Thanks very much for your input!

We are getting some new ideas. I like the simple idea of running a scan and clicking on the signal line. I will try that later today (its a weekend with great weather here too!).

Not sure but I seem to remember that Bar-Replay is not completely the same as scrolling one bar at a time - not sure how it differs. I will try that for sure.

But using a scan certainly gets us half-way there!

Thanks, Milosz,
have a great weekend!

1 Like

Bar-replay discretionary-trading exercises the mind exactly like real-time intraday trading does. Try it, when the price moves fast you can get just as flustered and fumble your orders as in real trading. Of course, you have to add software that logs/shows your trades as you place them.

I am not interested in what happened before the alert, that is history, I want to train my mind to respond in real-time to developing price patterns. Bar-Replay is perfect for that.

2 Likes

Yes indeed! Thanks.
May be i completely misread ur OP, Apologies.

I use BarReplay (closest to Real Time as you said) most of the times in Analysis window rather than on the Chart window to ,as i said before, catch a AFL' s flaws n fix it by Trial n Error.

How did you record that tiny video?

I use this program LINK to record such videos:

Bar%20replay%202

@Beaver give me half an hour to finish my preliminary version of Chart Bar Replay and I will post the code with description in my next post :slight_smile:

5 Likes

OK, here is the code from the upper video:

_SECTION_BEGIN( "Bar Replay v 1.0" );

// --------   Preliminary version    ------------
// --------   by  Milosz Mazurkiewicz  ----------
/// @link https://forum.amibroker.com/t/alert-driven-bar-replay-auto-syncing-charts-with-buy-sell-signals/6330/17

Minbars = 300;
Step = 1;

if( Status( "action" ) == actionIndicator )
{

    FVBI = Status( "FirstVisibleBarIndex" );
    LVBI = Status( "LastVisibleBarIndex" );
    DT = DateTime();
    Bi = BarIndex();
    BarsVisible = LVBI - FVBI;
    XShift = Param( "XShift", 0, 0, 2560 );
    YShift = Param( "YShift", 0, 0, 1600 );
    SetChartOptions(0, chartShowArrows);

    GfxSetBkMode( 1 );
    GfxGradientRect( XShift, Yshift, XShift + 200, YShift + 100, colorWhite, ColorBlend( colorGrey40, colorWhite, 0.5 ) );
    GfxSetTextColor( colorBlack );
    GfxSelectFont( "Segoe UI", 9, 500 );
    GfxTextOut( "Frequency (sec): ", XShift + 10, YShift + 35 );
    GuiButton( "Start", 1, Xshift + 10, Yshift + 65, 75, 25, 1 );
    GuiEdit( 3, Xshift + 120, Yshift + 35, 40, 20, 1 );

    id = GuiGetEvent( 0, 0 ); event = GuiGetEvent( 0, 1 );
    ButtonState = Nz( StaticVarGet( "ButtonState" ) );

    if( id == 1 && event == 1 ) // Start/Stop button clicked

    {
        if( ButtonState == 0 ) StaticVarSet( "ButtonState", 1 );
        else StaticVarSet( "ButtonState", 0 );
    }

    ButtonState = Nz( StaticVarGet( "ButtonState" ) );

    if( ButtonState )

    {
        if( Status( "RedrawAction" ) )

        {
            FDTStr = DateTimeToStr( DT[FVBI + Step] );
            LDTStr = DateTimeToStr( DT[LVBI + Step] );
            AB = CreateObject( "Broker.Application" );
            AW = AB.ActiveWindow;
            AW.ZoomToRange( FDTStr, LDTStr );
        }

        GuiSetText( "Stop", 1 );
        RequestTimedRefresh( StrToNum( GuiGetText( 3 ) ) );
    }

    else GuiSetText( "Start", 1 );

    MouseButtonPressed = GetCursorMouseButtons();
    ShiftPressed =  GetAsyncKeyState( 16 ) < 0 ;

    if( ShiftPressed AND MouseButtonPressed )

    {
        FirstExecution = Nz( StaticVarGet( "FirstExecution" ), 1 );

        if( FirstExecution )
        {
            LDTBI = FVBI + 20;
            LDTStr = DateTimeToStr( DT[LDTBI] );
            FDTStr = DateTimeToStr( DT[LDTBI - BarsVisible] );
            AB = CreateObject( "Broker.Application" );
            AW = AB.ActiveWindow;
            AW.ZoomToRange( FDTStr, LDTStr );
            StaticVarSet( "FirstExecution", 0 );
            StaticVarSet( "Counter", 0 );
        }
    }

    else StaticVarSet( "FirstExecution", 1 );

    if( ButtonState == 1 )  GfxSetTextColor( colorGreen );
    else GfxSetTextColor( colorRed );

    GfxSelectFont( "Segoe UI", 10, 700 );
    GfxTextOut( "Bar Replay v 1.0 ", XShift + 10, yShift + 5 );

}

Buy = ROC( C, 1 ) >= 1;
Sell = ROC( C, 1 ) < -1;

Plot( C, "Price", colorDefault, styleCandle );
PlotShapes( Buy * shapeDownTriangle, colorGreen, 0, H );
PlotShapes( Sell * shapeDownTriangle, colorRed, 0, H );
SetBarsRequired( MinBars, Step );

_SECTION_END();

What to do:

  1. Apply the code to the Automatic Analysis window and Indicator window (Periodicity in AA window must match chart's interval)

  2. Configure and run the Scan

  3. Double click the line with the signal while holding SHIFT key pressed down to synchronize and scroll the chart.

  4. Click on the chart while holding SHIFT key pressed down to scroll the chart to the starting position.

  5. In the indicator window, enter the frequency of automatic scrolling and to confirm - hit Enter on the keyboard!

  6. Click Start/Stop button to begin auto scrolling.

  7. Click Start/Stop button again to stop (or pause) auto scrolling.

Chart can be scrolled manually or automatically (every n seconds).

As I wrote, this is a preliminary version which needs some further work to function properly in all circumstances. I didn't have time to polish it. It was rather meant to provide some ideas. I wanted it to be as light and simple as possible.

Some issues:

  1. I wanted to automatically synchronize the chart when the user clicks on selected line in the Scan output (making use of the fact, that it can be done by clicking twice while holding SHIFT key pressed down - which can be easily recognized in AFL) but in spite of the fact that the chart is synchronized at this moment and chart's code is executed, AA window is still active (in focus) making completion this one step procedure impossible. For this reason, currently the user has to do it manually by clicking on the chart holding SHIFT key pressed down.

  2. I wanted to use SetBarsRequired(n, FutureBars = 0) at the end of the code! to overwritte the default number of bars in use and force AmiBroker not to see/use any bars after the last candle (exactly like in the original Bar Replay) to make possible testing reliably repainting codes (Zig-Zag for instance), but I only partially succeded in doing that - because this code needs 1 (one) additional future bar to make auto-scrolling possible!

There is room for the improvements and making this code fail proof. I didn't have enough time to do that. I'm open for suggestions, how to improve it and especially deal with those two above issues (however I might be quite busy in the upcoming few days :wink: )

8 Likes

The frequency of auto scrolling can be set from 0.1 second (10 bars per second) if someone likes watching fast slide show :wink:

Bar%20replay%204

3 Likes

Hello Milosz, you are a fast worker :clap:

I had to make a few small changes to make it work on my system with 1 min data. See lines 49 and 74 to keep the index above zero (it gave me an error), and the change of period in lines 94-95.

Otherwise, it works great, except... that the Alert/signal bar is centered in the middle of the chart. The offset changes depending on the number of bars displayed.

In Bar-Replay trading, the alert has to be located at the last bar to prevent having a visual look forward problem. I tried earlier to use a ref() to fix this but that wouldn't work - I probably did something wrong.

Perhaps you have an idea?

_SECTION_BEGIN( "Bar Replay v 1.0" ); 

// >>>>> THIS IS A MODIFIED TEST VERSION <<<<<
// CHANGES IN LINES 49, 74, AND 94-95.

// --------   Preliminary version    ------------
// --------   by  Milosz Mazurkiewicz  ----------
/// @link https://forum.amibroker.com/t/alert-driven-bar-replay-auto-syncing-charts-with-buy-sell-signals/6330/17

Minbars = 300;
Step = 1;

if( Status( "action" ) == actionIndicator )
{

    FVBI = Status( "FirstVisibleBarIndex" );
    LVBI = Status( "LastVisibleBarIndex" );
    DT = DateTime();
    Bi = BarIndex();
    BarsVisible = LVBI - FVBI;
    XShift = Param( "XShift", 0, 0, 2560 );
    YShift = Param( "YShift", 0, 0, 1600 );
    SetChartOptions(0, chartShowArrows);

    GfxSetBkMode( 1 );
    GfxGradientRect( XShift, Yshift, XShift + 200, YShift + 100, colorWhite, ColorBlend( colorGrey40, colorWhite, 0.5 ) );
    GfxSetTextColor( colorBlack );
    GfxSelectFont( "Segoe UI", 9, 500 );
    GfxTextOut( "Frequency (sec): ", XShift + 10, YShift + 35 );
    GuiButton( "Start", 1, Xshift + 10, Yshift + 65, 75, 25, 1 );
    GuiEdit( 3, Xshift + 120, Yshift + 35, 40, 20, 1 );

    id = GuiGetEvent( 0, 0 ); event = GuiGetEvent( 0, 1 );
    ButtonState = Nz( StaticVarGet( "ButtonState" ) );

    if( id == 1 && event == 1 ) // Start/Stop button clicked

    {
        if( ButtonState == 0 ) StaticVarSet( "ButtonState", 1 );
        else StaticVarSet( "ButtonState", 0 );
    }

    ButtonState = Nz( StaticVarGet( "ButtonState" ) );

    if( ButtonState )

    {
        if( Status( "RedrawAction" ) )

        {
            FDTStr = DateTimeToStr( DT[FVBI + Step] );
            b = Max( 0, LVBI + Step );
            LDTStr = DateTimeToStr( DT[b] );
            AB = CreateObject( "Broker.Application" );
            AW = AB.ActiveWindow;
            AW.ZoomToRange( FDTStr, LDTStr );
        }

        GuiSetText( "Stop", 1 );
        RequestTimedRefresh( StrToNum( GuiGetText( 3 ) ) );
    }

    else GuiSetText( "Start", 1 );

    MouseButtonPressed = GetCursorMouseButtons();
    ShiftPressed =  GetAsyncKeyState( 16 ) < 0 ;

    if( ShiftPressed AND MouseButtonPressed )

    {
        FirstExecution = Nz( StaticVarGet( "FirstExecution" ), 1 );

        if( FirstExecution )
        {
            LDTBI = FVBI + 20;
            LDTStr = DateTimeToStr( DT[LDTBI] );
            b = Max( 0, LDTBI - BarsVisible );
            FDTStr = DateTimeToStr( DT[b] );
            AB = CreateObject( "Broker.Application" );
            AW = AB.ActiveWindow;
            AW.ZoomToRange( FDTStr, LDTStr );
            StaticVarSet( "FirstExecution", 0 );
            StaticVarSet( "Counter", 0 );
        }
    }

    else StaticVarSet( "FirstExecution", 1 );

    if( ButtonState == 1 )  GfxSetTextColor( colorGreen );
    else GfxSetTextColor( colorRed );

    GfxSelectFont( "Segoe UI", 10, 700 );
    GfxTextOut( "Bar Replay v 1.0 ", XShift + 10, yShift + 5 );

}

Buy = ROC( C, 10 ) >= 1;
Sell = ROC( C, 10 ) < -1;

Plot( C, "Price", colorDefault, styleCandle );
PlotShapes( Buy * shapeDownTriangle, colorGreen, 0, H );
PlotShapes( Sell * shapeDownTriangle, colorRed, 0, H );
SetBarsRequired( MinBars, Step );

_SECTION_END();
3 Likes

I really didn't have much time. I spent most of the day outdoors enjoying beautiful weather in Warsaw, recharging my batteries for the busy week ahead :slight_smile:

Yes, I'm aware of that. As I wrote - this preliminary version needs some failproof adjustments.

This is worth checking. On my end (after manual sync/adjustment - which is performed by a mouse click while shift button pressed) the signal bar always becomes the last visible bar, no matter what the zoom level is. You can see it on my animated gifs. Maybe it has something to do with Blank bars in the right margin (but it shouldn't) or some other custom settings?

2 Likes