전체적인 리팩토링
This commit is contained in:
212
features/autotrade/stores/use-autotrade-engine-store.ts
Normal file
212
features/autotrade/stores/use-autotrade-engine-store.ts
Normal file
@@ -0,0 +1,212 @@
|
||||
"use client";
|
||||
|
||||
import { create } from "zustand";
|
||||
import type {
|
||||
AutotradeCompiledStrategy,
|
||||
AutotradeEngineState,
|
||||
AutotradeRuntimeLog,
|
||||
AutotradeSessionInfo,
|
||||
AutotradeSetupFormValues,
|
||||
AutotradeSignalCandidate,
|
||||
AutotradeValidationResult,
|
||||
} from "@/features/autotrade/types/autotrade.types";
|
||||
import { resolveSetupDefaults } from "@/lib/autotrade/strategy";
|
||||
|
||||
interface AutotradeEngineStoreState {
|
||||
panelOpen: boolean;
|
||||
setupForm: AutotradeSetupFormValues;
|
||||
engineState: AutotradeEngineState;
|
||||
isWorking: boolean;
|
||||
|
||||
activeSession: AutotradeSessionInfo | null;
|
||||
compiledStrategy: AutotradeCompiledStrategy | null;
|
||||
validation: AutotradeValidationResult | null;
|
||||
lastSignal: AutotradeSignalCandidate | null;
|
||||
|
||||
orderCountToday: number;
|
||||
cumulativeLossAmount: number;
|
||||
consecutiveFailures: number;
|
||||
lastOrderAtBySymbol: Record<string, number>;
|
||||
|
||||
logs: AutotradeRuntimeLog[];
|
||||
}
|
||||
|
||||
interface AutotradeEngineStoreActions {
|
||||
setPanelOpen: (open: boolean) => void;
|
||||
patchSetupForm: (patch: Partial<AutotradeSetupFormValues>) => void;
|
||||
setEngineState: (state: AutotradeEngineState) => void;
|
||||
setWorking: (working: boolean) => void;
|
||||
|
||||
setActiveSession: (session: AutotradeSessionInfo | null) => void;
|
||||
setCompiledStrategy: (strategy: AutotradeCompiledStrategy | null) => void;
|
||||
setValidation: (validation: AutotradeValidationResult | null) => void;
|
||||
setLastSignal: (signal: AutotradeSignalCandidate | null) => void;
|
||||
|
||||
increaseOrderCount: (count?: number) => void;
|
||||
addLossAmount: (lossAmount: number) => void;
|
||||
setLastOrderAt: (symbol: string, timestampMs: number) => void;
|
||||
increaseFailure: () => void;
|
||||
resetFailure: () => void;
|
||||
|
||||
appendLog: (
|
||||
level: AutotradeRuntimeLog["level"],
|
||||
message: string,
|
||||
options?: {
|
||||
stage?: AutotradeRuntimeLog["stage"];
|
||||
detail?: string | Record<string, unknown>;
|
||||
},
|
||||
) => void;
|
||||
clearRuntime: () => void;
|
||||
}
|
||||
|
||||
const INITIAL_FORM = resolveSetupDefaults();
|
||||
|
||||
const INITIAL_STATE: AutotradeEngineStoreState = {
|
||||
panelOpen: false,
|
||||
setupForm: INITIAL_FORM,
|
||||
engineState: "IDLE",
|
||||
isWorking: false,
|
||||
|
||||
activeSession: null,
|
||||
compiledStrategy: null,
|
||||
validation: null,
|
||||
lastSignal: null,
|
||||
|
||||
orderCountToday: 0,
|
||||
cumulativeLossAmount: 0,
|
||||
consecutiveFailures: 0,
|
||||
lastOrderAtBySymbol: {},
|
||||
|
||||
logs: [],
|
||||
};
|
||||
|
||||
export const useAutotradeEngineStore = create<
|
||||
AutotradeEngineStoreState & AutotradeEngineStoreActions
|
||||
>((set) => ({
|
||||
...INITIAL_STATE,
|
||||
|
||||
setPanelOpen: (open) => {
|
||||
set({ panelOpen: open });
|
||||
},
|
||||
|
||||
patchSetupForm: (patch) => {
|
||||
set((state) => ({
|
||||
setupForm: {
|
||||
...state.setupForm,
|
||||
...patch,
|
||||
},
|
||||
}));
|
||||
},
|
||||
|
||||
setEngineState: (engineState) => {
|
||||
set({ engineState });
|
||||
},
|
||||
|
||||
setWorking: (isWorking) => {
|
||||
set({ isWorking });
|
||||
},
|
||||
|
||||
setActiveSession: (activeSession) => {
|
||||
set({ activeSession });
|
||||
},
|
||||
|
||||
setCompiledStrategy: (compiledStrategy) => {
|
||||
set({ compiledStrategy });
|
||||
},
|
||||
|
||||
setValidation: (validation) => {
|
||||
set({ validation });
|
||||
},
|
||||
|
||||
setLastSignal: (lastSignal) => {
|
||||
set({ lastSignal });
|
||||
},
|
||||
|
||||
increaseOrderCount: (count = 1) => {
|
||||
set((state) => ({
|
||||
orderCountToday: state.orderCountToday + Math.max(1, count),
|
||||
}));
|
||||
},
|
||||
|
||||
addLossAmount: (lossAmount) => {
|
||||
set((state) => ({
|
||||
cumulativeLossAmount:
|
||||
state.cumulativeLossAmount + Math.max(0, Math.floor(lossAmount)),
|
||||
}));
|
||||
},
|
||||
|
||||
setLastOrderAt: (symbol, timestampMs) => {
|
||||
set((state) => ({
|
||||
lastOrderAtBySymbol: {
|
||||
...state.lastOrderAtBySymbol,
|
||||
[symbol]: timestampMs,
|
||||
},
|
||||
}));
|
||||
},
|
||||
|
||||
increaseFailure: () => {
|
||||
set((state) => ({
|
||||
consecutiveFailures: state.consecutiveFailures + 1,
|
||||
}));
|
||||
},
|
||||
|
||||
resetFailure: () => {
|
||||
set({ consecutiveFailures: 0 });
|
||||
},
|
||||
|
||||
appendLog: (level, message, options) => {
|
||||
const entry: AutotradeRuntimeLog = {
|
||||
id: safeLogId(),
|
||||
level,
|
||||
stage: options?.stage,
|
||||
message,
|
||||
detail: normalizeLogDetail(options?.detail),
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
set((state) => ({
|
||||
logs: [entry, ...state.logs].slice(0, 80),
|
||||
}));
|
||||
},
|
||||
|
||||
clearRuntime: () => {
|
||||
set((state) => ({
|
||||
...state,
|
||||
engineState: "IDLE",
|
||||
isWorking: false,
|
||||
activeSession: null,
|
||||
compiledStrategy: null,
|
||||
validation: null,
|
||||
lastSignal: null,
|
||||
orderCountToday: 0,
|
||||
cumulativeLossAmount: 0,
|
||||
consecutiveFailures: 0,
|
||||
lastOrderAtBySymbol: {},
|
||||
}));
|
||||
},
|
||||
}));
|
||||
|
||||
function safeLogId() {
|
||||
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
||||
return crypto.randomUUID();
|
||||
}
|
||||
|
||||
return `autotrade-log-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
||||
}
|
||||
|
||||
function normalizeLogDetail(detail: string | Record<string, unknown> | undefined) {
|
||||
if (!detail) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (typeof detail === "string") {
|
||||
const cleaned = detail.trim();
|
||||
return cleaned.length > 0 ? cleaned : undefined;
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.stringify(detail, null, 2);
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user