Skip to content

Commit

Permalink
started working
Browse files Browse the repository at this point in the history
on market_data=None option to
Policy.execute
  • Loading branch information
enzbus committed May 20, 2024
1 parent f8315a5 commit 9160c62
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 16 deletions.
10 changes: 9 additions & 1 deletion cvxportfolio/costs.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,12 @@ def values_in_time( # pylint: disable=arguments-differ
:returns: Trading periods per year.
:rtype: float
"""

if self.periods_per_year is None:
if past_returns is None:
raise ValueError(
"If not using Cvxportfolio's Market Data servers you"
+ " have to specify periods_per_year")
return periods_per_year_from_datetime_index(past_returns.index)
return self.periods_per_year

Expand Down Expand Up @@ -906,7 +911,10 @@ def values_in_time(
:returns: Estimated sigma
:rtype: np.array
"""

if past_returns is None:
raise ValueError(
"If not using Cvxportfolio's Market Data servers you"
+ " have to specify sigma")
return np.sqrt(
(past_returns.iloc[-self.window_sigma_est:, :-1]**2).mean()).values

Expand Down
51 changes: 36 additions & 15 deletions cvxportfolio/policies.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,11 @@ def execute(self, h, market_data, t=None):
(the last element).
:type h: pandas.Series
:param market_data: :class:`MarketData` instance used to provide
data to the policy
:type market_data: cvxportfolio.MarketData instance
data to the policy. If set to ``None``, the policy needs to
have *all* data specified. Exceptions are raised if some data
are missing. In particular, no built-in :doc:`forecaster
<forecasts>` can be used.
:type market_data: cvxportfolio.MarketData instance or None
:param t: Time at which we execute. If None (the default), the
last timestamp in the trading calendar provided by the
:class:`MarketData` instance is used. Note: if you use a default
Expand All @@ -80,14 +83,27 @@ def execute(self, h, market_data, t=None):
:rtype: pandas.Series, pandas.Timestamp, pandas.Series
"""

trading_calendar = market_data.trading_calendar()
if market_data is not None:

if t is None:
t = trading_calendar[-1]
trading_calendar = market_data.trading_calendar()

if not t in trading_calendar:
raise ValueError(f'Provided time {t} must be in the '
+ 'trading calendar implied by the market data server.')
if t is None:
t = trading_calendar[-1]

if not t in trading_calendar:
raise ValueError(f'Provided time {t} must be in the '
+ 'trading calendar implied by the market data server.')
else:
if t is None:
raise ValueError(
"If market_data is None you must specify t.")
# TODO: should be possible to pass trading_calendar
trading_calendar = pd.DateTimeIndex([t])

if np.any(h.isnull()):
raise ValueError(
f"Holdings provided to {self.__class__.__name__}.execute "
+ " have missing values!")

v = np.sum(h)

Expand All @@ -96,19 +112,24 @@ def execute(self, h, market_data, t=None):
f"Holdings provided to {self.__class__.__name__}.execute "
+ " have negative sum.")

past_returns, _, past_volumes, _, current_prices = market_data.serve(t)
if market_data is not None:
past_returns, _, past_volumes, _, current_prices = \
market_data.serve(t)

if sorted(h.index) != sorted(past_returns.columns):
raise DataError(
"Holdings provided don't match the universe"
" implied by the market data server.")
if sorted(h.index) != sorted(past_returns.columns):
raise DataError(
"Holdings provided don't match the universe"
" implied by the market data server.")

h = h[past_returns.columns]
else:
past_returns, past_volumes, current_prices = None, None, None

h = h[past_returns.columns]
w = h / v

# consider adding caching logic here
self.initialize_estimator_recursive(
universe=past_returns.columns,
universe=h.index,
trading_calendar=trading_calendar[trading_calendar >= t])

w_plus = self.values_in_time_recursive(
Expand Down

0 comments on commit 9160c62

Please sign in to comment.