コード例 #1
0
    def __init__(self,
                 portfolio: 'Portfolio',
                 feed: 'DataFeed' = None,
                 renderer_feed: 'DataFeed' = None,
                 stop_time: 'datetime.time' = dt.time(16, 0, 0),
                 window_size: int = 1,
                 min_periods: int = None,
                 randomize: bool = False,
                 **kwargs) -> None:
        internal_group = Stream.group(
            _create_internal_streams(portfolio)).rename("internal")
        external_group = Stream.group(feed.inputs).rename("external")

        if renderer_feed:
            renderer_group = Stream.group(
                renderer_feed.inputs).rename("renderer")

            self.feed = DataFeed(
                [internal_group, external_group, renderer_group])
        else:
            self.feed = DataFeed([internal_group, external_group])

        self.stop_time = stop_time
        self.window_size = window_size
        self.min_periods = min_periods
        self.randomize = randomize

        self._observation_dtype = kwargs.get('dtype', np.float32)
        self._observation_lows = kwargs.get('observation_lows', -np.inf)
        self._observation_highs = kwargs.get('observation_highs', np.inf)

        self.history = ObservationHistory(window_size=window_size)

        initial_obs = self.feed.next()["external"]
        initial_obs.pop('timestamp', None)
        n_features = len(initial_obs.keys())

        self._observation_space = Box(low=self._observation_lows,
                                      high=self._observation_highs,
                                      shape=(self.window_size, n_features),
                                      dtype=self._observation_dtype)

        self.feed = self.feed.attach(portfolio)

        self.renderer_history = []

        if self.randomize:
            self.num_episodes = 0
            while self.feed.has_next():
                ts = self.feed.next()["external"]["timestamp"]
                if ts.time() == self.stop_time:
                    self.num_episodes += 1

        self.feed.reset()
        self.warmup()

        self.stop = False
コード例 #2
0
    def __init__(self, price: 'Stream') -> None:
        super().__init__()
        self.position = -1

        r = Stream.sensor(price, lambda p: p.value, dtype="float").diff()
        position = Stream.sensor(self, lambda rs: rs.position, dtype="float")

        reward = (position * r).fillna(0).rename("reward")

        self.feed = DataFeed([reward])
        self.feed.compile()
コード例 #3
0
    def create_env(self, config):
        x = np.arange(0, 2 * np.pi, 2 * np.pi / 1001)
        y = 50 * np.sin(3 * x) + 100

        x = np.arange(0, 2 * np.pi, 2 * np.pi / 1000)
        iqc_stream = Stream.source(y, dtype="float").rename("CNY-IQC")

        iqcex = Exchange("iqcex", service=execute_order)(iqc_stream)
        CNY = Instrument("CNY", 2, "China Yuan")
        IQC = Instrument("IQC", 8, "Iching Quantitative Coin")
        cash = Wallet(iqcex, 100000 * CNY)
        asset = Wallet(iqcex, 0 * IQC)

        portfolio = Portfolio(CNY, [cash, asset])

        feed = DataFeed([
            iqc_stream,
            iqc_stream.rolling(window=10).mean().rename("fast"),
            iqc_stream.rolling(window=50).mean().rename("medium"),
            iqc_stream.rolling(window=100).mean().rename("slow"),
            iqc_stream.log().diff().fillna(0).rename("lr")
        ])

        reward_scheme = PBR(price=iqc_stream)

        action_scheme = BSH(cash=cash, asset=asset).attach(reward_scheme)
        # ?????????????????????????????????????????????????????
        self.agent = action_scheme.action_space

        renderer_feed = DataFeed([
            Stream.source(y, dtype="float").rename("price"),
            Stream.sensor(action_scheme, lambda s: s.action,
                          dtype="float").rename("action")
        ])

        environment = default.create(feed=feed,
                                     portfolio=portfolio,
                                     action_scheme=action_scheme,
                                     reward_scheme=reward_scheme,
                                     renderer_feed=renderer_feed,
                                     renderer=PositionChangeChart(),
                                     window_size=config["window_size"],
                                     max_allowed_loss=0.6)
        return environment
