From 2244399a69a0441b4471ae133fcef647505c224a Mon Sep 17 00:00:00 2001 From: robatobalzac <152008496+robatobalzac@users.noreply.github.com> Date: Sat, 2 Aug 2025 09:54:10 -0700 Subject: [PATCH 1/9] Green test-suite on Python 3: slice & dict fixes --- priceprop/__init__.py | 2 +- priceprop/propagator.py | 57 +++++++++++++++++++++++++++++++--------- setup.py | 28 +++++++++++--------- tests/test_propagator.py | 2 +- tests/test_tim2.py | 0 tox.ini | 6 +++++ 6 files changed, 69 insertions(+), 26 deletions(-) create mode 100644 tests/test_tim2.py create mode 100644 tox.ini diff --git a/priceprop/__init__.py b/priceprop/__init__.py index d6e952f..439814a 100644 --- a/priceprop/__init__.py +++ b/priceprop/__init__.py @@ -1,4 +1,4 @@ -from propagator import * +from .propagator import * def __reload_submodules__(): reload(propagator) \ No newline at end of file diff --git a/priceprop/propagator.py b/priceprop/propagator.py index 23165b9..5a0cb43 100644 --- a/priceprop/propagator.py +++ b/priceprop/propagator.py @@ -9,12 +9,26 @@ # ===================================================================== def integrate(x): - "Return lag 1 sum, i.e. price from return, or an integrated kernel." + """ + Return lag 1 sum, i.e. price from return, or an integrated kernel. + @param x: array-like + The signal to integrate + @return: array-like + The integrated signal + """ return np.concatenate([[0], np.cumsum(x[:-1])]) def smooth_tail_rbf(k, l0=3, tau=5, smooth=1, epsilon=1): - """Smooth tail of array k with radial basis functions""" + """ + Smooth tail of array k with radial basis functions + @param k: array-like + The array to smooth + @param l0: int + The lag at which to start the interpolation + @param tau: int + The time constant for the exponential decay + """ # interpolate in log-lags l = np.log(np.arange(l0,len(k))) # estimate functions @@ -33,6 +47,13 @@ def smooth_tail_rbf(k, l0=3, tau=5, smooth=1, epsilon=1): def propagate(s, G, sfunc=np.sign): """Simulate propagator model from signs and one kernel. Equivalent to tim1, one of the kernels in tim2 or hdim2. + @param s: array-like + The signs to propagate + @param G: array-like + The kernel to propagate with + @param sfunc: function + The function to apply to the signs. Default: np.sign + @return: array-like """ steps = len(s) s = sfunc(s[:len(s)]) @@ -43,7 +64,17 @@ def propagate(s, G, sfunc=np.sign): # ===================================================================== def _return_response(ret, x, maxlag): - """Helper for response and response_grouped_df.""" + """ + Helper for response and response_grouped_df. + @param ret: str + 'l' for lags, 's' for differential response, 'r' for return response + @param x: array-like + The signal to calculate the response of + @param maxlag: int + The maximum lag to calculate the response of + @return: tuple + """ + maxlag = int(maxlag) # return what? ret = ret.lower() res = [] @@ -75,21 +106,19 @@ def response(r, s, maxlag=10**4, ret='lsr', subtract_mean=False): Note that this commonly used price response is a simple cross correlation and NOT equivalent to the linear response in systems analysis. - - Parameters: - =========== - - r: array-like + @param r: array-like Returns - s: array-like + @param s: array-like Order signs - maxlag: int + @param maxlag: int Longest lag to calculate - ret: str + @param ret: str can include 'l' to return lags, 'r' to return response, and 's' to return differential response (in specified order). - subtract_mean: bool + @param subtract_mean: bool Subtract means first. Default: False (signal means already zero) + @return: tuple + The lag, differential response, and response """ maxlag = min(maxlag, len(r) - 2) s = s[:len(r)] @@ -147,6 +176,10 @@ def beta_from_gamma(gamma): G(lag) = lag**-beta that compensates a sign-autocorrelation C(lag) = lag**-gamma. + @param gamma: float + The exponent of the sign-autocorrelation + @return: float + The exponent beta """ return (1-gamma)/2. diff --git a/setup.py b/setup.py index f22235a..be412ff 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='priceprop', - version='1.0.2', + version='1.0.3', description=( 'Calibrate and simulate linear propagator models for the price ' 'impact of an extrinsic order flow.' @@ -15,19 +15,22 @@ Journal of Statistical Mechanics (2017, in print) Preprint at arXiv:1706.04163 """, + python_requires='>=3.8', classifiers=[ - 'Development Status :: 5 - Production/Stable', + 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'Intended Audience :: Education', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 2 :: Only', - 'Programming Language :: Python :: 2.7', - #'Programming Language :: Python :: 3', - #'Programming Language :: Python :: 3.6', 'Topic :: Scientific/Engineering', 'Topic :: Software Development :: Libraries', - 'Topic :: Software Development :: Libraries :: Python Modules' + 'Topic :: Software Development :: Libraries :: Python Modules', + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3 :: 8", + "Programming Language :: Python :: 3 :: 9", + "Programming Language :: Python :: 3 :: 10", + "Programming Language :: Python :: 3 :: 11" ], keywords=[ 'propagator', 'price impact', 'intra day', 'order flow', @@ -36,19 +39,20 @@ ], url='http://github.com/felixpatzelt/priceprop', download_url=( - 'https://github.com/felixpatzelt/priceprop/archive/1.0.2.tar.gz' + 'https://github.com/felixpatzelt/priceprop/archive/1.0.3.tar.gz' ), author='Felix Patzelt', author_email='felix@neuro.uni-bremen.de', license='MIT', packages=find_packages(), install_requires=[ - 'numpy', - 'scipy', - 'pandas', - 'scorr' + "numpy>=1.24", + "scipy>=1.10", + "pandas>=2.0", + "scorr @ git+https://github.com/robatobalzac/scorr.git" ], include_package_data=True, zip_safe=False, test_suite='tests', + extras_require={'dev': ['pytest>=8', 'tox>=4']} ) \ No newline at end of file diff --git a/tests/test_propagator.py b/tests/test_propagator.py index f1f807c..af54608 100644 --- a/tests/test_propagator.py +++ b/tests/test_propagator.py @@ -107,7 +107,7 @@ def test_calibrate_hdim2(self): lpars = { k: np.array(v) if hasattr(v, '__len__') else v - for k,v in json.load(f).iteritems() + for k,v in json.load(f).items() } kn_est, kc_est = prop.calibrate_hdim2( lpars['Cnnc'], diff --git a/tests/test_tim2.py b/tests/test_tim2.py new file mode 100644 index 0000000..e69de29 diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..e2d98cb --- /dev/null +++ b/tox.ini @@ -0,0 +1,6 @@ +[tox] +envlist = py311 + +[testenv] +deps = pytest +commands = pytest -q \ No newline at end of file From 2d87fe63c89419228222a898f9bbb86513b0d322 Mon Sep 17 00:00:00 2001 From: robatobalzac <152008496+robatobalzac@users.noreply.github.com> Date: Sat, 2 Aug 2025 10:14:38 -0700 Subject: [PATCH 2/9] Amending tox test conditions --- tox.ini | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index e2d98cb..4bc297d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,8 @@ [tox] -envlist = py311 +envlist = py311, py310, py39, py38 [testenv] deps = pytest +usedevelop = true # install package in editable mode instead of sdist +changedir = {toxinidir} # run tests in the repo root commands = pytest -q \ No newline at end of file From b1a67e2bb8187cd73021d3e31323214b5b5f5672 Mon Sep 17 00:00:00 2001 From: robatobalzac <152008496+robatobalzac@users.noreply.github.com> Date: Sat, 2 Aug 2025 10:25:28 -0700 Subject: [PATCH 3/9] adding ci.yaml --- .github/workflows/ci.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/ci.yaml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..9b7be4d --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,19 @@ +name: CI + +on: + push: + branches: [ py3-port ] + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.9", "3.10", "3.11"] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: {python-version: ${{ matrix.python-version }}} + - run: pip install -e ".[dev]" + - run: pytest -q \ No newline at end of file From 782383d420804a3473043a742eeb45a7fea9c7fd Mon Sep 17 00:00:00 2001 From: robatobalzac <152008496+robatobalzac@users.noreply.github.com> Date: Sat, 2 Aug 2025 10:35:53 -0700 Subject: [PATCH 4/9] added full docstrings --- priceprop/batch.py | 74 ++++++++++++- priceprop/propagator.py | 240 ++++++++++++++++++++++++---------------- 2 files changed, 213 insertions(+), 101 deletions(-) diff --git a/priceprop/batch.py b/priceprop/batch.py index a3845eb..6a1ba0e 100644 --- a/priceprop/batch.py +++ b/priceprop/batch.py @@ -12,7 +12,15 @@ def complete_data_columns( tt, split_dates=True ): - """Fill in columns necessary for models""" + """ + Fill in columns necessary for models + + Args: + tt: pandas.DataFrame + The trades DataFrame + split_dates: bool + Whether to split trades into two samples based on date + """ if not 'sc' in tt: tt['sc'] = tt['sign'] * tt['change'] @@ -31,7 +39,18 @@ def complete_data_columns( def get_trade_split(tt, split_by): - "Get dict of sample key-mask pairs for splitting trades into groups." + """ + Get dict of sample key-mask pairs for splitting trades into groups. + + Args: + tt: pandas.DataFrame + The trades DataFrame + split_by: str + The column to split trades by + Returns: + dict + A dictionary with sample keys and mask values + """ if split_by: samples = tt[split_by].unique() masks = {m: (tt[split_by] == m) for m in samples} @@ -41,10 +60,19 @@ def get_trade_split(tt, split_by): return masks def shift(x, n, val=np.nan): - """Shift array, pad with fixed value. + """ + Shift array, pad with fixed value. Example: Convert r_1 = p(t+1) - p(t) to causal return p(t) - p(t-1) without losing timesteps with pad(r_1, 1). + Args: + x: array-like + The array to shift + n: int + The number of steps to shift + val: float + The value to pad with + Returns: """ if n == 0: @@ -68,9 +96,23 @@ def calibrate_models( group=False, models = ['cim','tim1','tim2','hdim2','hdim2_x2'] ): - """Return dict with correlations, kernels, and responses. + """ + Return dict with correlations, kernels, and responses. Calculate sign & price change correlations, response functions, and fitted propagator kernels for trades in DataFrame. + + Args: + tt: pandas.DataFrame + The trades DataFrame + nfft: str + The nfft to calculate the response of + group: bool + Whether to group trades by date + models: list + The models to calibrate + Returns: + dict + A dictionary with the results """ # store results @@ -245,11 +287,33 @@ def calc_models( models = ['cim','tim1','tim2','hdim2','hdim2_x2'], smooth_kernel = True ): - """Add propagator(-like) models to trades. + """ + Add propagator(-like) models to trades. Pass a dict: calibration is added to dict, not returned. Pass trades DataFrame directly: calibration is returned as DataFrame(s) + Args: + dbc: dict + A dictionary with the trades DataFrame + nfft: str + The nfft to calculate the response of + group: bool + Whether to group trades by date + calibrate: bool + Whether to calibrate the models + split_by: str + The column to split trades by + rshift: int + The number of steps to shift the return + models: list + The models to run + smooth_kernel: bool + Whether to smooth the kernel + Returns: + dict + A dictionary with the results + See also: calibrate_models, aggregate_impact.add_models_to_trades """ # normalise inputs (dict / df) diff --git a/priceprop/propagator.py b/priceprop/propagator.py index 5a0cb43..dfe0464 100644 --- a/priceprop/propagator.py +++ b/priceprop/propagator.py @@ -11,10 +11,14 @@ def integrate(x): """ Return lag 1 sum, i.e. price from return, or an integrated kernel. - @param x: array-like - The signal to integrate - @return: array-like - The integrated signal + + Args: + x: array-like + The signal to integrate + Returns: + array-like + The integrated signal + """ return np.concatenate([[0], np.cumsum(x[:-1])]) @@ -22,12 +26,17 @@ def integrate(x): def smooth_tail_rbf(k, l0=3, tau=5, smooth=1, epsilon=1): """ Smooth tail of array k with radial basis functions - @param k: array-like - The array to smooth - @param l0: int - The lag at which to start the interpolation - @param tau: int - The time constant for the exponential decay + + Args: + k: array-like + The array to smooth + l0: int + The lag at which to start the interpolation + tau: int + The time constant for the exponential decay + Returns: + array-like + The smoothed signal """ # interpolate in log-lags l = np.log(np.arange(l0,len(k))) @@ -47,13 +56,17 @@ def smooth_tail_rbf(k, l0=3, tau=5, smooth=1, epsilon=1): def propagate(s, G, sfunc=np.sign): """Simulate propagator model from signs and one kernel. Equivalent to tim1, one of the kernels in tim2 or hdim2. - @param s: array-like - The signs to propagate - @param G: array-like - The kernel to propagate with - @param sfunc: function - The function to apply to the signs. Default: np.sign - @return: array-like + + Args: + s: array-like + The signs to propagate + G: array-like + The kernel to propagate with + sfunc: function + The function to apply to the signs. Default: np.sign + Returns: + array-like + The propagated signal """ steps = len(s) s = sfunc(s[:len(s)]) @@ -66,13 +79,17 @@ def propagate(s, G, sfunc=np.sign): def _return_response(ret, x, maxlag): """ Helper for response and response_grouped_df. - @param ret: str - 'l' for lags, 's' for differential response, 'r' for return response - @param x: array-like - The signal to calculate the response of - @param maxlag: int - The maximum lag to calculate the response of - @return: tuple + + Args: + ret: str + 'l' for lags, 's' for differential response, 'r' for return response + x: array-like + The signal to calculate the response of + maxlag: int + The maximum lag to calculate the response of + Returns: + tuple + The lag, differential response, and response """ maxlag = int(maxlag) # return what? @@ -106,19 +123,22 @@ def response(r, s, maxlag=10**4, ret='lsr', subtract_mean=False): Note that this commonly used price response is a simple cross correlation and NOT equivalent to the linear response in systems analysis. - @param r: array-like - Returns - @param s: array-like - Order signs - @param maxlag: int - Longest lag to calculate - @param ret: str - can include 'l' to return lags, 'r' to return response, and - 's' to return differential response (in specified order). - @param subtract_mean: bool - Subtract means first. Default: False (signal means already zero) - @return: tuple - The lag, differential response, and response + + Args: + r: array-like + Returns + s: array-like + Order signs + maxlag: int + Longest lag to calculate + ret: str + can include 'l' to return lags, 'r' to return response, and + 's' to return differential response (in specified order). + subtract_mean: bool + Subtract means first. Default: False (signal means already zero) + Returns: + tuple + The lag, differential response, and response """ maxlag = min(maxlag, len(r) - 2) s = s[:len(r)] @@ -135,19 +155,20 @@ def response_grouped_df( Note that this commonly used price response is a simple cross correlation and NOT equivalent to the linear response in systems analysis. - Parameters - ========== - - df: pandas.DataFrame - Dataframe containing order signs and returns - cols: tuple - The columns of interest - nfft: - Length of the fft segments - ret: str - What to return ('l': lags, 'r': response, 's': incremental response). - subtract_mean: bool - Subtract means first. Default: False (signal means already zero) + Args: + df: pandas.DataFrame + The dataframe to calculate the response of + cols: list + The columns to calculate the response of + nfft: str + The nfft to calculate the response of + ret: str + What to return ('l': lags, 'r': response, 's': incremental response). + subtract_mean: bool + Subtract means first. Default: False (signal means already zero) + Returns: + tuple + The lag, differential response, and response See also response, spectral.xcorr_grouped_df for more explanations """ @@ -172,25 +193,51 @@ def response_grouped_df( # ===================================================================== def beta_from_gamma(gamma): - """Return exponent beta for the (integrated) propagator decay + """ + Return exponent beta for the (integrated) propagator decay G(lag) = lag**-beta that compensates a sign-autocorrelation C(lag) = lag**-gamma. - @param gamma: float - The exponent of the sign-autocorrelation - @return: float - The exponent beta + + Args: + gamma: float + The exponent of the sign-autocorrelation + Returns: + float + The exponent beta """ return (1-gamma)/2. def G_pow(steps, beta): - """Return power-law Propagator kernel G(l). l=0...steps""" + """ + Return power-law Propagator kernel G(l). l=0...steps + + Args: + steps: int + The number of steps + beta: float + The exponent of the propagator decay + Returns: + array-like + The propagator kernel + """ G = np.arange(1,steps)**-beta#+1 G = np.r_[0, G] return G def k_pow(steps, beta): - """Return increment of power-law propagator kernel g. l=0...steps""" + """ + Return increment of power-law propagator kernel g. l=0...steps + + Args: + steps: int + The number of steps + beta: float + The exponent of the propagator decay + Returns: + array-like + The propagator kernel + """ return np.diff(G_pow(steps, beta)) # TIM1 specific @@ -199,10 +246,8 @@ def k_pow(steps, beta): def calibrate_tim1(c, Sl, maxlag=10**4): """Return empirical estimate TIM1 kernel - Parameters: - =========== - - c: array-like + Args: + c: array-like Cross-correlation (covariance). Sl: array-like Price-response. If the response is differential, so is the returned @@ -223,10 +268,8 @@ def tim1(s, G, sfunc=np.sign): and the 1 step ahead return p(t+1)-p(t) for the differential kernel g, where G == numpy.cumsum(g). - Parameters: - =========== - - s: array-like + Args: + s: array-like Order signs G: array-like Kernel @@ -245,24 +288,25 @@ def calibrate_tim2( Return empirical estimate for both kernels of the TIM2. (Transient Impact Model with two propagators) - Parameters: - =========== - - nncorr: array-like - Cross-covariance between non-price-changing (n-) orders. - cccorr: array-like - Cross-covariance between price-changing (c-) orders. - cncorr: array-like - Cross-covariance between c- and n-orders - nccorr: array-like - Cross-covariance between n- and c-orders. - Sln: array-like - (incremental) price response for n-orders - Slc: array-like - (incremental) price response for c-orders - maxlag: int - Length of the kernels. - + Args: + nncorr: array-like + Cross-correlation matrix for non-price-changing trades + cccorr: array-like + Cross-correlation matrix for price-changing trades + cncorr: array-like + Cross-correlation matrix for non-price-changing trades + nccorr: array-like + Cross-correlation matrix for non-price-changing trades + Sln: array-like + (incremental) price response for non-price-changing trades + Slc: array-like + (incremental) price response for price-changing trades + maxlag: int + Length of the kernels. + Returns: + tuple + The non-price-changing and price-changing kernels + See also: calibrate_tim1, calibrate_hdim2 """ # incremental response @@ -290,10 +334,9 @@ def tim2(s, c, G_n, G_c, sfunc=np.sign): Returns prices when integrated kernels are passed as arguments or returns for differential kernels. - Parameters: - =========== - s: array - Trade signs + Args: + s: array + Trade signs c: array Trade labels (1 = change; 0 = no change) G_n: array @@ -302,7 +345,9 @@ def tim2(s, c, G_n, G_c, sfunc=np.sign): Kernel for price-changing trades sfunc: function [optional] Function to apply to signs. Default: np.sign. - + Returns: + array-like + The propagated signal See also: calibrate_tim2, tim1, hdim2. """ assert c.dtype == bool, "c must be a boolean indicator!" @@ -325,8 +370,7 @@ def calibrate_hdim2( orders. The argument names corresponds to the argument order in spectral.x3corr. - Parameters: - =========== + Args: Cnnc: 2d-array-like Cross-covariance matrix for n-, n-, c- orders. Cccc: 2d-array-like @@ -339,7 +383,9 @@ def calibrate_hdim2( (incremental) lagged price response for c-orders maxlag: int Length of the kernels. - + Returns: + tuple + The non-price-changing and price-changing kernels See also: hdim2, """ maxlag = maxlag or min(len(Cccc), len(Sln))/2 @@ -371,11 +417,11 @@ def calibrate_hdim2( return gn, gc def hdim2(s, c, k_n, k_c, sfunc=np.sign): - """Simulate History Dependent Impact Model 2, return return. + """ + Simulate History Dependent Impact Model 2, return return. - Parameters: - =========== - s: array + Args: + s: array Trade signs c: array Trade labels (1 = change; 0 = no change) @@ -385,7 +431,9 @@ def hdim2(s, c, k_n, k_c, sfunc=np.sign): Differential kernel for price-changing trades sfunc: function [optional] Function to apply to signs. Default: np.sign. - + Returns: + array-like + The propagated signal See also: calibrate_hdim2, tim2, tim1. """ assert c.dtype == bool, "c must be a boolean indicator!" From 8447c22465a17b601bad2982a6e115f9b565dc57 Mon Sep 17 00:00:00 2001 From: robatobalzac <152008496+robatobalzac@users.noreply.github.com> Date: Sat, 2 Aug 2025 12:25:53 -0700 Subject: [PATCH 5/9] correting ci.yaml syntax error --- .github/workflows/ci.yaml | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9b7be4d..0dd6ddc 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -2,7 +2,7 @@ name: CI on: push: - branches: [ py3-port ] + branches: [py3-port] # or - py3-port pull_request: jobs: @@ -11,9 +11,19 @@ jobs: strategy: matrix: python-version: ["3.9", "3.10", "3.11"] + steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: {python-version: ${{ matrix.python-version }}} - - run: pip install -e ".[dev]" - - run: pytest -q \ No newline at end of file + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install test deps + run: | + python -m pip install --upgrade pip + pip install -e '.[dev]' # pulls pytest + tox (from setup.py extras) + + - name: Run pytest + run: python -m pytest -q From 2dd9dcfb87a04d4691be2c460b69cc2b42a1ae5e Mon Sep 17 00:00:00 2001 From: robatobalzac <152008496+robatobalzac@users.noreply.github.com> Date: Sat, 2 Aug 2025 15:11:47 -0700 Subject: [PATCH 6/9] py3-port: make batch.py import relative, drop Py2 refs, bump to v1.0.3 --- README.rst | 2 +- priceprop/__init__.py | 3 +++ priceprop/batch.py | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index ec8b06f..33d3ba4 100644 --- a/README.rst +++ b/README.rst @@ -51,7 +51,7 @@ Installation Dependencies (automatically installed) -------------------------------------- - - Python 2.7 + - Python 3.8+ - NumPy - SciPy - Pandas diff --git a/priceprop/__init__.py b/priceprop/__init__.py index 439814a..d12eabf 100644 --- a/priceprop/__init__.py +++ b/priceprop/__init__.py @@ -1,4 +1,7 @@ from .propagator import * +__version__ = "1.0.3" + + def __reload_submodules__(): reload(propagator) \ No newline at end of file diff --git a/priceprop/batch.py b/priceprop/batch.py index 6a1ba0e..58e2b1f 100644 --- a/priceprop/batch.py +++ b/priceprop/batch.py @@ -3,7 +3,7 @@ import numpy as np import matplotlib.pyplot as plt import scorr -import propagator as prop +from . import propagator as prop # Helpers # ============================================================================ From a2e677f215b1b79bf95626a6ffb363fc6feec3af Mon Sep 17 00:00:00 2001 From: robatobalzac <152008496+robatobalzac@users.noreply.github.com> Date: Sat, 2 Aug 2025 15:30:14 -0700 Subject: [PATCH 7/9] batch: restore calibrate_tim2_day convenience wrapper --- priceprop/batch.py | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/priceprop/batch.py b/priceprop/batch.py index 58e2b1f..b674079 100644 --- a/priceprop/batch.py +++ b/priceprop/batch.py @@ -87,6 +87,45 @@ def shift(x, n, val=np.nan): res[:n] = x[n:] return res + +def calibrate_tim2_day(r, eps, maxlag=180, norm='corr'): + """ + High-level shortcut: given raw return series ``r`` and order-flow + series ``eps`` (same length), compute sparse PC/NPC streams, the six + full-lag correlations, and call :pyfunc:`propagator.calibrate_tim2`. + + Args: + r: array-like + The return series + eps: array-like + The order-flow series + maxlag: int + The maximum lag to calculate the response of + norm: str + The normalization to use + Returns: + tuple + A tuple with the results + """ + import numpy as np, scorr + # PC/NPC masks (price-changing = mid-price move with matching sign) + mask_pc = (r != 0) & (np.sign(r) == np.sign(eps)) + mask_npc = ~mask_pc + eps_pc_full = np.where(mask_pc, eps, 0.0) + eps_npc_full = np.where(mask_npc, eps, 0.0) + + nncorr = scorr.acorr(eps_npc_full, norm=norm) + cccorr = scorr.acorr(eps_pc_full, norm=norm) + cncorr = scorr.xcorr(eps_pc_full, eps_npc_full, norm=norm) + ncncorr = scorr.xcorr(eps_npc_full, eps_pc_full, norm=norm) + Sln = scorr.xcorr(r, eps_pc_full, norm=norm) + Slc = scorr.xcorr(r, eps_npc_full, norm=norm) + + return propagator.calibrate_tim2( + nncorr, cccorr, cncorr, ncncorr, Sln, Slc, maxlag=maxlag + ) + + # Analyse Trades # ============================================================================ From 45ac204326f1d843024387d40116ebb2fea6d5b2 Mon Sep 17 00:00:00 2001 From: robatobalzac <152008496+robatobalzac@users.noreply.github.com> Date: Sat, 2 Aug 2025 15:39:36 -0700 Subject: [PATCH 8/9] batch: split concatenated kernel so helper returns (G_pc, G_npc, meta) --- priceprop/batch.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/priceprop/batch.py b/priceprop/batch.py index b674079..5950816 100644 --- a/priceprop/batch.py +++ b/priceprop/batch.py @@ -121,9 +121,12 @@ def calibrate_tim2_day(r, eps, maxlag=180, norm='corr'): Sln = scorr.xcorr(r, eps_pc_full, norm=norm) Slc = scorr.xcorr(r, eps_npc_full, norm=norm) - return propagator.calibrate_tim2( + g, meta = prop.calibrate_tim2( nncorr, cccorr, cncorr, ncncorr, Sln, Slc, maxlag=maxlag ) + G_pc = g[:maxlag] + G_npc = g[maxlag:] + return G_pc, G_npc, meta # Analyse Trades From 1471c36e819ceadf06a64cf921b185c74247e0e8 Mon Sep 17 00:00:00 2001 From: robatobalzac <152008496+robatobalzac@users.noreply.github.com> Date: Sat, 2 Aug 2025 15:42:02 -0700 Subject: [PATCH 9/9] batch: changelog update --- CHANGELOG.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 89262ba..7effdac 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,9 @@ Changelog ========= +:Version: 1.0.3 of 2025-08-02 +Support for Python 3.8+ +Added calibrate_tim2_day function to batch.py :Version: 1.0.2 of 2017-09-29