Allow Multiple Entries and Exits using histoical trades from CSV

I tweaked the formula in this knowledge base How generate backtest statistics from a list of historical trades stored in a file
I made it work to most of my Trades however i realized that it is only generating the first entry(Buy/Short) and first exit (Sell/Cover).

Is it possible to generate the series of entries and series of exits? If so hope you can guide me achieve that.

Here is the CSV where the data is being taken from:

Symbol,Trade,Datetime,Price,Shares,Time
AMD,Buy,2023-12-12,133.15,30,9:35:10
AMD,Buy,2023-12-12,133.5,40,9:36:57
AMD,Sell,2023-12-12,133.9,35,9:37:58
AMD,Sell,2023-12-12,134.13,28,9:40:11
AMD,Sell,2023-12-12,133.51,7,9:41:47

AMD,Buy,2023-12-12,133.35,30,9:44:39
AMD,Sell,2023-12-12,133.73,24,9:50:26
AMD,Sell,2023-12-12,134.09,6,9:51:34
AMD,Buy,2023-12-14,139.73,30,9:33:03
AMD,Sell,2023-12-14,138.68,30,9:35:03

Only the trades (in Bold) above were generated and did not include the other lines. Here's what the backtesting report looked like

Here's the my formula (I have included time and changed the Datetime):

file = "G:\\My Drive\\AmiBroker\\AFL\\Amibroker-Journal-trades.csv"; // change this to real location of your data file
//DATE

yr = Year();
mo = Month();
dy = day();
//TIME
hh = Hour();
mm = Minute();




// Initialize variables
Buy = Sell = Short = Cover = possize = 0;
//
fh = fopen( file, "r" );
//
if( fh )
 {
     while( ! feof( fh ) )
     {
         line = fgets( fh );
         // get the ticker symbol from the file
         sym = StrExtract( line, 0 );
         // if ticker matches current symbol
         if ( Name() == sym )
         {
             // extract data from line of text
             trade = StrExtract( line, 1 );
             mYear = StrToNum( StrExtract(StrExtract(line, 2),0,seperator='-'));
             mMonth = StrToNum( StrExtract(StrExtract(line, 2),1,seperator='-')); 
             mDay = StrToNum( StrExtract(StrExtract(line, 2),2,seperator='-')); 
             trade_datetime = NumToStr(mYear)+"-"+NumToStr(mMonth)+"-"+NumToStr(mDay);
             price = StrToNum( StrExtract( line, 3 ) );
             shares = StrToNum( StrExtract( line, 4 ) );
             mHour = StrToNum( StrExtract(StrExtract(line, 5),0,seperator=':'));
             mMin = StrToNum( StrExtract(StrExtract(line, 5),1,seperator=':'));
            
             
             //BUY
             if ( trade == "Buy" )
             {
               
                 newbuy = yr==mYear AND mo==mMonth AND dy == mDay AND hh==mHour AND mm==mMin;
                 Buy = Buy OR newbuy; // combine previous buy signals with new
                 BuyPrice = IIf( newbuy, price, BuyPrice );
                 possize = IIf( newbuy, shares, possize );
               
                 
             }
             
             //SELL
             if ( trade == "Sell" )
             {
                 newsell = yr==mYear AND mo==mMonth AND dy == mDay AND hh==mHour AND mm==mMin;
                 Sell = Sell OR newsell; // combine previous sell signals with new
                 SellPrice = IIf( newsell, price, SellPrice );
                 possize = IIf( newsell, shares, possize );
                 
             
                 
             }
              //SHORT
             if ( trade == "Short" )
             {
                 newshort = yr==mYear AND mo==mMonth AND dy == mDay AND hh==mHour AND mm==mMin;
                 Short = Short OR newshort; // combine previous short signals with new
                 ShortPrice = IIf( newshort, price, ShortPrice );
                 possize = IIf( newshort, shares, possize );
                 
             
                 
             }
              //COVER
             if ( trade == "Cover" )
             {
                 newcover = yr==mYear AND mo==mMonth AND dy == mDay AND hh==mHour AND mm==mMin;
                 Cover = Cover OR newcover; // combine previous cover signals with new
                 CoverPrice = IIf( newcover, price, CoverPrice );
                 possize = IIf( newcover, shares, possize );
                 
             
                 
             }
         }
     }
     //
     fclose( fh );
 }
 else
 {
     Error( "ERROR: file can not be open" );
 }
