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.
- package/LICENSE +21 -0
- package/README.md +388 -0
- package/assets/lightweight-charts.standalone.js +7 -0
- package/bin/bitbank-lab-mcp.js +20 -0
- package/lib/cache.ts +70 -0
- package/lib/candle-utils.ts +48 -0
- package/lib/candle-validate.ts +434 -0
- package/lib/conversions.ts +25 -0
- package/lib/datetime.ts +157 -0
- package/lib/depth-analysis.ts +51 -0
- package/lib/error.ts +15 -0
- package/lib/formatter.ts +296 -0
- package/lib/get-depth.ts +111 -0
- package/lib/http.ts +132 -0
- package/lib/indicator-config.ts +39 -0
- package/lib/indicator_buffer.ts +41 -0
- package/lib/indicators.ts +579 -0
- package/lib/logger.ts +120 -0
- package/lib/ma-snapshot-utils.ts +277 -0
- package/lib/math.ts +89 -0
- package/lib/pattern-diagrams.ts +562 -0
- package/lib/result.ts +104 -0
- package/lib/validate.ts +154 -0
- package/lib/volatility.ts +132 -0
- package/package.json +79 -0
- package/src/env.ts +4 -0
- package/src/handlers/analyzeCandlePatternsHandler.ts +383 -0
- package/src/handlers/analyzeFibonacciHandler.ts +54 -0
- package/src/handlers/analyzeIndicatorsHandler.ts +682 -0
- package/src/handlers/analyzeMarketSignalHandler.ts +272 -0
- package/src/handlers/analyzeMyPortfolioHandler.ts +800 -0
- package/src/handlers/detectPatternsHandler.ts +77 -0
- package/src/handlers/detectPatternsViewsHandler.ts +518 -0
- package/src/handlers/getTickersJpyHandler.ts +145 -0
- package/src/handlers/getVolatilityMetricsHandler.ts +234 -0
- package/src/handlers/portfolio/calc.ts +549 -0
- package/src/handlers/portfolio/fetch.ts +318 -0
- package/src/handlers/portfolio/types.ts +170 -0
- package/src/handlers/renderChartSvgHandler.ts +69 -0
- package/src/handlers/runBacktestHandler.ts +70 -0
- package/src/http.ts +107 -0
- package/src/private/auth.ts +104 -0
- package/src/private/client.ts +298 -0
- package/src/private/config.ts +25 -0
- package/src/private/confirmation.ts +185 -0
- package/src/private/schemas.ts +866 -0
- package/src/prompts.ts +2296 -0
- package/src/resources/app-resources.ts +79 -0
- package/src/schema/analysis.ts +942 -0
- package/src/schema/backtest.ts +100 -0
- package/src/schema/base.ts +88 -0
- package/src/schema/candle-validate.ts +135 -0
- package/src/schema/chart.ts +399 -0
- package/src/schema/index.ts +11 -0
- package/src/schema/indicators.ts +125 -0
- package/src/schema/market-data.ts +298 -0
- package/src/schema/patterns.ts +382 -0
- package/src/schema/types.ts +97 -0
- package/src/schemas.d.ts +37 -0
- package/src/schemas.ts +7 -0
- package/src/server.ts +405 -0
- package/src/tool-definition.ts +44 -0
- package/src/tool-registry.ts +174 -0
- package/src/types/express-shim.d.ts +9 -0
- package/src/types/schemas.generated.d.ts +23 -0
- package/tools/analyze_bb_snapshot.ts +385 -0
- package/tools/analyze_candle_patterns.ts +810 -0
- package/tools/analyze_currency_strength.ts +273 -0
- package/tools/analyze_ema_snapshot.ts +183 -0
- package/tools/analyze_fibonacci.ts +530 -0
- package/tools/analyze_ichimoku_snapshot.ts +606 -0
- package/tools/analyze_indicators.ts +691 -0
- package/tools/analyze_market_signal.ts +665 -0
- package/tools/analyze_mtf_fibonacci.ts +273 -0
- package/tools/analyze_mtf_sma.ts +175 -0
- package/tools/analyze_sma_snapshot.ts +146 -0
- package/tools/analyze_stoch_snapshot.ts +276 -0
- package/tools/analyze_support_resistance.ts +817 -0
- package/tools/analyze_volume_profile.ts +546 -0
- package/tools/chart/ichimoku-cloud.ts +113 -0
- package/tools/chart/render-depth.ts +139 -0
- package/tools/chart/render-sub-panels.ts +208 -0
- package/tools/chart/svg-utils.ts +102 -0
- package/tools/detect_macd_cross.ts +691 -0
- package/tools/detect_patterns.ts +424 -0
- package/tools/detect_whale_events.ts +181 -0
- package/tools/get_candles.ts +487 -0
- package/tools/get_flow_metrics.ts +596 -0
- package/tools/get_orderbook.ts +540 -0
- package/tools/get_ticker.ts +132 -0
- package/tools/get_tickers_jpy.ts +240 -0
- package/tools/get_transactions.ts +209 -0
- package/tools/get_volatility_metrics.ts +302 -0
- package/tools/patterns/aftermath.ts +212 -0
- package/tools/patterns/config.ts +151 -0
- package/tools/patterns/detect_doubles.ts +650 -0
- package/tools/patterns/detect_hs.ts +635 -0
- package/tools/patterns/detect_pennants.ts +373 -0
- package/tools/patterns/detect_triangles.ts +820 -0
- package/tools/patterns/detect_triples.ts +633 -0
- package/tools/patterns/detect_wedges.ts +1072 -0
- package/tools/patterns/helpers.ts +517 -0
- package/tools/patterns/index.ts +40 -0
- package/tools/patterns/regression.ts +153 -0
- package/tools/patterns/smoothing.ts +168 -0
- package/tools/patterns/swing.ts +91 -0
- package/tools/patterns/types.ts +193 -0
- package/tools/prepare_chart_data.ts +294 -0
- package/tools/prepare_depth_data.ts +189 -0
- package/tools/private/analyze_my_portfolio.ts +21 -0
- package/tools/private/cancel_order.ts +127 -0
- package/tools/private/cancel_orders.ts +121 -0
- package/tools/private/create_order.ts +236 -0
- package/tools/private/get_margin_positions.ts +134 -0
- package/tools/private/get_margin_status.ts +155 -0
- package/tools/private/get_margin_trade_history.ts +156 -0
- package/tools/private/get_my_assets.ts +207 -0
- package/tools/private/get_my_deposit_withdrawal.ts +500 -0
- package/tools/private/get_my_orders.ts +157 -0
- package/tools/private/get_my_trade_history.ts +229 -0
- package/tools/private/get_order.ts +95 -0
- package/tools/private/get_orders_info.ts +90 -0
- package/tools/private/preview_cancel_order.ts +172 -0
- package/tools/private/preview_cancel_orders.ts +137 -0
- package/tools/private/preview_order.ts +292 -0
- package/tools/render_candle_pattern_diagram.ts +389 -0
- package/tools/render_chart_svg.ts +799 -0
- package/tools/render_depth_svg.ts +274 -0
- package/tools/trading_process/index.ts +7 -0
- package/tools/trading_process/lib/backtest_engine.ts +252 -0
- package/tools/trading_process/lib/equity.ts +131 -0
- package/tools/trading_process/lib/fetch_candles.ts +181 -0
- package/tools/trading_process/lib/sma.ts +62 -0
- package/tools/trading_process/lib/strategies/bb_breakout.ts +141 -0
- package/tools/trading_process/lib/strategies/index.ts +52 -0
- package/tools/trading_process/lib/strategies/macd_cross.ts +256 -0
- package/tools/trading_process/lib/strategies/rsi.ts +133 -0
- package/tools/trading_process/lib/strategies/sma_cross.ts +214 -0
- package/tools/trading_process/lib/strategies/types.ts +118 -0
- package/tools/trading_process/lib/svg_to_png.ts +64 -0
- package/tools/trading_process/render_backtest_chart_generic.ts +729 -0
- package/tools/trading_process/run_backtest.ts +243 -0
- package/tools/trading_process/types.ts +85 -0
- package/tools/validate_candle_data.ts +260 -0
- package/tsconfig.json +17 -0
- package/ui/cancel-confirm/dist/cancel-confirm.html +99 -0
- package/ui/order-confirm/dist/order-confirm.html +99 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* patterns/smoothing.ts - 価格データのノイズ除去フィルタ
|
|
3
|
+
*
|
|
4
|
+
* Savitzky-Golay フィルタを実装。
|
|
5
|
+
* TradingPatternScanner (white07S) のアプローチを参考に、
|
|
6
|
+
* ピボット検出前にhigh/lowデータを平滑化し、誤ピボットを削減する。
|
|
7
|
+
*
|
|
8
|
+
* 参考:
|
|
9
|
+
* - savgol_filter(series, window_length, polyorder=2)
|
|
10
|
+
* - ウェーブレット系は依存ライブラリが重いため SG に絞る
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Savitzky-Golay フィルタの畳み込み係数を計算する。
|
|
15
|
+
*
|
|
16
|
+
* 最小二乗多項式フィッティングに基づくFIRフィルタ。
|
|
17
|
+
* scipy.signal.savgol_filter と同等のロジック。
|
|
18
|
+
*
|
|
19
|
+
* @param windowSize - ウィンドウ幅(奇数)
|
|
20
|
+
* @param polyOrder - 多項式の次数(windowSize > polyOrder)
|
|
21
|
+
* @returns 畳み込み係数の配列(長さ = windowSize)
|
|
22
|
+
*/
|
|
23
|
+
function savgolCoefficients(windowSize: number, polyOrder: number): number[] {
|
|
24
|
+
const m = Math.floor(windowSize / 2);
|
|
25
|
+
const order = polyOrder;
|
|
26
|
+
|
|
27
|
+
// Vandermonde行列 J を構築 (windowSize × (order+1))
|
|
28
|
+
// J[i][j] = (i - m)^j (i = 0..windowSize-1, j = 0..order)
|
|
29
|
+
const rows = windowSize;
|
|
30
|
+
const cols = order + 1;
|
|
31
|
+
|
|
32
|
+
// J^T * J を計算(cols × cols の正規方程式行列)
|
|
33
|
+
const JtJ: number[][] = Array.from({ length: cols }, () => Array.from<number>({ length: cols }).fill(0));
|
|
34
|
+
for (let j1 = 0; j1 < cols; j1++) {
|
|
35
|
+
for (let j2 = j1; j2 < cols; j2++) {
|
|
36
|
+
let sum = 0;
|
|
37
|
+
for (let i = 0; i < rows; i++) {
|
|
38
|
+
const x = i - m;
|
|
39
|
+
sum += x ** j1 * x ** j2;
|
|
40
|
+
}
|
|
41
|
+
JtJ[j1][j2] = sum;
|
|
42
|
+
JtJ[j2][j1] = sum;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// (J^T * J)^{-1} を Gauss-Jordan 法で求める
|
|
47
|
+
const aug: number[][] = JtJ.map((row, i) => {
|
|
48
|
+
const extended = Array.from<number>({ length: 2 * cols }).fill(0);
|
|
49
|
+
for (let j = 0; j < cols; j++) extended[j] = row[j];
|
|
50
|
+
extended[cols + i] = 1;
|
|
51
|
+
return extended;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
for (let col = 0; col < cols; col++) {
|
|
55
|
+
// ピボット選択
|
|
56
|
+
let maxRow = col;
|
|
57
|
+
let maxVal = Math.abs(aug[col][col]);
|
|
58
|
+
for (let row = col + 1; row < cols; row++) {
|
|
59
|
+
if (Math.abs(aug[row][col]) > maxVal) {
|
|
60
|
+
maxVal = Math.abs(aug[row][col]);
|
|
61
|
+
maxRow = row;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (maxRow !== col) {
|
|
65
|
+
[aug[col], aug[maxRow]] = [aug[maxRow], aug[col]];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const pivot = aug[col][col];
|
|
69
|
+
if (Math.abs(pivot) < 1e-15) continue;
|
|
70
|
+
|
|
71
|
+
for (let j = 0; j < 2 * cols; j++) aug[col][j] /= pivot;
|
|
72
|
+
|
|
73
|
+
for (let row = 0; row < cols; row++) {
|
|
74
|
+
if (row === col) continue;
|
|
75
|
+
const factor = aug[row][col];
|
|
76
|
+
for (let j = 0; j < 2 * cols; j++) {
|
|
77
|
+
aug[row][j] -= factor * aug[col][j];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 逆行列を抽出
|
|
83
|
+
const inv: number[][] = aug.map((row) => row.slice(cols));
|
|
84
|
+
|
|
85
|
+
// 係数 = (J^T J)^{-1} J^T の第0行(平滑化=0次の係数)
|
|
86
|
+
// c[i] = sum_j inv[0][j] * (i - m)^j
|
|
87
|
+
const coeffs = Array.from<number>({ length: windowSize }).fill(0);
|
|
88
|
+
for (let i = 0; i < windowSize; i++) {
|
|
89
|
+
const x = i - m;
|
|
90
|
+
let val = 0;
|
|
91
|
+
for (let j = 0; j < cols; j++) {
|
|
92
|
+
val += inv[0][j] * x ** j;
|
|
93
|
+
}
|
|
94
|
+
coeffs[i] = val;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return coeffs;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Savitzky-Golay フィルタを1次元配列に適用する。
|
|
102
|
+
*
|
|
103
|
+
* @param data - 入力データ
|
|
104
|
+
* @param windowSize - ウィンドウ幅(奇数, デフォルト 5)
|
|
105
|
+
* @param polyOrder - 多項式次数(デフォルト 2 = 2次多項式)
|
|
106
|
+
* @returns 平滑化されたデータ(元と同じ長さ)
|
|
107
|
+
*/
|
|
108
|
+
export function savgolFilter(data: number[], windowSize: number = 5, polyOrder: number = 2): number[] {
|
|
109
|
+
const n = data.length;
|
|
110
|
+
if (n === 0) return [];
|
|
111
|
+
|
|
112
|
+
// ウィンドウサイズを奇数に強制
|
|
113
|
+
let ws = Math.max(3, windowSize);
|
|
114
|
+
if (ws % 2 === 0) ws += 1;
|
|
115
|
+
// polyOrder < windowSize を保証
|
|
116
|
+
const po = Math.min(polyOrder, ws - 1);
|
|
117
|
+
|
|
118
|
+
if (n < ws) {
|
|
119
|
+
// データがウィンドウより短い場合はそのまま返す
|
|
120
|
+
return [...data];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const coeffs = savgolCoefficients(ws, po);
|
|
124
|
+
const half = Math.floor(ws / 2);
|
|
125
|
+
const result = Array.from<number>({ length: n });
|
|
126
|
+
|
|
127
|
+
// 中央部分: 畳み込み
|
|
128
|
+
for (let i = half; i < n - half; i++) {
|
|
129
|
+
let sum = 0;
|
|
130
|
+
for (let j = 0; j < ws; j++) {
|
|
131
|
+
sum += coeffs[j] * data[i - half + j];
|
|
132
|
+
}
|
|
133
|
+
result[i] = sum;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// 端の処理: 元データをそのまま使用(境界効果の回避)
|
|
137
|
+
for (let i = 0; i < half; i++) {
|
|
138
|
+
result[i] = data[i];
|
|
139
|
+
}
|
|
140
|
+
for (let i = n - half; i < n; i++) {
|
|
141
|
+
result[i] = data[i];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return result;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* ローソク足の high/low 系列にSGフィルタを適用する。
|
|
149
|
+
* 元のローソク足データは変更せず、平滑化された high/low 配列を返す。
|
|
150
|
+
*
|
|
151
|
+
* @param candles - ローソク足データ
|
|
152
|
+
* @param windowSize - SGフィルタのウィンドウ幅(奇数)
|
|
153
|
+
* @param polyOrder - 多項式次数
|
|
154
|
+
* @returns { smoothHigh, smoothLow } 平滑化されたhigh/low配列
|
|
155
|
+
*/
|
|
156
|
+
export function smoothCandleExtremes(
|
|
157
|
+
candles: Array<{ high: number; low: number }>,
|
|
158
|
+
windowSize: number = 5,
|
|
159
|
+
polyOrder: number = 2,
|
|
160
|
+
): { smoothHigh: number[]; smoothLow: number[] } {
|
|
161
|
+
const highs = candles.map((c) => c.high);
|
|
162
|
+
const lows = candles.map((c) => c.low);
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
smoothHigh: savgolFilter(highs, windowSize, polyOrder),
|
|
166
|
+
smoothLow: savgolFilter(lows, windowSize, polyOrder),
|
|
167
|
+
};
|
|
168
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* patterns/swing.ts - スイングポイント(ピボット)検出
|
|
3
|
+
*
|
|
4
|
+
* ローソク足データからスイングハイ/スイングローを検出する。
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** ローソク足の最小インターフェース */
|
|
8
|
+
export interface Candle {
|
|
9
|
+
open: number;
|
|
10
|
+
close: number;
|
|
11
|
+
high: number;
|
|
12
|
+
low: number;
|
|
13
|
+
isoTime?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** スイングポイント(ピボット) */
|
|
17
|
+
export interface Pivot {
|
|
18
|
+
idx: number;
|
|
19
|
+
price: number;
|
|
20
|
+
kind: 'H' | 'L';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface DetectSwingePointsOptions {
|
|
24
|
+
/** スイング検出の深さ(前後何本を比較するか) */
|
|
25
|
+
swingDepth: number;
|
|
26
|
+
/** 厳格モード: 全ての前後バーより高い/低い必要がある(false: 60%投票制) */
|
|
27
|
+
strictPivots?: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* ローソク足データからスイングポイント(ピボット)を検出する
|
|
32
|
+
*
|
|
33
|
+
* @param candles - ローソク足データ
|
|
34
|
+
* @param options - 検出オプション
|
|
35
|
+
* @returns 検出されたピボットの配列
|
|
36
|
+
*/
|
|
37
|
+
export function detectSwingPoints(candles: Candle[], options: DetectSwingePointsOptions): Pivot[] {
|
|
38
|
+
const { swingDepth, strictPivots = true } = options;
|
|
39
|
+
|
|
40
|
+
const highs = candles.map((c) => c.high);
|
|
41
|
+
const lows = candles.map((c) => c.low);
|
|
42
|
+
const pivots: Pivot[] = [];
|
|
43
|
+
|
|
44
|
+
for (let i = swingDepth; i < candles.length - swingDepth; i++) {
|
|
45
|
+
let isHigh = true;
|
|
46
|
+
let isLow = true;
|
|
47
|
+
|
|
48
|
+
if (strictPivots) {
|
|
49
|
+
// 厳格モード: 全ての前後バーより高い/低い必要がある
|
|
50
|
+
for (let k = 1; k <= swingDepth; k++) {
|
|
51
|
+
if (!(highs[i] > highs[i - k] && highs[i] > highs[i + k])) isHigh = false;
|
|
52
|
+
if (!(lows[i] < lows[i - k] && lows[i] < lows[i + k])) isLow = false;
|
|
53
|
+
if (!isHigh && !isLow) break;
|
|
54
|
+
}
|
|
55
|
+
} else {
|
|
56
|
+
// 緩和モード: 60%投票制
|
|
57
|
+
let votesHigh = 0;
|
|
58
|
+
let votesLow = 0;
|
|
59
|
+
for (let k = 1; k <= swingDepth; k++) {
|
|
60
|
+
votesHigh += highs[i] > highs[i - k] && highs[i] > highs[i + k] ? 1 : 0;
|
|
61
|
+
votesLow += lows[i] < lows[i - k] && lows[i] < lows[i + k] ? 1 : 0;
|
|
62
|
+
}
|
|
63
|
+
const need = Math.ceil(swingDepth * 0.6);
|
|
64
|
+
isHigh = votesHigh >= need;
|
|
65
|
+
isLow = votesLow >= need;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 判定は high/low、格納価格は close(ヒゲ影響を回避)
|
|
69
|
+
if (isHigh) {
|
|
70
|
+
pivots.push({ idx: i, price: candles[i].close, kind: 'H' });
|
|
71
|
+
} else if (isLow) {
|
|
72
|
+
pivots.push({ idx: i, price: candles[i].close, kind: 'L' });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return pivots;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* ピボットを高値(H)のみにフィルタリング
|
|
81
|
+
*/
|
|
82
|
+
export function filterPeaks(pivots: Pivot[]): Pivot[] {
|
|
83
|
+
return pivots.filter((p) => p.kind === 'H');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* ピボットを安値(L)のみにフィルタリング
|
|
88
|
+
*/
|
|
89
|
+
export function filterValleys(pivots: Pivot[]): Pivot[] {
|
|
90
|
+
return pivots.filter((p) => p.kind === 'L');
|
|
91
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* detect_patterns 系モジュール共通の型定義
|
|
3
|
+
*/
|
|
4
|
+
import type { Pivot } from './swing.js';
|
|
5
|
+
|
|
6
|
+
/** トレンドライン(線形回帰の結果) */
|
|
7
|
+
export interface TrendLine {
|
|
8
|
+
slope: number;
|
|
9
|
+
intercept: number;
|
|
10
|
+
r2?: number;
|
|
11
|
+
valueAt: (x: number) => number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** ウェッジ検出パラメータ */
|
|
15
|
+
export interface WedgeParams {
|
|
16
|
+
minSlope?: number;
|
|
17
|
+
slopeRatioMinRising?: number;
|
|
18
|
+
slopeRatioMinFalling?: number;
|
|
19
|
+
slopeRatioMin?: number;
|
|
20
|
+
minWeakerSlopeRatio?: number;
|
|
21
|
+
windowSizeMin?: number;
|
|
22
|
+
windowSizeMax?: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** パターンスコアの各構成要素 */
|
|
26
|
+
export interface PatternScoreComponents {
|
|
27
|
+
fitScore: number;
|
|
28
|
+
convergeScore: number;
|
|
29
|
+
touchScore: number;
|
|
30
|
+
alternationScore: number;
|
|
31
|
+
insideScore: number;
|
|
32
|
+
durationScore: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** パターンスコアの重み */
|
|
36
|
+
export interface PatternScoreWeights {
|
|
37
|
+
fit: number;
|
|
38
|
+
converge: number;
|
|
39
|
+
touch: number;
|
|
40
|
+
alternation: number;
|
|
41
|
+
inside: number;
|
|
42
|
+
duration: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** タッチポイント */
|
|
46
|
+
export interface TouchPoint {
|
|
47
|
+
index: number;
|
|
48
|
+
distance: number;
|
|
49
|
+
isBreak: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** evaluateTouchesEx の戻り値 */
|
|
53
|
+
export interface TouchResult {
|
|
54
|
+
upperTouches: TouchPoint[];
|
|
55
|
+
lowerTouches: TouchPoint[];
|
|
56
|
+
upperQuality: number;
|
|
57
|
+
lowerQuality: number;
|
|
58
|
+
score: number;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** 重複排除対象のパターンエントリ(最低限のフィールド + 任意の追加フィールド) */
|
|
62
|
+
export interface DeduplicablePattern {
|
|
63
|
+
type?: string;
|
|
64
|
+
confidence?: number;
|
|
65
|
+
range?: { start: string; end: string; current?: string };
|
|
66
|
+
pivots?: Array<{ idx?: number; price?: number; kind?: string }>;
|
|
67
|
+
[key: string]: unknown;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** ローソク足データ(detectSwingPoints 互換) */
|
|
71
|
+
export interface CandleData {
|
|
72
|
+
open: number;
|
|
73
|
+
close: number;
|
|
74
|
+
high: number;
|
|
75
|
+
low: number;
|
|
76
|
+
isoTime?: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** pushCand() に渡すデバッグ引数 */
|
|
80
|
+
export interface CandDebugArg {
|
|
81
|
+
type: string;
|
|
82
|
+
accepted: boolean;
|
|
83
|
+
reason?: string;
|
|
84
|
+
idxs?: number[];
|
|
85
|
+
pts?: Array<{ role: string; idx: number; price: number }>;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** debugCandidates 配列の要素 */
|
|
89
|
+
export interface CandDebugEntry {
|
|
90
|
+
type: string;
|
|
91
|
+
accepted: boolean;
|
|
92
|
+
reason?: string;
|
|
93
|
+
indices?: number[];
|
|
94
|
+
points?: Array<{ role: string; idx: number; price: number; isoTime?: string }>;
|
|
95
|
+
details?: unknown;
|
|
96
|
+
status?: string;
|
|
97
|
+
breakoutDirection?: string | null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* パターン検出コンテキスト — 各検出モジュールが共有するデータとコンフィグ。
|
|
102
|
+
* detectPatterns() が組み立てて各検出関数に渡す。
|
|
103
|
+
*/
|
|
104
|
+
export interface DetectContext {
|
|
105
|
+
candles: CandleData[];
|
|
106
|
+
pivots: Pivot[];
|
|
107
|
+
allPeaks: Pivot[];
|
|
108
|
+
allValleys: Pivot[];
|
|
109
|
+
tolerancePct: number;
|
|
110
|
+
minDist: number;
|
|
111
|
+
/** 検出対象パターン種別。空 = 全種 */
|
|
112
|
+
want: Set<string>;
|
|
113
|
+
includeForming: boolean;
|
|
114
|
+
/** デバッグ候補バッファ(各モジュールが直接 push する) */
|
|
115
|
+
debugCandidates: CandDebugEntry[];
|
|
116
|
+
/** 時間軸('1day', '1hour', '1week' 等) */
|
|
117
|
+
type: string;
|
|
118
|
+
/** スイング深度 */
|
|
119
|
+
swingDepth: number;
|
|
120
|
+
/** 近接判定ヘルパー(tolerancePct ベース) */
|
|
121
|
+
near: (a: number, b: number) => boolean;
|
|
122
|
+
/** 変化率計算 */
|
|
123
|
+
pct: (a: number, b: number) => number;
|
|
124
|
+
/** R² 付き線形回帰 */
|
|
125
|
+
lrWithR2: (pts: Array<{ x: number; y: number }>) => {
|
|
126
|
+
slope: number;
|
|
127
|
+
intercept: number;
|
|
128
|
+
r2: number;
|
|
129
|
+
valueAt: (x: number) => number;
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** 各パターン検出関数の戻り値 */
|
|
134
|
+
export interface DetectResult {
|
|
135
|
+
patterns: PatternEntry[];
|
|
136
|
+
/** 検出成否フラグ(後続の relaxed パスに使用) */
|
|
137
|
+
found?: Record<string, boolean>;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** 事後分析結果 */
|
|
141
|
+
export interface AftermathResult {
|
|
142
|
+
breakoutDate?: string | null;
|
|
143
|
+
breakoutConfirmed: boolean;
|
|
144
|
+
priceMove?: Record<string, { return: number; high: number; low: number } | null>;
|
|
145
|
+
targetReached: boolean;
|
|
146
|
+
theoreticalTarget?: number | null;
|
|
147
|
+
outcome: string;
|
|
148
|
+
daysToTarget?: number | null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** パターンエントリ(検出結果の1件)— 共通フィールド+任意拡張 */
|
|
152
|
+
export interface PatternEntry extends DeduplicablePattern {
|
|
153
|
+
confidence?: number;
|
|
154
|
+
timeframe?: string;
|
|
155
|
+
timeframeLabel?: string;
|
|
156
|
+
neckline?: Array<{ x?: number; y: number }>;
|
|
157
|
+
structureDiagram?: { svg: string; artifact?: { identifier: string; title: string } };
|
|
158
|
+
status?: string;
|
|
159
|
+
breakout?: { idx: number; price: number; direction?: string } | null;
|
|
160
|
+
breakoutDirection?: 'up' | 'down';
|
|
161
|
+
outcome?: 'success' | 'failure' | string;
|
|
162
|
+
breakoutTarget?: number;
|
|
163
|
+
targetMethod?: string;
|
|
164
|
+
targetReachedPct?: number;
|
|
165
|
+
trendlineLabel?: string;
|
|
166
|
+
poleDirection?: 'up' | 'down';
|
|
167
|
+
priorTrendDirection?: 'bullish' | 'bearish';
|
|
168
|
+
flagpoleHeight?: number;
|
|
169
|
+
retracementRatio?: number;
|
|
170
|
+
isTrendContinuation?: boolean;
|
|
171
|
+
apexDate?: string;
|
|
172
|
+
daysToApex?: number;
|
|
173
|
+
completionPct?: number;
|
|
174
|
+
breakoutDate?: string;
|
|
175
|
+
breakoutBarIndex?: number;
|
|
176
|
+
daysSinceBreakout?: number;
|
|
177
|
+
aftermath?: AftermathResult | null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** pushCand ヘルパー(デバッグ候補に isoTime を付加して追加) */
|
|
181
|
+
export function pushCand(ctx: DetectContext, arg: CandDebugArg): void {
|
|
182
|
+
const points = (arg.pts || []).map((p) => ({
|
|
183
|
+
...p,
|
|
184
|
+
isoTime: (ctx.candles[p.idx] as CandleData | undefined)?.isoTime,
|
|
185
|
+
}));
|
|
186
|
+
ctx.debugCandidates.push({
|
|
187
|
+
type: arg.type,
|
|
188
|
+
accepted: arg.accepted,
|
|
189
|
+
reason: arg.reason,
|
|
190
|
+
indices: arg.idxs,
|
|
191
|
+
points,
|
|
192
|
+
});
|
|
193
|
+
}
|