[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [amibroker] Re: Support Issues



PureBytes Links

Trading Reference Links



Hello,
 
You received the answer via support channel.
 
With regards to UpdateStats it is documented quite clearly
 
Quote from docs:
"UpdateStats( long Bar, long TimeInsideBar )
 
Low-level method that updates equity, exposure, trade excursions (for MAE/MFE calculations) and other internal variables required for correct calculation of statistics. You must NOT use this function in high-level and mid-level approaches. TimeInsideBar parameter specifies intraday time position.
 
TimeInsideBar = 0 means opening of the bar,
TimeInsideBar = 1 means middle of the bar,
TimeInsideBar = 2 means end of bar.
 
As certain internal calculations depend on end-of-bar calculations, this method must be called once and only once with TimeInsideBar parameter set to 2 at the end of processing of every bar inside in your custom backtesting loop. May be called zero or more times for every bar inside backtesting loop with TimeInsideBar parameter set to 0 (zero) or 1."
 
Whenever you need to read/use any stats (including portfolio equity) on open/in the middle/end of bar you should call UpdateStats with corresponding value. That's all. 
 
The same goes with HandleStops.
Quote from docs:
"HandleStops( long Bar )
 
This low-level method handles automatic stops (applystops). This method MUST NOT be used in high-level and mid-level approaches. In low-level mode you should call this method once for each bar inside trading loop."
 
Low-level custom backtester interface is solely for advanced programmers who want to implement/experiment with *their own* backtest methodologies completely *different* than built-in one,
and comes without hand-holding.

Best regards,
Tomasz Janeczko
amibroker.com
----- Original Message -----
From: Mike
Sent: Monday, September 21, 2009 1:40 PM
Subject: [amibroker] Re: Support Issues

Unfortunately, no. None of my questions are answered by this otherwise excellent document (which I have already read many times).

Perhaps my questions were not clearly expressed in the help request. But basically I want to know:

  1. When should we use bo.UpdateStats(bar, 0)
  2. When should we use bo.UpdateStats(bar, 1)
  3. When should we use bo.UpdateStats(bar, 2)
  4. When should we use bo.HandleStops(bar)

The author of the document that you pointed to seemed equally confused. When describing usage of UpdateStats he says:

"The AmiBroker help is a little vague on how the TimeInsideBar parameter works"

He then goes on to say:

"why it would be called with the value set to zero or more than once, I'm not sure."

In other words, he had the exact same questions that I have now. Further, after much experimentation, I must question his conclusions on when and where to use HandleStops(), at least as it applies to more recent versions of AmiBroker.

I have put togeather a sample Optimization, below, for a "percent of equity" position sizing that runs once for each of:

  1. default high level AmiBroker backtester
  2. low level backtester template described in the UKB document that you pointed to
  3. low level backtester using my own best guess at how these calls should be made.

If you (or anyone else) run it, you will see that my own best guess appears to match the default AmiBroker behavior. The UKB template (as I've understood it) does not match at all. I would like to get confirmation (or correction) that my conclusions are accurate. My conclusions are spelled out as comments in the code.

For the purposes of this example, I am running a Long only strategy, using AmiBroker version 5.26.5 beta, Norgate Premium Data for the period Jan 1/08 - Dec 31/08 on a watchlist containing:

  • AAPL
  • IBM
  • ORCL
  • MSFT

I am exagerating the position size to force scenarios where we run out of cash. The script can also be Backtested with default optimization argument set to 3 in order to see _TRACE statements in an AA Window "Detail Log" style report of the sfclimbers trades.

Here is the code:

// Simplify the example by disabling most of the variables that effect
// position size when expressed as a percentage of equity.


SetOption("AccountMargin", 100
);
SetOption("AllowPositionShrinking", false
);
SetOption("CommissionMode", 2
);
SetOption("CommissionAmount", 0
);
SetOption("InterestRate", 0
);
SetOption("MinShares", 1
);
SetOption("MinPosValue", 0
);

// These two options have a direct impact on low level backtest,

// far beyond what was covered in the otherwise excellent UKB document.

// Run this optimization once for each of the 4 combinations of these two

// options using a watchlist of AAPL, IBM, ORCL, MSFT from 1/1/08 - 12/31/08.


SetOption("UsePrevBarEquityForPosSizing", true
);
SetOption("ActivateStopsImmediately", true
);

// Simple random entry followed by N-bar stop.


SetOption("InitialEquity", 500000.00
);
SetTradeDelays(0, 0, 0, 0
);
SetPositionSize(33, spsPercentOfEquity
);

Buy = Random(13000) > 0.5
;
BuyPrice = Open
;
Sell = 0
;
ApplyStop(stopTypeNBar, stopModeBars, 3, 0
);

// Use optimizer to generate output for each of default AB, UKB and

// sfclimbers speculation. At a minimum it will illustrate that the

// UKB article is incomplete and/or out of date. Whether or not the
// sfclimbers conclusions are correct is the subject of this help request!


custom =
Optimize("Custom", 3, 1, 3, 1
);
SetCustomBacktestProc(""
);

if (Status("action") == actionPortfolio
) {
   maxPosition =
0.33;   // Must match call to SetPositionSize above

   marginMultiplier =
100 / GetOption("AccountMargin"
);
   usePreviousBar =
GetOption("UsePrevBarEquityForPosSizing"
);
   activateStopsImmediately =
GetOption("ActivateStopsImmediately"
);
   dates =
DateTime
();

   bo =
getBacktesterObject
();

   
switch
(custom) {
      
case 1
: {
         
// Default AmiBroker behavior

         bo.Backtest();
         
break
;
      }

      
case 2
: {
         
// User knowledge base template behavior

         bo.PreProcess();

         
for (bar = 0; bar < BarCount
; bar++)   {
            size = bo.Equity * maxPosition;
            quit =
0
;

            
for
(sig = bo.GetFirstSignal(bar); sig; sig = bo.GetNextSignal(bar)) {
               
if
(sig.IsEntry()) {
                  lotSize =
int((size / sig.Price) / RoundLotSize) * RoundLotSize
;

                  
if (bo.Cash >= ((lotSize * sig.Price) / marginMultiplier) && quit == 0
) {
                     sig.PosSize = -
2000
- lotSize;
                  }
else if (bo.Cash > 0 && quit == 0
) {
                     sig.PosSize =
0;   // Insufficient funds. Cancel signal.

                     quit =
1
;
                  }
else
{
                     sig.PosSize =
0;   // Already hit insufficient funds. Cancel remaining signals.

                     quit++;
                  }

                  
if (sig.PosSize < 0
) {
                     bo.EnterTrade(bar, sig.Symbol, sig.IsLong(), sig.Price, sig.PosSize);
                  }
               }
else if
(sig.IsExit()) {
                  bo.ExitTrade(bar, sig.Symbol, sig.Price);
               }
            }

            bo.HandleStops(bar);
            bo.UpdateStats(bar,
1
);
            bo.UpdateStats(bar,
2
);
         }

         bo.PostProcess();
      }

      
case 3
: {
         
// sfclimbers behavior

         bo.PreProcess();

         
for (bar = 0; bar < BarCount
; bar++) {
            
_TRACE(DateTimeToStr(dates[bar]) + "\t"
+ bar);

            
/*
             * Conclusion 1:
               * Must consult UsePrevBarEquityForPosSizingand call updateStats(bar, 0)
             * to get initial equity.
             */

            
if
(!usePreviousBar) {
               bo.updateStats(bar,
0);   // Update to bar open.

               baseEquity = bo.Equity;   
// Then calculate equity

            }
else
{
               baseEquity = bo.Equity;   
// Calculate equity

               bo.updateStats(bar,
0);   // Then update to bar open.

            }

            size = baseEquity * maxPosition;
            
_TRACE("\tBase Equity: " + baseEquity + ", Opening Equity: " + bo.Equity + ", Pct. of Base: " + size + ", Starting Cash: "
+ bo.Cash);
   
            
/*
             * Conclusion 2:
             * Must process regular exit signals at start of each bar, before new entries.
             *
             * Conclusion 3:
             * Must consult ActivateStopsImmediately to determine whether to additionally
             * process stops at start of each bar, before new entries.
             */

            
for
(sig = bo.GetFirstSignal(bar); sig; sig = bo.GetNextSignal(bar)) {
                
if (sig.IsExit() && (sig.Reason == 1
|| !activateStopsImmediately)) {
                  
if
(pos = bo.FindOpenPos(sig.Symbol)) {
                     msg =
"\tExit (" + sig.Reason + ") " + WriteIf(sig.IsLong(), "Long: ", "Short: ") + sig.Symbol + ", Shares: "
+ pos.Shares;

                     
/*
                      * Conclusion 4:
                      * Must call updateStats(bar, 1) after each trade entry or exit in order
                      * to have up to date Equity and Cash data.
                      */

                     bo.ExitTrade(bar, sig.Symbol, sig.Price);
                     bo.UpdateStats(bar,
1
);
                     
_TRACE(msg + ", Cash Balance: "
+ bo.Cash);
                  }
               }
            }

            quit =
0
;

            
for
(sig = bo.GetFirstSignal(bar); sig; sig = bo.GetNextSignal(bar)) {
               
if
(sig.IsEntry()) {
                  lotSize =
int((size / sig.Price) / RoundLotSize) * RoundLotSize
;

                  
if (bo.Cash >= ((lotSize * sig.Price) / marginMultiplier) && quit == 0
) {
                     sig.PosSize = -
2000
- lotSize;
                  }
else if (bo.Cash > 0 && quit == 0
) {
                     sig.PosSize =
0;   // Insufficient funds. Cancel signal.

                     quit =
1
;
                  }
else
{
                     sig.PosSize =
0;   // Already hit insufficient funds. Cancel remaining signals.

                     quit++;
                  }

                  
if (sig.PosSize < 0
) {
                     msg =
"\tEnter " + WriteIf(sig.IsLong(), "Long: ", "Short: ") + sig.Symbol + ", Price: " + sig.Price + ", Shares: " + abs(sig.PosSize + 2000) + " Margin Loan: " + (abs(sig.PosSize + 2000) * sig.Price) * (1 - (1
/ marginMultiplier));
                     result = bo.EnterTrade(bar, sig.Symbol, sig.IsLong(), sig.Price, sig.PosSize);
                     bo.UpdateStats(bar,
1
);
                     
_TRACE(msg + ", Cash Balance: " + bo.Cash + " Result: "
+ result);
                  }
else if (quit == 1
) {
                     
_TRACE("\t" + sig.Symbol + " not entered because of insufficient funds"
);
                  }
               }
            }

            
/*
             * Conclusion 5:
             * Must consult ActivateStopsImmediately to determine whether to process stops
             * at end of each bar, after new entries.
             */

            
if
(activateStopsImmediately) {
               
for
(sig = bo.GetFirstSignal(bar); sig; sig = bo.GetNextSignal(bar)) {
                   
if (sig.IsExit() && sig.Reason != 1
) {
                     
if
(pos = bo.FindOpenPos(sig.Symbol)) {
                        msg =
"\tExit (" + sig.Reason + ") " + WriteIf(sig.IsLong(), "Long: ", "Short: ") + sig.Symbol + ", Shares: "
+ pos.Shares;

                        bo.ExitTrade(bar, sig.Symbol, sig.Price);
                        bo.UpdateStats(bar,
1);   // Update running stats after each trade.

                        
_TRACE(msg + ", Cash Balance: "
+ bo.Cash);
                     }
                  }
               }
            }

            
/*
             * Conclusion 6:
             * HandleStops is obsolete and should no longer be called.
             */

            msg =
", Ending Cash: "
+ bo.Cash;
            bo.UpdateStats(bar,
2
);
            
_TRACE("\tEnding Equity: "
+ bo.Equity + msg);
         }

         bo.PostProcess();
         
break
;
      }
   }
}

Try with each of the following combinations (make changes in the code). The UKB template will always be wrong:

UsePrevBarEquityForPosSizing: true, ActivateStopsImmediately: true
UsePrevBarEquityForPosSizing: true, ActivateStopsImmediately: false
UsePrevBarEquityForPosSizing: false, ActivateStopsImmediately: true
UsePrevBarEquityForPosSizing:
false, ActivateStopsImmediately: false

Any attempt at low level custom code cannot be trusted until somebody can actually write low level custom backtester code that can be verified against AmiBroker built in code. I want to experiment with non trivial position sizing. But, I can't do it without a better description of how the low level backtester is supposed to be used.

I will send this note to support also, if you or Marcin prefer to reply privately. But, I suspect that any reply would be helpful to the whole group.

Mike


--- In amibroker@xxxxxxxxxxxxxxx, "Tomasz Janeczko" <groups@xxx> wrote:
>
> Hello,
>
> In short, all information you asked for in this particular request can be found on-line:
> http://www.amibroker.org/userkb/2008/03/16/amibroker-custom-backtester-interface-2/
>
> Best regards,
> Tomasz Janeczko
> amibroker.com
> ----- Original Message -----
> From: "Mike" sfclimbers@xxx
> To: amibroker@xxxxxxxxxxxxxxx
> Sent: Friday, September 18, 2009 7:17 PM
> Subject: [amibroker] Re: Support Issues
>
>
> > Well,
> >
> > Since there have been a few others, I guess I'll add my ticket to the pile, just in case there really is a technical problem. The
> > address I am registered with is a Yahoo dot com address.
> >
> > I received an auto reply for my support request #62580 on Thursday, August 27, 2009. I have not received anything since then. I
> > sent a follow up status request a week after that. Again, no reply.
> >
> > I have been checking my spam folder, but have not noticed anything from AmiBroker in there. Though, admittedly, I get a lot of
> > spam. So, I may have missed something.
> >
> > Mike
> >
> > --- In amibroker@xxxxxxxxxxxxxxx, "Tomasz Janeczko" groups@ wrote:
> >>
> >> Jeremy,
> >>
> >> I have instructed Marcin to double check if there is any message from you awaiting reply.
> >>
> >> Sometimes if there is long exchange between user and support, it may happen that support
> >> considers case as resolved, while customer expects some extra info. If this happens, please just
> >> reply again to any unanswered ticket and tell the support that you are waiting for specific info.
> >>
> >> Best regards,
> >> Tomasz Janeczko
> >> amibroker.com
> >> ----- Original Message -----
> >> From: "nyctastudent" jberkovits1@
> >> To: amibroker@xxxxxxxxxxxxxxx
> >> Sent: Friday, September 18, 2009 3:08 PM
> >> Subject: [amibroker] Re: Support Issues
> >>
> >>
> >> > TJ,
> >> >
> >> > There might be an issue on the AmiBroker side. I am having a problem geting a response to an item I submit on September 2nd.
> >> > Its
> >> > not due to spam filters. I sent a folow up email on the 17th and still no reply. AmiBroker usually has the best support in the
> >> > business. Something is causing a break in support communications. If you need any aditional info from me please let meknow.
> >> >
> >> > Thanks for a great product.
> >> >
> >> >
> >> > Best regards,
> >> >
> >> > Jeremy Berkovits, CMT
> >> >
> >> > Merc Partners
> >> > 11 Great Neck Road
> >> > Great Neck, NY-11021
> >> >
> >> > Direct: (516) 304-3200 EXT. 307
> >> > Cell: (917) 698-3444
> >> > jberkovits1@
> >> > AOL IM: jberkovitscmt
> >> > Yahoo IM: jeremy7827110028
> >> >
> >> >
> >> >
> >> >
> >> >
> >> > On Wed, Sep 2, 2009 at 8:42 AM, support@ wrote:
> >> >
> >> > Hello,
> >> >
> >> > Your message: "GICS Import File" has been received.
> >> > Ticket number is #62757 (please DO NOT remove it from the subject line when replying).
> >> >
> >> >
> >> >
> >> > ------------------------------------
> >> >
> >> > **** IMPORTANT PLEASE READ ****
> >> > This group is for the discussion between users only.
> >> > This is *NOT* technical support channel.
> >> >
> >> > TO GET TECHNICAL SUPPORT send an e-mail directly to
> >> > SUPPORT {at} amibroker.com
> >> >
> >> > TO SUBMIT SUGGESTIONS please use FEEDBACK CENTER at
> >> > http://www.amibroker.com/feedback/
> >> > (submissions sent via other channels won't be considered)
> >> >
> >> > For NEW RELEASE ANNOUNCEMENTS and other news always check DEVLOG:
> >> > http://www.amibroker.com/devlog/
> >> >
> >> > Yahoo! Groups Links
> >> >
> >> >
> >> >
> >>
> >
> >
> >
> >
> > ------------------------------------
> >
> > **** IMPORTANT PLEASE READ ****
> > This group is for the discussion between users only.
> > This is *NOT* technical support channel.
> >
> > TO GET TECHNICAL SUPPORT send an e-mail directly to
> > SUPPORT {at} amibroker.com
> >
> > TO SUBMIT SUGGESTIONS please use FEEDBACK CENTER at
> > http://www.amibroker.com/feedback/
> > (submissions sent via other channels won't be considered)
> >
> > For NEW RELEASE ANNOUNCEMENTS and other news always check DEVLOG:
> > http://www.amibroker.com/devlog/
> >
> > Yahoo! Groups Links
> >
> >
> >
>



__._,_.___


**** IMPORTANT PLEASE READ ****
This group is for the discussion between users only.
This is *NOT* technical support channel.

TO GET TECHNICAL SUPPORT send an e-mail directly to
SUPPORT {at} amibroker.com

TO SUBMIT SUGGESTIONS please use FEEDBACK CENTER at
http://www.amibroker.com/feedback/
(submissions sent via other channels won't be considered)

For NEW RELEASE ANNOUNCEMENTS and other news always check DEVLOG:
http://www.amibroker.com/devlog/





Your email settings: Individual Email|Traditional
Change settings via the Web (Yahoo! ID required)
Change settings via email: Switch delivery to Daily Digest | Switch to Fully Featured
Visit Your Group | Yahoo! Groups Terms of Use | Unsubscribe

__,_._,___