openalgo-script 0.2.0 → 0.4.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 +269 -0
- package/README.md +65 -31
- package/dist/adapters/charts/surfaces.d.ts +17 -0
- package/dist/adapters/charts/surfaces.d.ts.map +1 -1
- package/dist/adapters/charts/tables.js +82 -0
- package/dist/adapters/charts/tables.js.map +1 -1
- package/dist/adapters/codemirror/commands.d.ts +14 -0
- package/dist/adapters/codemirror/commands.d.ts.map +1 -0
- package/dist/adapters/codemirror/commands.js +52 -0
- package/dist/adapters/codemirror/commands.js.map +1 -0
- package/dist/adapters/codemirror/completion.d.ts +15 -0
- package/dist/adapters/codemirror/completion.d.ts.map +1 -0
- package/dist/adapters/codemirror/completion.js +64 -0
- package/dist/adapters/codemirror/completion.js.map +1 -0
- package/dist/adapters/codemirror/contract.d.ts +156 -0
- package/dist/adapters/codemirror/contract.d.ts.map +1 -0
- package/dist/adapters/codemirror/contract.js +42 -0
- package/dist/adapters/codemirror/contract.js.map +1 -0
- package/dist/adapters/codemirror/index.d.ts +43 -0
- package/dist/adapters/codemirror/index.d.ts.map +1 -0
- package/dist/adapters/codemirror/index.js +8 -0
- package/dist/adapters/codemirror/index.js.map +1 -0
- package/dist/adapters/codemirror/lint.d.ts +17 -0
- package/dist/adapters/codemirror/lint.d.ts.map +1 -0
- package/dist/adapters/codemirror/lint.js +62 -0
- package/dist/adapters/codemirror/lint.js.map +1 -0
- package/dist/adapters/codemirror/positions.d.ts +16 -0
- package/dist/adapters/codemirror/positions.d.ts.map +1 -0
- package/dist/adapters/codemirror/positions.js +65 -0
- package/dist/adapters/codemirror/positions.js.map +1 -0
- package/dist/adapters/codemirror/stream.d.ts +23 -0
- package/dist/adapters/codemirror/stream.d.ts.map +1 -0
- package/dist/adapters/codemirror/stream.js +70 -0
- package/dist/adapters/codemirror/stream.js.map +1 -0
- package/dist/adapters/codemirror/tokens.d.ts +44 -0
- package/dist/adapters/codemirror/tokens.d.ts.map +1 -0
- package/dist/adapters/codemirror/tokens.js +34 -0
- package/dist/adapters/codemirror/tokens.js.map +1 -0
- package/dist/adapters/codemirror/tooltips.d.ts +35 -0
- package/dist/adapters/codemirror/tooltips.d.ts.map +1 -0
- package/dist/adapters/codemirror/tooltips.js +108 -0
- package/dist/adapters/codemirror/tooltips.js.map +1 -0
- package/dist/core/accounting/charges.d.ts +136 -0
- package/dist/core/accounting/charges.d.ts.map +1 -0
- package/dist/core/accounting/charges.js +362 -0
- package/dist/core/accounting/charges.js.map +1 -0
- package/dist/core/accounting/equity.d.ts +158 -0
- package/dist/core/accounting/equity.d.ts.map +1 -0
- package/dist/core/accounting/equity.js +155 -0
- package/dist/core/accounting/equity.js.map +1 -0
- package/dist/core/accounting/index.d.ts +44 -0
- package/dist/core/accounting/index.d.ts.map +1 -0
- package/dist/core/accounting/index.js +36 -0
- package/dist/core/accounting/index.js.map +1 -0
- package/dist/core/accounting/markers.d.ts +43 -0
- package/dist/core/accounting/markers.d.ts.map +1 -0
- package/dist/core/accounting/markers.js +64 -0
- package/dist/core/accounting/markers.js.map +1 -0
- package/dist/core/accounting/monthly.d.ts +52 -0
- package/dist/core/accounting/monthly.d.ts.map +1 -0
- package/dist/core/accounting/monthly.js +99 -0
- package/dist/core/accounting/monthly.js.map +1 -0
- package/dist/core/accounting/report.d.ts +38 -0
- package/dist/core/accounting/report.d.ts.map +1 -0
- package/dist/core/accounting/report.js +63 -0
- package/dist/core/accounting/report.js.map +1 -0
- package/dist/core/accounting/shapes.d.ts +70 -0
- package/dist/core/accounting/shapes.d.ts.map +1 -0
- package/dist/core/accounting/shapes.js +21 -0
- package/dist/core/accounting/shapes.js.map +1 -0
- package/dist/core/accounting/statistics.d.ts +75 -0
- package/dist/core/accounting/statistics.d.ts.map +1 -0
- package/dist/core/accounting/statistics.js +246 -0
- package/dist/core/accounting/statistics.js.map +1 -0
- package/dist/core/accounting/trades.d.ts +118 -0
- package/dist/core/accounting/trades.d.ts.map +1 -0
- package/dist/core/accounting/trades.js +186 -0
- package/dist/core/accounting/trades.js.map +1 -0
- package/dist/core/backtest/compare.d.ts +38 -0
- package/dist/core/backtest/compare.d.ts.map +1 -0
- package/dist/core/backtest/compare.js +189 -0
- package/dist/core/backtest/compare.js.map +1 -0
- package/dist/core/backtest/declaration.d.ts +52 -0
- package/dist/core/backtest/declaration.d.ts.map +1 -0
- package/dist/core/backtest/declaration.js +48 -0
- package/dist/core/backtest/declaration.js.map +1 -0
- package/dist/core/backtest/drive.d.ts +29 -0
- package/dist/core/backtest/drive.d.ts.map +1 -0
- package/dist/core/backtest/drive.js +262 -0
- package/dist/core/backtest/drive.js.map +1 -0
- package/dist/core/backtest/index.d.ts +46 -0
- package/dist/core/backtest/index.d.ts.map +1 -0
- package/dist/core/backtest/index.js +36 -0
- package/dist/core/backtest/index.js.map +1 -0
- package/dist/core/backtest/range.d.ts +84 -0
- package/dist/core/backtest/range.d.ts.map +1 -0
- package/dist/core/backtest/range.js +90 -0
- package/dist/core/backtest/range.js.map +1 -0
- package/dist/core/backtest/record.d.ts +238 -0
- package/dist/core/backtest/record.d.ts.map +1 -0
- package/dist/core/backtest/record.js +176 -0
- package/dist/core/backtest/record.js.map +1 -0
- package/dist/core/backtest/replay.d.ts +48 -0
- package/dist/core/backtest/replay.d.ts.map +1 -0
- package/dist/core/backtest/replay.js +127 -0
- package/dist/core/backtest/replay.js.map +1 -0
- package/dist/core/backtest/resting.d.ts +62 -0
- package/dist/core/backtest/resting.d.ts.map +1 -0
- package/dist/core/backtest/resting.js +59 -0
- package/dist/core/backtest/resting.js.map +1 -0
- package/dist/core/backtest/settings.d.ts +117 -0
- package/dist/core/backtest/settings.d.ts.map +1 -0
- package/dist/core/backtest/settings.js +207 -0
- package/dist/core/backtest/settings.js.map +1 -0
- package/dist/core/backtest/simulate.d.ts +146 -0
- package/dist/core/backtest/simulate.d.ts.map +1 -0
- package/dist/core/backtest/simulate.js +217 -0
- package/dist/core/backtest/simulate.js.map +1 -0
- package/dist/core/catalogue/catalogue.generated.d.ts +66 -0
- package/dist/core/catalogue/catalogue.generated.d.ts.map +1 -1
- package/dist/core/catalogue/catalogue.generated.js +6 -0
- package/dist/core/catalogue/catalogue.generated.js.map +1 -1
- package/dist/core/catalogue/values.generated.d.ts +24 -0
- package/dist/core/catalogue/values.generated.d.ts.map +1 -1
- package/dist/core/check/index.d.ts +2 -1
- package/dist/core/check/index.d.ts.map +1 -1
- package/dist/core/check/index.js +1 -1
- package/dist/core/check/index.js.map +1 -1
- package/dist/core/check/library-prose.generated.d.ts +16 -0
- package/dist/core/check/library-prose.generated.d.ts.map +1 -0
- package/dist/core/check/library-prose.generated.js +353 -0
- package/dist/core/check/library-prose.generated.js.map +1 -0
- package/dist/core/check/surface.d.ts +24 -0
- package/dist/core/check/surface.d.ts.map +1 -1
- package/dist/core/check/surface.js +29 -0
- package/dist/core/check/surface.js.map +1 -1
- package/dist/core/emit/defaults.d.ts +35 -16
- package/dist/core/emit/defaults.d.ts.map +1 -1
- package/dist/core/emit/defaults.js +66 -0
- package/dist/core/emit/defaults.js.map +1 -1
- package/dist/core/emit/index.d.ts +2 -0
- package/dist/core/emit/index.d.ts.map +1 -1
- package/dist/core/emit/index.js +2 -0
- package/dist/core/emit/index.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/load.d.ts +15 -1
- package/dist/core/engine/load.d.ts.map +1 -1
- package/dist/core/engine/load.js +1 -0
- package/dist/core/engine/load.js.map +1 -1
- package/dist/core/index.d.ts +37 -3
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +17 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/version/version.generated.d.ts +1 -1
- package/dist/core/version/version.generated.js +1 -1
- package/dist/editor/complete.d.ts +40 -0
- package/dist/editor/complete.d.ts.map +1 -0
- package/dist/editor/complete.js +206 -0
- package/dist/editor/complete.js.map +1 -0
- package/dist/editor/diagnose.d.ts +18 -0
- package/dist/editor/diagnose.d.ts.map +1 -0
- package/dist/editor/diagnose.js +70 -0
- package/dist/editor/diagnose.js.map +1 -0
- package/dist/editor/format.d.ts +11 -0
- package/dist/editor/format.d.ts.map +1 -0
- package/dist/editor/format.js +50 -0
- package/dist/editor/format.js.map +1 -0
- package/dist/editor/highlight.d.ts +28 -0
- package/dist/editor/highlight.d.ts.map +1 -0
- package/dist/editor/highlight.js +65 -0
- package/dist/editor/highlight.js.map +1 -0
- package/dist/editor/hover.d.ts +40 -0
- package/dist/editor/hover.d.ts.map +1 -0
- package/dist/editor/hover.js +147 -0
- package/dist/editor/hover.js.map +1 -0
- package/dist/editor/index.d.ts +60 -0
- package/dist/editor/index.d.ts.map +1 -0
- package/dist/editor/index.js +7 -0
- package/dist/editor/index.js.map +1 -0
- package/dist/editor/kinds.d.ts +27 -0
- package/dist/editor/kinds.d.ts.map +1 -0
- package/dist/editor/kinds.js +118 -0
- package/dist/editor/kinds.js.map +1 -0
- package/dist/editor/layout.d.ts +47 -0
- package/dist/editor/layout.d.ts.map +1 -0
- package/dist/editor/layout.js +135 -0
- package/dist/editor/layout.js.map +1 -0
- package/dist/editor/manifest.d.ts +47 -0
- package/dist/editor/manifest.d.ts.map +1 -0
- package/dist/editor/manifest.js +93 -0
- package/dist/editor/manifest.js.map +1 -0
- package/dist/editor/reading.d.ts +41 -0
- package/dist/editor/reading.d.ts.map +1 -0
- package/dist/editor/reading.js +51 -0
- package/dist/editor/reading.js.map +1 -0
- package/dist/editor/scan.d.ts +26 -0
- package/dist/editor/scan.d.ts.map +1 -0
- package/dist/editor/scan.js +139 -0
- package/dist/editor/scan.js.map +1 -0
- package/dist/editor/scope.d.ts +19 -0
- package/dist/editor/scope.d.ts.map +1 -0
- package/dist/editor/scope.js +99 -0
- package/dist/editor/scope.js.map +1 -0
- package/dist/editor/signature.d.ts +38 -0
- package/dist/editor/signature.d.ts.map +1 -0
- package/dist/editor/signature.js +112 -0
- package/dist/editor/signature.js.map +1 -0
- package/dist/editor/site.d.ts +46 -0
- package/dist/editor/site.d.ts.map +1 -0
- package/dist/editor/site.js +184 -0
- package/dist/editor/site.js.map +1 -0
- package/dist/editor/spacing.d.ts +29 -0
- package/dist/editor/spacing.d.ts.map +1 -0
- package/dist/editor/spacing.js +116 -0
- package/dist/editor/spacing.js.map +1 -0
- package/package.json +30 -3
- package/spec/errors.json +140 -0
- package/src/adapters/charts/surfaces.ts +17 -0
- package/src/adapters/charts/tables.ts +88 -0
- package/src/adapters/codemirror/commands.ts +53 -0
- package/src/adapters/codemirror/completion.ts +74 -0
- package/src/adapters/codemirror/contract.ts +156 -0
- package/src/adapters/codemirror/index.ts +66 -0
- package/src/adapters/codemirror/lint.ts +66 -0
- package/src/adapters/codemirror/positions.ts +79 -0
- package/src/adapters/codemirror/stream.ts +87 -0
- package/src/adapters/codemirror/tokens.ts +64 -0
- package/src/adapters/codemirror/tooltips.ts +113 -0
- package/src/core/accounting/charges.ts +452 -0
- package/src/core/accounting/equity.ts +276 -0
- package/src/core/accounting/index.ts +49 -0
- package/src/core/accounting/markers.ts +95 -0
- package/src/core/accounting/monthly.ts +137 -0
- package/src/core/accounting/report.ts +89 -0
- package/src/core/accounting/shapes.ts +73 -0
- package/src/core/accounting/statistics.ts +350 -0
- package/src/core/accounting/trades.ts +313 -0
- package/src/core/backtest/compare.ts +244 -0
- package/src/core/backtest/declaration.ts +97 -0
- package/src/core/backtest/drive.ts +364 -0
- package/src/core/backtest/index.ts +52 -0
- package/src/core/backtest/range.ts +137 -0
- package/src/core/backtest/record.ts +341 -0
- package/src/core/backtest/replay.ts +158 -0
- package/src/core/backtest/resting.ts +125 -0
- package/src/core/backtest/settings.ts +280 -0
- package/src/core/backtest/simulate.ts +304 -0
- package/src/core/catalogue/catalogue.generated.ts +6 -0
- package/src/core/catalogue/values.generated.ts +6 -0
- package/src/core/check/index.ts +3 -0
- package/src/core/check/library-prose.generated.ts +367 -0
- package/src/core/check/surface.ts +34 -0
- package/src/core/emit/defaults.ts +70 -0
- package/src/core/emit/index.ts +2 -0
- package/src/core/engine/index.ts +1 -1
- package/src/core/engine/load.ts +16 -2
- package/src/core/index.ts +85 -1
- package/src/core/version/version.generated.ts +1 -1
- package/src/editor/complete.ts +266 -0
- package/src/editor/diagnose.ts +71 -0
- package/src/editor/format.ts +85 -0
- package/src/editor/highlight.ts +110 -0
- package/src/editor/hover.ts +199 -0
- package/src/editor/index.ts +65 -0
- package/src/editor/kinds.ts +157 -0
- package/src/editor/layout.ts +189 -0
- package/src/editor/manifest.ts +119 -0
- package/src/editor/reading.ts +69 -0
- package/src/editor/scan.ts +162 -0
- package/src/editor/scope.ts +122 -0
- package/src/editor/signature.ts +150 -0
- package/src/editor/site.ts +233 -0
- package/src/editor/spacing.ts +132 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The atoms the money is folded from: a fill, a contract and a bar's close.
|
|
3
|
+
*
|
|
4
|
+
* **Everything in this module is portable data.** No class, no function, no
|
|
5
|
+
* object reference, no absent field, no map and no date: a shape here is what
|
|
6
|
+
* `JSON.parse` gives back, so a report can be computed here, stored by a
|
|
7
|
+
* platform, sent to another process and recomputed there without this
|
|
8
|
+
* implementation being present. That is not a convenience. A run record is the
|
|
9
|
+
* conformance case a second engine is handed, and a case that can only be read
|
|
10
|
+
* by the engine that wrote it proves nothing about either.
|
|
11
|
+
*
|
|
12
|
+
* **A fill is the only thing money is folded from.** Not a position, not a
|
|
13
|
+
* ledger row, not a running total the engine happened to be holding: the fills
|
|
14
|
+
* the engine settled, in the order it settled them, each naming the position
|
|
15
|
+
* reference it moved and the size of that reference either side of the
|
|
16
|
+
* settlement. Every figure in a report is a function of that list and of the
|
|
17
|
+
* bars it is marked against, which is what makes a report reproducible from a
|
|
18
|
+
* record with no engine in the room.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Money, in the contract's own currency.
|
|
22
|
+
*
|
|
23
|
+
* A number rather than a type of its own, because a type of its own would be a
|
|
24
|
+
* class and a class does not survive `JSON.parse`. The rounding is stated once,
|
|
25
|
+
* on the contract, and applied once per fill total.
|
|
26
|
+
*/
|
|
27
|
+
export type Money = number;
|
|
28
|
+
/**
|
|
29
|
+
* The instrument facts a run was carried out under, as the host stated them.
|
|
30
|
+
*
|
|
31
|
+
* A snapshot rather than a reference. An instrument's lot size and tick size
|
|
32
|
+
* change, and a report recomputed months later under today's facts would be a
|
|
33
|
+
* different study wearing the same name, so the facts travel with the run.
|
|
34
|
+
*/
|
|
35
|
+
export interface Contract {
|
|
36
|
+
readonly symbol: string | null;
|
|
37
|
+
readonly exchange: string | null;
|
|
38
|
+
readonly currency: string;
|
|
39
|
+
readonly tickSize: number | null;
|
|
40
|
+
readonly lotSize: number | null;
|
|
41
|
+
/** Money per 1.0 of price per unit; 1 when the host states none. */
|
|
42
|
+
readonly pointValue: number;
|
|
43
|
+
/** Money rounding digits, half to even, once per fill total. */
|
|
44
|
+
readonly digits: number;
|
|
45
|
+
}
|
|
46
|
+
/** One settled fill. Every money figure is folded from these and nothing else. */
|
|
47
|
+
export interface RecordedFill {
|
|
48
|
+
readonly seq: number;
|
|
49
|
+
readonly intentId: number;
|
|
50
|
+
readonly orderRef: string;
|
|
51
|
+
readonly tag: string;
|
|
52
|
+
readonly positionRef: number;
|
|
53
|
+
readonly side: 'buy' | 'sell';
|
|
54
|
+
/** Positive, this fill's own quantity. */
|
|
55
|
+
readonly units: number;
|
|
56
|
+
readonly price: number;
|
|
57
|
+
readonly barIndex: number;
|
|
58
|
+
readonly barTime: number | null;
|
|
59
|
+
readonly refSizeBefore: number;
|
|
60
|
+
readonly refSizeAfter: number;
|
|
61
|
+
}
|
|
62
|
+
/** One bar as the report marks against it. Close only: 17.4 marks to the close. */
|
|
63
|
+
export interface BarMark {
|
|
64
|
+
readonly barIndex: number;
|
|
65
|
+
readonly time: number | null;
|
|
66
|
+
readonly close: number | null;
|
|
67
|
+
/** False for a warmup bar. */
|
|
68
|
+
readonly inReport: boolean;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=shapes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shapes.d.ts","sourceRoot":"","sources":["../../../src/core/accounting/shapes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;;;;GAMG;AACH,MAAM,MAAM,KAAK,GAAG,MAAM,CAAC;AAE3B;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,oEAAoE;IACpE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,gEAAgE;IAChE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,kFAAkF;AAClF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,CAAC;IAC9B,0CAA0C;IAC1C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,mFAAmF;AACnF,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,8BAA8B;IAC9B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The atoms the money is folded from: a fill, a contract and a bar's close.
|
|
3
|
+
*
|
|
4
|
+
* **Everything in this module is portable data.** No class, no function, no
|
|
5
|
+
* object reference, no absent field, no map and no date: a shape here is what
|
|
6
|
+
* `JSON.parse` gives back, so a report can be computed here, stored by a
|
|
7
|
+
* platform, sent to another process and recomputed there without this
|
|
8
|
+
* implementation being present. That is not a convenience. A run record is the
|
|
9
|
+
* conformance case a second engine is handed, and a case that can only be read
|
|
10
|
+
* by the engine that wrote it proves nothing about either.
|
|
11
|
+
*
|
|
12
|
+
* **A fill is the only thing money is folded from.** Not a position, not a
|
|
13
|
+
* ledger row, not a running total the engine happened to be holding: the fills
|
|
14
|
+
* the engine settled, in the order it settled them, each naming the position
|
|
15
|
+
* reference it moved and the size of that reference either side of the
|
|
16
|
+
* settlement. Every figure in a report is a function of that list and of the
|
|
17
|
+
* bars it is marked against, which is what makes a report reproducible from a
|
|
18
|
+
* record with no engine in the room.
|
|
19
|
+
*/
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=shapes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shapes.js","sourceRoot":"","sources":["../../../src/core/accounting/shapes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { EquityPoint } from './equity.js';
|
|
2
|
+
import type { Contract, Money } from './shapes.js';
|
|
3
|
+
import type { Trade } from './trades.js';
|
|
4
|
+
/** What the whole run came to. */
|
|
5
|
+
export interface Summary {
|
|
6
|
+
readonly capital: Money;
|
|
7
|
+
readonly currency: string;
|
|
8
|
+
readonly netProfit: Money;
|
|
9
|
+
/** Sum of winning trades, before charges. */
|
|
10
|
+
readonly grossProfit: Money;
|
|
11
|
+
/**
|
|
12
|
+
* The losing trades' gross, as a magnitude, and it can come out at or below
|
|
13
|
+
* zero.
|
|
14
|
+
*
|
|
15
|
+
* A trade wins or loses on its net after charges and contributes its gross
|
|
16
|
+
* here, so a trade whose gross was positive and whose charges took it under
|
|
17
|
+
* lands in the losses carrying a positive gross, which lowers this figure and
|
|
18
|
+
* with few enough trades beside it takes it to zero or past it. `tallyOf`
|
|
19
|
+
* says why that is preferred to counting one trade as a loser in one figure
|
|
20
|
+
* and a winner in another. It is written here because it was documented as a
|
|
21
|
+
* positive magnitude and is not one, and a reader dividing by it was handed a
|
|
22
|
+
* negative profit factor with nothing saying that could happen.
|
|
23
|
+
*/
|
|
24
|
+
readonly grossLoss: Money;
|
|
25
|
+
readonly charges: Money;
|
|
26
|
+
/** `netProfit / capital`, a fraction and not a figure times a hundred. */
|
|
27
|
+
readonly returnPercent: number;
|
|
28
|
+
/** Closed only. */
|
|
29
|
+
readonly tradeCount: number;
|
|
30
|
+
readonly openTradeCount: number;
|
|
31
|
+
readonly wins: number;
|
|
32
|
+
readonly losses: number;
|
|
33
|
+
/** Exactly zero net. */
|
|
34
|
+
readonly scratches: number;
|
|
35
|
+
/** wins / (wins + losses), null when none closed. */
|
|
36
|
+
readonly winRate: number | null;
|
|
37
|
+
readonly averageWin: Money;
|
|
38
|
+
/** Positive magnitude. */
|
|
39
|
+
readonly averageLoss: Money;
|
|
40
|
+
/** Money per closed trade. */
|
|
41
|
+
readonly expectancy: Money;
|
|
42
|
+
readonly expectancyStandardError: Money;
|
|
43
|
+
/**
|
|
44
|
+
* Gross profit over gross loss, or null where there is no ratio to take.
|
|
45
|
+
*
|
|
46
|
+
* Null when the gross loss is not above zero: a run with no losing trade has
|
|
47
|
+
* nothing to divide by, and one whose losses cost less in gross than their
|
|
48
|
+
* charges has a denominator at or below zero. A profit factor is a
|
|
49
|
+
* non-negative ratio everywhere it is used, so a negative one is not a
|
|
50
|
+
* surprising value, it is a number nobody can act on. It used to be
|
|
51
|
+
* reported: two trades, one charged into a loss on a positive gross, gave a
|
|
52
|
+
* profit factor of -0.5.
|
|
53
|
+
*/
|
|
54
|
+
readonly profitFactor: number | null;
|
|
55
|
+
/** Zero or negative, the same sign the curve states it with. */
|
|
56
|
+
readonly maxDrawdown: Money;
|
|
57
|
+
/** The deepest point's own fraction, not the worst fraction of any point. */
|
|
58
|
+
readonly maxDrawdownPercent: number;
|
|
59
|
+
/** A bar time, never an index. */
|
|
60
|
+
readonly maxDrawdownAt: number | null;
|
|
61
|
+
readonly longestDrawdownBars: number;
|
|
62
|
+
readonly averageBarsHeld: number | null;
|
|
63
|
+
readonly barsInMarket: number;
|
|
64
|
+
readonly barCount: number;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The whole run in one shape, folded from its trades and its own curve.
|
|
68
|
+
*
|
|
69
|
+
* The curve is passed in rather than recomputed, because a summary that folded
|
|
70
|
+
* its own would be a second equity curve with a second set of rounding, and the
|
|
71
|
+
* first disagreement between them would be a drawdown figure that no point in
|
|
72
|
+
* the reported curve ever reached.
|
|
73
|
+
*/
|
|
74
|
+
export declare function summaryOf(trades: readonly Trade[], equity: readonly EquityPoint[], contract: Contract, capital: Money): Summary;
|
|
75
|
+
//# sourceMappingURL=statistics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statistics.d.ts","sourceRoot":"","sources":["../../../src/core/accounting/statistics.ts"],"names":[],"mappings":"AA6DA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,kCAAkC;AAClC,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC;IAC1B,6CAA6C;IAC7C,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAC;IAC5B;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IACxB,0EAA0E;IAC1E,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,mBAAmB;IACnB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,wBAAwB;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,qDAAqD;IACrD,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,KAAK,CAAC;IAC3B,0BAA0B;IAC1B,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAC;IAC5B,8BAA8B;IAC9B,QAAQ,CAAC,UAAU,EAAE,KAAK,CAAC;IAC3B,QAAQ,CAAC,uBAAuB,EAAE,KAAK,CAAC;IACxC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,gEAAgE;IAChE,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAC;IAC5B,6EAA6E;IAC7E,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,kCAAkC;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AA2BD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,SAAS,KAAK,EAAE,EACxB,MAAM,EAAE,SAAS,WAAW,EAAE,EAC9B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,KAAK,GACb,OAAO,CAuCT"}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The summary, and the two figures in it that decide whether a run means
|
|
3
|
+
* anything.
|
|
4
|
+
*
|
|
5
|
+
* **Win rate is over closed trades, on net profit after charges**, and a trade
|
|
6
|
+
* whose net is exactly zero is a scratch counted in neither half. It is null
|
|
7
|
+
* where nothing closed rather than zero, because zero is a number a reader
|
|
8
|
+
* compares against and "nothing has closed yet" is not a losing run.
|
|
9
|
+
*
|
|
10
|
+
* **Expectancy is money per closed trade**, and it has two spellings that must
|
|
11
|
+
* agree: the win rate against the average win and the average loss, and the net
|
|
12
|
+
* profit over the trade count. Two spellings of one figure that disagree is how
|
|
13
|
+
* a report loses its reader, so one of them is the computation and the other is
|
|
14
|
+
* a test, and the test says which sequence of roundings it allows for.
|
|
15
|
+
*
|
|
16
|
+
* **And its standard error is what answers the question a comparison asks.**
|
|
17
|
+
* The sample standard deviation of per-trade net over the square root of the
|
|
18
|
+
* trade count is what turns "this run made more" into "this run made more than
|
|
19
|
+
* the noise", and without it a difference of two percent over eleven trades
|
|
20
|
+
* reads like a result.
|
|
21
|
+
*
|
|
22
|
+
* Bar times rather than bar indices, wherever a figure addresses a bar: loading
|
|
23
|
+
* more history shifts every index, so a report that addresses a bar by index
|
|
24
|
+
* changes when the warmup changes.
|
|
25
|
+
*
|
|
26
|
+
* ## Which trades a figure is counted over, which is three different answers
|
|
27
|
+
*
|
|
28
|
+
* A summary folds a list holding closed trades and open ones together, and
|
|
29
|
+
* almost every defect this file can have is a figure counted over the wrong
|
|
30
|
+
* half of it.
|
|
31
|
+
*
|
|
32
|
+
* - **Net profit, and everything derived from it**, is over closed trades. An
|
|
33
|
+
* open trade's net is its charges so far with no gross against them, so
|
|
34
|
+
* counting it would report a run holding a winner as having lost money.
|
|
35
|
+
* - **Charges are over every trade**, open ones included, because the money
|
|
36
|
+
* left the account whether or not the position came back. This is the figure
|
|
37
|
+
* the equity curve's last point carries, and the two are asserted equal.
|
|
38
|
+
* - **The drawdown figures are over the curve** and not over the trades at all.
|
|
39
|
+
* A drawdown is a thing equity did between two trades as often as during one.
|
|
40
|
+
*
|
|
41
|
+
* ## The cases where a statistic is not a number
|
|
42
|
+
*
|
|
43
|
+
* Every one of them is a division, and every one of them is answered here
|
|
44
|
+
* rather than left to arrive as a value JSON turns into `null`:
|
|
45
|
+
*
|
|
46
|
+
* - **Nothing closed.** The win rate is null, which is a different claim from
|
|
47
|
+
* zero. Expectancy and its error are zero, because the type is money and
|
|
48
|
+
* money is not nullable, and `tradeCount` beside them is the field that says
|
|
49
|
+
* whether they mean anything.
|
|
50
|
+
* - **One closed trade.** A sample of one has no spread, so the standard error
|
|
51
|
+
* is zero. Zero here means not measurable, never measured: anything dividing
|
|
52
|
+
* by it checks the trade count first.
|
|
53
|
+
* - **Every closed trade a scratch.** There is no denominator for a win rate,
|
|
54
|
+
* so it is null for the same reason as nothing closed.
|
|
55
|
+
* - **Nothing lost.** The profit factor is null rather than an infinity, which
|
|
56
|
+
* is the same decision `spec/conformance.md` takes about absence: a value
|
|
57
|
+
* that does not survive being written down is not a value a report may hold.
|
|
58
|
+
* - **Everything lost.** The profit factor is zero, expectancy is negative, the
|
|
59
|
+
* average win is zero, and none of the four is a division by zero.
|
|
60
|
+
*/
|
|
61
|
+
import { barsInMarketOver, ratioOf } from './equity.js';
|
|
62
|
+
/**
|
|
63
|
+
* The whole run in one shape, folded from its trades and its own curve.
|
|
64
|
+
*
|
|
65
|
+
* The curve is passed in rather than recomputed, because a summary that folded
|
|
66
|
+
* its own would be a second equity curve with a second set of rounding, and the
|
|
67
|
+
* first disagreement between them would be a drawdown figure that no point in
|
|
68
|
+
* the reported curve ever reached.
|
|
69
|
+
*/
|
|
70
|
+
export function summaryOf(trades, equity, contract, capital) {
|
|
71
|
+
const tally = tallyOf(trades);
|
|
72
|
+
const depth = depthOf(equity);
|
|
73
|
+
const decided = tally.wins + tally.losses;
|
|
74
|
+
// Net over the closed count, and nothing else, because this is the figure the
|
|
75
|
+
// other spelling is checked against. The win rate spelling divides by the
|
|
76
|
+
// decided trades instead, so the two are the same number exactly when no
|
|
77
|
+
// trade scratched, and `tests/accounting/statistics.test.ts` asserts both the
|
|
78
|
+
// agreement and the one case that parts them.
|
|
79
|
+
const expectancy = tally.tradeCount === 0 ? 0 : tally.netProfit / tally.tradeCount;
|
|
80
|
+
return {
|
|
81
|
+
capital,
|
|
82
|
+
currency: contract.currency,
|
|
83
|
+
netProfit: tally.netProfit,
|
|
84
|
+
grossProfit: tally.grossProfit,
|
|
85
|
+
grossLoss: tally.grossLoss,
|
|
86
|
+
charges: tally.charges,
|
|
87
|
+
returnPercent: ratioOf(tally.netProfit, capital),
|
|
88
|
+
tradeCount: tally.tradeCount,
|
|
89
|
+
openTradeCount: tally.openTradeCount,
|
|
90
|
+
wins: tally.wins,
|
|
91
|
+
losses: tally.losses,
|
|
92
|
+
scratches: tally.scratches,
|
|
93
|
+
winRate: decided === 0 ? null : tally.wins / decided,
|
|
94
|
+
averageWin: tally.wins === 0 ? 0 : tally.winTotal / tally.wins,
|
|
95
|
+
averageLoss: tally.losses === 0 ? 0 : -tally.lossTotal / tally.losses,
|
|
96
|
+
expectancy,
|
|
97
|
+
expectancyStandardError: standardErrorOf(trades, expectancy, tally.tradeCount),
|
|
98
|
+
profitFactor: tally.grossLoss > 0 ? tally.grossProfit / tally.grossLoss : null,
|
|
99
|
+
maxDrawdown: depth.maxDrawdown,
|
|
100
|
+
maxDrawdownPercent: depth.maxDrawdownPercent,
|
|
101
|
+
maxDrawdownAt: depth.maxDrawdownAt,
|
|
102
|
+
longestDrawdownBars: depth.longestDrawdownBars,
|
|
103
|
+
averageBarsHeld: tally.heldCount === 0 ? null : tally.heldTotal / tally.heldCount,
|
|
104
|
+
barsInMarket: barsInMarketOver(trades, equity),
|
|
105
|
+
barCount: equity.length,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* One pass over the trades, in the order they are given.
|
|
110
|
+
*
|
|
111
|
+
* A trade wins or loses on its net after charges, and its gross is what it
|
|
112
|
+
* contributes to the gross figures: "the sum of the winning trades, before
|
|
113
|
+
* charges" is two statements and this is where they meet. The one arrangement
|
|
114
|
+
* that reads oddly is a trade whose gross was positive and whose charges took
|
|
115
|
+
* it under, which lands in the losses and takes its positive gross with it,
|
|
116
|
+
* lowering the gross loss. That is on purpose. The alternative is a trade
|
|
117
|
+
* counted as a loser in one figure and a winner in another, and a profit factor
|
|
118
|
+
* whose two halves are counted over different sets is worse than one whose
|
|
119
|
+
* magnitude is odd on a trade that barely moved.
|
|
120
|
+
*
|
|
121
|
+
* What is not on purpose, and is why `profitFactor` is null rather than a ratio
|
|
122
|
+
* whenever this figure is not above zero: enough of those trades and the gross
|
|
123
|
+
* loss reaches zero or goes under, and dividing by it reported a profit factor
|
|
124
|
+
* of minus a half. A statistic being odd is a thing a reader can weigh. A
|
|
125
|
+
* statistic being negative where every use of it is a non-negative ratio is a
|
|
126
|
+
* number nobody can act on.
|
|
127
|
+
*/
|
|
128
|
+
function tallyOf(trades) {
|
|
129
|
+
let netProfit = 0;
|
|
130
|
+
let grossProfit = 0;
|
|
131
|
+
let grossLoss = 0;
|
|
132
|
+
let charges = 0;
|
|
133
|
+
let tradeCount = 0;
|
|
134
|
+
let openTradeCount = 0;
|
|
135
|
+
let wins = 0;
|
|
136
|
+
let losses = 0;
|
|
137
|
+
let scratches = 0;
|
|
138
|
+
let winTotal = 0;
|
|
139
|
+
let lossTotal = 0;
|
|
140
|
+
let heldTotal = 0;
|
|
141
|
+
let heldCount = 0;
|
|
142
|
+
for (const trade of trades) {
|
|
143
|
+
charges += trade.charges;
|
|
144
|
+
if (trade.isOpen) {
|
|
145
|
+
openTradeCount += 1;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
tradeCount += 1;
|
|
149
|
+
netProfit += trade.netProfit;
|
|
150
|
+
if (trade.barsHeld !== null) {
|
|
151
|
+
heldTotal += trade.barsHeld;
|
|
152
|
+
heldCount += 1;
|
|
153
|
+
}
|
|
154
|
+
if (trade.netProfit > 0) {
|
|
155
|
+
wins += 1;
|
|
156
|
+
winTotal += trade.netProfit;
|
|
157
|
+
grossProfit += trade.grossProfit;
|
|
158
|
+
}
|
|
159
|
+
else if (trade.netProfit < 0) {
|
|
160
|
+
losses += 1;
|
|
161
|
+
lossTotal += trade.netProfit;
|
|
162
|
+
grossLoss -= trade.grossProfit;
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
scratches += 1;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
netProfit,
|
|
170
|
+
grossProfit,
|
|
171
|
+
grossLoss,
|
|
172
|
+
charges,
|
|
173
|
+
tradeCount,
|
|
174
|
+
openTradeCount,
|
|
175
|
+
wins,
|
|
176
|
+
losses,
|
|
177
|
+
scratches,
|
|
178
|
+
winTotal,
|
|
179
|
+
lossTotal,
|
|
180
|
+
heldTotal,
|
|
181
|
+
heldCount,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* The deepest the curve went, named as one point rather than as three figures.
|
|
186
|
+
*
|
|
187
|
+
* The money, the fraction and the time all come from the same point, and the
|
|
188
|
+
* point is the deepest in money with the earliest one winning a tie. Taking the
|
|
189
|
+
* worst fraction from one bar and the worst money from another would describe a
|
|
190
|
+
* moment the run never had, and a reader comparing the two figures would find
|
|
191
|
+
* them inconsistent with every point in the curve they were drawn from.
|
|
192
|
+
*
|
|
193
|
+
* `longestDrawdownBars` is the longest run of consecutive bars under a peak: it
|
|
194
|
+
* starts at the first bar below one and ends at the bar before the recovery, so
|
|
195
|
+
* a run still under water at the last bar counts to the end. It is often the
|
|
196
|
+
* figure that actually stops a trader, and it is not the total number of bars
|
|
197
|
+
* spent under water, which is a different and much larger number.
|
|
198
|
+
*/
|
|
199
|
+
function depthOf(equity) {
|
|
200
|
+
let maxDrawdown = 0;
|
|
201
|
+
let maxDrawdownPercent = 0;
|
|
202
|
+
let maxDrawdownAt = null;
|
|
203
|
+
let longestDrawdownBars = 0;
|
|
204
|
+
let under = 0;
|
|
205
|
+
for (const point of equity) {
|
|
206
|
+
if (point.drawdown < maxDrawdown) {
|
|
207
|
+
maxDrawdown = point.drawdown;
|
|
208
|
+
maxDrawdownPercent = point.drawdownPercent;
|
|
209
|
+
maxDrawdownAt = point.time;
|
|
210
|
+
}
|
|
211
|
+
if (point.drawdown < 0) {
|
|
212
|
+
under += 1;
|
|
213
|
+
if (under > longestDrawdownBars)
|
|
214
|
+
longestDrawdownBars = under;
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
under = 0;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return { maxDrawdown, maxDrawdownPercent, maxDrawdownAt, longestDrawdownBars };
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* The standard error of the expectancy: the sample deviation over the root of
|
|
224
|
+
* the count.
|
|
225
|
+
*
|
|
226
|
+
* The sample deviation, with the count less one under it, and not the
|
|
227
|
+
* population one. The trades a run took are a sample of the trades the strategy
|
|
228
|
+
* would take, which is the whole reason this figure is here, and the population
|
|
229
|
+
* spelling understates the spread by exactly the amount that matters on the
|
|
230
|
+
* short runs where the question is asked.
|
|
231
|
+
*
|
|
232
|
+
* Fewer than two closed trades has no spread to measure and gives zero.
|
|
233
|
+
*/
|
|
234
|
+
function standardErrorOf(trades, expectancy, tradeCount) {
|
|
235
|
+
if (tradeCount < 2)
|
|
236
|
+
return 0;
|
|
237
|
+
let squares = 0;
|
|
238
|
+
for (const trade of trades) {
|
|
239
|
+
if (trade.isOpen)
|
|
240
|
+
continue;
|
|
241
|
+
const away = trade.netProfit - expectancy;
|
|
242
|
+
squares += away * away;
|
|
243
|
+
}
|
|
244
|
+
return Math.sqrt(squares / (tradeCount - 1) / tradeCount);
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=statistics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statistics.js","sourceRoot":"","sources":["../../../src/core/accounting/statistics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a trade is, which is the definition every statistic is counted over.
|
|
3
|
+
*
|
|
4
|
+
* **A trade is one position reference, from the fill that first takes it away
|
|
5
|
+
* from zero to the fill that returns it to zero.** Nothing else is invented,
|
|
6
|
+
* because the engine already mints a reference per position, no order crosses
|
|
7
|
+
* zero, and every fill names the reference it settled however late it arrives.
|
|
8
|
+
*
|
|
9
|
+
* Everything awkward falls out of that rather than needing a rule of its own. A
|
|
10
|
+
* pyramided entry is more entry fills on one trade. A partial close is an exit
|
|
11
|
+
* fill that does not close the trade. A flip is two references and therefore
|
|
12
|
+
* two trades, which is what a reversing order already sends. A reference still
|
|
13
|
+
* holding something at the last bar is an open trade: it is in the list with
|
|
14
|
+
* `isOpen` true, it is counted in equity, and it is counted in no win rate.
|
|
15
|
+
*
|
|
16
|
+
* The definition is written in the specification before it is written here,
|
|
17
|
+
* because a rule decided in code is a rule two engines decide differently.
|
|
18
|
+
*
|
|
19
|
+
* ## What the fold reads, and what it refuses to work out for itself
|
|
20
|
+
*
|
|
21
|
+
* A fill carries the signed size of its reference either side of the
|
|
22
|
+
* settlement, so the fold reads what the position book did rather than
|
|
23
|
+
* recomputing it from quantities and sides. That is the whole of how a partial
|
|
24
|
+
* close, a pyramided entry and a reversal tell themselves apart: the move from
|
|
25
|
+
* one size to the other says how much of the fill closed what was held and how
|
|
26
|
+
* much of it opened something, and nothing else has to be inferred.
|
|
27
|
+
*
|
|
28
|
+
* It also settles the one case the definition does not cover on its face. A
|
|
29
|
+
* destination that fills more than the order asked takes a reference through
|
|
30
|
+
* zero rather than to it, and the position book reads the remainder as a
|
|
31
|
+
* position in the other direction opened at that fill's price. So the fold does
|
|
32
|
+
* the same: the fill closes the trade that was held and opens a second one on
|
|
33
|
+
* the same reference, at its own price and on its own bar. A trade that ran
|
|
34
|
+
* from a size to the other side of zero would report a quantity nothing was
|
|
35
|
+
* ever entered at.
|
|
36
|
+
*
|
|
37
|
+
* **Reducing a position does not move its average**, which is the position
|
|
38
|
+
* book's rule read here rather than a second one: a reducing fill adds to the
|
|
39
|
+
* exits and touches neither the entry quantity nor the entry cost. Every figure
|
|
40
|
+
* measured from the entry, the entry price a reader compares against and the
|
|
41
|
+
* excursion at each bar close, is measured from the price the units were
|
|
42
|
+
* actually bought at.
|
|
43
|
+
*
|
|
44
|
+
* **A charge lands whole on one trade and is never split.** It was rounded once
|
|
45
|
+
* for the fill that incurred it, and splitting it between the trade a crossing
|
|
46
|
+
* fill closed and the trade it opened would round it again and put a residue
|
|
47
|
+
* somewhere. So it is attributed to the trade the fill closed where it closed
|
|
48
|
+
* one, and to the trade it opened otherwise, which makes the charges of the
|
|
49
|
+
* trades add up to the charges of the fills exactly rather than nearly.
|
|
50
|
+
*
|
|
51
|
+
* **Gross profit is over the units that have left.** For a closed trade that is
|
|
52
|
+
* every unit it entered, which is the formula the report is specified with. For
|
|
53
|
+
* one still open it is what its exits have realised so far, which is a figure
|
|
54
|
+
* that is true rather than a zero standing in for money the run has already
|
|
55
|
+
* made.
|
|
56
|
+
*/
|
|
57
|
+
import type { BarMark, Contract, Money, RecordedFill } from './shapes.js';
|
|
58
|
+
/** One round trip on one position reference. */
|
|
59
|
+
export interface Trade {
|
|
60
|
+
/** 1-based, in the order the trade opened. */
|
|
61
|
+
readonly index: number;
|
|
62
|
+
readonly positionRef: number;
|
|
63
|
+
readonly side: 'long' | 'short';
|
|
64
|
+
readonly openedOnBar: number;
|
|
65
|
+
readonly openedAt: number | null;
|
|
66
|
+
readonly closedOnBar: number | null;
|
|
67
|
+
readonly closedAt: number | null;
|
|
68
|
+
readonly barsHeld: number | null;
|
|
69
|
+
/** Total units entered. */
|
|
70
|
+
readonly units: number;
|
|
71
|
+
/** Quantity weighted over the entry fills. */
|
|
72
|
+
readonly entryPrice: number;
|
|
73
|
+
/** Quantity weighted over the exit fills. */
|
|
74
|
+
readonly exitPrice: number | null;
|
|
75
|
+
readonly entries: number;
|
|
76
|
+
readonly exits: number;
|
|
77
|
+
readonly grossProfit: Money;
|
|
78
|
+
readonly charges: Money;
|
|
79
|
+
readonly netProfit: Money;
|
|
80
|
+
/**
|
|
81
|
+
* Excursion at bar closes while open. Favourable is zero or better, adverse
|
|
82
|
+
* zero or worse, and both are zero for a trade no bar closed on.
|
|
83
|
+
*/
|
|
84
|
+
readonly maxFavourable: Money;
|
|
85
|
+
readonly maxAdverse: Money;
|
|
86
|
+
readonly isOpen: boolean;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The round trips a run's fills make up, in the order they opened.
|
|
90
|
+
*
|
|
91
|
+
* `charges[index]` is the money `fills[index]` was charged, rounded once by
|
|
92
|
+
* whoever computed it, so the two travel as one thing and nothing here rounds
|
|
93
|
+
* anything a second time. A caller with no cost model supplies no charges at
|
|
94
|
+
* all and every trade's charges are zero.
|
|
95
|
+
*
|
|
96
|
+
* The fills are read in `seq` order whatever order they are handed in, because
|
|
97
|
+
* `seq` is the order the engine folded them and a report that depended on the
|
|
98
|
+
* order a caller happened to be holding them in would not be reproducible. The
|
|
99
|
+
* marks are read in bar order for the same reason, and a bar is marked after
|
|
100
|
+
* every fill up to it has been folded, because a fill happens during its bar
|
|
101
|
+
* and the close comes after.
|
|
102
|
+
*/
|
|
103
|
+
export declare function tradesOf(fills: readonly RecordedFill[], charges: readonly Money[], marks: readonly BarMark[], contract: Contract): readonly Trade[];
|
|
104
|
+
/**
|
|
105
|
+
* How much of a move from one size to another closed what was held.
|
|
106
|
+
*
|
|
107
|
+
* Exported to the module and not through its door: `markers.ts` asks the same
|
|
108
|
+
* question of the same fills, and the rule for what a move closed and what it
|
|
109
|
+
* opened is one rule. Two folds may read a fill differently and produce a
|
|
110
|
+
* marker for an entry the trade list calls an exit, so they read it here.
|
|
111
|
+
*
|
|
112
|
+
* A move to the other side of zero closed all of it, which is the case a
|
|
113
|
+
* destination that overfilled produces and the one this has to get right.
|
|
114
|
+
*/
|
|
115
|
+
export declare function closedBy(before: number, after: number): number;
|
|
116
|
+
/** And how much of it opened something, which is the rest of the same move. */
|
|
117
|
+
export declare function openedBy(before: number, after: number): number;
|
|
118
|
+
//# sourceMappingURL=trades.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trades.d.ts","sourceRoot":"","sources":["../../../src/core/accounting/trades.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE1E,gDAAgD;AAChD,MAAM,WAAW,KAAK;IACpB,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,2BAA2B;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,8CAA8C;IAC9C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,6CAA6C;IAC7C,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,KAAK,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,KAAK,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,SAAS,YAAY,EAAE,EAC9B,OAAO,EAAE,SAAS,KAAK,EAAE,EACzB,KAAK,EAAE,SAAS,OAAO,EAAE,EACzB,QAAQ,EAAE,QAAQ,GACjB,SAAS,KAAK,EAAE,CAuBlB;AA0CD;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAI9D;AAED,+EAA+E;AAC/E,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAI9D"}
|