solana-traderclaw 1.0.92 → 1.0.93
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/dist/index.js +183 -34
- package/package.json +1 -1
- package/skills/solana-trader/HEARTBEAT.md +83 -150
- package/skills/solana-trader/workspace/MEMORY.md +93 -1
package/dist/index.js
CHANGED
|
@@ -1171,9 +1171,31 @@ var solanaTraderPlugin = {
|
|
|
1171
1171
|
if (typeof val === "object") return JSON.stringify(val);
|
|
1172
1172
|
return String(val);
|
|
1173
1173
|
};
|
|
1174
|
+
const getNestedValue = (obj, key) => {
|
|
1175
|
+
const nested = key.split(".");
|
|
1176
|
+
let cur = obj;
|
|
1177
|
+
for (const k of nested) {
|
|
1178
|
+
if (!cur || typeof cur !== "object") return void 0;
|
|
1179
|
+
cur = cur[k];
|
|
1180
|
+
}
|
|
1181
|
+
return cur;
|
|
1182
|
+
};
|
|
1183
|
+
const resolveStrategyField = (state, field) => {
|
|
1184
|
+
return getNestedValue(state, `strategy.${field}`) ?? state[field];
|
|
1185
|
+
};
|
|
1186
|
+
const renderKeyValueSection = (obj, indent = "") => {
|
|
1187
|
+
if (!obj || typeof obj !== "object") return [];
|
|
1188
|
+
const lines = [];
|
|
1189
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
1190
|
+
if (v !== void 0 && v !== null) {
|
|
1191
|
+
lines.push(`${indent}- ${k}: ${typeof v === "object" ? JSON.stringify(v) : String(v)}`);
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
return lines;
|
|
1195
|
+
};
|
|
1174
1196
|
const generateMemoryMd = (aid, stateObj) => {
|
|
1175
1197
|
const lines = [
|
|
1176
|
-
`#
|
|
1198
|
+
`# MEMORY.md`,
|
|
1177
1199
|
``,
|
|
1178
1200
|
`> Auto-generated by solana_state_save. OpenClaw loads this file into context at every session start.`,
|
|
1179
1201
|
`> Last updated: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
@@ -1184,52 +1206,175 @@ var solanaTraderPlugin = {
|
|
|
1184
1206
|
return lines.join("\n");
|
|
1185
1207
|
}
|
|
1186
1208
|
const state = stateObj;
|
|
1187
|
-
const
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1209
|
+
const identityFields = [
|
|
1210
|
+
["tier", "Tier"],
|
|
1211
|
+
["walletId", "Wallet"],
|
|
1212
|
+
["mode", "Mode"],
|
|
1213
|
+
["strategyVersion", "Strategy Version"],
|
|
1214
|
+
["regime", "Regime"],
|
|
1215
|
+
["maxPositions", "Max Positions"],
|
|
1216
|
+
["minBuy", "Min Buy"],
|
|
1217
|
+
["minTp", "Min TP"]
|
|
1218
|
+
];
|
|
1219
|
+
const identityLines = [];
|
|
1220
|
+
for (const [key, label] of identityFields) {
|
|
1221
|
+
const val = state[key];
|
|
1222
|
+
if (val !== void 0 && val !== null) {
|
|
1223
|
+
identityLines.push(`- ${label}: ${formatStateValue(val)}`);
|
|
1224
|
+
}
|
|
1197
1225
|
}
|
|
1198
|
-
if (state.
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
- **Active:** ${state.killSwitchActive}
|
|
1205
|
-
`);
|
|
1206
|
-
if (state.watchlist && Array.isArray(state.watchlist) && state.watchlist.length > 0) {
|
|
1207
|
-
lines.push("## Watchlist", "");
|
|
1208
|
-
for (const item of state.watchlist.slice(0, 20)) {
|
|
1209
|
-
lines.push(`- ${typeof item === "string" ? item : JSON.stringify(item)}`);
|
|
1226
|
+
if (state.maxPositionSizeSol) identityLines.push(`- Max Position Size: ${state.maxPositionSizeSol} SOL`);
|
|
1227
|
+
const tpStructure = state.tpStructure;
|
|
1228
|
+
if (tpStructure && typeof tpStructure === "object") {
|
|
1229
|
+
identityLines.push("- TP Structure:");
|
|
1230
|
+
for (const line of renderKeyValueSection(tpStructure, " ")) {
|
|
1231
|
+
identityLines.push(line);
|
|
1210
1232
|
}
|
|
1211
|
-
|
|
1233
|
+
}
|
|
1234
|
+
if (identityLines.length > 0) {
|
|
1235
|
+
lines.push("## Trading Identity", "", ...identityLines, "");
|
|
1236
|
+
}
|
|
1237
|
+
if (state.defenseMode !== void 0) lines.push(`## Defense Mode`, "", `- Active: ${state.defenseMode}`, "");
|
|
1238
|
+
if (state.killSwitchActive !== void 0) lines.push(`## Kill Switch`, "", `- Active: ${state.killSwitchActive}`, "");
|
|
1239
|
+
if (identityLines.length > 0 || state.defenseMode !== void 0 || state.killSwitchActive !== void 0) {
|
|
1240
|
+
lines.push("---", "");
|
|
1241
|
+
}
|
|
1242
|
+
const strategyHasContent = ["featureWeights", "positionSizing", "stopLoss", "takeProfit", "entryFilter", "deadMoney"].some((f) => resolveStrategyField(state, f) !== void 0);
|
|
1243
|
+
if (strategyHasContent) {
|
|
1244
|
+
lines.push("## STRATEGY", "");
|
|
1245
|
+
const featureWeights = resolveStrategyField(state, "featureWeights");
|
|
1246
|
+
if (featureWeights && typeof featureWeights === "object") {
|
|
1247
|
+
lines.push("### Feature Weights", "");
|
|
1248
|
+
lines.push(...renderKeyValueSection(featureWeights));
|
|
1249
|
+
lines.push("");
|
|
1250
|
+
}
|
|
1251
|
+
const positionSizing = resolveStrategyField(state, "positionSizing");
|
|
1252
|
+
if (positionSizing && typeof positionSizing === "object") {
|
|
1253
|
+
lines.push("### Position Sizing Rules", "");
|
|
1254
|
+
lines.push(...renderKeyValueSection(positionSizing));
|
|
1255
|
+
lines.push("");
|
|
1256
|
+
}
|
|
1257
|
+
const stopLoss = resolveStrategyField(state, "stopLoss");
|
|
1258
|
+
if (stopLoss && typeof stopLoss === "object") {
|
|
1259
|
+
lines.push("### Stop-Loss Rules", "");
|
|
1260
|
+
lines.push(...renderKeyValueSection(stopLoss));
|
|
1261
|
+
lines.push("");
|
|
1262
|
+
}
|
|
1263
|
+
const takeProfit = resolveStrategyField(state, "takeProfit");
|
|
1264
|
+
if (takeProfit && typeof takeProfit === "object") {
|
|
1265
|
+
lines.push("### Take-Profit Rules", "");
|
|
1266
|
+
lines.push(...renderKeyValueSection(takeProfit));
|
|
1267
|
+
lines.push("");
|
|
1268
|
+
}
|
|
1269
|
+
const entryFilter = resolveStrategyField(state, "entryFilter");
|
|
1270
|
+
if (entryFilter && typeof entryFilter === "object") {
|
|
1271
|
+
lines.push("### Entry Filter", "");
|
|
1272
|
+
lines.push(...renderKeyValueSection(entryFilter));
|
|
1273
|
+
lines.push("");
|
|
1274
|
+
}
|
|
1275
|
+
const deadMoney = resolveStrategyField(state, "deadMoney");
|
|
1276
|
+
if (deadMoney && typeof deadMoney === "object") {
|
|
1277
|
+
lines.push("### Dead Money Rule", "");
|
|
1278
|
+
lines.push(...renderKeyValueSection(deadMoney));
|
|
1279
|
+
lines.push("");
|
|
1280
|
+
}
|
|
1281
|
+
lines.push("---", "");
|
|
1212
1282
|
}
|
|
1213
1283
|
if (state.permanentLearnings && Array.isArray(state.permanentLearnings)) {
|
|
1214
1284
|
lines.push("## Permanent Learnings", "");
|
|
1215
|
-
|
|
1216
|
-
lines.push(
|
|
1285
|
+
state.permanentLearnings.slice(0, 30).forEach((learning, i) => {
|
|
1286
|
+
lines.push(`${i + 1}. ${typeof learning === "string" ? learning : JSON.stringify(learning)}`);
|
|
1287
|
+
});
|
|
1288
|
+
lines.push("", "---", "");
|
|
1289
|
+
}
|
|
1290
|
+
const capitalStatus = state.capitalStatus;
|
|
1291
|
+
if (capitalStatus && typeof capitalStatus === "object") {
|
|
1292
|
+
const cs = capitalStatus;
|
|
1293
|
+
lines.push("## Capital Status Tracker", "");
|
|
1294
|
+
if (cs.lastUpdated) lines.push(`Last Updated: ${cs.lastUpdated}`);
|
|
1295
|
+
const csFields = [
|
|
1296
|
+
["walletBalance", "Wallet Balance"],
|
|
1297
|
+
["realizedPnlAllTime", "Realized P&L (All-Time)"],
|
|
1298
|
+
["openPositions", "Open Positions"],
|
|
1299
|
+
["dailyNotionalUsed", "Daily Notional Used"],
|
|
1300
|
+
["dailyRealizedLoss", "Daily Realized Loss"],
|
|
1301
|
+
["killSwitch", "Kill Switch"]
|
|
1302
|
+
];
|
|
1303
|
+
for (const [key, label] of csFields) {
|
|
1304
|
+
if (cs[key] !== void 0) lines.push(`- ${label}: ${formatStateValue(cs[key])}`);
|
|
1217
1305
|
}
|
|
1218
|
-
|
|
1306
|
+
const renderedCsKeys = /* @__PURE__ */ new Set(["lastUpdated", ...csFields.map(([k]) => k)]);
|
|
1307
|
+
for (const [k, v] of Object.entries(cs)) {
|
|
1308
|
+
if (!renderedCsKeys.has(k) && v !== void 0) lines.push(`- ${k}: ${formatStateValue(v)}`);
|
|
1309
|
+
}
|
|
1310
|
+
lines.push("", "---", "");
|
|
1311
|
+
}
|
|
1312
|
+
if (state.watchlist && Array.isArray(state.watchlist) && state.watchlist.length > 0) {
|
|
1313
|
+
lines.push("## Watchlist", "");
|
|
1314
|
+
for (const item of state.watchlist.slice(0, 20)) {
|
|
1315
|
+
lines.push(`- ${typeof item === "string" ? item : JSON.stringify(item)}`);
|
|
1316
|
+
}
|
|
1317
|
+
lines.push("", "---", "");
|
|
1219
1318
|
}
|
|
1220
1319
|
if (state.regimeCanary && typeof state.regimeCanary === "object") {
|
|
1221
1320
|
const rc = state.regimeCanary;
|
|
1222
|
-
lines.push("## Regime Canary", "", `-
|
|
1321
|
+
lines.push("## Regime Canary", "", `- Regime: ${rc.regime || "unknown"}`, `- Detected At: ${rc.detectedAt || "unknown"}`, "", "---", "");
|
|
1223
1322
|
}
|
|
1224
1323
|
if (state.preferences && typeof state.preferences === "object") {
|
|
1225
1324
|
const prefs = state.preferences;
|
|
1226
1325
|
const prefLines = [];
|
|
1227
1326
|
for (const [pk, pv] of Object.entries(prefs)) {
|
|
1228
|
-
prefLines.push(`-
|
|
1327
|
+
prefLines.push(`- ${pk}: ${formatStateValue(pv)}`);
|
|
1328
|
+
}
|
|
1329
|
+
if (prefLines.length > 0) lines.push("## User Preferences (override defaults)", "", ...prefLines, "", "---", "");
|
|
1330
|
+
}
|
|
1331
|
+
const nextCycle = state.nextCycle;
|
|
1332
|
+
if (nextCycle && typeof nextCycle === "object") {
|
|
1333
|
+
const nc = nextCycle;
|
|
1334
|
+
lines.push("## Next Trading Cycle", "");
|
|
1335
|
+
const ncFields = [
|
|
1336
|
+
["scan", "Scan"],
|
|
1337
|
+
["candidatesInLab", "Candidates in Lab"],
|
|
1338
|
+
["strategy", "Strategy"],
|
|
1339
|
+
["focus", "Focus"],
|
|
1340
|
+
["action", "Action"]
|
|
1341
|
+
];
|
|
1342
|
+
for (const [key, label] of ncFields) {
|
|
1343
|
+
if (nc[key] !== void 0) lines.push(`- ${label}: ${formatStateValue(nc[key])}`);
|
|
1344
|
+
}
|
|
1345
|
+
const renderedNcKeys = new Set(ncFields.map(([k]) => k));
|
|
1346
|
+
for (const [k, v] of Object.entries(nc)) {
|
|
1347
|
+
if (!renderedNcKeys.has(k) && v !== void 0) lines.push(`- ${k}: ${formatStateValue(v)}`);
|
|
1229
1348
|
}
|
|
1230
|
-
|
|
1349
|
+
lines.push("");
|
|
1231
1350
|
}
|
|
1232
|
-
const structuredKeys = /* @__PURE__ */ new Set([
|
|
1351
|
+
const structuredKeys = /* @__PURE__ */ new Set([
|
|
1352
|
+
"tier",
|
|
1353
|
+
"walletId",
|
|
1354
|
+
"mode",
|
|
1355
|
+
"strategyVersion",
|
|
1356
|
+
"regime",
|
|
1357
|
+
"maxPositions",
|
|
1358
|
+
"maxPositionSizeSol",
|
|
1359
|
+
"defenseMode",
|
|
1360
|
+
"killSwitchActive",
|
|
1361
|
+
"watchlist",
|
|
1362
|
+
"permanentLearnings",
|
|
1363
|
+
"regimeCanary",
|
|
1364
|
+
"preferences",
|
|
1365
|
+
"minBuy",
|
|
1366
|
+
"minTp",
|
|
1367
|
+
"tpStructure",
|
|
1368
|
+
"strategy",
|
|
1369
|
+
"featureWeights",
|
|
1370
|
+
"positionSizing",
|
|
1371
|
+
"stopLoss",
|
|
1372
|
+
"takeProfit",
|
|
1373
|
+
"entryFilter",
|
|
1374
|
+
"deadMoney",
|
|
1375
|
+
"capitalStatus",
|
|
1376
|
+
"nextCycle"
|
|
1377
|
+
]);
|
|
1233
1378
|
const summaryKeys = /* @__PURE__ */ new Set(["lastCycleSummary"]);
|
|
1234
1379
|
const otherKeys = Object.keys(state).filter((k) => !structuredKeys.has(k) && !volatileStateKeys.has(k));
|
|
1235
1380
|
const summaryRendered = [];
|
|
@@ -1258,7 +1403,11 @@ var solanaTraderPlugin = {
|
|
|
1258
1403
|
const content = generateMemoryMd(aid, stateObj);
|
|
1259
1404
|
ensureDir(path.dirname(memoryMdPath));
|
|
1260
1405
|
fs.writeFileSync(memoryMdPath, content, "utf-8");
|
|
1261
|
-
|
|
1406
|
+
api.logger.info(`[solana-trader] MEMORY.md written successfully (${content.length} bytes) \u2192 ${memoryMdPath}`);
|
|
1407
|
+
return true;
|
|
1408
|
+
} catch (err) {
|
|
1409
|
+
api.logger.error(`[solana-trader] MEMORY.md write FAILED \u2192 path: ${memoryMdPath}, error: ${err instanceof Error ? err.message : String(err)}`);
|
|
1410
|
+
return false;
|
|
1262
1411
|
}
|
|
1263
1412
|
};
|
|
1264
1413
|
const getDailyLogPath = (date) => {
|
|
@@ -2779,8 +2928,8 @@ ${notes}
|
|
|
2779
2928
|
}
|
|
2780
2929
|
const payload = { agentId: targetAgentId, state: mergedState, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
2781
2930
|
writeJsonFile(filePath, payload);
|
|
2782
|
-
writeMemoryMd(targetAgentId, mergedState);
|
|
2783
|
-
return { ok: true, agentId: targetAgentId, updatedAt: payload.updatedAt, merged: !shouldOverwrite, memoryMdWritten:
|
|
2931
|
+
const mdWritten = writeMemoryMd(targetAgentId, mergedState);
|
|
2932
|
+
return { ok: true, agentId: targetAgentId, updatedAt: payload.updatedAt, merged: !shouldOverwrite, memoryMdWritten: mdWritten, memoryMdPath };
|
|
2784
2933
|
})
|
|
2785
2934
|
});
|
|
2786
2935
|
api.registerTool({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "solana-traderclaw",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.93",
|
|
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",
|
|
@@ -10,25 +10,25 @@ Read MEMORY.md (auto-loaded). If empty or missing wallet/tier/strategy → run M
|
|
|
10
10
|
|
|
11
11
|
1. **MEMORY.md** (already in context): tier, wallet, mode, strategy version, watchlist, regime canary
|
|
12
12
|
2. **Daily log** (`memory/YYYY-MM-DD.md`, auto-loaded): what already happened today — don't repeat work
|
|
13
|
-
3. **Context engine** (automatic): `[TraderClaw Trading Context]`
|
|
13
|
+
3. **Context engine** (automatic): `[TraderClaw Trading Context]` injected into system prompt at session start with current state, last 3 decisions, and entitlement limits. Just read it when present.
|
|
14
14
|
4. **Server-side memory** — call `solana_memory_search` for: `"source_reputation"`, `"strategy_drift_warning"`, `"pre_trade_rationale"`, `"meta_rotation"`
|
|
15
|
-
5. **QMD recall** — before analyzing any candidate, call `memory_search` with the token symbol or contract address. If
|
|
15
|
+
5. **QMD recall** — before analyzing any candidate, call `memory_search` with the token symbol or contract address. If seen before, use prior analysis to: skip repeat work, apply re-entry penalties, catch repeat rug patterns, reference prior confidence scores.
|
|
16
16
|
|
|
17
17
|
## User Preferences Override (apply before any other step)
|
|
18
18
|
|
|
19
|
-
If MEMORY.md contains a **User Preferences** section, those values override
|
|
19
|
+
If MEMORY.md contains a **User Preferences** section, those values override defaults in this document for this entire session.
|
|
20
20
|
|
|
21
21
|
| Preference key | What it overrides |
|
|
22
22
|
|---|---|
|
|
23
|
-
| `volumeMinUsd` |
|
|
24
|
-
| `marketCapMinUsd` |
|
|
25
|
-
| `maxPositionSizeSol` |
|
|
23
|
+
| `volumeMinUsd` | Min 24h volume filter in STEP 1 SCAN and alpha_scan cron (default: 50000) |
|
|
24
|
+
| `marketCapMinUsd` | Min market cap filter (default: 10000) |
|
|
25
|
+
| `maxPositionSizeSol` | Max position size in SOL (overrides entitlement cap if lower) |
|
|
26
26
|
| `scanMode` | `"conservative"` / `"standard"` / `"aggressive"` — adjusts confidence thresholds |
|
|
27
27
|
| `slPct` | Default stop-loss % for new positions (default: 20 HARDENED, 40 DEGEN) |
|
|
28
|
-
| `minConfidence` |
|
|
28
|
+
| `minConfidence` | Min confidence score to enter a trade (default: 0.65) |
|
|
29
29
|
| `narrativeFilter` | Comma-separated narrative clusters to focus on (e.g. `"AI,Gaming"`) |
|
|
30
30
|
|
|
31
|
-
Apply
|
|
31
|
+
Apply immediately. Durable — persists until user explicitly changes them.
|
|
32
32
|
|
|
33
33
|
---
|
|
34
34
|
|
|
@@ -40,23 +40,23 @@ Call `solana_positions`, `solana_killswitch_status`, `solana_capital_status`.
|
|
|
40
40
|
|
|
41
41
|
**Kill switch active → halt all trading. No exceptions.**
|
|
42
42
|
|
|
43
|
-
**Deployer reputation check
|
|
43
|
+
**Deployer reputation check:** For each open position, call `solana_deployer_trust_get({ address: "<deployer_address>" })`. If trust score dropped significantly since entry (e.g., they launched another token that rugged), flag for immediate review.
|
|
44
44
|
|
|
45
|
-
**Dead money check
|
|
45
|
+
**Dead money check — apply ALL four criteria:**
|
|
46
46
|
- Loss > 40%
|
|
47
47
|
- Held 90+ min AND still down 5%+
|
|
48
48
|
- 24h volume < $5,000
|
|
49
49
|
- Price flat (±5%) for 4+ hours
|
|
50
50
|
|
|
51
|
-
If ALL four
|
|
51
|
+
If ALL four true → exit immediately. Do NOT hold hoping for recovery. A position at -40% after 90 min with dead volume is NOT coming back.
|
|
52
52
|
|
|
53
|
-
**Strategy integrity:** Compare
|
|
53
|
+
**Strategy integrity:** Compare last 3 trade decisions (from memory) against feature weights. If actual decisions diverge from what weights would predict, log `strategy_drift_warning` via `solana_memory_write`.
|
|
54
54
|
|
|
55
55
|
## STEP 1: SCAN
|
|
56
56
|
|
|
57
57
|
Call `solana_scan_launches` for new launches and `solana_scan_hot_pairs` for hot pairs.
|
|
58
58
|
|
|
59
|
-
**Bitquery subscription events:** Check `solana_bitquery_subscriptions` for
|
|
59
|
+
**Bitquery subscription events:** Check `solana_bitquery_subscriptions` for active streams. Process buffered events from real-time subscriptions. If no subscriptions active and first heartbeat of session, call `solana_bitquery_templates` to discover available templates and cache in memory.
|
|
60
60
|
|
|
61
61
|
## STEP 1.5: ALPHA SIGNALS
|
|
62
62
|
|
|
@@ -67,29 +67,27 @@ Call `solana_alpha_signals` to poll the buffer. Score and classify each signal b
|
|
|
67
67
|
solana_source_trust_get({ name: "<signal source>" })
|
|
68
68
|
solana_alpha_sources()
|
|
69
69
|
```
|
|
70
|
-
If
|
|
70
|
+
If trust score < 30 or win rate < 25%, downgrade signal priority by one tier. Do NOT skip low-trust signals entirely — still log them — but reduce their weight.
|
|
71
71
|
|
|
72
|
-
**Multi-source conflict detection:** If 2+ signals reference
|
|
72
|
+
**Multi-source conflict detection:** If 2+ signals reference same token with conflicting `kind` values:
|
|
73
73
|
```
|
|
74
74
|
solana_contradiction_check({ claims: [{ source: "src1", claim: "bullish", confidence: 0.8 }, { source: "src2", claim: "bearish", confidence: 0.7 }] })
|
|
75
75
|
```
|
|
76
|
-
Log
|
|
76
|
+
Log contradiction. Default to more cautious signal (risk/exit > ca_drop).
|
|
77
77
|
|
|
78
|
-
**Historical context:**
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
```
|
|
82
|
-
If this token was called before and the outcome was a loss, apply the re-entry penalty (-0.15 confidence).
|
|
78
|
+
**Historical context:** Check prior signal history:
|
|
79
|
+
`solana_alpha_history({ tokenAddress: "CA", limit: 10 })`
|
|
80
|
+
If called before and outcome was a loss, apply re-entry penalty (-0.15 confidence).
|
|
83
81
|
|
|
84
82
|
## STEP 2: ANALYZE
|
|
85
83
|
|
|
86
|
-
For top candidates, call ALL
|
|
84
|
+
For top candidates, call ALL — no exceptions:
|
|
87
85
|
- `solana_token_snapshot` — price, volume, OHLC, trade count
|
|
88
86
|
- `solana_token_holders` — holder distribution, concentration, dev holdings
|
|
89
87
|
- `solana_token_flows` — buy/sell pressure, unique traders
|
|
90
88
|
- `solana_token_liquidity` — pool depth, DEX breakdown
|
|
91
89
|
- `solana_token_risk` — composite risk profile
|
|
92
|
-
- `solana_token_socials` — social media / community metadata
|
|
90
|
+
- `solana_token_socials` — social media / community metadata
|
|
93
91
|
|
|
94
92
|
**FRESH token deep scan (mandatory for tokens < 1h old):**
|
|
95
93
|
```
|
|
@@ -97,57 +95,36 @@ solana_bitquery_catalog({ templatePath: "pumpFunHoldersRisk.first100Buyers", var
|
|
|
97
95
|
solana_compute_deployer_risk({ previousTokens: N, rugHistory: R, avgTokenLifespanHours: H })
|
|
98
96
|
solana_deployer_trust_get({ address: "<deployer_address>" })
|
|
99
97
|
```
|
|
100
|
-
|
|
98
|
+
first100Buyers reveals serial dumpers and insider clusters. Deployer risk gives deterministic HIGH/MEDIUM/LOW. HIGH risk → hard skip. MEDIUM → reduce sizing by 50%.
|
|
101
99
|
|
|
102
100
|
**Candidate recording (mandatory for EVERY analyzed token):**
|
|
103
101
|
```
|
|
104
|
-
solana_candidate_write({
|
|
105
|
-
id: "CA",
|
|
106
|
-
tokenAddress: "CA",
|
|
107
|
-
tokenSymbol: "SYMBOL",
|
|
108
|
-
source: "scan|alpha|manual",
|
|
109
|
-
signalScore: 75,
|
|
110
|
-
signalStage: "early|confirmation|milestone|risk|exit",
|
|
111
|
-
features: { volume_momentum: 0.8, buy_pressure: 0.6, liquidity: 0.7, holder_quality: 0.5 }
|
|
112
|
-
})
|
|
102
|
+
solana_candidate_write({ id: "CA", tokenAddress: "CA", tokenSymbol: "SYMBOL", source: "scan|alpha|manual", signalScore: 75, signalStage: "early|confirmation|milestone|risk|exit", features: { volume_momentum: 0.8, buy_pressure: 0.6, liquidity: 0.7, holder_quality: 0.5 } })
|
|
113
103
|
```
|
|
114
|
-
Record
|
|
104
|
+
Record with features BEFORE deciding whether to trade. Feeds the intelligence lab dataset. Every analyzed token gets written, whether you trade it or skip it.
|
|
115
105
|
|
|
116
106
|
**Social intel (mandatory for any token scoring above 0.60):**
|
|
117
107
|
|
|
118
|
-
|
|
119
|
-
```
|
|
120
|
-
solana_token_socials({ tokenAddress: "CA" })
|
|
121
|
-
```
|
|
122
|
-
This returns Twitter/X handle, Telegram, Discord, website links. Use these for cross-referencing with on-chain metadata and X search results.
|
|
108
|
+
Get structured social metadata: `solana_token_socials({ tokenAddress: "CA" })` — returns Twitter/X, Telegram, Discord, website links for cross-referencing.
|
|
123
109
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
x_search_tweets({ query: "$SYMBOL" })
|
|
127
|
-
```
|
|
128
|
-
Check mention velocity, influencer clustering, sentiment tone. Cross-check any X handles found via `solana_token_socials` with actual tweet activity. If X tools fail, log the error and continue — but you MUST attempt the call. Skipping social intel is a violation.
|
|
110
|
+
Search X/Twitter for real-time sentiment: `x_search_tweets({ query: "$SYMBOL" })`
|
|
111
|
+
Check mention velocity, influencer clustering, sentiment tone. Cross-check X handles from `solana_token_socials` with actual tweet activity. If X tools fail, log error and continue — but you MUST attempt the call.
|
|
129
112
|
|
|
130
113
|
**Prompt scrubbing (mandatory for all external text):**
|
|
131
|
-
|
|
132
|
-
```
|
|
133
|
-
solana_scrub_untrusted_text({ text: "<raw external text>", maxLength: 500 })
|
|
134
|
-
```
|
|
114
|
+
`solana_scrub_untrusted_text({ text: "<raw external text>", maxLength: 500 })`
|
|
135
115
|
|
|
136
116
|
**Website legitimacy check (mandatory for any token scoring above 0.60):**
|
|
137
|
-
1. Check if `solana_token_socials` returned a website URL. If not
|
|
138
|
-
2. If
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
5. Cache rule: check `solana_memory_search` for `website_analyzed` before fetching. If same URL was analyzed in last 48h, reuse the cached result. After analysis, write findings via `solana_memory_write` with tag `website_analyzed`.
|
|
149
|
-
|
|
150
|
-
**Token lifecycle classification (drives everything downstream):**
|
|
117
|
+
1. Check if `solana_token_socials` returned a website URL. If not: `solana_bitquery_catalog({ templatePath: "pumpFunMetadata.tokenMetadataByAddress", variables: { token: "CA" } })`
|
|
118
|
+
2. If website found, fetch it: `web_fetch_url({ url: "<website_url>" })`
|
|
119
|
+
3. Analyze — tool returns `title`, `metaDescription`, `headings`, `socialLinks`, `outboundLinks`, `bodyText`.
|
|
120
|
+
4. Confidence adjustments:
|
|
121
|
+
- Professional site with matching social links → +0.02
|
|
122
|
+
- No website → neutral (many legit memecoins have no site)
|
|
123
|
+
- Generic template with no real content → -0.01
|
|
124
|
+
- Social links don't match on-chain metadata → -0.03 (red flag)
|
|
125
|
+
5. Cache: check `solana_memory_search` for `website_analyzed` before fetching. If analyzed in last 48h, reuse. After analysis, write via `solana_memory_write` tag `website_analyzed`.
|
|
126
|
+
|
|
127
|
+
**Token lifecycle classification:**
|
|
151
128
|
- FRESH (< 1h): Mint MUST be revoked, freeze MUST be inactive, LP MUST be burned/locked. Serial deployer (3+ tokens/24h) = hard skip. Volume >70% in first 15min = skip. EXPLORATORY SIZING ONLY (3-5% capital HARDENED, exploratory range DEGEN).
|
|
152
129
|
- EMERGING (1-24h): Top-10 concentration declining? Volume >20% of peak hour? Standard sizing.
|
|
153
130
|
- ESTABLISHED (>24h): Full sizing. Edge = flow analysis + narrative timing.
|
|
@@ -155,18 +132,14 @@ web_fetch_url({ url: "<website_url>" })
|
|
|
155
132
|
## STEP 3: RISK & SCORING
|
|
156
133
|
|
|
157
134
|
**Freshness decay (mandatory):**
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
```
|
|
161
|
-
Apply the returned decay factor to alpha signal scores. Older signals carry less weight.
|
|
135
|
+
`solana_compute_freshness_decay({ signalAgeMinutes: N, halfLifeMinutes: 30 })`
|
|
136
|
+
Apply returned decay factor to alpha signal scores.
|
|
162
137
|
|
|
163
138
|
**Use `solana_compute_confidence` — NEVER do manual math.** The tool returns deterministic results.
|
|
164
139
|
|
|
165
140
|
**Champion model scoring (if model exists):**
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
```
|
|
169
|
-
If the champion model returns a score that diverges from `compute_confidence` by more than 0.15, log the divergence via `solana_memory_write` with tag `model_divergence`. Use the more conservative score for the trade decision.
|
|
141
|
+
`solana_model_score_candidate({ modelId: "champion", features: { volume_momentum: 0.8, buy_pressure: 0.6, ... } })`
|
|
142
|
+
If score diverges from `compute_confidence` by >0.15, log via `solana_memory_write` tag `model_divergence`. Use the more conservative score.
|
|
170
143
|
|
|
171
144
|
**FOMO check BEFORE computing confidence:**
|
|
172
145
|
- Already moved +500% in <4h → skip
|
|
@@ -189,7 +162,7 @@ If the champion model returns a score that diverges from `compute_confidence` by
|
|
|
189
162
|
|
|
190
163
|
**Hard caps (non-negotiable):**
|
|
191
164
|
- Position ≤ 2% of pool depth in USD. Pool < $50K → max $1,000 SOL equivalent.
|
|
192
|
-
- Mint authority active OR freeze authority active → HARD SKIP.
|
|
165
|
+
- Mint authority active OR freeze authority active → HARD SKIP.
|
|
193
166
|
- Max 40% capital across same narrative cluster.
|
|
194
167
|
|
|
195
168
|
**Sizing reduction triggers (stack multiplicatively):**
|
|
@@ -212,18 +185,18 @@ If the champion model returns a score that diverges from `compute_confidence` by
|
|
|
212
185
|
**CRITICAL:** Every `solana_trade_execute` call MUST include `tpExits` with multiple levels:
|
|
213
186
|
```
|
|
214
187
|
tpExits: [
|
|
215
|
-
{ percent: 100, amountPct: 30 },
|
|
216
|
-
{ percent: 200, amountPct: 100 }
|
|
188
|
+
{ percent: 100, amountPct: 30 },
|
|
189
|
+
{ percent: 200, amountPct: 100 }
|
|
217
190
|
]
|
|
218
191
|
```
|
|
219
192
|
HARDENED range: +100–300%. DEGEN range: +200–500%. `percent` = price increase from entry, `amountPct` = % of position to sell.
|
|
220
193
|
|
|
221
|
-
**
|
|
222
|
-
- `percentage` — trailing drawdown % from
|
|
223
|
-
- `amount` — % of position to sell
|
|
224
|
-
- `triggerAboveATH` — **optional.** Price must reach this % above
|
|
194
|
+
**Structured `trailingStop` with `levels` array** (preferred over legacy `trailingStopPct`):
|
|
195
|
+
- `percentage` — trailing drawdown % from armed high once level is active.
|
|
196
|
+
- `amount` — % of position to sell (1–100; server default `100`).
|
|
197
|
+
- `triggerAboveATH` — **optional.** Price must reach this % above session ATH before level arms. Default `100` (2× ATH). Use `trailingStopPct` for simpler single-level trailing.
|
|
225
198
|
|
|
226
|
-
**`slExits
|
|
199
|
+
**`slExits`** — e.g., `[{ percent: 20, amountPct: 100 }]` (HARDENED) or `[{ percent: 40, amountPct: 100 }]` (DEGEN). `percent` = price decrease from entry, `amountPct` = % of remaining position to sell.
|
|
227
200
|
|
|
228
201
|
**Slippage:** >$500K pool = 100-200bps, $100-500K = 200-400bps, $50-100K = 300-500bps, <$50K = 400-800bps (cap). Exit = 1.5× entry.
|
|
229
202
|
|
|
@@ -233,36 +206,15 @@ HARDENED range: +100–300%. DEGEN range: +200–500%. `percent` = price increas
|
|
|
233
206
|
|
|
234
207
|
**Pre-trade journal FIRST** — call `solana_memory_write` with tag `pre_trade_rationale` BEFORE executing. Also call `solana_decision_log` to record the decision with confidence, sizing rationale, and risk factors.
|
|
235
208
|
|
|
236
|
-
**Source attribution (mandatory):** The `pre_trade_rationale`
|
|
209
|
+
**Source attribution (mandatory):** The `pre_trade_rationale` MUST include `source: "<how you found this token>"` — one of: `alpha_signal:<source_name>`, `scan_launches`, `scan_hot_pairs`, `bitquery_subscription`, `manual`, `watchlist`. Required for source trust scoring and strategy evolution.
|
|
237
210
|
|
|
238
211
|
**Prior history check (mandatory):**
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
```
|
|
242
|
-
Check for prior trades on this token. If you lost money on it before, the re-entry penalty (-0.15) must already be factored into your confidence score.
|
|
212
|
+
`solana_memory_by_token({ tokenAddress: "CA" })`
|
|
213
|
+
If you lost money on this token before, re-entry penalty (-0.15) must already be factored into confidence.
|
|
243
214
|
|
|
244
215
|
**REQUIRED PARAMETERS FOR solana_trade_execute:**
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
solana_trade_execute({
|
|
248
|
-
tokenAddress: "CA",
|
|
249
|
-
side: "buy",
|
|
250
|
-
symbol: "SYMBOL",
|
|
251
|
-
sizeSol: X,
|
|
252
|
-
slPct: 20,
|
|
253
|
-
tpExits: [
|
|
254
|
-
{ percent: 100, amountPct: 30 },
|
|
255
|
-
{ percent: 200, amountPct: 100 }
|
|
256
|
-
],
|
|
257
|
-
trailingStop: {
|
|
258
|
-
levels: [
|
|
259
|
-
{ percentage: 25, amount: 50 },
|
|
260
|
-
{ percentage: 35, amount: 100, triggerAboveATH: 100 }
|
|
261
|
-
]
|
|
262
|
-
},
|
|
263
|
-
slippageBps: 300, // REQUIRED — always send
|
|
264
|
-
idempotencyKey: "unique-id"
|
|
265
|
-
})
|
|
216
|
+
```
|
|
217
|
+
solana_trade_execute({ tokenAddress: "CA", side: "buy", symbol: "SYMBOL", sizeSol: X, slPct: 20, tpExits: [{ percent: 100, amountPct: 30 }, { percent: 200, amountPct: 100 }], trailingStop: { levels: [{ percentage: 25, amount: 50 }, { percentage: 35, amount: 100, triggerAboveATH: 100 }] }, slippageBps: 300, idempotencyKey: "unique-id" })
|
|
266
218
|
```
|
|
267
219
|
|
|
268
220
|
**ABSOLUTE RULES:**
|
|
@@ -271,13 +223,9 @@ solana_trade_execute({
|
|
|
271
223
|
- ❌ NEVER use tpLevels alone (defaults to 100% exit per level)
|
|
272
224
|
- ✅ Always send BOTH tpExits AND slExits
|
|
273
225
|
|
|
274
|
-
Then call `solana_trade_execute`.
|
|
275
|
-
|
|
276
226
|
**Post-buy Bitquery subscription (mandatory after successful buy):**
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
```
|
|
280
|
-
Start real-time price monitoring for the position. This gives you live price data between heartbeats.
|
|
227
|
+
`solana_bitquery_subscribe({ templateKey: "realtimeTokenPricesSolana", variables: { token: "CA" }, agentId: "main" })`
|
|
228
|
+
Start real-time price monitoring. Live price data between heartbeats.
|
|
281
229
|
|
|
282
230
|
**IMMEDIATELY after execution, post this EXACT format:**
|
|
283
231
|
|
|
@@ -298,19 +246,14 @@ For each open position: check PnL, SL/TP proximity, flow direction. **Use `unrea
|
|
|
298
246
|
|
|
299
247
|
**On-chain verification:** If any position balance looks inconsistent, call `solana_wallet_token_balance` with the token mint to verify actual on-chain holdings.
|
|
300
248
|
|
|
301
|
-
**Feature delta check
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
```
|
|
305
|
-
Compare the token's current features against what they were at entry. If features have degraded significantly (e.g., buy pressure flipped negative, volume collapsed), consider exiting even if SL hasn't triggered.
|
|
249
|
+
**Feature delta check (optional but recommended):**
|
|
250
|
+
`solana_candidate_delta({ id: "CA", currentFeatures: { volume_momentum: 0.5, buy_pressure: 0.3, ... } })`
|
|
251
|
+
Compare current features against entry. If degraded significantly (buy pressure flipped, volume collapsed), consider exiting even if SL hasn't triggered.
|
|
306
252
|
|
|
307
|
-
**Social exhaustion check
|
|
308
|
-
```
|
|
309
|
-
x_search_tweets({ query: "$SYMBOL" })
|
|
310
|
-
```
|
|
253
|
+
**Social exhaustion check:** `x_search_tweets({ query: "$SYMBOL" })`
|
|
311
254
|
Mention velocity declining + price flat/dropping = social exhaustion → consider exit.
|
|
312
255
|
|
|
313
|
-
**Dead money re-check:** Apply the 4 criteria from Step 0 again. Do NOT wait for the next cycle
|
|
256
|
+
**Dead money re-check:** Apply the 4 criteria from Step 0 again. Do NOT wait for the next cycle.
|
|
314
257
|
|
|
315
258
|
## STEP 7: EXIT + ANNOUNCE
|
|
316
259
|
|
|
@@ -332,33 +275,23 @@ Partial exits → "🔴 PARTIAL EXIT (50%): SYMBOL (CA)"
|
|
|
332
275
|
|
|
333
276
|
1. Call `solana_trade_review` for each closed position.
|
|
334
277
|
|
|
335
|
-
2. **LABEL THE OUTCOME —
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
```
|
|
339
|
-
The intelligence lab CANNOT learn without labeled outcomes. An unlabeled exit is wasted data. If you skip this call, the entire learning pipeline is broken — strategy evolution, model evaluation, and replay all depend on labeled candidates.
|
|
278
|
+
2. **LABEL THE OUTCOME — DO NOT SKIP:**
|
|
279
|
+
`solana_candidate_label_outcome({ id: "CA", outcome: "win|loss|skip|dead_money", pnlPct: X.XX, holdingHours: H })`
|
|
280
|
+
The intelligence lab CANNOT learn without labeled outcomes. Strategy evolution, model evaluation, and replay all depend on labeled candidates.
|
|
340
281
|
|
|
341
282
|
3. **LEARNING ENTRY — REQUIRED after every loss or dead_money exit:**
|
|
342
283
|
```
|
|
343
|
-
solana_memory_write({
|
|
344
|
-
content: "LEARNING ENTRY: LRN-YYYYMMDD-NNN\nPriority: P2\nArea: <area_tag>\nWHAT HAPPENED: <1 sentence>\nWHY IT WENT WRONG: <root cause>\nEVIDENCE: token CA, entry price, exit price, hold time\nSUGGESTED ADJUSTMENT: <what to change>",
|
|
345
|
-
tags: ["learning_entry", "learning_entry_<area>"]
|
|
346
|
-
})
|
|
284
|
+
solana_memory_write({ content: "LEARNING ENTRY: LRN-YYYYMMDD-NNN\nPriority: P2\nArea: <area_tag>\nWHAT HAPPENED: <1 sentence>\nWHY IT WENT WRONG: <root cause>\nEVIDENCE: token CA, entry price, exit price, hold time\nSUGGESTED ADJUSTMENT: <what to change>", tags: ["learning_entry", "learning_entry_<area>"] })
|
|
347
285
|
```
|
|
348
|
-
Losses without learning entries are the #1 reason the strategy fails to evolve.
|
|
286
|
+
Losses without learning entries are the #1 reason the strategy fails to evolve. See `refs/review-learning.md` for full format and area tags.
|
|
349
287
|
|
|
350
|
-
4. Unsubscribe from Bitquery stream
|
|
351
|
-
```
|
|
352
|
-
solana_bitquery_unsubscribe({ subscriptionId: "<id>" })
|
|
353
|
-
```
|
|
288
|
+
4. Unsubscribe from Bitquery stream: `solana_bitquery_unsubscribe({ subscriptionId: "<id>" })`
|
|
354
289
|
|
|
355
|
-
5. If
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
```
|
|
359
|
-
Log the source's accuracy via `solana_memory_write` with tag `source_reputation`.
|
|
290
|
+
5. If alpha-sourced trade, check source accuracy:
|
|
291
|
+
`solana_alpha_history({ tokenAddress: "CA", limit: 5 })`
|
|
292
|
+
Log via `solana_memory_write` with tag `source_reputation`.
|
|
360
293
|
|
|
361
|
-
## STEP 8: MEMORY WRITE-BACK (mandatory — call ALL
|
|
294
|
+
## STEP 8: MEMORY WRITE-BACK (mandatory — call ALL)
|
|
362
295
|
|
|
363
296
|
- `solana_state_save` if any durable state changed
|
|
364
297
|
- `solana_daily_log` with cycle summary
|
|
@@ -369,11 +302,11 @@ Log the source's accuracy via `solana_memory_write` with tag `source_reputation`
|
|
|
369
302
|
- `solana_context_snapshot_write` — write portfolio world-view for bootstrap injection
|
|
370
303
|
|
|
371
304
|
**Self-check before completing Step 8:**
|
|
372
|
-
- Did you exit any positions
|
|
373
|
-
-
|
|
374
|
-
-
|
|
305
|
+
- Did you exit any positions? → did you call `solana_candidate_label_outcome` for EACH? If not, do it now.
|
|
306
|
+
- Any loss or dead_money exit? → did you write a `learning_entry`? If not, write one now.
|
|
307
|
+
- Any trades executed? → does each `pre_trade_rationale` include `source:` attribution? If not, write correction now.
|
|
375
308
|
|
|
376
|
-
Do NOT skip
|
|
309
|
+
Do NOT skip these. They feed the bootstrap digest that loads into your next session.
|
|
377
310
|
|
|
378
311
|
## STEP 9: REPORT TO USER
|
|
379
312
|
|
|
@@ -400,18 +333,18 @@ OPEN POSITIONS:
|
|
|
400
333
|
[or "No open positions"]
|
|
401
334
|
|
|
402
335
|
SKIPPED:
|
|
403
|
-
- SYMBOL (full_CA): reason skipped
|
|
336
|
+
- SYMBOL (full_CA): reason skipped
|
|
404
337
|
[or "No candidates reached analysis"]
|
|
405
338
|
|
|
406
339
|
NEXT CYCLE: [1 sentence — what you're watching for]
|
|
407
340
|
```
|
|
408
341
|
|
|
409
342
|
**MANDATORY FORMAT RULES:**
|
|
410
|
-
- Every token MUST be SYMBOL (full_contract_address). NO EXCEPTIONS.
|
|
411
|
-
- PnL
|
|
412
|
-
- Capital must come from `solana_capital_status`. NEVER estimate
|
|
413
|
-
-
|
|
414
|
-
- Keep under 60 lines.
|
|
343
|
+
- Every token MUST be SYMBOL (full_contract_address). NO EXCEPTIONS.
|
|
344
|
+
- PnL must come from `solana_positions` or `solana_trade_review` — use `unrealizedPnl` / `realizedPnl` for SOL values. NEVER calculate manually. If tool didn't return it, say "PnL: pending".
|
|
345
|
+
- Capital must come from `solana_capital_status`. NEVER estimate.
|
|
346
|
+
- DEEP ANALYSIS section is MANDATORY. If zero advanced tools used, say so explicitly.
|
|
347
|
+
- Keep under 60 lines.
|
|
415
348
|
|
|
416
349
|
---
|
|
417
350
|
|
|
@@ -1,6 +1,98 @@
|
|
|
1
|
-
#
|
|
1
|
+
# MEMORY.md
|
|
2
2
|
|
|
3
3
|
> Auto-generated by solana_state_save. OpenClaw loads this file into context at every session start.
|
|
4
4
|
> Last updated: pending first startup
|
|
5
5
|
|
|
6
6
|
_No state saved yet._
|
|
7
|
+
|
|
8
|
+
<!--
|
|
9
|
+
Expected structure after first solana_state_save call:
|
|
10
|
+
|
|
11
|
+
## Trading Identity
|
|
12
|
+
- Tier: (free|pro|whale)
|
|
13
|
+
- Wallet: (public key)
|
|
14
|
+
- Mode: (HARDENED|DEGEN)
|
|
15
|
+
- Strategy Version: (semver)
|
|
16
|
+
- Min Buy: (minimum SOL per trade)
|
|
17
|
+
- Min TP: (minimum take-profit %)
|
|
18
|
+
- TP Structure:
|
|
19
|
+
- (TP configuration details)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## STRATEGY
|
|
24
|
+
|
|
25
|
+
### Feature Weights
|
|
26
|
+
- volume_momentum: 0.20
|
|
27
|
+
- buy_pressure: 0.20
|
|
28
|
+
- flow_divergence: 0.15
|
|
29
|
+
- liquidity_depth: 0.15
|
|
30
|
+
- risk_inverse: 0.15
|
|
31
|
+
- token_maturity: 0.10
|
|
32
|
+
- holder_quality: 0.05
|
|
33
|
+
|
|
34
|
+
### Position Sizing Rules
|
|
35
|
+
- 0.85+ (SUPER ALPHA): (sizing)
|
|
36
|
+
- 0.75-0.84 (Tier-1): (sizing)
|
|
37
|
+
- 0.65-0.74 (Tier-2): (sizing)
|
|
38
|
+
- 0.50-0.64 (Weak): (sizing)
|
|
39
|
+
- <0.50: (skip)
|
|
40
|
+
|
|
41
|
+
### Stop-Loss Rules
|
|
42
|
+
- FRESH (0-5 min): (SL%)
|
|
43
|
+
- EMERGING (5-30 min): (SL%)
|
|
44
|
+
- ESTABLISHED (30+ min): (SL%)
|
|
45
|
+
|
|
46
|
+
### Take-Profit Rules
|
|
47
|
+
- HARD RULE: (rule)
|
|
48
|
+
- 0.50-0.64: (TP%)
|
|
49
|
+
- 0.65-0.79: (TP%)
|
|
50
|
+
- 0.80+: (TP%)
|
|
51
|
+
|
|
52
|
+
### Entry Filter
|
|
53
|
+
- SUPER ALPHA (0.70+): (action)
|
|
54
|
+
- Tier-1 (0.65-0.69): (action)
|
|
55
|
+
- Tier-2 (0.60-0.64): (action)
|
|
56
|
+
- Below 0.60: (skip)
|
|
57
|
+
|
|
58
|
+
### Dead Money Rule
|
|
59
|
+
- Force close if: (criteria)
|
|
60
|
+
- No hope trades: (action)
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Permanent Learnings
|
|
65
|
+
1. (lesson 1)
|
|
66
|
+
2. (lesson 2)
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Capital Status Tracker
|
|
71
|
+
Last Updated: (timestamp)
|
|
72
|
+
- Wallet Balance: (SOL)
|
|
73
|
+
- Realized P&L (All-Time): (SOL)
|
|
74
|
+
- Open Positions: (count)
|
|
75
|
+
- Daily Notional Used: (SOL)
|
|
76
|
+
- Daily Realized Loss: (SOL)
|
|
77
|
+
- Kill Switch: (on/off)
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Next Trading Cycle
|
|
82
|
+
- Scan: (what to scan)
|
|
83
|
+
- Candidates in Lab: (count)
|
|
84
|
+
- Strategy: (approach)
|
|
85
|
+
- Focus: (narrative/sector)
|
|
86
|
+
- Action: (next step)
|
|
87
|
+
|
|
88
|
+
State keys the agent should use with solana_state_save:
|
|
89
|
+
- tier, walletId, mode, strategyVersion, minBuy, minTp, tpStructure
|
|
90
|
+
- strategy: { featureWeights, positionSizing, stopLoss, takeProfit, entryFilter, deadMoney }
|
|
91
|
+
(also accepted as flat keys: featureWeights, positionSizing, etc.)
|
|
92
|
+
- permanentLearnings: string[]
|
|
93
|
+
- capitalStatus: { lastUpdated, walletBalance, realizedPnlAllTime, openPositions, dailyNotionalUsed, dailyRealizedLoss, killSwitch }
|
|
94
|
+
- nextCycle: { scan, candidatesInLab, strategy, focus, action }
|
|
95
|
+
- watchlist: string[]
|
|
96
|
+
- regimeCanary: { regime, detectedAt }
|
|
97
|
+
- preferences: { key: value }
|
|
98
|
+
-->
|