@ch20026103/anysis 0.0.19-alpha1 → 0.0.19-beta

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.
@@ -0,0 +1,28 @@
1
+ import { StockListType, StockType } from "./types";
2
+ export type DmiResType = {
3
+ dataset: StockListType;
4
+ pDi: number;
5
+ mDi: number;
6
+ adx: number;
7
+ type: number;
8
+ smoothTr: number;
9
+ smoothPdm: number;
10
+ smoothMdm: number;
11
+ dxBuffer: number[];
12
+ smoothAdx: number;
13
+ };
14
+ export default class Dmi {
15
+ init(data: StockType, type: number): DmiResType;
16
+ next(data: StockType, preList: DmiResType, type: number): DmiResType;
17
+ calculateDmiValues(list: StockListType, period?: number): {
18
+ pDi: number;
19
+ mDi: number;
20
+ adx: number;
21
+ c: number;
22
+ v: number;
23
+ l: number;
24
+ h: number;
25
+ o: number;
26
+ t: number;
27
+ }[];
28
+ }
@@ -0,0 +1,206 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
14
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
15
+ if (ar || !(i in from)) {
16
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
17
+ ar[i] = from[i];
18
+ }
19
+ }
20
+ return to.concat(ar || Array.prototype.slice.call(from));
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ var Dmi = /** @class */ (function () {
24
+ function Dmi() {
25
+ }
26
+ Object.defineProperty(Dmi.prototype, "init", {
27
+ enumerable: false,
28
+ configurable: true,
29
+ writable: true,
30
+ value: function (data, type) {
31
+ return {
32
+ dataset: [data],
33
+ pDi: 0,
34
+ mDi: 0,
35
+ adx: 0,
36
+ type: type,
37
+ smoothTr: 0,
38
+ smoothPdm: 0,
39
+ smoothMdm: 0,
40
+ dxBuffer: [],
41
+ smoothAdx: 0,
42
+ };
43
+ }
44
+ });
45
+ Object.defineProperty(Dmi.prototype, "next", {
46
+ enumerable: false,
47
+ configurable: true,
48
+ writable: true,
49
+ value: function (data, preList, type) {
50
+ preList.dataset.push(data);
51
+ // Need type + 1 data points to have 'type' periods of change
52
+ if (preList.dataset.length < type + 1) {
53
+ return __assign(__assign({}, preList), { pDi: 0, mDi: 0, adx: 0 });
54
+ }
55
+ else {
56
+ var currentTr = 0;
57
+ var currentPdm = 0;
58
+ var currentMdm = 0;
59
+ // Logic to get TR, +DM, -DM for the NEWEST data point
60
+ // We need the newest point and the one before it.
61
+ // If we are in the initialization phase (length === type + 1), we process the whole window.
62
+ // If we are in the incremental phase (length > type + 1), we just process the last step.
63
+ var newSmoothTr = preList.smoothTr;
64
+ var newSmoothPdm = preList.smoothPdm;
65
+ var newSmoothMdm = preList.smoothMdm;
66
+ if (preList.dataset.length === type + 1) {
67
+ // Initialization: Calculate sum of first N periods (using N+1 data points)
68
+ var sumTr = 0;
69
+ var sumPdm = 0;
70
+ var sumMdm = 0;
71
+ for (var i = 1; i <= type; i++) {
72
+ var curr = preList.dataset[i];
73
+ var prev = preList.dataset[i - 1];
74
+ // TR
75
+ var hl = curr.h - curr.l;
76
+ var hpc = Math.abs(curr.h - prev.c);
77
+ var lpc = Math.abs(curr.l - prev.c);
78
+ var tr = Math.max(hl, hpc, lpc);
79
+ // DM
80
+ var hph = curr.h - prev.h;
81
+ var pll = prev.l - curr.l;
82
+ var pdm = 0;
83
+ var mdm = 0;
84
+ if (hph > pll && hph > 0) {
85
+ pdm = hph;
86
+ }
87
+ if (pll > hph && pll > 0) {
88
+ mdm = pll;
89
+ }
90
+ sumTr += tr;
91
+ sumPdm += pdm;
92
+ sumMdm += mdm;
93
+ }
94
+ // Wilder's first value is often just the Sum.
95
+ // But to make it consistent with the "Average" view for the formula:
96
+ // NextAvg = (PrevAvg * (N-1) + Curr) / N
97
+ // The first "PrevAvg" acts as the seed. The seed is usually the Simple Average.
98
+ // So we divide by type.
99
+ newSmoothTr = sumTr; // Some sources say keep Sum. But standard indicators often normalize to Average range.
100
+ // Let's check RSI implementation. RSI divides by type: gains / type.
101
+ // So we will divide by type to get the Average TR/DM.
102
+ // Wait! DMI standard often keeps the SUM for the first value?
103
+ // Wilder's book: "+DM14 is the sum of the +DM for the last 14 days".
104
+ // Then subsequent: "+DM14_today = +DM14_yesterday - (+DM14_yesterday/14) + +DM_today".
105
+ // This formula maintains the "Sum" magnitude (approx 14x the average).
106
+ // BUT, RSI implementation uses Average magnitude (0-100 range inputs usually lead to small AvgGain).
107
+ // Let's stick to the RSI pattern: Average.
108
+ // Formula: (Avg * (N-1) + Curr) / N. This maintains "Average" magnitude.
109
+ // If we used Sum logic: (Sum - Sum/N + Curr) = Sum * (1 - 1/N) + Curr.
110
+ // These are mathematically consistent in shape, just scaled by N.
111
+ // DI calculation is (Pdm / Tr) * 100. The scale cancels out!
112
+ // So using Average is safer for preventing overflow and easier to debug (per-day values).
113
+ newSmoothTr = sumTr / type;
114
+ newSmoothPdm = sumPdm / type;
115
+ newSmoothMdm = sumMdm / type;
116
+ }
117
+ else {
118
+ // Shift if needed to keep dataset size manageable, though strictly we only need last 2 points
119
+ // reusing rsi pattern:
120
+ if (preList.dataset.length > type + 1) {
121
+ preList.dataset.shift();
122
+ }
123
+ var curr = preList.dataset[preList.dataset.length - 1];
124
+ var prev = preList.dataset[preList.dataset.length - 2];
125
+ // TR
126
+ var hl = curr.h - curr.l;
127
+ var hpc = Math.abs(curr.h - prev.c);
128
+ var lpc = Math.abs(curr.l - prev.c);
129
+ var tr = Math.max(hl, hpc, lpc);
130
+ // DM
131
+ var hph = curr.h - prev.h;
132
+ var pll = prev.l - curr.l;
133
+ var pdm = 0;
134
+ var mdm = 0;
135
+ if (hph > pll && hph > 0)
136
+ pdm = hph;
137
+ if (pll > hph && pll > 0)
138
+ mdm = pll;
139
+ // Wilder's Smoothing (Average form)
140
+ newSmoothTr = (preList.smoothTr * (type - 1) + tr) / type;
141
+ newSmoothPdm = (preList.smoothPdm * (type - 1) + pdm) / type;
142
+ newSmoothMdm = (preList.smoothMdm * (type - 1) + mdm) / type;
143
+ }
144
+ // Calculate DI
145
+ // Avoid division by zero
146
+ var pDi = newSmoothTr === 0 ? 0 : (newSmoothPdm / newSmoothTr) * 100;
147
+ var mDi = newSmoothTr === 0 ? 0 : (newSmoothMdm / newSmoothTr) * 100;
148
+ // Calculate DX
149
+ var diDiff = Math.abs(pDi - mDi);
150
+ var diSum = pDi + mDi;
151
+ var dx = diSum === 0 ? 0 : (diDiff / diSum) * 100;
152
+ // ADX Logic
153
+ var dxBuffer = __spreadArray([], preList.dxBuffer, true);
154
+ var adx = preList.adx;
155
+ var newSmoothAdx = preList.smoothAdx;
156
+ if (dxBuffer.length < type) {
157
+ dxBuffer.push(dx);
158
+ // Special case: if we Just reached 'type' count, we can calc initial ADX
159
+ if (dxBuffer.length === type) {
160
+ // First ADX is average of the DX buffer?
161
+ // "ADX is the 14-day smoothed average of DX".
162
+ // First value is simple average of previous 14 DX values.
163
+ var sumDx = dxBuffer.reduce(function (a, b) { return a + b; }, 0);
164
+ newSmoothAdx = sumDx / type;
165
+ adx = newSmoothAdx;
166
+ }
167
+ else {
168
+ // Not enough data for ADX yet
169
+ adx = 0;
170
+ }
171
+ }
172
+ else {
173
+ // We already have ADX initialized, so we smooth it
174
+ // Note: we don't need to keep growing dxBuffer indefinitely.
175
+ // We just needed it for startup.
176
+ // Update ADX using Wilder's smoothing
177
+ newSmoothAdx = (preList.smoothAdx * (type - 1) + dx) / type;
178
+ adx = newSmoothAdx;
179
+ }
180
+ return __assign(__assign({}, preList), { pDi: pDi, // +DI
181
+ mDi: mDi, // -DI
182
+ adx: adx, smoothTr: newSmoothTr, smoothPdm: newSmoothPdm, smoothMdm: newSmoothMdm, dxBuffer: dxBuffer, smoothAdx: newSmoothAdx });
183
+ }
184
+ }
185
+ });
186
+ // Helper to get formatted results similar to ma.ts
187
+ Object.defineProperty(Dmi.prototype, "calculateDmiValues", {
188
+ enumerable: false,
189
+ configurable: true,
190
+ writable: true,
191
+ value: function (list, period) {
192
+ if (period === void 0) { period = 14; }
193
+ var res = [];
194
+ var state = this.init(list[0], period);
195
+ // First point (index 0) has 0 DMI
196
+ res.push(__assign(__assign({}, list[0]), { pDi: 0, mDi: 0, adx: 0 }));
197
+ for (var i = 1; i < list.length; i++) {
198
+ state = this.next(list[i], state, period);
199
+ res.push(__assign(__assign({}, list[i]), { pDi: state.pDi, mDi: state.mDi, adx: state.adx }));
200
+ }
201
+ return res;
202
+ }
203
+ });
204
+ return Dmi;
205
+ }());
206
+ exports.default = Dmi;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ var dmi_1 = require("./dmi");
4
+ var test_data_test_1 = require("./test_data.test");
5
+ describe("test dmi methods", function () {
6
+ it("test init & next", function () {
7
+ var dmi = new dmi_1.default();
8
+ var period = 14;
9
+ // Calculate all values using loop
10
+ var results = dmi.calculateDmiValues(test_data_test_1.default, period);
11
+ var lastResult = results[results.length - 1];
12
+ // Verify consistency
13
+ // Re-run step-by-step
14
+ var state = dmi.init(test_data_test_1.default[0], period);
15
+ for (var i = 1; i < test_data_test_1.default.length; i++) {
16
+ state = dmi.next(test_data_test_1.default[i], state, period);
17
+ }
18
+ expect(state.pDi).toEqual(lastResult.pDi);
19
+ expect(state.mDi).toEqual(lastResult.mDi);
20
+ expect(state.adx).toEqual(lastResult.adx);
21
+ });
22
+ it("test values consistency (basic sanity)", function () {
23
+ // Generate a simple synthetic dataset where Trend is obvious
24
+ // Upward trend -> +DI should be high, -DI low
25
+ var upTrendData = [];
26
+ for (var i = 0; i < 50; i++) {
27
+ upTrendData.push({
28
+ c: 10 + i,
29
+ h: 11 + i,
30
+ l: 9 + i,
31
+ o: 10 + i,
32
+ v: 1000,
33
+ t: 20210101 + i,
34
+ });
35
+ }
36
+ var dmi = new dmi_1.default();
37
+ var res = dmi.calculateDmiValues(upTrendData, 14);
38
+ var last = res[res.length - 1];
39
+ // +DI should be dominant
40
+ expect(last.pDi).toBeGreaterThan(last.mDi);
41
+ // ADX should be high (strong trend)
42
+ expect(last.adx).toBeGreaterThan(20);
43
+ });
44
+ it("test flat trend", function () {
45
+ // Flat data
46
+ var flatData = [];
47
+ for (var i = 0; i < 50; i++) {
48
+ flatData.push({
49
+ c: 10,
50
+ h: 11,
51
+ l: 9,
52
+ o: 10,
53
+ v: 1000,
54
+ t: 20210101 + i,
55
+ });
56
+ }
57
+ var dmi = new dmi_1.default();
58
+ var res = dmi.calculateDmiValues(flatData, 14);
59
+ var last = res[res.length - 1];
60
+ // No directional movement
61
+ // h-ph = 0, pl-l = 0.
62
+ // +DM = 0, -DM = 0.
63
+ // +DI = 0, -DI = 0.
64
+ // ADX = 0?
65
+ // DX = 0.
66
+ expect(last.pDi).toEqual(0);
67
+ expect(last.mDi).toEqual(0);
68
+ // ADX might be 0 or close to 0
69
+ expect(last.adx).toEqual(0);
70
+ });
71
+ });
@@ -15,7 +15,7 @@ interface IchimokuType {
15
15
  init: (data: NewStockType) => IchimokuResType;
16
16
  next: (data: NewStockType, preList: IchimokuResType) => IchimokuResType;
17
17
  }
