diff --git a/src/data/shiller.zig b/src/data/shiller.zig index d35625c..f897695 100644 --- a/src/data/shiller.zig +++ b/src/data/shiller.zig @@ -97,7 +97,7 @@ fn parseShillerData() []const ShillerYear { // Fast reject: date is "YYYY.01," if (line[4] != '.' or line[5] != '0' or line[6] != '1') continue; - const year = parseU16(line[0..4]) orelse continue; + const year = std.fmt.parseInt(u16, line[0..4], 10) catch continue; // Parse fields for this January row var col_iter = CsvFieldIterator{ .data = line }; @@ -112,8 +112,8 @@ fn parseShillerData() []const ShillerYear { _ = col_iter.next(); // col 8 const tr_price_field = col_iter.next() orelse continue; - const cpi = parseF64(stripSpaces(cpi_field)) orelse continue; - const gs10 = parseF64(stripSpaces(gs10_field)) orelse continue; + const cpi = parseF64WithCommas(cpi_field) orelse continue; + const gs10 = parseF64WithCommas(gs10_field) orelse continue; const tr_price = parseF64WithCommas(tr_price_field) orelse continue; if (cpi == 0.0 or tr_price == 0.0 or gs10 == 0.0) continue; @@ -144,60 +144,6 @@ fn parseShillerData() []const ShillerYear { if (pos < csv_data.len) pos += 1; } - // Single pass: scan lines, parse January rows, compute returns on the fly. - while (pos < csv_data.len) { - const line_start = pos; - while (pos < csv_data.len and csv_data[pos] != '\n') pos += 1; - const line_end = if (pos > line_start and csv_data[pos - 1] == '\r') pos - 1 else pos; - if (pos < csv_data.len) pos += 1; - - const line = csv_data[line_start..line_end]; - if (line.len < 7) continue; - - // Fast reject: date is "YYYY.01," — check fixed offsets - if (line[4] != '.' or line[5] != '0' or line[6] != '1') continue; - - const year = parseU16(line[0..4]) orelse continue; - - // Parse fields for this January row - var col_iter = CsvFieldIterator{ .data = line }; - _ = col_iter.next(); // col 0: Date - _ = col_iter.next(); // col 1: P - _ = col_iter.next(); // col 2: D - _ = col_iter.next(); // col 3: E - const cpi_field = col_iter.next() orelse continue; - _ = col_iter.next(); // col 5 - const gs10_field = col_iter.next() orelse continue; - _ = col_iter.next(); // col 7 - _ = col_iter.next(); // col 8 - const tr_price_field = col_iter.next() orelse continue; - - const cpi = parseF64(stripSpaces(cpi_field)) orelse continue; - const gs10 = parseF64(stripSpaces(gs10_field)) orelse continue; - const tr_price = parseF64WithCommas(tr_price_field) orelse continue; - - if (cpi == 0.0 or tr_price == 0.0 or gs10 == 0.0) continue; - - // Compute return from previous January (if consecutive) - if (prev_year > 0 and year == prev_year + 1) { - const cpi_change = (cpi / prev_cpi) - 1.0; - const real_sp500 = (tr_price / prev_tr_price) - 1.0; - - results[result_count] = .{ - .year = prev_year, - .sp500_total_return = (1.0 + real_sp500) * (1.0 + cpi_change) - 1.0, - .bond_total_return = prev_gs10 / 100.0, - .cpi_inflation = cpi_change, - }; - result_count += 1; - } - - prev_year = year; - prev_tr_price = tr_price; - prev_gs10 = gs10; - prev_cpi = cpi; - } - if (result_count == 0) return &.{}; const final = blk: { @@ -256,63 +202,6 @@ const CsvFieldIterator = struct { } }; -fn indexOf(s: []const u8, ch: u8) ?usize { - for (s, 0..) |c, i| { - if (c == ch) return i; - } - return null; -} - -fn parseU16(s: []const u8) ?u16 { - if (s.len == 0) return null; - var result: u16 = 0; - for (s) |c| { - if (c < '0' or c > '9') return null; - result = result * 10 + @as(u16, c - '0'); - } - return result; -} - -fn parseF64(s: []const u8) ?f64 { - if (s.len == 0) return null; - - var negative = false; - var start: usize = 0; - if (s[0] == '-') { - negative = true; - start = 1; - } - - var integer_part: f64 = 0; - var i = start; - while (i < s.len and s[i] != '.') : (i += 1) { - if (s[i] < '0' or s[i] > '9') return null; - integer_part = integer_part * 10.0 + @as(f64, @floatFromInt(s[i] - '0')); - } - - var frac_part: f64 = 0; - if (i < s.len and s[i] == '.') { - i += 1; - var divisor: f64 = 10.0; - while (i < s.len) : (i += 1) { - if (s[i] < '0' or s[i] > '9') return null; - frac_part += @as(f64, @floatFromInt(s[i] - '0')) / divisor; - divisor *= 10.0; - } - } - - const result = integer_part + frac_part; - return if (negative) -result else result; -} - -fn stripSpaces(s: []const u8) []const u8 { - var start: usize = 0; - var end: usize = s.len; - while (start < end and s[start] == ' ') start += 1; - while (end > start and s[end - 1] == ' ') end -= 1; - return s[start..end]; -} - fn parseF64WithCommas(s: []const u8) ?f64 { if (s.len == 0) return null;