bitbank-lab-mcp 0.1.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.
Files changed (147) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +388 -0
  3. package/assets/lightweight-charts.standalone.js +7 -0
  4. package/bin/bitbank-lab-mcp.js +20 -0
  5. package/lib/cache.ts +70 -0
  6. package/lib/candle-utils.ts +48 -0
  7. package/lib/candle-validate.ts +434 -0
  8. package/lib/conversions.ts +25 -0
  9. package/lib/datetime.ts +157 -0
  10. package/lib/depth-analysis.ts +51 -0
  11. package/lib/error.ts +15 -0
  12. package/lib/formatter.ts +296 -0
  13. package/lib/get-depth.ts +111 -0
  14. package/lib/http.ts +132 -0
  15. package/lib/indicator-config.ts +39 -0
  16. package/lib/indicator_buffer.ts +41 -0
  17. package/lib/indicators.ts +579 -0
  18. package/lib/logger.ts +120 -0
  19. package/lib/ma-snapshot-utils.ts +277 -0
  20. package/lib/math.ts +89 -0
  21. package/lib/pattern-diagrams.ts +562 -0
  22. package/lib/result.ts +104 -0
  23. package/lib/validate.ts +154 -0
  24. package/lib/volatility.ts +132 -0
  25. package/package.json +79 -0
  26. package/src/env.ts +4 -0
  27. package/src/handlers/analyzeCandlePatternsHandler.ts +383 -0
  28. package/src/handlers/analyzeFibonacciHandler.ts +54 -0
  29. package/src/handlers/analyzeIndicatorsHandler.ts +682 -0
  30. package/src/handlers/analyzeMarketSignalHandler.ts +272 -0
  31. package/src/handlers/analyzeMyPortfolioHandler.ts +800 -0
  32. package/src/handlers/detectPatternsHandler.ts +77 -0
  33. package/src/handlers/detectPatternsViewsHandler.ts +518 -0
  34. package/src/handlers/getTickersJpyHandler.ts +145 -0
  35. package/src/handlers/getVolatilityMetricsHandler.ts +234 -0
  36. package/src/handlers/portfolio/calc.ts +549 -0
  37. package/src/handlers/portfolio/fetch.ts +318 -0
  38. package/src/handlers/portfolio/types.ts +170 -0
  39. package/src/handlers/renderChartSvgHandler.ts +69 -0
  40. package/src/handlers/runBacktestHandler.ts +70 -0
  41. package/src/http.ts +107 -0
  42. package/src/private/auth.ts +104 -0
  43. package/src/private/client.ts +298 -0
  44. package/src/private/config.ts +25 -0
  45. package/src/private/confirmation.ts +185 -0
  46. package/src/private/schemas.ts +866 -0
  47. package/src/prompts.ts +2296 -0
  48. package/src/resources/app-resources.ts +79 -0
  49. package/src/schema/analysis.ts +942 -0
  50. package/src/schema/backtest.ts +100 -0
  51. package/src/schema/base.ts +88 -0
  52. package/src/schema/candle-validate.ts +135 -0
  53. package/src/schema/chart.ts +399 -0
  54. package/src/schema/index.ts +11 -0
  55. package/src/schema/indicators.ts +125 -0
  56. package/src/schema/market-data.ts +298 -0
  57. package/src/schema/patterns.ts +382 -0
  58. package/src/schema/types.ts +97 -0
  59. package/src/schemas.d.ts +37 -0
  60. package/src/schemas.ts +7 -0
  61. package/src/server.ts +405 -0
  62. package/src/tool-definition.ts +44 -0
  63. package/src/tool-registry.ts +174 -0
  64. package/src/types/express-shim.d.ts +9 -0
  65. package/src/types/schemas.generated.d.ts +23 -0
  66. package/tools/analyze_bb_snapshot.ts +385 -0
  67. package/tools/analyze_candle_patterns.ts +810 -0
  68. package/tools/analyze_currency_strength.ts +273 -0
  69. package/tools/analyze_ema_snapshot.ts +183 -0
  70. package/tools/analyze_fibonacci.ts +530 -0
  71. package/tools/analyze_ichimoku_snapshot.ts +606 -0
  72. package/tools/analyze_indicators.ts +691 -0
  73. package/tools/analyze_market_signal.ts +665 -0
  74. package/tools/analyze_mtf_fibonacci.ts +273 -0
  75. package/tools/analyze_mtf_sma.ts +175 -0
  76. package/tools/analyze_sma_snapshot.ts +146 -0
  77. package/tools/analyze_stoch_snapshot.ts +276 -0
  78. package/tools/analyze_support_resistance.ts +817 -0
  79. package/tools/analyze_volume_profile.ts +546 -0
  80. package/tools/chart/ichimoku-cloud.ts +113 -0
  81. package/tools/chart/render-depth.ts +139 -0
  82. package/tools/chart/render-sub-panels.ts +208 -0
  83. package/tools/chart/svg-utils.ts +102 -0
  84. package/tools/detect_macd_cross.ts +691 -0
  85. package/tools/detect_patterns.ts +424 -0
  86. package/tools/detect_whale_events.ts +181 -0
  87. package/tools/get_candles.ts +487 -0
  88. package/tools/get_flow_metrics.ts +596 -0
  89. package/tools/get_orderbook.ts +540 -0
  90. package/tools/get_ticker.ts +132 -0
  91. package/tools/get_tickers_jpy.ts +240 -0
  92. package/tools/get_transactions.ts +209 -0
  93. package/tools/get_volatility_metrics.ts +302 -0
  94. package/tools/patterns/aftermath.ts +212 -0
  95. package/tools/patterns/config.ts +151 -0
  96. package/tools/patterns/detect_doubles.ts +650 -0
  97. package/tools/patterns/detect_hs.ts +635 -0
  98. package/tools/patterns/detect_pennants.ts +373 -0
  99. package/tools/patterns/detect_triangles.ts +820 -0
  100. package/tools/patterns/detect_triples.ts +633 -0
  101. package/tools/patterns/detect_wedges.ts +1072 -0
  102. package/tools/patterns/helpers.ts +517 -0
  103. package/tools/patterns/index.ts +40 -0
  104. package/tools/patterns/regression.ts +153 -0
  105. package/tools/patterns/smoothing.ts +168 -0
  106. package/tools/patterns/swing.ts +91 -0
  107. package/tools/patterns/types.ts +193 -0
  108. package/tools/prepare_chart_data.ts +294 -0
  109. package/tools/prepare_depth_data.ts +189 -0
  110. package/tools/private/analyze_my_portfolio.ts +21 -0
  111. package/tools/private/cancel_order.ts +127 -0
  112. package/tools/private/cancel_orders.ts +121 -0
  113. package/tools/private/create_order.ts +236 -0
  114. package/tools/private/get_margin_positions.ts +134 -0
  115. package/tools/private/get_margin_status.ts +155 -0
  116. package/tools/private/get_margin_trade_history.ts +156 -0
  117. package/tools/private/get_my_assets.ts +207 -0
  118. package/tools/private/get_my_deposit_withdrawal.ts +500 -0
  119. package/tools/private/get_my_orders.ts +157 -0
  120. package/tools/private/get_my_trade_history.ts +229 -0
  121. package/tools/private/get_order.ts +95 -0
  122. package/tools/private/get_orders_info.ts +90 -0
  123. package/tools/private/preview_cancel_order.ts +172 -0
  124. package/tools/private/preview_cancel_orders.ts +137 -0
  125. package/tools/private/preview_order.ts +292 -0
  126. package/tools/render_candle_pattern_diagram.ts +389 -0
  127. package/tools/render_chart_svg.ts +799 -0
  128. package/tools/render_depth_svg.ts +274 -0
  129. package/tools/trading_process/index.ts +7 -0
  130. package/tools/trading_process/lib/backtest_engine.ts +252 -0
  131. package/tools/trading_process/lib/equity.ts +131 -0
  132. package/tools/trading_process/lib/fetch_candles.ts +181 -0
  133. package/tools/trading_process/lib/sma.ts +62 -0
  134. package/tools/trading_process/lib/strategies/bb_breakout.ts +141 -0
  135. package/tools/trading_process/lib/strategies/index.ts +52 -0
  136. package/tools/trading_process/lib/strategies/macd_cross.ts +256 -0
  137. package/tools/trading_process/lib/strategies/rsi.ts +133 -0
  138. package/tools/trading_process/lib/strategies/sma_cross.ts +214 -0
  139. package/tools/trading_process/lib/strategies/types.ts +118 -0
  140. package/tools/trading_process/lib/svg_to_png.ts +64 -0
  141. package/tools/trading_process/render_backtest_chart_generic.ts +729 -0
  142. package/tools/trading_process/run_backtest.ts +243 -0
  143. package/tools/trading_process/types.ts +85 -0
  144. package/tools/validate_candle_data.ts +260 -0
  145. package/tsconfig.json +17 -0
  146. package/ui/cancel-confirm/dist/cancel-confirm.html +99 -0
  147. package/ui/order-confirm/dist/order-confirm.html +99 -0
