- ago
Suggested importance: HIGH

This request is an offshoot of the discussion on the legacy Pos Sizer "Percent Volatility" (which has certain shortcomings) held here:
https://www.wealth-lab.com/Discussion/Meaning-of-quot-Percent-of-Volatility-quot-9447
Glitch asked me to put in a #FeatureRequest... here it is.


Experienced traders recognize the importance of managing risk. This Pos Sizer will address 2 types of risk:
- Percent of Equity to Risk per trade
- Percent of Equity (maximum) to Allocate per trade.

To achieve this the Sizer will need minimum of 4 fields requiring user input:
1. (int) "ATR Period" (risk will be based on ATR but see below for an option).
2. (int) "Number of ATRs".
3. (double) "Percent of Equity to Risk".
4. (double) "Max Percent of Equity to Allocate".
Suggested default values: 10, 3, 2.00, 5.00 (1, 2, 3, 4 respectively).

--------------------------
Optional:
- ATRP indicator may be offered in addition to ATR
- Decrease risk in drawdown (Turtles style)
- Use Round lots (always down, never up)
--------------------------


Usage example:
// User
ATR value (for user-defined period): 2.0
Number of ATRs: 4
Percent of Equity to Risk: 2.0
Max Percent of Equity to Allocate: 5.0
// Other
A/C Equity: $200,000
Stock price: $50

Point risk per trade: ATR value x # of ATRs = 2.0 x 4 = 8
Dollar risk per trade: $200,000 x 2.0 (% of Eq to risk) = 200,000 x 0.02 = $4,000
Pos Size 1 (using only % of Eq risked): Dollar risk per trade / Point risk per trade = 4000 / 8 = 500 shares
Max $$ allowed per trade: $200,000 x 5.0 (% of Eq to allocate) = 200,000 x 0.05 = $10,000
Pos Size 2 (using only % of Eq allocated): 10,000 / 50 (stock price) = 200 shares
Final Pos Size (lower of sizes 1 and 2): Math.Min(500, 200) = 200 shares*
*without this cap the trade size would have been 500 x 50 = $25,000 or 12.5% of Eq leaving less money for other trades
3
939
Solved
28 Replies

Closed

Bookmark

Sort
- ago
#1
There is an advanced position sizer called "Max Risk % Limited to % of Equity".
It is part of the finantic.Indicators extension.

It will fulfill all the requirements mentioned above if combined with an
GetMaxRiskStopLevel() method in a coded C# strategy
- or -
with the proper settings in
Preferences->Trading->Max Risk Percent Settings.
0
- ago
#2
Great, DrKoch - let's mark this request as completed.
0
- ago
#3
I believe such a Pos Sizer should be a part of Wealth-Lab's Pos Sizers.
1
- ago
#4
After introducing the number of ATR units to the Percent Volatility PosSizer (whose name is not subject to change) in PowerPack B20 (to be released this week alongside WL8 B33)...

https://www.wealth-lab.com/Discussion/Meaning-of-quot-Percent-of-Volatility-quot-9447

...it works PRECISELY as described in the title post. Technically, it has also had that "Cap position at X% of account equity" but it's only the ATR units option that is new. It's not in the classic formula for % Volatility but would be a good addition.
0
Best Answer
- ago
#5
Sounds good, Eugene. Hope you'll change the phrase "Percent of Volatility" inside the configuration window to whatever its supposed to be (probably "Percent of Equity") based on the code's presumed logic.
(And, if its not too much to ask... maybe restore the "Round down" option too as present in WL6).
0
Glitch8
 ( 10.62% )
- ago
#6
I did reopen the feature request, hopefully we can integrate your suggestions soon!
0
- ago
#7
Renaming "Percent of Volatility" is not a valid suggestion. It's a well-known position sizing technique and it's meant to be just it.

And I did drop the "Round down" option from its WL6 predecessor purposefully because I wanted to simplify the PosSizer for WL7. Even in WL6 I tried to collect such universal options in one place ("Position Options") because modifying the app itself wasn't made possible by Fidelity.

