전략 시간봉 오류 수정

This commit is contained in:
Macbook
2026-05-28 00:36:49 +09:00
parent 2713b2951d
commit 4f6694b206
16 changed files with 285 additions and 127 deletions
+10 -1
View File
@@ -147,11 +147,20 @@ function shouldShowBbBandFill(config: IndicatorConfig): boolean {
}
function attachBbBandFill(entry: IndicatorEntry, config: IndicatorConfig): void {
if (!shouldShowBbBandFill(config)) {
detachBbBandFill(entry);
return;
}
const basis = seriesByPlotId(entry, 'plot0');
const upper = seriesByPlotId(entry, 'plot1');
const lower = seriesByPlotId(entry, 'plot2');
if (!basis || !upper || !lower || !shouldShowBbBandFill(config)) return;
if (!basis || !upper || !lower) return;
const bg = resolveBbBandBackground(config.bandBackground);
if (entry.bbFillPrimitive) {
entry.bbFillPrimitive.updateBackground(bg);
entry.bbFillPrimitive.requestRefresh();
return;
}
entry.bbFillPrimitive = new BollingerBandFillPrimitive(upper, lower, bg);
basis.attachPrimitive(entry.bbFillPrimitive);
}
+3 -3
View File
@@ -329,10 +329,10 @@ export async function saveIndicatorSettings(
* 앱 시작 시 호출 — 전역 시각 기본값을 DB 에서 가져온다.
*/
export async function loadIndicatorVisualSettings(): Promise<
Record<string, { plots?: unknown[]; hlines?: unknown[] }>
Record<string, { plots?: unknown[]; hlines?: unknown[]; cloudColors?: unknown; bandBackground?: unknown }>
> {
return (
(await request<Record<string, { plots?: unknown[]; hlines?: unknown[] }>>(
(await request<Record<string, { plots?: unknown[]; hlines?: unknown[]; cloudColors?: unknown; bandBackground?: unknown }>>(
'/indicator-settings/visual'
)) ?? {}
);
@@ -347,7 +347,7 @@ export async function loadIndicatorVisualSettings(): Promise<
*/
export async function saveIndicatorVisualSettings(
indicatorType: string,
visual: { plots?: unknown[]; hlines?: unknown[] }
visual: { plots?: unknown[]; hlines?: unknown[]; cloudColors?: unknown; bandBackground?: unknown },
): Promise<void> {
await request(`/indicator-settings/${encodeURIComponent(indicatorType)}/visual`, {
method: 'PATCH',
+3 -2
View File
@@ -151,7 +151,7 @@ type GetVisual = (
type: string,
defaultPlots?: PlotDef[],
defaultHlines?: HLineDef[],
) => { plots: PlotDef[]; hlines: HLineDef[]; cloudColors?: IchimokuCloudColors };
) => { plots: PlotDef[]; hlines: HLineDef[]; cloudColors?: IchimokuCloudColors; bandBackground?: import('../types').HlinesBackground };
/** 탭 전체 추가 — 기존 차트 지표를 제거하고 types 목록만 새로 구성 */
export function replaceIndicatorConfigsFromTypes(
@@ -181,7 +181,7 @@ export function buildIndicatorConfigsFromTypes(
seen.add(type);
const params = getParams(type, def.defaultParams);
const { plots, hlines, cloudColors } = getVisualConfig(type, def.plots, def.hlines);
const { plots, hlines, cloudColors, bandBackground } = getVisualConfig(type, def.plots, def.hlines);
let cfg: IndicatorConfig = {
id: newId(),
type: def.type,
@@ -189,6 +189,7 @@ export function buildIndicatorConfigsFromTypes(
plots,
hlines,
...(cloudColors ? { cloudColors } : {}),
...(bandBackground ? { bandBackground } : {}),
};
if (type === 'SMA') {
cfg = normalizeSmaConfig({
@@ -54,7 +54,7 @@ export function initializeIndicatorConfigForEditor(
type: string,
defaultPlots: PlotDef[],
defaultHlines?: HLineDef[],
) => { plots: PlotDef[]; hlines: HLineDef[]; cloudColors?: IchimokuCloudColors },
) => { plots: PlotDef[]; hlines: HLineDef[]; cloudColors?: IchimokuCloudColors; bandBackground?: HlinesBackground },
): IndicatorConfig {
const def = getIndicatorDef(raw.type);
if (!def) return enrichIndicatorConfig(raw);
@@ -70,6 +70,7 @@ export function initializeIndicatorConfigForEditor(
plots: raw.plots?.length ? raw.plots : visual?.plots,
hlines: raw.hlines?.length ? raw.hlines : visual?.hlines,
cloudColors: raw.cloudColors ?? visual?.cloudColors,
bandBackground: raw.bandBackground ?? visual?.bandBackground,
});
}
+16 -1
View File
@@ -68,12 +68,27 @@ export function resolveHistogramDownColor(plot: PlotDef): string {
return plot.histogramDownColor ?? DEFAULT_HIST_DOWN;
}
/** MACD histogram 막대 색 (상승·하락/음수 구분) */
/** MACD 히스토그램 — histogramUp/DownColor 로 0선 위·아래 색 분리 */
export function isMacdDualHistogramPlot(plot: PlotDef): boolean {
return plot.type === 'histogram'
&& plot.histogramUpColor != null
&& plot.histogramDownColor != null;
}
/**
* histogram 막대 색.
* - MACD(상·하 색 지정): 0선 기준 — 양수=상승색, 음수=하락색 (전봴 대비 혼합 없음)
* - 기타: 전봴 대비 방향 + 음수 영역 하락색
*/
export function histogramBarColor(
value: number,
prev: number | null | undefined,
plot: PlotDef,
): string {
if (isMacdDualHistogramPlot(plot)) {
const raw = value < 0 ? resolveHistogramDownColor(plot) : resolveHistogramUpColor(plot);
return withHistogramAlpha(raw);
}
const isDown = prev != null && !isNaN(prev) && value < prev;
const isNeg = value < 0;
const raw = (isDown || isNeg) ? resolveHistogramDownColor(plot) : resolveHistogramUpColor(plot);
@@ -399,6 +399,31 @@ export function collectTimeframesFromEditorState(state: EditorConditionState): s
return [...set];
}
/** 매수·매도 START(기본) 평가 분봉을 동일하게 맞춤 — 한쪽만 3m·5m 체크 시 다른 쪽 1m 잔존 방지 */
export function syncBuySellPrimaryStartCandleTypes(
buy: EditorConditionState,
sell: EditorConditionState,
candleTypes: string[],
): { buy: EditorConditionState; sell: EditorConditionState } {
const types = normalizeCandleTypesList(candleTypes);
return {
buy: updateStartCandleTypes(buy, START_NODE_ID, types),
sell: updateStartCandleTypes(sell, START_NODE_ID, types),
};
}
/** 저장 직전 — 양쪽 START 분봉 합집합을 각 탭에 반영 (매수만 설정한 경우 매도 DSL도 동기화) */
export function alignBuySellStartCandleTypesForSave(
buy: EditorConditionState,
sell: EditorConditionState,
): { buy: EditorConditionState; sell: EditorConditionState } {
const merged = normalizeCandleTypesList([
...getStartCandleTypes(buy.startMeta[START_NODE_ID]),
...getStartCandleTypes(sell.startMeta[START_NODE_ID]),
]);
return syncBuySellPrimaryStartCandleTypes(buy, sell, merged);
}
/** 저장된 DSL에서 Logic Expression용 분기 목록 */
export function collectDslBranches(dsl: LogicNode | null): ConditionBranch[] {
return collectEditorBranches(decodeConditionForEditor(dsl));