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,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether this trade was still held at the close of this bar.
|
|
3
|
+
*
|
|
4
|
+
* The boundaries are the whole of the rule and both are decisions. A trade is
|
|
5
|
+
* held from the close of the bar it opened on, because an entry that settled
|
|
6
|
+
* during a bar is a position that bar ended holding. It is not held at the
|
|
7
|
+
* close of the bar it closed on, because that bar ended flat. So a trade
|
|
8
|
+
* opened and closed inside one bar is held at no close at all, which is what a
|
|
9
|
+
* run that was flat at every mark should report.
|
|
10
|
+
*
|
|
11
|
+
* Every figure in this module that asks which trades are open asks it here, so
|
|
12
|
+
* the curve, the exposure and the count of bars in the market cannot come to
|
|
13
|
+
* three different answers about one bar.
|
|
14
|
+
*/
|
|
15
|
+
export function openOnBar(trade, barIndex) {
|
|
16
|
+
if (barIndex < trade.openedOnBar)
|
|
17
|
+
return false;
|
|
18
|
+
return trade.closedOnBar === null || barIndex < trade.closedOnBar;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A ratio against a basis that may not be there to divide by.
|
|
22
|
+
*
|
|
23
|
+
* Capital of zero and a peak of zero are both reachable, and both turn an
|
|
24
|
+
* honest division into a value JSON cannot carry: a report whose worst figure
|
|
25
|
+
* comes back `null` from a round trip is worse than one that says zero. A basis
|
|
26
|
+
* that is not positive has no ratio to state, so the figure beside it, which is
|
|
27
|
+
* money and is always true, is the one a reader is left with.
|
|
28
|
+
*/
|
|
29
|
+
export function ratioOf(value, basis) {
|
|
30
|
+
return basis > 0 ? value / basis : 0;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The curve, one point per report bar, in the order the bars arrived.
|
|
34
|
+
*
|
|
35
|
+
* Warmup bars are swept and not reported: their orders were real, so a trade
|
|
36
|
+
* opened during the warmup is already in the fold at the first point, with its
|
|
37
|
+
* charges already paid and its position already marked. A curve that began its
|
|
38
|
+
* fold at the first report bar would lose both, and would lose them silently.
|
|
39
|
+
*
|
|
40
|
+
* The running peak starts at the capital rather than at the first point, so a
|
|
41
|
+
* run that is down from its first bar is in drawdown at its first bar. Starting
|
|
42
|
+
* it at the first point would report every run as having begun at its high.
|
|
43
|
+
*/
|
|
44
|
+
export function equityOver(trades, marks, contract, capital) {
|
|
45
|
+
const points = [];
|
|
46
|
+
let held = [];
|
|
47
|
+
let next = 0;
|
|
48
|
+
let realised = 0;
|
|
49
|
+
let charges = 0;
|
|
50
|
+
let peak = capital;
|
|
51
|
+
let mark = null;
|
|
52
|
+
for (const bar of marks) {
|
|
53
|
+
// Opened by this bar, charges and all. The pointer is why the trades have
|
|
54
|
+
// to arrive in the order they opened.
|
|
55
|
+
while (next < trades.length) {
|
|
56
|
+
const opening = trades[next];
|
|
57
|
+
if (opening === undefined || opening.openedOnBar > bar.barIndex)
|
|
58
|
+
break;
|
|
59
|
+
charges += opening.charges;
|
|
60
|
+
held.push(opening);
|
|
61
|
+
next += 1;
|
|
62
|
+
}
|
|
63
|
+
// Closed by this bar, gross and all. A trade that opened and closed inside
|
|
64
|
+
// one bar is taken on and given up here in that order, so its cost and its
|
|
65
|
+
// gross are both in this point and its position is in none.
|
|
66
|
+
let closedHere = false;
|
|
67
|
+
for (const trade of held) {
|
|
68
|
+
if (closedBy(trade, bar.barIndex)) {
|
|
69
|
+
realised += trade.grossProfit;
|
|
70
|
+
closedHere = true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (closedHere)
|
|
74
|
+
held = held.filter((trade) => !closedBy(trade, bar.barIndex));
|
|
75
|
+
// A close the host did not have leaves the previous mark standing. It is
|
|
76
|
+
// carried across the warmup boundary too, so the first report bar of a run
|
|
77
|
+
// whose close is absent is marked at the last price there was.
|
|
78
|
+
if (bar.close !== null)
|
|
79
|
+
mark = bar.close;
|
|
80
|
+
if (!bar.inReport)
|
|
81
|
+
continue;
|
|
82
|
+
let openProfit = 0;
|
|
83
|
+
let exposure = 0;
|
|
84
|
+
for (const trade of held) {
|
|
85
|
+
// Before the first close there has ever been, a trade is marked at its
|
|
86
|
+
// own entry: no profit, and the position still visible in the exposure.
|
|
87
|
+
const at = mark ?? trade.entryPrice;
|
|
88
|
+
const direction = trade.side === 'long' ? 1 : -1;
|
|
89
|
+
openProfit += direction * (at - trade.entryPrice) * trade.units * contract.pointValue;
|
|
90
|
+
exposure += Math.abs(trade.units * at * contract.pointValue);
|
|
91
|
+
}
|
|
92
|
+
const cash = capital + realised - charges;
|
|
93
|
+
const equity = cash + openProfit;
|
|
94
|
+
if (equity > peak)
|
|
95
|
+
peak = equity;
|
|
96
|
+
const drawdown = equity - peak;
|
|
97
|
+
points.push({
|
|
98
|
+
barIndex: bar.barIndex,
|
|
99
|
+
time: bar.time,
|
|
100
|
+
realised,
|
|
101
|
+
charges,
|
|
102
|
+
openProfit,
|
|
103
|
+
cash,
|
|
104
|
+
equity,
|
|
105
|
+
exposure,
|
|
106
|
+
drawdown,
|
|
107
|
+
drawdownPercent: ratioOf(drawdown, peak),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return points;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* How many of these bars ended with something held.
|
|
114
|
+
*
|
|
115
|
+
* Swept rather than searched: a sorted list of the bars trades opened on, a
|
|
116
|
+
* sorted list of the bars they closed on, and the running difference between
|
|
117
|
+
* how many of each have gone by. That is the boundary rule `openOnBar` states,
|
|
118
|
+
* arrived at from the other side, and the two are asserted to agree over a
|
|
119
|
+
* generated corpus rather than trusted to. A count that disagrees with the
|
|
120
|
+
* curve beside it about which bars were in the market is exactly the kind of
|
|
121
|
+
* defect a reader finds by adding two of the printed figures up.
|
|
122
|
+
*/
|
|
123
|
+
export function barsInMarketOver(trades, equity) {
|
|
124
|
+
const opens = trades.map((trade) => trade.openedOnBar).sort(ascending);
|
|
125
|
+
const closes = trades
|
|
126
|
+
.filter((trade) => trade.closedOnBar !== null)
|
|
127
|
+
.map((trade) => trade.closedOnBar ?? 0)
|
|
128
|
+
.sort(ascending);
|
|
129
|
+
let opened = 0;
|
|
130
|
+
let closed = 0;
|
|
131
|
+
let live = 0;
|
|
132
|
+
let bars = 0;
|
|
133
|
+
for (const point of equity) {
|
|
134
|
+
while (opened < opens.length && (opens[opened] ?? 0) <= point.barIndex) {
|
|
135
|
+
live += 1;
|
|
136
|
+
opened += 1;
|
|
137
|
+
}
|
|
138
|
+
while (closed < closes.length && (closes[closed] ?? 0) <= point.barIndex) {
|
|
139
|
+
live -= 1;
|
|
140
|
+
closed += 1;
|
|
141
|
+
}
|
|
142
|
+
if (live > 0)
|
|
143
|
+
bars += 1;
|
|
144
|
+
}
|
|
145
|
+
return bars;
|
|
146
|
+
}
|
|
147
|
+
/** Whether this bar is the bar the trade closed on, or one after it. */
|
|
148
|
+
function closedBy(trade, barIndex) {
|
|
149
|
+
return trade.closedOnBar !== null && trade.closedOnBar <= barIndex;
|
|
150
|
+
}
|
|
151
|
+
/** Smallest first, said once, because a sort without a comparison sorts text. */
|
|
152
|
+
function ascending(left, right) {
|
|
153
|
+
return left - right;
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=equity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"equity.js","sourceRoot":"","sources":["../../../src/core/accounting/equity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The money: what a run made, what it cost, and what that is worth knowing.
|
|
3
|
+
*
|
|
4
|
+
* **This module imports no engine and no emitter, and it never will.** It is
|
|
5
|
+
* arithmetic over portable data: a list of settled fills, a list of bar closes,
|
|
6
|
+
* a charge schedule and the contract the run was carried out under. Two things
|
|
7
|
+
* follow from that and both of them are the reason for it.
|
|
8
|
+
*
|
|
9
|
+
* A stored record can be reported again with no engine present, which is what
|
|
10
|
+
* makes a run record a conformance case rather than a souvenir. And the engine
|
|
11
|
+
* can call this, when the day comes that a script may read its own equity,
|
|
12
|
+
* without a cycle and without a second implementation of any of these formulas
|
|
13
|
+
* sitting inside the execution path disagreeing with this one.
|
|
14
|
+
*
|
|
15
|
+
* The door names what a caller may use. The fold itself, the cost basis, the
|
|
16
|
+
* round trip state machine and the statistics stay behind it: they are one
|
|
17
|
+
* algorithm with one caller.
|
|
18
|
+
*
|
|
19
|
+
* Behaviour lands beside these shapes, each call in the file its type is in.
|
|
20
|
+
* The cost model is here: `chargeFor` is what one fill came to,
|
|
21
|
+
* `scheduleFromDeclaration` is the declaration's own commission as the one kind
|
|
22
|
+
* of schedule this module evaluates, and `scheduleProblem` is what a schedule
|
|
23
|
+
* is refused for before the first bar. The round trips, the equity curve, the
|
|
24
|
+
* statistics and the report land beside their own shapes the same way.
|
|
25
|
+
*
|
|
26
|
+
* The shapes were agreed before any of it computed, because they are what the
|
|
27
|
+
* engine, the backtest driver and a second engine all have to agree about.
|
|
28
|
+
*/
|
|
29
|
+
export { chargeFor, scheduleFromDeclaration, scheduleProblem } from './charges.js';
|
|
30
|
+
export type { BarMark, Contract, Money, RecordedFill } from './shapes.js';
|
|
31
|
+
export type { ChargeBase, ChargeBreakdown, ChargeLine, ChargeSchedule, ChargeSide, } from './charges.js';
|
|
32
|
+
export { tradesOf } from './trades.js';
|
|
33
|
+
export type { Trade } from './trades.js';
|
|
34
|
+
export { equityOver } from './equity.js';
|
|
35
|
+
export type { EquityPoint } from './equity.js';
|
|
36
|
+
export { monthlyOver } from './monthly.js';
|
|
37
|
+
export type { MonthlyReturn } from './monthly.js';
|
|
38
|
+
export { markersOf } from './markers.js';
|
|
39
|
+
export type { TradeMarker } from './markers.js';
|
|
40
|
+
export { summaryOf } from './statistics.js';
|
|
41
|
+
export type { Summary } from './statistics.js';
|
|
42
|
+
export { reportOf } from './report.js';
|
|
43
|
+
export type { Report } from './report.js';
|
|
44
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/accounting/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,EAAE,SAAS,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACnF,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC1E,YAAY,EACV,UAAU,EACV,eAAe,EACf,UAAU,EACV,cAAc,EACd,UAAU,GACX,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,YAAY,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The money: what a run made, what it cost, and what that is worth knowing.
|
|
3
|
+
*
|
|
4
|
+
* **This module imports no engine and no emitter, and it never will.** It is
|
|
5
|
+
* arithmetic over portable data: a list of settled fills, a list of bar closes,
|
|
6
|
+
* a charge schedule and the contract the run was carried out under. Two things
|
|
7
|
+
* follow from that and both of them are the reason for it.
|
|
8
|
+
*
|
|
9
|
+
* A stored record can be reported again with no engine present, which is what
|
|
10
|
+
* makes a run record a conformance case rather than a souvenir. And the engine
|
|
11
|
+
* can call this, when the day comes that a script may read its own equity,
|
|
12
|
+
* without a cycle and without a second implementation of any of these formulas
|
|
13
|
+
* sitting inside the execution path disagreeing with this one.
|
|
14
|
+
*
|
|
15
|
+
* The door names what a caller may use. The fold itself, the cost basis, the
|
|
16
|
+
* round trip state machine and the statistics stay behind it: they are one
|
|
17
|
+
* algorithm with one caller.
|
|
18
|
+
*
|
|
19
|
+
* Behaviour lands beside these shapes, each call in the file its type is in.
|
|
20
|
+
* The cost model is here: `chargeFor` is what one fill came to,
|
|
21
|
+
* `scheduleFromDeclaration` is the declaration's own commission as the one kind
|
|
22
|
+
* of schedule this module evaluates, and `scheduleProblem` is what a schedule
|
|
23
|
+
* is refused for before the first bar. The round trips, the equity curve, the
|
|
24
|
+
* statistics and the report land beside their own shapes the same way.
|
|
25
|
+
*
|
|
26
|
+
* The shapes were agreed before any of it computed, because they are what the
|
|
27
|
+
* engine, the backtest driver and a second engine all have to agree about.
|
|
28
|
+
*/
|
|
29
|
+
export { chargeFor, scheduleFromDeclaration, scheduleProblem } from './charges.js';
|
|
30
|
+
export { tradesOf } from './trades.js';
|
|
31
|
+
export { equityOver } from './equity.js';
|
|
32
|
+
export { monthlyOver } from './monthly.js';
|
|
33
|
+
export { markersOf } from './markers.js';
|
|
34
|
+
export { summaryOf } from './statistics.js';
|
|
35
|
+
export { reportOf } from './report.js';
|
|
36
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/accounting/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,EAAE,SAAS,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AASnF,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One marker per entry and exit fill, which is the chart's whole input.
|
|
3
|
+
*
|
|
4
|
+
* A chart draws a trade as two marks and a line between them, and everything it
|
|
5
|
+
* needs to do that is in the fills: the bar, the trade the fill belongs to, the
|
|
6
|
+
* side, the units, the price and the tag the order carried. So the markers are
|
|
7
|
+
* produced here, by the module that already knows which fill belongs to which
|
|
8
|
+
* trade, and no chart is needed to produce them and none is imported to.
|
|
9
|
+
*/
|
|
10
|
+
import type { RecordedFill } from './shapes.js';
|
|
11
|
+
import type { Trade } from './trades.js';
|
|
12
|
+
/** One entry or exit fill, addressed as a chart addresses it. */
|
|
13
|
+
export interface TradeMarker {
|
|
14
|
+
readonly barIndex: number;
|
|
15
|
+
readonly time: number | null;
|
|
16
|
+
readonly tradeIndex: number;
|
|
17
|
+
readonly kind: 'entry' | 'exit';
|
|
18
|
+
readonly side: 'buy' | 'sell';
|
|
19
|
+
readonly units: number;
|
|
20
|
+
readonly price: number;
|
|
21
|
+
readonly tag: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* One marker per entry and exit fill, against the trades those fills made up.
|
|
25
|
+
*
|
|
26
|
+
* **The fill is read with the same rule the trade list read it with.**
|
|
27
|
+
* `closedBy` and `openedBy` are imported from `trades.ts` rather than restated,
|
|
28
|
+
* because a marker that called an exit an entry would draw the chart the report
|
|
29
|
+
* contradicts. A fill that carried a reference through zero is both: it closes
|
|
30
|
+
* the trade the reference held and opens the next one, so it produces two
|
|
31
|
+
* markers, in that order, which is the order the trade list folded it in.
|
|
32
|
+
*
|
|
33
|
+
* **A trade is found by its reference and by the order it opened**, never by
|
|
34
|
+
* the bar it opened on: a reference that went to zero and was entered again on
|
|
35
|
+
* the same bar is two trades, and addressing them by bar would put both
|
|
36
|
+
* markers on the first. The trades are walked once per reference, oldest first,
|
|
37
|
+
* which is the order `tradesOf` built them in.
|
|
38
|
+
*
|
|
39
|
+
* The count is an identity rather than a claim: the markers of one trade are
|
|
40
|
+
* its `entries` plus its `exits`, and a test asserts it over the same fills.
|
|
41
|
+
*/
|
|
42
|
+
export declare function markersOf(fills: readonly RecordedFill[], trades: readonly Trade[]): readonly TradeMarker[];
|
|
43
|
+
//# sourceMappingURL=markers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markers.d.ts","sourceRoot":"","sources":["../../../src/core/accounting/markers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,iEAAiE;AACjE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,SAAS,YAAY,EAAE,EAC9B,MAAM,EAAE,SAAS,KAAK,EAAE,GACvB,SAAS,WAAW,EAAE,CA6BxB"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { closedBy, openedBy } from './trades.js';
|
|
2
|
+
/**
|
|
3
|
+
* One marker per entry and exit fill, against the trades those fills made up.
|
|
4
|
+
*
|
|
5
|
+
* **The fill is read with the same rule the trade list read it with.**
|
|
6
|
+
* `closedBy` and `openedBy` are imported from `trades.ts` rather than restated,
|
|
7
|
+
* because a marker that called an exit an entry would draw the chart the report
|
|
8
|
+
* contradicts. A fill that carried a reference through zero is both: it closes
|
|
9
|
+
* the trade the reference held and opens the next one, so it produces two
|
|
10
|
+
* markers, in that order, which is the order the trade list folded it in.
|
|
11
|
+
*
|
|
12
|
+
* **A trade is found by its reference and by the order it opened**, never by
|
|
13
|
+
* the bar it opened on: a reference that went to zero and was entered again on
|
|
14
|
+
* the same bar is two trades, and addressing them by bar would put both
|
|
15
|
+
* markers on the first. The trades are walked once per reference, oldest first,
|
|
16
|
+
* which is the order `tradesOf` built them in.
|
|
17
|
+
*
|
|
18
|
+
* The count is an identity rather than a claim: the markers of one trade are
|
|
19
|
+
* its `entries` plus its `exits`, and a test asserts it over the same fills.
|
|
20
|
+
*/
|
|
21
|
+
export function markersOf(fills, trades) {
|
|
22
|
+
const ordered = fills.slice().sort((a, b) => a.seq - b.seq);
|
|
23
|
+
const queues = new Map();
|
|
24
|
+
for (const trade of trades) {
|
|
25
|
+
const held = queues.get(trade.positionRef) ?? [];
|
|
26
|
+
held.push(trade);
|
|
27
|
+
queues.set(trade.positionRef, held);
|
|
28
|
+
}
|
|
29
|
+
const out = [];
|
|
30
|
+
for (const fill of ordered) {
|
|
31
|
+
const queue = queues.get(fill.positionRef) ?? [];
|
|
32
|
+
const closing = closedBy(fill.refSizeBefore, fill.refSizeAfter);
|
|
33
|
+
const opening = openedBy(fill.refSizeBefore, fill.refSizeAfter);
|
|
34
|
+
if (closing > 0) {
|
|
35
|
+
const held = queue[0];
|
|
36
|
+
if (held !== undefined)
|
|
37
|
+
out.push(markerFor(fill, held.index, 'exit', closing));
|
|
38
|
+
// The trade the reference held is finished by a fill that closed the
|
|
39
|
+
// whole of it, and the next trade on that reference is the one the fills
|
|
40
|
+
// after this belong to.
|
|
41
|
+
if (held !== undefined && (opening > 0 || fill.refSizeAfter === 0))
|
|
42
|
+
queue.shift();
|
|
43
|
+
}
|
|
44
|
+
if (opening > 0) {
|
|
45
|
+
const held = queue[0];
|
|
46
|
+
if (held !== undefined)
|
|
47
|
+
out.push(markerFor(fill, held.index, 'entry', opening));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
function markerFor(fill, tradeIndex, kind, units) {
|
|
53
|
+
return {
|
|
54
|
+
barIndex: fill.barIndex,
|
|
55
|
+
time: fill.barTime,
|
|
56
|
+
tradeIndex,
|
|
57
|
+
kind,
|
|
58
|
+
side: fill.side,
|
|
59
|
+
units,
|
|
60
|
+
price: fill.price,
|
|
61
|
+
tag: fill.tag,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=markers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markers.js","sourceRoot":"","sources":["../../../src/core/accounting/markers.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAejD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,SAAS,CACvB,KAA8B,EAC9B,MAAwB;IAExB,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,IAAI,GAAG,EAAmB,CAAC;IAC1C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;QACjD,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjB,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,GAAG,GAAkB,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;QACjD,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAEhE,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACtB,IAAI,IAAI,KAAK,SAAS;gBAAE,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;YAC/E,qEAAqE;YACrE,yEAAyE;YACzE,wBAAwB;YACxB,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,OAAO,GAAG,CAAC,IAAI,IAAI,CAAC,YAAY,KAAK,CAAC,CAAC;gBAAE,KAAK,CAAC,KAAK,EAAE,CAAC;QACpF,CAAC;QACD,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACtB,IAAI,IAAI,KAAK,SAAS;gBAAE,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QAClF,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,SAAS,CAChB,IAAkB,EAClB,UAAkB,EAClB,IAAsB,EACtB,KAAa;IAEb,OAAO;QACL,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,IAAI,EAAE,IAAI,CAAC,OAAO;QAClB,UAAU;QACV,IAAI;QACJ,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,KAAK;QACL,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,GAAG,EAAE,IAAI,CAAC,GAAG;KACd,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The month by month table, bucketed in UTC from bar times.
|
|
3
|
+
*
|
|
4
|
+
* **UTC, and it says so on the type.** A calendar month in the instrument's own
|
|
5
|
+
* timezone would need the session machinery and the instrument's calendar, and
|
|
6
|
+
* a table that silently buckets a trade into the wrong month is worse than one
|
|
7
|
+
* that states the basis it used. No timezone library, and no pretence of the
|
|
8
|
+
* instrument's calendar.
|
|
9
|
+
*/
|
|
10
|
+
import type { EquityPoint } from './equity.js';
|
|
11
|
+
import type { Money } from './shapes.js';
|
|
12
|
+
import type { Trade } from './trades.js';
|
|
13
|
+
/** One calendar month of the run, in UTC. */
|
|
14
|
+
export interface MonthlyReturn {
|
|
15
|
+
readonly year: number;
|
|
16
|
+
/** 1 to 12, UTC. */
|
|
17
|
+
readonly month: number;
|
|
18
|
+
readonly netProfit: Money;
|
|
19
|
+
/** Against the equity at the month's first bar. */
|
|
20
|
+
readonly returnPercent: number;
|
|
21
|
+
readonly trades: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The months a run passed through, in the order it passed through them.
|
|
25
|
+
*
|
|
26
|
+
* **A month holds the change in equity across the closes inside it.** The first
|
|
27
|
+
* point of the curve has nothing before it to be compared with, so it opens the
|
|
28
|
+
* table rather than contributing to it, and every later point contributes what
|
|
29
|
+
* it moved from the point before. The consequence is an identity rather than a
|
|
30
|
+
* claim: the months add up to the equity at the last point less the equity at
|
|
31
|
+
* the first, and nothing that happened during the warmup is attributed to a
|
|
32
|
+
* month it did not happen in.
|
|
33
|
+
*
|
|
34
|
+
* `returnPercent` is that change over the equity at the month's first bar,
|
|
35
|
+
* which is the basis this table states and the reason the figure is a fraction
|
|
36
|
+
* rather than a fraction times a hundred: `drawdownPercent` beside it is
|
|
37
|
+
* `drawdown / peak`, and one report with two conventions is a report a reader
|
|
38
|
+
* has to check every figure of.
|
|
39
|
+
*
|
|
40
|
+
* `trades` counts the trades that closed inside the month, by the time they
|
|
41
|
+
* closed. An open trade is in no month, because the month it will be counted in
|
|
42
|
+
* is not decided yet.
|
|
43
|
+
*
|
|
44
|
+
* **A point with no time is in no month.** A bucket is a calendar fact and a
|
|
45
|
+
* bar with no time states no calendar, so such a point carries its change into
|
|
46
|
+
* the month in force rather than opening one, and where none is in force it is
|
|
47
|
+
* outside the table altogether. That is the honest reading: bucketing it by the
|
|
48
|
+
* month that happened to come before would put money in a month on the strength
|
|
49
|
+
* of nothing.
|
|
50
|
+
*/
|
|
51
|
+
export declare function monthlyOver(equity: readonly EquityPoint[], trades: readonly Trade[]): readonly MonthlyReturn[];
|
|
52
|
+
//# sourceMappingURL=monthly.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"monthly.d.ts","sourceRoot":"","sources":["../../../src/core/accounting/monthly.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,6CAA6C;AAC7C,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oBAAoB;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC;IAC1B,mDAAmD;IACnD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,SAAS,WAAW,EAAE,EAC9B,MAAM,EAAE,SAAS,KAAK,EAAE,GACvB,SAAS,aAAa,EAAE,CA2C1B"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The months a run passed through, in the order it passed through them.
|
|
3
|
+
*
|
|
4
|
+
* **A month holds the change in equity across the closes inside it.** The first
|
|
5
|
+
* point of the curve has nothing before it to be compared with, so it opens the
|
|
6
|
+
* table rather than contributing to it, and every later point contributes what
|
|
7
|
+
* it moved from the point before. The consequence is an identity rather than a
|
|
8
|
+
* claim: the months add up to the equity at the last point less the equity at
|
|
9
|
+
* the first, and nothing that happened during the warmup is attributed to a
|
|
10
|
+
* month it did not happen in.
|
|
11
|
+
*
|
|
12
|
+
* `returnPercent` is that change over the equity at the month's first bar,
|
|
13
|
+
* which is the basis this table states and the reason the figure is a fraction
|
|
14
|
+
* rather than a fraction times a hundred: `drawdownPercent` beside it is
|
|
15
|
+
* `drawdown / peak`, and one report with two conventions is a report a reader
|
|
16
|
+
* has to check every figure of.
|
|
17
|
+
*
|
|
18
|
+
* `trades` counts the trades that closed inside the month, by the time they
|
|
19
|
+
* closed. An open trade is in no month, because the month it will be counted in
|
|
20
|
+
* is not decided yet.
|
|
21
|
+
*
|
|
22
|
+
* **A point with no time is in no month.** A bucket is a calendar fact and a
|
|
23
|
+
* bar with no time states no calendar, so such a point carries its change into
|
|
24
|
+
* the month in force rather than opening one, and where none is in force it is
|
|
25
|
+
* outside the table altogether. That is the honest reading: bucketing it by the
|
|
26
|
+
* month that happened to come before would put money in a month on the strength
|
|
27
|
+
* of nothing.
|
|
28
|
+
*/
|
|
29
|
+
export function monthlyOver(equity, trades) {
|
|
30
|
+
const buckets = [];
|
|
31
|
+
let previous;
|
|
32
|
+
let current;
|
|
33
|
+
for (const point of equity) {
|
|
34
|
+
const at = monthOf(point.time);
|
|
35
|
+
if (at !== null && (current === undefined || current.year !== at.year || current.month !== at.month)) {
|
|
36
|
+
// The equity this month started from, which is where the previous month
|
|
37
|
+
// left the account and not where this one's first bar closed. Taking the
|
|
38
|
+
// opening point's own equity put the month's first move into the
|
|
39
|
+
// numerator and into the denominator at once: a February that doubled a
|
|
40
|
+
// thousand pounds reported fifty percent, because the gain was divided by
|
|
41
|
+
// the two thousand it had already produced.
|
|
42
|
+
current = {
|
|
43
|
+
year: at.year,
|
|
44
|
+
month: at.month,
|
|
45
|
+
netProfit: 0,
|
|
46
|
+
basis: previous === undefined ? point.equity : previous.equity,
|
|
47
|
+
trades: 0,
|
|
48
|
+
};
|
|
49
|
+
buckets.push(current);
|
|
50
|
+
}
|
|
51
|
+
if (previous !== undefined && current !== undefined) {
|
|
52
|
+
current.netProfit += point.equity - previous.equity;
|
|
53
|
+
}
|
|
54
|
+
previous = point;
|
|
55
|
+
}
|
|
56
|
+
for (const trade of trades) {
|
|
57
|
+
const at = monthOf(trade.closedAt);
|
|
58
|
+
if (at === null)
|
|
59
|
+
continue;
|
|
60
|
+
const bucket = buckets.find((one) => one.year === at.year && one.month === at.month);
|
|
61
|
+
if (bucket !== undefined)
|
|
62
|
+
bucket.trades += 1;
|
|
63
|
+
}
|
|
64
|
+
return buckets.map((one) => ({
|
|
65
|
+
year: one.year,
|
|
66
|
+
month: one.month,
|
|
67
|
+
netProfit: one.netProfit,
|
|
68
|
+
returnPercent: one.basis > 0 ? one.netProfit / one.basis : 0,
|
|
69
|
+
trades: one.trades,
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The calendar month an instant falls in, in UTC and in no other zone.
|
|
74
|
+
*
|
|
75
|
+
* Decomposed rather than formatted, so no locale, no zone table and no library
|
|
76
|
+
* is involved: the same instant produces the same month on every machine this
|
|
77
|
+
* ever runs on.
|
|
78
|
+
*/
|
|
79
|
+
function monthOf(time) {
|
|
80
|
+
if (time === null || !Number.isFinite(time) || Math.abs(time) > LATEST_INSTANT)
|
|
81
|
+
return null;
|
|
82
|
+
const at = new Date(time);
|
|
83
|
+
return { year: at.getUTCFullYear(), month: at.getUTCMonth() + 1 };
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The furthest either way an instant can be and still name a month.
|
|
87
|
+
*
|
|
88
|
+
* A finite number outside it decomposes to NaN rather than throwing, and a NaN
|
|
89
|
+
* year never equals the next one, so every point opened a bucket of its own and
|
|
90
|
+
* a fifty thousand bar run produced fifty thousand rows of NaN. The canonical
|
|
91
|
+
* writer then threw a bare error with no code on them, out of core, on a path a
|
|
92
|
+
* host could not tell from an internal fault. The mistake that gets here is
|
|
93
|
+
* ordinary: bar times supplied in nanoseconds rather than milliseconds.
|
|
94
|
+
*
|
|
95
|
+
* A point whose time names no month contributes to no month, which is what an
|
|
96
|
+
* absent time already did.
|
|
97
|
+
*/
|
|
98
|
+
const LATEST_INSTANT = 8.64e15;
|
|
99
|
+
//# sourceMappingURL=monthly.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"monthly.js","sourceRoot":"","sources":["../../../src/core/accounting/monthly.ts"],"names":[],"mappings":"AAwBA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,WAAW,CACzB,MAA8B,EAC9B,MAAwB;IAExB,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,QAAiC,CAAC;IACtC,IAAI,OAA2B,CAAC;IAEhC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,EAAE,KAAK,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,OAAO,CAAC,IAAI,KAAK,EAAE,CAAC,IAAI,IAAI,OAAO,CAAC,KAAK,KAAK,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;YACrG,wEAAwE;YACxE,yEAAyE;YACzE,iEAAiE;YACjE,wEAAwE;YACxE,0EAA0E;YAC1E,4CAA4C;YAC5C,OAAO,GAAG;gBACR,IAAI,EAAE,EAAE,CAAC,IAAI;gBACb,KAAK,EAAE,EAAE,CAAC,KAAK;gBACf,SAAS,EAAE,CAAC;gBACZ,KAAK,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM;gBAC9D,MAAM,EAAE,CAAC;aACV,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;QACD,IAAI,QAAQ,KAAK,SAAS,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YACpD,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;QACtD,CAAC;QACD,QAAQ,GAAG,KAAK,CAAC;IACnB,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACnC,IAAI,EAAE,KAAK,IAAI;YAAE,SAAS;QAC1B,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,EAAE,CAAC,IAAI,IAAI,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;QACrF,IAAI,MAAM,KAAK,SAAS;YAAE,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC3B,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,aAAa,EAAE,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5D,MAAM,EAAE,GAAG,CAAC,MAAM;KACnB,CAAC,CAAC,CAAC;AACN,CAAC;AAYD;;;;;;GAMG;AACH,SAAS,OAAO,CAAC,IAAmB;IAClC,IAAI,IAAI,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,cAAc;QAAE,OAAO,IAAI,CAAC;IAC5F,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,WAAW,EAAE,GAAG,CAAC,EAAE,CAAC;AACpE,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,cAAc,GAAG,OAAO,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ChargeSchedule } from './charges.js';
|
|
2
|
+
import type { EquityPoint } from './equity.js';
|
|
3
|
+
import type { MonthlyReturn } from './monthly.js';
|
|
4
|
+
import type { TradeMarker } from './markers.js';
|
|
5
|
+
import type { BarMark, Contract, Money, RecordedFill } from './shapes.js';
|
|
6
|
+
import type { Summary } from './statistics.js';
|
|
7
|
+
import type { Trade } from './trades.js';
|
|
8
|
+
/** Everything a run is reported as, and nothing a chart has to compute. */
|
|
9
|
+
export interface Report {
|
|
10
|
+
readonly summary: Summary;
|
|
11
|
+
readonly trades: readonly Trade[];
|
|
12
|
+
readonly equity: readonly EquityPoint[];
|
|
13
|
+
readonly monthly: readonly MonthlyReturn[];
|
|
14
|
+
readonly markers: readonly TradeMarker[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The whole report, folded from the fills, the bar closes and the schedule.
|
|
18
|
+
*
|
|
19
|
+
* **One pass, in one order, and the order is the result.** The fills are put in
|
|
20
|
+
* `seq` order once, here, and every fold below reads that same list: the
|
|
21
|
+
* charges are computed in it, the trades are built from it, the curve is marked
|
|
22
|
+
* along it and the markers come off it. A second ordering anywhere would be a
|
|
23
|
+
* report that is right to eleven digits and different in the twelfth on
|
|
24
|
+
* somebody else's engine, which is the failure this module is shaped to make
|
|
25
|
+
* impossible rather than unlikely.
|
|
26
|
+
*
|
|
27
|
+
* **A charge belongs to the fill that incurred it.** `chargeFor` rounds one
|
|
28
|
+
* fill's total once, and nothing here rounds it again or re-sums the collection
|
|
29
|
+
* in another order, so `sum(trade.charges)` and `summary.charges` are the same
|
|
30
|
+
* money and a test asserts it rather than a page claiming it.
|
|
31
|
+
*
|
|
32
|
+
* A run carried out under no schedule at all is charged nothing, which is a
|
|
33
|
+
* study of the strategy before costs and is a thing worth being able to ask
|
|
34
|
+
* for. It is not a default: `scheduleFromDeclaration` is what a run under the
|
|
35
|
+
* declaration's own commission uses, and the caller states which it wants.
|
|
36
|
+
*/
|
|
37
|
+
export declare function reportOf(fills: readonly RecordedFill[], marks: readonly BarMark[], schedule: ChargeSchedule | null, contract: Contract, capital: Money): Report;
|
|
38
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../../src/core/accounting/report.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE1E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,2EAA2E;AAC3E,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC;IACxC,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;CAC1C;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,SAAS,YAAY,EAAE,EAC9B,KAAK,EAAE,SAAS,OAAO,EAAE,EACzB,QAAQ,EAAE,cAAc,GAAG,IAAI,EAC/B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,KAAK,GACb,MAAM,CAiBR"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The report: what a run came to, folded from its fills and its bar closes.
|
|
3
|
+
*
|
|
4
|
+
* **The evaluation order is fixed here and nowhere else**, because a report
|
|
5
|
+
* that is right to eleven digits and different in the twelfth fails a
|
|
6
|
+
* conformance comparison months later on somebody else's engine, and the cause
|
|
7
|
+
* is always a line nobody thought was arithmetic. Fills in `seq` order, charge
|
|
8
|
+
* lines in declaration order, one rounding per fill total, no collection
|
|
9
|
+
* re-summed in another order, no dependence on a map's iteration order, no wall
|
|
10
|
+
* clock and no random number generator anywhere in this module.
|
|
11
|
+
*
|
|
12
|
+
* **What the report is not is read by a script.** The money entries of the
|
|
13
|
+
* `pos` namespace stay planned and go on refusing at the call. The moment a
|
|
14
|
+
* script can read its own equity mid-run, the money layer joins the execution
|
|
15
|
+
* path, and therefore joins the conformance surface, and every formula in this
|
|
16
|
+
* module has to be agreed by a second engine before a script may branch on it.
|
|
17
|
+
* This module computes the money after the fact from a record; whether a script
|
|
18
|
+
* may read it is a later decision. That this module imports no engine is the
|
|
19
|
+
* structural half of keeping that decision open: when it is taken, the engine
|
|
20
|
+
* calls this, and there is no second implementation to disagree with.
|
|
21
|
+
*/
|
|
22
|
+
import { chargeFor } from './charges.js';
|
|
23
|
+
import { equityOver } from './equity.js';
|
|
24
|
+
import { monthlyOver } from './monthly.js';
|
|
25
|
+
import { markersOf } from './markers.js';
|
|
26
|
+
import { summaryOf } from './statistics.js';
|
|
27
|
+
import { tradesOf } from './trades.js';
|
|
28
|
+
/**
|
|
29
|
+
* The whole report, folded from the fills, the bar closes and the schedule.
|
|
30
|
+
*
|
|
31
|
+
* **One pass, in one order, and the order is the result.** The fills are put in
|
|
32
|
+
* `seq` order once, here, and every fold below reads that same list: the
|
|
33
|
+
* charges are computed in it, the trades are built from it, the curve is marked
|
|
34
|
+
* along it and the markers come off it. A second ordering anywhere would be a
|
|
35
|
+
* report that is right to eleven digits and different in the twelfth on
|
|
36
|
+
* somebody else's engine, which is the failure this module is shaped to make
|
|
37
|
+
* impossible rather than unlikely.
|
|
38
|
+
*
|
|
39
|
+
* **A charge belongs to the fill that incurred it.** `chargeFor` rounds one
|
|
40
|
+
* fill's total once, and nothing here rounds it again or re-sums the collection
|
|
41
|
+
* in another order, so `sum(trade.charges)` and `summary.charges` are the same
|
|
42
|
+
* money and a test asserts it rather than a page claiming it.
|
|
43
|
+
*
|
|
44
|
+
* A run carried out under no schedule at all is charged nothing, which is a
|
|
45
|
+
* study of the strategy before costs and is a thing worth being able to ask
|
|
46
|
+
* for. It is not a default: `scheduleFromDeclaration` is what a run under the
|
|
47
|
+
* declaration's own commission uses, and the caller states which it wants.
|
|
48
|
+
*/
|
|
49
|
+
export function reportOf(fills, marks, schedule, contract, capital) {
|
|
50
|
+
const ordered = fills.slice().sort((a, b) => a.seq - b.seq);
|
|
51
|
+
const charges = ordered.map((fill) => schedule === null ? 0 : chargeFor(schedule, fill, contract).total);
|
|
52
|
+
const trades = tradesOf(ordered, charges, marks, contract);
|
|
53
|
+
const equity = equityOver(trades, marks, contract, capital);
|
|
54
|
+
const summary = summaryOf(trades, equity, contract, capital);
|
|
55
|
+
return {
|
|
56
|
+
summary,
|
|
57
|
+
trades,
|
|
58
|
+
equity,
|
|
59
|
+
monthly: monthlyOver(equity, trades),
|
|
60
|
+
markers: markersOf(ordered, trades),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/core/accounting/report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAYvC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,QAAQ,CACtB,KAA8B,EAC9B,KAAyB,EACzB,QAA+B,EAC/B,QAAkB,EAClB,OAAc;IAEd,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACnC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,KAAK,CAClE,CAAC;IAEF,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAE7D,OAAO;QACL,OAAO;QACP,MAAM;QACN,MAAM;QACN,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC;QACpC,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;KACpC,CAAC;AACJ,CAAC"}
|