@quantform/core 0.5.14 → 0.5.15
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 +16 -18
- package/dist/adapter/adapter-aggregate.js.map +1 -1
- package/dist/adapter/adapter.d.ts +20 -21
- package/dist/adapter/adapter.js +8 -43
- package/dist/adapter/adapter.js.map +1 -1
- package/dist/adapter/backtester/backtester-adapter.d.ts +9 -7
- package/dist/adapter/backtester/backtester-adapter.js +13 -12
- package/dist/adapter/backtester/backtester-adapter.js.map +1 -1
- package/dist/{tests → adapter/backtester}/backtester-adapter.spec.d.ts +0 -0
- package/dist/adapter/backtester/backtester-adapter.spec.js +82 -0
- package/dist/adapter/backtester/backtester-adapter.spec.js.map +1 -0
- package/dist/adapter/backtester/backtester-cursor.d.ts +3 -4
- package/dist/adapter/backtester/backtester-cursor.js +2 -1
- package/dist/adapter/backtester/backtester-cursor.js.map +1 -1
- package/dist/adapter/backtester/backtester-cursor.spec.js +17 -18
- package/dist/adapter/backtester/backtester-cursor.spec.js.map +1 -1
- package/dist/adapter/backtester/backtester-streamer.d.ts +4 -1
- package/dist/adapter/backtester/backtester-streamer.js +39 -18
- package/dist/adapter/backtester/backtester-streamer.js.map +1 -1
- package/dist/adapter/backtester/backtester-streamer.spec.js +13 -13
- package/dist/adapter/backtester/backtester-streamer.spec.js.map +1 -1
- package/dist/adapter/error.d.ts +2 -0
- package/dist/adapter/error.js +12 -0
- package/dist/adapter/error.js.map +1 -0
- package/dist/adapter/paper/engine/paper-engine.d.ts +11 -0
- package/dist/adapter/paper/engine/paper-engine.js +103 -0
- package/dist/adapter/paper/engine/paper-engine.js.map +1 -0
- package/dist/adapter/paper/{simulator/paper-spot-simulator.spec.d.ts → engine/paper-engine.spec.d.ts} +0 -0
- package/dist/adapter/paper/engine/paper-engine.spec.js +54 -0
- package/dist/adapter/paper/engine/paper-engine.spec.js.map +1 -0
- package/dist/adapter/paper/index.d.ts +1 -2
- package/dist/adapter/paper/index.js +1 -2
- package/dist/adapter/paper/index.js.map +1 -1
- package/dist/adapter/paper/paper-adapter.d.ts +7 -7
- package/dist/adapter/paper/paper-adapter.js +20 -18
- package/dist/adapter/paper/paper-adapter.js.map +1 -1
- package/dist/adapter/paper/paper-adapter.spec.js +35 -17
- package/dist/adapter/paper/paper-adapter.spec.js.map +1 -1
- package/dist/bootstrap.js +11 -10
- package/dist/bootstrap.js.map +1 -1
- package/dist/cli/pull.js +3 -1
- package/dist/cli/pull.js.map +1 -1
- package/dist/cli/test.js +5 -1
- package/dist/cli/test.js.map +1 -1
- package/dist/domain/asset.d.ts +6 -5
- package/dist/domain/asset.js +22 -16
- package/dist/domain/asset.js.map +1 -1
- package/dist/domain/asset.spec.js +32 -32
- package/dist/domain/asset.spec.js.map +1 -1
- package/dist/domain/balance.d.ts +7 -7
- package/dist/domain/balance.js +26 -21
- package/dist/domain/balance.js.map +1 -1
- package/dist/domain/balance.operator.d.ts +6 -0
- package/dist/domain/balance.operator.js +10 -0
- package/dist/domain/balance.operator.js.map +1 -0
- package/dist/{shared/policy.spec.d.ts → domain/balance.operator.spec.d.ts} +0 -0
- package/dist/domain/balance.operator.spec.js +23 -0
- package/dist/domain/balance.operator.spec.js.map +1 -0
- package/dist/domain/balance.spec.js +67 -7
- package/dist/domain/balance.spec.js.map +1 -1
- package/dist/domain/candle.d.ts +2 -17
- package/dist/domain/candle.js +3 -70
- package/dist/domain/candle.js.map +1 -1
- package/dist/domain/candle.operator.d.ts +9 -0
- package/dist/domain/candle.operator.js +64 -0
- package/dist/domain/candle.operator.js.map +1 -0
- package/dist/{shared/topic.spec.d.ts → domain/candle.operator.spec.d.ts} +0 -0
- package/dist/domain/candle.operator.spec.js +111 -0
- package/dist/domain/candle.operator.spec.js.map +1 -0
- package/dist/domain/candle.spec.js +11 -53
- package/dist/domain/candle.spec.js.map +1 -1
- package/dist/domain/commission.d.ts +4 -1
- package/dist/domain/commission.js +2 -2
- package/dist/domain/commission.js.map +1 -1
- package/dist/{store/event/store-balance.event.spec.d.ts → domain/commission.spec.d.ts} +0 -0
- package/dist/domain/commission.spec.js +30 -0
- package/dist/domain/commission.spec.js.map +1 -0
- package/dist/domain/component.d.ts +1 -0
- package/dist/domain/error.d.ts +5 -0
- package/dist/domain/error.js +24 -0
- package/dist/domain/error.js.map +1 -0
- package/dist/domain/index.d.ts +8 -1
- package/dist/domain/index.js +8 -1
- package/dist/domain/index.js.map +1 -1
- package/dist/domain/instrument.d.ts +3 -2
- package/dist/domain/instrument.js +17 -9
- package/dist/domain/instrument.js.map +1 -1
- package/dist/domain/instrument.operator.d.ts +6 -0
- package/dist/domain/instrument.operator.js +14 -0
- package/dist/domain/instrument.operator.js.map +1 -0
- package/dist/{store/event/store-candle.event.spec.d.ts → domain/instrument.operator.spec.d.ts} +0 -0
- package/dist/domain/instrument.operator.spec.js +24 -0
- package/dist/domain/instrument.operator.spec.js.map +1 -0
- package/dist/domain/instrument.spec.js +22 -30
- package/dist/domain/instrument.spec.js.map +1 -1
- package/dist/domain/order.d.ts +12 -14
- package/dist/domain/order.js +37 -26
- package/dist/domain/order.js.map +1 -1
- package/dist/domain/order.operator.d.ts +7 -0
- package/dist/domain/order.operator.js +14 -0
- package/dist/domain/order.operator.js.map +1 -0
- package/dist/{store/event/store-instrument.event.spec.d.ts → domain/order.operator.spec.d.ts} +0 -0
- package/dist/domain/order.operator.spec.js +64 -0
- package/dist/domain/order.operator.spec.js.map +1 -0
- package/dist/{store/event/store-order.event.spec.d.ts → domain/order.spec.d.ts} +0 -0
- package/dist/domain/order.spec.js +33 -0
- package/dist/domain/order.spec.js.map +1 -0
- 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/orderbook.operator.d.ts +6 -0
- package/dist/domain/orderbook.operator.js +10 -0
- package/dist/domain/orderbook.operator.js.map +1 -0
- package/dist/{store/event/store-trade.event.spec.d.ts → domain/orderbook.operator.spec.d.ts} +0 -0
- package/dist/domain/orderbook.operator.spec.js +22 -0
- package/dist/domain/orderbook.operator.spec.js.map +1 -0
- package/dist/domain/orderbook.spec.d.ts +1 -0
- package/dist/domain/orderbook.spec.js +13 -0
- package/dist/domain/orderbook.spec.js.map +1 -0
- package/dist/domain/position.d.ts +6 -11
- package/dist/domain/position.js +9 -31
- package/dist/domain/position.js.map +1 -1
- package/dist/domain/position.operator.d.ts +10 -0
- package/dist/domain/position.operator.js +38 -0
- package/dist/domain/position.operator.js.map +1 -0
- package/dist/domain/position.operator.spec.d.ts +1 -0
- package/dist/domain/position.operator.spec.js +48 -0
- package/dist/domain/position.operator.spec.js.map +1 -0
- package/dist/domain/position.spec.js +21 -17
- package/dist/domain/position.spec.js.map +1 -1
- package/dist/domain/session.d.ts +15 -18
- package/dist/domain/session.js +21 -31
- 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 +1 -0
- package/dist/domain/trade.js +1 -0
- package/dist/domain/trade.js.map +1 -1
- package/dist/domain/trade.operator.d.ts +6 -0
- package/dist/domain/trade.operator.js +10 -0
- package/dist/domain/trade.operator.js.map +1 -0
- package/dist/domain/trade.operator.spec.d.ts +1 -0
- package/dist/domain/trade.operator.spec.js +24 -0
- package/dist/domain/trade.operator.spec.js.map +1 -0
- package/dist/domain/trade.spec.d.ts +1 -0
- package/dist/domain/trade.spec.js +13 -0
- package/dist/domain/trade.spec.js.map +1 -0
- package/dist/indicator/cross.spec.js +2 -2
- package/dist/indicator/cross.spec.js.map +1 -1
- package/dist/indicator/ema.spec.js +1 -1
- package/dist/indicator/ema.spec.js.map +1 -1
- package/dist/indicator/sma.spec.js +1 -1
- package/dist/indicator/sma.spec.js.map +1 -1
- package/dist/indicator/tma.spec.js +1 -1
- package/dist/indicator/tma.spec.js.map +1 -1
- package/dist/indicator/trailing.spec.js +2 -2
- package/dist/indicator/trailing.spec.js.map +1 -1
- package/dist/indicator/truerange.spec.js +1 -1
- package/dist/indicator/truerange.spec.js.map +1 -1
- package/dist/indicator/wma.spec.js +1 -1
- package/dist/indicator/wma.spec.js.map +1 -1
- package/dist/shared/collections.d.ts +10 -0
- package/dist/shared/collections.js +33 -0
- package/dist/shared/collections.js.map +1 -0
- package/dist/shared/datetime.d.ts +0 -1
- package/dist/shared/datetime.js +1 -12
- package/dist/shared/datetime.js.map +1 -1
- package/dist/shared/decimals.d.ts +1 -1
- package/dist/shared/decimals.js +4 -5
- package/dist/shared/decimals.js.map +1 -1
- package/dist/shared/decimals.spec.js +2 -1
- package/dist/shared/decimals.spec.js.map +1 -1
- package/dist/shared/index.d.ts +1 -1
- package/dist/shared/index.js +1 -1
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/io.js.map +1 -1
- package/dist/shared/policy.d.ts +0 -1
- package/dist/shared/policy.js +1 -11
- package/dist/shared/policy.js.map +1 -1
- package/dist/storage/cache.js +1 -1
- package/dist/storage/cache.js.map +1 -1
- package/dist/storage/cache.spec.d.ts +1 -0
- package/dist/storage/cache.spec.js +18 -0
- package/dist/storage/cache.spec.js.map +1 -0
- package/dist/storage/feed.d.ts +3 -4
- package/dist/storage/feed.js +16 -6
- package/dist/storage/feed.js.map +1 -1
- package/dist/storage/storage.d.ts +2 -7
- package/dist/storage/storage.js +6 -11
- package/dist/storage/storage.js.map +1 -1
- package/dist/store/index.d.ts +8 -2
- package/dist/store/index.js +8 -2
- package/dist/store/index.js.map +1 -1
- package/dist/store/store-balance.event.d.ts +33 -0
- package/dist/store/store-balance.event.js +90 -0
- package/dist/store/store-balance.event.js.map +1 -0
- package/dist/store/store-balance.event.spec.d.ts +1 -0
- package/dist/store/{event/store-balance.event.spec.js → store-balance.event.spec.js} +7 -7
- package/dist/store/store-balance.event.spec.js.map +1 -0
- package/dist/store/{event/store-instrument.event.d.ts → store-instrument.event.d.ts} +5 -8
- package/dist/store/store-instrument.event.js +52 -0
- package/dist/store/store-instrument.event.js.map +1 -0
- package/dist/store/store-instrument.event.spec.d.ts +1 -0
- package/dist/store/store-instrument.event.spec.js +22 -0
- package/dist/store/store-instrument.event.spec.js.map +1 -0
- package/dist/store/store-order.event.d.ts +59 -0
- package/dist/store/store-order.event.js +181 -0
- package/dist/store/store-order.event.js.map +1 -0
- package/dist/store/store-order.event.spec.d.ts +1 -0
- package/dist/store/{event/store-order.event.spec.js → store-order.event.spec.js} +8 -8
- package/dist/store/store-order.event.spec.js.map +1 -0
- package/dist/store/{event/store-orderbook.event.d.ts → store-orderbook.event.d.ts} +4 -5
- package/dist/store/store-orderbook.event.js +42 -0
- package/dist/store/store-orderbook.event.js.map +1 -0
- package/dist/store/{event/store-position.event.d.ts → store-position.event.d.ts} +5 -7
- package/dist/store/store-position.event.js +77 -0
- package/dist/store/store-position.event.js.map +1 -0
- package/dist/store/store-state.d.ts +27 -0
- package/dist/store/store-state.js +29 -0
- package/dist/store/store-state.js.map +1 -0
- package/dist/store/{event/store-trade.event.d.ts → store-trade.event.d.ts} +4 -5
- package/dist/store/store-trade.event.js +25 -0
- package/dist/store/store-trade.event.js.map +1 -0
- package/dist/store/store-trade.event.spec.d.ts +1 -0
- package/dist/store/{event/store-trade.event.spec.js → store-trade.event.spec.js} +13 -13
- package/dist/store/store-trade.event.spec.js.map +1 -0
- package/dist/store/store.d.ts +4 -25
- package/dist/store/store.event.d.ts +6 -0
- package/dist/store/{event/store.event.js → store.event.js} +0 -0
- package/dist/store/store.event.js.map +1 -0
- package/dist/store/store.js +7 -195
- package/dist/store/store.js.map +1 -1
- package/dist/store/store.spec.d.ts +1 -0
- package/dist/store/store.spec.js +119 -0
- package/dist/store/store.spec.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/{jestconfig.unit.json → jestconfig.json} +1 -2
- package/package.json +2 -6
- package/src/adapter/adapter-aggregate.ts +27 -35
- package/src/adapter/adapter.ts +25 -54
- package/src/adapter/backtester/backtester-adapter.spec.ts +124 -0
- package/src/adapter/backtester/backtester-adapter.ts +28 -17
- package/src/adapter/backtester/backtester-cursor.spec.ts +18 -19
- package/src/adapter/backtester/backtester-cursor.ts +7 -7
- package/src/adapter/backtester/backtester-streamer.spec.ts +19 -19
- package/src/adapter/backtester/backtester-streamer.ts +50 -20
- package/src/adapter/error.ts +9 -0
- package/src/adapter/paper/engine/paper-engine.spec.ts +92 -0
- package/src/adapter/paper/engine/paper-engine.ts +135 -0
- package/src/adapter/paper/index.ts +1 -2
- package/src/adapter/paper/paper-adapter.spec.ts +55 -19
- package/src/adapter/paper/paper-adapter.ts +27 -24
- package/src/bootstrap.ts +26 -19
- package/src/cli/pull.ts +5 -1
- package/src/cli/test.ts +5 -2
- package/src/domain/asset.spec.ts +33 -29
- package/src/domain/asset.ts +27 -21
- package/src/domain/balance.operator.spec.ts +25 -0
- package/src/domain/balance.operator.ts +15 -0
- package/src/domain/balance.spec.ts +95 -7
- package/src/domain/balance.ts +35 -29
- package/src/domain/candle.operator.spec.ts +125 -0
- package/src/domain/candle.operator.ts +106 -0
- package/src/domain/candle.spec.ts +12 -68
- package/src/domain/candle.ts +2 -114
- package/src/domain/commission.spec.ts +33 -0
- package/src/domain/commission.ts +2 -2
- package/src/domain/component.ts +1 -0
- package/src/domain/error.ts +25 -0
- package/src/domain/index.ts +8 -1
- package/src/domain/instrument.operator.spec.ts +28 -0
- package/src/domain/instrument.operator.ts +25 -0
- package/src/domain/instrument.spec.ts +22 -30
- package/src/domain/instrument.ts +20 -11
- package/src/domain/order.operator.spec.ts +81 -0
- package/src/domain/order.operator.ts +23 -0
- package/src/domain/order.spec.ts +43 -0
- package/src/domain/order.ts +43 -46
- package/src/domain/orderbook.operator.spec.ts +28 -0
- package/src/domain/orderbook.operator.ts +15 -0
- package/src/domain/orderbook.spec.ts +17 -0
- package/src/domain/orderbook.ts +4 -1
- package/src/domain/position.operator.spec.ts +58 -0
- package/src/domain/position.operator.ts +61 -0
- package/src/domain/position.spec.ts +28 -24
- package/src/domain/position.ts +16 -48
- package/src/domain/session.spec.ts +1 -1
- package/src/domain/session.ts +41 -131
- package/src/domain/trade.operator.spec.ts +31 -0
- package/src/domain/trade.operator.ts +15 -0
- package/src/domain/trade.spec.ts +17 -0
- package/src/domain/trade.ts +4 -1
- package/src/indicator/cross.spec.ts +2 -2
- package/src/indicator/ema.spec.ts +1 -1
- package/src/indicator/sma.spec.ts +1 -1
- package/src/indicator/tma.spec.ts +1 -1
- package/src/indicator/trailing.spec.ts +2 -2
- package/src/indicator/truerange.spec.ts +1 -1
- package/src/indicator/wma.spec.ts +1 -1
- package/src/shared/collections.ts +35 -0
- package/src/shared/datetime.ts +0 -12
- package/src/shared/decimals.spec.ts +2 -1
- package/src/shared/decimals.ts +6 -6
- package/src/shared/index.ts +1 -1
- package/src/shared/io.ts +0 -2
- package/src/shared/policy.ts +0 -13
- package/src/storage/cache.spec.ts +18 -0
- package/src/storage/cache.ts +1 -1
- package/src/storage/feed.ts +26 -16
- package/src/storage/storage.ts +9 -13
- package/src/store/index.ts +8 -2
- package/src/store/{event/store-balance.event.spec.ts → store-balance.event.spec.ts} +6 -6
- package/src/store/store-balance.event.ts +124 -0
- package/src/store/store-instrument.event.spec.ts +25 -0
- package/src/store/store-instrument.event.ts +72 -0
- package/src/store/store-order.event.spec.ts +28 -0
- package/src/store/store-order.event.ts +214 -0
- package/src/store/store-orderbook.event.ts +54 -0
- package/src/store/store-position.event.ts +102 -0
- package/src/store/store-state.ts +48 -0
- package/src/store/{event/store-trade.event.spec.ts → store-trade.event.spec.ts} +14 -14
- package/src/store/store-trade.event.ts +36 -0
- package/src/store/store.event.ts +8 -0
- package/src/store/store.spec.ts +180 -0
- package/src/store/store.ts +10 -208
- package/dist/adapter/paper/simulator/paper-margin-simulator.d.ts +0 -10
- package/dist/adapter/paper/simulator/paper-margin-simulator.js +0 -69
- package/dist/adapter/paper/simulator/paper-margin-simulator.js.map +0 -1
- package/dist/adapter/paper/simulator/paper-simulator.d.ts +0 -16
- package/dist/adapter/paper/simulator/paper-simulator.js +0 -93
- package/dist/adapter/paper/simulator/paper-simulator.js.map +0 -1
- package/dist/adapter/paper/simulator/paper-spot-simulator.d.ts +0 -13
- package/dist/adapter/paper/simulator/paper-spot-simulator.js +0 -81
- package/dist/adapter/paper/simulator/paper-spot-simulator.js.map +0 -1
- package/dist/adapter/paper/simulator/paper-spot-simulator.spec.js +0 -49
- package/dist/adapter/paper/simulator/paper-spot-simulator.spec.js.map +0 -1
- package/dist/domain/statement.d.ts +0 -4
- package/dist/domain/statement.js +0 -87
- package/dist/domain/statement.js.map +0 -1
- package/dist/shared/policy.spec.js +0 -22
- package/dist/shared/policy.spec.js.map +0 -1
- package/dist/shared/topic.d.ts +0 -14
- package/dist/shared/topic.js +0 -40
- package/dist/shared/topic.js.map +0 -1
- package/dist/shared/topic.spec.js +0 -43
- package/dist/shared/topic.spec.js.map +0 -1
- package/dist/store/event/index.d.ts +0 -8
- package/dist/store/event/index.js +0 -25
- package/dist/store/event/index.js.map +0 -1
- package/dist/store/event/store-balance.event.d.ts +0 -37
- package/dist/store/event/store-balance.event.js +0 -119
- package/dist/store/event/store-balance.event.js.map +0 -1
- package/dist/store/event/store-balance.event.spec.js.map +0 -1
- package/dist/store/event/store-candle.event.d.ts +0 -18
- package/dist/store/event/store-candle.event.js +0 -63
- package/dist/store/event/store-candle.event.js.map +0 -1
- package/dist/store/event/store-candle.event.spec.js +0 -23
- package/dist/store/event/store-candle.event.spec.js.map +0 -1
- package/dist/store/event/store-instrument.event.js +0 -78
- package/dist/store/event/store-instrument.event.js.map +0 -1
- package/dist/store/event/store-instrument.event.spec.js +0 -21
- package/dist/store/event/store-instrument.event.spec.js.map +0 -1
- package/dist/store/event/store-order.event.d.ts +0 -61
- package/dist/store/event/store-order.event.js +0 -205
- package/dist/store/event/store-order.event.js.map +0 -1
- package/dist/store/event/store-order.event.spec.js.map +0 -1
- package/dist/store/event/store-orderbook.event.js +0 -65
- package/dist/store/event/store-orderbook.event.js.map +0 -1
- package/dist/store/event/store-position.event.js +0 -97
- package/dist/store/event/store-position.event.js.map +0 -1
- package/dist/store/event/store-trade.event.js +0 -47
- package/dist/store/event/store-trade.event.js.map +0 -1
- package/dist/store/event/store-trade.event.spec.js.map +0 -1
- package/dist/store/event/store.event.d.ts +0 -5
- package/dist/store/event/store.event.js.map +0 -1
- package/dist/store/store.state.d.ts +0 -21
- package/dist/store/store.state.js +0 -21
- package/dist/store/store.state.js.map +0 -1
- package/dist/tests/backtester-adapter.spec.js +0 -61
- package/dist/tests/backtester-adapter.spec.js.map +0 -1
- package/dist/tests/session.spec.d.ts +0 -0
- package/dist/tests/session.spec.js +0 -1
- package/dist/tests/session.spec.js.map +0 -1
- package/jestconfig.integration.json +0 -12
- package/src/adapter/paper/simulator/paper-margin-simulator.ts +0 -108
- package/src/adapter/paper/simulator/paper-simulator.ts +0 -121
- package/src/adapter/paper/simulator/paper-spot-simulator.spec.ts +0 -87
- package/src/adapter/paper/simulator/paper-spot-simulator.ts +0 -134
- package/src/domain/statement.ts +0 -119
- package/src/shared/policy.spec.ts +0 -25
- package/src/shared/topic.spec.ts +0 -34
- package/src/shared/topic.ts +0 -43
- package/src/store/event/index.ts +0 -8
- package/src/store/event/store-balance.event.ts +0 -161
- package/src/store/event/store-candle.event.spec.ts +0 -30
- package/src/store/event/store-candle.event.ts +0 -71
- package/src/store/event/store-instrument.event.spec.ts +0 -25
- package/src/store/event/store-instrument.event.ts +0 -84
- package/src/store/event/store-order.event.spec.ts +0 -28
- package/src/store/event/store-order.event.ts +0 -218
- package/src/store/event/store-orderbook.event.ts +0 -70
- package/src/store/event/store-position.event.ts +0 -109
- package/src/store/event/store-trade.event.ts +0 -52
- package/src/store/event/store.event.ts +0 -6
- package/src/store/store.state.ts +0 -43
- package/src/tests/backtester-adapter.spec.ts +0 -88
- package/src/tests/session.spec.ts +0 -121
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { InstrumentSelector } from '../../domain';
|
|
2
2
|
import { timestamp } from '../../shared';
|
|
3
3
|
import { Feed } from '../../storage';
|
|
4
|
-
import { Store } from '../../store';
|
|
4
|
+
import { OrderbookPatchEvent, Store, TradePatchEvent } from '../../store';
|
|
5
|
+
import { AdapterTimeProvider } from '../adapter';
|
|
5
6
|
import { BacktesterCursor } from './backtester-cursor';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -45,14 +46,22 @@ export class BacktesterStreamer {
|
|
|
45
46
|
this.timestamp = period.from;
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
getTimeProvider(): AdapterTimeProvider {
|
|
50
|
+
const provider = {
|
|
51
|
+
timestamp: () => this.timestamp
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return provider;
|
|
55
|
+
}
|
|
56
|
+
|
|
48
57
|
subscribe(instrument: InstrumentSelector) {
|
|
49
|
-
if (instrument.
|
|
58
|
+
if (instrument.id in this.cursor) {
|
|
50
59
|
return;
|
|
51
60
|
}
|
|
52
61
|
|
|
53
62
|
const cursor = new BacktesterCursor(instrument, this.feed);
|
|
54
63
|
|
|
55
|
-
this.cursor[instrument.
|
|
64
|
+
this.cursor[instrument.id] = cursor;
|
|
56
65
|
}
|
|
57
66
|
|
|
58
67
|
/**
|
|
@@ -65,7 +74,7 @@ export class BacktesterStreamer {
|
|
|
65
74
|
/**
|
|
66
75
|
* Decreases stop counter and continues execution if no more stops requested.
|
|
67
76
|
*/
|
|
68
|
-
|
|
77
|
+
tryContinue() {
|
|
69
78
|
if (this.stopAcquire == 0) {
|
|
70
79
|
return;
|
|
71
80
|
}
|
|
@@ -82,21 +91,25 @@ export class BacktesterStreamer {
|
|
|
82
91
|
}
|
|
83
92
|
}
|
|
84
93
|
|
|
85
|
-
|
|
86
|
-
if (
|
|
87
|
-
if (this.
|
|
88
|
-
this.listener.onBacktestUpdated
|
|
94
|
+
const next = async () => {
|
|
95
|
+
if (await this.processNext()) {
|
|
96
|
+
if (this.sequence % this.sequenceUpdateBatch == 0) {
|
|
97
|
+
if (this.listener.onBacktestUpdated) {
|
|
98
|
+
this.listener.onBacktestUpdated(this);
|
|
99
|
+
}
|
|
89
100
|
}
|
|
90
|
-
}
|
|
91
101
|
|
|
92
|
-
|
|
93
|
-
|
|
102
|
+
if (this.stopAcquire === 0) {
|
|
103
|
+
setImmediate(next);
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
if (this.listener.onBacktestCompleted) {
|
|
107
|
+
this.listener.onBacktestCompleted(this);
|
|
108
|
+
}
|
|
94
109
|
}
|
|
95
|
-
}
|
|
110
|
+
};
|
|
96
111
|
|
|
97
|
-
|
|
98
|
-
this.listener.onBacktestCompleted(this);
|
|
99
|
-
}
|
|
112
|
+
next();
|
|
100
113
|
}
|
|
101
114
|
|
|
102
115
|
private async processNext(): Promise<boolean> {
|
|
@@ -105,20 +118,37 @@ export class BacktesterStreamer {
|
|
|
105
118
|
return false;
|
|
106
119
|
}
|
|
107
120
|
|
|
108
|
-
const
|
|
121
|
+
const candle = cursor.peek();
|
|
122
|
+
const instrument = cursor.instrument;
|
|
123
|
+
const volume = candle.volume ?? 0;
|
|
109
124
|
|
|
110
|
-
this.timestamp =
|
|
125
|
+
this.timestamp = candle.timestamp;
|
|
111
126
|
this.sequence++;
|
|
112
127
|
|
|
113
|
-
this.
|
|
128
|
+
this.dispatch(candle.timestamp, instrument, candle.open, volume);
|
|
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);
|
|
114
132
|
|
|
115
|
-
if (cursor.dequeue().timestamp !=
|
|
133
|
+
if (cursor.dequeue().timestamp != candle.timestamp) {
|
|
116
134
|
throw new Error('invalid event to consume');
|
|
117
135
|
}
|
|
118
136
|
|
|
119
137
|
return true;
|
|
120
138
|
}
|
|
121
139
|
|
|
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
|
+
|
|
122
152
|
private async current(from: timestamp, to: timestamp): Promise<BacktesterCursor> {
|
|
123
153
|
for (const cursor of Object.values(this.cursor)) {
|
|
124
154
|
if (cursor.size == 0 && !cursor.completed) {
|
|
@@ -127,7 +157,7 @@ export class BacktesterStreamer {
|
|
|
127
157
|
}
|
|
128
158
|
|
|
129
159
|
return Object.values(this.cursor)
|
|
130
|
-
.filter(it => it.peek() !=
|
|
160
|
+
.filter(it => it.peek() != undefined)
|
|
131
161
|
.sort((lhs, rhs) => lhs.peek().timestamp - rhs.peek().timestamp)
|
|
132
162
|
.find(() => true);
|
|
133
163
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function adapterNotFoundError(adapterName: string) {
|
|
2
|
+
return new Error(
|
|
3
|
+
`Unknown adapter: ${adapterName}. You should provide adapter in session descriptor.`
|
|
4
|
+
);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function backtestPageNotEmpty() {
|
|
8
|
+
return new Error('Backtest page is not empty');
|
|
9
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Asset, commissionPercentOf, Instrument, Order } from '../../../domain';
|
|
2
|
+
import { now } from '../../../shared';
|
|
3
|
+
import {
|
|
4
|
+
BalancePatchEvent,
|
|
5
|
+
InstrumentPatchEvent,
|
|
6
|
+
InstrumentSubscriptionEvent,
|
|
7
|
+
OrderbookPatchEvent,
|
|
8
|
+
Store
|
|
9
|
+
} from '../../../store';
|
|
10
|
+
import { PaperEngine } from './paper-engine';
|
|
11
|
+
|
|
12
|
+
describe('PaperEngine', () => {
|
|
13
|
+
const instrument = new Instrument(
|
|
14
|
+
new Asset('btc', 'binance', 8),
|
|
15
|
+
new Asset('usdt', 'binance', 2),
|
|
16
|
+
'binance:btc-usdt'
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
const commission = commissionPercentOf({
|
|
20
|
+
maker: 0.1,
|
|
21
|
+
taker: 0.1
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('should open a new buy market order', () => {
|
|
25
|
+
const store = new Store();
|
|
26
|
+
const engine = new PaperEngine(store);
|
|
27
|
+
const order = Order.market(instrument, 1.0);
|
|
28
|
+
|
|
29
|
+
store.dispatch(
|
|
30
|
+
new InstrumentPatchEvent(now(), instrument.base, instrument.quote, commission, ''),
|
|
31
|
+
new BalancePatchEvent(instrument.base, 1, 0, now()),
|
|
32
|
+
new BalancePatchEvent(instrument.quote, 1000, 0, now())
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
engine.open(order);
|
|
36
|
+
|
|
37
|
+
expect(store.snapshot.order.asReadonlyArray().length).toEqual(1);
|
|
38
|
+
expect(store.snapshot.order.get(instrument.id).get(order.id)).toEqual(order);
|
|
39
|
+
expect(store.snapshot.balance.get(instrument.quote.id).free).toEqual(0);
|
|
40
|
+
expect(store.snapshot.balance.get(instrument.quote.id).locked).toEqual(1000);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('should open a new sell market order', () => {
|
|
44
|
+
const store = new Store();
|
|
45
|
+
const engine = new PaperEngine(store);
|
|
46
|
+
const order = Order.market(instrument, -0.6);
|
|
47
|
+
|
|
48
|
+
store.dispatch(
|
|
49
|
+
new InstrumentPatchEvent(now(), instrument.base, instrument.quote, commission, ''),
|
|
50
|
+
new BalancePatchEvent(instrument.base, 1, 0, now()),
|
|
51
|
+
new BalancePatchEvent(instrument.quote, 1000, 0, now())
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
engine.open(order);
|
|
55
|
+
|
|
56
|
+
expect(store.snapshot.order.asReadonlyArray().length).toEqual(1);
|
|
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);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('should open and fill a new sell limit order', () => {
|
|
63
|
+
const store = new Store();
|
|
64
|
+
const engine = new PaperEngine(store);
|
|
65
|
+
const order = Order.limit(instrument, -0.6, 100);
|
|
66
|
+
|
|
67
|
+
store.dispatch(
|
|
68
|
+
new InstrumentPatchEvent(now(), instrument.base, instrument.quote, commission, ''),
|
|
69
|
+
new BalancePatchEvent(instrument.base, 1, 0, now()),
|
|
70
|
+
new BalancePatchEvent(instrument.quote, 1000, 0, now()),
|
|
71
|
+
new InstrumentSubscriptionEvent(now(), instrument, true)
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
engine.open(order);
|
|
75
|
+
|
|
76
|
+
expect(store.snapshot.order.asReadonlyArray().length).toEqual(1);
|
|
77
|
+
expect(store.snapshot.order.get(instrument.id).get(order.id).state).toEqual(
|
|
78
|
+
'PENDING'
|
|
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);
|
|
82
|
+
|
|
83
|
+
store.dispatch(new OrderbookPatchEvent(instrument, 102, 1, 101, 1, now()));
|
|
84
|
+
|
|
85
|
+
expect(store.snapshot.order.asReadonlyArray().length).toEqual(1);
|
|
86
|
+
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(0);
|
|
89
|
+
expect(store.snapshot.balance.get(instrument.quote.id).free).toEqual(1060.53);
|
|
90
|
+
expect(store.snapshot.balance.get(instrument.quote.id).locked).toEqual(0);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { tap } from 'rxjs';
|
|
2
|
+
|
|
3
|
+
import { Order, Orderbook, Trade } from '../../../domain';
|
|
4
|
+
import {
|
|
5
|
+
BalanceLockOrderEvent,
|
|
6
|
+
BalanceTransactEvent,
|
|
7
|
+
BalanceUnlockOrderEvent,
|
|
8
|
+
OrderCanceledEvent,
|
|
9
|
+
OrderCancelingEvent,
|
|
10
|
+
OrderFilledEvent,
|
|
11
|
+
OrderNewEvent,
|
|
12
|
+
OrderPendingEvent,
|
|
13
|
+
OrderRejectedEvent,
|
|
14
|
+
Store
|
|
15
|
+
} from '../../../store';
|
|
16
|
+
|
|
17
|
+
export class PaperEngine {
|
|
18
|
+
constructor(private readonly store: Store) {
|
|
19
|
+
store.changes$
|
|
20
|
+
.pipe(
|
|
21
|
+
tap(it => {
|
|
22
|
+
if (it instanceof Orderbook) {
|
|
23
|
+
this.onOrderbook(it);
|
|
24
|
+
} else if (it instanceof Trade) {
|
|
25
|
+
this.onTrade(it);
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
)
|
|
29
|
+
.subscribe();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public open(order: Order) {
|
|
33
|
+
const { timestamp } = this.store.snapshot;
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
this.store.dispatch(
|
|
37
|
+
new OrderNewEvent(order, timestamp),
|
|
38
|
+
new BalanceLockOrderEvent(order.id, order.instrument, timestamp)
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
this.store.dispatch(new OrderPendingEvent(order.id, order.instrument, timestamp));
|
|
42
|
+
} catch (error) {
|
|
43
|
+
this.store.dispatch(
|
|
44
|
+
new BalanceUnlockOrderEvent(order.id, order.instrument, timestamp),
|
|
45
|
+
new OrderRejectedEvent(order.id, order.instrument, timestamp)
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public cancel(order: Order) {
|
|
51
|
+
const { timestamp } = this.store.snapshot;
|
|
52
|
+
|
|
53
|
+
this.store.dispatch(new OrderCancelingEvent(order.id, order.instrument, timestamp));
|
|
54
|
+
|
|
55
|
+
this.store.dispatch(
|
|
56
|
+
new BalanceUnlockOrderEvent(order.id, order.instrument, timestamp),
|
|
57
|
+
new OrderCanceledEvent(order.id, order.instrument, timestamp)
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private onOrderbook(orderbook: Orderbook) {
|
|
62
|
+
this.store.snapshot.order
|
|
63
|
+
.get(orderbook.instrument.id)
|
|
64
|
+
.asReadonlyArray()
|
|
65
|
+
.forEach(it => {
|
|
66
|
+
if (it.state != 'PENDING') {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (it.type == 'LIMIT') {
|
|
71
|
+
if (it.quantity > 0 && it.rate > orderbook.bestAskRate) {
|
|
72
|
+
this.completeOrder(it, orderbook.bestAskRate);
|
|
73
|
+
} else if (it.quantity < 0 && it.rate < orderbook.bestBidRate) {
|
|
74
|
+
this.completeOrder(it, orderbook.bestBidRate);
|
|
75
|
+
}
|
|
76
|
+
} else if (it.type == 'MARKET') {
|
|
77
|
+
if (it.quantity > 0) {
|
|
78
|
+
this.completeOrder(it, orderbook.bestAskRate);
|
|
79
|
+
} else if (it.quantity < 0) {
|
|
80
|
+
this.completeOrder(it, orderbook.bestBidRate);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private onTrade(trade: Trade) {
|
|
87
|
+
this.store.snapshot.order
|
|
88
|
+
.get(trade.instrument.id)
|
|
89
|
+
.asReadonlyArray()
|
|
90
|
+
.forEach(it => {
|
|
91
|
+
if (it.state != 'PENDING') {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (it.type == 'LIMIT') {
|
|
96
|
+
if (it.quantity > 0 && it.rate > trade.rate) {
|
|
97
|
+
this.completeOrder(it, trade.rate);
|
|
98
|
+
} else if (it.quantity < 0 && it.rate < trade.rate) {
|
|
99
|
+
this.completeOrder(it, trade.rate);
|
|
100
|
+
}
|
|
101
|
+
} else if (it.type == 'MARKET') {
|
|
102
|
+
this.completeOrder(it, trade.rate);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private completeOrder(order: Order, averageExecutionRate: number) {
|
|
108
|
+
const { timestamp } = this.store.snapshot;
|
|
109
|
+
|
|
110
|
+
const instrument = this.store.snapshot.universe.instrument.get(order.instrument.id);
|
|
111
|
+
const transacted = {
|
|
112
|
+
base: 0,
|
|
113
|
+
quote: 0
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const qty = Math.abs(order.quantity);
|
|
117
|
+
|
|
118
|
+
if (order.quantity > 0) {
|
|
119
|
+
transacted.base += instrument.base.floor(instrument.commission.applyMakerFee(qty));
|
|
120
|
+
transacted.quote -= instrument.quote.floor(averageExecutionRate * qty);
|
|
121
|
+
} else if (order.quantity < 0) {
|
|
122
|
+
transacted.base -= instrument.base.floor(qty);
|
|
123
|
+
transacted.quote += instrument.quote.floor(
|
|
124
|
+
instrument.commission.applyMakerFee(averageExecutionRate * qty)
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
this.store.dispatch(
|
|
129
|
+
new BalanceUnlockOrderEvent(order.id, order.instrument, timestamp),
|
|
130
|
+
new OrderFilledEvent(order.id, order.instrument, averageExecutionRate, timestamp),
|
|
131
|
+
new BalanceTransactEvent(instrument.base, transacted.base, timestamp),
|
|
132
|
+
new BalanceTransactEvent(instrument.quote, transacted.quote, timestamp)
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -1,25 +1,58 @@
|
|
|
1
|
-
import { Cache, InMemoryStorage } from '../../storage';
|
|
2
1
|
import { InstrumentPatchEvent, Store } from '../../store';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
import {
|
|
3
|
+
Adapter,
|
|
4
|
+
AdapterTimeProvider,
|
|
5
|
+
DefaultTimeProvider,
|
|
6
|
+
FeedQuery,
|
|
7
|
+
HistoryQuery
|
|
8
|
+
} from '../adapter';
|
|
9
|
+
import {
|
|
10
|
+
Asset,
|
|
11
|
+
Candle,
|
|
12
|
+
Commission,
|
|
13
|
+
instrumentOf,
|
|
14
|
+
InstrumentSelector,
|
|
15
|
+
Order
|
|
16
|
+
} from './../../domain';
|
|
17
|
+
import { PaperEngine } from './engine/paper-engine';
|
|
7
18
|
import { PaperAdapter } from './paper-adapter';
|
|
8
|
-
import { PaperSimulator } from './simulator/paper-simulator';
|
|
9
19
|
|
|
10
20
|
class DefaultAdapter extends Adapter {
|
|
21
|
+
dispose(): Promise<void> {
|
|
22
|
+
throw new Error('Method not implemented.');
|
|
23
|
+
}
|
|
24
|
+
subscribe(instruments: InstrumentSelector[]): Promise<void> {
|
|
25
|
+
throw new Error('Method not implemented.');
|
|
26
|
+
}
|
|
27
|
+
account(): Promise<void> {
|
|
28
|
+
throw new Error('Method not implemented.');
|
|
29
|
+
}
|
|
30
|
+
open(order: Order): Promise<void> {
|
|
31
|
+
throw new Error('Method not implemented.');
|
|
32
|
+
}
|
|
33
|
+
cancel(order: Order): Promise<void> {
|
|
34
|
+
throw new Error('Method not implemented.');
|
|
35
|
+
}
|
|
36
|
+
history(query: HistoryQuery): Promise<Candle[]> {
|
|
37
|
+
throw new Error('Method not implemented.');
|
|
38
|
+
}
|
|
39
|
+
feed(query: FeedQuery): Promise<void> {
|
|
40
|
+
throw new Error('Method not implemented.');
|
|
41
|
+
}
|
|
11
42
|
name = 'default';
|
|
12
43
|
|
|
13
44
|
timestamp() {
|
|
14
45
|
return 123;
|
|
15
46
|
}
|
|
16
47
|
|
|
17
|
-
|
|
18
|
-
super
|
|
48
|
+
constructor(timeProvider: AdapterTimeProvider, private readonly store: Store) {
|
|
49
|
+
super(timeProvider);
|
|
50
|
+
}
|
|
19
51
|
|
|
20
|
-
|
|
52
|
+
async awake(): Promise<void> {
|
|
53
|
+
this.store.dispatch(
|
|
21
54
|
new InstrumentPatchEvent(
|
|
22
|
-
|
|
55
|
+
this.timestamp(),
|
|
23
56
|
new Asset('a', this.name, 8),
|
|
24
57
|
new Asset('b', this.name, 4),
|
|
25
58
|
new Commission(0.1, 0.1),
|
|
@@ -28,12 +61,12 @@ class DefaultAdapter extends Adapter {
|
|
|
28
61
|
);
|
|
29
62
|
}
|
|
30
63
|
|
|
31
|
-
|
|
32
|
-
return new
|
|
64
|
+
createPaperEngine(adapter: PaperAdapter): PaperEngine {
|
|
65
|
+
return new PaperEngine(adapter.store);
|
|
33
66
|
}
|
|
34
67
|
}
|
|
35
68
|
|
|
36
|
-
describe('
|
|
69
|
+
describe('PaperAdapter', () => {
|
|
37
70
|
const options = {
|
|
38
71
|
balance: {
|
|
39
72
|
['default:a']: 1000,
|
|
@@ -44,7 +77,11 @@ describe('paper adapter tests', () => {
|
|
|
44
77
|
test('should return wrapped adapter name and timestamp', () => {
|
|
45
78
|
const store = new Store();
|
|
46
79
|
|
|
47
|
-
const sut = new PaperAdapter(
|
|
80
|
+
const sut = new PaperAdapter(
|
|
81
|
+
new DefaultAdapter(DefaultTimeProvider, store),
|
|
82
|
+
store,
|
|
83
|
+
options
|
|
84
|
+
);
|
|
48
85
|
|
|
49
86
|
expect(sut.name).toEqual('default');
|
|
50
87
|
expect(sut.timestamp()).toEqual(123);
|
|
@@ -52,18 +89,17 @@ describe('paper adapter tests', () => {
|
|
|
52
89
|
|
|
53
90
|
test('', async () => {
|
|
54
91
|
const store = new Store();
|
|
55
|
-
const adapter = new DefaultAdapter();
|
|
56
|
-
const cache = new Cache(new InMemoryStorage());
|
|
92
|
+
const adapter = new DefaultAdapter(DefaultTimeProvider, store);
|
|
57
93
|
|
|
58
94
|
const sut = new PaperAdapter(adapter, store, options);
|
|
59
95
|
|
|
60
|
-
await sut.awake(
|
|
96
|
+
await sut.awake();
|
|
61
97
|
await sut.account();
|
|
62
98
|
|
|
63
|
-
const order = Order.
|
|
99
|
+
const order = Order.market(instrumentOf('default:a-b'), 1.0);
|
|
64
100
|
|
|
65
101
|
await sut.open(order);
|
|
66
102
|
|
|
67
|
-
expect(store.snapshot.order
|
|
103
|
+
expect(store.snapshot.order.get(order.instrument.id).get(order.id)).toEqual(order);
|
|
68
104
|
});
|
|
69
105
|
});
|
|
@@ -1,34 +1,39 @@
|
|
|
1
1
|
import { assetOf, Candle, InstrumentSelector, Order } from '../../domain';
|
|
2
2
|
import { BalancePatchEvent, Store } from '../../store';
|
|
3
|
-
import { Adapter
|
|
4
|
-
import { FeedQuery, HistoryQuery } from '../adapter';
|
|
5
|
-
import {
|
|
3
|
+
import { Adapter } from '..';
|
|
4
|
+
import { AdapterFactory, FeedQuery, HistoryQuery } from '../adapter';
|
|
5
|
+
import { PaperEngine } from './engine/paper-engine';
|
|
6
6
|
|
|
7
7
|
export interface PaperOptions {
|
|
8
8
|
balance: { [key: string]: number };
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
export function createPaperAdapterFactory(
|
|
12
|
+
decoratedAdapterFactory: AdapterFactory,
|
|
13
|
+
options: PaperOptions
|
|
14
|
+
): AdapterFactory {
|
|
15
|
+
return (timeProvider, store, cache) =>
|
|
16
|
+
new PaperAdapter(decoratedAdapterFactory(timeProvider, store, cache), store, options);
|
|
17
|
+
}
|
|
18
|
+
|
|
11
19
|
export class PaperAdapter extends Adapter {
|
|
12
20
|
readonly name = this.decoratedAdapter.name;
|
|
13
|
-
|
|
21
|
+
private engine: PaperEngine;
|
|
14
22
|
|
|
15
23
|
constructor(
|
|
16
24
|
readonly decoratedAdapter: Adapter,
|
|
17
25
|
readonly store: Store,
|
|
18
26
|
readonly options: PaperOptions
|
|
19
27
|
) {
|
|
20
|
-
super(
|
|
21
|
-
|
|
22
|
-
|
|
28
|
+
super({
|
|
29
|
+
timestamp: () => this.decoratedAdapter.timestamp()
|
|
30
|
+
});
|
|
23
31
|
}
|
|
24
32
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
33
|
+
async awake(): Promise<void> {
|
|
34
|
+
this.engine = this.createPaperEngine(this);
|
|
28
35
|
|
|
29
|
-
|
|
30
|
-
await super.awake(context);
|
|
31
|
-
await this.decoratedAdapter.awake(context);
|
|
36
|
+
await this.decoratedAdapter.awake();
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
dispose(): Promise<void> {
|
|
@@ -41,36 +46,34 @@ export class PaperAdapter extends Adapter {
|
|
|
41
46
|
|
|
42
47
|
async account(): Promise<void> {
|
|
43
48
|
let subscribed = Object.values(this.store.snapshot.subscription.asset).filter(
|
|
44
|
-
it => it.
|
|
49
|
+
it => it.adapterName == this.name
|
|
45
50
|
);
|
|
46
51
|
|
|
47
52
|
for (const balance in this.options.balance) {
|
|
48
53
|
const asset = assetOf(balance);
|
|
49
54
|
|
|
50
|
-
if (asset.
|
|
55
|
+
if (asset.adapterName != this.name) {
|
|
51
56
|
continue;
|
|
52
57
|
}
|
|
53
58
|
|
|
54
59
|
const free = this.options.balance[balance];
|
|
55
60
|
|
|
56
|
-
subscribed = subscribed.filter(it => it.
|
|
61
|
+
subscribed = subscribed.filter(it => it.id != asset.id);
|
|
57
62
|
|
|
58
|
-
this.store.dispatch(new BalancePatchEvent(asset, free, 0, this.
|
|
63
|
+
this.store.dispatch(new BalancePatchEvent(asset, free, 0, this.timestamp()));
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
for (const missingAsset of subscribed) {
|
|
62
|
-
this.store.dispatch(
|
|
63
|
-
new BalancePatchEvent(missingAsset, 0, 0, this.context.timestamp)
|
|
64
|
-
);
|
|
67
|
+
this.store.dispatch(new BalancePatchEvent(missingAsset, 0, 0, this.timestamp()));
|
|
65
68
|
}
|
|
66
69
|
}
|
|
67
70
|
|
|
68
71
|
async open(order: Order): Promise<void> {
|
|
69
|
-
this.
|
|
72
|
+
this.engine.open(order);
|
|
70
73
|
}
|
|
71
74
|
|
|
72
75
|
async cancel(order: Order): Promise<void> {
|
|
73
|
-
this.
|
|
76
|
+
this.engine.cancel(order);
|
|
74
77
|
}
|
|
75
78
|
|
|
76
79
|
history(query: HistoryQuery): Promise<Candle[]> {
|
|
@@ -81,7 +84,7 @@ export class PaperAdapter extends Adapter {
|
|
|
81
84
|
return this.decoratedAdapter.feed(query);
|
|
82
85
|
}
|
|
83
86
|
|
|
84
|
-
|
|
85
|
-
return this.decoratedAdapter.
|
|
87
|
+
createPaperEngine(adapter: PaperAdapter): PaperEngine {
|
|
88
|
+
return this.decoratedAdapter.createPaperEngine(adapter);
|
|
86
89
|
}
|
|
87
90
|
}
|
package/src/bootstrap.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AdapterAggregate,
|
|
3
|
-
BacktesterAdapter,
|
|
4
3
|
BacktesterListener,
|
|
5
4
|
BacktesterStreamer,
|
|
6
|
-
|
|
5
|
+
createBacktesterAdapterFactory,
|
|
6
|
+
createPaperAdapterFactory,
|
|
7
|
+
DefaultTimeProvider
|
|
7
8
|
} from './adapter';
|
|
8
9
|
import { Session, SessionDescriptor } from './domain';
|
|
9
|
-
import { Cache, Feed,
|
|
10
|
+
import { Cache, Feed, inMemoryStorageFactory } from './storage';
|
|
10
11
|
import { Store } from './store';
|
|
11
12
|
|
|
12
13
|
export class Bootstrap {
|
|
@@ -56,9 +57,9 @@ export class Bootstrap {
|
|
|
56
57
|
*/
|
|
57
58
|
backtest(listener?: BacktesterListener): [Session, BacktesterStreamer] {
|
|
58
59
|
const store = new Store();
|
|
59
|
-
const
|
|
60
|
-
const feed = new Feed(storage
|
|
61
|
-
const cache = new Cache(storage
|
|
60
|
+
const storage = this.descriptor.storage ?? inMemoryStorageFactory();
|
|
61
|
+
const feed = new Feed(storage('feed'));
|
|
62
|
+
const cache = new Cache(storage('cache'));
|
|
62
63
|
|
|
63
64
|
const streamer = new BacktesterStreamer(
|
|
64
65
|
store,
|
|
@@ -68,13 +69,13 @@ export class Bootstrap {
|
|
|
68
69
|
);
|
|
69
70
|
|
|
70
71
|
const aggregate = new AdapterAggregate(
|
|
71
|
-
this.descriptor.adapter.map(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
)
|
|
72
|
+
this.descriptor.adapter.map(it =>
|
|
73
|
+
createBacktesterAdapterFactory(
|
|
74
|
+
createPaperAdapterFactory(it, this.descriptor.simulation),
|
|
75
|
+
streamer
|
|
76
|
+
)
|
|
77
77
|
),
|
|
78
|
+
streamer.getTimeProvider(),
|
|
78
79
|
store,
|
|
79
80
|
cache
|
|
80
81
|
);
|
|
@@ -102,13 +103,14 @@ export class Bootstrap {
|
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
const store = new Store();
|
|
105
|
-
const storage = this.descriptor.storage ??
|
|
106
|
-
const cache = new Cache(storage
|
|
106
|
+
const storage = this.descriptor.storage ?? inMemoryStorageFactory();
|
|
107
|
+
const cache = new Cache(storage('cache'));
|
|
107
108
|
|
|
108
109
|
const aggregate = new AdapterAggregate(
|
|
109
|
-
this.descriptor.adapter.map(
|
|
110
|
-
|
|
110
|
+
this.descriptor.adapter.map(it =>
|
|
111
|
+
createPaperAdapterFactory(it, this.descriptor.simulation)
|
|
111
112
|
),
|
|
113
|
+
DefaultTimeProvider,
|
|
112
114
|
store,
|
|
113
115
|
cache
|
|
114
116
|
);
|
|
@@ -122,10 +124,15 @@ export class Bootstrap {
|
|
|
122
124
|
*/
|
|
123
125
|
live(): Session {
|
|
124
126
|
const store = new Store();
|
|
125
|
-
const storage = this.descriptor.storage ??
|
|
126
|
-
const cache = new Cache(storage
|
|
127
|
+
const storage = this.descriptor.storage ?? inMemoryStorageFactory();
|
|
128
|
+
const cache = new Cache(storage('cache'));
|
|
127
129
|
|
|
128
|
-
const aggregate = new AdapterAggregate(
|
|
130
|
+
const aggregate = new AdapterAggregate(
|
|
131
|
+
this.descriptor.adapter,
|
|
132
|
+
DefaultTimeProvider,
|
|
133
|
+
store,
|
|
134
|
+
cache
|
|
135
|
+
);
|
|
129
136
|
|
|
130
137
|
return new Session(store, aggregate, this.descriptor);
|
|
131
138
|
}
|