Example #1
0
    def calculate_single_forecast(self, multiplier: int = 1000) -> float:
        """
        Calculates volatility forecast for single asset. It is expressed in the frequency of returns.
        Value is calculated based on the configuration as in the object attributes. The result of the calculation
        is returned as well as assigned as self.forecasted_volatility object attribute.

        Parameters
        ----------
        multiplier: int
            ex. 100 (should be > 1)
            improves the optimization performance, as for very small values the results may be faulty;
            after optimization the results are scaled back (division by multiplier value)

        Returns
        -------
        float
            Forecasted value of the volatility.
        """

        assert self.forecasted_volatility is None, "The forecast was already calculated."
        assert multiplier >= 1

        returns_tms = self.returns_tms * multiplier
        volatility_value = self._calculate_single_value(returns_tms)
        volatility_value = volatility_value / multiplier

        if self.annualise:
            volatility_value = annualise_with_sqrt(volatility_value, self.frequency)

        self.forecasted_volatility = volatility_value
        return volatility_value
Example #2
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
Example #3
0
    def _calculate_risk_stats(self):
        self.cvar = cvar(self.returns_tms, 0.05)  # default is the 5% CVaR
        log_cvar = simple_to_log_return(self.cvar)
        annualised_log_cvar = annualise_with_sqrt(log_cvar, self.frequency)
        self.annualised_cvar = log_to_simple_return(annualised_log_cvar)

        prices_tms = self.returns_tms.to_prices()
        self.max_drawdown = max_drawdown(prices_tms)
        self.avg_drawdown = avg_drawdown(prices_tms)
        self.avg_drawdown_duration = avg_drawdown_duration(prices_tms)
Example #4
0
    def get_volatility(ohlc: PricesDataFrame,
                       frequency: Frequency = None,
                       annualise: bool = True,
                       alpha: float = None) -> float:
        """
        Implementation of the algorithm described in 'Drift Independent Volatility Estimation Based on High, Low,
        Open and Close Prices', developed by Dennis Yang and Qiang Zhang, published in June 2000 issue of Journal
        of Business. The new estimator has the following nice properties:

        - unbiased in the continuous limit,
        - independent of the drift,
        - dealing with opening price jumps in a consistent way,
        - smallest variance among all estimators with the similar properties.

        Parameters
        ----------
        ohlc: PricesDataFrame
            QFDataFrame consisting of four QFPricesSeries: open, high, low, close
        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.
        alpha: float
            expectation of u(u-c)+d(d-c) squared, values in range of (1.331, 1.5);
            authors of the algorithm suggest 1.34 in practice

        Returns
        -------
        float
            Drift Independent Volatility of type float
        """
        assert ohlc.num_of_rows >= 2
        assert not annualise or frequency is not None

        var_RS = DriftIndependentVolatility._rogers_satchell_variance(ohlc)
        var_O = DriftIndependentVolatility._open_variance(ohlc)
        var_C = DriftIndependentVolatility._close_variance(ohlc)
        k = DriftIndependentVolatility._k_factor(ohlc, alpha)

        variance = var_O + k * var_C + (1 - k) * var_RS
        volatility = np.sqrt(variance)

        if annualise:
            volatility = annualise_with_sqrt(volatility, frequency)

        return volatility
Example #5
0
    def calculate_timeseries(self,
                             window_len: int,
                             multiplier: int = 1) -> QFSeries:
        """
        Calculates volatility forecast for single asset. It is expressed in the frequency of returns.
        Value is calculated based on the configuration as in the object attributes. The result of the calculation
        is returned as well as assigned as self.forecasted_volatility object attribute.

        Parameters
        ----------
        window_len
            size of the rolling window, number of rows used as input data to calculate forecasted volatility
        multiplier
            ex. 100 (should be > 1)
            improves the optimization performance, as for very small values the results may be faulty;
            after optimization the results are scaled back (division by multiplier value)

        Returns
        -------
        Timeseries of forecasted volatility.
        """

        assert self.forecasted_volatility is None, "The forecast was already calculated."
        assert window_len is not None, "For timeseries calculation the rolling window length must be specified."
        self.window_len = window_len
        assert multiplier >= 1

        returns_tms = self.returns_tms * multiplier
        volatility_tms = returns_tms.rolling_window(
            window_len, self._calculate_single_value)
        volatility_tms = volatility_tms.dropna()
        volatility_tms = volatility_tms / multiplier

        if self.annualise:
            volatility_tms = annualise_with_sqrt(volatility_tms,
                                                 self.frequency)

        self.forecasted_volatility = volatility_tms
        return volatility_tms
Example #6
0
    def test_annualise_with_sqrt(self):
        actual_annualised_values = annualise_with_sqrt(
            self.test_returns, frequency=Frequency.DAILY)
        expected_annualised_values = [i * sqrt(252) for i in self.test_returns]

        self.assertEqual(expected_annualised_values, actual_annualised_values)