Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Draft] Minimum Profit Condition Optimization - Cointegration Approach #7

Closed
wants to merge 3 commits into from

Conversation

Stochastic-Adventure
Copy link

Description

Implementations in this module are based on the following paper:
Lin, Y.-X., McCrae, M., and Gulati, C. (2006). Loss protection in pairs trading through minimum profit bounds: A cointegration approach.Journal of Applied Mathematics and Decision Sciences, 2006(1):1–14.
Puspaningrum, H., Lin, Y.-X., and Gulati, C. M. (2010).  Finding the optimal pre-set boundaries for pairs trading strategy based on cointegration technique. Journal of  Statistical  Theory and Practice, 4(3):391–419.

Implemented features are:

  • Simulate AR(1) processes in batch
  • Simulate cointegrated time series pairs in batch
  • Calculate cointegration coefficient based on either Engle-Granger or Johansen test
  • Fit the AR(1) coefficient of cointegration error
  • Calculate optimal preset upper-bound and minimal total profit for cointegrated pairs trading strategy
  • Trade the strategy based on the optimal parameters

Dependency:

  • mlfinlab.statistical_arbitrage

Type of change

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update

How Has This Been Tested?

This unit tests file was created to test the added functions:

  • test\test_minimum_profit.py

Test Configuration:

  • Windows 10
  • PyCharm

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

# Description

Implementations in this module are based on the book by Ernest P. Chan **"Algorithmic Trading: Winning Strategies and Their Rationale"**.

Implemented features are:
- Johansen cointegration test
- Engle-Granger cointegration test
- Half-life of mean reversion function
- Linear trading strategy
- Bollinger Bands trading strategy

## Type of change

- [x] New feature (non-breaking change which adds functionality)
- [x] This change requires a documentation update

# How Has This Been Tested?

This unit tests file was created to test the added functions:

- [x] test_mean_reversion.py

**Test Configuration**:
* Windows 10
* PyCharm

# Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my feature works
- [x] New and existing unit tests pass locally with my changes
- [x] Any dependent changes have been merged and published in downstream modules
@PanPip PanPip self-requested a review November 10, 2020 11:35
@PanPip PanPip added documentation Improvements or additions to documentation enhancement New feature or request labels Nov 10, 2020
Copy link
Contributor

@PanPip PanPip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Went over the code part. It's great that we're close to getting all the functionality ready 👍

Left some comments covering possible style improvements and code restructuring. We'll discuss some parts in more detail over a call.

@@ -0,0 +1,420 @@
import warnings
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add a copyright note to every code and unit test file.

@@ -0,0 +1,420 @@
import warnings

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, these files should be inside the arbitragelab folder.

We will solve the questions regarding naming during the call.

import numpy as np
import pandas as pd
import statsmodels.api as sm
from mlfinlab.statistical_arbitrage import JohansenPortfolio, EngleGrangerPortfolio
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A reminder to later redirect this to functions from the ArbitrageLab.

Comment on lines 31 to 32
Build a pd.DataFrame of both series for cointegration error calculation.
Initialize a built-in trade book with position, entry price, P&L, and number of trades information.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can try to simplify this by requiring a pd.DataFrame as an input format.

Comment on lines 34 to 37
:param price_s1: (pd.Series or np.array) Share S1 price series
:param price_s2: (pd.Series or np.array) Share S2 price series
:param s1_name: (str) Share S1 name
:param s2_name: (str) Share S2 name
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the right style for variable descriptions, but please add fulls stops at the end.

Comment on lines 343 to 361
if capital_req <= dollar_constraint:
# Record the entry price.
self._entry_price = current_price

# Do we open a U-trade or L-trade?
if trade_df_with_cond['otc_U'].iloc[i]:

# U-trade, short share S1, long share S2
self._position = position * np.array([-1, 1])
current_trade = 1

elif allow_ltrade and trade_df_with_cond['otc_L'].iloc[i]:

# L-trade, long share S1, short share S2
self._position = position * np.array([1, -1])
current_trade = -1
else:
# No opening condition met, forward to next day
continue
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll have to refactor this to make it more compact and readable. I'll help.

Comment on lines 16 to 24
Methods:
train_test_split(date_cutoff, num_cutoff): A method that splits the price data into a training set and
a test set according to the cutoff. In-sample simulation can be done when both cutoffs are set to None.
fit(train_df): Derive the cointegration coefficient, cointegration error, AR(1) cofficient and the fitted
residual of the AR(1) process.
optimize(ar_coeff, epsilon_t, ar_resid, horizon, granularity):
Optimize the upper bound for U-trade by optimizing minimum trade profit
trade(self, trade_df, upper_bound, minimum_profit, beta, epsilon_t, **kwarg):
Simulate trades applying the optimal upper bound and lower bound for U-trade and L-trade, respectively.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we'll keep this style for internal methods. But it's ok if you write them for now as:

Methods:
- train_...
    ....
- fit ...
   ....

Comment on lines 50 to 52
"ar_coeff": 0.1,
"white_noise_var": 0.5,
"constant_trend": 13.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should later make these input parameters instead of hardcoded ones.

Setter for price simulation parameters
:param param: (str) Parameter dictionary key
:param value: (float) Parameter value
:return:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returns can be removed if it's a setter method.

Comment on lines 173 to 174
:return:
(np.array, np.array, np.array) Price series of share S1, price series of share S2, and cointegration error.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't move the variable description to the next line like this. It should be:

:return: (np.array, np.array, np.array) Price series of share S1, price series of share S2,
    and cointegration error.

@PanPip
Copy link
Contributor

PanPip commented Nov 18, 2020

This PR was moved to PR#19.

@PanPip PanPip closed this Nov 18, 2020
@PanPip PanPip deleted the minimum_profit_optimization branch December 9, 2020 12:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants