@aiaiaichain/agent 0.1.6 → 0.1.8
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/api/ExtensionAPI.d.ts +0 -1
- package/dist/api/ExtensionAPI.js +3 -7
- package/dist/api/Registry.d.ts +0 -1
- package/dist/api/Registry.js +54 -57
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +364 -768
- package/dist/core/AgentDir.d.ts +1 -1
- package/dist/core/AgentDir.js +45 -39
- package/dist/core/ChainConfig.d.ts +0 -1
- package/dist/core/ChainConfig.js +51 -55
- package/dist/core/EnvLoader.d.ts +4 -1
- package/dist/core/EnvLoader.js +97 -84
- package/dist/core/SystemMonitor.d.ts +0 -1
- package/dist/core/SystemMonitor.js +70 -85
- package/dist/index.d.ts +4 -61
- package/dist/index.js +19 -26
- package/dist/loader.d.ts +0 -1
- package/dist/loader.js +64 -67
- package/dist/mcp/entry.d.ts +0 -1
- package/dist/mcp/entry.js +3 -6
- package/dist/mcp/server.d.ts +0 -1
- package/dist/mcp/server.js +152 -156
- package/dist/models/CostTracker.d.ts +0 -1
- package/dist/models/CostTracker.js +58 -61
- package/dist/models/ModelRegistry.d.ts +0 -1
- package/dist/models/ModelRegistry.js +195 -155
- package/dist/providers/ProviderRegistry.d.ts +0 -1
- package/dist/providers/ProviderRegistry.js +33 -36
- package/dist/runner/AgentRunner.d.ts +0 -1
- package/dist/runner/AgentRunner.js +180 -184
- package/dist/runner/ModelClient.d.ts +0 -1
- package/dist/runner/ModelClient.js +133 -134
- package/dist/runner/SwarmRouter.d.ts +0 -1
- package/dist/runner/SwarmRouter.js +17 -22
- package/dist/runner/ToolDispatcher.d.ts +0 -1
- package/dist/runner/ToolDispatcher.js +30 -33
- package/dist/scheduler/AgentScheduler.d.ts +0 -1
- package/dist/scheduler/AgentScheduler.js +99 -103
- package/dist/session/ContextStore.d.ts +1 -1
- package/dist/session/ContextStore.js +76 -78
- package/dist/session/GoalManager.d.ts +0 -1
- package/dist/session/GoalManager.js +96 -100
- package/dist/session/MemoryStore.d.ts +2 -1
- package/dist/session/MemoryStore.js +108 -87
- package/dist/session/SessionManager.d.ts +5 -4
- package/dist/session/SessionManager.js +83 -62
- package/dist/session/SessionStore.d.ts +0 -1
- package/dist/session/SessionStore.js +112 -116
- package/dist/setup/SetupWizard.d.ts +0 -1
- package/dist/setup/SetupWizard.js +61 -64
- package/dist/tools/CrossTools.d.ts +0 -1
- package/dist/tools/CrossTools.js +140 -144
- package/dist/tools/GmgnIntegration.d.ts +0 -1
- package/dist/tools/GmgnIntegration.js +220 -230
- package/dist/tools/MarketSentiment.d.ts +0 -1
- package/dist/tools/MarketSentiment.js +213 -195
- package/dist/tools/NewsSentiment.d.ts +0 -1
- package/dist/tools/NewsSentiment.js +126 -130
- package/dist/tools/PriceFeed.d.ts +6 -1
- package/dist/tools/PriceFeed.js +201 -133
- package/dist/tools/TechnicalAnalysis.d.ts +1 -2
- package/dist/tools/TechnicalAnalysis.js +248 -216
- package/dist/tools/TechnicalAnalysis.worker.d.ts +25 -0
- package/dist/tools/TechnicalAnalysis.worker.js +92 -0
- package/dist/tools/TokenCalendar.d.ts +0 -1
- package/dist/tools/TokenCalendar.js +63 -68
- package/dist/tools/TokenSecurityScanner.d.ts +0 -1
- package/dist/tools/TokenSecurityScanner.js +93 -96
- package/dist/tools/TransactionSim.d.ts +0 -1
- package/dist/tools/TransactionSim.js +65 -71
- package/dist/tui/App.d.ts +1 -7
- package/dist/tui/App.js +896 -825
- package/dist/tui/ModelSelector.d.ts +1 -3
- package/dist/tui/ModelSelector.js +47 -50
- package/dist/tui/REPL.d.ts +1 -3
- package/dist/tui/REPL.js +222 -210
- package/dist/tui/Sparkline.d.ts +1 -3
- package/dist/tui/Sparkline.js +38 -37
- package/dist/tui/StatusBar.d.ts +1 -3
- package/dist/tui/StatusBar.js +11 -10
- package/dist/tui/ThemePresets.d.ts +0 -1
- package/dist/tui/ThemePresets.js +99 -103
- package/dist/tui/theme.d.ts +0 -1
- package/dist/tui/theme.js +50 -31
- package/dist/util/clipboard.d.ts +0 -1
- package/dist/util/clipboard.js +16 -20
- package/dist/util/commandSuggest.d.ts +0 -1
- package/dist/util/commandSuggest.js +34 -38
- package/dist/util/confirmation.d.ts +0 -1
- package/dist/util/confirmation.js +8 -11
- package/dist/util/errorHandler.d.ts +0 -1
- package/dist/util/errorHandler.js +20 -23
- package/dist/util/errors.d.ts +59 -0
- package/dist/util/errors.js +93 -0
- package/dist/util/logger.d.ts +0 -1
- package/dist/util/logger.js +30 -33
- package/dist/util/processManager.d.ts +0 -1
- package/dist/util/processManager.js +33 -36
- package/dist/util/resilientFetch.d.ts +6 -1
- package/dist/util/resilientFetch.js +134 -80
- package/dist/util/responseCache.d.ts +0 -1
- package/dist/util/responseCache.js +36 -45
- package/dist/util/rpc.d.ts +16 -0
- package/dist/util/rpc.js +69 -0
- package/dist/util/safeLog.d.ts +0 -1
- package/dist/util/safeLog.js +52 -53
- package/dist/util/scheduler.d.ts +0 -1
- package/dist/util/scheduler.js +53 -58
- package/dist/util/webhooks.d.ts +0 -1
- package/dist/util/webhooks.js +54 -58
- package/dist/wallet/ActionFeed.d.ts +0 -1
- package/dist/wallet/ActionFeed.js +189 -200
- package/dist/wallet/AgentWallet.d.ts +7 -8
- package/dist/wallet/AgentWallet.js +117 -144
- package/dist/wallet/ProfitTracker.d.ts +0 -1
- package/dist/wallet/ProfitTracker.js +71 -74
- package/package.json +14 -8
- package/scripts/build-esbuild.mjs +40 -0
- package/scripts/bundle-dts.mjs +58 -0
- package/scripts/minify.mjs +44 -0
- package/scripts/postinstall.js +41 -0
|
@@ -34,7 +34,7 @@ export declare function bollingerBands(data: number[], period?: number, stdDev?:
|
|
|
34
34
|
};
|
|
35
35
|
export declare function bollingerSignal(bb: ReturnType<typeof bollingerBands>, currentPrice: number): AnalysisResult;
|
|
36
36
|
export declare function atr(candles: OHLCV[], period?: number): number;
|
|
37
|
-
export declare function fullAnalysis(candles: OHLCV[]): AnalysisResult[]
|
|
37
|
+
export declare function fullAnalysis(candles: OHLCV[]): Promise<AnalysisResult[]>;
|
|
38
38
|
export declare const getCandlesParams: import("@sinclair/typebox").TObject<{
|
|
39
39
|
symbol: import("@sinclair/typebox").TString;
|
|
40
40
|
interval: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
@@ -47,4 +47,3 @@ export declare const analyzeTAParams: import("@sinclair/typebox").TObject<{
|
|
|
47
47
|
volumes: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TNumber>>;
|
|
48
48
|
}>;
|
|
49
49
|
export declare function getCandlesTool(_id: string, params: Record<string, unknown>): Promise<ToolResult>;
|
|
50
|
-
//# sourceMappingURL=TechnicalAnalysis.d.ts.map
|
|
@@ -1,235 +1,267 @@
|
|
|
1
|
-
|
|
2
|
-
* TechnicalAnalysis — RSI, MACD, Bollinger Bands, EMA, SMA, ATR.
|
|
3
|
-
* Works with OHLCV candle data. Tools for the agent to query.
|
|
4
|
-
*/
|
|
1
|
+
|
|
5
2
|
import { Type } from "@sinclair/typebox";
|
|
6
3
|
import { resilientFetch } from "../util/resilientFetch.js";
|
|
7
|
-
|
|
4
|
+
|
|
5
|
+
function yieldToEventLoop() {
|
|
6
|
+
return new Promise(resolve => setImmediate(resolve));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async function rsiAsync(data, period = 14, chunkSize = 50) {
|
|
10
|
+
const result = [];
|
|
11
|
+
const gains = [];
|
|
12
|
+
const losses = [];
|
|
13
|
+
for (let i = 1; i < data.length; i++) {
|
|
14
|
+
const diff = data[i] - data[i - 1];
|
|
15
|
+
gains.push(Math.max(0, diff));
|
|
16
|
+
losses.push(Math.max(0, -diff));
|
|
17
|
+
}
|
|
18
|
+
for (let i = period; i < gains.length; i++) {
|
|
19
|
+
let avgGain = 0, avgLoss = 0;
|
|
20
|
+
for (let j = 0; j < period; j++) {
|
|
21
|
+
avgGain += gains[i - j];
|
|
22
|
+
avgLoss += losses[i - j];
|
|
23
|
+
}
|
|
24
|
+
avgGain /= period;
|
|
25
|
+
avgLoss /= period;
|
|
26
|
+
if (avgLoss === 0) {
|
|
27
|
+
result.push(100);
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const rs = avgGain / avgLoss;
|
|
31
|
+
result.push(100 - 100 / (1 + rs));
|
|
32
|
+
|
|
33
|
+
if (data.length > 100 && i % chunkSize === 0)
|
|
34
|
+
await yieldToEventLoop();
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
|
|
8
39
|
export function sma(data, period) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
40
|
+
const result = [];
|
|
41
|
+
for (let i = period - 1; i < data.length; i++) {
|
|
42
|
+
let sum = 0;
|
|
43
|
+
for (let j = 0; j < period; j++)
|
|
44
|
+
sum += data[i - j];
|
|
45
|
+
result.push(sum / period);
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
|
|
19
50
|
export function ema(data, period) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
51
|
+
const result = [];
|
|
52
|
+
const k = 2 / (period + 1);
|
|
53
|
+
const initialSma = data.slice(0, period).reduce((a, b) => a + b, 0) / period;
|
|
54
|
+
result.push(initialSma);
|
|
55
|
+
for (let i = period; i < data.length; i++) {
|
|
56
|
+
result.push(data[i] * k + result[result.length - 1] * (1 - k));
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
|
|
30
61
|
export function rsi(data, period = 14) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
62
|
+
const result = [];
|
|
63
|
+
const gains = [];
|
|
64
|
+
const losses = [];
|
|
65
|
+
for (let i = 1; i < data.length; i++) {
|
|
66
|
+
const diff = data[i] - data[i - 1];
|
|
67
|
+
gains.push(Math.max(0, diff));
|
|
68
|
+
losses.push(Math.max(0, -diff));
|
|
69
|
+
}
|
|
70
|
+
for (let i = period; i < gains.length; i++) {
|
|
71
|
+
let avgGain = 0, avgLoss = 0;
|
|
72
|
+
for (let j = 0; j < period; j++) {
|
|
73
|
+
avgGain += gains[i - j];
|
|
74
|
+
avgLoss += losses[i - j];
|
|
75
|
+
}
|
|
76
|
+
avgGain /= period;
|
|
77
|
+
avgLoss /= period;
|
|
78
|
+
if (avgLoss === 0) {
|
|
79
|
+
result.push(100);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const rs = avgGain / avgLoss;
|
|
83
|
+
result.push(100 - 100 / (1 + rs));
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
55
86
|
}
|
|
56
87
|
export function rsiSignal(rsiValues, currentPrice, prices) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
|
|
88
|
+
const last = rsiValues[rsiValues.length - 1];
|
|
89
|
+
let signal = "neutral";
|
|
90
|
+
if (last > 70)
|
|
91
|
+
signal = "bearish";
|
|
92
|
+
else if (last < 30)
|
|
93
|
+
signal = "bullish";
|
|
94
|
+
return {
|
|
95
|
+
indicator: "RSI",
|
|
96
|
+
value: parseFloat(last.toFixed(2)),
|
|
97
|
+
signal,
|
|
98
|
+
details: `RSI(14) = ${last.toFixed(2)}${last > 70 ? " — overbought" : last < 30 ? " — oversold" : " — neutral zone"}`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
71
102
|
export function macd(data, fast = 12, slow = 26, signalPeriod = 9) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
103
|
+
const fastEma = ema(data, fast);
|
|
104
|
+
const slowEma = ema(data, slow);
|
|
105
|
+
const macdLine = [];
|
|
106
|
+
|
|
107
|
+
const offset = slow - fast;
|
|
108
|
+
for (let i = 0; i < slowEma.length; i++) {
|
|
109
|
+
macdLine.push(fastEma[i + offset] - slowEma[i]);
|
|
110
|
+
}
|
|
111
|
+
const signal = ema(macdLine, signalPeriod);
|
|
112
|
+
|
|
113
|
+
const sigShift = signalPeriod - 1;
|
|
114
|
+
const histogram = [];
|
|
115
|
+
for (let i = 0; i < macdLine.length - sigShift; i++) {
|
|
116
|
+
histogram.push(macdLine[i + sigShift] - signal[i]);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const trimmed = macdLine.slice(sigShift);
|
|
120
|
+
return { macd: trimmed, signal, histogram };
|
|
90
121
|
}
|
|
91
122
|
export function macdSignal(macdData) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
|
|
123
|
+
const hist = macdData.histogram;
|
|
124
|
+
const last = hist[hist.length - 1] ?? 0;
|
|
125
|
+
const prev = hist[hist.length - 2] ?? 0;
|
|
126
|
+
let signal = "neutral";
|
|
127
|
+
if (last > 0 && prev <= 0)
|
|
128
|
+
signal = "bullish";
|
|
129
|
+
else if (last < 0 && prev >= 0)
|
|
130
|
+
signal = "bearish";
|
|
131
|
+
return {
|
|
132
|
+
indicator: "MACD",
|
|
133
|
+
value: parseFloat(last.toFixed(6)),
|
|
134
|
+
signal,
|
|
135
|
+
details: `MACD histogram: ${last.toFixed(6)}${signal !== "neutral" ? ` — ${signal} crossover` : ""}`,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
108
139
|
export function bollingerBands(data, period = 20, stdDev = 2) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
140
|
+
const middle = sma(data, period);
|
|
141
|
+
const upper = [];
|
|
142
|
+
const lower = [];
|
|
143
|
+
for (let i = 0; i < middle.length; i++) {
|
|
144
|
+
const start = i;
|
|
145
|
+
let sumSq = 0;
|
|
146
|
+
for (let j = 0; j < period; j++) {
|
|
147
|
+
const idx = start + j;
|
|
148
|
+
if (idx < data.length)
|
|
149
|
+
sumSq += (data[idx] - middle[i]) ** 2;
|
|
150
|
+
}
|
|
151
|
+
const std = Math.sqrt(sumSq / period);
|
|
152
|
+
upper.push(middle[i] + stdDev * std);
|
|
153
|
+
lower.push(middle[i] - stdDev * std);
|
|
154
|
+
}
|
|
155
|
+
return { upper, middle, lower };
|
|
125
156
|
}
|
|
126
157
|
export function bollingerSignal(bb, currentPrice) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
|
|
158
|
+
const lastUpper = bb.upper[bb.upper.length - 1];
|
|
159
|
+
const lastLower = bb.lower[bb.lower.length - 1];
|
|
160
|
+
const lastMid = bb.middle[bb.middle.length - 1];
|
|
161
|
+
let signal = "neutral";
|
|
162
|
+
if (currentPrice >= lastUpper)
|
|
163
|
+
signal = "bearish";
|
|
164
|
+
else if (currentPrice <= lastLower)
|
|
165
|
+
signal = "bullish";
|
|
166
|
+
return {
|
|
167
|
+
indicator: "Bollinger",
|
|
168
|
+
value: [parseFloat(lastUpper.toFixed(6)), parseFloat(lastMid.toFixed(6)), parseFloat(lastLower.toFixed(6))],
|
|
169
|
+
signal,
|
|
170
|
+
details: signal === "bearish" ? "Price at upper band — overextended" : signal === "bullish" ? "Price at lower band — oversold" : "Within bands",
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
143
174
|
export function atr(candles, period = 14) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export function fullAnalysis(candles) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
-
|
|
175
|
+
const trueRanges = [];
|
|
176
|
+
for (let i = 1; i < candles.length; i++) {
|
|
177
|
+
const high = candles[i].high;
|
|
178
|
+
const low = candles[i].low;
|
|
179
|
+
const prevClose = candles[i - 1].close;
|
|
180
|
+
trueRanges.push(Math.max(high - low, Math.abs(high - prevClose), Math.abs(low - prevClose)));
|
|
181
|
+
}
|
|
182
|
+
if (trueRanges.length < period)
|
|
183
|
+
return trueRanges.reduce((a, b) => a + b, 0) / Math.max(1, trueRanges.length);
|
|
184
|
+
return trueRanges.slice(-period).reduce((a, b) => a + b, 0) / period;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export async function fullAnalysis(candles) {
|
|
188
|
+
const closes = candles.map(c => c.close);
|
|
189
|
+
if (closes.length < 30)
|
|
190
|
+
return [];
|
|
191
|
+
const results = [];
|
|
192
|
+
|
|
193
|
+
const rsiValues = await rsiAsync(closes, 14);
|
|
194
|
+
results.push(rsiSignal(rsiValues, closes[closes.length - 1], closes));
|
|
195
|
+
results.push(macdSignal(macd(closes, 12, 26, 9)));
|
|
196
|
+
const bb = bollingerBands(closes, 20, 2);
|
|
197
|
+
results.push(bollingerSignal(bb, closes[closes.length - 1]));
|
|
198
|
+
const atrValue = atr(candles, 14);
|
|
199
|
+
results.push({
|
|
200
|
+
indicator: "ATR",
|
|
201
|
+
value: parseFloat(atrValue.toFixed(6)),
|
|
202
|
+
signal: "neutral",
|
|
203
|
+
details: `ATR(14) = ${atrValue.toFixed(6)}`,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
const bullish = results.filter(r => r.signal === "bullish").length;
|
|
207
|
+
const bearish = results.filter(r => r.signal === "bearish").length;
|
|
208
|
+
const overall = bullish > bearish ? "bullish" : bearish > bullish ? "bearish" : "neutral";
|
|
209
|
+
results.push({
|
|
210
|
+
indicator: "SUMMARY",
|
|
211
|
+
value: results.length,
|
|
212
|
+
signal: overall,
|
|
213
|
+
details: `${bullish} bullish, ${bearish} bearish, ${results.length - bullish - bearish} neutral — overall ${overall}`,
|
|
214
|
+
});
|
|
215
|
+
return results;
|
|
216
|
+
}
|
|
217
|
+
|
|
185
218
|
export const getCandlesParams = Type.Object({
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
219
|
+
symbol: Type.String({ description: "Trading pair symbol (e.g., BTCUSDT, SOLUSDT)" }),
|
|
220
|
+
interval: Type.Optional(Type.String({ description: "Candle interval: 1m, 5m, 15m, 1h, 4h, 1d", default: "1d" })),
|
|
221
|
+
limit: Type.Optional(Type.Number({ description: "Number of candles", default: 50 })),
|
|
189
222
|
});
|
|
190
223
|
export const analyzeTAParams = Type.Object({
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
224
|
+
prices: Type.Array(Type.Number({ description: "Closing prices" })),
|
|
225
|
+
highs: Type.Optional(Type.Array(Type.Number({ description: "High prices" }))),
|
|
226
|
+
lows: Type.Optional(Type.Array(Type.Number({ description: "Low prices" }))),
|
|
227
|
+
volumes: Type.Optional(Type.Array(Type.Number({ description: "Volumes" }))),
|
|
195
228
|
});
|
|
196
229
|
export async function getCandlesTool(_id, params) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
}
|
|
235
|
-
//# sourceMappingURL=TechnicalAnalysis.js.map
|
|
230
|
+
const symbol = params.symbol;
|
|
231
|
+
const interval = params.interval || "1d";
|
|
232
|
+
const limit = params.limit || 50;
|
|
233
|
+
try {
|
|
234
|
+
const response = await resilientFetch(`https://api.binance.com/api/v3/klines?symbol=${symbol}&interval=${interval}&limit=${limit}`, { timeout: 10_000, retries: 1 });
|
|
235
|
+
if (!response.ok) {
|
|
236
|
+
return { content: [{ type: "text", text: `Failed to fetch candles for ${symbol}: ${response.status}` }] };
|
|
237
|
+
}
|
|
238
|
+
const data = await response.json();
|
|
239
|
+
const candles = data.map(k => ({
|
|
240
|
+
timestamp: k[0],
|
|
241
|
+
open: parseFloat(k[1]),
|
|
242
|
+
high: parseFloat(k[2]),
|
|
243
|
+
low: parseFloat(k[3]),
|
|
244
|
+
close: parseFloat(k[4]),
|
|
245
|
+
volume: parseFloat(k[5]),
|
|
246
|
+
}));
|
|
247
|
+
const closes = candles.map(c => c.close);
|
|
248
|
+
const results = await fullAnalysis(candles);
|
|
249
|
+
const lines = [
|
|
250
|
+
`--- ${symbol} ${interval} candles (${candles.length}) ---`,
|
|
251
|
+
`Last: $${closes[closes.length - 1].toFixed(6)}`,
|
|
252
|
+
`Range: $${Math.min(...closes).toFixed(6)} - $${Math.max(...closes).toFixed(6)}`,
|
|
253
|
+
``,
|
|
254
|
+
...results.map(r => {
|
|
255
|
+
const icon = r.signal === "bullish" ? "🟢" : r.signal === "bearish" ? "🔴" : "⚪";
|
|
256
|
+
return `${icon} ${r.indicator}: ${JSON.stringify(typeof r.value === "number" ? r.value.toFixed(4) : r.value)} — ${r.details ?? ""}`;
|
|
257
|
+
}),
|
|
258
|
+
];
|
|
259
|
+
return {
|
|
260
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
261
|
+
details: { candles: candles.slice(-5), analysis: results },
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
catch (e) {
|
|
265
|
+
return { content: [{ type: "text", text: `Error fetching candles: ${e instanceof Error ? e.message : String(e)}` }], isError: true };
|
|
266
|
+
}
|
|
267
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #21: WebWorker for TechnicalAnalysis — offloads RSI/MACD/Bollinger from main thread.
|
|
3
|
+
* Falls back to synchronous computation if Workers aren't available.
|
|
4
|
+
*/
|
|
5
|
+
interface Candle {
|
|
6
|
+
timestamp: number;
|
|
7
|
+
open: number;
|
|
8
|
+
high: number;
|
|
9
|
+
low: number;
|
|
10
|
+
close: number;
|
|
11
|
+
volume: number;
|
|
12
|
+
}
|
|
13
|
+
declare function calcRSI(closes: number[], period?: number): number;
|
|
14
|
+
declare function calcMACD(closes: number[]): {
|
|
15
|
+
macd: number;
|
|
16
|
+
signal: number;
|
|
17
|
+
histogram: number;
|
|
18
|
+
};
|
|
19
|
+
declare function calcBollinger(closes: number[], period?: number): {
|
|
20
|
+
upper: number;
|
|
21
|
+
middle: number;
|
|
22
|
+
lower: number;
|
|
23
|
+
};
|
|
24
|
+
declare function calcATR(candles: Candle[], period?: number): number;
|
|
25
|
+
export { calcRSI, calcMACD, calcBollinger, calcATR };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
function calcRSI(closes, period = 14) {
|
|
4
|
+
if (closes.length < period + 1)
|
|
5
|
+
return 50;
|
|
6
|
+
let gains = 0, losses = 0;
|
|
7
|
+
for (let i = closes.length - period; i < closes.length; i++) {
|
|
8
|
+
const diff = closes[i] - closes[i - 1];
|
|
9
|
+
if (diff > 0)
|
|
10
|
+
gains += diff;
|
|
11
|
+
else
|
|
12
|
+
losses -= diff;
|
|
13
|
+
}
|
|
14
|
+
const avgGain = gains / period;
|
|
15
|
+
const avgLoss = losses / period;
|
|
16
|
+
if (avgLoss === 0)
|
|
17
|
+
return 100;
|
|
18
|
+
const rs = avgGain / avgLoss;
|
|
19
|
+
return 100 - (100 / (1 + rs));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function ema(data, period) {
|
|
23
|
+
const result = [];
|
|
24
|
+
const k = 2 / (period + 1);
|
|
25
|
+
result[0] = data[0];
|
|
26
|
+
for (let i = 1; i < data.length; i++) {
|
|
27
|
+
result[i] = data[i] * k + result[i - 1] * (1 - k);
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function calcMACD(closes) {
|
|
33
|
+
if (closes.length < 26)
|
|
34
|
+
return { macd: 0, signal: 0, histogram: 0 };
|
|
35
|
+
const ema12 = ema(closes, 12);
|
|
36
|
+
const ema26 = ema(closes, 26);
|
|
37
|
+
const macdLine = ema12.map((v, i) => v - ema26[i]);
|
|
38
|
+
const signalLine = ema(macdLine, 9);
|
|
39
|
+
const lastIdx = macdLine.length - 1;
|
|
40
|
+
return {
|
|
41
|
+
macd: macdLine[lastIdx],
|
|
42
|
+
signal: signalLine[lastIdx],
|
|
43
|
+
histogram: macdLine[lastIdx] - signalLine[lastIdx],
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function calcBollinger(closes, period = 20) {
|
|
48
|
+
if (closes.length < period) {
|
|
49
|
+
const avg = closes.reduce((a, b) => a + b, 0) / closes.length;
|
|
50
|
+
return { upper: avg * 1.02, middle: avg, lower: avg * 0.98 };
|
|
51
|
+
}
|
|
52
|
+
const slice = closes.slice(-period);
|
|
53
|
+
const mean = slice.reduce((a, b) => a + b, 0) / period;
|
|
54
|
+
const variance = slice.reduce((sum, v) => sum + (v - mean) ** 2, 0) / period;
|
|
55
|
+
const stdDev = Math.sqrt(variance);
|
|
56
|
+
return { upper: mean + 2 * stdDev, middle: mean, lower: mean - 2 * stdDev };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function calcATR(candles, period = 14) {
|
|
60
|
+
if (candles.length < period + 1)
|
|
61
|
+
return 0;
|
|
62
|
+
const trs = [];
|
|
63
|
+
for (let i = 1; i < candles.length; i++) {
|
|
64
|
+
const high = candles[i].high;
|
|
65
|
+
const low = candles[i].low;
|
|
66
|
+
const prevClose = candles[i - 1].close;
|
|
67
|
+
trs.push(Math.max(high - low, Math.abs(high - prevClose), Math.abs(low - prevClose)));
|
|
68
|
+
}
|
|
69
|
+
const recent = trs.slice(-period);
|
|
70
|
+
return recent.reduce((a, b) => a + b, 0) / period;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (typeof self !== 'undefined') {
|
|
74
|
+
self.onmessage = (e) => {
|
|
75
|
+
const { candles, id } = e.data;
|
|
76
|
+
const closes = candles.map((c) => c.close);
|
|
77
|
+
const rsi = calcRSI(closes);
|
|
78
|
+
const macd = calcMACD(closes);
|
|
79
|
+
const bollinger = calcBollinger(closes);
|
|
80
|
+
const atr = calcATR(candles);
|
|
81
|
+
const results = [
|
|
82
|
+
{ indicator: 'RSI', value: rsi, signal: rsi > 70 ? 'overbought' : rsi < 30 ? 'oversold' : 'neutral' },
|
|
83
|
+
{ indicator: 'MACD', value: [macd.macd, macd.signal, macd.histogram], signal: macd.histogram > 0 ? 'bullish' : 'bearish' },
|
|
84
|
+
{ indicator: 'Bollinger', value: [bollinger.upper, bollinger.middle, bollinger.lower], signal: closes[closes.length - 1] > bollinger.upper ? 'overbought' : closes[closes.length - 1] < bollinger.lower ? 'oversold' : 'neutral' },
|
|
85
|
+
{ indicator: 'ATR', value: atr, signal: 'neutral' },
|
|
86
|
+
{ indicator: 'SUMMARY', value: 0, signal: rsi > 50 && macd.histogram > 0 ? 'bullish' : rsi < 50 && macd.histogram < 0 ? 'bearish' : 'neutral' },
|
|
87
|
+
];
|
|
88
|
+
self.postMessage({ id, results });
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export { calcRSI, calcMACD, calcBollinger, calcATR };
|
|
@@ -21,4 +21,3 @@ export declare const launchCalendarParams: import("@sinclair/typebox").TObject<{
|
|
|
21
21
|
export declare function launchCalendarTool(_id: string, params: Record<string, unknown>): Promise<ToolResult>;
|
|
22
22
|
/** Get sidebar-ready summary */
|
|
23
23
|
export declare function getLaunchSummary(): string;
|
|
24
|
-
//# sourceMappingURL=TokenCalendar.d.ts.map
|