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/README.md
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# 📚 High-Level API Wrapper - Usage Guide
|
|
2
|
+
|
|
3
|
+
## 🎯 Two-Tier API Architecture
|
|
4
|
+
|
|
5
|
+
### **Tier 1: Simplified API** ⭐ (90% use cases)
|
|
6
|
+
- Zero configuration
|
|
7
|
+
- Pre-configured defaults
|
|
8
|
+
- Built-in signal calculations
|
|
9
|
+
- Ready-to-use components
|
|
10
|
+
|
|
11
|
+
### **Tier 2: Advanced API** (10% use cases)
|
|
12
|
+
- Full customization
|
|
13
|
+
- Custom parameters
|
|
14
|
+
- Direct control
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 🚀 Quick Start (Tier 1)
|
|
19
|
+
|
|
20
|
+
### Example 1: Simple MA
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { useQuickMA, QuickIndicatorDisplay } from 'chart-library-native/src';
|
|
24
|
+
|
|
25
|
+
const MyComponent = () => {
|
|
26
|
+
const closes = [100, 101, 102, 101, 100, 99, 98, 99, 100, 101];
|
|
27
|
+
const { data, lastValues, loading } = useQuickMA(closes);
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<View>
|
|
31
|
+
<QuickIndicatorDisplay
|
|
32
|
+
name="MA20"
|
|
33
|
+
value={lastValues.current}
|
|
34
|
+
previousValue={lastValues.previous}
|
|
35
|
+
/>
|
|
36
|
+
<Text>Trend: {lastValues.trend}</Text>
|
|
37
|
+
</View>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Example 2: Multiple Indicators
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import {
|
|
46
|
+
useQuickMA,
|
|
47
|
+
useQuickRSI,
|
|
48
|
+
useQuickMACD,
|
|
49
|
+
QuickIndicatorDisplay
|
|
50
|
+
} from 'chart-library-native/src';
|
|
51
|
+
|
|
52
|
+
const Dashboard = () => {
|
|
53
|
+
const closes = [100, 101, 102, 101, 100, 99, 98, 99, 100, 101];
|
|
54
|
+
|
|
55
|
+
const ma = useQuickMA(closes);
|
|
56
|
+
const rsi = useQuickRSI(closes);
|
|
57
|
+
const macd = useQuickMACD(closes);
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<ScrollView>
|
|
61
|
+
<QuickIndicatorDisplay
|
|
62
|
+
name="MA20"
|
|
63
|
+
value={ma.lastValues.current}
|
|
64
|
+
/>
|
|
65
|
+
|
|
66
|
+
<QuickIndicatorDisplay
|
|
67
|
+
name="RSI14"
|
|
68
|
+
value={rsi.currentLevel.value}
|
|
69
|
+
color={rsi.currentLevel.level === 'overbought' ? '#f44336' : '#4CAF50'}
|
|
70
|
+
/>
|
|
71
|
+
|
|
72
|
+
<View>
|
|
73
|
+
<Text>MACD Signal: {macd.currentSignal.signal}</Text>
|
|
74
|
+
</View>
|
|
75
|
+
</ScrollView>
|
|
76
|
+
);
|
|
77
|
+
};
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 🔧 Advanced Usage (Tier 2)
|
|
83
|
+
|
|
84
|
+
### Custom MA Period
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { useMA } from 'chart-library-native/src';
|
|
88
|
+
|
|
89
|
+
const CustomMA = () => {
|
|
90
|
+
const closes = [100, 101, 102, 101, 100, 99, 98, 99, 100, 101];
|
|
91
|
+
|
|
92
|
+
// Custom period: MA50
|
|
93
|
+
const { data, loading } = useMA(closes, {
|
|
94
|
+
period: 50,
|
|
95
|
+
type: 'simple'
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
return <Text>MA50: {data[data.length - 1]}</Text>;
|
|
99
|
+
};
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Custom MACD Settings
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { useMACD } from 'chart-library-native/src';
|
|
106
|
+
|
|
107
|
+
const CustomMACD = () => {
|
|
108
|
+
const closes = [100, 101, 102, 101, 100, 99, 98, 99, 100, 101];
|
|
109
|
+
|
|
110
|
+
// Custom MACD: fast=8, slow=21, signal=5
|
|
111
|
+
const { macd, signal, histogram } = useMACD(closes, {
|
|
112
|
+
fast: 8,
|
|
113
|
+
slow: 21,
|
|
114
|
+
signal: 5
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<View>
|
|
119
|
+
<Text>MACD: {macd[macd.length - 1]}</Text>
|
|
120
|
+
<Text>Signal: {signal[signal.length - 1]}</Text>
|
|
121
|
+
</View>
|
|
122
|
+
);
|
|
123
|
+
};
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## 📊 Available Tier 1 Hooks
|
|
129
|
+
|
|
130
|
+
| Hook | Default | Description |
|
|
131
|
+
|------|---------|-------------|
|
|
132
|
+
| `useQuickMA` | MA20 | Simple Moving Average |
|
|
133
|
+
| `useQuickEMA` | EMA12 | Exponential Moving Average |
|
|
134
|
+
| `useQuickMACD` | 12/26/9 | MACD with signal calculation |
|
|
135
|
+
| `useQuickRSI` | RSI14 | RSI with overbought/oversold levels |
|
|
136
|
+
| `useQuickKDJ` | 9/3/3 | KDJ Stochastic |
|
|
137
|
+
| `useQuickBollinger` | BB(20,2) | Bollinger Bands |
|
|
138
|
+
| `useQuickDMI` | DMI(14) | Directional Movement Index |
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## 🎨 Components
|
|
143
|
+
|
|
144
|
+
### QuickIndicatorDisplay
|
|
145
|
+
|
|
146
|
+
Pre-built component to display indicator values:
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
<QuickIndicatorDisplay
|
|
150
|
+
name="MA20"
|
|
151
|
+
value={106.5}
|
|
152
|
+
previousValue={105.8}
|
|
153
|
+
decimals={2}
|
|
154
|
+
color="#1f77b4"
|
|
155
|
+
status="success"
|
|
156
|
+
/>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Props:**
|
|
160
|
+
- `name`: Indicator name
|
|
161
|
+
- `value`: Current value
|
|
162
|
+
- `previousValue`: Previous value (optional, for trend calculation)
|
|
163
|
+
- `decimals`: Number of decimal places (default: 2)
|
|
164
|
+
- `color`: Text color (default: '#1f77b4')
|
|
165
|
+
- `status`: 'success' | 'error'
|
|
166
|
+
- `error`: Error message (if status is 'error')
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 📝 Migration: Tier 1 → Tier 2
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
// Start with Tier 1
|
|
174
|
+
import { useQuickMA } from 'chart-library-native/src';
|
|
175
|
+
const { data } = useQuickMA(closes);
|
|
176
|
+
|
|
177
|
+
// Later, migrate to Tier 2 for custom period
|
|
178
|
+
import { useMA } from 'chart-library-native/src';
|
|
179
|
+
const { data } = useMA(closes, { period: 50, type: 'simple' });
|
|
180
|
+
|
|
181
|
+
// Zero breaking changes!
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## 🔗 Architecture
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
┌─────────────────────────────────┐
|
|
190
|
+
│ Tier 1: Simplified API │
|
|
191
|
+
│ useQuickMA, useQuickRSI, etc. │
|
|
192
|
+
└──────────────┬──────────────────┘
|
|
193
|
+
│
|
|
194
|
+
┌──────────────▼──────────────────┐
|
|
195
|
+
│ Tier 2: Advanced API │
|
|
196
|
+
│ useMA, useRSI, useMACD, etc. │
|
|
197
|
+
└──────────────┬──────────────────┘
|
|
198
|
+
│
|
|
199
|
+
┌──────────────▼──────────────────┐
|
|
200
|
+
│ Low-Level: ChartLibrary │
|
|
201
|
+
│ Direct JSI calls │
|
|
202
|
+
└──────────────┬──────────────────┘
|
|
203
|
+
│
|
|
204
|
+
┌──────────────▼──────────────────┐
|
|
205
|
+
│ C API Layer │
|
|
206
|
+
│ chart_calculate_ma, etc. │
|
|
207
|
+
└──────────────┬──────────────────┘
|
|
208
|
+
│
|
|
209
|
+
┌──────────────▼──────────────────┐
|
|
210
|
+
│ C++ Core │
|
|
211
|
+
│ calculateMA, calculateRSI, etc│
|
|
212
|
+
└─────────────────────────────────┘
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## ✅ Benefits
|
|
218
|
+
|
|
219
|
+
### Tier 1 Benefits:
|
|
220
|
+
- ✅ Zero configuration
|
|
221
|
+
- ✅ Industry-standard defaults
|
|
222
|
+
- ✅ Built-in signal calculations
|
|
223
|
+
- ✅ Ready-to-use components
|
|
224
|
+
- ✅ Perfect for 90% of use cases
|
|
225
|
+
|
|
226
|
+
### Tier 2 Benefits:
|
|
227
|
+
- ✅ Full customization
|
|
228
|
+
- ✅ Any parameters
|
|
229
|
+
- ✅ Advanced features
|
|
230
|
+
- ✅ Direct control
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## 📚 More Examples
|
|
235
|
+
|
|
236
|
+
See `examples/` directory for complete examples:
|
|
237
|
+
- Simple dashboard
|
|
238
|
+
- Multiple indicators
|
|
239
|
+
- Custom configurations
|
|
240
|
+
- Chart integration
|
|
241
|
+
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// 📄 bindings/react-native/src/api/tier1/components/QuickIndicatorDisplay.tsx
|
|
3
|
+
// Pre-built component to display any indicator
|
|
4
|
+
// ============================================================================
|
|
5
|
+
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { View, Text, StyleSheet } from 'react-native';
|
|
8
|
+
|
|
9
|
+
interface QuickIndicatorDisplayProps {
|
|
10
|
+
name: string;
|
|
11
|
+
value: number | null;
|
|
12
|
+
previousValue?: number | null;
|
|
13
|
+
decimals?: number;
|
|
14
|
+
color?: string;
|
|
15
|
+
status?: 'success' | 'error';
|
|
16
|
+
error?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Pre-built indicator display component
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* <QuickIndicatorDisplay
|
|
24
|
+
* name="MA20"
|
|
25
|
+
* value={106.5}
|
|
26
|
+
* previousValue={105.8}
|
|
27
|
+
* status="success"
|
|
28
|
+
* />
|
|
29
|
+
*/
|
|
30
|
+
export const QuickIndicatorDisplay: React.FC<QuickIndicatorDisplayProps> = ({
|
|
31
|
+
name,
|
|
32
|
+
value,
|
|
33
|
+
previousValue,
|
|
34
|
+
decimals = 2,
|
|
35
|
+
color = '#1f77b4',
|
|
36
|
+
status = 'success',
|
|
37
|
+
error
|
|
38
|
+
}) => {
|
|
39
|
+
const formattedValue = value !== null ? value.toFixed(decimals) : 'N/A';
|
|
40
|
+
const change =
|
|
41
|
+
value !== null && previousValue !== null && previousValue !== undefined
|
|
42
|
+
? ((value - previousValue) / Math.abs(previousValue) * 100).toFixed(2)
|
|
43
|
+
: null;
|
|
44
|
+
|
|
45
|
+
const changeColor = change && parseFloat(change) > 0 ? '#4CAF50' : '#f44336';
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<View style={styles.container}>
|
|
49
|
+
<View style={styles.header}>
|
|
50
|
+
<Text style={styles.name}>{name}</Text>
|
|
51
|
+
{status === 'error' && (
|
|
52
|
+
<Text style={styles.error}>❌ {error || 'Error'}</Text>
|
|
53
|
+
)}
|
|
54
|
+
</View>
|
|
55
|
+
|
|
56
|
+
<View style={styles.content}>
|
|
57
|
+
<Text style={[styles.value, { color }]}>
|
|
58
|
+
{formattedValue}
|
|
59
|
+
</Text>
|
|
60
|
+
|
|
61
|
+
{change !== null && (
|
|
62
|
+
<Text style={[styles.change, { color: changeColor }]}>
|
|
63
|
+
{parseFloat(change) > 0 ? '↑' : '↓'} {change}%
|
|
64
|
+
</Text>
|
|
65
|
+
)}
|
|
66
|
+
</View>
|
|
67
|
+
</View>
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const styles = StyleSheet.create({
|
|
72
|
+
container: {
|
|
73
|
+
padding: 12,
|
|
74
|
+
backgroundColor: '#fff',
|
|
75
|
+
borderRadius: 8,
|
|
76
|
+
marginVertical: 6,
|
|
77
|
+
borderLeftWidth: 4,
|
|
78
|
+
borderLeftColor: '#1f77b4'
|
|
79
|
+
},
|
|
80
|
+
header: {
|
|
81
|
+
flexDirection: 'row',
|
|
82
|
+
justifyContent: 'space-between',
|
|
83
|
+
alignItems: 'center'
|
|
84
|
+
},
|
|
85
|
+
name: {
|
|
86
|
+
fontSize: 12,
|
|
87
|
+
fontWeight: '600',
|
|
88
|
+
color: '#666'
|
|
89
|
+
},
|
|
90
|
+
error: {
|
|
91
|
+
fontSize: 10,
|
|
92
|
+
color: '#f44336'
|
|
93
|
+
},
|
|
94
|
+
content: {
|
|
95
|
+
flexDirection: 'row',
|
|
96
|
+
justifyContent: 'space-between',
|
|
97
|
+
alignItems: 'baseline',
|
|
98
|
+
marginTop: 8
|
|
99
|
+
},
|
|
100
|
+
value: {
|
|
101
|
+
fontSize: 18,
|
|
102
|
+
fontWeight: 'bold'
|
|
103
|
+
},
|
|
104
|
+
change: {
|
|
105
|
+
fontSize: 12,
|
|
106
|
+
fontWeight: '600'
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// 📄 bindings/react-native/src/api/tier1/components/index.ts
|
|
3
|
+
// Pre-built components ready to use
|
|
4
|
+
// ============================================================================
|
|
5
|
+
|
|
6
|
+
export { QuickIndicatorDisplay } from './QuickIndicatorDisplay';
|
|
7
|
+
// Note: Chart components (SimpleLineChart, MAChart, etc.) would require
|
|
8
|
+
// react-native-chart-kit or similar library. They are placeholders for now.
|
|
9
|
+
// export { SimpleLineChart } from './SimpleLineChart';
|
|
10
|
+
// export { MAChart } from './MAChart';
|
|
11
|
+
// export { MACDChart } from './MACDChart';
|
|
12
|
+
// export { RSIChart } from './RSIChart';
|
|
13
|
+
// export { KDJChart } from './KDJChart';
|
|
14
|
+
// export { BollingerChart } from './BollingerChart';
|
|
15
|
+
// export { ChartCard } from './ChartCard';
|
|
16
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// 📄 bindings/react-native/src/api/tier1/index.ts
|
|
3
|
+
// Tier 1 Simplified API exports
|
|
4
|
+
// ============================================================================
|
|
5
|
+
|
|
6
|
+
export { useQuickMA } from './useQuickMA';
|
|
7
|
+
export { useQuickEMA } from './useQuickEMA';
|
|
8
|
+
export { useQuickMACD } from './useQuickMACD';
|
|
9
|
+
export { useQuickRSI } from './useQuickRSI';
|
|
10
|
+
export { useQuickKDJ } from './useQuickKDJ';
|
|
11
|
+
export { useQuickBollinger } from './useQuickBollinger';
|
|
12
|
+
export { useQuickDMI } from './useQuickDMI';
|
|
13
|
+
|
|
14
|
+
export * from './components';
|
|
15
|
+
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// 📄 bindings/react-native/src/api/tier1/useQuickBollinger.ts
|
|
3
|
+
// Tier 1 API: Bollinger Bands
|
|
4
|
+
// ============================================================================
|
|
5
|
+
|
|
6
|
+
import { useBollinger } from '../../hooks/useIndicators';
|
|
7
|
+
|
|
8
|
+
export interface UseQuickBollingerResult {
|
|
9
|
+
upper: (number | null)[];
|
|
10
|
+
middle: (number | null)[];
|
|
11
|
+
lower: (number | null)[];
|
|
12
|
+
loading: boolean;
|
|
13
|
+
error?: string;
|
|
14
|
+
currentBands: {
|
|
15
|
+
upper: number | null;
|
|
16
|
+
middle: number | null;
|
|
17
|
+
lower: number | null;
|
|
18
|
+
price: number | null;
|
|
19
|
+
position: 'above' | 'within' | 'below';
|
|
20
|
+
};
|
|
21
|
+
status: 'success' | 'error';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Quick Bollinger Bands Hook - Standard BB(20,2)
|
|
26
|
+
*
|
|
27
|
+
* @param closes - Array of close prices
|
|
28
|
+
* @returns { upper, middle, lower, currentBands, loading, error, status }
|
|
29
|
+
*/
|
|
30
|
+
export const useQuickBollinger = (closes: number[]): UseQuickBollingerResult => {
|
|
31
|
+
const { upper, middle, lower, loading, status, error } = useBollinger(closes, {
|
|
32
|
+
period: 20,
|
|
33
|
+
k: 2.0
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const validUpper = upper.filter(v => v !== null && Number.isFinite(v)) as number[];
|
|
37
|
+
const validMiddle = middle.filter(v => v !== null && Number.isFinite(v)) as number[];
|
|
38
|
+
const validLower = lower.filter(v => v !== null && Number.isFinite(v)) as number[];
|
|
39
|
+
|
|
40
|
+
const u = validUpper.length > 0 ? validUpper[validUpper.length - 1] : null;
|
|
41
|
+
const m = validMiddle.length > 0 ? validMiddle[validMiddle.length - 1] : null;
|
|
42
|
+
const l = validLower.length > 0 ? validLower[validLower.length - 1] : null;
|
|
43
|
+
const price = closes.length > 0 ? closes[closes.length - 1] : null;
|
|
44
|
+
|
|
45
|
+
const currentBands = {
|
|
46
|
+
upper: u,
|
|
47
|
+
middle: m,
|
|
48
|
+
lower: l,
|
|
49
|
+
price,
|
|
50
|
+
position: ((): 'above' | 'within' | 'below' => {
|
|
51
|
+
if (u === null || l === null || price === null) return 'within';
|
|
52
|
+
return price > u ? 'above' : price < l ? 'below' : 'within';
|
|
53
|
+
})()
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
return { upper, middle, lower, loading, error, currentBands, status };
|
|
57
|
+
};
|
|
58
|
+
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// 📄 bindings/react-native/src/api/tier1/useQuickDMI.ts
|
|
3
|
+
// Tier 1 API: DMI (Directional Movement Index)
|
|
4
|
+
// ============================================================================
|
|
5
|
+
|
|
6
|
+
import { useDMI } from '../../hooks/useIndicators';
|
|
7
|
+
import type { CandleData } from '../../types';
|
|
8
|
+
|
|
9
|
+
export interface UseQuickDMIResult {
|
|
10
|
+
pdi: (number | null)[];
|
|
11
|
+
mdi: (number | null)[];
|
|
12
|
+
adx: (number | null)[];
|
|
13
|
+
adxr: (number | null)[];
|
|
14
|
+
loading: boolean;
|
|
15
|
+
error?: string;
|
|
16
|
+
currentTrend: {
|
|
17
|
+
pdi: number | null;
|
|
18
|
+
mdi: number | null;
|
|
19
|
+
adx: number | null;
|
|
20
|
+
direction: 'uptrend' | 'downtrend' | 'no_trend';
|
|
21
|
+
strength: 'strong' | 'moderate' | 'weak';
|
|
22
|
+
};
|
|
23
|
+
status: 'success' | 'error';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Quick DMI Hook - Standard DMI(14)
|
|
28
|
+
*
|
|
29
|
+
* ADX > 25: Strong trend
|
|
30
|
+
* ADX 20-25: Moderate trend
|
|
31
|
+
* ADX < 20: Weak trend / No trend
|
|
32
|
+
*
|
|
33
|
+
* @param candleData - Array of candle data
|
|
34
|
+
* @returns { pdi, mdi, adx, adxr, currentTrend, loading, error, status }
|
|
35
|
+
*/
|
|
36
|
+
export const useQuickDMI = (candleData: CandleData[]): UseQuickDMIResult => {
|
|
37
|
+
const { pdi, mdi, adx, adxr, loading, status, error } = useDMI(candleData, {
|
|
38
|
+
period: 14
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const validPDI = pdi.filter(v => v !== null && Number.isFinite(v)) as number[];
|
|
42
|
+
const validMDI = mdi.filter(v => v !== null && Number.isFinite(v)) as number[];
|
|
43
|
+
const validADX = adx.filter(v => v !== null && Number.isFinite(v)) as number[];
|
|
44
|
+
|
|
45
|
+
const pdiVal = validPDI.length > 0 ? validPDI[validPDI.length - 1] : null;
|
|
46
|
+
const mdiVal = validMDI.length > 0 ? validMDI[validMDI.length - 1] : null;
|
|
47
|
+
const adxVal = validADX.length > 0 ? validADX[validADX.length - 1] : null;
|
|
48
|
+
|
|
49
|
+
const currentTrend = {
|
|
50
|
+
pdi: pdiVal,
|
|
51
|
+
mdi: mdiVal,
|
|
52
|
+
adx: adxVal,
|
|
53
|
+
direction: ((): 'uptrend' | 'downtrend' | 'no_trend' => {
|
|
54
|
+
if (pdiVal === null || mdiVal === null) return 'no_trend';
|
|
55
|
+
return pdiVal > mdiVal ? 'uptrend' : mdiVal > pdiVal ? 'downtrend' : 'no_trend';
|
|
56
|
+
})(),
|
|
57
|
+
strength: ((): 'strong' | 'moderate' | 'weak' => {
|
|
58
|
+
if (adxVal === null) return 'weak';
|
|
59
|
+
return adxVal > 25 ? 'strong' : adxVal > 20 ? 'moderate' : 'weak';
|
|
60
|
+
})()
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
return { pdi, mdi, adx, adxr, loading, error, currentTrend, status };
|
|
64
|
+
};
|
|
65
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// 📄 bindings/react-native/src/api/tier1/useQuickEMA.ts
|
|
3
|
+
// Tier 1 API: Exponential Moving Average
|
|
4
|
+
// ============================================================================
|
|
5
|
+
|
|
6
|
+
import { useEMA } from '../../hooks/useIndicators';
|
|
7
|
+
|
|
8
|
+
export interface UseQuickEMAResult {
|
|
9
|
+
data: (number | null)[];
|
|
10
|
+
loading: boolean;
|
|
11
|
+
error?: string;
|
|
12
|
+
lastValues: {
|
|
13
|
+
current: number | null;
|
|
14
|
+
previous: number | null;
|
|
15
|
+
trend: 'up' | 'down' | 'flat';
|
|
16
|
+
};
|
|
17
|
+
status: 'success' | 'error';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Quick EMA Hook - No configuration needed
|
|
22
|
+
*
|
|
23
|
+
* Default: EMA12 (fast EMA, commonly used with EMA26)
|
|
24
|
+
*
|
|
25
|
+
* @param closes - Array of close prices
|
|
26
|
+
* @returns { data, loading, error, lastValues, status }
|
|
27
|
+
*/
|
|
28
|
+
export const useQuickEMA = (closes: number[]): UseQuickEMAResult => {
|
|
29
|
+
const { data, loading, status, error } = useEMA(closes, {
|
|
30
|
+
period: 12,
|
|
31
|
+
type: 'exponential'
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const validData = data.filter(v => v !== null && Number.isFinite(v)) as number[];
|
|
35
|
+
const lastValues = {
|
|
36
|
+
current: validData.length > 0 ? validData[validData.length - 1] : null,
|
|
37
|
+
previous: validData.length > 1 ? validData[validData.length - 2] : null,
|
|
38
|
+
trend: ((): 'up' | 'down' | 'flat' => {
|
|
39
|
+
if (validData.length < 2) return 'flat';
|
|
40
|
+
const curr = validData[validData.length - 1];
|
|
41
|
+
const prev = validData[validData.length - 2];
|
|
42
|
+
return curr > prev ? 'up' : curr < prev ? 'down' : 'flat';
|
|
43
|
+
})()
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
return { data, loading, error, lastValues, status };
|
|
47
|
+
};
|
|
48
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// 📄 bindings/react-native/src/api/tier1/useQuickKDJ.ts
|
|
3
|
+
// Tier 1 API: KDJ Stochastic
|
|
4
|
+
// ============================================================================
|
|
5
|
+
|
|
6
|
+
import { useKDJ } from '../../hooks/useIndicators';
|
|
7
|
+
import type { CandleData } from '../../types';
|
|
8
|
+
|
|
9
|
+
export interface UseQuickKDJResult {
|
|
10
|
+
k: (number | null)[];
|
|
11
|
+
d: (number | null)[];
|
|
12
|
+
j: (number | null)[];
|
|
13
|
+
loading: boolean;
|
|
14
|
+
error?: string;
|
|
15
|
+
currentValues: {
|
|
16
|
+
k: number | null;
|
|
17
|
+
d: number | null;
|
|
18
|
+
j: number | null;
|
|
19
|
+
signal: 'buy' | 'sell' | 'neutral';
|
|
20
|
+
};
|
|
21
|
+
status: 'success' | 'error';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Quick KDJ Hook - Standard KDJ(9,3,3)
|
|
26
|
+
*
|
|
27
|
+
* @param candleData - Array of candle data with OHLC
|
|
28
|
+
* @returns { k, d, j, currentValues, loading, error, status }
|
|
29
|
+
*/
|
|
30
|
+
export const useQuickKDJ = (candleData: CandleData[]): UseQuickKDJResult => {
|
|
31
|
+
const { k, d, j, loading, status, error } = useKDJ(candleData, {
|
|
32
|
+
n: 9,
|
|
33
|
+
m1: 3,
|
|
34
|
+
m2: 3
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const validK = k.filter(v => v !== null && Number.isFinite(v)) as number[];
|
|
38
|
+
const validD = d.filter(v => v !== null && Number.isFinite(v)) as number[];
|
|
39
|
+
const validJ = j.filter(v => v !== null && Number.isFinite(v)) as number[];
|
|
40
|
+
|
|
41
|
+
const currentValues = {
|
|
42
|
+
k: validK.length > 0 ? validK[validK.length - 1] : null,
|
|
43
|
+
d: validD.length > 0 ? validD[validD.length - 1] : null,
|
|
44
|
+
j: validJ.length > 0 ? validJ[validJ.length - 1] : null,
|
|
45
|
+
signal: ((): 'buy' | 'sell' | 'neutral' => {
|
|
46
|
+
if (validK.length === 0 || validD.length === 0) return 'neutral';
|
|
47
|
+
const kVal = validK[validK.length - 1];
|
|
48
|
+
const dVal = validD[validD.length - 1];
|
|
49
|
+
return kVal > dVal && kVal < 80 ? 'buy' : kVal < dVal && kVal > 20 ? 'sell' : 'neutral';
|
|
50
|
+
})()
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return { k, d, j, loading, error, currentValues, status };
|
|
54
|
+
};
|
|
55
|
+
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// 📄 bindings/react-native/src/api/tier1/useQuickMA.ts
|
|
3
|
+
// Tier 1 API: Simple Moving Average
|
|
4
|
+
// Usage: const { data, loading, error } = useQuickMA(closes);
|
|
5
|
+
// ============================================================================
|
|
6
|
+
|
|
7
|
+
import { useMA } from '../../hooks/useIndicators';
|
|
8
|
+
|
|
9
|
+
export interface UseQuickMAResult {
|
|
10
|
+
data: (number | null)[];
|
|
11
|
+
loading: boolean;
|
|
12
|
+
error?: string;
|
|
13
|
+
lastValues: {
|
|
14
|
+
current: number | null;
|
|
15
|
+
previous: number | null;
|
|
16
|
+
trend: 'up' | 'down' | 'flat';
|
|
17
|
+
};
|
|
18
|
+
status: 'success' | 'error';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Quick Moving Average Hook - No configuration needed
|
|
23
|
+
*
|
|
24
|
+
* Default: MA20 (most common period for day traders)
|
|
25
|
+
*
|
|
26
|
+
* @param closes - Array of close prices
|
|
27
|
+
* @returns { data, loading, error, lastValues, status }
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* const { data, lastValues } = useQuickMA(closePrices);
|
|
31
|
+
* console.log(`MA20: ${lastValues.current}, Trend: ${lastValues.trend}`);
|
|
32
|
+
*/
|
|
33
|
+
export const useQuickMA = (closes: number[]): UseQuickMAResult => {
|
|
34
|
+
const { data, loading, status, error } = useMA(closes, {
|
|
35
|
+
period: 20,
|
|
36
|
+
type: 'simple'
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Calculate trend
|
|
40
|
+
const validData = data.filter(v => v !== null && Number.isFinite(v)) as number[];
|
|
41
|
+
const lastValues = {
|
|
42
|
+
current: validData.length > 0 ? validData[validData.length - 1] : null,
|
|
43
|
+
previous: validData.length > 1 ? validData[validData.length - 2] : null,
|
|
44
|
+
trend: ((): 'up' | 'down' | 'flat' => {
|
|
45
|
+
if (validData.length < 2) return 'flat';
|
|
46
|
+
const curr = validData[validData.length - 1];
|
|
47
|
+
const prev = validData[validData.length - 2];
|
|
48
|
+
return curr > prev ? 'up' : curr < prev ? 'down' : 'flat';
|
|
49
|
+
})()
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
data,
|
|
54
|
+
loading,
|
|
55
|
+
error,
|
|
56
|
+
lastValues,
|
|
57
|
+
status
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
|