-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBench.java
More file actions
131 lines (125 loc) · 4.93 KB
/
Copy pathBench.java
File metadata and controls
131 lines (125 loc) · 4.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// VolumeSpike backtest micro-kernel — Java. See SPEC.md.
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Bench {
static final long BAR_NS = 60000000000L;
static final int W = 20;
static final double TRAIL_TRIGGER = 0.005;
static final double PRICE_CHANGE_MIN = 0.0;
static final double[] VOL_MULT = {2.0, 2.5, 3.0, 3.5, 4.0, 5.0, 6.0, 8.0};
static final double[] SL_PCT = {0.010, 0.015, 0.020, 0.030, 0.040};
static final double[] TRAIL_PCT = {0.005, 0.010, 0.020, 0.030};
static long[] ts;
static double[] price;
static double[] qty;
static double outPnl;
static long runBacktest(double volMult, double slPct, double trailPct) {
int n = ts.length;
long curBarId = -1;
double barOpen = 0, barClose = 0, barVol = 0;
double[] ring = new double[W];
int ringIdx = 0, ringCount = 0;
double ringSum = 0;
boolean inPos = false;
double entry = 0, stop = 0, peak = 0, trig = 0;
long trades = 0;
double pnl = 0;
for (int i = 0; i < n; i++) {
long t = ts[i];
double p = price[i];
double q = qty[i];
long barId = t / BAR_NS;
if (barId != curBarId) {
if (curBarId >= 0) {
if (!inPos && ringCount >= W) {
double avg = ringSum / (double) ringCount;
if (avg > 0.0) {
double volRatio = barVol / avg;
double priceChange = (barClose - barOpen) / barOpen;
if (volRatio >= volMult && priceChange >= PRICE_CHANGE_MIN) {
inPos = true;
entry = barClose;
stop = entry * (1.0 - slPct);
peak = entry;
trig = entry * (1.0 + TRAIL_TRIGGER);
}
}
}
if (ringCount == W) {
ringSum -= ring[ringIdx];
} else {
ringCount++;
}
ringSum += barVol;
ring[ringIdx] = barVol;
ringIdx++;
if (ringIdx == W) ringIdx = 0;
}
curBarId = barId;
barOpen = p;
barClose = p;
barVol = q;
} else {
barClose = p;
barVol += q;
}
if (inPos) {
if (p <= stop) {
pnl += (stop - entry) / entry;
trades++;
inPos = false;
} else {
if (p > peak) peak = p;
if (p >= trig) {
double newStop = peak * (1.0 - trailPct);
if (newStop > stop) stop = newStop;
}
}
}
}
outPnl += pnl;
return trades;
}
public static void main(String[] a) throws IOException {
String path = a[0];
int repeats = a.length > 1 ? Integer.parseInt(a[1]) : 3;
byte[] bytes = Files.readAllBytes(Paths.get(path));
int n = bytes.length / 24;
ts = new long[n];
price = new double[n];
qty = new double[n];
ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
for (int i = 0; i < n; i++) {
ts[i] = bb.getLong();
price[i] = (double) bb.getLong();
qty[i] = (double) bb.getLong();
}
long sumPrice = 0;
for (int i = 0; i < n; i++) sumPrice += (long) price[i];
System.err.printf("[java] loaded n=%d first_ts=%d last_ts=%d sum_price=%d%n", n, ts[0], ts[n - 1], sumPrice);
int k = VOL_MULT.length * SL_PCT.length * TRAIL_PCT.length;
long totalIters = (long) n * (long) k;
double best = Double.POSITIVE_INFINITY;
long ckTrades = 0;
double ckPnl = 0;
for (int r = 0; r < repeats; r++) {
long t0 = System.nanoTime();
long totalTrades = 0;
outPnl = 0;
for (double vm : VOL_MULT)
for (double sl : SL_PCT)
for (double tp : TRAIL_PCT)
totalTrades += runBacktest(vm, sl, tp);
double dt = (System.nanoTime() - t0) / 1e9;
if (dt < best) best = dt;
ckTrades = totalTrades;
ckPnl = outPnl;
System.err.printf("[java] run %d %.4fs %.1f Mticks/s%n", r, dt, totalIters / dt / 1e6);
}
System.out.printf("RESULT lang=java n=%d k=%d iters=%d best_s=%.4f mticks_s=%.1f trades=%d pnl=%.6f%n",
n, k, totalIters, best, totalIters / best / 1e6, ckTrades, ckPnl);
}
}