- ago
I would like to rebalance my portfolio automatically and I'm wondering how to accomplish that.
1
338
Solved
13 Replies

Reply

Bookmark

Sort
- ago
#1
If you choose a Rotation strategy, Wealth-Lab supports periodic portfolio rebalancing with any given frequency:


0
Glitch8
 ( 10.62% )
- ago
#2
There is much more that we could add to WL7 to support a "Balanced Portfolio" type of Strategy. In fact, I think it could deserve its own new Strategy Type even, with some simplified way to add rules for how you want to balance the portfolio.
0
Best Answer
- ago
#3
Yeah, im new to WL8 and finding it hard to just code up some simple strategic allocations... 80/20, 60/40, etc. Did I miss a special indicator for use with the rotation strategies?
0
Cone8
 ( 4.98% )
- ago
#4
This is a 2-year old thread and Rotation strategies now have more features, including "Additional Conditions". You can use any indicator in the library.

Block rotation strategies divide equity equally between candidates. But you can program your own rotation in any manner that you want.
0
- ago
#5
Thanks Cone,

What indicator or additional condition should I use in either a rotation or block strategy to build a portfolio that maintains a 60% allocation to SPY and a 40% allocation to TLT?
0
Cone8
 ( 4.98% )
- ago
#6
You can't do that from blocks or a Rotation strategy. It requires a custom C#-coded strategy. There, you'd program a Rotation strategy using PreExecute (or PostExecute), where you can access all the BarHistory candidates at the same time.
0
Glitch8
 ( 10.62% )
- ago
#7
PreExecute isn't really necessary in this case. Here's the simplest Strategy that maintains a 60/40 split between SPY and the second symbol in the DataSet. Run it on a DataSet that contains symbols SPY and TLT. It rebalances monthly so adjust to your needs.

CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Data; using WealthLab.Indicators; using System.Collections.Generic; namespace WealthScript1 { public class MyStrategy : UserStrategyBase { //create indicators and other objects here, this is executed prior to the main trading loop public override void Initialize(BarHistory bars) { } //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 (idx == 0 | bars.DateTimes[idx].IsLastTradingDayOfMonth(bars))          {             //determine allocation             double allocation = bars.Symbol == "SPY" ? 60 : 40;             //this makes sure we have that much             Rebalance(bars, allocation);          } } } }
0
- ago
#8
Thanks. As I understand it now, that won’t work in live trading right?

From what I’ve pieced together I need to get the live broker and the valueAsOf for each position and calculate the buys and sells separately.

I’m gonna try it but I think it’s gonna be hard… like it’s gonna take multiple days to rebalance… first day it will do the sells and second day it will do the buys. So I think I need to keep track of whether the rebalance was completed.

Maybe I can do the sells with market on close and the buys will be sent that night at close and happen on open. But if the buys didn’t occur then I still need to track if the rebalance happened.

Am I overthinking this?
0
Cone8
 ( 4.98% )
- ago
#9
I was thrown off the scent by the talk of Rotation strategies.

As I understand it now, the "strategy" is simply to Rebalance (which is what Glitch shows for a backtest in Post #7) but applied to a live account, right?
0
Cone8
 ( 4.98% )
- ago
#10
Here's the live solution - your freebie for becoming a future customer.

This will backtest based on the the data range and strategy settings, but on the final bar, it will look at the live account to create signals. You can run it every day and ignore the signals except for the day that you want to trade them.

Follow the comments in the code carefully. You need to edit the _acctID statement and add/delete allocation statements as required. Ask questions if you have doubts.

CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Data; using WealthLab.Indicators; using System.Collections.Generic; using System.Linq; namespace WealthScript3 {    public class MyStrategy : UserStrategyBase    {       string _acctID = "DU5591190";       static Dictionary<string, double> _allocation = new(); public override void BacktestBegin() {          //add allocations for each of your symbols. The DataSet must contain these symbols (and cah also have others)          _allocation["SPY"] = 20;          _allocation["MSFT"] = 30;          _allocation["TSLA"] = 25;          _allocation["TTD"] = 25; } //create indicators and other objects here, this is executed prior to the main trading loop public override void Initialize(BarHistory bars)       {       }       //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 (idx == bars.Count - 1 | bars.DateTimes[idx].IsLastTradingDayOfMonth(bars))          {             RebalanceLive(_acctID, bars);          }          else if (idx == 0 | bars.DateTimes[idx].IsLastTradingDayOfMonth(bars))          {             if (_allocation.ContainsKey(bars.Symbol))                Rebalance(bars, _allocation[bars.Symbol]);          }       }       public Transaction RebalanceLive(string accountId, BarHistory bars)       {          Transaction tres = null;          if (!_allocation.ContainsKey(bars.Symbol))             return null;                    BrokerAccount brokerAccount = GetBrokerAccount(accountId);          if (brokerAccount != null)          {             double qtyNeeded = Math.Floor(_allocation[bars.Symbol] / 100d * brokerAccount.AccountValue / bars.LastValue);             double qtyBroker = 0;             //find the shares if a position for bars.Symbol exists             foreach (BrokerPosition bp in brokerAccount.Positions)             {                if (bp.Symbol == bars.Symbol)                {                   qtyBroker = bp.Quantity;                   break;                }             }             if (qtyBroker > qtyNeeded) //sell shares             {                tres = PlaceTrade(bars, TransactionType.Sell, OrderType.Market, 0, "RebalanceLive");                tres.Quantity = qtyBroker - qtyNeeded;             }             else if (qtyBroker < qtyNeeded) // buy shares             {                tres = PlaceTrade(bars, TransactionType.Buy, OrderType.Market, 0, "RebalanceLive");                tres.Quantity = qtyNeeded - qtyBroker;             }          }          return tres;       }       public BrokerAccount GetBrokerAccount(string acct)       {          foreach (BrokerBase broker in SignalManager.Brokers)          {             BrokerAccount ba = broker.FindAccount(acct);             if (ba != null)                return ba;          }          return null;       }    } }
1
- ago
#11
CONE! YOU ROCK!

I ran your stuff, saw what it did, and I've made some modifications. I'm probably gonna learn some more now lol... But with my mods it runs the backtest and rebalances properly at the right times. When run with the strategy monitor, it stages orders! This is huge progress! I have some questions...

1. Why did you hardcode the broker account id. Seems like i could just get it from the Backtester.LiveAccount. Is there a problem with that?

2. When running the backtest, it didn't actually rebalance at the right times before. It only rebalanced once. I now check the execution mode and got the backtester to rebalance monthly. Do you see an issue with this change?

3. Finally, when i ran it with strategy monitor on my alpaca paper account, i selected "% of equity" and told it to use 10% of the account value. It totally ignored that and alllocated based on the _allocation percentage of the brokerAccount.AccountValue. I can easily hardcode the percentage of the account I want this strategy to use. But maybe I can access the % of account equity variable somewhere and use that in the strategy?

Anyway, this is huge! Thanks for the help!

CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Data; using WealthLab.Indicators; using System.Collections.Generic; using System.Linq; namespace WealthScript7 {    public class MyGlobalEightyTwentyReplica : UserStrategyBase    {       static Dictionary<string, double> _allocation = new();       public override void BacktestBegin()       {          //add allocations for each of your symbols. The DataSet must contain these symbols (and cah also have others)          _allocation["VT"] = 79;          _allocation["BNDW"] = 20;       }       //create indicators and other objects here, this is executed prior to the main trading loop       public override void Initialize(BarHistory bars)       {       }       //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 (ExecutionMode == StrategyExecutionMode.StrategyMonitor)          {             if (idx == bars.Count - 1 || bars.DateTimes[idx].IsLastTradingDayOfMonth(bars))             {                RebalanceLive(bars);             }          }          else          {             if (idx == 0 || bars.DateTimes[idx].IsLastTradingDayOfMonth(bars))             {                WriteToDebugLog($"Rebalancing {bars.Symbol} at {bars.DateTimes[idx].ToShortDateString()}");                Rebalance(bars, _allocation[bars.Symbol]);             }          }       }       public Transaction RebalanceLive(BarHistory bars)       {          Transaction trade = null;          if (!_allocation.ContainsKey(bars.Symbol))             return null;          BrokerAccount brokerAccount = Backtester.LiveAccount;          if (brokerAccount != null)          {             double qtyNeeded = Math.Floor(_allocation[bars.Symbol] / 100d * brokerAccount.AccountValue / bars.LastValue);             double qtyBroker = 0;             //find the shares if a position for bars.Symbol exists             foreach (BrokerPosition bp in brokerAccount.Positions)             {                if (bp.Symbol == bars.Symbol)                {                   qtyBroker = bp.Quantity;                   break;                }             }             if (qtyBroker > qtyNeeded) //sell shares             {                trade = PlaceTrade(bars, TransactionType.Sell, OrderType.Market, 0, "RebalanceLive");                trade.Quantity = qtyBroker - qtyNeeded;             }             else if (qtyBroker < qtyNeeded) // buy shares             {                trade = PlaceTrade(bars, TransactionType.Buy, OrderType.Market, 0, "RebalanceLive");                trade.Quantity = qtyNeeded - qtyBroker;             }          }          return trade;       }    } }
0
Cone8
 ( 4.98% )
- ago
#12
1. Re: Backtester.LiveAccount.
Sure, you can do that, but it's available only in the Strategy Monitor and Streaming Charts.

2. Change(s) look fine. Nice job.

3. When a strategy assigns Quantity to the Transaction, that's a manual override and position sizing in the settings is ignored.
But good thinking - you can get the sizing amount from the settings like this:

CODE:
// the amount set for % double pct = Backtester.Strategy.PositionSize.Amount / 100.0; // Also, to avoid errors when running with other symbols you should add this check that I missed for the backtest Rebalance -                WriteToDebugLog($"Rebalancing {bars.Symbol} at {bars.DateTimes[idx].ToShortDateString()}");                if (_allocation.ContainsKey(bars.Symbol))                   Rebalance(bars, _allocation[bars.Symbol]);
1
- ago
#13
Thanks Cone! Seems to be working!!
1

Reply

Bookmark

Sort