추세선 전략추가

This commit is contained in:
Macbook
2026-06-25 02:45:39 +09:00
parent ee8cd50781
commit f9447ea52f
31 changed files with 1793 additions and 49 deletions
+38 -2
View File
@@ -48,6 +48,8 @@ import {
import IndicatorPaletteTab from './strategyEditor/IndicatorPaletteTab';
import TemplatePaletteTab, { type TemplatePaletteRow } from './strategyEditor/TemplatePaletteTab';
import SidewaysFilterPaletteTab from './strategyEditor/SidewaysFilterPaletteTab';
import TrendLinePaletteTab from './strategyEditor/TrendLinePaletteTab';
import { buildTrendLineConditionNode } from '../utils/trendLinePalette';
import { buildSidewaysFilterNode, loadSidewaysPaletteItems } from '../utils/sidewaysFilterPaletteStorage';
import {
BAND_PALETTE_CHIP_ITEMS,
@@ -319,7 +321,7 @@ export default function StrategyEditorPage({
const [sellCondition, setSellCondition] = useState<LogicNode | null>(null);
const [signalTab, setSignalTab] = useState<SignalTab>('buy');
const [rightTab, setRightTab] = useState<'indicators' | 'templates'>('indicators');
const [indicatorSubTab, setIndicatorSubTab] = useState<'auxiliary' | 'composite' | 'range'>('auxiliary');
const [indicatorSubTab, setIndicatorSubTab] = useState<'auxiliary' | 'composite' | 'range' | 'trendline'>('auxiliary');
const [auxiliaryPalette, setAuxiliaryPalette] = useState<PaletteItem[]>(() => loadPaletteItems('auxiliary'));
const [compositePalette, setCompositePalette] = useState<PaletteItem[]>(() => loadPaletteItems('composite'));
const [sidewaysPalette, setSidewaysPalette] = useState(() => loadSidewaysPaletteItems());
@@ -1436,6 +1438,15 @@ export default function StrategyEditorPage({
scheduleStrategyPersist();
}, [DEF, currentRoot, setCurrentRoot, scheduleStrategyPersist, sidewaysPalette]);
const applyTrendLine = useCallback((item: { indicatorType: string; leftField?: string }, lookback: number) => {
const newNode = buildTrendLineConditionNode(item, buySellTab(signalTab), DEF, lookback);
handleEditorStateChange(prev => {
const root = prev.root;
if (!root) return updateBranchRoot(prev, START_NODE_ID, newNode);
return updateBranchRoot(prev, START_NODE_ID, mergeAtRoot(root, newNode, false));
});
}, [signalTab, DEF, handleEditorStateChange]);
const templateRows = useMemo(
() => buildStrategyTemplatePaletteRows({
def: DEF,
@@ -2487,6 +2498,16 @@ export default function StrategyEditorPage({
>
</button>
<button
type="button"
className={`se-palette-subtab se-palette-subtab--trendline${indicatorSubTab === 'trendline' ? ' se-palette-subtab--on' : ''}`}
onClick={() => {
setIndicatorSubTab('trendline');
setSelectedPaletteKey(null);
}}
>
</button>
</div>
{indicatorSubTab === 'auxiliary' ? (
<IndicatorPaletteTab
@@ -2524,7 +2545,7 @@ export default function StrategyEditorPage({
applyPaletteItem(item);
}}
/>
) : (
) : indicatorSubTab === 'range' ? (
<SidewaysFilterPaletteTab
def={DEF}
items={sidewaysPalette}
@@ -2541,6 +2562,21 @@ export default function StrategyEditorPage({
applySidewaysFilter(item.id);
}}
/>
) : (
<TrendLinePaletteTab
signalType={buySellTab(signalTab)}
searchQuery={paletteSearch}
selectedItemId={
selectedPaletteKey?.startsWith('trendline:')
? selectedPaletteKey.slice('trendline:'.length)
: null
}
onSelectItem={id => setSelectedPaletteKey(id ? paletteKey('trendline', id) : null)}
onAddToCanvas={(item, lookback) => {
selectPalette('trendline', item.id);
applyTrendLine(item, lookback);
}}
/>
)}
</>
)}