@quantform/core 0.5.15 → 0.5.23
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 +5 -4
- package/dist/adapter/adapter-aggregate.js +4 -4
- package/dist/adapter/adapter-aggregate.js.map +1 -1
- package/dist/adapter/adapter.d.ts +4 -15
- package/dist/adapter/adapter.js.map +1 -1
- package/dist/adapter/backtester/backtester-adapter.d.ts +3 -3
- package/dist/adapter/backtester/backtester-adapter.js +4 -4
- package/dist/adapter/backtester/backtester-adapter.js.map +1 -1
- package/dist/adapter/backtester/backtester-adapter.spec.js +7 -6
- package/dist/adapter/backtester/backtester-adapter.spec.js.map +1 -1
- package/dist/adapter/backtester/backtester-cursor.d.ts +4 -4
- package/dist/adapter/backtester/backtester-cursor.js.map +1 -1
- package/dist/adapter/backtester/backtester-cursor.spec.js +19 -17
- package/dist/adapter/backtester/backtester-cursor.spec.js.map +1 -1
- package/dist/adapter/backtester/backtester-streamer.d.ts +0 -1
- package/dist/adapter/backtester/backtester-streamer.js +4 -14
- package/dist/adapter/backtester/backtester-streamer.js.map +1 -1
- package/dist/adapter/backtester/backtester-streamer.spec.js +12 -11
- package/dist/adapter/backtester/backtester-streamer.spec.js.map +1 -1
- package/dist/adapter/paper/engine/paper-engine.js +20 -19
- package/dist/adapter/paper/engine/paper-engine.js.map +1 -1
- package/dist/adapter/paper/engine/paper-engine.spec.js +19 -19
- package/dist/adapter/paper/engine/paper-engine.spec.js.map +1 -1
- package/dist/adapter/paper/paper-adapter.d.ts +4 -3
- package/dist/adapter/paper/paper-adapter.js +8 -7
- package/dist/adapter/paper/paper-adapter.js.map +1 -1
- package/dist/adapter/paper/paper-adapter.spec.js +5 -4
- package/dist/adapter/paper/paper-adapter.spec.js.map +1 -1
- package/dist/cli/pull.js +5 -10
- package/dist/cli/pull.js.map +1 -1
- package/dist/domain/asset.d.ts +4 -4
- package/dist/domain/asset.js +4 -7
- package/dist/domain/asset.js.map +1 -1
- package/dist/domain/asset.spec.js +4 -4
- package/dist/domain/asset.spec.js.map +1 -1
- package/dist/domain/balance.d.ts +9 -9
- package/dist/domain/balance.js +16 -15
- package/dist/domain/balance.js.map +1 -1
- package/dist/domain/balance.spec.js +37 -36
- package/dist/domain/balance.spec.js.map +1 -1
- package/dist/domain/candle.d.ts +8 -8
- package/dist/domain/candle.js +3 -2
- package/dist/domain/candle.js.map +1 -1
- package/dist/domain/candle.operator.d.ts +3 -2
- package/dist/domain/candle.operator.js.map +1 -1
- package/dist/domain/candle.operator.spec.js +43 -42
- package/dist/domain/candle.operator.spec.js.map +1 -1
- package/dist/domain/candle.spec.js +11 -11
- package/dist/domain/candle.spec.js.map +1 -1
- package/dist/domain/commission.d.ts +10 -9
- package/dist/domain/commission.js +5 -5
- package/dist/domain/commission.js.map +1 -1
- package/dist/domain/commission.spec.js +13 -12
- package/dist/domain/commission.spec.js.map +1 -1
- package/dist/domain/error.d.ts +2 -1
- package/dist/domain/error.js +1 -1
- package/dist/domain/error.js.map +1 -1
- package/dist/domain/order.d.ts +13 -13
- package/dist/domain/order.js +10 -9
- package/dist/domain/order.js.map +1 -1
- package/dist/domain/order.operator.spec.js +6 -5
- package/dist/domain/order.operator.spec.js.map +1 -1
- package/dist/domain/order.spec.js +11 -10
- package/dist/domain/order.spec.js.map +1 -1
- package/dist/domain/orderbook.d.ts +18 -6
- package/dist/domain/orderbook.js +5 -4
- package/dist/domain/orderbook.js.map +1 -1
- package/dist/domain/position.d.ts +7 -7
- package/dist/domain/position.js +2 -2
- package/dist/domain/position.js.map +1 -1
- package/dist/domain/position.operator.d.ts +3 -2
- package/dist/domain/position.operator.js +3 -3
- package/dist/domain/position.operator.js.map +1 -1
- package/dist/domain/position.operator.spec.js +4 -3
- package/dist/domain/position.operator.spec.js.map +1 -1
- package/dist/domain/position.spec.js +10 -9
- package/dist/domain/position.spec.js.map +1 -1
- package/dist/domain/session.js +1 -1
- package/dist/domain/session.js.map +1 -1
- package/dist/domain/session.spec.js +1 -1
- package/dist/domain/session.spec.js.map +1 -1
- package/dist/domain/trade.d.ts +3 -3
- package/dist/indicator/atr.d.ts +2 -1
- package/dist/indicator/atr.js +3 -3
- package/dist/indicator/atr.js.map +1 -1
- package/dist/indicator/cross.d.ts +3 -2
- package/dist/indicator/cross.js +13 -13
- package/dist/indicator/cross.js.map +1 -1
- package/dist/indicator/cross.spec.js +22 -21
- package/dist/indicator/cross.spec.js.map +1 -1
- package/dist/indicator/donchian.d.ts +3 -2
- package/dist/indicator/donchian.js.map +1 -1
- package/dist/indicator/drawdown.d.ts +2 -1
- package/dist/indicator/drawdown.js +3 -2
- package/dist/indicator/drawdown.js.map +1 -1
- package/dist/indicator/ema.d.ts +2 -1
- package/dist/indicator/ema.js +3 -2
- package/dist/indicator/ema.js.map +1 -1
- package/dist/indicator/ema.spec.js +3 -2
- package/dist/indicator/ema.spec.js.map +1 -1
- package/dist/indicator/envelope.d.ts +4 -3
- package/dist/indicator/envelope.js +4 -4
- 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.d.ts +2 -1
- package/dist/indicator/macd.js +1 -1
- package/dist/indicator/macd.js.map +1 -1
- package/dist/indicator/min-max.d.ts +4 -3
- package/dist/indicator/min-max.js +5 -4
- package/dist/indicator/min-max.js.map +1 -1
- package/dist/indicator/rma.d.ts +2 -1
- package/dist/indicator/rma.js +3 -2
- package/dist/indicator/rma.js.map +1 -1
- package/dist/indicator/sma.d.ts +2 -1
- package/dist/indicator/sma.js +4 -6
- package/dist/indicator/sma.js.map +1 -1
- package/dist/indicator/sma.spec.js +3 -2
- package/dist/indicator/sma.spec.js.map +1 -1
- package/dist/indicator/swma.d.ts +2 -1
- package/dist/indicator/swma.js +5 -1
- package/dist/indicator/swma.js.map +1 -1
- package/dist/indicator/tma.d.ts +2 -1
- package/dist/indicator/tma.js.map +1 -1
- package/dist/indicator/tma.spec.js +3 -2
- package/dist/indicator/tma.spec.js.map +1 -1
- package/dist/indicator/trailing.d.ts +8 -7
- package/dist/indicator/trailing.js +12 -11
- package/dist/indicator/trailing.js.map +1 -1
- package/dist/indicator/trailing.spec.js +15 -14
- package/dist/indicator/trailing.spec.js.map +1 -1
- package/dist/indicator/true-range.d.ts +4 -0
- package/dist/indicator/true-range.js +20 -0
- package/dist/indicator/true-range.js.map +1 -0
- package/dist/indicator/{truerange.spec.d.ts → true-range.spec.d.ts} +0 -0
- package/dist/indicator/true-range.spec.js +28 -0
- package/dist/indicator/true-range.spec.js.map +1 -0
- package/dist/indicator/window.d.ts +1 -1
- package/dist/indicator/window.js +1 -1
- package/dist/indicator/window.js.map +1 -1
- package/dist/indicator/wma.d.ts +2 -1
- package/dist/indicator/wma.js +6 -5
- package/dist/indicator/wma.js.map +1 -1
- package/dist/indicator/wma.spec.js +3 -2
- package/dist/indicator/wma.spec.js.map +1 -1
- package/dist/shared/collections.d.ts +16 -0
- package/dist/shared/collections.js +83 -1
- package/dist/shared/collections.js.map +1 -1
- package/dist/shared/collections.spec.d.ts +1 -0
- package/dist/shared/collections.spec.js +28 -0
- package/dist/shared/collections.spec.js.map +1 -0
- package/dist/shared/decimals.d.ts +15 -6
- package/dist/shared/decimals.js +21 -34
- package/dist/shared/decimals.js.map +1 -1
- package/dist/shared/decimals.spec.js +17 -22
- package/dist/shared/decimals.spec.js.map +1 -1
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.js +1 -0
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/pipe.d.ts +4 -0
- package/dist/shared/pipe.js +9 -0
- package/dist/shared/pipe.js.map +1 -0
- package/dist/storage/feed.d.ts +8 -4
- package/dist/storage/feed.js +55 -18
- package/dist/storage/feed.js.map +1 -1
- package/dist/store/store-balance.event.d.ts +6 -6
- package/dist/store/store-balance.event.js +2 -2
- package/dist/store/store-balance.event.js.map +1 -1
- package/dist/store/store-balance.event.spec.js +4 -4
- package/dist/store/store-balance.event.spec.js.map +1 -1
- package/dist/store/store-instrument.event.js.map +1 -1
- package/dist/store/store-instrument.event.spec.js +1 -1
- package/dist/store/store-instrument.event.spec.js.map +1 -1
- package/dist/store/store-order.event.d.ts +3 -3
- package/dist/store/store-order.event.js.map +1 -1
- package/dist/store/store-order.event.spec.js +1 -1
- package/dist/store/store-order.event.spec.js.map +1 -1
- package/dist/store/store-orderbook.event.d.ts +4 -6
- package/dist/store/store-orderbook.event.js +13 -13
- package/dist/store/store-orderbook.event.js.map +1 -1
- package/dist/store/store-orderbook.event.spec.d.ts +1 -0
- package/dist/store/store-orderbook.event.spec.js +28 -0
- package/dist/store/store-orderbook.event.spec.js.map +1 -0
- package/dist/store/store-position.event.d.ts +4 -4
- package/dist/store/store-position.event.js +23 -11
- package/dist/store/store-position.event.js.map +1 -1
- package/dist/store/store-trade.event.d.ts +4 -4
- package/dist/store/store-trade.event.js +2 -2
- package/dist/store/store-trade.event.js.map +1 -1
- package/dist/store/store-trade.event.spec.js +8 -8
- package/dist/store/store-trade.event.spec.js.map +1 -1
- package/dist/store/store.spec.js +15 -15
- package/dist/store/store.spec.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/jestconfig.json +1 -0
- package/package.json +3 -1
- package/src/adapter/adapter-aggregate.ts +16 -7
- package/src/adapter/adapter.ts +15 -18
- package/src/adapter/backtester/backtester-adapter.spec.ts +18 -9
- package/src/adapter/backtester/backtester-adapter.ts +14 -5
- package/src/adapter/backtester/backtester-cursor.spec.ts +20 -18
- package/src/adapter/backtester/backtester-cursor.ts +5 -5
- package/src/adapter/backtester/backtester-streamer.spec.ts +14 -13
- package/src/adapter/backtester/backtester-streamer.ts +5 -22
- package/src/adapter/paper/engine/paper-engine.spec.ts +30 -23
- package/src/adapter/paper/engine/paper-engine.ts +28 -21
- package/src/adapter/paper/paper-adapter.spec.ts +15 -6
- package/src/adapter/paper/paper-adapter.ts +20 -8
- package/src/cli/pull.ts +6 -5
- package/src/domain/asset.spec.ts +4 -4
- package/src/domain/asset.ts +7 -14
- package/src/domain/balance.spec.ts +37 -36
- package/src/domain/balance.ts +29 -29
- package/src/domain/candle.operator.spec.ts +43 -42
- package/src/domain/candle.operator.ts +4 -3
- package/src/domain/candle.spec.ts +13 -12
- package/src/domain/candle.ts +9 -9
- package/src/domain/commission.spec.ts +13 -12
- package/src/domain/commission.ts +13 -11
- package/src/domain/error.ts +5 -3
- package/src/domain/order.operator.spec.ts +6 -5
- package/src/domain/order.spec.ts +11 -10
- package/src/domain/order.ts +25 -22
- package/src/domain/orderbook.ts +14 -8
- package/src/domain/position.operator.spec.ts +5 -4
- package/src/domain/position.operator.ts +8 -5
- package/src/domain/position.spec.ts +10 -9
- package/src/domain/position.ts +8 -8
- package/src/domain/session.spec.ts +3 -3
- package/src/domain/session.ts +1 -3
- package/src/domain/trade.ts +3 -3
- package/src/indicator/atr.ts +6 -5
- package/src/indicator/cross.spec.ts +32 -47
- package/src/indicator/cross.ts +18 -10
- package/src/indicator/donchian.ts +5 -4
- package/src/indicator/drawdown.ts +7 -5
- package/src/indicator/ema.spec.ts +4 -3
- package/src/indicator/ema.ts +7 -6
- package/src/indicator/envelope.ts +11 -6
- package/src/indicator/index.ts +1 -1
- package/src/indicator/macd.ts +5 -4
- package/src/indicator/min-max.ts +10 -7
- package/src/indicator/rma.ts +7 -6
- package/src/indicator/sma.spec.ts +4 -3
- package/src/indicator/sma.ts +9 -8
- package/src/indicator/swma.ts +8 -4
- package/src/indicator/tma.spec.ts +4 -3
- package/src/indicator/tma.ts +4 -3
- package/src/indicator/trailing.spec.ts +29 -16
- package/src/indicator/trailing.ts +22 -16
- package/src/indicator/true-range.spec.ts +32 -0
- package/src/indicator/true-range.ts +32 -0
- package/src/indicator/window.ts +3 -3
- package/src/indicator/wma.spec.ts +4 -3
- package/src/indicator/wma.ts +8 -7
- package/src/shared/collections.spec.ts +30 -0
- package/src/shared/collections.ts +106 -0
- package/src/shared/decimals.spec.ts +18 -24
- package/src/shared/decimals.ts +22 -55
- package/src/shared/index.ts +1 -0
- package/src/shared/pipe.ts +12 -0
- package/src/storage/feed.ts +89 -34
- package/src/store/store-balance.event.spec.ts +5 -5
- package/src/store/store-balance.event.ts +6 -6
- package/src/store/store-instrument.event.spec.ts +2 -2
- package/src/store/store-instrument.event.ts +2 -2
- package/src/store/store-order.event.spec.ts +2 -2
- package/src/store/store-order.event.ts +2 -2
- package/src/store/store-orderbook.event.spec.ts +37 -0
- package/src/store/store-orderbook.event.ts +13 -13
- package/src/store/store-position.event.ts +27 -15
- package/src/store/store-trade.event.spec.ts +9 -9
- package/src/store/store-trade.event.ts +5 -5
- package/src/store/store.spec.ts +16 -16
- package/dist/indicator/truerange.d.ts +0 -3
- package/dist/indicator/truerange.js +0 -19
- package/dist/indicator/truerange.js.map +0 -1
- package/dist/indicator/truerange.spec.js +0 -28
- package/dist/indicator/truerange.spec.js.map +0 -1
- package/src/indicator/truerange.spec.ts +0 -32
- package/src/indicator/truerange.ts +0 -31
package/src/adapter/adapter.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Candle, InstrumentSelector, Order } from '../domain';
|
|
2
2
|
import { now, timestamp } from '../shared';
|
|
3
|
-
import { Cache,
|
|
3
|
+
import { Cache, StorageEvent } from '../storage';
|
|
4
4
|
import { Store } from '../store';
|
|
5
5
|
import { PaperAdapter } from './paper';
|
|
6
6
|
import { PaperEngine } from './paper/engine/paper-engine';
|
|
@@ -13,26 +13,14 @@ export const DefaultTimeProvider = {
|
|
|
13
13
|
timestamp: () => now()
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
+
export type FeedAsyncCallback = (timestamp: number, chunk: StorageEvent[]) => void;
|
|
17
|
+
|
|
16
18
|
export type AdapterFactory = (
|
|
17
19
|
timeProvider: AdapterTimeProvider,
|
|
18
20
|
store: Store,
|
|
19
21
|
cache: Cache
|
|
20
22
|
) => Adapter;
|
|
21
23
|
|
|
22
|
-
export type HistoryQuery = {
|
|
23
|
-
instrument: InstrumentSelector;
|
|
24
|
-
timeframe: number;
|
|
25
|
-
length: number;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export type FeedQuery = {
|
|
29
|
-
instrument: InstrumentSelector;
|
|
30
|
-
from: timestamp;
|
|
31
|
-
to: timestamp;
|
|
32
|
-
destination: Feed;
|
|
33
|
-
callback: (timestamp: number) => void;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
24
|
/**
|
|
37
25
|
* Base adapter class, you should derive your own adapter from this class.
|
|
38
26
|
* @abstract
|
|
@@ -78,9 +66,18 @@ export abstract class Adapter {
|
|
|
78
66
|
*/
|
|
79
67
|
abstract cancel(order: Order): Promise<void>;
|
|
80
68
|
|
|
81
|
-
abstract history(
|
|
82
|
-
|
|
83
|
-
|
|
69
|
+
abstract history(
|
|
70
|
+
instrument: InstrumentSelector,
|
|
71
|
+
timeframe: number,
|
|
72
|
+
length: number
|
|
73
|
+
): Promise<Candle[]>;
|
|
74
|
+
|
|
75
|
+
abstract feed(
|
|
76
|
+
instrument: InstrumentSelector,
|
|
77
|
+
from: timestamp,
|
|
78
|
+
to: timestamp,
|
|
79
|
+
callback: FeedAsyncCallback
|
|
80
|
+
): Promise<void>;
|
|
84
81
|
|
|
85
82
|
abstract createPaperEngine(adapter: PaperAdapter): PaperEngine;
|
|
86
83
|
}
|
|
@@ -6,14 +6,14 @@ import {
|
|
|
6
6
|
InstrumentSelector,
|
|
7
7
|
Order
|
|
8
8
|
} from '../../domain';
|
|
9
|
+
import { d, timestamp } from '../../shared';
|
|
9
10
|
import { Cache, Feed, InMemoryStorage } from '../../storage';
|
|
10
|
-
import { InstrumentPatchEvent, Store } from '../../store';
|
|
11
|
+
import { InstrumentPatchEvent, Store, TradePatchEvent } from '../../store';
|
|
11
12
|
import {
|
|
12
13
|
Adapter,
|
|
13
14
|
AdapterTimeProvider,
|
|
14
15
|
DefaultTimeProvider,
|
|
15
|
-
|
|
16
|
-
HistoryQuery
|
|
16
|
+
FeedAsyncCallback
|
|
17
17
|
} from '../adapter';
|
|
18
18
|
import { PaperEngine } from '../paper/engine/paper-engine';
|
|
19
19
|
import { PaperAdapter } from '../paper/paper-adapter';
|
|
@@ -39,10 +39,19 @@ class DefaultAdapter extends Adapter {
|
|
|
39
39
|
cancel(order: Order): Promise<void> {
|
|
40
40
|
throw new Error('Method not implemented.');
|
|
41
41
|
}
|
|
42
|
-
history(
|
|
42
|
+
history(
|
|
43
|
+
instrument: InstrumentSelector,
|
|
44
|
+
timeframe: number,
|
|
45
|
+
length: number
|
|
46
|
+
): Promise<Candle[]> {
|
|
43
47
|
throw new Error('Method not implemented.');
|
|
44
48
|
}
|
|
45
|
-
feed(
|
|
49
|
+
feed(
|
|
50
|
+
instrument: InstrumentSelector,
|
|
51
|
+
from: timestamp,
|
|
52
|
+
to: timestamp,
|
|
53
|
+
callback: FeedAsyncCallback
|
|
54
|
+
): Promise<void> {
|
|
46
55
|
throw new Error('Method not implemented.');
|
|
47
56
|
}
|
|
48
57
|
name = 'default';
|
|
@@ -65,7 +74,7 @@ class DefaultAdapter extends Adapter {
|
|
|
65
74
|
this.timestamp(),
|
|
66
75
|
base,
|
|
67
76
|
quote,
|
|
68
|
-
new Commission(0.1, 0.1),
|
|
77
|
+
new Commission(d(0.1), d(0.1)),
|
|
69
78
|
'btc-usdt'
|
|
70
79
|
)
|
|
71
80
|
);
|
|
@@ -104,15 +113,15 @@ describe('BacktesterAdapter', () => {
|
|
|
104
113
|
{
|
|
105
114
|
onBacktestCompleted: () => {
|
|
106
115
|
expect(store.snapshot.timestamp).toEqual(1);
|
|
107
|
-
expect(store.snapshot.trade.get(instrument.id).rate).toEqual(100);
|
|
108
|
-
expect(store.snapshot.trade.get(instrument.id).quantity).toEqual(10);
|
|
116
|
+
expect(store.snapshot.trade.get(instrument.id).rate).toEqual(d(100));
|
|
117
|
+
expect(store.snapshot.trade.get(instrument.id).quantity).toEqual(d(10));
|
|
109
118
|
|
|
110
119
|
done();
|
|
111
120
|
}
|
|
112
121
|
}
|
|
113
122
|
);
|
|
114
123
|
|
|
115
|
-
feed.save(
|
|
124
|
+
feed.save([new TradePatchEvent(instrument, d(100), d(10), 1)]);
|
|
116
125
|
|
|
117
126
|
const sut = new BacktesterAdapter(adapter, streamer, store);
|
|
118
127
|
|
|
@@ -2,7 +2,7 @@ import { Candle, InstrumentSelector, Order } from '../../domain';
|
|
|
2
2
|
import { timestamp } from '../../shared';
|
|
3
3
|
import { InstrumentSubscriptionEvent, Store } from '../../store';
|
|
4
4
|
import { Adapter } from '..';
|
|
5
|
-
import { AdapterFactory,
|
|
5
|
+
import { AdapterFactory, FeedAsyncCallback } from '../adapter';
|
|
6
6
|
import { PaperAdapter, PaperOptions } from '../paper';
|
|
7
7
|
import { PaperEngine } from '../paper/engine/paper-engine';
|
|
8
8
|
import { BacktesterStreamer } from './backtester-streamer';
|
|
@@ -69,18 +69,27 @@ export class BacktesterAdapter extends Adapter {
|
|
|
69
69
|
return this.decoratedAdapter.cancel(order);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
async history(
|
|
72
|
+
async history(
|
|
73
|
+
instrument: InstrumentSelector,
|
|
74
|
+
timeframe: number,
|
|
75
|
+
length: number
|
|
76
|
+
): Promise<Candle[]> {
|
|
73
77
|
this.streamer.stop();
|
|
74
78
|
|
|
75
|
-
const response = await this.decoratedAdapter.history(
|
|
79
|
+
const response = await this.decoratedAdapter.history(instrument, timeframe, length);
|
|
76
80
|
|
|
77
81
|
this.streamer.tryContinue();
|
|
78
82
|
|
|
79
83
|
return response;
|
|
80
84
|
}
|
|
81
85
|
|
|
82
|
-
feed(
|
|
83
|
-
|
|
86
|
+
feed(
|
|
87
|
+
instrument: InstrumentSelector,
|
|
88
|
+
from: timestamp,
|
|
89
|
+
to: timestamp,
|
|
90
|
+
callback: FeedAsyncCallback
|
|
91
|
+
): Promise<void> {
|
|
92
|
+
return this.decoratedAdapter.feed(instrument, from, to, callback);
|
|
84
93
|
}
|
|
85
94
|
|
|
86
95
|
createPaperEngine(adapter: PaperAdapter): PaperEngine {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { instrumentOf } from '../../domain';
|
|
2
|
+
import { d } from '../../shared';
|
|
2
3
|
import { Feed, InMemoryStorage } from '../../storage';
|
|
4
|
+
import { TradePatchEvent } from '../../store';
|
|
3
5
|
import { BacktesterCursor } from './backtester-cursor';
|
|
4
6
|
|
|
5
7
|
describe('BacktesterCursor', () => {
|
|
@@ -8,35 +10,35 @@ describe('BacktesterCursor', () => {
|
|
|
8
10
|
const feed = new Feed(new InMemoryStorage());
|
|
9
11
|
const cursor = new BacktesterCursor(instrument, feed);
|
|
10
12
|
|
|
11
|
-
feed.save(
|
|
12
|
-
new
|
|
13
|
-
new
|
|
14
|
-
new
|
|
15
|
-
new
|
|
16
|
-
new
|
|
17
|
-
new
|
|
18
|
-
new
|
|
19
|
-
new
|
|
13
|
+
feed.save([
|
|
14
|
+
new TradePatchEvent(instrument, d(1), d(1), 1),
|
|
15
|
+
new TradePatchEvent(instrument, d(2), d(2), 2),
|
|
16
|
+
new TradePatchEvent(instrument, d(3), d(3), 3),
|
|
17
|
+
new TradePatchEvent(instrument, d(4), d(4), 4),
|
|
18
|
+
new TradePatchEvent(instrument, d(5), d(5), 5),
|
|
19
|
+
new TradePatchEvent(instrument, d(6), d(6), 6),
|
|
20
|
+
new TradePatchEvent(instrument, d(7), d(7), 7),
|
|
21
|
+
new TradePatchEvent(instrument, d(8), d(8), 8)
|
|
20
22
|
]);
|
|
21
23
|
|
|
22
24
|
await cursor.fetchNextPage(0, 4);
|
|
23
25
|
|
|
24
|
-
expect(cursor.dequeue()
|
|
25
|
-
expect(cursor.dequeue()
|
|
26
|
-
expect(cursor.dequeue()
|
|
26
|
+
expect(cursor.dequeue()).toEqual(new TradePatchEvent(instrument, d(1), d(1), 1));
|
|
27
|
+
expect(cursor.dequeue()).toEqual(new TradePatchEvent(instrument, d(2), d(2), 2));
|
|
28
|
+
expect(cursor.dequeue()).toEqual(new TradePatchEvent(instrument, d(3), d(3), 3));
|
|
27
29
|
expect(cursor.peek()).toEqual(undefined);
|
|
28
30
|
|
|
29
31
|
await cursor.fetchNextPage(3, 7);
|
|
30
32
|
|
|
31
|
-
expect(cursor.dequeue()
|
|
32
|
-
expect(cursor.dequeue()
|
|
33
|
-
expect(cursor.dequeue()
|
|
33
|
+
expect(cursor.dequeue()).toEqual(new TradePatchEvent(instrument, d(4), d(4), 4));
|
|
34
|
+
expect(cursor.dequeue()).toEqual(new TradePatchEvent(instrument, d(5), d(5), 5));
|
|
35
|
+
expect(cursor.dequeue()).toEqual(new TradePatchEvent(instrument, d(6), d(6), 6));
|
|
34
36
|
expect(cursor.peek()).toEqual(undefined);
|
|
35
37
|
|
|
36
38
|
await cursor.fetchNextPage(6, 10);
|
|
37
39
|
|
|
38
|
-
expect(cursor.dequeue()
|
|
39
|
-
expect(cursor.dequeue()
|
|
40
|
+
expect(cursor.dequeue()).toEqual(new TradePatchEvent(instrument, d(7), d(7), 7));
|
|
41
|
+
expect(cursor.dequeue()).toEqual(new TradePatchEvent(instrument, d(8), d(8), 8));
|
|
40
42
|
expect(cursor.peek()).toEqual(undefined);
|
|
41
43
|
});
|
|
42
44
|
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { InstrumentSelector } from '../../domain';
|
|
2
2
|
import { timestamp } from '../../shared';
|
|
3
|
-
import { Feed } from '../../storage';
|
|
3
|
+
import { Feed, StorageEvent } from '../../storage';
|
|
4
4
|
import { backtestPageNotEmpty } from '../error';
|
|
5
5
|
|
|
6
6
|
export class BacktesterCursor {
|
|
7
|
-
private page = new Array<
|
|
7
|
+
private page = new Array<StorageEvent>();
|
|
8
8
|
private pageIndex = 0;
|
|
9
9
|
completed = false;
|
|
10
10
|
|
|
@@ -14,7 +14,7 @@ export class BacktesterCursor {
|
|
|
14
14
|
|
|
15
15
|
constructor(readonly instrument: InstrumentSelector, private readonly feed: Feed) {}
|
|
16
16
|
|
|
17
|
-
peek():
|
|
17
|
+
peek(): StorageEvent {
|
|
18
18
|
if (!this.page) {
|
|
19
19
|
return undefined;
|
|
20
20
|
}
|
|
@@ -22,7 +22,7 @@ export class BacktesterCursor {
|
|
|
22
22
|
return this.page[this.pageIndex];
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
dequeue():
|
|
25
|
+
dequeue(): StorageEvent {
|
|
26
26
|
return this.page[this.pageIndex++];
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Asset,
|
|
1
|
+
import { Asset, Instrument } from '../../domain';
|
|
2
|
+
import { d } from '../../shared';
|
|
2
3
|
import { Feed, InMemoryStorage } from '../../storage';
|
|
3
|
-
import { Store } from '../../store';
|
|
4
|
+
import { Store, TradePatchEvent } from '../../store';
|
|
4
5
|
import { BacktesterStreamer } from './backtester-streamer';
|
|
5
6
|
|
|
6
7
|
describe('BacktesterStreamer', () => {
|
|
@@ -29,8 +30,8 @@ describe('BacktesterStreamer', () => {
|
|
|
29
30
|
const trade = store.snapshot.trade.get(instrument.id);
|
|
30
31
|
|
|
31
32
|
expect(trade.timestamp).toEqual(8);
|
|
32
|
-
expect(trade.rate).toEqual(8);
|
|
33
|
-
expect(trade.quantity).toEqual(8);
|
|
33
|
+
expect(trade.rate).toEqual(d(8));
|
|
34
|
+
expect(trade.quantity).toEqual(d(8));
|
|
34
35
|
expect(store.snapshot.timestamp).toEqual(8);
|
|
35
36
|
|
|
36
37
|
done();
|
|
@@ -39,15 +40,15 @@ describe('BacktesterStreamer', () => {
|
|
|
39
40
|
);
|
|
40
41
|
|
|
41
42
|
feed
|
|
42
|
-
.save(
|
|
43
|
-
new
|
|
44
|
-
new
|
|
45
|
-
new
|
|
46
|
-
new
|
|
47
|
-
new
|
|
48
|
-
new
|
|
49
|
-
new
|
|
50
|
-
new
|
|
43
|
+
.save([
|
|
44
|
+
new TradePatchEvent(instrument, d(1), d(1), 1),
|
|
45
|
+
new TradePatchEvent(instrument, d(2), d(2), 2),
|
|
46
|
+
new TradePatchEvent(instrument, d(3), d(3), 3),
|
|
47
|
+
new TradePatchEvent(instrument, d(4), d(4), 4),
|
|
48
|
+
new TradePatchEvent(instrument, d(5), d(5), 5),
|
|
49
|
+
new TradePatchEvent(instrument, d(6), d(6), 6),
|
|
50
|
+
new TradePatchEvent(instrument, d(7), d(7), 7),
|
|
51
|
+
new TradePatchEvent(instrument, d(8), d(8), 8)
|
|
51
52
|
])
|
|
52
53
|
.then(() => {
|
|
53
54
|
streamer.subscribe(instrument);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { InstrumentSelector } from '../../domain';
|
|
2
2
|
import { timestamp } from '../../shared';
|
|
3
3
|
import { Feed } from '../../storage';
|
|
4
|
-
import {
|
|
4
|
+
import { Store } from '../../store';
|
|
5
5
|
import { AdapterTimeProvider } from '../adapter';
|
|
6
6
|
import { BacktesterCursor } from './backtester-cursor';
|
|
7
7
|
|
|
@@ -118,37 +118,20 @@ export class BacktesterStreamer {
|
|
|
118
118
|
return false;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
const
|
|
122
|
-
const instrument = cursor.instrument;
|
|
123
|
-
const volume = candle.volume ?? 0;
|
|
121
|
+
const event = cursor.peek();
|
|
124
122
|
|
|
125
|
-
this.timestamp =
|
|
123
|
+
this.timestamp = event.timestamp;
|
|
126
124
|
this.sequence++;
|
|
127
125
|
|
|
128
|
-
this.dispatch(
|
|
129
|
-
this.dispatch(candle.timestamp, instrument, candle.high, volume);
|
|
130
|
-
this.dispatch(candle.timestamp, instrument, candle.low, volume);
|
|
131
|
-
this.dispatch(candle.timestamp, instrument, candle.close, volume);
|
|
126
|
+
this.store.dispatch(event);
|
|
132
127
|
|
|
133
|
-
if (cursor.dequeue().timestamp !=
|
|
128
|
+
if (cursor.dequeue().timestamp != event.timestamp) {
|
|
134
129
|
throw new Error('invalid event to consume');
|
|
135
130
|
}
|
|
136
131
|
|
|
137
132
|
return true;
|
|
138
133
|
}
|
|
139
134
|
|
|
140
|
-
private dispatch(
|
|
141
|
-
timestamp: number,
|
|
142
|
-
instrument: InstrumentSelector,
|
|
143
|
-
rate: number,
|
|
144
|
-
volume: number
|
|
145
|
-
) {
|
|
146
|
-
this.store.dispatch(
|
|
147
|
-
new TradePatchEvent(instrument, rate, volume, timestamp),
|
|
148
|
-
new OrderbookPatchEvent(instrument, rate, volume, rate, volume, timestamp)
|
|
149
|
-
);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
135
|
private async current(from: timestamp, to: timestamp): Promise<BacktesterCursor> {
|
|
153
136
|
for (const cursor of Object.values(this.cursor)) {
|
|
154
137
|
if (cursor.size == 0 && !cursor.completed) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Asset, commissionPercentOf, Instrument, Order } from '../../../domain';
|
|
2
|
-
import { now } from '../../../shared';
|
|
2
|
+
import { d, now } from '../../../shared';
|
|
3
3
|
import {
|
|
4
4
|
BalancePatchEvent,
|
|
5
5
|
InstrumentPatchEvent,
|
|
@@ -17,57 +17,57 @@ describe('PaperEngine', () => {
|
|
|
17
17
|
);
|
|
18
18
|
|
|
19
19
|
const commission = commissionPercentOf({
|
|
20
|
-
maker: 0.1,
|
|
21
|
-
taker: 0.1
|
|
20
|
+
maker: d(0.1),
|
|
21
|
+
taker: d(0.1)
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
test('should open a new buy market order', () => {
|
|
25
25
|
const store = new Store();
|
|
26
26
|
const engine = new PaperEngine(store);
|
|
27
|
-
const order = Order.market(instrument, 1.0);
|
|
27
|
+
const order = Order.market(instrument, d(1.0));
|
|
28
28
|
|
|
29
29
|
store.dispatch(
|
|
30
30
|
new InstrumentPatchEvent(now(), instrument.base, instrument.quote, commission, ''),
|
|
31
|
-
new BalancePatchEvent(instrument.base, 1,
|
|
32
|
-
new BalancePatchEvent(instrument.quote, 1000,
|
|
31
|
+
new BalancePatchEvent(instrument.base, d(1), d.Zero, now()),
|
|
32
|
+
new BalancePatchEvent(instrument.quote, d(1000), d.Zero, now())
|
|
33
33
|
);
|
|
34
34
|
|
|
35
35
|
engine.open(order);
|
|
36
36
|
|
|
37
37
|
expect(store.snapshot.order.asReadonlyArray().length).toEqual(1);
|
|
38
38
|
expect(store.snapshot.order.get(instrument.id).get(order.id)).toEqual(order);
|
|
39
|
-
expect(store.snapshot.balance.get(instrument.quote.id).free).toEqual(
|
|
40
|
-
expect(store.snapshot.balance.get(instrument.quote.id).locked).toEqual(1000);
|
|
39
|
+
expect(store.snapshot.balance.get(instrument.quote.id).free).toEqual(d.Zero);
|
|
40
|
+
expect(store.snapshot.balance.get(instrument.quote.id).locked).toEqual(d(1000));
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
test('should open a new sell market order', () => {
|
|
44
44
|
const store = new Store();
|
|
45
45
|
const engine = new PaperEngine(store);
|
|
46
|
-
const order = Order.market(instrument, -0.6);
|
|
46
|
+
const order = Order.market(instrument, d(-0.6));
|
|
47
47
|
|
|
48
48
|
store.dispatch(
|
|
49
49
|
new InstrumentPatchEvent(now(), instrument.base, instrument.quote, commission, ''),
|
|
50
|
-
new BalancePatchEvent(instrument.base, 1,
|
|
51
|
-
new BalancePatchEvent(instrument.quote, 1000,
|
|
50
|
+
new BalancePatchEvent(instrument.base, d(1), d.Zero, now()),
|
|
51
|
+
new BalancePatchEvent(instrument.quote, d(1000), d.Zero, now())
|
|
52
52
|
);
|
|
53
53
|
|
|
54
54
|
engine.open(order);
|
|
55
55
|
|
|
56
56
|
expect(store.snapshot.order.asReadonlyArray().length).toEqual(1);
|
|
57
57
|
expect(store.snapshot.order.get(instrument.id).get(order.id)).toEqual(order);
|
|
58
|
-
expect(store.snapshot.balance.get(instrument.base.id).free).toEqual(0.4);
|
|
59
|
-
expect(store.snapshot.balance.get(instrument.base.id).locked).toEqual(0.6);
|
|
58
|
+
expect(store.snapshot.balance.get(instrument.base.id).free).toEqual(d(0.4));
|
|
59
|
+
expect(store.snapshot.balance.get(instrument.base.id).locked).toEqual(d(0.6));
|
|
60
60
|
});
|
|
61
61
|
|
|
62
62
|
test('should open and fill a new sell limit order', () => {
|
|
63
63
|
const store = new Store();
|
|
64
64
|
const engine = new PaperEngine(store);
|
|
65
|
-
const order = Order.limit(instrument, -0.6, 100);
|
|
65
|
+
const order = Order.limit(instrument, d(-0.6), d(100));
|
|
66
66
|
|
|
67
67
|
store.dispatch(
|
|
68
68
|
new InstrumentPatchEvent(now(), instrument.base, instrument.quote, commission, ''),
|
|
69
|
-
new BalancePatchEvent(instrument.base, 1,
|
|
70
|
-
new BalancePatchEvent(instrument.quote, 1000,
|
|
69
|
+
new BalancePatchEvent(instrument.base, d(1), d.Zero, now()),
|
|
70
|
+
new BalancePatchEvent(instrument.quote, d(1000), d.Zero, now()),
|
|
71
71
|
new InstrumentSubscriptionEvent(now(), instrument, true)
|
|
72
72
|
);
|
|
73
73
|
|
|
@@ -77,16 +77,23 @@ describe('PaperEngine', () => {
|
|
|
77
77
|
expect(store.snapshot.order.get(instrument.id).get(order.id).state).toEqual(
|
|
78
78
|
'PENDING'
|
|
79
79
|
);
|
|
80
|
-
expect(store.snapshot.balance.get(instrument.base.id).free).toEqual(0.4);
|
|
81
|
-
expect(store.snapshot.balance.get(instrument.base.id).locked).toEqual(0.6);
|
|
80
|
+
expect(store.snapshot.balance.get(instrument.base.id).free).toEqual(d(0.4));
|
|
81
|
+
expect(store.snapshot.balance.get(instrument.base.id).locked).toEqual(d(0.6));
|
|
82
82
|
|
|
83
|
-
store.dispatch(
|
|
83
|
+
store.dispatch(
|
|
84
|
+
new OrderbookPatchEvent(
|
|
85
|
+
instrument,
|
|
86
|
+
{ rate: d(102), quantity: d(1), next: undefined },
|
|
87
|
+
{ rate: d(101), quantity: d(1), next: undefined },
|
|
88
|
+
now()
|
|
89
|
+
)
|
|
90
|
+
);
|
|
84
91
|
|
|
85
92
|
expect(store.snapshot.order.asReadonlyArray().length).toEqual(1);
|
|
86
93
|
expect(store.snapshot.order.get(instrument.id).get(order.id).state).toEqual('FILLED');
|
|
87
|
-
expect(store.snapshot.balance.get(instrument.base.id).free).toEqual(0.4);
|
|
88
|
-
expect(store.snapshot.balance.get(instrument.base.id).locked).toEqual(
|
|
89
|
-
expect(store.snapshot.balance.get(instrument.quote.id).free).toEqual(1060.53);
|
|
90
|
-
expect(store.snapshot.balance.get(instrument.quote.id).locked).toEqual(
|
|
94
|
+
expect(store.snapshot.balance.get(instrument.base.id).free).toEqual(d(0.4));
|
|
95
|
+
expect(store.snapshot.balance.get(instrument.base.id).locked).toEqual(d.Zero);
|
|
96
|
+
expect(store.snapshot.balance.get(instrument.quote.id).free).toEqual(d(1060.53));
|
|
97
|
+
expect(store.snapshot.balance.get(instrument.quote.id).locked).toEqual(d.Zero);
|
|
91
98
|
});
|
|
92
99
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { tap } from 'rxjs';
|
|
2
2
|
|
|
3
3
|
import { Order, Orderbook, Trade } from '../../../domain';
|
|
4
|
+
import { d, decimal } from '../../../shared';
|
|
4
5
|
import {
|
|
5
6
|
BalanceLockOrderEvent,
|
|
6
7
|
BalanceTransactEvent,
|
|
@@ -68,16 +69,16 @@ export class PaperEngine {
|
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
if (it.type == 'LIMIT') {
|
|
71
|
-
if (it.quantity
|
|
72
|
-
this.completeOrder(it, orderbook.
|
|
73
|
-
} else if (it.quantity
|
|
74
|
-
this.completeOrder(it, orderbook.
|
|
72
|
+
if (it.quantity.greaterThan(0) && it.rate.greaterThan(orderbook.asks.rate)) {
|
|
73
|
+
this.completeOrder(it, orderbook.asks.rate);
|
|
74
|
+
} else if (it.quantity.lessThan(0) && it.rate.lessThan(orderbook.bids.rate)) {
|
|
75
|
+
this.completeOrder(it, orderbook.bids.rate);
|
|
75
76
|
}
|
|
76
77
|
} else if (it.type == 'MARKET') {
|
|
77
|
-
if (it.quantity
|
|
78
|
-
this.completeOrder(it, orderbook.
|
|
79
|
-
} else if (it.quantity
|
|
80
|
-
this.completeOrder(it, orderbook.
|
|
78
|
+
if (it.quantity.greaterThan(0)) {
|
|
79
|
+
this.completeOrder(it, orderbook.asks.rate);
|
|
80
|
+
} else if (it.quantity.lessThan(0)) {
|
|
81
|
+
this.completeOrder(it, orderbook.bids.rate);
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
84
|
});
|
|
@@ -93,9 +94,9 @@ export class PaperEngine {
|
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
if (it.type == 'LIMIT') {
|
|
96
|
-
if (it.quantity
|
|
97
|
+
if (it.quantity.greaterThan(0) && it.rate.greaterThan(trade.rate)) {
|
|
97
98
|
this.completeOrder(it, trade.rate);
|
|
98
|
-
} else if (it.quantity
|
|
99
|
+
} else if (it.quantity.lessThan(0) && it.rate.lessThan(trade.rate)) {
|
|
99
100
|
this.completeOrder(it, trade.rate);
|
|
100
101
|
}
|
|
101
102
|
} else if (it.type == 'MARKET') {
|
|
@@ -104,24 +105,30 @@ export class PaperEngine {
|
|
|
104
105
|
});
|
|
105
106
|
}
|
|
106
107
|
|
|
107
|
-
private completeOrder(order: Order, averageExecutionRate:
|
|
108
|
+
private completeOrder(order: Order, averageExecutionRate: decimal) {
|
|
108
109
|
const { timestamp } = this.store.snapshot;
|
|
109
110
|
|
|
110
111
|
const instrument = this.store.snapshot.universe.instrument.get(order.instrument.id);
|
|
111
112
|
const transacted = {
|
|
112
|
-
base:
|
|
113
|
-
quote:
|
|
113
|
+
base: d.Zero,
|
|
114
|
+
quote: d.Zero
|
|
114
115
|
};
|
|
115
116
|
|
|
116
|
-
const qty =
|
|
117
|
+
const qty = order.quantity.abs();
|
|
117
118
|
|
|
118
|
-
if (order.quantity
|
|
119
|
-
transacted.base
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
transacted.
|
|
123
|
-
|
|
124
|
-
|
|
119
|
+
if (order.quantity.greaterThan(0)) {
|
|
120
|
+
transacted.base = transacted.base.plus(
|
|
121
|
+
instrument.base.floor(instrument.commission.applyMakerFee(qty))
|
|
122
|
+
);
|
|
123
|
+
transacted.quote = transacted.quote.minus(
|
|
124
|
+
instrument.quote.floor(averageExecutionRate.mul(qty))
|
|
125
|
+
);
|
|
126
|
+
} else if (order.quantity.lessThan(0)) {
|
|
127
|
+
transacted.base = transacted.base.minus(instrument.base.floor(qty));
|
|
128
|
+
transacted.quote = transacted.quote.plus(
|
|
129
|
+
instrument.quote.floor(
|
|
130
|
+
instrument.commission.applyMakerFee(averageExecutionRate.mul(qty))
|
|
131
|
+
)
|
|
125
132
|
);
|
|
126
133
|
}
|
|
127
134
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import { d, timestamp } from '../../shared';
|
|
1
2
|
import { InstrumentPatchEvent, Store } from '../../store';
|
|
2
3
|
import {
|
|
3
4
|
Adapter,
|
|
4
5
|
AdapterTimeProvider,
|
|
5
6
|
DefaultTimeProvider,
|
|
6
|
-
|
|
7
|
-
HistoryQuery
|
|
7
|
+
FeedAsyncCallback
|
|
8
8
|
} from '../adapter';
|
|
9
9
|
import {
|
|
10
10
|
Asset,
|
|
@@ -33,10 +33,19 @@ class DefaultAdapter extends Adapter {
|
|
|
33
33
|
cancel(order: Order): Promise<void> {
|
|
34
34
|
throw new Error('Method not implemented.');
|
|
35
35
|
}
|
|
36
|
-
history(
|
|
36
|
+
history(
|
|
37
|
+
instrument: InstrumentSelector,
|
|
38
|
+
timeframe: number,
|
|
39
|
+
length: number
|
|
40
|
+
): Promise<Candle[]> {
|
|
37
41
|
throw new Error('Method not implemented.');
|
|
38
42
|
}
|
|
39
|
-
feed(
|
|
43
|
+
feed(
|
|
44
|
+
instrument: InstrumentSelector,
|
|
45
|
+
from: timestamp,
|
|
46
|
+
to: timestamp,
|
|
47
|
+
callback: FeedAsyncCallback
|
|
48
|
+
): Promise<void> {
|
|
40
49
|
throw new Error('Method not implemented.');
|
|
41
50
|
}
|
|
42
51
|
name = 'default';
|
|
@@ -55,7 +64,7 @@ class DefaultAdapter extends Adapter {
|
|
|
55
64
|
this.timestamp(),
|
|
56
65
|
new Asset('a', this.name, 8),
|
|
57
66
|
new Asset('b', this.name, 4),
|
|
58
|
-
new Commission(0.1, 0.1),
|
|
67
|
+
new Commission(d(0.1), d(0.1)),
|
|
59
68
|
'a-b'
|
|
60
69
|
)
|
|
61
70
|
);
|
|
@@ -96,7 +105,7 @@ describe('PaperAdapter', () => {
|
|
|
96
105
|
await sut.awake();
|
|
97
106
|
await sut.account();
|
|
98
107
|
|
|
99
|
-
const order = Order.market(instrumentOf('default:a-b'), 1.0);
|
|
108
|
+
const order = Order.market(instrumentOf('default:a-b'), d(1.0));
|
|
100
109
|
|
|
101
110
|
await sut.open(order);
|
|
102
111
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { assetOf, Candle, InstrumentSelector, Order } from '../../domain';
|
|
2
|
+
import { d, timestamp } from '../../shared';
|
|
2
3
|
import { BalancePatchEvent, Store } from '../../store';
|
|
3
4
|
import { Adapter } from '..';
|
|
4
|
-
import { AdapterFactory,
|
|
5
|
+
import { AdapterFactory, FeedAsyncCallback } from '../adapter';
|
|
5
6
|
import { PaperEngine } from './engine/paper-engine';
|
|
6
7
|
|
|
7
8
|
export interface PaperOptions {
|
|
@@ -56,15 +57,17 @@ export class PaperAdapter extends Adapter {
|
|
|
56
57
|
continue;
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
const free = this.options.balance[balance];
|
|
60
|
+
const free = d(this.options.balance[balance]);
|
|
60
61
|
|
|
61
62
|
subscribed = subscribed.filter(it => it.id != asset.id);
|
|
62
63
|
|
|
63
|
-
this.store.dispatch(new BalancePatchEvent(asset, free,
|
|
64
|
+
this.store.dispatch(new BalancePatchEvent(asset, free, d.Zero, this.timestamp()));
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
for (const missingAsset of subscribed) {
|
|
67
|
-
this.store.dispatch(
|
|
68
|
+
this.store.dispatch(
|
|
69
|
+
new BalancePatchEvent(missingAsset, d.Zero, d.Zero, this.timestamp())
|
|
70
|
+
);
|
|
68
71
|
}
|
|
69
72
|
}
|
|
70
73
|
|
|
@@ -76,12 +79,21 @@ export class PaperAdapter extends Adapter {
|
|
|
76
79
|
this.engine.cancel(order);
|
|
77
80
|
}
|
|
78
81
|
|
|
79
|
-
history(
|
|
80
|
-
|
|
82
|
+
history(
|
|
83
|
+
instrument: InstrumentSelector,
|
|
84
|
+
timeframe: number,
|
|
85
|
+
length: number
|
|
86
|
+
): Promise<Candle[]> {
|
|
87
|
+
return this.decoratedAdapter.history(instrument, timeframe, length);
|
|
81
88
|
}
|
|
82
89
|
|
|
83
|
-
feed(
|
|
84
|
-
|
|
90
|
+
feed(
|
|
91
|
+
instrument: InstrumentSelector,
|
|
92
|
+
from: timestamp,
|
|
93
|
+
to: timestamp,
|
|
94
|
+
callback: FeedAsyncCallback
|
|
95
|
+
): Promise<void> {
|
|
96
|
+
return this.decoratedAdapter.feed(instrument, from, to, callback);
|
|
85
97
|
}
|
|
86
98
|
|
|
87
99
|
createPaperEngine(adapter: PaperAdapter): PaperEngine {
|