コード例 #4
0
    def __init__(self,
                 portfolio: 'Portfolio',
                 feed: 'DataFeed' = None,
                 renderer_feed: 'DataFeed' = None,
                 window_size: int = 1,
                 min_periods: int = None,
                 **kwargs) -> None:
        internal_group = Stream.group(
            _create_internal_streams(portfolio)).rename("internal")
        external_group = Stream.group(feed.inputs).rename("external")

        if renderer_feed:
            renderer_group = Stream.group(
                renderer_feed.inputs).rename("renderer")

            self.feed = DataFeed(
                [internal_group, external_group, renderer_group])
        else:
            self.feed = DataFeed([internal_group, external_group])

        self.window_size = window_size
        self.min_periods = min_periods

        self._observation_dtype = kwargs.get('dtype', np.float32)
        self._observation_lows = kwargs.get('observation_lows', -np.inf)
        self._observation_highs = kwargs.get('observation_highs', np.inf)

        self.history = ObservationHistory(window_size=window_size)

        initial_obs = self.feed.next()["external"]
        n_features = len(initial_obs.keys())

        self._observation_space = Box(low=self._observation_lows,
                                      high=self._observation_highs,
                                      shape=(self.window_size, n_features),
                                      dtype=self._observation_dtype)

        self.feed = self.feed.attach(portfolio)

        self.renderer_history = []

        self.feed.reset()
        self.warmup()
コード例 #5
0
class PBR(iqtRewardScheme):
    """A reward scheme for position-based returns.

    * Let :math:`p_t` denote the price at time t.
    * Let :math:`x_t` denote the position at time t.
    * Let :math:`R_t` denote the reward at time t.

    Then the reward is defined as,
    :math:`R_{t} = (p_{t} - p_{t-1}) \cdot x_{t}`.

    Parameters
    ----------
    price : `Stream`
        The price stream to use for computing rewards.
    """

    registered_name = "pbr"

    def __init__(self, price: 'Stream') -> None:
        super().__init__()
        self.position = -1

        r = Stream.sensor(price, lambda p: p.value, dtype="float").diff()
        position = Stream.sensor(self, lambda rs: rs.position, dtype="float")

        reward = (position * r).fillna(0).rename("reward")

        self.feed = DataFeed([reward])
        self.feed.compile()

    def on_action(self, action: int) -> None:
        self.position = -1 if action == 0 else 1

    def get_reward(self, portfolio: 'Portfolio') -> float:
        return self.feed.next()["reward"]

    def reset(self) -> None:
        """Resets the `position` and `feed` of the reward scheme."""
        self.position = -1
        self.feed.reset()
コード例 #6
0
ファイル: dct_app.py プロジェクト: yt7589/iching
    def test_ledger(self):
        print('test ledger')
        ds = DctDs()
        bitfinex_btc, bitfinex_eth, bitstamp_btc, bitstamp_eth, bitstamp_ltc = ds.load_data(
        )
        # 定义交易所
        bitfinex = Exchange("bitfinex", service=execute_order)(
            Stream.source(list(bitfinex_btc['close'][-100:]),
                          dtype="float").rename("USD-BTC"),
            Stream.source(list(bitfinex_eth['close'][-100:]),
                          dtype="float").rename("USD-ETH"))
        bitstamp = Exchange("bitstamp", service=execute_order)(
            Stream.source(list(bitstamp_btc['close'][-100:]),
                          dtype="float").rename("USD-BTC"),
            Stream.source(list(bitstamp_eth['close'][-100:]),
                          dtype="float").rename("USD-ETH"),
            Stream.source(list(bitstamp_ltc['close'][-100:]),
                          dtype="float").rename("USD-LTC"))
        # 定义在各个交易所的投资组合
        portfolio = Portfolio(USD, [
            Wallet(bitfinex, 1000000 * USD),
            Wallet(bitfinex, 1000 * BTC),
            Wallet(bitfinex, 500 * ETH),
            Wallet(bitstamp, 100000 * USD),
            Wallet(bitstamp, 500 * BTC),
            Wallet(bitstamp, 2000 * ETH),
            Wallet(bitstamp, 300 * LTC)
        ])
        # 定义数据源
        feed = DataFeed([
            Stream.source(list(bitstamp_eth['volume'][-100:]),
                          dtype="float").rename("volume:/USD-ETH"),
            Stream.source(list(bitstamp_ltc['volume'][-100:]),
                          dtype="float").rename("volume:/USD-LTC")
        ])
        # 生成环境
        env = default.create(
            portfolio=portfolio,
            action_scheme=default.actions.SimpleOrders(min_order_pct=0.0001),
            reward_scheme=default.rewards.SimpleProfit(),
            feed=feed)
        done = False
        obs = env.reset()
        env.action_scheme.min_order_pct = 0.0
        while not done:
            action = env.action_space.sample()
            obs, reward, done, info = env.step(action)

        df = portfolio.ledger.as_frame().head(7)
        print('result: {0};'.format(df))
