PureBytes Links
Trading Reference Links
|
Tomasz,
Thank you for your continued replies.
I am trading in a REAL account in REAL life with 50% margin. Some
nights I get few signals, other nights I get many. I trade over 7000
symbols accross NYSE, NASDAQ, and AMEX. I have had as many as 60
signals in one night. Even using all available margin, there are
sometimes not enough funds to cover the orders.
Saying that your strategies do not encounter the problem does not
imply that the problem does not exist.
I gave a simplistic one order example just to illustrate the point.
Now that you understand the scenario, expand the example to a 10
position account using any amount of margin and you hit the exact
same issue as soon as you have more signals than available funds.
Even using the simplistic one position example, I believe that the
backtester would still THINK that there were enough funds available
to fill the BB signal since it IGNORES funds allocated to the AA
order that did not result in a signal. So, I think that your comment
does not apply here and BB would in fact get filled.
The underlying problem is that AmiBroker does not appear to have a
way to model the fact that the broker will commit funds to orders
*placed*, even if those orders do not get *filled*. If I am not
mistaken, AmiBroker only considers funds commited to a *filled* order
(i.e. a signal).
There are at least 3 other forum members that have written about this
issue, so the scenario is real.
Based on my experiments so far, my code will correctly model the
scenario described. I was hoping for either A) a better solution, or
B) validation that the code works for others.
Thanks,
Mike
--- In amibroker@xxxxxxxxxxxxxxx, "Tomasz Janeczko" <groups@xxx>
wrote:
>
> I disagree completely.
> I am trading on REAL margin account in REAL life. With 50% margin
account
> I am always able to place limit orders for all signals I am getting.
>
> As to "cleaner" solution to theoretical example that you have
provided:
> it is as easy as setting "MaxOpenPositions" to ONE.
>
> You would end up with no position open on Tuesday night (your
desired behaviour) because backtester
> STOPS opening positions if "top" signal can not enter due to lack
of funds.
>
> Best regards,
> Tomasz Janeczko
> amibroker.com
> ----- Original Message -----
> From: "Mike" <sfclimbers@xxx>
> To: <amibroker@xxxxxxxxxxxxxxx>
> Sent: Tuesday, September 04, 2007 9:11 PM
> Subject: [amibroker] Re: How do I backtest placing a restricted
number of limit orders each night?
>
>
> > Tomasz,
> >
> > 1. Margin does not solve the problem, it just delays it. As soon
as
> > you get one too many setups you hit the same problem again. Also,
for
> > aggressive strategies using full margin, margin will already have
> > been accounted for when placing the first 10 orders of my example.
> >
> > 2. When using a cash account you are not "DONE". Your code will
> > accept the top ten *SIGNALS*. The problem is that the trader can
not
> > afford to place all the *ORDERS*. Your system will accept signals
for
> > orders that were *NEVER PLACED*.
> >
> > To make this as simple as possible:
> >
> > Monday day:
> > - Have $5,000 available cash
> > - Receive entry setup for AA, BB, CC
> > - PositionScore for AA > BB > CC
> >
> > Monday night:
> > - Place Tuesday limit order for $5,000 AA (since highest score)
> > - Have $0 available cash (broker immediately *reserved* $5,000
for AA)
> > - Can *not* afford to place limit order for BB, CC
> >
> > Tuesday day:
> > - Limit order for AA *not* met
> > - Limit for BB *would* have been met, but order was *not* placed
> > - Limit for CC *would* have been met, but order was *not* placed
> >
> > Tuesday night (YOUR CODE):
> > - Holding $5,000 of BB <--- Wrong!
> > - $0 available cash <--- Wrong!
> >
> > Tuesday night (REAL LIFE):
> > - No holdings <--- Correct
> > - $5,000 available cash <--- Correct
> >
> > In your code, I would be filled for $5,000 of BB which *I never
> > placed an order for*. Your code correctly determined that there
was
> > only room to buy 1 position (e.g. did not also buy CC), but it
used
> > funds that were *not available*. All funds were already used up
by
> > the limit order placed for AA, so the signal for BB was
impossible.
> >
> > In my code, the signals for BB and CC would be cancelled since
their
> > PositionScores are *less* than the top PositionScore (AA) and I
only
> > had room to place 1 order, regardless of the fact that AA was
never
> > filled. The system now correctly shows that there was no *valid*
> > signal for BB and CC.
> >
> > If you have a cleaner way to model this behavior, I would very
much
> > like to use it.
> >
> > Thanks,
> >
> > Mike
> >
> > --- In amibroker@xxxxxxxxxxxxxxx, "Tomasz Janeczko" <groups@>
> > wrote:
> >>
> >> Hello,
> >>
> >> In addition to the fact that if you are using MARGIN account
this
> > is not a problem to place
> >> 15 orders because they will all be within your buying power
> > (including margin),
> >> there is one more thing:
> >> if you are using cash account that does not allow buying power >
> > cash
> >> the problem you are describing is non-existing. Just define
> >> SetOption("MaxOpenPositions", 10 )
> >> and you are DONE. The code will accept only TEN TOP entry
signals
> > and nothing more.
> >> (And instead of "exploration", you should use "Add artificial
> > future bar" in the settings and run BACKTEST
> >> with TOMMORROWS date to find out signals for tommorrow).
> >>
> >> Best regards,
> >> Tomasz Janeczko
> >> amibroker.com
> >> ----- Original Message -----
> >> From: "Mike" <sfclimbers@>
> >> To: <amibroker@xxxxxxxxxxxxxxx>
> >> Sent: Tuesday, September 04, 2007 7:00 PM
> >> Subject: [amibroker] Re: How do I backtest placing a restricted
> > number of limit orders each night?
> >>
> >>
> >> > Tomasz,
> >> >
> >> > You are missing the problem.
> >> >
> >> > Yes, setting a limit order is easy. The problem is that in
real
> > life
> >> > the broker will *reserve the funds* necessary to fill a limit
> > order
> >> > *at the time that the order is placed*, even if the order is
> > never
> >> > filled. If the limit is not reached, the funds will only
become
> >> > available again *after* the close of the bar.
> >> >
> >> > Using portfolio constraints, the sample that you have provided
> > can be
> >> > made to ensure that only 10 orders are *filled*. But, it
assumes
> > that
> >> > limit orders were *placed* for all setups. That is not
realistic.
> >> >
> >> > So, if I have $50,000, I can only place 10 limit orders of
$5,000
> >> > each. If I receive more than 10 setups from the previous bar,
> > then I
> >> > do not have enough funds to place orders for all of them and
must
> >> > choose the top 10 of 15.
> >> >
> >> > Since we can only place *some* limit orders, the trading
system
> > must
> >> > recognize *which* limit orders were placed, and ignore the
rest.
> >> >
> >> > To repeat, if I have only placed limit orders for the top 10
> > setups,
> >> > then if the limit is not reached for any of those 10, I will
have
> > 0
> >> > positions filled. The price action of the remaining 5 is
> >> > irrelevant. I could not afford to place orders on all 15, so
my
> >> > system must reflect that any fills of the remaining 5 *were
never
> >> > placed* and must be cancelled.
> >> >
> >> > Is there a better way to model this behavior?
> >> >
> >> > Thanks,
> >> >
> >> > Mike
> >> >
> >> > --- In amibroker@xxxxxxxxxxxxxxx, "Tomasz Janeczko" <groups@>
> >> > wrote:
> >> >>
> >> >> Solution was provided before. It does not require any custom
> >> > backtest code
> >> >> and is actually easy.
> >> >> I repeat:
> >> >>
> >> >> LimitPrice =
> >> >> Buy = your original buy rule
> >> >>
> >> >> SetTradeDelays( 0, 0, 0, 0 ); // we use zero delays but we
use
> > Ref
> >> > () to shift buy signal.
> >> >>
> >> >> Buy = Ref( Buy, -1 ) AND Low < LimitPrice; // this handles
LIMIT
> >> > order
> >> >> BuyPrice = Min( Open, LimitPrice ); // this ensures
limitprice
> > is
> >> > used for entry or the Open price if it is lower than limit
> >> >>
> >> >> SetBacktestMode( backtestRegularRaw ); // this makes sure
that
> >> > repeated signals occuring on many bars in sequence are not
ignored
> >> >>
> >> >>
> >> >> You don't need to do anything as convoluted as you are
> > apparently
> >> > doing in your formula
> >> >> as the code ABOVE handles placing limit orders (which are
only
> >> > executed if
> >> >> price penetrates your desired limit level).
> >> >>
> >> >> Best regards,
> >> >> Tomasz Janeczko
> >> >> amibroker.com
> >> >> ----- Original Message -----
> >> >> From: "Mike" <sfclimbers@>
> >> >> To: <amibroker@xxxxxxxxxxxxxxx>
> >> >> Sent: Tuesday, September 04, 2007 9:08 AM
> >> >> Subject: [amibroker] Re: How do I backtest placing a
restricted
> >> > number of limit orders each night?
> >> >>
> >> >>
> >> >> > Hi, I am submitting the following code for comment. I
believe
> >> > that I
> >> >> > have a generic solution for the "fixed number of
conditional
> >> > orders
> >> >> > on next bar" problem.
> >> >> >
> >> >> > Constructive criticism is welcomed. Please feel free to
point
> > out
> >> > any
> >> >> > bugs, inefficiencies, suggested enhancements, etc.
> >> >> >
> >> >> > If this is deemed valuable, I can clean up the formatting
and
> > add
> >> > it
> >> >> > to the files section.
> >> >> >
> >> >> > Mike
> >> >> >
> >> >> > Problem Statement:
> >> >> > ------------------
> >> >> > Need programatic support for simulating the placement of a
> > fixed
> >> >> > number of prioritized *conditional* orders at the next bar,
in
> >> >> > response to one or more favorable "setups" triggered by the
> >> > current
> >> >> > bar, and constrained by the number of positions permitted
by
> > the
> >> >> > strategy.
> >> >> >
> >> >> > Example:
> >> >> > --------
> >> >> > Consider a strategy that calls for the placement of limit
> > orders
> >> > at
> >> >> > the next bar after recognizing one or more favorable setups
on
> >> > the
> >> >> > current bar. Assume that the strategy allows a maximum of
only
> > 10
> >> >> > open positions at any given time, and that the setups are
> >> > prioritized
> >> >> > from most preferred (position 1) to least preferred
(position
> > 10).
> >> >> >
> >> >> > If on the first day of the strategy 20 favorable setups
were
> >> >> > recognized, then the strategy would call for placing limit
> > orders
> >> > at
> >> >> > the next bar for *only* the top 10 preferred setups (since
> > only
> >> > 10
> >> >> > positions are permitted and we can not know in advance
whether
> >> > any or
> >> >> > all of the 10 orders would actually get filled).
> >> >> >
> >> >> > Similarly, if at some point after starting the strategy we
> > found
> >> >> > ourself with 2 currently open positions and received 20
> > setups,
> >> > we
> >> >> > would place 8 (10 - 2 = 8) limit orders for the top 8
> > preferred
> >> >> > setups.
> >> >> >
> >> >> > Complications
> >> >> > -------------
> >> >> > 1. Using PositionScore and position sizing is not
sufficient
> >> > since
> >> >> > they do not recognize the allocation of funds commited to
> >> >> > *conditional* order placements that do *not* get filled.
> >> > Resulting
> >> >> > code would typically continue to attempt to fill allowable
> >> > position
> >> >> > count despite not having enough funds to cover all possible
> >> > setups.
> >> >> >
> >> >> > 2. Script execution for any given symbol does not have
access
> > to
> >> > the
> >> >> > PositionScore of the remaining symbols.
> >> >> >
> >> >> > 3. Custom backtester object does not have access to the
> >> > PositionScore
> >> >> > of any symbol that did *not* result in a generated trade
> > signal
> >> > (i.e.
> >> >> > if a limit order was not met, the custom backtester would
not
> >> > have a
> >> >> > signal object for that conditional placement, and thus
would
> > not
> >> > have
> >> >> > access to the PositionScore of the unsuccessful order).
> >> >> >
> >> >> > Solution
> >> >> > --------
> >> >> > 1. Generate a "composite" symbol for each allowable
position
> > of
> >> > the
> >> >> > strategy (e.g. for a strategy allowing a maximum of 10 open
> >> >> > positions, geneare composites ~Position1, ~Position2, ...,
> >> >> > ~Position10).
> >> >> >
> >> >> > 2. At each bar of each symbol, calculate a PositionScore
for
> > any
> >> >> > conditional order based on the recognition of a setup on
the
> >> > previous
> >> >> > bar (e.g. PositionScore for a limit order in response to a
> >> > recognized
> >> >> > setup the bar before). Note that this is a PositionScore
for
> > the
> >> >> > *conditional* order which *may or may not* have been
filled.
> > If
> >> > no
> >> >> > setup was recognized in the previous bar the PositionScore
> > would
> >> > be
> >> >> > zero.
> >> >> >
> >> >> > 3. Insert, in a sorted manner, the calculated PositionScore
> > into
> >> > the
> >> >> > appropriate composite, bumping down in a chain reaction any
> >> > current
> >> >> > composite occupants as needed.
> >> >> >
> >> >> > For example; if the PositionScore for the current symbol at
> > the
> >> >> > current bar was found to be less than the value held by
> >> > ~Position1
> >> >> > for that bar, the comparrison would next be made against
> >> > ~Position2.
> >> >> > If the PositionScore was found to be greater than the value
> > held
> >> > by
> >> >> > ~Position2 for that bar, then the value for that bar of
> >> > ~Position2
> >> >> > would be replaced (bumped) by PositionScore, and the value
> > that
> >> > had
> >> >> > been in ~Position2 would be moved down to ~Position3 for
that
> >> > same
> >> >> > bar, bumping down any value held by ~Position3 in a chain
> >> > reaction
> >> >> > until a zero composite value was found (i.e. nothing to
bump)
> > or
> >> > all
> >> >> > composites had been updated.
> >> >> >
> >> >> > e.g. given:
> >> >> >
> >> >> > PositionScore[x] is 99 and;
> >> >> >
> >> >> > ~Position1[x] is 100
> >> >> > ~Position2[x] is 50
> >> >> > ~Position3[x] is 49
> >> >> > ~Position4[x] is 0
> >> >> > ...
> >> >> > ~Position10[x] is 0
> >> >> >
> >> >> > Result after insertion would be:
> >> >> >
> >> >> > ~Position1[x] is 100
> >> >> > ~Position2[x] is 99
> >> >> > ~Position3[x] is 50
> >> >> > ~Position4[x] is 49
> >> >> > ~Position5[x] is 0
> >> >> > ...
> >> >> > ~Position10[x] is 0
> >> >> >
> >> >> > 4. Write custom backtester logic to calculate, at each bar,
> > how
> >> > many
> >> >> > open positions exist, and reset to 0 the PosSize of any
Signal
> >> > whose
> >> >> > PositionScore is *less* than the PositionScore held by the
N-
> > th
> >> >> > composite, where N is calculated as max allowed positions
> > minus
> >> > the
> >> >> > number of currently opened positions (e.g. 10 max
positions -
> > 2
> >> > open
> >> >> > positions = composite ~Position8). This emulates not having
> >> > placed
> >> >> > orders for any but the top N preferred setups.
> >> >> >
> >> >> > 5. Leave to the native backtester all other decisions
> > regarding
> >> > enty
> >> >> > into positions and tie-breaking of equal PositionScore.
> >> >> >
> >> >> > Advantages
> >> >> > ----------
> >> >> > 1. Works generically for any conditional strategy, Long or
> > Short*.
> >> >> > 2. Works equally well for scale-in strategies.
> >> >> > 3. Makes no assumptions regarding Buy/Sell rules.
> >> >> > 4. Does not result in any phantom/artificial trades.
> >> >> > 5. Does not generate any phantom/artificial commisions.
> >> >> > 6. Does not depend on any backtester settings "tweaks".
> >> >> > 7. PositionScore data is available at all times for
additional
> >> >> > analysis.
> >> >> >
> >> >> > * Backtester logic must be custom fit to your strategy, but
> >> >> > persistence of scores is generic to all.
> >> >> >
> >> >> > Disadvantages
> >> >> > -------------
> >> >> > 1. Slower execution resulting from heavy looping (loops N
> > times
> >> > more
> >> >> > than alternative proposed in msg #113384, where N equals
> > maximum
> >> >> > allowed positions).
> >> >> >
> >> >> > For example; A strategy backtested 3 months over 7800+
symbols
> >> > using
> >> >> > 10 allowed positions on a 1.4Ghz laptop with 1GB RAM takes
> > about
> >> > 10
> >> >> > minutes.
> >> >> >
> >> >> > 2. Code is more complex than alternative proposed in msg
> > #113384.
> >> >> >
> >> >> > -----
> >> >> > ----- Sample code snippets for your review (Long only)
> >> >> > ----- I have left in _TRACE statements to see what's
happening
> >> >> > -----
> >> >> >
> >> >> > /*
> >> >> > * Carry fixed number of positions, equally divided.
> >> >> > */
> >> >> > maxPositions = 10;
> >> >> > PositionSize = -100/maxPositions;
> >> >> > SetOption("MaxOpenPositions", maxPositions);
> >> >> >
> >> >> > /*
> >> >> > * Custom backtester implementation to strip out orders that
in
> >> >> > * reality would not have been placed due to a limitation of
> >> >> > * available capital to cover bids on all setups.
> >> >> > *
> >> >> > * Note: This implementation assumes Long positions only!
> >> >> > */
> >> >> > SetCustomBacktestProc("");
> >> >> >
> >> >> > if (Status("action") == actionPortfolio) {
> >> >> > bo = GetBacktesterObject();
> >> >> > bo.PreProcess();
> >> >> >
> >> >> > for (bar = 0; bar < BarCount; bar++) {
> >> >> > openCount = 0;
> >> >> >
> >> >> > for (openPos = bo.GetFirstOpenPos();
> >> >> > openPos;
> >> >> > openPos = bo.GetNextOpenPos())
> >> >> > {
> >> >> > openCount++;
> >> >> > }
> >> >> >
> >> >> > minPos = maxPositions - openCount;
> >> >> > posScores = IIF(minPos,
> >> >> > Foreign("~Position" + minPos, "X", 0),
> >> >> > 9999); // Highest possible score!
> >> >> >
> >> >> > for (sig = bo.GetFirstSignal(bar);
> >> >> > sig;
> >> >> > sig = bo.GetNextSignal(bar))
> >> >> > {
> >> >> > if (sig.IsEntry() AND sig.IsLong()) {
> >> >> > if (sig.PosScore < posScores[bar]) {
> >> >> > /*_TRACE(StrFormat("Score %9.4f less than top %
1.0f
> >> > scores
> >> >> > of %9.4f at bar %5.0f, cancel signal for ", sig.PosScore,
> > minPos,
> >> >> > posScores[bar], bar) + sig.Symbol);*/
> >> >> >
> >> >> > // Order would not have been placed, cancel it out.
> >> >> > sig.PosSize = 0;
> >> >> > }
> >> >> > }
> >> >> > }
> >> >> >
> >> >> > bo.ProcessTradeSignals(bar);
> >> >> > }
> >> >> >
> >> >> > bo.PostProcess();
> >> >> > }
> >> >> >
> >> >> > /*
> >> >> > * For each bar following entry setup, persist PositionScore
> > into
> >> > an
> >> >> > * ordered list of Foreign symbols such that we may later
have
> >> > access
> >> >> > * to the top scores during backtesting, regardless of
whether
> > a
> >> >> > * concrete signal for the ranked symbol is actually found.
See
> >> >> > * custom backtester method for filtering logic.
> >> >> > *
> >> >> > * For example; a 10 position, limit order strategy
currently
> >> > holding
> >> >> > * 2 positions might place limit orders for only the top 8
> > setups,
> >> >> > * despite recognizing more than 8 candidate setups. This
> > method
> >> >> > * would sort the PositionScore of all candidate setups into
10
> >> >> > * foreign symbols, regardless of whether or not the limit
> > order
> >> > was
> >> >> > * met. The backtester would then compare the PositionScore
of
> > all
> >> >> > * filled signals (i.e. all signals of the limit price
having
> > been
> >> >> > * met), and cancel out those whose score was less than the
top
> > 8
> >> >> > * scores found in the Foreign symbols (i.e. cancel out
signals
> >> > for
> >> >> > * those symbols upon which, in reality, a limit order would
> > never
> >> >> > * actually have been placed).
> >> >> > *
> >> >> > * Note: This implementation leaves the responsibility of
tie-
> >> >> > * breaking to the backtester, when multiple symbols have
the
> > same
> >> >> > * PositionScore for a limited number of available
positions.
> > The
> >> >> > * symbol selected by the backtester may not be the one for
> > which
> >> > an
> >> >> > * order was actually placed in real life. But, the symbol
> >> > selected
> >> >> > * is guaranteed to at least have an equivalent
PositionScore.
> > Use
> >> >> > * unique PosittionScore values, or trade in real life using
> > the
> >> > same
> >> >> > * tie-breaking logic that AmiBroker uses :)
> >> >> > *
> >> >> > * Note: This implementation assumes that PositionScore will
be
> >> >> > * either zero, for bars not recognized as following order
> >> > placement
> >> >> > * criteria (i.e. no setup from previous bar), or a non zero
> >> > positive
> >> >> > * number, for bars where order placement criteria has been
> > met. To
> >> >> > * reiterate, this refers to order *placement* criteria
(i.e.
> >> > setup),
> >> >> > * not order *fulfillment*.
> >> >> > */
> >> >> > procedure persistScores(scores) {
> >> >> > local maxPositions; // Max positions allowed in portfolio
> >> >> > local empty; // Array of zeros
> >> >> > local bar; // Loop variable
> >> >> > local score; // PositionScore of bar-th bar
> >> >> > local pos; // Loop variable
> >> >> > local composite; // Name of pos-th composite
> >> >> > local posScores; // Scores persisted to composite
> >> >> > local delta; // Delta between PositionScore and
> > composite
> >> >> > local affected; // Flag whether any deltas were added
> >> >> >
> >> >> > maxPositions = GetOption("MaxOpenPositions");
> >> >> > empty = Cum(0);
> >> >> >
> >> >> > for (pos = 1; pos <= maxPositions; pos++) {
> >> >> > /*_TRACE("Persist " + Name() + " to position " + pos);*/
> >> >> > composite = "~Position" + pos;
> >> >> > AddToComposite(0, composite, "X", 1 + 2 + 4 + 8); //
> >> > Initialize
> >> >> > posScores = Foreign(composite, "X", 0); // Do not fill
> > holes!
> >> >> > delta = empty;
> >> >> > affected = false;
> >> >> >
> >> >> > for (bar = 0; bar < BarCount; bar++) {
> >> >> > if (scores[bar]) {
> >> >> > score = scores[bar];
> >> >> >
> >> >> > if (score > posScores[bar]) {
> >> >> > /*_TRACE(StrFormat("Score %9.4f bumps down
position %
> >> > 1.0f
> >> >> > score of %9.4f at bar %5.0f", score, pos, posScores[bar],
> > bar));*/
> >> >> >
> >> >> > // Grab current best value and hold for next
composite
> >> >> > // iteratation, and calculate delta needed to add
to
> >> >> > // this composite in order to make it equal new
high
> >> > score
> >> >> >
> >> >> > scores[bar] = posScores[bar];
> >> >> > delta[bar] = score - posScores[bar];
> >> >> > affected = true;
> >> >> > }
> >> >> > /*else if (posScores[bar]) _TRACE(StrFormat("Score %
> > 9.4f
> >> >> > blocked by position %1.0f score of %9.4f at bar %5.0f",
score,
> >> > pos,
> >> >> > posScores[bar], bar));*/
> >> >> > }
> >> >> > }
> >> >> >
> >> >> > if (affected) {
> >> >> > AddToComposite(delta, composite, "X", 1 + 2 + 4 + 8);
> >> >> > }
> >> >> > }
> >> >> >
> >> >> > /*_TRACE("\n");*/
> >> >> > }
> >> >> >
> >> >> > setup = ... // Some setup recognition logic
> >> >> > Buy = Ref(setup, -1) AND ... // Some conditional entry logic
> >> >> > PositionScore = IIF(Ref(setup, -1), ..., 0); // Some score
> > logic
> >> > or 0
> >> >> > Sell = ... // Some Sell logic
> >> >> >
> >> >> > persistScores(PositionScore);
> >> >> >
> >> >> > /*
> >> >> > * Example of 5% dip limit conditional entry:
> >> >> > * BuyPrice = min(Open, (Ref(Close, -1) * 0.95));
> >> >> > * Buy = Ref(setup, -1) AND Low <= BuyPrice;
> >> >> > */
> >> >> >
> >> >> > ------
> >> >> > ------ End code snippets
> >> >> > ------
> >> >> >
> >> >> > --- In amibroker@xxxxxxxxxxxxxxx, "ed2000nl" <empottasch@>
> > wrote:
> >> >> >>
> >> >> >> i'll try to reply directly from yahoo. My posts aren't
coming
> >> >> > through
> >> >> >> anymore. Might be because of the ISP ...
> >> >> >>
> >> >> >>
> >> >> >> so if I understand correctly the problem is not that the
> >> > backtester
> >> >> >> picks 20 stocks while there is only money for 10 but you
> > have a
> >> >> > problem
> >> >> >> with the fact that if the 10 actual signals are not
filled
> > it
> >> > will
> >> >> > use
> >> >> >> the lower ranking 10 signals and this is not what you
> > want.
> >> > You
> >> >> > can
> >> >> >> include this in the backtester. I explained the same thing
> > some
> >> >> > time
> >> >> >> ago. For signals that you actually want to enter but in
real
> >> > life
> >> >> > will
> >> >> >> not be entered because the limit is not reached then you
can
> >> > tell
> >> >> > the
> >> >> >> backtester to enter at the open and exit at the open and
do
> > not
> >> >> > allow
> >> >> >> for a single bar trade (in the settings window). There
> > might
> >> > be
> >> >> >> easier ways to do this (I mean using arrays only) but I
have
> >> > some
> >> >> >> example code below. I did not check if the code is
entirely
> >> > correct
> >> >> > but
> >> >> >> I'll explain the idea: The Buy array is fed to the
> > sellAtLimit
> >> >> > procedure
> >> >> >> and when it finds a buy it will check if the buy limit is
> >> > reached
> >> >> > for
> >> >> >> that signal. If it is not reached (so if Low[ i ] >=
buyLimit
> > [
> >> >> > i ] )
> >> >> >> then you tell the backtester to enter and exit at the
same
> >> > price,
> >> >> > same
> >> >> >> bar. What happens is that the backtester reserves this
money
> >> > for
> >> >> > this
> >> >> >> trade and will not use it for another trade. The only
thing
> >> > that
> >> >> > is not
> >> >> >> realistic is that you will pay commission. But this will
be
> > a
> >> > small
> >> >> >> factor. rgds, Ed procedure
> >> >> >> sellAtLimit_proc(Buy,BuyPrice,buyLimit,sellLimit) {
> >> >> >>
> >> >> >> global Sell;
> >> >> >> global SellPrice;
> >> >> >> global BuyAdjusted;
> >> >> >> global BuyPriceAdjusted;
> >> >> >>
> >> >> >>
> >> >> >> // initialise arrays
> >> >> >> SellPrice = 0;
> >> >> >> Sell = 0;
> >> >> >> BuyAdjusted = 0;
> >> >> >> BuyPriceAdjusted = 0;
> >> >> >>
> >> >> >> for (i = 1; i < BarCount; i++) {
> >> >> >>
> >> >> >>
> >> >> >> // case where it is likely to enter a long position
> >> >> >> if (Buy[ i ] == 1 AND Low[ i ] < buyLimit[ i ]) {
> >> >> >>
> >> >> >>
> >> >> >> // buy at limit
> >> >> >> BuyAdjusted[ i ] = 1;
> >> >> >>
> >> >> >> if (Open[ i ] < buyLimit[ i ]) {
> >> >> >>
> >> >> >>
> >> >> >> BuyPriceAdjusted[ i ] = Open[ i ];
> >> >> >>
> >> >> >> } else {
> >> >> >>
> >> >> >> BuyPriceAdjusted[ i ] = buyLimit[ i ];
> >> >> >>
> >> >> >> }
> >> >> >>
> >> >> >>
> >> >> >> // find a sell position + sellprice
> >> >> >> for (j = i; j < BarCount; j++) {
> >> >> >>
> >> >> >> if (O[ j ] > sellLimit[ j ]) {
> >> >> >>
> >> >> >> Sell[ j ] = 1;
> >> >> >> SellPrice[ j ] = O[ j ];
> >> >> >> i = j;
> >> >> >> break;
> >> >> >>
> >> >> >> } else if (O[ j ] < sellLimit[ j ] AND H[ j ] >
> >> > sellLimit
> >> >> > [ j
> >> >> >> ]) {
> >> >> >>
> >> >> >> Sell[ j ] = 1;
> >> >> >> SellPrice[ j ] = sellLimit[ j ];
> >> >> >> i = j;
> >> >> >> break;
> >> >> >>
> >> >> >> } else if (j == BarCount - 1) {
> >> >> >>
> >> >> >> i = BarCount;
> >> >> >>
> >> >> >> }
> >> >> >>
> >> >> >>
> >> >> >>
> >> >> >>
> >> >> >>
> >> >> >> }
> >> >> >>
> >> >> >> } else if (Buy[ i ] == 1 AND Low[ i ] >= buyLimit[
i ])
> > {
> >> >> >>
> >> >> >> // enter and exit at the same price and time
("VOID"
> >> > trade)
> >> >> >> BuyAdjusted[ i ] = 1;
> >> >> >> BuyPriceAdjusted[ i ] = Open[ i ];
> >> >> >>
> >> >> >> Sell[ i ] = 1;
> >> >> >> SellPrice[ i ] = Open[ i ];
> >> >> >>
> >> >> >>
> >> >> >> }
> >> >> >>
> >> >> >> }
> >> >> >>
> >> >> >>
> >> >> >> } // end procedure
> >> >> >>
> >> >> >>
> >> >> >> --- In amibroker@xxxxxxxxxxxxxxx, "sfclimbers"
<sfclimbers@>
> >> > wrote:
> >> >> >> >
> >> >> >> > Thanks for your reply. I will look into your suggestion,
> > but I
> >> >> > don't
> >> >> >> > think that that is the issue that I am up against. I
have
> >> > actual
> >> >> >> > trade data from months of live trading. I am now trying
to
> >> >> > backtest
> >> >> >> > the strategy used, and match the results to the actual
data.
> >> >> >> >
> >> >> >> > My script, as written, is correctly entering and exiting
> > with
> >> > the
> >> >> >> > correct number of shares and correct price points on all
> > the
> >> >> > correct
> >> >> >> > days for all the trades that actually took place.
> >> >> >> >
> >> >> >> > The problem is that if I receive 20 "go long" signals on
> > Monday
> >> >> >> > night, but only have enough money to afford 8 more
> > positions,
> >> >> > then in
> >> >> >> > real life I only place limit orders for the *top* 8 of
the
> > 20
> >> >> >> > candidates, not all 20.
> >> >> >> >
> >> >> >> > This means that in reality, if none of the top 8 dip to
my
> >> > limit
> >> >> >> > order, then I will not get any fills on Tuesday, even
> > though I
> >> >> > still
> >> >> >> > have not filled my slots, and even though some of the
lesser
> >> >> >> > candidates would have resulted in a fill had I place an
> > order
> >> > for
> >> >> >> > them.
> >> >> >> >
> >> >> >> > However, the script is considering *all* 20 candidates,
and
> >> > fills
> >> >> > up
> >> >> >> > to 8 that dip enough to trigger a limit order. In other
> > words,
> >> > the
> >> >> >> > script assumes that there are limit orders on all
> > candidates
> >> >> > instead
> >> >> >> > of only the top 8.
> >> >> >> >
> >> >> >> > Using position score and position sizing is not enough,
> > since
> >> >> > these
> >> >> >> > assume that the universe of candidates fitting the
criteria
> > is
> >> >> > always
> >> >> >> > available for prioritizing and filling available slots.
> > But, in
> >> >> >> > reality, only a subset are being bid on.
> >> >> >> >
> >> >> >> > As an example, if I'm currently holding:
> >> >> >> > AAA, BBB
> >> >> >> >
> >> >> >> > And I then get signals for (in sorted order):
> >> >> >> > CCC, DDD, EEE, FFF, GGG, HHH, III, JJJ, KKK, LLL, ... TTT
> >> >> >> >
> >> >> >> > I will only place limit orders for the top 8:
> >> >> >> > CCC, DDD, EEE, FFF, GGG, HHH, III, JJJ
> >> >> >> >
> >> >> >> > If none of the top 8 above reach my limit, but say 8
lesser
> >> > ones
> >> >> > do
> >> >> >> > (that I did not bid on), then in real life I will get no
> > fills
> >> > for
> >> >> >> > the day. However, my script is saying that I picked up
the
> > 8
> >> >> > lesser
> >> >> >> > fills since I had 8 slots open and these 8 met the limit
> > price.
> >> >> >> >
> >> >> >> > How can I structure my code to recognize that 20 entry
> > setups
> >> > were
> >> >> >> > found, but only 8 of them were acted upon, none of which
> >> > actually
> >> >> >> > worked out due to not meeting the limit price?
> >> >> >> >
> >> >> >> > I can't seem to use the custom backtester to sweep
through
> > the
> >> >> > orders
> >> >> >> > and null out the false buys that would not have taken
> > place,
> >> >> > since I
> >> >> >> > don't have access to the scores of the candidates that
> > didn't
> >> > get
> >> >> >> > filled.
> >> >> >> >
> >> >> >> > Yet, similarly, I can't seem to prevent triggering the
buys
> > in
> >> > the
> >> >> >> > first place, since I don't have access to the scores of
the
> >> > other
> >> >> >> > candidates at that time either.
> >> >> >> >
> >> >> >> > When there are fewer signals than slots to fill,
everything
> > is
> >> >> >> > great :) But this strategy often results in more signals
> > than
> >> >> > there
> >> >> >> > is money to bid with :(
> >> >> >> >
> >> >> >> > Thanks.
> >> >> >> >
> >> >> >> >
> >> >> >> > --- In amibroker@xxxxxxxxxxxxxxx, "Edward Pottasch"
> > empottasch@
> >> >> >> > wrote:
> >> >> >> > >
> >> >> >> > > hi,
> >> >> >> > >
> >> >> >> > > the way you set it up it shoudl not be possible.
However,
> >> > what
> >> >> > can
> >> >> >> > happen is that the backtester finds exits for the next
day
> > and
> >> >> >> > immediatelly fills them with new positions. So you need
to
> >> > make
> >> >> > sure
> >> >> >> > that you first exit your positions and tell the
backtester
> > to
> >> >> > enter
> >> >> >> > only on the next bar. This is usually the problem.
There
> > are
> >> >> > several
> >> >> >> > ways to achieve this. Maybe you will get a more
> > satisfactory
> >> >> > result
> >> >> >> > when you set settradedelays(1,1,1,1).
> >> >> >> > >
> >> >> >> > > I use setttradedelays(0,0,0,0) but I make sure that
the
> >> > trade is
> >> >> >> > entered 1 bar after the signal (same with the exits),
> >> >> >> > >
> >> >> >> > > Ed
> >> >> >> > >
> >> >> >> > >
> >> >> >> > >
> >> >> >> > >
> >> >> >> > > ----- Original Message -----
> >> >> >> > > From: Michael White
> >> >> >> > > To: amibroker@xxxxxxxxxxxxxxx
> >> >> >> > > Sent: Friday, August 24, 2007 11:37 AM
> >> >> >> > > Subject: [amibroker] How do I backtest placing a
> > restricted
> >> >> >> > number of limit orders each night?
> >> >> >> > >
> >> >> >> > >
> >> >> >> > > Can anyone help me model the following scenario?
> >> >> >> > >
> >> >> >> > > - Assume a portfolio is allowed to consist of some
> > fixed
> >> >> > number
> >> >> >> > > of "slots" with equity equally divided among them
(e.g.
> > 10
> >> >> > slots
> >> >> >> > at
> >> >> >> > > 10% of equity).
> >> >> >> > > - Check for setup criteria at close of each day.
> >> >> >> > > - Place next day limit buy orders for as many
unfilled
> >> > slots
> >> >> > as
> >> >> >> > are
> >> >> >> > > currently available (e.g. if already have 2 fills
after
> >> > day 1,
> >> >> >> > then
> >> >> >> > > there are only 10 - 2 = 8 slots remaining for day 2,
> > etc.).
> >> >> >> > > - Buy orders are prioritized by a calculated value.
> >> >> >> > >
> >> >> >> > > My problem is that if I receive a setup for more
> > symbols
> >> > than
> >> >> > I
> >> >> >> > have
> >> >> >> > > available slots (e.g. receive 20 setups but only
have 8
> >> >> > available
> >> >> >> > > slots), my script will try to fill all 8 slots from
the
> > 20
> >> >> >> > > candidates, and the portfolio manager will correctly
> >> > prevent
> >> >> > me
> >> >> >> > from
> >> >> >> > > having more positions than allowed (e.g. no more
than
> > 10).
> >> >> >> > >
> >> >> >> > > However, in reality, I will only have placed as many
> > limit
> >> >> > orders
> >> >> >> > as
> >> >> >> > > I have available slots (e.g. 8 limit orders when 8
> >> > available
> >> >> >> > slots,
> >> >> >> > > not limit orders for all 20 candidates, since I only
> > have
> >> >> > funds
> >> >> >> > to
> >> >> >> > > cover placing 8 orders).
> >> >> >> > >
> >> >> >> > > What is happening is that my script is filling
orders
> > that
> >> > I
> >> >> >> > would
> >> >> >> > > not have placed! I need a way to indicate that
despite
> > 20
> >> >> > setups,
> >> >> >> > > only 8 limit orders were placed.
> >> >> >> > >
> >> >> >> > > Following is some script snippets.
> >> >> >> > >
> >> >> >> > > /*
> >> >> >> > > * Assume an initial purse and brokerage fees
> > ($0.01/share)
> >> >> >> > > */
> >> >> >> > > SetOption("InitialEquity", 50000);
> >> >> >> > > SetOption("CommissionMode", 3);
> >> >> >> > > SetOption("CommissionAmount", 0.01);
> >> >> >> > >
> >> >> >> > > /*
> >> >> >> > > * Carry fixed number of positions, dividing 100% of
> > Equity
> >> >> > between
> >> >> >> > > * them (based on previous bar's closing).
> >> >> >> > > */
> >> >> >> > > PositionSize = -100/10; // Each position is 10% of
> > equity
> >> >> >> > >
> >> >> >> > > SetOption("MaxOpenPositions", 10); // No more than
10
> >> >> > positions
> >> >> >> > > SetOption("UsePrevBarEquityForPosSizing", True);
> >> >> >> > >
> >> >> >> > > /*
> >> >> >> > > * We recognize the sale signal at the close of a bar
> > and
> >> >> > execute
> >> >> >> > the
> >> >> >> > > * sale at the open of the next one, delay sale by 1
day.
> >> >> >> > > */
> >> >> >> > > SetTradeDelays(0, 1, 0, 0);
> >> >> >> > >
> >> >> >> > > /*
> >> >> >> > > * Trigger a Buy signal when previous bar meets the
setup
> >> >> >> > > * requirements AND this bar's Low has dropped to
less
> > than
> >> > a
> >> >> > fixed
> >> >> >> > > * percentage below the previous bar's close. This
> > emulates
> >> >> > having
> >> >> >> > > * placed a limit order the night before after having
> > seen
> >> > the
> >> >> >> > signal
> >> >> >> > > * on that day's close.
> >> >> >> > > */
> >> >> >> > > setup = ... // Some position entry logic.
> >> >> >> > > PositionScore = ... // Some prioritization logic.
> >> >> >> > >
> >> >> >> > > BuyPrice = Ref(Close, -1) * 0.95;
> >> >> >> > > Buy = Ref(setup, -1) AND Low <= BuyPrice; // Problem
> >> > here!!!
> >> >> >> > >
> >> >> >> > > Sell = ... // Some sell logic.
> >> >> >> > >
> >> >> >> > > As indicated in my earlier comments. The problem is
> > that in
> >> >> >> > reality I
> >> >> >> > > will not actually have placed orders for all
> > candidates,
> >> > but
> >> >> >> > rather
> >> >> >> > > only for as many as there are available slots (e.g.
8).
> >> >> > However,
> >> >> >> > the
> >> >> >> > > script will attempt to fill the available slots
based
> > on
> >> > all
> >> >> >> > > candidates (e.g. 20).
> >> >> >> > >
> >> >> >> > > How can I restrict the Buy assignment to only apply
to
> > the
> >> >> > top X
> >> >> >> > of Y
> >> >> >> > > candidates based on priority (e.g. top 8 of 20 in
> > example
> >> >> > above).
> >> >> >> > >
> >> >> >> > > Thanks in advance.
> >> >> >> > >
> >> >> >> >
> >> >> >>
> >> >> >
> >> >> >
> >> >> >
> >> >> >
> >> >> > Please note that this group is for discussion between users
> > only.
> >> >> >
> >> >> > To get support from AmiBroker please send an e-mail
directly
> > to
> >> >> > SUPPORT {at} amibroker.com
> >> >> >
> >> >> > For NEW RELEASE ANNOUNCEMENTS and other news always check
> > DEVLOG:
> >> >> > http://www.amibroker.com/devlog/
> >> >> >
> >> >> > For other support material please check also:
> >> >> > http://www.amibroker.com/support.html
> >> >> >
> >> >> > Yahoo! Groups Links
> >> >> >
> >> >> >
> >> >> >
> >> >> >
> >> >> >
> >> >>
> >> >
> >> >
> >> >
> >> >
> >> > Please note that this group is for discussion between users
only.
> >> >
> >> > To get support from AmiBroker please send an e-mail directly
to
> >> > SUPPORT {at} amibroker.com
> >> >
> >> > For NEW RELEASE ANNOUNCEMENTS and other news always check
DEVLOG:
> >> > http://www.amibroker.com/devlog/
> >> >
> >> > For other support material please check also:
> >> > http://www.amibroker.com/support.html
> >> >
> >> > Yahoo! Groups Links
> >> >
> >> >
> >> >
> >> >
> >> >
> >>
> >
> >
> >
> >
> > Please note that this group is for discussion between users only.
> >
> > To get support from AmiBroker please send an e-mail directly to
> > SUPPORT {at} amibroker.com
> >
> > For NEW RELEASE ANNOUNCEMENTS and other news always check DEVLOG:
> > http://www.amibroker.com/devlog/
> >
> > For other support material please check also:
> > http://www.amibroker.com/support.html
> >
> > Yahoo! Groups Links
> >
> >
> >
> >
> >
>
Please note that this group is for discussion between users only.
To get support from AmiBroker please send an e-mail directly to
SUPPORT {at} amibroker.com
For NEW RELEASE ANNOUNCEMENTS and other news always check DEVLOG:
http://www.amibroker.com/devlog/
For other support material please check also:
http://www.amibroker.com/support.html
Yahoo! Groups Links
<*> To visit your group on the web, go to:
http://groups.yahoo.com/group/amibroker/
<*> Your email settings:
Individual Email | Traditional
<*> To change settings online go to:
http://groups.yahoo.com/group/amibroker/join
(Yahoo! ID required)
<*> To change settings via email:
mailto:amibroker-digest@xxxxxxxxxxxxxxx
mailto:amibroker-fullfeatured@xxxxxxxxxxxxxxx
<*> To unsubscribe from this group, send an email to:
amibroker-unsubscribe@xxxxxxxxxxxxxxx
<*> Your use of Yahoo! Groups is subject to:
http://docs.yahoo.com/info/terms/
|