WL8 already has a Round Lots options in Preferences > Backtest > "Convert trade quantities to round lots". The great thing about it is that it applies universally. I'm really reluctant to duplicating it and making a "sore thumb" sticking in the Percent Volatility PosSizer that would just "Round down". That's not the Wealth-Lab way.

But you're welcome to create a new #FeatureRequest for "Round down, never up" as a new option in Preferences. The way I see it we could replace the checkbox with a dropdown box with two options "Round lots" and "Always round down".
0
- ago
#8
You're right, the Round Lots option is unnecessary, I'd forgotten about the setting in Prefs.
I'm still confused about what "Percent of Volatility" is supposed to mean but if its another way to say "Percent of Equity" I can adjust to that.
0
- ago
#9
I was checking out the revised "Percent Volatility" Pos Sizer.
The position sizes being calculated are a tiny fraction of what they ought to be.
Best I can tell the value inside the Percent of Volatility box is getting divided by 100 twice so when I put in, say, 2 (meaning 2%) its getting interpreted in the code as 2 /100 /100 = 0.0002 instead of 0.02 (expressing % in fractions).
Hope this gets fixed soon.
0
Glitch8
 ( 10.62% )
- ago
#10
It's not doing that, here's the implementation. Good to get another Advanced Position Sizer internals exposed as an example so thought I'd take the chance to do so :)

CODE:
//size the position public override double SizePosition(Transaction t, BarHistory bars, int idx, double basisPrice, double equity, double cash) { _atr = ATR.Series(bars, _periodATR); ... double volatility = _atr[idx] * factor; if (Double.IsNaN(volatility)) return 0; double size = 0; double vola = (bars.SymbolInfo != null ? volatility * bars.SymbolInfo.PointValue : volatility); size = (equity * this._percentVolatility / 100d) / vola; ... return (volatility <= 0) ? 0 : size; }
0
- ago
#11
Thanks, Glitch.
CODE:
size = (equity * this._percentVolatility / 100d) / vola;

Maybe I missed it but I don't see _percentVolatility defined anywhere in the code snippet. My gut feeling is its being passed as a fraction (i.e. 2% is being passed as 0.02 instead of as 2) and we can see that its getting divided by 100d again.
0
- ago
#12
Your gut feeling is wrong, it's always been passed as double.
0
- ago
#13
Being passed as double doesn't preclude passing as a decimal value.

Care to post how/where _percentVolatility is defined?
0
Glitch8
 ( 10.62% )
- ago
#14
In the Initialize method of the Position Sizer:

CODE:
//initialize public override void Initialize() { _percentVolatility = Parameters[1].AsDouble;
0
- ago
#15
Thanks for engaging, Glitch. Hopefully you can figure out why the Percent Volatility sizer is giving such small sizes.

