chart-library-native 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CMakeLists.txt +70 -0
- package/EXPO_SETUP.md +335 -0
- package/LICENSE +22 -0
- package/README.md +275 -0
- package/index.d.ts +66 -0
- package/index.js +86 -0
- package/package.json +76 -0
- package/src/ChartModule.cpp +249 -0
- package/src/ChartModule.h +35 -0
- package/src/README.md +241 -0
- package/src/api/tier1/components/QuickIndicatorDisplay.tsx +109 -0
- package/src/api/tier1/components/index.ts +16 -0
- package/src/api/tier1/index.ts +15 -0
- package/src/api/tier1/useQuickBollinger.ts +58 -0
- package/src/api/tier1/useQuickDMI.ts +65 -0
- package/src/api/tier1/useQuickEMA.ts +48 -0
- package/src/api/tier1/useQuickKDJ.ts +55 -0
- package/src/api/tier1/useQuickMA.ts +60 -0
- package/src/api/tier1/useQuickMACD.ts +60 -0
- package/src/api/tier1/useQuickRSI.ts +38 -0
- package/src/helpers.cpp +135 -0
- package/src/helpers.h +65 -0
- package/src/hooks/useIndicators.ts +388 -0
- package/src/index.ts +51 -0
- package/src/jsi_bindings.cpp +532 -0
- package/src/types/index.ts +58 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// 📄 bindings/react-native/src/index.ts
|
|
3
|
+
// Main export - Simplified API cho 90% use cases
|
|
4
|
+
// ============================================================================
|
|
5
|
+
|
|
6
|
+
// ========== TIER 1: SIMPLIFIED API (No configuration needed) ==========
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
useQuickMA,
|
|
10
|
+
useQuickEMA,
|
|
11
|
+
useQuickMACD,
|
|
12
|
+
useQuickRSI,
|
|
13
|
+
useQuickKDJ,
|
|
14
|
+
useQuickBollinger,
|
|
15
|
+
useQuickDMI
|
|
16
|
+
} from './api/tier1';
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
QuickIndicatorDisplay
|
|
20
|
+
} from './api/tier1/components';
|
|
21
|
+
|
|
22
|
+
// ========== TIER 2: ADVANCED API (Full customization) ==========
|
|
23
|
+
|
|
24
|
+
export {
|
|
25
|
+
useMA,
|
|
26
|
+
useEMA,
|
|
27
|
+
useWMA,
|
|
28
|
+
useMACD,
|
|
29
|
+
useRSI,
|
|
30
|
+
useKDJ,
|
|
31
|
+
useBollinger,
|
|
32
|
+
useDMI,
|
|
33
|
+
useMultipleIndicators
|
|
34
|
+
} from './hooks/useIndicators';
|
|
35
|
+
|
|
36
|
+
// ========== TYPES ==========
|
|
37
|
+
|
|
38
|
+
export type {
|
|
39
|
+
CandleData,
|
|
40
|
+
MAResult,
|
|
41
|
+
MACDResult,
|
|
42
|
+
KDJResult,
|
|
43
|
+
BOLLResult,
|
|
44
|
+
DMIResult
|
|
45
|
+
} from './types';
|
|
46
|
+
|
|
47
|
+
// ========== LOW-LEVEL API (Direct JSI access) ==========
|
|
48
|
+
|
|
49
|
+
// Re-export the low-level ChartLibrary for advanced users
|
|
50
|
+
export { default as ChartLibrary } from '../index';
|
|
51
|
+
|
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// 📄 bindings/react-native/src/jsi_bindings.cpp
|
|
3
|
+
// Mục Ä‘Ãch: React Native JSI bridge
|
|
4
|
+
// Kết nối JavaScript → C API
|
|
5
|
+
// ============================================================================
|
|
6
|
+
|
|
7
|
+
#include <jsi/jsi.h>
|
|
8
|
+
#include "../../core/c_api/chart_api.h"
|
|
9
|
+
#include <cmath>
|
|
10
|
+
#include <vector>
|
|
11
|
+
|
|
12
|
+
using namespace facebook::jsi;
|
|
13
|
+
|
|
14
|
+
// Helper: Convert JSI Array → C++ vector<double>
|
|
15
|
+
static std::vector<double> jsArrayToVector(Runtime& rt, const Array& arr) {
|
|
16
|
+
std::vector<double> result;
|
|
17
|
+
size_t len = arr.size(rt);
|
|
18
|
+
for (size_t i = 0; i < len; ++i) {
|
|
19
|
+
Value v = arr.getValueAtIndex(rt, i);
|
|
20
|
+
if (v.isNumber()) {
|
|
21
|
+
result.push_back(v.asNumber());
|
|
22
|
+
} else if (v.isNull() || v.isUndefined()) {
|
|
23
|
+
result.push_back(std::nan(""));
|
|
24
|
+
} else {
|
|
25
|
+
result.push_back(std::nan(""));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ============================================================================
|
|
32
|
+
// JSI FUNCTION: calculateMA
|
|
33
|
+
// ============================================================================
|
|
34
|
+
void installCalculateMA(Runtime& rt, Object& module) {
|
|
35
|
+
module.setProperty(
|
|
36
|
+
rt,
|
|
37
|
+
"calculateMA",
|
|
38
|
+
Function::createFromHostFunction(
|
|
39
|
+
rt,
|
|
40
|
+
PropNameID::forAscii(rt, "calculateMA"),
|
|
41
|
+
2, // closes[], period
|
|
42
|
+
[](Runtime& rt, const Value& thisVal, const Value* args, size_t count) -> Value {
|
|
43
|
+
if (count < 2) {
|
|
44
|
+
throw JSError(rt, "calculateMA requires 2 arguments: closes[], period");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
Array closesArr = args[0].asObject(rt).asArray(rt);
|
|
48
|
+
int32_t period = (int32_t)args[1].asNumber();
|
|
49
|
+
|
|
50
|
+
auto closes_vec = jsArrayToVector(rt, closesArr);
|
|
51
|
+
|
|
52
|
+
DoubleArrayResult cres = chart_calculate_ma(
|
|
53
|
+
closes_vec.data(),
|
|
54
|
+
closes_vec.size(),
|
|
55
|
+
period
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
if (cres.error != CHART_OK) {
|
|
59
|
+
chart_free_double_array_result(&cres);
|
|
60
|
+
throw JSError(rt, cres.message ? cres.message : "Unknown error");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
Array jsResult(rt, cres.length);
|
|
64
|
+
for (size_t i = 0; i < cres.length; ++i) {
|
|
65
|
+
double val = cres.data[i];
|
|
66
|
+
if (std::isnan(val)) {
|
|
67
|
+
jsResult.setValueAtIndex(rt, i, Value::null());
|
|
68
|
+
} else {
|
|
69
|
+
jsResult.setValueAtIndex(rt, i, Value(val));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
chart_free_double_array_result(&cres);
|
|
74
|
+
return jsResult;
|
|
75
|
+
}
|
|
76
|
+
)
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ============================================================================
|
|
81
|
+
// JSI FUNCTION: calculateEMA
|
|
82
|
+
// ============================================================================
|
|
83
|
+
void installCalculateEMA(Runtime& rt, Object& module) {
|
|
84
|
+
module.setProperty(
|
|
85
|
+
rt,
|
|
86
|
+
"calculateEMA",
|
|
87
|
+
Function::createFromHostFunction(
|
|
88
|
+
rt,
|
|
89
|
+
PropNameID::forAscii(rt, "calculateEMA"),
|
|
90
|
+
2,
|
|
91
|
+
[](Runtime& rt, const Value& thisVal, const Value* args, size_t count) -> Value {
|
|
92
|
+
if (count < 2) {
|
|
93
|
+
throw JSError(rt, "calculateEMA requires 2 arguments: closes[], period");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
Array closesArr = args[0].asObject(rt).asArray(rt);
|
|
97
|
+
int32_t period = (int32_t)args[1].asNumber();
|
|
98
|
+
|
|
99
|
+
auto closes_vec = jsArrayToVector(rt, closesArr);
|
|
100
|
+
|
|
101
|
+
DoubleArrayResult cres = chart_calculate_ema(
|
|
102
|
+
closes_vec.data(),
|
|
103
|
+
closes_vec.size(),
|
|
104
|
+
period
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
if (cres.error != CHART_OK) {
|
|
108
|
+
chart_free_double_array_result(&cres);
|
|
109
|
+
throw JSError(rt, cres.message ? cres.message : "Unknown error");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
Array jsResult(rt, cres.length);
|
|
113
|
+
for (size_t i = 0; i < cres.length; ++i) {
|
|
114
|
+
double val = cres.data[i];
|
|
115
|
+
if (std::isnan(val)) {
|
|
116
|
+
jsResult.setValueAtIndex(rt, i, Value::null());
|
|
117
|
+
} else {
|
|
118
|
+
jsResult.setValueAtIndex(rt, i, Value(val));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
chart_free_double_array_result(&cres);
|
|
123
|
+
return jsResult;
|
|
124
|
+
}
|
|
125
|
+
)
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ============================================================================
|
|
130
|
+
// JSI FUNCTION: calculateMACD
|
|
131
|
+
// ============================================================================
|
|
132
|
+
void installCalculateMACD(Runtime& rt, Object& module) {
|
|
133
|
+
module.setProperty(
|
|
134
|
+
rt,
|
|
135
|
+
"calculateMACD",
|
|
136
|
+
Function::createFromHostFunction(
|
|
137
|
+
rt,
|
|
138
|
+
PropNameID::forAscii(rt, "calculateMACD"),
|
|
139
|
+
4, // closes[], fast, slow, signal
|
|
140
|
+
[](Runtime& rt, const Value& thisVal, const Value* args, size_t count) -> Value {
|
|
141
|
+
if (count < 4) {
|
|
142
|
+
throw JSError(rt, "calculateMACD requires 4 arguments");
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
Array closesArr = args[0].asObject(rt).asArray(rt);
|
|
146
|
+
int32_t fast = (int32_t)args[1].asNumber();
|
|
147
|
+
int32_t slow = (int32_t)args[2].asNumber();
|
|
148
|
+
int32_t signal = (int32_t)args[3].asNumber();
|
|
149
|
+
|
|
150
|
+
auto closes_vec = jsArrayToVector(rt, closesArr);
|
|
151
|
+
|
|
152
|
+
MACDResult cres = chart_calculate_macd(
|
|
153
|
+
closes_vec.data(),
|
|
154
|
+
closes_vec.size(),
|
|
155
|
+
fast, slow, signal
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
if (cres.error != CHART_OK) {
|
|
159
|
+
chart_free_macd_result(&cres);
|
|
160
|
+
throw JSError(rt, cres.message ? cres.message : "Unknown error");
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Return object: { macd: [...], signal: [...], histogram: [...] }
|
|
164
|
+
Object jsResult(rt);
|
|
165
|
+
|
|
166
|
+
Array macdArr(rt, cres.length);
|
|
167
|
+
for (size_t i = 0; i < cres.length; ++i) {
|
|
168
|
+
double val = cres.macd[i];
|
|
169
|
+
if (std::isnan(val)) {
|
|
170
|
+
macdArr.setValueAtIndex(rt, i, Value::null());
|
|
171
|
+
} else {
|
|
172
|
+
macdArr.setValueAtIndex(rt, i, Value(val));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
jsResult.setProperty(rt, "macd", macdArr);
|
|
176
|
+
|
|
177
|
+
Array signalArr(rt, cres.length);
|
|
178
|
+
for (size_t i = 0; i < cres.length; ++i) {
|
|
179
|
+
double val = cres.signal[i];
|
|
180
|
+
if (std::isnan(val)) {
|
|
181
|
+
signalArr.setValueAtIndex(rt, i, Value::null());
|
|
182
|
+
} else {
|
|
183
|
+
signalArr.setValueAtIndex(rt, i, Value(val));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
jsResult.setProperty(rt, "signal", signalArr);
|
|
187
|
+
|
|
188
|
+
Array histArr(rt, cres.length);
|
|
189
|
+
for (size_t i = 0; i < cres.length; ++i) {
|
|
190
|
+
double val = cres.histogram[i];
|
|
191
|
+
if (std::isnan(val)) {
|
|
192
|
+
histArr.setValueAtIndex(rt, i, Value::null());
|
|
193
|
+
} else {
|
|
194
|
+
histArr.setValueAtIndex(rt, i, Value(val));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
jsResult.setProperty(rt, "histogram", histArr);
|
|
198
|
+
|
|
199
|
+
chart_free_macd_result(&cres);
|
|
200
|
+
return jsResult;
|
|
201
|
+
}
|
|
202
|
+
)
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ============================================================================
|
|
207
|
+
// JSI FUNCTION: calculateRSI
|
|
208
|
+
// ============================================================================
|
|
209
|
+
void installCalculateRSI(Runtime& rt, Object& module) {
|
|
210
|
+
module.setProperty(
|
|
211
|
+
rt,
|
|
212
|
+
"calculateRSI",
|
|
213
|
+
Function::createFromHostFunction(
|
|
214
|
+
rt,
|
|
215
|
+
PropNameID::forAscii(rt, "calculateRSI"),
|
|
216
|
+
2,
|
|
217
|
+
[](Runtime& rt, const Value& thisVal, const Value* args, size_t count) -> Value {
|
|
218
|
+
if (count < 2) {
|
|
219
|
+
throw JSError(rt, "calculateRSI requires 2 arguments: closes[], period");
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
Array closesArr = args[0].asObject(rt).asArray(rt);
|
|
223
|
+
int32_t period = (int32_t)args[1].asNumber();
|
|
224
|
+
|
|
225
|
+
auto closes_vec = jsArrayToVector(rt, closesArr);
|
|
226
|
+
|
|
227
|
+
DoubleArrayResult cres = chart_calculate_rsi(
|
|
228
|
+
closes_vec.data(),
|
|
229
|
+
closes_vec.size(),
|
|
230
|
+
period
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
if (cres.error != CHART_OK) {
|
|
234
|
+
chart_free_double_array_result(&cres);
|
|
235
|
+
throw JSError(rt, cres.message ? cres.message : "Unknown error");
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
Array jsResult(rt, cres.length);
|
|
239
|
+
for (size_t i = 0; i < cres.length; ++i) {
|
|
240
|
+
double val = cres.data[i];
|
|
241
|
+
if (std::isnan(val)) {
|
|
242
|
+
jsResult.setValueAtIndex(rt, i, Value::null());
|
|
243
|
+
} else {
|
|
244
|
+
jsResult.setValueAtIndex(rt, i, Value(val));
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
chart_free_double_array_result(&cres);
|
|
249
|
+
return jsResult;
|
|
250
|
+
}
|
|
251
|
+
)
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// ============================================================================
|
|
256
|
+
// JSI FUNCTION: calculateKDJ
|
|
257
|
+
// ============================================================================
|
|
258
|
+
void installCalculateKDJ(Runtime& rt, Object& module) {
|
|
259
|
+
module.setProperty(
|
|
260
|
+
rt,
|
|
261
|
+
"calculateKDJ",
|
|
262
|
+
Function::createFromHostFunction(
|
|
263
|
+
rt,
|
|
264
|
+
PropNameID::forAscii(rt, "calculateKDJ"),
|
|
265
|
+
6, // highs[], lows[], closes[], n, m1, m2
|
|
266
|
+
[](Runtime& rt, const Value& thisVal, const Value* args, size_t count) -> Value {
|
|
267
|
+
if (count < 6) {
|
|
268
|
+
throw JSError(rt, "calculateKDJ requires 6 arguments");
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
Array highsArr = args[0].asObject(rt).asArray(rt);
|
|
272
|
+
Array lowsArr = args[1].asObject(rt).asArray(rt);
|
|
273
|
+
Array closesArr = args[2].asObject(rt).asArray(rt);
|
|
274
|
+
int32_t n = (int32_t)args[3].asNumber();
|
|
275
|
+
int32_t m1 = (int32_t)args[4].asNumber();
|
|
276
|
+
int32_t m2 = (int32_t)args[5].asNumber();
|
|
277
|
+
|
|
278
|
+
auto highs_vec = jsArrayToVector(rt, highsArr);
|
|
279
|
+
auto lows_vec = jsArrayToVector(rt, lowsArr);
|
|
280
|
+
auto closes_vec = jsArrayToVector(rt, closesArr);
|
|
281
|
+
|
|
282
|
+
KDJResult cres = chart_calculate_kdj(
|
|
283
|
+
highs_vec.data(),
|
|
284
|
+
lows_vec.data(),
|
|
285
|
+
closes_vec.data(),
|
|
286
|
+
closes_vec.size(),
|
|
287
|
+
n, m1, m2
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
if (cres.error != CHART_OK) {
|
|
291
|
+
chart_free_kdj_result(&cres);
|
|
292
|
+
throw JSError(rt, cres.message ? cres.message : "Unknown error");
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
Object jsResult(rt);
|
|
296
|
+
|
|
297
|
+
Array kArr(rt, cres.length);
|
|
298
|
+
for (size_t i = 0; i < cres.length; ++i) {
|
|
299
|
+
double val = cres.k[i];
|
|
300
|
+
if (std::isnan(val)) {
|
|
301
|
+
kArr.setValueAtIndex(rt, i, Value::null());
|
|
302
|
+
} else {
|
|
303
|
+
kArr.setValueAtIndex(rt, i, Value(val));
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
jsResult.setProperty(rt, "k", kArr);
|
|
307
|
+
|
|
308
|
+
Array dArr(rt, cres.length);
|
|
309
|
+
for (size_t i = 0; i < cres.length; ++i) {
|
|
310
|
+
double val = cres.d[i];
|
|
311
|
+
if (std::isnan(val)) {
|
|
312
|
+
dArr.setValueAtIndex(rt, i, Value::null());
|
|
313
|
+
} else {
|
|
314
|
+
dArr.setValueAtIndex(rt, i, Value(val));
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
jsResult.setProperty(rt, "d", dArr);
|
|
318
|
+
|
|
319
|
+
Array jArr(rt, cres.length);
|
|
320
|
+
for (size_t i = 0; i < cres.length; ++i) {
|
|
321
|
+
double val = cres.j[i];
|
|
322
|
+
if (std::isnan(val)) {
|
|
323
|
+
jArr.setValueAtIndex(rt, i, Value::null());
|
|
324
|
+
} else {
|
|
325
|
+
jArr.setValueAtIndex(rt, i, Value(val));
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
jsResult.setProperty(rt, "j", jArr);
|
|
329
|
+
|
|
330
|
+
chart_free_kdj_result(&cres);
|
|
331
|
+
return jsResult;
|
|
332
|
+
}
|
|
333
|
+
)
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// ============================================================================
|
|
338
|
+
// JSI FUNCTION: calculateBOLL
|
|
339
|
+
// ============================================================================
|
|
340
|
+
void installCalculateBOLL(Runtime& rt, Object& module) {
|
|
341
|
+
module.setProperty(
|
|
342
|
+
rt,
|
|
343
|
+
"calculateBOLL",
|
|
344
|
+
Function::createFromHostFunction(
|
|
345
|
+
rt,
|
|
346
|
+
PropNameID::forAscii(rt, "calculateBOLL"),
|
|
347
|
+
3, // closes[], period, k
|
|
348
|
+
[](Runtime& rt, const Value& thisVal, const Value* args, size_t count) -> Value {
|
|
349
|
+
if (count < 3) {
|
|
350
|
+
throw JSError(rt, "calculateBOLL requires 3 arguments: closes[], period, k");
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
Array closesArr = args[0].asObject(rt).asArray(rt);
|
|
354
|
+
int32_t period = (int32_t)args[1].asNumber();
|
|
355
|
+
double k = args[2].asNumber();
|
|
356
|
+
|
|
357
|
+
auto closes_vec = jsArrayToVector(rt, closesArr);
|
|
358
|
+
|
|
359
|
+
BOLLResult cres = chart_calculate_boll(
|
|
360
|
+
closes_vec.data(),
|
|
361
|
+
closes_vec.size(),
|
|
362
|
+
period,
|
|
363
|
+
k
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
if (cres.error != CHART_OK) {
|
|
367
|
+
chart_free_boll_result(&cres);
|
|
368
|
+
throw JSError(rt, cres.message ? cres.message : "Unknown error");
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
Object jsResult(rt);
|
|
372
|
+
|
|
373
|
+
Array upperArr(rt, cres.length);
|
|
374
|
+
for (size_t i = 0; i < cres.length; ++i) {
|
|
375
|
+
double val = cres.upper[i];
|
|
376
|
+
if (std::isnan(val)) {
|
|
377
|
+
upperArr.setValueAtIndex(rt, i, Value::null());
|
|
378
|
+
} else {
|
|
379
|
+
upperArr.setValueAtIndex(rt, i, Value(val));
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
jsResult.setProperty(rt, "upper", upperArr);
|
|
383
|
+
|
|
384
|
+
Array midArr(rt, cres.length);
|
|
385
|
+
for (size_t i = 0; i < cres.length; ++i) {
|
|
386
|
+
double val = cres.middle[i];
|
|
387
|
+
if (std::isnan(val)) {
|
|
388
|
+
midArr.setValueAtIndex(rt, i, Value::null());
|
|
389
|
+
} else {
|
|
390
|
+
midArr.setValueAtIndex(rt, i, Value(val));
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
jsResult.setProperty(rt, "middle", midArr);
|
|
394
|
+
|
|
395
|
+
Array lowerArr(rt, cres.length);
|
|
396
|
+
for (size_t i = 0; i < cres.length; ++i) {
|
|
397
|
+
double val = cres.lower[i];
|
|
398
|
+
if (std::isnan(val)) {
|
|
399
|
+
lowerArr.setValueAtIndex(rt, i, Value::null());
|
|
400
|
+
} else {
|
|
401
|
+
lowerArr.setValueAtIndex(rt, i, Value(val));
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
jsResult.setProperty(rt, "lower", lowerArr);
|
|
405
|
+
|
|
406
|
+
chart_free_boll_result(&cres);
|
|
407
|
+
return jsResult;
|
|
408
|
+
}
|
|
409
|
+
)
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// ============================================================================
|
|
414
|
+
// JSI FUNCTION: calculateDMI
|
|
415
|
+
// ============================================================================
|
|
416
|
+
void installCalculateDMI(Runtime& rt, Object& module) {
|
|
417
|
+
module.setProperty(
|
|
418
|
+
rt,
|
|
419
|
+
"calculateDMI",
|
|
420
|
+
Function::createFromHostFunction(
|
|
421
|
+
rt,
|
|
422
|
+
PropNameID::forAscii(rt, "calculateDMI"),
|
|
423
|
+
5, // opens[], highs[], lows[], closes[], period
|
|
424
|
+
[](Runtime& rt, const Value& thisVal, const Value* args, size_t count) -> Value {
|
|
425
|
+
if (count < 5) {
|
|
426
|
+
throw JSError(rt, "calculateDMI requires 5 arguments");
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
Array opensArr = args[0].asObject(rt).asArray(rt);
|
|
430
|
+
Array highsArr = args[1].asObject(rt).asArray(rt);
|
|
431
|
+
Array lowsArr = args[2].asObject(rt).asArray(rt);
|
|
432
|
+
Array closesArr = args[3].asObject(rt).asArray(rt);
|
|
433
|
+
int32_t period = (int32_t)args[4].asNumber();
|
|
434
|
+
|
|
435
|
+
auto opens_vec = jsArrayToVector(rt, opensArr);
|
|
436
|
+
auto highs_vec = jsArrayToVector(rt, highsArr);
|
|
437
|
+
auto lows_vec = jsArrayToVector(rt, lowsArr);
|
|
438
|
+
auto closes_vec = jsArrayToVector(rt, closesArr);
|
|
439
|
+
|
|
440
|
+
// Build Candle array
|
|
441
|
+
std::vector<Candle> candles_c;
|
|
442
|
+
for (size_t i = 0; i < opens_vec.size(); ++i) {
|
|
443
|
+
Candle c;
|
|
444
|
+
c.open = opens_vec[i];
|
|
445
|
+
c.high = highs_vec[i];
|
|
446
|
+
c.low = lows_vec[i];
|
|
447
|
+
c.close = closes_vec[i];
|
|
448
|
+
candles_c.push_back(c);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
DMIResult cres = chart_calculate_dmi(
|
|
452
|
+
candles_c.data(),
|
|
453
|
+
candles_c.size(),
|
|
454
|
+
period
|
|
455
|
+
);
|
|
456
|
+
|
|
457
|
+
if (cres.error != CHART_OK) {
|
|
458
|
+
chart_free_dmi_result(&cres);
|
|
459
|
+
throw JSError(rt, cres.message ? cres.message : "Unknown error");
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
Object jsResult(rt);
|
|
463
|
+
|
|
464
|
+
Array pdiArr(rt, cres.length);
|
|
465
|
+
for (size_t i = 0; i < cres.length; ++i) {
|
|
466
|
+
double val = cres.pdi[i];
|
|
467
|
+
if (std::isnan(val)) {
|
|
468
|
+
pdiArr.setValueAtIndex(rt, i, Value::null());
|
|
469
|
+
} else {
|
|
470
|
+
pdiArr.setValueAtIndex(rt, i, Value(val));
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
jsResult.setProperty(rt, "pdi", pdiArr);
|
|
474
|
+
|
|
475
|
+
Array mdiArr(rt, cres.length);
|
|
476
|
+
for (size_t i = 0; i < cres.length; ++i) {
|
|
477
|
+
double val = cres.mdi[i];
|
|
478
|
+
if (std::isnan(val)) {
|
|
479
|
+
mdiArr.setValueAtIndex(rt, i, Value::null());
|
|
480
|
+
} else {
|
|
481
|
+
mdiArr.setValueAtIndex(rt, i, Value(val));
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
jsResult.setProperty(rt, "mdi", mdiArr);
|
|
485
|
+
|
|
486
|
+
Array adxArr(rt, cres.length);
|
|
487
|
+
for (size_t i = 0; i < cres.length; ++i) {
|
|
488
|
+
double val = cres.adx[i];
|
|
489
|
+
if (std::isnan(val)) {
|
|
490
|
+
adxArr.setValueAtIndex(rt, i, Value::null());
|
|
491
|
+
} else {
|
|
492
|
+
adxArr.setValueAtIndex(rt, i, Value(val));
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
jsResult.setProperty(rt, "adx", adxArr);
|
|
496
|
+
|
|
497
|
+
Array adxrArr(rt, cres.length);
|
|
498
|
+
for (size_t i = 0; i < cres.length; ++i) {
|
|
499
|
+
double val = cres.adxr[i];
|
|
500
|
+
if (std::isnan(val)) {
|
|
501
|
+
adxrArr.setValueAtIndex(rt, i, Value::null());
|
|
502
|
+
} else {
|
|
503
|
+
adxrArr.setValueAtIndex(rt, i, Value(val));
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
jsResult.setProperty(rt, "adxr", adxrArr);
|
|
507
|
+
|
|
508
|
+
chart_free_dmi_result(&cres);
|
|
509
|
+
return jsResult;
|
|
510
|
+
}
|
|
511
|
+
)
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// ============================================================================
|
|
516
|
+
// MAIN INSTALLATION FUNCTION
|
|
517
|
+
// ============================================================================
|
|
518
|
+
|
|
519
|
+
extern "C" void installChartLibrary(jsi::Runtime& rt) {
|
|
520
|
+
auto module = Object(rt);
|
|
521
|
+
|
|
522
|
+
installCalculateMA(rt, module);
|
|
523
|
+
installCalculateEMA(rt, module);
|
|
524
|
+
installCalculateMACD(rt, module);
|
|
525
|
+
installCalculateRSI(rt, module);
|
|
526
|
+
installCalculateKDJ(rt, module);
|
|
527
|
+
installCalculateBOLL(rt, module);
|
|
528
|
+
installCalculateDMI(rt, module);
|
|
529
|
+
|
|
530
|
+
rt.global().setProperty(rt, "ChartLibrary", module);
|
|
531
|
+
}
|
|
532
|
+
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// 📄 bindings/react-native/src/types/index.ts
|
|
3
|
+
// Type definitions for Chart Library React Native API
|
|
4
|
+
// ============================================================================
|
|
5
|
+
|
|
6
|
+
export interface CandleData {
|
|
7
|
+
open: number;
|
|
8
|
+
high: number;
|
|
9
|
+
low: number;
|
|
10
|
+
close: number;
|
|
11
|
+
volume?: number;
|
|
12
|
+
timestamp?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface MAResult {
|
|
16
|
+
data: (number | null)[];
|
|
17
|
+
loading: boolean;
|
|
18
|
+
error?: string;
|
|
19
|
+
status: 'success' | 'error';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface MACDResult {
|
|
23
|
+
macd: (number | null)[];
|
|
24
|
+
signal: (number | null)[];
|
|
25
|
+
histogram: (number | null)[];
|
|
26
|
+
loading: boolean;
|
|
27
|
+
error?: string;
|
|
28
|
+
status: 'success' | 'error';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface KDJResult {
|
|
32
|
+
k: (number | null)[];
|
|
33
|
+
d: (number | null)[];
|
|
34
|
+
j: (number | null)[];
|
|
35
|
+
loading: boolean;
|
|
36
|
+
error?: string;
|
|
37
|
+
status: 'success' | 'error';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface BOLLResult {
|
|
41
|
+
upper: (number | null)[];
|
|
42
|
+
middle: (number | null)[];
|
|
43
|
+
lower: (number | null)[];
|
|
44
|
+
loading: boolean;
|
|
45
|
+
error?: string;
|
|
46
|
+
status: 'success' | 'error';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface DMIResult {
|
|
50
|
+
pdi: (number | null)[];
|
|
51
|
+
mdi: (number | null)[];
|
|
52
|
+
adx: (number | null)[];
|
|
53
|
+
adxr: (number | null)[];
|
|
54
|
+
loading: boolean;
|
|
55
|
+
error?: string;
|
|
56
|
+
status: 'success' | 'error';
|
|
57
|
+
}
|
|
58
|
+
|