Skip to content

Commit fd5a529

Browse files
committed
test accepted ratchet strategy adapter
1 parent 88fd690 commit fd5a529

1 file changed

Lines changed: 89 additions & 0 deletions

File tree

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { describe, expect, it } from "vitest";
2+
import {
3+
ACCEPTED_RATCHET,
4+
applyAcceptedRatchet5m
5+
} from "../research/regime-trend-v1/accepted-ratchet-tools.mjs";
6+
7+
const FIVE = 5 * 60 * 1000;
8+
9+
function trade(overrides = {}) {
10+
return {
11+
strategy_id: "regime-trend-v1",
12+
implementation_version: "test",
13+
dataset_hash: "test",
14+
symbol: "TESTUSDT",
15+
timeframe: "4h",
16+
direction: "long",
17+
signal_timestamp: -4 * 60 * 60 * 1000,
18+
entry_timestamp: 0,
19+
raw_entry_open: 100,
20+
entry_fill: 100,
21+
entry_atr: 10,
22+
initial_stop: 90,
23+
exit_timestamp: 4 * FIVE,
24+
raw_exit_reference: 100,
25+
exit_fill: 99.95,
26+
exit_reason: "trend_exit",
27+
quantity: 0.01,
28+
entry_fee: 0.001,
29+
exit_fee: 0.0009995,
30+
gross_pnl: -0.0005,
31+
net_pnl: -0.0024995,
32+
net_return: -0.0024995,
33+
bars_held: 0,
34+
...overrides
35+
};
36+
}
37+
38+
function candle(timestamp: number, overrides = {}) {
39+
return {
40+
timestamp,
41+
open: 100,
42+
high: 102,
43+
low: 98,
44+
close: 100,
45+
volume: 1,
46+
...overrides
47+
};
48+
}
49+
50+
function map(candles: ReturnType<typeof candle>[]) {
51+
return new Map(candles.map((item) => [item.timestamp, item]));
52+
}
53+
54+
describe("Regime Trend v1 accepted +2 ATR break-even ratchet", () => {
55+
it("freezes the accepted candidate", () => {
56+
expect(ACCEPTED_RATCHET).toEqual({
57+
id: "touch-2.00-lock-0.00",
58+
activationAtr: 2,
59+
floorAtr: 0
60+
});
61+
expect(Object.isFrozen(ACCEPTED_RATCHET)).toBe(true);
62+
});
63+
64+
it("activates on +2 ATR and exits from the next 5m candle when binding", () => {
65+
const result = applyAcceptedRatchet5m(
66+
trade(),
67+
[],
68+
map([
69+
candle(0, { high: 121, low: 95 }),
70+
candle(FIVE, { open: 101, high: 103, low: 99 }),
71+
candle(2 * FIVE, { open: 103, high: 104, low: 102 }),
72+
candle(3 * FIVE, { open: 103, high: 104, low: 102 })
73+
])
74+
);
75+
76+
expect(result.classification).toBe("RATCHET_EXIT");
77+
expect(result.overlay.activated).toBe(true);
78+
expect(result.overlay.trade.exit_timestamp).toBe(FIVE);
79+
});
80+
81+
it("keeps the baseline result when a required 5m candle is missing", () => {
82+
const original = trade();
83+
const result = applyAcceptedRatchet5m(original, [], map([candle(0)]));
84+
85+
expect(result.classification).toBe("DATA_GAP");
86+
expect(result.baseline_trade).toBe(original);
87+
expect(result.overlay_trade).toBe(original);
88+
});
89+
});

0 commit comments

Comments
 (0)