복합지표 전략 추가
This commit is contained in:
@@ -10,12 +10,31 @@ import StartTimeframeCheckboxes from './StartTimeframeCheckboxes';
|
||||
import LogicGateOpToggle from './LogicGateOpToggle';
|
||||
import { hasNodeSettings } from '../../utils/conditionPeriods';
|
||||
import { getStrategyIndicatorDisplayName } from '../../utils/strategyPaletteStorage';
|
||||
import {
|
||||
isPriceExtremeBreakoutPairRoot,
|
||||
priceExtremePairDisplayName,
|
||||
inferPriceExtremeFilterLevel,
|
||||
} from '../../utils/priceExtremeBreakoutPair';
|
||||
import {
|
||||
isInflection33PairRoot,
|
||||
inflection33DisplayName,
|
||||
inferInflection33FilterLevel,
|
||||
} from '../../utils/inflection33Strategy';
|
||||
import Inflection33PairNodeSettings from './Inflection33PairNodeSettings';
|
||||
import {
|
||||
isStableStrategyPairRoot,
|
||||
stableStrategyDisplayName,
|
||||
inferStableStrategyFilterLevel,
|
||||
type StableStrategyId,
|
||||
} from '../../utils/stableStrategyPairs';
|
||||
import StableStrategyPairNodeSettings from './StableStrategyPairNodeSettings';
|
||||
import {
|
||||
isStochOverboughtPairRoot,
|
||||
stochPairDisplayName,
|
||||
} from '../../utils/stochOverboughtPair';
|
||||
import ConditionNodeSettings from './ConditionNodeSettings';
|
||||
import StochPairNodeSettings from './StochPairNodeSettings';
|
||||
import PriceExtremePairNodeSettings from './PriceExtremePairNodeSettings';
|
||||
|
||||
const LOGIC_COLORS: Record<string, string> = {
|
||||
AND: '#00aaff',
|
||||
@@ -196,12 +215,15 @@ export const LogicGateNode = memo(function LogicGateNode({ id, data, selected }:
|
||||
const color = LOGIC_COLORS[node.type] ?? '#00aaff';
|
||||
const isSell = d.signalTab === 'sell';
|
||||
const isStochPair = isStochOverboughtPairRoot(node);
|
||||
const isPriceExtremePair = isPriceExtremeBreakoutPairRoot(node);
|
||||
const isInflection33Pair = isInflection33PairRoot(node);
|
||||
const isStableStrategyPair = isStableStrategyPairRoot(node);
|
||||
const { onDragOver, onDragLeave, onDrop } = usePaletteDropHandlers(id, d);
|
||||
const [settingsOpen, setSettingsOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`se-flow-node se-flow-node--logic${isStochPair ? ' se-flow-node--stoch-pair' : ''}${isSell ? ' se-flow-node--sell-mode' : ''}${d.isOrphan ? ' se-flow-node--orphan' : ''} ${selected ? 'se-flow-node--selected' : ''} ${d.dragOver ? 'se-flow-node--drop' : ''}${settingsOpen ? ' se-flow-node--settings-open' : ''}`}
|
||||
className={`se-flow-node se-flow-node--logic${isStochPair ? ' se-flow-node--stoch-pair' : ''}${isPriceExtremePair ? ' se-flow-node--price-extreme-pair' : ''}${isInflection33Pair ? ' se-flow-node--inflection33-pair' : ''}${isStableStrategyPair ? ' se-flow-node--stable-strategy-pair' : ''}${isSell ? ' se-flow-node--sell-mode' : ''}${d.isOrphan ? ' se-flow-node--orphan' : ''} ${selected ? 'se-flow-node--selected' : ''} ${d.dragOver ? ' se-flow-node--drop' : ''}${settingsOpen ? ' se-flow-node--settings-open' : ''}`}
|
||||
style={{ '--se-gate-color': color } as React.CSSProperties}
|
||||
onDragOver={onDragOver}
|
||||
onDragLeave={onDragLeave}
|
||||
@@ -224,6 +246,79 @@ export const LogicGateNode = memo(function LogicGateNode({ id, data, selected }:
|
||||
<span className="se-flow-gate-badge">[{node.type}]</span>
|
||||
)}
|
||||
</div>
|
||||
{isStableStrategyPair && node.stableStrategyPair && (
|
||||
<div className="se-flow-gate-stoch-pair">
|
||||
<span className="se-flow-gate-stoch-pair-title">
|
||||
{stableStrategyDisplayName(
|
||||
node.stableStrategyPair.strategyId as StableStrategyId,
|
||||
node.stableStrategyPair.mode,
|
||||
)}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
className="se-flow-settings"
|
||||
title="필터 강도 설정"
|
||||
aria-label="필터 강도 설정"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
setSettingsOpen(v => !v);
|
||||
}}
|
||||
>
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<circle cx="12" cy="12" r="3"/>
|
||||
<path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{isInflection33Pair && node.inflection33Pair && (
|
||||
<div className="se-flow-gate-stoch-pair">
|
||||
<span className="se-flow-gate-stoch-pair-title">
|
||||
{inflection33DisplayName(node.inflection33Pair.mode, node.inflection33Pair.period)}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
className="se-flow-settings"
|
||||
title="필터 강도 설정"
|
||||
aria-label="필터 강도 설정"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
setSettingsOpen(v => !v);
|
||||
}}
|
||||
>
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<circle cx="12" cy="12" r="3"/>
|
||||
<path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{isPriceExtremePair && node.priceExtremePair && (
|
||||
<div className="se-flow-gate-stoch-pair">
|
||||
<span className="se-flow-gate-stoch-pair-title">
|
||||
{priceExtremePairDisplayName(
|
||||
node.priceExtremePair.mode,
|
||||
node.priceExtremePair.shortPeriod,
|
||||
node.priceExtremePair.longPeriod,
|
||||
)}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
className="se-flow-settings"
|
||||
title="필터 강도 설정"
|
||||
aria-label="필터 강도 설정"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
setSettingsOpen(v => !v);
|
||||
}}
|
||||
>
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<circle cx="12" cy="12" r="3"/>
|
||||
<path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{isStochPair && node.stochPair && (
|
||||
<div className="se-flow-gate-stoch-pair">
|
||||
<span className="se-flow-gate-stoch-pair-title">
|
||||
@@ -257,6 +352,35 @@ export const LogicGateNode = memo(function LogicGateNode({ id, data, selected }:
|
||||
onClose={() => setSettingsOpen(false)}
|
||||
/>
|
||||
)}
|
||||
{settingsOpen && isStableStrategyPair && node.stableStrategyPair && (
|
||||
<StableStrategyPairNodeSettings
|
||||
strategyId={node.stableStrategyPair.strategyId as StableStrategyId}
|
||||
mode={node.stableStrategyPair.mode}
|
||||
filterLevel={inferStableStrategyFilterLevel(node)}
|
||||
def={d.def!}
|
||||
onChange={level => d.onUpdateStableStrategyFilterLevel?.(id, level)}
|
||||
onClose={() => setSettingsOpen(false)}
|
||||
/>
|
||||
)}
|
||||
{settingsOpen && isInflection33Pair && node.inflection33Pair && (
|
||||
<Inflection33PairNodeSettings
|
||||
mode={node.inflection33Pair.mode}
|
||||
period={node.inflection33Pair.period}
|
||||
filterLevel={inferInflection33FilterLevel(node)}
|
||||
onChange={level => d.onUpdateInflection33FilterLevel?.(id, level)}
|
||||
onClose={() => setSettingsOpen(false)}
|
||||
/>
|
||||
)}
|
||||
{settingsOpen && isPriceExtremePair && node.priceExtremePair && (
|
||||
<PriceExtremePairNodeSettings
|
||||
mode={node.priceExtremePair.mode}
|
||||
shortPeriod={node.priceExtremePair.shortPeriod}
|
||||
longPeriod={node.priceExtremePair.longPeriod}
|
||||
filterLevel={inferPriceExtremeFilterLevel(node)}
|
||||
onChange={level => d.onUpdatePriceExtremeFilterLevel?.(id, level)}
|
||||
onClose={() => setSettingsOpen(false)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user