def __init__(self, param_dict):
        super(ValParamMovingAverage, self).__init__(param_dict)

        self.type = 'moving_average'

        if 'window_size' in param_dict.keys():
            self.window_size = param_dict['window_size']
        else:
            error('window_size needs to be given when method = moving_average')

        if 'tolerance_up' in param_dict.keys():
            self.tolerance_up = param_dict['tolerance_up']
        else:
            self.tolerance_up = 100

        if 'tolerance_down' in param_dict.keys():
            self.tolerance_down = param_dict['tolerance_down']
        else:
            self.tolerance_down = 1

        if 'calculation_period' in param_dict.keys():
            self.calculation_period = param_dict['calculation_period']
        else:
            self.calculation_period = 2

        if 'damping_factor' in param_dict.keys():
            self.damping_factor = param_dict['damping_factor']
        else:
            self.damping_factor = 1
Exemple #2
0
    def get_close_moving_average(self, window_size, time=None, damping_factor=None):
        if time is None:
            time_end = self.data.index[-1]
            time_start = self.data.index[0]
        else:
            time_end = time
            time_start = time - timedelta(days=window_size)

        df = self.get_price_close()
        if damping_factor is None:
            ma_series = df.truncate(before=time_start, after=time_end)
            ma_series = ma_series.rolling(window_size).mean()
            ma_series = ma_series.dropna()
        else:
            series = df.truncate(before=time_start, after=time_end)
            series_size = len(series)
            if series_size < window_size:
                error('The input series is shorter than the window size.')

            ma_series = pd.Series()
            for i in range(series_size - window_size):
                avg = 0.0
                for j in range(window_size):
                    scalar = damping_factor ** j
                    avg = avg + scalar * series.iloc[window_size + i - j - 1]
                avg = avg / window_size
                ma_series.at[window_size + i - 1] = avg

        return ma_series
def signal_average_envelope(env, asset, time=None, val_param=None):
    if val_param is None:
        val_param = {
            'window_size': [5],
            'tolerance_up': 0.025,
            'tolerance_down': 0.025,
            'damping_factor': 1.0
        }

    ma_param = ValParamMovingAverage(val_param)
    if len(ma_param.window_size) != 1:
        error('The window size list needs to be of size 1')
    window_size = ma_param.window_size[0]

    section = env.get_section(asset)

    if time is None:
        time = section.data.index[-1]

    if section.data.size < window_size + 2:
        error('Cannot calculate the moving average. The series is too short.')

    factor = ma_param.damping_factor

    price = section.get_price_close(time)
    ma = section.get_close_moving_average(window_size, time, factor)

    if price > (1 + ma_param.tolerance_up) * ma.iloc[-1]:
        return -1
    elif price < (1 - ma_param.tolerance_down) * ma.iloc[-1]:
        return 1
    else:
        return 0
Exemple #4
0
    def plot_close_moving_average(self, window_sizes, damping_factor=None):
        if len(window_sizes) == 0:
            error('List of window sizes needs to be provided.')

        for size in window_sizes:
            series = self.get_close_moving_average(size, None, damping_factor)
            plt.plot(series.index, series.values)

        plt.show()
    def value(self, asset_prices):
        total = self.cash + self.wife_pocket
        for asset in self.holdings.keys():
            if asset not in asset_prices.keys():
                error('The price of ' + asset +
                      'is not given in the input dict.')
            total = total + self.holdings[asset] * asset_prices[asset]

        return total
Exemple #6
0
    def get_price_close(self, time=None):
        if 'price_close' in self.data.columns:
            price_close = 'price_close'
        elif self.target + '_price_close' in self.data.columns:
            price_close = self.target + '_price_close'
        else:
            error('Price close is not in the env section data.')

        if time is None:
            return self.data[price_close]

        series = self.data[price_close]
        series_trunc = series.truncate(after=time)
        return series_trunc.iloc[-1]
    def sim_price_close(self, num_regimes=1, time_start=None, time_end=None):
        time_spot = self.data.index[-1]

        sim_price_close = pd.Series()
        sim_price_close.index.name = 'time_close'
        sim_price_close.rename('price_close_sim')
        sim_price_close[time_spot] = self.get_price_close(time_spot)

        if num_regimes <= 0:
            error('num_regimes needs to be positive integer.')

        if time_start is None:
            time_start = self.data.index[0]

        if time_end is None:
            time_end = self.data.index[-1]

        time_start = self._round_time(time_start)
        time_end = self._round_time(time_end)

        inter_length = (time_end - time_start) / num_regimes

        for i in range(num_regimes):
            hist_start = time_start + i * inter_length
            hist_end = hist_start + inter_length

            hist_start = self._round_time(hist_start)
            hist_end = self._round_time(hist_end)

            statistics = self.stat(hist_start, hist_end)
            avg = statistics['period_log_return']['mean']
            stdev = statistics['period_log_return']['std']
            count = int(statistics['period_log_return']['count'])

            # TODO: use ARIMA for sampling
            # Here we use p(t_i+1) = p(t_i) * exp( (avg+stdev*N(0,1)) * (t_i+1-t_i) )
            norm_vec = np.random.normal(avg, stdev, count - 1)

            for j in range(count - 1):
                # TODO: only handle hourly or daily data.
                if self.data_info['period_id'] == '1HRS':
                    sim_time = sim_price_close.index[-1] + timedelta(hours=1)
                else:
                    sim_time = sim_price_close.index[-1] + timedelta(days=1)

                sim_time = self._round_time(sim_time)
                sim_price_close[sim_time] = sim_price_close.values[
                    -1] * np.exp(norm_vec[j])

        return sim_price_close
