{"id":37080808,"url":"https://github.com/agpenas/tstrends","last_synced_at":"2026-01-14T09:48:37.075Z","repository":{"id":278227128,"uuid":"893113384","full_name":"agpenas/tstrends","owner":"agpenas","description":"Advanced trend labelling for time series","archived":false,"fork":false,"pushed_at":"2025-10-16T21:12:23.000Z","size":2024,"stargazers_count":13,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-10-17T22:31:51.178Z","etag":null,"topics":["financial-analysis","forecasting","time-series","time-series-analysis","timeseries","trend-analysis","trend-detection","trend-following","trend-prediction"],"latest_commit_sha":null,"homepage":"https://tstrends.xyz","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/agpenas.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-11-23T15:13:23.000Z","updated_at":"2025-10-16T21:07:01.000Z","dependencies_parsed_at":"2025-02-18T17:37:24.289Z","dependency_job_id":"edf34198-ace4-46fd-8024-b0369393a459","html_url":"https://github.com/agpenas/tstrends","commit_stats":null,"previous_names":["agpenas/python-trend-labeller","agpenas/tstrends"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/agpenas/tstrends","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agpenas%2Ftstrends","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agpenas%2Ftstrends/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agpenas%2Ftstrends/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agpenas%2Ftstrends/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/agpenas","download_url":"https://codeload.github.com/agpenas/tstrends/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agpenas%2Ftstrends/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28416120,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T08:38:59.149Z","status":"ssl_error","status_checked_at":"2026-01-14T08:38:43.588Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["financial-analysis","forecasting","time-series","time-series-analysis","timeseries","trend-analysis","trend-detection","trend-following","trend-prediction"],"created_at":"2026-01-14T09:48:36.333Z","updated_at":"2026-01-14T09:48:37.061Z","avatar_url":"https://github.com/agpenas.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/agpenas/python-trend-labeller/main/images/example_labelling2.png\" width=\"400\" height=\"100\"/\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/agpenas/python-trend-labeller/main/images/tuned_labels.png\" width=\"400\" height=\"100\"/\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.python.org/downloads/\"\u003e\u003cimg src=\"https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-blue.svg\" alt=\"Python Version\"\u003e\u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/codecov/c/github/agpenas/python-trend-labeller\" alt=\"Codecov\"\u003e\n  \u003ca href=\"https://pepy.tech/project/tstrends\"\u003e\u003cimg src=\"https://static.pepy.tech/badge/tstrends\" alt=\"Downloads\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/agpenas/tstrends/commits/main\"\u003e\u003cimg src=\"https://img.shields.io/github/last-commit/agpenas/python-trend-labeller\" alt=\"Last Commit\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/agpenas/tstrends/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-BSD--2--Clause-green.svg\" alt=\"License\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://tstrends.xyz/\"\u003e\u003cimg src=\"https://readthedocs.org/projects/tstrends/badge/?version=latest\" alt=\"Docs\"\u003e\u003c/a\u003e\n\n\u003c/p\u003e\n\n# TStrends (Time Series Trends): Advanced trend detection and labelling with Python\n\n## Overview\n\nA robust Python package for automated trend labelling in time series data with a strong financial flavour, implementing SOTA trend labelling algorithms ([bibliography](https://github.com/agpenas/tstrends/tree/main?tab=readme-ov-file#bibliography)) with returns estimation and parameter bayesian optimization capabilities. Main features:\n- \u003cins\u003e**Two-state**\u003c/ins\u003e (upwards/downwards) and \u003cins\u003e**three-state**\u003c/ins\u003e (upwards/neutral/downwards) trend labelling algorithms.\n- Returns estimation with transaction costs and holding fees.\n- Bayesian parameter optimization to select the optimal labelling (powered by [bayesian-optimization](https://github.com/bayesian-optimization/BayesianOptimization)).\n- \u003cins\u003e**Label tuning**\u003c/ins\u003e to transform discrete labels into highly customisable continuous values expressing trend potential.\n\n\n## 📜 Table of Contents\n- [Features](#features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Core Components](#core-components)\n  - [A) Trend Labellers](#a-trend-labellers)\n  - [B) Returns Estimation](#b-returns-estimation)\n  - [C) Parameter Optimization](#c-parameter-optimization)\n  - [D) Label Tuning](#d-label-tuning-expressing-trend-potential)\n- [Roadmap](#roadmap)\n- [Contributing](#contributing)\n- [Bibliography](#bibliography)\n- [License](#license)\n\n\n\u003ca id=\"features\"\u003e\u003c/a\u003e\n## ✨ Features\n\n### Trend Labelling Approaches\n- **Continuous Trend Labelling (CTL)**:\n  - Binary CTL (Up/Down trends) - Based on [Wu et al.](https://github.com/agpenas/tstrends/tree/main?tab=readme-ov-file#bibliography)\n  - Ternary CTL (Up/Neutral/Down trends) - Inspired by [Dezhkam et al.](https://github.com/agpenas/tstrends/tree/main?tab=readme-ov-file#bibliography)\n- **Oracle Labelling**\n  - Binary Oracle (optimizes for maximum returns) - Based on [Kovačević et al.](https://github.com/agpenas/tstrends/tree/main?tab=readme-ov-file#bibliography)\n  - Ternary Oracle (includes neutral state optimization) - Extension of the binary oracle labeller to include a neutral state.\n\n### Returns Estimation\n- Simple returns calculation\n- Transaction costs consideration\n- Holding fees support\n- Position-specific fee structures\n\n### Parameter Optimization\n- Bayesian optimization for parameter tuning\n- Support for multiple time series optimization\n- Customizable acquisition functions\n- Empirically tested and customizable parameter bounds\n\n\n\u003ca id=\"installation\"\u003e\u003c/a\u003e\n## 🔧 Installation\n\n```bash\npip install tstrends\n```\n\n\u003ca id=\"quick-start\"\u003e\u003c/a\u003e\n## 🚀 Quick Start\n\n```python\nfrom tstrends.trend_labelling import BinaryCTL\nfrom tstrends.returns_estimation import SimpleReturnEstimator\nfrom tstrends.parameter_optimization import Optimizer\n\n# Sample price data\nprices = [100.0, 102.0, 105.0, 103.0, 98.0, 97.0, 99.0, 102.0, 104.0]\n\n# 1. Basic naïve CTL Labelling\nbinary_labeller = BinaryCTL(omega=0.02)\nbinary_labels = binary_labeller.get_labels(prices)\n\n# 2. Returns Estimation\nestimator = SimpleReturnEstimator()\nreturns = estimator.estimate_return(prices, binary_labels)\n\n# 3. Parameter Optimization\noptimizer = Optimizer(\n    returns_estimator=SimpleReturnEstimator,\n    initial_points=5,\n    nb_iter=100\n)\noptimal_params = optimizer.optimize(BinaryCTL, prices)\nprint(f\"Optimal parameters: {optimal_params['params']}\")\n\n# 4. Optimized Labelling\noptimal_labeller = BinaryCTL(\n    **optimal_params['params']\n)\noptimal_labels = optimal_labeller.get_labels(prices)\n```\n\n\u003ca id=\"core-components\"\u003e\u003c/a\u003e\n## 🔩 Core Components\n\n### A) Trend Labellers\n\nSee the notebook [labellers_catalogue.ipynb](https://github.com/agpenas/tstrends/blob/main/notebooks/labellers_catalogue.ipynb) for a detailed example of the trend labellers.\n\n#### 1. Labellers based on Continuous Trend Labelling (CTL)\n- **BinaryCTL**: Implements the [Wu et al.](https://github.com/agpenas/tstrends/tree/main?tab=readme-ov-file#bibliography) algorithm for binary trend labelling. When the market rises above a certain proportion parameter \u003cins\u003eomega\u003c/ins\u003e from the current lowest point or recedes from the current highest point to a certain proportion parameter \u003cins\u003eomega\u003c/ins\u003e, the two segments are labeled as rising and falling segments, respectively. \n  - Parameters:\n    - `omega`: Threshold for trend changes (float). Key to manage the sensitivity of the labeller.\\\n    **For instance, for a value of 0.001, 0.005, 0.01, 0.015, the labeller behaves as follows:**\n    \n    \u003cp align=\"center\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/agpenas/python-trend-labeller/main/images/binary_ctl_omega_effect.png\" alt=\"Omega effect on binary CTL\" width=\"800\"/\u003e\u003c/p\u003e\n\n  \n- **TernaryCTL**: Extends CTL with a neutral state. It introduces a window_size parameter to look for trend confirmation before resetting state to neutral, similar to the second loop in the [Dezhkam et al.](https://github.com/agpenas/tstrends/tree/main?tab=readme-ov-file#bibliography) algorithm.\n  - Parameters:\n    - `marginal_change_thres`: Threshold for significant time series movements as a percentage of the current value.\n    - `window_size`: Maximum window to look for trend confirmation before resetting state to neutral.\\\n    **For instance, for different combinations of `marginal_change_thres` and `window_size`, the labeller behaves as follows:**\n\n    \u003cp align=\"center\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/agpenas/python-trend-labeller/main/images/ternaryCTL_params_effect.png\" alt=\"Ternary CTL parameters effect\" width=\"800\"/\u003e\u003c/p\u003e\n\n#### 2. Labellers based on the Oracle Labeller\n- **OracleBinaryTrendLabeller**: Implements the [Kovačević et al.](https://github.com/agpenas/tstrends/tree/main?tab=readme-ov-file#bibliography) algorithm for binary trend labelling, optimizing labels for maximum returns given a transaction cost parameter. Algorithm complexity is optimized via dynamic programming.\n  - Parameters:\n    - `transaction_cost`: Cost coefficient for position changes.\\\n    **For instance, for different values of `transaction_cost`, the labeller behaves as follows:**\n\n    \u003cp align=\"center\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/agpenas/python-trend-labeller/main/images/oracle_binary_param_effect.png\" alt=\"Oracle binary transaction cost effect\" width=\"800\"/\u003e\u003c/p\u003e\n\n- **OracleTernaryTrendLabeller**: Extends the binary oracle labeller to include neutral state in optimization. It constrains the switch between upward et downwards trends to go through a neutral state. The reward for staying in a neutral state is managed via a `neutral_reward_factor` parameter.\n  - Parameters:\n    - `transaction_cost`: Cost coefficient for position changes\n    - `neutral_reward_factor`: Coefficient for the reward of staying in a neutral state.\\\n    **For instance, for different values of `neutral_reward_factor`, the labeller behaves as follows:**\n\n    \u003cp align=\"center\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/agpenas/python-trend-labeller/main/images/oracle_ternary_params_effect.png\" alt=\"Oracle ternary neutral reward factor effect\" width=\"800\"/\u003e\u003c/p\u003e\n\n### B) Returns Estimation\n\nThe package provides flexible returns estimation with transaction costs. It introduces:\n- **Returns estimation**, based on the price fluctuations correctly labelled vs incorrectly labelled.\n- **Percentage transaction costs**, based on the position changes. It pushes the labeller to identify long term trends.\n- **Constant holding fees**, based on the position duration. Useful for ternary labellers to reward the identification of neutral trends.\n\n```python\nfrom tstrends.returns_estimation import ReturnsEstimatorWithFees, FeesConfig\n\n# Configure fees\nfees_config = FeesConfig(\n    lp_transaction_fees=0.001,  # 0.1% fee for long positions\n    sp_transaction_fees=0.001,  # 0.1% fee for short positions\n    lp_holding_fees=0.0001,    # 0.0001 constant fee for long positions\n    sp_holding_fees=0.0001     # 0.0001 constant fee for short positions\n)\n\n# Create estimator with fees\nestimator = ReturnsEstimatorWithFees(fees_config)\n\n# Calculate returns with fees\nreturns = estimator.estimate_return(prices, labels)\n```\n\n### C) Parameter Optimization\n\nThe package uses Bayesian optimization to find optimal parameters, optimizing the returns for a given fees/no fees configuration.\nBy definition this is a bounded optimization problem, and some default bounds are provided for each labeller implementation:\n- `BinaryCTL`: `omega` is bounded between 0 and 0.01\n- `TernaryCTL`: `marginal_change_thres` is bounded between 0.000001 and 0.1, `window_size` is bounded between 1 and 5000\n- `OracleBinaryTrendLabeller`: `transaction_cost` is bounded between 0 and 0.01\n- `OracleTernaryTrendLabeller`: `transaction_cost` is bounded between 0 and 0.01, `neutral_reward_factor` is bounded between 0 and 0.1\n\n```python\nfrom tstrends.parameter_optimization import Optimizer\nfrom tstrends.returns_estimation import ReturnsEstimatorWithFees\nfrom tstrends.trend_labelling import OracleTernaryTrendLabeller\n\n# Create optimizer\noptimizer = Optimizer(\n    returns_estimator=ReturnsEstimatorWithFees,\n    initial_points=10,\n    nb_iter=1000,\n    # random_state=42\n)\n\n# Custom bounds (optional)\nbounds = {\n    'transaction_cost': (0.0, 0.01),\n    'neutral_reward_factor': (0.0, 0.1)\n}\n\n# Optimize parameters\nresult = optimizer.optimize(\n    labeller_class=OracleTernaryTrendLabeller,\n    time_series_list=prices,\n    bounds=bounds,\n    # acquisition_function=my_acquisition_function,\n    # verbose=2\n)\n\nprint(f\"Optimal parameters: {result['params']}\")\nprint(f\"Maximum return: {result['target']}\")\n```\n\n\u003e [!WARNING]\n\u003e The acquisition function is set to UpperConfidenceBound(kappa=2) by default. This is a good default choice that balances exploration and exploitation, but you may want to experiment with other values for kappa or other acquisition functions like bayes_opt.acquisition.ExpectedImprovement() or bayes_opt.acquisition.ProbabilityOfImprovement() for your specific use case.\n\n\u003e [!CAUTION]\n\u003e The default bounds are presetted for relatively constant time series and may not be optimal for all use cases. It is recommended to test the waters by testing the labels with some parameters at different orders of magnitude before optimizing. See [optimization example notebook](https://github.com/agpenas/tstrends/blob/main/notebooks/optimization_example.ipynb) for a detailed example of parameter optimization.\n\n### D) Label Tuning (expressing trend potential)\n\nThe label tuning module enhances binary and ternary trend labels by adding trend potential information to make them more useful for training prediction models. It transforms discrete labels (-1, 0, 1) into continuous values that express the potential of the trend at each point.\n\n#### 1. Remaining Value Tuner\n\nThe `RemainingValueTuner` transforms labels into continuous values that represent, for each time point, the difference between the current value and the maximum/minimum value reached by the end of the trend. The output values maintain the original label's sign but provide additional information about trend strength:\n\n- For uptrends (1): positive values indicating remaining upside potential\n- For downtrends (-1): negative values indicating remaining downside\n- For neutral trends (0): values close to zero\n\nThis approach is particularly valuable in financial applications where:\n- Correctly predicting a trend is most critical at its beginning\n- The impact of a prediction depends on the magnitude of the trend's total price change\n\nKey parameters of the `tune` method:\n- `enforce_monotonicity`: If True, labels in each interval will not reverse on uncaptured countertrends\n- `normalize_over_interval`: If True, the remaining value change will be normalized over each interval\n- `shift_periods`: Number of periods to shift the labels forward (if positive) or backward (if negative)\n- `smoother`: Optional smoother object to smooth the resulting tuned labels (see [Smoothing Options](#2-smoothing-options) below)\n\n```python\nfrom tstrends.label_tuning import RemainingValueTuner\nfrom tstrends.label_tuning.smoothing import LinearWeightedAverage\nfrom tstrends.trend_labelling import OracleTernaryTrendLabeller\n\n# Generate trend labels\nlabeller = OracleTernaryTrendLabeller(transaction_cost=0.006, neutral_reward_factor=0.03)\nlabels = labeller.get_labels(prices)\n\n# Create a smoother for enhancing the tuned labels (optional)\nsmoother = LinearWeightedAverage(window_size=5, direction=\"left\")\n\n# Tune the labels\ntuner = RemainingValueTuner()\ntuned_labels = tuner.tune(\n    time_series=prices,\n    labels=labels,\n    enforce_monotonicity=True,\n    normalize_over_interval=False,\n    smoother=smoother\n)\n```\n\n#### 2. Smoothing Options\n\nThe label tuning module provides smoothing classes to enhance the tuned label output:\n\n- `SimpleMovingAverage`: Equal-weight smoothing across the window\n- `LinearWeightedAverage`: Higher weights on more recent values (for left-directed smoothing) or central values (for centered smoothing)\n\nBoth smoothers support \"left\" direction (using only past data) or \"centered\" direction (using both past and future data).\n\nSee the [label tuner example notebook](https://github.com/agpenas/tstrends/blob/main/notebooks/label_tuner_example.ipynb) for a detailed example of label tuning.\n\n\u003ca id=\"roadmap\"\u003e\u003c/a\u003e\n## 🚧 Roadmap\n\n- [x] Transform labels into trend momentum / potential.\n- [ ] Calculate returns for one subset of labels only.\n- [ ] Always good to explore more labellers.\n\n\u003ca id=\"contributing\"\u003e\u003c/a\u003e\n## 🤝 Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.\n\nPlease make sure to update tests as appropriate and adhere to the existing coding style.\n\n\u003ca id=\"bibliography\"\u003e\u003c/a\u003e\n## 📚 Bibliography\n\nThe algorithms implemented in this package are based or inspired by the following academic papers:\n\n[1]: Wu, D., Wang, X., Su, J., Tang, B., \u0026 Wu, S. (2020). A Labeling Method for Financial Time Series Prediction Based on Trends. Entropy, 22(10), 1162. https://doi.org/10.3390/e22101162\n\n[2]: Dezhkam, A., Manzuri, M. T., Aghapour, A., Karimi, A., Rabiee, A., \u0026 Shalmani, S. M. (2023). A Bayesian-based classification framework for financial time series trend prediction. The Journal of supercomputing, 79(4), 4622–4659. https://doi.org/10.1007/s11227-022-04834-4\n\n[3]: Kovačević, Tomislav \u0026 Merćep, Andro \u0026 Begušić, Stjepan \u0026 Kostanjcar, Zvonko. (2023). Optimal Trend Labeling in Financial Time Series. IEEE Access. PP. 1-1. 10.1109/ACCESS.2023.3303283. \n\n\u003ca id=\"license\"\u003e\u003c/a\u003e\n## 📄 License\n\n[BSD-2-Clause](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagpenas%2Ftstrends","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagpenas%2Ftstrends","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagpenas%2Ftstrends/lists"}