Skip to main content

Detect trend in timeseries.

Project description

python   MIT license  

pytrendseries is a Python library for detection of trends in time series like: stock prices, monthly sales, daily temperature of a city and so on. The input data must be a pandas.DataFrame format containing one column as observed data (in float or int format). Follow example below:

import pandas as pd
data = pd.read_csv("tests/resource/stock_prices.csv")
filtered_data = data[['period','close']].set_index("period")
filtered_data.columns = ['close_price']
filtered_data.index = pd.to_datetime(filtered_data.index)
filtered_data = filtered_data.sort_index()

Once some trend is identified, pytrendseries provides period on trend, drawdown, maximum drawdown (or drawup in case of uptrend) and a plot with all trends found.

Installation

Using pip

You can install using the pip package manager by running:

pip install pytrendseries

Alternatively, you could install the latest version directly from Github:

pip install https://github.com/rafa-rod/pytrendseries/archive/refs/heads/main.zip

Why pytrendseries is important?

Detection of trends could be used in machine learning algorithms such as classification problems like binary (1 = uptrend, 0 = otherwise) or non-binary classifications (1 = uptrend, -1 = downtrend, 0 = otherwise). Besides that, could be used in prediction problems.

Example

Inform:

  • type of trend you desire to investigate => downtrend or uptrend;
  • window or maximum period of a trend (example: 60 days considering 1 day as 1 period);
  • the minimum value that represents the number of consecutive days (or another period of time) to be considered a trend (default 5 periods).
import pytrendseries

trend = "downtrend"
window = 126 #6 months

trends_detected = pytrendseries.detecttrend(filtered_data, trend=trend, window=window)

The variable trends_detected is a dataframe that contains the initial and end date of each trend, the prices of each date, time span of each trend and the drawdown of each trend. Let's see the first five rows of this dataframe:

| from                | to                  |   price0 |   price1 |   indice_from |   indice_to |   time_span |   drawdown |
|:--------------------|:--------------------|---------:|---------:|--------------:|------------:|------------:|-----------:|
| 2000-01-03 00:00:00 | 2000-01-31 00:00:00 |  5.90057 |  5.12252 |             0 |          19 |          19 |  0.131859  |
| 2000-03-09 00:00:00 | 2000-04-24 00:00:00 |  6.42701 |  5.02208 |            45 |          76 |          31 |  0.218597  |
| 2000-05-02 00:00:00 | 2000-05-11 00:00:00 |  5.53684 |  5.29352 |            81 |          88 |           7 |  0.0439456 |
| 2000-05-16 00:00:00 | 2000-05-24 00:00:00 |  5.59962 |  5.24807 |            91 |          97 |           6 |  0.0627803 |
| 2000-06-08 00:00:00 | 2000-06-15 00:00:00 |  6.30359 |  6.1646  |           108 |         113 |           5 |  0.0220487 |

The easiest way to vizualize the trends detected, just call plot_trend function. All trends detected, with maximum window informed and the minimum informed by the limit value, will be displayed.

import pytrendseries
trend = "downtrend"
window = 30
year = 2020

trends_detected = pytrendseries.detecttrend(filtered_data, trend=trend, window=window)
pytrendseries.vizplot.plot_trend(filtered_data, trends_detected, trend, year)

To visualize all uptrends found, inform trend='uptrend':

import pytrendseries
window = 30
year = 2020

trends_detected = pytrendseries.detecttrend(filtered_data, trend='uptrend', window=window)
pytrendseries.vizplot.plot_trend(filtered_data, trends_detected, 'uptrend', year)

The maximum drawdown or maximum drawup can be obtained by sorting the dataframe by column drawdown. To do that, just code:

maxdd_in_window = trends_detected.sort_values("drawdown", ascending=False).iloc[0:1]

Another way is to call the function maxdrawdown. Note that this result will be differente once the maximum drawdown of the intire timeseries.

maxdd = pytrendseries.maxdrawdown(filtered_data)

You can code to vizualize as follows:

import matplotlib.pyplot as plt

plt.figure(figsize=(14,5))
plt.plot(filtered_data, alpha=0.6)
location_x = maxdd.values[:,0]
location_y = maxdd.values[:,1]
for i in range(location_x.shape[0]):
    plt.axvspan(location_x[i], location_y[i], alpha=0.3, color="red")
plt.grid(axis='x')
plt.show()

You may pass the parameter window to obtain the same result:

maxdd_in_window = pytrendseries.maxdrawdown(filtered_data, window=252)

To vizualize all drawdowns of timeseries, call the following function:

import pytrendseries
pytrendseries.plot_drawdowns(filtered_data, figsize = (10,4), color="gray", alpha=0.6, title="Drawdowns", axis="y")

Another option is:

import pytrendseries
pytrendseries.plot_evolution(filtered_data, figsize = (10,4), colors=["gray", "red"], alphas=[1,0.6])

To get time underwater (tuw), just type:

