Skip to content
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

BT seems unable to composite three or more layers strategy, ZeroDivisionError #433

Open
tunkills opened this issue Jan 15, 2024 · 4 comments

Comments

@tunkills
Copy link

tunkills commented Jan 15, 2024

When I only composite two layers strategy,it woks well, but when I add more layer strategy,such as there is a grandson strategy, threre is something wrong!
"ZeroDivisionError: Could not update third on 2017-01-02 00:00:00. Last value was 0 and net flows were 0. Currentvalue is 1000000.0. Therefore, we are dividing by zero to obtain the return for the period."


import numpy as np
import pandas as pd
import bt
import warnings


warnings.simplefilter('ignore', FutureWarning)
warnings.simplefilter('ignore', UserWarning)


# create fake index data

names = ['foo', 'bar', 'rf']

dates = pd.date_range('20170101', '20171231', freq=pd.tseries.offsets.BDay())
n = len(dates)

rdf = pd.DataFrame(np.zeros((n, len(names))), index=dates, columns=names)

np.random.seed(1)
rdf['foo'] = np.random.normal(loc=0.1/n, scale=0.2/np.sqrt(n), size=n)
rdf['bar'] = np.random.normal(loc=0.04/n, scale=0.05/np.sqrt(n), size=n)
rdf['rf'] = 0.0

pdf = 100 * np.cumprod(1+rdf)

# composite three layer strategy
weights = pd.Series([0.6, 0.2, 0.1], index=rdf.columns)
strat = bt.Strategy('static',
                    [bt.algos.RunMonthly(run_on_first_date=True),
                     bt.algos.WeighSpecified(**weights),
                     bt.algos.Rebalance()]
                    )

second_strat = bt.Strategy('second',
                           [bt.algos.RunMonthly(run_on_first_date=True),
                            bt.algos.SelectAll(),
                            bt.algos.WeighEqually(),
                            bt.algos.Rebalance()],
                           children=[strat, 'foo'])

third_strat = bt.Strategy('third',
                          [bt.algos.RunMonthly(run_on_first_date=True),
                           bt.algos.SelectAll(),
                           bt.algos.WeighEqually(),
                           bt.algos.Rebalance()],
                          children=[second_strat, 'bar'])
third_bk = bt.Backtest(third_strat, pdf, integer_positions=False)
third_re = bt.run(third_bk)

``

File "bt/core.py", line 777, in bt.core.StrategyBase.update

ZeroDivisionError: Could not update third on 2017-01-02 00:00:00. Last value was 0 and net flows were 0. Currentvalue is 1000000.0. Therefore, we are dividing by zero to obtain the return for the period.
`

I find the problem may be caused by


class StrategyBase(Node):
......
    @cy.locals(
        newpt=cy.bint,
        val=cy.double,
        ret=cy.double,
        coupons=cy.double,
        notl_val=cy.double,
        bidoffer_paid=cy.double,
    )
    def update(self, date, data=None, inow=None):
    .......
     # update paper trade if necessary
        if self._paper_trade:
            if newpt:
                self._paper.update(date)
                self._paper.run()
                self._paper.update(date)
            # update price
            self._price = self._paper.price
            self._prices.values[inow] = self._price`

when I comment out the lines “if self._paper_trade:” and below, it works well.
But I'm not sure if this modification will cause other issues.

@timkpaine
Copy link
Collaborator

If I recall, usually this occurs when you don't take any positions over the whole backtest.

@tunkills
Copy link
Author

tunkills commented Jan 16, 2024

If I recall, usually this occurs when you don't take any positions over the whole backtest.

it happens at the first day, the strategy just begin, no matter what strategy, if the layer is three or more, it will give the sample error, you can just backtest and run from the second layer, it works well, so its not the problem of positions!If you have a three layers strategy, and it works well, could you provide me with the code, I'd appreciate it

@tunkills
Copy link
Author

tunkills commented Jan 16, 2024

If I recall, usually this occurs when you don't take any positions over the whole backtest.

In the file core.py:
if the strategy is not the root strategy, the strategy will create a paper trade。
at the line 571:


class StrategyBase(Node):
......
    def setup(self, universe, **kwargs):
.....
        if self is not self.parent:  
            self._paper_trade = True
            self._paper_amount = 1000000

            paper = deepcopy(self)
            paper.parent = paper  
            paper.root = paper
            paper._paper_trade = False
            paper.setup(self._original_data, **kwargs) 
            paper.adjust(self._paper_amount)
            self._paper = paper

but we see when a children strategy update itself, the paper update iteself too。
at the line 767:

        self._price = self._last_price + ret
        self._prices.values[inow] = self._price

and at the line 827:

# update paper trade if necessary
        if self._paper_trade:
            if newpt:
                self._paper.update(date)
                self._paper.run()
                self._paper.update(date)
            # update price
            self._price = self._paper.price
            self._prices.values[inow] = self._price

that make me confused, if the self._paper_trade, it seems the paper just overwritten the original update。And I don't think the paper trading is required!

@youyixiao189cn
Copy link

If I recall, usually this occurs when you don't take any positions over the whole backtest.

it happens at the first day, the strategy just begin, no matter what strategy, if the layer is three or more, it will give the sample error, you can just backtest and run from the second layer, it works well, so its not the problem of positions!If you have a three layers strategy, and it works well, could you provide me with the code, I'd appreciate it

determine if needs paper trading

    # and setup if so
    #if self is not self.parent:       #old
    if False:  #self != self.parent:  # never ever
        self._paper_trade = True
        self._paper_amount = 1000000

        paper = deepcopy(self)
        paper.parent = paper
        paper.root = paper

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants