@dshtrading/client-ui-indicators 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 +75 -0
- package/lib/client.js +580 -0
- package/lib/client.js.map +1 -0
- package/lib/index.d.ts +12 -0
- package/lib/index.js +12 -0
- package/package.json +44 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
Copyright (c) 2026 zhu1090093659 (dsh-trading)
|
|
2
|
+
|
|
3
|
+
# PolyForm Noncommercial License 1.0.0
|
|
4
|
+
|
|
5
|
+
<https://polyformproject.org/licenses/noncommercial/1.0.0>
|
|
6
|
+
|
|
7
|
+
## Acceptance
|
|
8
|
+
|
|
9
|
+
In order to get any license under these terms, you must agree to them as both strict obligations and conditions to all your licenses.
|
|
10
|
+
|
|
11
|
+
## Copyright License
|
|
12
|
+
|
|
13
|
+
The licensor grants you a copyright license for the software to do everything you might do with the software that would otherwise infringe the licensor's copyright in it for any permitted purpose. However, you may only distribute the software according to [Distribution License](#distribution-license) and make changes or new works based on the software according to [Changes and New Works License](#changes-and-new-works-license).
|
|
14
|
+
|
|
15
|
+
## Distribution License
|
|
16
|
+
|
|
17
|
+
The licensor grants you an additional copyright license to distribute copies of the software. Your license to distribute covers distributing the software with changes and new works permitted by [Changes and New Works License](#changes-and-new-works-license).
|
|
18
|
+
|
|
19
|
+
## Notices
|
|
20
|
+
|
|
21
|
+
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms or the URL for them above, as well as copies of any plain-text lines beginning with `Required Notice:` that the licensor provided with the software. For example:
|
|
22
|
+
|
|
23
|
+
> Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
|
|
24
|
+
|
|
25
|
+
## Changes and New Works License
|
|
26
|
+
|
|
27
|
+
The licensor grants you an additional copyright license to make changes and new works based on the software for any permitted purpose.
|
|
28
|
+
|
|
29
|
+
## Patent License
|
|
30
|
+
|
|
31
|
+
The licensor grants you a patent license for the software that covers patent claims the licensor can license, or becomes able to license, that you would infringe by using the software.
|
|
32
|
+
|
|
33
|
+
## Noncommercial Purposes
|
|
34
|
+
|
|
35
|
+
Any noncommercial purpose is a permitted purpose.
|
|
36
|
+
|
|
37
|
+
## Personal Uses
|
|
38
|
+
|
|
39
|
+
Personal use for research, experiment, and testing for the benefit of public knowledge, personal study, private entertainment, hobby projects, amateur pursuits, or religious observance, without any anticipated commercial application, is use for a permitted purpose.
|
|
40
|
+
|
|
41
|
+
## Noncommercial Organizations
|
|
42
|
+
|
|
43
|
+
Use by any charitable organization, educational institution, public research organization, public safety or health organization, environmental protection organization, or government institution is use for a permitted purpose regardless of the source of funding or obligations resulting from the funding.
|
|
44
|
+
|
|
45
|
+
## Fair Use
|
|
46
|
+
|
|
47
|
+
You may have "fair use" rights for the software under the law. These terms do not limit them.
|
|
48
|
+
|
|
49
|
+
## No Other Rights
|
|
50
|
+
|
|
51
|
+
These terms do not allow you to sublicense or transfer any of your licenses to anyone else, or prevent the licensor from granting licenses to anyone else. These terms do not imply any other licenses.
|
|
52
|
+
|
|
53
|
+
## Patent Defense
|
|
54
|
+
|
|
55
|
+
If you make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
|
|
56
|
+
|
|
57
|
+
## Violations
|
|
58
|
+
|
|
59
|
+
The first time you are notified in writing that you have violated any of these terms, or done anything with the software not covered by your licenses, your licenses can nonetheless continue if you come into full compliance with these terms, and take practical steps to correct past violations, within 32 days of receiving notice. Otherwise, all your licenses end immediately.
|
|
60
|
+
|
|
61
|
+
## No Liability
|
|
62
|
+
|
|
63
|
+
***As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.***
|
|
64
|
+
|
|
65
|
+
## Definitions
|
|
66
|
+
|
|
67
|
+
The **licensor** is the individual or entity offering these terms, and the **software** is the software the licensor makes available under these terms.
|
|
68
|
+
|
|
69
|
+
**You** refers to the individual or entity agreeing to these terms.
|
|
70
|
+
|
|
71
|
+
**Your company** is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. **Control** means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
|
|
72
|
+
|
|
73
|
+
**Your licenses** are all the licenses granted to you for the software under these terms.
|
|
74
|
+
|
|
75
|
+
**Use** means anything you do with the software requiring one of your licenses.
|
package/lib/client.js
ADDED
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "@dshtrading/client-ui-indicators",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
var exports = module.exports;
|
|
6
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
//#region ../indicators/lib/registry.js
|
|
8
|
+
function createIndicatorRegistry() {
|
|
9
|
+
const registry = /* @__PURE__ */ new Map();
|
|
10
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
11
|
+
let version = 0;
|
|
12
|
+
const register = (definition) => {
|
|
13
|
+
registry.set(definition.id, definition);
|
|
14
|
+
version += 1;
|
|
15
|
+
for (const listener of listeners) listener();
|
|
16
|
+
};
|
|
17
|
+
const definitionParams = (id) => registry.get(id)?.params ?? [];
|
|
18
|
+
return {
|
|
19
|
+
register,
|
|
20
|
+
unregister(id) {
|
|
21
|
+
if (!registry.delete(id)) return;
|
|
22
|
+
version += 1;
|
|
23
|
+
for (const listener of listeners) listener();
|
|
24
|
+
},
|
|
25
|
+
get: (id) => registry.get(id),
|
|
26
|
+
list: () => [...registry.values()],
|
|
27
|
+
defaultParams(definition) {
|
|
28
|
+
const params = {};
|
|
29
|
+
for (const spec of definition.params) params[spec.key] = spec.default;
|
|
30
|
+
return params;
|
|
31
|
+
},
|
|
32
|
+
defaultInstance(id) {
|
|
33
|
+
const definition = registry.get(id);
|
|
34
|
+
if (definition === void 0) return void 0;
|
|
35
|
+
return {
|
|
36
|
+
id,
|
|
37
|
+
params: this.defaultParams(definition)
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
instanceKey(instance) {
|
|
41
|
+
const values = definitionParams(instance.id).map((spec) => instance.params[spec.key] ?? spec.default);
|
|
42
|
+
return `${instance.id}:${values.join(",")}`;
|
|
43
|
+
},
|
|
44
|
+
clampParams(definition, params) {
|
|
45
|
+
const out = {};
|
|
46
|
+
for (const spec of definition.params) {
|
|
47
|
+
const raw = params[spec.key];
|
|
48
|
+
out[spec.key] = typeof raw === "number" && Number.isFinite(raw) ? Math.min(spec.max, Math.max(spec.min, Math.round(raw))) : spec.default;
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
},
|
|
52
|
+
sanitizeInstances(instances) {
|
|
53
|
+
if (!Array.isArray(instances)) return [];
|
|
54
|
+
const seen = /* @__PURE__ */ new Set();
|
|
55
|
+
const out = [];
|
|
56
|
+
for (const raw of instances) {
|
|
57
|
+
if (typeof raw !== "object" || raw === null) continue;
|
|
58
|
+
const { id, params } = raw;
|
|
59
|
+
if (typeof id !== "string" || seen.has(id)) continue;
|
|
60
|
+
const definition = registry.get(id);
|
|
61
|
+
if (definition === void 0) continue;
|
|
62
|
+
seen.add(id);
|
|
63
|
+
out.push({
|
|
64
|
+
id,
|
|
65
|
+
params: this.clampParams(definition, typeof params === "object" && params !== null ? params : {})
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
},
|
|
70
|
+
subscribe(listener) {
|
|
71
|
+
listeners.add(listener);
|
|
72
|
+
return () => {
|
|
73
|
+
listeners.delete(listener);
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
getVersion: () => version
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
//#region ../indicators/lib/math.js
|
|
81
|
+
/** 简单移动平均(滚动和,O(n))。 */
|
|
82
|
+
function sma(values, period) {
|
|
83
|
+
const out = new Array(values.length).fill(void 0);
|
|
84
|
+
if (!valid(period, values.length)) return out;
|
|
85
|
+
let sum = 0;
|
|
86
|
+
for (let index = 0; index < values.length; index++) {
|
|
87
|
+
sum += values[index];
|
|
88
|
+
if (index >= period) sum -= values[index - period];
|
|
89
|
+
if (index >= period - 1) out[index] = sum / period;
|
|
90
|
+
}
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
/** 指数移动平均(标准 EMA:种子 = 前 period 个的 SMA)。 */
|
|
94
|
+
function ema(values, period) {
|
|
95
|
+
const out = new Array(values.length).fill(void 0);
|
|
96
|
+
if (!valid(period, values.length)) return out;
|
|
97
|
+
const k = 2 / (period + 1);
|
|
98
|
+
let seed = 0;
|
|
99
|
+
for (let index = 0; index < period; index++) seed += values[index];
|
|
100
|
+
let prev = seed / period;
|
|
101
|
+
out[period - 1] = prev;
|
|
102
|
+
for (let index = period; index < values.length; index++) {
|
|
103
|
+
prev = values[index] * k + prev * (1 - k);
|
|
104
|
+
out[index] = prev;
|
|
105
|
+
}
|
|
106
|
+
return out;
|
|
107
|
+
}
|
|
108
|
+
/** 滚动样本标准差(无偏校正关——与主流行情软件一致用总体口径)。 */
|
|
109
|
+
function stdev(values, period) {
|
|
110
|
+
const out = new Array(values.length).fill(void 0);
|
|
111
|
+
if (!valid(period, values.length)) return out;
|
|
112
|
+
for (let index = period - 1; index < values.length; index++) {
|
|
113
|
+
let mean = 0;
|
|
114
|
+
for (let offset = 0; offset < period; offset++) mean += values[index - offset];
|
|
115
|
+
mean /= period;
|
|
116
|
+
let variance = 0;
|
|
117
|
+
for (let offset = 0; offset < period; offset++) {
|
|
118
|
+
const delta = values[index - offset] - mean;
|
|
119
|
+
variance += delta * delta;
|
|
120
|
+
}
|
|
121
|
+
out[index] = Math.sqrt(variance / period);
|
|
122
|
+
}
|
|
123
|
+
return out;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* 布林带:返回中轨(SMA)与上下轨(中轨 ± N 倍标准差)。
|
|
127
|
+
* 主图叠加指标,三条线共享 warm-up。
|
|
128
|
+
*/
|
|
129
|
+
function bollinger(values, period, mult) {
|
|
130
|
+
const mid = sma(values, period);
|
|
131
|
+
const sd = stdev(values, period);
|
|
132
|
+
const upper = new Array(values.length).fill(void 0);
|
|
133
|
+
const lower = new Array(values.length).fill(void 0);
|
|
134
|
+
for (let index = 0; index < values.length; index++) {
|
|
135
|
+
const base = mid[index];
|
|
136
|
+
const dev = sd[index];
|
|
137
|
+
if (base === void 0 || dev === void 0) continue;
|
|
138
|
+
upper[index] = base + mult * dev;
|
|
139
|
+
lower[index] = base - mult * dev;
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
mid,
|
|
143
|
+
upper,
|
|
144
|
+
lower
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* MACD:DIF = EMA(fast) - EMA(slow);DEA = DIF 的 EMA(signal);
|
|
149
|
+
* 柱 = (DIF - DEA) × 2。warm-up 取两者较大者(EMA 串联)。
|
|
150
|
+
*/
|
|
151
|
+
function macd(values, fast, slow, signal) {
|
|
152
|
+
const emaFast = ema(values, fast);
|
|
153
|
+
const emaSlow = ema(values, slow);
|
|
154
|
+
const dif = values.map((_, index) => {
|
|
155
|
+
const a = emaFast[index];
|
|
156
|
+
const b = emaSlow[index];
|
|
157
|
+
return a === void 0 || b === void 0 ? void 0 : a - b;
|
|
158
|
+
});
|
|
159
|
+
const deaCompact = ema(dif.filter((value) => value !== void 0), signal);
|
|
160
|
+
const dea = new Array(values.length).fill(void 0);
|
|
161
|
+
let cursor = 0;
|
|
162
|
+
for (let index = 0; index < values.length; index++) {
|
|
163
|
+
if (dif[index] === void 0) continue;
|
|
164
|
+
dea[index] = deaCompact[cursor];
|
|
165
|
+
cursor++;
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
dif,
|
|
169
|
+
dea,
|
|
170
|
+
hist: values.map((_, index) => {
|
|
171
|
+
const d = dif[index];
|
|
172
|
+
const e = dea[index];
|
|
173
|
+
return d === void 0 || e === void 0 ? void 0 : (d - e) * 2;
|
|
174
|
+
})
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* RSI(Wilder 平滑)。种子 = 前 period 个涨跌均值,其后
|
|
179
|
+
* avgGain/avgLoss 递推;前 period 位为 undefined。
|
|
180
|
+
*/
|
|
181
|
+
function rsi(values, period) {
|
|
182
|
+
const out = new Array(values.length).fill(void 0);
|
|
183
|
+
if (!valid(period, values.length)) return out;
|
|
184
|
+
let gain = 0;
|
|
185
|
+
let loss = 0;
|
|
186
|
+
for (let index = 1; index <= period; index++) {
|
|
187
|
+
const delta = values[index] - values[index - 1];
|
|
188
|
+
if (delta >= 0) gain += delta;
|
|
189
|
+
else loss -= delta;
|
|
190
|
+
}
|
|
191
|
+
gain /= period;
|
|
192
|
+
loss /= period;
|
|
193
|
+
out[period] = loss === 0 ? 100 : 100 - 100 / (1 + gain / loss);
|
|
194
|
+
for (let index = period + 1; index < values.length; index++) {
|
|
195
|
+
const delta = values[index] - values[index - 1];
|
|
196
|
+
gain = (gain * (period - 1) + Math.max(delta, 0)) / period;
|
|
197
|
+
loss = (loss * (period - 1) + Math.max(-delta, 0)) / period;
|
|
198
|
+
out[index] = loss === 0 ? 100 : 100 - 100 / (1 + gain / loss);
|
|
199
|
+
}
|
|
200
|
+
return out;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* KDJ(RSV 的 SMA[Wilder] 平滑,初始值 50)。
|
|
204
|
+
* 返回 k/d/j 三条序列;warm-up = N-1。
|
|
205
|
+
*/
|
|
206
|
+
function kdj(highs, lows, closes, n) {
|
|
207
|
+
const length = closes.length;
|
|
208
|
+
const k = new Array(length).fill(void 0);
|
|
209
|
+
const d = new Array(length).fill(void 0);
|
|
210
|
+
const j = new Array(length).fill(void 0);
|
|
211
|
+
if (!valid(n, length)) return {
|
|
212
|
+
k,
|
|
213
|
+
d,
|
|
214
|
+
j
|
|
215
|
+
};
|
|
216
|
+
let prevK = 50;
|
|
217
|
+
let prevD = 50;
|
|
218
|
+
for (let index = n - 1; index < length; index++) {
|
|
219
|
+
let hh = -Infinity;
|
|
220
|
+
let ll = Infinity;
|
|
221
|
+
for (let offset = 0; offset < n; offset++) {
|
|
222
|
+
hh = Math.max(hh, highs[index - offset]);
|
|
223
|
+
ll = Math.min(ll, lows[index - offset]);
|
|
224
|
+
}
|
|
225
|
+
const rsvValue = hh === ll ? 50 : (closes[index] - ll) / (hh - ll) * 100;
|
|
226
|
+
prevK = prevK + (rsvValue - prevK) / 3;
|
|
227
|
+
prevD = prevD + (prevK - prevD) / 3;
|
|
228
|
+
k[index] = prevK;
|
|
229
|
+
d[index] = prevD;
|
|
230
|
+
j[index] = 3 * prevK - 2 * prevD;
|
|
231
|
+
}
|
|
232
|
+
return {
|
|
233
|
+
k,
|
|
234
|
+
d,
|
|
235
|
+
j
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
function valid(period, length) {
|
|
239
|
+
return Number.isFinite(period) && period >= 1 && length >= period;
|
|
240
|
+
}
|
|
241
|
+
//#endregion
|
|
242
|
+
//#region ../indicators/lib/presets.js
|
|
243
|
+
/** MA 线配色(富途系配色 + 扩展周期轮换调色板)。 */
|
|
244
|
+
const MA_COLORS = {
|
|
245
|
+
MA5: "#e6b800",
|
|
246
|
+
MA10: "#4a90e2",
|
|
247
|
+
MA20: "#c05fd8",
|
|
248
|
+
MA30: "#2ba471",
|
|
249
|
+
MA60: "#f97316",
|
|
250
|
+
MA120: "#0ea5e9",
|
|
251
|
+
MA250: "#8a8f99"
|
|
252
|
+
};
|
|
253
|
+
/** EMA 线配色。 */
|
|
254
|
+
const EMA_COLORS = {
|
|
255
|
+
EMA5: "#e6b800",
|
|
256
|
+
EMA6: "#e6b800",
|
|
257
|
+
EMA10: "#4a90e2",
|
|
258
|
+
EMA12: "#ff9800",
|
|
259
|
+
EMA20: "#c05fd8",
|
|
260
|
+
EMA26: "#00bcd4",
|
|
261
|
+
EMA30: "#2ba471",
|
|
262
|
+
EMA50: "#2ba471",
|
|
263
|
+
EMA60: "#f97316",
|
|
264
|
+
EMA120: "#0ea5e9",
|
|
265
|
+
EMA200: "#8a8f99",
|
|
266
|
+
EMA250: "#8a8f99"
|
|
267
|
+
};
|
|
268
|
+
/** 均线 6 色备用调色板(富途黄/蓝/紫/绿/橙/青)。 */
|
|
269
|
+
const FALLBACK_PALETTE = [
|
|
270
|
+
"#e6b800",
|
|
271
|
+
"#4a90e2",
|
|
272
|
+
"#c05fd8",
|
|
273
|
+
"#2ba471",
|
|
274
|
+
"#f97316",
|
|
275
|
+
"#0ea5e9"
|
|
276
|
+
];
|
|
277
|
+
function maColor(period, index) {
|
|
278
|
+
return MA_COLORS[`MA${period}`] ?? FALLBACK_PALETTE[index % FALLBACK_PALETTE.length] ?? "#8a8f99";
|
|
279
|
+
}
|
|
280
|
+
function emaColor(period, index) {
|
|
281
|
+
return EMA_COLORS[`EMA${period}`] ?? FALLBACK_PALETTE[index % FALLBACK_PALETTE.length] ?? "#8a8f99";
|
|
282
|
+
}
|
|
283
|
+
const closesOf = (bars) => bars.map((bar) => bar.close);
|
|
284
|
+
/** 六个预置 definition(纯数据,注册时机归消费方)。 */
|
|
285
|
+
function presetDefinitions() {
|
|
286
|
+
return [
|
|
287
|
+
{
|
|
288
|
+
id: "ma",
|
|
289
|
+
pane: "main",
|
|
290
|
+
title: "MA",
|
|
291
|
+
params: [
|
|
292
|
+
{
|
|
293
|
+
key: "n1",
|
|
294
|
+
label: "周期1",
|
|
295
|
+
default: 5,
|
|
296
|
+
min: 0,
|
|
297
|
+
max: 250
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
key: "n2",
|
|
301
|
+
label: "周期2",
|
|
302
|
+
default: 10,
|
|
303
|
+
min: 0,
|
|
304
|
+
max: 250
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
key: "n3",
|
|
308
|
+
label: "周期3",
|
|
309
|
+
default: 20,
|
|
310
|
+
min: 0,
|
|
311
|
+
max: 250
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
key: "n4",
|
|
315
|
+
label: "周期4",
|
|
316
|
+
default: 30,
|
|
317
|
+
min: 0,
|
|
318
|
+
max: 250
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
key: "n5",
|
|
322
|
+
label: "周期5",
|
|
323
|
+
default: 60,
|
|
324
|
+
min: 0,
|
|
325
|
+
max: 250
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
key: "n6",
|
|
329
|
+
label: "周期6",
|
|
330
|
+
default: 120,
|
|
331
|
+
min: 0,
|
|
332
|
+
max: 250
|
|
333
|
+
}
|
|
334
|
+
],
|
|
335
|
+
compute(bars, params) {
|
|
336
|
+
const closes = closesOf(bars);
|
|
337
|
+
return [
|
|
338
|
+
params.n1,
|
|
339
|
+
params.n2,
|
|
340
|
+
params.n3,
|
|
341
|
+
params.n4,
|
|
342
|
+
params.n5,
|
|
343
|
+
params.n6
|
|
344
|
+
].filter((period) => typeof period === "number" && Number.isFinite(period) && period > 0).map((period, index) => ({
|
|
345
|
+
key: `MA${period}`,
|
|
346
|
+
kind: "line",
|
|
347
|
+
color: maColor(period, index),
|
|
348
|
+
values: sma(closes, period)
|
|
349
|
+
}));
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
id: "ema",
|
|
354
|
+
pane: "main",
|
|
355
|
+
title: "EMA",
|
|
356
|
+
params: [
|
|
357
|
+
{
|
|
358
|
+
key: "n1",
|
|
359
|
+
label: "周期1",
|
|
360
|
+
default: 5,
|
|
361
|
+
min: 0,
|
|
362
|
+
max: 250
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
key: "n2",
|
|
366
|
+
label: "周期2",
|
|
367
|
+
default: 10,
|
|
368
|
+
min: 0,
|
|
369
|
+
max: 250
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
key: "n3",
|
|
373
|
+
label: "周期3",
|
|
374
|
+
default: 20,
|
|
375
|
+
min: 0,
|
|
376
|
+
max: 250
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
key: "n4",
|
|
380
|
+
label: "周期4",
|
|
381
|
+
default: 30,
|
|
382
|
+
min: 0,
|
|
383
|
+
max: 250
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
key: "n5",
|
|
387
|
+
label: "周期5",
|
|
388
|
+
default: 60,
|
|
389
|
+
min: 0,
|
|
390
|
+
max: 250
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
key: "n6",
|
|
394
|
+
label: "周期6",
|
|
395
|
+
default: 120,
|
|
396
|
+
min: 0,
|
|
397
|
+
max: 250
|
|
398
|
+
}
|
|
399
|
+
],
|
|
400
|
+
compute(bars, params) {
|
|
401
|
+
const closes = closesOf(bars);
|
|
402
|
+
return [
|
|
403
|
+
params.n1,
|
|
404
|
+
params.n2,
|
|
405
|
+
params.n3,
|
|
406
|
+
params.n4,
|
|
407
|
+
params.n5,
|
|
408
|
+
params.n6
|
|
409
|
+
].filter((period) => typeof period === "number" && Number.isFinite(period) && period > 0).map((period, index) => ({
|
|
410
|
+
key: `EMA${period}`,
|
|
411
|
+
kind: "line",
|
|
412
|
+
color: emaColor(period, index),
|
|
413
|
+
values: ema(closes, period)
|
|
414
|
+
}));
|
|
415
|
+
}
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
id: "boll",
|
|
419
|
+
pane: "main",
|
|
420
|
+
title: "BOLL",
|
|
421
|
+
params: [{
|
|
422
|
+
key: "n",
|
|
423
|
+
label: "周期",
|
|
424
|
+
default: 20,
|
|
425
|
+
min: 2,
|
|
426
|
+
max: 250
|
|
427
|
+
}, {
|
|
428
|
+
key: "k",
|
|
429
|
+
label: "倍数",
|
|
430
|
+
default: 2,
|
|
431
|
+
min: 1,
|
|
432
|
+
max: 5
|
|
433
|
+
}],
|
|
434
|
+
compute(bars, params) {
|
|
435
|
+
const { mid, upper, lower } = bollinger(closesOf(bars), params.n, params.k);
|
|
436
|
+
return [
|
|
437
|
+
{
|
|
438
|
+
key: "MID",
|
|
439
|
+
kind: "line",
|
|
440
|
+
color: "#8a8f99",
|
|
441
|
+
values: mid
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
key: "UP",
|
|
445
|
+
kind: "line",
|
|
446
|
+
color: "#4a90e2",
|
|
447
|
+
values: upper
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
key: "LOW",
|
|
451
|
+
kind: "line",
|
|
452
|
+
color: "#4a90e2",
|
|
453
|
+
values: lower
|
|
454
|
+
}
|
|
455
|
+
];
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
id: "macd",
|
|
460
|
+
pane: "sub",
|
|
461
|
+
title: "MACD",
|
|
462
|
+
params: [
|
|
463
|
+
{
|
|
464
|
+
key: "fast",
|
|
465
|
+
label: "快线",
|
|
466
|
+
default: 12,
|
|
467
|
+
min: 2,
|
|
468
|
+
max: 100
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
key: "slow",
|
|
472
|
+
label: "慢线",
|
|
473
|
+
default: 26,
|
|
474
|
+
min: 2,
|
|
475
|
+
max: 200
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
key: "signal",
|
|
479
|
+
label: "信号",
|
|
480
|
+
default: 9,
|
|
481
|
+
min: 1,
|
|
482
|
+
max: 60
|
|
483
|
+
}
|
|
484
|
+
],
|
|
485
|
+
compute(bars, params) {
|
|
486
|
+
const { dif, dea, hist } = macd(closesOf(bars), params.fast, params.slow, params.signal);
|
|
487
|
+
return [
|
|
488
|
+
{
|
|
489
|
+
key: "DIF",
|
|
490
|
+
kind: "line",
|
|
491
|
+
color: "#e6b800",
|
|
492
|
+
values: dif
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
key: "DEA",
|
|
496
|
+
kind: "line",
|
|
497
|
+
color: "#4a90e2",
|
|
498
|
+
values: dea
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
key: "HIST",
|
|
502
|
+
kind: "histogram",
|
|
503
|
+
color: "#8a8f99",
|
|
504
|
+
values: hist,
|
|
505
|
+
histogramBySign: true
|
|
506
|
+
}
|
|
507
|
+
];
|
|
508
|
+
}
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
id: "rsi",
|
|
512
|
+
pane: "sub",
|
|
513
|
+
title: "RSI",
|
|
514
|
+
params: [{
|
|
515
|
+
key: "n",
|
|
516
|
+
label: "周期",
|
|
517
|
+
default: 14,
|
|
518
|
+
min: 2,
|
|
519
|
+
max: 120
|
|
520
|
+
}],
|
|
521
|
+
compute(bars, params) {
|
|
522
|
+
return [{
|
|
523
|
+
key: `RSI${params.n}`,
|
|
524
|
+
kind: "line",
|
|
525
|
+
color: "#c05fd8",
|
|
526
|
+
values: rsi(closesOf(bars), params.n)
|
|
527
|
+
}];
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
id: "kdj",
|
|
532
|
+
pane: "sub",
|
|
533
|
+
title: "KDJ",
|
|
534
|
+
params: [{
|
|
535
|
+
key: "n",
|
|
536
|
+
label: "周期",
|
|
537
|
+
default: 9,
|
|
538
|
+
min: 1,
|
|
539
|
+
max: 120
|
|
540
|
+
}],
|
|
541
|
+
compute(bars, params) {
|
|
542
|
+
const { k, d, j } = kdj(bars.map((bar) => bar.high), bars.map((bar) => bar.low), closesOf(bars), params.n);
|
|
543
|
+
return [
|
|
544
|
+
{
|
|
545
|
+
key: "K",
|
|
546
|
+
kind: "line",
|
|
547
|
+
color: "#e6b800",
|
|
548
|
+
values: k
|
|
549
|
+
},
|
|
550
|
+
{
|
|
551
|
+
key: "D",
|
|
552
|
+
kind: "line",
|
|
553
|
+
color: "#4a90e2",
|
|
554
|
+
values: d
|
|
555
|
+
},
|
|
556
|
+
{
|
|
557
|
+
key: "J",
|
|
558
|
+
kind: "line",
|
|
559
|
+
color: "#c05fd8",
|
|
560
|
+
values: j
|
|
561
|
+
}
|
|
562
|
+
];
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
];
|
|
566
|
+
}
|
|
567
|
+
//#endregion
|
|
568
|
+
//#region src/client/index.ts
|
|
569
|
+
function apply(ctx) {
|
|
570
|
+
const registry = createIndicatorRegistry();
|
|
571
|
+
for (const definition of presetDefinitions()) registry.register(definition);
|
|
572
|
+
ctx.reflect.provide("tradingIndicators", registry);
|
|
573
|
+
}
|
|
574
|
+
//#endregion
|
|
575
|
+
exports.apply = apply;
|
|
576
|
+
return module.exports;
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","names":[],"sources":["../../indicators/lib/registry.js","../../indicators/lib/math.js","../../indicators/lib/presets.js","../src/client/index.ts"],"sourcesContent":["//#region src/registry.ts\nfunction createIndicatorRegistry() {\n\tconst registry = /* @__PURE__ */ new Map();\n\tconst listeners = /* @__PURE__ */ new Set();\n\tlet version = 0;\n\tconst register = (definition) => {\n\t\tregistry.set(definition.id, definition);\n\t\tversion += 1;\n\t\tfor (const listener of listeners) listener();\n\t};\n\tconst definitionParams = (id) => registry.get(id)?.params ?? [];\n\treturn {\n\t\tregister,\n\t\tunregister(id) {\n\t\t\tif (!registry.delete(id)) return;\n\t\t\tversion += 1;\n\t\t\tfor (const listener of listeners) listener();\n\t\t},\n\t\tget: (id) => registry.get(id),\n\t\tlist: () => [...registry.values()],\n\t\tdefaultParams(definition) {\n\t\t\tconst params = {};\n\t\t\tfor (const spec of definition.params) params[spec.key] = spec.default;\n\t\t\treturn params;\n\t\t},\n\t\tdefaultInstance(id) {\n\t\t\tconst definition = registry.get(id);\n\t\t\tif (definition === void 0) return void 0;\n\t\t\treturn {\n\t\t\t\tid,\n\t\t\t\tparams: this.defaultParams(definition)\n\t\t\t};\n\t\t},\n\t\tinstanceKey(instance) {\n\t\t\tconst values = definitionParams(instance.id).map((spec) => instance.params[spec.key] ?? spec.default);\n\t\t\treturn `${instance.id}:${values.join(\",\")}`;\n\t\t},\n\t\tclampParams(definition, params) {\n\t\t\tconst out = {};\n\t\t\tfor (const spec of definition.params) {\n\t\t\t\tconst raw = params[spec.key];\n\t\t\t\tout[spec.key] = typeof raw === \"number\" && Number.isFinite(raw) ? Math.min(spec.max, Math.max(spec.min, Math.round(raw))) : spec.default;\n\t\t\t}\n\t\t\treturn out;\n\t\t},\n\t\tsanitizeInstances(instances) {\n\t\t\tif (!Array.isArray(instances)) return [];\n\t\t\tconst seen = /* @__PURE__ */ new Set();\n\t\t\tconst out = [];\n\t\t\tfor (const raw of instances) {\n\t\t\t\tif (typeof raw !== \"object\" || raw === null) continue;\n\t\t\t\tconst { id, params } = raw;\n\t\t\t\tif (typeof id !== \"string\" || seen.has(id)) continue;\n\t\t\t\tconst definition = registry.get(id);\n\t\t\t\tif (definition === void 0) continue;\n\t\t\t\tseen.add(id);\n\t\t\t\tout.push({\n\t\t\t\t\tid,\n\t\t\t\t\tparams: this.clampParams(definition, typeof params === \"object\" && params !== null ? params : {})\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn out;\n\t\t},\n\t\tsubscribe(listener) {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t};\n\t\t},\n\t\tgetVersion: () => version\n\t};\n}\n//#endregion\nexport { createIndicatorRegistry };\n","//#region src/math.ts\n/** 简单移动平均(滚动和,O(n))。 */\nfunction sma(values, period) {\n\tconst out = new Array(values.length).fill(void 0);\n\tif (!valid(period, values.length)) return out;\n\tlet sum = 0;\n\tfor (let index = 0; index < values.length; index++) {\n\t\tsum += values[index];\n\t\tif (index >= period) sum -= values[index - period];\n\t\tif (index >= period - 1) out[index] = sum / period;\n\t}\n\treturn out;\n}\n/** 指数移动平均(标准 EMA:种子 = 前 period 个的 SMA)。 */\nfunction ema(values, period) {\n\tconst out = new Array(values.length).fill(void 0);\n\tif (!valid(period, values.length)) return out;\n\tconst k = 2 / (period + 1);\n\tlet seed = 0;\n\tfor (let index = 0; index < period; index++) seed += values[index];\n\tlet prev = seed / period;\n\tout[period - 1] = prev;\n\tfor (let index = period; index < values.length; index++) {\n\t\tprev = values[index] * k + prev * (1 - k);\n\t\tout[index] = prev;\n\t}\n\treturn out;\n}\n/** 滚动样本标准差(无偏校正关——与主流行情软件一致用总体口径)。 */\nfunction stdev(values, period) {\n\tconst out = new Array(values.length).fill(void 0);\n\tif (!valid(period, values.length)) return out;\n\tfor (let index = period - 1; index < values.length; index++) {\n\t\tlet mean = 0;\n\t\tfor (let offset = 0; offset < period; offset++) mean += values[index - offset];\n\t\tmean /= period;\n\t\tlet variance = 0;\n\t\tfor (let offset = 0; offset < period; offset++) {\n\t\t\tconst delta = values[index - offset] - mean;\n\t\t\tvariance += delta * delta;\n\t\t}\n\t\tout[index] = Math.sqrt(variance / period);\n\t}\n\treturn out;\n}\n/**\n* 布林带:返回中轨(SMA)与上下轨(中轨 ± N 倍标准差)。\n* 主图叠加指标,三条线共享 warm-up。\n*/\nfunction bollinger(values, period, mult) {\n\tconst mid = sma(values, period);\n\tconst sd = stdev(values, period);\n\tconst upper = new Array(values.length).fill(void 0);\n\tconst lower = new Array(values.length).fill(void 0);\n\tfor (let index = 0; index < values.length; index++) {\n\t\tconst base = mid[index];\n\t\tconst dev = sd[index];\n\t\tif (base === void 0 || dev === void 0) continue;\n\t\tupper[index] = base + mult * dev;\n\t\tlower[index] = base - mult * dev;\n\t}\n\treturn {\n\t\tmid,\n\t\tupper,\n\t\tlower\n\t};\n}\n/**\n* MACD:DIF = EMA(fast) - EMA(slow);DEA = DIF 的 EMA(signal);\n* 柱 = (DIF - DEA) × 2。warm-up 取两者较大者(EMA 串联)。\n*/\nfunction macd(values, fast, slow, signal) {\n\tconst emaFast = ema(values, fast);\n\tconst emaSlow = ema(values, slow);\n\tconst dif = values.map((_, index) => {\n\t\tconst a = emaFast[index];\n\t\tconst b = emaSlow[index];\n\t\treturn a === void 0 || b === void 0 ? void 0 : a - b;\n\t});\n\tconst deaCompact = ema(dif.filter((value) => value !== void 0), signal);\n\tconst dea = new Array(values.length).fill(void 0);\n\tlet cursor = 0;\n\tfor (let index = 0; index < values.length; index++) {\n\t\tif (dif[index] === void 0) continue;\n\t\tdea[index] = deaCompact[cursor];\n\t\tcursor++;\n\t}\n\treturn {\n\t\tdif,\n\t\tdea,\n\t\thist: values.map((_, index) => {\n\t\t\tconst d = dif[index];\n\t\t\tconst e = dea[index];\n\t\t\treturn d === void 0 || e === void 0 ? void 0 : (d - e) * 2;\n\t\t})\n\t};\n}\n/**\n* RSI(Wilder 平滑)。种子 = 前 period 个涨跌均值,其后\n* avgGain/avgLoss 递推;前 period 位为 undefined。\n*/\nfunction rsi(values, period) {\n\tconst out = new Array(values.length).fill(void 0);\n\tif (!valid(period, values.length)) return out;\n\tlet gain = 0;\n\tlet loss = 0;\n\tfor (let index = 1; index <= period; index++) {\n\t\tconst delta = values[index] - values[index - 1];\n\t\tif (delta >= 0) gain += delta;\n\t\telse loss -= delta;\n\t}\n\tgain /= period;\n\tloss /= period;\n\tout[period] = loss === 0 ? 100 : 100 - 100 / (1 + gain / loss);\n\tfor (let index = period + 1; index < values.length; index++) {\n\t\tconst delta = values[index] - values[index - 1];\n\t\tgain = (gain * (period - 1) + Math.max(delta, 0)) / period;\n\t\tloss = (loss * (period - 1) + Math.max(-delta, 0)) / period;\n\t\tout[index] = loss === 0 ? 100 : 100 - 100 / (1 + gain / loss);\n\t}\n\treturn out;\n}\n/**\n* KDJ(RSV 的 SMA[Wilder] 平滑,初始值 50)。\n* 返回 k/d/j 三条序列;warm-up = N-1。\n*/\nfunction kdj(highs, lows, closes, n) {\n\tconst length = closes.length;\n\tconst k = new Array(length).fill(void 0);\n\tconst d = new Array(length).fill(void 0);\n\tconst j = new Array(length).fill(void 0);\n\tif (!valid(n, length)) return {\n\t\tk,\n\t\td,\n\t\tj\n\t};\n\tlet prevK = 50;\n\tlet prevD = 50;\n\tfor (let index = n - 1; index < length; index++) {\n\t\tlet hh = -Infinity;\n\t\tlet ll = Infinity;\n\t\tfor (let offset = 0; offset < n; offset++) {\n\t\t\thh = Math.max(hh, highs[index - offset]);\n\t\t\tll = Math.min(ll, lows[index - offset]);\n\t\t}\n\t\tconst rsvValue = hh === ll ? 50 : (closes[index] - ll) / (hh - ll) * 100;\n\t\tprevK = prevK + (rsvValue - prevK) / 3;\n\t\tprevD = prevD + (prevK - prevD) / 3;\n\t\tk[index] = prevK;\n\t\td[index] = prevD;\n\t\tj[index] = 3 * prevK - 2 * prevD;\n\t}\n\treturn {\n\t\tk,\n\t\td,\n\t\tj\n\t};\n}\nfunction valid(period, length) {\n\treturn Number.isFinite(period) && period >= 1 && length >= period;\n}\n//#endregion\nexport { bollinger, ema, kdj, macd, rsi, sma, stdev };\n","import { bollinger, ema, kdj, macd, rsi, sma } from \"./math.js\";\n//#region src/presets.ts\n/** MA 线配色(富途系配色 + 扩展周期轮换调色板)。 */\nconst MA_COLORS = {\n\tMA5: \"#e6b800\",\n\tMA10: \"#4a90e2\",\n\tMA20: \"#c05fd8\",\n\tMA30: \"#2ba471\",\n\tMA60: \"#f97316\",\n\tMA120: \"#0ea5e9\",\n\tMA250: \"#8a8f99\"\n};\n/** EMA 线配色。 */\nconst EMA_COLORS = {\n\tEMA5: \"#e6b800\",\n\tEMA6: \"#e6b800\",\n\tEMA10: \"#4a90e2\",\n\tEMA12: \"#ff9800\",\n\tEMA20: \"#c05fd8\",\n\tEMA26: \"#00bcd4\",\n\tEMA30: \"#2ba471\",\n\tEMA50: \"#2ba471\",\n\tEMA60: \"#f97316\",\n\tEMA120: \"#0ea5e9\",\n\tEMA200: \"#8a8f99\",\n\tEMA250: \"#8a8f99\"\n};\n/** 均线 6 色备用调色板(富途黄/蓝/紫/绿/橙/青)。 */\nconst FALLBACK_PALETTE = [\n\t\"#e6b800\",\n\t\"#4a90e2\",\n\t\"#c05fd8\",\n\t\"#2ba471\",\n\t\"#f97316\",\n\t\"#0ea5e9\"\n];\nfunction maColor(period, index) {\n\treturn MA_COLORS[`MA${period}`] ?? FALLBACK_PALETTE[index % FALLBACK_PALETTE.length] ?? \"#8a8f99\";\n}\nfunction emaColor(period, index) {\n\treturn EMA_COLORS[`EMA${period}`] ?? FALLBACK_PALETTE[index % FALLBACK_PALETTE.length] ?? \"#8a8f99\";\n}\nconst closesOf = (bars) => bars.map((bar) => bar.close);\n/** 六个预置 definition(纯数据,注册时机归消费方)。 */\nfunction presetDefinitions() {\n\treturn [\n\t\t{\n\t\t\tid: \"ma\",\n\t\t\tpane: \"main\",\n\t\t\ttitle: \"MA\",\n\t\t\tparams: [\n\t\t\t\t{\n\t\t\t\t\tkey: \"n1\",\n\t\t\t\t\tlabel: \"周期1\",\n\t\t\t\t\tdefault: 5,\n\t\t\t\t\tmin: 0,\n\t\t\t\t\tmax: 250\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tkey: \"n2\",\n\t\t\t\t\tlabel: \"周期2\",\n\t\t\t\t\tdefault: 10,\n\t\t\t\t\tmin: 0,\n\t\t\t\t\tmax: 250\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tkey: \"n3\",\n\t\t\t\t\tlabel: \"周期3\",\n\t\t\t\t\tdefault: 20,\n\t\t\t\t\tmin: 0,\n\t\t\t\t\tmax: 250\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tkey: \"n4\",\n\t\t\t\t\tlabel: \"周期4\",\n\t\t\t\t\tdefault: 30,\n\t\t\t\t\tmin: 0,\n\t\t\t\t\tmax: 250\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tkey: \"n5\",\n\t\t\t\t\tlabel: \"周期5\",\n\t\t\t\t\tdefault: 60,\n\t\t\t\t\tmin: 0,\n\t\t\t\t\tmax: 250\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tkey: \"n6\",\n\t\t\t\t\tlabel: \"周期6\",\n\t\t\t\t\tdefault: 120,\n\t\t\t\t\tmin: 0,\n\t\t\t\t\tmax: 250\n\t\t\t\t}\n\t\t\t],\n\t\t\tcompute(bars, params) {\n\t\t\t\tconst closes = closesOf(bars);\n\t\t\t\treturn [\n\t\t\t\t\tparams.n1,\n\t\t\t\t\tparams.n2,\n\t\t\t\t\tparams.n3,\n\t\t\t\t\tparams.n4,\n\t\t\t\t\tparams.n5,\n\t\t\t\t\tparams.n6\n\t\t\t\t].filter((period) => typeof period === \"number\" && Number.isFinite(period) && period > 0).map((period, index) => ({\n\t\t\t\t\tkey: `MA${period}`,\n\t\t\t\t\tkind: \"line\",\n\t\t\t\t\tcolor: maColor(period, index),\n\t\t\t\t\tvalues: sma(closes, period)\n\t\t\t\t}));\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tid: \"ema\",\n\t\t\tpane: \"main\",\n\t\t\ttitle: \"EMA\",\n\t\t\tparams: [\n\t\t\t\t{\n\t\t\t\t\tkey: \"n1\",\n\t\t\t\t\tlabel: \"周期1\",\n\t\t\t\t\tdefault: 5,\n\t\t\t\t\tmin: 0,\n\t\t\t\t\tmax: 250\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tkey: \"n2\",\n\t\t\t\t\tlabel: \"周期2\",\n\t\t\t\t\tdefault: 10,\n\t\t\t\t\tmin: 0,\n\t\t\t\t\tmax: 250\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tkey: \"n3\",\n\t\t\t\t\tlabel: \"周期3\",\n\t\t\t\t\tdefault: 20,\n\t\t\t\t\tmin: 0,\n\t\t\t\t\tmax: 250\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tkey: \"n4\",\n\t\t\t\t\tlabel: \"周期4\",\n\t\t\t\t\tdefault: 30,\n\t\t\t\t\tmin: 0,\n\t\t\t\t\tmax: 250\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tkey: \"n5\",\n\t\t\t\t\tlabel: \"周期5\",\n\t\t\t\t\tdefault: 60,\n\t\t\t\t\tmin: 0,\n\t\t\t\t\tmax: 250\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tkey: \"n6\",\n\t\t\t\t\tlabel: \"周期6\",\n\t\t\t\t\tdefault: 120,\n\t\t\t\t\tmin: 0,\n\t\t\t\t\tmax: 250\n\t\t\t\t}\n\t\t\t],\n\t\t\tcompute(bars, params) {\n\t\t\t\tconst closes = closesOf(bars);\n\t\t\t\treturn [\n\t\t\t\t\tparams.n1,\n\t\t\t\t\tparams.n2,\n\t\t\t\t\tparams.n3,\n\t\t\t\t\tparams.n4,\n\t\t\t\t\tparams.n5,\n\t\t\t\t\tparams.n6\n\t\t\t\t].filter((period) => typeof period === \"number\" && Number.isFinite(period) && period > 0).map((period, index) => ({\n\t\t\t\t\tkey: `EMA${period}`,\n\t\t\t\t\tkind: \"line\",\n\t\t\t\t\tcolor: emaColor(period, index),\n\t\t\t\t\tvalues: ema(closes, period)\n\t\t\t\t}));\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tid: \"boll\",\n\t\t\tpane: \"main\",\n\t\t\ttitle: \"BOLL\",\n\t\t\tparams: [{\n\t\t\t\tkey: \"n\",\n\t\t\t\tlabel: \"周期\",\n\t\t\t\tdefault: 20,\n\t\t\t\tmin: 2,\n\t\t\t\tmax: 250\n\t\t\t}, {\n\t\t\t\tkey: \"k\",\n\t\t\t\tlabel: \"倍数\",\n\t\t\t\tdefault: 2,\n\t\t\t\tmin: 1,\n\t\t\t\tmax: 5\n\t\t\t}],\n\t\t\tcompute(bars, params) {\n\t\t\t\tconst { mid, upper, lower } = bollinger(closesOf(bars), params.n, params.k);\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: \"MID\",\n\t\t\t\t\t\tkind: \"line\",\n\t\t\t\t\t\tcolor: \"#8a8f99\",\n\t\t\t\t\t\tvalues: mid\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: \"UP\",\n\t\t\t\t\t\tkind: \"line\",\n\t\t\t\t\t\tcolor: \"#4a90e2\",\n\t\t\t\t\t\tvalues: upper\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: \"LOW\",\n\t\t\t\t\t\tkind: \"line\",\n\t\t\t\t\t\tcolor: \"#4a90e2\",\n\t\t\t\t\t\tvalues: lower\n\t\t\t\t\t}\n\t\t\t\t];\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tid: \"macd\",\n\t\t\tpane: \"sub\",\n\t\t\ttitle: \"MACD\",\n\t\t\tparams: [\n\t\t\t\t{\n\t\t\t\t\tkey: \"fast\",\n\t\t\t\t\tlabel: \"快线\",\n\t\t\t\t\tdefault: 12,\n\t\t\t\t\tmin: 2,\n\t\t\t\t\tmax: 100\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tkey: \"slow\",\n\t\t\t\t\tlabel: \"慢线\",\n\t\t\t\t\tdefault: 26,\n\t\t\t\t\tmin: 2,\n\t\t\t\t\tmax: 200\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tkey: \"signal\",\n\t\t\t\t\tlabel: \"信号\",\n\t\t\t\t\tdefault: 9,\n\t\t\t\t\tmin: 1,\n\t\t\t\t\tmax: 60\n\t\t\t\t}\n\t\t\t],\n\t\t\tcompute(bars, params) {\n\t\t\t\tconst { dif, dea, hist } = macd(closesOf(bars), params.fast, params.slow, params.signal);\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: \"DIF\",\n\t\t\t\t\t\tkind: \"line\",\n\t\t\t\t\t\tcolor: \"#e6b800\",\n\t\t\t\t\t\tvalues: dif\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: \"DEA\",\n\t\t\t\t\t\tkind: \"line\",\n\t\t\t\t\t\tcolor: \"#4a90e2\",\n\t\t\t\t\t\tvalues: dea\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: \"HIST\",\n\t\t\t\t\t\tkind: \"histogram\",\n\t\t\t\t\t\tcolor: \"#8a8f99\",\n\t\t\t\t\t\tvalues: hist,\n\t\t\t\t\t\thistogramBySign: true\n\t\t\t\t\t}\n\t\t\t\t];\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tid: \"rsi\",\n\t\t\tpane: \"sub\",\n\t\t\ttitle: \"RSI\",\n\t\t\tparams: [{\n\t\t\t\tkey: \"n\",\n\t\t\t\tlabel: \"周期\",\n\t\t\t\tdefault: 14,\n\t\t\t\tmin: 2,\n\t\t\t\tmax: 120\n\t\t\t}],\n\t\t\tcompute(bars, params) {\n\t\t\t\treturn [{\n\t\t\t\t\tkey: `RSI${params.n}`,\n\t\t\t\t\tkind: \"line\",\n\t\t\t\t\tcolor: \"#c05fd8\",\n\t\t\t\t\tvalues: rsi(closesOf(bars), params.n)\n\t\t\t\t}];\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tid: \"kdj\",\n\t\t\tpane: \"sub\",\n\t\t\ttitle: \"KDJ\",\n\t\t\tparams: [{\n\t\t\t\tkey: \"n\",\n\t\t\t\tlabel: \"周期\",\n\t\t\t\tdefault: 9,\n\t\t\t\tmin: 1,\n\t\t\t\tmax: 120\n\t\t\t}],\n\t\t\tcompute(bars, params) {\n\t\t\t\tconst highs = bars.map((bar) => bar.high);\n\t\t\t\tconst lows = bars.map((bar) => bar.low);\n\t\t\t\tconst { k, d, j } = kdj(highs, lows, closesOf(bars), params.n);\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: \"K\",\n\t\t\t\t\t\tkind: \"line\",\n\t\t\t\t\t\tcolor: \"#e6b800\",\n\t\t\t\t\t\tvalues: k\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: \"D\",\n\t\t\t\t\t\tkind: \"line\",\n\t\t\t\t\t\tcolor: \"#4a90e2\",\n\t\t\t\t\t\tvalues: d\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: \"J\",\n\t\t\t\t\t\tkind: \"line\",\n\t\t\t\t\t\tcolor: \"#c05fd8\",\n\t\t\t\t\t\tvalues: j\n\t\t\t\t\t}\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\t];\n}\n//#endregion\nexport { EMA_COLORS, MA_COLORS, presetDefinitions };\n","/**\n * 预置指标提供插件(client 半):在 client 上下文提供 tradingIndicators\n * 服务 = IndicatorRegistry 单例(注册六个预置指标)。机制先例 =\n * session-controller 的 `reflect.provide('sessions')`(dsh\n * packages/api/session-controller/src/client/sessions/service.ts:263)。\n *\n * 社区指标插件的接入方式:client 半 `ctx.inject(['tradingIndicators'],\n * scope => scope.tradingIndicators.register(definition))` —— 服务可用时\n * 回调才触发,加载顺序由 cordis 依赖解析保证;与本插件零耦合。\n *\n * 消费方 client-ui-trading 以可选依赖桥接(同样 ctx.inject),插件未\n * 安装时行情视图零指标正常工作。\n */\nimport type { Context } from '@deepseek-ai/cordis'\nimport { createIndicatorRegistry, presetDefinitions } from '@dshtrading/indicators'\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n /** dsh-trading 技术指标注册表(社区指标经 ctx.inject 消费后 register)。 */\n tradingIndicators: import('@dshtrading/indicators').IndicatorRegistry\n }\n}\n\nexport function apply(ctx: Context): void {\n const registry = createIndicatorRegistry()\n for (const definition of presetDefinitions()) registry.register(definition)\n // provide 由插件 fiber 持有:插件卸载/重载时服务随之注销/重建。\n ctx.reflect.provide('tradingIndicators', registry)\n}\n"],"mappings":"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"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/index.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* client-ui-indicators node half. The empty apply exists so the plugin
|
|
4
|
+
* appears in the host cordis.yml / Loader (same pattern as
|
|
5
|
+
* client-ui-settings); the browser half owns the tradingIndicators service
|
|
6
|
+
* through exports["./client"], discovered from the package.json dsh.client
|
|
7
|
+
* declaration. All indicator logic lives in @dshtrading/indicators.
|
|
8
|
+
*/
|
|
9
|
+
/** Host plugin body — no host-side behavior for this surface plugin. */
|
|
10
|
+
declare function apply(): void;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { apply };
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* client-ui-indicators node half. The empty apply exists so the plugin
|
|
4
|
+
* appears in the host cordis.yml / Loader (same pattern as
|
|
5
|
+
* client-ui-settings); the browser half owns the tradingIndicators service
|
|
6
|
+
* through exports["./client"], discovered from the package.json dsh.client
|
|
7
|
+
* declaration. All indicator logic lives in @dshtrading/indicators.
|
|
8
|
+
*/
|
|
9
|
+
/** Host plugin body — no host-side behavior for this surface plugin. */
|
|
10
|
+
function apply() {}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { apply };
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dshtrading/client-ui-indicators",
|
|
3
|
+
"description": "Technical indicator provider plugin for dsh-trading: provides the tradingIndicators service (IndicatorRegistry with six presets MA/EMA/BOLL/MACD/RSI/KDJ) on the client context. Community indicators consume the same service via ctx.inject. Node half is a host loader placeholder; the browser half owns the service.",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "lib/index.js",
|
|
7
|
+
"types": "./lib/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./lib/index.d.ts",
|
|
11
|
+
"default": "./lib/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./client": {
|
|
14
|
+
"types": "./lib/types/client/index.d.ts",
|
|
15
|
+
"default": "./lib/client.js"
|
|
16
|
+
},
|
|
17
|
+
"./package.json": "./package.json"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"lib"
|
|
21
|
+
],
|
|
22
|
+
"license": "PolyForm-Noncommercial-1.0.0",
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@dshtrading/indicators": "^0.1.0"
|
|
25
|
+
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"@deepseek-ai/cordis": ">=4.0.0"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"tsdown": "^0.22.0",
|
|
31
|
+
"vitest": "^3.0.0",
|
|
32
|
+
"typescript": "^5.5.0"
|
|
33
|
+
},
|
|
34
|
+
"dsh": {
|
|
35
|
+
"client": {
|
|
36
|
+
"inject": [],
|
|
37
|
+
"platform": "web"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsdown && tsdown --config tsdown.client.config.mjs",
|
|
42
|
+
"test": "vitest run"
|
|
43
|
+
}
|
|
44
|
+
}
|