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/index.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// 📄 bindings/react-native/index.d.ts
|
|
3
|
+
// Mục Ä‘Ãch: TypeScript types & exports cho React Native
|
|
4
|
+
// ============================================================================
|
|
5
|
+
|
|
6
|
+
declare const ChartLibrary: {
|
|
7
|
+
calculateMA(closes: number[], period: number): (number | null)[];
|
|
8
|
+
calculateEMA(closes: number[], period: number): (number | null)[];
|
|
9
|
+
|
|
10
|
+
calculateMACD(
|
|
11
|
+
closes: number[],
|
|
12
|
+
fast: number,
|
|
13
|
+
slow: number,
|
|
14
|
+
signal: number
|
|
15
|
+
): {
|
|
16
|
+
macd: (number | null)[];
|
|
17
|
+
signal: (number | null)[];
|
|
18
|
+
histogram: (number | null)[];
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
calculateRSI(closes: number[], period: number): (number | null)[];
|
|
22
|
+
|
|
23
|
+
calculateKDJ(
|
|
24
|
+
highs: number[],
|
|
25
|
+
lows: number[],
|
|
26
|
+
closes: number[],
|
|
27
|
+
n: number,
|
|
28
|
+
m1: number,
|
|
29
|
+
m2: number
|
|
30
|
+
): {
|
|
31
|
+
k: (number | null)[];
|
|
32
|
+
d: (number | null)[];
|
|
33
|
+
j: (number | null)[];
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
calculateBOLL(
|
|
37
|
+
closes: number[],
|
|
38
|
+
period: number,
|
|
39
|
+
k: number
|
|
40
|
+
): {
|
|
41
|
+
upper: (number | null)[];
|
|
42
|
+
middle: (number | null)[];
|
|
43
|
+
lower: (number | null)[];
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
calculateDMI(
|
|
47
|
+
opens: number[],
|
|
48
|
+
highs: number[],
|
|
49
|
+
lows: number[],
|
|
50
|
+
closes: number[],
|
|
51
|
+
period: number
|
|
52
|
+
): {
|
|
53
|
+
pdi: (number | null)[];
|
|
54
|
+
mdi: (number | null)[];
|
|
55
|
+
adx: (number | null)[];
|
|
56
|
+
adxr: (number | null)[];
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export default ChartLibrary;
|
|
61
|
+
|
|
62
|
+
// Usage in React Native:
|
|
63
|
+
// import ChartLibrary from 'chart-library-native'
|
|
64
|
+
// const ma = ChartLibrary.calculateMA([10, 11, 12, 13], 2);
|
|
65
|
+
// const macd = ChartLibrary.calculateMACD(closes, 12, 26, 9);
|
|
66
|
+
|
package/index.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// 📄 bindings/react-native/index.js
|
|
3
|
+
// Mục Ä‘Ãch: JavaScript entry point for React Native package
|
|
4
|
+
// ============================================================================
|
|
5
|
+
|
|
6
|
+
// Check if ChartLibrary is available (JSI module)
|
|
7
|
+
// This is registered by installChartLibrary() in jsi_bindings.cpp
|
|
8
|
+
let ChartLibrary = global.ChartLibrary;
|
|
9
|
+
|
|
10
|
+
if (!ChartLibrary) {
|
|
11
|
+
console.warn(
|
|
12
|
+
'ChartLibrary: JSI module not found. ' +
|
|
13
|
+
'Make sure you have properly installed and linked the native module. ' +
|
|
14
|
+
'Call installChartLibrary(runtime) in your native code.'
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
// Provide a stub object to prevent crashes
|
|
18
|
+
ChartLibrary = {
|
|
19
|
+
calculateMA: () => { throw new Error('ChartLibrary not initialized'); },
|
|
20
|
+
calculateEMA: () => { throw new Error('ChartLibrary not initialized'); },
|
|
21
|
+
calculateMACD: () => { throw new Error('ChartLibrary not initialized'); },
|
|
22
|
+
calculateRSI: () => { throw new Error('ChartLibrary not initialized'); },
|
|
23
|
+
calculateKDJ: () => { throw new Error('ChartLibrary not initialized'); },
|
|
24
|
+
calculateBOLL: () => { throw new Error('ChartLibrary not initialized'); },
|
|
25
|
+
calculateDMI: () => { throw new Error('ChartLibrary not initialized'); },
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Export all indicator functions
|
|
30
|
+
// These directly call the JSI functions registered by installChartLibrary()
|
|
31
|
+
export default {
|
|
32
|
+
// Moving Averages
|
|
33
|
+
calculateMA: (closes, period) => {
|
|
34
|
+
if (!ChartLibrary.calculateMA) {
|
|
35
|
+
throw new Error('calculateMA is not available. Make sure native module is properly installed.');
|
|
36
|
+
}
|
|
37
|
+
return ChartLibrary.calculateMA(closes, period);
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
calculateEMA: (closes, period) => {
|
|
41
|
+
if (!ChartLibrary.calculateEMA) {
|
|
42
|
+
throw new Error('calculateEMA is not available. Make sure native module is properly installed.');
|
|
43
|
+
}
|
|
44
|
+
return ChartLibrary.calculateEMA(closes, period);
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
// MACD
|
|
48
|
+
calculateMACD: (closes, fastPeriod = 12, slowPeriod = 26, signalPeriod = 9) => {
|
|
49
|
+
if (!ChartLibrary.calculateMACD) {
|
|
50
|
+
throw new Error('calculateMACD is not available. Make sure native module is properly installed.');
|
|
51
|
+
}
|
|
52
|
+
return ChartLibrary.calculateMACD(closes, fastPeriod, slowPeriod, signalPeriod);
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
// RSI
|
|
56
|
+
calculateRSI: (closes, period = 14) => {
|
|
57
|
+
if (!ChartLibrary.calculateRSI) {
|
|
58
|
+
throw new Error('calculateRSI is not available. Make sure native module is properly installed.');
|
|
59
|
+
}
|
|
60
|
+
return ChartLibrary.calculateRSI(closes, period);
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
// KDJ
|
|
64
|
+
calculateKDJ: (highs, lows, closes, n = 9, m1 = 3, m2 = 3) => {
|
|
65
|
+
if (!ChartLibrary.calculateKDJ) {
|
|
66
|
+
throw new Error('calculateKDJ is not available. Make sure native module is properly installed.');
|
|
67
|
+
}
|
|
68
|
+
return ChartLibrary.calculateKDJ(highs, lows, closes, n, m1, m2);
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
// Bollinger Bands
|
|
72
|
+
calculateBOLL: (closes, period = 20, k = 2.0) => {
|
|
73
|
+
if (!ChartLibrary.calculateBOLL) {
|
|
74
|
+
throw new Error('calculateBOLL is not available. Make sure native module is properly installed.');
|
|
75
|
+
}
|
|
76
|
+
return ChartLibrary.calculateBOLL(closes, period, k);
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
// DMI (requires opens, highs, lows, closes)
|
|
80
|
+
calculateDMI: (opens, highs, lows, closes, period = 14) => {
|
|
81
|
+
if (!ChartLibrary.calculateDMI) {
|
|
82
|
+
throw new Error('calculateDMI is not available. Make sure native module is properly installed.');
|
|
83
|
+
}
|
|
84
|
+
return ChartLibrary.calculateDMI(opens, highs, lows, closes, period);
|
|
85
|
+
}
|
|
86
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "chart-library-native",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "âš¡ High-performance chart library with 20 technical indicators for React Native. C++ core + JSI bindings.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"module": "src/index.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./index.d.ts",
|
|
11
|
+
"import": "./index.js",
|
|
12
|
+
"require": "./index.js"
|
|
13
|
+
},
|
|
14
|
+
"./src": {
|
|
15
|
+
"types": "./src/index.ts",
|
|
16
|
+
"import": "./src/index.ts"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"index.js",
|
|
21
|
+
"index.d.ts",
|
|
22
|
+
"src/",
|
|
23
|
+
"CMakeLists.txt",
|
|
24
|
+
"README.md",
|
|
25
|
+
"LICENSE",
|
|
26
|
+
"EXPO_SETUP.md"
|
|
27
|
+
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsc || echo 'TypeScript not installed, skipping build. Source files are in src/ and can be used directly.'",
|
|
30
|
+
"build:check": "tsc --noEmit",
|
|
31
|
+
"prepublishOnly": "echo 'Preparing to publish...'",
|
|
32
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"react-native",
|
|
36
|
+
"expo",
|
|
37
|
+
"chart",
|
|
38
|
+
"technical-indicators",
|
|
39
|
+
"trading",
|
|
40
|
+
"ma",
|
|
41
|
+
"macd",
|
|
42
|
+
"rsi",
|
|
43
|
+
"kdj",
|
|
44
|
+
"bollinger",
|
|
45
|
+
"dmi",
|
|
46
|
+
"indicators",
|
|
47
|
+
"stock",
|
|
48
|
+
"crypto",
|
|
49
|
+
"finance",
|
|
50
|
+
"c++",
|
|
51
|
+
"jsi",
|
|
52
|
+
"expo-development-build"
|
|
53
|
+
],
|
|
54
|
+
"author": "",
|
|
55
|
+
"license": "MIT",
|
|
56
|
+
"repository": {
|
|
57
|
+
"type": "git",
|
|
58
|
+
"url": "https://github.com/yourusername/chart-across-platform.git"
|
|
59
|
+
},
|
|
60
|
+
"bugs": {
|
|
61
|
+
"url": "https://github.com/yourusername/chart-across-platform/issues"
|
|
62
|
+
},
|
|
63
|
+
"homepage": "https://github.com/yourusername/chart-across-platform#readme",
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"react": ">=16.8.0",
|
|
66
|
+
"react-native": ">=0.60.0"
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@types/react": "^18.0.0",
|
|
70
|
+
"@types/react-native": "^0.72.0",
|
|
71
|
+
"typescript": "^5.9.3"
|
|
72
|
+
},
|
|
73
|
+
"optionalDependencies": {
|
|
74
|
+
"typescript": "^5.0.0"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// 📄 bindings/react-native/src/ChartModule.cpp
|
|
3
|
+
// Mục Ä‘Ãch: JSI Bridge Module Implementation for React Native
|
|
4
|
+
// ============================================================================
|
|
5
|
+
|
|
6
|
+
#include "ChartModule.h"
|
|
7
|
+
#include "helpers.h"
|
|
8
|
+
#include "../../core/indicators/indicators.h"
|
|
9
|
+
#include <stdexcept>
|
|
10
|
+
|
|
11
|
+
using namespace facebook;
|
|
12
|
+
|
|
13
|
+
namespace chart {
|
|
14
|
+
namespace reactnative {
|
|
15
|
+
|
|
16
|
+
// ========================================================================
|
|
17
|
+
// Install the module into JSI runtime
|
|
18
|
+
// ========================================================================
|
|
19
|
+
void ChartModule::install(jsi::Runtime& runtime) {
|
|
20
|
+
auto chartModule = std::make_shared<ChartModule>();
|
|
21
|
+
auto object = jsi::Object::createFromHostObject(runtime, chartModule);
|
|
22
|
+
runtime.global().setProperty(runtime, "ChartNative", std::move(object));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// ========================================================================
|
|
26
|
+
// Get property handler - maps JavaScript function calls to C++ functions
|
|
27
|
+
// ========================================================================
|
|
28
|
+
jsi::Value ChartModule::get(jsi::Runtime& runtime, const jsi::PropNameID& name) {
|
|
29
|
+
std::string propName = name.utf8(runtime);
|
|
30
|
+
|
|
31
|
+
// ========== MOVING AVERAGES ==========
|
|
32
|
+
if (propName == "calculateMA") {
|
|
33
|
+
return jsi::Function::createFromHostFunction(
|
|
34
|
+
runtime,
|
|
35
|
+
name,
|
|
36
|
+
2, // 2 parameters: closes, period
|
|
37
|
+
[](jsi::Runtime& rt, const jsi::Value* args, size_t count) -> jsi::Value {
|
|
38
|
+
if (count < 2) {
|
|
39
|
+
throw jsi::JSError(rt, "calculateMA requires 2 arguments: closes, period");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
auto closes = helpers::jsArrayToVector(rt, args[0]);
|
|
43
|
+
int period = static_cast<int>(args[1].asNumber());
|
|
44
|
+
|
|
45
|
+
auto result = indicators::calculateMA(closes, period);
|
|
46
|
+
return helpers::vectorToJSArray(rt, result);
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (propName == "calculateEMA") {
|
|
52
|
+
return jsi::Function::createFromHostFunction(
|
|
53
|
+
runtime,
|
|
54
|
+
name,
|
|
55
|
+
2,
|
|
56
|
+
[](jsi::Runtime& rt, const jsi::Value* args, size_t count) -> jsi::Value {
|
|
57
|
+
if (count < 2) {
|
|
58
|
+
throw jsi::JSError(rt, "calculateEMA requires 2 arguments: closes, period");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
auto closes = helpers::jsArrayToVector(rt, args[0]);
|
|
62
|
+
int period = static_cast<int>(args[1].asNumber());
|
|
63
|
+
|
|
64
|
+
auto result = indicators::calculateEMA(closes, period);
|
|
65
|
+
return helpers::vectorToJSArray(rt, result);
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ========== MACD ==========
|
|
71
|
+
if (propName == "calculateMACD") {
|
|
72
|
+
return jsi::Function::createFromHostFunction(
|
|
73
|
+
runtime,
|
|
74
|
+
name,
|
|
75
|
+
4, // closes, fastPeriod, slowPeriod, signalPeriod
|
|
76
|
+
[](jsi::Runtime& rt, const jsi::Value* args, size_t count) -> jsi::Value {
|
|
77
|
+
if (count < 1) {
|
|
78
|
+
throw jsi::JSError(rt, "calculateMACD requires at least 1 argument: closes");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
auto closes = helpers::jsArrayToVector(rt, args[0]);
|
|
82
|
+
int fastPeriod = count > 1 ? static_cast<int>(args[1].asNumber()) : 12;
|
|
83
|
+
int slowPeriod = count > 2 ? static_cast<int>(args[2].asNumber()) : 26;
|
|
84
|
+
int signalPeriod = count > 3 ? static_cast<int>(args[3].asNumber()) : 9;
|
|
85
|
+
|
|
86
|
+
auto result = indicators::calculateMACD(closes, fastPeriod, slowPeriod, signalPeriod);
|
|
87
|
+
return helpers::macdResultToJSObject(rt, result);
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ========== RSI ==========
|
|
93
|
+
if (propName == "calculateRSI") {
|
|
94
|
+
return jsi::Function::createFromHostFunction(
|
|
95
|
+
runtime,
|
|
96
|
+
name,
|
|
97
|
+
2,
|
|
98
|
+
[](jsi::Runtime& rt, const jsi::Value* args, size_t count) -> jsi::Value {
|
|
99
|
+
if (count < 1) {
|
|
100
|
+
throw jsi::JSError(rt, "calculateRSI requires at least 1 argument: closes");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
auto closes = helpers::jsArrayToVector(rt, args[0]);
|
|
104
|
+
int period = count > 1 ? static_cast<int>(args[1].asNumber()) : 14;
|
|
105
|
+
|
|
106
|
+
auto result = indicators::calculateRSI(closes, period);
|
|
107
|
+
return helpers::vectorToJSArray(rt, result);
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ========== KDJ ==========
|
|
113
|
+
if (propName == "calculateKDJ") {
|
|
114
|
+
return jsi::Function::createFromHostFunction(
|
|
115
|
+
runtime,
|
|
116
|
+
name,
|
|
117
|
+
6, // highs, lows, closes, period, kSmooth, dSmooth
|
|
118
|
+
[](jsi::Runtime& rt, const jsi::Value* args, size_t count) -> jsi::Value {
|
|
119
|
+
if (count < 3) {
|
|
120
|
+
throw jsi::JSError(rt, "calculateKDJ requires at least 3 arguments: highs, lows, closes");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
auto highs = helpers::jsArrayToVector(rt, args[0]);
|
|
124
|
+
auto lows = helpers::jsArrayToVector(rt, args[1]);
|
|
125
|
+
auto closes = helpers::jsArrayToVector(rt, args[2]);
|
|
126
|
+
int period = count > 3 ? static_cast<int>(args[3].asNumber()) : 9;
|
|
127
|
+
int kSmooth = count > 4 ? static_cast<int>(args[4].asNumber()) : 3;
|
|
128
|
+
int dSmooth = count > 5 ? static_cast<int>(args[5].asNumber()) : 3;
|
|
129
|
+
|
|
130
|
+
auto result = indicators::calculateKDJ(highs, lows, closes, period, kSmooth, dSmooth);
|
|
131
|
+
return helpers::kdjResultToJSObject(rt, result);
|
|
132
|
+
}
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ========== BOLLINGER BANDS ==========
|
|
137
|
+
if (propName == "calculateBollinger") {
|
|
138
|
+
return jsi::Function::createFromHostFunction(
|
|
139
|
+
runtime,
|
|
140
|
+
name,
|
|
141
|
+
3, // closes, period, multiplier
|
|
142
|
+
[](jsi::Runtime& rt, const jsi::Value* args, size_t count) -> jsi::Value {
|
|
143
|
+
if (count < 1) {
|
|
144
|
+
throw jsi::JSError(rt, "calculateBollinger requires at least 1 argument: closes");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
auto closes = helpers::jsArrayToVector(rt, args[0]);
|
|
148
|
+
int period = count > 1 ? static_cast<int>(args[1].asNumber()) : 20;
|
|
149
|
+
double multiplier = count > 2 ? args[2].asNumber() : 2.0;
|
|
150
|
+
|
|
151
|
+
auto result = indicators::calculateBollinger(closes, period, multiplier);
|
|
152
|
+
return helpers::bollingerResultToJSObject(rt, result);
|
|
153
|
+
}
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ========== DMI ==========
|
|
158
|
+
if (propName == "calculateDMI") {
|
|
159
|
+
return jsi::Function::createFromHostFunction(
|
|
160
|
+
runtime,
|
|
161
|
+
name,
|
|
162
|
+
4, // highs, lows, closes, period
|
|
163
|
+
[](jsi::Runtime& rt, const jsi::Value* args, size_t count) -> jsi::Value {
|
|
164
|
+
if (count < 3) {
|
|
165
|
+
throw jsi::JSError(rt, "calculateDMI requires at least 3 arguments: highs, lows, closes");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
auto highs = helpers::jsArrayToVector(rt, args[0]);
|
|
169
|
+
auto lows = helpers::jsArrayToVector(rt, args[1]);
|
|
170
|
+
auto closes = helpers::jsArrayToVector(rt, args[2]);
|
|
171
|
+
int period = count > 3 ? static_cast<int>(args[3].asNumber()) : 14;
|
|
172
|
+
|
|
173
|
+
auto result = indicators::calculateDMI(highs, lows, closes, period);
|
|
174
|
+
return helpers::dmiResultToJSObject(rt, result);
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ========== OBV ==========
|
|
180
|
+
if (propName == "calculateOBV") {
|
|
181
|
+
return jsi::Function::createFromHostFunction(
|
|
182
|
+
runtime,
|
|
183
|
+
name,
|
|
184
|
+
2, // closes, volumes
|
|
185
|
+
[](jsi::Runtime& rt, const jsi::Value* args, size_t count) -> jsi::Value {
|
|
186
|
+
if (count < 2) {
|
|
187
|
+
throw jsi::JSError(rt, "calculateOBV requires 2 arguments: closes, volumes");
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
auto closes = helpers::jsArrayToVector(rt, args[0]);
|
|
191
|
+
auto volumes = helpers::jsArrayToVector(rt, args[1]);
|
|
192
|
+
|
|
193
|
+
auto result = indicators::calculateOBV(closes, volumes);
|
|
194
|
+
return helpers::vectorToJSArray(rt, result);
|
|
195
|
+
}
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ========== CCI ==========
|
|
200
|
+
if (propName == "calculateCCI") {
|
|
201
|
+
return jsi::Function::createFromHostFunction(
|
|
202
|
+
runtime,
|
|
203
|
+
name,
|
|
204
|
+
4, // highs, lows, closes, period
|
|
205
|
+
[](jsi::Runtime& rt, const jsi::Value* args, size_t count) -> jsi::Value {
|
|
206
|
+
if (count < 3) {
|
|
207
|
+
throw jsi::JSError(rt, "calculateCCI requires at least 3 arguments: highs, lows, closes");
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
auto highs = helpers::jsArrayToVector(rt, args[0]);
|
|
211
|
+
auto lows = helpers::jsArrayToVector(rt, args[1]);
|
|
212
|
+
auto closes = helpers::jsArrayToVector(rt, args[2]);
|
|
213
|
+
int period = count > 3 ? static_cast<int>(args[3].asNumber()) : 20;
|
|
214
|
+
|
|
215
|
+
auto result = indicators::calculateCCI(highs, lows, closes, period);
|
|
216
|
+
return helpers::vectorToJSArray(rt, result);
|
|
217
|
+
}
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ========== ATR ==========
|
|
222
|
+
if (propName == "calculateATR") {
|
|
223
|
+
return jsi::Function::createFromHostFunction(
|
|
224
|
+
runtime,
|
|
225
|
+
name,
|
|
226
|
+
4, // highs, lows, closes, period
|
|
227
|
+
[](jsi::Runtime& rt, const jsi::Value* args, size_t count) -> jsi::Value {
|
|
228
|
+
if (count < 3) {
|
|
229
|
+
throw jsi::JSError(rt, "calculateATR requires at least 3 arguments: highs, lows, closes");
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
auto highs = helpers::jsArrayToVector(rt, args[0]);
|
|
233
|
+
auto lows = helpers::jsArrayToVector(rt, args[1]);
|
|
234
|
+
auto closes = helpers::jsArrayToVector(rt, args[2]);
|
|
235
|
+
int period = count > 3 ? static_cast<int>(args[3].asNumber()) : 14;
|
|
236
|
+
|
|
237
|
+
auto result = indicators::calculateATR(highs, lows, closes, period);
|
|
238
|
+
return helpers::vectorToJSArray(rt, result);
|
|
239
|
+
}
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Return undefined for unknown properties
|
|
244
|
+
return jsi::Value::undefined();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
} // namespace reactnative
|
|
248
|
+
} // namespace chart
|
|
249
|
+
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// 📄 bindings/react-native/src/ChartModule.h
|
|
3
|
+
// Mục Ä‘Ãch: JSI Bridge Module Header for React Native
|
|
4
|
+
// ============================================================================
|
|
5
|
+
|
|
6
|
+
#ifndef CHART_MODULE_H
|
|
7
|
+
#define CHART_MODULE_H
|
|
8
|
+
|
|
9
|
+
#include <jsi/jsi.h>
|
|
10
|
+
#include <memory>
|
|
11
|
+
|
|
12
|
+
using namespace facebook;
|
|
13
|
+
|
|
14
|
+
namespace chart {
|
|
15
|
+
namespace reactnative {
|
|
16
|
+
|
|
17
|
+
// ========================================================================
|
|
18
|
+
// ChartModule: JSI Module for React Native
|
|
19
|
+
// ========================================================================
|
|
20
|
+
class ChartModule : public jsi::HostObject {
|
|
21
|
+
public:
|
|
22
|
+
// Install the module into JSI runtime
|
|
23
|
+
static void install(jsi::Runtime& runtime);
|
|
24
|
+
|
|
25
|
+
// JSI HostObject methods
|
|
26
|
+
jsi::Value get(jsi::Runtime& runtime, const jsi::PropNameID& name) override;
|
|
27
|
+
|
|
28
|
+
private:
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
} // namespace reactnative
|
|
32
|
+
} // namespace chart
|
|
33
|
+
|
|
34
|
+
#endif // CHART_MODULE_H
|
|
35
|
+
|