- ago
I built a simple buy and hold test strategy but I'm finding that, when comparing the strategy to the same symbol as a benchmark I'm getting different return results. Using SPY as an example:
- There is only one entry, in 1996, and no sales
- however, the exposure in the benchmark is right, 99.96%, but the exposure in the strategy is only 87.9%
- the difference in return seems to start around 2011, and in 2019 the cash balance starts to grow. Cash interest is much higher as well.

This seems to say that there is no dividend reinvestment. How can I add this to the code below? And does the benchmark testing assume reinvestment?


CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Data; using WealthLab.Indicators; using System.Collections.Generic; namespace WealthScript5 { public class MyStrategy : UserStrategyBase {     public MyStrategy() : base() { StartIndex = 1; } public override void Initialize(BarHistory bars) { foreach(IndicatorBase ib in _startIndexList) if (ib.FirstValidIndex > StartIndex) StartIndex = ib.FirstValidIndex; } public override void Execute(BarHistory bars, int idx) {          int index = idx;          Backtester.CancelationCode = 1;          _transaction = PlaceTrade(bars, TransactionType.Buy, OrderType.Market, 0, 0, "Buy At Market (1)"); }       private Transaction _transaction; private List<IndicatorBase> _startIndexList = new List<IndicatorBase>(); } }
0
190
Solved
18 Replies

Reply

Bookmark

Sort
Cone8
 ( 12.18% )