@@ -0,0 +1,276 @@
1
+ import type { z } from 'zod';
2
+ import { today } from '../lib/datetime.js';
3
+ import { formatSummary } from '../lib/formatter.js';
4
+ import { fail, failFromError, failFromValidation, ok } from '../lib/result.js';
5
+ import { createMeta, ensurePair } from '../lib/validate.js';
6
+ import {
7
+ type AnalyzeStochSnapshotDataSchemaOut,
8
+ AnalyzeStochSnapshotInputSchema,
9
+ AnalyzeStochSnapshotOutputSchema,
10
+ } from '../src/schemas.js';
11
+ import type { ToolDefinition } from '../src/tool-definition.js';
12
+ import analyzeIndicators, { computeClassicStochastic } from './analyze_indicators.js';
13
+ import getCandles from './get_candles.js';
14
+
15
+ const DEFAULT_K_PERIOD = 14;
16
+ const DEFAULT_SMOOTH_K = 3;
17
+ const DEFAULT_SMOOTH_D = 3;
18
+
19
+ export interface BuildStochSnapshotTextInput {
20
+ baseSummary: string;
21
+ kStr: string;
22
+ dStr: string;
23
+ zoneJp: string;
24
+ kPeriod: number;
25
+ smoothK: number;
26
+ smoothD: number;
27
+ crossDesc: string;
28
+ divType: 'bullish' | 'bearish' | 'none';
29
+ divDesc: string;
30
+ recentCrosses: Array<{
31
+ type: 'bullish_cross' | 'bearish_cross';
32
+ barsAgo: number;
33
+ date: string;
34
+ zone: 'overbought' | 'oversold' | 'neutral';
35
+ }>;
36
+ }
37
+
38
+ /** テキスト組み立て(Stochスナップショット)— テスト可能な純粋関数 */
39
+ export function buildStochSnapshotText(input: BuildStochSnapshotTextInput): string {
40
+ const { baseSummary, kStr, dStr, zoneJp, kPeriod, smoothK, smoothD, crossDesc, divType, divDesc, recentCrosses } =
41
+ input;
42
+ const recentLines = recentCrosses
43
+ .slice(-5)
44
+ .reverse()
45
+ .map((rc) => {
46
+ const zJp =
47
+ rc.zone === 'overbought' ? '買われすぎ圏' : rc.zone === 'oversold' ? '売られすぎ圏' : 'ニュートラル圏';
48
+ return `${rc.type === 'bullish_cross' ? '↑' : '↓'} ${rc.type} - ${rc.barsAgo} bars ago (${rc.date}) [${zJp}]`;
49
+ });
50
+ return [
51
+ baseSummary,
52
+ '',
53
+ `%K: ${kStr}`,
54
+ `%D: ${dStr}`,
55
+ `ゾーン: ${zoneJp}`,
56
+ `パラメータ: (${kPeriod}, ${smoothK}, ${smoothD})`,
57
+ '',
58
+ `クロス: ${crossDesc}`,
59
+ ...(divType !== 'none' ? [`ダイバージェンス: ${divDesc}`] : []),
60
+ ...(recentLines.length ? ['', 'Recent Crosses:', ...recentLines] : []),
61
+ '',
62
+ '---',
63
+ '📌 含まれるもの: %K・%D の値、ゾーン判定、クロスオーバー、ダイバージェンス',
64
+ '📌 含まれないもの: RSI・SMA・EMA・MACD・BB・一目均衡表、出来高フロー',
65
+ '📌 補完ツール: analyze_indicators(他指標), analyze_rsi_snapshot(RSI), analyze_ema_snapshot(EMA)',
66
+ ]
67
+ .filter(Boolean)
68
+ .join('\n');
69
+ }
70
+
71
+ function zoneOf(k: number | null): 'overbought' | 'oversold' | 'neutral' {
72
+ if (k == null) return 'neutral';
73
+ if (k >= 80) return 'overbought';
74
+ if (k <= 20) return 'oversold';
75
+ return 'neutral';
76
+ }
77
+
78
+ export default async function analyzeStochSnapshot(
79
+ pair: string = 'btc_jpy',
80
+ type: string = '1day',
81
+ limit: number = 120,
82
+ kPeriod: number = DEFAULT_K_PERIOD,
83
+ smoothK: number = DEFAULT_SMOOTH_K,
84
+ smoothD: number = DEFAULT_SMOOTH_D,
85
+ ) {
86
+ const chk = ensurePair(pair);
87
+ if (!chk.ok) return failFromValidation(chk, AnalyzeStochSnapshotOutputSchema);
88
+ try {
89
+ const isDefault = kPeriod === DEFAULT_K_PERIOD && smoothK === DEFAULT_SMOOTH_K && smoothD === DEFAULT_SMOOTH_D;
90
+
91
+ let close: number | null = null;
92
+ let kSeries: (number | null)[] = [];
93
+ let dSeries: (number | null)[] = [];
94
+ let stochK: number | null = null;
95
+ let stochD: number | null = null;
96
+ let prevK: number | null = null;
97
+ let prevD: number | null = null;
98
+ let candles: Array<{ isoTime?: string | null; close: number }> = [];
99
+ let normalizedLen = 0;
100
+
101
+ if (isDefault) {
102
+ const indRes = await analyzeIndicators(chk.pair, type, limit);
103
+ if (!indRes.ok)
104
+ return AnalyzeStochSnapshotOutputSchema.parse(
105
+ fail(indRes.summary || 'indicators failed', indRes.meta.errorType || 'internal'),
106
+ );
107
+ const ind = indRes.data.indicators;
108
+ close = indRes.data.normalized.at(-1)?.close ?? null;
109
+ stochK = ind.STOCH_K ?? null;
110
+ stochD = ind.STOCH_D ?? null;
111
+ prevK = ind.STOCH_prevK ?? null;
112
+ prevD = ind.STOCH_prevD ?? null;
113
+ kSeries = Array.isArray(ind.stoch_k_series) ? ind.stoch_k_series : [];
114
+ dSeries = Array.isArray(ind.stoch_d_series) ? ind.stoch_d_series : [];
115
+ candles = Array.isArray(indRes?.data?.chart?.candles)
116
+ ? indRes.data.chart.candles
117
+ : Array.isArray(indRes?.data?.normalized)
118
+ ? indRes.data.normalized
119
+ : [];
120
+ normalizedLen = indRes.data.normalized.length;
121
+ } else {
122
+ const candlesResult = await getCandles(chk.pair, type, undefined, limit);
123
+ if (!candlesResult.ok)
124
+ return AnalyzeStochSnapshotOutputSchema.parse(
125
+ fail(candlesResult.summary || 'candles failed', candlesResult.meta.errorType || 'internal'),
126
+ );
127
+ const normalized = candlesResult.data.normalized;
128
+ const highs = normalized.map((c) => c.high);
129
+ const lows = normalized.map((c) => c.low);
130
+ const closes = normalized.map((c) => c.close);
131
+ close = closes.at(-1) ?? null;
132
+ candles = normalized;
133
+ normalizedLen = normalized.length;
134
+ const result = computeClassicStochastic(highs, lows, closes, kPeriod, smoothK, smoothD);
135
+ stochK = result.k;
136
+ stochD = result.d;
137
+ prevK = result.prevK;
138
+ prevD = result.prevD;
139
+ kSeries = result.kSeries;
140
+ dSeries = result.dSeries;
141
+ }
142
+
143
+ const zone = zoneOf(stochK);
144
+
145
+ let crossType: 'bullish_cross' | 'bearish_cross' | 'none' = 'none';
146
+ let crossDesc = 'クロスなし';
147
+ if (stochK != null && stochD != null && prevK != null && prevD != null) {
148
+ const prevDiff = prevK - prevD;
149
+ const currDiff = stochK - stochD;
150
+ const zoneLabel =
151
+ zone === 'overbought' ? '買われすぎ圏' : zone === 'oversold' ? '売られすぎ圏' : 'ニュートラル圏';
152
+ if (prevDiff <= 0 && currDiff > 0) {
153
+ crossType = 'bullish_cross';
154
+ crossDesc = `%K が %D を上抜け(${zone === 'oversold' ? '売られすぎ圏からの反転 → 強いシグナル' : zoneLabel})`;
155
+ } else if (prevDiff >= 0 && currDiff < 0) {
156
+ crossType = 'bearish_cross';
157
+ crossDesc = `%K が %D を下抜け(${zone === 'overbought' ? '買われすぎ圏からの反転 → 強いシグナル' : zoneLabel})`;
158
+ }
159
+ }
160
+
161
+ const lookback = 30;
162
+ type RecentCross = {
163
+ type: 'bullish_cross' | 'bearish_cross';
164
+ barsAgo: number;
165
+ date: string;
166
+ zone: 'overbought' | 'oversold' | 'neutral';
167
+ };
168
+ const recentCrosses: RecentCross[] = [];
169
+ const n = Math.min(kSeries.length, dSeries.length, candles.length);
170
+ if (n >= 2) {
171
+ const start = Math.max(1, n - lookback);
172
+ for (let i = start; i < n; i++) {
173
+ const pK = kSeries[i - 1];
174
+ const pD = dSeries[i - 1];
175
+ const cK = kSeries[i];
176
+ const cD = dSeries[i];
177
+ if (pK == null || pD == null || cK == null || cD == null) continue;
178
+ const prev = pK - pD;
179
+ const curr = cK - cD;
180
+ if ((prev <= 0 && curr > 0) || (prev >= 0 && curr < 0)) {
181
+ const ct = curr > 0 ? 'bullish_cross' : 'bearish_cross';
182
+ const barsAgo = n - 1 - i;
183
+ const date = String(candles[i]?.isoTime || '').slice(0, 10) || today('YYYY-MM-DD');
184
+ recentCrosses.push({ type: ct, barsAgo, date, zone: zoneOf(cK) });
185
+ }
186
+ }
187
+ }
188
+
189
+ let divType: 'bullish' | 'bearish' | 'none' = 'none';
190
+ let divDesc = 'ダイバージェンスなし';
191
+ const divWindow = 14;
192
+ if (n >= divWindow && close != null) {
193
+ const recentCloses = candles.slice(-divWindow).map((c) => c.close);
194
+ const recentK = kSeries.slice(-divWindow).filter((v): v is number => v != null);
195
+ if (recentCloses.length >= 2 && recentK.length >= 2) {
196
+ const priceSlope = recentCloses[recentCloses.length - 1] - recentCloses[0];
197
+ const kSlope = recentK[recentK.length - 1] - recentK[0];
198
+ if (priceSlope > 0 && kSlope < -5) {
199
+ divType = 'bearish';
200
+ divDesc = '価格は上昇しているが %K は下降 → 上昇勢力の弱まりを示唆';
201
+ } else if (priceSlope < 0 && kSlope > 5) {
202
+ divType = 'bullish';
203
+ divDesc = '価格は下降しているが %K は上昇 → 下降勢力の弱まりを示唆';
204
+ }
205
+ }
206
+ }
207
+
208
+ const tags: string[] = [];
209
+ if (zone === 'overbought') tags.push('stoch_overbought');
210
+ if (zone === 'oversold') tags.push('stoch_oversold');
211
+ if (crossType === 'bullish_cross') tags.push('stoch_bullish_cross');
212
+ if (crossType === 'bearish_cross') tags.push('stoch_bearish_cross');
213
+ if (crossType === 'bullish_cross' && zone === 'oversold') tags.push('stoch_strong_buy');
214
+ if (crossType === 'bearish_cross' && zone === 'overbought') tags.push('stoch_strong_sell');
215
+ if (divType === 'bullish') tags.push('stoch_bullish_divergence');
216
+ if (divType === 'bearish') tags.push('stoch_bearish_divergence');
217
+
218
+ const kStr = stochK != null ? stochK.toFixed(2) : 'n/a';
219
+ const dStr = stochD != null ? stochD.toFixed(2) : 'n/a';
220
+ const zoneJp =
221
+ zone === 'overbought' ? '買われすぎ (>80)' : zone === 'oversold' ? '売られすぎ (<20)' : 'ニュートラル';
222
+ const summaryText = buildStochSnapshotText({
223
+ baseSummary: formatSummary({
224
+ pair: chk.pair,
225
+ latest: close ?? undefined,
226
+ extra: `Stoch(%K/${kStr}, %D/${dStr}) zone=${zone}`,
227
+ }),
228
+ kStr,
229
+ dStr,
230
+ zoneJp,
231
+ kPeriod,
232
+ smoothK,
233
+ smoothD,
234
+ crossDesc,
235
+ divType,
236
+ divDesc,
237
+ recentCrosses,
238
+ });
239
+
240
+ const data: z.infer<typeof AnalyzeStochSnapshotDataSchemaOut> = {
241
+ latest: { close },
242
+ stoch: { k: stochK, d: stochD, prevK, prevD },
243
+ zone,
244
+ crossover: { type: crossType, description: crossDesc },
245
+ recentCrosses,
246
+ divergence: { type: divType, description: divDesc },
247
+ tags,
248
+ };
249
+ const meta = createMeta(chk.pair, { type, count: normalizedLen, params: { kPeriod, smoothK, smoothD } });
250
+ return AnalyzeStochSnapshotOutputSchema.parse(ok(summaryText, data, meta));
251
+ } catch (e: unknown) {
252
+ return failFromError(e, { schema: AnalyzeStochSnapshotOutputSchema });
253
+ }
254
+ }
255
+
256
+ export const toolDef: ToolDefinition = {
257
+ name: 'analyze_stoch_snapshot',
258
+ description:
259
+ '[Stochastic / Overbought / Oversold] Stochastic(stochastic / %K / %D / overbought / oversold / divergence)の最新状態。ゾーン・クロス・ダイバージェンスを判定。\n\n⚠️ 最新値のみ。時系列チャート描画 → prepare_chart_data(indicators: ["STOCH"])。',
260
+ inputSchema: AnalyzeStochSnapshotInputSchema,
261
+ handler: async ({
262
+ pair,
263
+ type,
264
+ limit,
265
+ kPeriod,
266
+ smoothK,
267
+ smoothD,
268
+ }: {
269
+ pair?: string;
270
+ type?: string;
271
+ limit?: number;
272
+ kPeriod?: number;
273
+ smoothK?: number;
274
+ smoothD?: number;
275
+ }) => analyzeStochSnapshot(pair, type, limit, kPeriod, smoothK, smoothD),
276
+ };