예제 #1
0
def get_volatility(qf_series: QFSeries,
                   frequency: Frequency = None,
                   annualise: bool = True) -> float:
    """
    Calculates a volatility for the given series of returns or prices. If a PricesSeries is given,
    the calculation window is shorter by 1 due to the initial conversion into returns.

    Parameters
    ----------
    qf_series: QFSeries
        series of prices/returns (as numbers, e.g. 0.5 corresponds to 50% return)
    frequency: Frequency
        the frequency of samples in the returns series; it is only obligatory to specify frequency if the annualise
        parameter is set to True, which is a default value
    annualise: bool
        True if the volatility values should be annualised; False otherwise. If it is set to True, then it is obligatory
        to specify a frequency of the returns series.

    Returns
    -------
    float
        volatility for the whole series.
    """
    returns_tms = qf_series.to_log_returns()
    assert len(
        returns_tms) >= 2, "minimal num_of_rows to receive a real result is 2"
    assert not annualise or frequency is not None

    volatility = returns_tms.std()

    if annualise:
        volatility = annualise_with_sqrt(volatility, frequency)

    return volatility
예제 #2
0
def create_qq_chart(strategy: QFSeries) -> Chart:
    colors = Chart.get_axes_colors()

    strategy = strategy.to_log_returns()
    # Normalize
    strategy = strategy - strategy.mean()
    strategy = strategy / strategy.std()
    # Sort
    strategy_values = sorted(strategy.values)

    # Create benchmark
    benchmark_values = list(range(1, len(strategy_values) + 1))
    n = len(strategy_values) + 1
    benchmark_values = map(lambda x: x / n, benchmark_values)
    benchmark_values = list(map(lambda x: norm.ppf(x), benchmark_values))

    # Figure out the limits.
    maximum = max(max(benchmark_values), max(strategy_values))

    result = LineChart(start_x=-maximum, end_x=maximum, upper_y=maximum, lower_y=-maximum)
    result.add_decorator(ScatterDecorator(
        benchmark_values, strategy_values, color=colors[0], alpha=0.6, edgecolors='black', linewidths=0.5))

    result.add_decorator(VerticalLineDecorator(0, color='black', linewidth=1))
    result.add_decorator(HorizontalLineDecorator(0, color='black', linewidth=1))

    result.add_decorator(TitleDecorator("Normal Distribution Q-Q"))
    result.add_decorator(AxesLabelDecorator("Normal Distribution Quantile", "Observed Quantile"))

    # Add diagonal line.
    result.add_decorator(DiagonalLineDecorator(color=colors[1]))

    return result
예제 #3
0
    def calculate_aggregated_cone_oos_only(
            self, oos_series: QFSeries, is_mean_return: float, is_sigma: float,
            number_of_std: float) -> QFDataFrame:
        """
        This functions does not need the IS history, only the IS statistics.

        Parameters
        ----------
        oos_series
            series that is plotted on the cone - corresponds to the oos returns
        is_mean_return
            mean daily log return of the strategy In Sample
        is_sigma
            std of daily log returns of the strategy In Sample
        number_of_std
            corresponds to the randomness of the stochastic process. reflects number of standard deviations
            to get expected values for. For example 1.0 means 1 standard deviation above the expected value.

        Returns
        -------
        QFDataFrame: contains values corresponding to Strategy, Mean and Std. Values are indexed by number of days
            from which given cone was evaluated
        """

        log_returns_tms = oos_series.to_log_returns()
        nr_of_data_points = oos_series.size

        strategy_values = np.empty(nr_of_data_points)
        expected_values = np.empty(nr_of_data_points)

        for i in range(nr_of_data_points):
            cone_start_idx = i + 1

            # calculate total return of the strategy
            oos_log_returns = log_returns_tms[cone_start_idx:]
            total_strategy_return = exp(
                oos_log_returns.sum())  # 1 + percentage return

            # calculate expectation
            number_of_steps = len(oos_log_returns)
            starting_price = 1  # we take 1 as a base value
            total_expected_return = self.get_expected_value(
                is_mean_return, is_sigma, starting_price, number_of_steps,
                number_of_std)

            # writing to the array starting from the last array element and then moving towards the first one
            strategy_values[-i - 1] = total_strategy_return
            expected_values[-i - 1] = total_expected_return

        index = Int64Index(range(0, nr_of_data_points))

        strategy_values_tms = PricesSeries(index=index, data=strategy_values)
        expected_tms = QFSeries(index=index, data=expected_values)

        return QFDataFrame({
            'Strategy': strategy_values_tms,
            'Expectation': expected_tms,
        })