//
SetPositionSize( possize, spsShares );

Hope you can help out. Thanks in Advance

@arcee, try adding to your code:

SetBacktestMode(backtestRegularRawMulti); // to allow multiple open positions on the same symbol
SetOption( "MaxOpenPositions", 20 ); //  set it to a sensible number as per you needs 
SetOption("InitialEquity", 100000 ); // set up enough initial capital to purchase all the simultaneous transactions including commissions

I suggest reviewing the documentation for the first suggestion:
https://www.amibroker.com/guide/afl/setbacktestmode.html

And if the backtest still does not report all the transactions I suggest you use the "detailed log" report to verify the reasons for the possible failure to execute certain signals.

1 Like

Thanks for the help @beppe It did show all the trades.
I also reviewed the documentation for SetBacktestMode( mode ) and tried all the modes available.

There's just one thing that I want to clarify.

in this set of data (I numbered the rows for easy reference):

row Symbol,Trade,Datetime,Price,Shares,Time
row 1 AMD,Buy,2023-12-12,133.15,30,9:35:10
row 2 AMD,Buy,2023-12-12,133.5,40,9:36:57
row 3 AMD,Sell,2023-12-12,133.9,35,9:37:58
row 4 AMD,Sell,2023-12-12,134.13,28,9:40:11
row 5 AMD,Sell,2023-12-12,133.51,7,9:41:47

It's not really executing the exact order of trades.
What it did was
a) execute (entry) row 1 and then execute (exit) row 3
b) execute (entry) row 2 and then execute (exit) row 3 again
as shown here

I'm not sure if I'm missing something but it seems that the backtester in this case can only do 1 entry and 1 exit? or is it possible to set it to work according to the order of our data in the csv?

Looking at your trade file it seems that you may further work on your formula to handle scaling out orders too.

Pyramiding (scaling in/out) and mutliple currencies in the portfolio backtester

But I think that you also need to modify and add some extra lines to close/scale out each order properly:

row 1 AMD,Buy,2023-12-12,133.15,30,9:35:10   // Order 1 - Buy 30
row 2 AMD,Buy,2023-12-12,133.5,40,9:36:57    // Order 2 - Buy 40
row 3 AMD,Sell,2023-12-12,133.9,35,9:37:58   // Order 1 - Sell 30 - Closing it 

row x AMD,Sell,2023-12-12,133.9,35,9:37:58   // Order 2 - Scale out 5 - Remain 35

row 4 AMD,Sell,2023-12-12,134.13,28,9:40:11  // Order 2 - Scale out 28 - Remain 7
row 5 AMD,Sell,2023-12-12,133.51,7,9:41:47   // Order 2 - Sell 7 - Closing it 
1 Like

@arcee , actually I forgot to modify the extra row to indicate the number of shares to scale out and also changing some "Sell" to "ScaleOut", a new "trade" command that you need to implement in your formula. Something like this:

AMD,Buy,2023-12-12,133.15,30,9:35:10
AMD,Buy,2023-12-12,133.5,40,9:36:57
AMD,Sell,2023-12-12,133.9,30,9:37:58 
AMD,ScaleOut,2023-12-12,133.9,5,9:37:58
AMD,ScaleOut,2023-12-12,134.13,28,9:40:11
AMD,Sell,2023-12-12,133.51,7,9:41:47
1 Like

@arcee, the above is just an example.

Another possible way to handle this, is to consider the second line a "ScaleIn" (to be implemented further) to a single order and all other lines are "ScaleOut" until the final Sell.
In this case the extra row is not necessary.

As a consequence in the trade report you will only see only 1 order with the ScaleIn/Out column with values ​​other than 0/0.

To verify that everything is as desired you will then need to consult the Detailed log to see the individual ScaleIn and ScaleOut operations.

Thank you for taking the time to look into my querries @beppe . Thank you as well for the idea about scale in/out. I will work into my data as well as with my formula. Will give an update as soon as I have made the modifications. :smiley:

This topic was automatically closed 100 days after the last reply. New replies are no longer allowed.