コード例 #7
0
class IntradayObserver(Observer):
    """The IntradayObserver observer that is compatible with the other `default`
    components.
    Parameters
    ----------
    portfolio : `Portfolio`
        The portfolio to be used to create the internal data feed mechanism.
    feed : `DataFeed`
        The feed to be used to collect observations to the observation window.
    renderer_feed : `DataFeed`
        The feed to be used for giving information to the renderer.
    stop_time : datetime.time
        The time at which the episode will stop.
    window_size : int
        The size of the observation window.
    min_periods : int
        The amount of steps needed to warmup the `feed`.
    randomize : bool
        Whether or not to select a random episode when reset.
    **kwargs : keyword arguments
        Additional keyword arguments for observer creation.
    Attributes
    ----------
    feed : `DataFeed`
        The master feed in charge of streaming the internal, external, and
        renderer data feeds.
    stop_time : datetime.time
        The time at which the episode will stop.
    window_size : int
        The size of the observation window.
    min_periods : int
        The amount of steps needed to warmup the `feed`.
    randomize : bool
        Whether or not a random episode is selected when reset.
    history : `ObservationHistory`
        The observation history.
    renderer_history : `List[dict]`
        The history of the renderer data feed.
    """
    def __init__(self,
                 portfolio: 'Portfolio',
                 feed: 'DataFeed' = None,
                 renderer_feed: 'DataFeed' = None,
                 stop_time: 'datetime.time' = dt.time(16, 0, 0),
                 window_size: int = 1,
                 min_periods: int = None,
                 randomize: bool = False,
                 **kwargs) -> None:
        internal_group = Stream.group(
            _create_internal_streams(portfolio)).rename("internal")
        external_group = Stream.group(feed.inputs).rename("external")

        if renderer_feed:
            renderer_group = Stream.group(
                renderer_feed.inputs).rename("renderer")

            self.feed = DataFeed(
                [internal_group, external_group, renderer_group])
        else:
            self.feed = DataFeed([internal_group, external_group])

        self.stop_time = stop_time
        self.window_size = window_size
        self.min_periods = min_periods
        self.randomize = randomize

        self._observation_dtype = kwargs.get('dtype', np.float32)
        self._observation_lows = kwargs.get('observation_lows', -np.inf)
        self._observation_highs = kwargs.get('observation_highs', np.inf)

        self.history = ObservationHistory(window_size=window_size)

        initial_obs = self.feed.next()["external"]
        initial_obs.pop('timestamp', None)
        n_features = len(initial_obs.keys())

        self._observation_space = Box(low=self._observation_lows,
                                      high=self._observation_highs,
                                      shape=(self.window_size, n_features),
                                      dtype=self._observation_dtype)

        self.feed = self.feed.attach(portfolio)

        self.renderer_history = []

        if self.randomize:
            self.num_episodes = 0
            while self.feed.has_next():
                ts = self.feed.next()["external"]["timestamp"]
                if ts.time() == self.stop_time:
                    self.num_episodes += 1

        self.feed.reset()
        self.warmup()

        self.stop = False

    @property
    def observation_space(self) -> Space:
        return self._observation_space

    def warmup(self) -> None:
        """Warms up the data feed.
        """
        if self.min_periods is not None:
            for _ in range(self.min_periods):
                if self.has_next():
                    obs_row = self.feed.next()["external"]
                    obs_row.pop('timestamp', None)
                    self.history.push(obs_row)

    def observe(self, env: 'TradingEnv') -> np.array:
        """Observes the environment.
        As a consequence of observing the `env`, a new observation is generated
        from the `feed` and stored in the observation history.
        Returns
        -------
        `np.array`
            The current observation of the environment.
        """
        data = self.feed.next()

        # Save renderer information to history
        if "renderer" in data.keys():
            self.renderer_history += [data["renderer"]]

        # Push new observation to observation history
        obs_row = data["external"]
        try:
            obs_ts = obs_row.pop('timestamp')
        except KeyError:
            raise KeyError(
                "Include Stream of Timestamps named 'timestamp' in feed")
        self.history.push(obs_row)

        # Check if episode should be stopped
        if obs_ts.time() == self.stop_time:
            self.stop = True

        obs = self.history.observe()
        obs = obs.astype(self._observation_dtype)
        return obs

    def has_next(self) -> bool:
        """Checks if there is another observation to be generated.
        Returns
        -------
        bool
            Whether there is another observation to be generated.
        """
        return self.feed.has_next() and not self.stop

    def reset(self) -> None:
        """Resets the observer"""
        self.renderer_history = []
        self.history.reset()

        if self.randomize or not self.feed.has_next():
            self.feed.reset()
            if self.randomize:
                episode_num = 0
                while episode_num < randrange(self.num_episodes):
                    ts = self.feed.next()["external"]["timestamp"]
                    if ts.time() == self.stop_time:
                        episode_num += 1

        self.warmup()

        self.stop = False
