openalgo-script 0.4.0 → 0.5.0
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/CHANGELOG.md +929 -0
- package/README.md +69 -16
- package/dist/adapters/charts/driving.d.ts +50 -0
- package/dist/adapters/charts/driving.d.ts.map +1 -0
- package/dist/adapters/charts/driving.js +57 -0
- package/dist/adapters/charts/driving.js.map +1 -0
- package/dist/adapters/charts/run.d.ts +20 -0
- package/dist/adapters/charts/run.d.ts.map +1 -1
- package/dist/adapters/charts/run.js +83 -16
- package/dist/adapters/charts/run.js.map +1 -1
- package/dist/adapters/charts/venue.d.ts +73 -0
- package/dist/adapters/charts/venue.d.ts.map +1 -0
- package/dist/adapters/charts/venue.js +104 -0
- package/dist/adapters/charts/venue.js.map +1 -0
- package/dist/core/accounting/analysis.d.ts +111 -0
- package/dist/core/accounting/analysis.d.ts.map +1 -0
- package/dist/core/accounting/analysis.js +123 -0
- package/dist/core/accounting/analysis.js.map +1 -0
- package/dist/core/accounting/equity.d.ts +33 -0
- package/dist/core/accounting/equity.d.ts.map +1 -1
- package/dist/core/accounting/equity.js +12 -0
- package/dist/core/accounting/equity.js.map +1 -1
- package/dist/core/accounting/index.d.ts +2 -0
- package/dist/core/accounting/index.d.ts.map +1 -1
- package/dist/core/accounting/index.js +1 -0
- package/dist/core/accounting/index.js.map +1 -1
- package/dist/core/accounting/report.d.ts +3 -0
- package/dist/core/accounting/report.d.ts.map +1 -1
- package/dist/core/accounting/report.js +2 -0
- package/dist/core/accounting/report.js.map +1 -1
- package/dist/core/accounting/statistics.d.ts +12 -0
- package/dist/core/accounting/statistics.d.ts.map +1 -1
- package/dist/core/accounting/statistics.js +23 -1
- package/dist/core/accounting/statistics.js.map +1 -1
- package/dist/core/backtest/case.d.ts +60 -0
- package/dist/core/backtest/case.d.ts.map +1 -0
- package/dist/core/backtest/case.js +319 -0
- package/dist/core/backtest/case.js.map +1 -0
- package/dist/core/backtest/compare.d.ts.map +1 -1
- package/dist/core/backtest/compare.js +2 -0
- package/dist/core/backtest/compare.js.map +1 -1
- package/dist/core/backtest/deliver.d.ts +93 -0
- package/dist/core/backtest/deliver.d.ts.map +1 -0
- package/dist/core/backtest/deliver.js +94 -0
- package/dist/core/backtest/deliver.js.map +1 -0
- package/dist/core/backtest/drive.d.ts +66 -8
- package/dist/core/backtest/drive.d.ts.map +1 -1
- package/dist/core/backtest/drive.js +109 -59
- package/dist/core/backtest/drive.js.map +1 -1
- package/dist/core/backtest/index.d.ts +24 -12
- package/dist/core/backtest/index.d.ts.map +1 -1
- package/dist/core/backtest/index.js +21 -10
- package/dist/core/backtest/index.js.map +1 -1
- package/dist/core/backtest/record.d.ts +63 -2
- package/dist/core/backtest/record.d.ts.map +1 -1
- package/dist/core/backtest/record.js +71 -4
- package/dist/core/backtest/record.js.map +1 -1
- package/dist/core/backtest/replay.d.ts.map +1 -1
- package/dist/core/backtest/replay.js +11 -1
- package/dist/core/backtest/replay.js.map +1 -1
- package/dist/core/backtest/simulate.d.ts +113 -1
- package/dist/core/backtest/simulate.d.ts.map +1 -1
- package/dist/core/backtest/simulate.js +123 -5
- package/dist/core/backtest/simulate.js.map +1 -1
- package/dist/core/catalogue/catalogue.generated.d.ts +1 -1
- package/dist/core/catalogue/catalogue.generated.js +1 -1
- package/dist/core/catalogue/catalogue.generated.js.map +1 -1
- package/dist/core/check/library-orders.js +2 -2
- package/dist/core/check/library-orders.js.map +1 -1
- package/dist/core/check/library-prose.generated.js +2 -2
- package/dist/core/check/library-prose.generated.js.map +1 -1
- package/dist/core/emit/canonical.d.ts +22 -8
- package/dist/core/emit/canonical.d.ts.map +1 -1
- package/dist/core/emit/canonical.js +67 -6
- package/dist/core/emit/canonical.js.map +1 -1
- package/dist/core/engine/arithmetic.d.ts +6 -25
- package/dist/core/engine/arithmetic.d.ts.map +1 -1
- package/dist/core/engine/arithmetic.js +48 -3
- package/dist/core/engine/arithmetic.js.map +1 -1
- package/dist/core/engine/index.d.ts +1 -1
- package/dist/core/engine/index.d.ts.map +1 -1
- package/dist/core/engine/index.js +1 -1
- package/dist/core/engine/index.js.map +1 -1
- package/dist/core/engine/library/arrays.d.ts.map +1 -1
- package/dist/core/engine/library/arrays.js +8 -2
- package/dist/core/engine/library/arrays.js.map +1 -1
- package/dist/core/engine/library/code-points.d.ts +40 -0
- package/dist/core/engine/library/code-points.d.ts.map +1 -0
- package/dist/core/engine/library/code-points.js +74 -0
- package/dist/core/engine/library/code-points.js.map +1 -0
- package/dist/core/engine/library/index.d.ts +5 -0
- package/dist/core/engine/library/index.d.ts.map +1 -1
- package/dist/core/engine/library/index.js +5 -0
- package/dist/core/engine/library/index.js.map +1 -1
- package/dist/core/engine/library/text.d.ts.map +1 -1
- package/dist/core/engine/library/text.js +51 -34
- package/dist/core/engine/library/text.js.map +1 -1
- package/dist/core/engine/load.d.ts +20 -0
- package/dist/core/engine/load.d.ts.map +1 -1
- package/dist/core/engine/load.js +62 -0
- package/dist/core/engine/load.js.map +1 -1
- package/dist/core/engine/verify-tables.d.ts.map +1 -1
- package/dist/core/engine/verify-tables.js +41 -0
- package/dist/core/engine/verify-tables.js.map +1 -1
- package/dist/core/index.d.ts +10 -5
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +8 -3
- package/dist/core/index.js.map +1 -1
- package/dist/core/stdlib/index.d.ts +1 -1
- package/dist/core/stdlib/index.d.ts.map +1 -1
- package/dist/core/stdlib/index.js +1 -1
- package/dist/core/stdlib/index.js.map +1 -1
- package/dist/core/stdlib/maths/index.d.ts +1 -1
- package/dist/core/stdlib/maths/index.d.ts.map +1 -1
- package/dist/core/stdlib/maths/index.js +1 -1
- package/dist/core/stdlib/maths/index.js.map +1 -1
- package/dist/core/stdlib/maths/rounding.d.ts +5 -0
- package/dist/core/stdlib/maths/rounding.d.ts.map +1 -1
- package/dist/core/stdlib/maths/rounding.js +19 -1
- package/dist/core/stdlib/maths/rounding.js.map +1 -1
- package/dist/core/version/version.generated.d.ts +1 -1
- package/dist/core/version/version.generated.js +1 -1
- package/package.json +14 -2
- package/spec/README.md +2 -1
- package/spec/errors.json +3 -3
- package/src/adapters/charts/driving.ts +109 -0
- package/src/adapters/charts/run.ts +120 -28
- package/src/adapters/charts/venue.ts +132 -0
- package/src/core/accounting/analysis.ts +188 -0
- package/src/core/accounting/equity.ts +38 -0
- package/src/core/accounting/index.ts +2 -0
- package/src/core/accounting/report.ts +5 -0
- package/src/core/accounting/statistics.ts +38 -1
- package/src/core/backtest/case.ts +395 -0
- package/src/core/backtest/compare.ts +2 -0
- package/src/core/backtest/deliver.ts +161 -0
- package/src/core/backtest/drive.ts +175 -71
- package/src/core/backtest/index.ts +24 -12
- package/src/core/backtest/record.ts +134 -5
- package/src/core/backtest/replay.ts +11 -1
- package/src/core/backtest/simulate.ts +201 -6
- package/src/core/catalogue/catalogue.generated.ts +1 -1
- package/src/core/check/library-orders.ts +2 -2
- package/src/core/check/library-prose.generated.ts +2 -2
- package/src/core/emit/canonical.ts +67 -9
- package/src/core/engine/arithmetic.ts +23 -3
- package/src/core/engine/index.ts +1 -1
- package/src/core/engine/library/arrays.ts +8 -2
- package/src/core/engine/library/code-points.ts +73 -0
- package/src/core/engine/library/index.ts +6 -0
- package/src/core/engine/library/text.ts +53 -35
- package/src/core/engine/load.ts +68 -0
- package/src/core/engine/verify-tables.ts +43 -0
- package/src/core/index.ts +16 -2
- package/src/core/stdlib/index.ts +1 -0
- package/src/core/stdlib/maths/index.ts +1 -0
- package/src/core/stdlib/maths/rounding.ts +23 -1
- package/src/core/version/version.generated.ts +1 -1
package/README.md
CHANGED
|
@@ -15,6 +15,15 @@ can write their own engine for it.
|
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
18
|
+
## Architecture at a glance
|
|
19
|
+
|
|
20
|
+
[](https://raw.githubusercontent.com/marketcalls/openscript/main/docs/architecture-overview.png)
|
|
21
|
+
|
|
22
|
+
Write an indicator or a strategy once, then use it on a chart or test it against
|
|
23
|
+
historical data. Your platform supplies the editor, saved scripts, market data
|
|
24
|
+
and connections. The live runner is planned, with sandbox testing before live
|
|
25
|
+
execution; see [Phase 6](./ROADMAP.md#phase-6-the-second-engine-and-live-running).
|
|
26
|
+
|
|
18
27
|
## Status
|
|
19
28
|
|
|
20
29
|
**`0.4.0` runs studies, backtests strategies, and ships the language
|
|
@@ -57,12 +66,21 @@ first thing a stranger reads:
|
|
|
57
66
|
[`docs/integrating/the-editor-half.md`](./docs/integrating/the-editor-half.md).
|
|
58
67
|
The language server that would put the same errors in a desktop editor is the
|
|
59
68
|
rest of Phase 4 and is not written.
|
|
60
|
-
- **No
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
69
|
+
- **No engine anybody else wrote has run the suite, so the portability claim is
|
|
70
|
+
still untested.** The second engine is here: `engine/` holds a complete
|
|
71
|
+
engine in Python with a test suite of its own, and `npm test` runs both on
|
|
72
|
+
every build. A run record carries its own
|
|
73
|
+
source text rather than only a hash of it (`sourceText` in
|
|
74
|
+
[`src/core/backtest/record.ts`](./src/core/backtest/record.ts)), and
|
|
75
|
+
`caseFilesFrom` in [`src/core/backtest/case.ts`](./src/core/backtest/case.ts)
|
|
76
|
+
writes the files a suite runs from straight out of a record, which is where the
|
|
77
|
+
eight cases under [`cases/`](./cases) came from. `npm run suite:agree` reports
|
|
78
|
+
8 pass of 8 between the two engines. What that run does not prove is the thing
|
|
79
|
+
the suite exists for: both engines were written in this repository, from the
|
|
80
|
+
same specification, by the same hands, so their agreement is evidence about
|
|
81
|
+
this repository rather than about the specification. Until an engine written by
|
|
82
|
+
somebody who had only the specification passes these cases, portability is a
|
|
83
|
+
design with one corroborating implementation, not a result.
|
|
66
84
|
|
|
67
85
|
The version is `0.4.0` rather than `1.0` because of that list. The studies
|
|
68
86
|
surface is the part that is finished, and it is the part to build on.
|
|
@@ -116,8 +134,8 @@ OpenScript is the opposite of that:
|
|
|
116
134
|
timeout, and nothing you drew silently dropped to make room for the next one.
|
|
117
135
|
- **Honest.** A higher timeframe read has to say whether it repaints. The
|
|
118
136
|
compiler warns when a script would.
|
|
119
|
-
- **Connected.**
|
|
120
|
-
|
|
137
|
+
- **Connected.** Designed to route orders through your own broker connection,
|
|
138
|
+
with sandbox testing before live execution. The live runner is planned.
|
|
121
139
|
- **Open.** Apache-2.0, a written specification, and a conformance suite anyone
|
|
122
140
|
can run against their own implementation.
|
|
123
141
|
|
|
@@ -146,14 +164,49 @@ own, with their fixes taken from the error catalogue. A host supplies the text
|
|
|
146
164
|
component and the panel around it, and keeps its own design. The editor is not a
|
|
147
165
|
second implementation of the language to be kept in step.
|
|
148
166
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
167
|
+
[](https://raw.githubusercontent.com/marketcalls/openscript/main/docs/architecture-compiler.png)
|
|
168
|
+
|
|
169
|
+
### From source to a compiled program
|
|
170
|
+
|
|
171
|
+
| Stage | What happens | Implementation |
|
|
172
|
+
|---|---|---|
|
|
173
|
+
| Lex | Turns text into tokens with source positions. Newlines, indentation and dedentation become explicit tokens, so later stages do not reinterpret whitespace. | [`src/core/lex`](./src/core/lex/index.ts) |
|
|
174
|
+
| Parse | Builds the abstract syntax tree (AST). It recovers around malformed statements so an editor can still work with a partially typed file. | [`src/core/parse`](./src/core/parse/index.ts) |
|
|
175
|
+
| Check | Resolves names, checks types and calls, determines storage and tracks when a value becomes available. `CheckedScript` keeps those answers beside the original tree. | [`src/core/check`](./src/core/check/index.ts) |
|
|
176
|
+
| Emit | Allocates registers and persistent state, lowers statements into instructions, links calls and requests, and checks stack depths and limits. | [`src/core/emit`](./src/core/emit/emit.ts) |
|
|
177
|
+
|
|
178
|
+
The result is a [`CompiledProgram`](./src/core/emit/program.ts), not executable
|
|
179
|
+
code in the host's language. Alongside its instructions it carries the constants,
|
|
180
|
+
inputs, output declarations, storage layout and source mapping the engine needs.
|
|
181
|
+
Its [canonical encoding](./src/core/emit/canonical.ts) makes the program portable
|
|
182
|
+
and gives it stable bytes for hashing. The language and compiled format have
|
|
183
|
+
separate versions, defined by the [compiled program specification](./spec/compiled-program.md).
|
|
184
|
+
|
|
185
|
+
Every compiler stage reports through the same diagnostic system. Codes, messages
|
|
186
|
+
and fixes come from the [error catalogue](./spec/errors.json); the
|
|
187
|
+
[headless editor](./src/editor/index.ts) reuses the compiler and its language
|
|
188
|
+
tables for highlighting, completion, diagnostics, hover, signatures and formatting.
|
|
189
|
+
|
|
190
|
+
### From a compiled program to results
|
|
191
|
+
|
|
192
|
+
Before the first bar, [`load`](./src/core/engine/load.ts) verifies the program's
|
|
193
|
+
format, capabilities, tables and instructions, including stack and address
|
|
194
|
+
bounds. It checks the host's limits, resolves inputs and plans requested series.
|
|
195
|
+
A rejected program returns a diagnostic before execution starts.
|
|
196
|
+
|
|
197
|
+
The [engine](./src/core/engine/engine.ts) then advances one bar at a time. Its
|
|
198
|
+
[interpreter](./src/core/engine/machine.ts) walks the instruction list using
|
|
199
|
+
registers, persistent memory and the standard library, with instruction, memory
|
|
200
|
+
and time budgets. Updating the newest bar restores its checkpoint before
|
|
201
|
+
recomputing it; explicitly live state is retained. Drawing values are published
|
|
202
|
+
on updates, while signals, alerts and orders follow the confirmation policy.
|
|
203
|
+
|
|
204
|
+
The [chart adapter](./src/adapters/charts/index.ts) maps study outputs into the
|
|
205
|
+
host's chart. The [backtest driver](./src/core/backtest/drive.ts) supplies a
|
|
206
|
+
simulated order destination and records frames, fills, orders and the report.
|
|
207
|
+
[Replay and rerun](./src/core/backtest/replay.ts) let a stored result be checked
|
|
208
|
+
again. The host owns data access, rendering, persistence and order routing;
|
|
209
|
+
the language core does not reach into those systems itself.
|
|
157
210
|
|
|
158
211
|
## The pieces, and which way they point
|
|
159
212
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Walking the bars, for a study and for a strategy.
|
|
3
|
+
*
|
|
4
|
+
* Split from `run.ts` because they are two things. That file decides what an
|
|
5
|
+
* engine is loaded with: the host record, the clock, the settings, the venue.
|
|
6
|
+
* This one decides how the bars are then handed over, and the two differ by
|
|
7
|
+
* exactly one thing, whether frames have to reach the engine between them.
|
|
8
|
+
*/
|
|
9
|
+
import type { CompiledProgram } from '../../core/emit/index.js';
|
|
10
|
+
import type { Engine } from '../../core/engine/index.js';
|
|
11
|
+
import type { ChartBar, ChartCalcContext, ChartSettings } from './contract.js';
|
|
12
|
+
import type { HeldVenue } from './venue.js';
|
|
13
|
+
/**
|
|
14
|
+
* A run in hand, held between a chart's recomputes.
|
|
15
|
+
*
|
|
16
|
+
* The signature and the bar times are what a tail run is checked against before
|
|
17
|
+
* it is trusted: splicing a tail onto a history that has changed underneath it
|
|
18
|
+
* draws a wrong study that looks entirely plausible.
|
|
19
|
+
*/
|
|
20
|
+
export interface Held {
|
|
21
|
+
readonly engine: Engine;
|
|
22
|
+
readonly signature: string;
|
|
23
|
+
count: number;
|
|
24
|
+
firstTime: number;
|
|
25
|
+
lastTime: number;
|
|
26
|
+
/**
|
|
27
|
+
* The destination this run's orders go to, for a strategy.
|
|
28
|
+
*
|
|
29
|
+
* Held with the engine because the two are one run: the venue holds the
|
|
30
|
+
* orders that have not filled yet, and an engine continued onto a new bar
|
|
31
|
+
* against a fresh venue would have its working orders silently forgotten.
|
|
32
|
+
*/
|
|
33
|
+
readonly venue: HeldVenue | null;
|
|
34
|
+
}
|
|
35
|
+
/** A study: every bar in one hand-over, which is what `run` is for. */
|
|
36
|
+
export declare function runWhole(engine: Engine, bars: readonly ChartBar[], ctx: ChartCalcContext | undefined, program: CompiledProgram, settings: ChartSettings): Held;
|
|
37
|
+
/**
|
|
38
|
+
* A strategy: one bar at a time, with the venue answering between them.
|
|
39
|
+
*
|
|
40
|
+
* The order is deliver, execute, then ask. A driver that asked the venue before
|
|
41
|
+
* executing would price a fill against a bar the strategy had not seen yet, and
|
|
42
|
+
* one that delivered after executing would let a script read a position its own
|
|
43
|
+
* order on this bar had just created.
|
|
44
|
+
*
|
|
45
|
+
* `supplied` is the whole count rather than the index reached, so `bar.isLast`
|
|
46
|
+
* means the same on this path as on the one above it: a strategy written to act
|
|
47
|
+
* on the final bar acts on the final bar, not on every bar in turn.
|
|
48
|
+
*/
|
|
49
|
+
export declare function walkWith(engine: Engine, held: HeldVenue, bars: readonly ChartBar[], ctx: ChartCalcContext | undefined, program: CompiledProgram, settings: ChartSettings): Held;
|
|
50
|
+
//# sourceMappingURL=driving.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driving.d.ts","sourceRoot":"","sources":["../../../src/adapters/charts/driving.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAEzD,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAI/E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;;GAMG;AACH,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;CAClC;AAED,uEAAuE;AACvE,wBAAgB,QAAQ,CACtB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,SAAS,QAAQ,EAAE,EACzB,GAAG,EAAE,gBAAgB,GAAG,SAAS,EACjC,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,aAAa,GACtB,IAAI,CAON;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CACtB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,SAAS,QAAQ,EAAE,EACzB,GAAG,EAAE,gBAAgB,GAAG,SAAS,EACjC,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,aAAa,GACtB,IAAI,CAcN"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Walking the bars, for a study and for a strategy.
|
|
3
|
+
*
|
|
4
|
+
* Split from `run.ts` because they are two things. That file decides what an
|
|
5
|
+
* engine is loaded with: the host record, the clock, the settings, the venue.
|
|
6
|
+
* This one decides how the bars are then handed over, and the two differ by
|
|
7
|
+
* exactly one thing, whether frames have to reach the engine between them.
|
|
8
|
+
*/
|
|
9
|
+
import { hostBar, stateFor } from './bars.js';
|
|
10
|
+
import { stopped } from './errors.js';
|
|
11
|
+
import { signatureOf } from './settings.js';
|
|
12
|
+
import { answersFor } from './venue.js';
|
|
13
|
+
/** A study: every bar in one hand-over, which is what `run` is for. */
|
|
14
|
+
export function runWhole(engine, bars, ctx, program, settings) {
|
|
15
|
+
const result = engine.run(bars.map(hostBar), bars.map((_, index) => stateFor(index, bars, ctx)));
|
|
16
|
+
if (result.diagnostic !== undefined)
|
|
17
|
+
throw stopped(result.diagnostic);
|
|
18
|
+
return heldFrom(engine, null, bars, program, settings);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A strategy: one bar at a time, with the venue answering between them.
|
|
22
|
+
*
|
|
23
|
+
* The order is deliver, execute, then ask. A driver that asked the venue before
|
|
24
|
+
* executing would price a fill against a bar the strategy had not seen yet, and
|
|
25
|
+
* one that delivered after executing would let a script read a position its own
|
|
26
|
+
* order on this bar had just created.
|
|
27
|
+
*
|
|
28
|
+
* `supplied` is the whole count rather than the index reached, so `bar.isLast`
|
|
29
|
+
* means the same on this path as on the one above it: a strategy written to act
|
|
30
|
+
* on the final bar acts on the final bar, not on every bar in turn.
|
|
31
|
+
*/
|
|
32
|
+
export function walkWith(engine, held, bars, ctx, program, settings) {
|
|
33
|
+
for (let index = 0; index < bars.length; index += 1) {
|
|
34
|
+
const bar = bars[index];
|
|
35
|
+
if (bar === undefined)
|
|
36
|
+
continue;
|
|
37
|
+
for (const frame of held.pending)
|
|
38
|
+
engine.deliver(frame);
|
|
39
|
+
held.pending = [];
|
|
40
|
+
const result = engine.append(hostBar(bar), stateFor(index, bars, ctx), bars.length);
|
|
41
|
+
if (result.diagnostic !== undefined)
|
|
42
|
+
throw stopped(result.diagnostic);
|
|
43
|
+
answersFor(held, index);
|
|
44
|
+
}
|
|
45
|
+
return heldFrom(engine, held, bars, program, settings);
|
|
46
|
+
}
|
|
47
|
+
function heldFrom(engine, venue, bars, program, settings) {
|
|
48
|
+
return {
|
|
49
|
+
engine,
|
|
50
|
+
venue,
|
|
51
|
+
signature: signatureOf(program, settings),
|
|
52
|
+
count: bars.length,
|
|
53
|
+
firstTime: bars[0]?.time ?? 0,
|
|
54
|
+
lastTime: bars[bars.length - 1]?.time ?? 0,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=driving.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driving.js","sourceRoot":"","sources":["../../../src/adapters/charts/driving.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE9C,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA0BxC,uEAAuE;AACvE,MAAM,UAAU,QAAQ,CACtB,MAAc,EACd,IAAyB,EACzB,GAAiC,EACjC,OAAwB,EACxB,QAAuB;IAEvB,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CACvB,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EACjB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CACnD,CAAC;IACF,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS;QAAE,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACtE,OAAO,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;AACzD,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,QAAQ,CACtB,MAAc,EACd,IAAe,EACf,IAAyB,EACzB,GAAiC,EACjC,OAAwB,EACxB,QAAuB;IAEvB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,GAAG,KAAK,SAAS;YAAE,SAAS;QAEhC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO;YAAE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACxD,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QAElB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACpF,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS;YAAE,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAEtE,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;AACzD,CAAC;AAED,SAAS,QAAQ,CACf,MAAc,EACd,KAAuB,EACvB,IAAyB,EACzB,OAAwB,EACxB,QAAuB;IAEvB,OAAO;QACL,MAAM;QACN,KAAK;QACL,SAAS,EAAE,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC;QACzC,KAAK,EAAE,IAAI,CAAC,MAAM;QAClB,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,CAAC;QAC7B,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,IAAI,IAAI,CAAC;KAC3C,CAAC;AACJ,CAAC"}
|
|
@@ -98,6 +98,26 @@ export interface ChartAdapterOptions {
|
|
|
98
98
|
* (`stdlib.md` 17.1), never handed over by the chart.
|
|
99
99
|
*/
|
|
100
100
|
readonly orders?: EffectRoute;
|
|
101
|
+
/**
|
|
102
|
+
* Run a strategy against a simulated destination where the host gives none.
|
|
103
|
+
*
|
|
104
|
+
* **Off by default, because the refusal it replaces is useful.** A strategy
|
|
105
|
+
* with nowhere to send an order is refused at load with OS6006 naming the
|
|
106
|
+
* capability, which is exactly what a host that meant to wire a destination
|
|
107
|
+
* and forgot needs to be told. A chart that quietly filled one in for them
|
|
108
|
+
* would draw a convincing strategy that routed nothing.
|
|
109
|
+
*
|
|
110
|
+
* **On, it is the venue a backtest uses.** A chart drawing a strategy then
|
|
111
|
+
* fills the same orders at the same prices as the report of the same script,
|
|
112
|
+
* so the marks on the price and the trades in the report are one answer
|
|
113
|
+
* rather than two. This is what a host turns on to draw a strategy the way it
|
|
114
|
+
* draws a study: the plots, the legend row and the settings all follow from
|
|
115
|
+
* the program running at all.
|
|
116
|
+
*
|
|
117
|
+
* It does not place an order anywhere. A host that wants that supplies
|
|
118
|
+
* `orders`, which wins over this.
|
|
119
|
+
*/
|
|
120
|
+
readonly simulateOrders?: boolean;
|
|
101
121
|
readonly limits?: Partial<EngineLimits>;
|
|
102
122
|
readonly clock?: Clock;
|
|
103
123
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/adapters/charts/run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EACV,KAAK,EACL,WAAW,EAGX,YAAY,EACZ,IAAI,EAEJ,UAAU,EACV,OAAO,EAEP,KAAK,EACN,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/adapters/charts/run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EACV,KAAK,EACL,WAAW,EAGX,YAAY,EACZ,IAAI,EAEJ,UAAU,EACV,OAAO,EAEP,KAAK,EACN,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAU3F,iFAAiF;AACjF,MAAM,WAAW,mBAAmB;IAClC;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,aAAa,CAAC;IAClC;;;;;;;OAOG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,yEAAyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IAC7B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IACjC;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B;;;;;;;;;;;;;;;;;;OAkBG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACxC,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;IACvB;;;;;;;OAOG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;CACnE;AAMD,gEAAgE;AAChE,MAAM,MAAM,OAAO,GAAG,SAAS,CAAC,SAAS,KAAK,EAAE,CAAC,EAAE,CAAC;AAEpD;;;;;;;;GAQG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,IAAI,EAAE,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;CACvC;AAED,wBAAgB,OAAO,CACrB,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,SAAS,QAAQ,EAAE,EACzB,QAAQ,EAAE,aAAa,EACvB,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,gBAAgB,GAAG,SAAS,EACjC,OAAO,EAAE,mBAAmB,GAC3B,SAAS,CAmBX;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CACrB,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,SAAS,QAAQ,EAAE,EACzB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,aAAa,EACvB,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,gBAAgB,GAAG,SAAS,EAGjC,QAAQ,EAAE,mBAAmB,GAC5B,SAAS,GAAG,IAAI,CA6ClB;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAG/C"}
|
|
@@ -3,21 +3,26 @@ import { hostBar, hostNow, stateFor } from './bars.js';
|
|
|
3
3
|
import { refused, stopped } from './errors.js';
|
|
4
4
|
import { stationIn, stationOf } from './requests.js';
|
|
5
5
|
import { engineSettings, signatureOf } from './settings.js';
|
|
6
|
+
import { answersFor, needsVenue, routeInto, venueFor } from './venue.js';
|
|
7
|
+
import { runWhole, walkWith } from './driving.js';
|
|
8
|
+
/** The engine one chart instance is holding, between recomputes. */
|
|
6
9
|
/** The store key. Namespaced, because the store belongs to the host as well. */
|
|
7
10
|
const HELD = 'openscript';
|
|
8
11
|
export function fullRun(program, bars, settings, store, ctx, options) {
|
|
9
12
|
const station = stationIn(store);
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
const started = start(program, settings, ctx, options, station.provider(bars), bars);
|
|
14
|
+
const engine = started.engine;
|
|
15
|
+
// **A strategy is walked bar by bar and a study is handed the lot.** The
|
|
16
|
+
// difference is the venue: its frames reach the engine between bars, which is
|
|
17
|
+
// the only place they can, so a strategy's position is right on the bar after
|
|
18
|
+
// the one it traded on. `run()` has no gap to put them in.
|
|
19
|
+
//
|
|
20
|
+
// It is also the loop the backtest uses, which is the point: a chart drawing a
|
|
21
|
+
// strategy and a report of the same strategy walk the same bars in the same
|
|
22
|
+
// order against the same venue, so they cannot disagree about what filled.
|
|
23
|
+
const held = started.venue === null
|
|
24
|
+
? runWhole(engine, bars, ctx, program, settings)
|
|
25
|
+
: walkWith(engine, started.venue, bars, ctx, program, settings);
|
|
21
26
|
store[HELD] = held;
|
|
22
27
|
station.settle();
|
|
23
28
|
return outputOf(program, engine);
|
|
@@ -51,11 +56,28 @@ _options) {
|
|
|
51
56
|
if (bar === undefined)
|
|
52
57
|
return null;
|
|
53
58
|
const state = stateFor(index, bars, ctx);
|
|
59
|
+
// The venue's answers about the bar before this one, delivered before this
|
|
60
|
+
// one runs, exactly as the full walk does. A tail that skipped this would
|
|
61
|
+
// draw the first bars of a strategy correctly and then quietly stop folding
|
|
62
|
+
// its fills the moment the chart went live, which is the half of the run
|
|
63
|
+
// nobody re-checks.
|
|
64
|
+
//
|
|
65
|
+
// Only when the bar is new. Re-executing the bar that moved must not
|
|
66
|
+
// deliver again: a frame is cumulative and folding one twice is harmless,
|
|
67
|
+
// but the bar's own orders have been rolled back and answering them a
|
|
68
|
+
// second time would fill an order the engine no longer knows it sent.
|
|
69
|
+
if (held.venue !== null && index !== from) {
|
|
70
|
+
for (const frame of held.venue.pending)
|
|
71
|
+
held.engine.deliver(frame);
|
|
72
|
+
held.venue.pending = [];
|
|
73
|
+
}
|
|
54
74
|
const result = index === from
|
|
55
75
|
? held.engine.update(hostBar(bar), state)
|
|
56
76
|
: held.engine.append(hostBar(bar), state);
|
|
57
77
|
if (result.diagnostic !== undefined)
|
|
58
78
|
throw stopped(result.diagnostic);
|
|
79
|
+
if (held.venue !== null)
|
|
80
|
+
answersFor(held.venue, index);
|
|
59
81
|
}
|
|
60
82
|
held.count = bars.length;
|
|
61
83
|
held.lastTime = bars[bars.length - 1]?.time ?? held.lastTime;
|
|
@@ -86,10 +108,38 @@ function outputOf(program, engine) {
|
|
|
86
108
|
// `tables.ts`'s own first paragraph.
|
|
87
109
|
return { columns, tables: engine.tables(), drawings: engine.drawings() };
|
|
88
110
|
}
|
|
89
|
-
|
|
111
|
+
/**
|
|
112
|
+
* Load the program, and give a strategy somewhere for its orders to go.
|
|
113
|
+
*
|
|
114
|
+
* **The venue is built after the load and reached through a holder, because
|
|
115
|
+
* neither can come first.** The route has to be handed to `load`, since that is
|
|
116
|
+
* what declares the `orders` capability and a program needing one is otherwise
|
|
117
|
+
* refused. The venue has to be built after it, because the declaration it reads
|
|
118
|
+
* may state its fill rule through an `input()`, and inputs are not resolved
|
|
119
|
+
* until `load` has run. The route is only ever called from inside an execution,
|
|
120
|
+
* which is after both, so the holder is always filled by the time anything
|
|
121
|
+
* reaches it.
|
|
122
|
+
*
|
|
123
|
+
* **A host that supplied its own route keeps it.** Somewhere real to send an
|
|
124
|
+
* order is a better destination than a simulated one, and a host that wired one
|
|
125
|
+
* up meant it.
|
|
126
|
+
*
|
|
127
|
+
* **And simulation is asked for rather than assumed.** Without
|
|
128
|
+
* `simulateOrders` a strategy with nowhere to send an order is still refused at
|
|
129
|
+
* load, which is the answer a host that meant to wire a destination and forgot
|
|
130
|
+
* needs to see. Filling in a venue for them would turn that mistake into a
|
|
131
|
+
* chart that draws convincingly and routes nothing, discovered whenever
|
|
132
|
+
* somebody next looked for the orders.
|
|
133
|
+
*/
|
|
134
|
+
function start(program, settings, ctx, options, requests, bars) {
|
|
135
|
+
const holder = { current: null };
|
|
136
|
+
const simulate = options.simulateOrders === true && options.orders === undefined && needsVenue(program);
|
|
137
|
+
const withRoute = simulate
|
|
138
|
+
? { ...options, orders: routeInto(holder) }
|
|
139
|
+
: options;
|
|
90
140
|
const loaded = load(program, {
|
|
91
141
|
settings: engineSettings(program, settings),
|
|
92
|
-
host: hostFor(ctx,
|
|
142
|
+
host: hostFor(ctx, withRoute, requests),
|
|
93
143
|
time: timeFor(options, ctx?.timezone ?? ''),
|
|
94
144
|
...(options.limits === undefined ? {} : { limits: options.limits }),
|
|
95
145
|
...(options.source === undefined ? {} : { source: options.source }),
|
|
@@ -97,7 +147,13 @@ function start(program, settings, ctx, options, requests) {
|
|
|
97
147
|
});
|
|
98
148
|
if (!loaded.ok)
|
|
99
149
|
throw refused(loaded.diagnostic);
|
|
100
|
-
|
|
150
|
+
if (!simulate)
|
|
151
|
+
return { engine: loaded.engine, venue: null };
|
|
152
|
+
const venue = venueFor(program, bars, loaded.inputs, instrumentFor(ctx, options));
|
|
153
|
+
if (venue === null)
|
|
154
|
+
return { engine: loaded.engine, venue: null };
|
|
155
|
+
holder.current = venue;
|
|
156
|
+
return { engine: loaded.engine, venue: { venue, pending: [] } };
|
|
101
157
|
}
|
|
102
158
|
/**
|
|
103
159
|
* The host the engine reads, which always serves requests.
|
|
@@ -109,8 +165,16 @@ function start(program, settings, ctx, options, requests) {
|
|
|
109
165
|
* the chart's own sentence in `req.error`, instead of being refused at load
|
|
110
166
|
* with OS6006 naming a capability the chart does have.
|
|
111
167
|
*/
|
|
112
|
-
|
|
113
|
-
|
|
168
|
+
/**
|
|
169
|
+
* The instrument record, from what the host stated and what the chart knows.
|
|
170
|
+
*
|
|
171
|
+
* Its own function because two callers need it and they must not each build
|
|
172
|
+
* one: the engine is loaded with this record, and the venue prices fills
|
|
173
|
+
* against the tick size in it. Two spellings of the same record is how a fill
|
|
174
|
+
* gets rounded to a tick the strategy was never told about.
|
|
175
|
+
*/
|
|
176
|
+
function instrumentFor(ctx, options) {
|
|
177
|
+
return {
|
|
114
178
|
...(options.instrument ?? {}),
|
|
115
179
|
...(ctx?.symbol === undefined ? {} : { symbol: ctx.symbol }),
|
|
116
180
|
...(ctx?.interval === undefined ? {} : { interval: ctx.interval }),
|
|
@@ -121,6 +185,9 @@ function hostFor(ctx, options, requests) {
|
|
|
121
185
|
// the chart it was drawn on.
|
|
122
186
|
...(ctx === undefined || ctx.timezone === '' ? {} : { timezone: ctx.timezone }),
|
|
123
187
|
};
|
|
188
|
+
}
|
|
189
|
+
function hostFor(ctx, options, requests) {
|
|
190
|
+
const instrument = instrumentFor(ctx, options);
|
|
124
191
|
return {
|
|
125
192
|
instrument,
|
|
126
193
|
requestBars: requests,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/adapters/charts/run.ts"],"names":[],"mappings":"AAmCA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEvD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/adapters/charts/run.ts"],"names":[],"mappings":"AAmCA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEvD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEzE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AA+GlD,oEAAoE;AACpE,gFAAgF;AAChF,MAAM,IAAI,GAAG,YAAY,CAAC;AAoB1B,MAAM,UAAU,OAAO,CACrB,OAAwB,EACxB,IAAyB,EACzB,QAAuB,EACvB,KAAiB,EACjB,GAAiC,EACjC,OAA4B;IAE5B,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IACjC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;IACrF,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAE9B,yEAAyE;IACzE,8EAA8E;IAC9E,8EAA8E;IAC9E,2DAA2D;IAC3D,EAAE;IACF,+EAA+E;IAC/E,4EAA4E;IAC5E,2EAA2E;IAC3E,MAAM,IAAI,GAAS,OAAO,CAAC,KAAK,KAAK,IAAI;QACvC,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,CAAC;QAChD,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IAClE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACnB,OAAO,CAAC,MAAM,EAAE,CAAC;IACjB,OAAO,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AACnC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,OAAO,CACrB,OAAwB,EACxB,IAAyB,EACzB,IAAY,EACZ,QAAuB,EACvB,KAAiB,EACjB,GAAiC;AACjC,4EAA4E;AAC5E,8DAA8D;AAC9D,QAA6B;IAE7B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAqB,CAAC;IAC7C,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAC1D,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACjF,IAAI,IAAI,CAAC,SAAS,KAAK,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IACnE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IACzD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAE3D,KAAK,IAAI,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACvD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QACnC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QAEzC,2EAA2E;QAC3E,0EAA0E;QAC1E,4EAA4E;QAC5E,yEAAyE;QACzE,oBAAoB;QACpB,EAAE;QACF,qEAAqE;QACrE,0EAA0E;QAC1E,sEAAsE;QACtE,sEAAsE;QACtE,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAC1C,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO;gBAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YACnE,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC;QAC1B,CAAC;QAED,MAAM,MAAM,GACV,KAAK,KAAK,IAAI;YACZ,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;YACzC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;QAC9C,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS;YAAE,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAEtE,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI;YAAE,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACzD,CAAC;IAED,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;IACzB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC;IAC7D,8EAA8E;IAC9E,wEAAwE;IACxE,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;AACxC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,KAAiB;IACvC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC;IACnB,SAAS,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC;AAC5B,CAAC;AAED,SAAS,QAAQ,CAAC,OAAwB,EAAE,MAAc;IACxD,MAAM,OAAO,GAAyB,EAAE,CAAC;IACzC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;QACtE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACvC,CAAC;IACD,8EAA8E;IAC9E,2EAA2E;IAC3E,qCAAqC;IACrC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;AAC3E,CAAC;AAQD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,SAAS,KAAK,CACZ,OAAwB,EACxB,QAAuB,EACvB,GAAiC,EACjC,OAA4B,EAC5B,QAAyB,EACzB,IAAyB;IAEzB,MAAM,MAAM,GAAkC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAChE,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc,KAAK,IAAI,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;IACxG,MAAM,SAAS,GAAwB,QAAQ;QAC7C,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE;QAC3C,CAAC,CAAC,OAAO,CAAC;IAEZ,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE;QAC3B,QAAQ,EAAE,cAAc,CAAC,OAAO,EAAE,QAAQ,CAAC;QAC3C,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,CAAC;QACvC,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,QAAQ,IAAI,EAAE,CAAC;QAC3C,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;QACnE,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;QACnE,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;KACjE,CAAC,CAAC;IACH,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAEjD,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAE7D,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;IAClF,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAClE,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC;IACvB,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC;AAClE,CAAC;AAED;;;;;;;;;GASG;AACH;;;;;;;GAOG;AACH,SAAS,aAAa,CACpB,GAAiC,EACjC,OAA4B;IAE5B,OAAO;QACL,GAAG,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;QAC7B,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC;QAC5D,GAAG,CAAC,GAAG,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC;QAClE,GAAG,CAAC,GAAG,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC;QAClE,0EAA0E;QAC1E,2EAA2E;QAC3E,4EAA4E;QAC5E,6BAA6B;QAC7B,GAAG,CAAC,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC;KAChF,CAAC;AACJ,CAAC;AAED,SAAS,OAAO,CACd,GAAiC,EACjC,OAA4B,EAC5B,QAAyB;IAEzB,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC/C,OAAO;QACL,UAAU;QACV,WAAW,EAAE,QAAQ;QACrB,GAAG,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;QACzD,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;KACnE,CAAC;AACJ,CAAC;AAED,SAAS,OAAO,CAAC,OAA4B,EAAE,QAAgB;IAC7D,MAAM,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC;IACpC,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC;IAC1C,OAAO,CAAC,IAAY,EAAiB,EAAE;QACrC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YACxC,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5D,CAAC;QAAC,MAAM,CAAC;YACP,0EAA0E;YAC1E,uEAAuE;YACvE,uEAAuE;YACvE,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The destination a strategy runs against when a chart draws one.
|
|
3
|
+
*
|
|
4
|
+
* **Why a chart needs one at all.** A strategy asks a destination to do things
|
|
5
|
+
* and folds its position from what comes back. Handed no destination it is
|
|
6
|
+
* refused at load with OS6006, and handed one that answers nothing it runs but
|
|
7
|
+
* never learns it is in a position: every `close()` closes nothing, every entry
|
|
8
|
+
* is allowed again on the next signal, and the study draws a strategy that is
|
|
9
|
+
* wrong about itself while looking entirely normal. Measured on a stop and
|
|
10
|
+
* reverse script, that shape produced five buys and no sells.
|
|
11
|
+
*
|
|
12
|
+
* **It is the backtest's own venue, not a second one.** `Simulator` is what
|
|
13
|
+
* `backtest()` runs against, so a chart running a strategy through it fills the
|
|
14
|
+
* same orders at the same prices as the report the trader ran a moment ago. A
|
|
15
|
+
* venue written here to be simpler would be a second answer to "what would this
|
|
16
|
+
* have filled at", and the two would disagree the first time either changed:
|
|
17
|
+
* the chart would draw one set of trades and the report would list another.
|
|
18
|
+
*
|
|
19
|
+
* **What a chart supplies and what it invents.** The bars, the instrument and
|
|
20
|
+
* the declaration are the chart's own and are passed through. Money is not: a
|
|
21
|
+
* chart draws a strategy, it does not report one, so the currency, the point
|
|
22
|
+
* value and the rounding are stated here as the neutral values that make the
|
|
23
|
+
* accounting a no-op. Nothing a chart draws reads them, and a chart that
|
|
24
|
+
* guessed a point value would put a wrong profit in front of somebody.
|
|
25
|
+
*
|
|
26
|
+
* **Nothing here decides when a fill happens.** The declaration does, through
|
|
27
|
+
* `fillOn`, and the venue reads it. A market order priced at the next bar's
|
|
28
|
+
* open is known at that open; one that rested and traded inside a bar is known
|
|
29
|
+
* once the bar is complete. Both are what a venue could have told anybody at
|
|
30
|
+
* the time, and that is the whole reason the frames arrive between bars rather
|
|
31
|
+
* than inside the execution that sent them.
|
|
32
|
+
*/
|
|
33
|
+
import { Simulator } from '../../core/backtest/index.js';
|
|
34
|
+
import type { CompiledProgram } from '../../core/emit/index.js';
|
|
35
|
+
import type { Instrument, OrderFrame, ResolvedInput, RoutedEffect } from '../../core/engine/index.js';
|
|
36
|
+
import type { ChartBar } from './contract.js';
|
|
37
|
+
/**
|
|
38
|
+
* Whether this program needs a destination before it can run at all.
|
|
39
|
+
*
|
|
40
|
+
* Read from the program's own declared capabilities rather than from whether
|
|
41
|
+
* its source said `strategy()`, because `requires` is the same fact the engine
|
|
42
|
+
* tests at load. A strategy that places no orders needs none, and anything that
|
|
43
|
+
* does need one is refused without it.
|
|
44
|
+
*/
|
|
45
|
+
export declare function needsVenue(program: CompiledProgram): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* The venue for one chart run, or nothing where the program does not need one.
|
|
48
|
+
*
|
|
49
|
+
* `inputs` are the ones the engine resolved at load, because a declaration
|
|
50
|
+
* field may be written as an `input()`: a script whose `fillOn` comes from a
|
|
51
|
+
* setting would otherwise be filled the way its source happened to be written
|
|
52
|
+
* rather than the way the trader is running it.
|
|
53
|
+
*/
|
|
54
|
+
export declare function venueFor(program: CompiledProgram, bars: readonly ChartBar[], inputs: readonly ResolvedInput[], instrument: Instrument | undefined): Simulator | null;
|
|
55
|
+
/**
|
|
56
|
+
* A venue that can be asked for frames, held across a chart's recomputes.
|
|
57
|
+
*
|
|
58
|
+
* The bars a `Simulator` prices against are the ones it was built with, so a
|
|
59
|
+
* chart that has grown a bar needs a venue that knows about it. `extend` is how
|
|
60
|
+
* the tail path says so without rebuilding the orders it is already holding.
|
|
61
|
+
*/
|
|
62
|
+
export interface HeldVenue {
|
|
63
|
+
readonly venue: Simulator;
|
|
64
|
+
/** Frames the venue answered for a bar, waiting to be delivered before the next. */
|
|
65
|
+
pending: readonly OrderFrame[];
|
|
66
|
+
}
|
|
67
|
+
/** What a venue has to say after one bar, which the next bar's engine reads. */
|
|
68
|
+
export declare function answersFor(held: HeldVenue, barIndex: number): void;
|
|
69
|
+
/** The route an engine is loaded with, pointing at a venue built after it. */
|
|
70
|
+
export declare function routeInto(holder: {
|
|
71
|
+
current: Simulator | null;
|
|
72
|
+
}): (effect: RoutedEffect, bar: number) => void;
|
|
73
|
+
//# sourceMappingURL=venue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"venue.d.ts","sourceRoot":"","sources":["../../../src/adapters/charts/venue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAgB,SAAS,EAAiB,MAAM,8BAA8B,CAAC;AAEtF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AACtG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAE5D;AAeD;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CACtB,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,SAAS,QAAQ,EAAE,EACzB,MAAM,EAAE,SAAS,aAAa,EAAE,EAChC,UAAU,EAAE,UAAU,GAAG,SAAS,GACjC,SAAS,GAAG,IAAI,CA0BlB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,oFAAoF;IACpF,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;CAChC;AAED,gFAAgF;AAChF,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAElE;AAED,8EAA8E;AAC9E,wBAAgB,SAAS,CAAC,MAAM,EAAE;IAAE,OAAO,EAAE,SAAS,GAAG,IAAI,CAAA;CAAE,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAO5G"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The destination a strategy runs against when a chart draws one.
|
|
3
|
+
*
|
|
4
|
+
* **Why a chart needs one at all.** A strategy asks a destination to do things
|
|
5
|
+
* and folds its position from what comes back. Handed no destination it is
|
|
6
|
+
* refused at load with OS6006, and handed one that answers nothing it runs but
|
|
7
|
+
* never learns it is in a position: every `close()` closes nothing, every entry
|
|
8
|
+
* is allowed again on the next signal, and the study draws a strategy that is
|
|
9
|
+
* wrong about itself while looking entirely normal. Measured on a stop and
|
|
10
|
+
* reverse script, that shape produced five buys and no sells.
|
|
11
|
+
*
|
|
12
|
+
* **It is the backtest's own venue, not a second one.** `Simulator` is what
|
|
13
|
+
* `backtest()` runs against, so a chart running a strategy through it fills the
|
|
14
|
+
* same orders at the same prices as the report the trader ran a moment ago. A
|
|
15
|
+
* venue written here to be simpler would be a second answer to "what would this
|
|
16
|
+
* have filled at", and the two would disagree the first time either changed:
|
|
17
|
+
* the chart would draw one set of trades and the report would list another.
|
|
18
|
+
*
|
|
19
|
+
* **What a chart supplies and what it invents.** The bars, the instrument and
|
|
20
|
+
* the declaration are the chart's own and are passed through. Money is not: a
|
|
21
|
+
* chart draws a strategy, it does not report one, so the currency, the point
|
|
22
|
+
* value and the rounding are stated here as the neutral values that make the
|
|
23
|
+
* accounting a no-op. Nothing a chart draws reads them, and a chart that
|
|
24
|
+
* guessed a point value would put a wrong profit in front of somebody.
|
|
25
|
+
*
|
|
26
|
+
* **Nothing here decides when a fill happens.** The declaration does, through
|
|
27
|
+
* `fillOn`, and the venue reads it. A market order priced at the next bar's
|
|
28
|
+
* open is known at that open; one that rested and traded inside a bar is known
|
|
29
|
+
* once the bar is complete. Both are what a venue could have told anybody at
|
|
30
|
+
* the time, and that is the whole reason the frames arrive between bars rather
|
|
31
|
+
* than inside the execution that sent them.
|
|
32
|
+
*/
|
|
33
|
+
import { DEFAULT_FILL, Simulator, declarationOf } from '../../core/backtest/index.js';
|
|
34
|
+
/**
|
|
35
|
+
* Whether this program needs a destination before it can run at all.
|
|
36
|
+
*
|
|
37
|
+
* Read from the program's own declared capabilities rather than from whether
|
|
38
|
+
* its source said `strategy()`, because `requires` is the same fact the engine
|
|
39
|
+
* tests at load. A strategy that places no orders needs none, and anything that
|
|
40
|
+
* does need one is refused without it.
|
|
41
|
+
*/
|
|
42
|
+
export function needsVenue(program) {
|
|
43
|
+
return program.requires.includes('orders');
|
|
44
|
+
}
|
|
45
|
+
/** One chart bar as the venue reads it. */
|
|
46
|
+
function recorded(bar) {
|
|
47
|
+
return {
|
|
48
|
+
time: bar.time,
|
|
49
|
+
open: bar.open,
|
|
50
|
+
high: bar.high,
|
|
51
|
+
low: bar.low,
|
|
52
|
+
close: bar.close,
|
|
53
|
+
volume: bar.volume ?? null,
|
|
54
|
+
oi: bar.oi ?? null,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The venue for one chart run, or nothing where the program does not need one.
|
|
59
|
+
*
|
|
60
|
+
* `inputs` are the ones the engine resolved at load, because a declaration
|
|
61
|
+
* field may be written as an `input()`: a script whose `fillOn` comes from a
|
|
62
|
+
* setting would otherwise be filled the way its source happened to be written
|
|
63
|
+
* rather than the way the trader is running it.
|
|
64
|
+
*/
|
|
65
|
+
export function venueFor(program, bars, inputs, instrument) {
|
|
66
|
+
if (!needsVenue(program))
|
|
67
|
+
return null;
|
|
68
|
+
const declared = declarationOf(program, inputs);
|
|
69
|
+
return new Simulator({
|
|
70
|
+
bars: bars.map(recorded),
|
|
71
|
+
contract: {
|
|
72
|
+
symbol: instrument?.symbol ?? null,
|
|
73
|
+
exchange: instrument?.exchange ?? null,
|
|
74
|
+
// Neutral money. A chart draws a strategy and does not report one, so
|
|
75
|
+
// nothing it puts on screen reads these; stating a point value a host
|
|
76
|
+
// never gave would be inventing the size of somebody's position.
|
|
77
|
+
currency: declared.currency,
|
|
78
|
+
tickSize: instrument?.tickSize ?? null,
|
|
79
|
+
lotSize: null,
|
|
80
|
+
pointValue: 1,
|
|
81
|
+
digits: 2,
|
|
82
|
+
},
|
|
83
|
+
fill: DEFAULT_FILL,
|
|
84
|
+
// The declaration's own, so slippage is applied the way the backtest
|
|
85
|
+
// applies it. Ticks, against the instrument's tick size.
|
|
86
|
+
slippageTicks: declared.slippage,
|
|
87
|
+
fillOn: declared.fillOn,
|
|
88
|
+
qtyType: declared.qtyType,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/** What a venue has to say after one bar, which the next bar's engine reads. */
|
|
92
|
+
export function answersFor(held, barIndex) {
|
|
93
|
+
held.pending = held.venue.framesFor(barIndex);
|
|
94
|
+
}
|
|
95
|
+
/** The route an engine is loaded with, pointing at a venue built after it. */
|
|
96
|
+
export function routeInto(holder) {
|
|
97
|
+
// Late bound on purpose. The route is handed to `load`, and the venue cannot
|
|
98
|
+
// be built until `load` has resolved the inputs the declaration reads. The
|
|
99
|
+
// route is only ever called from inside an execution, which is after both.
|
|
100
|
+
return (effect, bar) => {
|
|
101
|
+
holder.current?.route(effect, bar);
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=venue.js.map
|