vectorbt
vectorbt copied to clipboard
Open short position right after closing long position with full capital
First of all, thanks for developing this excellent library!
My strategy will enter short/long position right after closing long/short position, while short/long signal happens. And each postion will entry with full capital
Here is my code:
start = '2019-01-01 UTC' # crypto is in UTC
end = '2020-01-01 UTC'
btc_price = vbt.YFData.download('BTC-USD', start=start, end=end).get('Close')
fast_ma = vbt.MA.run(btc_price, 10, short_name='fast')
slow_ma = vbt.MA.run(btc_price, 20, short_name='slow')
entries = fast_ma.ma_crossed_above(slow_ma)
exits = fast_ma.ma_crossed_below(slow_ma)
pf = vbt.Portfolio.from_signals(btc_price,
entries=entries,
exits=exits,
short_entries=exits,
short_exits=entries,
size = 1,
# size_type='amount',
size_type=2,
fees=0.001,
init_cash=1000)
And I got an error, seems like vectorbt does not support this behavior.
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[37], [line 12](vscode-notebook-cell:?execution_count=37&line=12)
[9](vscode-notebook-cell:?execution_count=37&line=9) entries = fast_ma.ma_crossed_above(slow_ma)
[10](vscode-notebook-cell:?execution_count=37&line=10) exits = fast_ma.ma_crossed_below(slow_ma)
---> [12](vscode-notebook-cell:?execution_count=37&line=12) pf = vbt.Portfolio.from_signals(btc_price,
[13](vscode-notebook-cell:?execution_count=37&line=13) entries=entries,
[14](vscode-notebook-cell:?execution_count=37&line=14) exits=exits,
[15](vscode-notebook-cell:?execution_count=37&line=15) short_entries=exits,
[16](vscode-notebook-cell:?execution_count=37&line=16) short_exits=entries,
[17](vscode-notebook-cell:?execution_count=37&line=17) size = 1,
[18](vscode-notebook-cell:?execution_count=37&line=18) # size_type='amount',
[19](vscode-notebook-cell:?execution_count=37&line=19) size_type=2,
[20](vscode-notebook-cell:?execution_count=37&line=20) fees=0.001,
[21](vscode-notebook-cell:?execution_count=37&line=21) init_cash=1000)
File [~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2960](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2960), in Portfolio.from_signals(cls, close, entries, exits, short_entries, short_exits, signal_func_nb, signal_args, size, size_type, price, fees, fixed_fees, slippage, min_size, max_size, size_granularity, reject_prob, lock_cash, allow_partial, raise_reject, log, accumulate, upon_long_conflict, upon_short_conflict, upon_dir_conflict, upon_opposite_entry, direction, val_price, open, high, low, sl_stop, sl_trail, tp_stop, stop_entry_price, stop_exit_price, upon_stop_exit, upon_stop_update, adjust_sl_func_nb, adjust_sl_args, adjust_tp_func_nb, adjust_tp_args, use_stops, init_cash, cash_sharing, call_seq, ffill_val_price, update_value, max_orders, max_logs, seed, group_by, broadcast_named_args, broadcast_kwargs, template_mapping, wrapper_kwargs, freq, attach_call_seq, **kwargs)
[2957](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2957) checks.assert_numba_func(adjust_tp_func_nb)
[2959](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2959) # Perform the simulation
-> [2960](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2960) order_records, log_records = nb.simulate_from_signal_func_nb(
[2961](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2961) target_shape_2d,
[2962](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2962) cs_group_lens, # group only if cash sharing is enabled to speed up
[2963](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2963) init_cash,
[2964](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2964) call_seq,
[2965](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2965) signal_func_nb=signal_func_nb,
[2966](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2966) signal_args=signal_args,
[2967](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2967) size=broadcasted_args['size'],
[2968](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2968) price=broadcasted_args['price'],
[2969](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2969) size_type=broadcasted_args['size_type'],
[2970](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2970) fees=broadcasted_args['fees'],
[2971](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2971) fixed_fees=broadcasted_args['fixed_fees'],
[2972](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2972) slippage=broadcasted_args['slippage'],
[2973](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2973) min_size=broadcasted_args['min_size'],
[2974](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2974) max_size=broadcasted_args['max_size'],
[2975](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2975) size_granularity=broadcasted_args['size_granularity'],
[2976](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2976) reject_prob=broadcasted_args['reject_prob'],
[2977](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2977) lock_cash=broadcasted_args['lock_cash'],
[2978](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2978) allow_partial=broadcasted_args['allow_partial'],
[2979](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2979) raise_reject=broadcasted_args['raise_reject'],
[2980](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2980) log=broadcasted_args['log'],
[2981](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2981) accumulate=broadcasted_args['accumulate'],
[2982](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2982) upon_long_conflict=broadcasted_args['upon_long_conflict'],
[2983](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2983) upon_short_conflict=broadcasted_args['upon_short_conflict'],
[2984](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2984) upon_dir_conflict=broadcasted_args['upon_dir_conflict'],
[2985](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2985) upon_opposite_entry=broadcasted_args['upon_opposite_entry'],
[2986](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2986) val_price=broadcasted_args['val_price'],
[2987](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2987) open=broadcasted_args['open'],
[2988](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2988) high=broadcasted_args['high'],
[2989](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2989) low=broadcasted_args['low'],
[2990](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2990) close=broadcasted_args['close'],
[2991](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2991) sl_stop=broadcasted_args['sl_stop'],
[2992](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2992) sl_trail=broadcasted_args['sl_trail'],
[2993](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2993) tp_stop=broadcasted_args['tp_stop'],
[2994](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2994) stop_entry_price=broadcasted_args['stop_entry_price'],
[2995](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2995) stop_exit_price=broadcasted_args['stop_exit_price'],
[2996](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2996) upon_stop_exit=broadcasted_args['upon_stop_exit'],
[2997](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2997) upon_stop_update=broadcasted_args['upon_stop_update'],
[2998](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2998) adjust_sl_func_nb=adjust_sl_func_nb,
[2999](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:2999) adjust_sl_args=adjust_sl_args,
[3000](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:3000) adjust_tp_func_nb=adjust_tp_func_nb,
[3001](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:3001) adjust_tp_args=adjust_tp_args,
[3002](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:3002) use_stops=use_stops,
[3003](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:3003) auto_call_seq=auto_call_seq,
[3004](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:3004) ffill_val_price=ffill_val_price,
[3005](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:3005) update_value=update_value,
[3006](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:3006) max_orders=max_orders,
[3007](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:3007) max_logs=max_logs,
[3008](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:3008) flex_2d=close.ndim == 2
[3009](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:3009) )
[3011](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:3011) # Create an instance
[3012](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:3012) return cls(
[3013](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:3013) wrapper,
[3014](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:3014) close,
(...)
[3020](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:3020) **kwargs
[3021](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/base.py:3021) )
File [~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/nb.py:1724](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/nb.py:1724), in signals_to_size_nb()
[1722](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/nb.py:1722) if not np.isnan(size):
[1723](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/nb.py:1723) if size_type == SizeType.Percent:
-> [1724](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/nb.py:1724) raise ValueError(
[1725](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/nb.py:1725) "SizeType.Percent does not support position reversal using signals")
[1726](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/nb.py:1726) if size_type == SizeType.Value:
[1727](https://file+.vscode-resource.vscode-cdn.net/Users/kevin851066/Desktop/JZ/range_filter/~/opt/anaconda3/envs/quant/lib/python3.8/site-packages/vectorbt/portfolio/nb.py:1727) order_size -= size [/](https://file+.vscode-resource.vscode-cdn.net/) val_price_now
ValueError: SizeType.Percent does not support position reversal using signals
Is there any methods that can implement it?
The first straightforward method came up with my mind is that I can let short_entries = np.roll(exits, 1)
to make them not to happen at the same time. But this method will make the backtest result inaccurate since my short_entries lag by one timeframe
Thanks in advance!
You just need to remove size and size_type, VBT enters with full capital by default.
And for position reversal, instead of providing short_entries and short_exits you can simply use direction="both".
I see. Thank for your quick reply!
Another question:
I would like to calculate the benchmark's mdd, sharpe ratio. Could it be done by pf.stats()
?
My current usage for pf.stats()
:
stats = pf.stats(metrics=[
'start',
'end',
'total_return',
'benchmark_return',
'sharpe_ratio',
'max_dd',
'total_trades',
'win_rate'], agg_func=None)