コード例 #8
0
class IqtObserver(Observer):
    """The iqt observer that is compatible with the other `default`
    components.

    Parameters
    ----------
    portfolio : `Portfolio`
        The portfolio to be used to create the internal data feed mechanism.
    feed : `DataFeed`
        The feed to be used to collect observations to the observation window.
    renderer_feed : `DataFeed`
        The feed to be used for giving information to the renderer.
    window_size : int
        The size of the observation window.
    min_periods : int
        The amount of steps needed to warmup the `feed`.
    **kwargs : keyword arguments
        Additional keyword arguments for observer creation.

    Attributes
    ----------
    feed : `DataFeed`
        The master feed in charge of streaming the internal, external, and
        renderer data feeds.
    window_size : int
        The size of the observation window.
    min_periods : int
        The amount of steps needed to warmup the `feed`.
    history : `ObservationHistory`
        The observation history.
    renderer_history : `List[dict]`
        The history of the renderer data feed.
    """
    def __init__(self,
                 portfolio: 'Portfolio',
                 feed: 'DataFeed' = None,
                 renderer_feed: 'DataFeed' = None,
                 window_size: int = 1,
                 min_periods: int = None,
                 **kwargs) -> None:
        internal_group = Stream.group(
            _create_internal_streams(portfolio)).rename("internal")
        external_group = Stream.group(feed.inputs).rename("external")

        if renderer_feed:
            renderer_group = Stream.group(
                renderer_feed.inputs).rename("renderer")

            self.feed = DataFeed(
                [internal_group, external_group, renderer_group])
        else:
            self.feed = DataFeed([internal_group, external_group])

        self.window_size = window_size
        self.min_periods = min_periods

        self._observation_dtype = kwargs.get('dtype', np.float32)
        self._observation_lows = kwargs.get('observation_lows', -np.inf)
        self._observation_highs = kwargs.get('observation_highs', np.inf)

        self.history = ObservationHistory(window_size=window_size)

        initial_obs = self.feed.next()["external"]
        n_features = len(initial_obs.keys())

        self._observation_space = Box(low=self._observation_lows,
                                      high=self._observation_highs,
                                      shape=(self.window_size, n_features),
                                      dtype=self._observation_dtype)

        self.feed = self.feed.attach(portfolio)

        self.renderer_history = []

        self.feed.reset()
        self.warmup()

    @property
    def observation_space(self) -> Space:
        return self._observation_space

    def warmup(self) -> None:
        """Warms up the data feed.
        """
        if self.min_periods is not None:
            for _ in range(self.min_periods):
                if self.has_next():
                    obs_row = self.feed.next()["external"]
                    self.history.push(obs_row)

    def observe(self, env: 'TradingEnv') -> np.array:
        """Observes the environment.

        As a consequence of observing the `env`, a new observation is generated
        from the `feed` and stored in the observation history.

        Returns
        -------
        `np.array`
            The current observation of the environment.
        """
        data = self.feed.next()

        # Save renderer information to history
        if "renderer" in data.keys():
            self.renderer_history += [data["renderer"]]

        # Push new observation to observation history
        obs_row = data["external"]
        self.history.push(obs_row)

        obs = self.history.observe()
        obs = obs.astype(self._observation_dtype)
        return obs

    def has_next(self) -> bool:
        """Checks if there is another observation to be generated.

        Returns
        -------
        bool
            Whether there is another observation to be generated.
        """
        return self.feed.has_next()

    def reset(self) -> None:
        """Resets the observer"""
        self.renderer_history = []
        self.history.reset()
        self.feed.reset()
        self.warmup()