remove unused polygon candle fetching

This commit is contained in:
Emil Lerch 2026-03-06 16:02:12 -08:00
parent 26b831631d
commit 497b1d3c2d
Signed by: lobo
GPG key ID: A7B62D657EF764F8

View file

@ -1,15 +1,13 @@
//! Polygon.io API provider -- primary source for dividend/split reference data
//! and secondary source for daily OHLCV bars.
//! Polygon.io API provider -- primary source for dividend/split reference data.
//! API docs: https://polygon.io/docs
//!
//! Free tier: 5 requests/min, unlimited daily, 2yr historical bars.
//! Free tier: 5 requests/min, unlimited daily.
//! Dividends and splits are available for all history.
const std = @import("std");
const http = @import("../net/http.zig");
const RateLimiter = @import("../net/RateLimiter.zig");
const Date = @import("../models/date.zig").Date;
const Candle = @import("../models/candle.zig").Candle;
const Dividend = @import("../models/dividend.zig").Dividend;
const DividendType = @import("../models/dividend.zig").DividendType;
const Split = @import("../models/split.zig").Split;
@ -135,39 +133,6 @@ pub const Polygon = struct {
return parseSplitsResponse(allocator, response.body);
}
/// Fetch daily OHLCV bars. Polygon free tier: 2 years max history.
/// Polygon endpoint: GET /v2/aggs/ticker/{ticker}/range/1/day/{from}/{to}
pub fn fetchCandles(
self: *Polygon,
allocator: std.mem.Allocator,
symbol: []const u8,
from: Date,
to: Date,
) ![]Candle {
self.rate_limiter.acquire();
var from_buf: [10]u8 = undefined;
var to_buf: [10]u8 = undefined;
const from_str = from.format(&from_buf);
const to_str = to.format(&to_buf);
// Build URL manually since the path contains the date range
const path = try std.fmt.allocPrint(
allocator,
"{s}/v2/aggs/ticker/{s}/range/1/day/{s}/{s}?adjusted=true&sort=asc&limit=5000",
.{ base_url, symbol, from_str, to_str },
);
defer allocator.free(path);
const authed = try appendApiKey(allocator, path, self.api_key);
defer allocator.free(authed);
var response = try self.client.get(authed);
defer response.deinit();
return parseCandlesResponse(allocator, response.body);
}
};
// -- JSON parsing --
@ -290,65 +255,6 @@ fn parseSplitsResponse(allocator: std.mem.Allocator, body: []const u8) ![]Split
return try splits.toOwnedSlice(allocator);
}
fn parseCandlesResponse(allocator: std.mem.Allocator, body: []const u8) ![]Candle {
const parsed = std.json.parseFromSlice(std.json.Value, allocator, body, .{}) catch
return error.ParseError;
defer parsed.deinit();
const root = parsed.value.object;
if (root.get("status")) |s| {
if (s == .string and std.mem.eql(u8, s.string, "ERROR"))
return error.RequestFailed;
}
const results = root.get("results") orelse {
return try allocator.alloc(Candle, 0);
};
const items = switch (results) {
.array => |a| a.items,
else => {
return try allocator.alloc(Candle, 0);
},
};
var candles: std.ArrayList(Candle) = .empty;
errdefer candles.deinit(allocator);
for (items) |item| {
const obj = switch (item) {
.object => |o| o,
else => continue,
};
// Polygon returns timestamp in milliseconds
const ts_ms = blk: {
const v = obj.get("t") orelse continue;
break :blk switch (v) {
.integer => |i| i,
.float => |f| @as(i64, @intFromFloat(f)),
else => continue,
};
};
const days: i32 = @intCast(@divFloor(ts_ms, 86400 * 1000));
const date = Date{ .days = days };
const close = parseJsonFloat(obj.get("c"));
try candles.append(allocator, .{
.date = date,
.open = parseJsonFloat(obj.get("o")),
.high = parseJsonFloat(obj.get("h")),
.low = parseJsonFloat(obj.get("l")),
.close = close,
.adj_close = close, // Polygon adjusted=true gives adjusted values
.volume = @intFromFloat(parseJsonFloat(obj.get("v"))),
});
}
return try candles.toOwnedSlice(allocator);
}
// -- Helpers --
fn appendApiKey(allocator: std.mem.Allocator, url: []const u8, api_key: []const u8) ![]const u8 {
@ -506,25 +412,3 @@ test "parseSplitsResponse empty results" {
try std.testing.expectEqual(@as(usize, 0), splits.len);
}
test "parseCandlesResponse basic" {
const body =
\\{
\\ "status": "OK",
\\ "results": [
\\ {"t": 1704067200000, "o": 185.5, "h": 186.2, "l": 184.1, "c": 185.8, "v": 52000000}
\\ ]
\\}
;
const allocator = std.testing.allocator;
const candles = try parseCandlesResponse(allocator, body);
defer allocator.free(candles);
try std.testing.expectEqual(@as(usize, 1), candles.len);
try std.testing.expectApproxEqAbs(@as(f64, 185.5), candles[0].open, 0.01);
try std.testing.expectApproxEqAbs(@as(f64, 186.2), candles[0].high, 0.01);
try std.testing.expectApproxEqAbs(@as(f64, 185.8), candles[0].close, 0.01);
try std.testing.expectApproxEqAbs(candles[0].close, candles[0].adj_close, 0.01);
try std.testing.expectEqual(@as(u64, 52000000), candles[0].volume);
}