WU Trading Library 0.2.0
A backtesting and trading strategy library
Loading...
Searching...
No Matches
json.c
Go to the documentation of this file.
1#include <stdlib.h>
2#include <stdio.h>
3#include <string.h>
4#include <ctype.h>
5#include <math.h>
6#include "wu.h"
7
8static void trim_line(char* line) {
9 size_t len = strlen(line);
10 while (len > 0 && (line[len - 1] == '\r' || line[len - 1] == '\n')) {
11 line[--len] = '\0';
12 }
13}
14
15static bool read_line(WU_JsonReader reader) {
16 if (!reader->file) {
17 reader->last_error = WU_JSON_ERROR_PARSE;
18 return false;
19 }
20
21 if (!fgets(reader->line_buffer, WU_JSON_MAX_LINE_SIZE, reader->file)) {
22 reader->last_error = WU_JSON_ERROR_EOF;
23 return false;
24 }
25
26 trim_line(reader->line_buffer);
27 return true;
28}
29
30static bool json_has_field(const char* json, const char* key) {
31 char search[256];
32 snprintf(search, sizeof(search), "\"%s\":", key);
33 return strstr(json, search) != NULL;
34}
35
36static double json_get_number_value(const char* json, const char* key) {
37 char search[256];
38 snprintf(search, sizeof(search), "\"%s\":", key);
39
40 const char* pos = strstr(json, search);
41 if (!pos) return NAN;
42
43 pos += strlen(search);
44 while (*pos && isspace(*pos)) pos++;
45
46 char* endptr;
47 double value = strtod(pos, &endptr);
48
49 if (pos == endptr) return NAN;
50
51 return value;
52}
53
54static long json_get_long_value(const char* json, const char* key) {
55 char search[256];
56 snprintf(search, sizeof(search), "\"%s\":", key);
57
58 const char* pos = strstr(json, search);
59 if (!pos) return 0;
60
61 pos += strlen(search);
62 while (*pos && isspace(*pos)) pos++;
63
64 char* endptr;
65 long value = strtol(pos, &endptr, 10);
66 return value;
67}
68
69static void* read_candle_json(WU_JsonReader reader) {
70 if (!read_line(reader)) {
71 return NULL;
72 }
73
74 bool has_timestamp = json_has_field(reader->line_buffer, "timestamp");
75 bool has_open = json_has_field(reader->line_buffer, "open");
76 bool has_high = json_has_field(reader->line_buffer, "high");
77 bool has_low = json_has_field(reader->line_buffer, "low");
78 bool has_close = json_has_field(reader->line_buffer, "close");
79 bool has_volume = json_has_field(reader->line_buffer, "volume");
80
81 int field_count = has_timestamp + has_open + has_high + has_low + has_close + has_volume;
82
83 if (field_count == 0) {
84 reader->last_error = WU_JSON_ERROR_PARSE;
85 return NULL;
86 }
87
88 if (!has_timestamp || !has_open || !has_high || !has_low || !has_close || !has_volume) {
89 reader->last_error = WU_JSON_ERROR_MISSING_FIELD;
90 return NULL;
91 }
92
93 reader->data.candle.timestamp.mark = json_get_long_value(reader->line_buffer, "timestamp");
94 reader->data.candle.open = json_get_number_value(reader->line_buffer, "open");
95 reader->data.candle.high = json_get_number_value(reader->line_buffer, "high");
96 reader->data.candle.low = json_get_number_value(reader->line_buffer, "low");
97 reader->data.candle.close = json_get_number_value(reader->line_buffer, "close");
98 reader->data.candle.volume = json_get_number_value(reader->line_buffer, "volume");
99
100 if (isnan(reader->data.candle.open) || isnan(reader->data.candle.high) ||
101 isnan(reader->data.candle.low) || isnan(reader->data.candle.close) ||
102 isnan(reader->data.candle.volume)) {
103 reader->last_error = WU_JSON_ERROR_MISSING_FIELD;
104 return NULL;
105 }
106
107 reader->data.candle.data_type = WU_DATA_TYPE_CANDLE;
108 reader->last_error = WU_JSON_OK;
109 return &reader->data.candle;
110}
111
112static void* read_trade_json(WU_JsonReader reader) {
113 if (!read_line(reader)) {
114 return NULL;
115 }
116
117 bool has_timestamp = json_has_field(reader->line_buffer, "timestamp");
118 bool has_price = json_has_field(reader->line_buffer, "price");
119 bool has_volume = json_has_field(reader->line_buffer, "volume");
120 bool has_side = json_has_field(reader->line_buffer, "side");
121
122 int field_count = has_timestamp + has_price + has_volume + has_side;
123
124 if (field_count == 0) {
125 reader->last_error = WU_JSON_ERROR_PARSE;
126 return NULL;
127 }
128
129 if (!has_timestamp || !has_price || !has_volume || !has_side) {
130 reader->last_error = WU_JSON_ERROR_MISSING_FIELD;
131 return NULL;
132 }
133
134 reader->data.trade.timestamp.mark = json_get_long_value(reader->line_buffer, "timestamp");
135 reader->data.trade.price = json_get_number_value(reader->line_buffer, "price");
136 reader->data.trade.volume = json_get_number_value(reader->line_buffer, "volume");
137
138 long side_value = json_get_long_value(reader->line_buffer, "side");
139 reader->data.trade.side = (WU_Side)side_value;
140
141 if (isnan(reader->data.trade.price) || isnan(reader->data.trade.volume)) {
142 reader->last_error = WU_JSON_ERROR_MISSING_FIELD;
143 return NULL;
144 }
145
146 reader->data.trade.data_type = WU_DATA_TYPE_TRADE;
147 reader->last_error = WU_JSON_OK;
148 return &reader->data.trade;
149}
150
151static void* read_single_value_json(WU_JsonReader reader) {
152 if (!read_line(reader)) {
153 return NULL;
154 }
155
156 bool has_timestamp = json_has_field(reader->line_buffer, "timestamp");
157 bool has_value = json_has_field(reader->line_buffer, "value");
158
159 int field_count = has_timestamp + has_value;
160
161 if (field_count == 0) {
162 reader->last_error = WU_JSON_ERROR_PARSE;
163 return NULL;
164 }
165
166 if (!has_timestamp || !has_value) {
167 reader->last_error = WU_JSON_ERROR_MISSING_FIELD;
168 return NULL;
169 }
170
171 reader->data.single_value.timestamp.mark = json_get_long_value(reader->line_buffer, "timestamp");
172 reader->data.single_value.value = json_get_number_value(reader->line_buffer, "value");
173
174 if (isnan(reader->data.single_value.value)) {
175 reader->last_error = WU_JSON_ERROR_MISSING_FIELD;
176 return NULL;
177 }
178
179 reader->data.single_value.data_type = WU_DATA_TYPE_SINGLE_VALUE;
180 reader->last_error = WU_JSON_OK;
181 return &reader->data.single_value;
182}
183
184static void wu_json_reader_free(WU_JsonReader reader) {
185 if (!reader) return;
186 free(reader);
187}
188
189WU_JsonReader wu_json_reader_new(FILE* file, WU_DataType data_type,
190 WU_TimeUnit time_units) {
191 if (!file) return NULL;
192 WU_JsonReader reader = (WU_JsonReader)malloc(sizeof(struct WU_JsonReader_));
193 if (!reader) return NULL;
194
195 reader->file = file;
196 reader->data_type = data_type;
197 reader->last_error = WU_JSON_OK;
198
199 switch (data_type) {
201 reader->data.candle.timestamp.units = time_units;
202 reader->base.next = (void* (*)(struct WU_Reader_*))read_candle_json;
203 break;
205 reader->data.trade.timestamp.units = time_units;
206 reader->base.next = (void* (*)(struct WU_Reader_*))read_trade_json;
207 break;
209 reader->data.single_value.timestamp.units = time_units;
210 reader->base.next = (void* (*)(struct WU_Reader_*))read_single_value_json;
211 break;
212 default:
213 free(reader);
214 return NULL;
215 }
216 reader->base.delete = (void (*)(struct WU_Reader_*))wu_json_reader_free;
217
218 return reader;
219}
static void * read_candle_json(WU_JsonReader reader)
Definition json.c:69
static double json_get_number_value(const char *json, const char *key)
Definition json.c:36
static long json_get_long_value(const char *json, const char *key)
Definition json.c:54
static void trim_line(char *line)
Definition json.c:8
static void wu_json_reader_free(WU_JsonReader reader)
Definition json.c:184
static bool read_line(WU_JsonReader reader)
Definition json.c:15
WU_JsonReader wu_json_reader_new(FILE *file, WU_DataType data_type, WU_TimeUnit time_units)
Definition json.c:189
static void * read_trade_json(WU_JsonReader reader)
Definition json.c:112
static void * read_single_value_json(WU_JsonReader reader)
Definition json.c:151
static bool json_has_field(const char *json, const char *key)
Definition json.c:30
#define WU_JSON_MAX_LINE_SIZE
Definition readers.h:31
@ WU_JSON_ERROR_PARSE
Definition readers.h:42
@ WU_JSON_OK
Definition readers.h:40
@ WU_JSON_ERROR_MISSING_FIELD
Definition readers.h:43
@ WU_JSON_ERROR_EOF
Definition readers.h:41
WU_JsonReader is a concrete implementation of the WU_Reader interface that reads data from a JSON Lin...
Definition readers.h:68
Base for a reader, which defines the minimal interface for reading the next data point from a data so...
Definition readers.h:16
WU_TimeUnit
WU_TimeUnit represents a unit of time used for time-based calculations such as time-weighted returns ...
Definition timeutils.h:10
WU_Side
WU_Side represents the direction of a signal or a trade.
Definition types.h:11
WU_DataType
WU_DataType represents the type of input data, which can be a candle, a trade, or a single value.
Definition types.h:24
@ WU_DATA_TYPE_TRADE
Definition types.h:26
@ WU_DATA_TYPE_SINGLE_VALUE
Definition types.h:27
@ WU_DATA_TYPE_CANDLE
Definition types.h:25