18
- export default class IchimokuCloud implements IchimokuType {
18
+ export default class Ichimoku implements IchimokuType {
19
19
  init(data: NewStockType): IchimokuResType;
20
20
  /**
21
21
  * 優化說明:
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- var IchimokuCloud = /** @class */ (function () {
4
- function IchimokuCloud() {
3
+ var Ichimoku = /** @class */ (function () {
4
+ function Ichimoku() {
5
5
  }
6
- Object.defineProperty(IchimokuCloud.prototype, "init", {
6
+ Object.defineProperty(Ichimoku.prototype, "init", {
7
7
  enumerable: false,
8
8
  configurable: true,
9
9
  writable: true,
@@ -21,7 +21,7 @@ var IchimokuCloud = /** @class */ (function () {
21
21
  * 如果你的框架 (如 React state) 強制要求 immutable,則需要改回 [...prev, data] 的寫法。
22
22
  * 下面的寫法假設可以 Mutation (這在 Class 內部運算或 Backend 處理很常見)。
23
23
  */
24
- Object.defineProperty(IchimokuCloud.prototype, "next", {
24
+ Object.defineProperty(Ichimoku.prototype, "next", {
25
25
  enumerable: false,
26
26
  configurable: true,
27
27
  writable: true,
@@ -38,7 +38,7 @@ var IchimokuCloud = /** @class */ (function () {
38
38
  }
39
39
  });
40
40
  // 核心計算邏輯
41
- Object.defineProperty(IchimokuCloud.prototype, "calcIchimoku", {
41
+ Object.defineProperty(Ichimoku.prototype, "calcIchimoku", {
42
42
  enumerable: false,
43
43
  configurable: true,
44
44
  writable: true,
@@ -66,7 +66,7 @@ var IchimokuCloud = /** @class */ (function () {
66
66
  * 1. 移除 .slice(),避免產生 Garbage Collection。
67
67
  * 2. 使用反向迴圈 (i--),通常在 JS 引擎中微幅快一點,且語意上是「從現在往回看」。
68
68
  */
69
- Object.defineProperty(IchimokuCloud.prototype, "getMidPrice", {
69
+ Object.defineProperty(Ichimoku.prototype, "getMidPrice", {
70
70
  enumerable: false,
71
71
  configurable: true,
72
72
  writable: true,
@@ -91,6 +91,6 @@ var IchimokuCloud = /** @class */ (function () {
91
91
  return (maxH + minL) / 2;
92
92
  }
93
93
  });
94
- return IchimokuCloud;
94
+ return Ichimoku;
95
95
  }());
96
- exports.default = IchimokuCloud;
96
+ exports.default = Ichimoku;
@@ -17,7 +17,7 @@ var ichimoku_1 = require("./ichimoku");
17
17
  var createStock = function (idx, override) {
18
18
  return __assign({ t: idx, o: 100, c: 100, h: 100, l: 100, v: 1000 }, override);
19
19
  };
20
- (0, vitest_1.describe)("IchimokuCloud Algo", function () {
20
+ (0, vitest_1.describe)("Ichimoku Algo", function () {
21
21
  var ichimoku;
22
22
  (0, vitest_1.beforeEach)(function () {
23
23
  ichimoku = new ichimoku_1.default();
@@ -0,0 +1,28 @@
1
+ import { StockListType, StockType } from "./types";
2
+ export type DmiResType = {
3
+ dataset: StockListType;
4
+ pDi: number;
5
+ mDi: number;
6
+ adx: number;
7
+ type: number;
8
+ smoothTr: number;
9
+ smoothPdm: number;
10
+ smoothMdm: number;
11
+ dxBuffer: number[];
12
+ smoothAdx: number;
13
+ };
14
+ export default class Dmi {
15
+ init(data: StockType, type: number): DmiResType;
16
+ next(data: StockType, preList: DmiResType, type: number): DmiResType;
17
+ calculateDmiValues(list: StockListType, period?: number): {
18
+ pDi: number;
19
+ mDi: number;
20
+ adx: number;
21
+ c: number;
22
+ v: number;
23
+ l: number;
24
+ h: number;
25
+ o: number;
26
+ t: number;
27
+ }[];
28
+ }
@@ -0,0 +1,204 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
13
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
14
+ if (ar || !(i in from)) {
15
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
16
+ ar[i] = from[i];
17
+ }
18
+ }
19
+ return to.concat(ar || Array.prototype.slice.call(from));
20
+ };
21
+ var Dmi = /** @class */ (function () {
22
+ function Dmi() {
23
+ }
24
+ Object.defineProperty(Dmi.prototype, "init", {
25
+ enumerable: false,
26
+ configurable: true,
27
+ writable: true,
28
+ value: function (data, type) {
29
+ return {
30
+ dataset: [data],
31
+ pDi: 0,
32
+ mDi: 0,
33
+ adx: 0,
34
+ type: type,
35
+ smoothTr: 0,
36
+ smoothPdm: 0,
37
+ smoothMdm: 0,
38
+ dxBuffer: [],
39
+ smoothAdx: 0,
40
+ };
41
+ }
42
+ });
43
+ Object.defineProperty(Dmi.prototype, "next", {
44
+ enumerable: false,
45
+ configurable: true,
46
+ writable: true,
47
+ value: function (data, preList, type) {
48
+ preList.dataset.push(data);
49
+ // Need type + 1 data points to have 'type' periods of change
50
+ if (preList.dataset.length < type + 1) {
51
+ return __assign(__assign({}, preList), { pDi: 0, mDi: 0, adx: 0 });
52
+ }
53
+ else {
54
+ var currentTr = 0;
55
+ var currentPdm = 0;
56
+ var currentMdm = 0;
57
+ // Logic to get TR, +DM, -DM for the NEWEST data point
58
+ // We need the newest point and the one before it.
59
+ // If we are in the initialization phase (length === type + 1), we process the whole window.
60
+ // If we are in the incremental phase (length > type + 1), we just process the last step.
61
+ var newSmoothTr = preList.smoothTr;
62
+ var newSmoothPdm = preList.smoothPdm;
63
+ var newSmoothMdm = preList.smoothMdm;
64
+ if (preList.dataset.length === type + 1) {
65
+ // Initialization: Calculate sum of first N periods (using N+1 data points)
66
+ var sumTr = 0;
67
+ var sumPdm = 0;
68
+ var sumMdm = 0;
69
+ for (var i = 1; i <= type; i++) {
70
+ var curr = preList.dataset[i];
71
+ var prev = preList.dataset[i - 1];
72
+ // TR
73
+ var hl = curr.h - curr.l;
74
+ var hpc = Math.abs(curr.h - prev.c);
75
+ var lpc = Math.abs(curr.l - prev.c);
76
+ var tr = Math.max(hl, hpc, lpc);
77
+ // DM
78
+ var hph = curr.h - prev.h;
79
+ var pll = prev.l - curr.l;
80
+ var pdm = 0;
81
+ var mdm = 0;
82
+ if (hph > pll && hph > 0) {
83
+ pdm = hph;
84
+ }
85
+ if (pll > hph && pll > 0) {
86
+ mdm = pll;
87
+ }
88
+ sumTr += tr;
89
+ sumPdm += pdm;
90
+ sumMdm += mdm;
91
+ }
92
+ // Wilder's first value is often just the Sum.
93
+ // But to make it consistent with the "Average" view for the formula:
94
+ // NextAvg = (PrevAvg * (N-1) + Curr) / N
95
+ // The first "PrevAvg" acts as the seed. The seed is usually the Simple Average.
96
+ // So we divide by type.
97
+ newSmoothTr = sumTr; // Some sources say keep Sum. But standard indicators often normalize to Average range.
98
+ // Let's check RSI implementation. RSI divides by type: gains / type.
99
+ // So we will divide by type to get the Average TR/DM.
100
+ // Wait! DMI standard often keeps the SUM for the first value?
101
+ // Wilder's book: "+DM14 is the sum of the +DM for the last 14 days".
102
+ // Then subsequent: "+DM14_today = +DM14_yesterday - (+DM14_yesterday/14) + +DM_today".
103
+ // This formula maintains the "Sum" magnitude (approx 14x the average).
104
+ // BUT, RSI implementation uses Average magnitude (0-100 range inputs usually lead to small AvgGain).
105
+ // Let's stick to the RSI pattern: Average.
106
+ // Formula: (Avg * (N-1) + Curr) / N. This maintains "Average" magnitude.
107
+ // If we used Sum logic: (Sum - Sum/N + Curr) = Sum * (1 - 1/N) + Curr.
108
+ // These are mathematically consistent in shape, just scaled by N.
109
+ // DI calculation is (Pdm / Tr) * 100. The scale cancels out!
110
+ // So using Average is safer for preventing overflow and easier to debug (per-day values).
111
+ newSmoothTr = sumTr / type;
112
+ newSmoothPdm = sumPdm / type;
113
+ newSmoothMdm = sumMdm / type;
114
+ }
115
+ else {
116
+ // Shift if needed to keep dataset size manageable, though strictly we only need last 2 points
117
+ // reusing rsi pattern:
118
+ if (preList.dataset.length > type + 1) {
119
+ preList.dataset.shift();
120
+ }
121
+ var curr = preList.dataset[preList.dataset.length - 1];
122
+ var prev = preList.dataset[preList.dataset.length - 2];
123
+ // TR
124
+ var hl = curr.h - curr.l;
125
+ var hpc = Math.abs(curr.h - prev.c);
126
+ var lpc = Math.abs(curr.l - prev.c);
127
+ var tr = Math.max(hl, hpc, lpc);
128
+ // DM
129
+ var hph = curr.h - prev.h;
130
+ var pll = prev.l - curr.l;
131
+ var pdm = 0;
132
+ var mdm = 0;
133
+ if (hph > pll && hph > 0)
134
+ pdm = hph;
135
+ if (pll > hph && pll > 0)
136
+ mdm = pll;
137
+ // Wilder's Smoothing (Average form)
138
+ newSmoothTr = (preList.smoothTr * (type - 1) + tr) / type;
139
+ newSmoothPdm = (preList.smoothPdm * (type - 1) + pdm) / type;
140
+ newSmoothMdm = (preList.smoothMdm * (type - 1) + mdm) / type;
141
+ }
142
+ // Calculate DI
143
+ // Avoid division by zero
144
+ var pDi = newSmoothTr === 0 ? 0 : (newSmoothPdm / newSmoothTr) * 100;
145
+ var mDi = newSmoothTr === 0 ? 0 : (newSmoothMdm / newSmoothTr) * 100;
146
+ // Calculate DX
147
+ var diDiff = Math.abs(pDi - mDi);
148
+ var diSum = pDi + mDi;
149
+ var dx = diSum === 0 ? 0 : (diDiff / diSum) * 100;
150
+ // ADX Logic
151
+ var dxBuffer = __spreadArray([], preList.dxBuffer, true);
152
+ var adx = preList.adx;
153
+ var newSmoothAdx = preList.smoothAdx;
154
+ if (dxBuffer.length < type) {
155
+ dxBuffer.push(dx);
156
+ // Special case: if we Just reached 'type' count, we can calc initial ADX
157
+ if (dxBuffer.length === type) {
158
+ // First ADX is average of the DX buffer?
159
+ // "ADX is the 14-day smoothed average of DX".
160
+ // First value is simple average of previous 14 DX values.
161
+ var sumDx = dxBuffer.reduce(function (a, b) { return a + b; }, 0);
162
+ newSmoothAdx = sumDx / type;
163
+ adx = newSmoothAdx;
164
+ }
165
+ else {
166
+ // Not enough data for ADX yet
167
+ adx = 0;
168
+ }
169
+ }
170
+ else {
171
+ // We already have ADX initialized, so we smooth it
172
+ // Note: we don't need to keep growing dxBuffer indefinitely.
173
+ // We just needed it for startup.
174
+ // Update ADX using Wilder's smoothing
175
+ newSmoothAdx = (preList.smoothAdx * (type - 1) + dx) / type;
176
+ adx = newSmoothAdx;
177
+ }
178
+ return __assign(__assign({}, preList), { pDi: pDi, // +DI
179
+ mDi: mDi, // -DI
180
+ adx: adx, smoothTr: newSmoothTr, smoothPdm: newSmoothPdm, smoothMdm: newSmoothMdm, dxBuffer: dxBuffer, smoothAdx: newSmoothAdx });
181
+ }
182
+ }
183
+ });
184
+ // Helper to get formatted results similar to ma.ts
185
+ Object.defineProperty(Dmi.prototype, "calculateDmiValues", {
186
+ enumerable: false,
187
+ configurable: true,
188
+ writable: true,
189
+ value: function (list, period) {
190
+ if (period === void 0) { period = 14; }
191
+ var res = [];
192
+ var state = this.init(list[0], period);
193
+ // First point (index 0) has 0 DMI
194
+ res.push(__assign(__assign({}, list[0]), { pDi: 0, mDi: 0, adx: 0 }));
195
+ for (var i = 1; i < list.length; i++) {
196
+ state = this.next(list[i], state, period);
197
+ res.push(__assign(__assign({}, list[i]), { pDi: state.pDi, mDi: state.mDi, adx: state.adx }));
198
+ }
199
+ return res;
200
+ }
201
+ });
202
+ return Dmi;
203
+ }());
204
+ export default Dmi;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,69 @@
1
+ import Dmi from "./dmi";
2
+ import data from "./test_data.test";
3
+ describe("test dmi methods", function () {
4
+ it("test init & next", function () {
5
+ var dmi = new Dmi();
6
+ var period = 14;
7
+ // Calculate all values using loop
8
+ var results = dmi.calculateDmiValues(data, period);
9
+ var lastResult = results[results.length - 1];
10
+ // Verify consistency
11
+ // Re-run step-by-step
12
+ var state = dmi.init(data[0], period);
13
+ for (var i = 1; i < data.length; i++) {
14
+ state = dmi.next(data[i], state, period);
15
+ }
16
+ expect(state.pDi).toEqual(lastResult.pDi);
17
+ expect(state.mDi).toEqual(lastResult.mDi);
18
+ expect(state.adx).toEqual(lastResult.adx);
19
+ });
20
+ it("test values consistency (basic sanity)", function () {
21
+ // Generate a simple synthetic dataset where Trend is obvious
22
+ // Upward trend -> +DI should be high, -DI low
23
+ var upTrendData = [];
24
+ for (var i = 0; i < 50; i++) {
25
+ upTrendData.push({
26
+ c: 10 + i,
27
+ h: 11 + i,
28
+ l: 9 + i,
29
+ o: 10 + i,
30
+ v: 1000,
31
+ t: 20210101 + i,
32
+ });
33
+ }
34
+ var dmi = new Dmi();
35
+ var res = dmi.calculateDmiValues(upTrendData, 14);
36
+ var last = res[res.length - 1];
37
+ // +DI should be dominant
38
+ expect(last.pDi).toBeGreaterThan(last.mDi);
39
+ // ADX should be high (strong trend)
40
+ expect(last.adx).toBeGreaterThan(20);
41
+ });
42
+ it("test flat trend", function () {
43
+ // Flat data
44
+ var flatData = [];
45
+ for (var i = 0; i < 50; i++) {
46
+ flatData.push({
47
+ c: 10,
48
+ h: 11,
49
+ l: 9,
50
+ o: 10,
51
+ v: 1000,
52
+ t: 20210101 + i,
53
+ });
54
+ }
55
+ var dmi = new Dmi();
56
+ var res = dmi.calculateDmiValues(flatData, 14);
57
+ var last = res[res.length - 1];
58
+ // No directional movement
59
+ // h-ph = 0, pl-l = 0.
60
+ // +DM = 0, -DM = 0.
61
+ // +DI = 0, -DI = 0.
62
+ // ADX = 0?
63
+ // DX = 0.
64
+ expect(last.pDi).toEqual(0);
65
+ expect(last.mDi).toEqual(0);
66
+ // ADX might be 0 or close to 0
67
+ expect(last.adx).toEqual(0);
68
+ });
69
+ });
@@ -15,7 +15,7 @@ interface IchimokuType {
15
15
  init: (data: NewStockType) => IchimokuResType;
16
16
  next: (data: NewStockType, preList: IchimokuResType) => IchimokuResType;
17
17
  }
18
- export default class IchimokuCloud implements IchimokuType {
18
+ export default class Ichimoku implements IchimokuType {
19
19
  init(data: NewStockType): IchimokuResType;
20
20
  /**
21
21
  * 優化說明:
@@ -1,7 +1,7 @@
1
- var IchimokuCloud = /** @class */ (function () {
2
- function IchimokuCloud() {
1
+ var Ichimoku = /** @class */ (function () {
2
+ function Ichimoku() {
3
3
  }
4
- Object.defineProperty(IchimokuCloud.prototype, "init", {
4
+ Object.defineProperty(Ichimoku.prototype, "init", {
5
5
  enumerable: false,
6
6
  configurable: true,
7
7
  writable: true,
@@ -19,7 +19,7 @@ var IchimokuCloud = /** @class */ (function () {
19
19
  * 如果你的框架 (如 React state) 強制要求 immutable,則需要改回 [...prev, data] 的寫法。
20
20
  * 下面的寫法假設可以 Mutation (這在 Class 內部運算或 Backend 處理很常見)。
21
21
  */
22
- Object.defineProperty(IchimokuCloud.prototype, "next", {
22
+ Object.defineProperty(Ichimoku.prototype, "next", {
23
23
  enumerable: false,
24
24
  configurable: true,
25
25
  writable: true,
@@ -36,7 +36,7 @@ var IchimokuCloud = /** @class */ (function () {
36
36
  }
37
37
  });
38
38
  // 核心計算邏輯
39
- Object.defineProperty(IchimokuCloud.prototype, "calcIchimoku", {
39
+ Object.defineProperty(Ichimoku.prototype, "calcIchimoku", {
40
40
  enumerable: false,
41
41
  configurable: true,
42
42
  writable: true,
@@ -64,7 +64,7 @@ var IchimokuCloud = /** @class */ (function () {
64
64
  * 1. 移除 .slice(),避免產生 Garbage Collection。
65
65
  * 2. 使用反向迴圈 (i--),通常在 JS 引擎中微幅快一點,且語意上是「從現在往回看」。
66
66
  */
67
- Object.defineProperty(IchimokuCloud.prototype, "getMidPrice", {
67
+ Object.defineProperty(Ichimoku.prototype, "getMidPrice", {
68
68
  enumerable: false,
69
69
  configurable: true,
70
70
  writable: true,
@@ -89,6 +89,6 @@ var IchimokuCloud = /** @class */ (function () {
89
89
  return (maxH + minL) / 2;
90
90
  }
91
91
  });
92
- return IchimokuCloud;
92
+ return Ichimoku;
93
93
  }());
94
- export default IchimokuCloud;
94
+ export default Ichimoku;
@@ -10,15 +10,15 @@ var __assign = (this && this.__assign) || function () {
10
10
  return __assign.apply(this, arguments);
11
11
  };
12
12
  import { beforeEach, describe, expect, it } from "vitest";
13
- import IchimokuCloud from "./ichimoku";
13
+ import Ichimoku from "./ichimoku";
14
14
  // 輔助函式:快速產生測試用的假資料
15
15
  var createStock = function (idx, override) {
16
16
  return __assign({ t: idx, o: 100, c: 100, h: 100, l: 100, v: 1000 }, override);
17
17
  };
18
- describe("IchimokuCloud Algo", function () {
18
+ describe("Ichimoku Algo", function () {
19
19
  var ichimoku;
20
20
  beforeEach(function () {
21
- ichimoku = new IchimokuCloud();
21
+ ichimoku = new Ichimoku();
22
22
  });
23
23
  describe("init", function () {
24
24
  it("should initialize with correct structure", function () {
@@ -112,7 +112,7 @@ describe("IchimokuCloud Algo", function () {
112
112
  // 注意:上面的 init 和 next 已經把資料寫死為 100 了,這在單元測試有點難搞
113
113
  // 所以我們用更簡單的方法:在 next 過程中精準控制
114
114
  // --- 重來:精準控制版 ---
115
- var ichi = new IchimokuCloud();
115
+ var ichi = new Ichimoku();
116
116
  var r = ichi.init(createStock(0, { h: 120, l: 80 })); // Kijun Range: H=120, L=80
117
117
  // 填滿中間 16 筆 (Index 1~16),數值平穩不影響極值,且不讓 Tenkan 抓到
118
118
  for (var i = 1; i <= 16; i++) {
package/dist/umd/index.js CHANGED
@@ -1869,10 +1869,10 @@
1869
1869
  return Mfi;
1870
1870
  }());
1871
1871
 
1872
- var IchimokuCloud = /** @class */ (function () {
1873
- function IchimokuCloud() {
1872
+ var Ichimoku = /** @class */ (function () {
1873
+ function Ichimoku() {
1874
1874
  }
1875
- Object.defineProperty(IchimokuCloud.prototype, "init", {
1875
+ Object.defineProperty(Ichimoku.prototype, "init", {
1876
1876
  enumerable: false,
1877
1877
  configurable: true,
1878
1878
  writable: true,
@@ -1890,7 +1890,7 @@
1890
1890
  * 如果你的框架 (如 React state) 強制要求 immutable,則需要改回 [...prev, data] 的寫法。
1891
1891
  * 下面的寫法假設可以 Mutation (這在 Class 內部運算或 Backend 處理很常見)。
1892
1892
  */
1893
- Object.defineProperty(IchimokuCloud.prototype, "next", {
1893
+ Object.defineProperty(Ichimoku.prototype, "next", {
1894
1894
  enumerable: false,
1895
1895
  configurable: true,
1896
1896
  writable: true,
@@ -1907,7 +1907,7 @@
1907
1907
  }
1908
1908
  });
1909
1909
  // 核心計算邏輯
1910
- Object.defineProperty(IchimokuCloud.prototype, "calcIchimoku", {
1910
+ Object.defineProperty(Ichimoku.prototype, "calcIchimoku", {
1911
1911
  enumerable: false,
1912
1912
  configurable: true,
1913
1913
  writable: true,
@@ -1935,7 +1935,7 @@
1935
1935
  * 1. 移除 .slice(),避免產生 Garbage Collection。
1936
1936
  * 2. 使用反向迴圈 (i--),通常在 JS 引擎中微幅快一點,且語意上是「從現在往回看」。
1937
1937
  */
1938
- Object.defineProperty(IchimokuCloud.prototype, "getMidPrice", {
1938
+ Object.defineProperty(Ichimoku.prototype, "getMidPrice", {
1939
1939
  enumerable: false,
1940
1940
  configurable: true,
1941
1941
  writable: true,
@@ -1960,7 +1960,7 @@
1960
1960
  return (maxH + minL) / 2;
1961
1961
  }
1962
1962
  });
1963
- return IchimokuCloud;
1963
+ return Ichimoku;
1964
1964
  }());
1965
1965
 
1966
1966
  function add(a, b) {
@@ -2003,7 +2003,7 @@
2003
2003
  exports.Boll = Boll;
2004
2004
  exports.Ema = Ema;
2005
2005
  exports.Gold = Gold;
2006
- exports.Ichimoku = IchimokuCloud;
2006
+ exports.Ichimoku = Ichimoku;
2007
2007
  exports.Kd = Kd;
2008
2008
  exports.Ma = Ma;
2009
2009
  exports.Macd = MACD;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ch20026103/anysis",
3
- "version": "0.0.19-alpha1",
3
+ "version": "0.0.19-beta",
4
4
  "description": "provide many analyze methods in the library.",
5
5
  "keywords": [],
6
6
  "bugs": "git@github.com:cosmic1330/anysis/issues",