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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Diagnostic } from '../diagnostics/index.js';
|
|
2
2
|
import type { CompiledProgram } from '../emit/index.js';
|
|
3
|
-
import type {
|
|
3
|
+
import type { Instrument } from '../engine/index.js';
|
|
4
|
+
import type { RecordedBar, RecordedFrame, RunRecord } from './record.js';
|
|
4
5
|
import type { BacktestSettings } from './settings.js';
|
|
5
6
|
/** What a run came to, or why it could not be carried out at all. */
|
|
6
7
|
export type BacktestResult = {
|
|
@@ -10,20 +11,77 @@ export type BacktestResult = {
|
|
|
10
11
|
readonly ok: false;
|
|
11
12
|
readonly diagnostic: Diagnostic;
|
|
12
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* The facts of `host-interface.md` 4.1 that the contract does not hold.
|
|
16
|
+
*
|
|
17
|
+
* The contract already states six of the twelve, the ones the money is priced
|
|
18
|
+
* under, and a fact stated in two places is a fact that can disagree with
|
|
19
|
+
* itself: a tick size the engine rounds to and a different one the venue
|
|
20
|
+
* worsens a fill by is a run under two instruments. So the other six are
|
|
21
|
+
* stated here and the six the contract holds cannot be, which the compiler
|
|
22
|
+
* enforces rather than a check at run time.
|
|
23
|
+
*/
|
|
24
|
+
export type InstrumentFacts = Omit<Instrument, 'symbol' | 'exchange' | 'tickSize' | 'lotSize' | 'pointValue' | 'currency'>;
|
|
13
25
|
/** The few choices a driver has that are not settings of the run itself. */
|
|
14
26
|
export interface DriveOptions {
|
|
15
27
|
/** Whether the bars travel in the record. Inline is the conformance form. */
|
|
16
28
|
readonly form?: 'inline' | 'referenced';
|
|
29
|
+
/**
|
|
30
|
+
* What the host states about the instrument beside the contract, so the
|
|
31
|
+
* record it produces is a conformance case.
|
|
32
|
+
*
|
|
33
|
+
* A case holds `instrument.json`, which `conformance.md` section 2 says is
|
|
34
|
+
* the record of `host-interface.md` 4.1, and that page requires one fact of
|
|
35
|
+
* every host: `hasVolume`, because no derivation recovers it (4.2). The
|
|
36
|
+
* engine reads the record and does not refuse a run without it, so a caller
|
|
37
|
+
* that leaves this out gets a record that replays and reruns like any other
|
|
38
|
+
* and cannot become a case, exactly as one without `sourceText` cannot.
|
|
39
|
+
*
|
|
40
|
+
* A session stated without a timezone is refused at load, OS6012, by the
|
|
41
|
+
* same rule that refuses it for any host.
|
|
42
|
+
*/
|
|
43
|
+
readonly instrument?: InstrumentFacts;
|
|
44
|
+
/**
|
|
45
|
+
* The script's own text, so the record it produces is a conformance case.
|
|
46
|
+
*
|
|
47
|
+
* A compiled program identifies its source and cannot reproduce it, and a
|
|
48
|
+
* case has to hold `script.os`. A caller holding only a program leaves this
|
|
49
|
+
* out and gets a record that replays and reruns like any other; the one
|
|
50
|
+
* thing it cannot do is be handed to somebody else's engine as a case.
|
|
51
|
+
*
|
|
52
|
+
* It is checked against the program's own source hash, so text from a
|
|
53
|
+
* different revision than the one that was compiled is refused rather than
|
|
54
|
+
* written into a case that could never make its own expected output.
|
|
55
|
+
*/
|
|
56
|
+
readonly sourceText?: string;
|
|
17
57
|
}
|
|
18
58
|
/**
|
|
19
|
-
* One run, from a compiled program to a record
|
|
59
|
+
* One run against a simulated destination, from a compiled program to a record.
|
|
20
60
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* be a document asserting figures nothing computed. A failure during a bar is
|
|
25
|
-
* the other way round: the run happened, it stopped, and the record carries
|
|
26
|
-
* both what it did and the diagnostic that stopped it.
|
|
61
|
+
* The frames are the destination's own: it is handed the orders, it reads the
|
|
62
|
+
* bars, and what it answers is what the engine folds. A run whose frames
|
|
63
|
+
* somebody else is supplying is `backtestSupplied` below.
|
|
27
64
|
*/
|
|
28
65
|
export declare function backtest(program: CompiledProgram, bars: readonly RecordedBar[], settings: BacktestSettings, options?: DriveOptions): BacktestResult;
|
|
66
|
+
/**
|
|
67
|
+
* One run over the frames somebody else supplied, which this engine does not
|
|
68
|
+
* choose and does not add to.
|
|
69
|
+
*
|
|
70
|
+
* `conformance.md` section 3 gives a case a `frames.csv` that supplies order
|
|
71
|
+
* frames the way `bars.csv` supplies bars, so that a case asserts the fold
|
|
72
|
+
* against input the engine did not choose. Every other argument is `backtest`'s
|
|
73
|
+
* and means there what it means here. A row is delivered at the boundary it
|
|
74
|
+
* names and folded before the next bar, and the record carries the rows it was
|
|
75
|
+
* handed rather than a second spelling of them.
|
|
76
|
+
*
|
|
77
|
+
* **Nothing is invented.** No fill is priced off a bar, no order rests and no
|
|
78
|
+
* schedule is read, so an order the frames say nothing about stays where its
|
|
79
|
+
* placement left it, which is what a case saying nothing about it means.
|
|
80
|
+
*
|
|
81
|
+
* **A record made here is a record of this run and not of a simulated one.**
|
|
82
|
+
* `rerun` puts a record's program back on a simulated destination, because a
|
|
83
|
+
* record does not say which of the two answered it, so a rerun of one of these
|
|
84
|
+
* reproduces it only where that destination would answer these same frames.
|
|
85
|
+
*/
|
|
86
|
+
export declare function backtestSupplied(program: CompiledProgram, bars: readonly RecordedBar[], settings: BacktestSettings, frames: readonly RecordedFrame[], options?: DriveOptions): BacktestResult;
|
|
29
87
|
//# sourceMappingURL=drive.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drive.d.ts","sourceRoot":"","sources":["../../../src/core/backtest/drive.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"drive.d.ts","sourceRoot":"","sources":["../../../src/core/backtest/drive.ts"],"names":[],"mappings":"AAqCA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD,OAAO,KAAK,EAIV,UAAU,EAIX,MAAM,oBAAoB,CAAC;AAQ5B,OAAO,KAAK,EACV,WAAW,EAEX,aAAa,EAEb,SAAS,EACV,MAAM,aAAa,CAAC;AAGrB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,qEAAqE;AACrE,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;CAAE,GACjD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAA;CAAE,CAAC;AAE5D;;;;;;;;;GASG;AACH,MAAM,MAAM,eAAe,GAAG,IAAI,CAChC,UAAU,EACV,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,YAAY,GAAG,UAAU,CAC3E,CAAC;AAEF,4EAA4E;AAC5E,MAAM,WAAW,YAAY;IAC3B,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,YAAY,CAAC;IACxC;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,CAAC;IACtC;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CACtB,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,SAAS,WAAW,EAAE,EAC5B,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,GAAE,YAAiB,GACzB,cAAc,CAahB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,SAAS,WAAW,EAAE,EAC5B,QAAQ,EAAE,gBAAgB,EAC1B,MAAM,EAAE,SAAS,aAAa,EAAE,EAChC,OAAO,GAAE,YAAiB,GACzB,cAAc,CAEhB"}
|
|
@@ -25,16 +25,64 @@
|
|
|
25
25
|
* is reported on bar k + 1. A frame answered after the last bar has no boundary
|
|
26
26
|
* left to fold at: it is not delivered, it is not recorded as delivered, and
|
|
27
27
|
* the order it was about is in the ledger at whatever it last said.
|
|
28
|
+
*
|
|
29
|
+
* **Two drivers, and the only difference between them is where the frames come
|
|
30
|
+
* from.** `backtest` runs against the simulated destination, which decides a
|
|
31
|
+
* fill from the bars and answers frames of its own; `backtestSupplied` is
|
|
32
|
+
* handed the frames and delivers those. Everything else about the two is one
|
|
33
|
+
* function below: the same window, the same load, the same refusals, the same
|
|
34
|
+
* loop and the same record.
|
|
28
35
|
*/
|
|
29
36
|
import { reportOf, scheduleFromDeclaration } from '../accounting/index.js';
|
|
30
37
|
import { load } from '../engine/index.js';
|
|
31
38
|
import { declarationOf } from './declaration.js';
|
|
39
|
+
import { Delivery, framedAs, ordinalsOf } from './deliver.js';
|
|
32
40
|
import { marksFor, windowFor } from './range.js';
|
|
33
41
|
import { diagnosticIn, orderIn, recordOf } from './record.js';
|
|
34
42
|
import { Simulator } from './simulate.js';
|
|
35
43
|
import { checkSettings } from './settings.js';
|
|
36
44
|
/**
|
|
37
|
-
* One run, from a compiled program to a record
|
|
45
|
+
* One run against a simulated destination, from a compiled program to a record.
|
|
46
|
+
*
|
|
47
|
+
* The frames are the destination's own: it is handed the orders, it reads the
|
|
48
|
+
* bars, and what it answers is what the engine folds. A run whose frames
|
|
49
|
+
* somebody else is supplying is `backtestSupplied` below.
|
|
50
|
+
*/
|
|
51
|
+
export function backtest(program, bars, settings, options = {}) {
|
|
52
|
+
return drive(program, bars, settings, options, (declared, schedule) => simulated(new Simulator({
|
|
53
|
+
bars,
|
|
54
|
+
contract: settings.contract,
|
|
55
|
+
fill: settings.fill,
|
|
56
|
+
slippageTicks: schedule.slippageTicks,
|
|
57
|
+
fillOn: declared.fillOn,
|
|
58
|
+
qtyType: declared.qtyType,
|
|
59
|
+
})));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* One run over the frames somebody else supplied, which this engine does not
|
|
63
|
+
* choose and does not add to.
|
|
64
|
+
*
|
|
65
|
+
* `conformance.md` section 3 gives a case a `frames.csv` that supplies order
|
|
66
|
+
* frames the way `bars.csv` supplies bars, so that a case asserts the fold
|
|
67
|
+
* against input the engine did not choose. Every other argument is `backtest`'s
|
|
68
|
+
* and means there what it means here. A row is delivered at the boundary it
|
|
69
|
+
* names and folded before the next bar, and the record carries the rows it was
|
|
70
|
+
* handed rather than a second spelling of them.
|
|
71
|
+
*
|
|
72
|
+
* **Nothing is invented.** No fill is priced off a bar, no order rests and no
|
|
73
|
+
* schedule is read, so an order the frames say nothing about stays where its
|
|
74
|
+
* placement left it, which is what a case saying nothing about it means.
|
|
75
|
+
*
|
|
76
|
+
* **A record made here is a record of this run and not of a simulated one.**
|
|
77
|
+
* `rerun` puts a record's program back on a simulated destination, because a
|
|
78
|
+
* record does not say which of the two answered it, so a rerun of one of these
|
|
79
|
+
* reproduces it only where that destination would answer these same frames.
|
|
80
|
+
*/
|
|
81
|
+
export function backtestSupplied(program, bars, settings, frames, options = {}) {
|
|
82
|
+
return drive(program, bars, settings, options, () => new Delivery(frames));
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The run both drivers are, and the one place a record is made.
|
|
38
86
|
*
|
|
39
87
|
* A refusal before the first bar comes back as a refusal and not as a record:
|
|
40
88
|
* a program that would not load, a setting that cannot be applied and a window
|
|
@@ -42,19 +90,22 @@ import { checkSettings } from './settings.js';
|
|
|
42
90
|
* be a document asserting figures nothing computed. A failure during a bar is
|
|
43
91
|
* the other way round: the run happened, it stopped, and the record carries
|
|
44
92
|
* both what it did and the diagnostic that stopped it.
|
|
93
|
+
*
|
|
94
|
+
* **The destination is chosen after the program is loaded**, which is why it
|
|
95
|
+
* arrives as a function of the declaration and the schedule: the bar a market
|
|
96
|
+
* order is priced at is the declaration's, and the declaration is resolved at
|
|
97
|
+
* load. The route is wired first and reaches whatever is chosen through the
|
|
98
|
+
* binding below, which is what lets one host serve both halves.
|
|
45
99
|
*/
|
|
46
|
-
|
|
100
|
+
function drive(program, bars, settings, options, choose) {
|
|
47
101
|
const framed = windowFor(bars, settings.range);
|
|
48
102
|
if (!framed.ok)
|
|
49
103
|
return { ok: false, diagnostic: framed.diagnostic };
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
// load. The route is wired first and reaches it through this binding, which
|
|
53
|
-
// is what lets one host serve both halves.
|
|
54
|
-
let venue;
|
|
104
|
+
let sending;
|
|
105
|
+
const instrument = instrumentFor(settings.contract, options.instrument ?? {});
|
|
55
106
|
const loaded = load(program, {
|
|
56
107
|
settings: settings.inputs,
|
|
57
|
-
host: hostFor(settings, (effect, bar) =>
|
|
108
|
+
host: hostFor(instrument, settings.now, (effect, bar) => sending?.route(effect, bar)),
|
|
58
109
|
});
|
|
59
110
|
if (!loaded.ok)
|
|
60
111
|
return { ok: false, diagnostic: loaded.diagnostic };
|
|
@@ -64,32 +115,39 @@ export function backtest(program, bars, settings, options = {}) {
|
|
|
64
115
|
if (problem !== null)
|
|
65
116
|
return { ok: false, diagnostic: problem };
|
|
66
117
|
const schedule = scheduleFor(settings, declared);
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
slippageTicks: schedule.slippageTicks,
|
|
72
|
-
fillOn: declared.fillOn,
|
|
73
|
-
qtyType: declared.qtyType,
|
|
74
|
-
});
|
|
75
|
-
const run = walk(engine, venue, bars, framed.covered);
|
|
76
|
-
const ordinals = ordinalsOf(venue.intents);
|
|
118
|
+
const destination = choose(declared, schedule);
|
|
119
|
+
sending = destination;
|
|
120
|
+
const run = walk(engine, destination, bars, framed.covered);
|
|
121
|
+
const ordinals = ordinalsOf(destination.intents);
|
|
77
122
|
const marks = marksFor(bars, framed.covered);
|
|
78
123
|
return {
|
|
79
124
|
ok: true,
|
|
80
125
|
record: recordOf({
|
|
81
126
|
program: engine.program,
|
|
127
|
+
...(options.sourceText === undefined ? {} : { sourceText: options.sourceText }),
|
|
82
128
|
settings,
|
|
129
|
+
instrument,
|
|
83
130
|
bars,
|
|
84
131
|
form: options.form ?? 'inline',
|
|
85
|
-
|
|
132
|
+
// The row where a case supplied one, because that row is the input and a
|
|
133
|
+
// record of a run over it says what it was given rather than what it
|
|
134
|
+
// would have written down had it decided the frame itself.
|
|
135
|
+
frames: run.frames.map((one) => one.row ?? framedAs(one.frame, one.afterBar, ordinals)),
|
|
86
136
|
fills: run.fills,
|
|
87
|
-
orders: ordersOf(engine.orders(),
|
|
137
|
+
orders: ordersOf(engine.orders(), destination.intents, ordinals),
|
|
88
138
|
diagnostics: run.diagnostics,
|
|
89
139
|
report: reportOf(run.fills, marks, schedule, settings.contract, declared.capital),
|
|
90
140
|
}),
|
|
91
141
|
};
|
|
92
142
|
}
|
|
143
|
+
/** The simulated destination, as a destination the loop below can drive. */
|
|
144
|
+
function simulated(venue) {
|
|
145
|
+
return {
|
|
146
|
+
route: (effect, barIndex) => venue.route(effect, barIndex),
|
|
147
|
+
answers: (barIndex) => venue.framesFor(barIndex).map((frame) => ({ frame, afterBar: barIndex, row: null })),
|
|
148
|
+
intents: venue.intents,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
93
151
|
/**
|
|
94
152
|
* The bars, in order, with the venue answering between them.
|
|
95
153
|
*
|
|
@@ -97,7 +155,7 @@ export function backtest(program, bars, settings, options = {}) {
|
|
|
97
155
|
* reported, then ask the venue what this bar did. A driver that asked the venue
|
|
98
156
|
* before appending would price a fill against a bar the strategy had not seen.
|
|
99
157
|
*/
|
|
100
|
-
function walk(engine,
|
|
158
|
+
function walk(engine, destination, bars, covered) {
|
|
101
159
|
const fills = [];
|
|
102
160
|
const frames = [];
|
|
103
161
|
const diagnostics = [];
|
|
@@ -127,7 +185,7 @@ function walk(engine, venue, bars, covered) {
|
|
|
127
185
|
diagnostics.push(diagnosticIn(result.diagnostic, index));
|
|
128
186
|
break;
|
|
129
187
|
}
|
|
130
|
-
pending =
|
|
188
|
+
pending = destination.answers(index);
|
|
131
189
|
}
|
|
132
190
|
return { fills, frames, diagnostics };
|
|
133
191
|
}
|
|
@@ -189,33 +247,6 @@ function intentsIn(result) {
|
|
|
189
247
|
out.push(intent);
|
|
190
248
|
return out;
|
|
191
249
|
}
|
|
192
|
-
/**
|
|
193
|
-
* The ordinal of every intent, which is how a case names one.
|
|
194
|
-
*
|
|
195
|
-
* One, two, three in the order the run placed them, because no engine can know
|
|
196
|
-
* the id another minted and a case that named one would only ever be readable
|
|
197
|
-
* by the engine that wrote it.
|
|
198
|
-
*/
|
|
199
|
-
function ordinalsOf(intents) {
|
|
200
|
-
const out = new Map();
|
|
201
|
-
for (const intent of intents) {
|
|
202
|
-
if (!out.has(intent.intentId))
|
|
203
|
-
out.set(intent.intentId, out.size + 1);
|
|
204
|
-
}
|
|
205
|
-
return out;
|
|
206
|
-
}
|
|
207
|
-
/** One delivered frame, in the columns a case file prints. */
|
|
208
|
-
function framedAs(frame, afterBar, ordinals) {
|
|
209
|
-
return {
|
|
210
|
-
afterBar,
|
|
211
|
-
intent: ordinals.get(frame.intentId) ?? 0,
|
|
212
|
-
status: frame.status,
|
|
213
|
-
filledQty: frame.filledQty,
|
|
214
|
-
avgFillPrice: frame.avgFillPrice ?? null,
|
|
215
|
-
orderRef: frame.orderRef ?? null,
|
|
216
|
-
text: frame.text ?? null,
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
250
|
/** The ledger at the end, copied out of the engine's own array. */
|
|
220
251
|
function ordersOf(rows, intents, ordinals) {
|
|
221
252
|
return rows.map((row) => {
|
|
@@ -236,6 +267,33 @@ function scheduleFor(settings, declared) {
|
|
|
236
267
|
return settings.costs;
|
|
237
268
|
return scheduleFromDeclaration(declared.commission, declared.commissionType, declared.slippage, settings.contract.currency, settings.contract.digits);
|
|
238
269
|
}
|
|
270
|
+
/**
|
|
271
|
+
* The instrument record of `host-interface.md` 4.1 the engine is handed, and
|
|
272
|
+
* the record carries verbatim.
|
|
273
|
+
*
|
|
274
|
+
* Composed once, here, from the contract's six facts and the six stated beside
|
|
275
|
+
* it, so the engine and the record read one document and there is no second
|
|
276
|
+
* composition for the two to disagree by. A fact nobody stated is left out
|
|
277
|
+
* rather than written as undefined: the record travels as JSON, which drops an
|
|
278
|
+
* undefined member, and a document that changes shape in transit is not the
|
|
279
|
+
* document the engine read.
|
|
280
|
+
*/
|
|
281
|
+
function instrumentFor(contract, facts) {
|
|
282
|
+
return {
|
|
283
|
+
...(contract.symbol === null ? {} : { symbol: contract.symbol }),
|
|
284
|
+
...(contract.exchange === null ? {} : { exchange: contract.exchange }),
|
|
285
|
+
...(facts.interval === undefined ? {} : { interval: facts.interval }),
|
|
286
|
+
...(facts.timezone === undefined ? {} : { timezone: facts.timezone }),
|
|
287
|
+
...(contract.tickSize === null ? {} : { tickSize: contract.tickSize }),
|
|
288
|
+
...(contract.lotSize === null ? {} : { lotSize: contract.lotSize }),
|
|
289
|
+
pointValue: contract.pointValue,
|
|
290
|
+
currency: contract.currency,
|
|
291
|
+
...(facts.instrumentType === undefined ? {} : { instrumentType: facts.instrumentType }),
|
|
292
|
+
...(facts.hasVolume === undefined ? {} : { hasVolume: facts.hasVolume }),
|
|
293
|
+
...(facts.hasOpenInterest === undefined ? {} : { hasOpenInterest: facts.hasOpenInterest }),
|
|
294
|
+
...(facts.session === undefined ? {} : { session: facts.session }),
|
|
295
|
+
};
|
|
296
|
+
}
|
|
239
297
|
/**
|
|
240
298
|
* The host a backtest is: an instrument record, a clock and a destination.
|
|
241
299
|
*
|
|
@@ -244,18 +302,10 @@ function scheduleFor(settings, declared) {
|
|
|
244
302
|
* does not have and is refused at load, by name, rather than drawing a line
|
|
245
303
|
* with nothing in it.
|
|
246
304
|
*/
|
|
247
|
-
function hostFor(
|
|
248
|
-
const instrument = {
|
|
249
|
-
...(settings.contract.symbol === null ? {} : { symbol: settings.contract.symbol }),
|
|
250
|
-
...(settings.contract.exchange === null ? {} : { exchange: settings.contract.exchange }),
|
|
251
|
-
...(settings.contract.tickSize === null ? {} : { tickSize: settings.contract.tickSize }),
|
|
252
|
-
...(settings.contract.lotSize === null ? {} : { lotSize: settings.contract.lotSize }),
|
|
253
|
-
pointValue: settings.contract.pointValue,
|
|
254
|
-
currency: settings.contract.currency,
|
|
255
|
-
};
|
|
305
|
+
function hostFor(instrument, now, route) {
|
|
256
306
|
return {
|
|
257
307
|
instrument,
|
|
258
|
-
...(
|
|
308
|
+
...(now === null ? {} : { now }),
|
|
259
309
|
route,
|
|
260
310
|
};
|
|
261
311
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drive.js","sourceRoot":"","sources":["../../../src/core/backtest/drive.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"drive.js","sourceRoot":"","sources":["../../../src/core/backtest/drive.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,18 +14,28 @@
|
|
|
14
14
|
* worsened by a tick and a fill is charged. The engine never adjusts a price and
|
|
15
15
|
* this module never folds one.
|
|
16
16
|
*
|
|
17
|
-
* `backtest` drives one
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
17
|
+
* `backtest` drives one against a simulated destination and `backtestSupplied`
|
|
18
|
+
* drives one over frames somebody else supplied, which is what `conformance.md`
|
|
19
|
+
* section 3 asks of an engine running a case. `replay` folds a stored one's
|
|
20
|
+
* money again from its own fills, and `rerun` executes a stored one again and
|
|
21
|
+
* is held to producing the same bytes. `recordToJson` and `recordFromJson` are
|
|
22
|
+
* the document itself. `compareRuns` puts two records beside each other and
|
|
23
|
+
* says whether the gap between them clears the noise. `caseFilesFrom` turns a
|
|
24
|
+
* record into the files of a conformance case, returning text and writing
|
|
25
|
+
* nothing because core does no I/O. It needed three channels the record did not
|
|
26
|
+
* carry. `conformance.md` section 2 requires a case to hold `script.os`, the
|
|
27
|
+
* source text, and a record carried only the source's hash, its line count and
|
|
28
|
+
* its file name: record version 2 carries the text, checked against that hash.
|
|
29
|
+
* The same section says `instrument.json` is the record of `host-interface.md`
|
|
30
|
+
* 4.1, and a record carried the money layer's contract, which holds six of its
|
|
31
|
+
* twelve facts: record version 3 carries the record the engine was handed,
|
|
32
|
+
* whole. And a case is handed frames, which `stdlib.md` 17.7 folds one ledger
|
|
33
|
+
* field from an instant of: a record carried a frame without the instant it
|
|
34
|
+
* arrived at, so a case projected from it asserted a field its own input could
|
|
35
|
+
* not reproduce. Record version 4 carries a frame's time.
|
|
26
36
|
*/
|
|
27
|
-
export { backtest } from './drive.js';
|
|
28
|
-
export type { BacktestResult, DriveOptions } from './drive.js';
|
|
37
|
+
export { backtest, backtestSupplied } from './drive.js';
|
|
38
|
+
export type { BacktestResult, DriveOptions, InstrumentFacts } from './drive.js';
|
|
29
39
|
export { declarationOf } from './declaration.js';
|
|
30
40
|
export type { RunDeclaration } from './declaration.js';
|
|
31
41
|
export { marksFor, windowFor } from './range.js';
|
|
@@ -35,8 +45,10 @@ export type { ReplayResult } from './replay.js';
|
|
|
35
45
|
export { testResting } from './resting.js';
|
|
36
46
|
export type { RestOutcome, RestingOrder } from './resting.js';
|
|
37
47
|
export { Simulator } from './simulate.js';
|
|
38
|
-
export type { SimulatorOptions } from './simulate.js';
|
|
48
|
+
export type { SimulatorOptions, VenueAct, VenueDoes, VenuePolicy } from './simulate.js';
|
|
39
49
|
export { DEFAULT_FILL, EXACT, WHOLE_RANGE, checkSettings, settingsFor } from './settings.js';
|
|
50
|
+
export { caseFilesFrom } from './case.js';
|
|
51
|
+
export type { CaseFiles, CaseIdentity, CaseResult } from './case.js';
|
|
40
52
|
export { RECORD_VERSION, barsHash, recordFromJson, recordOf, recordToJson, runBytes } from './record.js';
|
|
41
53
|
export type { RecordParts } from './record.js';
|
|
42
54
|
export type { BacktestSettings, DateRange, FillPolicy, Tolerance } from './settings.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/backtest/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/backtest/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACxD,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACjD,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC5C,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,YAAY,EAAE,gBAAgB,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACxF,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC7F,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACzG,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EAAE,gBAAgB,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACxF,YAAY,EACV,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,SAAS,GACV,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -14,23 +14,34 @@
|
|
|
14
14
|
* worsened by a tick and a fill is charged. The engine never adjusts a price and
|
|
15
15
|
* this module never folds one.
|
|
16
16
|
*
|
|
17
|
-
* `backtest` drives one
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
17
|
+
* `backtest` drives one against a simulated destination and `backtestSupplied`
|
|
18
|
+
* drives one over frames somebody else supplied, which is what `conformance.md`
|
|
19
|
+
* section 3 asks of an engine running a case. `replay` folds a stored one's
|
|
20
|
+
* money again from its own fills, and `rerun` executes a stored one again and
|
|
21
|
+
* is held to producing the same bytes. `recordToJson` and `recordFromJson` are
|
|
22
|
+
* the document itself. `compareRuns` puts two records beside each other and
|
|
23
|
+
* says whether the gap between them clears the noise. `caseFilesFrom` turns a
|
|
24
|
+
* record into the files of a conformance case, returning text and writing
|
|
25
|
+
* nothing because core does no I/O. It needed three channels the record did not
|
|
26
|
+
* carry. `conformance.md` section 2 requires a case to hold `script.os`, the
|
|
27
|
+
* source text, and a record carried only the source's hash, its line count and
|
|
28
|
+
* its file name: record version 2 carries the text, checked against that hash.
|
|
29
|
+
* The same section says `instrument.json` is the record of `host-interface.md`
|
|
30
|
+
* 4.1, and a record carried the money layer's contract, which holds six of its
|
|
31
|
+
* twelve facts: record version 3 carries the record the engine was handed,
|
|
32
|
+
* whole. And a case is handed frames, which `stdlib.md` 17.7 folds one ledger
|
|
33
|
+
* field from an instant of: a record carried a frame without the instant it
|
|
34
|
+
* arrived at, so a case projected from it asserted a field its own input could
|
|
35
|
+
* not reproduce. Record version 4 carries a frame's time.
|
|
26
36
|
*/
|
|
27
|
-
export { backtest } from './drive.js';
|
|
37
|
+
export { backtest, backtestSupplied } from './drive.js';
|
|
28
38
|
export { declarationOf } from './declaration.js';
|
|
29
39
|
export { marksFor, windowFor } from './range.js';
|
|
30
40
|
export { replay, rerun } from './replay.js';
|
|
31
41
|
export { testResting } from './resting.js';
|
|
32
42
|
export { Simulator } from './simulate.js';
|
|
33
43
|
export { DEFAULT_FILL, EXACT, WHOLE_RANGE, checkSettings, settingsFor } from './settings.js';
|
|
44
|
+
export { caseFilesFrom } from './case.js';
|
|
34
45
|
export { RECORD_VERSION, barsHash, recordFromJson, recordOf, recordToJson, runBytes } from './record.js';
|
|
35
46
|
export { compareRuns } from './compare.js';
|
|
36
47
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/backtest/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/backtest/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEjD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC7F,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAWzG,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
import type { RecordedFill, Report } from '../accounting/index.js';
|
|
28
28
|
import type { Diagnostic } from '../diagnostics/index.js';
|
|
29
29
|
import type { CompiledProgram, SourceStamp } from '../emit/index.js';
|
|
30
|
-
import type { LedgerRow } from '../engine/index.js';
|
|
30
|
+
import type { Instrument, LedgerRow } from '../engine/index.js';
|
|
31
31
|
import type { BacktestSettings } from './settings.js';
|
|
32
32
|
/** One bar as a record holds it. */
|
|
33
33
|
export interface RecordedBar {
|
|
@@ -68,6 +68,20 @@ export interface RecordedFrame {
|
|
|
68
68
|
readonly avgFillPrice: number | null;
|
|
69
69
|
readonly orderRef: string | null;
|
|
70
70
|
readonly text: string | null;
|
|
71
|
+
/**
|
|
72
|
+
* The destination's own instant for this frame, or null where it stated none.
|
|
73
|
+
*
|
|
74
|
+
* **One field of the ledger is folded from it.** `host-interface.md` 7.2
|
|
75
|
+
* gives a frame a `time` and `stdlib.md` 17.7 moves `updatedAt` to it, so a
|
|
76
|
+
* record that dropped it wrote a ledger no engine reading the case back could
|
|
77
|
+
* fold to: handed frames with no instant, that engine leaves every
|
|
78
|
+
* `updatedAt` at `placedAt`, and the two disagree on exactly the rows whose
|
|
79
|
+
* destination answered later than the bar that placed the order.
|
|
80
|
+
*
|
|
81
|
+
* Absent rather than substituted, because 7.2 lets a destination state none
|
|
82
|
+
* and a row whose frame stated none keeps the instant it had.
|
|
83
|
+
*/
|
|
84
|
+
readonly time: number | null;
|
|
71
85
|
}
|
|
72
86
|
/** A ledger row of `stdlib.md` 17.7, flattened: the `orders` channel of expected.json. */
|
|
73
87
|
export interface RecordedOrder {
|
|
@@ -114,7 +128,43 @@ export interface RunRecord {
|
|
|
114
128
|
readonly programHash: string;
|
|
115
129
|
/** Hash, lines, file: the script revision. */
|
|
116
130
|
readonly source: SourceStamp;
|
|
131
|
+
/**
|
|
132
|
+
* The source text itself, or null on a record written before version 2.
|
|
133
|
+
*
|
|
134
|
+
* **A record is the conformance case, and a case has to hold `script.os`.**
|
|
135
|
+
* `source` above identifies the script and cannot reproduce it: a hash is a
|
|
136
|
+
* fingerprint, so it settles whether two files are the same and yields
|
|
137
|
+
* neither of them. Without the text a stored record could be replayed months
|
|
138
|
+
* later and still not be handed to anybody else to run, which is the whole
|
|
139
|
+
* claim the suite exists to test.
|
|
140
|
+
*
|
|
141
|
+
* It lives here and not on the compiled program on purpose. A program is
|
|
142
|
+
* executable data that no engine needs the source to run, and it is the
|
|
143
|
+
* versioned artefact adopters depend on; putting the text there would send a
|
|
144
|
+
* script everywhere its program travels and widen the format every engine
|
|
145
|
+
* has to read. The record is the thing that wants to be self-contained.
|
|
146
|
+
*/
|
|
147
|
+
readonly sourceText: string | null;
|
|
117
148
|
readonly settings: BacktestSettings;
|
|
149
|
+
/**
|
|
150
|
+
* The instrument record of `host-interface.md` 4.1, as the engine was handed
|
|
151
|
+
* it, or null on a record written before version 3.
|
|
152
|
+
*
|
|
153
|
+
* **A case holds `instrument.json`, and `conformance.md` section 2 says that
|
|
154
|
+
* file is this record.** The contract in `settings` is the money layer's
|
|
155
|
+
* snapshot of the same instrument and holds six of the twelve facts; the
|
|
156
|
+
* ones a script reads and the money never does, the interval, the timezone,
|
|
157
|
+
* the session and the volume flag, were handed to the engine and written
|
|
158
|
+
* down nowhere. A case harvested from such a record either omitted a fact
|
|
159
|
+
* the page requires or stated one the run never had, and either way the
|
|
160
|
+
* second engine ran a different study than the one the expected output
|
|
161
|
+
* came from.
|
|
162
|
+
*
|
|
163
|
+
* It is the whole record and not the six facts beside the contract, because
|
|
164
|
+
* what is recorded is what the engine read at load, verbatim, and a reader
|
|
165
|
+
* should not have to compose it.
|
|
166
|
+
*/
|
|
167
|
+
readonly instrument: Instrument | null;
|
|
118
168
|
readonly bars: BarsInRecord;
|
|
119
169
|
/** What the destination answered, in delivery order. */
|
|
120
170
|
readonly frames: readonly RecordedFrame[];
|
|
@@ -133,11 +183,22 @@ export interface RunRecord {
|
|
|
133
183
|
* file alone. It moves when a channel is added or a meaning changes, never when
|
|
134
184
|
* a figure in a report does.
|
|
135
185
|
*/
|
|
136
|
-
export declare const RECORD_VERSION =
|
|
186
|
+
export declare const RECORD_VERSION = 4;
|
|
137
187
|
/** The parts a run hands over, each already in the shape the record holds. */
|
|
138
188
|
export interface RecordParts {
|
|
139
189
|
readonly program: CompiledProgram;
|
|
190
|
+
/**
|
|
191
|
+
* The script's own text, so the record can become a conformance case.
|
|
192
|
+
*
|
|
193
|
+
* Optional because a caller that has only a compiled program cannot invent
|
|
194
|
+
* it, and a run is still worth recording without it. `caseFilesFrom` is the
|
|
195
|
+
* one thing that then cannot be served, and it says so rather than writing a
|
|
196
|
+
* case with a hole in it.
|
|
197
|
+
*/
|
|
198
|
+
readonly sourceText?: string;
|
|
140
199
|
readonly settings: BacktestSettings;
|
|
200
|
+
/** The instrument record the engine was handed, `host-interface.md` 4.1. */
|
|
201
|
+
readonly instrument: Instrument;
|
|
141
202
|
readonly bars: readonly RecordedBar[];
|
|
142
203
|
/**
|
|
143
204
|
* Whether the bars travel in the record or are pointed at.
|