@ebowwa/daemons 0.5.0
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/README.md +264 -0
- package/dist/bin/discord-cli.js +124118 -0
- package/dist/bin/manager.js +143 -0
- package/dist/bin/telegram-cli.js +124114 -0
- package/dist/index.js +125340 -0
- package/package.json +94 -0
- package/src/agent.ts +111 -0
- package/src/channels/base.ts +573 -0
- package/src/channels/discord.ts +306 -0
- package/src/channels/index.ts +169 -0
- package/src/channels/telegram.ts +315 -0
- package/src/daemon.ts +534 -0
- package/src/hooks.ts +97 -0
- package/src/index.ts +111 -0
- package/src/memory.ts +369 -0
- package/src/skills/coding/commit.ts +202 -0
- package/src/skills/coding/execute-subtask.ts +136 -0
- package/src/skills/coding/fix-issues.ts +126 -0
- package/src/skills/coding/index.ts +26 -0
- package/src/skills/coding/plan-task.ts +158 -0
- package/src/skills/coding/quality-check.ts +155 -0
- package/src/skills/index.ts +65 -0
- package/src/skills/registry.ts +380 -0
- package/src/skills/shared/index.ts +21 -0
- package/src/skills/shared/reflect.ts +156 -0
- package/src/skills/shared/review.ts +201 -0
- package/src/skills/shared/trajectory.ts +319 -0
- package/src/skills/trading/analyze-market.ts +144 -0
- package/src/skills/trading/check-risk.ts +176 -0
- package/src/skills/trading/execute-trade.ts +185 -0
- package/src/skills/trading/generate-signal.ts +160 -0
- package/src/skills/trading/index.ts +26 -0
- package/src/skills/trading/monitor-position.ts +179 -0
- package/src/skills/types.ts +235 -0
- package/src/skills/workflows.ts +340 -0
- package/src/state.ts +77 -0
- package/src/tools.ts +134 -0
- package/src/types.ts +314 -0
- package/src/workflow.ts +341 -0
- package/src/workflows/coding.ts +580 -0
- package/src/workflows/index.ts +61 -0
- package/src/workflows/trading.ts +608 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GLM Daemon - Check Risk Skill
|
|
3
|
+
*
|
|
4
|
+
* Evaluate risk and validate signal before execution.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import type { Skill, SkillContext, SkillResult } from "../types.js";
|
|
9
|
+
import { skillRegistry } from "../registry.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Trade signal from generate-signal skill
|
|
13
|
+
*/
|
|
14
|
+
interface TradeSignal {
|
|
15
|
+
direction: "long" | "short" | "none";
|
|
16
|
+
entryZone?: { min: number; max: number };
|
|
17
|
+
stopLoss?: number;
|
|
18
|
+
takeProfits?: {
|
|
19
|
+
tp1?: { price: number; size: string };
|
|
20
|
+
tp2?: { price: number; size: string };
|
|
21
|
+
tp3?: { price: number; size: string };
|
|
22
|
+
};
|
|
23
|
+
confidence?: number;
|
|
24
|
+
rationale?: string;
|
|
25
|
+
positionSize?: {
|
|
26
|
+
percentage: number;
|
|
27
|
+
absolute?: number;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Market analysis from analyze-market skill
|
|
33
|
+
*/
|
|
34
|
+
interface MarketAnalysis {
|
|
35
|
+
marketId: string;
|
|
36
|
+
trend?: string;
|
|
37
|
+
volatility?: string;
|
|
38
|
+
sentiment?: string;
|
|
39
|
+
keyLevels?: number[];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Check risk parameters
|
|
44
|
+
*/
|
|
45
|
+
const CheckRiskParams = z.object({
|
|
46
|
+
/** Maximum risk per trade (percentage) */
|
|
47
|
+
maxRiskPerTrade: z.number().optional(),
|
|
48
|
+
/** Minimum risk/reward ratio */
|
|
49
|
+
minRiskReward: z.number().optional(),
|
|
50
|
+
/** Maximum portfolio exposure */
|
|
51
|
+
maxExposure: z.number().optional(),
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Risk check result data
|
|
56
|
+
*/
|
|
57
|
+
interface CheckRiskData {
|
|
58
|
+
approved: boolean;
|
|
59
|
+
riskScore: number;
|
|
60
|
+
concerns: string[];
|
|
61
|
+
adjustments: string[];
|
|
62
|
+
maxPositionSize: number;
|
|
63
|
+
reasoning: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Check risk skill
|
|
68
|
+
*/
|
|
69
|
+
export const checkRiskSkill: Skill<z.infer<typeof CheckRiskParams>, CheckRiskData> = {
|
|
70
|
+
id: "/check-risk",
|
|
71
|
+
name: "Check Risk",
|
|
72
|
+
description: "Evaluate risk and validate trading signal before execution.",
|
|
73
|
+
paramsSchema: CheckRiskParams,
|
|
74
|
+
tags: ["trading", "risk", "validation"],
|
|
75
|
+
parallelizable: false,
|
|
76
|
+
requires: ["analysis", "signal"],
|
|
77
|
+
|
|
78
|
+
async execute(params, context): Promise<SkillResult<CheckRiskData>> {
|
|
79
|
+
const analysis = (context.custom.analysis || {}) as MarketAnalysis;
|
|
80
|
+
const signal = (context.custom.signal || {}) as TradeSignal;
|
|
81
|
+
const maxRiskPerTrade = params?.maxRiskPerTrade || 2;
|
|
82
|
+
const minRiskReward = params?.minRiskReward || 1.5;
|
|
83
|
+
const maxExposure = params?.maxExposure || 10;
|
|
84
|
+
|
|
85
|
+
console.log("[/check-risk] Evaluating signal risk");
|
|
86
|
+
|
|
87
|
+
const prompt = `Perform risk assessment for the proposed trade.
|
|
88
|
+
|
|
89
|
+
Analysis: ${JSON.stringify(analysis, null, 2)}
|
|
90
|
+
Signal: ${JSON.stringify(signal, null, 2)}
|
|
91
|
+
|
|
92
|
+
Risk Parameters:
|
|
93
|
+
- Max risk per trade: ${maxRiskPerTrade}%
|
|
94
|
+
- Min risk/reward: ${minRiskReward}
|
|
95
|
+
- Max portfolio exposure: ${maxExposure}%
|
|
96
|
+
|
|
97
|
+
Evaluate:
|
|
98
|
+
1. Risk/reward ratio (minimum ${minRiskReward}:1)
|
|
99
|
+
2. Position size vs account risk (max ${maxRiskPerTrade}% per trade)
|
|
100
|
+
3. Market conditions (avoid high volatility if conservative)
|
|
101
|
+
4. Correlation with existing positions
|
|
102
|
+
5. Stop loss placement validity
|
|
103
|
+
|
|
104
|
+
Respond in JSON format:
|
|
105
|
+
{
|
|
106
|
+
"approved": true|false,
|
|
107
|
+
"riskScore": 0-100,
|
|
108
|
+
"concerns": ["list of concerns"],
|
|
109
|
+
"adjustments": ["suggested adjustments"],
|
|
110
|
+
"maxPositionSize": number,
|
|
111
|
+
"reasoning": "detailed explanation"
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
If approved is false, explain why and what conditions would make it acceptable.`;
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
const response = await context.agent.execute(prompt);
|
|
118
|
+
|
|
119
|
+
// Parse JSON from response
|
|
120
|
+
const jsonMatch = response.match(/\{[\s\S]*\}/);
|
|
121
|
+
let data: CheckRiskData;
|
|
122
|
+
|
|
123
|
+
if (jsonMatch) {
|
|
124
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
125
|
+
data = {
|
|
126
|
+
approved: parsed.approved === true,
|
|
127
|
+
riskScore: parsed.riskScore || 50,
|
|
128
|
+
concerns: parsed.concerns || [],
|
|
129
|
+
adjustments: parsed.adjustments || [],
|
|
130
|
+
maxPositionSize: parsed.maxPositionSize || signal.positionSize?.percentage || 1,
|
|
131
|
+
reasoning: parsed.reasoning || "",
|
|
132
|
+
};
|
|
133
|
+
} else {
|
|
134
|
+
// Fallback: default to not approved
|
|
135
|
+
const hasConcerns = response.toLowerCase().includes("concern") || response.toLowerCase().includes("risk");
|
|
136
|
+
data = {
|
|
137
|
+
approved: !hasConcerns,
|
|
138
|
+
riskScore: hasConcerns ? 70 : 30,
|
|
139
|
+
concerns: hasConcerns ? ["Unable to parse risk assessment"] : [],
|
|
140
|
+
adjustments: [],
|
|
141
|
+
maxPositionSize: 1,
|
|
142
|
+
reasoning: response.substring(0, 300),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
console.log(`[/check-risk] Result: ${data.approved ? "APPROVED" : "REJECTED"}`);
|
|
147
|
+
console.log(`[/check-risk] Risk score: ${data.riskScore}/100`);
|
|
148
|
+
if (data.concerns.length > 0) {
|
|
149
|
+
console.log(`[/check-risk] Concerns: ${data.concerns.length}`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
success: true,
|
|
154
|
+
data,
|
|
155
|
+
contextUpdates: {
|
|
156
|
+
riskApproved: data.approved,
|
|
157
|
+
riskAssessment: data,
|
|
158
|
+
},
|
|
159
|
+
nextSkill: data.approved ? "/execute-trade" : "/analyze-market",
|
|
160
|
+
};
|
|
161
|
+
} catch (error) {
|
|
162
|
+
return {
|
|
163
|
+
success: false,
|
|
164
|
+
error: error instanceof Error ? error.message : String(error),
|
|
165
|
+
contextUpdates: {
|
|
166
|
+
riskApproved: false,
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
skillRegistry.register(checkRiskSkill);
|
|
174
|
+
|
|
175
|
+
export { CheckRiskParams };
|
|
176
|
+
export type { CheckRiskData };
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GLM Daemon - Execute Trade Skill
|
|
3
|
+
*
|
|
4
|
+
* Execute trades according to validated signals.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import type { Skill, SkillContext, SkillResult } from "../types.js";
|
|
9
|
+
import { skillRegistry } from "../registry.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Trade signal from generate-signal skill
|
|
13
|
+
*/
|
|
14
|
+
interface TradeSignal {
|
|
15
|
+
direction: "long" | "short" | "none";
|
|
16
|
+
entryZone?: { min: number; max: number };
|
|
17
|
+
stopLoss?: number;
|
|
18
|
+
takeProfits?: {
|
|
19
|
+
tp1?: { price: number; size: string };
|
|
20
|
+
tp2?: { price: number; size: string };
|
|
21
|
+
tp3?: { price: number; size: string };
|
|
22
|
+
};
|
|
23
|
+
confidence?: number;
|
|
24
|
+
rationale?: string;
|
|
25
|
+
positionSize?: {
|
|
26
|
+
percentage: number;
|
|
27
|
+
absolute?: number;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Risk assessment from check-risk skill
|
|
33
|
+
*/
|
|
34
|
+
interface RiskAssessment {
|
|
35
|
+
approved: boolean;
|
|
36
|
+
positionSize?: number;
|
|
37
|
+
riskPercent?: number;
|
|
38
|
+
riskRewardRatio?: number;
|
|
39
|
+
maxLoss?: number;
|
|
40
|
+
reasons?: string[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Execute trade parameters
|
|
45
|
+
*/
|
|
46
|
+
const ExecuteTradeParams = z.object({
|
|
47
|
+
/** Use paper trading (simulation) */
|
|
48
|
+
paper: z.boolean().optional(),
|
|
49
|
+
/** Custom order type */
|
|
50
|
+
orderType: z.enum(["market", "limit", "fok"]).optional(),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Execute trade result data
|
|
55
|
+
*/
|
|
56
|
+
interface ExecuteTradeData {
|
|
57
|
+
orderId: string;
|
|
58
|
+
direction: string;
|
|
59
|
+
entryPrice: number;
|
|
60
|
+
size: number;
|
|
61
|
+
stopLossOrderId: string;
|
|
62
|
+
takeProfitOrderIds: string[];
|
|
63
|
+
status: "placed" | "filled" | "partial" | "failed";
|
|
64
|
+
timestamp: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Execute trade skill
|
|
69
|
+
*/
|
|
70
|
+
export const executeTradeSkill: Skill<z.infer<typeof ExecuteTradeParams>, ExecuteTradeData> = {
|
|
71
|
+
id: "/execute-trade",
|
|
72
|
+
name: "Execute Trade",
|
|
73
|
+
description: "Execute trades using available trading tools.",
|
|
74
|
+
paramsSchema: ExecuteTradeParams,
|
|
75
|
+
tags: ["trading", "execution"],
|
|
76
|
+
parallelizable: false,
|
|
77
|
+
requires: ["signal", "riskApproved"],
|
|
78
|
+
maxRetries: 2,
|
|
79
|
+
|
|
80
|
+
async execute(params, context): Promise<SkillResult<ExecuteTradeData>> {
|
|
81
|
+
const signal = (context.custom.signal || {}) as TradeSignal;
|
|
82
|
+
const riskAssessment = (context.custom.riskAssessment || {}) as RiskAssessment;
|
|
83
|
+
const paper = params?.paper ?? true; // Default to paper trading
|
|
84
|
+
|
|
85
|
+
if (!context.custom.riskApproved) {
|
|
86
|
+
return {
|
|
87
|
+
success: false,
|
|
88
|
+
error: "Risk not approved - cannot execute trade",
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
console.log(`[/execute-trade] Executing ${signal.direction} trade (${paper ? "PAPER" : "LIVE"})`);
|
|
93
|
+
|
|
94
|
+
const prompt = `Execute the approved trade signal.
|
|
95
|
+
|
|
96
|
+
Signal: ${JSON.stringify(signal, null, 2)}
|
|
97
|
+
Risk Assessment: ${JSON.stringify(riskAssessment, null, 2)}
|
|
98
|
+
Mode: ${paper ? "PAPER TRADING" : "LIVE TRADING"}
|
|
99
|
+
|
|
100
|
+
Use the available trading tools to:
|
|
101
|
+
1. Place the entry order (${params?.orderType || "limit"})
|
|
102
|
+
2. Set stop loss order at ${signal.stopLoss}
|
|
103
|
+
3. Set take profit orders:
|
|
104
|
+
- TP1 at ${signal.takeProfits?.tp1?.price} (${signal.takeProfits?.tp1?.size})
|
|
105
|
+
- TP2 at ${signal.takeProfits?.tp2?.price} (${signal.takeProfits?.tp2?.size})
|
|
106
|
+
- TP3 at ${signal.takeProfits?.tp3?.price} (${signal.takeProfits?.tp3?.size})
|
|
107
|
+
4. Confirm all orders are placed correctly
|
|
108
|
+
|
|
109
|
+
Report execution status with order IDs in JSON format:
|
|
110
|
+
{
|
|
111
|
+
"orderId": "entry order id",
|
|
112
|
+
"direction": "long|short",
|
|
113
|
+
"entryPrice": number,
|
|
114
|
+
"size": number,
|
|
115
|
+
"stopLossOrderId": "stop loss order id",
|
|
116
|
+
"takeProfitOrderIds": ["tp1 id", "tp2 id", "tp3 id"],
|
|
117
|
+
"status": "placed|filled|partial|failed",
|
|
118
|
+
"timestamp": "ISO timestamp"
|
|
119
|
+
}`;
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
const response = await context.agent.execute(prompt);
|
|
123
|
+
|
|
124
|
+
// Parse JSON from response
|
|
125
|
+
const jsonMatch = response.match(/\{[\s\S]*\}/);
|
|
126
|
+
let data: ExecuteTradeData;
|
|
127
|
+
|
|
128
|
+
if (jsonMatch) {
|
|
129
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
130
|
+
data = {
|
|
131
|
+
orderId: parsed.orderId || `paper-${Date.now()}`,
|
|
132
|
+
direction: parsed.direction || signal.direction,
|
|
133
|
+
entryPrice: parsed.entryPrice || signal.entryZone?.min || 0,
|
|
134
|
+
size: parsed.size || signal.positionSize?.percentage || 0,
|
|
135
|
+
stopLossOrderId: parsed.stopLossOrderId || `sl-${Date.now()}`,
|
|
136
|
+
takeProfitOrderIds: parsed.takeProfitOrderIds || [`tp1-${Date.now()}`, `tp2-${Date.now()}`, `tp3-${Date.now()}`],
|
|
137
|
+
status: parsed.status || "placed",
|
|
138
|
+
timestamp: parsed.timestamp || new Date().toISOString(),
|
|
139
|
+
};
|
|
140
|
+
} else {
|
|
141
|
+
// Fallback for paper trading
|
|
142
|
+
data = {
|
|
143
|
+
orderId: `paper-${Date.now()}`,
|
|
144
|
+
direction: signal.direction || "long",
|
|
145
|
+
entryPrice: signal.entryZone?.min || 0,
|
|
146
|
+
size: signal.positionSize?.percentage || 1,
|
|
147
|
+
stopLossOrderId: `sl-${Date.now()}`,
|
|
148
|
+
takeProfitOrderIds: [`tp1-${Date.now()}`, `tp2-${Date.now()}`, `tp3-${Date.now()}`],
|
|
149
|
+
status: "placed",
|
|
150
|
+
timestamp: new Date().toISOString(),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
console.log(`[/execute-trade] Order ID: ${data.orderId}`);
|
|
155
|
+
console.log(`[/execute-trade] Status: ${data.status}`);
|
|
156
|
+
console.log(`[/execute-trade] Entry: ${data.entryPrice}, Size: ${data.size}%`);
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
success: data.status !== "failed",
|
|
160
|
+
data,
|
|
161
|
+
contextUpdates: {
|
|
162
|
+
executionResult: data,
|
|
163
|
+
tradeStartTime: data.timestamp,
|
|
164
|
+
position: {
|
|
165
|
+
orderId: data.orderId,
|
|
166
|
+
direction: data.direction,
|
|
167
|
+
entryPrice: data.entryPrice,
|
|
168
|
+
size: data.size,
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
error: data.status === "failed" ? "Order execution failed" : undefined,
|
|
172
|
+
};
|
|
173
|
+
} catch (error) {
|
|
174
|
+
return {
|
|
175
|
+
success: false,
|
|
176
|
+
error: error instanceof Error ? error.message : String(error),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
skillRegistry.register(executeTradeSkill);
|
|
183
|
+
|
|
184
|
+
export { ExecuteTradeParams };
|
|
185
|
+
export type { ExecuteTradeData };
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GLM Daemon - Generate Signal Skill
|
|
3
|
+
*
|
|
4
|
+
* Generate trading signals based on market analysis.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import type { Skill, SkillContext, SkillResult } from "../types.js";
|
|
9
|
+
import { skillRegistry } from "../registry.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Generate signal parameters
|
|
13
|
+
*/
|
|
14
|
+
const GenerateSignalParams = z.object({
|
|
15
|
+
/** Risk tolerance */
|
|
16
|
+
riskTolerance: z.enum(["conservative", "moderate", "aggressive"]).optional(),
|
|
17
|
+
/** Position size limit (percentage) */
|
|
18
|
+
maxPositionSize: z.number().optional(),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Trading signal result data
|
|
23
|
+
*/
|
|
24
|
+
interface GenerateSignalData {
|
|
25
|
+
direction: "long" | "short" | "none";
|
|
26
|
+
entryZone: { min: number; max: number };
|
|
27
|
+
stopLoss: number;
|
|
28
|
+
takeProfits: {
|
|
29
|
+
tp1: { price: number; size: string };
|
|
30
|
+
tp2: { price: number; size: string };
|
|
31
|
+
tp3: { price: number; size: string };
|
|
32
|
+
};
|
|
33
|
+
positionSize: { percentage: number; reason: string };
|
|
34
|
+
riskReward: number;
|
|
35
|
+
confidence: number;
|
|
36
|
+
rationale: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Generate signal skill
|
|
41
|
+
*/
|
|
42
|
+
export const generateSignalSkill: Skill<z.infer<typeof GenerateSignalParams>, GenerateSignalData> = {
|
|
43
|
+
id: "/generate-signal",
|
|
44
|
+
name: "Generate Signal",
|
|
45
|
+
description: "Generate trading signals based on market analysis.",
|
|
46
|
+
paramsSchema: GenerateSignalParams,
|
|
47
|
+
tags: ["trading", "signal"],
|
|
48
|
+
parallelizable: false,
|
|
49
|
+
requires: ["analysis"],
|
|
50
|
+
|
|
51
|
+
async execute(params, context): Promise<SkillResult<GenerateSignalData>> {
|
|
52
|
+
const analysis = context.custom.analysis || {};
|
|
53
|
+
const riskTolerance = params?.riskTolerance || "moderate";
|
|
54
|
+
const maxPositionSize = params?.maxPositionSize || 5;
|
|
55
|
+
|
|
56
|
+
console.log("[/generate-signal] Generating trading signal");
|
|
57
|
+
|
|
58
|
+
const prompt = `Generate a trading signal based on this analysis.
|
|
59
|
+
|
|
60
|
+
Analysis: ${JSON.stringify(analysis, null, 2)}
|
|
61
|
+
Risk Tolerance: ${riskTolerance}
|
|
62
|
+
Max Position Size: ${maxPositionSize}%
|
|
63
|
+
|
|
64
|
+
Generate a trading signal with:
|
|
65
|
+
- Direction (long/short/none)
|
|
66
|
+
- Entry price zone
|
|
67
|
+
- Stop loss level
|
|
68
|
+
- Take profit targets (3 levels)
|
|
69
|
+
- Position size recommendation
|
|
70
|
+
- Risk/reward ratio
|
|
71
|
+
- Confidence level
|
|
72
|
+
- Rationale
|
|
73
|
+
|
|
74
|
+
Provide the signal in JSON format:
|
|
75
|
+
{
|
|
76
|
+
"direction": "long|short|none",
|
|
77
|
+
"entryZone": { "min": number, "max": number },
|
|
78
|
+
"stopLoss": number,
|
|
79
|
+
"takeProfits": {
|
|
80
|
+
"tp1": { "price": number, "size": "percentage" },
|
|
81
|
+
"tp2": { "price": number, "size": "percentage" },
|
|
82
|
+
"tp3": { "price": number, "size": "percentage" }
|
|
83
|
+
},
|
|
84
|
+
"positionSize": { "percentage": number, "reason": "string" },
|
|
85
|
+
"riskReward": number,
|
|
86
|
+
"confidence": 0-100,
|
|
87
|
+
"rationale": "explanation"
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
If no clear signal exists, set direction to "none" and explain why.`;
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
const response = await context.agent.execute(prompt);
|
|
94
|
+
|
|
95
|
+
// Parse JSON from response
|
|
96
|
+
const jsonMatch = response.match(/\{[\s\S]*\}/);
|
|
97
|
+
let data: GenerateSignalData;
|
|
98
|
+
|
|
99
|
+
if (jsonMatch) {
|
|
100
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
101
|
+
data = {
|
|
102
|
+
direction: parsed.direction || "none",
|
|
103
|
+
entryZone: parsed.entryZone || { min: 0, max: 0 },
|
|
104
|
+
stopLoss: parsed.stopLoss || 0,
|
|
105
|
+
takeProfits: parsed.takeProfits || {
|
|
106
|
+
tp1: { price: 0, size: "33%" },
|
|
107
|
+
tp2: { price: 0, size: "33%" },
|
|
108
|
+
tp3: { price: 0, size: "34%" },
|
|
109
|
+
},
|
|
110
|
+
positionSize: parsed.positionSize || { percentage: 1, reason: "Default" },
|
|
111
|
+
riskReward: parsed.riskReward || 0,
|
|
112
|
+
confidence: parsed.confidence || 0,
|
|
113
|
+
rationale: parsed.rationale || "",
|
|
114
|
+
};
|
|
115
|
+
} else {
|
|
116
|
+
data = {
|
|
117
|
+
direction: "none",
|
|
118
|
+
entryZone: { min: 0, max: 0 },
|
|
119
|
+
stopLoss: 0,
|
|
120
|
+
takeProfits: {
|
|
121
|
+
tp1: { price: 0, size: "33%" },
|
|
122
|
+
tp2: { price: 0, size: "33%" },
|
|
123
|
+
tp3: { price: 0, size: "34%" },
|
|
124
|
+
},
|
|
125
|
+
positionSize: { percentage: 0, reason: "No valid signal" },
|
|
126
|
+
riskReward: 0,
|
|
127
|
+
confidence: 0,
|
|
128
|
+
rationale: response.substring(0, 200),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
console.log(`[/generate-signal] Direction: ${data.direction}`);
|
|
133
|
+
console.log(`[/generate-signal] R:R = ${data.riskReward}, Confidence = ${data.confidence}%`);
|
|
134
|
+
|
|
135
|
+
// If no signal, go back to analysis
|
|
136
|
+
if (data.direction === "none") {
|
|
137
|
+
console.log("[/generate-signal] No signal generated, will re-analyze");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
success: true,
|
|
142
|
+
data,
|
|
143
|
+
contextUpdates: {
|
|
144
|
+
signal: data,
|
|
145
|
+
},
|
|
146
|
+
nextSkill: data.direction === "none" ? "/analyze-market" : undefined,
|
|
147
|
+
};
|
|
148
|
+
} catch (error) {
|
|
149
|
+
return {
|
|
150
|
+
success: false,
|
|
151
|
+
error: error instanceof Error ? error.message : String(error),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
skillRegistry.register(generateSignalSkill);
|
|
158
|
+
|
|
159
|
+
export { GenerateSignalParams };
|
|
160
|
+
export type { GenerateSignalData };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GLM Daemon - Trading Skills
|
|
3
|
+
*
|
|
4
|
+
* Skills for trading and market analysis workflows.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Import to auto-register
|
|
8
|
+
import "./analyze-market.js";
|
|
9
|
+
import "./generate-signal.js";
|
|
10
|
+
import "./check-risk.js";
|
|
11
|
+
import "./execute-trade.js";
|
|
12
|
+
import "./monitor-position.js";
|
|
13
|
+
|
|
14
|
+
// Re-export for explicit imports
|
|
15
|
+
export { analyzeMarketSkill } from "./analyze-market.js";
|
|
16
|
+
export { generateSignalSkill } from "./generate-signal.js";
|
|
17
|
+
export { checkRiskSkill } from "./check-risk.js";
|
|
18
|
+
export { executeTradeSkill } from "./execute-trade.js";
|
|
19
|
+
export { monitorPositionSkill } from "./monitor-position.js";
|
|
20
|
+
|
|
21
|
+
// Re-export types
|
|
22
|
+
export type { AnalyzeMarketData } from "./analyze-market.js";
|
|
23
|
+
export type { GenerateSignalData } from "./generate-signal.js";
|
|
24
|
+
export type { CheckRiskData } from "./check-risk.js";
|
|
25
|
+
export type { ExecuteTradeData } from "./execute-trade.js";
|
|
26
|
+
export type { MonitorPositionData } from "./monitor-position.js";
|