solana-traderclaw 1.0.96 → 1.0.98
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.
|
@@ -22,9 +22,6 @@
|
|
|
22
22
|
keepLines: 2000
|
|
23
23
|
},
|
|
24
24
|
jobs: [
|
|
25
|
-
<<<<<<< feat/cron-jobs-upgrade
|
|
26
|
-
// ── Alpha Scanning ──────────────────────────────────────────────
|
|
27
|
-
=======
|
|
28
25
|
// ── Strategy & Learning ───────────────────────────────────────
|
|
29
26
|
{
|
|
30
27
|
id: "strategy-evolution",
|
|
@@ -35,7 +32,6 @@
|
|
|
35
32
|
message: "CRON_JOB: strategy_evolution\n\nStep 1: Call solana_journal_summary to get aggregate performance stats (win rate, avg PnL, trade count). If fewer than 10 closed trades since the last strategy evolution, skip weight updates but still run pattern detection.\n\nStep 2: Call solana_memory_search for 'strategy_evolution' — find last 3 evolution cycle results. Call solana_memory_search for 'strategy_drift_warning' — find drift warnings since last evolution. Call solana_memory_search for 'pre_trade_rationale' — recent decision patterns.\n\nStep 3: Run Recurring Pattern Detection — search for learning_entry tags, group by area, check linked chains (3+ = confirmed pattern), investigate drift warnings.\n\nStep 4: Call solana_strategy_state to read current feature weights.\n\nStep 5: Call solana_trades to get recent closed trades. Apply ADL checks (direction consistency, weight velocity, reversion check).\n\nStep 6: Compute proposed weight changes. Score each with VFM (Frequency + Failure Reduction + Self-Cost). Only apply changes scoring >= 3/5.\n\nStep 7: Verify guardrails: maxDeltaOk, sumWeightsOk, minTradesOk, floorCapOk. If all pass, call solana_strategy_update with incremented version.\n\nStep 8: Run Named Pattern Recognition — search for winning trade clusters, catalog new patterns, evolve existing ones.\n\nStep 9: Evaluate discovery filter performance. Log all results via solana_memory_write with tags: strategy_evolution, vfm_scorecard, pattern_detection, named_pattern.\n\nFORMATTING RULES:\n- Every token reference MUST use SYMBOL (full_CA) format.\n- Do not execute trades. Do not ask questions.",
|
|
36
33
|
enabled: true
|
|
37
34
|
},
|
|
38
|
-
>>>>>>> main
|
|
39
35
|
{
|
|
40
36
|
id: "alpha-scan",
|
|
41
37
|
schedule: "0 */3 * * *",
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// src/alpha-ws.ts
|
|
2
2
|
var RECONNECT_DELAYS = [1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
|
|
3
|
+
var PING_INTERVAL_MS = 3e4;
|
|
4
|
+
var PONG_TIMEOUT_MS = 1e4;
|
|
3
5
|
var AlphaStreamManager = class {
|
|
4
6
|
config;
|
|
5
7
|
ws = null;
|
|
@@ -110,13 +112,42 @@ var AlphaStreamManager = class {
|
|
|
110
112
|
reject(new Error("WebSocket connection timed out"));
|
|
111
113
|
}
|
|
112
114
|
}, 1e4);
|
|
115
|
+
let pingInterval = null;
|
|
116
|
+
let pongTimer = null;
|
|
117
|
+
const clearKeepalive = () => {
|
|
118
|
+
if (pingInterval) {
|
|
119
|
+
clearInterval(pingInterval);
|
|
120
|
+
pingInterval = null;
|
|
121
|
+
}
|
|
122
|
+
if (pongTimer) {
|
|
123
|
+
clearTimeout(pongTimer);
|
|
124
|
+
pongTimer = null;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
113
127
|
this.ws.on("open", () => {
|
|
114
128
|
clearTimeout(connectTimeout);
|
|
115
129
|
this.connectedAt = Date.now();
|
|
116
130
|
this.reconnectAttempt = 0;
|
|
117
131
|
this.log("info", "WebSocket connected, waiting for server handshake...");
|
|
132
|
+
pingInterval = setInterval(() => {
|
|
133
|
+
if (!this.ws || this.ws.readyState !== 1) return;
|
|
134
|
+
pongTimer = setTimeout(() => {
|
|
135
|
+
this.log("warn", "Pong timeout \u2014 forcing reconnect");
|
|
136
|
+
this.ws?.terminate();
|
|
137
|
+
}, PONG_TIMEOUT_MS);
|
|
138
|
+
try {
|
|
139
|
+
this.ws.ping();
|
|
140
|
+
} catch {
|
|
141
|
+
}
|
|
142
|
+
}, PING_INTERVAL_MS);
|
|
118
143
|
resolve();
|
|
119
144
|
});
|
|
145
|
+
this.ws.on("pong", () => {
|
|
146
|
+
if (pongTimer) {
|
|
147
|
+
clearTimeout(pongTimer);
|
|
148
|
+
pongTimer = null;
|
|
149
|
+
}
|
|
150
|
+
});
|
|
120
151
|
this.ws.on("message", (data) => {
|
|
121
152
|
try {
|
|
122
153
|
const msg = JSON.parse(data.toString());
|
|
@@ -127,6 +158,7 @@ var AlphaStreamManager = class {
|
|
|
127
158
|
});
|
|
128
159
|
this.ws.on("close", () => {
|
|
129
160
|
clearTimeout(connectTimeout);
|
|
161
|
+
clearKeepalive();
|
|
130
162
|
this.subscribed = false;
|
|
131
163
|
this.authenticated = false;
|
|
132
164
|
this.log("info", "WebSocket closed");
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// src/bitquery-ws.ts
|
|
2
2
|
var RECONNECT_DELAYS = [1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
|
|
3
|
+
var PING_INTERVAL_MS = 3e4;
|
|
4
|
+
var PONG_TIMEOUT_MS = 1e4;
|
|
3
5
|
var BitqueryStreamManager = class {
|
|
4
6
|
config;
|
|
5
7
|
ws = null;
|
|
@@ -98,6 +100,27 @@ var BitqueryStreamManager = class {
|
|
|
98
100
|
}
|
|
99
101
|
this.authenticated = false;
|
|
100
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Close the socket and schedule a reconnect without marking the close as
|
|
105
|
+
* intentional. Used for auth errors where we want to reconnect with a fresh
|
|
106
|
+
* token rather than leaving the socket permanently dead.
|
|
107
|
+
*/
|
|
108
|
+
forceReconnect(reason) {
|
|
109
|
+
this.log("warn", `Force reconnect: ${reason}`);
|
|
110
|
+
if (this.reconnectTimer) {
|
|
111
|
+
clearTimeout(this.reconnectTimer);
|
|
112
|
+
this.reconnectTimer = null;
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
this.ws?.close();
|
|
116
|
+
} catch {
|
|
117
|
+
}
|
|
118
|
+
this.ws = null;
|
|
119
|
+
this.authenticated = false;
|
|
120
|
+
if (this.activeSubscriptions.size > 0) {
|
|
121
|
+
this.scheduleReconnect();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
101
124
|
async ensureConnected() {
|
|
102
125
|
if (this.ws && this.ws.readyState === 1 && this.authenticated) return;
|
|
103
126
|
if (this.connecting) {
|
|
@@ -152,12 +175,41 @@ var BitqueryStreamManager = class {
|
|
|
152
175
|
reject(new Error("WS connection timed out"));
|
|
153
176
|
}
|
|
154
177
|
}, 1e4);
|
|
178
|
+
let pingInterval = null;
|
|
179
|
+
let pongTimer = null;
|
|
180
|
+
const clearKeepalive = () => {
|
|
181
|
+
if (pingInterval) {
|
|
182
|
+
clearInterval(pingInterval);
|
|
183
|
+
pingInterval = null;
|
|
184
|
+
}
|
|
185
|
+
if (pongTimer) {
|
|
186
|
+
clearTimeout(pongTimer);
|
|
187
|
+
pongTimer = null;
|
|
188
|
+
}
|
|
189
|
+
};
|
|
155
190
|
ws.on("open", () => {
|
|
156
191
|
clearTimeout(connectTimeout);
|
|
157
192
|
this.reconnectAttempt = 0;
|
|
158
193
|
this.log("info", "Connected");
|
|
194
|
+
pingInterval = setInterval(() => {
|
|
195
|
+
if (!this.ws || this.ws.readyState !== 1) return;
|
|
196
|
+
pongTimer = setTimeout(() => {
|
|
197
|
+
this.log("warn", "Pong timeout \u2014 forcing reconnect");
|
|
198
|
+
this.ws?.terminate();
|
|
199
|
+
}, PONG_TIMEOUT_MS);
|
|
200
|
+
try {
|
|
201
|
+
this.ws.ping();
|
|
202
|
+
} catch {
|
|
203
|
+
}
|
|
204
|
+
}, PING_INTERVAL_MS);
|
|
159
205
|
resolve();
|
|
160
206
|
});
|
|
207
|
+
ws.on("pong", () => {
|
|
208
|
+
if (pongTimer) {
|
|
209
|
+
clearTimeout(pongTimer);
|
|
210
|
+
pongTimer = null;
|
|
211
|
+
}
|
|
212
|
+
});
|
|
161
213
|
ws.on("message", (data) => {
|
|
162
214
|
try {
|
|
163
215
|
const msg = JSON.parse(data.toString());
|
|
@@ -168,6 +220,7 @@ var BitqueryStreamManager = class {
|
|
|
168
220
|
});
|
|
169
221
|
ws.on("close", () => {
|
|
170
222
|
clearTimeout(connectTimeout);
|
|
223
|
+
clearKeepalive();
|
|
171
224
|
this.authenticated = false;
|
|
172
225
|
this.log("info", "WS closed");
|
|
173
226
|
this.drainPendingOnClose();
|
|
@@ -242,7 +295,7 @@ var BitqueryStreamManager = class {
|
|
|
242
295
|
}
|
|
243
296
|
}
|
|
244
297
|
if (["WS_AUTH_REQUIRED", "WS_AUTH_INVALID", "ACCESS_TOKEN_EXPIRED"].includes(code)) {
|
|
245
|
-
this.
|
|
298
|
+
this.forceReconnect(code);
|
|
246
299
|
}
|
|
247
300
|
break;
|
|
248
301
|
}
|
|
@@ -263,9 +316,9 @@ var BitqueryStreamManager = class {
|
|
|
263
316
|
async resubscribeAll() {
|
|
264
317
|
if (this.activeSubscriptions.size === 0) return;
|
|
265
318
|
const subs = [...this.activeSubscriptions.values()];
|
|
266
|
-
this.activeSubscriptions.clear();
|
|
267
319
|
this.log("info", `Re-subscribing ${subs.length} subscription(s) after reconnect`);
|
|
268
320
|
for (const sub of subs) {
|
|
321
|
+
this.activeSubscriptions.delete(sub.subscriptionId);
|
|
269
322
|
try {
|
|
270
323
|
const result = await this.subscribe({
|
|
271
324
|
templateKey: sub.templateKey,
|
|
@@ -276,6 +329,7 @@ var BitqueryStreamManager = class {
|
|
|
276
329
|
this.log("info", `Re-subscribed ${sub.templateKey} \u2192 new id: ${result.subscriptionId}`);
|
|
277
330
|
} catch (err) {
|
|
278
331
|
this.log("error", `Re-subscribe failed for ${sub.templateKey}: ${err}`);
|
|
332
|
+
this.activeSubscriptions.set(sub.subscriptionId, sub);
|
|
279
333
|
}
|
|
280
334
|
}
|
|
281
335
|
}
|
package/dist/index.js
CHANGED
|
@@ -15,10 +15,10 @@ import {
|
|
|
15
15
|
} from "./chunk-3UQIQJPQ.js";
|
|
16
16
|
import {
|
|
17
17
|
AlphaStreamManager
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-ATWB7K63.js";
|
|
19
19
|
import {
|
|
20
20
|
BitqueryStreamManager
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-S2DLZKMQ.js";
|
|
22
22
|
import {
|
|
23
23
|
orchestratorRequest
|
|
24
24
|
} from "./chunk-6GSGHMUH.js";
|
|
@@ -4284,6 +4284,30 @@ Context compaction triggered. STATE.md synced from last persisted state. Decisio
|
|
|
4284
4284
|
} catch (err) {
|
|
4285
4285
|
api.logger.warn(`[solana-trader] Forward probe failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
4286
4286
|
}
|
|
4287
|
+
const WATCHDOG_INTERVAL_MS = 9e4;
|
|
4288
|
+
const watchdogTimer = setInterval(async () => {
|
|
4289
|
+
if (!alphaStreamManager.isSubscribed()) {
|
|
4290
|
+
api.logger.warn("[watchdog] Alpha stream not subscribed \u2014 resubscribing...");
|
|
4291
|
+
try {
|
|
4292
|
+
await alphaStreamManager.subscribe();
|
|
4293
|
+
api.logger.info("[watchdog] Alpha stream resubscribed successfully.");
|
|
4294
|
+
} catch (err) {
|
|
4295
|
+
api.logger.error(`[watchdog] Alpha resubscribe failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
4296
|
+
}
|
|
4297
|
+
}
|
|
4298
|
+
try {
|
|
4299
|
+
const creds = await get("/api/agents/gateway-credentials");
|
|
4300
|
+
if (!getActiveCredential(creds)) {
|
|
4301
|
+
api.logger.warn("[watchdog] Gateway credentials inactive \u2014 re-registering...");
|
|
4302
|
+
await runStartupGate({ autoFixGateway: true, force: true });
|
|
4303
|
+
}
|
|
4304
|
+
} catch (err) {
|
|
4305
|
+
api.logger.warn(`[watchdog] Gateway credential check failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
4306
|
+
}
|
|
4307
|
+
}, WATCHDOG_INTERVAL_MS);
|
|
4308
|
+
if (watchdogTimer && typeof watchdogTimer === "object" && "unref" in watchdogTimer) {
|
|
4309
|
+
watchdogTimer.unref();
|
|
4310
|
+
}
|
|
4287
4311
|
}
|
|
4288
4312
|
});
|
|
4289
4313
|
if (typeof api.registerContextEngine === "function") {
|
package/dist/src/alpha-ws.js
CHANGED
package/dist/src/bitquery-ws.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "solana-traderclaw",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.98",
|
|
4
4
|
"description": "TraderClaw V1-Upgraded — Solana trading for OpenClaw with intelligence lab, tool envelopes, prompt scrubbing, read-only X social intel, and split skill docs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|