I cooked up a quick test code and ran it on TQQQ:
CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Data; using WealthLab.Indicators; using System.Collections.Generic; namespace WealthScript15 { public class MyStrategy : UserStrategyBase {       IndicatorBase rsi2, atr10; //create indicators and other objects here, this is executed prior to the main trading loop public override void Initialize(BarHistory bars) {          rsi2 = new RSI(bars.Close, 2);          atr10 = new ATR(bars, 10);          PlotIndicator(rsi2, WLColor.Red, paneTag: "rsi");          DrawHorzLine(20, WLColor.Fuchsia, paneTag: "rsi");          PlotIndicator(atr10);          PlotStopsAndLimits(dotSize: 3);          StartIndex = 10 + 1; } //execute the strategy rules here, this is executed once for each bar in the backtest history public override void Execute(BarHistory bars, int idx) { if (!HasOpenPosition(bars, PositionType.Long)) {             if (rsi2.CrossesUnder(20, idx))             {                Transaction t = PlaceTrade(bars, TransactionType.Buy, OrderType.Market);                t.Weight = -rsi2[idx];             } } else {             Position p = LastOpenPosition; if (idx - p.EntryBar >= 5)                ClosePosition(p, OrderType.Market, 0, "5 day exit");             else             {                if (rsi2.CrossesOver(50, idx))                   ClosePosition(p, OrderType.Market, 0, "rsi > 50");                else                {                   double stop = bars.Low[p.EntryBar] - (3.0 * atr10[p.EntryBar]);                   ClosePosition(p, OrderType.Stop, stop, "3 ATR Stop");                }             } } }       public override double GetMaxRiskStopLevel(BarHistory bars, PositionType pt, int idx)       {          double _stop = bars.Low[idx] - 3 * atr10[idx];          return _stop;       }    } }


Test 1: First, lets use Max Risk Percent sizer set at Max Risk = 2%:

Note Position Count is 208, none was dropped, position sizes are as one would expect.


Test 2: Lets test with Percent Volatility sizer; in the config box the "Percent of Volatility" (correct name ought to be "Percent of Equity based on Volatility") is set at 2 meaning 2% of Equity; ATR period & units are set to match those inside the code as used by Max Risk % sizer; there's no cap for Max % of Equity just as Max Risk % doesn't have one:

Note the puny position sizes - so small that quite a few trades got dropped (117 positions vs 208 in Test #1)!!


Test 3: Lets set Percent of Volatility at 100% - the max possible - and see what happens:

Position sizes are still puny - averaging around $500 on a $100k account - but atleast it filled all 208 trades.
--------------------------------

Feel free to test on your PC, all details given above.

Can you figure out why the Percent Volatility sizer is sizing so small?
0
Cone8
 ( 4.98% )
- ago
#16
Didn't happen that way for me. This is my result with the 2% volatility settings.

0
Cone8
 ( 4.98% )
- ago
#17
Which data source are you using for TQQQ so that we're all using the same data? Mine is Wealth-Data.

And, you better show your commission settings too.
0
- ago
#18
TQQQ data source: Norgate, not div adjusted.

Commissions: Zero, you can see that in my pics above.

Please post a screenshot of the Pos Sizing method + settings used alongside each pic so I can re-create.
Also, I'm using WL8 b33 and PowerPack b20, both latest. You same?
0
- ago
#19
How is the point value defined?
0
Cone8
 ( 4.98% )
- ago
#20
I recreated your settings. The picture would be identical. But I now see that I made a mistake with the Max Risk % - it's clear I actually used 2% of Equity. I'll remove that image.

After running 2% Max Risk again, those results were identical to yours.

What the heck, just in case I missed something (it happens...)



Produces....

0
- ago
#21
I re-ran the test...



Using Norgate Data extension I get this:



But if I use WealthData (or Norgate -> ASCII export) I get this:


So... its a Norgate Data Extension issue!! Who would've thunk it?!
Hope this gets fixed soon.

Thanks for narrowing down the culprit, Cone!
0
Cone8
 ( 4.98% )
- ago
#22
Wow, thank you. After seeing that the trade prices were the same, I didn't think that could possibly be it. We'll have to dig in and see what the real issue is.
0
Glitch8
 ( 10.62% )
- ago
#23
Norgate defines a SymbolInfo for TQQQ with a PointValue of 1000.

Eugene, maybe the Position Sizer should not apply the PointValue if the SecurtityType.IsFuturesModeSecType() == false?
0
- ago
#24
Another bug in the Norgate Data Extension:
When running a strategy standalone using Norgate Data it works OK but if you use Norgate Data as the dataset inside Strategy Monitor it fails at the Loading stage. Do check it out on your PC, too.
Hope this also gets fixed.
1
Glitch8
 ( 10.62% )
- ago
#25
This is going off topic, but I released a Norgate Build 5 which should resolve the issue in the SM. The point value I feel needs to be handled in the Position Sizer.
1
- ago
#26
I had a feeling it might have to do with the point value (Post #19).
0
Glitch8
 ( 10.62% )
- ago
#27
We should go through our Position Sizers and ensure point value logic is only being applied when PositionSizerBase.UseFuturesMode(BarHistory) returns true.
1
- ago
#28
Committed this enhancement to PowerPack B21.
1

Closed

Bookmark

Sort