@quantform/core 0.3.217 → 0.3.222
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/indicator/atr.d.ts +1 -2
- package/dist/indicator/atr.js +4 -1
- package/dist/indicator/atr.js.map +1 -1
- package/dist/indicator/donchian.d.ts +7 -6
- package/dist/indicator/donchian.js +6 -15
- package/dist/indicator/donchian.js.map +1 -1
- package/dist/indicator/ema.d.ts +1 -10
- package/dist/indicator/ema.js +13 -32
- package/dist/indicator/ema.js.map +1 -1
- package/dist/indicator/ema.spec.js +4 -23
- package/dist/indicator/ema.spec.js.map +1 -1
- package/dist/indicator/envelope.js +4 -8
- package/dist/indicator/envelope.js.map +1 -1
- package/dist/indicator/index.d.ts +1 -1
- package/dist/indicator/index.js +1 -1
- package/dist/indicator/index.js.map +1 -1
- package/dist/indicator/macd.js +3 -12
- package/dist/indicator/macd.js.map +1 -1
- package/dist/indicator/min-max.d.ts +4 -11
- package/dist/indicator/min-max.js +12 -29
- package/dist/indicator/min-max.js.map +1 -1
- package/dist/indicator/rma.d.ts +1 -10
- package/dist/indicator/rma.js +13 -32
- package/dist/indicator/rma.js.map +1 -1
- package/dist/indicator/sma.d.ts +1 -10
- package/dist/indicator/sma.js +11 -22
- package/dist/indicator/sma.js.map +1 -1
- package/dist/indicator/sma.spec.js +1 -1
- package/dist/indicator/sma.spec.js.map +1 -1
- package/dist/indicator/swma.d.ts +1 -9
- package/dist/indicator/swma.js +11 -26
- package/dist/indicator/swma.js.map +1 -1
- package/dist/indicator/tma.d.ts +1 -2
- package/dist/indicator/tma.js +4 -1
- package/dist/indicator/tma.js.map +1 -1
- package/dist/indicator/tma.spec.js +1 -1
- package/dist/indicator/tma.spec.js.map +1 -1
- package/dist/indicator/truerange.d.ts +1 -1
- package/dist/indicator/truerange.js +3 -1
- package/dist/indicator/truerange.js.map +1 -1
- package/dist/indicator/truerange.spec.js +2 -2
- package/dist/indicator/truerange.spec.js.map +1 -1
- package/dist/indicator/window.d.ts +3 -0
- package/dist/indicator/window.js +22 -0
- package/dist/indicator/window.js.map +1 -0
- package/dist/indicator/wma.d.ts +1 -11
- package/dist/indicator/wma.js +13 -33
- package/dist/indicator/wma.js.map +1 -1
- package/dist/indicator/wma.spec.js +1 -1
- package/dist/indicator/wma.spec.js.map +1 -1
- package/dist/session/session-descriptor.d.ts +0 -1
- package/dist/session/session-optimizer.js.map +1 -1
- package/dist/session/session.d.ts +10 -6
- package/dist/session/session.js +26 -15
- package/dist/session/session.js.map +1 -1
- package/dist/storage/measurement.d.ts +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/indicator/atr.ts +9 -4
- package/src/indicator/donchian.ts +26 -26
- package/src/indicator/ema.spec.ts +4 -23
- package/src/indicator/ema.ts +15 -42
- package/src/indicator/envelope.ts +8 -14
- package/src/indicator/index.ts +1 -1
- package/src/indicator/macd.ts +8 -19
- package/src/indicator/min-max.ts +15 -37
- package/src/indicator/rma.ts +15 -43
- package/src/indicator/sma.spec.ts +1 -1
- package/src/indicator/sma.ts +13 -29
- package/src/indicator/swma.ts +14 -35
- package/src/indicator/tma.spec.ts +1 -1
- package/src/indicator/tma.ts +9 -4
- package/src/indicator/truerange.spec.ts +2 -2
- package/src/indicator/truerange.ts +15 -10
- package/src/indicator/window.ts +27 -0
- package/src/indicator/wma.spec.ts +1 -1
- package/src/indicator/wma.ts +16 -44
- package/src/session/session-descriptor.ts +0 -2
- package/src/session/session-optimizer.ts +1 -1
- package/src/session/session.ts +47 -17
- package/src/storage/measurement.ts +1 -2
- package/dist/indicator/window-indicator.d.ts +0 -10
- package/dist/indicator/window-indicator.js +0 -28
- package/dist/indicator/window-indicator.js.map +0 -1
- package/src/indicator/window-indicator.ts +0 -35
package/src/indicator/ema.ts
CHANGED
|
@@ -1,52 +1,25 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { WindowIndicator } from './window-indicator';
|
|
5
|
-
|
|
6
|
-
export class EMA extends WindowIndicator<number> {
|
|
7
|
-
private _alpha = 0;
|
|
8
|
-
private _sma: SMA;
|
|
9
|
-
private _value = null;
|
|
10
|
-
|
|
11
|
-
get value(): number {
|
|
12
|
-
return this._value;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
constructor(capacity: number) {
|
|
16
|
-
super(capacity);
|
|
17
|
-
|
|
18
|
-
this._alpha = 2.0 / (capacity + 1);
|
|
19
|
-
this._sma = new SMA(capacity);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
calculate(added: number) {
|
|
23
|
-
this._sma.append(added);
|
|
24
|
-
|
|
25
|
-
if (!this._sma.isCompleted) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (!this.value) {
|
|
30
|
-
this._value = this._sma.value;
|
|
31
|
-
} else {
|
|
32
|
-
//this._value = (added - this._value) * this._alpha + this._value;
|
|
33
|
-
|
|
34
|
-
this._value = this._alpha * added + (1.0 - this._alpha) * this._value;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
2
|
+
import { map, share } from 'rxjs/operators';
|
|
3
|
+
import { sma } from './sma';
|
|
38
4
|
|
|
39
5
|
export function ema<T>(length: number, fn: (it: T) => number) {
|
|
40
|
-
return function(source: Observable<T>): Observable<
|
|
41
|
-
const
|
|
6
|
+
return function (source: Observable<T>): Observable<[T, number]> {
|
|
7
|
+
const alpha = 2.0 / (length + 1);
|
|
8
|
+
let value: number = null;
|
|
42
9
|
|
|
43
10
|
return source.pipe(
|
|
44
|
-
|
|
45
|
-
|
|
11
|
+
sma(length, fn),
|
|
12
|
+
map(([it, sma]) => {
|
|
13
|
+
if (!value) {
|
|
14
|
+
value = sma;
|
|
15
|
+
} else {
|
|
16
|
+
value = alpha * fn(it) + (1.0 - alpha) * value;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const tuple: [T, number] = [it, value];
|
|
46
20
|
|
|
47
|
-
return
|
|
21
|
+
return tuple;
|
|
48
22
|
}),
|
|
49
|
-
map(() => indicator),
|
|
50
23
|
share()
|
|
51
24
|
);
|
|
52
25
|
};
|
|
@@ -1,23 +1,17 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { map, share } from 'rxjs/operators';
|
|
3
|
+
import { sma } from './sma';
|
|
4
4
|
|
|
5
5
|
export function envelope<T>(length: number, percent: number, valueFn: (it: T) => number) {
|
|
6
|
-
return function(source: Observable<T>): Observable<{ min: number; max: number }> {
|
|
7
|
-
const indicator = new SMA(length);
|
|
8
|
-
|
|
6
|
+
return function (source: Observable<T>): Observable<{ min: number; max: number }> {
|
|
9
7
|
return source.pipe(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return indicator.isCompleted;
|
|
14
|
-
}),
|
|
15
|
-
map(it => {
|
|
16
|
-
const offset = (indicator.value * percent) / 100;
|
|
8
|
+
sma(length, valueFn),
|
|
9
|
+
map(([it, sma]) => {
|
|
10
|
+
const offset = (sma * percent) / 100;
|
|
17
11
|
|
|
18
12
|
return {
|
|
19
|
-
min:
|
|
20
|
-
max:
|
|
13
|
+
min: sma - offset,
|
|
14
|
+
max: sma + offset
|
|
21
15
|
};
|
|
22
16
|
}),
|
|
23
17
|
share()
|
package/src/indicator/index.ts
CHANGED
|
@@ -10,7 +10,7 @@ export * from './swma';
|
|
|
10
10
|
export * from './tma';
|
|
11
11
|
export * from './trailing';
|
|
12
12
|
export * from './truerange';
|
|
13
|
-
export * from './window
|
|
13
|
+
export * from './window';
|
|
14
14
|
export * from './wma';
|
|
15
15
|
export * from './donchian';
|
|
16
16
|
export * from './atr';
|
package/src/indicator/macd.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Observable } from 'rxjs';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { Observable, withLatestFrom } from 'rxjs';
|
|
2
|
+
import { map, share } from 'rxjs/operators';
|
|
3
|
+
import { ema } from './ema';
|
|
4
4
|
|
|
5
5
|
export function macd<T>(
|
|
6
6
|
fast: number,
|
|
@@ -8,24 +8,13 @@ export function macd<T>(
|
|
|
8
8
|
length: number,
|
|
9
9
|
fn: (it: T) => number
|
|
10
10
|
) {
|
|
11
|
-
return function(source: Observable<T>): Observable<number> {
|
|
12
|
-
|
|
13
|
-
fast: new EMA(fast),
|
|
14
|
-
slow: new EMA(slow),
|
|
15
|
-
macd: new EMA(length)
|
|
16
|
-
};
|
|
11
|
+
return function (source: Observable<T>): Observable<number> {
|
|
12
|
+
source = source.pipe(share());
|
|
17
13
|
|
|
18
14
|
return source.pipe(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
ema.fast.append(value);
|
|
23
|
-
ema.slow.append(value);
|
|
24
|
-
ema.macd.append(ema.fast.value - ema.slow.value);
|
|
25
|
-
|
|
26
|
-
return ema.macd.isCompleted;
|
|
27
|
-
}),
|
|
28
|
-
map(_ => ema.macd.value),
|
|
15
|
+
withLatestFrom(source.pipe(ema(fast, fn)), source.pipe(ema(slow, fn))),
|
|
16
|
+
ema(length, it => it[1][1] - it[2][1]),
|
|
17
|
+
map(([it, macd]) => macd),
|
|
29
18
|
share()
|
|
30
19
|
);
|
|
31
20
|
};
|
package/src/indicator/min-max.ts
CHANGED
|
@@ -1,46 +1,24 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
2
|
import { filter, map, share } from 'rxjs/operators';
|
|
3
|
-
import {
|
|
4
|
-
import { WindowIndicator } from './window-indicator';
|
|
5
|
-
|
|
6
|
-
export class MinMax extends WindowIndicator<number> {
|
|
7
|
-
private _min = 0;
|
|
8
|
-
private _max = 0;
|
|
9
|
-
|
|
10
|
-
get min(): number {
|
|
11
|
-
return this._min;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
get max(): number {
|
|
15
|
-
return this._max;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
constructor(capacity: number) {
|
|
19
|
-
super(capacity);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
calculate(added: number, removed: number, buffer: RingBuffer<number>) {
|
|
23
|
-
this._min = added;
|
|
24
|
-
this._max = added;
|
|
25
|
-
|
|
26
|
-
buffer.forEach(it => {
|
|
27
|
-
this._min = Math.min(it, this._min);
|
|
28
|
-
this._max = Math.max(it, this._max);
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
}
|
|
3
|
+
import { window } from './window';
|
|
32
4
|
|
|
33
5
|
export function minMax<T>(length: number, fn: (it: T) => number) {
|
|
34
|
-
return function(source: Observable<T>): Observable<
|
|
35
|
-
const indicator = new MinMax(length);
|
|
36
|
-
|
|
6
|
+
return function (source: Observable<T>): Observable<[T, { min: number; max: number }]> {
|
|
37
7
|
return source.pipe(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
8
|
+
window(length, fn),
|
|
9
|
+
filter(([, buffer]) => buffer.isFull),
|
|
10
|
+
map(([it, buffer]) => {
|
|
11
|
+
let min = 0;
|
|
12
|
+
let max = 0;
|
|
13
|
+
|
|
14
|
+
buffer.forEach(it => {
|
|
15
|
+
min = Math.min(it, min);
|
|
16
|
+
max = Math.max(it, max);
|
|
17
|
+
});
|
|
18
|
+
const tuple: [T, { min: number; max: number }] = [it, { min, max }];
|
|
19
|
+
|
|
20
|
+
return tuple;
|
|
42
21
|
}),
|
|
43
|
-
map(() => indicator),
|
|
44
22
|
share()
|
|
45
23
|
);
|
|
46
24
|
};
|
package/src/indicator/rma.ts
CHANGED
|
@@ -1,52 +1,24 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { WindowIndicator } from './window-indicator';
|
|
5
|
-
|
|
6
|
-
export class RMA extends WindowIndicator<number> {
|
|
7
|
-
private _alpha = 0;
|
|
8
|
-
private _sma: SMA;
|
|
9
|
-
private _value = null;
|
|
10
|
-
|
|
11
|
-
get value(): number {
|
|
12
|
-
return this._value;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
constructor(capacity: number) {
|
|
16
|
-
super(capacity);
|
|
17
|
-
|
|
18
|
-
this._alpha = 1.0 / capacity;
|
|
19
|
-
this._sma = new SMA(capacity);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
calculate(added: number) {
|
|
23
|
-
this._sma.append(added);
|
|
24
|
-
|
|
25
|
-
if (!this._sma.isCompleted) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (!this.value) {
|
|
30
|
-
this._value = this._sma.value;
|
|
31
|
-
} else {
|
|
32
|
-
//this._value = (added - this._value) * this._alpha + this._value;
|
|
33
|
-
|
|
34
|
-
this._value = this._alpha * added + (1.0 - this._alpha) * this._value;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
2
|
+
import { map, share } from 'rxjs/operators';
|
|
3
|
+
import { sma } from '.';
|
|
38
4
|
|
|
39
5
|
export function rma<T>(length: number, fn: (it: T) => number) {
|
|
40
|
-
return function(source: Observable<T>): Observable<
|
|
41
|
-
const
|
|
6
|
+
return function (source: Observable<T>): Observable<[T, number]> {
|
|
7
|
+
const alpha = 1.0 / length;
|
|
8
|
+
let value: number = null;
|
|
42
9
|
|
|
43
10
|
return source.pipe(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
11
|
+
sma(length, fn),
|
|
12
|
+
map(([it, sma]) => {
|
|
13
|
+
if (!value) {
|
|
14
|
+
value = sma;
|
|
15
|
+
} else {
|
|
16
|
+
value = alpha * fn(it) + (1.0 - alpha) * value;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const tuple: [T, number] = [it, value];
|
|
20
|
+
return tuple;
|
|
48
21
|
}),
|
|
49
|
-
map(() => indicator),
|
|
50
22
|
share()
|
|
51
23
|
);
|
|
52
24
|
};
|
|
@@ -9,7 +9,7 @@ describe('sma tests', () => {
|
|
|
9
9
|
from([18136.17, 18092.15, 18082.39, 18065.4, 18046.47])
|
|
10
10
|
.pipe(sma(5, it => it))
|
|
11
11
|
.subscribe({
|
|
12
|
-
next: it => (value = it
|
|
12
|
+
next: ([, it]) => (value = it),
|
|
13
13
|
complete: () => {
|
|
14
14
|
expect(parseFloat(value.toFixed(2))).toBe(18084.52);
|
|
15
15
|
done();
|
package/src/indicator/sma.ts
CHANGED
|
@@ -1,39 +1,23 @@
|
|
|
1
|
-
import { Observable } from 'rxjs';
|
|
1
|
+
import { Observable, tap } from 'rxjs';
|
|
2
2
|
import { filter, map, share } from 'rxjs/operators';
|
|
3
|
-
import {
|
|
4
|
-
import { WindowIndicator } from './window-indicator';
|
|
5
|
-
|
|
6
|
-
export class SMA extends WindowIndicator<number> {
|
|
7
|
-
private _accmulated = 0;
|
|
8
|
-
private _value: number;
|
|
9
|
-
|
|
10
|
-
get value(): number {
|
|
11
|
-
return this._value;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
constructor(capacity: number) {
|
|
15
|
-
super(capacity);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
calculate(added: number, removed: number, buffer: RingBuffer<number>) {
|
|
19
|
-
this._accmulated += added;
|
|
20
|
-
this._accmulated -= removed;
|
|
21
|
-
|
|
22
|
-
this._value = this._accmulated / buffer.size;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
3
|
+
import { window } from './window';
|
|
25
4
|
|
|
26
5
|
export function sma<T>(length: number, fn: (it: T) => number) {
|
|
27
|
-
return function(source: Observable<T>): Observable<
|
|
28
|
-
|
|
6
|
+
return function (source: Observable<T>): Observable<[T, number]> {
|
|
7
|
+
let accumulated = 0;
|
|
29
8
|
|
|
30
9
|
return source.pipe(
|
|
31
|
-
|
|
32
|
-
|
|
10
|
+
window(length, fn),
|
|
11
|
+
tap(([, , added, removed]) => {
|
|
12
|
+
accumulated += added;
|
|
13
|
+
accumulated -= removed;
|
|
14
|
+
}),
|
|
15
|
+
filter(([, buffer]) => buffer.isFull),
|
|
16
|
+
map(([it, buffer]) => {
|
|
17
|
+
const tuple: [T, number] = [it, accumulated / buffer.size];
|
|
33
18
|
|
|
34
|
-
return
|
|
19
|
+
return tuple;
|
|
35
20
|
}),
|
|
36
|
-
map(_ => indicator),
|
|
37
21
|
share()
|
|
38
22
|
);
|
|
39
23
|
};
|
package/src/indicator/swma.ts
CHANGED
|
@@ -1,44 +1,23 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
2
|
import { filter, map, share } from 'rxjs/operators';
|
|
3
|
-
import {
|
|
4
|
-
import { WindowIndicator } from './window-indicator';
|
|
5
|
-
|
|
6
|
-
export class SWMA extends WindowIndicator<number> {
|
|
7
|
-
private _value;
|
|
8
|
-
|
|
9
|
-
get value(): number {
|
|
10
|
-
return this._value;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
constructor() {
|
|
14
|
-
super(4);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
calculate(added: number, removed: number, buffer: RingBuffer<number>) {
|
|
18
|
-
if (!this.isCompleted) {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const x3 = buffer.at(this.capacity - (3 + 1));
|
|
23
|
-
const x2 = buffer.at(this.capacity - (2 + 1));
|
|
24
|
-
const x1 = buffer.at(this.capacity - (1 + 1));
|
|
25
|
-
const x0 = buffer.at(this.capacity - (0 + 1));
|
|
26
|
-
|
|
27
|
-
this._value = (x3 * 1) / 6 + (x2 * 2) / 6 + (x1 * 2) / 6 + (x0 * 1) / 6;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
3
|
+
import { window } from './window';
|
|
30
4
|
|
|
31
5
|
export function swma<T>(fn: (it: T) => number) {
|
|
32
|
-
return function(source: Observable<T>): Observable<
|
|
33
|
-
const indicator = new SWMA();
|
|
34
|
-
|
|
6
|
+
return function (source: Observable<T>): Observable<[T, number]> {
|
|
35
7
|
return source.pipe(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
8
|
+
window(4, fn),
|
|
9
|
+
filter(([, buffer]) => buffer.isFull),
|
|
10
|
+
map(([it, buffer]) => {
|
|
11
|
+
const x3 = buffer.at(buffer.capacity - (3 + 1));
|
|
12
|
+
const x2 = buffer.at(buffer.capacity - (2 + 1));
|
|
13
|
+
const x1 = buffer.at(buffer.capacity - (1 + 1));
|
|
14
|
+
const x0 = buffer.at(buffer.capacity - (0 + 1));
|
|
15
|
+
|
|
16
|
+
const value = (x3 * 1) / 6 + (x2 * 2) / 6 + (x1 * 2) / 6 + (x0 * 1) / 6;
|
|
17
|
+
|
|
18
|
+
const tuple: [T, number] = [it, value];
|
|
19
|
+
return tuple;
|
|
40
20
|
}),
|
|
41
|
-
map(_ => indicator),
|
|
42
21
|
share()
|
|
43
22
|
);
|
|
44
23
|
};
|
|
@@ -9,7 +9,7 @@ describe('tma tests', () => {
|
|
|
9
9
|
from([18086.36, 18116.15, 18127.81, 18136.17, 18092.15, 18082.39, 18065.4, 18046.47])
|
|
10
10
|
.pipe(tma(4, it => it))
|
|
11
11
|
.subscribe({
|
|
12
|
-
next: it => (value = it
|
|
12
|
+
next: ([, it]) => (value = it),
|
|
13
13
|
complete: () => {
|
|
14
14
|
expect(parseFloat(value.toFixed(2))).toBe(18090.98);
|
|
15
15
|
done();
|
package/src/indicator/tma.ts
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
|
-
import { share } from 'rxjs/operators';
|
|
3
|
-
import {
|
|
2
|
+
import { share, map } from 'rxjs/operators';
|
|
3
|
+
import { swma } from './swma';
|
|
4
4
|
import { wma } from './wma';
|
|
5
5
|
|
|
6
6
|
export function tma<T>(length: number, fn: (it: T) => number) {
|
|
7
|
-
return function(source: Observable<T>): Observable<
|
|
7
|
+
return function (source: Observable<T>): Observable<[T, number]> {
|
|
8
8
|
return source.pipe(
|
|
9
9
|
wma(length, fn),
|
|
10
|
-
swma(it => it
|
|
10
|
+
swma(([, it]) => it),
|
|
11
|
+
map(([[it], swma]) => {
|
|
12
|
+
const tuple: [T, number] = [it, swma];
|
|
13
|
+
|
|
14
|
+
return tuple;
|
|
15
|
+
}),
|
|
11
16
|
share()
|
|
12
17
|
);
|
|
13
18
|
};
|
|
@@ -18,10 +18,10 @@ describe('truerange atr tests', () => {
|
|
|
18
18
|
])
|
|
19
19
|
.pipe(
|
|
20
20
|
truerange(it => it),
|
|
21
|
-
sma(4, it => it)
|
|
21
|
+
sma(4, ([, it]) => it)
|
|
22
22
|
)
|
|
23
23
|
.subscribe({
|
|
24
|
-
next: it => (value = it
|
|
24
|
+
next: ([, it]) => (value = it),
|
|
25
25
|
complete: () => {
|
|
26
26
|
expect(parseFloat(value.toFixed(2))).toBe(42.41);
|
|
27
27
|
done();
|
|
@@ -3,22 +3,27 @@ import { map, share } from 'rxjs/operators';
|
|
|
3
3
|
import { Candle } from '../domain';
|
|
4
4
|
|
|
5
5
|
export function truerange<T>(fn: (it: T) => Candle) {
|
|
6
|
-
return function(source: Observable<T>): Observable<number> {
|
|
6
|
+
return function (source: Observable<T>): Observable<[T, number]> {
|
|
7
7
|
let previous;
|
|
8
8
|
|
|
9
9
|
return source.pipe(
|
|
10
10
|
map(it => {
|
|
11
11
|
const current = fn(it);
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
const value =
|
|
14
|
+
previous == null
|
|
15
|
+
? current.high - current.low
|
|
16
|
+
: Math.max(
|
|
17
|
+
Math.max(
|
|
18
|
+
current.high - current.low,
|
|
19
|
+
Math.abs(current.high - previous.close)
|
|
20
|
+
),
|
|
21
|
+
Math.abs(current.low - previous.close)
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const tuple: [T, number] = [it, value];
|
|
25
|
+
|
|
26
|
+
return tuple;
|
|
22
27
|
}),
|
|
23
28
|
share()
|
|
24
29
|
);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Observable, share, map } from 'rxjs';
|
|
2
|
+
import { RingBuffer } from './ring-buffer';
|
|
3
|
+
|
|
4
|
+
export function window<T, Y>(length: number, fn: (value: T) => Y) {
|
|
5
|
+
return function (source: Observable<T>): Observable<[T, RingBuffer<Y>, Y, Y]> {
|
|
6
|
+
const buffer = new RingBuffer<Y>(length);
|
|
7
|
+
|
|
8
|
+
return source.pipe(
|
|
9
|
+
map(it => {
|
|
10
|
+
let removed = null;
|
|
11
|
+
|
|
12
|
+
if (buffer.isFull) {
|
|
13
|
+
removed = buffer.peek();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const value = fn(it);
|
|
17
|
+
|
|
18
|
+
buffer.enqueue(value);
|
|
19
|
+
|
|
20
|
+
const tuple: [T, RingBuffer<Y>, Y, Y] = [it, buffer, value, removed];
|
|
21
|
+
|
|
22
|
+
return tuple;
|
|
23
|
+
}),
|
|
24
|
+
share()
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -8,7 +8,7 @@ describe('wma tests', () => {
|
|
|
8
8
|
from([18136.17, 18092.15, 18082.39, 18065.4, 18046.47])
|
|
9
9
|
.pipe(wma(5, it => it))
|
|
10
10
|
.subscribe({
|
|
11
|
-
next: it => (value = it
|
|
11
|
+
next: ([, it]) => (value = it),
|
|
12
12
|
complete: () => {
|
|
13
13
|
expect(parseFloat(value.toFixed(2))).toBe(18070.77);
|
|
14
14
|
done();
|
package/src/indicator/wma.ts
CHANGED
|
@@ -1,55 +1,27 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
2
|
import { filter, map, share } from 'rxjs/operators';
|
|
3
|
-
import {
|
|
4
|
-
import { SMA } from './sma';
|
|
5
|
-
import { WindowIndicator } from './window-indicator';
|
|
3
|
+
import { window } from './window';
|
|
6
4
|
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
constructor(capacity: number) {
|
|
17
|
-
super(capacity);
|
|
18
|
-
|
|
19
|
-
this._k = 1.0 / capacity;
|
|
20
|
-
this._sma = new SMA(capacity);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
calculate(added: number, removed: number, buffer: RingBuffer<number>) {
|
|
24
|
-
if (!this.isCompleted) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
let norm = 0.0;
|
|
29
|
-
let sum = 0.0;
|
|
30
|
-
|
|
31
|
-
for (let i = 0; i < this.capacity; i++) {
|
|
32
|
-
const weight = (this.capacity - i) * this.capacity;
|
|
33
|
-
norm = norm + weight;
|
|
34
|
-
|
|
35
|
-
sum = sum + buffer.at(this.capacity - (i + 1)) * weight;
|
|
36
|
-
}
|
|
5
|
+
export function wma<T>(length: number, fn: (it: T) => number) {
|
|
6
|
+
return function (source: Observable<T>): Observable<[T, number]> {
|
|
7
|
+
return source.pipe(
|
|
8
|
+
window(length, fn),
|
|
9
|
+
filter(([, buffer]) => buffer.isFull),
|
|
10
|
+
map(([it, buffer]) => {
|
|
11
|
+
let norm = 0.0;
|
|
12
|
+
let sum = 0.0;
|
|
37
13
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
14
|
+
for (let i = 0; i < buffer.capacity; i++) {
|
|
15
|
+
const weight = (buffer.capacity - i) * buffer.capacity;
|
|
41
16
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
17
|
+
norm = norm + weight;
|
|
18
|
+
sum = sum + buffer.at(buffer.capacity - (i + 1)) * weight;
|
|
19
|
+
}
|
|
45
20
|
|
|
46
|
-
|
|
47
|
-
filter(it => {
|
|
48
|
-
indicator.append(fn(it));
|
|
21
|
+
const tuple: [T, number] = [it, sum / norm];
|
|
49
22
|
|
|
50
|
-
return
|
|
23
|
+
return tuple;
|
|
51
24
|
}),
|
|
52
|
-
map(_ => indicator),
|
|
53
25
|
share()
|
|
54
26
|
);
|
|
55
27
|
};
|