def __init__(self, strategy: Strategy, tie_breaker: Optional[TieBreaker] = None, isins: Optional[Iterable[str]] = None, num_portfolio: Optional[int] = None, hold_interval=None, buy_sell_gap=None): # apply default values if tie_breaker is None: from lib.simulate.tiebreaker.max_returns_tie_breaker import MaxReturnsTieBreaker tie_breaker = MaxReturnsTieBreaker() num_portfolio = num_portfolio or self.DEFAULT_NUM_PORTFOLIO hold_interval = hold_interval or self.DEFAULT_HOLD_INTERVAL buy_sell_gap = buy_sell_gap or self.DEFAULT_BUY_SELL_GAP funds = fund_cache.get(isins) self._strategy = strategy self._tie_breaker = tie_breaker self._num_portfolio = num_portfolio self._hold_interval = hold_interval self._buy_sell_gap = buy_sell_gap # computed properties self._prices_df = fund_cache.get_prices(isins) self._fees_df = calc_fees(funds) self._last_valid_date = self._prices_df.last_valid_index() self._broadcast_data( Simulator.Data(prices_df=self._prices_df, fees_df=self._fees_df, num_portfolio=self._num_portfolio, hold_interval=self._hold_interval))
def update_similar_funds(): funds = fund_cache.get() corr_df = fund_cache.get_corr() fees_df = calc_fees(funds) def to_similar_funds_entry(isin: str, corr_series: pd.Series) -> SimilarFundsEntry: similar_isins = corr_series[corr_series > THRESHOLD].index.tolist() [fund] = fund_cache.get([isin]) fees_per_year = fees_df.at[isin, "total_one_off_fees"] + fees_df.at[ isin, "total_annual_fees"] returns_per_year = fund.returns["1Y"] if returns_per_year: after_fees_return = returns_per_year - fees_per_year else: after_fees_return = None return SimilarFundsEntry(isin=isin, similar_isins=similar_isins, after_fees_return=after_fees_return) similar_funds = [ to_similar_funds_entry(isin, corr_series) for isin, corr_series in corr_df.iterrows() ] post_similar_funds(similar_funds)
def predict(self, dt: Optional[date] = None) -> Prediction: """ Generates prediction at given date, or the last valid date if not supplied. :param dt: Date of prediction. Defaults to last valid date. :return: """ if dt is None: dt = self._last_valid_date allowed_isins = self._strategy.run(dt, self._prices_df, self._fees_df) max_isins = self._tie_breaker.run(allowed_isins, self._num_portfolio, dt, self._prices_df, self._fees_df) return Simulator.Prediction(date=dt, funds=fund_cache.get(max_isins))
def to_similar_funds_entry(isin: str, corr_series: pd.Series) -> SimilarFundsEntry: similar_isins = corr_series[corr_series > THRESHOLD].index.tolist() [fund] = fund_cache.get([isin]) fees_per_year = fees_df.at[isin, "total_one_off_fees"] + fees_df.at[ isin, "total_annual_fees"] returns_per_year = fund.returns["1Y"] if returns_per_year: after_fees_return = returns_per_year - fees_per_year else: after_fees_return = None return SimilarFundsEntry(isin=isin, similar_isins=similar_isins, after_fees_return=after_fees_return)
def _to_events(cls, account: pd.DataFrame) -> List[Event]: events = [] for i in range(len(account.index) - 1): next_isins = account.iloc[i + 1, :]["isins"] if next_isins: next_funds = fund_cache.get(next_isins) events.append(Event( type="fund", from_date=account.index[i], to_date=account.index[i + 1], holdings=[ Holding( isin=fund.isin, name=fund.name, sedol=fund.sedol, weight=1 / len(next_isins) ) for fund in next_funds ], pct_change=(account["value"].iat[i + 1] / account["value"].iat[i]) - 1 )) return events
def test_get(): funds = fund_cache.get() assert len(funds) > 3000