Write trade data to disk - From Quantitative Technical Analysis by Howard Bandy

Hello,

I don't have much of a programming background and was looking for some help with something that I don't think should be very difficult, but is for me. I've been reading Quantitative Technical Analysis by Howard Bandy and am trying to apply the coding in the book relative to AmiBroker. One part that isn't written and is tripping me up is writing 3 values to a disk file.

He gives an example (figure 4.3 in his book) on how to do something similar, but I cannot get it to write the data I would like. In the book he has a simple file on disk which is just Date / Signal / and GainAhead. In the example figure 4.3 it just writes trade number and profit. I haven't been able to figure out how to write Date, Signal (long or flat), and GainAhead (change from current close to next close). Could anyone offer me help with this?

I've been trying to code it on my own with no success. Any similar examples would help. Or if the book is popular, has anyone else done this already and could point me to the code?

Welcome @paulbruns,

If you spend more time searching and generally looking at other posts you can learn lots.

  1. You need to Verify your License
  2. You need to post your own code - even if it is not doing what you want (use Code Blocks <>)
  3. Lots of examples in the Manual and on the website.

Come back and show us your work, and there are lots of very helpful users on this forum that can help guide you to a solution.

You can find an example that includes writing out the date to a file here: AmiBroker Knowledge Base » How to export quotes to separate text files per symbol

Also, make sure you verify your license when using the forum.

Hello @snoopy.pa30 and @MacAllan, Thank you so much for the replies!

I'm limited to about one day a week to work on learning programming, so I'm excited to work on this today. I did spend a while trying to search the forum last week and see if I could find anything similar prior to posting. Last week I got far enough to create a text file output, but it doesn't have the right data that outputs. I have added this to my systems to make the file:

// Custom Backtester begins here
SetCustomBacktestProc( "" );

if ( Status( "action" ) == actionPortfolio )
{
    bo = GetBacktesterObject();
    bo.Backtest( 1 );
    path = "ShadowTradesDPO.csv";
    fh = fopen( path, "w" );

    if ( fh )
    {
        trnum = 0;

        for ( trade = bo.GetFirstTrade(); trade;
                trade = bo.GetNextTrade() )
        {
            trnum = trnum + 1;
            trp = trade.GetPercentProfit();
            outstr =
                StrFormat( "Trade Number %5.0f PctGain %3.6f\n",
                           trnum, trp );
            fputs( outstr, fh );
        }

        outstr = StrFormat( "Number of trades %5.0f \n",

                            trnum );
        fputs( outstr, fh );
        fclose( fh );
    }
    else
    {
        Error( "Error -- file cannot be opened" );
    }

//bo.ListTrades();
}

I'll spend today working on this and checking out that example and post back with my progress later!

I've been able to create a text file with the date, which is great! However I'm struggling with signal and gain ahead.

Per the book:

The signal field has two values:
1 - beLong
-1 - beFlat

GainAhead is the change in price of the primary data series from the current close to the next close. A gain of 1% is 0.01.

I've been trying to learn by doing a lot of experimenting, so there are lots of things commented out. I wonder if my issue is that where I am working has no data? Am I doing something wrong in that this is before the trade rules? I'm not sure how it will compute the gain or signal? My current output has 0 for open/high/low/close.

// Custom Backtester begins here
SetCustomBacktestProc( "" );

