Skip to content

Commit

Permalink
Separate context for after_order_func_nb
Browse files Browse the repository at this point in the history
  • Loading branch information
polakowo committed May 22, 2021
1 parent 55b833c commit 866b46c
Show file tree
Hide file tree
Showing 12 changed files with 1,173 additions and 665 deletions.
Binary file modified docs/img/simulate_nb.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/img/simulate_row_wise_nb.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 21 additions & 23 deletions examples/PairsTrading.ipynb

Large diffs are not rendered by default.

324 changes: 162 additions & 162 deletions examples/PortfolioOptimization.ipynb

Large diffs are not rendered by default.

142 changes: 71 additions & 71 deletions tests/notebooks/portfolio.ipynb

Large diffs are not rendered by default.

415 changes: 272 additions & 143 deletions tests/test_portfolio.py

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions vectorbt/_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ def reset_theme(self) -> None:
signal_direction='longonly',
order_direction='all',
cash_sharing=False,
update_value=False,
row_wise=False,
use_numba=True,
seed=None,
Expand Down
2 changes: 1 addition & 1 deletion vectorbt/data/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ def download(cls: tp.Type[BinanceDataT],
def download_symbol(cls,
symbol: str,
client: tp.Optional["ClientT"] = None,
interval: tp.Optional[str] = None,
interval: str = '1d',
start: tp.DatetimeLike = 0,
end: tp.DatetimeLike = 'now UTC',
delay: tp.Optional[float] = 500,
Expand Down
8 changes: 4 additions & 4 deletions vectorbt/indicators/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -3559,7 +3559,7 @@ def apply_func(input_list: tp.List[tp.SeriesFrame],
return np.column_stack(outputs)

defaults = config.pop('defaults')
TALibIndicator = cls(
PTAIndicator = cls(
**merge_dicts(
config,
init_kwargs
Expand All @@ -3572,7 +3572,7 @@ def apply_func(input_list: tp.List[tp.SeriesFrame],
**defaults,
**kwargs
)
return TALibIndicator
return PTAIndicator

@classmethod
def get_ta_indicators(cls) -> tp.Set[str]:
Expand Down Expand Up @@ -3740,7 +3740,7 @@ def apply_func(input_list: tp.List[tp.SeriesFrame],
return np.column_stack(outputs)

defaults = config.pop('defaults')
TALibIndicator = cls(
TAIndicator = cls(
**merge_dicts(
config,
init_kwargs
Expand All @@ -3753,4 +3753,4 @@ def apply_func(input_list: tp.List[tp.SeriesFrame],
**defaults,
**kwargs
)
return TALibIndicator
return TAIndicator
94 changes: 53 additions & 41 deletions vectorbt/portfolio/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -632,14 +632,15 @@ def from_signals(cls: tp.Type[PortfolioT],
reject_prob: tp.Optional[tp.ArrayLike] = None,
allow_partial: tp.Optional[tp.ArrayLike] = None,
raise_reject: tp.Optional[tp.ArrayLike] = None,
accumulate: tp.Optional[tp.ArrayLike] = None,
log: tp.Optional[tp.ArrayLike] = None,
accumulate: tp.Optional[tp.ArrayLike] = None,
conflict_mode: tp.Optional[tp.ArrayLike] = None,
close_first: tp.Optional[tp.ArrayLike] = None,
val_price: tp.Optional[tp.ArrayLike] = None,
init_cash: tp.Optional[tp.ArrayLike] = None,
cash_sharing: tp.Optional[bool] = None,
call_seq: tp.Optional[tp.ArrayLike] = None,
update_value: tp.Optional[tp.ArrayLike] = None,
max_orders: tp.Optional[int] = None,
max_logs: tp.Optional[int] = None,
seed: tp.Optional[int] = None,
Expand Down Expand Up @@ -735,27 +736,24 @@ def from_signals(cls: tp.Type[PortfolioT],
the opposite position. This allows to define parameters such as `fixed_fees` for long
and short positions separately.
val_price (array_like of float): Asset valuation price.
Defaults to `price` if set, otherwise to previous `close`.
See `val_price` in `Portfolio.from_orders`.
init_cash (InitCashMode, float or array_like of float): Initial capital.
See `init_cash` in `Portfolio.from_order_func`.
See `init_cash` in `Portfolio.from_orders`.
cash_sharing (bool): Whether to share cash within the same group.
See `cash_sharing` in `Portfolio.from_orders`.
call_seq (CallSeqType or array_like of int): Default sequence of calls per row and group.
See `call_seq` in `Portfolio.from_orders`.
update_value (bool): Whether to update group value after each filled order.
max_orders (int): Size of the order records array.
Defaults to the number of elements in the broadcasted shape.
Set to a lower number if you run out of memory.
See `max_orders` in `Portfolio.from_orders`.
max_logs (int): Size of the log records array.
Defaults to the number of elements in the broadcasted shape if any of the `log` is True,
otherwise to 1.
Set to a lower number if you run out of memory.
See `max_logs` in `Portfolio.from_orders`.
seed (int): Seed to be set for both `call_seq` and at the beginning of the simulation.
group_by (any): Group columns. See `vectorbt.base.column_grouper.ColumnGrouper`.
broadcast_kwargs (dict): Keyword arguments passed to `vectorbt.base.reshape_fns.broadcast`.
Expand Down Expand Up @@ -973,7 +971,7 @@ def from_signals(cls: tp.Type[PortfolioT],
!!! note
By cleaning signals, you lose information. Moreover, this automatically assumes
that each entry/signal signal succeeds (= order gets filled). Use this with caution,
and consider rewriting your strategy for `Portfolio.from_order_func`, which is a
and consider rewriting your strategy with `Portfolio.from_order_func`, which is a
preferred way of defining complex logic in vectorbt.
"""
# Get defaults
Expand Down Expand Up @@ -1035,6 +1033,8 @@ def from_signals(cls: tp.Type[PortfolioT],
if call_seq == CallSeqType.Auto:
call_seq = CallSeqType.Default
auto_call_seq = True
if update_value is None:
update_value = portfolio_cfg['update_value']
if seed is None:
seed = portfolio_cfg['seed']
if seed is not None:
Expand All @@ -1055,9 +1055,9 @@ def from_signals(cls: tp.Type[PortfolioT],
entries,
exits,
size,
price,
size_type,
direction,
price,
fees,
fixed_fees,
slippage,
Expand All @@ -1066,8 +1066,8 @@ def from_signals(cls: tp.Type[PortfolioT],
reject_prob,
allow_partial,
raise_reject,
accumulate,
log,
accumulate,
conflict_mode,
close_first,
val_price
Expand Down Expand Up @@ -1100,8 +1100,9 @@ def from_signals(cls: tp.Type[PortfolioT],
cs_group_lens, # group only if cash sharing is enabled to speed up
init_cash,
call_seq,
auto_call_seq,
*broadcasted_args[1:],
auto_call_seq,
update_value,
max_orders,
max_logs,
close.ndim == 2
Expand Down Expand Up @@ -1139,6 +1140,7 @@ def from_orders(cls: tp.Type[PortfolioT],
init_cash: tp.Optional[tp.ArrayLike] = None,
cash_sharing: tp.Optional[bool] = None,
call_seq: tp.Optional[tp.ArrayLike] = None,
update_value: tp.Optional[tp.ArrayLike] = None,
max_orders: tp.Optional[int] = None,
max_logs: tp.Optional[int] = None,
seed: tp.Optional[int] = None,
Expand Down Expand Up @@ -1223,7 +1225,14 @@ def from_orders(cls: tp.Type[PortfolioT],
otherwise you're cheating yourself.
init_cash (InitCashMode, float or array_like of float): Initial capital.
See `init_cash` in `Portfolio.from_order_func`.
By default, will broadcast to the number of columns.
If cash sharing is enabled, will broadcast to the number of groups.
See `vectorbt.portfolio.enums.InitCashMode` to find optimal initial cash.
!!! note
Mode `InitCashMode.AutoAlign` is applied after the portfolio is initialized
to set the same initial cash for all columns/groups. Changing grouping
will change the initial cash, so be aware when indexing.
cash_sharing (bool): Whether to share cash within the same group.
!!! warning
Expand Down Expand Up @@ -1260,6 +1269,7 @@ def from_orders(cls: tp.Type[PortfolioT],
leave them without required funds.
For more control, use `Portfolio.from_order_func`.
update_value (bool): Whether to update group value after each filled order.
max_orders (int): Size of the order records array.
Defaults to the number of elements in the broadcasted shape.
Expand Down Expand Up @@ -1419,6 +1429,8 @@ def from_orders(cls: tp.Type[PortfolioT],
if call_seq == CallSeqType.Auto:
call_seq = CallSeqType.Default
auto_call_seq = True
if update_value is None:
update_value = portfolio_cfg['update_value']
if seed is None:
seed = portfolio_cfg['seed']
if seed is not None:
Expand All @@ -1437,9 +1449,9 @@ def from_orders(cls: tp.Type[PortfolioT],
broadcastable_args = (
close,
size,
price,
size_type,
direction,
price,
fees,
fixed_fees,
slippage,
Expand Down Expand Up @@ -1479,8 +1491,9 @@ def from_orders(cls: tp.Type[PortfolioT],
cs_group_lens, # group only if cash sharing is enabled to speed up
init_cash,
call_seq,
auto_call_seq,
*broadcasted_args[1:],
auto_call_seq,
update_value,
max_orders,
max_logs,
close.ndim == 2
Expand Down Expand Up @@ -1519,6 +1532,7 @@ def from_order_func(cls: tp.Type[PortfolioT],
segment_prep_args: tp.Optional[tp.Args] = None,
after_order_func_nb: tp.Optional[nb.AfterOrderFuncT] = None,
after_order_args: tp.Optional[tp.Args] = None,
update_value: tp.Optional[tp.ArrayLike] = None,
row_wise: tp.Optional[bool] = None,
use_numba: tp.Optional[bool] = None,
max_orders: tp.Optional[int] = None,
Expand Down Expand Up @@ -1549,14 +1563,7 @@ def from_order_func(cls: tp.Type[PortfolioT],
Should be set only if `target_shape` is bigger than `close.shape`.
init_cash (InitCashMode, float or array_like of float): Initial capital.
By default, will broadcast to the number of columns.
If cash sharing is enabled, will broadcast to the number of groups.
See `vectorbt.portfolio.enums.InitCashMode` to find optimal initial cash.
!!! note
Mode `InitCashMode.AutoAlign` is applied after the portfolio is initialized
to set the same initial cash for all columns/groups. Changing grouping
will change the initial cash, so be aware when indexing.
See `init_cash` in `Portfolio.from_orders`.
cash_sharing (bool): Whether to share cash within the same group.
!!! warning
Expand Down Expand Up @@ -1597,6 +1604,7 @@ def from_order_func(cls: tp.Type[PortfolioT],
after_order_args (tuple): Packed arguments passed to `after_order_func_nb`.
Defaults to `()`.
update_value (bool): Whether to update group value after each filled order.
row_wise (bool): Whether to iterate over rows rather than columns/groups.
See `vectorbt.portfolio.nb.simulate_row_wise_nb`.
Expand Down Expand Up @@ -1648,7 +1656,7 @@ def from_order_func(cls: tp.Type[PortfolioT],
>>> @njit
... def order_func_nb(c, size):
... return create_order_nb(size=size, price=c.close[c.i, c.col])
... return create_order_nb(size, c.close[c.i, c.col])
>>> close = pd.Series([1, 2, 3, 4, 5])
>>> portfolio = vbt.Portfolio.from_order_func(close, order_func_nb, 10)
Expand Down Expand Up @@ -1693,24 +1701,24 @@ def from_order_func(cls: tp.Type[PortfolioT],
... size = np.inf # open long
... last_pos_state[0] = 1
...
... return create_order_nb(size=size, price=c.close[c.i, c.col])
... return create_order_nb(size, c.close[c.i, c.col])
>>> portfolio = vbt.Portfolio.from_order_func(
... close, order_func_nb, group_prep_func_nb=group_prep_func_nb)
>>> portfolio.shares()
0 100.0
1 0.0
2 -100.0
3 0.0
4 20.0
0 100.000000
1 0.000000
2 -66.666667
3 0.000000
4 26.666667
dtype: float64
>>> portfolio.cash()
0 0.0
1 200.0
2 500.0
3 100.0
4 0.0
0 0.000000
1 200.000000
2 400.000000
3 133.333333
4 0.000000
dtype: float64
```
Expand Down Expand Up @@ -1742,10 +1750,10 @@ def from_order_func(cls: tp.Type[PortfolioT],
... def order_func_nb(c, size, size_type, direction, fees, fixed_fees, slippage):
... '''Place an order.'''
... return create_order_nb(
... size=size,
... size,
... c.close[c.i, c.col],
... size_type=size_type,
... direction=direction,
... price=c.close[c.i, c.col],
... fees=fees,
... fixed_fees=fixed_fees,
... slippage=slippage
Expand Down Expand Up @@ -1797,14 +1805,14 @@ def from_order_func(cls: tp.Type[PortfolioT],
... if entries[c.i, c.col]:
... if c.shares_now == 0:
... return create_order_nb(
... size=size_now,
... price=price_now,
... size_now,
... price_now,
... direction=Direction.LongOnly)
... elif exits[c.i, c.col] or price_now >= stop_price_now:
... if c.shares_now > 0:
... return create_order_nb(
... size=-size_now,
... price=price_now,
... -size_now,
... price_now,
... direction=Direction.LongOnly)
... return NoOrder
Expand Down Expand Up @@ -1895,6 +1903,8 @@ def from_order_func(cls: tp.Type[PortfolioT],
"Use sort_call_seq_nb in segment_prep_func_nb.")
if active_mask is None:
active_mask = True
if update_value is None:
update_value = portfolio_cfg['update_value']
if row_wise is None:
row_wise = portfolio_cfg['row_wise']
if use_numba is None:
Expand Down Expand Up @@ -1997,6 +2007,7 @@ def from_order_func(cls: tp.Type[PortfolioT],
order_args,
after_order_func_nb,
after_order_args,
update_value,
max_orders,
max_logs
)
Expand All @@ -2023,6 +2034,7 @@ def from_order_func(cls: tp.Type[PortfolioT],
order_args,
after_order_func_nb,
after_order_args,
update_value,
max_orders,
max_logs
)
Expand Down
Loading

0 comments on commit 866b46c

Please sign in to comment.