1 | replace real with double. |
2 | replace Real with Double. |
3 | |
4 | srecord noeq MPM2(real[] ticker) { |
5 | // how much percentual slippage we have for each position on |
6 | // average dependent on the market (trading site) we are using |
7 | srecord Market(real adversity) {} |
8 | |
9 | srecord Juicer(real lossTolerance, real pullback) {} |
10 | |
11 | srecord Position(real openingTime, real direction) {} |
12 | |
13 | srecord noeq LiveTicker(real[] data, int time) { |
14 | Real currently() { ret lookback(0); } |
15 | Real lookback(real time) { |
16 | int index = iceil(this.time-1-time); |
17 | ret index >= 0 ? data[index] : null; |
18 | } |
19 | |
20 | void add(real value) { |
21 | if (time >= l(data)) { |
22 | data = resizeArray(data, max(1, limitToSafeArraySize(l(data)*2L))); |
23 | if (time >= l(data)) fail("Can't handle more than 2 billion ticker entries"); |
24 | } |
25 | data[time++] = value; |
26 | } |
27 | } |
28 | |
29 | srecord Eye(real time, real minMove) { |
30 | real adviseDirection(LiveTicker ticker) { |
31 | Real currently = ticker.currently(); |
32 | if (currently == null) ret 0; |
33 | Real before = ticker.lookback(time); |
34 | if (before == null) ret 0; |
35 | real move = currently-before; |
36 | if (abs(move) >= minMove) ret (real) sign(move); |
37 | ret 0; |
38 | } |
39 | } |
40 | |
41 | real ticker(real time) { ret ticker(iceil(time)); } |
42 | |
43 | real openingPrice(Position p) { ret ticker(p.openingTime); } |
44 | |
45 | // all "profit" functions return a positive or negative percent value |
46 | real profit(Position p, real time, Market m) { |
47 | ret (ticker(time)/openingPrice(p)*100-100)*p.direction - m.adversity; |
48 | } |
49 | |
50 | Real closingTime(Position p, Juicer j, Market m) { |
51 | int time = iceil(p.openingTime); |
52 | real openingPrice = ticker(time); |
53 | real crest = -infinity(); |
54 | while (time < ticker.length-1) { |
55 | real profit = profit(p, time, m); |
56 | crest = max(crest, profit); |
57 | if (profit < (profit < 0 ? -j.lossTolerance : crest-j.pullback)) break; |
58 | ++time; |
59 | } |
60 | null; |
61 | } |
62 | |
63 | Real profit(Position p, Juicer j, Market m) { |
64 | Real closingTime = closingTime(p, j, m); |
65 | ret closingTime == null ? null : profit(p, closingTime, m); |
66 | } |
67 | |
68 | // How profitable is it to open a position of any direction |
69 | // at a certain point in time? |
70 | Real profitability(real time, Juicer j, Market m) { |
71 | ret maxAllowingNull( |
72 | profit(new Position(time, -1), j, m), |
73 | profit(new Position(time, 1), j, m)); |
74 | } |
75 | |
76 | abstract class Convergent extends ItIt<Real> { |
77 | Real value; |
78 | bool stepped, done; |
79 | |
80 | public bool hasNext() { |
81 | if (done) false; |
82 | |
83 | if (!stepped) { |
84 | stepped = true; |
85 | step(); |
86 | } |
87 | |
88 | ret !done; |
89 | } |
90 | |
91 | public Real next() { |
92 | assertTrue(hasNext()); |
93 | stepped = false; |
94 | ret value; |
95 | } |
96 | |
97 | abstract void step(); |
98 | } |
99 | |
100 | // eye can be null, then we just test the juicer |
101 | record noeq Backtest(Eye eye, Juicer j, Market m) extends Convergent { |
102 | Iterator<Int> openingTimes = new WeightlessShuffledIterator<Int>(intRangeList(ticker.length)); |
103 | new Average profitPerPosition; |
104 | |
105 | new Average positionsOpenedPercentage; |
106 | |
107 | // percentage of positions closed before reaching the end of the ticker "tape" |
108 | new Average positionsClosedInTimePercentage; |
109 | |
110 | void step { |
111 | if (!openingTimes.hasNext()) |
112 | ret with done = true; |
113 | |
114 | int openingTime = openingTimes.next(); |
115 | |
116 | Real profit; |
117 | if (eye == null) |
118 | profit = profitability(openingTime, j, m); |
119 | else { |
120 | real direction = eye.adviseDirection(new LiveTicker(ticker, openingTime)); |
121 | positionsOpenedPercentage.addSample(direction != 0 ? 100 : 0); |
122 | if (direction == 0) |
123 | ret; |
124 | Position position = new Position(openingTime, direction); |
125 | profit = profit(position, j, m); |
126 | } |
127 | |
128 | positionsClosedInTimePercentage.addSample(profit != null ? 100 : 0); |
129 | if (profit != null) |
130 | profitPerPosition.addSample(profit); |
131 | value = profitPerPosition!; |
132 | } |
133 | } |
134 | } |
Began life as a copy of #1036148
download show line numbers debug dex old transpilations
Travelled to 2 computer(s): mqqgnosmbjvj, wnsclhtenguj
No comments. add comment
Snippet ID: | #1036152 |
Snippet name: | MPM2 backup untested |
Eternal ID of this version: | #1036152/2 |
Text MD5: | d9aa50c1837b83965f4784e733b73844 |
Author: | stefan |
Category: | javax / trading bot |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2022-10-01 06:21:14 |
Source code size: | 4081 bytes / 134 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 149 / 154 |
Version history: | 1 change(s) |
Referenced in: | [show references] |