@quantform/core 0.4.8 → 0.5.13
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/adapter/adapter-aggregate.d.ts +4 -2
- package/dist/adapter/adapter-aggregate.js +4 -3
- package/dist/adapter/adapter-aggregate.js.map +1 -1
- package/dist/adapter/adapter.d.ts +3 -2
- package/dist/adapter/adapter.js +5 -2
- package/dist/adapter/adapter.js.map +1 -1
- package/dist/adapter/backtester/backtester-adapter.d.ts +1 -1
- package/dist/adapter/backtester/backtester-adapter.js +2 -1
- package/dist/adapter/backtester/backtester-adapter.js.map +1 -1
- package/dist/adapter/backtester/index.js +5 -1
- package/dist/adapter/backtester/index.js.map +1 -1
- package/dist/adapter/index.js +5 -1
- package/dist/adapter/index.js.map +1 -1
- package/dist/adapter/paper/index.js +5 -1
- package/dist/adapter/paper/index.js.map +1 -1
- package/dist/adapter/paper/paper-adapter.d.ts +1 -1
- package/dist/adapter/paper/paper-adapter.js +1 -1
- package/dist/adapter/paper/paper-adapter.js.map +1 -1
- package/dist/adapter/paper/paper-adapter.spec.js +5 -3
- package/dist/adapter/paper/paper-adapter.spec.js.map +1 -1
- package/dist/adapter/paper/simulator/paper-margin-simulator.d.ts +1 -1
- package/dist/adapter/paper/simulator/paper-margin-simulator.js.map +1 -1
- package/dist/adapter/paper/simulator/paper-simulator.d.ts +1 -1
- package/dist/adapter/paper/simulator/paper-simulator.js.map +1 -1
- package/dist/adapter/paper/simulator/paper-spot-simulator.d.ts +1 -1
- package/dist/adapter/paper/simulator/paper-spot-simulator.js +1 -1
- package/dist/adapter/paper/simulator/paper-spot-simulator.js.map +1 -1
- package/dist/bootstrap.js +31 -15
- package/dist/bootstrap.js.map +1 -1
- package/dist/cli/build.d.ts +1 -0
- package/dist/cli/build.js +16 -0
- package/dist/cli/build.js.map +1 -0
- package/dist/cli/dev.d.ts +1 -0
- package/dist/cli/dev.js +17 -0
- package/dist/cli/dev.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +72 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/internal/workspace.d.ts +8 -0
- package/dist/cli/internal/workspace.js +14 -0
- package/dist/cli/internal/workspace.js.map +1 -0
- package/dist/cli/pull.d.ts +1 -0
- package/dist/cli/pull.js +50 -0
- package/dist/cli/pull.js.map +1 -0
- package/dist/cli/run.d.ts +1 -0
- package/dist/cli/run.js +19 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/cli/test.d.ts +1 -0
- package/dist/cli/test.js +37 -0
- package/dist/cli/test.js.map +1 -0
- package/dist/domain/balance.d.ts +4 -3
- package/dist/domain/balance.js +20 -19
- package/dist/domain/balance.js.map +1 -1
- package/dist/domain/balance.spec.js +2 -2
- package/dist/domain/balance.spec.js.map +1 -1
- package/dist/domain/candle.d.ts +4 -2
- package/dist/domain/candle.js +13 -9
- package/dist/domain/candle.js.map +1 -1
- package/dist/domain/candle.spec.js.map +1 -1
- package/dist/domain/component.d.ts +1 -0
- package/dist/domain/index.js +5 -1
- package/dist/domain/index.js.map +1 -1
- package/dist/domain/instrument.d.ts +1 -0
- package/dist/domain/instrument.js +1 -0
- package/dist/domain/instrument.js.map +1 -1
- package/dist/domain/order.d.ts +3 -2
- package/dist/domain/order.js +2 -0
- package/dist/domain/order.js.map +1 -1
- package/dist/domain/orderbook.d.ts +1 -0
- package/dist/domain/orderbook.js +1 -0
- package/dist/domain/orderbook.js.map +1 -1
- package/dist/domain/position.d.ts +1 -0
- package/dist/domain/position.js +1 -0
- package/dist/domain/position.js.map +1 -1
- package/dist/domain/session.d.ts +4 -18
- package/dist/domain/session.js +10 -24
- package/dist/domain/session.js.map +1 -1
- package/dist/domain/statement.js +11 -11
- package/dist/domain/statement.js.map +1 -1
- package/dist/domain/trade.d.ts +2 -1
- package/dist/domain/trade.js +1 -0
- package/dist/domain/trade.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/indicator/atr.js.map +1 -1
- package/dist/indicator/cross.spec.js.map +1 -1
- package/dist/indicator/donchian.js.map +1 -1
- package/dist/indicator/ema.js.map +1 -1
- package/dist/indicator/ema.spec.js.map +1 -1
- package/dist/indicator/envelope.js.map +1 -1
- package/dist/indicator/index.js +5 -1
- package/dist/indicator/index.js.map +1 -1
- package/dist/indicator/macd.js.map +1 -1
- package/dist/indicator/min-max.js.map +1 -1
- package/dist/indicator/rma.js.map +1 -1
- package/dist/indicator/sma.js.map +1 -1
- package/dist/indicator/sma.spec.js.map +1 -1
- package/dist/indicator/swma.js.map +1 -1
- package/dist/indicator/tma.js.map +1 -1
- package/dist/indicator/tma.spec.js.map +1 -1
- package/dist/indicator/trailing.spec.js.map +1 -1
- package/dist/indicator/truerange.js.map +1 -1
- package/dist/indicator/truerange.spec.js.map +1 -1
- package/dist/indicator/window.js.map +1 -1
- package/dist/indicator/wma.js.map +1 -1
- package/dist/indicator/wma.spec.js.map +1 -1
- package/dist/shared/index.d.ts +0 -2
- package/dist/shared/index.js +5 -3
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/policy.spec.js +2 -6
- package/dist/shared/policy.spec.js.map +1 -1
- package/dist/storage/cache.d.ts +9 -0
- package/dist/storage/cache.js +32 -0
- package/dist/storage/cache.js.map +1 -0
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.js +6 -1
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/storage.d.ts +7 -0
- package/dist/storage/storage.js +11 -1
- package/dist/storage/storage.js.map +1 -1
- package/dist/store/event/index.js +5 -1
- package/dist/store/event/index.js.map +1 -1
- package/dist/store/event/store-balance.event.spec.js +3 -3
- package/dist/store/event/store-balance.event.spec.js.map +1 -1
- package/dist/store/event/store-candle.event.d.ts +1 -1
- package/dist/store/event/store-candle.event.js.map +1 -1
- package/dist/store/event/store-candle.event.spec.js +1 -1
- package/dist/store/event/store-candle.event.spec.js.map +1 -1
- package/dist/store/event/store-instrument.event.spec.js +1 -1
- package/dist/store/event/store-instrument.event.spec.js.map +1 -1
- package/dist/store/event/store-trade.event.spec.js +2 -2
- package/dist/store/event/store-trade.event.spec.js.map +1 -1
- package/dist/store/index.js +5 -1
- package/dist/store/index.js.map +1 -1
- package/dist/store/store.js.map +1 -1
- package/dist/tests/backtester-adapter.spec.js +2 -1
- package/dist/tests/backtester-adapter.spec.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +26 -24
- package/src/adapter/adapter-aggregate.ts +8 -3
- package/src/adapter/adapter.ts +9 -3
- package/src/adapter/backtester/backtester-adapter.ts +3 -1
- package/src/adapter/paper/paper-adapter.spec.ts +5 -3
- package/src/adapter/paper/paper-adapter.ts +1 -1
- package/src/adapter/paper/simulator/paper-margin-simulator.ts +1 -1
- package/src/adapter/paper/simulator/paper-simulator.ts +2 -1
- package/src/adapter/paper/simulator/paper-spot-simulator.ts +2 -2
- package/src/bootstrap.ts +47 -18
- package/src/cli/build.ts +15 -0
- package/src/cli/dev.ts +18 -0
- package/src/cli/index.ts +81 -0
- package/src/cli/internal/workspace.ts +18 -0
- package/src/cli/pull.ts +67 -0
- package/src/cli/run.ts +22 -0
- package/src/cli/test.ts +50 -0
- package/src/domain/balance.spec.ts +2 -2
- package/src/domain/balance.ts +20 -19
- package/src/domain/candle.spec.ts +1 -0
- package/src/domain/candle.ts +20 -10
- package/src/domain/component.ts +1 -0
- package/src/domain/instrument.ts +1 -0
- package/src/domain/order.ts +3 -1
- package/src/domain/orderbook.ts +1 -0
- package/src/domain/position.ts +2 -0
- package/src/domain/session.ts +25 -72
- package/src/domain/statement.ts +13 -12
- package/src/domain/trade.ts +2 -1
- package/src/index.ts +0 -1
- package/src/indicator/atr.ts +1 -0
- package/src/indicator/cross.spec.ts +1 -0
- package/src/indicator/donchian.ts +1 -0
- package/src/indicator/ema.spec.ts +1 -0
- package/src/indicator/ema.ts +1 -0
- package/src/indicator/envelope.ts +1 -0
- package/src/indicator/macd.ts +1 -0
- package/src/indicator/min-max.ts +1 -0
- package/src/indicator/rma.ts +1 -0
- package/src/indicator/sma.spec.ts +1 -0
- package/src/indicator/sma.ts +1 -0
- package/src/indicator/swma.ts +1 -0
- package/src/indicator/tma.spec.ts +1 -0
- package/src/indicator/tma.ts +1 -0
- package/src/indicator/trailing.spec.ts +1 -0
- package/src/indicator/truerange.spec.ts +1 -0
- package/src/indicator/truerange.ts +1 -0
- package/src/indicator/window.ts +1 -0
- package/src/indicator/wma.spec.ts +1 -0
- package/src/indicator/wma.ts +1 -0
- package/src/shared/index.ts +0 -2
- package/src/shared/policy.spec.ts +2 -6
- package/src/storage/cache.ts +35 -0
- package/src/storage/index.ts +1 -0
- package/src/storage/storage.ts +15 -0
- package/src/store/event/store-balance.event.spec.ts +3 -3
- package/src/store/event/store-candle.event.spec.ts +1 -1
- package/src/store/event/store-candle.event.ts +2 -2
- package/src/store/event/store-instrument.event.spec.ts +1 -1
- package/src/store/event/store-trade.event.spec.ts +2 -2
- package/src/store/store.ts +1 -0
- package/src/tests/backtester-adapter.spec.ts +3 -2
- package/tsconfig.json +2 -2
- package/dist/ipc.d.ts +0 -33
- package/dist/ipc.js +0 -244
- package/dist/ipc.js.map +0 -1
- package/dist/ipc.spec.d.ts +0 -1
- package/dist/ipc.spec.js +0 -57
- package/dist/ipc.spec.js.map +0 -1
- package/dist/shared/task.d.ts +0 -6
- package/dist/shared/task.js +0 -25
- package/dist/shared/task.js.map +0 -1
- package/dist/shared/worker.d.ts +0 -10
- package/dist/shared/worker.js +0 -46
- package/dist/shared/worker.js.map +0 -1
- package/dist/shared/worker.spec.d.ts +0 -1
- package/dist/shared/worker.spec.js +0 -18
- package/dist/shared/worker.spec.js.map +0 -1
- package/jestconfig.json +0 -11
- package/src/ipc.spec.ts +0 -73
- package/src/ipc.ts +0 -321
- package/src/shared/task.ts +0 -30
- package/src/shared/worker.spec.ts +0 -25
- package/src/shared/worker.ts +0 -55
package/src/domain/candle.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
skipLast,
|
|
10
10
|
withLatestFrom
|
|
11
11
|
} from 'rxjs';
|
|
12
|
+
|
|
12
13
|
import { timestamp } from '../shared';
|
|
13
14
|
import { tf } from './timeframe';
|
|
14
15
|
|
|
@@ -29,10 +30,10 @@ export class Candle {
|
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
export class CandleBuilder {
|
|
32
|
-
private
|
|
33
|
+
private current: Candle;
|
|
33
34
|
|
|
34
35
|
get candle(): Candle {
|
|
35
|
-
return this.
|
|
36
|
+
return this.current;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
constructor(readonly timeframe: number) {}
|
|
@@ -40,8 +41,8 @@ export class CandleBuilder {
|
|
|
40
41
|
append(value: number, timestamp: timestamp): Candle {
|
|
41
42
|
const frame = tf(timestamp, this.timeframe);
|
|
42
43
|
|
|
43
|
-
if (!this.
|
|
44
|
-
this.
|
|
44
|
+
if (!this.current) {
|
|
45
|
+
this.current = new Candle(frame, value, value, value, value);
|
|
45
46
|
|
|
46
47
|
return null;
|
|
47
48
|
}
|
|
@@ -52,25 +53,34 @@ export class CandleBuilder {
|
|
|
52
53
|
return null;
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
const previous = this.
|
|
56
|
+
const previous = this.current;
|
|
56
57
|
|
|
57
|
-
this.
|
|
58
|
+
this.current = new Candle(frame, value, value, value, value);
|
|
58
59
|
return previous;
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
export function candle<T extends { timestamp: number }>(
|
|
63
64
|
timeframe: number,
|
|
64
|
-
fn: (x: T) => number
|
|
65
|
+
fn: (x: T) => number,
|
|
66
|
+
options: { passThru: boolean } = { passThru: false }
|
|
65
67
|
) {
|
|
66
68
|
return function (source: Observable<T>): Observable<Candle> {
|
|
67
69
|
const builder = new CandleBuilder(timeframe);
|
|
68
70
|
let candle: Candle;
|
|
69
71
|
|
|
72
|
+
if (options.passThru) {
|
|
73
|
+
return source.pipe(
|
|
74
|
+
map(it => {
|
|
75
|
+
builder.append(fn(it), it.timestamp);
|
|
76
|
+
return builder.candle;
|
|
77
|
+
}),
|
|
78
|
+
share()
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
70
82
|
return source.pipe(
|
|
71
|
-
filter(it =>
|
|
72
|
-
return (candle = builder.append(fn(it), it.timestamp)) != null;
|
|
73
|
-
}),
|
|
83
|
+
filter(it => (candle = builder.append(fn(it), it.timestamp)) != null),
|
|
74
84
|
map(_ => candle),
|
|
75
85
|
share()
|
|
76
86
|
);
|
package/src/domain/component.ts
CHANGED
package/src/domain/instrument.ts
CHANGED
|
@@ -25,6 +25,7 @@ export class InstrumentSelector {
|
|
|
25
25
|
* Represents trading market which is made up by two trading assets (base and quoted).
|
|
26
26
|
*/
|
|
27
27
|
export class Instrument extends InstrumentSelector implements Component {
|
|
28
|
+
kind = 'instrument';
|
|
28
29
|
timestamp: timestamp;
|
|
29
30
|
commission: Commission;
|
|
30
31
|
cross: Instrument;
|
package/src/domain/order.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { v4 } from 'uuid';
|
|
2
|
+
|
|
2
3
|
import { timestamp } from '../shared';
|
|
3
4
|
import { Component } from './component';
|
|
4
5
|
import { InstrumentSelector } from './instrument';
|
|
@@ -14,12 +15,13 @@ export type OrderState =
|
|
|
14
15
|
| 'REJECTED';
|
|
15
16
|
|
|
16
17
|
export class Order implements Component {
|
|
18
|
+
kind = 'order';
|
|
17
19
|
timestamp: timestamp;
|
|
18
20
|
id = v4();
|
|
19
21
|
externalId: string;
|
|
20
22
|
state: OrderState = 'NEW';
|
|
21
23
|
|
|
22
|
-
quantityExecuted
|
|
24
|
+
quantityExecuted = 0;
|
|
23
25
|
averageExecutionRate: number;
|
|
24
26
|
createdAt: timestamp;
|
|
25
27
|
comment: string;
|
package/src/domain/orderbook.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { Component } from './component';
|
|
|
6
6
|
* Provides an access to pending buy and sell orders on the specific market.
|
|
7
7
|
*/
|
|
8
8
|
export class Orderbook implements Component {
|
|
9
|
+
kind = 'orderbook';
|
|
9
10
|
timestamp: timestamp;
|
|
10
11
|
bestAskRate: number;
|
|
11
12
|
bestAskQuantity: number;
|
package/src/domain/position.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { map, Observable, share } from 'rxjs';
|
|
2
|
+
|
|
2
3
|
import { Instrument } from '../domain';
|
|
3
4
|
import { pnl, timestamp, weightedMean } from '../shared';
|
|
4
5
|
import { Component } from './component';
|
|
@@ -6,6 +7,7 @@ import { Component } from './component';
|
|
|
6
7
|
export type PositionMode = 'CROSS' | 'ISOLATED';
|
|
7
8
|
|
|
8
9
|
export class Position implements Component {
|
|
10
|
+
kind = 'position';
|
|
9
11
|
timestamp: timestamp;
|
|
10
12
|
averageExecutionRate: number;
|
|
11
13
|
size: number;
|
package/src/domain/session.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
concat,
|
|
3
2
|
defer,
|
|
4
3
|
distinctUntilChanged,
|
|
5
4
|
filter,
|
|
5
|
+
finalize,
|
|
6
6
|
from,
|
|
7
7
|
map,
|
|
8
|
+
merge,
|
|
8
9
|
mergeMap,
|
|
9
10
|
Observable,
|
|
10
|
-
share,
|
|
11
11
|
shareReplay,
|
|
12
12
|
startWith,
|
|
13
13
|
Subject,
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
switchMap,
|
|
16
16
|
take
|
|
17
17
|
} from 'rxjs';
|
|
18
|
+
|
|
18
19
|
import { Adapter, BacktesterOptions, PaperOptions } from '../adapter';
|
|
19
20
|
import { AdapterAggregate } from '../adapter/adapter-aggregate';
|
|
20
21
|
import {
|
|
@@ -26,15 +27,13 @@ import {
|
|
|
26
27
|
Order,
|
|
27
28
|
Orderbook,
|
|
28
29
|
OrderState,
|
|
29
|
-
Position
|
|
30
|
+
Position,
|
|
31
|
+
Trade
|
|
30
32
|
} from '../domain';
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import { Feed, Measurement } from '../storage';
|
|
33
|
+
import { now } from '../shared';
|
|
34
|
+
import { StorageFactory } from '../storage';
|
|
34
35
|
import { Store } from '../store';
|
|
35
36
|
|
|
36
|
-
type Optional<T, K extends keyof T> = Omit<T, K> & Partial<T>;
|
|
37
|
-
|
|
38
37
|
/**
|
|
39
38
|
* Describes a single session.
|
|
40
39
|
* You can use @run function to start a new session managed by CLI.
|
|
@@ -64,29 +63,20 @@ export interface SessionDescriptor {
|
|
|
64
63
|
|
|
65
64
|
/**
|
|
66
65
|
* Provides historical data for backtest, it's not required for live and paper
|
|
67
|
-
* sessions.
|
|
68
|
-
*/
|
|
69
|
-
feed?: Feed;
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Stores session variables i.e. indicators, orders, or any other type of time
|
|
66
|
+
* sessions. Stores session variables i.e. indicators, orders, or any other type of time
|
|
73
67
|
* series data. You can install @quantform/editor to render this data in your browser.
|
|
74
68
|
*/
|
|
75
|
-
|
|
69
|
+
storage?: StorageFactory;
|
|
76
70
|
|
|
77
71
|
/**
|
|
78
72
|
* Session additional options.
|
|
79
73
|
*/
|
|
80
|
-
|
|
81
|
-
backtester?: BacktesterOptions;
|
|
82
|
-
paper?: PaperOptions;
|
|
83
|
-
};
|
|
74
|
+
simulation?: PaperOptions & BacktesterOptions;
|
|
84
75
|
}
|
|
85
76
|
|
|
86
77
|
export class Session {
|
|
87
78
|
private initialized = false;
|
|
88
79
|
private subscription: Subscription;
|
|
89
|
-
private worker = new Worker();
|
|
90
80
|
|
|
91
81
|
get timestamp(): number {
|
|
92
82
|
return this.store.snapshot.timestamp;
|
|
@@ -116,7 +106,9 @@ export class Session {
|
|
|
116
106
|
await this.aggregate.awake();
|
|
117
107
|
|
|
118
108
|
if (describe) {
|
|
119
|
-
this.subscription = describe(this)
|
|
109
|
+
this.subscription = describe(this)
|
|
110
|
+
.pipe(finalize(() => this.dispose()))
|
|
111
|
+
.subscribe();
|
|
120
112
|
}
|
|
121
113
|
}
|
|
122
114
|
|
|
@@ -125,63 +117,22 @@ export class Session {
|
|
|
125
117
|
return;
|
|
126
118
|
}
|
|
127
119
|
|
|
128
|
-
this.store.dispose();
|
|
129
|
-
|
|
130
120
|
if (this.subscription) {
|
|
131
121
|
this.subscription.unsubscribe();
|
|
122
|
+
this.subscription = undefined;
|
|
132
123
|
}
|
|
133
124
|
|
|
125
|
+
this.store.dispose();
|
|
126
|
+
|
|
134
127
|
await this.aggregate.dispose();
|
|
135
|
-
|
|
128
|
+
|
|
129
|
+
this.initialized = false;
|
|
136
130
|
}
|
|
137
131
|
|
|
138
132
|
useStatement(section: string): Record<string, any> {
|
|
139
133
|
return this.statement[section] ?? (this.statement[section] = {});
|
|
140
134
|
}
|
|
141
135
|
|
|
142
|
-
/**
|
|
143
|
-
* Returns last stored measurement and setter for it in session.
|
|
144
|
-
* For example you can save and restore variables in same session between runs.
|
|
145
|
-
* Example usage:
|
|
146
|
-
* const [order$, setOrder] = session.measurement<Order>('order');
|
|
147
|
-
*
|
|
148
|
-
* order.pipe(tap(it => console.log(`your last order was: ${it}`)));
|
|
149
|
-
*
|
|
150
|
-
* setOrder(order);
|
|
151
|
-
*/
|
|
152
|
-
useMeasure<T extends { timestamp: number }>(
|
|
153
|
-
params: { kind: string; timestamp?: number },
|
|
154
|
-
defaultValue: T = undefined
|
|
155
|
-
): [Observable<T>, (value: Optional<T, 'timestamp'>) => void] {
|
|
156
|
-
const stored$ = from(
|
|
157
|
-
this.descriptor.measurement.query(this.descriptor.id, {
|
|
158
|
-
to: params.timestamp ?? this.timestamp,
|
|
159
|
-
kind: params.kind,
|
|
160
|
-
count: 1
|
|
161
|
-
})
|
|
162
|
-
).pipe(
|
|
163
|
-
map(it =>
|
|
164
|
-
it.length ? { timestamp: it[0].timestamp, ...it[0].payload } : defaultValue
|
|
165
|
-
),
|
|
166
|
-
share()
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
const subject$ = new Subject<T>();
|
|
170
|
-
|
|
171
|
-
const setter = (value: T) => {
|
|
172
|
-
const timestamp = value.timestamp ?? this.timestamp;
|
|
173
|
-
const measure = { timestamp, kind: params.kind, payload: value };
|
|
174
|
-
|
|
175
|
-
this.worker.enqueue(() =>
|
|
176
|
-
this.descriptor.measurement.save(this.descriptor.id, [measure])
|
|
177
|
-
);
|
|
178
|
-
|
|
179
|
-
subject$.next({ ...value, timestamp });
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
return [concat(stored$, subject$.asObservable()), setter];
|
|
183
|
-
}
|
|
184
|
-
|
|
185
136
|
/**
|
|
186
137
|
* Return values for patch provided in optimization file.
|
|
187
138
|
* Example usage:
|
|
@@ -205,11 +156,13 @@ export class Session {
|
|
|
205
156
|
* session.open(Order.buyMarket(instrument, 100));
|
|
206
157
|
*/
|
|
207
158
|
open(order: Order): Observable<Order> {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
159
|
+
const subject = new Subject<Order>();
|
|
160
|
+
|
|
161
|
+
this.aggregate.open(order).catch(subject.error);
|
|
162
|
+
|
|
163
|
+
return merge(
|
|
164
|
+
subject.asObservable(),
|
|
165
|
+
this.order(order.instrument).pipe(filter(it => it.id == order.id))
|
|
213
166
|
);
|
|
214
167
|
}
|
|
215
168
|
|
package/src/domain/statement.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { combineLatest, finalize, map, take, tap } from 'rxjs';
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
import { drawdown } from '../indicator';
|
|
4
4
|
import { floor, precision } from '../shared';
|
|
5
|
+
import { InstrumentSelector, Session } from '.';
|
|
5
6
|
|
|
6
7
|
export function period() {
|
|
7
8
|
return (session: Session) => {
|
|
@@ -46,11 +47,11 @@ export function benchmark(instrument: InstrumentSelector) {
|
|
|
46
47
|
finalize(() => {
|
|
47
48
|
const pnl = exit / entry - 1;
|
|
48
49
|
|
|
49
|
-
statement
|
|
50
|
-
statement
|
|
51
|
-
statement
|
|
52
|
-
statement
|
|
53
|
-
statement
|
|
50
|
+
statement.benchmark_entry = entry;
|
|
51
|
+
statement.benchmark_exit = exit;
|
|
52
|
+
statement.benchmark_pnl = floor(balance * pnl, precision(entry));
|
|
53
|
+
statement.benchmark_pnl_pp = floor(pnl * 100, 2);
|
|
54
|
+
statement.benchmark_drawdown_pp = floor(dd * 100, 2);
|
|
54
55
|
})
|
|
55
56
|
);
|
|
56
57
|
};
|
|
@@ -106,12 +107,12 @@ export function equity(instrument: InstrumentSelector) {
|
|
|
106
107
|
const pnl = equity / balance - 1;
|
|
107
108
|
const scale = precision(equity);
|
|
108
109
|
|
|
109
|
-
statement
|
|
110
|
-
statement
|
|
111
|
-
statement
|
|
112
|
-
statement
|
|
113
|
-
statement
|
|
114
|
-
statement
|
|
110
|
+
statement.equity = equity;
|
|
111
|
+
statement.equity_min = min;
|
|
112
|
+
statement.equity_max = max;
|
|
113
|
+
statement.equity_pnl = floor(balance * pnl, scale);
|
|
114
|
+
statement.equity_pnl_pp = floor(pnl * 100, 2);
|
|
115
|
+
statement.equity_drawdown_pp = floor(dd * 100, 2);
|
|
115
116
|
})
|
|
116
117
|
);
|
|
117
118
|
};
|
package/src/domain/trade.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Instrument } from '.';
|
|
2
1
|
import { timestamp } from '../shared';
|
|
2
|
+
import { Instrument } from '.';
|
|
3
3
|
import { Component } from './component';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -7,6 +7,7 @@ import { Component } from './component';
|
|
|
7
7
|
* and seller of the same asset.
|
|
8
8
|
*/
|
|
9
9
|
export class Trade implements Component {
|
|
10
|
+
kind = 'trade';
|
|
10
11
|
timestamp: timestamp;
|
|
11
12
|
rate: number;
|
|
12
13
|
quantity: number;
|
package/src/index.ts
CHANGED
package/src/indicator/atr.ts
CHANGED
package/src/indicator/ema.ts
CHANGED
package/src/indicator/macd.ts
CHANGED
package/src/indicator/min-max.ts
CHANGED
package/src/indicator/rma.ts
CHANGED
package/src/indicator/sma.ts
CHANGED
package/src/indicator/swma.ts
CHANGED
package/src/indicator/tma.ts
CHANGED
package/src/indicator/window.ts
CHANGED
package/src/indicator/wma.ts
CHANGED
package/src/shared/index.ts
CHANGED
|
@@ -4,9 +4,7 @@ describe('cache policy tests', () => {
|
|
|
4
4
|
test('string as key cache', async () => {
|
|
5
5
|
let counter = 0;
|
|
6
6
|
|
|
7
|
-
const request = async () =>
|
|
8
|
-
return ++counter;
|
|
9
|
-
};
|
|
7
|
+
const request = async () => ++counter;
|
|
10
8
|
|
|
11
9
|
expect(await cache('abc', request)).toBe(1);
|
|
12
10
|
expect(await cache('abc', request)).toBe(1);
|
|
@@ -17,9 +15,7 @@ describe('cache policy tests', () => {
|
|
|
17
15
|
test('object as key cache', async () => {
|
|
18
16
|
let counter = 0;
|
|
19
17
|
|
|
20
|
-
const request = async () =>
|
|
21
|
-
return ++counter;
|
|
22
|
-
};
|
|
18
|
+
const request = async () => ++counter;
|
|
23
19
|
|
|
24
20
|
expect(await cache({ from: 1, to: 2, content: 'abc' }, request)).toBe(1);
|
|
25
21
|
expect(await cache({ from: 1, to: 2, content: 'abc' }, request)).toBe(1);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { now } from '../shared';
|
|
2
|
+
import { Storage } from './storage';
|
|
3
|
+
|
|
4
|
+
export class Cache {
|
|
5
|
+
constructor(private readonly storage: Storage) {}
|
|
6
|
+
|
|
7
|
+
async tryGet<T>(
|
|
8
|
+
getter: () => Promise<T>,
|
|
9
|
+
options: { key: string; ttl?: number }
|
|
10
|
+
): Promise<T> {
|
|
11
|
+
const time = now();
|
|
12
|
+
|
|
13
|
+
const payload = await this.storage.query(options.key, {
|
|
14
|
+
kind: 'cache',
|
|
15
|
+
count: 1,
|
|
16
|
+
to: time
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
if ((!payload.length || payload[0].timestamp < time - options.ttl) ?? 60 * 60 * 24) {
|
|
20
|
+
const value = await getter();
|
|
21
|
+
|
|
22
|
+
await this.storage.save(options.key, [
|
|
23
|
+
{
|
|
24
|
+
timestamp: time,
|
|
25
|
+
kind: 'cache',
|
|
26
|
+
json: JSON.stringify(value)
|
|
27
|
+
}
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return JSON.parse(payload[0].json);
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/storage/index.ts
CHANGED
package/src/storage/storage.ts
CHANGED
|
@@ -35,6 +35,13 @@ export interface Storage {
|
|
|
35
35
|
query(library: string, options: StorageQueryOptions): Promise<StorageDocument[]>;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
*
|
|
40
|
+
*/
|
|
41
|
+
export interface StorageFactory {
|
|
42
|
+
create(type: string): Storage;
|
|
43
|
+
}
|
|
44
|
+
|
|
38
45
|
/**
|
|
39
46
|
*
|
|
40
47
|
*/
|
|
@@ -111,3 +118,11 @@ export class InMemoryStorage implements Storage {
|
|
|
111
118
|
this.tables = {};
|
|
112
119
|
}
|
|
113
120
|
}
|
|
121
|
+
|
|
122
|
+
export class InMemoryStorageFactory implements StorageFactory {
|
|
123
|
+
private readonly storage: Record<string, Storage> = {};
|
|
124
|
+
|
|
125
|
+
create(type: string): Storage {
|
|
126
|
+
return this.storage[type] ?? (this.storage[type] = new InMemoryStorage());
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { BalancePatchEvent } from '.';
|
|
2
|
-
import { Store } from '..';
|
|
3
1
|
import { Asset, Commission } from '../../domain';
|
|
4
2
|
import { now } from '../../shared';
|
|
3
|
+
import { Store } from '..';
|
|
4
|
+
import { BalancePatchEvent } from '.';
|
|
5
5
|
import { InstrumentPatchEvent } from './store-instrument.event';
|
|
6
6
|
|
|
7
7
|
describe('balance event tests', () => {
|
|
@@ -23,7 +23,7 @@ describe('balance event tests', () => {
|
|
|
23
23
|
|
|
24
24
|
expect(balance).toEqual(component);
|
|
25
25
|
expect(balance.free).toEqual(100);
|
|
26
|
-
expect(balance.
|
|
26
|
+
expect(balance.locked).toEqual(0);
|
|
27
27
|
expect(balance.timestamp).toEqual(timestamp);
|
|
28
28
|
expect(store.snapshot.timestamp).toEqual(timestamp);
|
|
29
29
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { CandleEvent } from '.';
|
|
2
1
|
import { Asset, Instrument } from '../../domain';
|
|
3
2
|
import { now } from '../../shared';
|
|
4
3
|
import { Store } from '../store';
|
|
4
|
+
import { CandleEvent } from '.';
|
|
5
5
|
|
|
6
6
|
const instrument = new Instrument(
|
|
7
7
|
new Asset('btc', 'binance', 8),
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { StateChangeTracker } from '..';
|
|
2
1
|
import { InstrumentSelector } from '../../domain';
|
|
3
2
|
import { timestamp } from '../../shared/datetime';
|
|
4
3
|
import { event } from '../../shared/topic';
|
|
4
|
+
import { StateChangeTracker } from '..';
|
|
5
5
|
import { State } from '../store.state';
|
|
6
|
+
import { StoreEvent } from './store.event';
|
|
6
7
|
import { OrderbookPatchEventHandler } from './store-orderbook.event';
|
|
7
8
|
import { TradePatchEventHandler } from './store-trade.event';
|
|
8
|
-
import { StoreEvent } from './store.event';
|
|
9
9
|
|
|
10
10
|
@event
|
|
11
11
|
export class CandleEvent implements StoreEvent {
|