教程
投资组合优化
设计、集成优化后的投资组合,并进行动态再平衡
会员内容预览(英文)
Portfolio optimization focuses on constructing a portfolio of assets that seeks to maximize returns and minimize risk. In this context, a portfolio refers to the distribution of an investor's assets—a weight vector—which can be optimized for risk tolerance, expected rate of return, cost minimization, and other objectives. This optimization can be performed regularly to reflect recent changes in market behavior.
In VBT, a portfolio is a collection of asset vectors combined into a larger array along the column axis. By default, each of these vectors is treated as a separate backtesting instance, but you can apply a grouping instruction to treat multiple assets as a single unit. Portfolio optimization then becomes the process of converting a set of pricing vectors (information as input) into a set of allocation vectors (actions as output), which can then be provided to any simulator.
Thanks to VBT's modular design (and in line with the key principles of data science), optimization and simulation are handled separately. This enables you to analyze and filter allocation vectors even before they are backtested. This approach is similar to the typical workflow for working with signals: 1) generate, 2) pre-analyze, 3) simulate, and 4) post-analyze. In this example, we will cover how to complete each of these steps for the highest informational yield.
Data
As always, we should begin by obtaining some data. Because portfolio optimization involves working with a group of assets, we need to fetch data for more than one symbol. Here, we will fetch one year of hourly data for 5 different cryptocurrencies:
from vectorbtpro import *
symbols = ["BTCUSDT", "ETHUSDT", "BNBUSDT", "XRPUSDT", "ADAUSDT"]
data = vbt.BinanceData.pull(
symbols,
start="2020-01-01 UTC",
end="2021-01-01 UTC",
timeframe="1h"
)Let's save the data locally to avoid re-fetching it every time we start a new runtime:
data.to_hdf()
data = vbt.HDFData.pull("BinanceData.h5").select(symbols) Allocation
In simple terms, asset allocation is the process of deciding where to invest funds in the market—it
is a horizontal vector composed of weights or amounts of assets at a specific timestamp. For
example, to allocate 50% to BTCUSDT, 20% to ETHUSDT, and distribute the remainder equally among
the other assets, the allocation vector would be [0.5, 0.2, 0.1, 0.1, 0.1]. Frequently, weight
allocations sum to 1, ensuring the entire stake is continuously invested, but you can also choose to
invest only a portion of your balance or specify a particular (continuous or discrete) number of
assets instead of weights. Since we generally want to allocate periodically rather than hold
positions indefinitely, we also need to decide on rebalancing timestamps.
Manually
Let's manually generate and simulate allocations to better understand how everything works together.
Index points
The first step is to decide when to re-allocate. This is straightforward using
vectorbtpro.base.wrapping.ArrayWrapper.get_index_points, which converts a human-readable query
into a list of index positions (also called "index points" or "allocation points"). These positions
are simple numeric indices, where 0 is the first row and len(index) - 1 is the last.
For example, let's convert the first day of each month into index points:
ms_points = data.wrapper.get_index_points(every="M")
ms_pointsarray([0, 744, 1434, 2177, 2895, 3639, 4356, 5100, 5844, 6564, 7308, 8027])You can check the indices above using Pandas:
data.wrapper.index.get_indexer(
pd.Series(index=data.wrapper.index).resample(vbt.offset("M")).asfreq().index,
method="bfill"
)array([0, 744, 1434, 2177, 2895, 3639, 4356, 5100, 5844, 6564, 7308, 8027])We can also convert these index points back to timestamps:
data.wrapper.index[ms_points]DatetimeIndex(['2020-01-01 00:00:00+00:00', '2020-02-01 00:00:00+00:00',
'2020-03-01 00:00:00+00:00', '2020-04-01 00:00:00+00:00',
'2020-05-01 00:00:00+00:00', '2020-06-01 00:00:00+00:00',
'2020-07-01 00:00:00+00:00', '2020-08-01 00:00:00+00:00',
'2020-09-01 00:00:00+00:00', '2020-10-01 00:00:00+00:00',
'2020-11-01 00:00:00+00:00', '2020-12-01 00:00:00+00:00'],
dtype='datetime64[ns, UTC]', name='Open time', freq=None)vectorbtpro.base.wrapping.ArrayWrapper.get_index_points always returns indices that can be used on
the index, unless skipna is disabled. In that case, it will return -1 wherever an index point
cannot be found.
These are our rebalancing timestamps!
The main advantage of this method is its flexibility. The every argument can be a string, an
integer, a pd.Timedelta object, or a pd.DateOffset object:
您是否希望构建一个在可接受风险水平下,尽可能实现最高收益的投资组合?
✅ 学习设计和实现自己的投资组合优化模型 🎂
✅ 了解 VBT 如何集成 PyPortfolioOpt、Riskfolio-Lib 和 Universal Portfolios 等第三方库,让您只需几行代码即可实现再平衡!
✅ 学习使用 Numba 进行动态再平衡。我们将实现一个基于阈值的再平衡模板,可与任何优化函数配合使用。此外,我们还将从零构建一个均值—方差优化器(MVO),显著提升性能 💨
会员主题(英文内容)
版权所有 © 2021–2026 Oleg Polakow。保留所有权利。
本站内容与文档供使用和评估 VectorBT PRO 以及教育用途。任何其他用途,包括开发或支持竞争产品或服务,均须事先取得书面同意。