Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: apply the new accessor to replace length - 1 / length -2 #37

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions @libs/indicators/MAX.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,31 @@ export const useMAX = (source: Series, period: number) => {
// 单调队列: 保存当前窗口期内,比最新的元素小的元素的索引
const queue = useRef<number[]>([]);
useEffect(() => {
const i = source.length - 2;
if (i < 0) return;
const previousIndex = source.previousIndex;
if (previousIndex < 0) return;
// 从栈顶开始,移除所有小于当前值的元素
while (
queue.current.length > 0 &&
source[queue.current[queue.current.length - 1]] <= source[i]
source[queue.current[queue.current.length - 1]] <= source.previousValue
) {
queue.current.pop();
}
// 将当前值入栈
queue.current.push(i);
queue.current.push(previousIndex);
// 移除超出窗口期的元素 (通常一次只会移除一个)
while (queue.current.length > 0 && queue.current[0] <= i - period) {
while (
queue.current.length > 0 &&
queue.current[0] <= previousIndex - period
) {
queue.current.shift();
}
}, [source.length]);
useEffect(() => {
const i = source.length - 1;
if (i < 0) return;
const currentIndex = source.currentIndex;
if (currentIndex < 0) return;
// 队首元素即为当前窗口期内的最小值
MAX[i] = Math.max(
source[source.length - 1],
MAX[currentIndex] = Math.max(
source.currentValue,
source[queue.current[0]] || -Infinity
);
});
Expand Down
21 changes: 12 additions & 9 deletions @libs/indicators/MIN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,31 @@ export const useMIN = (source: Series, period: number) => {
// 单调队列: 保存当前窗口期内,比最新的元素小的元素的索引
const queue = useRef<number[]>([]);
useEffect(() => {
const i = source.length - 2;
if (i < 0) return;
const previousIndex = source.previousIndex;
if (previousIndex < 0) return;
// 从栈顶开始,移除所有大于当前值的元素
while (
queue.current.length > 0 &&
source[queue.current[queue.current.length - 1]] >= source[i]
source[queue.current[queue.current.length - 1]] >= source.previousValue
) {
queue.current.pop();
}
// 将当前值入栈
queue.current.push(i);
queue.current.push(previousIndex);
// 移除超出窗口期的元素 (通常一次只会移除一个)
while (queue.current.length > 0 && queue.current[0] <= i - period) {
while (
queue.current.length > 0 &&
queue.current[0] <= previousIndex - period
) {
queue.current.shift();
}
}, [source.length]);
useEffect(() => {
const i = source.length - 1;
if (i < 0) return;
const currentIndex = source.currentIndex;
if (currentIndex < 0) return;
// 队首元素即为当前窗口期内的最小值
MIN[i] = Math.min(
source[source.length - 1],
MIN[currentIndex] = Math.min(
source.currentValue,
source[queue.current[0]] || Infinity
);
});
Expand Down
6 changes: 3 additions & 3 deletions @libs/indicators/RANGE.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ export const useRANGE = (source: Series, period: number) => {
chart: "new",
});
useEffect(() => {
const i = source.length - 1;
if (i < 0) return;
Range[i] = max[i] - min[i];
const currentIndex = source.currentIndex;
if (currentIndex < 0) return;
Range[currentIndex] = max.currentValue - min.currentValue;
});
return Range;
};
60 changes: 32 additions & 28 deletions @libs/indicators/SAR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,72 +22,76 @@ export const useSAR = (
const direction = useSeries("direction", high); // 1 for upward, -1 for downward, 0 for unknown

useEffect(() => {
const i = high.length - 1;
const i = high.currentIndex;
if (i < 0) return;

if (i === 0) {
MAX[i] = high[i];
MIN[i] = low[i];
MAX[i] = high.currentValue;
MIN[i] = low.currentValue;
AF[i] = start;
U[i] = high[i];
D[i] = low[i];
U[i] = high.currentValue;
D[i] = low.currentValue;
direction[i] = 0;
return;
}
// U[i] = U[i - 1];
// D[i] = D[i - 1];

if (direction[i - 1] !== 1) {
if (direction.previousValue !== 1) {
// 按下行处理

// 检查是否向上反转
if (high[i] >= U[i - 1]) {
if (high.currentValue >= U.previousValue) {
direction[i] = 1;
MAX[i] = high[i];
MIN[i] = low[i];
MAX[i] = high.currentValue;
MIN[i] = low.currentValue;
U[i] = NaN; // MAX[i];
D[i] = MIN[i - 1]; // 从上一个区间的最小值开始
D[i] = MIN.previousValue; // 从上一个区间的最小值开始
AF[i] = start;
return;
}
direction[i] = direction[i - 1];
direction[i] = direction.previousValue;
// 检查是否创新低
if (low[i] < MIN[i - 1]) {
AF[i] = Math.min(max, AF[i - 1] + increment);
if (low.currentValue < MIN.previousValue) {
AF[i] = Math.min(max, AF.previousValue + increment);
} else {
AF[i] = AF[i - 1];
AF[i] = AF.previousValue;
}
// 维护区间极值
MAX[i] = Math.max(MAX[i - 1], high[i]);
MIN[i] = Math.min(MIN[i - 1], low[i]);
MAX[i] = Math.max(MAX.previousValue, high.currentValue);
MIN[i] = Math.min(MIN.previousValue, low.currentValue);

U[i] = U[i - 1] + AF[i] * (MIN[i - 1] - U[i - 1]);
U[i] =
U.previousValue +
AF.currentValue * (MIN.previousValue - U.previousValue);
D[i] = NaN; // MIN[i];
} else {
// 按上行处理

// 检查是否向下反转
if (low[i] <= D[i - 1]) {
if (low.currentValue <= D.previousValue) {
direction[i] = -1;
MAX[i] = high[i];
MIN[i] = low[i];
MAX[i] = high.currentValue;
MIN[i] = low.currentValue;
AF[i] = start;
U[i] = MAX[i - 1]; // 从上一个区间的最大值开始
U[i] = MAX.previousValue; // 从上一个区间的最大值开始
D[i] = NaN; // MIN[i];
return;
}
direction[i] = direction[i - 1];
direction[i] = direction.previousValue;
// 检查是否创新高
if (high[i] < MAX[i - 1]) {
AF[i] = Math.min(max, AF[i - 1] + increment);
if (high.currentValue < MAX.previousValue) {
AF[i] = Math.min(max, AF.previousValue + increment);
} else {
AF[i] = AF[i - 1];
AF[i] = AF.previousValue;
}
// 维护区间极值
MAX[i] = Math.max(MAX[i - 1], high[i]);
MIN[i] = Math.min(MIN[i - 1], low[i]);
MAX[i] = Math.max(MAX.previousValue, high.currentValue);
MIN[i] = Math.min(MIN.previousValue, low.currentValue);
U[i] = NaN; //MAX[i];
D[i] = D[i - 1] + AF[i] * (MAX[i - 1] - D[i - 1]);
D[i] =
D.previousValue +
AF.currentValue * (MAX.previousValue - D.previousValue);
}
});
return { U, D, direction, MAX, MIN, AF };
Expand Down
14 changes: 7 additions & 7 deletions @libs/indicators/TD.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ export const useTD = (source: Series) => {
});

useEffect(() => {
const i = source.length - 1;
if (i < 0) return;
TD[i] = 0;
if (source[i] > source[i - 4]) {
TD[i] = Math.max(0, TD[i - 1] ?? 0) + 1;
const currentIndex = source.currentIndex;
if (currentIndex < 0) return;
TD[currentIndex] = 0;
if (source.currentValue > source[currentIndex - 4]) {
TD[currentIndex] = Math.max(0, TD.previousValue ?? 0) + 1;
}
if (source[i] < source[i - 4]) {
TD[i] = Math.min(0, TD[i - 1] ?? 0) - 1;
if (source.currentValue < source[currentIndex - 4]) {
TD[currentIndex] = Math.min(0, TD.previousValue ?? 0) - 1;
}
});

Expand Down
12 changes: 6 additions & 6 deletions @libs/indicators/ZIGZAG.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const useZigZag = (high: Series, low: Series, period: number) => {
useEffect(() => {
for (
let i = Math.max(0, lastLowPeak.length) - 1;
i < high.length - 1;
i < high.currentIndex;
i++
) {
if (i <= 0) {
Expand Down Expand Up @@ -100,11 +100,11 @@ export const useZigZag = (high: Series, low: Series, period: number) => {
}
}
if (high.length >= 1) {
lastHighPeak[high.length - 1] = NaN;
lastLowPeak[high.length - 1] = NaN;
currentZigzagValue[high.length - 1] = NaN;
lastZigzagValue[high.length - 1] = NaN;
secondLastZigzagValue[high.length - 1] = NaN;
lastHighPeak[high.currentIndex] = NaN;
lastLowPeak[high.currentIndex] = NaN;
currentZigzagValue[high.currentIndex] = NaN;
lastZigzagValue[high.currentIndex] = NaN;
secondLastZigzagValue[high.currentIndex] = NaN;
}
});

Expand Down
2 changes: 1 addition & 1 deletion @libs/utils/useSeriesMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const useSeriesMap = (
) => {
const series = useSeries(name, parent, tags);
useEffect(() => {
const i = parent.length - 1;
const i = parent.currentIndex;
if (i < 0) return;
series[i] = fn(i, series);
});
Expand Down
18 changes: 9 additions & 9 deletions @libs/utils/useThrottle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@ export const useThrottle = (series: Series, period: number) => {
const ret = useSeries(`THROTTLE(${series.name},${period})`, series, {});
const openIdxRef = useRef(0);
useEffect(() => {
const i = series.length - 1;
if (i < 0) return;
if (i < openIdxRef.current) {
ret[i] = NaN;
const currentIndex = series.currentIndex;
if (currentIndex < 0) return;
if (currentIndex < openIdxRef.current) {
ret[currentIndex] = NaN;
return;
}
if (series[i - 1]) {
openIdxRef.current = i + period;
ret[i - 1] = series[i - 1];
ret[i] = NaN;
if (series[currentIndex - 1]) {
openIdxRef.current = currentIndex + period;
ret[currentIndex - 1] = series.previousValue;
ret[currentIndex] = NaN;
return;
}
ret[i] = series[i];
ret[currentIndex] = series.currentValue;
});
return ret;
};
16 changes: 8 additions & 8 deletions @libs/utils/useTopK.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,26 @@
export const useTopK = (series: Series, k: number, period: number) => {
const indexes = useRef<number[]>([]);
const ret = useSeries(`TOP_K(${series.name},${k},${period})`, series, {});
const i = series.length - 1;
const currentIndex = series.currentIndex;
useEffect(() => {
if (i < 0) return;
if (currentIndex < 0) return;
let isChanged = false;
// remove expired indexes
if (indexes.current[0] <= i - period) {
if (indexes.current[0] <= currentIndex - period) {
indexes.current.shift();
isChanged = true;
}
if (series[i - 1]) {
indexes.current.push(i - 1);
if (series.previousValue) {
indexes.current.push(currentIndex - 1);
isChanged = true;
}

if (isChanged) {
const sorted = [...indexes.current].sort((a, b) => series[b] - series[a]);
ret[i] = series[sorted[Math.min(k, sorted.length) - 1]];
ret[currentIndex] = series[sorted[Math.min(k, sorted.length) - 1]];
} else {
ret[i] = ret[i - 1] ?? NaN;
ret[currentIndex] = ret.previousValue ?? NaN;
}
}, [i]);
}, [currentIndex]);
return ret;
};
35 changes: 22 additions & 13 deletions @models/CCI-trending.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import {
*/
export default () => {
const { product_id, high, low, close } = useParamOHLC("SomeKey");
const idx = close.length - 2;

const cciFast = useCCI(high, low, close, 18);
const cciSlow = useCCI(high, low, close, 54);
Expand All @@ -48,42 +47,52 @@ export default () => {
accountInfo.account_id,
product_id
);
const stopLossPrice = useRef(close[idx] - 6 * atr108[idx]);
const stopLossPrice = useRef(close.previousValue - 6 * atr108.previousValue);

useEffect(() => {
if (idx < 108) return; // 确保ATR有足够的数据
if (close.previousIndex < 108) return; // 确保ATR有足够的数据

// 空头信号:当CCI快线进入正200以上,且下穿慢线时,建立空单。
if (cciFast[idx] > 200 && cciFast[idx] < cciSlow[idx]) {
if (
cciFast.previousValue > 200 &&
cciFast.previousValue < cciSlow.previousValue
) {
setTargetVolume(-1);
stopLossPrice.current = close[idx] + 6 * atr108[idx]; // 使用6倍ATR的值作为停损点位。
stopLossPrice.current = close.previousValue + 6 * atr108.previousValue; // 使用6倍ATR的值作为停损点位。
}

// 多头信号:当CCI快线进入负200以下,且上穿慢线时,建立多单。
if (cciFast[idx] < -200 && cciFast[idx] > cciSlow[idx]) {
if (
cciFast.previousValue < -200 &&
cciFast.previousValue > cciSlow.previousValue
) {
setTargetVolume(1);
stopLossPrice.current = close[idx] - 6 * atr108[idx]; // 使用6倍ATR的值作为停损点位。
stopLossPrice.current = close.previousValue - 6 * atr108.previousValue; // 使用6倍ATR的值作为停损点位。
}

// 多单平仓:当CCI快线进入正200以上,且下穿慢线时,平多单。
if (targetVolume > 0 && cciFast[idx] > 200 && cciFast[idx] < cciSlow[idx]) {
if (
targetVolume > 0 &&
cciFast.previousValue > 200 &&
cciFast.previousValue < cciSlow.previousValue
) {
setTargetVolume(0);
}
// 空单平仓:当CCI快线进入负200以下,且上穿慢线时,平空单。
if (
targetVolume < 0 &&
cciFast[idx] < -200 &&
cciFast[idx] > cciSlow[idx]
cciFast.previousValue < -200 &&
cciFast.previousValue > cciSlow.previousValue
) {
setTargetVolume(0);
}

// 停损条件
if (
(targetVolume > 0 && close[idx] < stopLossPrice.current) ||
(targetVolume < 0 && close[idx] > stopLossPrice.current)
(targetVolume > 0 && close.previousValue < stopLossPrice.current) ||
(targetVolume < 0 && close.previousValue > stopLossPrice.current)
) {
setTargetVolume(0);
}
}, [idx]);
}, [close.previousIndex]);
};
Loading