react-native-vroom-chart 0.15.0 → 0.16.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 +171 -1
- package/cpp/_core_include/vroom/vroom_chart.h +137 -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/chart.cpp +461 -172
- package/cpp/_core_src/chart.h +150 -1
- package/cpp/_core_src/chart_facade.cpp +209 -23
- 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/ma_overlay.cpp +259 -36
- package/cpp/_core_src/ma_overlay.h +57 -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/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/viewport.h +35 -0
- package/lib/index.d.mts +251 -3
- package/lib/index.d.ts +251 -3
- package/lib/index.js +224 -6
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +224 -6
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/VroomChart.tsx +21 -3
- package/src/dataTransitions.ts +47 -0
- package/src/index.ts +5 -0
- package/src/jsi.d.ts +97 -1
- package/src/types.ts +5 -0
- package/src/useChartCore.ts +284 -5
package/lib/index.mjs
CHANGED
|
@@ -71,6 +71,13 @@ function classifyTransition(prev, next, seriesKeyChanged) {
|
|
|
71
71
|
const endsTogether = Math.abs(nextEnd - prevEnd) <= MAX_END_DRIFT_STEPS * Math.max(prevStep, nextStep);
|
|
72
72
|
return closeRatio <= MAX_SAME_ASSET_CLOSE_RATIO && endsTogether ? "timeframe" : "reset";
|
|
73
73
|
}
|
|
74
|
+
function classifyStream(prev, next) {
|
|
75
|
+
if (prev.length === 0 || next.length === 0) return "tick";
|
|
76
|
+
return next[next.length - 1].timeMs > prev[prev.length - 1].timeMs ? "append" : "tick";
|
|
77
|
+
}
|
|
78
|
+
function isPinnedToLatest(window, lastMs, stepMs) {
|
|
79
|
+
return window.endMs >= lastMs + stepMs;
|
|
80
|
+
}
|
|
74
81
|
function timeframeWindow(oldWindow, oldStepMs, oldLastMs, newStepMs, newLastMs) {
|
|
75
82
|
const slots = (oldWindow.endMs - oldWindow.startMs) / oldStepMs;
|
|
76
83
|
const offsetRaw = (oldWindow.endMs - oldLastMs) / oldStepMs;
|
|
@@ -216,6 +223,7 @@ var MA_SOURCES = [
|
|
|
216
223
|
"hlc3",
|
|
217
224
|
"ohlc4"
|
|
218
225
|
];
|
|
226
|
+
var ATR_SMOOTHINGS = ["rma", "sma", "ema"];
|
|
219
227
|
var inheritColor = (v) => (v != null ? parseColor(v) : null) ?? 0;
|
|
220
228
|
function overlayToNumeric(o) {
|
|
221
229
|
const srcIdx = o.source ? MA_SOURCES.indexOf(o.source) : 0;
|
|
@@ -242,7 +250,8 @@ function rsiToSpec(cfg) {
|
|
|
242
250
|
maColor: inheritColor(cfg?.maColor),
|
|
243
251
|
maWidth: cfg?.maWidth ?? -1,
|
|
244
252
|
bandColor: inheritColor(cfg?.bandColor),
|
|
245
|
-
bandsVisible: cfg?.bandsVisible ?? true
|
|
253
|
+
bandsVisible: cfg?.bandsVisible ?? true,
|
|
254
|
+
extremeFill: cfg?.extremeFill ?? true
|
|
246
255
|
};
|
|
247
256
|
}
|
|
248
257
|
function vwapToSpec(cfg) {
|
|
@@ -273,6 +282,79 @@ function bollingerToSpec(cfg) {
|
|
|
273
282
|
fillOpacity: cfg?.fillOpacity ?? 0.1
|
|
274
283
|
};
|
|
275
284
|
}
|
|
285
|
+
var DEFAULT_ICH_GREEN = 4280723098;
|
|
286
|
+
var DEFAULT_ICH_RED = 4293874512;
|
|
287
|
+
var DEFAULT_ICH_BLUE = 4280902399;
|
|
288
|
+
var DEFAULT_ICH_ORANGE = 4294929664;
|
|
289
|
+
var DEFAULT_ICH_TEAL = 4278238420;
|
|
290
|
+
function ichimokuToSpec(cfg) {
|
|
291
|
+
const color = (v, fallback) => (v != null ? parseColor(v) : null) ?? fallback;
|
|
292
|
+
return {
|
|
293
|
+
enabled: cfg?.enabled ?? false,
|
|
294
|
+
tenkanPeriod: cfg?.tenkanPeriod ?? 9,
|
|
295
|
+
kijunPeriod: cfg?.kijunPeriod ?? 26,
|
|
296
|
+
senkouBPeriod: cfg?.senkouBPeriod ?? 52,
|
|
297
|
+
displacement: cfg?.displacement ?? 26,
|
|
298
|
+
tenkanColor: color(cfg?.tenkanColor, DEFAULT_ICH_BLUE),
|
|
299
|
+
tenkanWidth: cfg?.tenkanWidth ?? 1,
|
|
300
|
+
tenkanEnabled: cfg?.tenkanVisible ?? true,
|
|
301
|
+
kijunColor: color(cfg?.kijunColor, DEFAULT_ICH_RED),
|
|
302
|
+
kijunWidth: cfg?.kijunWidth ?? 1,
|
|
303
|
+
kijunEnabled: cfg?.kijunVisible ?? true,
|
|
304
|
+
senkouAColor: color(cfg?.senkouAColor, DEFAULT_ICH_GREEN),
|
|
305
|
+
senkouAWidth: cfg?.senkouAWidth ?? 1,
|
|
306
|
+
senkouAEnabled: cfg?.senkouAVisible ?? true,
|
|
307
|
+
senkouBColor: color(cfg?.senkouBColor, DEFAULT_ICH_ORANGE),
|
|
308
|
+
senkouBWidth: cfg?.senkouBWidth ?? 1,
|
|
309
|
+
senkouBEnabled: cfg?.senkouBVisible ?? true,
|
|
310
|
+
chikouColor: color(cfg?.chikouColor, DEFAULT_ICH_TEAL),
|
|
311
|
+
chikouWidth: cfg?.chikouWidth ?? 1,
|
|
312
|
+
chikouEnabled: cfg?.chikouVisible ?? true,
|
|
313
|
+
cloudEnabled: cfg?.cloudVisible ?? true,
|
|
314
|
+
bullishCloudColor: color(cfg?.bullishCloudColor, DEFAULT_ICH_GREEN),
|
|
315
|
+
bearishCloudColor: color(cfg?.bearishCloudColor, DEFAULT_ICH_RED),
|
|
316
|
+
cloudOpacity: cfg?.cloudOpacity ?? 0.15
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
var DEFAULT_FVG_GREEN = 4280723098;
|
|
320
|
+
var DEFAULT_FVG_RED = 4293874512;
|
|
321
|
+
var FVG_FILL_TYPES = ["close", "wick"];
|
|
322
|
+
var FVG_BORDER_STYLES = ["solid", "dotted", "dashed"];
|
|
323
|
+
function fvgToSpec(cfg) {
|
|
324
|
+
const color = (v, fallback) => (v != null ? parseColor(v) : null) ?? fallback;
|
|
325
|
+
const bullish = color(cfg?.bullishColor, DEFAULT_FVG_GREEN);
|
|
326
|
+
const bearish = color(cfg?.bearishColor, DEFAULT_FVG_RED);
|
|
327
|
+
return {
|
|
328
|
+
enabled: cfg?.enabled ?? false,
|
|
329
|
+
maxBarsBack: cfg?.maxBarsBack ?? 300,
|
|
330
|
+
waitForClose: cfg?.waitForClose ?? false,
|
|
331
|
+
fillType: Math.max(0, FVG_FILL_TYPES.indexOf(cfg?.fillType ?? "close")),
|
|
332
|
+
deleteAfterFill: cfg?.deleteAfterFill ?? true,
|
|
333
|
+
extendBoxes: cfg?.extendBoxes ?? false,
|
|
334
|
+
boxLength: cfg?.boxLength ?? 20,
|
|
335
|
+
bullishColor: bullish,
|
|
336
|
+
bearishColor: bearish,
|
|
337
|
+
opacity: cfg?.opacity ?? 0.15,
|
|
338
|
+
borderEnabled: cfg?.borderVisible ?? true,
|
|
339
|
+
borderStyle: Math.max(
|
|
340
|
+
0,
|
|
341
|
+
FVG_BORDER_STYLES.indexOf(cfg?.borderStyle ?? "solid")
|
|
342
|
+
),
|
|
343
|
+
borderWidth: cfg?.borderWidth ?? 1,
|
|
344
|
+
bullishBorderColor: color(cfg?.bullishBorderColor, bullish),
|
|
345
|
+
bearishBorderColor: color(cfg?.bearishBorderColor, bearish),
|
|
346
|
+
labelsEnabled: cfg?.showLabels ?? true,
|
|
347
|
+
label: cfg?.label ?? "FVG",
|
|
348
|
+
labelDistance: cfg?.labelDistance ?? 10,
|
|
349
|
+
// Alpha 0 is the core's "inherit the border color" sentinel.
|
|
350
|
+
labelColor: color(cfg?.labelColor, 0),
|
|
351
|
+
labelFontSize: cfg?.labelFontSize ?? 0,
|
|
352
|
+
showInverse: cfg?.showInverse ?? false,
|
|
353
|
+
inverseBullishColor: color(cfg?.inverseBullishColor, bullish),
|
|
354
|
+
inverseBearishColor: color(cfg?.inverseBearishColor, bearish),
|
|
355
|
+
inverseLabel: cfg?.inverseLabel ?? "iFVG"
|
|
356
|
+
};
|
|
357
|
+
}
|
|
276
358
|
function macdToSpec(cfg) {
|
|
277
359
|
const srcIdx = cfg?.source ? MA_SOURCES.indexOf(cfg.source) : 0;
|
|
278
360
|
return {
|
|
@@ -298,6 +380,15 @@ function macdToSpec(cfg) {
|
|
|
298
380
|
zeroVisible: cfg?.zeroLineVisible ?? true
|
|
299
381
|
};
|
|
300
382
|
}
|
|
383
|
+
function atrToSpec(cfg) {
|
|
384
|
+
return {
|
|
385
|
+
enabled: cfg?.enabled ?? false,
|
|
386
|
+
period: cfg?.period ?? 14,
|
|
387
|
+
smoothing: Math.max(0, ATR_SMOOTHINGS.indexOf(cfg?.smoothing ?? "rma")),
|
|
388
|
+
lineColor: inheritColor(cfg?.lineColor),
|
|
389
|
+
lineWidth: cfg?.lineWidth ?? -1
|
|
390
|
+
};
|
|
391
|
+
}
|
|
301
392
|
function volumeToSpec(cfg) {
|
|
302
393
|
return {
|
|
303
394
|
enabled: cfg?.enabled ?? true,
|
|
@@ -368,23 +459,37 @@ function ensureInstalled() {
|
|
|
368
459
|
}
|
|
369
460
|
installed = true;
|
|
370
461
|
}
|
|
371
|
-
function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType, theme, rsi, macd, movingAverages, vwap, bollingerBands, volume, priceLines, footprints, transition) {
|
|
462
|
+
function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType, theme, rsi, macd, atr, movingAverages, vwap, bollingerBands, ichimoku, fairValueGaps, volume, priceLines, footprints, transition) {
|
|
372
463
|
const handleRef = useRef(null);
|
|
373
464
|
const defaultWidthAppliedRef = useRef(false);
|
|
374
465
|
const volumeCollapseRef = useRef(null);
|
|
375
466
|
const prevDataRef = useRef(null);
|
|
376
467
|
const intervalMorphRaf = useRef(null);
|
|
468
|
+
const streamRaf = useRef(null);
|
|
469
|
+
const streamWindowRef = useRef(null);
|
|
470
|
+
const streamMorphRef = useRef(false);
|
|
377
471
|
const [picture, setPicture] = useState(null);
|
|
378
472
|
if (!handleRef.current && size.width > 0 && size.height > 0) {
|
|
379
473
|
ensureInstalled();
|
|
380
474
|
handleRef.current = globalThis.VroomChartJSI.create();
|
|
381
475
|
}
|
|
382
|
-
const animRef = useRef({
|
|
476
|
+
const animRef = useRef({
|
|
477
|
+
ms: 300,
|
|
478
|
+
easing: void 0,
|
|
479
|
+
reduceMotion: false,
|
|
480
|
+
interval: "transform",
|
|
481
|
+
stream: "none",
|
|
482
|
+
streamMs: 150
|
|
483
|
+
});
|
|
383
484
|
animRef.current = {
|
|
384
485
|
ms: Math.max(0, transition?.transitionMs ?? 300),
|
|
385
486
|
easing: transition?.transitionEasing,
|
|
386
487
|
reduceMotion: transition?.reduceMotion ?? false,
|
|
387
|
-
interval: transition?.intervalTransition === "fade" ? "fade" : "transform"
|
|
488
|
+
interval: transition?.intervalTransition === "fade" ? "fade" : "transform",
|
|
489
|
+
stream: transition?.streamTransition === "transform" ? "transform" : "none",
|
|
490
|
+
// Shorter than transitionMs by default: ticks can land faster than a 300ms
|
|
491
|
+
// curve, and every one that does interrupts the last.
|
|
492
|
+
streamMs: Math.max(0, transition?.streamTransitionMs ?? 150)
|
|
388
493
|
};
|
|
389
494
|
const onFrameRef = useRef(transition?.onFrame);
|
|
390
495
|
onFrameRef.current = transition?.onFrame;
|
|
@@ -408,12 +513,70 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
408
513
|
};
|
|
409
514
|
intervalMorphRaf.current = requestAnimationFrame(step);
|
|
410
515
|
}, []);
|
|
516
|
+
const settleStream = useCallback((keepMorph = false) => {
|
|
517
|
+
if (streamRaf.current != null) {
|
|
518
|
+
cancelAnimationFrame(streamRaf.current);
|
|
519
|
+
streamRaf.current = null;
|
|
520
|
+
}
|
|
521
|
+
const h = handleRef.current;
|
|
522
|
+
const target = streamWindowRef.current;
|
|
523
|
+
streamWindowRef.current = null;
|
|
524
|
+
if (target) h?.setVisibleRange(target.startMs, target.endMs);
|
|
525
|
+
if (streamMorphRef.current && !keepMorph) {
|
|
526
|
+
streamMorphRef.current = false;
|
|
527
|
+
h?.setIntervalMorph(1);
|
|
528
|
+
}
|
|
529
|
+
}, []);
|
|
530
|
+
const startStreamAnim = useCallback(
|
|
531
|
+
(h, morphing, window) => {
|
|
532
|
+
const { streamMs, easing } = animRef.current;
|
|
533
|
+
let from = window ? h.getVisibleRange() : null;
|
|
534
|
+
let applied = null;
|
|
535
|
+
streamWindowRef.current = window;
|
|
536
|
+
streamMorphRef.current = morphing;
|
|
537
|
+
const start = performance.now();
|
|
538
|
+
const step = (now) => {
|
|
539
|
+
if (from && applied) {
|
|
540
|
+
const now_w = h.getVisibleRange();
|
|
541
|
+
if (now_w.startMs !== applied.startMs || now_w.endMs !== applied.endMs) {
|
|
542
|
+
from = null;
|
|
543
|
+
streamWindowRef.current = null;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
const p = Math.min(1, (now - start) / streamMs);
|
|
547
|
+
const e = p < 1 ? ease(easing, p) : 1;
|
|
548
|
+
if (morphing) h.setIntervalMorph(e);
|
|
549
|
+
if (from && window) {
|
|
550
|
+
applied = {
|
|
551
|
+
startMs: Math.round(from.startMs + (window.startMs - from.startMs) * e),
|
|
552
|
+
endMs: Math.round(from.endMs + (window.endMs - from.endMs) * e)
|
|
553
|
+
};
|
|
554
|
+
h.setVisibleRange(applied.startMs, applied.endMs);
|
|
555
|
+
}
|
|
556
|
+
const pic = h.render();
|
|
557
|
+
if (pic) onFrameRef.current?.(pic);
|
|
558
|
+
if (p < 1) {
|
|
559
|
+
streamRaf.current = requestAnimationFrame(step);
|
|
560
|
+
} else {
|
|
561
|
+
streamRaf.current = null;
|
|
562
|
+
streamWindowRef.current = null;
|
|
563
|
+
streamMorphRef.current = false;
|
|
564
|
+
}
|
|
565
|
+
};
|
|
566
|
+
streamRaf.current = requestAnimationFrame(step);
|
|
567
|
+
},
|
|
568
|
+
[]
|
|
569
|
+
);
|
|
411
570
|
useEffect(() => {
|
|
412
571
|
return () => {
|
|
413
572
|
if (intervalMorphRaf.current != null) {
|
|
414
573
|
cancelAnimationFrame(intervalMorphRaf.current);
|
|
415
574
|
intervalMorphRaf.current = null;
|
|
416
575
|
}
|
|
576
|
+
if (streamRaf.current != null) {
|
|
577
|
+
cancelAnimationFrame(streamRaf.current);
|
|
578
|
+
streamRaf.current = null;
|
|
579
|
+
}
|
|
417
580
|
};
|
|
418
581
|
}, []);
|
|
419
582
|
const explicit = visibleRange != null;
|
|
@@ -422,9 +585,12 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
422
585
|
const themeKey = theme ? JSON.stringify(theme) : "";
|
|
423
586
|
const rsiKey = rsi ? JSON.stringify(rsi) : "";
|
|
424
587
|
const macdKey = macd ? JSON.stringify(macd) : "";
|
|
588
|
+
const atrKey = atr ? JSON.stringify(atr) : "";
|
|
425
589
|
const maKey = movingAverages ? JSON.stringify(movingAverages) : "";
|
|
426
590
|
const vwapKey = vwap ? JSON.stringify(vwap) : "";
|
|
427
591
|
const bollingerKey = bollingerBands ? JSON.stringify(bollingerBands) : "";
|
|
592
|
+
const ichimokuKey = ichimoku ? JSON.stringify(ichimoku) : "";
|
|
593
|
+
const fvgKey = fairValueGaps ? JSON.stringify(fairValueGaps) : "";
|
|
428
594
|
const volumeKey = volume ? JSON.stringify(volume) : "";
|
|
429
595
|
const priceLinesKey = priceLines ? JSON.stringify(priceLines) : "";
|
|
430
596
|
const footprintsKey = footprints ? JSON.stringify(footprints) : "";
|
|
@@ -432,6 +598,7 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
432
598
|
const h = handleRef.current;
|
|
433
599
|
if (!h) return;
|
|
434
600
|
h.setSize(size.width, size.height, size.pxRatio ?? 1);
|
|
601
|
+
h.setIchimoku(ichimokuToSpec(ichimoku));
|
|
435
602
|
if (!defaultWidthAppliedRef.current && !explicit && defaultCandleWidth != null && defaultCandleWidth > 0) {
|
|
436
603
|
h.setDefaultCandleWidth(defaultCandleWidth);
|
|
437
604
|
defaultWidthAppliedRef.current = true;
|
|
@@ -444,6 +611,36 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
444
611
|
const transitionKind = freshHandle ? "initial" : explicit ? "stream" : classifyTransition(prev.candles, candles, seriesKey !== prev.seriesKey);
|
|
445
612
|
let tfArgs = null;
|
|
446
613
|
let prevEnvelope = null;
|
|
614
|
+
let stream = null;
|
|
615
|
+
if (transitionKind === "stream" && prev != null && !explicit) {
|
|
616
|
+
const { stream: mode, streamMs, reduceMotion } = animRef.current;
|
|
617
|
+
const stepMs = inferStepMs(candles);
|
|
618
|
+
if (mode === "transform" && streamMs > 0 && stepMs != null && !reduceMotion && onFrameRef.current != null) {
|
|
619
|
+
const lastMs = candles[candles.length - 1].timeMs;
|
|
620
|
+
const prevLastMs = prev.candles[prev.candles.length - 1].timeMs;
|
|
621
|
+
if (classifyStream(prev.candles, candles) === "append") {
|
|
622
|
+
const w = h.getVisibleRange();
|
|
623
|
+
const prevStepMs = inferStepMs(prev.candles) ?? stepMs;
|
|
624
|
+
if (isPinnedToLatest(w, prevLastMs, prevStepMs)) {
|
|
625
|
+
const by = lastMs - prevLastMs;
|
|
626
|
+
stream = {
|
|
627
|
+
morph: false,
|
|
628
|
+
window: { startMs: w.startMs + by, endMs: w.endMs + by }
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
} else {
|
|
632
|
+
stream = { morph: true, window: null };
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
if (stream?.morph) {
|
|
636
|
+
settleStream(true);
|
|
637
|
+
h.beginStreamMorph();
|
|
638
|
+
} else {
|
|
639
|
+
settleStream();
|
|
640
|
+
}
|
|
641
|
+
} else if (transitionKind === "stream") {
|
|
642
|
+
settleStream();
|
|
643
|
+
}
|
|
447
644
|
if (transitionKind === "timeframe" && prev != null) {
|
|
448
645
|
const oldWindow = h.getVisibleRange();
|
|
449
646
|
const oldStepMs = inferStepMs(prev.candles);
|
|
@@ -479,6 +676,8 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
479
676
|
if (prevEnvelope) h.preservePriceEnvelope(prevEnvelope.low, prevEnvelope.high);
|
|
480
677
|
else h.resetPriceScale();
|
|
481
678
|
if (morphing) startIntervalMorph(h);
|
|
679
|
+
} else if (stream) {
|
|
680
|
+
startStreamAnim(h, stream.morph, stream.window);
|
|
482
681
|
} else if (transitionKind === "reset") {
|
|
483
682
|
h.resetView();
|
|
484
683
|
}
|
|
@@ -496,9 +695,11 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
496
695
|
}
|
|
497
696
|
h.setRSI(rsiToSpec(rsi));
|
|
498
697
|
h.setMACD(macdToSpec(macd));
|
|
698
|
+
h.setATR(atrToSpec(atr));
|
|
499
699
|
h.setOverlays((movingAverages ?? []).map(overlayToNumeric));
|
|
500
700
|
h.setVWAP(vwapToSpec(vwap));
|
|
501
701
|
h.setBollinger(bollingerToSpec(bollingerBands));
|
|
702
|
+
h.setFairValueGaps(fvgToSpec(fairValueGaps));
|
|
502
703
|
h.setVolume(volumeToSpec(volume));
|
|
503
704
|
const collapse = volumeCollapseRef.current;
|
|
504
705
|
if (collapse) h.setVolumeCollapse(collapse.t, collapse.easing);
|
|
@@ -509,7 +710,7 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
509
710
|
footprints?.prints.length ? footprintsToSpec(footprints) : EMPTY_FOOTPRINTS
|
|
510
711
|
);
|
|
511
712
|
if (!morphing) setPicture(h.render());
|
|
512
|
-
}, [candles, seriesKey, size.width, size.height, size.pxRatio, explicit, startMs, endMs, defaultCandleWidth, themeKey, rsiKey, macdKey, maKey, vwapKey, bollingerKey, volumeKey, priceLinesKey, footprintsKey, startIntervalMorph, endIntervalMorph]);
|
|
713
|
+
}, [candles, seriesKey, size.width, size.height, size.pxRatio, explicit, startMs, endMs, defaultCandleWidth, themeKey, rsiKey, macdKey, atrKey, maKey, vwapKey, bollingerKey, ichimokuKey, fvgKey, volumeKey, priceLinesKey, footprintsKey, startIntervalMorph, endIntervalMorph, startStreamAnim, settleStream]);
|
|
513
714
|
return { handle: handleRef.current, picture, volumeCollapseRef };
|
|
514
715
|
}
|
|
515
716
|
|
|
@@ -531,12 +732,17 @@ function VroomChart(props) {
|
|
|
531
732
|
transitionMs,
|
|
532
733
|
transitionEasing,
|
|
533
734
|
intervalTransition,
|
|
735
|
+
streamTransition,
|
|
736
|
+
streamTransitionMs,
|
|
534
737
|
theme,
|
|
535
738
|
rsi,
|
|
536
739
|
macd,
|
|
740
|
+
atr,
|
|
537
741
|
movingAverages,
|
|
538
742
|
vwap,
|
|
539
743
|
bollingerBands,
|
|
744
|
+
ichimoku,
|
|
745
|
+
fairValueGaps,
|
|
540
746
|
volume,
|
|
541
747
|
crosshairOffset = 40,
|
|
542
748
|
onCrosshair,
|
|
@@ -615,13 +821,25 @@ function VroomChart(props) {
|
|
|
615
821
|
theme,
|
|
616
822
|
rsi,
|
|
617
823
|
macd,
|
|
824
|
+
atr,
|
|
618
825
|
movingAverages,
|
|
619
826
|
vwap,
|
|
620
827
|
bollingerBands,
|
|
828
|
+
ichimoku,
|
|
829
|
+
fairValueGaps,
|
|
621
830
|
volume,
|
|
622
831
|
priceLinesProp,
|
|
623
832
|
footprintsProp,
|
|
624
|
-
{
|
|
833
|
+
{
|
|
834
|
+
seriesKey,
|
|
835
|
+
transitionMs,
|
|
836
|
+
transitionEasing,
|
|
837
|
+
intervalTransition,
|
|
838
|
+
streamTransition,
|
|
839
|
+
streamTransitionMs,
|
|
840
|
+
reduceMotion,
|
|
841
|
+
onFrame
|
|
842
|
+
}
|
|
625
843
|
);
|
|
626
844
|
const crosshairActive = useRef2(false);
|
|
627
845
|
const footprintActive = useRef2(false);
|