예제 #4
0
    def __init__(self, returns_tms: QFSeries, vol_process: VolatilityProcess, method: str = 'analytic',
                 horizon: int = 1, annualise: bool = True, frequency: Frequency = Frequency.DAILY):
        self.vol_process = vol_process
        self.method = method
        self.horizon = horizon
        self.window_len = None  # will be assigned after calculate_timeseries() method call

        assert not annualise or frequency is not None
        self.annualise = annualise
        self.frequency = frequency

        self.returns_tms = returns_tms.to_log_returns()
        self.forecasted_volatility = None  # will be assigned after calling one of the calculation methods
예제 #5
0
def rolling_volatility(qf_series: QFSeries,
                       frequency: Frequency = None,
                       annualise: bool = True,
                       window_size: int = None) -> QFSeries:
    """
    Calculates the rolling volatility for the given series of returns. If the annualise parameter is set to be True,
    then it is obligatory to specify frequency.

    Parameters
    ----------
    qf_series: QFSeries
        series of returns or prices
    frequency: Frequency
        the frequency of samples in the returns series; it is only obligatory to specify frequency if the annualise
        parameter is set to True, which is a default value
    annualise: bool
        True if the volatility values should be annualised; False otherwise. If it is set to True, then it is obligatory
        to specify a frequency of the returns series.
    window_size: int
        number of samples from which the rolling volatility will be calculated. If it is not set, then only overall
        volatility (of the whole series) will be calculated

    Returns
    -------
    QFSeries
        Series of volatility values for each day concerning last window_size days.
    """
    returns_tms = qf_series.to_log_returns()
    if annualise:
        assert frequency is not None

    volatility_values = []
    for i in range(window_size - 1, len(returns_tms)):
        start_index = i - window_size + 1
        end_index = i + 1

        returns_from_window = returns_tms[start_index:end_index]
        volatility = get_volatility(returns_from_window, frequency, annualise)

        volatility_values.append(volatility)

    first_date_idx = window_size - 1
    dates = returns_tms.index[first_date_idx::]
    volatility_tms = QFSeries(data=volatility_values, index=dates)

    return volatility_tms
예제 #6
0
    def __init__(self,
                 returns_tms: QFSeries,
                 vol_process: VolatilityProcess,
                 method: str = 'analytic',
                 horizon: int = 1,
                 annualise: bool = True,
                 frequency: Frequency = Frequency.DAILY):
        """
        Creates class used for vol forecasting: describes the volatility forecast configuration as well as the input
        and output data (output is created and assigned by calling one of the class methods).

        An instance of this class should describe one specific forecast and store its parameters.
        Parameters should NOT be modified after calling one of the calculation methods (only one call is allowed)

        Parameters
        ----------
        returns_tms
            series of returns of the asset
        vol_process
            volatility process used for forecasting. For example EGARCH(p=p, o=o, q=q)
        horizon
            horizon for the volatility forecast. It is expressed in the frequency of the returns provided
        method
            method of forecast calculation. Possible: 'analytic', 'simulation' or 'bootstrap'
            'analytic' is the fastest but is not available for EGARCH and possibly some other models.
            For details check arch documentation
        annualise
            flag indicating whether the result is annualised; True by default
        frequency
            if annualise is True, this should be the frequency of the returns timeseries that is provided as input;
            not used if annualise is False.

        """
        self.vol_process = vol_process
        self.method = method
        self.horizon = horizon
        self.window_len = None  # will be assigned after calculate_timeseries() method call

        assert not annualise or frequency is not None
        self.annualise = annualise
        self.frequency = frequency

        self.returns_tms = returns_tms.to_log_returns()
        self.forecasted_volatility = None  # will be assigned after calling one of the calculation methods
예제 #7
0
 def __init__(self, series: QFSeries = None):
     self.series = series
     self.log_returns_tms = series.to_log_returns()
예제 #8
0
 def get_stats_from_tms(series: QFSeries):
     log_ret_tms = series.to_log_returns()
     return InSampleReturnStats(log_ret_tms.mean(), log_ret_tms.std())