react-native-vroom-chart 0.15.0 → 0.17.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/cpp/VroomChartHostObject.cpp +252 -1
- package/cpp/_core_include/vroom/vroom_chart.h +178 -4
- package/cpp/_core_src/atr.cpp +67 -0
- package/cpp/_core_src/atr.h +44 -0
- package/cpp/_core_src/atr_pane.cpp +162 -0
- package/cpp/_core_src/atr_pane.h +48 -0
- package/cpp/_core_src/candles.cpp +15 -14
- package/cpp/_core_src/chart.cpp +758 -200
- package/cpp/_core_src/chart.h +221 -3
- package/cpp/_core_src/chart_facade.cpp +236 -23
- package/cpp/_core_src/color_lerp.h +28 -0
- package/cpp/_core_src/fair_value_gaps.cpp +76 -0
- package/cpp/_core_src/fair_value_gaps.h +54 -0
- package/cpp/_core_src/fvg_overlay.cpp +262 -0
- package/cpp/_core_src/fvg_overlay.h +43 -0
- package/cpp/_core_src/ichimoku.cpp +65 -0
- package/cpp/_core_src/ichimoku.h +45 -0
- package/cpp/_core_src/labels.cpp +3 -0
- package/cpp/_core_src/line_morph.h +159 -0
- package/cpp/_core_src/loading_line.cpp +183 -0
- package/cpp/_core_src/loading_line.h +38 -0
- package/cpp/_core_src/loading_wave.h +140 -0
- package/cpp/_core_src/ma_overlay.cpp +273 -45
- package/cpp/_core_src/ma_overlay.h +64 -2
- package/cpp/_core_src/macd.cpp +24 -1
- package/cpp/_core_src/macd.h +16 -0
- package/cpp/_core_src/macd_pane.cpp +71 -62
- package/cpp/_core_src/macd_pane.h +13 -1
- package/cpp/_core_src/pane_series.h +169 -0
- package/cpp/_core_src/price_indicator.cpp +21 -7
- package/cpp/_core_src/price_indicator.h +11 -1
- package/cpp/_core_src/price_indicator_anim.h +81 -0
- package/cpp/_core_src/rsi.cpp +4 -0
- package/cpp/_core_src/rsi.h +7 -0
- package/cpp/_core_src/rsi_pane.cpp +85 -29
- package/cpp/_core_src/rsi_pane.h +11 -1
- package/cpp/_core_src/theme.cpp +5 -0
- package/cpp/_core_src/tip_geometry.h +55 -0
- package/cpp/_core_src/viewport.h +68 -0
- package/lib/index.d.mts +281 -3
- package/lib/index.d.ts +281 -3
- package/lib/index.js +292 -14
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +292 -14
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/VroomChart.tsx +33 -3
- package/src/dataTransitions.ts +47 -0
- package/src/index.ts +5 -0
- package/src/jsi.d.ts +139 -1
- package/src/theme.ts +1 -0
- package/src/types.ts +5 -0
- package/src/useChartCore.ts +402 -8
package/cpp/_core_src/chart.h
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
#pragma once
|
|
10
10
|
|
|
11
11
|
#include <chrono>
|
|
12
|
+
#include <cstddef>
|
|
12
13
|
#include <string>
|
|
13
14
|
#include <vector>
|
|
14
15
|
|
|
@@ -22,14 +23,33 @@
|
|
|
22
23
|
#include "include/core/SkRefCnt.h"
|
|
23
24
|
#pragma clang diagnostic pop
|
|
24
25
|
|
|
26
|
+
#include "fair_value_gaps.h"
|
|
25
27
|
#include "footprints_layout.h"
|
|
26
28
|
#include "labels.h"
|
|
29
|
+
#include "line_morph.h"
|
|
27
30
|
#include "price_format.h"
|
|
28
31
|
#include "theme.h"
|
|
29
32
|
#include "viewport.h"
|
|
30
33
|
|
|
31
34
|
class SkCanvas;
|
|
32
35
|
|
|
36
|
+
namespace vroom {
|
|
37
|
+
|
|
38
|
+
// Which indicator owns a below-chart pane. Panes are otherwise
|
|
39
|
+
// interchangeable: they are all the same height and stack in enable order.
|
|
40
|
+
enum class PaneKind { Rsi, Macd, Atr };
|
|
41
|
+
|
|
42
|
+
// Count of PaneKind values — the most panes that can be stacked at once.
|
|
43
|
+
constexpr int kMaxPanes = 3;
|
|
44
|
+
|
|
45
|
+
// One enabled pane and the sequence number it claimed when it was turned on.
|
|
46
|
+
struct IndicatorPane {
|
|
47
|
+
int order;
|
|
48
|
+
PaneKind kind;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
} // namespace vroom
|
|
52
|
+
|
|
33
53
|
struct VroomChart {
|
|
34
54
|
// --- bridge / lifecycle -------------------------------------------------
|
|
35
55
|
VroomCallbacks cb{};
|
|
@@ -72,6 +92,42 @@ struct VroomChart {
|
|
|
72
92
|
// is_animating_now keeps the host's redraw loop alive (see tip_pulse.h).
|
|
73
93
|
float tip_pulse_elapsed_s = 0.f;
|
|
74
94
|
|
|
95
|
+
// --- loading line -------------------------------------------------------
|
|
96
|
+
// See loading_line.h for the three stages this state drives.
|
|
97
|
+
//
|
|
98
|
+
// Authoritative, not inferred: the host tells us it's loading *and* that it
|
|
99
|
+
// has no data, because an empty `candles` alone can't be trusted here. The
|
|
100
|
+
// hosts' data effects skip pushing an empty array (it would read as "hold
|
|
101
|
+
// the last frame"), so a chart mid-asset-switch can be loading while still
|
|
102
|
+
// holding the previous asset's bars — inferring from emptiness would show
|
|
103
|
+
// that stale series as if it were the new one's.
|
|
104
|
+
//
|
|
105
|
+
// True for stages 1 and 2 both: the line stands in for the chart until the
|
|
106
|
+
// candles actually take over in stage 3.
|
|
107
|
+
bool loading = false;
|
|
108
|
+
// Whether the wave travels. Cleared for reduced motion, which both freezes
|
|
109
|
+
// the line at phase 0 and keeps is_animating_now from pinning a host loop.
|
|
110
|
+
bool loading_animate = true;
|
|
111
|
+
// Phase of the wave, in seconds, advanced by begin_frame like the tip pulse
|
|
112
|
+
// above and wrapped for the same reason.
|
|
113
|
+
float loading_elapsed_s = 0.f;
|
|
114
|
+
// Fades the line in on arrival, so a chart that resolves instantly from
|
|
115
|
+
// cache doesn't flash a placeholder.
|
|
116
|
+
float loading_fade_in = 0.f;
|
|
117
|
+
|
|
118
|
+
// The line's morph vertices, left to right, captured when the data lands.
|
|
119
|
+
// Empty means stage 1 — nothing to morph toward yet — which is what
|
|
120
|
+
// loading_line::draw switches on.
|
|
121
|
+
std::vector<vroom::LinePoint> loading_line;
|
|
122
|
+
// Stage 2's progress, 0 = the frozen sine, 1 = through the candle centres.
|
|
123
|
+
// Parked at 1 when no morph is running.
|
|
124
|
+
float loading_line_t = 1.f;
|
|
125
|
+
// Set for stage 3, where the line rides `interval_morph_t` out on the same
|
|
126
|
+
// clock as the candles growing out of it. A flag rather than its own float
|
|
127
|
+
// because the two have to finish together to avoid a line left hanging over
|
|
128
|
+
// a settled chart.
|
|
129
|
+
bool loading_line_revealing = false;
|
|
130
|
+
|
|
75
131
|
// Interval morph: the outgoing candle geometry captured when a timeframe
|
|
76
132
|
// switch begins, indexed from the right of the visible slice (slot 0 =
|
|
77
133
|
// newest). `interval_morph_fade` is the host's choice at capture time:
|
|
@@ -82,6 +138,19 @@ struct VroomChart {
|
|
|
82
138
|
std::vector<vroom::CandleSnapshot> morph_from;
|
|
83
139
|
float interval_morph_t = 1.f; // 1 = not morphing
|
|
84
140
|
bool interval_morph_fade = false;
|
|
141
|
+
// Set when the capture came from a live update rather than a timeframe
|
|
142
|
+
// switch. Same slot machinery, but the axis holds still: a stream morph
|
|
143
|
+
// only reshapes the last bar, and the ticks it sits between don't move, so
|
|
144
|
+
// running them through the interval envelope would flash the whole axis on
|
|
145
|
+
// every tick (see labels::interval_phase).
|
|
146
|
+
bool morph_is_stream = false;
|
|
147
|
+
// The outgoing shape of every indicator series that was on screen, captured
|
|
148
|
+
// alongside the candles and keyed by identity so a toggle landing in the
|
|
149
|
+
// same commit as the switch can't pair two different lines (see
|
|
150
|
+
// line_morph.h). A timeframe switch invalidates every indicator cache at
|
|
151
|
+
// once, so without this the lines would pop to their new values while the
|
|
152
|
+
// candles under them reshape.
|
|
153
|
+
std::vector<vroom::LineMorph> morph_lines;
|
|
85
154
|
// The pre-switch price scale and time window. The candle capture above is
|
|
86
155
|
// normalized against these, and the axes keep rendering their old ticks from
|
|
87
156
|
// them while fading out (see labels::interval_phase), so a label is never
|
|
@@ -123,7 +192,8 @@ struct VroomChart {
|
|
|
123
192
|
VroomRSI rsi{0, 14, 70.0, 30.0, 14, 0, 1,
|
|
124
193
|
0u, -1.f, 1, // RSI line
|
|
125
194
|
0u, -1.f, // trendline
|
|
126
|
-
0u, 1
|
|
195
|
+
0u, 1, // band rules
|
|
196
|
+
1}; // extreme shading
|
|
127
197
|
std::vector<double> rsi_cache; // RSI per candle (NaN where undefined)
|
|
128
198
|
std::vector<double> rsi_ma_cache; // MA of rsi_cache (empty if MA off)
|
|
129
199
|
bool rsi_dirty = true;
|
|
@@ -147,11 +217,23 @@ struct VroomChart {
|
|
|
147
217
|
// default auto-fit amplitude; >1 zooms in, <1 zooms out. Anchored at zero.
|
|
148
218
|
double macd_y_scale = 1.0;
|
|
149
219
|
|
|
220
|
+
// ATR, drawn in its own pane. atr_cache is aligned to `candles` (NaN
|
|
221
|
+
// warmup), recomputed lazily by ensure_atr() when atr_dirty.
|
|
222
|
+
// Defaults: 14-period true range under Wilder smoothing, style fields on
|
|
223
|
+
// their inherit sentinel.
|
|
224
|
+
VroomATR atr{0, 14, 0, 0u, -1.f};
|
|
225
|
+
std::vector<double> atr_cache;
|
|
226
|
+
bool atr_dirty = true;
|
|
227
|
+
// User y-axis zoom for the ATR pane (drag on its y-axis strip). 1.0 = the
|
|
228
|
+
// default 0..peak fit; >1 zooms in, <1 zooms out. Anchored at the baseline.
|
|
229
|
+
double atr_y_scale = 1.0;
|
|
230
|
+
|
|
150
231
|
// Stacking order for the indicator panes: each indicator gets the next
|
|
151
232
|
// sequence number on its off->on transition, so the most recently enabled
|
|
152
233
|
// pane sorts last (bottom). -1 = not currently enabled.
|
|
153
234
|
int rsi_order = -1;
|
|
154
235
|
int macd_order = -1;
|
|
236
|
+
int atr_order = -1;
|
|
155
237
|
int pane_seq = 0;
|
|
156
238
|
|
|
157
239
|
// Moving-average overlay lines (SMA/EMA) drawn on the price pane. Not panes
|
|
@@ -183,6 +265,46 @@ struct VroomChart {
|
|
|
183
265
|
std::vector<double> bb_lower_cache;
|
|
184
266
|
bool bollinger_dirty = true;
|
|
185
267
|
|
|
268
|
+
// Ichimoku overlay (price pane; no pane reserved). Caches aligned to
|
|
269
|
+
// `candles` (NaN warmup) and indexed by the bar each value was computed
|
|
270
|
+
// from — displacement is applied when drawing, so the caches survive a
|
|
271
|
+
// change to it. Recomputed lazily by ensure_ichimoku() when ichimoku_dirty.
|
|
272
|
+
// Defaults: the standard 9/26/52/26, blue tenkan / red kijun, green span A
|
|
273
|
+
// over orange span B, teal chikou, 15% cloud.
|
|
274
|
+
VroomIchimoku ichimoku{0, 9, 26, 52, 26,
|
|
275
|
+
0xff2962ff, 1.f, 1, // tenkan: blue
|
|
276
|
+
0xffef5350, 1.f, 1, // kijun: red
|
|
277
|
+
0xff26a69a, 1.f, 1, // senkou A: green
|
|
278
|
+
0xffff6d00, 1.f, 1, // senkou B: orange
|
|
279
|
+
0xff00bcd4, 1.f, 1, // chikou: teal
|
|
280
|
+
1, 0xff26a69a, 0xffef5350, 0.15f};
|
|
281
|
+
std::vector<double> ich_tenkan_cache;
|
|
282
|
+
std::vector<double> ich_kijun_cache;
|
|
283
|
+
std::vector<double> ich_senkou_a_cache;
|
|
284
|
+
std::vector<double> ich_senkou_b_cache;
|
|
285
|
+
std::vector<double> ich_chikou_cache;
|
|
286
|
+
bool ichimoku_dirty = true;
|
|
287
|
+
|
|
288
|
+
// Fair Value Gap overlay (price pane; no pane reserved). The cache holds the
|
|
289
|
+
// detected imbalances in absolute time/price, oldest first, so box geometry
|
|
290
|
+
// and style are free to change without re-scanning — only the detection
|
|
291
|
+
// inputs below dirty it. Recomputed lazily by ensure_fvg() when fvg_dirty.
|
|
292
|
+
//
|
|
293
|
+
// Defaults: 300 bars back, close-settled fills, deleted once filled, 20-slot
|
|
294
|
+
// boxes in green/red at 15%, solid 1px border, labels on.
|
|
295
|
+
VroomFairValueGaps fvg{0, 300, 0, 0, 1, 0, 20,
|
|
296
|
+
0xff26a69a, 0xffef5350, 0.15f,
|
|
297
|
+
1, 0, 1.f, 0xff26a69a, 0xffef5350,
|
|
298
|
+
1, nullptr, 10, 0u, 0.f,
|
|
299
|
+
0, 0xff26a69a, 0xffef5350, nullptr};
|
|
300
|
+
// Owns the label texts, so the caller may free theirs as soon as the setter
|
|
301
|
+
// returns. `fvg.label` and `fvg.inverse_label` are left null and these are
|
|
302
|
+
// what the renderer reads.
|
|
303
|
+
std::string fvg_label = "FVG";
|
|
304
|
+
std::string fvg_inverse_label = "iFVG";
|
|
305
|
+
std::vector<vroom::fvg::Gap> fvg_cache;
|
|
306
|
+
bool fvg_dirty = true;
|
|
307
|
+
|
|
186
308
|
// Volume bars (price pane, under the candles). On by default with every
|
|
187
309
|
// style field left on its inherit sentinel, so an untouched chart looks
|
|
188
310
|
// exactly as it did before the config existed. No cache — bar heights come
|
|
@@ -348,6 +470,69 @@ struct VroomChart {
|
|
|
348
470
|
// indicator is enabled.
|
|
349
471
|
void ensure_bollinger();
|
|
350
472
|
|
|
473
|
+
// Recomputes the Ichimoku caches when ichimoku_dirty and the indicator is
|
|
474
|
+
// enabled.
|
|
475
|
+
void ensure_ichimoku();
|
|
476
|
+
|
|
477
|
+
// Redetects the Fair Value Gaps when fvg_dirty and the indicator is enabled.
|
|
478
|
+
void ensure_fvg();
|
|
479
|
+
|
|
480
|
+
// Recomputes the ATR cache when atr_dirty and the indicator is enabled.
|
|
481
|
+
void ensure_atr();
|
|
482
|
+
|
|
483
|
+
// Fills morph_lines with the outgoing shape of every enabled indicator,
|
|
484
|
+
// normalized the way morph_from is. Called by begin_interval_morph while
|
|
485
|
+
// the pre-switch candles and caches are still resident — after the swap
|
|
486
|
+
// there is nothing left to capture. `range` is the visible slice and
|
|
487
|
+
// `bounds` the price band the capture is taken against, both shared with
|
|
488
|
+
// the candle capture so the two land on the same pixels.
|
|
489
|
+
void capture_morph_lines(const vroom::Layout& lay,
|
|
490
|
+
const vroom::PriceBounds& bounds,
|
|
491
|
+
vroom::IndexRange range, int64_t window_ms);
|
|
492
|
+
|
|
493
|
+
// Source indices whose *displaced* plot time lands in the visible window,
|
|
494
|
+
// for an Ichimoku span drawn at `time_ms + shift_ms`. A bar of padding
|
|
495
|
+
// either side keeps a run reaching the pane edge instead of stopping at the
|
|
496
|
+
// last bar strictly inside it. Shared by the cloud, the lines and the
|
|
497
|
+
// interval-morph capture so all three slice the same bars.
|
|
498
|
+
vroom::IndexRange ichimoku_source_range(int64_t shift_ms) const;
|
|
499
|
+
|
|
500
|
+
// The enabled panes written to `out` top to bottom, returning how many.
|
|
501
|
+
// Both the draw pass and the y-axis hit test read this, so the stack they
|
|
502
|
+
// see can't drift apart.
|
|
503
|
+
int indicator_panes(vroom::IndicatorPane out[vroom::kMaxPanes]) const;
|
|
504
|
+
|
|
505
|
+
// Draws the pane stack into the band below the candles, starting at
|
|
506
|
+
// `pane_top`. Shared by the settled draw and the interval-morph fade, which
|
|
507
|
+
// paint the panes at different points in the z-order.
|
|
508
|
+
void draw_indicator_panes(SkCanvas* canvas, const vroom::Layout& lay,
|
|
509
|
+
const VroomCandle* visible, std::size_t n,
|
|
510
|
+
std::size_t first, int64_t window_ms,
|
|
511
|
+
float candle_right, float pane_top,
|
|
512
|
+
bool use_capture, float morph_t);
|
|
513
|
+
|
|
514
|
+
// The price-pane indicator overlays, split where the candles sit in the
|
|
515
|
+
// z-order: the Bollinger band and Ichimoku cloud go behind them, the moving
|
|
516
|
+
// averages, VWAP, Bollinger and Ichimoku lines over them.
|
|
517
|
+
//
|
|
518
|
+
// `use_capture` and `morph_t` carry the interval morph, on the same terms
|
|
519
|
+
// the candles take it. A transform pairs each series with its capture (see
|
|
520
|
+
// morph_lines) and eases toward the new shape. A fade's outgoing half
|
|
521
|
+
// passes n = 0 with morph_t = 0, replaying the capture alone. A settled
|
|
522
|
+
// frame passes no capture at all.
|
|
523
|
+
void draw_overlay_fills(SkCanvas* canvas, const vroom::Layout& lay,
|
|
524
|
+
const vroom::PriceBounds& bounds,
|
|
525
|
+
const VroomCandle* visible, std::size_t n,
|
|
526
|
+
std::size_t first, int64_t window_ms,
|
|
527
|
+
float candle_right, float candle_area_h,
|
|
528
|
+
bool use_capture, float morph_t);
|
|
529
|
+
void draw_overlay_lines(SkCanvas* canvas, const vroom::Layout& lay,
|
|
530
|
+
const vroom::PriceBounds& bounds,
|
|
531
|
+
const VroomCandle* visible, std::size_t n,
|
|
532
|
+
std::size_t first, int64_t window_ms,
|
|
533
|
+
float candle_right, float candle_area_h,
|
|
534
|
+
bool use_capture, float morph_t);
|
|
535
|
+
|
|
351
536
|
// The main drawing pass. Calls into the labels and candles modules, and owns
|
|
352
537
|
// the per-frame animation clock (see begin_frame) so every host gets it —
|
|
353
538
|
// the web build draws straight through vroom_chart_draw rather than the
|
|
@@ -359,6 +544,38 @@ struct VroomChart {
|
|
|
359
544
|
// draw_chart.
|
|
360
545
|
void begin_frame();
|
|
361
546
|
|
|
547
|
+
// Enters or leaves the loading line. `animate` false pins it still for
|
|
548
|
+
// reduced motion. Entering restarts the phase and the fade-in; leaving
|
|
549
|
+
// outright (rather than through the two calls below) drops the line with no
|
|
550
|
+
// hand-off, which is what an error or a cancelled fetch wants.
|
|
551
|
+
void set_loading(bool on, bool animate);
|
|
552
|
+
|
|
553
|
+
// Stage 2. Call *after* pushing the real candles: it needs them to know
|
|
554
|
+
// where the line is heading. Freezes the sine at its current phase and
|
|
555
|
+
// pairs each vertex with the vertical centre of the candle that will occupy
|
|
556
|
+
// that column, then hands `loading_line_t` to the host to drive 0 → 1.
|
|
557
|
+
//
|
|
558
|
+
// Freezing rather than letting the wave run underneath is deliberate — a
|
|
559
|
+
// moving source makes the morph read as two animations fighting instead of
|
|
560
|
+
// one shape resolving.
|
|
561
|
+
void begin_loading_morph();
|
|
562
|
+
|
|
563
|
+
// The visible slice and price bounds the hand-off aims at, as draw_chart
|
|
564
|
+
// would resolve them. `n == 0` when there is nothing to hand off to.
|
|
565
|
+
struct LoadingTarget {
|
|
566
|
+
const ::VroomCandle* visible = nullptr;
|
|
567
|
+
std::size_t n = 0;
|
|
568
|
+
vroom::PriceBounds bounds{};
|
|
569
|
+
};
|
|
570
|
+
LoadingTarget loading_target() const;
|
|
571
|
+
|
|
572
|
+
// Stage 3. Captures every candle collapsed onto its own vertical centre at
|
|
573
|
+
// zero alpha and hands it to the interval-morph machinery, so the existing
|
|
574
|
+
// slot lerp grows each bar outward from the line while candles::draw blends
|
|
575
|
+
// its colour up out of nothing. Also releases `loading`, letting the axes,
|
|
576
|
+
// price badge and panes come back.
|
|
577
|
+
void begin_loading_reveal();
|
|
578
|
+
|
|
362
579
|
// True when the line tip's pulse ring is on screen and looping. Gated on
|
|
363
580
|
// line mode and on having data, so a chart that isn't showing the ring can
|
|
364
581
|
// still go idle.
|
|
@@ -368,7 +585,8 @@ struct VroomChart {
|
|
|
368
585
|
// SkPictureRecorder.
|
|
369
586
|
void rebuild_chart_picture();
|
|
370
587
|
|
|
371
|
-
// True if any axis label is mid-fade,
|
|
372
|
-
// the JS-side animation loop to know
|
|
588
|
+
// True if any axis label is mid-fade, the tip pulse is running, or the
|
|
589
|
+
// loading skeleton is waving. Used by the JS-side animation loop to know
|
|
590
|
+
// when to keep ticking.
|
|
373
591
|
bool is_animating_now() const;
|
|
374
592
|
};
|