hyperprop-charting-library 0.1.132 → 0.1.133
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/hyperprop-charting-library.cjs +319 -8
- package/dist/hyperprop-charting-library.d.ts +8 -1
- package/dist/hyperprop-charting-library.js +317 -7
- package/dist/index.cjs +319 -8
- package/dist/index.d.cts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +317 -7
- package/docs/API.md +15 -0
- package/package.json +1 -1
|
@@ -23,7 +23,8 @@ __export(index_exports, {
|
|
|
23
23
|
FIB_DEFAULT_PALETTE: () => FIB_DEFAULT_PALETTE,
|
|
24
24
|
POSITION_DEFAULT_COLORS: () => POSITION_DEFAULT_COLORS,
|
|
25
25
|
compileScriptIndicator: () => compileScriptIndicator,
|
|
26
|
-
createChart: () => createChart
|
|
26
|
+
createChart: () => createChart,
|
|
27
|
+
validateScriptSource: () => validateScriptSource
|
|
27
28
|
});
|
|
28
29
|
module.exports = __toCommonJS(index_exports);
|
|
29
30
|
var POSITION_DEFAULT_COLORS = ["#26a69a", "#ef5350", "#ffffff"];
|
|
@@ -630,14 +631,23 @@ var withCachedSeries = (key, data, compute) => {
|
|
|
630
631
|
return values;
|
|
631
632
|
};
|
|
632
633
|
var builtInComputationCache = /* @__PURE__ */ new Map();
|
|
634
|
+
var COMPUTATION_CACHE_MAX_ENTRIES = 128;
|
|
633
635
|
var withCachedComputation = (key, data, compute) => {
|
|
634
636
|
const fingerprint = getSeriesFingerprint(data);
|
|
635
637
|
const existing = builtInComputationCache.get(key);
|
|
636
638
|
if (existing && existing.fingerprint === fingerprint) {
|
|
639
|
+
builtInComputationCache.delete(key);
|
|
640
|
+
builtInComputationCache.set(key, existing);
|
|
637
641
|
return existing.value;
|
|
638
642
|
}
|
|
639
643
|
const value = compute();
|
|
644
|
+
builtInComputationCache.delete(key);
|
|
640
645
|
builtInComputationCache.set(key, { fingerprint, value });
|
|
646
|
+
while (builtInComputationCache.size > COMPUTATION_CACHE_MAX_ENTRIES) {
|
|
647
|
+
const oldest = builtInComputationCache.keys().next().value;
|
|
648
|
+
if (oldest === void 0) break;
|
|
649
|
+
builtInComputationCache.delete(oldest);
|
|
650
|
+
}
|
|
641
651
|
return value;
|
|
642
652
|
};
|
|
643
653
|
var rollingExtremeSeries = (values, length, mode) => {
|
|
@@ -1569,14 +1579,304 @@ var hashScriptSource = (source) => {
|
|
|
1569
1579
|
}
|
|
1570
1580
|
return (hash >>> 0).toString(36);
|
|
1571
1581
|
};
|
|
1572
|
-
var
|
|
1573
|
-
|
|
1582
|
+
var SCRIPT_GUARD_BUDGET_MS = 1e3;
|
|
1583
|
+
var ScriptBudgetError = class extends Error {
|
|
1584
|
+
constructor() {
|
|
1585
|
+
super(
|
|
1586
|
+
`Script exceeded the ${SCRIPT_GUARD_BUDGET_MS}ms execution budget (possible infinite loop) \u2014 edit the script to retry`
|
|
1587
|
+
);
|
|
1588
|
+
this.name = "ScriptBudgetError";
|
|
1589
|
+
}
|
|
1590
|
+
};
|
|
1591
|
+
var createScriptGuard = () => {
|
|
1592
|
+
let deadline = Date.now() + SCRIPT_GUARD_BUDGET_MS;
|
|
1593
|
+
let count = 0;
|
|
1594
|
+
const guard = (() => {
|
|
1595
|
+
count += 1;
|
|
1596
|
+
if ((count & 1023) === 0 && Date.now() > deadline) {
|
|
1597
|
+
throw new ScriptBudgetError();
|
|
1598
|
+
}
|
|
1599
|
+
return true;
|
|
1600
|
+
});
|
|
1601
|
+
guard.reset = () => {
|
|
1602
|
+
count = 0;
|
|
1603
|
+
deadline = Date.now() + SCRIPT_GUARD_BUDGET_MS;
|
|
1604
|
+
};
|
|
1605
|
+
return guard;
|
|
1606
|
+
};
|
|
1607
|
+
var injectLoopGuards = (source, guardName) => {
|
|
1608
|
+
const n = source.length;
|
|
1609
|
+
const isIdChar = (ch) => ch >= "a" && ch <= "z" || ch >= "A" && ch <= "Z" || ch >= "0" && ch <= "9" || ch === "_" || ch === "$";
|
|
1610
|
+
const scanString = (start) => {
|
|
1611
|
+
const quote = source[start];
|
|
1612
|
+
let j = start + 1;
|
|
1613
|
+
while (j < n) {
|
|
1614
|
+
const cj = source[j];
|
|
1615
|
+
if (cj === "\\") {
|
|
1616
|
+
j += 2;
|
|
1617
|
+
continue;
|
|
1618
|
+
}
|
|
1619
|
+
if (cj === quote) {
|
|
1620
|
+
return j + 1;
|
|
1621
|
+
}
|
|
1622
|
+
if (quote === "`" && cj === "$" && source[j + 1] === "{") {
|
|
1623
|
+
let depth = 1;
|
|
1624
|
+
j += 2;
|
|
1625
|
+
while (j < n && depth > 0) {
|
|
1626
|
+
const ce = source[j];
|
|
1627
|
+
if (ce === "\\") {
|
|
1628
|
+
j += 2;
|
|
1629
|
+
continue;
|
|
1630
|
+
}
|
|
1631
|
+
if (ce === '"' || ce === "'" || ce === "`") {
|
|
1632
|
+
j = scanString(j);
|
|
1633
|
+
continue;
|
|
1634
|
+
}
|
|
1635
|
+
if (ce === "{") depth += 1;
|
|
1636
|
+
else if (ce === "}") depth -= 1;
|
|
1637
|
+
j += 1;
|
|
1638
|
+
}
|
|
1639
|
+
continue;
|
|
1640
|
+
}
|
|
1641
|
+
j += 1;
|
|
1642
|
+
}
|
|
1643
|
+
return n;
|
|
1644
|
+
};
|
|
1645
|
+
const scanRegex = (start) => {
|
|
1646
|
+
let j = start + 1;
|
|
1647
|
+
let inClass = false;
|
|
1648
|
+
while (j < n) {
|
|
1649
|
+
const cj = source[j];
|
|
1650
|
+
if (cj === "\\") {
|
|
1651
|
+
j += 2;
|
|
1652
|
+
continue;
|
|
1653
|
+
}
|
|
1654
|
+
if (cj === "\n") return j;
|
|
1655
|
+
if (cj === "[") inClass = true;
|
|
1656
|
+
else if (cj === "]") inClass = false;
|
|
1657
|
+
else if (cj === "/" && !inClass) return j + 1;
|
|
1658
|
+
j += 1;
|
|
1659
|
+
}
|
|
1660
|
+
return n;
|
|
1661
|
+
};
|
|
1662
|
+
const skipWsAndComments = (k) => {
|
|
1663
|
+
let j = k;
|
|
1664
|
+
while (j < n) {
|
|
1665
|
+
const cj = source[j];
|
|
1666
|
+
if (cj === " " || cj === " " || cj === "\n" || cj === "\r") {
|
|
1667
|
+
j += 1;
|
|
1668
|
+
continue;
|
|
1669
|
+
}
|
|
1670
|
+
if (cj === "/" && source[j + 1] === "/") {
|
|
1671
|
+
const nl = source.indexOf("\n", j);
|
|
1672
|
+
j = nl === -1 ? n : nl + 1;
|
|
1673
|
+
continue;
|
|
1674
|
+
}
|
|
1675
|
+
if (cj === "/" && source[j + 1] === "*") {
|
|
1676
|
+
const end = source.indexOf("*/", j + 2);
|
|
1677
|
+
j = end === -1 ? n : end + 2;
|
|
1678
|
+
continue;
|
|
1679
|
+
}
|
|
1680
|
+
return j;
|
|
1681
|
+
}
|
|
1682
|
+
return n;
|
|
1683
|
+
};
|
|
1684
|
+
const matchParen = (openIdx) => {
|
|
1685
|
+
let depth = 0;
|
|
1686
|
+
let j = openIdx;
|
|
1687
|
+
while (j < n) {
|
|
1688
|
+
const cj = source[j];
|
|
1689
|
+
if (cj === '"' || cj === "'" || cj === "`") {
|
|
1690
|
+
j = scanString(j);
|
|
1691
|
+
continue;
|
|
1692
|
+
}
|
|
1693
|
+
if (cj === "/" && source[j + 1] === "/") {
|
|
1694
|
+
const nl = source.indexOf("\n", j);
|
|
1695
|
+
j = nl === -1 ? n : nl + 1;
|
|
1696
|
+
continue;
|
|
1697
|
+
}
|
|
1698
|
+
if (cj === "/" && source[j + 1] === "*") {
|
|
1699
|
+
const end = source.indexOf("*/", j + 2);
|
|
1700
|
+
j = end === -1 ? n : end + 2;
|
|
1701
|
+
continue;
|
|
1702
|
+
}
|
|
1703
|
+
if (cj === "(") depth += 1;
|
|
1704
|
+
else if (cj === ")") {
|
|
1705
|
+
depth -= 1;
|
|
1706
|
+
if (depth === 0) return j;
|
|
1707
|
+
}
|
|
1708
|
+
j += 1;
|
|
1709
|
+
}
|
|
1710
|
+
return -1;
|
|
1711
|
+
};
|
|
1712
|
+
const splitTopLevelSemicolons = (inner) => {
|
|
1713
|
+
const parts = [];
|
|
1714
|
+
let depth = 0;
|
|
1715
|
+
let j = 0;
|
|
1716
|
+
let last = 0;
|
|
1717
|
+
const m = inner.length;
|
|
1718
|
+
while (j < m) {
|
|
1719
|
+
const cj = inner[j];
|
|
1720
|
+
if (cj === '"' || cj === "'" || cj === "`") {
|
|
1721
|
+
const quote = cj;
|
|
1722
|
+
j += 1;
|
|
1723
|
+
while (j < m) {
|
|
1724
|
+
if (inner[j] === "\\") {
|
|
1725
|
+
j += 2;
|
|
1726
|
+
continue;
|
|
1727
|
+
}
|
|
1728
|
+
if (inner[j] === quote) {
|
|
1729
|
+
j += 1;
|
|
1730
|
+
break;
|
|
1731
|
+
}
|
|
1732
|
+
j += 1;
|
|
1733
|
+
}
|
|
1734
|
+
continue;
|
|
1735
|
+
}
|
|
1736
|
+
if (cj === "(" || cj === "[" || cj === "{") depth += 1;
|
|
1737
|
+
else if (cj === ")" || cj === "]" || cj === "}") depth -= 1;
|
|
1738
|
+
else if (cj === ";" && depth === 0) {
|
|
1739
|
+
parts.push(inner.slice(last, j));
|
|
1740
|
+
last = j + 1;
|
|
1741
|
+
}
|
|
1742
|
+
j += 1;
|
|
1743
|
+
}
|
|
1744
|
+
parts.push(inner.slice(last));
|
|
1745
|
+
return parts;
|
|
1746
|
+
};
|
|
1747
|
+
const REGEX_PRECEDING_WORDS = /* @__PURE__ */ new Set([
|
|
1748
|
+
"return",
|
|
1749
|
+
"typeof",
|
|
1750
|
+
"case",
|
|
1751
|
+
"do",
|
|
1752
|
+
"else",
|
|
1753
|
+
"in",
|
|
1754
|
+
"of",
|
|
1755
|
+
"new",
|
|
1756
|
+
"delete",
|
|
1757
|
+
"void",
|
|
1758
|
+
"instanceof",
|
|
1759
|
+
"yield",
|
|
1760
|
+
"await"
|
|
1761
|
+
]);
|
|
1762
|
+
let out = "";
|
|
1763
|
+
let i = 0;
|
|
1764
|
+
let lastSig = "";
|
|
1765
|
+
let lastWord = "";
|
|
1766
|
+
while (i < n) {
|
|
1767
|
+
const ch = source[i];
|
|
1768
|
+
if (ch === "/" && source[i + 1] === "/") {
|
|
1769
|
+
const nl = source.indexOf("\n", i);
|
|
1770
|
+
const end = nl === -1 ? n : nl;
|
|
1771
|
+
out += source.slice(i, end);
|
|
1772
|
+
i = end;
|
|
1773
|
+
continue;
|
|
1774
|
+
}
|
|
1775
|
+
if (ch === "/" && source[i + 1] === "*") {
|
|
1776
|
+
const close = source.indexOf("*/", i + 2);
|
|
1777
|
+
const end = close === -1 ? n : close + 2;
|
|
1778
|
+
out += source.slice(i, end);
|
|
1779
|
+
i = end;
|
|
1780
|
+
continue;
|
|
1781
|
+
}
|
|
1782
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
1783
|
+
const end = scanString(i);
|
|
1784
|
+
out += source.slice(i, end);
|
|
1785
|
+
lastSig = ch;
|
|
1786
|
+
lastWord = "";
|
|
1787
|
+
i = end;
|
|
1788
|
+
continue;
|
|
1789
|
+
}
|
|
1790
|
+
if (ch === "/") {
|
|
1791
|
+
const regexLikely = lastSig === "" || "(,=:;!&|?{}[+-*%~^<>".includes(lastSig) || REGEX_PRECEDING_WORDS.has(lastWord);
|
|
1792
|
+
if (regexLikely) {
|
|
1793
|
+
const end = scanRegex(i);
|
|
1794
|
+
out += source.slice(i, end);
|
|
1795
|
+
lastSig = "/";
|
|
1796
|
+
lastWord = "";
|
|
1797
|
+
i = end;
|
|
1798
|
+
continue;
|
|
1799
|
+
}
|
|
1800
|
+
out += ch;
|
|
1801
|
+
lastSig = ch;
|
|
1802
|
+
lastWord = "";
|
|
1803
|
+
i += 1;
|
|
1804
|
+
continue;
|
|
1805
|
+
}
|
|
1806
|
+
if (isIdChar(ch)) {
|
|
1807
|
+
let j = i;
|
|
1808
|
+
while (j < n && isIdChar(source[j])) j += 1;
|
|
1809
|
+
const word = source.slice(i, j);
|
|
1810
|
+
if ((word === "while" || word === "for") && lastSig !== ".") {
|
|
1811
|
+
const k = skipWsAndComments(j);
|
|
1812
|
+
if (source[k] === "(") {
|
|
1813
|
+
const close = matchParen(k);
|
|
1814
|
+
if (close !== -1) {
|
|
1815
|
+
const inner = source.slice(k + 1, close);
|
|
1816
|
+
if (word === "while") {
|
|
1817
|
+
out += `while (${guardName}() && (${inner}))`;
|
|
1818
|
+
lastSig = ")";
|
|
1819
|
+
lastWord = "";
|
|
1820
|
+
i = close + 1;
|
|
1821
|
+
continue;
|
|
1822
|
+
}
|
|
1823
|
+
const parts = splitTopLevelSemicolons(inner);
|
|
1824
|
+
if (parts.length === 3) {
|
|
1825
|
+
const cond = parts[1].trim();
|
|
1826
|
+
const guardedCond = cond ? `${guardName}() && (${cond})` : `${guardName}()`;
|
|
1827
|
+
out += `for (${parts[0]}; ${guardedCond}; ${parts[2]})`;
|
|
1828
|
+
lastSig = ")";
|
|
1829
|
+
lastWord = "";
|
|
1830
|
+
i = close + 1;
|
|
1831
|
+
continue;
|
|
1832
|
+
}
|
|
1833
|
+
out += source.slice(i, close + 1);
|
|
1834
|
+
lastSig = ")";
|
|
1835
|
+
lastWord = "";
|
|
1836
|
+
i = close + 1;
|
|
1837
|
+
continue;
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
out += word;
|
|
1842
|
+
lastSig = word[word.length - 1];
|
|
1843
|
+
lastWord = word;
|
|
1844
|
+
i = j;
|
|
1845
|
+
continue;
|
|
1846
|
+
}
|
|
1847
|
+
out += ch;
|
|
1848
|
+
if (ch !== " " && ch !== " " && ch !== "\n" && ch !== "\r") {
|
|
1849
|
+
lastSig = ch;
|
|
1850
|
+
lastWord = "";
|
|
1851
|
+
}
|
|
1852
|
+
i += 1;
|
|
1853
|
+
}
|
|
1854
|
+
return out;
|
|
1855
|
+
};
|
|
1856
|
+
var compileScriptCompute = (source, guard) => {
|
|
1857
|
+
const makeFactory = (body) => new Function(
|
|
1858
|
+
"__hpGuard",
|
|
1574
1859
|
`"use strict";
|
|
1575
|
-
${
|
|
1860
|
+
${body}
|
|
1576
1861
|
;if (typeof compute !== "function") { throw new Error("Script must define function compute(bars, inputs, hp)"); }
|
|
1577
1862
|
return compute;`
|
|
1578
1863
|
);
|
|
1579
|
-
|
|
1864
|
+
let factory;
|
|
1865
|
+
try {
|
|
1866
|
+
factory = makeFactory(injectLoopGuards(source, "__hpGuard"));
|
|
1867
|
+
} catch {
|
|
1868
|
+
factory = makeFactory(source);
|
|
1869
|
+
}
|
|
1870
|
+
guard.reset();
|
|
1871
|
+
return factory(guard);
|
|
1872
|
+
};
|
|
1873
|
+
var validateScriptSource = (source) => {
|
|
1874
|
+
try {
|
|
1875
|
+
compileScriptCompute(source, createScriptGuard());
|
|
1876
|
+
return null;
|
|
1877
|
+
} catch (error) {
|
|
1878
|
+
return error instanceof Error ? error.message : String(error);
|
|
1879
|
+
}
|
|
1580
1880
|
};
|
|
1581
1881
|
var drawScriptError = (ctx, renderContext, name, message) => {
|
|
1582
1882
|
ctx.save();
|
|
@@ -1596,17 +1896,23 @@ var compileScriptIndicator = (definition) => {
|
|
|
1596
1896
|
}
|
|
1597
1897
|
let compiled = null;
|
|
1598
1898
|
let compileError = null;
|
|
1899
|
+
const guard = createScriptGuard();
|
|
1599
1900
|
try {
|
|
1600
|
-
compiled = compileScriptCompute(definition.source);
|
|
1901
|
+
compiled = compileScriptCompute(definition.source, guard);
|
|
1601
1902
|
} catch (error) {
|
|
1602
1903
|
compileError = error instanceof Error ? error.message : String(error);
|
|
1603
1904
|
}
|
|
1604
1905
|
const sourceKey = hashScriptSource(definition.source);
|
|
1906
|
+
let trippedError = null;
|
|
1605
1907
|
const runCompute = (data, inputs) => {
|
|
1606
1908
|
if (!compiled) {
|
|
1607
1909
|
return { error: compileError ?? "Script failed to compile" };
|
|
1608
1910
|
}
|
|
1911
|
+
if (trippedError) {
|
|
1912
|
+
return { error: trippedError };
|
|
1913
|
+
}
|
|
1609
1914
|
try {
|
|
1915
|
+
guard.reset();
|
|
1610
1916
|
const result = compiled(data, inputs, SCRIPT_HELPERS);
|
|
1611
1917
|
if (!result || !Array.isArray(result.plots)) {
|
|
1612
1918
|
return { error: "compute() must return { plots: [...] }" };
|
|
@@ -1618,7 +1924,11 @@ var compileScriptIndicator = (definition) => {
|
|
|
1618
1924
|
}
|
|
1619
1925
|
return { result };
|
|
1620
1926
|
} catch (error) {
|
|
1621
|
-
|
|
1927
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1928
|
+
if (error instanceof ScriptBudgetError) {
|
|
1929
|
+
trippedError = message;
|
|
1930
|
+
}
|
|
1931
|
+
return { error: message };
|
|
1622
1932
|
}
|
|
1623
1933
|
};
|
|
1624
1934
|
const cachedCompute = (data, inputs) => withCachedComputation(
|
|
@@ -8068,5 +8378,6 @@ function createChart(element, options = {}) {
|
|
|
8068
8378
|
FIB_DEFAULT_PALETTE,
|
|
8069
8379
|
POSITION_DEFAULT_COLORS,
|
|
8070
8380
|
compileScriptIndicator,
|
|
8071
|
-
createChart
|
|
8381
|
+
createChart,
|
|
8382
|
+
validateScriptSource
|
|
8072
8383
|
});
|
|
@@ -547,6 +547,13 @@ interface ScriptComputeResult {
|
|
|
547
547
|
guides?: number[];
|
|
548
548
|
decimals?: number;
|
|
549
549
|
}
|
|
550
|
+
/**
|
|
551
|
+
* Compile-check a script without registering it: returns an error message, or
|
|
552
|
+
* `null` when the script compiles. Runs with the same execution guard as the
|
|
553
|
+
* chart, so a top-level infinite loop returns a budget error instead of
|
|
554
|
+
* hanging the caller (e.g. an editor's save validation).
|
|
555
|
+
*/
|
|
556
|
+
declare const validateScriptSource: (source: string) => string | null;
|
|
550
557
|
/**
|
|
551
558
|
* Compile a user-authored script into a regular indicator plugin. The plugin
|
|
552
559
|
* can then be registered with `chart.registerIndicator(...)` and behaves like
|
|
@@ -653,4 +660,4 @@ interface ViewportState {
|
|
|
653
660
|
}
|
|
654
661
|
declare function createChart(element: HTMLElement, options?: ChartOptions): ChartInstance;
|
|
655
662
|
|
|
656
|
-
export { type AxisOptions, type BuiltInIndicatorInfo, type ChartClickEvent, type ChartInstance, type ChartOptions, type ChartType, type CrosshairMoveEvent, type CrosshairOptions, type CrosshairPriceActionEvent, type DashPatternOptions, type DrawingDefaults, type DrawingHoverEvent, type DrawingObjectOptions, type DrawingPoint, type DrawingSelectEvent, type DrawingToolType, FIB_DEFAULT_PALETTE, type GridOptions, type IndicatorInstanceOptions, type IndicatorPane, type IndicatorPaneActionEvent, type IndicatorPaneAxisOptions, type IndicatorPaneGuideLine, type IndicatorPaneHeightChangeEvent, type IndicatorPaneRenderInfo, type IndicatorPaneValue, type IndicatorPaneValueLabel, type IndicatorPlugin, type IndicatorRenderContext, type LabelsOptions, type OhlcDataPoint, type OrderActionButton, type OrderActionEvent, type OrderLineOptions, POSITION_DEFAULT_COLORS, type PriceLineOptions, type ScriptComputeResult, type ScriptIndicatorDefinition, type ScriptIndicatorInputDef, type ScriptPlotSpec, type TickerLineOptions, type TradeMarkerOptions, type ViewportState, type WatermarkOptions, compileScriptIndicator, createChart };
|
|
663
|
+
export { type AxisOptions, type BuiltInIndicatorInfo, type ChartClickEvent, type ChartInstance, type ChartOptions, type ChartType, type CrosshairMoveEvent, type CrosshairOptions, type CrosshairPriceActionEvent, type DashPatternOptions, type DrawingDefaults, type DrawingHoverEvent, type DrawingObjectOptions, type DrawingPoint, type DrawingSelectEvent, type DrawingToolType, FIB_DEFAULT_PALETTE, type GridOptions, type IndicatorInstanceOptions, type IndicatorPane, type IndicatorPaneActionEvent, type IndicatorPaneAxisOptions, type IndicatorPaneGuideLine, type IndicatorPaneHeightChangeEvent, type IndicatorPaneRenderInfo, type IndicatorPaneValue, type IndicatorPaneValueLabel, type IndicatorPlugin, type IndicatorRenderContext, type LabelsOptions, type OhlcDataPoint, type OrderActionButton, type OrderActionEvent, type OrderLineOptions, POSITION_DEFAULT_COLORS, type PriceLineOptions, type ScriptComputeResult, type ScriptIndicatorDefinition, type ScriptIndicatorInputDef, type ScriptPlotSpec, type TickerLineOptions, type TradeMarkerOptions, type ViewportState, type WatermarkOptions, compileScriptIndicator, createChart, validateScriptSource };
|