@hardlydifficult/math 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/RingBuffer.d.ts +17 -0
- package/dist/RingBuffer.d.ts.map +1 -0
- package/dist/RingBuffer.js +63 -0
- package/dist/RingBuffer.js.map +1 -0
- package/dist/RollingVwap.d.ts +12 -0
- package/dist/RollingVwap.d.ts.map +1 -0
- package/dist/RollingVwap.js +37 -0
- package/dist/RollingVwap.js.map +1 -0
- package/dist/SlopeTracker.d.ts +10 -0
- package/dist/SlopeTracker.d.ts.map +1 -0
- package/dist/SlopeTracker.js +36 -0
- package/dist/SlopeTracker.js.map +1 -0
- package/dist/VwapTracker.d.ts +13 -0
- package/dist/VwapTracker.d.ts.map +1 -0
- package/dist/VwapTracker.js +37 -0
- package/dist/VwapTracker.js.map +1 -0
- package/dist/WindowedChange.d.ts +11 -0
- package/dist/WindowedChange.d.ts.map +1 -0
- package/dist/WindowedChange.js +46 -0
- package/dist/WindowedChange.js.map +1 -0
- package/dist/bookImbalance.d.ts +6 -0
- package/dist/bookImbalance.d.ts.map +1 -0
- package/dist/bookImbalance.js +38 -0
- package/dist/bookImbalance.js.map +1 -0
- package/dist/clamp.d.ts +3 -0
- package/dist/clamp.d.ts.map +1 -0
- package/dist/clamp.js +8 -0
- package/dist/clamp.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/linearRegression.d.ts +7 -0
- package/dist/linearRegression.d.ts.map +1 -0
- package/dist/linearRegression.js +32 -0
- package/dist/linearRegression.js.map +1 -0
- package/dist/trend.d.ts +4 -0
- package/dist/trend.d.ts.map +1 -0
- package/dist/trend.js +14 -0
- package/dist/trend.js.map +1 -0
- package/package.json +34 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
*/
|
|
4
|
+
export declare class RingBuffer<T> {
|
|
5
|
+
readonly capacity: number;
|
|
6
|
+
private readonly buffer;
|
|
7
|
+
private head;
|
|
8
|
+
private count;
|
|
9
|
+
constructor(capacity: number);
|
|
10
|
+
push(item: T): void;
|
|
11
|
+
get length(): number;
|
|
12
|
+
toArray(): T[];
|
|
13
|
+
first(): T | undefined;
|
|
14
|
+
last(): T | undefined;
|
|
15
|
+
clear(): void;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=RingBuffer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RingBuffer.d.ts","sourceRoot":"","sources":["../src/RingBuffer.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,UAAU,CAAC,CAAC;IAKX,QAAQ,CAAC,QAAQ,EAAE,MAAM;IAJrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,KAAK,CAAK;gBAEG,QAAQ,EAAE,MAAM;IAOrC,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI;IAQnB,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,OAAO,IAAI,CAAC,EAAE;IAed,KAAK,IAAI,CAAC,GAAG,SAAS;IAQtB,IAAI,IAAI,CAAC,GAAG,SAAS;IAOrB,KAAK,IAAI,IAAI;CAKd"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RingBuffer = void 0;
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
class RingBuffer {
|
|
8
|
+
capacity;
|
|
9
|
+
buffer;
|
|
10
|
+
head = 0;
|
|
11
|
+
count = 0;
|
|
12
|
+
constructor(capacity) {
|
|
13
|
+
this.capacity = capacity;
|
|
14
|
+
if (capacity < 1) {
|
|
15
|
+
throw new Error("RingBuffer capacity must be >= 1");
|
|
16
|
+
}
|
|
17
|
+
this.buffer = new Array(capacity);
|
|
18
|
+
}
|
|
19
|
+
push(item) {
|
|
20
|
+
this.buffer[this.head] = item;
|
|
21
|
+
this.head = (this.head + 1) % this.capacity;
|
|
22
|
+
if (this.count < this.capacity) {
|
|
23
|
+
this.count++;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
get length() {
|
|
27
|
+
return this.count;
|
|
28
|
+
}
|
|
29
|
+
toArray() {
|
|
30
|
+
if (this.count === 0) {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
const start = this.count < this.capacity ? 0 : this.head;
|
|
34
|
+
const result = [];
|
|
35
|
+
for (let i = 0; i < this.count; i++) {
|
|
36
|
+
const item = this.buffer[(start + i) % this.capacity];
|
|
37
|
+
if (item !== undefined) {
|
|
38
|
+
result.push(item);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
first() {
|
|
44
|
+
if (this.count === 0) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
const start = this.count < this.capacity ? 0 : this.head;
|
|
48
|
+
return this.buffer[start];
|
|
49
|
+
}
|
|
50
|
+
last() {
|
|
51
|
+
if (this.count === 0) {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
return this.buffer[(this.head - 1 + this.capacity) % this.capacity];
|
|
55
|
+
}
|
|
56
|
+
clear() {
|
|
57
|
+
this.head = 0;
|
|
58
|
+
this.count = 0;
|
|
59
|
+
this.buffer.fill(undefined);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.RingBuffer = RingBuffer;
|
|
63
|
+
//# sourceMappingURL=RingBuffer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RingBuffer.js","sourceRoot":"","sources":["../src/RingBuffer.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,MAAa,UAAU;IAKA;IAJJ,MAAM,CAAoB;IACnC,IAAI,GAAG,CAAC,CAAC;IACT,KAAK,GAAG,CAAC,CAAC;IAElB,YAAqB,QAAgB;QAAhB,aAAQ,GAAR,QAAQ,CAAQ;QACnC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,IAAI,KAAK,CAAgB,QAAQ,CAAC,CAAC;IACnD,CAAC;IAED,IAAI,CAAC,IAAO;QACV,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC5C,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC/B,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC;IACH,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,OAAO;QACL,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;YACrB,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACzD,MAAM,MAAM,GAAQ,EAAE,CAAC;QACvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YACpC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;YACtD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACvB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpB,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;YACrB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACzD,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;YACrB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtE,CAAC;IAED,KAAK;QACH,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;QACd,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC9B,CAAC;CACF;AA3DD,gCA2DC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
*/
|
|
4
|
+
export declare class RollingVwap {
|
|
5
|
+
private readonly buffer;
|
|
6
|
+
private readonly windowMs;
|
|
7
|
+
constructor(windowMs: number, capacity?: number);
|
|
8
|
+
addTrade(ts: number, price: number, size: number): this;
|
|
9
|
+
get value(): number;
|
|
10
|
+
valueAt(now: number): number;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=RollingVwap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RollingVwap.d.ts","sourceRoot":"","sources":["../src/RollingVwap.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;IACjD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,QAAQ,EAAE,MAAM,EAAE,QAAQ,SAAS;IAK/C,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAKvD,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;CAa7B"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RollingVwap = void 0;
|
|
4
|
+
const RingBuffer_js_1 = require("./RingBuffer.js");
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
class RollingVwap {
|
|
9
|
+
buffer;
|
|
10
|
+
windowMs;
|
|
11
|
+
constructor(windowMs, capacity = 50_000) {
|
|
12
|
+
this.windowMs = windowMs;
|
|
13
|
+
this.buffer = new RingBuffer_js_1.RingBuffer(capacity);
|
|
14
|
+
}
|
|
15
|
+
addTrade(ts, price, size) {
|
|
16
|
+
this.buffer.push({ ts, price, size });
|
|
17
|
+
return this;
|
|
18
|
+
}
|
|
19
|
+
get value() {
|
|
20
|
+
return this.valueAt(Date.now());
|
|
21
|
+
}
|
|
22
|
+
valueAt(now) {
|
|
23
|
+
const arr = this.buffer.toArray();
|
|
24
|
+
let pv = 0;
|
|
25
|
+
let v = 0;
|
|
26
|
+
for (let i = arr.length - 1; i >= 0; i--) {
|
|
27
|
+
if (now - arr[i].ts > this.windowMs) {
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
pv += arr[i].price * arr[i].size;
|
|
31
|
+
v += arr[i].size;
|
|
32
|
+
}
|
|
33
|
+
return v > 0 ? pv / v : 0;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.RollingVwap = RollingVwap;
|
|
37
|
+
//# sourceMappingURL=RollingVwap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RollingVwap.js","sourceRoot":"","sources":["../src/RollingVwap.ts"],"names":[],"mappings":";;;AAAA,mDAA6C;AAQ7C;;GAEG;AACH,MAAa,WAAW;IACL,MAAM,CAA0B;IAChC,QAAQ,CAAS;IAElC,YAAY,QAAgB,EAAE,QAAQ,GAAG,MAAM;QAC7C,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,IAAI,0BAAU,CAAc,QAAQ,CAAC,CAAC;IACtD,CAAC;IAED,QAAQ,CAAC,EAAU,EAAE,KAAa,EAAE,IAAY;QAC9C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,CAAC,GAAW;QACjB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAClC,IAAI,EAAE,GAAG,CAAC,CAAC;QACX,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,KAAK,IAAI,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACzC,IAAI,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACpC,MAAM;YACR,CAAC;YACD,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YACjC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACnB,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;CACF;AA/BD,kCA+BC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SlopeTracker.d.ts","sourceRoot":"","sources":["../src/SlopeTracker.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+B;gBAE1C,QAAQ,SAAM;IAI1B,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAK1C,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;CAkBhC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SlopeTracker = void 0;
|
|
4
|
+
const linearRegression_js_1 = require("./linearRegression.js");
|
|
5
|
+
const RingBuffer_js_1 = require("./RingBuffer.js");
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
class SlopeTracker {
|
|
10
|
+
buffer;
|
|
11
|
+
constructor(capacity = 600) {
|
|
12
|
+
this.buffer = new RingBuffer_js_1.RingBuffer(capacity);
|
|
13
|
+
}
|
|
14
|
+
addSample(ts, value) {
|
|
15
|
+
this.buffer.push({ ts, value });
|
|
16
|
+
return this;
|
|
17
|
+
}
|
|
18
|
+
slope(windowMs) {
|
|
19
|
+
const arr = this.buffer.toArray();
|
|
20
|
+
if (arr.length < 2) {
|
|
21
|
+
return 0;
|
|
22
|
+
}
|
|
23
|
+
const cutoff = arr[arr.length - 1].ts - windowMs;
|
|
24
|
+
const windowSamples = [];
|
|
25
|
+
for (let i = arr.length - 1; i >= 0; i--) {
|
|
26
|
+
if (arr[i].ts < cutoff) {
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
windowSamples.push({ t: arr[i].ts, v: arr[i].value });
|
|
30
|
+
}
|
|
31
|
+
windowSamples.reverse();
|
|
32
|
+
return (0, linearRegression_js_1.computeSlope)(windowSamples);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.SlopeTracker = SlopeTracker;
|
|
36
|
+
//# sourceMappingURL=SlopeTracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SlopeTracker.js","sourceRoot":"","sources":["../src/SlopeTracker.ts"],"names":[],"mappings":";;;AAAA,+DAAkE;AAClE,mDAA6C;AAO7C;;GAEG;AACH,MAAa,YAAY;IACN,MAAM,CAA+B;IAEtD,YAAY,QAAQ,GAAG,GAAG;QACxB,IAAI,CAAC,MAAM,GAAG,IAAI,0BAAU,CAAmB,QAAQ,CAAC,CAAC;IAC3D,CAAC;IAED,SAAS,CAAC,EAAU,EAAE,KAAa;QACjC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,QAAgB;QACpB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAClC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnB,OAAO,CAAC,CAAC;QACX,CAAC;QAED,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,QAAQ,CAAC;QACjD,MAAM,aAAa,GAAa,EAAE,CAAC;QACnC,KAAK,IAAI,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACzC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC;gBACvB,MAAM;YACR,CAAC;YACD,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;QACxD,CAAC;QAED,aAAa,CAAC,OAAO,EAAE,CAAC;QACxB,OAAO,IAAA,kCAAY,EAAC,aAAa,CAAC,CAAC;IACrC,CAAC;CACF;AA9BD,oCA8BC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
*/
|
|
4
|
+
export declare class VwapTracker {
|
|
5
|
+
private sumPV;
|
|
6
|
+
private sumV;
|
|
7
|
+
private sumPV2;
|
|
8
|
+
addTrade(price: number, size: number): this;
|
|
9
|
+
reset(): this;
|
|
10
|
+
get value(): number;
|
|
11
|
+
zScore(currentPrice: number): number;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=VwapTracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VwapTracker.d.ts","sourceRoot":"","sources":["../src/VwapTracker.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,MAAM,CAAK;IAEnB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAO3C,KAAK,IAAI,IAAI;IAOb,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;CASrC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VwapTracker = void 0;
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
class VwapTracker {
|
|
8
|
+
sumPV = 0;
|
|
9
|
+
sumV = 0;
|
|
10
|
+
sumPV2 = 0;
|
|
11
|
+
addTrade(price, size) {
|
|
12
|
+
this.sumPV += price * size;
|
|
13
|
+
this.sumV += size;
|
|
14
|
+
this.sumPV2 += price * price * size;
|
|
15
|
+
return this;
|
|
16
|
+
}
|
|
17
|
+
reset() {
|
|
18
|
+
this.sumPV = 0;
|
|
19
|
+
this.sumV = 0;
|
|
20
|
+
this.sumPV2 = 0;
|
|
21
|
+
return this;
|
|
22
|
+
}
|
|
23
|
+
get value() {
|
|
24
|
+
return this.sumV > 0 ? this.sumPV / this.sumV : 0;
|
|
25
|
+
}
|
|
26
|
+
zScore(currentPrice) {
|
|
27
|
+
const vwap = this.value;
|
|
28
|
+
if (vwap === 0 || this.sumV === 0 || currentPrice === 0) {
|
|
29
|
+
return 0;
|
|
30
|
+
}
|
|
31
|
+
const variance = this.sumPV2 / this.sumV - vwap * vwap;
|
|
32
|
+
const sigma = variance > 0 ? Math.sqrt(variance) : 0;
|
|
33
|
+
return sigma > 0 ? (currentPrice - vwap) / sigma : 0;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.VwapTracker = VwapTracker;
|
|
37
|
+
//# sourceMappingURL=VwapTracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VwapTracker.js","sourceRoot":"","sources":["../src/VwapTracker.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,MAAa,WAAW;IACd,KAAK,GAAG,CAAC,CAAC;IACV,IAAI,GAAG,CAAC,CAAC;IACT,MAAM,GAAG,CAAC,CAAC;IAEnB,QAAQ,CAAC,KAAa,EAAE,IAAY;QAClC,IAAI,CAAC,KAAK,IAAI,KAAK,GAAG,IAAI,CAAC;QAC3B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC;QAClB,IAAI,CAAC,MAAM,IAAI,KAAK,GAAG,KAAK,GAAG,IAAI,CAAC;QACpC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;QACd,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QAChB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,CAAC,YAAoB;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,YAAY,KAAK,CAAC,EAAE,CAAC;YACxD,OAAO,CAAC,CAAC;QACX,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;QACvD,MAAM,KAAK,GAAG,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACrD,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,CAAC;CACF;AAhCD,kCAgCC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
*/
|
|
4
|
+
export declare class WindowedChange {
|
|
5
|
+
private readonly buffer;
|
|
6
|
+
private readonly windowMs;
|
|
7
|
+
constructor(windowMs: number, capacity?: number);
|
|
8
|
+
addSample(ts: number, value: number): this;
|
|
9
|
+
get change(): number;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=WindowedChange.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WindowedChange.d.ts","sourceRoot":"","sources":["../src/WindowedChange.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+B;IACtD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,QAAQ,EAAE,MAAM,EAAE,QAAQ,SAAM;IAK5C,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAK1C,IAAI,MAAM,IAAI,MAAM,CA2BnB;CACF"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WindowedChange = void 0;
|
|
4
|
+
const RingBuffer_js_1 = require("./RingBuffer.js");
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
class WindowedChange {
|
|
9
|
+
buffer;
|
|
10
|
+
windowMs;
|
|
11
|
+
constructor(windowMs, capacity = 240) {
|
|
12
|
+
this.windowMs = windowMs;
|
|
13
|
+
this.buffer = new RingBuffer_js_1.RingBuffer(capacity);
|
|
14
|
+
}
|
|
15
|
+
addSample(ts, value) {
|
|
16
|
+
this.buffer.push({ ts, value });
|
|
17
|
+
return this;
|
|
18
|
+
}
|
|
19
|
+
get change() {
|
|
20
|
+
const arr = this.buffer.toArray();
|
|
21
|
+
if (arr.length < 2) {
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
const latest = arr[arr.length - 1];
|
|
25
|
+
const cutoff = latest.ts - this.windowMs;
|
|
26
|
+
let oldest;
|
|
27
|
+
for (const sample of arr) {
|
|
28
|
+
if (sample.ts <= cutoff) {
|
|
29
|
+
oldest = sample;
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (!oldest || oldest.value === 0) {
|
|
36
|
+
const first = arr[0];
|
|
37
|
+
if (first.value === 0) {
|
|
38
|
+
return 0;
|
|
39
|
+
}
|
|
40
|
+
return (latest.value - first.value) / first.value;
|
|
41
|
+
}
|
|
42
|
+
return (latest.value - oldest.value) / oldest.value;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.WindowedChange = WindowedChange;
|
|
46
|
+
//# sourceMappingURL=WindowedChange.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WindowedChange.js","sourceRoot":"","sources":["../src/WindowedChange.ts"],"names":[],"mappings":";;;AAAA,mDAA6C;AAO7C;;GAEG;AACH,MAAa,cAAc;IACR,MAAM,CAA+B;IACrC,QAAQ,CAAS;IAElC,YAAY,QAAgB,EAAE,QAAQ,GAAG,GAAG;QAC1C,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,IAAI,0BAAU,CAAmB,QAAQ,CAAC,CAAC;IAC3D,CAAC;IAED,SAAS,CAAC,EAAU,EAAE,KAAa;QACjC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,MAAM;QACR,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAClC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnB,OAAO,CAAC,CAAC;QACX,CAAC;QAED,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACnC,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC;QAEzC,IAAI,MAAoC,CAAC;QACzC,KAAK,MAAM,MAAM,IAAI,GAAG,EAAE,CAAC;YACzB,IAAI,MAAM,CAAC,EAAE,IAAI,MAAM,EAAE,CAAC;gBACxB,MAAM,GAAG,MAAM,CAAC;YAClB,CAAC;iBAAM,CAAC;gBACN,MAAM;YACR,CAAC;QACH,CAAC;QAED,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;YAClC,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;YACrB,IAAI,KAAK,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;gBACtB,OAAO,CAAC,CAAC;YACX,CAAC;YACD,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;QACpD,CAAC;QAED,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC;IACtD,CAAC;CACF;AA1CD,wCA0CC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type Level = readonly [price: number, size: number];
|
|
2
|
+
/** Top-of-book imbalance: (bidSize - askSize) / (bidSize + askSize). */
|
|
3
|
+
export declare function bookImbalance(bidSize: number, askSize: number): number;
|
|
4
|
+
/** Depth-weighted imbalance within ±depthPct of mid price. */
|
|
5
|
+
export declare function depthImbalance(bids: readonly Level[], asks: readonly Level[], depthPct: number): number;
|
|
6
|
+
//# sourceMappingURL=bookImbalance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bookImbalance.d.ts","sourceRoot":"","sources":["../src/bookImbalance.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AAE3D,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAGtE;AAED,8DAA8D;AAC9D,wBAAgB,cAAc,CAC5B,IAAI,EAAE,SAAS,KAAK,EAAE,EACtB,IAAI,EAAE,SAAS,KAAK,EAAE,EACtB,QAAQ,EAAE,MAAM,GACf,MAAM,CA+BR"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.bookImbalance = bookImbalance;
|
|
4
|
+
exports.depthImbalance = depthImbalance;
|
|
5
|
+
/** Top-of-book imbalance: (bidSize - askSize) / (bidSize + askSize). */
|
|
6
|
+
function bookImbalance(bidSize, askSize) {
|
|
7
|
+
const total = bidSize + askSize;
|
|
8
|
+
return total > 0 ? (bidSize - askSize) / total : 0;
|
|
9
|
+
}
|
|
10
|
+
/** Depth-weighted imbalance within ±depthPct of mid price. */
|
|
11
|
+
function depthImbalance(bids, asks, depthPct) {
|
|
12
|
+
if (bids.length === 0 || asks.length === 0) {
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
const mid = (bids[0][0] + asks[0][0]) / 2;
|
|
16
|
+
if (mid <= 0) {
|
|
17
|
+
return 0;
|
|
18
|
+
}
|
|
19
|
+
const lower = mid * (1 - depthPct);
|
|
20
|
+
const upper = mid * (1 + depthPct);
|
|
21
|
+
let sumBid = 0;
|
|
22
|
+
for (const [px, sz] of bids) {
|
|
23
|
+
if (px < lower) {
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
sumBid += sz;
|
|
27
|
+
}
|
|
28
|
+
let sumAsk = 0;
|
|
29
|
+
for (const [px, sz] of asks) {
|
|
30
|
+
if (px > upper) {
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
sumAsk += sz;
|
|
34
|
+
}
|
|
35
|
+
const total = sumBid + sumAsk;
|
|
36
|
+
return total > 0 ? (sumBid - sumAsk) / total : 0;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=bookImbalance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bookImbalance.js","sourceRoot":"","sources":["../src/bookImbalance.ts"],"names":[],"mappings":";;AAGA,sCAGC;AAGD,wCAmCC;AA1CD,wEAAwE;AACxE,SAAgB,aAAa,CAAC,OAAe,EAAE,OAAe;IAC5D,MAAM,KAAK,GAAG,OAAO,GAAG,OAAO,CAAC;IAChC,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,8DAA8D;AAC9D,SAAgB,cAAc,CAC5B,IAAsB,EACtB,IAAsB,EACtB,QAAgB;IAEhB,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3C,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC1C,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;QACb,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,KAAK,GAAG,GAAG,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,GAAG,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC;IAEnC,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;QAC5B,IAAI,EAAE,GAAG,KAAK,EAAE,CAAC;YACf,MAAM;QACR,CAAC;QACD,MAAM,IAAI,EAAE,CAAC;IACf,CAAC;IAED,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;QAC5B,IAAI,EAAE,GAAG,KAAK,EAAE,CAAC;YACf,MAAM;QACR,CAAC;QACD,MAAM,IAAI,EAAE,CAAC;IACf,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;IAC9B,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,CAAC"}
|
package/dist/clamp.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clamp.d.ts","sourceRoot":"","sources":["../src/clamp.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAErE"}
|
package/dist/clamp.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.clamp = clamp;
|
|
4
|
+
/** Constrain a value to the inclusive [min, max] range. */
|
|
5
|
+
function clamp(value, min, max) {
|
|
6
|
+
return Math.min(Math.max(value, min), max);
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=clamp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clamp.js","sourceRoot":"","sources":["../src/clamp.ts"],"names":[],"mappings":";;AACA,sBAEC;AAHD,2DAA2D;AAC3D,SAAgB,KAAK,CAAC,KAAa,EAAE,GAAW,EAAE,GAAW;IAC3D,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;AAC7C,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { RingBuffer } from "./RingBuffer.js";
|
|
2
|
+
export { type Sample, computeSlope } from "./linearRegression.js";
|
|
3
|
+
export { clamp } from "./clamp.js";
|
|
4
|
+
export { type TrendLabel, classifyTrend } from "./trend.js";
|
|
5
|
+
export { type Level, bookImbalance, depthImbalance } from "./bookImbalance.js";
|
|
6
|
+
export { VwapTracker } from "./VwapTracker.js";
|
|
7
|
+
export { RollingVwap } from "./RollingVwap.js";
|
|
8
|
+
export { SlopeTracker } from "./SlopeTracker.js";
|
|
9
|
+
export { WindowedChange } from "./WindowedChange.js";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,KAAK,MAAM,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,KAAK,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,KAAK,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WindowedChange = exports.SlopeTracker = exports.RollingVwap = exports.VwapTracker = exports.depthImbalance = exports.bookImbalance = exports.classifyTrend = exports.clamp = exports.computeSlope = exports.RingBuffer = void 0;
|
|
4
|
+
var RingBuffer_js_1 = require("./RingBuffer.js");
|
|
5
|
+
Object.defineProperty(exports, "RingBuffer", { enumerable: true, get: function () { return RingBuffer_js_1.RingBuffer; } });
|
|
6
|
+
var linearRegression_js_1 = require("./linearRegression.js");
|
|
7
|
+
Object.defineProperty(exports, "computeSlope", { enumerable: true, get: function () { return linearRegression_js_1.computeSlope; } });
|
|
8
|
+
var clamp_js_1 = require("./clamp.js");
|
|
9
|
+
Object.defineProperty(exports, "clamp", { enumerable: true, get: function () { return clamp_js_1.clamp; } });
|
|
10
|
+
var trend_js_1 = require("./trend.js");
|
|
11
|
+
Object.defineProperty(exports, "classifyTrend", { enumerable: true, get: function () { return trend_js_1.classifyTrend; } });
|
|
12
|
+
var bookImbalance_js_1 = require("./bookImbalance.js");
|
|
13
|
+
Object.defineProperty(exports, "bookImbalance", { enumerable: true, get: function () { return bookImbalance_js_1.bookImbalance; } });
|
|
14
|
+
Object.defineProperty(exports, "depthImbalance", { enumerable: true, get: function () { return bookImbalance_js_1.depthImbalance; } });
|
|
15
|
+
var VwapTracker_js_1 = require("./VwapTracker.js");
|
|
16
|
+
Object.defineProperty(exports, "VwapTracker", { enumerable: true, get: function () { return VwapTracker_js_1.VwapTracker; } });
|
|
17
|
+
var RollingVwap_js_1 = require("./RollingVwap.js");
|
|
18
|
+
Object.defineProperty(exports, "RollingVwap", { enumerable: true, get: function () { return RollingVwap_js_1.RollingVwap; } });
|
|
19
|
+
var SlopeTracker_js_1 = require("./SlopeTracker.js");
|
|
20
|
+
Object.defineProperty(exports, "SlopeTracker", { enumerable: true, get: function () { return SlopeTracker_js_1.SlopeTracker; } });
|
|
21
|
+
var WindowedChange_js_1 = require("./WindowedChange.js");
|
|
22
|
+
Object.defineProperty(exports, "WindowedChange", { enumerable: true, get: function () { return WindowedChange_js_1.WindowedChange; } });
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,iDAA6C;AAApC,2GAAA,UAAU,OAAA;AACnB,6DAAkE;AAA5C,mHAAA,YAAY,OAAA;AAClC,uCAAmC;AAA1B,iGAAA,KAAK,OAAA;AACd,uCAA4D;AAAlC,yGAAA,aAAa,OAAA;AACvC,uDAA+E;AAA1D,iHAAA,aAAa,OAAA;AAAE,kHAAA,cAAc,OAAA;AAClD,mDAA+C;AAAtC,6GAAA,WAAW,OAAA;AACpB,mDAA+C;AAAtC,6GAAA,WAAW,OAAA;AACpB,qDAAiD;AAAxC,+GAAA,YAAY,OAAA;AACrB,yDAAqD;AAA5C,mHAAA,cAAc,OAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linearRegression.d.ts","sourceRoot":"","sources":["../src/linearRegression.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,+DAA+D;AAC/D,wBAAgB,YAAY,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CA8B/D"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.computeSlope = computeSlope;
|
|
4
|
+
/** Least-squares regression slope over time-series samples. */
|
|
5
|
+
function computeSlope(samples) {
|
|
6
|
+
if (samples.length < 2) {
|
|
7
|
+
return 0;
|
|
8
|
+
}
|
|
9
|
+
const t0 = samples[0].t;
|
|
10
|
+
const n = samples.length;
|
|
11
|
+
let sumT = 0;
|
|
12
|
+
let sumV = 0;
|
|
13
|
+
for (let i = 0; i < n; i++) {
|
|
14
|
+
sumT += (samples[i].t - t0) / 1000;
|
|
15
|
+
sumV += samples[i].v;
|
|
16
|
+
}
|
|
17
|
+
const meanT = sumT / n;
|
|
18
|
+
const meanV = sumV / n;
|
|
19
|
+
let num = 0;
|
|
20
|
+
let den = 0;
|
|
21
|
+
for (let i = 0; i < n; i++) {
|
|
22
|
+
const dt = (samples[i].t - t0) / 1000 - meanT;
|
|
23
|
+
const dv = samples[i].v - meanV;
|
|
24
|
+
num += dt * dv;
|
|
25
|
+
den += dt * dt;
|
|
26
|
+
}
|
|
27
|
+
if (den === 0) {
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
return num / den;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=linearRegression.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linearRegression.js","sourceRoot":"","sources":["../src/linearRegression.ts"],"names":[],"mappings":";;AAMA,oCA8BC;AA/BD,+DAA+D;AAC/D,SAAgB,YAAY,CAAC,OAA0B;IACrD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxB,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAEzB,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;QACnC,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC;IACvB,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC;IAEvB,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC;QAC9C,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;QAChC,GAAG,IAAI,EAAE,GAAG,EAAE,CAAC;QACf,GAAG,IAAI,EAAE,GAAG,EAAE,CAAC;IACjB,CAAC;IAED,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC;QACd,OAAO,CAAC,CAAC;IACX,CAAC;IACD,OAAO,GAAG,GAAG,GAAG,CAAC;AACnB,CAAC"}
|
package/dist/trend.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trend.d.ts","sourceRoot":"","sources":["../src/trend.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;AAEhD,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,UAAU,CAQ1E"}
|
package/dist/trend.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.classifyTrend = classifyTrend;
|
|
4
|
+
/** Classify a value as up/down/flat against a symmetric threshold. */
|
|
5
|
+
function classifyTrend(value, threshold) {
|
|
6
|
+
if (value > threshold) {
|
|
7
|
+
return "up";
|
|
8
|
+
}
|
|
9
|
+
if (value < -threshold) {
|
|
10
|
+
return "down";
|
|
11
|
+
}
|
|
12
|
+
return "flat";
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=trend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trend.js","sourceRoot":"","sources":["../src/trend.ts"],"names":[],"mappings":";;AAGA,sCAQC;AATD,sEAAsE;AACtE,SAAgB,aAAa,CAAC,KAAa,EAAE,SAAiB;IAC5D,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,KAAK,GAAG,CAAC,SAAS,EAAE,CAAC;QACvB,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hardlydifficult/math",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "./dist/index.js",
|
|
5
|
+
"types": "./dist/index.d.ts",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"test": "vitest run",
|
|
12
|
+
"test:watch": "vitest",
|
|
13
|
+
"test:coverage": "vitest run --coverage",
|
|
14
|
+
"lint": "tsc --noEmit",
|
|
15
|
+
"clean": "node --eval \"fs.rmSync('dist', { recursive: true, force: true })\""
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"typescript": "5.9.3",
|
|
19
|
+
"vitest": "4.0.18",
|
|
20
|
+
"@vitest/coverage-v8": "4.0.18"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=20.19.0"
|
|
24
|
+
},
|
|
25
|
+
"type": "commonjs",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"import": "./dist/index.js",
|
|
30
|
+
"require": "./dist/index.js",
|
|
31
|
+
"default": "./dist/index.js"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|