Esempio n. 1
0
    def __init__(self,
                 processed_assets: PricesProcessor,
                 risk_free_rate: Union[int, float, Series, DataFrame, RiskFreeRateProcessor] = 0):

        check_type(processed_assets, [PricesProcessor])
        check_type(risk_free_rate, [int, float, Series, DataFrame, RiskFreeRateProcessor])

        self.prices: DataFrame = processed_assets.prices
        self.returns1p: DataFrame = processed_assets.returns1p
        self.num_risky_assets: int = processed_assets.num_risky_assets
        self.num_periods: int = processed_assets.num_periods
        self.rf: DataFrame = self.__set_risk_free_rate(risk_free_rate)
 def load(filepath: str, key: Optional[str] = None) -> Union[ndarray, DataFrame]:
     check_type(filepath, [str])
     if filepath.endswith('.npy'):
         data = np.load(filepath)
     elif filepath.endswith('.csv'):
         data = pd.read_csv(filepath, parse_dates=['Date'], index_col=['Date'])
     elif filepath.endswith('.h5'):
         store = pd.HDFStore(filepath, mode='r')
         data = store.get(key)
     else:
         data = None
         print('Not recognized extension.')
     return data
Esempio n. 3
0
    def __init__(self,
                 trader_portfolio: Portfolio,
                 baseline_portfolio: Optional[Portfolio] = None,
                 trading_periods: int = 252,
                 min_action: Union[int, float] = 0,
                 verbose: bool = False):
        check_type(trader_portfolio, [Portfolio])
        check_type(trading_periods, [int])
        check_type(min_action, [int, float])
        check_type(verbose, [bool])

        self.trading_periods: int = trading_periods
        self.verbose: bool = verbose
        self.simulator: TradingSimulator = TradingSimulator(trader_portfolio,
                                                            baseline_portfolio=baseline_portfolio,
                                                            trading_periods=self.trading_periods)
        if min_action > 0:
            raise ValueError(f"You must pass a negative value. You passed {min_action!r} instead.")

        # Action space
        self.__min_action: Union[int, float] = min_action
        n_risky_assets: int = self.simulator.trader_portfolio.n_risky_assets
        self.action_space = spaces.Box(low=self.__min_action, high=1, shape=(n_risky_assets,))

        # TODO: define the observation space
        # Observation space
        data_min_values: ndarray = trader_portfolio.risky_asset_returns.min().to_numpy()
        data_max_values: ndarray = trader_portfolio.risky_asset_returns.max().to_numpy()
        self.observation_space = spaces.Box(data_min_values, data_max_values)

        self.reset()
