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
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
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, })
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
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
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
def __init__(self, series: QFSeries = None): self.series = series self.log_returns_tms = series.to_log_returns()
def get_stats_from_tms(series: QFSeries): log_ret_tms = series.to_log_returns() return InSampleReturnStats(log_ret_tms.mean(), log_ret_tms.std())