Exemple #8
0
def signal_double_dip(env, asset, time=None, val_param=None):
    if val_param is None:
        val_param = {'window_size': [3, 20]}

    if len(val_param['window_size']) != 2:
        error(
            'For double dip, two window sizes need to be provided in the rule.'
        )

    dip_param = ValParamMovingAverage(val_param)
    window_ma = dip_param.window_size[0]
    window_dip = dip_param.window_size[1]
    section = env.get_section(asset)

    series = section.get_price_close()

    if time is None:
        time = series.index[-1]

    if series.index[0] + timedelta(days=window_ma + window_dip) > time:
        error(
            'The given time is early than the series start date plus window.')

    series_trunc = series.rolling(window=window_ma,
                                  center=False).mean().dropna()
    end_date = time
    start_date = time - timedelta(days=window_dip)

    series_trunc = series_trunc.truncate(before=start_date, after=end_date)
    y = np.array(list(series_trunc.values))
    x = np.arange(len(y))
    # t = np.array(list(series_trunc.index))
    z = np.polyfit(x, y, 4)

    a = 4 * z.item(0)
    b = 3 * z.item(1)
    c = 2 * z.item(2)
    d = z.item(3)

    ind_roots = -27 * a**2 * d**2 + 18 * a * b * c * d - 4 * a * c**3 - 4 * b**3 * d + b**2 * c**2

    if z.item(0) > 0:
        if ind_roots > 0:
            return 1
    else:
        if ind_roots > 0:
            return -1

    return 0
Exemple #9
0
def signal_consecutive_moves(env, asset, time=None, val_param=None):
    if val_param is None:
        val_param = {
            'method': 'moving_average',
            'window_size': [10],
            'tolerance_up': 0.03,
            'tolerance_down': 0.03
        }

    if val_param['method'] == 'moving_average':
        ma_param = ValParamMovingAverage(val_param)
        section = env.get_section(asset)
        window_size = ma_param.window_size[0]

        if time is None:
            time = section.data.index[-1]

        if section.data.size < window_size + 2:
            error(
                'Cannot calculate the moving average. The series is too short.'
            )

        factor = ma_param.damping_factor

        is_bull = True
        is_bear = True

        average = []
        for i in range(ma_param.calculation_period):
            time_end = time - timedelta(days=i)
            average.append(
                section.get_close_moving_average(window_size, time_end,
                                                 factor).iloc[-1])

        for i in range(len(average) - 1):
            is_bull = is_bull and (
                average[i] > (1 - ma_param.tolerance_up) * average[i + 1])
            is_bear = is_bear and (
                average[i] < (1 - ma_param.tolerance_down) * average[i + 1])

        if is_bear:
            return -1
        elif is_bull:
            return 1
        else:
            return 0
    else:
        error('Only moving average is implemented for bear market indicator.')
    def __init__(self, section_list):
        """
        create a collection of market environment based on a list of envr sections
        :param section_list:
        """
        model_dict = {}

        if len(section_list) > 0 and 'period_id' in section_list[0].data_info:
            freq = section_list[0].data_info['period_id']

        for i in range(len(section_list)):
            model_dict[section_list[i].target] = section_list[i]
            if 'period_id' in section_list[i].data_info:
                if section_list[0].data_info['period_id'] != freq:
                    error(
                        'All the sections in the list should have the data with same freq.'
                    )

        self.model_dict = model_dict
def signal_long_short_crossing(env, asset, time=None, val_param=None):
    if val_param is None:
        val_param = {
            'window_size': [5, 30],
            'tolerance_up': 0.0,
            'tolerance_down': 0.0
        }

    if val_param['window_size'][0] > val_param['window_size'][1]:
        window_short = val_param['window_size'][1]
        window_long = val_param['window_size'][0]
    else:
        window_short = val_param['window_size'][0]
        window_long = val_param['window_size'][1]

    ma_param = ValParamMovingAverage(val_param)
    section = env.get_section(asset)

    if time is None:
        time = section.data.index[-1]

    if section.data.size < window_long + 2:
        error('Cannot calculate the moving average. The series is too short.')

    factor = ma_param.damping_factor

    series_short = section.get_close_moving_average(window_short, time, factor)
    series_long = section.get_close_moving_average(window_long, time, factor)

    if series_short.iloc[-1] > (1 +
                                ma_param.tolerance_up) * series_long.iloc[-1]:
        return -1
    elif series_short.iloc[-1] < (
            1 - ma_param.tolerance_down) * series_long.iloc[-1]:
        return 1
    else:
        return 0