factory module¶
A factory for building new signal generators with ease.
The signal factory class SignalFactory extends IndicatorFactory to offer a convenient way to create signal generators of any complexity. By providing it with information such as entry and exit functions and the names of inputs, parameters, and outputs, it will create a stand-alone class capable of generating signals for an arbitrary combination of inputs and parameters.
SignalFactory class¶
SignalFactory(
*args,
mode=2,
input_names=None,
attr_settings=None,
**kwargs
)
A factory for building signal generators.
Extends IndicatorFactory with choice functions.
Generates a fixed number of outputs (depending upon mode
). If you need to generate other outputs, use in-place outputs (via in_output_names
).
See FactoryMode for supported generation modes.
Other arguments are passed to IndicatorFactory.
A factory for creating new indicators.
Initialize `IndicatorFactory` to create a skeleton and then use a class method
such as `IndicatorFactory.from_custom_func` to bind a calculation function to the skeleton.
__Args__
**```class_name```** : `str`
: Name for the created indicator class.
**```class_docstring```** : `str`
: Docstring for the created indicator class.
**```module_name```** : `str`
: Specify the module the class originates from.
**```short_name```** : `str`
: A short name of the indicator.
Defaults to lower-case `class_name`.
**```prepend_name```** : `bool`
: Whether to prepend `short_name` to each parameter level.
**```input_names```** : `list` of `str`
: A list of names of input arrays.
**```param_names```** : `list` of `str`
: A list of names of parameters.
**```in_output_names```** : `list` of `str`
: A list of names of in-place output arrays.
An in-place output is an output that is not returned but modified in-place.
Some advantages of such outputs include:
1) they don't need to be returned,
2) they can be passed between functions as easily as inputs,
3) they can be provided with already allocated data to safe memory,
4) if data or default value are not provided, they are created empty to not occupy memory.
**```output_names```** : `list` of `str`
: A list of names of output arrays.
**```output_flags```** : `dict`
: A dictionary of in-place and regular output flags.
**```custom_output_props```** : `dict`
: A dictionary with user-defined functions that will be
bound to the indicator class and wrapped with `@cached_property`.
**```attr_settings```** : `dict`
: A dictionary of settings by attribute name.
Attributes can be `input_names`, `in_output_names`, `output_names` and `custom_output_props`.
Following keys are accepted:
* `dtype`: Data type used to determine which methods to generate around this attribute.
Set to None to disable. Default is `np.float64`. Can be set to instance of
`collections.namedtuple` acting as enumerated type, or any other mapping;
It will then create a property with suffix `readable` that contains data in a string format.
**```metrics```** : `dict`
: Metrics supported by [StatsBuilderMixin.stats()](/api/generic/stats_builder/#vectorbt.generic.stats_builder.StatsBuilderMixin.stats "vectorbt.generic.stats_builder.StatsBuilderMixin.stats").
If dict, will be converted to [Config](/api/utils/config/#vectorbt.utils.config.Config "vectorbt.utils.config.Config").
**```stats_defaults```** : `callable` or `dict`
: Defaults for [StatsBuilderMixin.stats()](/api/generic/stats_builder/#vectorbt.generic.stats_builder.StatsBuilderMixin.stats "vectorbt.generic.stats_builder.StatsBuilderMixin.stats").
If dict, will be converted into a property.
**```subplots```** : `dict`
: Subplots supported by [PlotsBuilderMixin.plots()](/api/generic/plots_builder/#vectorbt.generic.plots_builder.PlotsBuilderMixin.plots "vectorbt.generic.plots_builder.PlotsBuilderMixin.plots").
If dict, will be converted to [Config](/api/utils/config/#vectorbt.utils.config.Config "vectorbt.utils.config.Config").
**```plots_defaults```** : `callable` or `dict`
: Defaults for [PlotsBuilderMixin.plots()](/api/generic/plots_builder/#vectorbt.generic.plots_builder.PlotsBuilderMixin.plots "vectorbt.generic.plots_builder.PlotsBuilderMixin.plots").
If dict, will be converted into a property.
!!! note
The `__init__` method is not used for running the indicator, for this use `run`.
The reason for this is indexing, which requires a clean `__init__` method for creating
a new indicator object with newly indexed attributes.
__Superclasses__
* [IndicatorFactory](/api/indicators/factory/#vectorbt.indicators.factory.IndicatorFactory "vectorbt.indicators.factory.IndicatorFactory")
__Inherited members__
* [IndicatorFactory.find_ta_indicator()](/api/indicators/factory/#vectorbt.indicators.factory.IndicatorFactory.find_ta_indicator "vectorbt.indicators.factory.IndicatorFactory.find_ta_indicator")
* [IndicatorFactory.from_apply_func()](/api/indicators/factory/#vectorbt.indicators.factory.IndicatorFactory.from_apply_func "vectorbt.indicators.factory.IndicatorFactory.from_apply_func")
* [IndicatorFactory.from_custom_func()](/api/indicators/factory/#vectorbt.indicators.factory.IndicatorFactory.from_custom_func "vectorbt.indicators.factory.IndicatorFactory.from_custom_func")
* [IndicatorFactory.from_pandas_ta()](/api/indicators/factory/#vectorbt.indicators.factory.IndicatorFactory.from_pandas_ta "vectorbt.indicators.factory.IndicatorFactory.from_pandas_ta")
* [IndicatorFactory.from_ta()](/api/indicators/factory/#vectorbt.indicators.factory.IndicatorFactory.from_ta "vectorbt.indicators.factory.IndicatorFactory.from_ta")
* [IndicatorFactory.from_talib()](/api/indicators/factory/#vectorbt.indicators.factory.IndicatorFactory.from_talib "vectorbt.indicators.factory.IndicatorFactory.from_talib")
* [IndicatorFactory.get_pandas_ta_indicators()](/api/indicators/factory/#vectorbt.indicators.factory.IndicatorFactory.get_pandas_ta_indicators "vectorbt.indicators.factory.IndicatorFactory.get_pandas_ta_indicators")
* [IndicatorFactory.get_ta_indicators()](/api/indicators/factory/#vectorbt.indicators.factory.IndicatorFactory.get_ta_indicators "vectorbt.indicators.factory.IndicatorFactory.get_ta_indicators")
* [IndicatorFactory.get_talib_indicators()](/api/indicators/factory/#vectorbt.indicators.factory.IndicatorFactory.get_talib_indicators "vectorbt.indicators.factory.IndicatorFactory.get_talib_indicators")
* [IndicatorFactory.parse_pandas_ta_config()](/api/indicators/factory/#vectorbt.indicators.factory.IndicatorFactory.parse_pandas_ta_config "vectorbt.indicators.factory.IndicatorFactory.parse_pandas_ta_config")
* [IndicatorFactory.parse_ta_config()](/api/indicators/factory/#vectorbt.indicators.factory.IndicatorFactory.parse_ta_config "vectorbt.indicators.factory.IndicatorFactory.parse_ta_config")
---
### from_choice_func <span class="dobjtype">method</span><a class="githublink" href="https://github.com/polakowo/vectorbt/blob/8936ddd22b243635d690dd5d033834e62fb31391/vectorbt/signals/factory.py#L165-L950" target="_blank" title="Jump to source">:material-github:</a> { #vectorbt.signals.factory.SignalFactory.from_choice_func data-toc-label='from_choice_func()' }
```python
SignalFactory.from_choice_func(
entry_choice_func=None,
exit_choice_func=None,
generate_func=generate_nb,
generate_ex_func=generate_ex_nb,
generate_enex_func=generate_enex_nb,
cache_func=None,
entry_settings=None,
exit_settings=None,
cache_settings=None,
numba_loop=False,
**kwargs
)
Build signal generator class around entry and exit choice functions.
A choice function is simply a function that returns indices of signals. There are two types of it: entry choice function and exit choice function. Each choice function takes broadcast time series, broadcast in-place output time series, broadcast parameter arrays, and other arguments, and returns an array of indices corresponding to chosen signals. See generate_nb().
Args
entry_choice_func
:callable
-
choice_func_nb
that returns indices of entries.Defaults to first_choice_nb() for
FactoryMode.Chain
. exit_choice_func
:callable
choice_func_nb
that returns indices of exits.generate_func
:callable
-
Entry generation function.
Defaults to generate_nb().
generate_ex_func
:callable
-
Exit generation function.
Defaults to generate_ex_nb().
generate_enex_func
:callable
-
Entry and exit generation function.
Defaults to generate_enex_nb().
cache_func
:callable
-
A caching function to preprocess data beforehand.
All returned objects will be passed as last arguments to choice functions.
entry_settings
:dict
- Settings dict for
entry_choice_func
. exit_settings
:dict
- Settings dict for
exit_choice_func
. cache_settings
:dict
- Settings dict for
cache_func
. numba_loop
:bool
-
Whether to loop using Numba.
Set to True when iterating large number of times over small input.
**kwargs
- Keyword arguments passed to
IndicatorFactory.from_custom_func
.
Note
Choice functions should be Numba-compiled.
Which inputs, parameters and arguments to pass to each function should be explicitly indicated in the function's settings dict. By default, nothing is passed.
Passing keyword arguments directly to the choice functions is not supported. Use pass_kwargs
in a settings dict to pass keyword arguments as positional.
Settings dict of each function can have the following keys:
Attributes
pass_inputs
:list
ofstr
-
Input names to pass to the choice function.
Defaults to []. Order matters. Each name must be in
input_names
. pass_in_outputs
:list
ofstr
-
In-place output names to pass to the choice function.
Defaults to []. Order matters. Each name must be in
in_output_names
. pass_params
:list
ofstr
-
Parameter names to pass to the choice function.
Defaults to []. Order matters. Each name must be in
param_names
. pass_kwargs
:dict
,list
ofstr
orlist
oftuple
-
Keyword arguments from
kwargs
dict to pass as positional arguments to the choice function.Defaults to []. Order matters.
If any element is a tuple, should contain the name and the default value. If any element is a string, the default value is None.
Built-in keys include:
input_shape
: Input shape if no input time series passed. Default is provided by the pipeline ifpass_input_shape
is True.wait
: Number of ticks to wait before placing signals. Default is 1.-
until_next
: Whether to place signals up to the next entry signal. Default is True.Applied in
generate_ex_func
only. *skip_until_exit
: Whether to skip processing entry signals until the next exit. Default is False.Applied in
generate_ex_func
only. *pick_first
: Whether to stop as soon as the first exit signal is found. Default is False withFactoryMode.Entries
, otherwise is True. *temp_idx_arr
: Empty integer array used to temporarily store indices. Default is an automatically generated array of shapeinput_shape[0]
.You can also pass
temp_idx_arr1
,temp_idx_arr2
, etc. to generate multiple. *flex_2d
: See flex_select_auto_nb(). Default is provided by the pipeline ifpass_flex_2d
is True.
pass_cache
:bool
-
Whether to pass cache from
cache_func
to the choice function.Defaults to False. Cache is passed unpacked.
The following arguments can be passed to run
and run_combs
methods:
Args
*args
- Should be used instead of
entry_args
withFactoryMode.Entries
and instead ofexit_args
withFactoryMode.Exits
andFactoryMode.Chain
with defaultentry_choice_func
. entry_args
:tuple
- Arguments passed to the entry choice function.
exit_args
:tuple
- Arguments passed to the exit choice function.
cache_args
:tuple
- Arguments passed to the cache function.
entry_kwargs
:tuple
- Settings for the entry choice function. Also contains arguments passed as positional if in
pass_kwargs
. exit_kwargs
:tuple
- Settings for the exit choice function. Also contains arguments passed as positional if in
pass_kwargs
. cache_kwargs
:tuple
- Settings for the cache function. Also contains arguments passed as positional if in
pass_kwargs
. return_cache
:bool
- Whether to return only cache.
use_cache
:any
- Cache to use.
**kwargs
- Should be used instead of
entry_kwargs
withFactoryMode.Entries
and instead ofexit_kwargs
withFactoryMode.Exits
andFactoryMode.Chain
with defaultentry_choice_func
.
For more arguments, see run_pipeline().
Usage
- The simplest signal indicator that places True at the very first index:
>>> from numba import njit
>>> import vectorbt as vbt
>>> import numpy as np
>>> @njit
... def entry_choice_func(from_i, to_i, col):
... return np.array([from_i])
>>> @njit
... def exit_choice_func(from_i, to_i, col):
... return np.array([from_i])
>>> MySignals = vbt.SignalFactory().from_choice_func(
... entry_choice_func=entry_choice_func,
... exit_choice_func=exit_choice_func,
... entry_kwargs=dict(wait=1),
... exit_kwargs=dict(wait=1)
... )
>>> my_sig = MySignals.run(input_shape=(3, 3))
>>> my_sig.entries
0 1 2
0 True True True
1 False False False
2 True True True
>>> my_sig.exits
0 1 2
0 False False False
1 True True True
2 False False False
- Take the first entry and place an exit after waiting
n
ticks. Find the next entry and repeat. Test three differentn
values.
>>> from numba import njit
>>> from vectorbt.signals.factory import SignalFactory
>>> @njit
... def wait_choice_nb(from_i, to_i, col, n, temp_idx_arr):
... temp_idx_arr[0] = from_i + n # index of next exit
... if temp_idx_arr[0] < to_i:
... return temp_idx_arr[:1]
... return temp_idx_arr[:0] # must return array anyway
>>> # Build signal generator
>>> MySignals = SignalFactory(
... mode='chain',
... param_names=['n']
... ).from_choice_func(
... exit_choice_func=wait_choice_nb,
... exit_settings=dict(
... pass_params=['n'],
... pass_kwargs=['temp_idx_arr'] # built-in kwarg
... )
... )
>>> # Run signal generator
>>> entries = [True, True, True, True, True]
>>> my_sig = MySignals.run(entries, [0, 1, 2])
>>> my_sig.entries # input entries
custom_n 0 1 2
0 True True True
1 True True True
2 True True True
3 True True True
4 True True True
>>> my_sig.new_entries # output entries
custom_n 0 1 2
0 True True True
1 False False False
2 True False False
3 False True False
4 True False True
>>> my_sig.exits # output exits
custom_n 0 1 2
0 False False False
1 True False False
2 False True False
3 True False True
4 False False False
- To combine multiple iterative signals, you would need to create a custom choice function. Here is an example of combining two random generators using "OR" rule (the first signal wins):
>>> from numba import njit
>>> from collections import namedtuple
>>> from vectorbt.indicators.configs import flex_elem_param_config
>>> from vectorbt.signals.factory import SignalFactory
>>> from vectorbt.signals.nb import rand_by_prob_choice_nb
>>> # Enum to distinguish random generators
>>> RandType = namedtuple('RandType', ['R1', 'R2'])(0, 1)
>>> # Define exit choice function
>>> @njit
... def rand_exit_choice_nb(from_i, to_i, col, rand_type, prob1,
... prob2, temp_idx_arr1, temp_idx_arr2, flex_2d):
... idxs1 = rand_by_prob_choice_nb(from_i, to_i, col, prob1, True, temp_idx_arr1, flex_2d)
... if len(idxs1) > 0:
... to_i = idxs1[0] # no need to go beyond first the first found signal
... idxs2 = rand_by_prob_choice_nb(from_i, to_i, col, prob2, True, temp_idx_arr2, flex_2d)
... if len(idxs2) > 0:
... rand_type[idxs2[0], col] = RandType.R2
... return idxs2
... if len(idxs1) > 0:
... rand_type[idxs1[0], col] = RandType.R1
... return idxs1
... return temp_idx_arr1[:0]
>>> # Build signal generator
>>> MySignals = SignalFactory(
... mode='chain',
... in_output_names=['rand_type'],
... param_names=['prob1', 'prob2'],
... attr_settings=dict(
... rand_type=dict(dtype=RandType) # creates rand_type_readable
... )
... ).from_choice_func(
... exit_choice_func=rand_exit_choice_nb,
... exit_settings=dict(
... pass_in_outputs=['rand_type'],
... pass_params=['prob1', 'prob2'],
... pass_kwargs=['temp_idx_arr1', 'temp_idx_arr2', 'flex_2d']
... ),
... param_settings=dict(
... prob1=flex_elem_param_config, # param per frame/row/col/element
... prob2=flex_elem_param_config
... ),
... pass_flex_2d=True,
... rand_type=-1 # fill with this value
... )
>>> # Run signal generator
>>> entries = [True, True, True, True, True]
>>> my_sig = MySignals.run(entries, [0., 1.], [0., 1.], param_product=True)
>>> my_sig.new_entries
custom_prob1 0.0 1.0
custom_prob2 0.0 1.0 0.0 1.0
0 True True True True
1 False False False False
2 False True True True
3 False False False False
4 False True True True
>>> my_sig.exits
custom_prob1 0.0 1.0
custom_prob2 0.0 1.0 0.0 1.0
0 False False False False
1 False True True True
2 False False False False
3 False True True True
4 False False False False
>>> my_sig.rand_type_readable
custom_prob1 0.0 1.0
custom_prob2 0.0 1.0 0.0 1.0
0
1 R2 R1 R1
2
3 R2 R1 R1
4