Screamer

Screamer is a high-performance Python library for time series analysis, designed for speed, accuracy, and versatility in handling both NumPy arrays and streaming data.

pip install screamer
License Python Versions Tests Documentation PyPI

Easy to use, and powerfull

The 3-lines-of-code example below shows a stream processor that fits a trendline to a sliding window of the last 50 values. It then returns the slope of this fitted line. This slope is fed into a second stream processor, which outputs the sign of the slope, indicating the trend direction (upward or downward).

 from screamer import RollingPoly2, Sign

 slope = RollingPoly2(window_size=50, derivative_order=1)
 sign = Sign()

 result = sign(slope(data))

The plot below shows the input data (top, blue), the slope calculated over the previous 50 samples (middle, orange), and the sign of the slope (bottom, red).

Build for speed

Engineered in C++ with state-of-the-art numerical algorithms, Screamer delivers exceptional computational efficiency, consistently outperforming traditional libraries like NumPy and Pandas—often by factors of two or more, and in some cases by orders of magnitude.

speed comparison

Streaming- or batch- processing

Screamer seamlessly handles both batch and streaming data with the same code, producing identical results regardless of the data source. This design means that models tested offline on batch datasets will perform exactly the same when deployed with live streaming data, providing confidence in the consistency and reliability of your results.

Screamer’s streaming design ensures that all transformations are naturally free from look-ahead bias, guaranteeing accurate and reliable results

Mini Tutorial

Using screamer Functions

screamer functions share a common structure with function-specific settings.

  1. First, create a screamer function object by specifying the parameters for data transformation. For example, obj = RollingMean(30) creates an object to apply a 30-step moving average to the input data.

  2. Next, pass either streaming data (obj(datafeed)) or batch data (obj(dataset)) to this object. It will then process each data element as specified.

  3. screamer functions return data in the same format as the input. A NumPy array input returns a NumPy array of the same size, while a Python generator input returns a generator that yields transformed elements.

The screamer library’s unified interface supports both batch and streaming data, making it easy to transition from backtesting on historical datasets to live streaming deployment without modifying your code.


Example 1: Batch Processing with NumPy Arrays

This example shows the simplest use of screamer for batch processing a NumPy array with RollingMax. Given a one-dimensional array, RollingMax computes the rolling maximum over a specified window size, here set to 4. You can initialize the object once and apply it, or perform this in a single line with RollingMax(window_size=4)(data). This approach efficiently processes pre-loaded data with results returned as a new array.

# Sample data
data = np.random.normal(size=10)

print("Data:")
print(data)
Data:
[ 0.49671415 -0.1382643   0.64768854  1.52302986 -0.23415337 -0.23413696
  1.57921282  0.76743473 -0.46947439  0.54256004]

The following code creates a screamer object to computes the rolling maximum over a sliding window of size 4.

# Create a screamer object
obj = RollingMax(window_size=4)

# Transform the data
result = obj(data)

or alternatively in a one-liner

# Create a screamer object and transform the data
result = RollingMax(window_size=4)(data)

The result is a numpy array with the same size as the input data. This is in general the case with all screamer transformations.

print("Result:")
print(result)
Result:
[0.49671415 0.49671415 0.64768854 1.52302986 1.52302986 1.52302986
 1.57921282 1.57921282 1.57921282 1.57921282]

Example 2: Batch Processing Multi-Dimensional Arrays

For multi-dimensional arrays like matrices, screamer applies rolling operations column-by-column as if they were independent vectors.

Column processing

Using RollingMax of the following two column data will give the exact same result as applying it to each column separately.

This method is particularly useful for time series data with multiple features, where each column (representing a feature) is transformed independently but remains synchronized across rows.

1# Sample data
2data = np.random.normal(size=(10, 2))
3
4# Process the multi-dimensional array with RollingMax
5result = RollingMax(window_size=4)(data)
Result:
[[ 0.49671415 -0.1382643 ]
 [ 0.64768854  1.52302986]
 [ 0.64768854  1.52302986]
 [ 1.57921282  1.52302986]
 [ 1.57921282  1.52302986]
 [ 1.57921282  0.76743473]
 [ 1.57921282  0.76743473]
 [ 0.24196227  0.54256004]
 [ 0.24196227  0.31424733]
 [ 0.24196227  0.31424733]]

Example 3: Element-Wise Stream Processing

screamer functions support element-by-element processing for streaming applications. In this example, RollingMax calculates the rolling maximum for each new element as it arrives, using a window size of 4. Processing data sequentially enables real-time transformation without loading the entire dataset into memory, ideal for streaming use cases.

# Sample data
data = np.random.normal(size=10)

# Element-by-element processing
rolling_max = RollingMax(window_size=4)

for x in data:
   y = rolling_max(x)
   print(f'input: {x:.4f}, output: {y:.4f}')
input: 0.4967, output: 0.4967
input: -0.1383, output: 0.4967
input: 0.6477, output: 0.6477
input: 1.5230, output: 1.5230
input: -0.2342, output: 1.5230
input: -0.2341, output: 1.5230
input: 1.5792, output: 1.5792
input: 0.7674, output: 1.5792
input: -0.4695, output: 1.5792
input: 0.5426, output: 1.5792

Example 4: Using screamer Objects as Generators

screamer objects can act as generators for real-time data transformation. This example sets up RollingMax as a generator with a 4-element window, allowing it to compute the rolling maximum as elements arrive. This approach processes data as an iterable, suitable for large or streaming datasets where loading everything at once is impractical.

# Sample data
data = np.random.normal(size=10)
data_generator = iter(data)

# RollingMax as a generator
obj = RollingMax(window_size=4)
rolling_max_generator = obj(data_generator)

for x in rolling_max_generator:
   print(f'{x:.4f}')
0.4967
0.4967
0.6477
1.5230
1.5230
1.5230
1.5792
1.5792
1.5792
1.5792

Example 5: Composing Generators

screamer supports chaining multiple generators for complex transformations. Here, Diff first applies a 3-point difference operation, and RollingMax then computes the rolling maximum on the results with a window size of 4. This composition processes each data element sequentially, making it efficient for streaming applications where memory conservation is key.

# Sample data
data = np.random.normal(size=10)
data_generator = iter(data)

# Compose Diff and RollingMax as chained generators
diff = Diff(3)
rmax = RollingMax(window_size=4)
chained_generator = rmax(diff(data_generator))

for x in chained_generator:
   print(f'{x:.4f}')
nan
nan
nan
nan
nan
nan
1.0263
1.0016
1.0016
1.0016