Skip to content

Commit 32cfdd7

Browse files
committed
♻️ No recursive call in data_handler + overall cleanup
1 parent 4036a85 commit 32cfdd7

File tree

7 files changed

+28
-124
lines changed

7 files changed

+28
-124
lines changed

src/core/engine.zig

Whitespace-only changes.

src/core/types.zig

Whitespace-only changes.

src/engine/data_handler.zig

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -25,45 +25,43 @@ pub const DataHandler = struct {
2525
// Returns null if there are no more bars or if the next row fails to parse.
2626
// Uses an ArenaAllocator for temporary allocations during parsing.
2727
pub fn nextBar(self: *DataHandler) !?Bar {
28-
if (self.current_index >= self.all_rows.items.len) {
29-
return null; // No more data
30-
}
28+
while (self.current_index < self.all_rows.items.len) {
29+
// Use a temporary ArenaAllocator for parsing each row
30+
var arena = std.heap.ArenaAllocator.init(self.allocator);
31+
defer arena.deinit(); // Ensure arena is deinitialized even if we continue the loop
32+
const temp_allocator = arena.allocator();
3133

32-
// Use a temporary ArenaAllocator for parsing each row
33-
var arena = std.heap.ArenaAllocator.init(self.allocator);
34-
defer arena.deinit();
35-
const temp_allocator = arena.allocator();
34+
const row_str = self.all_rows.items[self.current_index];
35+
const current_row_index = self.current_index; // Store index before potential increment
36+
self.current_index += 1;
3637

37-
const row_str = self.all_rows.items[self.current_index];
38-
self.current_index += 1;
38+
// Try parsing the row
39+
const maybe_bar = Bar.parse(row_str, temp_allocator) catch |err| {
40+
// Log or handle allocation errors during parsing if necessary
41+
std.debug.print("ERROR: Allocation error during Bar.parse at index {d}: {s}\n", .{ current_row_index, @errorName(err) });
42+
// If allocation fails, we might want to stop completely or skip.
43+
// Continuing the loop might lead to repeated allocation errors.
44+
// For now, let's skip this row like other parsing errors.
45+
continue; // Skip to the next iteration (next row)
46+
};
3947

40-
// Try parsing the row
41-
const maybe_bar = Bar.parse(row_str, temp_allocator) catch |err| {
42-
// Log or handle allocation errors during parsing if necessary
43-
std.debug.print("ERROR: Allocation error during Bar.parse: {s}\n", .{@errorName(err)});
44-
return error.ParsingAllocationError; // Propagate allocation errors
45-
};
48+
if (maybe_bar == null) {
49+
// Parsing failed (e.g., bad format, wrong field count), warning printed inside Bar.parse
50+
// Log the index of the bad row for easier debugging
51+
std.debug.print("WARN: Skipping invalid bar data at index {d}\n", .{current_row_index});
52+
continue; // Skip to the next iteration (next row)
53+
}
4654

47-
if (maybe_bar == null) {
48-
// Parsing failed (e.g., bad format, wrong field count), warning printed inside Bar.parse
49-
// Optionally log here too, or decide to retry/skip
50-
// For now, we just return null, effectively skipping the bad row.
51-
// To distinguish between end-of-data and bad row, the loop calling this
52-
// might need to check the index or we could return an error enum.
53-
// Let's try fetching the *next* valid bar instead of returning null immediately.
54-
return self.nextBar(); // Recursive call to get the next *valid* one
55-
// WARNING: Recursive call could lead to stack overflow on large chunks of bad data.
56-
// An iterative approach would be safer.
57-
// TODO: Refactor to iterative loop to find next valid bar.
55+
// Successfully parsed a bar
56+
return maybe_bar.?;
5857
}
5958

60-
return maybe_bar.?;
59+
// Reached the end of the data without finding a valid bar
60+
return null;
6161
}
6262

6363
// Resets the handler to the beginning of the data stream.
6464
pub fn reset(self: *DataHandler) void {
6565
self.current_index = 0;
6666
}
6767
};
68-
69-
// TODO: Add test cases for DataHandler

src/main.zig

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,6 @@ pub fn main() !void {
1717
// --- Log Initial Config --- (Keep this part)
1818
logger.logConfig(context.config.value);
1919
logger.logStrategy(context.strategy.value);
20-
// logger.logOhlcvHeader(); // Engine/Results will handle data logging if needed
21-
// // Log the first 10 rows using the pretty logger
22-
// var i: usize = 0;
23-
// for (context.ohlcvData.body.items) |row_str| {
24-
// if (i >= 10) break; // Stop after logging 10 rows
25-
// logger.logOhlcvRowPretty(row_str, allocator);
26-
// i += 1;
27-
// }
2820

2921
// --- Initialize and Run Backtest Engine ---
3022
var engine = try BacktestEngine.init(allocator, &context);
@@ -33,5 +25,5 @@ pub fn main() !void {
3325

3426
try engine.run();
3527

36-
print("\nApplication finished successfully.\n", .{});
28+
print("\nBacktest finished successfully.\n", .{});
3729
}

src/utils/csv/csv-parser.zig

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
//! This module provides structs for parsing and manipulating CSV data
2-
//! [Released under GNU LGPLv3]
3-
//!
41
const std = @import("std");
52
const Allocator = std.mem.Allocator;
63
const ArrayList = std.ArrayList;

src/utils/csv/iterators.zig

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
//! This module provides structs for parsing and manipulating CSV data
2-
//! [Released under GNU LGPLv3]
31
const std = @import("std");
42
const TableError = @import("csv-parser.zig").TableError;
53

src/utils/load-config.zig

Lines changed: 0 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -79,84 +79,3 @@ pub const AppContext = struct {
7979
// Note: We don't deinit the allocator itself here, assuming it's managed externally (e.g., GPA in main)
8080
}
8181
};
82-
83-
test "loadConfig" {
84-
// Test the new AppContext init
85-
// Use the testing allocator directly for automatic leak detection
86-
const allocator = std.testing.allocator;
87-
88-
// Mock file system (Assuming a test setup or adjust paths)
89-
// For simplicity, we'll assume config/config.json, config/buy-and-hold.json, data/btc.csv exist
90-
// In a real scenario, you'd mock std.fs.cwd() or create temporary test files.
91-
92-
// Create dummy files for testing if they don't exist
93-
_ = std.fs.cwd().makePath("config") catch |err| switch (err) {
94-
error.PathAlreadyExists => {},
95-
else => |e| return e,
96-
};
97-
_ = std.fs.cwd().makePath("data") catch |err| switch (err) {
98-
error.PathAlreadyExists => {},
99-
else => |e| return e,
100-
};
101-
102-
var config_file = try std.fs.cwd().createFile("config/config.json", .{});
103-
defer config_file.close();
104-
_ = try config_file.writeAll(
105-
\\{
106-
\\ "budget": 10000,
107-
\\ "strategy": "buy-and-hold.json",
108-
\\ "data": "btc.csv"
109-
\\}
110-
);
111-
112-
var strat_file = try std.fs.cwd().createFile("config/buy-and-hold.json", .{});
113-
defer strat_file.close();
114-
_ = try strat_file.writeAll(
115-
\\{
116-
\\ "buyAt": 1000
117-
\\}
118-
);
119-
120-
var data_file = try std.fs.cwd().createFile("data/btc.csv", .{});
121-
defer data_file.close();
122-
_ = try data_file.writeAll(
123-
\\timestamp,open,high,low,close,volume
124-
\\2024-01-01T00:00:00Z,42000.00,42100.00,41900.00,42050.00,100.50
125-
);
126-
127-
var context = try AppContext.init(allocator);
128-
defer context.deinit();
129-
130-
try std.testing.expectEqual(@as(u64, 10000), context.config.value.budget);
131-
try std.testing.expectEqualSlices(u8, "buy-and-hold.json", context.config.value.strategy);
132-
try std.testing.expectEqualSlices(u8, "btc.csv", context.config.value.data);
133-
try std.testing.expectEqual(@as(u64, 1000), context.strategy.value.buyAt);
134-
try std.testing.expectEqual(@as(usize, 1), context.ohlcvData.body.items.len); // Check if CSV data was loaded
135-
136-
// Clean up dummy files
137-
try std.fs.cwd().deleteFile("config/config.json");
138-
try std.fs.cwd().deleteFile("config/buy-and-hold.json");
139-
try std.fs.cwd().deleteFile("data/btc.csv");
140-
try std.fs.cwd().deleteDir("config");
141-
try std.fs.cwd().deleteDir("data");
142-
}
143-
144-
// Comment out old tests or remove them
145-
// test "loadConfig" {
146-
// const config = try loadConfig(std.testing.allocator);
147-
// defer config.deinit();
148-
//
149-
// try std.testing.expectEqual(@as(u64, 10000), config.value.budget);
150-
// try std.testing.expectEqualSlices(u8, "buy-and-hold.json", config.value.strategy);
151-
// try std.testing.expectEqualSlices(u8, "btc.csv", config.value.data);
152-
// }
153-
//
154-
// test "loadStrategySettings" {
155-
// // Need to create dummy config/buy-and-hold.json for this test
156-
// // ... (test setup code) ...
157-
// const strat = try loadStrategySettings(std.testing.allocator, "config/buy-and-hold.json");
158-
// defer strat.deinit();
159-
//
160-
// try std.testing.expectEqual(@as(u64, 1000), strat.value.buyAt);
161-
// // ... (test cleanup code) ...
162-
// }

0 commit comments

Comments
 (0)