orderflow-metrics 0.24.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/CHANGELOG.md +229 -0
- package/LICENSE +21 -0
- package/README.md +556 -0
- package/dist/bars.d.ts +67 -0
- package/dist/bars.d.ts.map +1 -0
- package/dist/bars.js +92 -0
- package/dist/bars.js.map +1 -0
- package/dist/classify.d.ts +25 -0
- package/dist/classify.d.ts.map +1 -0
- package/dist/classify.js +57 -0
- package/dist/classify.js.map +1 -0
- package/dist/covariance.d.ts +37 -0
- package/dist/covariance.d.ts.map +1 -0
- package/dist/covariance.js +72 -0
- package/dist/covariance.js.map +1 -0
- package/dist/efficiency.d.ts +24 -0
- package/dist/efficiency.d.ts.map +1 -0
- package/dist/efficiency.js +65 -0
- package/dist/efficiency.js.map +1 -0
- package/dist/entropy.d.ts +40 -0
- package/dist/entropy.d.ts.map +1 -0
- package/dist/entropy.js +73 -0
- package/dist/entropy.js.map +1 -0
- package/dist/execution.d.ts +40 -0
- package/dist/execution.d.ts.map +1 -0
- package/dist/execution.js +64 -0
- package/dist/execution.js.map +1 -0
- package/dist/fairvalue.d.ts +19 -0
- package/dist/fairvalue.d.ts.map +1 -0
- package/dist/fairvalue.js +27 -0
- package/dist/fairvalue.js.map +1 -0
- package/dist/hurst.d.ts +23 -0
- package/dist/hurst.d.ts.map +1 -0
- package/dist/hurst.js +71 -0
- package/dist/hurst.js.map +1 -0
- package/dist/imbalance.d.ts +12 -0
- package/dist/imbalance.d.ts.map +1 -0
- package/dist/imbalance.js +19 -0
- package/dist/imbalance.js.map +1 -0
- package/dist/impact.d.ts +59 -0
- package/dist/impact.d.ts.map +1 -0
- package/dist/impact.js +63 -0
- package/dist/impact.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/jumps.d.ts +33 -0
- package/dist/jumps.d.ts.map +1 -0
- package/dist/jumps.js +63 -0
- package/dist/jumps.js.map +1 -0
- package/dist/liquidity.d.ts +18 -0
- package/dist/liquidity.d.ts.map +1 -0
- package/dist/liquidity.js +22 -0
- package/dist/liquidity.js.map +1 -0
- package/dist/moments.d.ts +20 -0
- package/dist/moments.d.ts.map +1 -0
- package/dist/moments.js +48 -0
- package/dist/moments.js.map +1 -0
- package/dist/ofi.d.ts +22 -0
- package/dist/ofi.d.ts.map +1 -0
- package/dist/ofi.js +25 -0
- package/dist/ofi.js.map +1 -0
- package/dist/online.d.ts +101 -0
- package/dist/online.d.ts.map +1 -0
- package/dist/online.js +205 -0
- package/dist/online.js.map +1 -0
- package/dist/orderbook.d.ts +30 -0
- package/dist/orderbook.d.ts.map +1 -0
- package/dist/orderbook.js +66 -0
- package/dist/orderbook.js.map +1 -0
- package/dist/rangevol.d.ts +40 -0
- package/dist/rangevol.d.ts.map +1 -0
- package/dist/rangevol.js +101 -0
- package/dist/rangevol.js.map +1 -0
- package/dist/scheduling.d.ts +19 -0
- package/dist/scheduling.d.ts.map +1 -0
- package/dist/scheduling.js +45 -0
- package/dist/scheduling.js.map +1 -0
- package/dist/semivar.d.ts +49 -0
- package/dist/semivar.d.ts.map +1 -0
- package/dist/semivar.js +59 -0
- package/dist/semivar.js.map +1 -0
- package/dist/shortfall.d.ts +42 -0
- package/dist/shortfall.d.ts.map +1 -0
- package/dist/shortfall.js +32 -0
- package/dist/shortfall.js.map +1 -0
- package/dist/simulate.d.ts +29 -0
- package/dist/simulate.d.ts.map +1 -0
- package/dist/simulate.js +36 -0
- package/dist/simulate.js.map +1 -0
- package/dist/spreadest.d.ts +38 -0
- package/dist/spreadest.d.ts.map +1 -0
- package/dist/spreadest.js +68 -0
- package/dist/spreadest.js.map +1 -0
- package/dist/types.d.ts +24 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/volatility.d.ts +21 -0
- package/dist/volatility.d.ts.map +1 -0
- package/dist/volatility.js +33 -0
- package/dist/volatility.js.map +1 -0
- package/dist/vpin.d.ts +38 -0
- package/dist/vpin.d.ts.map +1 -0
- package/dist/vpin.js +81 -0
- package/dist/vpin.js.map +1 -0
- package/package.json +70 -0
- package/src/bars.ts +141 -0
- package/src/classify.ts +59 -0
- package/src/covariance.ts +72 -0
- package/src/efficiency.ts +64 -0
- package/src/entropy.ts +67 -0
- package/src/execution.ts +100 -0
- package/src/fairvalue.ts +33 -0
- package/src/hurst.ts +77 -0
- package/src/imbalance.ts +25 -0
- package/src/impact.ts +99 -0
- package/src/index.ts +87 -0
- package/src/jumps.ts +61 -0
- package/src/liquidity.ts +29 -0
- package/src/moments.ts +45 -0
- package/src/ofi.ts +46 -0
- package/src/online.ts +228 -0
- package/src/orderbook.ts +76 -0
- package/src/rangevol.ts +108 -0
- package/src/scheduling.ts +50 -0
- package/src/semivar.ts +67 -0
- package/src/shortfall.ts +69 -0
- package/src/simulate.ts +68 -0
- package/src/spreadest.ts +75 -0
- package/src/types.ts +26 -0
- package/src/volatility.ts +36 -0
- package/src/vpin.ts +98 -0
package/dist/moments.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Realized higher moments from an intraday return series.
|
|
3
|
+
*
|
|
4
|
+
* Following Amaya, Christoffersen, Jacobs & Vasquez (2015), the realized
|
|
5
|
+
* skewness and kurtosis of a set of high-frequency returns summarise the shape
|
|
6
|
+
* of the intraday return distribution — asymmetry and tail heaviness — beyond
|
|
7
|
+
* what realized variance (see `volatility`) captures. Realized skewness in
|
|
8
|
+
* particular has been shown to predict the cross-section of subsequent returns.
|
|
9
|
+
*
|
|
10
|
+
* With N returns r and realized variance RV = Σ r²:
|
|
11
|
+
* realized skewness = √N · Σ r³ / RV^(3/2)
|
|
12
|
+
* realized kurtosis = N · Σ r⁴ / RV²
|
|
13
|
+
* The √N and N scalings make the estimates comparable across sampling
|
|
14
|
+
* frequencies. Both return 0 for an empty series or one with no variation.
|
|
15
|
+
*/
|
|
16
|
+
/** Realized skewness: √N · Σ r³ / (Σ r²)^(3/2). */
|
|
17
|
+
export function realizedSkewness(returns) {
|
|
18
|
+
const n = returns.length;
|
|
19
|
+
if (n === 0)
|
|
20
|
+
return 0;
|
|
21
|
+
let s2 = 0;
|
|
22
|
+
let s3 = 0;
|
|
23
|
+
for (const r of returns) {
|
|
24
|
+
const r2 = r * r;
|
|
25
|
+
s2 += r2;
|
|
26
|
+
s3 += r2 * r;
|
|
27
|
+
}
|
|
28
|
+
if (s2 === 0)
|
|
29
|
+
return 0;
|
|
30
|
+
return (Math.sqrt(n) * s3) / Math.pow(s2, 1.5);
|
|
31
|
+
}
|
|
32
|
+
/** Realized kurtosis: N · Σ r⁴ / (Σ r²)². */
|
|
33
|
+
export function realizedKurtosis(returns) {
|
|
34
|
+
const n = returns.length;
|
|
35
|
+
if (n === 0)
|
|
36
|
+
return 0;
|
|
37
|
+
let s2 = 0;
|
|
38
|
+
let s4 = 0;
|
|
39
|
+
for (const r of returns) {
|
|
40
|
+
const r2 = r * r;
|
|
41
|
+
s2 += r2;
|
|
42
|
+
s4 += r2 * r2;
|
|
43
|
+
}
|
|
44
|
+
if (s2 === 0)
|
|
45
|
+
return 0;
|
|
46
|
+
return (n * s4) / (s2 * s2);
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=moments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moments.js","sourceRoot":"","sources":["../src/moments.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,mDAAmD;AACnD,MAAM,UAAU,gBAAgB,CAAC,OAA0B;IACzD,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IACzB,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACtB,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;QACjB,EAAE,IAAI,EAAE,CAAC;QACT,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;IACf,CAAC;IACD,IAAI,EAAE,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACvB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;AACjD,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,gBAAgB,CAAC,OAA0B;IACzD,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IACzB,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACtB,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;QACjB,EAAE,IAAI,EAAE,CAAC;QACT,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IAChB,CAAC;IACD,IAAI,EAAE,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACvB,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;AAC9B,CAAC"}
|
package/dist/ofi.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Order Flow Imbalance (OFI).
|
|
3
|
+
*
|
|
4
|
+
* Implements the level-1 OFI of Cont, Kukanov & Stoikov (2014), "The price
|
|
5
|
+
* impact of order book events". For consecutive best-quote observations
|
|
6
|
+
* (n-1, n) the event contribution is:
|
|
7
|
+
*
|
|
8
|
+
* e_n = q^b_n · 1{P^b_n ≥ P^b_{n-1}} − q^b_{n-1} · 1{P^b_n ≤ P^b_{n-1}}
|
|
9
|
+
* − q^a_n · 1{P^a_n ≤ P^a_{n-1}} + q^a_{n-1} · 1{P^a_n ≥ P^a_{n-1}}
|
|
10
|
+
*
|
|
11
|
+
* OFI over a window is the sum of e_n. Positive OFI means net buy-side
|
|
12
|
+
* pressure at the top of book; it is a strong linear predictor of short-term
|
|
13
|
+
* price moves.
|
|
14
|
+
*/
|
|
15
|
+
import type { L1Quote } from "./types.ts";
|
|
16
|
+
/** OFI contribution of a single best-quote transition (prev → curr). */
|
|
17
|
+
export declare function ofiContribution(prev: L1Quote, curr: L1Quote): number;
|
|
18
|
+
/** Per-step OFI contributions for a sequence of quotes (length n-1). */
|
|
19
|
+
export declare function ofiSeries(quotes: L1Quote[]): number[];
|
|
20
|
+
/** Cumulative OFI over the whole sequence of quotes. */
|
|
21
|
+
export declare function ofi(quotes: L1Quote[]): number;
|
|
22
|
+
//# sourceMappingURL=ofi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ofi.d.ts","sourceRoot":"","sources":["../src/ofi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAUpE;AAED,wEAAwE;AACxE,wBAAgB,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAMrD;AAED,wDAAwD;AACxD,wBAAgB,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAM7C"}
|
package/dist/ofi.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** OFI contribution of a single best-quote transition (prev → curr). */
|
|
2
|
+
export function ofiContribution(prev, curr) {
|
|
3
|
+
const bidTerm = (curr.bidPrice >= prev.bidPrice ? curr.bidSize : 0) -
|
|
4
|
+
(curr.bidPrice <= prev.bidPrice ? prev.bidSize : 0);
|
|
5
|
+
const askTerm = (curr.askPrice >= prev.askPrice ? prev.askSize : 0) -
|
|
6
|
+
(curr.askPrice <= prev.askPrice ? curr.askSize : 0);
|
|
7
|
+
return bidTerm + askTerm;
|
|
8
|
+
}
|
|
9
|
+
/** Per-step OFI contributions for a sequence of quotes (length n-1). */
|
|
10
|
+
export function ofiSeries(quotes) {
|
|
11
|
+
const out = [];
|
|
12
|
+
for (let i = 1; i < quotes.length; i++) {
|
|
13
|
+
out.push(ofiContribution(quotes[i - 1], quotes[i]));
|
|
14
|
+
}
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
17
|
+
/** Cumulative OFI over the whole sequence of quotes. */
|
|
18
|
+
export function ofi(quotes) {
|
|
19
|
+
let total = 0;
|
|
20
|
+
for (let i = 1; i < quotes.length; i++) {
|
|
21
|
+
total += ofiContribution(quotes[i - 1], quotes[i]);
|
|
22
|
+
}
|
|
23
|
+
return total;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=ofi.js.map
|
package/dist/ofi.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ofi.js","sourceRoot":"","sources":["../src/ofi.ts"],"names":[],"mappings":"AAgBA,wEAAwE;AACxE,MAAM,UAAU,eAAe,CAAC,IAAa,EAAE,IAAa;IAC1D,MAAM,OAAO,GACX,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QACnD,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEtD,MAAM,OAAO,GACX,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QACnD,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEtD,OAAO,OAAO,GAAG,OAAO,CAAC;AAC3B,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,SAAS,CAAC,MAAiB;IACzC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,GAAG,CAAC,MAAiB;IACnC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,KAAK,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/dist/online.d.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Online (streaming) estimators — O(1) per update, no rescans.
|
|
3
|
+
*
|
|
4
|
+
* Batch metrics recompute over the whole history every time a tick arrives;
|
|
5
|
+
* that is fine offline but wasteful in a live pipeline. The estimators here
|
|
6
|
+
* update in constant time and constant memory as each observation streams in,
|
|
7
|
+
* which is what you want feeding volatility or risk off a real-time tape.
|
|
8
|
+
*
|
|
9
|
+
* They are numerically careful: `Welford` and `RollingWindow` use Welford's
|
|
10
|
+
* and West's algorithms rather than the naive Σx² − (Σx)²/n form, which loses
|
|
11
|
+
* precision catastrophically when the mean is large relative to the variance.
|
|
12
|
+
*
|
|
13
|
+
* Welford — running mean & variance over all data seen so far
|
|
14
|
+
* Ewma — exponentially weighted moving average (a level)
|
|
15
|
+
* EwmaVariance — RiskMetrics-style EWMA variance (a volatility)
|
|
16
|
+
* RollingWindow — mean & variance over a fixed trailing window
|
|
17
|
+
*
|
|
18
|
+
* Sample variance uses the (n − 1) denominator; each class also exposes the
|
|
19
|
+
* population (n) form. Variance getters are floored at 0 to absorb the tiny
|
|
20
|
+
* negative values floating-point round-off can produce near zero.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Streaming mean and variance over every value pushed so far, via Welford's
|
|
24
|
+
* online algorithm. Constant time and memory per update, and numerically
|
|
25
|
+
* stable regardless of the mean's magnitude.
|
|
26
|
+
*/
|
|
27
|
+
export declare class Welford {
|
|
28
|
+
#private;
|
|
29
|
+
/** Incorporate one observation. */
|
|
30
|
+
push(x: number): void;
|
|
31
|
+
/** Number of observations seen. */
|
|
32
|
+
get count(): number;
|
|
33
|
+
/** Running mean (0 before any observation). */
|
|
34
|
+
get mean(): number;
|
|
35
|
+
/** Sample variance, (n − 1) denominator (0 for fewer than two observations). */
|
|
36
|
+
get variance(): number;
|
|
37
|
+
/** Population variance, n denominator (0 before any observation). */
|
|
38
|
+
get populationVariance(): number;
|
|
39
|
+
/** Sample standard deviation. */
|
|
40
|
+
get std(): number;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Exponentially weighted moving average of a level: vₜ = λ·vₜ₋₁ + (1 − λ)·xₜ.
|
|
44
|
+
* `lambda` is the weight on history (decay), in (0, 1) — larger is smoother and
|
|
45
|
+
* slower to react. Seeded with the first value pushed.
|
|
46
|
+
*/
|
|
47
|
+
export declare class Ewma {
|
|
48
|
+
#private;
|
|
49
|
+
constructor(lambda: number);
|
|
50
|
+
/** Incorporate one observation. */
|
|
51
|
+
push(x: number): void;
|
|
52
|
+
/** Current EWMA level (0 before any observation). */
|
|
53
|
+
get value(): number;
|
|
54
|
+
/** Whether at least one value has been pushed. */
|
|
55
|
+
get initialized(): boolean;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* RiskMetrics-style exponentially weighted variance of a return series:
|
|
59
|
+
* σ²ₜ = λ·σ²ₜ₋₁ + (1 − λ)·r²ₜ. Assumes approximately zero-mean returns (the
|
|
60
|
+
* standard RiskMetrics assumption). `lambda` in (0, 1) is the decay; RiskMetrics
|
|
61
|
+
* uses 0.94 for daily data. Seeded with r² of the first value pushed.
|
|
62
|
+
*/
|
|
63
|
+
export declare class EwmaVariance {
|
|
64
|
+
#private;
|
|
65
|
+
constructor(lambda: number);
|
|
66
|
+
/** Incorporate one return. */
|
|
67
|
+
push(r: number): void;
|
|
68
|
+
/** Current EWMA variance (0 before any observation). */
|
|
69
|
+
get variance(): number;
|
|
70
|
+
/** Current EWMA volatility (standard deviation). */
|
|
71
|
+
get std(): number;
|
|
72
|
+
/** Whether at least one value has been pushed. */
|
|
73
|
+
get initialized(): boolean;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Mean and variance over a fixed trailing window of the last `size` values.
|
|
77
|
+
* Each push is O(1): the incoming value is added and, once the window is full,
|
|
78
|
+
* the oldest is removed, both via West's (1979) incremental update — so there is
|
|
79
|
+
* no per-tick rescan and no Σx² cancellation.
|
|
80
|
+
*/
|
|
81
|
+
export declare class RollingWindow {
|
|
82
|
+
#private;
|
|
83
|
+
constructor(size: number);
|
|
84
|
+
/** Push one value, evicting the oldest once the window is full. */
|
|
85
|
+
push(x: number): void;
|
|
86
|
+
/** Configured window size. */
|
|
87
|
+
get size(): number;
|
|
88
|
+
/** Number of values currently in the window (≤ size). */
|
|
89
|
+
get count(): number;
|
|
90
|
+
/** Whether the window has filled to `size`. */
|
|
91
|
+
get full(): boolean;
|
|
92
|
+
/** Mean of the current window (0 when empty). */
|
|
93
|
+
get mean(): number;
|
|
94
|
+
/** Sample variance of the current window (0 for fewer than two values). */
|
|
95
|
+
get variance(): number;
|
|
96
|
+
/** Population variance of the current window (0 when empty). */
|
|
97
|
+
get populationVariance(): number;
|
|
98
|
+
/** Sample standard deviation of the current window. */
|
|
99
|
+
get std(): number;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=online.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"online.d.ts","sourceRoot":"","sources":["../src/online.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH;;;;GAIG;AACH,qBAAa,OAAO;;IAKlB,mCAAmC;IACnC,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAOrB,mCAAmC;IACnC,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,+CAA+C;IAC/C,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,gFAAgF;IAChF,IAAI,QAAQ,IAAI,MAAM,CAIrB;IAED,qEAAqE;IACrE,IAAI,kBAAkB,IAAI,MAAM,CAI/B;IAED,iCAAiC;IACjC,IAAI,GAAG,IAAI,MAAM,CAEhB;CACF;AAED;;;;GAIG;AACH,qBAAa,IAAI;;gBAKH,MAAM,EAAE,MAAM;IAO1B,mCAAmC;IACnC,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAKrB,qDAAqD;IACrD,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,kDAAkD;IAClD,IAAI,WAAW,IAAI,OAAO,CAEzB;CACF;AAED;;;;;GAKG;AACH,qBAAa,YAAY;;gBAKX,MAAM,EAAE,MAAM;IAO1B,8BAA8B;IAC9B,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAKrB,wDAAwD;IACxD,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,oDAAoD;IACpD,IAAI,GAAG,IAAI,MAAM,CAEhB;IAED,kDAAkD;IAClD,IAAI,WAAW,IAAI,OAAO,CAEzB;CACF;AAED;;;;;GAKG;AACH,qBAAa,aAAa;;gBAQZ,IAAI,EAAE,MAAM;IAOxB,mEAAmE;IACnE,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAuBrB,8BAA8B;IAC9B,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,yDAAyD;IACzD,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,+CAA+C;IAC/C,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,iDAAiD;IACjD,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,2EAA2E;IAC3E,IAAI,QAAQ,IAAI,MAAM,CAIrB;IAED,gEAAgE;IAChE,IAAI,kBAAkB,IAAI,MAAM,CAI/B;IAED,uDAAuD;IACvD,IAAI,GAAG,IAAI,MAAM,CAEhB;CACF"}
|
package/dist/online.js
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Online (streaming) estimators — O(1) per update, no rescans.
|
|
3
|
+
*
|
|
4
|
+
* Batch metrics recompute over the whole history every time a tick arrives;
|
|
5
|
+
* that is fine offline but wasteful in a live pipeline. The estimators here
|
|
6
|
+
* update in constant time and constant memory as each observation streams in,
|
|
7
|
+
* which is what you want feeding volatility or risk off a real-time tape.
|
|
8
|
+
*
|
|
9
|
+
* They are numerically careful: `Welford` and `RollingWindow` use Welford's
|
|
10
|
+
* and West's algorithms rather than the naive Σx² − (Σx)²/n form, which loses
|
|
11
|
+
* precision catastrophically when the mean is large relative to the variance.
|
|
12
|
+
*
|
|
13
|
+
* Welford — running mean & variance over all data seen so far
|
|
14
|
+
* Ewma — exponentially weighted moving average (a level)
|
|
15
|
+
* EwmaVariance — RiskMetrics-style EWMA variance (a volatility)
|
|
16
|
+
* RollingWindow — mean & variance over a fixed trailing window
|
|
17
|
+
*
|
|
18
|
+
* Sample variance uses the (n − 1) denominator; each class also exposes the
|
|
19
|
+
* population (n) form. Variance getters are floored at 0 to absorb the tiny
|
|
20
|
+
* negative values floating-point round-off can produce near zero.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Streaming mean and variance over every value pushed so far, via Welford's
|
|
24
|
+
* online algorithm. Constant time and memory per update, and numerically
|
|
25
|
+
* stable regardless of the mean's magnitude.
|
|
26
|
+
*/
|
|
27
|
+
export class Welford {
|
|
28
|
+
#n = 0;
|
|
29
|
+
#mean = 0;
|
|
30
|
+
#m2 = 0;
|
|
31
|
+
/** Incorporate one observation. */
|
|
32
|
+
push(x) {
|
|
33
|
+
this.#n += 1;
|
|
34
|
+
const delta = x - this.#mean;
|
|
35
|
+
this.#mean += delta / this.#n;
|
|
36
|
+
this.#m2 += delta * (x - this.#mean);
|
|
37
|
+
}
|
|
38
|
+
/** Number of observations seen. */
|
|
39
|
+
get count() {
|
|
40
|
+
return this.#n;
|
|
41
|
+
}
|
|
42
|
+
/** Running mean (0 before any observation). */
|
|
43
|
+
get mean() {
|
|
44
|
+
return this.#n > 0 ? this.#mean : 0;
|
|
45
|
+
}
|
|
46
|
+
/** Sample variance, (n − 1) denominator (0 for fewer than two observations). */
|
|
47
|
+
get variance() {
|
|
48
|
+
if (this.#n < 2)
|
|
49
|
+
return 0;
|
|
50
|
+
const v = this.#m2 / (this.#n - 1);
|
|
51
|
+
return v > 0 ? v : 0;
|
|
52
|
+
}
|
|
53
|
+
/** Population variance, n denominator (0 before any observation). */
|
|
54
|
+
get populationVariance() {
|
|
55
|
+
if (this.#n < 1)
|
|
56
|
+
return 0;
|
|
57
|
+
const v = this.#m2 / this.#n;
|
|
58
|
+
return v > 0 ? v : 0;
|
|
59
|
+
}
|
|
60
|
+
/** Sample standard deviation. */
|
|
61
|
+
get std() {
|
|
62
|
+
return Math.sqrt(this.variance);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Exponentially weighted moving average of a level: vₜ = λ·vₜ₋₁ + (1 − λ)·xₜ.
|
|
67
|
+
* `lambda` is the weight on history (decay), in (0, 1) — larger is smoother and
|
|
68
|
+
* slower to react. Seeded with the first value pushed.
|
|
69
|
+
*/
|
|
70
|
+
export class Ewma {
|
|
71
|
+
#lambda;
|
|
72
|
+
#value = 0;
|
|
73
|
+
#init = false;
|
|
74
|
+
constructor(lambda) {
|
|
75
|
+
if (!(lambda > 0 && lambda < 1)) {
|
|
76
|
+
throw new RangeError("lambda must be in the open interval (0, 1)");
|
|
77
|
+
}
|
|
78
|
+
this.#lambda = lambda;
|
|
79
|
+
}
|
|
80
|
+
/** Incorporate one observation. */
|
|
81
|
+
push(x) {
|
|
82
|
+
this.#value = this.#init ? this.#lambda * this.#value + (1 - this.#lambda) * x : x;
|
|
83
|
+
this.#init = true;
|
|
84
|
+
}
|
|
85
|
+
/** Current EWMA level (0 before any observation). */
|
|
86
|
+
get value() {
|
|
87
|
+
return this.#value;
|
|
88
|
+
}
|
|
89
|
+
/** Whether at least one value has been pushed. */
|
|
90
|
+
get initialized() {
|
|
91
|
+
return this.#init;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* RiskMetrics-style exponentially weighted variance of a return series:
|
|
96
|
+
* σ²ₜ = λ·σ²ₜ₋₁ + (1 − λ)·r²ₜ. Assumes approximately zero-mean returns (the
|
|
97
|
+
* standard RiskMetrics assumption). `lambda` in (0, 1) is the decay; RiskMetrics
|
|
98
|
+
* uses 0.94 for daily data. Seeded with r² of the first value pushed.
|
|
99
|
+
*/
|
|
100
|
+
export class EwmaVariance {
|
|
101
|
+
#lambda;
|
|
102
|
+
#var = 0;
|
|
103
|
+
#init = false;
|
|
104
|
+
constructor(lambda) {
|
|
105
|
+
if (!(lambda > 0 && lambda < 1)) {
|
|
106
|
+
throw new RangeError("lambda must be in the open interval (0, 1)");
|
|
107
|
+
}
|
|
108
|
+
this.#lambda = lambda;
|
|
109
|
+
}
|
|
110
|
+
/** Incorporate one return. */
|
|
111
|
+
push(r) {
|
|
112
|
+
this.#var = this.#init ? this.#lambda * this.#var + (1 - this.#lambda) * r * r : r * r;
|
|
113
|
+
this.#init = true;
|
|
114
|
+
}
|
|
115
|
+
/** Current EWMA variance (0 before any observation). */
|
|
116
|
+
get variance() {
|
|
117
|
+
return this.#var;
|
|
118
|
+
}
|
|
119
|
+
/** Current EWMA volatility (standard deviation). */
|
|
120
|
+
get std() {
|
|
121
|
+
return Math.sqrt(this.#var);
|
|
122
|
+
}
|
|
123
|
+
/** Whether at least one value has been pushed. */
|
|
124
|
+
get initialized() {
|
|
125
|
+
return this.#init;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Mean and variance over a fixed trailing window of the last `size` values.
|
|
130
|
+
* Each push is O(1): the incoming value is added and, once the window is full,
|
|
131
|
+
* the oldest is removed, both via West's (1979) incremental update — so there is
|
|
132
|
+
* no per-tick rescan and no Σx² cancellation.
|
|
133
|
+
*/
|
|
134
|
+
export class RollingWindow {
|
|
135
|
+
#size;
|
|
136
|
+
#buf = [];
|
|
137
|
+
#idx = 0;
|
|
138
|
+
#n = 0;
|
|
139
|
+
#mean = 0;
|
|
140
|
+
#m2 = 0;
|
|
141
|
+
constructor(size) {
|
|
142
|
+
if (!Number.isInteger(size) || size < 1) {
|
|
143
|
+
throw new RangeError("size must be a positive integer");
|
|
144
|
+
}
|
|
145
|
+
this.#size = size;
|
|
146
|
+
}
|
|
147
|
+
/** Push one value, evicting the oldest once the window is full. */
|
|
148
|
+
push(x) {
|
|
149
|
+
if (this.#n < this.#size) {
|
|
150
|
+
// Window not yet full: plain Welford add.
|
|
151
|
+
this.#n += 1;
|
|
152
|
+
const delta = x - this.#mean;
|
|
153
|
+
this.#mean += delta / this.#n;
|
|
154
|
+
this.#m2 += delta * (x - this.#mean);
|
|
155
|
+
this.#buf.push(x);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
// Full: add the newcomer, then remove the oldest (West's add + remove).
|
|
159
|
+
const old = this.#buf[this.#idx];
|
|
160
|
+
const n1 = this.#n + 1;
|
|
161
|
+
const delta = x - this.#mean;
|
|
162
|
+
const mean1 = this.#mean + delta / n1;
|
|
163
|
+
const m2Added = this.#m2 + delta * (x - mean1);
|
|
164
|
+
const mean0 = (n1 * mean1 - old) / this.#size;
|
|
165
|
+
this.#m2 = m2Added - (old - mean0) * (old - mean1);
|
|
166
|
+
this.#mean = mean0;
|
|
167
|
+
this.#buf[this.#idx] = x;
|
|
168
|
+
this.#idx = (this.#idx + 1) % this.#size;
|
|
169
|
+
}
|
|
170
|
+
/** Configured window size. */
|
|
171
|
+
get size() {
|
|
172
|
+
return this.#size;
|
|
173
|
+
}
|
|
174
|
+
/** Number of values currently in the window (≤ size). */
|
|
175
|
+
get count() {
|
|
176
|
+
return this.#n;
|
|
177
|
+
}
|
|
178
|
+
/** Whether the window has filled to `size`. */
|
|
179
|
+
get full() {
|
|
180
|
+
return this.#n === this.#size;
|
|
181
|
+
}
|
|
182
|
+
/** Mean of the current window (0 when empty). */
|
|
183
|
+
get mean() {
|
|
184
|
+
return this.#n > 0 ? this.#mean : 0;
|
|
185
|
+
}
|
|
186
|
+
/** Sample variance of the current window (0 for fewer than two values). */
|
|
187
|
+
get variance() {
|
|
188
|
+
if (this.#n < 2)
|
|
189
|
+
return 0;
|
|
190
|
+
const v = this.#m2 / (this.#n - 1);
|
|
191
|
+
return v > 0 ? v : 0;
|
|
192
|
+
}
|
|
193
|
+
/** Population variance of the current window (0 when empty). */
|
|
194
|
+
get populationVariance() {
|
|
195
|
+
if (this.#n < 1)
|
|
196
|
+
return 0;
|
|
197
|
+
const v = this.#m2 / this.#n;
|
|
198
|
+
return v > 0 ? v : 0;
|
|
199
|
+
}
|
|
200
|
+
/** Sample standard deviation of the current window. */
|
|
201
|
+
get std() {
|
|
202
|
+
return Math.sqrt(this.variance);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=online.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"online.js","sourceRoot":"","sources":["../src/online.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Limit order book reconstruction from incremental level updates.
|
|
3
|
+
*
|
|
4
|
+
* Feed it level updates (price + new size per side); it maintains both sides
|
|
5
|
+
* and answers the usual top-of-book and depth questions. A size of 0 removes
|
|
6
|
+
* the level. Prices are the level keys, so re-sending a price overwrites it.
|
|
7
|
+
*/
|
|
8
|
+
export type BookSide = "bid" | "ask";
|
|
9
|
+
export interface Level {
|
|
10
|
+
price: number;
|
|
11
|
+
size: number;
|
|
12
|
+
}
|
|
13
|
+
export declare class OrderBook {
|
|
14
|
+
private readonly bids;
|
|
15
|
+
private readonly asks;
|
|
16
|
+
/** Apply a level update. ``size <= 0`` removes the price level. */
|
|
17
|
+
update(side: BookSide, price: number, size: number): void;
|
|
18
|
+
bestBid(): Level | null;
|
|
19
|
+
bestAsk(): Level | null;
|
|
20
|
+
mid(): number | null;
|
|
21
|
+
spread(): number | null;
|
|
22
|
+
/** Top ``n`` levels of a side, best price first. */
|
|
23
|
+
depth(side: BookSide, n: number): Level[];
|
|
24
|
+
/**
|
|
25
|
+
* Book imbalance over the top ``n`` levels:
|
|
26
|
+
* (bidVolume − askVolume) / (bidVolume + askVolume), in [-1, 1].
|
|
27
|
+
*/
|
|
28
|
+
imbalance(n?: number): number;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=orderbook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orderbook.d.ts","sourceRoot":"","sources":["../src/orderbook.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,KAAK,CAAC;AAErC,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA6B;IAClD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA6B;IAElD,mEAAmE;IACnE,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAMzD,OAAO,IAAI,KAAK,GAAG,IAAI;IAQvB,OAAO,IAAI,KAAK,GAAG,IAAI;IAQvB,GAAG,IAAI,MAAM,GAAG,IAAI;IAMpB,MAAM,IAAI,MAAM,GAAG,IAAI;IAMvB,oDAAoD;IACpD,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,GAAG,KAAK,EAAE;IAUzC;;;OAGG;IACH,SAAS,CAAC,CAAC,SAAI,GAAG,MAAM;CAMzB"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Limit order book reconstruction from incremental level updates.
|
|
3
|
+
*
|
|
4
|
+
* Feed it level updates (price + new size per side); it maintains both sides
|
|
5
|
+
* and answers the usual top-of-book and depth questions. A size of 0 removes
|
|
6
|
+
* the level. Prices are the level keys, so re-sending a price overwrites it.
|
|
7
|
+
*/
|
|
8
|
+
export class OrderBook {
|
|
9
|
+
bids = new Map();
|
|
10
|
+
asks = new Map();
|
|
11
|
+
/** Apply a level update. ``size <= 0`` removes the price level. */
|
|
12
|
+
update(side, price, size) {
|
|
13
|
+
const book = side === "bid" ? this.bids : this.asks;
|
|
14
|
+
if (size <= 0)
|
|
15
|
+
book.delete(price);
|
|
16
|
+
else
|
|
17
|
+
book.set(price, size);
|
|
18
|
+
}
|
|
19
|
+
bestBid() {
|
|
20
|
+
let best = null;
|
|
21
|
+
for (const [price, size] of this.bids) {
|
|
22
|
+
if (best === null || price > best.price)
|
|
23
|
+
best = { price, size };
|
|
24
|
+
}
|
|
25
|
+
return best;
|
|
26
|
+
}
|
|
27
|
+
bestAsk() {
|
|
28
|
+
let best = null;
|
|
29
|
+
for (const [price, size] of this.asks) {
|
|
30
|
+
if (best === null || price < best.price)
|
|
31
|
+
best = { price, size };
|
|
32
|
+
}
|
|
33
|
+
return best;
|
|
34
|
+
}
|
|
35
|
+
mid() {
|
|
36
|
+
const b = this.bestBid();
|
|
37
|
+
const a = this.bestAsk();
|
|
38
|
+
return b && a ? (b.price + a.price) / 2 : null;
|
|
39
|
+
}
|
|
40
|
+
spread() {
|
|
41
|
+
const b = this.bestBid();
|
|
42
|
+
const a = this.bestAsk();
|
|
43
|
+
return b && a ? a.price - b.price : null;
|
|
44
|
+
}
|
|
45
|
+
/** Top ``n`` levels of a side, best price first. */
|
|
46
|
+
depth(side, n) {
|
|
47
|
+
const book = side === "bid" ? this.bids : this.asks;
|
|
48
|
+
const levels = [...book.entries()].map(([price, size]) => ({
|
|
49
|
+
price,
|
|
50
|
+
size,
|
|
51
|
+
}));
|
|
52
|
+
levels.sort((x, y) => (side === "bid" ? y.price - x.price : x.price - y.price));
|
|
53
|
+
return levels.slice(0, n);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Book imbalance over the top ``n`` levels:
|
|
57
|
+
* (bidVolume − askVolume) / (bidVolume + askVolume), in [-1, 1].
|
|
58
|
+
*/
|
|
59
|
+
imbalance(n = 1) {
|
|
60
|
+
const bidVol = this.depth("bid", n).reduce((s, l) => s + l.size, 0);
|
|
61
|
+
const askVol = this.depth("ask", n).reduce((s, l) => s + l.size, 0);
|
|
62
|
+
const denom = bidVol + askVol;
|
|
63
|
+
return denom === 0 ? 0 : (bidVol - askVol) / denom;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=orderbook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orderbook.js","sourceRoot":"","sources":["../src/orderbook.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Range-based volatility estimators from OHLC candles.
|
|
3
|
+
*
|
|
4
|
+
* Close-to-close realized volatility (see `volatility`) throws away most of each
|
|
5
|
+
* bar — it reads only the close. But the open, high, and low carry information
|
|
6
|
+
* too, and using them yields far more efficient volatility estimates from the
|
|
7
|
+
* same data. Four classic estimators, in increasing order of what they use:
|
|
8
|
+
*
|
|
9
|
+
* - Parkinson (1980): the high-low range only.
|
|
10
|
+
* - Garman-Klass (1980): adds the open and close.
|
|
11
|
+
* - Rogers-Satchell (1991): drift-independent (correct under a trending mean).
|
|
12
|
+
* - Yang-Zhang (2000): drift-independent and robust to overnight jumps.
|
|
13
|
+
*
|
|
14
|
+
* Each returns the estimated volatility (standard deviation) *per bar*. To
|
|
15
|
+
* annualize, multiply the variance by the number of bars per year, or the
|
|
16
|
+
* volatility by its square root. Prices must be strictly positive.
|
|
17
|
+
*/
|
|
18
|
+
export interface Candle {
|
|
19
|
+
open: number;
|
|
20
|
+
high: number;
|
|
21
|
+
low: number;
|
|
22
|
+
close: number;
|
|
23
|
+
}
|
|
24
|
+
/** Parkinson (1980) high-low volatility. Returns 0 for an empty input. */
|
|
25
|
+
export declare function parkinsonVolatility(bars: Candle[]): number;
|
|
26
|
+
/** Garman-Klass (1980) OHLC volatility. Returns 0 for an empty input. */
|
|
27
|
+
export declare function garmanKlassVolatility(bars: Candle[]): number;
|
|
28
|
+
/**
|
|
29
|
+
* Rogers-Satchell (1991) drift-independent OHLC volatility. Correct even when
|
|
30
|
+
* the price has a non-zero mean drift. Returns 0 for an empty input.
|
|
31
|
+
*/
|
|
32
|
+
export declare function rogersSatchellVolatility(bars: Candle[]): number;
|
|
33
|
+
/**
|
|
34
|
+
* Yang-Zhang (2000) volatility: a minimum-variance combination of overnight,
|
|
35
|
+
* open-to-close, and Rogers-Satchell variances that is both drift-independent
|
|
36
|
+
* and robust to opening jumps. Uses each bar's open relative to the previous
|
|
37
|
+
* close, so it needs at least three bars; returns 0 otherwise.
|
|
38
|
+
*/
|
|
39
|
+
export declare function yangZhangVolatility(bars: Candle[]): number;
|
|
40
|
+
//# sourceMappingURL=rangevol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rangevol.d.ts","sourceRoot":"","sources":["../src/rangevol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAID,0EAA0E;AAC1E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAS1D;AAED,yEAAyE;AACzE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAW5D;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAW/D;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CA+B1D"}
|