import pytrendseries
pytrendseries.tuw(filtered_data)

The output would be (showing the tail of the dataframe):

| inital_date|   peak    |   valley  |   drawdown  |   time underwater |   final_date |
|:-----------|----------:|----------:|------------:|------------------:|-------------:|
| 2007-12-28 |  44.66140 |  33.58194 |     0.24808 |                85 |   2008-05-06 |
| 2008-05-06 |  45.00000 |  44.85000 |     0.00333 |                4  |   2008-05-09 |
| 2008-05-13 |  46.95000 |  46.30000 |     0.01384 |                3  |   2008-05-15 |
| 2008-05-21 |  52.51000 |  4.20000  |     0.92002 |               NaN |          NaN |

The table shows time underwater as NaN, it means that the timeseries still on downtrend.

Another important usage of pytrendseries is to obtain the series of drawdowns or series of maximum drawdowns in order to calculate the drawdown at risk or maximum drawdown at risk.

import pytrendseries
import matplotlib.pyplot as plt
import seaborn as sns; sns.set_style("white")

trend = "downtrend"
window = 126 #6 months

trends_detected = pytrendseries.detecttrend(filtered_data, trend=trend, window=window)

plt.figure(figsize=(15,5))
sns.histplot(trends_detected["drawdown"]*100, kde=True, bins=30)
plt.ylabel("")
plt.box(False)
plt.annotate('Maximum Drawdown', xy=((trends_detected["drawdown"].max()-0.005)*100, 1),
             xycoords='data',
            xytext=(-105, 30), textcoords='offset points',color="red",
            weight='bold',
            arrowprops=dict(arrowstyle="->", color="r",
                            connectionstyle='arc3,rad=-0.1'))
plt.annotate('Quantile 97,5%', xy=((trends_detected["drawdown"].quantile(0.975)-0.005)*100, 0.2),
             xycoords='data',
            xytext=(-135, 30), textcoords='offset points',color="red",
            weight='bold',
            arrowprops=dict(arrowstyle="->", color="r",
                            connectionstyle='arc3,rad=-0.1'))
plt.xlabel("Drawdown (%)")
plt.ylabel("Density", rotation=0, labelpad=-30, loc="top")
plt.show()
import pytrendseries
import matplotlib.pyplot as plt
import seaborn as sns; sns.set_style("white")

maxdd_in_window = maxdrawdown(filtered_data, window=126)

plt.figure(figsize=(15,5))
sns.histplot(maxdd_in_window["MaxDD"]*100, kde=True, bins=30)
plt.ylabel("")
plt.box(False)
plt.annotate('Maximum Drawdown', xy=((maxdd_in_window["MaxDD"].max()-0.005)*100, 1),
             xycoords='data',
            xytext=(-105, 30), textcoords='offset points',color="red",
            weight='bold',
            arrowprops=dict(arrowstyle="->", color="r",
                            connectionstyle='arc3,rad=-0.1'))
plt.annotate('Quantile 95%', xy=((maxdd_in_window["MaxDD"].quantile(0.95)-0.005)*100, 0.2),
             xycoords='data',
            xytext=(-135, 50), textcoords='offset points',color="red",
            weight='bold',
            arrowprops=dict(arrowstyle="->", color="r",
                            connectionstyle='arc3,rad=-0.1'))
plt.xlabel("Maximum Drawdowns (%)")
plt.ylabel("Density", rotation=0, labelpad=-30, loc="top")
plt.show()

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pytrendseries-0.1.10.tar.gz (7.7 kB view details)

Uploaded Source

Built Distribution

pytrendseries-0.1.10-py3-none-any.whl (9.5 kB view details)

Uploaded Python 3

File details

Details for the file pytrendseries-0.1.10.tar.gz.

File metadata

  • Download URL: pytrendseries-0.1.10.tar.gz
  • Upload date:
  • Size: 7.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.8

File hashes

Hashes for pytrendseries-0.1.10.tar.gz
Algorithm Hash digest
SHA256 e9d9a090a7846df612859e4b87c87fda07c145a1510b53c643e574195fed9789
MD5 c15e8370ecf4ec7284189f2297cb175c
BLAKE2b-256 bfed295e34506c54b6d44262e05432341741ba25155a243696beed969494fa62

See more details on using hashes here.

File details

Details for the file pytrendseries-0.1.10-py3-none-any.whl.

File metadata

  • Download URL: pytrendseries-0.1.10-py3-none-any.whl
  • Upload date:
  • Size: 9.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.8

File hashes

Hashes for pytrendseries-0.1.10-py3-none-any.whl
Algorithm Hash digest
SHA256 f0d7f06fa605f49d255a683e737d4e91b477dfd0b8cb5bfcde6066e508b4fd77
MD5 cde98277750e3a0e14d546bef8a2d38d
BLAKE2b-256 fd91a7aab10ea24f0a51448d31c5ddc84fb15ebcbd99153cc11a3ea2489f7298

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page