datainquiry/ta-zig
Zig package with time series finance indicators to process streaming data.
Documentation: https://datainquiry.github.io/ta-zig/
I'm just starting. At this moment I have implemented a few technical analysis indicators for streaming data:
Trend:
Volatility:
Momentum:
This implementation, based on circular lists, keeps just a window of values for an indicator, including the current one and a few past ones.
Input data is not stored. When new data is pushed, the indicator is updated and older values exceeding the memory size are forgotten.
For example, computing a moving average at each update, it doesn't include all values involved. Instead, it just takes the previous average to update it with the proportion of the arriving value, performing a minimal number of operations.
$$\text{MA}{t,p} = \text{MA}{t-1,p} + \frac{x_t - x_{t-p}}{p}$$
Where:
Therefore, this implementation avoids recomputing the indicator over all the input data every time it's updated. All parameters are defined at compile time. Finally, memory is only statically allocated. All these features make indicator processing highly CPU and memory efficient.
Example:
// Number of points to include in the moving average
const period = 3;
// How many results should be kept in memory
const memory_size = 5;
// Simple Moving Average
var ma = SMAvg(period, memory_size){};
// Pushing a few values
ma.update(1.0);
ma.update(2.0);
ma.update(3.0);
// At this point the moving average is 2.0
try std.testing.expectApproxEqAbs(2.0, ma.curr(), 1e-9);
// Updating the moving average with a new value
ma.update(4.0);
// Now the moving average is 3.0
try std.testing.expectApproxEqAbs(3.0, ma.curr(), 1e-9);
// Retrieving the moving average for t-1 (previous value)
// Past values are indexed by backward positive integers
try std.testing.expectApproxEqAbs(2.0, ma.get(1), 1e-9);
In your project directory, run the following command:
zig fetch --save "git+https://github.com/datainquiry/ta-zig#main"
Add the following sections to your build.zig
file:
...
const ta_zig = b.dependency("ta_zig", .{
.target = target,
.optimize = optimize,
});
...
exe.root_module.addImport("ta_zig", ta_zig.module("ta_zig"));
...
In your code, you can use the library like in this example:
const std = @import("std");
const ta = @import("ta_zig");
pub fn main() !void {
const period = 3;
const mem_size = 1;
var ma = ta.SMA(period, mem_size){};
const serie = [_]f64{112.15, 116.72, 119.21, 117.05, 119.01};
for (serie) |value| {
ma.update(value);
}
std.debug.print("Moving average: {}\n", .{ma.curr()});
}