orderflow-metrics 0.27.0 → 0.28.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 +12 -0
- package/README.md +21 -0
- package/dist/bookdepth.d.ts +73 -0
- package/dist/bookdepth.d.ts.map +1 -0
- package/dist/bookdepth.js +119 -0
- package/dist/bookdepth.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/bookdepth.ts +149 -0
- package/src/index.ts +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|
|
4
4
|
This project follows [Semantic Versioning](https://semver.org/); pre-1.0 the
|
|
5
5
|
public API may still change between minor versions.
|
|
6
6
|
|
|
7
|
+
## [0.28.0] - 2026-08-29
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- Book-depth liquidity (`bookdepth`) — `depthWithin` (resting size within ±bps
|
|
11
|
+
of mid, split by side), `orderBookSlope` (cumulative size per unit of relative
|
|
12
|
+
price distance — how steeply the book thickens away from mid), and
|
|
13
|
+
`costOfRoundTrip` (the basis-point "liquidity tax" of buying then selling a
|
|
14
|
+
given size, walking both sides of the book). Snapshot statistics of the
|
|
15
|
+
*standing* book, complementing `amihudIlliquidity` (impact over time) and
|
|
16
|
+
`simulateMarketOrder` (a single execution). Operate on plain `Level[]` arrays
|
|
17
|
+
sorted best-first. Test suite included. (Python: 0.16.0.)
|
|
18
|
+
|
|
7
19
|
## [0.27.0] - 2026-08-28
|
|
8
20
|
|
|
9
21
|
### Added
|
package/README.md
CHANGED
|
@@ -237,6 +237,27 @@ r.slippageBps; // cost vs mid, in basis points
|
|
|
237
237
|
r.remainingSize; // > 0 if the book was too thin
|
|
238
238
|
```
|
|
239
239
|
|
|
240
|
+
### Book-depth liquidity
|
|
241
|
+
|
|
242
|
+
Read liquidity off a book snapshot — near-touch depth, how steeply the book
|
|
243
|
+
thickens away from mid, and the round-trip cost of a given size. Take plain
|
|
244
|
+
`Level[]` arrays sorted best-first (bids high→low, asks low→high):
|
|
245
|
+
|
|
246
|
+
```ts
|
|
247
|
+
import { depthWithin, orderBookSlope, costOfRoundTrip } from "orderflow-metrics";
|
|
248
|
+
|
|
249
|
+
const bids = [{ price: 99.95, size: 6 }, { price: 99.9, size: 10 }];
|
|
250
|
+
const asks = [{ price: 100.0, size: 5 }, { price: 100.05, size: 8 }];
|
|
251
|
+
|
|
252
|
+
depthWithin(bids, asks, 10); // { bidDepth, askDepth, total } within ±10 bps of mid
|
|
253
|
+
orderBookSlope(asks, 99.975); // cumulative size per unit of relative price move
|
|
254
|
+
costOfRoundTrip(bids, asks, 15); // { roundTripBps, avgBuyPrice, avgSellPrice, filledSize }
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
- `depthWithin` — resting size within ±bps of mid, split by side
|
|
258
|
+
- `orderBookSlope` — (Σ size) / (relative distance to the outermost level)
|
|
259
|
+
- `costOfRoundTrip` — basis-point liquidity tax of buying then selling `size`
|
|
260
|
+
|
|
240
261
|
## Execution scheduling
|
|
241
262
|
|
|
242
263
|
Split a parent order into child slices:
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Book-depth liquidity metrics — reading liquidity straight off a limit-order
|
|
3
|
+
* book snapshot.
|
|
4
|
+
*
|
|
5
|
+
* Where `amihudIlliquidity` (see `liquidity.ts`) measures liquidity from
|
|
6
|
+
* realized price impact over time, these functions measure it from the *shape*
|
|
7
|
+
* of the resting book at a single instant: how much size is quoted near the
|
|
8
|
+
* touch, how steeply depth thickens away from mid, and what a round trip would
|
|
9
|
+
* actually cost. They complement `simulateMarketOrder` (which walks the book
|
|
10
|
+
* for one execution): these are summary statistics of the standing book, not a
|
|
11
|
+
* fill simulation.
|
|
12
|
+
*
|
|
13
|
+
* Every function takes plain `Level[]` arrays sorted best-first — bids by
|
|
14
|
+
* descending price, asks by ascending price — exactly as `OrderBook.depth()`
|
|
15
|
+
* returns them.
|
|
16
|
+
*/
|
|
17
|
+
import type { Level } from "./orderbook.ts";
|
|
18
|
+
/** Resting size available within a price band around the mid. */
|
|
19
|
+
export interface DepthWithin {
|
|
20
|
+
/** total bid size within the band */
|
|
21
|
+
bidDepth: number;
|
|
22
|
+
/** total ask size within the band */
|
|
23
|
+
askDepth: number;
|
|
24
|
+
/** bidDepth + askDepth */
|
|
25
|
+
total: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Total resting size within `±bps` of the mid price, split by side.
|
|
29
|
+
*
|
|
30
|
+
* A snapshot of near-touch liquidity: how much can trade close to the current
|
|
31
|
+
* price before walking into deeper, worse-priced levels. The band half-width is
|
|
32
|
+
* `mid · bps / 10_000`, applied symmetrically. Levels must be sorted best-first.
|
|
33
|
+
* Returns zeros if either side is empty (no mid) or `bps <= 0`.
|
|
34
|
+
*/
|
|
35
|
+
export declare function depthWithin(bids: readonly Level[], asks: readonly Level[], bps: number): DepthWithin;
|
|
36
|
+
/**
|
|
37
|
+
* Order-book slope: cumulative resting size divided by the relative price
|
|
38
|
+
* distance from `refPrice` to the outermost supplied level.
|
|
39
|
+
*
|
|
40
|
+
* slope = (Σ size) / ( |P_last − refPrice| / refPrice )
|
|
41
|
+
*
|
|
42
|
+
* It answers "how much size is packed per unit of relative price move" — a
|
|
43
|
+
* steeper (larger) slope means depth builds up quickly near the reference
|
|
44
|
+
* price, i.e. a thicker, more liquid book. Pass one side's levels (best-first)
|
|
45
|
+
* and a reference price (typically the mid). Returns 0 for empty input, a
|
|
46
|
+
* non-positive `refPrice`, or when the outermost level sits at the reference
|
|
47
|
+
* price (zero distance).
|
|
48
|
+
*/
|
|
49
|
+
export declare function orderBookSlope(levels: readonly Level[], refPrice: number): number;
|
|
50
|
+
/** The cost of buying then selling the same size against the standing book. */
|
|
51
|
+
export interface RoundTripCost {
|
|
52
|
+
/** size-weighted average price paid buying `size` from the asks */
|
|
53
|
+
avgBuyPrice: number;
|
|
54
|
+
/** size-weighted average price received selling `size` into the bids */
|
|
55
|
+
avgSellPrice: number;
|
|
56
|
+
/** round-trip cost in basis points of mid: (avgBuy − avgSell) / mid · 10⁴ */
|
|
57
|
+
roundTripBps: number;
|
|
58
|
+
/** size actually round-tripped (min of the fill each side supports) */
|
|
59
|
+
filledSize: number;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Round-trip liquidity cost: the basis-point gap between the VWAP of buying
|
|
63
|
+
* `size` from the asks and the VWAP of selling `size` into the bids, measured
|
|
64
|
+
* against the mid. This is the immediate "liquidity tax" of entering and
|
|
65
|
+
* exiting a position of `size` — spread plus the price impact of walking both
|
|
66
|
+
* sides of the book.
|
|
67
|
+
*
|
|
68
|
+
* Levels must be sorted best-first. `filledSize` is the smaller of the two
|
|
69
|
+
* sides' fills, so a book too thin on one side reports how much actually
|
|
70
|
+
* round-tripped. Returns zeros if either side is empty or `size <= 0`.
|
|
71
|
+
*/
|
|
72
|
+
export declare function costOfRoundTrip(bids: readonly Level[], asks: readonly Level[], size: number): RoundTripCost;
|
|
73
|
+
//# sourceMappingURL=bookdepth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bookdepth.d.ts","sourceRoot":"","sources":["../src/bookdepth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C,iEAAiE;AACjE,MAAM,WAAW,WAAW;IAC1B,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,0BAA0B;IAC1B,KAAK,EAAE,MAAM,CAAC;CACf;AAOD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,SAAS,KAAK,EAAE,EACtB,IAAI,EAAE,SAAS,KAAK,EAAE,EACtB,GAAG,EAAE,MAAM,GACV,WAAW,CAWb;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,SAAS,KAAK,EAAE,EACxB,QAAQ,EAAE,MAAM,GACf,MAAM,CAOR;AAED,+EAA+E;AAC/E,MAAM,WAAW,aAAa;IAC5B,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,YAAY,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,YAAY,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,UAAU,EAAE,MAAM,CAAC;CACpB;AAmBD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,SAAS,KAAK,EAAE,EACtB,IAAI,EAAE,SAAS,KAAK,EAAE,EACtB,IAAI,EAAE,MAAM,GACX,aAAa,CAoBf"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Book-depth liquidity metrics — reading liquidity straight off a limit-order
|
|
3
|
+
* book snapshot.
|
|
4
|
+
*
|
|
5
|
+
* Where `amihudIlliquidity` (see `liquidity.ts`) measures liquidity from
|
|
6
|
+
* realized price impact over time, these functions measure it from the *shape*
|
|
7
|
+
* of the resting book at a single instant: how much size is quoted near the
|
|
8
|
+
* touch, how steeply depth thickens away from mid, and what a round trip would
|
|
9
|
+
* actually cost. They complement `simulateMarketOrder` (which walks the book
|
|
10
|
+
* for one execution): these are summary statistics of the standing book, not a
|
|
11
|
+
* fill simulation.
|
|
12
|
+
*
|
|
13
|
+
* Every function takes plain `Level[]` arrays sorted best-first — bids by
|
|
14
|
+
* descending price, asks by ascending price — exactly as `OrderBook.depth()`
|
|
15
|
+
* returns them.
|
|
16
|
+
*/
|
|
17
|
+
function mid(bids, asks) {
|
|
18
|
+
if (bids.length === 0 || asks.length === 0)
|
|
19
|
+
return null;
|
|
20
|
+
return (bids[0].price + asks[0].price) / 2;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Total resting size within `±bps` of the mid price, split by side.
|
|
24
|
+
*
|
|
25
|
+
* A snapshot of near-touch liquidity: how much can trade close to the current
|
|
26
|
+
* price before walking into deeper, worse-priced levels. The band half-width is
|
|
27
|
+
* `mid · bps / 10_000`, applied symmetrically. Levels must be sorted best-first.
|
|
28
|
+
* Returns zeros if either side is empty (no mid) or `bps <= 0`.
|
|
29
|
+
*/
|
|
30
|
+
export function depthWithin(bids, asks, bps) {
|
|
31
|
+
const m = mid(bids, asks);
|
|
32
|
+
if (m === null || bps <= 0)
|
|
33
|
+
return { bidDepth: 0, askDepth: 0, total: 0 };
|
|
34
|
+
const band = (m * bps) / 10_000;
|
|
35
|
+
const lo = m - band;
|
|
36
|
+
const hi = m + band;
|
|
37
|
+
let bidDepth = 0;
|
|
38
|
+
for (const l of bids)
|
|
39
|
+
if (l.price >= lo)
|
|
40
|
+
bidDepth += l.size;
|
|
41
|
+
let askDepth = 0;
|
|
42
|
+
for (const l of asks)
|
|
43
|
+
if (l.price <= hi)
|
|
44
|
+
askDepth += l.size;
|
|
45
|
+
return { bidDepth, askDepth, total: bidDepth + askDepth };
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Order-book slope: cumulative resting size divided by the relative price
|
|
49
|
+
* distance from `refPrice` to the outermost supplied level.
|
|
50
|
+
*
|
|
51
|
+
* slope = (Σ size) / ( |P_last − refPrice| / refPrice )
|
|
52
|
+
*
|
|
53
|
+
* It answers "how much size is packed per unit of relative price move" — a
|
|
54
|
+
* steeper (larger) slope means depth builds up quickly near the reference
|
|
55
|
+
* price, i.e. a thicker, more liquid book. Pass one side's levels (best-first)
|
|
56
|
+
* and a reference price (typically the mid). Returns 0 for empty input, a
|
|
57
|
+
* non-positive `refPrice`, or when the outermost level sits at the reference
|
|
58
|
+
* price (zero distance).
|
|
59
|
+
*/
|
|
60
|
+
export function orderBookSlope(levels, refPrice) {
|
|
61
|
+
if (levels.length === 0 || refPrice <= 0)
|
|
62
|
+
return 0;
|
|
63
|
+
let cum = 0;
|
|
64
|
+
for (const l of levels)
|
|
65
|
+
cum += l.size;
|
|
66
|
+
const dist = Math.abs(levels[levels.length - 1].price - refPrice) / refPrice;
|
|
67
|
+
if (dist === 0)
|
|
68
|
+
return 0;
|
|
69
|
+
return cum / dist;
|
|
70
|
+
}
|
|
71
|
+
function vwapFill(levels, size) {
|
|
72
|
+
let remaining = size;
|
|
73
|
+
let notional = 0;
|
|
74
|
+
let filled = 0;
|
|
75
|
+
for (const l of levels) {
|
|
76
|
+
if (remaining <= 0)
|
|
77
|
+
break;
|
|
78
|
+
const take = Math.min(remaining, l.size);
|
|
79
|
+
notional += take * l.price;
|
|
80
|
+
filled += take;
|
|
81
|
+
remaining -= take;
|
|
82
|
+
}
|
|
83
|
+
return { notional, filled };
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Round-trip liquidity cost: the basis-point gap between the VWAP of buying
|
|
87
|
+
* `size` from the asks and the VWAP of selling `size` into the bids, measured
|
|
88
|
+
* against the mid. This is the immediate "liquidity tax" of entering and
|
|
89
|
+
* exiting a position of `size` — spread plus the price impact of walking both
|
|
90
|
+
* sides of the book.
|
|
91
|
+
*
|
|
92
|
+
* Levels must be sorted best-first. `filledSize` is the smaller of the two
|
|
93
|
+
* sides' fills, so a book too thin on one side reports how much actually
|
|
94
|
+
* round-tripped. Returns zeros if either side is empty or `size <= 0`.
|
|
95
|
+
*/
|
|
96
|
+
export function costOfRoundTrip(bids, asks, size) {
|
|
97
|
+
const m = mid(bids, asks);
|
|
98
|
+
const zero = {
|
|
99
|
+
avgBuyPrice: 0,
|
|
100
|
+
avgSellPrice: 0,
|
|
101
|
+
roundTripBps: 0,
|
|
102
|
+
filledSize: 0,
|
|
103
|
+
};
|
|
104
|
+
if (m === null || size <= 0)
|
|
105
|
+
return zero;
|
|
106
|
+
const buy = vwapFill(asks, size);
|
|
107
|
+
const sell = vwapFill(bids, size);
|
|
108
|
+
if (buy.filled === 0 || sell.filled === 0)
|
|
109
|
+
return zero;
|
|
110
|
+
const avgBuyPrice = buy.notional / buy.filled;
|
|
111
|
+
const avgSellPrice = sell.notional / sell.filled;
|
|
112
|
+
return {
|
|
113
|
+
avgBuyPrice,
|
|
114
|
+
avgSellPrice,
|
|
115
|
+
roundTripBps: ((avgBuyPrice - avgSellPrice) / m) * 10_000,
|
|
116
|
+
filledSize: Math.min(buy.filled, sell.filled),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=bookdepth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bookdepth.js","sourceRoot":"","sources":["../src/bookdepth.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,8 @@ export type { BookSide, Level } from "./orderbook.ts";
|
|
|
16
16
|
export { OrderBook } from "./orderbook.ts";
|
|
17
17
|
export type { Fill, MarketOrderResult } from "./simulate.ts";
|
|
18
18
|
export { simulateMarketOrder } from "./simulate.ts";
|
|
19
|
+
export type { DepthWithin, RoundTripCost } from "./bookdepth.ts";
|
|
20
|
+
export { depthWithin, orderBookSlope, costOfRoundTrip, } from "./bookdepth.ts";
|
|
19
21
|
export { twap, pov } from "./scheduling.ts";
|
|
20
22
|
export type { Bar } from "./bars.ts";
|
|
21
23
|
export { tickBars, volumeBars, dollarBars } from "./bars.ts";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EACL,IAAI,EACJ,cAAc,EACd,cAAc,EACd,iBAAiB,GAClB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,WAAW,EACX,UAAU,EACV,UAAU,GACX,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACrE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACnD,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACjE,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,YAAY,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EACL,WAAW,EACX,cAAc,EACd,eAAe,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC7D,YAAY,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,OAAO,EACP,cAAc,GACf,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAC7E,YAAY,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC5D,YAAY,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,qBAAqB,GACtB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAClE,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EACL,aAAa,EACb,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,wBAAwB,EACxB,0BAA0B,GAC3B,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,OAAO,EACP,IAAI,EACJ,YAAY,EACZ,aAAa,GACd,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,GACb,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export { realizedVariance, realizedVolatility, annualizedVolatility, } from "./v
|
|
|
9
9
|
export { autocorrelation, varianceRatio } from "./efficiency.js";
|
|
10
10
|
export { OrderBook } from "./orderbook.js";
|
|
11
11
|
export { simulateMarketOrder } from "./simulate.js";
|
|
12
|
+
export { depthWithin, orderBookSlope, costOfRoundTrip, } from "./bookdepth.js";
|
|
12
13
|
export { twap, pov } from "./scheduling.js";
|
|
13
14
|
export { tickBars, volumeBars, dollarBars } from "./bars.js";
|
|
14
15
|
export { squareRootImpact, linearPermanentImpact, linearTemporaryImpact, almgrenChrissCost, markout, averageMarkout, } from "./impact.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhE,OAAO,EACL,IAAI,EACJ,cAAc,EACd,cAAc,EACd,iBAAiB,GAClB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,WAAW,EACX,UAAU,EACV,UAAU,GACX,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAErE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEjE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhE,OAAO,EACL,IAAI,EACJ,cAAc,EACd,cAAc,EACd,iBAAiB,GAClB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,WAAW,EACX,UAAU,EACV,UAAU,GACX,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAErE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEjE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,EACL,WAAW,EACX,cAAc,EACd,eAAe,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE7D,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,OAAO,EACP,cAAc,GACf,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAE7E,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE5D,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,qBAAqB,GACtB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAElE,OAAO,EACL,aAAa,EACb,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,wBAAwB,EACxB,0BAA0B,GAC3B,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,OAAO,EACP,IAAI,EACJ,YAAY,EACZ,aAAa,GACd,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,GACb,MAAM,iBAAiB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "orderflow-metrics",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"description": "Microstructure metrics in dependency-free TypeScript — OFI, VPIN, information-driven bars, market impact (square-root & Almgren-Chriss), markouts, implementation shortfall, high-low spread estimators (Corwin-Schultz, Abdi-Ranaldo), range-based volatility (Parkinson, Garman-Klass, Rogers-Satchell, Yang-Zhang), Hurst exponent, realized skewness & kurtosis, bipower variation & jump detection, jump-robust variance (MinRV, MedRV) & realized quarticity, realized semivariance & signed jump variation, order-flow entropy, online/streaming estimators (Welford, EWMA, rolling window), realized covariance/correlation/beta, microstructure-noise-robust variance (subsampling, volatility signature, two-scale realized variance), Kyle's lambda, trade-sign classification, Amihud illiquidity.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
package/src/bookdepth.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Book-depth liquidity metrics — reading liquidity straight off a limit-order
|
|
3
|
+
* book snapshot.
|
|
4
|
+
*
|
|
5
|
+
* Where `amihudIlliquidity` (see `liquidity.ts`) measures liquidity from
|
|
6
|
+
* realized price impact over time, these functions measure it from the *shape*
|
|
7
|
+
* of the resting book at a single instant: how much size is quoted near the
|
|
8
|
+
* touch, how steeply depth thickens away from mid, and what a round trip would
|
|
9
|
+
* actually cost. They complement `simulateMarketOrder` (which walks the book
|
|
10
|
+
* for one execution): these are summary statistics of the standing book, not a
|
|
11
|
+
* fill simulation.
|
|
12
|
+
*
|
|
13
|
+
* Every function takes plain `Level[]` arrays sorted best-first — bids by
|
|
14
|
+
* descending price, asks by ascending price — exactly as `OrderBook.depth()`
|
|
15
|
+
* returns them.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type { Level } from "./orderbook.ts";
|
|
19
|
+
|
|
20
|
+
/** Resting size available within a price band around the mid. */
|
|
21
|
+
export interface DepthWithin {
|
|
22
|
+
/** total bid size within the band */
|
|
23
|
+
bidDepth: number;
|
|
24
|
+
/** total ask size within the band */
|
|
25
|
+
askDepth: number;
|
|
26
|
+
/** bidDepth + askDepth */
|
|
27
|
+
total: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function mid(bids: readonly Level[], asks: readonly Level[]): number | null {
|
|
31
|
+
if (bids.length === 0 || asks.length === 0) return null;
|
|
32
|
+
return (bids[0].price + asks[0].price) / 2;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Total resting size within `±bps` of the mid price, split by side.
|
|
37
|
+
*
|
|
38
|
+
* A snapshot of near-touch liquidity: how much can trade close to the current
|
|
39
|
+
* price before walking into deeper, worse-priced levels. The band half-width is
|
|
40
|
+
* `mid · bps / 10_000`, applied symmetrically. Levels must be sorted best-first.
|
|
41
|
+
* Returns zeros if either side is empty (no mid) or `bps <= 0`.
|
|
42
|
+
*/
|
|
43
|
+
export function depthWithin(
|
|
44
|
+
bids: readonly Level[],
|
|
45
|
+
asks: readonly Level[],
|
|
46
|
+
bps: number,
|
|
47
|
+
): DepthWithin {
|
|
48
|
+
const m = mid(bids, asks);
|
|
49
|
+
if (m === null || bps <= 0) return { bidDepth: 0, askDepth: 0, total: 0 };
|
|
50
|
+
const band = (m * bps) / 10_000;
|
|
51
|
+
const lo = m - band;
|
|
52
|
+
const hi = m + band;
|
|
53
|
+
let bidDepth = 0;
|
|
54
|
+
for (const l of bids) if (l.price >= lo) bidDepth += l.size;
|
|
55
|
+
let askDepth = 0;
|
|
56
|
+
for (const l of asks) if (l.price <= hi) askDepth += l.size;
|
|
57
|
+
return { bidDepth, askDepth, total: bidDepth + askDepth };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Order-book slope: cumulative resting size divided by the relative price
|
|
62
|
+
* distance from `refPrice` to the outermost supplied level.
|
|
63
|
+
*
|
|
64
|
+
* slope = (Σ size) / ( |P_last − refPrice| / refPrice )
|
|
65
|
+
*
|
|
66
|
+
* It answers "how much size is packed per unit of relative price move" — a
|
|
67
|
+
* steeper (larger) slope means depth builds up quickly near the reference
|
|
68
|
+
* price, i.e. a thicker, more liquid book. Pass one side's levels (best-first)
|
|
69
|
+
* and a reference price (typically the mid). Returns 0 for empty input, a
|
|
70
|
+
* non-positive `refPrice`, or when the outermost level sits at the reference
|
|
71
|
+
* price (zero distance).
|
|
72
|
+
*/
|
|
73
|
+
export function orderBookSlope(
|
|
74
|
+
levels: readonly Level[],
|
|
75
|
+
refPrice: number,
|
|
76
|
+
): number {
|
|
77
|
+
if (levels.length === 0 || refPrice <= 0) return 0;
|
|
78
|
+
let cum = 0;
|
|
79
|
+
for (const l of levels) cum += l.size;
|
|
80
|
+
const dist = Math.abs(levels[levels.length - 1].price - refPrice) / refPrice;
|
|
81
|
+
if (dist === 0) return 0;
|
|
82
|
+
return cum / dist;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** The cost of buying then selling the same size against the standing book. */
|
|
86
|
+
export interface RoundTripCost {
|
|
87
|
+
/** size-weighted average price paid buying `size` from the asks */
|
|
88
|
+
avgBuyPrice: number;
|
|
89
|
+
/** size-weighted average price received selling `size` into the bids */
|
|
90
|
+
avgSellPrice: number;
|
|
91
|
+
/** round-trip cost in basis points of mid: (avgBuy − avgSell) / mid · 10⁴ */
|
|
92
|
+
roundTripBps: number;
|
|
93
|
+
/** size actually round-tripped (min of the fill each side supports) */
|
|
94
|
+
filledSize: number;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function vwapFill(
|
|
98
|
+
levels: readonly Level[],
|
|
99
|
+
size: number,
|
|
100
|
+
): { notional: number; filled: number } {
|
|
101
|
+
let remaining = size;
|
|
102
|
+
let notional = 0;
|
|
103
|
+
let filled = 0;
|
|
104
|
+
for (const l of levels) {
|
|
105
|
+
if (remaining <= 0) break;
|
|
106
|
+
const take = Math.min(remaining, l.size);
|
|
107
|
+
notional += take * l.price;
|
|
108
|
+
filled += take;
|
|
109
|
+
remaining -= take;
|
|
110
|
+
}
|
|
111
|
+
return { notional, filled };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Round-trip liquidity cost: the basis-point gap between the VWAP of buying
|
|
116
|
+
* `size` from the asks and the VWAP of selling `size` into the bids, measured
|
|
117
|
+
* against the mid. This is the immediate "liquidity tax" of entering and
|
|
118
|
+
* exiting a position of `size` — spread plus the price impact of walking both
|
|
119
|
+
* sides of the book.
|
|
120
|
+
*
|
|
121
|
+
* Levels must be sorted best-first. `filledSize` is the smaller of the two
|
|
122
|
+
* sides' fills, so a book too thin on one side reports how much actually
|
|
123
|
+
* round-tripped. Returns zeros if either side is empty or `size <= 0`.
|
|
124
|
+
*/
|
|
125
|
+
export function costOfRoundTrip(
|
|
126
|
+
bids: readonly Level[],
|
|
127
|
+
asks: readonly Level[],
|
|
128
|
+
size: number,
|
|
129
|
+
): RoundTripCost {
|
|
130
|
+
const m = mid(bids, asks);
|
|
131
|
+
const zero: RoundTripCost = {
|
|
132
|
+
avgBuyPrice: 0,
|
|
133
|
+
avgSellPrice: 0,
|
|
134
|
+
roundTripBps: 0,
|
|
135
|
+
filledSize: 0,
|
|
136
|
+
};
|
|
137
|
+
if (m === null || size <= 0) return zero;
|
|
138
|
+
const buy = vwapFill(asks, size);
|
|
139
|
+
const sell = vwapFill(bids, size);
|
|
140
|
+
if (buy.filled === 0 || sell.filled === 0) return zero;
|
|
141
|
+
const avgBuyPrice = buy.notional / buy.filled;
|
|
142
|
+
const avgSellPrice = sell.notional / sell.filled;
|
|
143
|
+
return {
|
|
144
|
+
avgBuyPrice,
|
|
145
|
+
avgSellPrice,
|
|
146
|
+
roundTripBps: ((avgBuyPrice - avgSellPrice) / m) * 10_000,
|
|
147
|
+
filledSize: Math.min(buy.filled, sell.filled),
|
|
148
|
+
};
|
|
149
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -32,6 +32,12 @@ export type { BookSide, Level } from "./orderbook.ts";
|
|
|
32
32
|
export { OrderBook } from "./orderbook.ts";
|
|
33
33
|
export type { Fill, MarketOrderResult } from "./simulate.ts";
|
|
34
34
|
export { simulateMarketOrder } from "./simulate.ts";
|
|
35
|
+
export type { DepthWithin, RoundTripCost } from "./bookdepth.ts";
|
|
36
|
+
export {
|
|
37
|
+
depthWithin,
|
|
38
|
+
orderBookSlope,
|
|
39
|
+
costOfRoundTrip,
|
|
40
|
+
} from "./bookdepth.ts";
|
|
35
41
|
export { twap, pov } from "./scheduling.ts";
|
|
36
42
|
export type { Bar } from "./bars.ts";
|
|
37
43
|
export { tickBars, volumeBars, dollarBars } from "./bars.ts";
|