Esempio n. 4
0
    def __init__(self,
                 initial_cash: Union[int, float],
                 dataset: DataProcessor,
                 trading_periods: int,
                 transaction_cost: Union[int, float],
                 rf: Union[int, float, Series, DataFrame] = 0,
                 name: Optional[str] = None):
        # Raise TypeError messages for debugging
        check_type(initial_cash, [int, float])
        check_type(dataset, [DataProcessor])
        check_type(trading_periods, [int])
        check_type(transaction_cost, [int, float])
        check_type(rf, [int, float, Series, DataFrame])
        check_type(name, [str, type(None)])

        # Constant attributes
        self.initial_cash: Union[int, float] = initial_cash
        self.trading_periods: int = trading_periods
        self.tau: Union[int, float] = transaction_cost
        self.__id: str = hex(id(self))
        self.name: str = self.__id if name is None else name

        # TODO: Whilst creating a DataProcessor object, this could be removed
        # Data
        self.dataset: DataProcessor = dataset
        # self.risky_asset_prices: DataFrame = risky_asset_prices
        self.n_risky_assets: int = self.risky_asset_prices.shape[1]
        # Risky assets plus a risk-free asset:
        self.n_assets: int = self.n_risky_assets + 1
        # The dataset height
        self.whole_dataset_periods: int = len(self.risky_asset_prices)

        self.offset: Optional[int] = None

        # TODO: test if it works with a dynamic series
        # Assign the risk-free rate correctly:
        self.rf: DataFrame = self.__check_risk_free_rate(rf)

        # TODO: Whilst creating a DataProcessor object, this could be removed
        # Compute risk-asset dataset returns and concatenate them with the risk-free asset
        self.risky_asset_returns: DataFrame = self.risky_asset_prices.pct_change(
        ).dropna()
        self.all_asset_returns: DataFrame = pd.concat(
            [self.rf, self.risky_asset_returns], axis=1)

        # Initial weights are following allocations:
        #   -> 100% in the bank account (risk-free asset), and
        #   -> 0% in every other asset.
        self.initial_weights: ndarray = np.append(
            1, np.repeat(0, self.n_risky_assets))
        # The weights are the "actions" taken by the agent, or also the "positions" at time t:
        self.__weights: ndarray = np.zeros(
            (self.trading_periods, self.n_assets))
        # `weights_ante` are the weights just before the period rebalancing, i.e., at t-1:
        self.positions_ante: ndarray = np.zeros_like(self.__weights)
        # Initially, all money is in the bank account. Thus, the risk-free asset:
        self.positions_ante[0][0] = 1

        # The weighted-returns of each asset in which the agent is long.
        self.portfolio_returns: ndarray = np.zeros_like(self.__weights)

        # The monetary value of each position the agent is in:
        self.cash_positions_ante: ndarray = np.zeros_like(self.positions_ante)
        self.cash_positions_ante[0][0] = self.initial_cash
        self.cash_positions: ndarray = np.zeros_like(self.__weights)

        # The monetary value of the portfolio, i.e., the sum of the cash positions at time t
        self.portfolio_value_ante: ndarray = np.sum(self.cash_positions_ante,
                                                    axis=1)
        self.portfolio_value: ndarray = np.zeros_like(
            self.portfolio_value_ante)

        # Rewards are used to compute the total return, thus they are the portfolio returns
        self.rewards: ndarray = np.zeros(
            self.trading_periods)  # = Portfolio returns
        self.nav: ndarray = np.ones(
            self.trading_periods)  # = Portfolio value of $1
        self.nav_ante: ndarray = np.ones(self.trading_periods)
        self.turnover_per_risky_asset: ndarray = np.zeros(
            (self.trading_periods, self.n_risky_assets))
        self.turnover: ndarray = np.zeros(self.trading_periods)
        self.trading_costs: ndarray = np.zeros(
            self.trading_periods)  # Monetary value

        self.__verbose: bool = False
Esempio n. 5
0
 def __init__(self, data: DataFrame):
     check_type(data, [DataFrame])
 def reset(self, offset: int):
     check_type(offset, [int])
     self.current_step = 0
     self.offset = offset
    def __init__(self,
                 data_path: Path,
                 filename: str,
                 key: Optional[str] = None,
                 rf: Optional[DataFrame] = None,  # TODO: allow propagation of int or float
                 macroindicators: Optional[DataFrame] = None,
                 normalize: bool = True,
                 freq: str = 'B',
                 trading_periods: Optional[int] = None):
        check_type(data_path, [Path])
        check_type(filename, [str])
        check_type(key, [str, type(None)])
        check_type(rf, [DataFrame, type(None)])
        check_type(macroindicators, [DataFrame, type(None)])
        check_type(normalize, [bool])
        check_type(freq, [str])
        check_type(trading_periods, [int, type(None)])

        self.macroindicators: Optional[DataFrame] = macroindicators
        self.rf: Optional[DataFrame] = rf
        self.freq: str = freq
        filepath: str = str(data_path / filename)
        self.data: DataFrame = self.load(filepath, key)
        self.normalize: bool = normalize
        self.current_step: int = 0
        self.offset: Optional[int] = None
        self.X: Optional[ndarray] = None
        self.trading_periods: Optional[int] = trading_periods