-
Notifications
You must be signed in to change notification settings - Fork 431
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CorporateActions: new algo to model dividends and splits #382
base: master
Are you sure you want to change the base?
Conversation
Codecov ReportAttention: Patch coverage is
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. Additional details and impacted files@@ Coverage Diff @@
## master #382 +/- ##
==========================================
- Coverage 45.50% 45.24% -0.27%
==========================================
Files 4 4
Lines 1936 1954 +18
Branches 449 455 +6
==========================================
+ Hits 881 884 +3
- Misses 998 1013 +15
Partials 57 57 ☔ View full report in Codecov by Sentry. |
this needs a test but otherwise lgtm |
This is an initial proposal for an algo to model dividends and splits. The intention is to be able to use unadjusted price data and to get historically correct transactions (position sizes and commissions). It should be tested more extensively before adoption. The only way I could find to change positions due to splits on the fly was by changing the `_position` member on each security (otherwise security and portfolio values wouldn't be updated correctly). This requires the algo to be run on every row and so, it needs to be positioned before any algos that skip bars, such as RunMonthly. This and other constraints are described in the last paragraph of the docstring. This algorithm could be improved by someone more familiar with the library internals. The input data is similar to what can be obtained from free sources such as Yahoo Finance. An example is provided below, showing backtests with adjusted prices and unadjusted prices with splits and dividends. The results will not be identical, since adjusted data considers that the dividend inflows are reinvested on the same security at the `ex` date. The simulation using CorporateActions will get the dividend inflows as cash at the `ex` date, but the cash will be reinvested on the whole portfolio only at the next rebalancing event. Finally, this simulation doesn't completely correspond to reality since dividends are paid at a later time and not on the `ex` date. But since data about payment dates is not easy to obtain, this improvement was left for the future. Sample code: ``` import pandas as pd import yahooquery as yq import bt data = yq.Ticker(['GLD', 'TLT', 'VTI']).history(period='max', interval='1d').unstack('symbol') data.index = pd.to_datetime(data.index) divs = data['dividends'] splits = data['splits'].replace(0.0, 1.0) close = data['adjclose'] splits_multiplier = splits.sort_index(ascending=False).cumprod().shift(1).ffill().fillna(1.0).sort_index() unadjclose = data['close'] * splits_multiplier s_adj = bt.Strategy('adj', [ bt.algos.RunMonthly(run_on_end_of_period=True), bt.algos.SelectAll(), bt.algos.WeighEqually(), bt.algos.Rebalance()]) s_div = bt.Strategy('div', [ bt.algos.CorporateActions(divs, splits), bt.algos.RunMonthly(run_on_end_of_period=True), bt.algos.SelectAll(), bt.algos.WeighEqually(), bt.algos.Rebalance()]) b_adj = bt.Backtest(s_adj, close, initial_capital=100000, commissions=lambda quantity, price: 0, integer_positions=False) b_div = bt.Backtest(s_div, unadjclose, initial_capital=100000, commissions=lambda quantity, price: 0, integer_positions=True) r = bt.run(b_adj, b_div) r.display() r.plot() ``` Update algos.py Removed white space on empty lines.
Merge from upstream
Added test, please move it if appropriate. |
…olumns); added extra price column on test data to check
This is an initial proposal for an algo to model dividends and splits. The intention is to be able to use unadjusted price data and to get historically correct transactions (position sizes and commissions). It should be tested more extensively before adoption.
The only way I could find to change positions due to splits on the fly was by changing the
_position
member on each security (otherwise security and portfolio values wouldn't be updated correctly). This requires the algo to be run on every row and so, it needs to be positioned before any algos that skip bars, such as RunMonthly. This and other constraints are described in the last paragraph of the docstring. This algorithm could be improved by someone more familiar with the library internals.The input data is similar to what can be obtained from free sources such as Yahoo Finance. An example is provided below, showing backtests with adjusted prices and unadjusted prices with splits and dividends. The results will not be identical, since adjusted data considers that the dividend inflows are reinvested on the same security at the 'ex' date. The simulation using CorporateActions will get the dividend inflows as cash at the
ex
date, but the cash will be reinvested on the whole portfolio only at the next rebalancing event.Finally, this simulation doesn't completely correspond to reality since dividends are paid at a later time and not on the 'ex' date. But since data about payment dates is not easy to obtain, this improvement was left for the future.
Sample code: