edtechre / pybroker

Algorithmic Trading in Python with Machine Learning
https://www.pybroker.com
Other
1.94k stars 246 forks source link

Rotational Trading not working when using start_of_month #98

Closed none2003 closed 8 months ago

none2003 commented 8 months ago

Hi @edtechre,

I was testing "10. Rotational Trading.ipynb", but this time I want the rebalancing been performed only at the begin of the month, rather than every bar. So I copied "start_of_month" function from "9. Rebalancing Positions.ipynb" and revised function "rotate" like:

def rotate(ctx: ExecContext):
    if start_of_month(ctx.dt): # <--- adding start_of_month here
        if ctx.long_pos():
            if ctx.symbol not in pyb.param('top_symbols'):
                ctx.sell_all_shares()
        else:
            target_size = pyb.param('target_size')
            ctx.buy_shares = ctx.calc_target_shares(target_size)
            ctx.score = ctx.indicator('roc_20')[-1]

I remain rest of notebook like original. Then odd thing happened, after backtesting, "result.orders" shows only AAPL have trading record. And dut to "max_long_positions=2" and "pyb.param('rank_threshold', 5)", I guess only trading one symbol is not right.

result.orders of rebalance every bars: 1 buy NFLX 2018-02-01 184 NaN 267.67 0.0 2 buy AMD 2018-02-01 3639 NaN 13.53 0.0 3 sell AMD 2018-02-05 3639 NaN 11.56 0.0 4 buy AMZN 2018-02-05 627 NaN 69.49 0.0 5 sell AMZN 2018-04-03 627 NaN 69.23 0.0 6 sell NFLX 2018-04-03 184 NaN 284.63 0.0 7 buy INTC 2018-04-03 966 NaN 49.18 0.0 8 buy MSFT 2018-04-03 534 NaN 88.97 0.0 9 sell INTC 2018-04-26 966 NaN 52.67 0.0 10 buy META 2018-04-26 297 NaN 173.54 0.0 ...

result.orders of rebalance every month: 1 buy AAPL 2018-02-01 1194 NaN 41.92 0.0 2 sell AAPL 2018-02-02 1194 NaN 40.86 0.0 3 buy AAPL 2018-03-02 1128 NaN 43.59 0.0 4 sell AAPL 2018-05-02 1128 NaN 43.94 0.0 5 buy AAPL 2018-06-04 1042 NaN 48.10 0.0 ...

I uploaded my notebook here, please take a look if it's a pyb bug. Much appreciate.

10. Rotational Trading.zip

edtechre commented 8 months ago

Hi @none2003,

That is because of the code you copied:

def start_of_month(dt: datetime) -> bool:
    if dt.month != pyb.param('current_month'):
        pyb.param('current_month', dt.month)
        return True
    return False

That will overwrite the current_month param, limiting you to only one symbol per month. It only returns True once per month, and will return False for the other symbols. The original notebook you referenced calls start_of_month in the set_after_exec callback for multiple symbols.