if ( Status( "action" ) == actionPortfolio )
{
    bo = GetBacktesterObject();
    bo.Backtest( 1 );
    path = "write data tester2.csv";
    fh = fopen( path, "w" );

    if ( fh )
    {
        trnum = 0;
        dt = DateTime();
        // writes the header
        fputs("date,signal,gainahead\n", fh );

        for ( trade = bo.GetFirstTrade(); trade;
                trade = bo.GetNextTrade() )
        {
            trnum = trnum + 1;
            
            //original
            //trp = trade.GetPercentProfit();
            //outstr =
            //    StrFormat( "Trade Number %5.0f PctGain %3.6f\n",
            //               trnum, trp );
            //fputs( outstr, fh );
            
            // using https://www.amibroker.com/kb/2014/11/14/how-to-export-quotes-to-separate-text-files-per-symbol/
            //fputs( DateTimeToStr (dt [i] ), fh );  //doesn't work because i not initialized
            fputs( DateTimeToStr (dt [trnum] ), fh );  //works but all on one line, no return?  
            //outstr = StrFormat( "%g,%g,%g\n", dt [trnum], dt [trnum], dt [trnum] );
            //fputs (outstr, fh);  // works, but displays values oddly
            //outstr = StrFormat ("%g,%g\n", O[trnum], C[trnum]); works, but displays zeros
            //fputs (outstr, fh );
            
            //write quotations and go to the next line
			qs = StrFormat( "%g,%g,%g,%g,%g\n", O[ trnum ], H[ trnum ], L[ trnum ], C[ trnum ], V[ trnum ] );
			fputs( qs, fh );
            // this works, but all data is zero
            
            
            
            // using https://www.amibroker.com/kb/2014/12/22/text-output-in-explorations/
            //Buy = Cross( MACD(), Signal() );
			//Sell = Cross( Signal(), MACD() );
			//Filter = Buy OR Sell;
			//AddColumn( IIf( Buy, 'B', 'S' ), "Signal", formatChar );  //not helpful
            


            
        }

        outstr = StrFormat( "Number of trades %5.0f \n",

                            trnum );
        fputs( outstr, fh );
        fclose( fh );
    }
    else
    {
        Error( "Error -- file cannot be opened" );
    }

//bo.ListTrades();
}

// trading system
Buy = DayOfWeek() == 1;
Sell = DayOfWeek() == 5;





///////////////////////////// end /////////////////


After a while working on the above I've generated the following code:

// Custom Backtester begins here
SetCustomBacktestProc( "" );

if ( Status( "action" ) == actionPortfolio )
{
    bo = GetBacktesterObject();
    bo.Backtest( 1 );
    path = "write data tester2.csv";
    fh = fopen( path, "w" );

    if ( fh )
    {
        trnum = 0;
        dt = DateTime();
        // writes the header
        fputs("date,signal,gainahead\n", fh );

        for ( trade = bo.GetFirstTrade(); trade;
                trade = bo.GetNextTrade() )
        {
            trnum = trnum + 1;
            
            //original
            //trp = trade.GetPercentProfit();
            //outstr =
            //    StrFormat( "Trade Number %5.0f PctGain %3.6f\n",
            //               trnum, trp );
            //fputs( outstr, fh );
            
            // using https://www.amibroker.com/kb/2014/11/14/how-to-export-quotes-to-separate-text-files-per-symbol/
            //fputs( DateTimeToStr (dt [i] ), fh );  //doesn't work because i not initialized
            fputs( DateTimeToStr (dt [trnum] ), fh );  //works but all on one line, no return?  
            //outstr = StrFormat( "%g,%g,%g\n", dt [trnum], dt [trnum], dt [trnum] );
            //fputs (outstr, fh);  // works, but displays values oddly
            //outstr = StrFormat ("%g,%g\n", O[trnum], C[trnum]); works, but displays zeros
            //fputs (outstr, fh );
            
            //write quotations and go to the next line
			//qs = StrFormat( "%g,%g,%g,%g,%g\n", O[ trnum ], H[ trnum ], L[ trnum ], C[ trnum ], V[ trnum ] );
			//fputs( qs, fh );
            // this works, but all data is zero
            
            //trp = trade.GetNextSignal();  // GetNextSignal does not exist
            trp1 = trade.EntryPrice();  // this is helpful
            trp2 = trade.ExitPrice();  // also helpful
            //trp = trade.FindSignal();  // FindSignal does not exist
            //trp = trade.FindOpenPos();  // FindOpenPos does not exist
            trp3 = trade.GetEntryValue ();  // not useful
            //trp = trade.IsEntry(); // IsEntry does not exist
            //trp = trade.IsExit();  // is Exit does not exist
            trp4 = trade.IsLong();  // helpful?  always -1 (there are two instances, this is the first)
            //trp = trade.IsLong();  // same as above, but second instance
            trp5 = trade.IsOpen();  // helpful
            trp6 = trade.Shares ();  // changes, shows that system is running
            trp7 = trade.GetPercentProfit ();
                        
            outstr =
            StrFormat( "placeholder for signal %5.0f entryPrice %5.5f exitPrice %5.5f entryValue %5.5f IsLong %5.5f IsOpen %5.5f Shares %5.5f GetPercentProfit %5.5f\n",
                        trnum, trp1, trp2, trp3, trp4, trp5, trp6, trp7 );
            fputs (outstr, fh);
            
            // using https://www.amibroker.com/kb/2014/12/22/text-output-in-explorations/
            //Buy = Cross( MACD(), Signal() );
			//Sell = Cross( Signal(), MACD() );
			//Filter = Buy OR Sell;
			//AddColumn( IIf( Buy, 'B', 'S' ), "Signal", formatChar );  //not helpful
            


            
        }

        outstr = StrFormat( "Number of trades %5.0f \n",

                            trnum );
        fputs( outstr, fh );
        fclose( fh );
    }
    else
    {
        Error( "Error -- file cannot be opened" );
    }

//bo.ListTrades();
}

// trading system
Buy = DayOfWeek() == 1;
Sell = DayOfWeek() == 5;





///////////////////////////// end /////////////////

and it gives me this output

image

I think that there is a flaw this though. The above code is working off of trade numbers, and I'm looking for a daily output. I started over trying to work day by day.

// Custom Backtester begins here
SetCustomBacktestProc( "" );

if ( Status( "action" ) == actionPortfolio )
{
    bo = GetBacktesterObject();
    bo.Backtest( 1 );
    path = "write data tester3.csv";
    fh = fopen( path, "w" );

    if ( fh )
    {

	dt = DateTime();

    // write header line
    fputs( "Date/Time,Open,High,Low,Close,Volume\n", fh );

    // iterate through all the bars
    for ( i = 0; i < BarCount; i++ )


        {
       
		// write ticker name
        //fputs( Name() + "," , fh );

        // write date/time information
        fputs( DateTimeToStr( dt[ i ] ) + ",", fh );

        //write quotations and go to the next line
        qs = StrFormat( "%g,%g,%g,%g,%g\n", O[ i ], H[ i ], L[ i ], C[ i ], V[ i ] );
        fputs( qs, fh );
        
             
        }


        fclose( fh );
    }
    else
    {
        Error( "Error -- file cannot be opened" );
    }

//bo.ListTrades();
}

// trading system
Buy = DayOfWeek() == 1;
Sell = DayOfWeek() == 5;





///////////////////////////// end /////////////////

This is now walking me through an output day by day, so I think I've made progress there. However, I'm no closer to generating a signal or gainAhead. In fact I can't figure out how to get any data or figures out of this to work with. So I think I've regressed in that nature.

Here is my current output:

image

I've had a bit of a breakthrough with this. I can now create date / Signal / gain/Ahead in the Explore tab.

I'm having trouble with two parts. First, I am not sure how to actually write the code for signal. I am still working on that part. Second, (apologies if this is an easy question, I've been busy working on my first issue and haven't searched yet) is it possible to export the Explore tab to a CSV, and if so how?

image

// trading system
Buy = DayOfWeek() == 1;
Sell = DayOfWeek() == 5;
GainAhead = (Ref(C,1) - C) / C;
mysignal = 1;

// use Explore to create a table
Filter = 1;
AddColumn (mysignal, "Signal", 10.6);
AddColumn (GainAhead, "GainbloAhead", 10.6);
//AddColumn (Signal(), "Signal", 10.0);