- ago
#1
CODE:
using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Data; using WealthLab.Indicators; using System.Collections.Generic; namespace WealthScript5 {    public class MyStrategy : UserStrategyBase    {       public MyStrategy() : base()       {          StartIndex = 1;       }       public override void Initialize(BarHistory bars)       {       }       public override void Execute(BarHistory bars, int idx)       {             // if there's enough cash to buy at least 1 share, buy them          if (CurrentCash > bars.Close[idx])          {             _t = PlaceTrade(bars, TransactionType.Buy, OrderType.Market, 0, 0, $"Buy At Market: ${CurrentCash:N2}");             _t.Quantity = CurrentCash / bars.Close[idx];          }       }       private Transaction _t;    } }
0
Glitch8
 ( 9.17% )
- ago
#2
Translation: our benchmark strategy re-invests dividends.
0
- ago
#3
Thanks, gents.

So, I ran it with SPY and it worked great - they match up. However, when I run it with JEPI (covered call ETF) the dividends don't show up on this symbol.

Is there a different code that I should use?
0
Cone8
 ( 12.18% )
- ago
#4
Why would the code be different for that symbol?
For me it's close enough to a perfect match not to want to investigate.
0
Cone8
 ( 12.18% )
- ago
#5
Actually, I know why it's slightly different.. the code above is buying fractional shares, but the benchmark buys an integer number. Just change _t.Quantity to:

CODE:
_t.Quantity = (int)CurrentCash / bars.Close[idx];
1
Best Answer
- ago
#6
Castings take higher precedence over division. And you knew that.

CODE:
_t.Quantity = (int)(CurrentCash / bars.Close[idx]);
0
- ago
#7
Thanks all.

When I run the code, it will place one trade on dividends but none after that. Do I have this right?

CODE:
      public override void Execute(BarHistory bars, int idx)       {          // if there's enough cash to buy at least 1 share, buy them          if (CurrentCash > bars.Close[idx])          {             _t = PlaceTrade(bars, TransactionType.Buy, OrderType.Market, 0, 0, $"Buy At Market: ${CurrentCash:N2}");             _t.Quantity = (int)CurrentCash / bars.Close[idx];          }       }
0
- ago
#8
QUOTE:
Do I have this right?

Your expression for t.Quantity in Post #7 is still computing a "real" when you want an "integer". You need to study Post #6 for the correction. Do you understand operator "precedence" for C#? By default, casting takes greater precedence over division. That's why Post #6 has added the parentheses. You want the division to occur before the cast to integer, which is not the C# default behavior.

QUOTE:
it will place one trade on dividends but none after that.

Is that a problem? What matters is that your investment on the market grows with the dividends paid to the shares you already own. "Most" Historical providers (for BarHistory) are factoring that into the prices they're showing automatically. That dividend-inclusion behavior suppose to be a positive feature.
0
Cone8
 ( 12.18% )
- ago
#9
If "Collect Dividends" is selected in Preferences > Backtest,
AND you have an Event provider selected that can supply dividends,
AND the position is large enough to generate enough cash by collecting dividends to buy at least 1 share at the current market price,
it will work.

Check the Equity Curve for Cash or use WriteToDebugLog() in the strategy to see the values at play.
0
- ago
#10
I figured out the issue.

I had "Collect Dividends" selected in the Backtest tab of Preferences, but I did not have dividends selected under Event Providers for Yahoo! Finance.

FYI, IQFeed does not provide dividends for ETFs generally.
0
- ago
#11
QUOTE:
... IQFeed does not provide dividends for ETFs generally.

IQFeed, as a historical provider, doesn't provide any real fundamentals, including dividends. You need an event provider for that.

However, IQFeed does include the reinvested dividends in the historical stock prices it returns--they are "price corrected". I can't speak for ETFs, though. I kind of thought they were price corrected as well.
0
Cone8
 ( 12.18% )
- ago
#12
Re: IQFeed does include the reinvested dividends in the historical stock prices it returns--they are "price corrected".

That's off topic and untrue. IQFeed does not adjust for regular dividends or even smallish special dividends. And, they don't even adjust intraday data for splits (WealthLab's IQFeed provider does that).

IQFeed does adjust for some large special dividends and corporate events in EOD, but they're not consistent about it. A year or two ago, I gave them a list of about 100 events that they had missed; weeks later they told me that had adjusted them (but I didn't check on it).
1
- ago
#13
Ok, next issue.

I'm building a Meta analysis on multiple buy & hold funds. I entered a specific % for each fund, let's say 5%, but the first fund enters at 100% and the remaining funds barely get invested.

Is there a setting to enforce the percent invested on each fund?
0
Cone8
 ( 12.18% )
- ago
#14
You entered a "specific %" where?
What strategy are you using? (You certainly can't use the one above for that.)
0
- ago
#15
QUOTE:
Re: IQFeed does include the reinvested dividends in the historical stock prices it returns--they are "price corrected".

That's off topic and untrue. IQFeed does not adjust for regular dividends or even smallish special dividends. And, they don't even adjust intraday data for splits (WealthLab's IQFeed provider does that).

What I meant is that the prices WL "sees" via the WL IQFeed provider has adjusted prices. But I greatly appreciate your clarification. This explains why some WL historical price providers have a checkbox to enable/disable this price correcting on or off.
0
- ago
#16
The specific % is in the metastrategy settings.

Why wouldn't I be able to use the individual strategies using the code above in the meta strategy?

0
Cone8
 ( 12.18% )
- ago
#17
The Common Capital Pool setting would make a big difference here.

Anyway, the strategy above just takes "all the CurrentCash" and the first symbol that executes that statement gets all the cash.

Reinvesting dividend cash from "AVDV" back into "AVDV" will require more logic. It's probably a small Concierge job, unless superticker wants to knock it out for you.
0
- ago
#18
QUOTE:
It's probably a small Concierge job, unless superticker wants to knock it out for you.

I don't use Meta strategies. Instead, my entry and exit points look like this:
CODE:
      public override void Execute(BarHistory bars, int idx)       {          if (HasOpenPosition(bars, PositionType.Long))          {             //sell conditions below             if (...)             else if (...)             else if (...)             else if (...)          }          else          {             //buy conditions below             if (...)             else if (...)             else if (...)             else if (...)                      }       }
Of course you could use this approach to decimate your CurrentCash into different parts (accounts).

Not to change topics, but if your goal is to Buy & Hold, then I would recommend a Modern Portfolio Theory (MPT) approach to investing. IMPORTANT: If MPT is new to you, I would buy a book and read about it. One popular MPT method is called Efficient Frontier, and you may have heard of it because the developer got the Nobel Prize in Economics for it. Moreover, Fidelity Investments employs Efficient Frontier in many of its Mutual Funds because their customers are in higher tax brackets and want to compound their investments without turnover and get that Mitt capital-gains tax rate of 15%.

I've personally used Fidelity Select Sector Funds for one account, which employs Efficient Frontier, and made 22% in the last 12 months, which is very good for high-risk mutual funds. But we really need to start a new topic about MPT if you want to talk more.

You might want to search the Internet for a forum to discuss MPT methods or Efficient Frontier because WL doesn't support Buy & Hold methods out of the box. A partial exception might be https://www.wealth-lab.com/extension/detail/Portfolio123, but I haven't used it. Portfolio123 does have a forum, so you can ask them about MPT methods. They might have a portfolio setup that's optimized around one of the MPT methods.
2

Reply

Bookmark

Sort