@quantform/core 0.3.264 → 0.3.272
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 +2 -2
- package/dist/adapter/adapter-aggregate.js.map +1 -1
- package/dist/adapter/adapter.d.ts +5 -6
- package/dist/adapter/adapter.js.map +1 -1
- package/dist/adapter/backtester/backtester-adapter.d.ts +6 -6
- package/dist/adapter/backtester/backtester-adapter.js +5 -9
- package/dist/adapter/backtester/backtester-adapter.js.map +1 -1
- package/dist/adapter/backtester/backtester-cursor.d.ts +2 -2
- package/dist/adapter/backtester/backtester-cursor.spec.js +9 -9
- package/dist/adapter/backtester/backtester-cursor.spec.js.map +1 -1
- package/dist/adapter/backtester/backtester-streamer.d.ts +6 -4
- package/dist/adapter/backtester/backtester-streamer.js +5 -5
- package/dist/adapter/backtester/backtester-streamer.js.map +1 -1
- package/dist/adapter/backtester/backtester-streamer.spec.js +9 -11
- package/dist/adapter/backtester/backtester-streamer.spec.js.map +1 -1
- package/dist/adapter/index.d.ts +2 -0
- package/dist/adapter/index.js +2 -0
- package/dist/adapter/index.js.map +1 -1
- package/dist/adapter/paper/index.d.ts +2 -2
- package/dist/adapter/paper/index.js +2 -2
- package/dist/adapter/paper/index.js.map +1 -1
- package/dist/adapter/paper/paper-adapter.d.ts +5 -5
- package/dist/adapter/paper/paper-adapter.js +9 -12
- package/dist/adapter/paper/paper-adapter.js.map +1 -1
- package/dist/adapter/paper/paper-adapter.spec.js +5 -7
- package/dist/adapter/paper/paper-adapter.spec.js.map +1 -1
- package/dist/adapter/paper/{executor/paper-margin-executor.d.ts → simulator/paper-margin-simulator.d.ts} +3 -3
- package/dist/adapter/paper/{executor/paper-margin-executor.js → simulator/paper-margin-simulator.js} +11 -11
- package/dist/adapter/paper/simulator/paper-margin-simulator.js.map +1 -0
- package/dist/adapter/paper/{executor/paper-executor.d.ts → simulator/paper-simulator.d.ts} +2 -2
- package/dist/adapter/paper/{executor/paper-executor.js → simulator/paper-simulator.js} +7 -7
- package/dist/adapter/paper/simulator/paper-simulator.js.map +1 -0
- package/dist/adapter/paper/{executor/paper-spot-executor.d.ts → simulator/paper-spot-simulator.d.ts} +3 -3
- package/dist/adapter/paper/{executor/paper-spot-executor.js → simulator/paper-spot-simulator.js} +17 -17
- package/dist/adapter/paper/simulator/paper-spot-simulator.js.map +1 -0
- package/dist/adapter/paper/simulator/paper-spot-simulator.spec.d.ts +1 -0
- package/dist/adapter/paper/simulator/paper-spot-simulator.spec.js +49 -0
- package/dist/adapter/paper/simulator/paper-spot-simulator.spec.js.map +1 -0
- package/dist/bootstrap.d.ts +1 -1
- package/dist/bootstrap.js +3 -5
- package/dist/bootstrap.js.map +1 -1
- package/dist/domain/balance.d.ts +1 -1
- package/dist/domain/candle.d.ts +14 -0
- package/dist/domain/candle.js +65 -1
- package/dist/domain/candle.js.map +1 -1
- package/dist/domain/candle.spec.js +11 -13
- package/dist/domain/candle.spec.js.map +1 -1
- package/dist/domain/index.d.ts +6 -8
- package/dist/domain/index.js +6 -8
- package/dist/domain/index.js.map +1 -1
- package/dist/domain/order.d.ts +1 -1
- package/dist/domain/order.js.map +1 -1
- package/dist/domain/orderbook.d.ts +1 -1
- package/dist/domain/position.d.ts +2 -2
- package/dist/domain/position.js +3 -3
- package/dist/domain/position.js.map +1 -1
- package/dist/domain/session.d.ts +14 -3
- package/dist/domain/session.js +17 -18
- package/dist/domain/session.js.map +1 -1
- package/dist/domain/session.spec.js +3 -3
- package/dist/domain/session.spec.js.map +1 -1
- package/dist/domain/statement.d.ts +1 -2
- package/dist/domain/statement.js.map +1 -1
- package/dist/domain/trade.d.ts +1 -1
- package/dist/index.d.ts +4 -7
- package/dist/index.js +4 -7
- package/dist/index.js.map +1 -1
- package/dist/indicator/atr.js +3 -3
- package/dist/indicator/atr.js.map +1 -1
- package/dist/indicator/cross.js +3 -3
- package/dist/indicator/cross.js.map +1 -1
- package/dist/indicator/donchian.js +3 -4
- package/dist/indicator/donchian.js.map +1 -1
- package/dist/indicator/drawdown.js +3 -3
- package/dist/indicator/drawdown.js.map +1 -1
- package/dist/indicator/ema.js +3 -3
- package/dist/indicator/ema.js.map +1 -1
- package/dist/indicator/envelope.js +3 -3
- package/dist/indicator/envelope.js.map +1 -1
- package/dist/indicator/index.d.ts +3 -3
- package/dist/indicator/index.js +3 -3
- package/dist/indicator/index.js.map +1 -1
- package/dist/indicator/macd.js +2 -3
- package/dist/indicator/macd.js.map +1 -1
- package/dist/indicator/min-max.js +3 -3
- package/dist/indicator/min-max.js.map +1 -1
- package/dist/indicator/rma.js +3 -3
- package/dist/indicator/rma.js.map +1 -1
- package/dist/indicator/sma.js +2 -3
- package/dist/indicator/sma.js.map +1 -1
- package/dist/indicator/swma.js +3 -3
- package/dist/indicator/swma.js.map +1 -1
- package/dist/indicator/tma.js +3 -3
- package/dist/indicator/tma.js.map +1 -1
- package/dist/indicator/trailing.js +3 -3
- package/dist/indicator/trailing.js.map +1 -1
- package/dist/indicator/truerange.js +3 -3
- 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/wma.js +3 -3
- package/dist/indicator/wma.js.map +1 -1
- package/dist/ipc.d.ts +1 -1
- package/dist/ipc.js +3 -3
- package/dist/ipc.js.map +1 -1
- package/dist/ipc.spec.js +4 -5
- package/dist/ipc.spec.js.map +1 -1
- package/dist/shared/index.d.ts +4 -4
- package/dist/shared/index.js +4 -4
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/policy.js +1 -1
- package/dist/shared/policy.js.map +1 -1
- package/dist/storage/feed.d.ts +1 -1
- package/dist/storage/feed.js.map +1 -1
- package/dist/storage/index.d.ts +1 -1
- package/dist/storage/index.js +1 -1
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/measurement.js.map +1 -1
- package/dist/storage/storage.js.map +1 -1
- package/dist/store/event/index.d.ts +4 -4
- package/dist/store/event/index.js +4 -4
- package/dist/store/event/index.js.map +1 -1
- package/dist/store/event/store-balance.event.d.ts +1 -1
- package/dist/store/event/store-balance.event.js +1 -1
- package/dist/store/event/store-balance.event.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 +2 -2
- package/dist/store/event/store-candle.event.js +2 -2
- 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.d.ts +1 -1
- package/dist/store/event/store-instrument.event.js +1 -1
- package/dist/store/event/store-instrument.event.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-order.event.d.ts +1 -1
- package/dist/store/event/store-order.event.js +6 -6
- package/dist/store/event/store-order.event.js.map +1 -1
- package/dist/store/event/store-order.event.spec.js +2 -2
- package/dist/store/event/store-order.event.spec.js.map +1 -1
- package/dist/store/event/store-orderbook.event.d.ts +1 -1
- package/dist/store/event/store-orderbook.event.js +1 -1
- package/dist/store/event/store-orderbook.event.js.map +1 -1
- package/dist/store/event/store-position.event.d.ts +1 -1
- package/dist/store/event/store-position.event.js +1 -1
- package/dist/store/event/store-position.event.js.map +1 -1
- package/dist/store/event/store-trade.event.d.ts +1 -1
- package/dist/store/event/store-trade.event.js +1 -1
- package/dist/store/event/store-trade.event.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.d.ts +1 -0
- package/dist/store/index.js +1 -0
- package/dist/store/index.js.map +1 -1
- package/dist/store/store.d.ts +2 -5
- package/dist/store/store.js +4 -8
- package/dist/store/store.js.map +1 -1
- package/dist/store/store.state.d.ts +1 -1
- package/dist/tests/backtester-adapter.spec.js +8 -15
- package/dist/tests/backtester-adapter.spec.js.map +1 -1
- package/dist/tests/session.spec.d.ts +0 -1
- package/dist/tests/session.spec.js +0 -2
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/adapter/adapter-aggregate.ts +2 -3
- package/src/adapter/adapter.ts +5 -6
- package/src/adapter/backtester/backtester-adapter.ts +8 -8
- package/src/adapter/backtester/backtester-cursor.spec.ts +1 -1
- package/src/adapter/backtester/backtester-cursor.ts +2 -2
- package/src/adapter/backtester/backtester-streamer.spec.ts +1 -3
- package/src/adapter/backtester/backtester-streamer.ts +7 -8
- package/src/adapter/index.ts +2 -0
- package/src/adapter/paper/index.ts +2 -2
- package/src/adapter/paper/paper-adapter.spec.ts +6 -8
- package/src/adapter/paper/paper-adapter.ts +9 -11
- package/src/adapter/paper/{executor/paper-margin-executor.ts → simulator/paper-margin-simulator.ts} +5 -5
- package/src/adapter/paper/{executor/paper-executor.ts → simulator/paper-simulator.ts} +4 -4
- package/src/adapter/paper/simulator/paper-spot-simulator.spec.ts +87 -0
- package/src/adapter/paper/{executor/paper-spot-executor.ts → simulator/paper-spot-simulator.ts} +6 -6
- package/src/bootstrap.ts +4 -4
- package/src/domain/balance.ts +1 -1
- package/src/domain/candle.spec.ts +3 -5
- package/src/domain/candle.ts +103 -0
- package/src/domain/index.ts +6 -8
- package/src/domain/order.ts +2 -2
- package/src/domain/orderbook.ts +1 -1
- package/src/domain/position.ts +2 -3
- package/src/domain/session.spec.ts +3 -3
- package/src/domain/session.ts +61 -8
- package/src/domain/statement.ts +1 -2
- package/src/domain/trade.ts +1 -1
- package/src/index.ts +4 -7
- package/src/indicator/atr.ts +1 -2
- package/src/indicator/cross.ts +3 -4
- package/src/indicator/donchian.ts +2 -3
- package/src/indicator/drawdown.ts +2 -3
- package/src/indicator/ema.ts +1 -2
- package/src/indicator/envelope.ts +1 -2
- package/src/indicator/index.ts +3 -3
- package/src/indicator/macd.ts +1 -2
- package/src/indicator/min-max.ts +1 -2
- package/src/indicator/rma.ts +1 -2
- package/src/indicator/sma.ts +1 -2
- package/src/indicator/swma.ts +1 -2
- package/src/indicator/tma.ts +1 -2
- package/src/indicator/trailing.ts +3 -4
- package/src/indicator/truerange.spec.ts +2 -2
- package/src/indicator/truerange.ts +1 -2
- package/src/indicator/window.ts +1 -1
- package/src/indicator/wma.ts +1 -2
- package/src/ipc.spec.ts +6 -7
- package/src/ipc.ts +6 -6
- package/src/shared/index.ts +4 -4
- package/src/shared/policy.ts +1 -1
- package/src/shared/topic.spec.ts +1 -1
- package/src/storage/feed.ts +20 -1
- package/src/storage/index.ts +1 -1
- package/src/storage/measurement.ts +19 -0
- package/src/storage/storage.ts +37 -0
- package/src/store/event/index.ts +4 -4
- package/src/store/event/store-balance.event.spec.ts +3 -3
- package/src/store/event/store-balance.event.ts +2 -2
- package/src/store/event/store-candle.event.spec.ts +1 -1
- package/src/store/event/store-candle.event.ts +5 -5
- package/src/store/event/store-instrument.event.spec.ts +1 -1
- package/src/store/event/store-instrument.event.ts +2 -2
- package/src/store/event/store-order.event.spec.ts +2 -2
- package/src/store/event/store-order.event.ts +7 -7
- package/src/store/event/store-orderbook.event.ts +2 -2
- package/src/store/event/store-position.event.ts +2 -2
- package/src/store/event/store-trade.event.spec.ts +2 -2
- package/src/store/event/store-trade.event.ts +2 -2
- package/src/store/index.ts +1 -0
- package/src/store/store.state.ts +7 -7
- package/src/store/store.ts +6 -9
- package/src/tests/backtester-adapter.spec.ts +8 -15
- package/src/tests/session.spec.ts +0 -3
- package/dist/adapter/paper/executor/paper-executor.js.map +0 -1
- package/dist/adapter/paper/executor/paper-margin-executor.js.map +0 -1
- package/dist/adapter/paper/executor/paper-spot-executor.js.map +0 -1
- package/dist/domain/candle-builder.d.ts +0 -16
- package/dist/domain/candle-builder.js +0 -70
- package/dist/domain/candle-builder.js.map +0 -1
- package/dist/domain/session-descriptor.d.ts +0 -15
- package/dist/domain/session-descriptor.js +0 -3
- package/dist/domain/session-descriptor.js.map +0 -1
- package/src/domain/candle-builder.ts +0 -104
- package/src/domain/session-descriptor.ts +0 -53
package/src/adapter/index.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export * from './paper-adapter';
|
|
2
|
-
export * from './
|
|
3
|
-
export * from './
|
|
2
|
+
export * from './simulator/paper-margin-simulator';
|
|
3
|
+
export * from './simulator/paper-spot-simulator';
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PaperSpotSimulator } from '.';
|
|
2
2
|
import { AdapterContext } from '..';
|
|
3
|
-
import { Store } from '../../store';
|
|
3
|
+
import { InstrumentPatchEvent, Store } from '../../store';
|
|
4
4
|
import { Adapter } from '../adapter';
|
|
5
|
-
import {
|
|
5
|
+
import { Asset, Commission, instrumentOf, Order } from './../../domain';
|
|
6
6
|
import { PaperAdapter } from './paper-adapter';
|
|
7
|
-
import {
|
|
8
|
-
import { instrumentOf } from './../../domain/instrument';
|
|
9
|
-
import { BalancePatchEvent, InstrumentPatchEvent } from '../../store/event';
|
|
7
|
+
import { PaperSimulator } from './simulator/paper-simulator';
|
|
10
8
|
|
|
11
9
|
class DefaultAdapter extends Adapter {
|
|
12
10
|
name = 'default';
|
|
@@ -29,8 +27,8 @@ class DefaultAdapter extends Adapter {
|
|
|
29
27
|
);
|
|
30
28
|
}
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
return new
|
|
30
|
+
createPaperSimulator(adapter: PaperAdapter): PaperSimulator {
|
|
31
|
+
return new PaperSpotSimulator(adapter);
|
|
34
32
|
}
|
|
35
33
|
}
|
|
36
34
|
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import { Adapter, AdapterContext } from '..';
|
|
2
|
-
import { Store } from '../../store';
|
|
3
|
-
import { PaperExecutor } from './executor/paper-executor';
|
|
4
2
|
import { assetOf, Candle, InstrumentSelector, Order } from '../../domain';
|
|
5
|
-
import { BalancePatchEvent } from '../../store
|
|
6
|
-
import { Feed } from 'src/storage';
|
|
3
|
+
import { BalancePatchEvent, Store } from '../../store';
|
|
7
4
|
import { FeedQuery, HistoryQuery } from '../adapter';
|
|
5
|
+
import { PaperSimulator } from './simulator/paper-simulator';
|
|
8
6
|
|
|
9
|
-
export
|
|
7
|
+
export interface PaperOptions {
|
|
10
8
|
balance: { [key: string]: number };
|
|
11
9
|
}
|
|
12
10
|
|
|
13
11
|
export class PaperAdapter extends Adapter {
|
|
14
12
|
readonly name = this.decoratedAdapter.name;
|
|
15
|
-
readonly
|
|
13
|
+
readonly simulator: PaperSimulator;
|
|
16
14
|
|
|
17
15
|
constructor(
|
|
18
16
|
readonly decoratedAdapter: Adapter,
|
|
@@ -21,7 +19,7 @@ export class PaperAdapter extends Adapter {
|
|
|
21
19
|
) {
|
|
22
20
|
super();
|
|
23
21
|
|
|
24
|
-
this.
|
|
22
|
+
this.simulator = this.createPaperSimulator(this);
|
|
25
23
|
}
|
|
26
24
|
|
|
27
25
|
timestamp() {
|
|
@@ -68,11 +66,11 @@ export class PaperAdapter extends Adapter {
|
|
|
68
66
|
}
|
|
69
67
|
|
|
70
68
|
async open(order: Order): Promise<void> {
|
|
71
|
-
this.
|
|
69
|
+
this.simulator.open(order);
|
|
72
70
|
}
|
|
73
71
|
|
|
74
72
|
async cancel(order: Order): Promise<void> {
|
|
75
|
-
this.
|
|
73
|
+
this.simulator.cancel(order);
|
|
76
74
|
}
|
|
77
75
|
|
|
78
76
|
history(query: HistoryQuery): Promise<Candle[]> {
|
|
@@ -83,7 +81,7 @@ export class PaperAdapter extends Adapter {
|
|
|
83
81
|
return this.decoratedAdapter.feed(query);
|
|
84
82
|
}
|
|
85
83
|
|
|
86
|
-
|
|
87
|
-
return this.decoratedAdapter.
|
|
84
|
+
createPaperSimulator(adapter: PaperAdapter): PaperSimulator {
|
|
85
|
+
return this.decoratedAdapter.createPaperSimulator(adapter);
|
|
88
86
|
}
|
|
89
87
|
}
|
package/src/adapter/paper/{executor/paper-margin-executor.ts → simulator/paper-margin-simulator.ts}
RENAMED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PaperAdapter } from '..';
|
|
2
2
|
import { Order } from '../../../domain';
|
|
3
|
+
import { pnl, weightedMean } from '../../../shared';
|
|
3
4
|
import {
|
|
4
5
|
BalanceTransactEvent,
|
|
5
6
|
OrderCanceledEvent,
|
|
@@ -8,11 +9,10 @@ import {
|
|
|
8
9
|
OrderNewEvent,
|
|
9
10
|
OrderPendingEvent,
|
|
10
11
|
PositionPatchEvent
|
|
11
|
-
} from '../../../store
|
|
12
|
-
import {
|
|
13
|
-
import { PaperExecutor } from './paper-executor';
|
|
12
|
+
} from '../../../store';
|
|
13
|
+
import { PaperSimulator } from './paper-simulator';
|
|
14
14
|
|
|
15
|
-
export class
|
|
15
|
+
export class PaperMarginSimulator extends PaperSimulator {
|
|
16
16
|
leverage = 10;
|
|
17
17
|
|
|
18
18
|
constructor(adapter: PaperAdapter) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { tap } from 'rxjs
|
|
2
|
-
import { Component, InstrumentSelector, Order, Orderbook, Trade } from '../../../domain';
|
|
3
|
-
import { PaperAdapter } from '..';
|
|
1
|
+
import { tap } from 'rxjs';
|
|
4
2
|
import { Set } from 'typescript-collections';
|
|
3
|
+
import { PaperAdapter } from '..';
|
|
4
|
+
import { Component, InstrumentSelector, Order, Orderbook, Trade } from '../../../domain';
|
|
5
5
|
|
|
6
|
-
export abstract class
|
|
6
|
+
export abstract class PaperSimulator {
|
|
7
7
|
private readonly pending: Record<string, Set<Order>> = {};
|
|
8
8
|
|
|
9
9
|
constructor(readonly adapter: PaperAdapter) {
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { PaperAdapter } from '../paper-adapter';
|
|
2
|
+
import {
|
|
3
|
+
Asset,
|
|
4
|
+
assetOf,
|
|
5
|
+
Commission,
|
|
6
|
+
commissionPercentOf,
|
|
7
|
+
instrumentOf,
|
|
8
|
+
Order
|
|
9
|
+
} from './../../../domain';
|
|
10
|
+
import {
|
|
11
|
+
BalancePatchEvent,
|
|
12
|
+
InstrumentPatchEvent,
|
|
13
|
+
InstrumentSubscriptionEvent,
|
|
14
|
+
Store,
|
|
15
|
+
TradePatchEvent
|
|
16
|
+
} from './../../../store';
|
|
17
|
+
import { Adapter, AdapterContext } from './../../adapter';
|
|
18
|
+
import { PaperSimulator } from './paper-simulator';
|
|
19
|
+
import { PaperSpotSimulator } from './paper-spot-simulator';
|
|
20
|
+
|
|
21
|
+
class DefaultAdapter extends Adapter {
|
|
22
|
+
name = 'default';
|
|
23
|
+
|
|
24
|
+
timestamp() {
|
|
25
|
+
return 123;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async awake(context: AdapterContext): Promise<void> {
|
|
29
|
+
await super.awake(context);
|
|
30
|
+
|
|
31
|
+
context.dispatch(
|
|
32
|
+
new InstrumentPatchEvent(
|
|
33
|
+
context.timestamp,
|
|
34
|
+
new Asset('a', this.name, 8),
|
|
35
|
+
new Asset('b', this.name, 4),
|
|
36
|
+
new Commission(0.1, 0.1),
|
|
37
|
+
'a-b'
|
|
38
|
+
)
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
createPaperSimulator(adapter: PaperAdapter): PaperSimulator {
|
|
43
|
+
return new PaperSpotSimulator(adapter);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
describe('paper spot simulator tests', () => {
|
|
48
|
+
const options = {
|
|
49
|
+
balance: {
|
|
50
|
+
['default:a']: 1000,
|
|
51
|
+
['default:b']: 200
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
test('should open an market order', async () => {
|
|
56
|
+
const store = new Store();
|
|
57
|
+
const adapter = new DefaultAdapter();
|
|
58
|
+
const order = Order.buyMarket(instrumentOf('default:a-b'), 1);
|
|
59
|
+
|
|
60
|
+
store.dispatch(
|
|
61
|
+
new InstrumentPatchEvent(
|
|
62
|
+
0,
|
|
63
|
+
new Asset('a', 'default', 8),
|
|
64
|
+
new Asset('b', 'default', 4),
|
|
65
|
+
commissionPercentOf(0.1, 0.1),
|
|
66
|
+
'a-b'
|
|
67
|
+
),
|
|
68
|
+
new BalancePatchEvent(assetOf('default:a'), 1000, 0, 1)
|
|
69
|
+
);
|
|
70
|
+
store.dispatch(new BalancePatchEvent(assetOf('default:b'), 1000, 0, 1));
|
|
71
|
+
store.dispatch(new InstrumentSubscriptionEvent(1, instrumentOf('default:a-b'), true));
|
|
72
|
+
|
|
73
|
+
const sut = new PaperSpotSimulator(new PaperAdapter(adapter, store, options));
|
|
74
|
+
|
|
75
|
+
await sut.open(order);
|
|
76
|
+
|
|
77
|
+
expect(store.snapshot.order[order.id].state).toBe('PENDING');
|
|
78
|
+
|
|
79
|
+
store.dispatch(new TradePatchEvent(instrumentOf('default:a-b'), 5, 1, 2));
|
|
80
|
+
|
|
81
|
+
expect(store.snapshot.order[order.id].quantity).toBe(1);
|
|
82
|
+
expect(store.snapshot.order[order.id].averageExecutionRate).toBe(5);
|
|
83
|
+
expect(store.snapshot.order[order.id].state).toBe('FILLED');
|
|
84
|
+
expect(store.snapshot.balance['default:b'].free).toBe(995);
|
|
85
|
+
expect(store.snapshot.balance['default:a'].free).toBe(1000.999);
|
|
86
|
+
});
|
|
87
|
+
});
|
package/src/adapter/paper/{executor/paper-spot-executor.ts → simulator/paper-spot-simulator.ts}
RENAMED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PaperAdapter } from '..';
|
|
2
|
+
import { Order } from '../../../domain';
|
|
3
|
+
import { timestamp } from '../../../shared';
|
|
2
4
|
import {
|
|
3
5
|
BalanceFreezEvent,
|
|
4
6
|
BalanceTransactEvent,
|
|
@@ -8,12 +10,10 @@ import {
|
|
|
8
10
|
OrderFilledEvent,
|
|
9
11
|
OrderNewEvent,
|
|
10
12
|
OrderPendingEvent
|
|
11
|
-
} from '../../../store
|
|
12
|
-
import {
|
|
13
|
-
import { PaperExecutor } from './paper-executor';
|
|
14
|
-
import { timestamp } from '../../../shared';
|
|
13
|
+
} from '../../../store';
|
|
14
|
+
import { PaperSimulator } from './paper-simulator';
|
|
15
15
|
|
|
16
|
-
export class
|
|
16
|
+
export class PaperSpotSimulator extends PaperSimulator {
|
|
17
17
|
constructor(readonly adapter: PaperAdapter) {
|
|
18
18
|
super(adapter);
|
|
19
19
|
}
|
package/src/bootstrap.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
+
AdapterAggregate,
|
|
2
3
|
BacktesterAdapter,
|
|
3
4
|
BacktesterListener,
|
|
4
|
-
BacktesterStreamer
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import { PaperAdapter } from './adapter/paper';
|
|
5
|
+
BacktesterStreamer,
|
|
6
|
+
PaperAdapter
|
|
7
|
+
} from './adapter';
|
|
8
8
|
import { Session, SessionDescriptor } from './domain';
|
|
9
9
|
import { Store } from './store';
|
|
10
10
|
|
package/src/domain/balance.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { timestamp } from '../shared';
|
|
2
2
|
import { Asset } from './';
|
|
3
|
-
import { Position, PositionMode } from './position';
|
|
4
3
|
import { Component } from './component';
|
|
4
|
+
import { Position, PositionMode } from './position';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Represents single asset balance in your wallet.
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { from } from 'rxjs';
|
|
2
|
-
import { map } from 'rxjs/operators';
|
|
3
|
-
import { TradePatchEvent } from '../store/event';
|
|
1
|
+
import { from, map } from 'rxjs';
|
|
4
2
|
import { now } from '../shared';
|
|
5
|
-
import {
|
|
6
|
-
import { mergeCandle } from './candle
|
|
3
|
+
import { TradePatchEvent } from '../store';
|
|
4
|
+
import { Candle, mergeCandle } from './candle';
|
|
7
5
|
import { instrumentOf } from './instrument';
|
|
8
6
|
import { Timeframe } from './timeframe';
|
|
9
7
|
|
package/src/domain/candle.ts
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
concat,
|
|
3
|
+
filter,
|
|
4
|
+
last,
|
|
5
|
+
map,
|
|
6
|
+
mergeMap,
|
|
7
|
+
Observable,
|
|
8
|
+
share,
|
|
9
|
+
skipLast,
|
|
10
|
+
withLatestFrom
|
|
11
|
+
} from 'rxjs';
|
|
1
12
|
import { timestamp } from '../shared';
|
|
13
|
+
import { tf } from './timeframe';
|
|
2
14
|
|
|
3
15
|
export class Candle {
|
|
4
16
|
constructor(
|
|
@@ -15,3 +27,94 @@ export class Candle {
|
|
|
15
27
|
this.close = value;
|
|
16
28
|
}
|
|
17
29
|
}
|
|
30
|
+
|
|
31
|
+
export class CandleBuilder {
|
|
32
|
+
private _candle: Candle;
|
|
33
|
+
|
|
34
|
+
get candle(): Candle {
|
|
35
|
+
return this._candle;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
constructor(readonly timeframe: number) {}
|
|
39
|
+
|
|
40
|
+
append(value: number, timestamp: timestamp): Candle {
|
|
41
|
+
const frame = tf(timestamp, this.timeframe);
|
|
42
|
+
|
|
43
|
+
if (!this._candle) {
|
|
44
|
+
this._candle = new Candle(frame, value, value, value, value);
|
|
45
|
+
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (this.candle.timestamp == frame) {
|
|
50
|
+
this.candle.apply(value);
|
|
51
|
+
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const previous = this._candle;
|
|
56
|
+
|
|
57
|
+
this._candle = new Candle(frame, value, value, value, value);
|
|
58
|
+
return previous;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function candle<T extends { timestamp: number }>(
|
|
63
|
+
timeframe: number,
|
|
64
|
+
fn: (x: T) => number
|
|
65
|
+
) {
|
|
66
|
+
return function (source: Observable<T>): Observable<Candle> {
|
|
67
|
+
const builder = new CandleBuilder(timeframe);
|
|
68
|
+
let candle: Candle;
|
|
69
|
+
|
|
70
|
+
return source.pipe(
|
|
71
|
+
filter(it => {
|
|
72
|
+
return (candle = builder.append(fn(it), it.timestamp)) != null;
|
|
73
|
+
}),
|
|
74
|
+
map(_ => candle),
|
|
75
|
+
share()
|
|
76
|
+
);
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function mergeCandle<T extends { timestamp: number }>(
|
|
81
|
+
timeframe: number,
|
|
82
|
+
fn: (x: T) => number,
|
|
83
|
+
history$: Observable<Candle>
|
|
84
|
+
) {
|
|
85
|
+
return function (source$: Observable<T>): Observable<Candle> {
|
|
86
|
+
const builder = new CandleBuilder(timeframe);
|
|
87
|
+
let hasMergedHistory = false;
|
|
88
|
+
|
|
89
|
+
return concat(
|
|
90
|
+
history$.pipe(skipLast(1)),
|
|
91
|
+
source$.pipe(
|
|
92
|
+
withLatestFrom(history$.pipe(last())),
|
|
93
|
+
mergeMap(([it, history]) => {
|
|
94
|
+
const completed = builder.append(fn(it), it.timestamp);
|
|
95
|
+
|
|
96
|
+
if (completed) {
|
|
97
|
+
if (completed.timestamp == history.timestamp) {
|
|
98
|
+
completed.open = history.open;
|
|
99
|
+
completed.high = Math.max(completed.high, history.high);
|
|
100
|
+
completed.low = Math.min(completed.low, history.low);
|
|
101
|
+
|
|
102
|
+
hasMergedHistory = true;
|
|
103
|
+
} else if (completed.timestamp > history.timestamp) {
|
|
104
|
+
if (!hasMergedHistory) {
|
|
105
|
+
hasMergedHistory = true;
|
|
106
|
+
return [history, completed];
|
|
107
|
+
}
|
|
108
|
+
} else if (completed.timestamp < history.timestamp) {
|
|
109
|
+
throw new Error('invalid candle sequence, input data is to old.');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return [completed];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return [];
|
|
116
|
+
})
|
|
117
|
+
)
|
|
118
|
+
);
|
|
119
|
+
};
|
|
120
|
+
}
|
package/src/domain/index.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
export * from './asset';
|
|
2
|
-
export * from './instrument';
|
|
3
2
|
export * from './balance';
|
|
4
|
-
export * from './
|
|
5
|
-
export * from './orderbook';
|
|
3
|
+
export * from './candle';
|
|
6
4
|
export * from './commission';
|
|
7
5
|
export * from './component';
|
|
8
|
-
export * from './
|
|
9
|
-
export * from './
|
|
10
|
-
export * from './
|
|
6
|
+
export * from './instrument';
|
|
7
|
+
export * from './order';
|
|
8
|
+
export * from './orderbook';
|
|
11
9
|
export * from './position';
|
|
12
|
-
export * from './trade';
|
|
13
10
|
export * from './session';
|
|
14
|
-
export * from './session-descriptor';
|
|
15
11
|
export * from './statement';
|
|
12
|
+
export * from './timeframe';
|
|
13
|
+
export * from './trade';
|
package/src/domain/order.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Component } from './component';
|
|
2
1
|
import { v4 } from 'uuid';
|
|
3
|
-
import { InstrumentSelector } from './instrument';
|
|
4
2
|
import { timestamp } from '../shared';
|
|
3
|
+
import { Component } from './component';
|
|
4
|
+
import { InstrumentSelector } from './instrument';
|
|
5
5
|
|
|
6
6
|
export type OrderSide = 'SELL' | 'BUY';
|
|
7
7
|
export type OrderType = 'MARKET' | 'LIMIT' | 'STOP-MARKET' | 'STOP-LIMIT';
|
package/src/domain/orderbook.ts
CHANGED
package/src/domain/position.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
+
import { map, Observable, share } from 'rxjs';
|
|
1
2
|
import { Instrument } from '../domain';
|
|
2
|
-
import { Component } from './component';
|
|
3
3
|
import { pnl, timestamp, weightedMean } from '../shared';
|
|
4
|
-
import {
|
|
5
|
-
import { map, share } from 'rxjs/operators';
|
|
4
|
+
import { Component } from './component';
|
|
6
5
|
|
|
7
6
|
export type PositionMode = 'CROSS' | 'ISOLATED';
|
|
8
7
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Bootstrap } from '../bootstrap';
|
|
2
2
|
import { Asset, Commission } from '../domain';
|
|
3
3
|
import { now } from '../shared';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { InstrumentPatchEvent } from '../store';
|
|
5
|
+
import { SessionDescriptor } from './session';
|
|
6
6
|
|
|
7
7
|
describe('session tests', () => {
|
|
8
8
|
const descriptor: SessionDescriptor = {
|
package/src/domain/session.ts
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
|
+
concat,
|
|
2
3
|
distinctUntilChanged,
|
|
3
4
|
filter,
|
|
5
|
+
from,
|
|
4
6
|
map,
|
|
5
7
|
mergeMap,
|
|
8
|
+
Observable,
|
|
6
9
|
share,
|
|
7
10
|
shareReplay,
|
|
8
11
|
startWith,
|
|
12
|
+
Subject,
|
|
13
|
+
Subscription,
|
|
9
14
|
switchMap,
|
|
10
15
|
take
|
|
11
|
-
} from 'rxjs
|
|
16
|
+
} from 'rxjs';
|
|
17
|
+
import { Adapter, BacktesterOptions, PaperOptions } from '../adapter';
|
|
18
|
+
import { AdapterAggregate } from '../adapter/adapter-aggregate';
|
|
12
19
|
import {
|
|
13
20
|
AssetSelector,
|
|
14
21
|
Balance,
|
|
@@ -16,19 +23,65 @@ import {
|
|
|
16
23
|
Instrument,
|
|
17
24
|
InstrumentSelector,
|
|
18
25
|
Order,
|
|
19
|
-
Position,
|
|
20
26
|
Orderbook,
|
|
21
|
-
OrderState
|
|
27
|
+
OrderState,
|
|
28
|
+
Position
|
|
22
29
|
} from '../domain';
|
|
23
|
-
import { Store } from '../store';
|
|
24
|
-
import { concat, from, Observable, Subject, Subscription } from 'rxjs';
|
|
25
|
-
import { AdapterAggregate } from '../adapter/adapter-aggregate';
|
|
26
|
-
import { Worker, now } from '../shared';
|
|
27
30
|
import { Trade } from '../domain/trade';
|
|
28
|
-
import {
|
|
31
|
+
import { now, Worker } from '../shared';
|
|
32
|
+
import { Feed, Measurement } from '../storage';
|
|
33
|
+
import { Store } from '../store';
|
|
29
34
|
|
|
30
35
|
type Optional<T, K extends keyof T> = Omit<T, K> & Partial<T>;
|
|
31
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Describes a single session.
|
|
39
|
+
* You can use @run function to start a new session managed by CLI.
|
|
40
|
+
* To start managed session you should install @quantform/cli package and run
|
|
41
|
+
* specific command:
|
|
42
|
+
* - qf paper (to paper trade strategy)
|
|
43
|
+
* - qf backtest (to backtest strategy based on provided feed)
|
|
44
|
+
* - qf live (to live trade strategy)
|
|
45
|
+
* or run on your own in code:
|
|
46
|
+
* - paper(descriptor, options)
|
|
47
|
+
* - backtest(descriptor, options)
|
|
48
|
+
* - live(descriptor)
|
|
49
|
+
*/
|
|
50
|
+
export interface SessionDescriptor {
|
|
51
|
+
/**
|
|
52
|
+
* Unique session identifier, used to identify session in the storage.
|
|
53
|
+
* You can generate new id every time you start the new session or provide
|
|
54
|
+
* session id explicitly to resume previous session (in code or via CLI).
|
|
55
|
+
* If you don't provide session id, it will generate new one based on time.
|
|
56
|
+
*/
|
|
57
|
+
id?: number;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Collection of adapters used to connect to the exchanges.
|
|
61
|
+
*/
|
|
62
|
+
adapter: Adapter[];
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Provides historical data for backtest, it's not required for live and paper
|
|
66
|
+
* sessions.
|
|
67
|
+
*/
|
|
68
|
+
feed?: Feed;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Stores session variables i.e. indicators, orders, or any other type of time
|
|
72
|
+
* series data. You can install @quantform/editor to render this data in your browser.
|
|
73
|
+
*/
|
|
74
|
+
measurement?: Measurement;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Session additional options.
|
|
78
|
+
*/
|
|
79
|
+
options?: {
|
|
80
|
+
backtester?: BacktesterOptions;
|
|
81
|
+
paper?: PaperOptions;
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
32
85
|
export class Session {
|
|
33
86
|
private initialized = false;
|
|
34
87
|
private subscription: Subscription;
|
package/src/domain/statement.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { Session } from '.';
|
|
2
|
-
import { InstrumentSelector } from '.';
|
|
3
1
|
import { combineLatest, finalize, map, take, tap } from 'rxjs';
|
|
2
|
+
import { InstrumentSelector, Session } from '.';
|
|
4
3
|
import { drawdown } from '../indicator';
|
|
5
4
|
import { floor, precision } from '../shared';
|
|
6
5
|
|
package/src/domain/trade.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
export * from './shared';
|
|
2
|
-
export * from './domain';
|
|
3
1
|
export * from './adapter';
|
|
4
|
-
export * from './
|
|
5
|
-
export * from './
|
|
2
|
+
export * from './bootstrap';
|
|
3
|
+
export * from './domain';
|
|
6
4
|
export * from './indicator';
|
|
5
|
+
export * from './ipc';
|
|
6
|
+
export * from './shared';
|
|
7
7
|
export * from './storage';
|
|
8
8
|
export * from './store';
|
|
9
|
-
export * from './store/event';
|
|
10
|
-
export * from './bootstrap';
|
|
11
|
-
export * from './ipc';
|
package/src/indicator/atr.ts
CHANGED
package/src/indicator/cross.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { Observable } from 'rxjs';
|
|
2
|
-
import { filter } from 'rxjs/operators';
|
|
1
|
+
import { filter, Observable } from 'rxjs';
|
|
3
2
|
|
|
4
3
|
export function crossunder<T>(limitFn: (it: T) => number, currentFn: (it: T) => number) {
|
|
5
|
-
return function(source: Observable<T>): Observable<T> {
|
|
4
|
+
return function (source: Observable<T>): Observable<T> {
|
|
6
5
|
let triggered = false;
|
|
7
6
|
|
|
8
7
|
return source.pipe(
|
|
@@ -27,7 +26,7 @@ export function crossunder<T>(limitFn: (it: T) => number, currentFn: (it: T) =>
|
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
export function crossover<T>(limitFn: (it: T) => number, currentFn: (it: T) => number) {
|
|
30
|
-
return function(source: Observable<T>): Observable<T> {
|
|
29
|
+
return function (source: Observable<T>): Observable<T> {
|
|
31
30
|
let triggered = false;
|
|
32
31
|
|
|
33
32
|
return source.pipe(
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { Observable, withLatestFrom } from 'rxjs';
|
|
2
|
-
import { map, share } from 'rxjs/operators';
|
|
3
|
-
import { minMax } from './min-max';
|
|
1
|
+
import { map, Observable, share, withLatestFrom } from 'rxjs';
|
|
4
2
|
import { Candle } from '../domain';
|
|
3
|
+
import { minMax } from './min-max';
|
|
5
4
|
|
|
6
5
|
export function donchian<T>(length: number, fn: (it: T) => Candle) {
|
|
7
6
|
return function (source: Observable<T>): Observable<
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { Observable } from 'rxjs';
|
|
2
|
-
import { map, share } from 'rxjs/operators';
|
|
1
|
+
import { map, Observable, share } from 'rxjs';
|
|
3
2
|
|
|
4
3
|
export function drawdown<T>(fn: (it: T) => number) {
|
|
5
|
-
return function(source: Observable<T>): Observable<number> {
|
|
4
|
+
return function (source: Observable<T>): Observable<number> {
|
|
6
5
|
let rate;
|
|
7
6
|
let max = 0;
|
|
8
7
|
|
package/src/indicator/ema.ts
CHANGED