This guide explains how to add and use the OHLCV library as a dependency in your Zig project.
From your project directory, run:
# Using latest main branch
zig fetch --save https://github.com/Mario-SO/ohlcv/archive/refs/heads/main.tar.gz
# Or using a specific release (when available)
zig fetch --save https://github.com/Mario-SO/ohlcv/archive/refs/tags/v1.0.0.tar.gz
# Or using git protocol
zig fetch --save git+https://github.com/Mario-SO/ohlcv#mainThis will:
- Download the library
- Save it to your local zig cache
- Update your
build.zig.zonwith the dependency
Add the dependency to your build.zig:
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
// Add the OHLCV dependency
const ohlcv_dep = b.dependency("ohlcv", .{
.target = target,
.optimize = optimize,
});
// Create your executable
const exe = b.addExecutable(.{
.name = "my-trading-app",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
// Import the OHLCV module
exe.root_module.addImport("ohlcv", ohlcv_dep.module("ohlcv"));
// Install the executable
b.installArtifact(exe);
}const std = @import("std");
const ohlcv = @import("ohlcv");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Fetch preset data
var series = try ohlcv.fetchPreset(.btc_usd, allocator);
defer series.deinit();
std.debug.print("Loaded {d} rows\n", .{series.len()});
// Calculate indicators
const sma = ohlcv.SmaIndicator{ .u32_period = 20 };
var result = try sma.calculate(series, allocator);
defer result.deinit();
// Use the results
for (result.arr_values, result.arr_timestamps) |value, timestamp| {
std.debug.print("{d}: {d:.2}\n", .{ timestamp, value });
}
}.{
.name = "my-trading-app",
.version = "0.0.1",
.dependencies = .{
.ohlcv = .{
.url = "https://github.com/Mario-SO/ohlcv/archive/refs/heads/main.tar.gz",
.hash = "1220...", // Will be added by zig fetch
},
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}const std = @import("std");
const ohlcv = @import("ohlcv");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Example 1: Load and analyze Bitcoin data
try analyzeBitcoin(allocator);
// Example 2: Parse custom CSV data
try parseCustomData(allocator);
// Example 3: Calculate multiple indicators
try calculateIndicators(allocator);
}
fn analyzeBitcoin(allocator: std.mem.Allocator) !void {
// Fetch Bitcoin data
var series = try ohlcv.fetchPreset(.btc_usd, allocator);
defer series.deinit();
// Filter by date range (2024 data)
const start = 1704067200; // 2024-01-01
const end = 1735689599; // 2024-12-31
var filtered = try series.sliceByTime(start, end);
defer filtered.deinit();
// Calculate RSI
const rsi = ohlcv.RsiIndicator{ .u32_period = 14 };
var rsi_result = try rsi.calculate(filtered, allocator);
defer rsi_result.deinit();
std.debug.print("Bitcoin RSI: {d:.2}\n", .{
rsi_result.arr_values[rsi_result.len() - 1]
});
}
fn parseCustomData(allocator: std.mem.Allocator) !void {
const csv_data =
\\Date,Open,High,Low,Close,Volume
\\2024-01-01,100.0,110.0,95.0,105.0,1000000
\\2024-01-02,105.0,115.0,100.0,112.0,1200000
;
// Create memory data source
var source = try ohlcv.MemoryDataSource.init(allocator, csv_data, false);
defer source.dataSource().deinit();
// Fetch and parse
const data = try source.dataSource().fetch(allocator);
defer allocator.free(data);
const parser = ohlcv.CsvParser{ .allocator = allocator };
var series = try parser.parse(data);
defer series.deinit();
std.debug.print("Parsed {d} rows\n", .{series.len()});
}
fn calculateIndicators(allocator: std.mem.Allocator) !void {
// Load S&P 500 data
var series = try ohlcv.fetchPreset(.sp500, allocator);
defer series.deinit();
// Calculate multiple indicators
const indicators = .{
ohlcv.SmaIndicator{ .u32_period = 50 },
ohlcv.EmaIndicator{ .u32_period = 20 },
ohlcv.RsiIndicator{ .u32_period = 14 },
};
inline for (indicators) |indicator| {
var result = try indicator.calculate(series, allocator);
defer result.deinit();
const last_value = result.arr_values[result.len() - 1];
std.debug.print("{s}: {d:.2}\n", .{
@typeName(@TypeOf(indicator)),
last_value,
});
}
}const std = @import("std");
const ohlcv = @import("ohlcv");
fn processLargeDataset(allocator: std.mem.Allocator) !void {
var parser = ohlcv.StreamingCsvParser.init(allocator);
defer parser.deinit();
const file = try std.fs.cwd().openFile("huge_dataset.csv", .{});
defer file.close();
while (try parser.parseChunk(file.reader())) |chunk| {
defer chunk.deinit();
for (chunk.rows) |row| {
// Process each row without loading entire file
if (row.f64_close > 1000.0) {
std.debug.print("High value: {d}\n", .{row.f64_close});
}
}
}
}fn highPerformanceCalculations(allocator: std.mem.Allocator) !void {
// Create memory pool for efficient allocations
var pool = try ohlcv.MemoryPool.init(allocator, 1024 * 1024); // 1MB
defer pool.deinit();
var arena = ohlcv.IndicatorArena.init(&pool);
var series = try ohlcv.fetchPreset(.btc_usd, allocator);
defer series.deinit();
// Calculate multiple indicators without individual allocations
const sma_result = try sma.calculateWithArena(series, &arena);
const ema_result = try ema.calculateWithArena(series, &arena);
const rsi_result = try rsi.calculateWithArena(series, &arena);
// All results freed when arena is destroyed
}// From HTTP URL
var http_source = try ohlcv.HttpDataSource.init(
allocator,
"https://example.com/data.csv"
);
defer http_source.dataSource().deinit();
// From local file
var file_source = try ohlcv.FileDataSource.init(
allocator,
"/path/to/data.csv"
);
defer file_source.dataSource().deinit();
// Use the data source
const data = try file_source.dataSource().fetch(allocator);
defer allocator.free(data);The library provides 33 technical indicators:
SmaIndicator- Simple Moving AverageEmaIndicator- Exponential Moving AverageWmaIndicator- Weighted Moving AverageAdxIndicator- Average Directional IndexDmiIndicator- Directional Movement IndexParabolicSarIndicator- Parabolic SAR
RsiIndicator- Relative Strength IndexMacdIndicator- MACD with signal and histogramStochasticIndicator- Stochastic OscillatorStochasticRsiIndicator- Stochastic RSIMomentumIndicator- MomentumRocIndicator- Rate of ChangeWilliamsRIndicator- Williams %RTrixIndicator- TRIXUltimateOscillatorIndicator- Ultimate Oscillator
AtrIndicator- Average True RangeBollingerBandsIndicator- Bollinger BandsKeltnerChannelsIndicator- Keltner ChannelsDonchianChannelsIndicator- Donchian ChannelsPriceChannelsIndicator- Price Channels
ObvIndicator- On-Balance VolumeMfiIndicator- Money Flow IndexCmfIndicator- Chaikin Money FlowForceIndexIndicator- Force IndexAccumulationDistributionIndicator- A/D LineVwapIndicator- VWAPCciIndicator- Commodity Channel Index
IchimokuCloudIndicator- Ichimoku CloudHeikinAshiIndicator- Heikin AshiPivotPointsIndicator- Pivot PointsElderRayIndicator- Elder RayAroonIndicator- AroonZigZagIndicator- Zig Zag
// Handle specific errors
series = ohlcv.fetchPreset(.btc_usd, allocator) catch |err| {
switch (err) {
error.HttpError => std.debug.print("Network error\n", .{}),
error.ParseError => std.debug.print("Invalid CSV format\n", .{}),
error.OutOfMemory => std.debug.print("Not enough memory\n", .{}),
else => return err,
}
return;
};- Use streaming parser for files >100MB
- Use memory pools when calculating many indicators
- Pre-filter data with
sliceByTime()before calculations - Reuse TimeSeries objects when possible
- Use
.ReleaseFastoptimization for production
Delete the hash field and run zig fetch again to get the correct hash.
Ensure the import name matches exactly: @import("ohlcv")
- Use streaming parser for large files
- Enable optimizations:
-Doptimize=ReleaseFast - Use memory pools for repeated calculations
- GitHub Issues: https://github.com/Mario-SO/ohlcv/issues
- Documentation: See README.md and lib/README.md
- Examples: See demo.zig for comprehensive examples