Optimizing Number of Positions
Author: Panache
Creation Date: 1/19/2015 5:55 PM
profile picture

Panache

#1
I understand how to optimize Strategy Parameters, which is very useful.

One parameter which I can't figure out how to optimize is the number of positions a strategy holds. I can program the strategy to make the number of positions a strategy parameter. However, it is of limited utility in back testing because if I choose Percent of Equity in the Portfolio Simulation Mode, the position sizer is going to drive my optimization.

For example, let's say I want to optimize the number of positions my strategy should hold in a range of 5 to 10. If I set the Percent of Equity at 20%, the Position Sizer will effectively limit the number of positions to 5. If I decrease the Percent of Equity to 10%, the optimization results will be biased in favor of 10 positions, since with 5 positions, it would only be using 50% of the equity.

Alternatively, I can use SetShareSize to create my own position size and use WealthScript Override (SetShareSize) to test the correct number of positions. However, I don't know how to access the current capital to determine the correct share size after the first trade. If I simply base the share size on the initial capital, future trades may be smaller (hopefully not larger) than they would be if I used the same number of positions and set the Position Sizer to the applicable Percent of Equity.

I assume I'm not the first one to try to do this, but I haven't been able to find an answer.
profile picture

milesvantassel

#2
Would you share the code for the number of positions?

Below is a paragraph from the WealthScript Programming Guide, V6.8.

QUOTE:
Strategy Code Limitations
Strategies based on Portfolio Equity, Cash, or Drawdown
Due to the Wealth-Lab Pro Version 6 architecture, it is not possible to create trading
strategies that enter or exit trades as a function of Portfolio Equity, which includes
Portfolio Cash and Drawdown. Refer to the QuickRef when selecting WealthScript
functions or object properties for information regarding their use in Strategy code.
profile picture

Panache

#3
CODE:
Please log in to see this code.


This assumes your initial capital is $1,000,000 and you want to trade in round lots.

Just so you know, as of the last time I tried, using SetShareSize and WealthScript Override (SetShareSize) will NOT generate Alerts of the appropriate size.
profile picture

LenMoz

#4
Well, Panache. Last April I tackled this problem, but for a different reason. The problem I was trying to solve was the fact that the entire backtest period is run for each symbol without regard to available buying power. As a consequence, IsLastPositionActive is often out of sync with the trades after the PosSizer. So, buying opportunities can be missed where the strategy is looking to sell a position that didn't make it through the PosSizer, rather than looking to buy. I came up with a design to embed the PosSizer in the Strategy. I prototyped it for one of my strategies. It wasn't perfect, but it was pretty close. It could handle the case where Pct Of Equity is a strategy parameter. The design is below.

Purpose:
Buy the best positions by using an internal PosSizer to issue the actual BuyAt... calls.
Only open, in WL, positions that were accepted by the internal PosSizer.
How it works:
WealthLab's normal Multi-symbol backtest runs the strategy for every symbol in the portfolio.
During these executions of the strategy, every potential buy signal, with its corresponding
sell signal, is added to a table using calls similar to "BuyAtMarket", "SellAtLimit", etc.
All buy signals are added. The table is passed to each symbol through the WL Global facility.
After the last symbol is processed, the strategy-based PosSizer will determine which to turn
into Positions, and at what size. This is done in date then priority order. Buys are subject
to available buying power, and become Positions using the corresponding true WL calls.
The "WealthScript Override" PosSizer is used; position size is controlled in this script.
Strategy modifications:
The noted difference is that every possible buy and sell signal pair is produced by the strategy,
rather than using "if (IsLastPositionActive)" to run the "sell" rules. The "buy" rules are run
at every bar, looking to open a position. When buy conditions are met, a call to "PreBuyAt..."
is made. After each buy is signalled, the sell rules are run to find the bar where the
position will be closed. At this bar, a similar call to a "PreSellAt..." routine adds to the
signal data structure. This builds a data structure similar to the WL Position structure, but
no WL Positions yet. After all symbols have been run in the strategy, the strategy-resident PosSizer
will process the data structure, issuing the true WL "BuyAt..." and "SellAt..." calls.
Limitations: (strategy techniques that preclude this technique)
1. Strategies using a wait period after sell before repurchase (since unsure sell occurred)
2. Current design only supports long positions
3. Designed for strategies that hold one position at a time
4. Proof-of-concept only supports Buy/Sell "...AtMarket" and "...AtLimit" order types
5. Only PosSizer option is "Percent Of Equity"
6. Overnight strategies only; not for intra-day (equity curve and buying power calc'd daily)
7. Dividends not implemented (source of discrepancy vis-a-vis Visualizers)
8. Return on cash not implemented (source of discrepancy)
High Level Design:
A. Phase 1: WL runs the strategy symbol by symbol, with altered "BuyAt...", "SellAt..."
1. Build a data structure (PrePosition) of all buy opportunities by running the buy side of
the strategy for every bar. Rather than issue the "BuyAt..." call, add order specifics to
a PrePosition object for each bar that is considered a buy point, through helper routines,
e.g. "PreBuyAtLimit", "PreBuyAtMarket". Insure that market conditions would permit
the buy before adding it to the PrePosition list (legal peeking).
2. For each buy point added, determine which would have been the sell bar and add a
similar PrePosition for the sell, again via helper routines. Insure market conditions
permit the sell before adding (legal peeking).
B. Phase 2: (end of last symbol) Run the strategy "PosSizer" to open and close Positions per the
sorted data structure, at the appropriate size, recognizing buying power limitations.
1. Sort the PrePosition list on date, then closes before opens, then priority.
2. TODO Pick up PosSizer parameters from left side form(?) (hardcoded for now)
3. Walk through the date-ordered list, considering available buy power and converting PrePosition
buys to counterpart WL opening calls (BuyAtMarket, BuyAtLimit, BuyAtStop, etc.), reducing
cash. For each converted buy, mark the corresponding Sell as active. As active sells are
encountered, issue the designated closing WL call and add proceeds to cash.
Notes:
*IMPORTANT: Set PosSizer, "Position Size:" (left-hand menu), to "WealthScript Override"
*IMPORTANT: Doesn't create alerts, stops 1 bar short (bar+1 issues)