Created
November 12, 2025 22:36
-
-
Save flying3615/1d68faef742273d0c8d4e7a57fde8b37 to your computer and use it in GitHub Desktop.
price action decision tree
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 建仓决策树页面 v1.0 | |
| // 基于交易形态指南的完整决策树系统 | |
| // 使用 React Flow 实现决策树可视化 | |
| 'use client'; | |
| import { useCallback } from 'react'; | |
| import { | |
| ReactFlow, | |
| Node, | |
| Edge, | |
| addEdge, | |
| Connection, | |
| useNodesState, | |
| useEdgesState, | |
| Controls, | |
| MiniMap, | |
| Background, | |
| BackgroundVariant, | |
| Handle, | |
| Position, | |
| } from '@xyflow/react'; | |
| import '@xyflow/react/dist/style.css'; | |
| // 自定义决策节点组件 | |
| function DecisionNode({ | |
| data, | |
| }: { | |
| data: { label: string; question?: string; details?: string }; | |
| }) { | |
| return ( | |
| <div className='px-4 py-3 shadow-lg rounded-lg bg-white/90 backdrop-blur-sm border-2 border-blue-300 max-w-xs'> | |
| <Handle type='target' position={Position.Top} /> | |
| <Handle type='source' position={Position.Bottom} /> | |
| <div className='font-bold text-sm text-slate-800'>{data.label}</div> | |
| {data.question && ( | |
| <div className='text-xs text-slate-600 mt-1 font-medium'> | |
| {data.question} | |
| </div> | |
| )} | |
| {data.details && ( | |
| <div className='text-xs text-slate-500 mt-1 italic'>{data.details}</div> | |
| )} | |
| </div> | |
| ); | |
| } | |
| // 自定义结果节点组件 | |
| function ResultNode({ | |
| data, | |
| }: { | |
| data: { | |
| label: string; | |
| action?: string; | |
| tooltip?: string; | |
| details?: string; | |
| category?: string; | |
| }; | |
| }) { | |
| const categoryColors = { | |
| strong_trend: 'bg-red-50/90 border-red-400 text-red-800', | |
| trend_continuation: 'bg-blue-50/90 border-blue-400 text-blue-800', | |
| equilibrium: 'bg-orange-50/90 border-orange-400 text-orange-800', | |
| reversal: 'bg-purple-50/90 border-purple-400 text-purple-800', | |
| default: 'bg-emerald-50/90 border-emerald-400 text-emerald-800', | |
| }; | |
| const colorClass = | |
| categoryColors[data.category as keyof typeof categoryColors] || | |
| categoryColors.default; | |
| return ( | |
| <div | |
| className={`px-4 py-3 shadow-lg rounded-lg ${colorClass} max-w-xs`} | |
| title={data.tooltip || 'Placeholder tooltip'} | |
| > | |
| <Handle type='target' position={Position.Top} /> | |
| <div className='font-bold text-sm'>{data.label}</div> | |
| {data.action && ( | |
| <div className='text-xs mt-1 font-medium'>{data.action}</div> | |
| )} | |
| {data.details && ( | |
| <div className='text-xs mt-1 italic opacity-80'>{data.details}</div> | |
| )} | |
| </div> | |
| ); | |
| } | |
| // 节点类型映射 | |
| const nodeTypes = { | |
| decision: DecisionNode, | |
| result: ResultNode, | |
| }; | |
| // 初始节点数据(交易决策树) | |
| const initialNodes: Node[] = [ | |
| // 第一步:市场脉络判断 | |
| { | |
| id: 'context', | |
| type: 'decision', | |
| position: { x: 500, y: 50 }, | |
| data: { | |
| label: '市场脉络 (Context)', | |
| question: '当前市场处于哪个阶段?', | |
| details: 'K线形态、动能表现、回撤深度', | |
| }, | |
| }, | |
| { | |
| id: 'spike', | |
| type: 'decision', | |
| position: { x: -27.729411764705873, y: 193.91764705882352 }, | |
| data: { | |
| label: '急速 (Spike)', | |
| question: '连续顺畅趋势K线,回撤极浅?', | |
| details: '穿透支撑/阻力,动能强劲', | |
| }, | |
| }, | |
| { | |
| id: 'tight_channel', | |
| type: 'decision', | |
| position: { x: 331.75294117647053, y: 240.14352941176463 }, | |
| data: { | |
| label: '窄幅通道 (Tight Channel)', | |
| question: '稍短趋势K线,有轻微停顿回调?', | |
| details: '回调温和,趋势延续性强', | |
| }, | |
| }, | |
| { | |
| id: 'broad_channel', | |
| type: 'decision', | |
| position: { x: 618.2470588235294, y: 237.71058823529415 }, | |
| data: { | |
| label: '宽幅通道 (Broad Channel)', | |
| question: '回调明显、持续时间久、深度较大?', | |
| details: '回撤明显,可能出现持续或反转', | |
| }, | |
| }, | |
| { | |
| id: 'trading_range', | |
| type: 'decision', | |
| position: { x: 957.0494117647056, y: 185.40235294117647 }, | |
| data: { | |
| label: '区间 (Trading Range)', | |
| question: '双边交易特征明显,多空势均力敌?', | |
| details: '80%的时间市场处于这种状态', | |
| }, | |
| }, | |
| // 强势趋势建仓形态分支 | |
| { | |
| id: 'strong_trend_setups', | |
| type: 'decision', | |
| position: { x: 160.52705882352947, y: 358.515294117647 }, | |
| data: { | |
| label: '强势趋势建仓', | |
| question: '选择具体建仓形态', | |
| details: '动能交易者策略,高胜率风格', | |
| }, | |
| }, | |
| { | |
| id: 'momentum_entry', | |
| type: 'decision', | |
| position: { x: -82.47058823529413, y: 517.0305882352941 }, | |
| data: { | |
| label: '动能确认?', | |
| question: '是否有明确突破K线?', | |
| details: '穿透支撑/阻力,动能最强时入场', | |
| }, | |
| }, | |
| { | |
| id: 'close_based_entry', | |
| type: 'result', | |
| position: { x: -213.9741176470588, y: 703.524705882353 }, | |
| data: { | |
| label: '收线追进 (T-MOM)', | |
| action: '收线时市价追进突破方向', | |
| details: '剥头皮交易风格,高胜率(60%),1.0倍盈亏比,1-5根K线', | |
| category: 'strong_trend', | |
| }, | |
| }, | |
| { | |
| id: '20ma_gap_check', | |
| type: 'decision', | |
| position: { x: 224.4541176470588, y: 518.2470588235296 }, | |
| data: { | |
| label: '均线缺口形态?', | |
| question: '连续20根以上K线未触及均线?', | |
| details: '价格远离均线后首次回撤', | |
| }, | |
| }, | |
| { | |
| id: 'ma_gap_type', | |
| type: 'decision', | |
| position: { x: 84.80941176470589, y: 665.8141176470588 }, | |
| data: { | |
| label: '缺口类型', | |
| question: '首次均线回撤还是20均线缺口?', | |
| details: '微观多空竞合后顺势方重新占优', | |
| }, | |
| }, | |
| { | |
| id: 'first_ma_gap', | |
| type: 'result', | |
| position: { x: -46.69411764705882, y: 866.9058823529411 }, | |
| data: { | |
| label: '第一均线缺口 (T-MAG)', | |
| action: '信号K线外设止损,回调末端入场', | |
| details: '剥头皮交易风格,高胜率(60%),1.0倍盈亏比', | |
| category: 'strong_trend', | |
| }, | |
| }, | |
| { | |
| id: '20ma_gap', | |
| type: 'result', | |
| position: { x: 221.17882352941172, y: 868.1223529411764 }, | |
| data: { | |
| label: '20均线缺口 (T-MAG)', | |
| action: '重要波段点外设止损,同侧高/低1入场', | |
| details: '剥头皮交易风格,60%胜率,强势趋势延续,利用均线防线', | |
| category: 'strong_trend', | |
| }, | |
| }, | |
| // 趋势持续与测试形态分支 | |
| { | |
| id: 'continuation_setups', | |
| type: 'decision', | |
| position: { x: 928.4470588235295, y: 362.16470588235296 }, | |
| data: { | |
| label: '趋势持续与测试', | |
| question: '选择具体建仓形态', | |
| details: '波段交易策略,中高盈亏比', | |
| }, | |
| }, | |
| { | |
| id: 'counter_test', | |
| type: 'decision', | |
| position: { x: 642.3270588235296, y: 486.61882352941166 }, | |
| data: { | |
| label: '逆势测试?', | |
| question: '是否出现逆势K线但动能不足?', | |
| details: '低1失败,顺1成功是关键', | |
| }, | |
| }, | |
| { | |
| id: 'counter_pro_1', | |
| type: 'result', | |
| position: { x: 640.9858823529413, y: 662.1647058823529 }, | |
| data: { | |
| label: '逆1顺1 (T-C1P1)', | |
| action: '逆势止损后,顺势突破时入场', | |
| details: '波段交易风格,2.0倍盈亏比,40%胜率', | |
| category: 'trend_continuation', | |
| }, | |
| }, | |
| { | |
| id: 'breakout_test', | |
| type: 'decision', | |
| position: { x: 850.7176470588238, y: 585.1529411764704 }, | |
| data: { | |
| label: '突破测试?', | |
| question: '是否有成功突破后折返测试?', | |
| details: '突破动能是否延续到第二推', | |
| }, | |
| }, | |
| { | |
| id: 'breakout_pullback', | |
| type: 'result', | |
| position: { x: 791.1105882352942, y: 778.9458823529412 }, | |
| data: { | |
| label: '突破回调 (T-BOPB)', | |
| action: '测试点确认后,逆势疲弱时入场', | |
| details: '波段交易风格,2.0倍盈亏比,40%胜率,等待第二推,目标等距运动', | |
| category: 'trend_continuation', | |
| }, | |
| }, | |
| { | |
| id: 'double_test', | |
| type: 'decision', | |
| position: { x: 984.7788235294116, y: 700.7176470588238 }, | |
| data: { | |
| label: '双重测试?', | |
| question: '是否两次测试同一水平失败?', | |
| details: '磁体测试失败,逆势动能疲弱', | |
| }, | |
| }, | |
| { | |
| id: 'double_top_bottom', | |
| type: 'result', | |
| position: { x: 978.6964705882351, y: 881.1294117647058 }, | |
| data: { | |
| label: '双重顶/底 (T-DTB)', | |
| action: '第二次测试失败后顺势突破入场', | |
| details: '波段交易风格,2.0倍盈亏比,40%胜率,旗形回调变体,目标AB=CD等距', | |
| category: 'trend_continuation', | |
| }, | |
| }, | |
| { | |
| id: 'wedge_test', | |
| type: 'decision', | |
| position: { x: 1094.5105882352943, y: 486.61882352941166 }, | |
| data: { | |
| label: '楔形结构?', | |
| question: '是否三次推动失败,倾斜收敛?', | |
| details: '楔形底/顶,逆势力量消耗', | |
| }, | |
| }, | |
| { | |
| id: 'wedge_top_bottom', | |
| type: 'result', | |
| position: { x: 1178.4470588235292, y: 618.3717647058825 }, | |
| data: { | |
| label: '楔形顶/底 (T-WDG)', | |
| action: '楔形突破后,趋势恢复时入场', | |
| details: '波段交易风格,2.0倍盈亏比,40%胜率,三推失败,逆势方动能衰退', | |
| category: 'trend_continuation', | |
| }, | |
| }, | |
| // 均衡或区间形态分支 | |
| { | |
| id: 'range_setups', | |
| type: 'decision', | |
| position: { x: 1217.3741176470587, y: 303.7741176470589 }, | |
| data: { | |
| label: '均衡或区间形态', | |
| question: '选择具体建仓形态', | |
| details: '80%概率突破失败,逆势策略', | |
| }, | |
| }, | |
| { | |
| id: 'breakout_failure', | |
| type: 'decision', | |
| position: { x: 1326.6070588235298, y: 486.61882352941194 }, | |
| data: { | |
| label: '突破失败?', | |
| question: '是否出现突破但缺乏跟进?', | |
| details: '影线可视为突破失败信号', | |
| }, | |
| }, | |
| { | |
| id: 'fade_breakout', | |
| type: 'result', | |
| position: { x: 1302.1529411764704, y: 763.1317647058822 }, | |
| data: { | |
| label: '看衰突破 (E-FDB)', | |
| action: '突破失败后,信号K线反向突破时做空', | |
| details: '80%概率回归区间,逆势交易', | |
| category: 'equilibrium', | |
| }, | |
| }, | |
| { | |
| id: 'magnet_rush', | |
| type: 'decision', | |
| position: { x: 1537.555294117647, y: 437.9599999999998 }, | |
| data: { | |
| label: '磁体冲刺?', | |
| question: '价格是否快速奔向明确磁体?', | |
| details: '支撑/阻力、前波段点、均线等', | |
| }, | |
| }, | |
| { | |
| id: 'rush_to_magnet', | |
| type: 'result', | |
| position: { x: 1546.0705882352938, y: 765.564705882353 }, | |
| data: { | |
| label: '急赴磁体 (E-RTM)', | |
| action: '收线追进,目标是磁体位置', | |
| details: '剥头皮交易风格,1.0倍盈亏比,60%胜率,动能追进,磁体处高潮结束', | |
| category: 'equilibrium', | |
| }, | |
| }, | |
| // 反转形态分支 | |
| { | |
| id: 'reversal_setups', | |
| type: 'decision', | |
| position: { x: 450.37411764705894, y: 460.35529411764696 }, | |
| data: { | |
| label: '反转形态', | |
| question: '选择具体建仓形态', | |
| details: '趋势末期,动能衰退期', | |
| }, | |
| }, | |
| { | |
| id: 'final_flag_check', | |
| type: 'decision', | |
| position: { x: 421.1788235294117, y: 691.8588235294118 }, | |
| data: { | |
| label: '末端旗形?', | |
| question: '趋势末期旗形未能引发延续?', | |
| details: '关键磁体突破失败,逆势方占优', | |
| }, | |
| }, | |
| { | |
| id: 'final_flag_reversal', | |
| type: 'result', | |
| position: { x: 546.4752941176471, y: 878.3529411764705 }, | |
| data: { | |
| label: '末端旗形反转 (R-FFL)', | |
| action: '高潮后动能丧失,重要波段点外止损', | |
| details: '波段交易风格,至少2.0倍盈亏比,40%胜率,大波段反转交易', | |
| category: 'reversal', | |
| }, | |
| }, | |
| ]; | |
| // 初始边数据(交易决策树) | |
| const initialEdges: Edge[] = [ | |
| // 市场脉络分支 | |
| { | |
| id: 'context-spike', | |
| source: 'context', | |
| target: 'spike', | |
| label: '急速', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'context-tight', | |
| source: 'context', | |
| target: 'tight_channel', | |
| label: '窄幅通道', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'context-broad', | |
| source: 'context', | |
| target: 'broad_channel', | |
| label: '宽幅通道', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'context-range', | |
| source: 'context', | |
| target: 'trading_range', | |
| label: '区间', | |
| type: 'smoothstep', | |
| }, | |
| // 强势趋势分支 | |
| { | |
| id: 'spike-strong', | |
| source: 'spike', | |
| target: 'strong_trend_setups', | |
| label: '强顺势', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'tight-strong', | |
| source: 'tight_channel', | |
| target: 'strong_trend_setups', | |
| label: '顺势为主', | |
| type: 'smoothstep', | |
| }, | |
| // 强势趋势具体形态 | |
| { | |
| id: 'strong-momentum', | |
| source: 'strong_trend_setups', | |
| target: 'momentum_entry', | |
| label: '动能突破', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'momentum-entry', | |
| source: 'momentum_entry', | |
| target: 'close_based_entry', | |
| label: '确认突破', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'strong-ma-gap', | |
| source: 'strong_trend_setups', | |
| target: '20ma_gap_check', | |
| label: '均线缺口', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'ma-gap-confirm', | |
| source: '20ma_gap_check', | |
| target: 'ma_gap_type', | |
| label: '连续未触20线', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'gap-first', | |
| source: 'ma_gap_type', | |
| target: 'first_ma_gap', | |
| label: '首次回撤', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'gap-20', | |
| source: 'ma_gap_type', | |
| target: '20ma_gap', | |
| label: '20线缺口', | |
| type: 'smoothstep', | |
| }, | |
| // 趋势持续与测试分支 | |
| { | |
| id: 'broad-continuation', | |
| source: 'broad_channel', | |
| target: 'continuation_setups', | |
| label: '持续/测试', | |
| type: 'smoothstep', | |
| }, | |
| // 趋势持续具体形态 | |
| { | |
| id: 'cont-counter', | |
| source: 'continuation_setups', | |
| target: 'counter_test', | |
| label: '逆1顺1', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'counter-entry', | |
| source: 'counter_test', | |
| target: 'counter_pro_1', | |
| label: '逆势失败', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'cont-breakout', | |
| source: 'continuation_setups', | |
| target: 'breakout_test', | |
| label: '突破回调', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'breakout-entry', | |
| source: 'breakout_test', | |
| target: 'breakout_pullback', | |
| label: '测试确认', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'cont-double', | |
| source: 'continuation_setups', | |
| target: 'double_test', | |
| label: '双重顶/底', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'double-entry', | |
| source: 'double_test', | |
| target: 'double_top_bottom', | |
| label: '两次失败', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'cont-wedge', | |
| source: 'continuation_setups', | |
| target: 'wedge_test', | |
| label: '楔形结构', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'wedge-entry', | |
| source: 'wedge_test', | |
| target: 'wedge_top_bottom', | |
| label: '三推失败', | |
| type: 'smoothstep', | |
| }, | |
| // 区间形态分支 | |
| { | |
| id: 'range-setups', | |
| source: 'trading_range', | |
| target: 'range_setups', | |
| label: '双边交易', | |
| type: 'smoothstep', | |
| }, | |
| // 区间具体形态 | |
| { | |
| id: 'range-fade', | |
| source: 'range_setups', | |
| target: 'breakout_failure', | |
| label: '看衰突破', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'fade-entry', | |
| source: 'breakout_failure', | |
| target: 'fade_breakout', | |
| label: '突破失败', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'range-rush', | |
| source: 'range_setups', | |
| target: 'magnet_rush', | |
| label: '急赴磁体', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'rush-entry', | |
| source: 'magnet_rush', | |
| target: 'rush_to_magnet', | |
| label: '磁体冲刺', | |
| type: 'smoothstep', | |
| }, | |
| // 反转形态分支 | |
| { | |
| id: 'broad-reversal', | |
| source: 'broad_channel', | |
| target: 'reversal_setups', | |
| label: '反转可能', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'reversal-flag', | |
| source: 'reversal_setups', | |
| target: 'final_flag_check', | |
| label: '末端旗形', | |
| type: 'smoothstep', | |
| }, | |
| { | |
| id: 'final-entry', | |
| source: 'final_flag_check', | |
| target: 'final_flag_reversal', | |
| label: '动能丧失', | |
| type: 'smoothstep', | |
| }, | |
| ]; | |
| export default function DecisionTreePage() { | |
| const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes); | |
| const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges); | |
| const onConnect = useCallback( | |
| (params: Connection) => setEdges((eds) => addEdge(params, eds)), | |
| [setEdges] | |
| ); | |
| return ( | |
| <div className='w-full h-screen bg-gradient-to-br from-slate-50 to-slate-100'> | |
| <ReactFlow | |
| nodes={nodes} | |
| edges={edges} | |
| onNodesChange={onNodesChange} | |
| onEdgesChange={onEdgesChange} | |
| onConnect={onConnect} | |
| nodeTypes={nodeTypes} | |
| fitView | |
| attributionPosition='top-right' | |
| className='bg-transparent' | |
| defaultEdgeOptions={{ | |
| style: { stroke: '#374151', strokeWidth: 2 }, | |
| type: 'smoothstep', | |
| }} | |
| > | |
| <Controls className='bg-white/80 backdrop-blur-sm border border-slate-200 rounded-lg shadow-lg' /> | |
| <MiniMap className='bg-white/80 backdrop-blur-sm border border-slate-200 rounded-lg shadow-lg' /> | |
| <Background | |
| variant={BackgroundVariant.Dots} | |
| gap={16} | |
| size={1} | |
| className='opacity-30' | |
| /> | |
| </ReactFlow> | |
| </div> | |
| ); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment