velo-plot 1.19.0 → 2.20.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/dist/{ChartCore-DQ691eXH.js → ChartCore-ivzLqxVb.js} +1376 -1153
- package/dist/ChartCore-ivzLqxVb.js.map +1 -0
- package/dist/SciPlot-CEU4ApgD.js +463 -0
- package/dist/SciPlot-CEU4ApgD.js.map +1 -0
- package/dist/axisFormat-CzumxpCL.js +200 -0
- package/dist/axisFormat-CzumxpCL.js.map +1 -0
- package/dist/core/InteractionManager.d.ts +1 -0
- package/dist/core/OverlayRenderer.d.ts +11 -0
- package/dist/core/chart/ChartAxisManager.d.ts +2 -0
- package/dist/core/chart/ChartCore.d.ts +20 -0
- package/dist/core/chart/ChartPluginBridge.d.ts +1 -0
- package/dist/core/chart/ChartRenderLoop.d.ts +7 -0
- package/dist/core/chart/ChartRenderer.d.ts +5 -0
- package/dist/core/chart/ChartStateManager.d.ts +2 -0
- package/dist/core/chart/positionLines.d.ts +12 -0
- package/dist/core/chart/types.d.ts +7 -0
- package/dist/core/format/axisFormat.d.ts +2 -1
- package/dist/core/indicator/addIndicator.d.ts +1 -1
- package/dist/core/indicator/indicatorPresets.d.ts +10 -2
- package/dist/core/sync/index.d.ts +0 -1
- package/dist/core/time/TimeScale.d.ts +2 -2
- package/dist/core/time/applyTimeScale.d.ts +10 -0
- package/dist/createStackedChart-DxNW0VkF.js +705 -0
- package/dist/createStackedChart-DxNW0VkF.js.map +1 -0
- package/dist/{index-D7dTq6VB.js → index-BBpJwOct.js} +17 -19
- package/dist/index-BBpJwOct.js.map +1 -0
- package/dist/{index-CUGS98p4.js → index-CaXWSOTk.js} +3 -6
- package/dist/index-CaXWSOTk.js.map +1 -0
- package/dist/{index-DjeWClO9.js → index-qunX30Xu.js} +2 -2
- package/dist/{index-DjeWClO9.js.map → index-qunX30Xu.js.map} +1 -1
- package/dist/{index.core-BtGFYMOu.js → index.core-COREBDNq.js} +25 -24
- package/dist/{index.core-BtGFYMOu.js.map → index.core-COREBDNq.js.map} +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/mockDatafeed-927foCM4.js +511 -0
- package/dist/mockDatafeed-927foCM4.js.map +1 -0
- package/dist/plugins/analysis/contours.d.ts +31 -0
- package/dist/plugins/analysis.js +494 -407
- package/dist/plugins/analysis.js.map +1 -1
- package/dist/plugins/broken-axis.js +170 -181
- package/dist/plugins/broken-axis.js.map +1 -1
- package/dist/plugins/drawing-tools/index.d.ts +14 -1
- package/dist/plugins/drawing-tools/measure.d.ts +21 -0
- package/dist/plugins/drawing-tools/snapToCandle.d.ts +21 -0
- package/dist/plugins/forecasting/algorithms.d.ts +7 -2
- package/dist/plugins/forecasting/types.d.ts +13 -3
- package/dist/plugins/forecasting.js +355 -175
- package/dist/plugins/forecasting.js.map +1 -1
- package/dist/plugins/latex/symbols.d.ts +50 -0
- package/dist/plugins/latex/types.d.ts +13 -1
- package/dist/plugins/latex.js +351 -331
- package/dist/plugins/latex.js.map +1 -1
- package/dist/plugins/ml-integration/native-algorithms.d.ts +24 -4
- package/dist/plugins/ml-integration/types.d.ts +19 -0
- package/dist/plugins/ml-integration.js +191 -140
- package/dist/plugins/ml-integration.js.map +1 -1
- package/dist/plugins/pattern-recognition/types.d.ts +28 -1
- package/dist/plugins/pattern-recognition.js +416 -343
- package/dist/plugins/pattern-recognition.js.map +1 -1
- package/dist/plugins/snapshot.js +36 -36
- package/dist/plugins/snapshot.js.map +1 -1
- package/dist/plugins/sync.js +1 -1
- package/dist/plugins/tools.js +1 -1
- package/dist/plugins/virtualization.js +1 -1
- package/dist/react.js +5 -5
- package/dist/symbols-DT0eLlpW.js +568 -0
- package/dist/symbols-DT0eLlpW.js.map +1 -0
- package/dist/trading/datafeed.d.ts +48 -0
- package/dist/trading/index.d.ts +29 -0
- package/dist/trading/mockDatafeed.d.ts +9 -0
- package/dist/trading/ohlcvGenerator.d.ts +25 -0
- package/dist/trading.d.ts +1 -0
- package/dist/trading.js +95 -0
- package/dist/trading.js.map +1 -0
- package/dist/types.d.ts +1 -1
- package/dist/velo-plot.full.js +835 -1054
- package/dist/velo-plot.full.js.map +1 -1
- package/dist/velo-plot.js +13 -13
- package/dist/workers/indicatorsAsync.d.ts +24 -0
- package/package.json +13 -1
- package/dist/ChartCore-DQ691eXH.js.map +0 -1
- package/dist/axisFormat-B7o_uIEA.js +0 -127
- package/dist/axisFormat-B7o_uIEA.js.map +0 -1
- package/dist/createStackedChart-BPooTQ9z.js +0 -1164
- package/dist/createStackedChart-BPooTQ9z.js.map +0 -1
- package/dist/index-CUGS98p4.js.map +0 -1
- package/dist/index-D7dTq6VB.js.map +0 -1
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
function j(r, e) {
|
|
2
|
+
if (r.length === 0) return -1;
|
|
3
|
+
let s = 0, n = Math.abs(r[0] - e);
|
|
4
|
+
for (let i = 1; i < r.length; i++) {
|
|
5
|
+
const f = Math.abs(r[i] - e);
|
|
6
|
+
f < n && (n = f, s = i);
|
|
7
|
+
}
|
|
8
|
+
return s;
|
|
9
|
+
}
|
|
10
|
+
function J(r) {
|
|
11
|
+
if (r.barX.length === 0)
|
|
12
|
+
return { x: r.x, y: r.y };
|
|
13
|
+
const e = j(r.barX, r.x);
|
|
14
|
+
if (e < 0) return { x: r.x, y: r.y };
|
|
15
|
+
const s = r.barX[e], n = [
|
|
16
|
+
r.open[e],
|
|
17
|
+
r.high[e],
|
|
18
|
+
r.low[e],
|
|
19
|
+
r.close[e]
|
|
20
|
+
], i = r.dataToPixelY(r.y), f = r.pixelThreshold ?? 12;
|
|
21
|
+
let m = r.y, d = 1 / 0;
|
|
22
|
+
for (const c of n) {
|
|
23
|
+
const h = r.dataToPixelY(c), x = Math.abs(h - i);
|
|
24
|
+
x < d && x <= f && (d = x, m = c);
|
|
25
|
+
}
|
|
26
|
+
return { x: s, y: m };
|
|
27
|
+
}
|
|
28
|
+
function $(r, e) {
|
|
29
|
+
const s = e.y - r.y, n = Math.abs(r.y), i = n > 0 ? s / n * 100 : 0, f = Math.round(Math.abs(e.x - r.x));
|
|
30
|
+
return { change: s, percent: i, bars: f, up: s >= 0 };
|
|
31
|
+
}
|
|
32
|
+
function L(r) {
|
|
33
|
+
const e = r.change >= 0 ? "+" : "";
|
|
34
|
+
return `${e}${r.change.toFixed(2)} (${e}${r.percent.toFixed(2)}%) · ${r.bars} bars`;
|
|
35
|
+
}
|
|
36
|
+
function U(r) {
|
|
37
|
+
const e = Math.abs(r), s = e >= 1e3 ? 0 : e >= 1 ? 2 : 4;
|
|
38
|
+
return r.toLocaleString("en-US", {
|
|
39
|
+
minimumFractionDigits: s,
|
|
40
|
+
maximumFractionDigits: s
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
const Y = [0, 0.236, 0.382, 0.5, 0.618, 0.786, 1], K = 4, Q = "#26a69a", Z = "#ef5350";
|
|
44
|
+
function E(r, e) {
|
|
45
|
+
return r.startsWith("#") && r.length === 7 ? r + e : r;
|
|
46
|
+
}
|
|
47
|
+
const C = {
|
|
48
|
+
name: "velo-plot-drawing-tools",
|
|
49
|
+
version: "1.0.0",
|
|
50
|
+
description: "Interactive trendline, horizontal, vertical, rectangle, and fibonacci drawing",
|
|
51
|
+
provides: ["drawing"],
|
|
52
|
+
tags: ["drawing", "annotations", "trading"]
|
|
53
|
+
};
|
|
54
|
+
function B(r) {
|
|
55
|
+
return r !== "none" && r !== "pan";
|
|
56
|
+
}
|
|
57
|
+
function tt(r) {
|
|
58
|
+
for (const e of r.data.getAllSeries())
|
|
59
|
+
if (e.getType() === "candlestick") return e;
|
|
60
|
+
}
|
|
61
|
+
function it(r = {}) {
|
|
62
|
+
let e = null;
|
|
63
|
+
const s = r.autoDeselect !== !1;
|
|
64
|
+
let n = {
|
|
65
|
+
mode: "none",
|
|
66
|
+
pending: null,
|
|
67
|
+
start: null,
|
|
68
|
+
dragging: !1,
|
|
69
|
+
dragMoved: !1,
|
|
70
|
+
dragStartPixel: null,
|
|
71
|
+
cursor: null,
|
|
72
|
+
magnet: r.magnet ?? !1,
|
|
73
|
+
undoStack: [],
|
|
74
|
+
redoStack: []
|
|
75
|
+
};
|
|
76
|
+
const i = r.color ?? "#38bdf8", f = r.measureUpColor ?? Q, m = r.measureDownColor ?? Z;
|
|
77
|
+
function d() {
|
|
78
|
+
var t, o;
|
|
79
|
+
return ((o = e == null ? void 0 : (t = e.chart).getAnnotations) == null ? void 0 : o.call(t)) ?? [];
|
|
80
|
+
}
|
|
81
|
+
function c() {
|
|
82
|
+
n.undoStack.push(d()), n.redoStack = [];
|
|
83
|
+
}
|
|
84
|
+
function h() {
|
|
85
|
+
n.pending = null, n.start = null, n.dragging = !1, n.dragMoved = !1, n.dragStartPixel = null;
|
|
86
|
+
}
|
|
87
|
+
function x(t) {
|
|
88
|
+
var o, a;
|
|
89
|
+
n.mode = t, h(), (o = r.onModeChange) == null || o.call(r, t), (a = e == null ? void 0 : e.requestRender) == null || a.call(e);
|
|
90
|
+
}
|
|
91
|
+
function u() {
|
|
92
|
+
var t;
|
|
93
|
+
h(), s ? x("none") : (t = e == null ? void 0 : e.requestRender) == null || t.call(e);
|
|
94
|
+
}
|
|
95
|
+
function T(t, o) {
|
|
96
|
+
if (!e || !n.magnet) return { x: t, y: o };
|
|
97
|
+
const a = tt(e);
|
|
98
|
+
if (!a) return { x: t, y: o };
|
|
99
|
+
const l = a.getData();
|
|
100
|
+
return !l.open || !l.high || !l.low || !l.close ? { x: t, y: o } : J({
|
|
101
|
+
x: t,
|
|
102
|
+
y: o,
|
|
103
|
+
barX: l.x,
|
|
104
|
+
open: l.open,
|
|
105
|
+
high: l.high,
|
|
106
|
+
low: l.low,
|
|
107
|
+
close: l.close,
|
|
108
|
+
dataToPixelX: e.coords.dataToPixelX,
|
|
109
|
+
dataToPixelY: (y) => e.coords.dataToPixelY(y),
|
|
110
|
+
enabled: !0
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function k(t, o) {
|
|
114
|
+
return T(
|
|
115
|
+
t.coords.pixelToDataX(o.pixelX),
|
|
116
|
+
t.coords.pixelToDataY(o.pixelY)
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
function W(t) {
|
|
120
|
+
e && (c(), e.chart.addAnnotation({
|
|
121
|
+
type: "horizontal-line",
|
|
122
|
+
y: t,
|
|
123
|
+
color: i,
|
|
124
|
+
interactive: !0
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
function z(t) {
|
|
128
|
+
e && (c(), e.chart.addAnnotation({
|
|
129
|
+
type: "vertical-line",
|
|
130
|
+
x: t,
|
|
131
|
+
color: i,
|
|
132
|
+
interactive: !0
|
|
133
|
+
}));
|
|
134
|
+
}
|
|
135
|
+
function _(t, o) {
|
|
136
|
+
if (!e) return;
|
|
137
|
+
c();
|
|
138
|
+
const a = $(t, o), l = a.up ? f : m, y = (t.x + o.x) / 2;
|
|
139
|
+
e.chart.addAnnotation({
|
|
140
|
+
type: "rectangle",
|
|
141
|
+
xMin: Math.min(t.x, o.x),
|
|
142
|
+
xMax: Math.max(t.x, o.x),
|
|
143
|
+
yMin: Math.min(t.y, o.y),
|
|
144
|
+
yMax: Math.max(t.y, o.y),
|
|
145
|
+
strokeColor: l,
|
|
146
|
+
fillColor: E(l, "33"),
|
|
147
|
+
interactive: !0
|
|
148
|
+
}), e.chart.addAnnotation({
|
|
149
|
+
type: "arrow",
|
|
150
|
+
x1: y,
|
|
151
|
+
y1: t.y,
|
|
152
|
+
x2: y,
|
|
153
|
+
y2: o.y,
|
|
154
|
+
color: l,
|
|
155
|
+
headStyle: "filled",
|
|
156
|
+
interactive: !0
|
|
157
|
+
}), e.chart.addAnnotation({
|
|
158
|
+
type: "text",
|
|
159
|
+
x: y,
|
|
160
|
+
y: o.y,
|
|
161
|
+
text: L(a),
|
|
162
|
+
color: "#ffffff",
|
|
163
|
+
backgroundColor: l,
|
|
164
|
+
padding: 4,
|
|
165
|
+
fontWeight: "bold",
|
|
166
|
+
anchor: a.up ? "bottom-center" : "top-center",
|
|
167
|
+
interactive: !0
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
function F(t, o) {
|
|
171
|
+
if (e) {
|
|
172
|
+
if (n.mode === "measure") {
|
|
173
|
+
_(t, o);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (c(), n.mode === "trendline")
|
|
177
|
+
e.chart.addAnnotation({
|
|
178
|
+
type: "arrow",
|
|
179
|
+
x1: t.x,
|
|
180
|
+
y1: t.y,
|
|
181
|
+
x2: o.x,
|
|
182
|
+
y2: o.y,
|
|
183
|
+
color: i,
|
|
184
|
+
interactive: !0
|
|
185
|
+
});
|
|
186
|
+
else if (n.mode === "rectangle")
|
|
187
|
+
e.chart.addAnnotation({
|
|
188
|
+
type: "rectangle",
|
|
189
|
+
xMin: Math.min(t.x, o.x),
|
|
190
|
+
xMax: Math.max(t.x, o.x),
|
|
191
|
+
yMin: Math.min(t.y, o.y),
|
|
192
|
+
yMax: Math.max(t.y, o.y),
|
|
193
|
+
strokeColor: i,
|
|
194
|
+
fillColor: i + "22",
|
|
195
|
+
interactive: !0
|
|
196
|
+
});
|
|
197
|
+
else if (n.mode === "fibonacci") {
|
|
198
|
+
const a = Math.min(t.y, o.y), l = Math.max(t.y, o.y);
|
|
199
|
+
for (const y of Y) {
|
|
200
|
+
const M = l - (l - a) * y;
|
|
201
|
+
e.chart.addAnnotation({
|
|
202
|
+
type: "horizontal-line",
|
|
203
|
+
y: M,
|
|
204
|
+
color: i,
|
|
205
|
+
lineDash: y === 0 || y === 1 ? void 0 : [4, 4],
|
|
206
|
+
label: `${(y * 100).toFixed(1)}% ${U(M)}`,
|
|
207
|
+
labelPosition: "right",
|
|
208
|
+
interactive: !0
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function H(t, o, a) {
|
|
215
|
+
const l = n.mode;
|
|
216
|
+
if (!B(l) || !n.cursor) return;
|
|
217
|
+
const y = n.cursor, M = n.pending ?? n.start;
|
|
218
|
+
t.save(), t.strokeStyle = i, t.lineWidth = 1.5, t.setLineDash([6, 4]), t.globalAlpha = 0.85;
|
|
219
|
+
const b = (g, v) => ({
|
|
220
|
+
px: a.dataToPixelX(g),
|
|
221
|
+
py: a.dataToPixelY(v)
|
|
222
|
+
});
|
|
223
|
+
if (l === "horizontal") {
|
|
224
|
+
const { py: g } = b(0, y.y);
|
|
225
|
+
t.beginPath(), t.moveTo(o.x, g), t.lineTo(o.x + o.width, g), t.stroke();
|
|
226
|
+
} else if (l === "vertical") {
|
|
227
|
+
const { px: g } = b(y.x, 0);
|
|
228
|
+
t.beginPath(), t.moveTo(g, o.y), t.lineTo(g, o.y + o.height), t.stroke();
|
|
229
|
+
} else if (M) {
|
|
230
|
+
const g = b(M.x, M.y), v = b(y.x, y.y);
|
|
231
|
+
if (l === "trendline")
|
|
232
|
+
t.beginPath(), t.moveTo(g.px, g.py), t.lineTo(v.px, v.py), t.stroke();
|
|
233
|
+
else if (l === "rectangle") {
|
|
234
|
+
const S = Math.min(g.px, v.px), w = Math.min(g.py, v.py), p = Math.abs(v.px - g.px), P = Math.abs(v.py - g.py);
|
|
235
|
+
t.strokeRect(S, w, p, P), t.fillStyle = i + "22", t.fillRect(S, w, p, P);
|
|
236
|
+
} else if (l === "fibonacci") {
|
|
237
|
+
const S = Math.min(M.y, y.y), w = Math.max(M.y, y.y);
|
|
238
|
+
t.font = "11px sans-serif", t.textAlign = "left", t.textBaseline = "bottom";
|
|
239
|
+
for (const p of Y) {
|
|
240
|
+
const P = w - (w - S) * p, { py: A } = b(0, P);
|
|
241
|
+
t.beginPath(), t.moveTo(o.x, A), t.lineTo(o.x + o.width, A), t.stroke(), t.save(), t.setLineDash([]), t.globalAlpha = 1, t.fillStyle = i, t.fillText(
|
|
242
|
+
`${(p * 100).toFixed(1)}% ${U(P)}`,
|
|
243
|
+
o.x + 4,
|
|
244
|
+
A - 2
|
|
245
|
+
), t.restore();
|
|
246
|
+
}
|
|
247
|
+
} else l === "measure" && O(t, g, v, M, y);
|
|
248
|
+
}
|
|
249
|
+
t.restore();
|
|
250
|
+
}
|
|
251
|
+
function O(t, o, a, l, y) {
|
|
252
|
+
const M = $(l, y), b = M.up ? f : m, g = Math.min(o.px, a.px), v = Math.min(o.py, a.py), S = Math.abs(a.px - o.px), w = Math.abs(a.py - o.py);
|
|
253
|
+
t.setLineDash([]), t.globalAlpha = 0.9, t.fillStyle = E(b, "33"), t.fillRect(g, v, S, w), t.strokeStyle = b, t.lineWidth = 1.5, t.strokeRect(g, v, S, w);
|
|
254
|
+
const p = (o.px + a.px) / 2;
|
|
255
|
+
t.beginPath(), t.moveTo(p, o.py), t.lineTo(p, a.py), t.stroke();
|
|
256
|
+
const P = 7, A = a.py >= o.py ? 1 : -1;
|
|
257
|
+
t.beginPath(), t.moveTo(p, a.py), t.lineTo(p - 4, a.py - A * P), t.lineTo(p + 4, a.py - A * P), t.closePath(), t.fillStyle = b, t.fill();
|
|
258
|
+
const I = L(M);
|
|
259
|
+
t.font = "12px sans-serif";
|
|
260
|
+
const R = t.measureText(I).width + 6 * 2, D = 20, G = p - R / 2, X = M.up ? a.py - D - 8 : a.py + 8;
|
|
261
|
+
t.globalAlpha = 1, t.fillStyle = b, t.fillRect(G, X, R, D), t.fillStyle = "#ffffff", t.textAlign = "center", t.textBaseline = "middle", t.fillText(I, p, X + D / 2);
|
|
262
|
+
}
|
|
263
|
+
function N(t, o) {
|
|
264
|
+
var l;
|
|
265
|
+
if (!o.inPlotArea) return;
|
|
266
|
+
o.preventDefault();
|
|
267
|
+
const a = k(t, o);
|
|
268
|
+
if (n.mode === "horizontal") {
|
|
269
|
+
W(a.y), u();
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (n.mode === "vertical") {
|
|
273
|
+
z(a.x), u();
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
if (n.pending) {
|
|
277
|
+
F(n.pending, a), u();
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
n.start = a, n.dragging = !0, n.dragMoved = !1, n.dragStartPixel = { x: o.pixelX, y: o.pixelY }, n.cursor = a, (l = t.requestRender) == null || l.call(t);
|
|
281
|
+
}
|
|
282
|
+
function V(t, o) {
|
|
283
|
+
var l;
|
|
284
|
+
const a = k(t, o);
|
|
285
|
+
if (n.cursor = a, n.dragging && n.dragStartPixel) {
|
|
286
|
+
const y = o.pixelX - n.dragStartPixel.x, M = o.pixelY - n.dragStartPixel.y;
|
|
287
|
+
Math.hypot(y, M) >= K && (n.dragMoved = !0);
|
|
288
|
+
}
|
|
289
|
+
o.preventDefault(), (l = t.requestRender) == null || l.call(t);
|
|
290
|
+
}
|
|
291
|
+
function q(t, o) {
|
|
292
|
+
var y;
|
|
293
|
+
if (!n.dragging || !n.start) return;
|
|
294
|
+
const a = k(t, o), l = n.start;
|
|
295
|
+
if (n.dragging = !1, n.dragStartPixel = null, n.dragMoved) {
|
|
296
|
+
F(l, a), u();
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
n.pending = l, n.start = null, n.cursor = a, (y = t.requestRender) == null || y.call(t);
|
|
300
|
+
}
|
|
301
|
+
return {
|
|
302
|
+
manifest: C,
|
|
303
|
+
api: {
|
|
304
|
+
setMode(t) {
|
|
305
|
+
x(t);
|
|
306
|
+
},
|
|
307
|
+
getMode() {
|
|
308
|
+
return n.mode;
|
|
309
|
+
},
|
|
310
|
+
setMagnet(t) {
|
|
311
|
+
n.magnet = t;
|
|
312
|
+
},
|
|
313
|
+
isMagnet() {
|
|
314
|
+
return n.magnet;
|
|
315
|
+
},
|
|
316
|
+
undo() {
|
|
317
|
+
if (!e || n.undoStack.length === 0) return !1;
|
|
318
|
+
n.redoStack.push(d());
|
|
319
|
+
const t = n.undoStack.pop(), o = d();
|
|
320
|
+
for (const a of o) e.chart.removeAnnotation(a.id);
|
|
321
|
+
for (const a of t) e.chart.addAnnotation(a);
|
|
322
|
+
return !0;
|
|
323
|
+
},
|
|
324
|
+
redo() {
|
|
325
|
+
if (!e || n.redoStack.length === 0) return !1;
|
|
326
|
+
n.undoStack.push(d());
|
|
327
|
+
const t = n.redoStack.pop(), o = d();
|
|
328
|
+
for (const a of o) e.chart.removeAnnotation(a.id);
|
|
329
|
+
for (const a of t) e.chart.addAnnotation(a);
|
|
330
|
+
return !0;
|
|
331
|
+
},
|
|
332
|
+
clear() {
|
|
333
|
+
if (e) {
|
|
334
|
+
c();
|
|
335
|
+
for (const t of d()) e.chart.removeAnnotation(t.id);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
onInit(t) {
|
|
340
|
+
e = t;
|
|
341
|
+
},
|
|
342
|
+
onDestroy() {
|
|
343
|
+
e = null;
|
|
344
|
+
},
|
|
345
|
+
onInteraction(t, o) {
|
|
346
|
+
if (B(n.mode)) {
|
|
347
|
+
if (o.type === "mousedown") {
|
|
348
|
+
N(t, o);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
if (o.type === "mousemove") {
|
|
352
|
+
V(t, o);
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
o.type === "mouseup" && q(t, o);
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
onRenderOverlay(t) {
|
|
359
|
+
const o = t.render.ctx2d;
|
|
360
|
+
o && H(o, t.render.plotArea, t.coords);
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
const et = {
|
|
365
|
+
name: "velo-plot-replay",
|
|
366
|
+
version: "1.0.0",
|
|
367
|
+
description: "Bar-by-bar chart replay with speed control",
|
|
368
|
+
provides: ["replay"],
|
|
369
|
+
tags: ["replay", "trading"]
|
|
370
|
+
};
|
|
371
|
+
function lt(r) {
|
|
372
|
+
let e = null, s = null, n = 0, i = null, f = 1;
|
|
373
|
+
const m = r.frameMs ?? 250;
|
|
374
|
+
function d(h) {
|
|
375
|
+
if (!e || !s) return;
|
|
376
|
+
const x = Math.min(h + 1, s.x.length), u = (T) => T ? T.subarray(0, x) : void 0;
|
|
377
|
+
e.chart.updateSeries(r.seriesId, {
|
|
378
|
+
x: u(s.x),
|
|
379
|
+
y: u(s.y),
|
|
380
|
+
open: u(s.open),
|
|
381
|
+
high: u(s.high),
|
|
382
|
+
low: u(s.low),
|
|
383
|
+
close: u(s.close)
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
const c = {
|
|
387
|
+
play(h = 1) {
|
|
388
|
+
s && (f = Math.max(0.1, h), i && clearInterval(i), i = setInterval(() => {
|
|
389
|
+
if (n >= s.x.length - 1) {
|
|
390
|
+
c.pause();
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
n++, d(n);
|
|
394
|
+
}, m / f));
|
|
395
|
+
},
|
|
396
|
+
pause() {
|
|
397
|
+
i && (clearInterval(i), i = null);
|
|
398
|
+
},
|
|
399
|
+
step(h = 1) {
|
|
400
|
+
s && (n = Math.min(s.x.length - 1, n + h), d(n));
|
|
401
|
+
},
|
|
402
|
+
seek(h) {
|
|
403
|
+
s && (n = Math.max(0, Math.min(s.x.length - 1, h)), d(n));
|
|
404
|
+
},
|
|
405
|
+
getIndex() {
|
|
406
|
+
return n;
|
|
407
|
+
},
|
|
408
|
+
getLength() {
|
|
409
|
+
return (s == null ? void 0 : s.x.length) ?? 0;
|
|
410
|
+
},
|
|
411
|
+
isPlaying() {
|
|
412
|
+
return i != null;
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
return {
|
|
416
|
+
manifest: et,
|
|
417
|
+
api: c,
|
|
418
|
+
onInit(h) {
|
|
419
|
+
e = h;
|
|
420
|
+
const x = e.chart.getSeries(r.seriesId);
|
|
421
|
+
if (!x) {
|
|
422
|
+
console.warn(`[PluginReplay] Series "${r.seriesId}" not found`);
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
const u = x.getData();
|
|
426
|
+
s = {
|
|
427
|
+
x: Float32Array.from(u.x),
|
|
428
|
+
y: u.y ? Float32Array.from(u.y) : void 0,
|
|
429
|
+
open: u.open ? Float32Array.from(u.open) : void 0,
|
|
430
|
+
high: u.high ? Float32Array.from(u.high) : void 0,
|
|
431
|
+
low: u.low ? Float32Array.from(u.low) : void 0,
|
|
432
|
+
close: u.close ? Float32Array.from(u.close) : void 0
|
|
433
|
+
}, n = Math.max(0, s.x.length - 1);
|
|
434
|
+
},
|
|
435
|
+
onDestroy() {
|
|
436
|
+
c.pause(), e = null, s = null;
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
function ct(r) {
|
|
441
|
+
const e = r.length, s = new Float64Array(e), n = new Float32Array(e), i = new Float32Array(e), f = new Float32Array(e), m = new Float32Array(e), d = new Float32Array(e);
|
|
442
|
+
for (let c = 0; c < e; c++) {
|
|
443
|
+
const h = r[c];
|
|
444
|
+
s[c] = h.time, n[c] = h.open, i[c] = h.high, f[c] = h.low, m[c] = h.close, d[c] = h.volume ?? 0;
|
|
445
|
+
}
|
|
446
|
+
return { x: s, open: n, high: i, low: f, close: m, volume: d };
|
|
447
|
+
}
|
|
448
|
+
function nt(r) {
|
|
449
|
+
let e = r;
|
|
450
|
+
return () => (e = e * 16807 % 2147483647, (e - 1) / 2147483646);
|
|
451
|
+
}
|
|
452
|
+
function ot(r, e, s, n, i) {
|
|
453
|
+
const f = [];
|
|
454
|
+
let m = n;
|
|
455
|
+
for (let d = r; d <= e; d += s) {
|
|
456
|
+
const c = m, h = (i() - 0.48) * 2, x = Math.max(1, c + h), u = Math.max(c, x) + i() * 1.5, T = Math.min(c, x) - i() * 1.5;
|
|
457
|
+
f.push({
|
|
458
|
+
time: d,
|
|
459
|
+
open: c,
|
|
460
|
+
high: u,
|
|
461
|
+
low: T,
|
|
462
|
+
close: x,
|
|
463
|
+
volume: 1e3 + i() * 5e3
|
|
464
|
+
}), m = x;
|
|
465
|
+
}
|
|
466
|
+
return f;
|
|
467
|
+
}
|
|
468
|
+
function ft(r = {}) {
|
|
469
|
+
const e = r.barMs ?? 6e4, s = r.basePrice ?? 100, n = nt(r.seed ?? 42), i = /* @__PURE__ */ new Map();
|
|
470
|
+
return {
|
|
471
|
+
async resolveSymbol(f) {
|
|
472
|
+
return {
|
|
473
|
+
symbol: f,
|
|
474
|
+
name: f,
|
|
475
|
+
description: `Mock symbol ${f}`,
|
|
476
|
+
timezone: "UTC",
|
|
477
|
+
session: "24x7",
|
|
478
|
+
pricescale: 100
|
|
479
|
+
};
|
|
480
|
+
},
|
|
481
|
+
async getBars(f) {
|
|
482
|
+
const m = `${f.symbol}:${f.from}:${f.to}`;
|
|
483
|
+
return i.has(m) || i.set(
|
|
484
|
+
m,
|
|
485
|
+
ot(f.from, f.to, e, s, n)
|
|
486
|
+
), i.get(m);
|
|
487
|
+
},
|
|
488
|
+
subscribeBars(f) {
|
|
489
|
+
let m = s + n() * 5;
|
|
490
|
+
const d = setInterval(() => {
|
|
491
|
+
const c = m, h = Math.max(1, c + (n() - 0.5) * 2), x = Math.max(c, h) + n(), u = Math.min(c, h) - n();
|
|
492
|
+
f.onBar({
|
|
493
|
+
time: Date.now(),
|
|
494
|
+
open: c,
|
|
495
|
+
high: x,
|
|
496
|
+
low: u,
|
|
497
|
+
close: h,
|
|
498
|
+
volume: 1e3 + n() * 3e3
|
|
499
|
+
}), m = h;
|
|
500
|
+
}, e);
|
|
501
|
+
return () => clearInterval(d);
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
export {
|
|
506
|
+
it as P,
|
|
507
|
+
lt as a,
|
|
508
|
+
ct as b,
|
|
509
|
+
ft as c
|
|
510
|
+
};
|
|
511
|
+
//# sourceMappingURL=mockDatafeed-927foCM4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mockDatafeed-927foCM4.js","sources":["../src/plugins/drawing-tools/snapToCandle.ts","../src/plugins/drawing-tools/measure.ts","../src/plugins/drawing-tools/index.ts","../src/plugins/replay/index.ts","../src/trading/datafeed.ts","../src/trading/mockDatafeed.ts"],"sourcesContent":["/**\n * Snap drawing points to nearest candlestick O/H/L/C (TradingView-style magnet).\n */\n\nexport interface CandleSnapInput {\n x: number;\n y: number;\n barX: Float32Array | Float64Array;\n open: Float32Array | Float64Array;\n high: Float32Array | Float64Array;\n low: Float32Array | Float64Array;\n close: Float32Array | Float64Array;\n dataToPixelX: (x: number) => number;\n dataToPixelY: (y: number) => number;\n pixelThreshold?: number;\n enabled?: boolean;\n}\n\nexport function findNearestBarIndex(\n barX: Float32Array | Float64Array,\n x: number,\n): number {\n if (barX.length === 0) return -1;\n let bestIdx = 0;\n let bestDist = Math.abs(barX[0] - x);\n for (let i = 1; i < barX.length; i++) {\n const d = Math.abs(barX[i] - x);\n if (d < bestDist) {\n bestDist = d;\n bestIdx = i;\n }\n }\n return bestIdx;\n}\n\nexport function snapToCandle(input: CandleSnapInput): { x: number; y: number } {\n if (input.enabled === false || input.barX.length === 0) {\n return { x: input.x, y: input.y };\n }\n\n const idx = findNearestBarIndex(input.barX, input.x);\n if (idx < 0) return { x: input.x, y: input.y };\n\n const barX = input.barX[idx];\n const candidates = [\n input.open[idx],\n input.high[idx],\n input.low[idx],\n input.close[idx],\n ];\n\n const clickPy = input.dataToPixelY(input.y);\n const threshold = input.pixelThreshold ?? 12;\n let bestY = input.y;\n let bestPyDist = Infinity;\n\n for (const cy of candidates) {\n const py = input.dataToPixelY(cy);\n const dist = Math.abs(py - clickPy);\n if (dist < bestPyDist && dist <= threshold) {\n bestPyDist = dist;\n bestY = cy;\n }\n }\n\n return { x: barX, y: bestY };\n}\n","/**\n * Measurement helper for the price-range / measure tool (TradingView-style).\n */\n\nexport interface MeasurePoint {\n x: number;\n y: number;\n}\n\nexport interface Measurement {\n /** Absolute price change (end - start) */\n change: number;\n /** Percentage change relative to the start price */\n percent: number;\n /** Number of bars spanned (rounded X distance) */\n bars: number;\n /** True when the range moves up (change >= 0) */\n up: boolean;\n}\n\nexport function computeMeasurement(a: MeasurePoint, b: MeasurePoint): Measurement {\n const change = b.y - a.y;\n const denom = Math.abs(a.y);\n const percent = denom > 0 ? (change / denom) * 100 : 0;\n const bars = Math.round(Math.abs(b.x - a.x));\n return { change, percent, bars, up: change >= 0 };\n}\n\nexport function formatMeasurement(m: Measurement): string {\n const sign = m.change >= 0 ? \"+\" : \"\";\n return `${sign}${m.change.toFixed(2)} (${sign}${m.percent.toFixed(2)}%) · ${m.bars} bars`;\n}\n\n/** Compact price formatting used for level labels. */\nexport function formatPrice(value: number): string {\n const abs = Math.abs(value);\n const decimals = abs >= 1000 ? 0 : abs >= 1 ? 2 : 4;\n return value.toLocaleString(\"en-US\", {\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n });\n}\n","/**\n * PluginDrawingTools — interactive drawing on chart (Stage 2.9).\n * TradingView-style live preview, drag-to-draw, optional candle magnet.\n */\n\nimport type { ChartPlugin, InteractionEvent, PluginContext, PluginManifest } from \"../types\";\nimport type { Annotation } from \"../../core/annotations/types\";\nimport type { Series } from \"../../core/Series\";\nimport { snapToCandle } from \"./snapToCandle\";\nimport { computeMeasurement, formatMeasurement, formatPrice } from \"./measure\";\n\nexport type DrawingMode =\n | \"none\"\n | \"pan\"\n | \"trendline\"\n | \"horizontal\"\n | \"vertical\"\n | \"rectangle\"\n | \"fibonacci\"\n | \"measure\";\n\nconst FIB_LEVELS = [0, 0.236, 0.382, 0.5, 0.618, 0.786, 1];\nconst DRAG_THRESHOLD_PX = 4;\nconst DEFAULT_MEASURE_UP = \"#26a69a\";\nconst DEFAULT_MEASURE_DOWN = \"#ef5350\";\n\nexport interface PluginDrawingToolsConfig {\n /** Default stroke color */\n color?: string;\n /** Enable candle magnet by default */\n magnet?: boolean;\n /** Return to pan mode after each completed stroke (default true) */\n autoDeselect?: boolean;\n /** Notified when drawing mode changes (including auto-deselect to none) */\n onModeChange?: (mode: DrawingMode) => void;\n /** Color for upward measurements (default green) */\n measureUpColor?: string;\n /** Color for downward measurements (default red) */\n measureDownColor?: string;\n}\n\nfunction withAlpha(color: string, alpha: string): string {\n return color.startsWith(\"#\") && color.length === 7 ? color + alpha : color;\n}\n\nexport interface DrawingToolsAPI {\n setMode(mode: DrawingMode): void;\n getMode(): DrawingMode;\n setMagnet(enabled: boolean): void;\n isMagnet(): boolean;\n undo(): boolean;\n redo(): boolean;\n clear(): void;\n}\n\nconst manifest: PluginManifest = {\n name: \"velo-plot-drawing-tools\",\n version: \"1.0.0\",\n description: \"Interactive trendline, horizontal, vertical, rectangle, and fibonacci drawing\",\n provides: [\"drawing\"],\n tags: [\"drawing\", \"annotations\", \"trading\"],\n};\n\ninterface DrawPoint {\n x: number;\n y: number;\n}\n\ninterface DrawState {\n mode: DrawingMode;\n pending: DrawPoint | null;\n start: DrawPoint | null;\n dragging: boolean;\n dragMoved: boolean;\n dragStartPixel: { x: number; y: number } | null;\n cursor: DrawPoint | null;\n magnet: boolean;\n undoStack: Annotation[][];\n redoStack: Annotation[][];\n}\n\nfunction isDrawingMode(mode: DrawingMode): boolean {\n return mode !== \"none\" && mode !== \"pan\";\n}\n\nfunction findCandlestickSeries(ctx: PluginContext): Series | undefined {\n for (const s of ctx.data.getAllSeries()) {\n if (s.getType() === \"candlestick\") return s;\n }\n return undefined;\n}\n\nexport function PluginDrawingTools(\n config: PluginDrawingToolsConfig = {},\n): ChartPlugin<PluginDrawingToolsConfig> {\n let ctx: PluginContext | null = null;\n const autoDeselect = config.autoDeselect !== false;\n let state: DrawState = {\n mode: \"none\",\n pending: null,\n start: null,\n dragging: false,\n dragMoved: false,\n dragStartPixel: null,\n cursor: null,\n magnet: config.magnet ?? false,\n undoStack: [],\n redoStack: [],\n };\n\n const stroke = config.color ?? \"#38bdf8\";\n const measureUp = config.measureUpColor ?? DEFAULT_MEASURE_UP;\n const measureDown = config.measureDownColor ?? DEFAULT_MEASURE_DOWN;\n\n function snapshot(): Annotation[] {\n return ctx?.chart.getAnnotations?.() ?? [];\n }\n\n function pushUndo(): void {\n state.undoStack.push(snapshot());\n state.redoStack = [];\n }\n\n function resetInteractionState(): void {\n state.pending = null;\n state.start = null;\n state.dragging = false;\n state.dragMoved = false;\n state.dragStartPixel = null;\n }\n\n function setModeInternal(mode: DrawingMode): void {\n state.mode = mode;\n resetInteractionState();\n config.onModeChange?.(mode);\n ctx?.requestRender?.();\n }\n\n function finishStroke(): void {\n resetInteractionState();\n if (autoDeselect) {\n setModeInternal(\"none\");\n } else {\n ctx?.requestRender?.();\n }\n }\n\n function resolvePoint(x: number, y: number): DrawPoint {\n if (!ctx || !state.magnet) return { x, y };\n const series = findCandlestickSeries(ctx);\n if (!series) return { x, y };\n const d = series.getData();\n if (!d.open || !d.high || !d.low || !d.close) return { x, y };\n return snapToCandle({\n x,\n y,\n barX: d.x,\n open: d.open,\n high: d.high,\n low: d.low,\n close: d.close,\n dataToPixelX: ctx.coords.dataToPixelX,\n dataToPixelY: (dy) => ctx!.coords.dataToPixelY(dy),\n enabled: true,\n });\n }\n\n function pointFromEvent(pluginCtx: PluginContext, event: InteractionEvent): DrawPoint {\n return resolvePoint(\n pluginCtx.coords.pixelToDataX(event.pixelX),\n pluginCtx.coords.pixelToDataY(event.pixelY),\n );\n }\n\n function commitHorizontal(y: number): void {\n if (!ctx) return;\n pushUndo();\n ctx.chart.addAnnotation({\n type: \"horizontal-line\",\n y,\n color: stroke,\n interactive: true,\n });\n }\n\n function commitVertical(x: number): void {\n if (!ctx) return;\n pushUndo();\n ctx.chart.addAnnotation({\n type: \"vertical-line\",\n x,\n color: stroke,\n interactive: true,\n });\n }\n\n function commitMeasure(p0: DrawPoint, p1: DrawPoint): void {\n if (!ctx) return;\n pushUndo();\n\n const m = computeMeasurement(p0, p1);\n const color = m.up ? measureUp : measureDown;\n const midX = (p0.x + p1.x) / 2;\n ctx.chart.addAnnotation({\n type: \"rectangle\",\n xMin: Math.min(p0.x, p1.x),\n xMax: Math.max(p0.x, p1.x),\n yMin: Math.min(p0.y, p1.y),\n yMax: Math.max(p0.y, p1.y),\n strokeColor: color,\n fillColor: withAlpha(color, \"33\"),\n interactive: true,\n });\n ctx.chart.addAnnotation({\n type: \"arrow\",\n x1: midX,\n y1: p0.y,\n x2: midX,\n y2: p1.y,\n color,\n headStyle: \"filled\",\n interactive: true,\n });\n ctx.chart.addAnnotation({\n type: \"text\",\n x: midX,\n y: p1.y,\n text: formatMeasurement(m),\n color: \"#ffffff\",\n backgroundColor: color,\n padding: 4,\n fontWeight: \"bold\",\n anchor: m.up ? \"bottom-center\" : \"top-center\",\n interactive: true,\n });\n }\n\n function commitTwoPoint(p0: DrawPoint, p1: DrawPoint): void {\n if (!ctx) return;\n\n if (state.mode === \"measure\") {\n commitMeasure(p0, p1);\n return;\n }\n\n pushUndo();\n\n if (state.mode === \"trendline\") {\n ctx.chart.addAnnotation({\n type: \"arrow\",\n x1: p0.x,\n y1: p0.y,\n x2: p1.x,\n y2: p1.y,\n color: stroke,\n interactive: true,\n });\n } else if (state.mode === \"rectangle\") {\n ctx.chart.addAnnotation({\n type: \"rectangle\",\n xMin: Math.min(p0.x, p1.x),\n xMax: Math.max(p0.x, p1.x),\n yMin: Math.min(p0.y, p1.y),\n yMax: Math.max(p0.y, p1.y),\n strokeColor: stroke,\n fillColor: stroke + \"22\",\n interactive: true,\n });\n } else if (state.mode === \"fibonacci\") {\n const yMin = Math.min(p0.y, p1.y);\n const yMax = Math.max(p0.y, p1.y);\n for (const level of FIB_LEVELS) {\n const fy = yMax - (yMax - yMin) * level;\n ctx.chart.addAnnotation({\n type: \"horizontal-line\",\n y: fy,\n color: stroke,\n lineDash: level === 0 || level === 1 ? undefined : [4, 4],\n label: `${(level * 100).toFixed(1)}% ${formatPrice(fy)}`,\n labelPosition: \"right\",\n interactive: true,\n });\n }\n }\n }\n\n function drawPreview(\n c2d: CanvasRenderingContext2D,\n plotArea: { x: number; y: number; width: number; height: number },\n coords: PluginContext[\"coords\"],\n ): void {\n const mode = state.mode;\n if (!isDrawingMode(mode) || !state.cursor) return;\n\n const cursor = state.cursor;\n const anchor = state.pending ?? state.start;\n\n c2d.save();\n c2d.strokeStyle = stroke;\n c2d.lineWidth = 1.5;\n c2d.setLineDash([6, 4]);\n c2d.globalAlpha = 0.85;\n\n const toPx = (x: number, y: number) => ({\n px: coords.dataToPixelX(x),\n py: coords.dataToPixelY(y),\n });\n\n if (mode === \"horizontal\") {\n const { py } = toPx(0, cursor.y);\n c2d.beginPath();\n c2d.moveTo(plotArea.x, py);\n c2d.lineTo(plotArea.x + plotArea.width, py);\n c2d.stroke();\n } else if (mode === \"vertical\") {\n const { px } = toPx(cursor.x, 0);\n c2d.beginPath();\n c2d.moveTo(px, plotArea.y);\n c2d.lineTo(px, plotArea.y + plotArea.height);\n c2d.stroke();\n } else if (anchor) {\n const a = toPx(anchor.x, anchor.y);\n const b = toPx(cursor.x, cursor.y);\n\n if (mode === \"trendline\") {\n c2d.beginPath();\n c2d.moveTo(a.px, a.py);\n c2d.lineTo(b.px, b.py);\n c2d.stroke();\n } else if (mode === \"rectangle\") {\n const x = Math.min(a.px, b.px);\n const y = Math.min(a.py, b.py);\n const w = Math.abs(b.px - a.px);\n const h = Math.abs(b.py - a.py);\n c2d.strokeRect(x, y, w, h);\n c2d.fillStyle = stroke + \"22\";\n c2d.fillRect(x, y, w, h);\n } else if (mode === \"fibonacci\") {\n const yMin = Math.min(anchor.y, cursor.y);\n const yMax = Math.max(anchor.y, cursor.y);\n c2d.font = \"11px sans-serif\";\n c2d.textAlign = \"left\";\n c2d.textBaseline = \"bottom\";\n for (const level of FIB_LEVELS) {\n const fy = yMax - (yMax - yMin) * level;\n const { py } = toPx(0, fy);\n c2d.beginPath();\n c2d.moveTo(plotArea.x, py);\n c2d.lineTo(plotArea.x + plotArea.width, py);\n c2d.stroke();\n c2d.save();\n c2d.setLineDash([]);\n c2d.globalAlpha = 1;\n c2d.fillStyle = stroke;\n c2d.fillText(\n `${(level * 100).toFixed(1)}% ${formatPrice(fy)}`,\n plotArea.x + 4,\n py - 2,\n );\n c2d.restore();\n }\n } else if (mode === \"measure\") {\n drawMeasurePreview(c2d, a, b, anchor, cursor);\n }\n }\n\n c2d.restore();\n }\n\n function drawMeasurePreview(\n c2d: CanvasRenderingContext2D,\n a: { px: number; py: number },\n b: { px: number; py: number },\n anchor: DrawPoint,\n cursor: DrawPoint,\n ): void {\n const m = computeMeasurement(anchor, cursor);\n const color = m.up ? measureUp : measureDown;\n const x = Math.min(a.px, b.px);\n const y = Math.min(a.py, b.py);\n const w = Math.abs(b.px - a.px);\n const h = Math.abs(b.py - a.py);\n\n c2d.setLineDash([]);\n c2d.globalAlpha = 0.9;\n c2d.fillStyle = withAlpha(color, \"33\");\n c2d.fillRect(x, y, w, h);\n c2d.strokeStyle = color;\n c2d.lineWidth = 1.5;\n c2d.strokeRect(x, y, w, h);\n\n // Vertical direction arrow at the horizontal center.\n const midX = (a.px + b.px) / 2;\n c2d.beginPath();\n c2d.moveTo(midX, a.py);\n c2d.lineTo(midX, b.py);\n c2d.stroke();\n const headLen = 7;\n const dir = b.py >= a.py ? 1 : -1;\n c2d.beginPath();\n c2d.moveTo(midX, b.py);\n c2d.lineTo(midX - 4, b.py - dir * headLen);\n c2d.lineTo(midX + 4, b.py - dir * headLen);\n c2d.closePath();\n c2d.fillStyle = color;\n c2d.fill();\n\n // Label with change / percent / bars.\n const label = formatMeasurement(m);\n c2d.font = \"12px sans-serif\";\n const textW = c2d.measureText(label).width;\n const padX = 6;\n const boxW = textW + padX * 2;\n const boxH = 20;\n const boxX = midX - boxW / 2;\n const boxY = m.up ? b.py - boxH - 8 : b.py + 8;\n c2d.globalAlpha = 1;\n c2d.fillStyle = color;\n c2d.fillRect(boxX, boxY, boxW, boxH);\n c2d.fillStyle = \"#ffffff\";\n c2d.textAlign = \"center\";\n c2d.textBaseline = \"middle\";\n c2d.fillText(label, midX, boxY + boxH / 2);\n }\n\n function handleMouseDown(pluginCtx: PluginContext, event: InteractionEvent): void {\n if (!event.inPlotArea) return;\n\n event.preventDefault();\n const point = pointFromEvent(pluginCtx, event);\n\n if (state.mode === \"horizontal\") {\n commitHorizontal(point.y);\n finishStroke();\n return;\n }\n\n if (state.mode === \"vertical\") {\n commitVertical(point.x);\n finishStroke();\n return;\n }\n\n if (state.pending) {\n commitTwoPoint(state.pending, point);\n finishStroke();\n return;\n }\n\n state.start = point;\n state.dragging = true;\n state.dragMoved = false;\n state.dragStartPixel = { x: event.pixelX, y: event.pixelY };\n state.cursor = point;\n pluginCtx.requestRender?.();\n }\n\n function handleMouseMove(pluginCtx: PluginContext, event: InteractionEvent): void {\n const point = pointFromEvent(pluginCtx, event);\n state.cursor = point;\n\n if (state.dragging && state.dragStartPixel) {\n const dx = event.pixelX - state.dragStartPixel.x;\n const dy = event.pixelY - state.dragStartPixel.y;\n if (Math.hypot(dx, dy) >= DRAG_THRESHOLD_PX) {\n state.dragMoved = true;\n }\n }\n\n event.preventDefault();\n pluginCtx.requestRender?.();\n }\n\n function handleMouseUp(pluginCtx: PluginContext, event: InteractionEvent): void {\n if (!state.dragging || !state.start) return;\n\n const point = pointFromEvent(pluginCtx, event);\n const start = state.start;\n state.dragging = false;\n state.dragStartPixel = null;\n\n if (state.dragMoved) {\n commitTwoPoint(start, point);\n finishStroke();\n return;\n }\n\n state.pending = start;\n state.start = null;\n state.cursor = point;\n pluginCtx.requestRender?.();\n }\n\n const api: DrawingToolsAPI & Record<string, unknown> = {\n setMode(mode) {\n setModeInternal(mode);\n },\n getMode() {\n return state.mode;\n },\n setMagnet(enabled) {\n state.magnet = enabled;\n },\n isMagnet() {\n return state.magnet;\n },\n undo() {\n if (!ctx || state.undoStack.length === 0) return false;\n state.redoStack.push(snapshot());\n const prev = state.undoStack.pop()!;\n const current = snapshot();\n for (const a of current) ctx.chart.removeAnnotation(a.id!);\n for (const a of prev) ctx.chart.addAnnotation(a);\n return true;\n },\n redo() {\n if (!ctx || state.redoStack.length === 0) return false;\n state.undoStack.push(snapshot());\n const next = state.redoStack.pop()!;\n const current = snapshot();\n for (const a of current) ctx.chart.removeAnnotation(a.id!);\n for (const a of next) ctx.chart.addAnnotation(a);\n return true;\n },\n clear() {\n if (!ctx) return;\n pushUndo();\n for (const a of snapshot()) ctx.chart.removeAnnotation(a.id!);\n },\n };\n\n return {\n manifest,\n api,\n onInit(pluginCtx) {\n ctx = pluginCtx;\n },\n onDestroy() {\n ctx = null;\n },\n onInteraction(pluginCtx, event) {\n if (!isDrawingMode(state.mode)) return;\n\n if (event.type === \"mousedown\") {\n handleMouseDown(pluginCtx, event);\n return;\n }\n\n if (event.type === \"mousemove\") {\n handleMouseMove(pluginCtx, event);\n return;\n }\n\n if (event.type === \"mouseup\") {\n handleMouseUp(pluginCtx, event);\n }\n },\n onRenderOverlay(pluginCtx) {\n const c2d = pluginCtx.render.ctx2d;\n if (!c2d) return;\n drawPreview(c2d, pluginCtx.render.plotArea, pluginCtx.coords);\n },\n };\n}\n\nexport { snapToCandle, findNearestBarIndex } from \"./snapToCandle\";\nexport default PluginDrawingTools;\n","/**\n * PluginReplay — bar-by-bar playback (Stage 2.17 MVP).\n */\n\nimport type { ChartPlugin, PluginContext, PluginManifest } from \"../types\";\n\nexport interface PluginReplayConfig {\n /** Series id to replay */\n seriesId: string;\n /** Milliseconds between frames at 1x speed */\n frameMs?: number;\n}\n\nexport interface ReplayAPI {\n play(speed?: number): void;\n pause(): void;\n step(count?: number): void;\n seek(index: number): void;\n getIndex(): number;\n getLength(): number;\n isPlaying(): boolean;\n}\n\nconst manifest: PluginManifest = {\n name: \"velo-plot-replay\",\n version: \"1.0.0\",\n description: \"Bar-by-bar chart replay with speed control\",\n provides: [\"replay\"],\n tags: [\"replay\", \"trading\"],\n};\n\ninterface ReplayBuffer {\n x: Float32Array;\n open?: Float32Array;\n high?: Float32Array;\n low?: Float32Array;\n close?: Float32Array;\n y?: Float32Array;\n}\n\nexport function PluginReplay(config: PluginReplayConfig): ChartPlugin<PluginReplayConfig> {\n let ctx: PluginContext | null = null;\n let buffer: ReplayBuffer | null = null;\n let index = 0;\n let timer: ReturnType<typeof setInterval> | null = null;\n let speed = 1;\n const frameMs = config.frameMs ?? 250;\n\n function applyWindow(end: number): void {\n if (!ctx || !buffer) return;\n const n = Math.min(end + 1, buffer.x.length);\n const slice = (arr?: Float32Array) => (arr ? arr.subarray(0, n) : undefined);\n ctx.chart.updateSeries(config.seriesId, {\n x: slice(buffer.x)!,\n y: slice(buffer.y),\n open: slice(buffer.open),\n high: slice(buffer.high),\n low: slice(buffer.low),\n close: slice(buffer.close),\n });\n }\n\n const api: ReplayAPI & Record<string, unknown> = {\n play(s = 1) {\n if (!buffer) return;\n speed = Math.max(0.1, s);\n if (timer) clearInterval(timer);\n timer = setInterval(() => {\n if (index >= buffer!.x.length - 1) {\n api.pause();\n return;\n }\n index++;\n applyWindow(index);\n }, frameMs / speed);\n },\n pause() {\n if (timer) {\n clearInterval(timer);\n timer = null;\n }\n },\n step(count = 1) {\n if (!buffer) return;\n index = Math.min(buffer.x.length - 1, index + count);\n applyWindow(index);\n },\n seek(i) {\n if (!buffer) return;\n index = Math.max(0, Math.min(buffer.x.length - 1, i));\n applyWindow(index);\n },\n getIndex() {\n return index;\n },\n getLength() {\n return buffer?.x.length ?? 0;\n },\n isPlaying() {\n return timer != null;\n },\n };\n\n return {\n manifest,\n api,\n onInit(pluginCtx) {\n ctx = pluginCtx;\n const series = ctx.chart.getSeries(config.seriesId);\n if (!series) {\n console.warn(`[PluginReplay] Series \"${config.seriesId}\" not found`);\n return;\n }\n const d = series.getData();\n buffer = {\n x: Float32Array.from(d.x),\n y: d.y ? Float32Array.from(d.y) : undefined,\n open: d.open ? Float32Array.from(d.open) : undefined,\n high: d.high ? Float32Array.from(d.high) : undefined,\n low: d.low ? Float32Array.from(d.low) : undefined,\n close: d.close ? Float32Array.from(d.close) : undefined,\n };\n index = Math.max(0, buffer.x.length - 1);\n },\n onDestroy() {\n api.pause();\n ctx = null;\n buffer = null;\n },\n };\n}\n\nexport default PluginReplay;\n","/**\n * UDF-inspired datafeed contract for trading charts (Stage 2.24).\n */\n\nexport interface SymbolInfo {\n symbol: string;\n name: string;\n description?: string;\n timezone?: string;\n session?: string;\n pricescale?: number;\n minmov?: number;\n}\n\nexport interface Bar {\n time: number;\n open: number;\n high: number;\n low: number;\n close: number;\n volume?: number;\n}\n\nexport interface HistoryRequest {\n symbol: string;\n resolution: string;\n from: number;\n to: number;\n}\n\nexport interface SubscribeBarsRequest {\n symbol: string;\n resolution: string;\n onBar: (bar: Bar) => void;\n}\n\n/**\n * TradingView UDF-style adapter surface.\n */\nexport interface DatafeedAdapter {\n resolveSymbol(symbol: string): Promise<SymbolInfo>;\n getBars(request: HistoryRequest): Promise<Bar[]>;\n subscribeBars(request: SubscribeBarsRequest): () => void;\n}\n\n/** Convert bars to typed OHLC arrays for velo-plot series. */\nexport function barsToOhlc(bars: Bar[]): {\n x: Float64Array;\n open: Float32Array;\n high: Float32Array;\n low: Float32Array;\n close: Float32Array;\n volume: Float32Array;\n} {\n const n = bars.length;\n const x = new Float64Array(n);\n const open = new Float32Array(n);\n const high = new Float32Array(n);\n const low = new Float32Array(n);\n const close = new Float32Array(n);\n const volume = new Float32Array(n);\n for (let i = 0; i < n; i++) {\n const b = bars[i];\n x[i] = b.time;\n open[i] = b.open;\n high[i] = b.high;\n low[i] = b.low;\n close[i] = b.close;\n volume[i] = b.volume ?? 0;\n }\n return { x, open, high, low, close, volume };\n}\n","/**\n * Mock datafeed for demos and tests (Stage 2.25).\n */\n\nimport type {\n Bar,\n DatafeedAdapter,\n HistoryRequest,\n SubscribeBarsRequest,\n SymbolInfo,\n} from \"./datafeed\";\n\nexport interface MockDatafeedOptions {\n symbol?: string;\n barMs?: number;\n basePrice?: number;\n seed?: number;\n}\n\nfunction pseudoRandom(seed: number): () => number {\n let s = seed;\n return () => {\n s = (s * 16807) % 2147483647;\n return (s - 1) / 2147483646;\n };\n}\n\nfunction generateBars(from: number, to: number, barMs: number, base: number, rand: () => number): Bar[] {\n const bars: Bar[] = [];\n let price = base;\n for (let t = from; t <= to; t += barMs) {\n const open = price;\n const delta = (rand() - 0.48) * 2;\n const close = Math.max(1, open + delta);\n const high = Math.max(open, close) + rand() * 1.5;\n const low = Math.min(open, close) - rand() * 1.5;\n bars.push({\n time: t,\n open,\n high,\n low,\n close,\n volume: 1000 + rand() * 5000,\n });\n price = close;\n }\n return bars;\n}\n\nexport function createMockDatafeed(options: MockDatafeedOptions = {}): DatafeedAdapter {\n const barMs = options.barMs ?? 60_000;\n const basePrice = options.basePrice ?? 100;\n const rand = pseudoRandom(options.seed ?? 42);\n const cache = new Map<string, Bar[]>();\n\n return {\n async resolveSymbol(sym: string): Promise<SymbolInfo> {\n return {\n symbol: sym,\n name: sym,\n description: `Mock symbol ${sym}`,\n timezone: \"UTC\",\n session: \"24x7\",\n pricescale: 100,\n };\n },\n\n async getBars(request: HistoryRequest): Promise<Bar[]> {\n const key = `${request.symbol}:${request.from}:${request.to}`;\n if (!cache.has(key)) {\n cache.set(\n key,\n generateBars(request.from, request.to, barMs, basePrice, rand),\n );\n }\n return cache.get(key)!;\n },\n\n subscribeBars(request: SubscribeBarsRequest): () => void {\n let last = basePrice + rand() * 5;\n const timer = setInterval(() => {\n const open = last;\n const close = Math.max(1, open + (rand() - 0.5) * 2);\n const high = Math.max(open, close) + rand();\n const low = Math.min(open, close) - rand();\n request.onBar({\n time: Date.now(),\n open,\n high,\n low,\n close,\n volume: 1000 + rand() * 3000,\n });\n last = close;\n }, barMs);\n return () => clearInterval(timer);\n },\n };\n}\n"],"names":["findNearestBarIndex","barX","x","bestIdx","bestDist","d","snapToCandle","input","idx","candidates","clickPy","threshold","bestY","bestPyDist","cy","py","dist","computeMeasurement","a","b","change","denom","percent","bars","formatMeasurement","m","sign","formatPrice","value","abs","decimals","FIB_LEVELS","DRAG_THRESHOLD_PX","DEFAULT_MEASURE_UP","DEFAULT_MEASURE_DOWN","withAlpha","color","alpha","manifest","isDrawingMode","mode","findCandlestickSeries","ctx","s","PluginDrawingTools","config","autoDeselect","state","stroke","measureUp","measureDown","snapshot","_a","_b","pushUndo","resetInteractionState","setModeInternal","finishStroke","resolvePoint","y","series","dy","pointFromEvent","pluginCtx","event","commitHorizontal","commitVertical","commitMeasure","p0","p1","midX","commitTwoPoint","yMin","yMax","level","fy","drawPreview","c2d","plotArea","coords","cursor","anchor","toPx","px","w","h","drawMeasurePreview","headLen","dir","label","boxW","boxH","boxX","boxY","handleMouseDown","point","handleMouseMove","dx","handleMouseUp","start","enabled","prev","current","next","PluginReplay","buffer","index","timer","speed","frameMs","applyWindow","end","n","slice","arr","api","count","i","barsToOhlc","open","high","low","close","volume","pseudoRandom","seed","generateBars","from","to","barMs","base","rand","price","t","delta","createMockDatafeed","options","basePrice","cache","sym","request","key","last"],"mappings":"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"}
|
|
@@ -8,13 +8,44 @@ export interface ContourPoint {
|
|
|
8
8
|
export interface ContourLine {
|
|
9
9
|
level: number;
|
|
10
10
|
points: ContourPoint[];
|
|
11
|
+
/** Joined polylines (populated when `joinPaths` is enabled). */
|
|
12
|
+
polylines?: ContourPoint[][];
|
|
13
|
+
/** Suggested isoline label placements (populated when `labels` is enabled). */
|
|
14
|
+
labels?: ContourLabel[];
|
|
15
|
+
}
|
|
16
|
+
/** A placed label for an isoline, including rotation to follow the line. */
|
|
17
|
+
export interface ContourLabel {
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
level: number;
|
|
21
|
+
/** Text of the label (formatted level value). */
|
|
22
|
+
text: string;
|
|
23
|
+
/** Rotation angle in radians so the label follows the contour direction. */
|
|
24
|
+
angle: number;
|
|
11
25
|
}
|
|
12
26
|
export interface ContourOptions {
|
|
13
27
|
levels?: number[];
|
|
14
28
|
numLevels?: number;
|
|
29
|
+
/** Join marching-squares segments into continuous polylines. */
|
|
30
|
+
joinPaths?: boolean;
|
|
31
|
+
/** Compute isoline label placements (implies `joinPaths`). */
|
|
32
|
+
labels?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Minimum polyline length (in polyline vertices) required to receive a label.
|
|
35
|
+
* Prevents cluttering short/noisy isolines. Default: 6.
|
|
36
|
+
*/
|
|
37
|
+
minLabelLength?: number;
|
|
38
|
+
/** Formatter for label text. Default: fixed to 2 significant decimals. */
|
|
39
|
+
labelFormatter?: (level: number) => string;
|
|
15
40
|
}
|
|
16
41
|
/**
|
|
17
42
|
* Generate contour lines from a 2D grid of values
|
|
18
43
|
* Values are assumed to be in row-major order: z = values[y * width + x]
|
|
19
44
|
*/
|
|
20
45
|
export declare function generateContours(z: Float32Array | number[], xValues: Float32Array | number[], yValues: Float32Array | number[], options?: ContourOptions): ContourLine[];
|
|
46
|
+
/**
|
|
47
|
+
* Join disjoint marching-squares segments into continuous polylines by
|
|
48
|
+
* chaining segments whose endpoints coincide (within a tolerance). This yields
|
|
49
|
+
* smooth isolines suitable for labeling (task 3.13).
|
|
50
|
+
*/
|
|
51
|
+
export declare function joinSegments(segments: Array<[number, number, number, number]>, tolerance?: number): ContourPoint[][];
|