@dshtrading/strategies 0.1.5 → 0.1.6
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/lib/builtin-tombstones-fs.d.ts +5 -0
- package/lib/builtin-tombstones-fs.js +75 -0
- package/lib/builtin-tombstones.d.ts +24 -0
- package/lib/builtin-tombstones.js +16 -0
- package/lib/custom-fs.js +15 -3
- package/lib/custom-screener-fs.d.ts +5 -0
- package/lib/custom-screener-fs.js +85 -0
- package/lib/custom-screener.d.ts +31 -0
- package/lib/custom-screener.js +16 -0
- package/lib/custom.d.ts +2 -1
- package/lib/index.d.ts +7 -2
- package/lib/index.js +8 -3
- package/lib/management.d.ts +46 -0
- package/lib/management.js +135 -0
- package/lib/paradigms/bollinger-reversion.js +46 -14
- package/lib/paradigms/donchian-breakout.js +12 -6
- package/lib/paradigms/ema-crossover.js +28 -15
- package/lib/paradigms/momentum-12m.js +22 -13
- package/lib/paradigms/rsi-reversion.js +22 -9
- package/lib/paradigms/sma-baseline.js +24 -15
- package/lib/plugin.d.ts +100 -6
- package/lib/plugin.js +370 -29
- package/lib/price-format.d.ts +16 -0
- package/lib/price-format.js +25 -0
- package/lib/screeners/above-ma.js +12 -7
- package/lib/screeners/ma-bull-align.js +14 -8
- package/lib/screeners/rsi-oversold.js +22 -6
- package/lib/screeners/volume-breakout.js +12 -7
- package/lib/validate-node.d.ts +10 -0
- package/lib/validate-node.js +19 -2
- package/lib/validate.d.ts +22 -1
- package/lib/validate.js +292 -76
- package/package.json +4 -3
|
@@ -22,6 +22,12 @@ const donchianBreakoutStrategy = {
|
|
|
22
22
|
compute(bars, params) {
|
|
23
23
|
const n1 = Math.max(2, Math.round(params.lookbackEntry ?? 20));
|
|
24
24
|
const n2 = Math.max(1, Math.round(params.lookbackExit ?? 10));
|
|
25
|
+
const fmtPrice = (value) => {
|
|
26
|
+
if (!Number.isFinite(value)) return "—";
|
|
27
|
+
const abs = Math.abs(value);
|
|
28
|
+
if (abs < 1) return value.toFixed(abs >= .01 ? 4 : 6);
|
|
29
|
+
return value.toFixed(Math.abs(Number(value.toFixed(2)) - value) < 1e-9 ? 2 : 3);
|
|
30
|
+
};
|
|
25
31
|
const signals = [];
|
|
26
32
|
let inPosition = false;
|
|
27
33
|
for (let i = Math.max(n1, n2); i < bars.length; i++) {
|
|
@@ -37,12 +43,12 @@ const donchianBreakoutStrategy = {
|
|
|
37
43
|
action: "entry",
|
|
38
44
|
direction: "long",
|
|
39
45
|
price: currentClose,
|
|
40
|
-
reason: `收盘价 (${currentClose
|
|
46
|
+
reason: `收盘价 (${fmtPrice(currentClose)}) 突破前 ${n1} 根最高价 (${fmtPrice(highestHigh)})`,
|
|
41
47
|
reasonKey: "strat.donchian-breakout.reason.entry",
|
|
42
48
|
reasonParams: {
|
|
43
|
-
close: currentClose
|
|
49
|
+
close: fmtPrice(currentClose),
|
|
44
50
|
n: n1,
|
|
45
|
-
high: highestHigh
|
|
51
|
+
high: fmtPrice(highestHigh)
|
|
46
52
|
}
|
|
47
53
|
});
|
|
48
54
|
inPosition = true;
|
|
@@ -53,12 +59,12 @@ const donchianBreakoutStrategy = {
|
|
|
53
59
|
action: "exit",
|
|
54
60
|
direction: "flat",
|
|
55
61
|
price: currentClose,
|
|
56
|
-
reason: `收盘价 (${currentClose
|
|
62
|
+
reason: `收盘价 (${fmtPrice(currentClose)}) 跌破前 ${n2} 根最低价 (${fmtPrice(lowestLow)})`,
|
|
57
63
|
reasonKey: "strat.donchian-breakout.reason.exit",
|
|
58
64
|
reasonParams: {
|
|
59
|
-
close: currentClose
|
|
65
|
+
close: fmtPrice(currentClose),
|
|
60
66
|
n: n2,
|
|
61
|
-
low: lowestLow
|
|
67
|
+
low: fmtPrice(lowestLow)
|
|
62
68
|
}
|
|
63
69
|
});
|
|
64
70
|
inPosition = false;
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import { ema } from "@dshtrading/indicators";
|
|
2
1
|
//#region src/paradigms/ema-crossover.ts
|
|
3
|
-
/**
|
|
4
|
-
* 双均线趋势跟踪策略(波段)。
|
|
5
|
-
*
|
|
6
|
-
* 入场:EMA(fast) 上穿 EMA(slow) 金叉做多。
|
|
7
|
-
* 出场:EMA(fast) 下穿 EMA(slow) 死叉离场。
|
|
8
|
-
*/
|
|
9
2
|
const emaCrossoverStrategy = {
|
|
10
3
|
id: "ema-crossover",
|
|
11
4
|
horizon: "swing",
|
|
@@ -29,9 +22,29 @@ const emaCrossoverStrategy = {
|
|
|
29
22
|
compute(bars, params) {
|
|
30
23
|
const fastP = Math.max(2, Math.round(params.fastPeriod ?? 20));
|
|
31
24
|
const slowP = Math.max(fastP + 1, Math.round(params.slowPeriod ?? 60));
|
|
25
|
+
const fmtPrice = (value) => {
|
|
26
|
+
if (!Number.isFinite(value)) return "—";
|
|
27
|
+
const abs = Math.abs(value);
|
|
28
|
+
if (abs < 1) return value.toFixed(abs >= .01 ? 4 : 6);
|
|
29
|
+
return value.toFixed(Math.abs(Number(value.toFixed(2)) - value) < 1e-9 ? 2 : 3);
|
|
30
|
+
};
|
|
31
|
+
const emaOf = (values, period) => {
|
|
32
|
+
const out = new Array(values.length).fill(void 0);
|
|
33
|
+
if (!Number.isFinite(period) || period < 1 || values.length < period) return out;
|
|
34
|
+
const k = 2 / (period + 1);
|
|
35
|
+
let seed = 0;
|
|
36
|
+
for (let index = 0; index < period; index++) seed += values[index];
|
|
37
|
+
let prev = seed / period;
|
|
38
|
+
out[period - 1] = prev;
|
|
39
|
+
for (let index = period; index < values.length; index++) {
|
|
40
|
+
prev = values[index] * k + prev * (1 - k);
|
|
41
|
+
out[index] = prev;
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
};
|
|
32
45
|
const closes = bars.map((b) => b.close);
|
|
33
|
-
const fastEma =
|
|
34
|
-
const slowEma =
|
|
46
|
+
const fastEma = emaOf(closes, fastP);
|
|
47
|
+
const slowEma = emaOf(closes, slowP);
|
|
35
48
|
const signals = [];
|
|
36
49
|
let inPosition = false;
|
|
37
50
|
for (let i = 1; i < bars.length; i++) {
|
|
@@ -47,13 +60,13 @@ const emaCrossoverStrategy = {
|
|
|
47
60
|
action: "entry",
|
|
48
61
|
direction: "long",
|
|
49
62
|
price: bars[i].close,
|
|
50
|
-
reason: `EMA(${fastP}) (${currFast
|
|
63
|
+
reason: `EMA(${fastP}) (${fmtPrice(currFast)}) 上穿 EMA(${slowP}) (${fmtPrice(currSlow)}) 形成金叉`,
|
|
51
64
|
reasonKey: "strat.ema-crossover.reason.entry",
|
|
52
65
|
reasonParams: {
|
|
53
66
|
fastP,
|
|
54
|
-
fast: currFast
|
|
67
|
+
fast: fmtPrice(currFast),
|
|
55
68
|
slowP,
|
|
56
|
-
slow: currSlow
|
|
69
|
+
slow: fmtPrice(currSlow)
|
|
57
70
|
}
|
|
58
71
|
});
|
|
59
72
|
inPosition = true;
|
|
@@ -64,13 +77,13 @@ const emaCrossoverStrategy = {
|
|
|
64
77
|
action: "exit",
|
|
65
78
|
direction: "flat",
|
|
66
79
|
price: bars[i].close,
|
|
67
|
-
reason: `EMA(${fastP}) (${currFast
|
|
80
|
+
reason: `EMA(${fastP}) (${fmtPrice(currFast)}) 下穿 EMA(${slowP}) (${fmtPrice(currSlow)}) 形成死叉`,
|
|
68
81
|
reasonKey: "strat.ema-crossover.reason.exit",
|
|
69
82
|
reasonParams: {
|
|
70
83
|
fastP,
|
|
71
|
-
fast: currFast
|
|
84
|
+
fast: fmtPrice(currFast),
|
|
72
85
|
slowP,
|
|
73
|
-
slow: currSlow
|
|
86
|
+
slow: fmtPrice(currSlow)
|
|
74
87
|
}
|
|
75
88
|
});
|
|
76
89
|
inPosition = false;
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import { sma } from "@dshtrading/indicators";
|
|
2
1
|
//#region src/paradigms/momentum-12m.ts
|
|
3
|
-
/**
|
|
4
|
-
* 12 个月动量择时策略(长线,Fama-French 动量单标的经典化)。
|
|
5
|
-
*
|
|
6
|
-
* 入场:近 12 个月(约 250 根日 K)累计收益 > 0 且价格高于年线,强动量做多。
|
|
7
|
-
* 出场:动量转负或价格跌破年线,动量衰竭离场。
|
|
8
|
-
*/
|
|
9
2
|
const momentum12mStrategy = {
|
|
10
3
|
id: "momentum-12m",
|
|
11
4
|
horizon: "long",
|
|
@@ -21,8 +14,24 @@ const momentum12mStrategy = {
|
|
|
21
14
|
}],
|
|
22
15
|
compute(bars, params) {
|
|
23
16
|
const lookback = Math.max(10, Math.round(params.lookbackBars ?? 250));
|
|
24
|
-
const
|
|
25
|
-
|
|
17
|
+
const fmtPrice = (value) => {
|
|
18
|
+
if (!Number.isFinite(value)) return "—";
|
|
19
|
+
const abs = Math.abs(value);
|
|
20
|
+
if (abs < 1) return value.toFixed(abs >= .01 ? 4 : 6);
|
|
21
|
+
return value.toFixed(Math.abs(Number(value.toFixed(2)) - value) < 1e-9 ? 2 : 3);
|
|
22
|
+
};
|
|
23
|
+
const smaOf = (values, period) => {
|
|
24
|
+
const out = new Array(values.length).fill(void 0);
|
|
25
|
+
if (!Number.isFinite(period) || period < 1 || values.length < period) return out;
|
|
26
|
+
let sum = 0;
|
|
27
|
+
for (let index = 0; index < values.length; index++) {
|
|
28
|
+
sum += values[index];
|
|
29
|
+
if (index >= period) sum -= values[index - period];
|
|
30
|
+
if (index >= period - 1) out[index] = sum / period;
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
};
|
|
34
|
+
const smaValues = smaOf(bars.map((b) => b.close), lookback);
|
|
26
35
|
const signals = [];
|
|
27
36
|
let inPosition = false;
|
|
28
37
|
for (let i = lookback; i < bars.length; i++) {
|
|
@@ -38,12 +47,12 @@ const momentum12mStrategy = {
|
|
|
38
47
|
action: "entry",
|
|
39
48
|
direction: "long",
|
|
40
49
|
price: currentClose,
|
|
41
|
-
reason: `近 ${lookback} 周期动量为正 (+${(momentumReturn * 100).toFixed(1)}%) 且位于均线 (${currentSma
|
|
50
|
+
reason: `近 ${lookback} 周期动量为正 (+${(momentumReturn * 100).toFixed(1)}%) 且位于均线 (${fmtPrice(currentSma)}) 之上,确认强动量`,
|
|
42
51
|
reasonKey: "strat.momentum-12m.reason.entry",
|
|
43
52
|
reasonParams: {
|
|
44
53
|
n: lookback,
|
|
45
54
|
pct: (momentumReturn * 100).toFixed(1),
|
|
46
|
-
sma: currentSma
|
|
55
|
+
sma: fmtPrice(currentSma)
|
|
47
56
|
}
|
|
48
57
|
});
|
|
49
58
|
inPosition = true;
|
|
@@ -55,12 +64,12 @@ const momentum12mStrategy = {
|
|
|
55
64
|
action: "exit",
|
|
56
65
|
direction: "flat",
|
|
57
66
|
price: currentClose,
|
|
58
|
-
reason: `${exitCause} (${(momentumReturn * 100).toFixed(1)}% / SMA ${currentSma
|
|
67
|
+
reason: `${exitCause} (${(momentumReturn * 100).toFixed(1)}% / SMA ${fmtPrice(currentSma)}),动量衰减平仓`,
|
|
59
68
|
reasonKey: "strat.momentum-12m.reason.exit",
|
|
60
69
|
reasonParams: {
|
|
61
70
|
cause: momentumReturn <= 0 ? "momentumNegative" : "belowBaseline",
|
|
62
71
|
pct: (momentumReturn * 100).toFixed(1),
|
|
63
|
-
sma: currentSma
|
|
72
|
+
sma: fmtPrice(currentSma)
|
|
64
73
|
}
|
|
65
74
|
});
|
|
66
75
|
inPosition = false;
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import { rsi } from "@dshtrading/indicators";
|
|
2
1
|
//#region src/paradigms/rsi-reversion.ts
|
|
3
|
-
/**
|
|
4
|
-
* 短周期 RSI 极值均值回归策略(短线,Connors 式)。
|
|
5
|
-
*
|
|
6
|
-
* 入场:RSI(2) < 10 极端超卖入场。
|
|
7
|
-
* 出场:RSI(2) > 60 快速反弹获利了结。
|
|
8
|
-
*/
|
|
9
2
|
const rsiReversionStrategy = {
|
|
10
3
|
id: "rsi-reversion",
|
|
11
4
|
horizon: "short",
|
|
@@ -41,8 +34,28 @@ const rsiReversionStrategy = {
|
|
|
41
34
|
const period = Math.max(2, Math.round(params.rsiPeriod ?? 2));
|
|
42
35
|
const enterThresh = Number(params.entryThreshold ?? 10);
|
|
43
36
|
const exitThresh = Number(params.exitThreshold ?? 60);
|
|
44
|
-
const
|
|
45
|
-
|
|
37
|
+
const rsiOf = (values, period) => {
|
|
38
|
+
const out = new Array(values.length).fill(void 0);
|
|
39
|
+
if (!Number.isFinite(period) || period < 1 || values.length < period) return out;
|
|
40
|
+
let gain = 0;
|
|
41
|
+
let loss = 0;
|
|
42
|
+
for (let index = 1; index <= period; index++) {
|
|
43
|
+
const delta = values[index] - values[index - 1];
|
|
44
|
+
if (delta >= 0) gain += delta;
|
|
45
|
+
else loss -= delta;
|
|
46
|
+
}
|
|
47
|
+
gain /= period;
|
|
48
|
+
loss /= period;
|
|
49
|
+
out[period] = loss === 0 ? 100 : 100 - 100 / (1 + gain / loss);
|
|
50
|
+
for (let index = period + 1; index < values.length; index++) {
|
|
51
|
+
const delta = values[index] - values[index - 1];
|
|
52
|
+
gain = (gain * (period - 1) + Math.max(delta, 0)) / period;
|
|
53
|
+
loss = (loss * (period - 1) + Math.max(-delta, 0)) / period;
|
|
54
|
+
out[index] = loss === 0 ? 100 : 100 - 100 / (1 + gain / loss);
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
};
|
|
58
|
+
const rsiValues = rsiOf(bars.map((b) => b.close), period);
|
|
46
59
|
const signals = [];
|
|
47
60
|
let inPosition = false;
|
|
48
61
|
for (let i = 0; i < bars.length; i++) {
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import { sma } from "@dshtrading/indicators";
|
|
2
1
|
//#region src/paradigms/sma-baseline.ts
|
|
3
|
-
/**
|
|
4
|
-
* 200 日均线择时基线策略(长线,Meb Faber GTAA 经典)。
|
|
5
|
-
*
|
|
6
|
-
* 入场:收盘价站上 SMA200 牛市生命线,全仓持有。
|
|
7
|
-
* 出场:收盘价跌破 SMA200 熊市防线,空仓避险。
|
|
8
|
-
*/
|
|
9
2
|
const smaBaselineStrategy = {
|
|
10
3
|
id: "sma-baseline",
|
|
11
4
|
horizon: "long",
|
|
@@ -21,8 +14,24 @@ const smaBaselineStrategy = {
|
|
|
21
14
|
}],
|
|
22
15
|
compute(bars, params) {
|
|
23
16
|
const period = Math.max(10, Math.round(params.period ?? 200));
|
|
24
|
-
const
|
|
25
|
-
|
|
17
|
+
const fmtPrice = (value) => {
|
|
18
|
+
if (!Number.isFinite(value)) return "—";
|
|
19
|
+
const abs = Math.abs(value);
|
|
20
|
+
if (abs < 1) return value.toFixed(abs >= .01 ? 4 : 6);
|
|
21
|
+
return value.toFixed(Math.abs(Number(value.toFixed(2)) - value) < 1e-9 ? 2 : 3);
|
|
22
|
+
};
|
|
23
|
+
const smaOf = (values, period) => {
|
|
24
|
+
const out = new Array(values.length).fill(void 0);
|
|
25
|
+
if (!Number.isFinite(period) || period < 1 || values.length < period) return out;
|
|
26
|
+
let sum = 0;
|
|
27
|
+
for (let index = 0; index < values.length; index++) {
|
|
28
|
+
sum += values[index];
|
|
29
|
+
if (index >= period) sum -= values[index - period];
|
|
30
|
+
if (index >= period - 1) out[index] = sum / period;
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
};
|
|
34
|
+
const smaValues = smaOf(bars.map((b) => b.close), period);
|
|
26
35
|
const signals = [];
|
|
27
36
|
let inPosition = false;
|
|
28
37
|
for (let i = period - 1; i < bars.length; i++) {
|
|
@@ -36,12 +45,12 @@ const smaBaselineStrategy = {
|
|
|
36
45
|
action: "entry",
|
|
37
46
|
direction: "long",
|
|
38
47
|
price: currentClose,
|
|
39
|
-
reason: `收盘价 (${currentClose
|
|
48
|
+
reason: `收盘价 (${fmtPrice(currentClose)}) 站上长期基线 SMA(${period}) (${fmtPrice(currentSma)}),确立多头趋势`,
|
|
40
49
|
reasonKey: "strat.sma-baseline.reason.entry",
|
|
41
50
|
reasonParams: {
|
|
42
|
-
close: currentClose
|
|
51
|
+
close: fmtPrice(currentClose),
|
|
43
52
|
period,
|
|
44
|
-
sma: currentSma
|
|
53
|
+
sma: fmtPrice(currentSma)
|
|
45
54
|
}
|
|
46
55
|
});
|
|
47
56
|
inPosition = true;
|
|
@@ -52,12 +61,12 @@ const smaBaselineStrategy = {
|
|
|
52
61
|
action: "exit",
|
|
53
62
|
direction: "flat",
|
|
54
63
|
price: currentClose,
|
|
55
|
-
reason: `收盘价 (${currentClose
|
|
64
|
+
reason: `收盘价 (${fmtPrice(currentClose)}) 跌破长期基线 SMA(${period}) (${fmtPrice(currentSma)}),转入防御避险`,
|
|
56
65
|
reasonKey: "strat.sma-baseline.reason.exit",
|
|
57
66
|
reasonParams: {
|
|
58
|
-
close: currentClose
|
|
67
|
+
close: fmtPrice(currentClose),
|
|
59
68
|
period,
|
|
60
|
-
sma: currentSma
|
|
69
|
+
sma: fmtPrice(currentSma)
|
|
61
70
|
}
|
|
62
71
|
});
|
|
63
72
|
inPosition = false;
|
package/lib/plugin.d.ts
CHANGED
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
import { StrategyDefinition } from "./types.js";
|
|
2
2
|
import { CustomStrategyRecord, CustomStrategyStore } from "./custom.js";
|
|
3
|
+
import { CustomScreenerRecord, CustomScreenerStore } from "./custom-screener.js";
|
|
4
|
+
import { isBuiltinScreenerId, isBuiltinStrategyId } from "./management.js";
|
|
5
|
+
import { BuiltinTombstonesStore } from "./builtin-tombstones.js";
|
|
3
6
|
import { MarketDataService } from "./api/lib/index.js";
|
|
4
7
|
import { createFileCustomStrategyStore } from "./custom-fs.js";
|
|
5
|
-
import {
|
|
8
|
+
import { createFileBuiltinTombstonesStore } from "./builtin-tombstones-fs.js";
|
|
9
|
+
import { createFileCustomScreenerStore } from "./custom-screener-fs.js";
|
|
10
|
+
import { validateCustomScreenerNode, validateCustomStrategyNode } from "./validate-node.js";
|
|
11
|
+
import { Context, Service } from "@deepseek-ai/cordis";
|
|
6
12
|
//#region src/plugin.d.ts
|
|
7
13
|
/** Cordis 插件名 = patch 行 id(TEMPLATES §8),市场无关共享行命名空间。 */
|
|
8
14
|
declare const name = "dsh-trading-strategies";
|
|
9
15
|
/** 本插件不硬依赖任何服务(headless 宿主零要求);tools/注册表经 ctx.inject 声明。 */
|
|
10
16
|
declare const inject: string[];
|
|
11
|
-
/**
|
|
17
|
+
/** 默认存储路径:$DSH_HOME/strategies/custom.json(缺省 ~/.dsh)。 */
|
|
12
18
|
declare function defaultStorePath(): string;
|
|
19
|
+
/** 默认墓碑路径:$DSH_HOME/strategies/builtin-tombstones.json(策略管理)。 */
|
|
20
|
+
declare function defaultTombstonesStorePath(): string;
|
|
21
|
+
/** 默认自定义选股器路径:$DSH_HOME/strategies/custom-screeners.json(选股器管理)。 */
|
|
22
|
+
declare function defaultScreenerStorePath(): string;
|
|
23
|
+
/** SDK 服务键:自定义策略 store 单实例(桥与工具共享同一缓存)。 */
|
|
24
|
+
declare const TRADING_STRATEGIES_KEY = "tradingStrategies";
|
|
13
25
|
/** tradingEvents 的最小发布面(鸭式,不定死接口;总线缺席时静默降级)。 */
|
|
14
26
|
interface TradingEventsPublisher {
|
|
15
27
|
emit(store: 'strategies'): void;
|
|
@@ -21,6 +33,8 @@ interface StrategyMarketDataResolver {
|
|
|
21
33
|
declare function createMarketDataResolver(ctx: Context): StrategyMarketDataResolver;
|
|
22
34
|
interface StrategyAuthorToolOptions {
|
|
23
35
|
store: CustomStrategyStore;
|
|
36
|
+
/** 可选:墓碑表(覆盖内置 id 时顺带恢复删除标记,策略管理语义)。 */
|
|
37
|
+
tombstones?: BuiltinTombstonesStore;
|
|
24
38
|
/** 可选:策略成功落盘后的回调(issue #30:事件总线 emit('strategies') 接线点)。 */
|
|
25
39
|
onWritten?: (record: CustomStrategyRecord) => void;
|
|
26
40
|
}
|
|
@@ -28,17 +42,97 @@ interface StrategyAuthorToolOptions {
|
|
|
28
42
|
declare function createStrategyAuthorTool(options: StrategyAuthorToolOptions): import("@deepseek-ai/dsh-tools").ToolDefinition;
|
|
29
43
|
interface StrategyBacktestToolOptions {
|
|
30
44
|
store: CustomStrategyStore;
|
|
45
|
+
/** 可选:墓碑表(内置删除后回测拒绝并引导恢复,策略管理语义)。 */
|
|
46
|
+
tombstones?: BuiltinTombstonesStore;
|
|
31
47
|
marketData: StrategyMarketDataResolver;
|
|
32
48
|
}
|
|
33
|
-
/**
|
|
34
|
-
|
|
49
|
+
/**
|
|
50
|
+
* 自定义或范式策略 → 回测用 StrategyDefinition(自定义 compute 经编译落定)。
|
|
51
|
+
* 覆盖 + 墓碑合成:store 同 id 记录优先(含内置覆盖);墓碑命中的 id 一律
|
|
52
|
+
* 视为不存在(含误留覆盖记录的边界——删除语义优先)。
|
|
53
|
+
*/
|
|
54
|
+
declare function resolveStrategyDefinition(store: CustomStrategyStore, strategyId: string, options?: {
|
|
55
|
+
tombstones?: BuiltinTombstonesStore | undefined;
|
|
56
|
+
}): Promise<StrategyDefinition | undefined>;
|
|
35
57
|
interface StrategyBacktestToolDeps {
|
|
36
58
|
store: CustomStrategyStore;
|
|
59
|
+
tombstones?: BuiltinTombstonesStore;
|
|
37
60
|
marketData: StrategyMarketDataResolver;
|
|
38
61
|
}
|
|
39
62
|
/** strategy_backtest 工厂(独立导出便于单测)。 */
|
|
40
63
|
declare function createStrategyBacktestTool(deps: StrategyBacktestToolDeps): import("@deepseek-ai/dsh-tools").ToolDefinition;
|
|
41
|
-
|
|
64
|
+
interface StrategyDeleteToolOptions {
|
|
65
|
+
store: CustomStrategyStore;
|
|
66
|
+
tombstones?: BuiltinTombstonesStore;
|
|
67
|
+
/** 可选:删除成功后的回调(emit('strategies') 接线点;幂等未命中也通知,GUI 对账无害)。 */
|
|
68
|
+
onDeleted?: (id: string, scope: 'custom' | 'builtin', removed: boolean) => void;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* strategy_delete 工厂(策略管理):自定义策略 = 移除记录;内置范式 = 落墓碑
|
|
72
|
+
* (出厂代码不动,strategy_reset 可恢复)。覆盖 + 墓碑模型见 management.ts。
|
|
73
|
+
*/
|
|
74
|
+
declare function createStrategyDeleteTool(options: StrategyDeleteToolOptions): import("@deepseek-ai/dsh-tools").ToolDefinition;
|
|
75
|
+
interface StrategyResetToolOptions {
|
|
76
|
+
store: CustomStrategyStore;
|
|
77
|
+
tombstones?: BuiltinTombstonesStore;
|
|
78
|
+
/** 可选:恢复成功后的回调(emit('strategies') 接线点)。 */
|
|
79
|
+
onReset?: (id: string, changed: boolean) => void;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* strategy_reset 工厂(策略管理):恢复内置策略出厂默认——清覆盖记录与墓碑。
|
|
83
|
+
* 仅对内置范式 id 有意义;自定义策略无出厂版本,明确报错引导 strategy_delete。
|
|
84
|
+
*/
|
|
85
|
+
declare function createStrategyResetTool(options: StrategyResetToolOptions): import("@deepseek-ai/dsh-tools").ToolDefinition;
|
|
86
|
+
interface ScreenerAuthorToolOptions {
|
|
87
|
+
store: CustomScreenerStore;
|
|
88
|
+
/** 可选:墓碑表(覆盖内置选股器时顺带恢复删除标记)。 */
|
|
89
|
+
tombstones?: BuiltinTombstonesStore;
|
|
90
|
+
/** 可选:选股器成功落盘后的回调(emit('strategies') 接线点)。 */
|
|
91
|
+
onWritten?: (record: CustomScreenerRecord) => void;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* screener_author 工厂(选股器管理):提交 → 结构/语法/多场景试算校验(vm 熔断)
|
|
95
|
+
* → 落盘。evaluate(bars, params) 返回 ScreenerMatch | null(单时点截面判断,
|
|
96
|
+
* 无信号序列语义)。id 为内置选股器('scr.*')→ 覆盖该内置(strategy_reset/
|
|
97
|
+
* screener_reset 可恢复出厂)。
|
|
98
|
+
*/
|
|
99
|
+
declare function createScreenerAuthorTool(options: ScreenerAuthorToolOptions): import("@deepseek-ai/dsh-tools").ToolDefinition;
|
|
100
|
+
interface ScreenerDeleteToolOptions {
|
|
101
|
+
store: CustomScreenerStore;
|
|
102
|
+
tombstones?: BuiltinTombstonesStore;
|
|
103
|
+
/** 可选:删除成功后的回调(emit('strategies') 接线点)。 */
|
|
104
|
+
onDeleted?: (id: string, scope: 'custom' | 'builtin', removed: boolean) => void;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* screener_delete 工厂(选股器管理):自定义选股器 = 移除记录;内置选股器 =
|
|
108
|
+
* 落墓碑(出厂代码不动,screener_reset 可恢复)。与 strategy_delete 共用墓碑表。
|
|
109
|
+
*/
|
|
110
|
+
declare function createScreenerDeleteTool(options: ScreenerDeleteToolOptions): import("@deepseek-ai/dsh-tools").ToolDefinition;
|
|
111
|
+
interface ScreenerResetToolOptions {
|
|
112
|
+
store: CustomScreenerStore;
|
|
113
|
+
tombstones?: BuiltinTombstonesStore;
|
|
114
|
+
/** 可选:恢复成功后的回调(emit('strategies') 接线点)。 */
|
|
115
|
+
onReset?: (id: string, changed: boolean) => void;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* screener_reset 工厂(选股器管理):恢复内置选股器出厂默认——清覆盖记录与墓碑。
|
|
119
|
+
* 仅对内置选股器 id 有意义;自定义选股器无出厂版本,明确报错引导 screener_delete。
|
|
120
|
+
*/
|
|
121
|
+
declare function createScreenerResetTool(options: ScreenerResetToolOptions): import("@deepseek-ai/dsh-tools").ToolDefinition;
|
|
122
|
+
/** Host plugin body:provide store 服务 + 注册策略工具族(host 平面,全会话可见)。 */
|
|
42
123
|
declare function apply(ctx: Context): void;
|
|
124
|
+
/** 策略 store 服务(桥与工具的单实例共享点,issue #33 收口模式)。 */
|
|
125
|
+
declare class StrategiesStoreService extends Service {
|
|
126
|
+
readonly store: CustomStrategyStore;
|
|
127
|
+
/** 内置墓碑表(策略/选股器管理共用;桥 DELETE/POST /strategies/* 与工具共享)。 */
|
|
128
|
+
readonly tombstones: BuiltinTombstonesStore;
|
|
129
|
+
/** 自定义选股器 store(选股器管理)。 */
|
|
130
|
+
readonly screenerStore: CustomScreenerStore;
|
|
131
|
+
constructor(ctx: Context, deps: {
|
|
132
|
+
store: CustomStrategyStore;
|
|
133
|
+
tombstones: BuiltinTombstonesStore;
|
|
134
|
+
screenerStore: CustomScreenerStore;
|
|
135
|
+
}, serviceName?: string);
|
|
136
|
+
}
|
|
43
137
|
//#endregion
|
|
44
|
-
export { StrategyAuthorToolOptions, StrategyBacktestToolDeps, StrategyBacktestToolOptions, StrategyMarketDataResolver, TradingEventsPublisher, apply, createFileCustomStrategyStore, createMarketDataResolver, createStrategyAuthorTool, createStrategyBacktestTool, defaultStorePath, inject, name, resolveStrategyDefinition };
|
|
138
|
+
export { ScreenerAuthorToolOptions, ScreenerDeleteToolOptions, ScreenerResetToolOptions, StrategiesStoreService, StrategyAuthorToolOptions, StrategyBacktestToolDeps, StrategyBacktestToolOptions, StrategyDeleteToolOptions, StrategyMarketDataResolver, StrategyResetToolOptions, TRADING_STRATEGIES_KEY, TradingEventsPublisher, apply, createFileBuiltinTombstonesStore, createFileCustomScreenerStore, createFileCustomStrategyStore, createMarketDataResolver, createScreenerAuthorTool, createScreenerDeleteTool, createScreenerResetTool, createStrategyAuthorTool, createStrategyBacktestTool, createStrategyDeleteTool, createStrategyResetTool, defaultScreenerStorePath, defaultStorePath, defaultTombstonesStorePath, inject, isBuiltinScreenerId, isBuiltinStrategyId, name, resolveStrategyDefinition, validateCustomScreenerNode, validateCustomStrategyNode };
|