acttrader-charts 1.2.0-beta.7 → 1.2.0-beta.9
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/README.md +24 -0
- package/dist/{MACD-wDy-dPD_.d.cts → MACD-D1i-sEFR.d.cts} +9 -2
- package/dist/{MACD-wDy-dPD_.d.ts → MACD-D1i-sEFR.d.ts} +9 -2
- package/dist/index.cjs +127 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -2
- package/dist/index.d.ts +7 -2
- package/dist/index.js +127 -16
- package/dist/index.js.map +1 -1
- package/dist/indicators/index.d.cts +2 -2
- package/dist/indicators/index.d.ts +2 -2
- package/dist/webview/chart.html +6 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -892,6 +892,30 @@ Sub-pane heights are user-resizable by dragging the separator between panes.
|
|
|
892
892
|
|
|
893
893
|
`fibRetracement` · `fibExtension` · `fibChannel` · `fibTimezone` · `fibCircles` · `fibSpiral` · `fibFan` · `fibProjection` · `gannFan` · `gannSquare` · `gannBox`
|
|
894
894
|
|
|
895
|
+
**Editable Fib Retracement ratios.** Select a Fib Retracement and open **LEVELS → Configure ▾** in the style popover: each row's ratio is an editable field alongside its visibility checkbox and color swatch. Type a new ratio and press Enter (or click away) and the line moves to it, keeping that row's color and visibility. The number of levels never changes — a value that isn't a finite number, or that another row already uses, reverts to the previous one.
|
|
896
|
+
|
|
897
|
+
Defaults come from the theme (`0` · `0.236` · `0.382` · `0.5` · `0.618` · `0.786` · `1`) and can be changed per theme without touching a drawing:
|
|
898
|
+
|
|
899
|
+
```ts
|
|
900
|
+
new ChartEngine({
|
|
901
|
+
container,
|
|
902
|
+
themeOverrides: {
|
|
903
|
+
dark: {
|
|
904
|
+
drawing: {
|
|
905
|
+
fibRetracement: {
|
|
906
|
+
levels: {
|
|
907
|
+
'0.786': { visible: false, color: '#e8b84b' }, // hide a default ratio
|
|
908
|
+
'0.886': { visible: true, color: '#e8b84b' }, // and draw this one instead
|
|
909
|
+
},
|
|
910
|
+
},
|
|
911
|
+
},
|
|
912
|
+
},
|
|
913
|
+
},
|
|
914
|
+
});
|
|
915
|
+
```
|
|
916
|
+
|
|
917
|
+
In a **per-drawing** style (`SerializedDrawing.style.levels`), a level may also be set to `null` — that removes a theme-supplied ratio for that one drawing, which is how a retyped ratio replaces its original rather than adding to it. Ratios are map keys, so they are written in canonical number form (`'0.5'`, not `'0.50'`).
|
|
918
|
+
|
|
895
919
|
### Shapes
|
|
896
920
|
|
|
897
921
|
`rectangle` · `rotatedRectangle` · `ellipse` · `triangle` · `circle` · `arc` · `polyline` · `path` · `brush` · `highlighter`
|
|
@@ -1254,8 +1254,15 @@ interface DrawingLevelStyle {
|
|
|
1254
1254
|
}
|
|
1255
1255
|
/** Extends DrawingStyle for fib/multi-level drawings. */
|
|
1256
1256
|
interface DrawingFibStyle extends DrawingStyle {
|
|
1257
|
-
/**
|
|
1258
|
-
|
|
1257
|
+
/**
|
|
1258
|
+
* Map of level value (as string, e.g. '0', '0.236', '0.5', '1') → per-level style.
|
|
1259
|
+
*
|
|
1260
|
+
* In a **per-instance** style, `null` marks a level supplied by the theme as
|
|
1261
|
+
* removed for this drawing — used when the user retypes a level's ratio in
|
|
1262
|
+
* the LEVELS → Configure panel, so the old ratio does not come back through
|
|
1263
|
+
* the theme merge. Resolved styles (from `resolveStyle`) never contain null.
|
|
1264
|
+
*/
|
|
1265
|
+
levels?: Record<string, DrawingLevelStyle | null>;
|
|
1259
1266
|
}
|
|
1260
1267
|
/** Union of all drawing style shapes. */
|
|
1261
1268
|
type AnyDrawingStyle = DrawingStyle | DrawingTextStyle | DrawingFibStyle;
|
|
@@ -1254,8 +1254,15 @@ interface DrawingLevelStyle {
|
|
|
1254
1254
|
}
|
|
1255
1255
|
/** Extends DrawingStyle for fib/multi-level drawings. */
|
|
1256
1256
|
interface DrawingFibStyle extends DrawingStyle {
|
|
1257
|
-
/**
|
|
1258
|
-
|
|
1257
|
+
/**
|
|
1258
|
+
* Map of level value (as string, e.g. '0', '0.236', '0.5', '1') → per-level style.
|
|
1259
|
+
*
|
|
1260
|
+
* In a **per-instance** style, `null` marks a level supplied by the theme as
|
|
1261
|
+
* removed for this drawing — used when the user retypes a level's ratio in
|
|
1262
|
+
* the LEVELS → Configure panel, so the old ratio does not come back through
|
|
1263
|
+
* the theme merge. Resolved styles (from `resolveStyle`) never contain null.
|
|
1264
|
+
*/
|
|
1265
|
+
levels?: Record<string, DrawingLevelStyle | null>;
|
|
1259
1266
|
}
|
|
1260
1267
|
/** Union of all drawing style shapes. */
|
|
1261
1268
|
type AnyDrawingStyle = DrawingStyle | DrawingTextStyle | DrawingFibStyle;
|
package/dist/index.cjs
CHANGED
|
@@ -318,6 +318,7 @@ function resolveDrawingThemeVars(drawing, resolve) {
|
|
|
318
318
|
const levels = {};
|
|
319
319
|
for (const lk of Object.keys(resolved.levels)) {
|
|
320
320
|
const lv = resolved.levels[lk];
|
|
321
|
+
if (!lv) continue;
|
|
321
322
|
levels[lk] = { ...lv, color: resolve(lv.color) };
|
|
322
323
|
}
|
|
323
324
|
resolved.levels = levels;
|
|
@@ -8531,10 +8532,19 @@ function resolveStyle(type, instanceStyle, theme) {
|
|
|
8531
8532
|
const themeLevels = themeEntry.levels;
|
|
8532
8533
|
const instLevels = instanceStyle?.levels;
|
|
8533
8534
|
if (themeLevels || instLevels) {
|
|
8534
|
-
const out = {
|
|
8535
|
+
const out = {};
|
|
8536
|
+
for (const k of Object.keys(themeLevels ?? {})) {
|
|
8537
|
+
const lvl = themeLevels?.[k];
|
|
8538
|
+
if (lvl) out[k] = lvl;
|
|
8539
|
+
}
|
|
8535
8540
|
if (instLevels) {
|
|
8536
8541
|
for (const k of Object.keys(instLevels)) {
|
|
8537
|
-
|
|
8542
|
+
const inst = instLevels[k];
|
|
8543
|
+
if (inst === null) {
|
|
8544
|
+
delete out[k];
|
|
8545
|
+
continue;
|
|
8546
|
+
}
|
|
8547
|
+
out[k] = { ...out[k] ?? { visible: true, color: "#888888" }, ...inst };
|
|
8538
8548
|
}
|
|
8539
8549
|
}
|
|
8540
8550
|
merged.levels = out;
|
|
@@ -9155,6 +9165,12 @@ var DisjointChannel = class {
|
|
|
9155
9165
|
var FIB_LEVELS = [0, 0.236, 0.382, 0.5, 0.618, 0.786, 1];
|
|
9156
9166
|
var FIB_FALLBACK_COLORS = ["#ef5350", "#e8b84b", "#26a69a", "#2196f3", "#26a69a", "#e8b84b", "#ef5350"];
|
|
9157
9167
|
var HIT_TOLERANCE9 = 6;
|
|
9168
|
+
function fibLevelEntries(levels) {
|
|
9169
|
+
const fallback = () => FIB_LEVELS.map((value) => ({ key: String(value), value }));
|
|
9170
|
+
if (!levels) return fallback();
|
|
9171
|
+
const entries = Object.keys(levels).filter((key) => levels[key] !== null).map((key) => ({ key, value: Number(key) })).filter((e) => Number.isFinite(e.value));
|
|
9172
|
+
return entries.length ? entries.sort((a, b) => a.value - b.value) : fallback();
|
|
9173
|
+
}
|
|
9158
9174
|
var FibRetracement = class {
|
|
9159
9175
|
constructor(first) {
|
|
9160
9176
|
this.type = "fibRetracement";
|
|
@@ -9180,14 +9196,16 @@ var FibRetracement = class {
|
|
|
9180
9196
|
ctx.save();
|
|
9181
9197
|
ctx.font = "10px 'Inter', system-ui, sans-serif";
|
|
9182
9198
|
ctx.lineWidth = baseLineWidth;
|
|
9183
|
-
|
|
9184
|
-
|
|
9185
|
-
|
|
9199
|
+
const entries = fibLevelEntries(s.levels);
|
|
9200
|
+
const drawn = [];
|
|
9201
|
+
for (let i = 0; i < entries.length; i++) {
|
|
9202
|
+
const { key, value: level } = entries[i];
|
|
9186
9203
|
const lvl = s.levels?.[key];
|
|
9187
9204
|
if (lvl?.visible === false) continue;
|
|
9205
|
+
drawn.push(level);
|
|
9188
9206
|
const price = highPrice - range * level;
|
|
9189
9207
|
const y = scale.yToPixel(price, priceRange, chartH);
|
|
9190
|
-
const baseColor = lvl?.color ?? s.strokeColor ?? FIB_FALLBACK_COLORS[i];
|
|
9208
|
+
const baseColor = lvl?.color ?? s.strokeColor ?? FIB_FALLBACK_COLORS[i % FIB_FALLBACK_COLORS.length];
|
|
9191
9209
|
const color = hexWithAlpha(baseColor, isSelected ? 0.8 : 0.6);
|
|
9192
9210
|
ctx.strokeStyle = color;
|
|
9193
9211
|
applyLineStyle(ctx, isSelected ? "solid" : s.lineStyle, baseLineWidth);
|
|
@@ -9201,6 +9219,7 @@ var FibRetracement = class {
|
|
|
9201
9219
|
ctx.fillStyle = color;
|
|
9202
9220
|
ctx.fillText(lbl, xMin + 4, y - 3);
|
|
9203
9221
|
}
|
|
9222
|
+
this.visibleLevels = drawn;
|
|
9204
9223
|
for (const [ax, ay] of [[x1, y1], [x22, y22]]) {
|
|
9205
9224
|
ctx.beginPath();
|
|
9206
9225
|
ctx.arc(ax, ay, isSelected ? 4 : 3, 0, Math.PI * 2);
|
|
@@ -9214,7 +9233,7 @@ var FibRetracement = class {
|
|
|
9214
9233
|
const highPrice = Math.max(this.points[0].price, this.points[1].price);
|
|
9215
9234
|
const lowPrice = Math.min(this.points[0].price, this.points[1].price);
|
|
9216
9235
|
const range = highPrice - lowPrice;
|
|
9217
|
-
for (const level of FIB_LEVELS) {
|
|
9236
|
+
for (const level of this.visibleLevels ?? FIB_LEVELS) {
|
|
9218
9237
|
const price = highPrice - range * level;
|
|
9219
9238
|
const lineY = scale.yToPixel(price, priceRange, chartH);
|
|
9220
9239
|
if (Math.abs(y - lineY) <= HIT_TOLERANCE9) return true;
|
|
@@ -14800,9 +14819,9 @@ var DrawingManager = class {
|
|
|
14800
14819
|
updateDrawingStyle(id, patch) {
|
|
14801
14820
|
const drawing = this.getDrawingById(id);
|
|
14802
14821
|
if (!drawing) return null;
|
|
14822
|
+
const existingLevels = drawing.style?.levels;
|
|
14803
14823
|
drawing.style = { ...drawing.style ?? {}, ...patch };
|
|
14804
14824
|
const patchLevels = patch.levels;
|
|
14805
|
-
const existingLevels = drawing.style.levels;
|
|
14806
14825
|
if (patchLevels && existingLevels) {
|
|
14807
14826
|
drawing.style.levels = {
|
|
14808
14827
|
...existingLevels,
|
|
@@ -16854,6 +16873,23 @@ var POPOVER_CONTROLS = {
|
|
|
16854
16873
|
var LINE_WIDTHS = [1, 2, 3, 4];
|
|
16855
16874
|
var FONT_SIZES = [10, 11, 12, 13, 14, 16, 18, 20, 24];
|
|
16856
16875
|
var SWATCH_PX = 24;
|
|
16876
|
+
var EDITABLE_LEVEL_TYPES = /* @__PURE__ */ new Set(["fibRetracement"]);
|
|
16877
|
+
function mergeLevels(themeLevels, instLevels) {
|
|
16878
|
+
const out = {};
|
|
16879
|
+
for (const k of Object.keys(themeLevels ?? {})) {
|
|
16880
|
+
const lvl = themeLevels?.[k];
|
|
16881
|
+
if (lvl) out[k] = lvl;
|
|
16882
|
+
}
|
|
16883
|
+
for (const k of Object.keys(instLevels ?? {})) {
|
|
16884
|
+
const lvl = instLevels?.[k];
|
|
16885
|
+
if (lvl === null) delete out[k];
|
|
16886
|
+
else if (lvl) out[k] = { ...out[k] ?? { visible: true, color: "#888888" }, ...lvl };
|
|
16887
|
+
}
|
|
16888
|
+
return out;
|
|
16889
|
+
}
|
|
16890
|
+
function levelKey(value) {
|
|
16891
|
+
return String(value);
|
|
16892
|
+
}
|
|
16857
16893
|
var DrawingStylePopover = class {
|
|
16858
16894
|
constructor(container, theme, onChange) {
|
|
16859
16895
|
this.currentDrawing = null;
|
|
@@ -16998,7 +17034,9 @@ var DrawingStylePopover = class {
|
|
|
16998
17034
|
case "fibLevels":
|
|
16999
17035
|
groups.push(this.group(
|
|
17000
17036
|
"Levels",
|
|
17001
|
-
this.buildFibLevelsButton(
|
|
17037
|
+
this.buildFibLevelsButton(
|
|
17038
|
+
mergeLevels(themeEntry.levels, style.levels)
|
|
17039
|
+
)
|
|
17002
17040
|
));
|
|
17003
17041
|
break;
|
|
17004
17042
|
}
|
|
@@ -17198,6 +17236,65 @@ var DrawingStylePopover = class {
|
|
|
17198
17236
|
});
|
|
17199
17237
|
return wrap;
|
|
17200
17238
|
}
|
|
17239
|
+
/** Static ratio text — used for level sets whose ratios are fixed. */
|
|
17240
|
+
buildLevelRatioLabel(key) {
|
|
17241
|
+
const label = document.createElement("span");
|
|
17242
|
+
label.textContent = key;
|
|
17243
|
+
Object.assign(label.style, { fontSize: "11px", color: this.theme.tooltip.text });
|
|
17244
|
+
return label;
|
|
17245
|
+
}
|
|
17246
|
+
/**
|
|
17247
|
+
* Editable ratio field (TradingView-style): the user retypes a level's ratio
|
|
17248
|
+
* and the line moves, keeping its color and visibility. Commits on Enter or
|
|
17249
|
+
* blur; reverts when the value isn't a finite number or already belongs to
|
|
17250
|
+
* another row, so the level count never changes.
|
|
17251
|
+
*/
|
|
17252
|
+
buildLevelRatioInput(initialKey, taken, onCommit) {
|
|
17253
|
+
let current = initialKey;
|
|
17254
|
+
const input = document.createElement("input");
|
|
17255
|
+
input.type = "number";
|
|
17256
|
+
input.step = "0.001";
|
|
17257
|
+
input.value = current;
|
|
17258
|
+
input.title = "Level ratio \u2014 press Enter to apply";
|
|
17259
|
+
Object.assign(input.style, {
|
|
17260
|
+
width: "58px",
|
|
17261
|
+
padding: "2px 4px",
|
|
17262
|
+
fontSize: "11px",
|
|
17263
|
+
fontFamily: "inherit",
|
|
17264
|
+
color: this.theme.tooltip.text,
|
|
17265
|
+
background: this.theme.background,
|
|
17266
|
+
border: `1px solid ${this.theme.axisBorder}`,
|
|
17267
|
+
borderRadius: "3px",
|
|
17268
|
+
outline: "none"
|
|
17269
|
+
});
|
|
17270
|
+
input.addEventListener("focus", () => {
|
|
17271
|
+
input.style.borderColor = this.theme.ui.accent;
|
|
17272
|
+
});
|
|
17273
|
+
input.addEventListener("blur", () => {
|
|
17274
|
+
input.style.borderColor = this.theme.axisBorder;
|
|
17275
|
+
});
|
|
17276
|
+
input.addEventListener("keydown", (e) => {
|
|
17277
|
+
e.stopPropagation();
|
|
17278
|
+
if (e.key === "Enter") input.blur();
|
|
17279
|
+
});
|
|
17280
|
+
const commit = () => {
|
|
17281
|
+
const raw = Number(input.value);
|
|
17282
|
+
const next = Number.isFinite(raw) ? levelKey(raw) : null;
|
|
17283
|
+
if (next === null || next !== current && taken.has(next)) {
|
|
17284
|
+
input.value = current;
|
|
17285
|
+
return;
|
|
17286
|
+
}
|
|
17287
|
+
if (next === current) {
|
|
17288
|
+
input.value = current;
|
|
17289
|
+
return;
|
|
17290
|
+
}
|
|
17291
|
+
current = next;
|
|
17292
|
+
input.value = next;
|
|
17293
|
+
onCommit(next);
|
|
17294
|
+
};
|
|
17295
|
+
input.addEventListener("change", commit);
|
|
17296
|
+
return input;
|
|
17297
|
+
}
|
|
17201
17298
|
openFibPanel(anchor, levels) {
|
|
17202
17299
|
this.closeFibPanel();
|
|
17203
17300
|
const panel = document.createElement("div");
|
|
@@ -17219,23 +17316,37 @@ var DrawingStylePopover = class {
|
|
|
17219
17316
|
alignItems: "center"
|
|
17220
17317
|
});
|
|
17221
17318
|
const keys = Object.keys(levels).sort((a, b) => Number(a) - Number(b));
|
|
17319
|
+
const editable = this.currentDrawing !== null && EDITABLE_LEVEL_TYPES.has(this.currentDrawing.type);
|
|
17320
|
+
const taken = new Set(keys);
|
|
17222
17321
|
for (const k of keys) {
|
|
17223
17322
|
const level = levels[k];
|
|
17323
|
+
let key = k;
|
|
17324
|
+
let color = level.color;
|
|
17224
17325
|
const cb = document.createElement("input");
|
|
17225
17326
|
cb.type = "checkbox";
|
|
17226
17327
|
cb.checked = level.visible !== false;
|
|
17227
17328
|
cb.style.accentColor = this.theme.ui.accent;
|
|
17228
17329
|
cb.style.cursor = "pointer";
|
|
17229
|
-
const
|
|
17230
|
-
|
|
17231
|
-
|
|
17232
|
-
const swatch = this.makeColorSwatch(level.color, (hex) => {
|
|
17233
|
-
this.emit({ levels: { [k]: { visible: cb.checked, color: hex } } });
|
|
17330
|
+
const swatch = this.makeColorSwatch(color, (hex) => {
|
|
17331
|
+
color = hex;
|
|
17332
|
+
this.emit({ levels: { [key]: { visible: cb.checked, color: hex } } });
|
|
17234
17333
|
});
|
|
17235
17334
|
cb.addEventListener("change", () => {
|
|
17236
|
-
this.emit({ levels: { [
|
|
17335
|
+
this.emit({ levels: { [key]: { visible: cb.checked, color } } });
|
|
17237
17336
|
});
|
|
17238
|
-
panel.append(cb,
|
|
17337
|
+
panel.append(cb, editable ? this.buildLevelRatioInput(
|
|
17338
|
+
k,
|
|
17339
|
+
taken,
|
|
17340
|
+
(nextKey) => {
|
|
17341
|
+
this.emit({ levels: {
|
|
17342
|
+
[key]: null,
|
|
17343
|
+
[nextKey]: { visible: cb.checked, color }
|
|
17344
|
+
} });
|
|
17345
|
+
taken.delete(key);
|
|
17346
|
+
taken.add(nextKey);
|
|
17347
|
+
key = nextKey;
|
|
17348
|
+
}
|
|
17349
|
+
) : this.buildLevelRatioLabel(k), swatch);
|
|
17239
17350
|
}
|
|
17240
17351
|
const anchorRect = anchor.getBoundingClientRect();
|
|
17241
17352
|
const cRect = this.container.getBoundingClientRect();
|