arbitragelab.trading.basic_copula

Master module that implements the basic copula trading strategy.

This module is almost identical in terms of functionality as copula_strategy. But is designed with better efficiency, better structure, native pandas support, and supports mixed copulas. The trading logic is more clearly defined and all wrapped in one method for easier adjustment when needed, due to the ambiguities from the paper.

Module Contents

Classes

BasicCopulaTradingRule

This module is a realization of the methodology in the following paper:

class BasicCopulaTradingRule(open_probabilities: Tuple[float, float] = (0.05, 0.95), exit_probabilities: Tuple[float, float] = (0.5, 0.5), exit_rule: str = 'and')

This module is a realization of the methodology in the following paper: Liew, R.Q. and Wu, Y., 2013. Pairs trading: A copula approach. Journal of Derivatives & Hedge Funds, 19(1), pp.12-30.

This is the threshold basic copula trading strategy implemented by [Liew et al. 2013]. First, one uses formation period prices to train a copula, then trade based on conditional probabilities calculated from the quantiles of the current price u1 and u2. If we define the spread as stock 1 in relation to stock 2, then the logic is as follows (All the thresholds can be customized via open_thresholds, exit_thresholds parameters):

  • If P(U1 <= u1 | U2 = u2) <= 0.05 AND P(U2 <= u2 | U1 = u1) >= 0.95, then stock 1 is under-valued and stock 2 is over-valued. Thus we long the spread.

  • If P(U1 <= u1 | U2 = u2) >= 0.95 AND P(U2 <= u2 | U1 = u1) <= 0.05, then stock 2 is under-valued and stock 1 is over-valued. Thus we short the spread.

  • We close the position if the conditional probabilities cross with 0.5 (exit_probabilities).

For the exiting condition, the author proposed a closure when stock 1 AND 2’s conditional probabilities cross 0.5. However, we found it sometimes too strict and fails to exit a position when it should occasionally. Hence we also provide the OR logic implementation. You can use it by setting exit_rule=’or’. Also note that the signal generation is independent from the current position.

set_copula(copula: object)

Set fit copula to self.copula.

Parameters:

copula – (object) Fit copula object.

set_cdf(cdf_x: Callable[[float], float], cdf_y: Callable[[float], float])

Set marginal C.D.Fs functions which transform X, Y values into probabilities, usually ECDFs are used. One can use construct_ecdf_lin function from copula_calculations module.

Parameters:
  • cdf_x – (func) Marginal C.D.F. for series X.

  • cdf_y – (func) Marginal C.D.F. for series Y.

update_probabilities(x_value: float, y_value: float)

Update latest probabilities (p1,p2) values from empirical x_value and y_value, where:

p1=self.copula.get_condi_prob(self.cdf_x(x_value), self.cdf_y(y_value)), p2=self.copula.get_condi_prob(self.cdf_y(y_value), self.cdf_x(x_value)),

As a result, updated probabilities are stored in self.current_probabilities and previous probabilities are stored in self.prev_probabilities. These containers are used to check entry/exit signals.

Parameters:
  • x_value – (float) Latest value (price) for series X.

  • y_value – (float) Latest value (price) for series Y.

check_entry_signal() tuple

Function which checks entry condition based on self.current_probabilities.

  • If P(U1 <= u1 | U2 = u2) <= 0.05 AND P(U2 <= u2 | U1 = u1) >= 0.95, then stock 1 is under-valued and stock 2 is over-valued. Thus we long the spread.

  • If P(U1 <= u1 | U2 = u2) >= 0.95 AND P(U2 <= u2 | U1 = u1) <= 0.05, then stock 2 is under-valued and stock 1 is over-valued. Thus we short the spread.

Returns:

(tuple) Tuple of boolean entry flag and side (if entry flag is True).

add_trade(start_timestamp: pandas.Timestamp, side_prediction: int, uuid: uuid.UUID = None)

Adds a new trade to track. Calculates trigger timestamp.

Parameters:
  • start_timestamp – (pd.Timestamp) Timestamp of the future label.

  • side_prediction – (int) External prediction for the future label.

  • uuid – (str) Unique identifier used to link label to tradelog action.

update_trades(update_timestamp: pandas.Timestamp) list

Checks whether any of the thresholds are triggered and currently open trades should be closed. Before using the method, one should have called self.update_probabilities() to update recent probalities.

Parameters:

update_timestamp – (pd.Timestamp) New timestamp to check vertical threshold.

Returns:

(list) List of closed trades.