Yes. From the main menu select File / "Export HTML / CSV"

image

Thanks @MacAllan !

That was an easy one, I shouldn't have asked for help but I was too engrossed in things.

I've made some good progress, but there are two questions that perhaps someone could answer for me:

First - how do I code to check if I have an open position? I've tried coding a few ways and searched around a bit (found lots of interesting things, but not what I needed). Is there some way to test if I am long or short, or quantity is greater than one? I've tried many tests with the signal variables below, but none do what I need. I'm just looking to have an output of 1 when I have an open position, and -1 otherwise.

Second, is there a way to write this directly to a file instead of to explore and then to export it? I tried the backtester which I was able to get to write a file, but couldn't get it to display the info I needed. I'm able to get Explore to show (most) of what I need, so this is a smaller point.

Here is my current code.

// trading system
Buy = DayOfWeek() == 2;
Sell = DayOfWeek() == 4;

GainAhead = (Ref(C,1) - C) / C;

EntrySignal = dayofweek () ==2;
ExitSignal = DayOfWeek () == 4;

SecondSignal = PositionSize > 1;
FirstSignal = 0;
FirstSignal = Firstsignal + entrysignal - exitsignal;
ThirdSignal = entrysignal - exitsignal;
FourthSignal = IIf (Buy ==1, 1, 0);
FifthSignal = IIf (Sell ==1, 1, 0);
SixthSignal = 0;
SixthSignal = SixthSignal + fourthsignal - fifthsignal; 
SeventhSignal = IIf (PositionSize >1, 1, -1);
EighthSignal = IIf (OpenInt >1, 1, -1);
ThirteenthSignal = Hold(ThirdSignal, 3);

//mysignal = Buy();
//mysignal = 0;
//if Buy = DayOfWeek() == 1;
//mysignal = 1;
	//else
	//mysignal = 0;
	
//for (j = 0; j < BarCount; j++)
{
//if (Buy() ;
//mysignal = 1;
//else
//mysignal = 0;	
}

	
//for (j = 0; j < BarCount; j++)
{
//iif (Buy==1, TenthSignal=1, TenthSignal=0) ;
//Tenthsignal = 1;
//else
//iif (Sell==1);
//Tenthsignal = -1;	
}

//for (j = 0; j < BarCount; j++)
{
 //if( BarsInTrade > 0 ) BarsInTrade ++;
// else
 //if( Buy[ j ] ) BarsInTrade = 1;
//if (BarsInTrade > 0) EleventhSignal =1, -1
}

TwelvthSignal = ExRem (Buy, Sell);


// use Explore to create a table
Filter = 1;

AddColumn (GainAhead, "GainAhead", 10.6);
AddColumn (entrysignal, "EntrySignal", 1.0, colorDefault, IIf ( Buy, colorlime, colorDefault) );
AddColumn (ExitSignal, "ExitSignal", 1.0, colorDefault, IIf (Sell, colorRed, colorDefault) );
AddColumn (Firstsignal, "FirstSignal", 10.0);
AddColumn (SecondSignal, "SecondSignal", 10.0);
AddColumn (ThirdSignal, "ThirdSignal", 10.0);
//AddColumn( Buy, "Buy Signal", 1.0, colorDefault, iif( Buy, colorLime, colorDefault ) );
//AddColumn( ValueWhen( Buy, BuyPrice, 1 ), "BuyPrice" );
AddColumn (FourthSignal, "FourthSignal", 1.0);
AddColumn (FifthSignal, "fifthSignal", 1.0);
AddColumn (SixthSignal, "SixthSignal", 1.0);
AddColumn (SeventhSignal, "SeventhSignal", 1.0);
AddColumn (EighthSignal, "EighthSignal", 1.0);
//AddColumn (TenthSignal, "TenthSignal", 1.0);
//AddColumn (ElventhSignal, "EleventhSignal", 1.0);
AddColumn (TwelvthSignal, "TwelvthSignal", 1.0);
AddColumn (ThirteenthSignal, "ThirteenthSignal", 1.0);
//AddColumn (Signal(), "Signal", 10.0);



