Package: cvxsimulator
cvxsimulatorGiven a universe of $m$ assets we are given prices for each of them at
time $t_1, t_2, \ldots t_n$, e.g. we operate using an $n \times m$ matrix where
each column corresponds to a particular asset.In a backtest we iterate in time (e.g. row by row) through the matrix and
allocate positions to all or some of the assets. This tool shall help to
simplify the accounting. It keeps track of the available cash,
the profits achieved, etc.Creating portfoliosThe simulator shall be completely agnostic as to the trading policy/strategy.
Our approach follows a rather common pattern:Create the builder objectLoop through timeBuild the portfolioWe demonstrate those steps with somewhat silly policies.
They are never good strategies, but are always valid ones.Create the builder objectThe user defines a builder object by loading prices
and initialize the amount of cash used in an experiment:importpandasaspdfromcvx.simulatorimportBuilderprices=pd.read_csv("prices.csv",index_col=0,parse_dates=True,header=0)b=Builder(prices=prices,initial_cash=1e6)Prices have to be valid, there may be NaNs only at the beginning and the end of
each column in frame.
There can be no NaNs hiding in the middle of any time series.It is also possible to specify a model for trading costs.
The builder helps to fill up the frame of positions. Only once done
we construct the actual portfolio.Loop through timeWe have overloaded the__iter__and__setitem__methods to create a custom loop.
Let's start with a first strategy. Each day we choose two names from the
universe at random.
Buy one (say 0.1 of your portfolio wealth) and short one the same amount.fort,stateinb:# pick two assets at randompair=np.random.choice(state.assets,2,replace=False)# compute the pairunits=pd.Series(index=state.assets,data=0.0)units[pair]=[state.nav,-state.nav]/state.prices[pair].values# update the positionb.position=0.1*units# Do not apply trading costsb.aum=state.aumHere t is the growing list of timestamps, e.g. in the first iteration
t is $t1$, in the second iteration it will be $t1, t2$ etc.A lot of magic is hidden in the state variable.
The state gives access to the currently available cash, the current prices
and the current valuation of all holdings.Here's a slightly more realistic loop. Given a set of $4$ assets we want to
implemenent the popular $1/n$ strategy.fort,stateinb:# each day we invest a quarter of the capital in the assetsb.position=0.25*state.nav/state.pricesb.aum=state.aumNote that we update the position at the last element in the t list
using a series of actual units rather than weights or cashpositions.
The builder class also exposes setters for such alternative conventions.fort,stateinb:# each day we invest a quarter of the capital in the assetsb.weights=np.ones(4)*0.25b.aum=state.aumBuild the portfolioOnce finished it is possible to build the portfolio objectportfolio=b.build()AnalyticsThe portfolio object supports further analysis and exposes
a number of properties, e.g.portfolio.navportfolio.cashportfolio.equityIt is possible to performportfolio.snapshot()We have also integrated thequantstatspackage as an optional extra for further analysis. It is usually enough to inject
theportfolio.navinto the many functions exposed by this package.PoetryWe assume you share already the love forPoetry.
Once you have installed poetry you can performmakeinstallto replicate the virtual environment we have defined in pyproject.toml.JupyterWe installJupyterLabon the fly within the aforementioned
virtual environment. Executingmakejupyterwill install and start the jupyter lab.