cvxgrp / cvxportfolio

Portfolio optimization and back-testing.
https://www.cvxportfolio.com
Apache License 2.0
930 stars 244 forks source link

Feature Request: Ignore Tcosts in first period #160

Closed thayes75 closed 1 month ago

thayes75 commented 1 month ago

Hi All:

I wanted to raise what I thought would be a very useful feature to instantiate the portfolio's positions before any turnover constraints kick in. In general, if you want to run a backtest on a large AUM portfolio, depending on the turnover allowed, it could take a year or more to even be fully deployed properly. Often, a flag along the lines of "ignore_initial_tcost" allows the portfolio to settle upfront into a realistic set of initial holdings.

For example, note how the burn in period takes about a year for the Market Neutral example to achieve full 7x leverage here: https://www.cvxportfolio.com/en/stable/examples/market_neutral.html

At the moment, I suspect this is something most users have to do as a separate call to create the initial holdings, and then re-submit to the fully tcost constrained policy for the full history.

If I come up with a clean (and robust!) example to work around this, I will follow up with a subsequent post on this thread. For now, I wanted to flag this so it was logged somewhere and see if anyone else has already made progress on this.

Cheers

enzbus commented 1 month ago

Hi @thayes75 ; Cvxportfolio stable API already supports what you're asking for. Any parameter like the turnover limit can be specified by the user as time-varying. Here's how to do it (if I understand what you're asking). Note that it is explained also in the documentation -> https://www.cvxportfolio.com/en/stable/constraints.html#cvxportfolio.constraints.TurnoverLimit

simulator = ...
market_data = simulator.market_data # or define the market data server directly
trading_calendar = market_data.trading_calendar()

# define it as constant
turnover_limit_time_varying = pd.Series(0.05, index=trading_calendar)

# change what you wish
turnover_limit_time_varying[:pd.Timestamp('2020-01-01', tz='UTC')] = 0.2

# build your constraint with a time-varying limit
turnover_constraint_time_varying = cvx.TurnoverLimit(turnover_limit_time_varying)

Similarly you can pass time-varying parameters for the transaction cost object, or anything else.

thayes75 commented 1 month ago

Gah! Yes, this solves the issues quite elegantly. I was over complicating things and forgot about the timeseries nature of the parameters. This is closed!