///////////////////////////// end /////////////////

Thanks for the help guys!

You can use Flip to identify bars between two separate events.

DoW = DayOfWeek();

Buy 	= DoW == 2;
Sell 	= DoW == 4;

Short 	= DoW == 5;
Cover  	= DoW == 1;

InLong 	= Flip(Buy, Sell);
InShort = -Flip(Short, Cover);

Filter = 1;
AddColumn(InLong, "InLong", 1);
AddColumn(InShort, "InShort", 1);

image

You can use Batch to automate the Explore and export to file.

1 Like

Awesome!

I walked through the Users guide to look at different functions but I missed those two. Next week I'll play with Flip and Batch!

Thanks again for all of your help

1 Like

Flip was just what I was looking for. I was able to create the table I needed. I haven't looked at Batch much, but I did realize that I didn't have the most recent version and updated. When I have some more time I'll research (I think I also need to learn about projects).

One of the neat things I learned was to use Explore to check if the code is doing what you like. I left the Entry/Exit in there as a confirmation.

image

// trading system
Buy = DayOfWeek() == 2;
Sell = DayOfWeek() == 4;

GainAhead = (Ref(C,1) - C) / C;

EntrySignal = dayofweek () ==2;
ExitSignal = DayOfWeek () == 4;


mySignal = IIf(Flip(Buy, Sell), 1, -1);


// use Explore to create a table
Filter = 1;

AddColumn (mySignal, "Signal", 1.0);
AddColumn (GainAhead, "GainAhead", 10.6);
AddColumn (entrysignal, "EntrySignal", 1.0, colorDefault, IIf ( Buy, colorlime, colorDefault) );
AddColumn (ExitSignal, "ExitSignal", 1.0, colorDefault, IIf (Sell, colorRed, colorDefault) );





///////////////////////////// end /////////////////
1 Like

I've run into a problem. How can I incorporate stop types into the logic?

For example if I added a profit target, that is causing the exit instead of sell logic, so the signal does not flip. I've been able to code this correctly for hold days, but I'm struggling with profit target.

ExitSignal = BarsSince ( Short ) >= HoldDays OR Cross (L, ProfitTarget);

Assigning a variable HoldDays makes that part work. But the Cross part is not going to work. It doesn't seem that you can put ApplyStop in a variable like this

//Cover = BarsSince ( Short ) >= HoldDays OR ApplyStop (stopTypeProfit, stopModePercent, ProfitTarget );

Would someone have an idea on how I could put the same logic as the ApplyStop into a variable for ExitSignal?

// trading system
HoldDays = 2;
ProfitTarget = 0.05;

Buy = DayOfWeek() == 2;
Sell = BarsSince (Buy) >= HoldDays;


ApplyStop (stopTypeProfit, stopModePercent, profitTarget);

EntrySignal = dayofweek () ==2;
//Including a Profit Target stop is not recognized by the Exit Signal
ExitSignal = BarsSince (Buy) >= HoldDays OR ApplyStop (stopTypeProfit, stopModePercent, profitTarget);

// use Explore to create the gainAhead table for dynamic position sizing
gainAhead = (Ref(C,1) - C) / C;
mySignal = IIf(Flip(Buy, Sell), 1, -1);
// use Explore to create a table
Filter = 1;

AddColumn (mySignal, "signal", 1.0);
AddColumn (gainAhead, "gainAhead", 10.6);
AddColumn (entrysignal, "EntrySignal", 1.0, colorDefault, IIf ( Buy, colorlime, colorDefault) );
AddColumn (ExitSignal, "ExitSignal", 1.0, colorDefault, IIf (Sell, colorRed, colorDefault) );





///////////////////////////// end /////////////////