Skip to content

Latest release notes

All notable changes in reverse chronological order.

Version 2024.8.20

  • Portfolio instances now accept the argument weights, which is a vector of weights, one per column. Weights are applied to the initial position, initial cash, cash deposits, cash earnings, as well as order records. They are used to scale up or down a column relative to its group or the entire portfolio. Weights can be applied after creating a portfolio instance with Portfolio.apply_weights and optionally rescaled by group by passing rescale=True to the same method.
  • Implemented the data class FinPyData for findatapy (https://github.com/cuemacro/findatapy), which allows pulling data from Bloomberg, Eikon, Quandl, Dukascopy, etc.
  • Implemented portfolio views (that is, methods and properties that return other portfolio instances) that include orders of either long positions (Portfolio.long_view) or short positions (Portfolio.short_view)
  • Implemented methods to convert Pandas Series and DataFrames to Data instances: OHLC(V) DataFrames can be converted via data = df.vbt.ohlcv.to_data() while Series/DataFrames where symbols are columns can be converted via a more general data = df.vbt.to_data()
  • Indicators now behave like regular arrays when combined with other arrays. Also, when an indicator has multiple outputs but there's an output of the same name as the short name of the indicator (like "atr" in ATR), that one output becomes the main output that gets combined.
  • Added options PriceType.NextValidOpen (or "nextvalidopen") and PriceType.NextValidClose (or "nextvalidclose") that use the next non-NA open and close price respectively
  • Fixed TVClient.search_symbol. Added a back-adjustment option for symbols ending with "!A". Also, the user agent is now a global constant (see vbt.data.custom.tv.USER_AGENT) and is used in most connection settings by default.
  • Data.add_symbol re-uses keyword arguments previously used in fetching (if reuse_fetch_kwargs is True, which is now default). Also, Data.add_feature can use pulling instead of running as well (if pull_feature is True).
  • Fixed plotting of ADX
  • Fixed package version comparison that leads to "NameError: name 'post1' is not defined"
  • Fixed read_only argument resolution in DuckDBData
  • Allowed renaming index in Data
  • As per @rayanbenredjeb suggestion and contribution (thank you!), reduced two loops computation to a single loop in covariance and correlation functions
  • Fixed parameter index for per_column=True in IndicatorFactory
  • Fixed mapping of start and end dates in BentoData
  • Adapted scheduling functionality to the schedule package of the version 1.2.2 and above
  • Fixed integer size granularity leading to an incorrect order size due to floating-point errors
  • Fixed NaN resolution in PIVOTINFO
  • Re-added the arguments use_asset_returns and bm_returns to portfolio plotting methods

Version 2024.6.19

  • PortfolioOptimizer.from_allocate_func and PortfolioOptimizer.from_optimize_func accept an argument group_execute_kwargs that controls the execution of groups
  • PortfolioOptimizer.from_optimize_func accepts Takeable instances. Taking is done with Splitter.take_range_from_takeable, which also accepts many formats including arrays with a different index.
  • Most objects now have a split_apply method that splits the object and applies a function on each chunk. The first argument is the function while other arguments are distributed in the same way as in the method split.
  • If the index of data pulled by Data is not sorted, it will be sorted while keeping the order of duplicates. If it's monotonically decreasing, it will be reversed.
  • SQLData sorts data by index directly in the database
  • In-house Plotly figures have got a method select_range that recursively selects a specified date range across all traces and shapes in the figure, making it especially useful for rendering granular data quickly or for exploring specific parts of data more efficiently. By default, it returns a new figure.
  • Fixed NaN resolution in PIVOTINFO
  • Argument tz passed by the user when pulling data with most Data subclasses will also default to tz_localize (not only to tz_convert)
  • Added eval_id to all chunking classes. This enables nested chunking since now the user can specify which function (or decorator) should evaluate which array, for example, to define different execution rules for different arrays. If the eval_id of the function doesn't match with the eval_id of the array, the array will be forwarded downstream to be evaluated by the inner function.
  • Added the class Task, which behaves the same as the tuple format (func, args, kwargs), but in a more user-friendly way. Argument funcs_args in Executor.run and other places has been renamed to tasks. Also, renamed the option distribute="calls" to distribute="tasks".
  • Executor can merge execution results by accepting merge_func and merge_kwargs. Also, it can filter out NoResult instances if filter_results is True (not default) and raise an error if all results are NoResult instances and raise_no_results is True (default). Generally, the logic to filter out missing results has been standardized and outsourced to filter_out_no_results.
  • Implemented a new decorator @iterated that takes a function and executes it repeatedly on values of an argument passed to this function (usually the first argument, but can be specified with over_arg)
  • Connections in DuckDBData are closed automatically when provided as a string. This allows simultaneously opening two connections with different access modes.
  • Cache clearing (chunk_clear_cache), garbage collection (chunk_collect_garbage), and delay (chunk_delay) can be done after executing each (super-)chunk with Executor
  • Progress bars are now hidden within parallel workflows. Also, tqdm bars are no longer opened by default when progress shouldn't be shown (can be changed by setting force_open_bar=True)
  • Signal factory accepts jitted argument to control jitting of generation functions
  • Integrated Smart Money Concepts (SMC) into IndicatorFactory.from_smc
  • Added 5 different Numba-compiled implementations of (rolling) Hurst exponent in HURST

Version 2024.5.15

  • Refactored execution engines. In addition to the function execute, there's now a class Executor that takes execution-related arguments and exposes a method Executor.run to run these arguments on function(s) calls. Whenever the function execute is called, it constructs an instance of the executor and calls the run method. Also, outsourced many preprocessing and postprocessing workflows to standalone methods that can be overridden by the user, such as Executor.call_pre_chunk_func that is called before a chunk is processed. In addition, keys can be supplied along with function calls. Each key is a description of what the function call represents, and can be used in progress bars.
  • Implemented (super-)chunk caching in the executor. If (super-)chunking is enabled with cache_chunks=True and execution-specific caching directory is specified in chunk_cache_dir (will be created if not existing), the results of each chunk will be serialized and stored on disk. Whenever the execution is stopped and then re-run, the results of each (previously cached) chunk will be loaded from disk. If pre_clear_chunk_cache is True, will clear the caching directory before execution. If release_chunk_cache is True, won't keep the results in memory but replace them with a dummy object. Then, when the entire execution is complete, will replace all dummy objects with actual results loaded from disk. By default (post_clear_chunk_cache=True), will remove the caching directory once the entire execution is complete.
  • Resolution of defaults in all execution engines, the executor, the chunker, and the parameterizer now happens at the initialization time for atomicity
  • Each progress bar can now display a relevant description of the currently processed item. For instance, a daily range between the dates "2024-01-01 00:00:00" and "2025-01-01 00:00:00" is displayed as "2024-01-01 → 2025-01-01". Progress description is shown as a postfix to avoid progress bars of varying lengths. This option (as_postfix) can be changed in the pbar-related settings.
  • Progress bars are now enabled on default (i.e., there's no need to provide show_progress=True anymore), but will be displayed only if they aren't complete before a number of seconds (delay)
  • Implemented a context manager for progress bars ProgressBar that replaces the function get_pbar. It wraps a tqdm instance and supercharges it with userful enhancements while exposing identically-named methods. For example, ProgressBar.update not only updates the tqdm instance but also calls some pre-update and post-update workflows.
  • Enabled reusable and nested progress bars by implementing a registry class PBarRegistry and its instance pbar_reg, that registers all currently active and pending, parent and child progress bars. Each progress bar gets its own unique identifier, which can be either supplied by the user or generated automatically. Whenever a child progress bar finishes iterating, it gets a pending status; later, when a progress bar with the same identifier should be registered, it reuses the already registered pending progress bar. Once the parent progress bar stops, all children are closed and deregistered. The parent-child relationship is determined based on the time each bar was opened/updated/closed. To disable, set reuse to False.
  • All progress bars can be shown or hidden within a code block by using the context managers ProgressShown and ProgressHidden respectively
  • The case of the day unit has been changed to uppercase (from "d" to "D")
  • Extended offset string translation. For example, "businessmonthstart" will be translated to "BMS". Also, all aliases now work the same way in both older and newer Pandas versions.
  • Created many convenient datetime shortcuts, for example vbt.timestamp() returns the same as pd.Timestamp.now() while vbt.offset("M") returns pd.offsets.MonthBegin()
  • Simulation range can now be modified from within a simulation. Each context has new fields SimulationContext.sim_start and SimulationContext.sim_end, which are guaranteed to be one-dimensional NumPy arrays with values per group. Lowering the second array in-place will have an effect on the current simulation. In particular, setting it to the next row or earlier will process the current row to the end and stop the simulation at the next one; this can be done conveniently by calling vbt.stop_group_sim_nb(c).
  • Simulation range passed to a simulation method is persisted in the simulation output (SimulationOutput) per column (as opposed to the per-group layout when being passed to the method)
  • Adapted portfolio analysis as well as return methods and properties to simulation ranges. Whenever a simulation range is active, the respective Numba function will process data only within this range. Moreover, any simulation range can be activated/modified/deactivated dynamically, even in stats. For example, pf.get_sharpe_ratio(sim_start="2024") will return the Sharpe ratio only for the rows from 2024 onwards. If rec_sim_range is False (default), only the latest analysis step respects the simulation range. In the example above, returns are computed on all rows while only the Sharpe ratio is computed within the range. If rec_sim_range is True, the entire analysis chain respects the simulation range (similar to backpropagation). Here, pf.get_sharpe_ratio(sim_start="2024", rec_sim_range=True) will return the Sharpe ratio as if orders before 2024 didn't exist.
  • Renamed metrics "Start", "End", and "Period" to "Start Index", "End Index", and "Total Duration" respectively. These metrics respect the currently active simulation range.
  • Improved most portfolio subplots. They respect the currently active simulation range and, similarly to metrics, can be called as class methods on already pre-calculated arrays.
  • Redesigned Numba-compiled return metrics. Rolling metrics have become standalone Numba functions.
  • Symbol sorting in list_symbols of custom data classes is now optional. If sorting has been disabled by the user, symbols will be returned in the native order of the data provider.
  • Stops won't be executed right away if the option StopExitPrice.Close is active
  • A human-readable error will be thrown if the user failed to provide arguments as a tuple
  • OHLC DataFrames can be passed as close in portfolio factory methods. They will be recognized as data-like instances if all features ("Open", "High", "Low", and "Close") are present.
  • Refactored Numba functions in portfolio.nb.ctx_helpers. Those functions that have a prefix "col" or "group" can now be called from any callback, not only from callbacks that have a compatible context.
  • Whenever TVData fails at pulling a symbol, it retries several times

Version 2024.4.1

  • Limit and stop price checks are more robust to floating-point errors
  • Fixed partial resolution of keyword arguments when merging VBT objects
  • Fixed size_type not being applied to min_size and max_size in Portfolio.from_signals
  • BaseAccessor.combine always produces a DataFrame when passing a sequence of arrays (even with one array)
  • Providing a list with a single parameter value to an indicator always produces a DataFrame
  • Created decorators for all profilers in profiling
  • All simulation methods now take arguments sim_start and sim_end (both defaulting to None) that indicate at which row the simulation should start and end for each column or group. This will skip all rows preceding sim_start and succeeding sim_end, which may result in a faster execution, especially for simulations with sparse orders (such as due to signal unraveling). Both arguments can be provided as datetimes and human-readable strings - they will be converted to indices automatically. Also, many simulation methods accept sim_start="auto" and sim_end="auto" to determine an optimal simulation range from inputs such as signals or order size.
  • If an indicator has a single output (especially with a generic name such as "real"), VBT creates two dynamic aliases for it: the short name of the indicator (such as "sma") and "output". For example, the method real_crossed_above can be also accessed via sma_crossed_above, output_crossed_above, and even just crossed_above (without any prefix).
  • Renamed the field sub_id in templates to eval_id
  • Added eval_id to both parameters (Param) and takeables (Takeable). This enables nested parameterization and splitting since now the user can specify which function (or decorator) should evaluate which parameter, for example, to define different execution rules for different parameters. If the eval_id of the function doesn't match with the eval_id of the parameter, the parameter will be forwarded downstream to be evaluated by the inner function.
  • Standardized attribute classes, such as Param. To define an attribute class, decorate it with @define, subclass define.mixin, and define fields with define.field. Also, added a concept of a missing value (MISSING), which powers required and optional fields that don't raise an error during the initialization step, only at the validation step. This enables one key feature: instances of attribute classes know which arguments were explicitly provided by the user for better printing and more granular merging of multiple instances.
  • Fixed potential division-by-zero errors in portfolio records
  • Patched frequency-based dt_stop
  • When translating a datetime object to nanoseconds, there's now a global flag tz_naive_ns in settings.datetime_ that controls whether the timezone should be dropped (True) or converted to UTC (False) before conversion
  • Extended portfolio helper functions in portfolio.nb.ctx_helpers. For instance, the user can now get most information for a custom column or group.
  • Patched length="optimize" in Splitter.from_n_rolling
  • Renamed index_stack_kwargs to clean_index_kwargs
  • Most classes now subclass HasItems and Paramable. When calling obj.items(), it splits the object along the column/group axis and returns an iterator of column/group labels and sub-objects where each sub-object contains only one column/group of data. Also, when calling obj.as_param() or vbt.Param(obj), it returns a Param instance where values are sub-objects and keys are column/group labels. This way, the user can use objects of any complexity as parameters to process only one configuration at a time.
  • Renamed yield_group_lens_idxs to iter_group_lens, yield_group_map_idxs to iter_group_map, and __iter__ to iter_groups in Grouper
  • Records.records_readable and MappedArray.mapped_readable have now an alias readable
  • Most classes now subclass IndexApplier with methods for working with index and columns. For example, to drop a parameter from a portfolio: new_pf = pf.drop_levels(param_name)
  • Parameter conditions (Param.condition) can be provided as a template. Also, to access any key (or level in the parameter index) of a parameter combination, wrap the parameter (or level) name with __. For example, when combining a fast and slow SMA indicators, the condition can be "__fast_window__ < __slow_window__" if fast_window and slow_window are level names in the parameter index.
  • Short name and level names of an indicator can be changed using IndicatorBase.rename and IndicatorBase.rename_levels respectively
  • Method split of most objects, as well as the decorators @split and @cv_split, allow providing keyword arguments related to splitting, taking, and applying as variable arguments (in addition to splitter_kwargs, take_kwargs, and apply_kwargs). The distribution of these arguments over the the respective functions is done automatically. Also, the splitting method can be guessed by keyword arguments when splitter is None. For example, calling obj.split(n=10, into="stacked") will call Splitter.from_n_rolling with n=10 and then Splitter.take with into="stacked"
  • Adapted the package https://github.com/sam31415/timeseriescv in generic.splitting.purged and added factory methods Splitter.from_purged_walkforward and Splitter.from_purged_kfold
  • Renamed SKLSplitter to SplitterCV
  • Similar to StopExitPrice for stop orders, added LimitOrderPrice for limit orders
  • Wrote Backtest powerful intraday trading strategies 📔

Version 2024.2.22

  • Doing the star-import from vectorbtpro import * will return a minimal list of imports that are essential to working with VBT, such as pd, np, and vbt itself. This will not pollute the namespace with VBT-own objects as they are exclusively accessible from vbt. In case of any static analysis issues, VBT can still be imported in a classic way - import vectorbtpro as vbt. The start import behavior can be controlled by the setting star_import in settings.importing, which accepts be "all", "vbt" (previous behavior), "minimal" (current behavior), and "none". This setting can be changed only via a configuration file. All notebooks and website examples have been updated accordingly.
  • Implemented portfolio methods (and their corresponding properties) for calculating the average entry price and exit price of each position and bar - Portfolio.get_position_entry_price and Portfolio.get_position_exit_price respectively
  • Modeling of signal pairs for SignalsAccessor.between_ranges and other methods has been redesigned and is now based on relation of type SignalRelation. For example, behavior of from_other=True can now be replicated with relation="manyone". Also, changed other to target across SignalsAccessor.
  • Implemented the following methods for signal unraveling:
  • Standardized datetime and frequency functionality across the entire codebase. Added new frequency aliases, such as week days and months; for example, every="monday" will return an index with only mondays. Frequency is now allowed to be a date offset of any complexity, and will be stored in its original format. Only when actually needed, it can be converted into a timedelta by approximation. Also, frequency can now being detected automatically from index when set to "auto" (this is the new global default, see infer_index_freq for other options). Same for year frequency (the default remains "365 days" for backward compatibility, see ReturnsAccessor.get_year_freq for other options).
  • Records.to_readable and MappedArray.to_readable accept expand_columns=True to split column tuples into multiple columns - one per level
  • Fixed row stacking for one-dimensional NumPy arrays
  • Fixed handling of colons in symbols such as "BTC/USDT:USDT" in CCXTData. Previously, the first part was mistaken for an exchange even if an exchange was provided.
  • Added option if_exists to IndicatorFactory.register_custom_indicator
  • Added option magnet_kwargs to Data.run
  • Added Python 3.12 support ⚡

Version 2024.1.30

  • Introduced a new option cash_deposits_as_input that controls whether cash deposits should be added to the input value rather than subtracted from the output value when computing a return
  • Implemented the methods IndicatorBase.dropna and Data.dropna to drop any missing values from an indicator and a data instance respectively
  • Implemented or extended the 4 most basic operations on data. Each operation comprises 5 different methods: one for columns, one for keys, one for features, one for symbols, and one that can determine the right method automatically (listed below). Also, features and symbols have become case-insensitive.
  • Expanded registration of custom indicators. A custom indicator now can be registered under a custom location (which defaults to "custom"). Custom locations are effectively indicator groups or tags, and are stored as keys in IndicatorFactory.custom_indicators; they can be listed with IndicatorFactory.list_custom_locations. Built-in indicators can be added to custom locations too.
  • Data.run can return a data instance
  • Fixed path resolution and handling of keys with a period (.) in HDFData
  • Fixed filtering by the arguments start and end in DuckDBData
  • Improved resolution of datetime-like arguments (specifically dt_stop) in BasePreparer.prepare_dt_obj. When providing a date such as "2024-01-01" or a time such as "16:00", the stop is marked at the provided datetime. When providing a frequency such as "daily", the stop is marked at the end of the last bar of the current period. This behavior can be changed by overriding last_before in the argument config of the particular argument. Also, when providing just a time, the marked datetime will overflow to the next day if the requested time comes before the current time. In addition, the user can dynamically pass changes to the argument config by passing arg_config as a regular argument, which will be merged over the actual argument config.
  • Implemented NB function init_FSInOutputs_nb to initialize in-outputs
  • Implemented a function get_api_ref that for any VBT object returns the corresponding link to the private website and source code. Another function open_api_ref does the same but then automatically opens the link in a browser. If a third-party object was provided, parses the path to the object and opens the first search result on DuckDuckGo.
  • Fixed an error that gets raised when providing an integer (as opposed to floating) account state field to long_buy_nb, long_sell_nb, short_sell_nb, or short_buy_nb in portfolio.nb.core
  • Most classes now have a method Chainable.pipe that enables built-in and user-defined methods in method chains. Supports deep attribute retrieval.
  • Added a light and dark color palette toggle to the website 🌔
  • Wrote Easily cross-validate parameters to boost your trading strategy 📔