UNPKG

@gabriel3615/ta_analysis

Version:

stock ta analysis

686 lines (685 loc) 24.8 kB
export let patternConfig = { windows: { sliceRecentCount: 100, peakWindow: 5, recentEmphasis: true, formingNearDistance: 5, }, weights: { timeframe: { weekly: 1.5, daily: 1.3, '1hour': 1.0 }, confirmedBoost: 1.5, formingBoost: 1.3, patternDistanceDecay: 0.05, peakImportanceDecay: 0.01, }, signals: { strongRatio: 1.5, combineBiasRatio: 1.2, recentCount: 10, reliabilityBoostThreshold: 70, recencyHighThreshold: 0.8, recencyMediumThreshold: 0.6, recencyHighBonus: 10, recencyMediumBonus: 5, }, // 新增:统一的形态验证参数默认值 validation: { priceSimilarityThreshold: 0.05, // 5% minPatternHeightRatio: 0.02, // 2% minPatternDuration: 5, maxPatternDuration: 100, breakoutConfirmationBars: 3, breakoutConfirmationPercent: 0.01, // 1% failureRetracementThreshold: 0.6, // 60% volumeConfirmationMultiplier: 1.5, minTrendlineTouches: 3, trendlineTouchTolerance: 0.005, // 0.5% }, }; export function updatePatternConfig(partial) { patternConfig = { ...patternConfig, ...partial, windows: { ...patternConfig.windows, ...(partial.windows || {}) }, weights: { ...patternConfig.weights, ...(partial.weights || {}), timeframe: { ...patternConfig.weights.timeframe, ...((partial.weights && partial.weights.timeframe) || {}), }, }, signals: { ...patternConfig.signals, ...(partial.signals || {}) }, validation: { ...patternConfig.validation, ...(partial.validation || {}) }, }; } /** * 检查两个价格是否在同一水平(相似度检查) */ export function arePricesSimilar(price1, price2) { const avgPrice = (price1 + price2) / 2; const priceDiff = Math.abs(price1 - price2) / avgPrice; return priceDiff <= patternConfig.validation.priceSimilarityThreshold; } /** * 检查价格是否接近趋势线 */ export function isPriceNearTrendline(price, trendlinePrice) { const priceDiff = Math.abs(price - trendlinePrice) / trendlinePrice; return priceDiff <= patternConfig.validation.trendlineTouchTolerance; } /** * 计算形态高度是否足够显著 */ export function isPatternHeightSignificant(patternHeight, avgPrice) { const heightRatio = patternHeight / avgPrice; return heightRatio >= patternConfig.validation.minPatternHeightRatio; } /** * 检查形态持续时间是否在合理范围内 */ export function isPatternDurationValid(duration) { return (duration >= patternConfig.validation.minPatternDuration && duration <= patternConfig.validation.maxPatternDuration); } /** * 检查是否为有效突破 */ export function isValidBreakout(data, breakoutIndex, breakoutLevel, isUpward) { // 检查是否有足够的确认K线 const confirmationBars = Math.min(patternConfig.validation.breakoutConfirmationBars, data.length - breakoutIndex - 1); if (confirmationBars < 1) return false; let confirmedBars = 0; const requiredMove = breakoutLevel * patternConfig.validation.breakoutConfirmationPercent; for (let i = 1; i <= confirmationBars; i++) { const candle = data[breakoutIndex + i]; if (isUpward) { // 向上突破:收盘价应持续高于突破水平 if (candle.close > breakoutLevel + requiredMove) { confirmedBars++; } } else { // 向下突破:收盘价应持续低于突破水平 if (candle.close < breakoutLevel - requiredMove) { confirmedBars++; } } } // 至少需要60%的确认K线满足条件 return confirmedBars >= confirmationBars * 0.6; } /** * 检查形态是否失败 */ export function isPatternFailed(data, patternEndIndex, breakoutLevel, isUpward) { // 检查突破后的价格走势 for (let i = patternEndIndex + 1; i < data.length; i++) { const candle = data[i]; if (isUpward) { // 向上突破后,如果价格大幅回撤到突破水平以下,可能失败 const retracement = (breakoutLevel - candle.low) / (candle.high - breakoutLevel); if (retracement > patternConfig.validation.failureRetracementThreshold) { return true; } } else { // 向下突破后,如果价格大幅反弹到突破水平以上,可能失败 const retracement = (candle.high - breakoutLevel) / (breakoutLevel - candle.low); if (retracement > patternConfig.validation.failureRetracementThreshold) { return true; } } } return false; } /** * 计算标准化的可靠性评分 */ export function calculateStandardReliability(factors) { let score = 50; // 基础分数 // 1. 形态高度评分(0-15分) const heightRatio = factors.patternHeight / factors.avgPrice; if (heightRatio > 0.1) { score += 15; // 高度非常显著 } else if (heightRatio > 0.05) { score += 12; // 高度显著 } else if (heightRatio > 0.03) { score += 8; // 高度中等 } else if (heightRatio > 0.02) { score += 4; // 高度较小 } // 2. 形态持续时间评分(0-10分) if (factors.duration > 30) { score += 10; // 长期形态 } else if (factors.duration > 20) { score += 8; // 中长期形态 } else if (factors.duration > 10) { score += 6; // 中期形态 } else if (factors.duration > 5) { score += 3; // 短期形态 } // 3. 对称性评分(0-10分) if (factors.symmetry !== undefined) { score += factors.symmetry * 10; } // 4. 趋势线触碰评分(0-10分) if (factors.trendlineTouches !== undefined && factors.expectedTouches !== undefined) { const touchRatio = factors.trendlineTouches / factors.expectedTouches; if (touchRatio >= 1) { score += 10; // 触碰次数达到或超过预期 } else if (touchRatio >= 0.8) { score += 8; // 触碰次数接近预期 } else if (touchRatio >= 0.6) { score += 5; // 触碰次数中等 } else if (touchRatio >= 0.4) { score += 2; // 触碰次数较少 } } // 5. 成交量确认评分(0-15分) if (factors.volumeConfirmation !== undefined) { if (factors.volumeConfirmation) { score += 15; // 有成交量确认 } else { score += 5; // 无成交量确认 } } // 6. 成交量模式质量评分(0-10分) if (factors.volumePattern !== undefined) { switch (factors.volumePattern) { case 'ideal': score += 10; break; case 'good': score += 7; break; case 'acceptable': score += 4; break; case 'poor': score += 0; break; } } // 7. 突破确认评分(0-15分) if (factors.breakoutConfirmed !== undefined) { if (factors.breakoutConfirmed) { score += 15; // 突破已确认 // 突破强度额外加分(0-5分) if (factors.breakoutStrength !== undefined) { score += factors.breakoutStrength * 5; } } else { score += 5; // 突破未确认 } } // 8. 新近度评分(0-10分) if (factors.recency !== undefined) { score += factors.recency * 10; } // 9. 形态特定因素评分(0-15分) if (factors.specificFactors !== undefined) { for (const [key, value] of Object.entries(factors.specificFactors)) { // 根据因素权重分配分数 switch (key) { case 'headProminence': // 头肩形态头部突出程度 score += value * 8; break; case 'necklineSlope': // 头肩形态颈线斜率 score += value * 5; break; case 'cupDepth': // 杯柄形态杯深度 score += value * 7; break; case 'handleDepth': // 杯柄形态柄深度 score += value * 5; break; case 'convergenceProximity': // 三角形收敛接近度 score += value * 6; break; default: score += value * 3; // 默认权重 break; } } } // 确保分数在0-100范围内 return Math.max(0, Math.min(100, score)); } /** * 分析成交量模式质量 */ export function analyzeVolumePatternQuality(data, startIndex, endIndex, patternType) { // 计算各阶段成交量 const patternVolumes = data .slice(startIndex, endIndex + 1) .map(d => d.volume); const avgPatternVolume = patternVolumes.reduce((sum, v) => sum + v, 0) / patternVolumes.length; // 计算成交量趋势 let volumeTrend = 0; for (let i = 1; i < patternVolumes.length; i++) { volumeTrend += patternVolumes[i] > patternVolumes[i - 1] ? 1 : -1; } const trendStrength = Math.abs(volumeTrend) / (patternVolumes.length - 1); // 检查突破时的成交量(如果有) let breakoutVolume = 0; if (endIndex + 1 < data.length) { breakoutVolume = data[endIndex + 1].volume; } // 根据形态类型评估成交量模式 if (patternType === 'reversal') { // 反转形态:理想情况是形态内成交量萎缩,突破时放量 if (trendStrength < 0.3 && breakoutVolume > avgPatternVolume * 1.5) { return 'ideal'; } else if (trendStrength < 0.5 && breakoutVolume > avgPatternVolume * 1.2) { return 'good'; } else if (trendStrength < 0.7) { return 'acceptable'; } else { return 'poor'; } } else if (patternType === 'continuation') { // 持续形态:理想情况是形态内成交量萎缩,突破时放量 if (trendStrength < 0.3 && breakoutVolume > avgPatternVolume * 1.5) { return 'ideal'; } else if (trendStrength < 0.5 && breakoutVolume > avgPatternVolume * 1.2) { return 'good'; } else if (trendStrength < 0.7) { return 'acceptable'; } else { return 'poor'; } } else { // 整理形态:理想情况是成交量逐渐萎缩 if (trendStrength < 0.2) { return 'ideal'; } else if (trendStrength < 0.4) { return 'good'; } else if (trendStrength < 0.6) { return 'acceptable'; } else { return 'poor'; } } } /** * 计算突破强度 */ export function calculateBreakoutStrength(data, breakoutIndex, breakoutLevel, isUpward) { if (breakoutIndex >= data.length) return 0; const breakoutCandle = data[breakoutIndex]; const breakoutPrice = isUpward ? breakoutCandle.close : breakoutCandle.close; const breakoutSize = Math.abs(breakoutPrice - breakoutLevel) / breakoutLevel; // 计算突破成交量 const avgVolume = data .slice(Math.max(0, breakoutIndex - 20), breakoutIndex) .reduce((sum, d) => sum + d.volume, 0) / Math.min(20, breakoutIndex); const volumeRatio = breakoutCandle.volume / avgVolume; // 综合价格突破和成交量因素 const priceStrength = Math.min(breakoutSize * 10, 1); // 标准化到0-1 const volumeStrength = Math.min(volumeRatio / 3, 1); // 标准化到0-1 return (priceStrength + volumeStrength) / 2; } /** * 形态冲突处理机制 */ // 需要导入PatternType和PatternAnalysisResult类型 import { PatternType, PatternDirection, } from './analyzeMultiTimeframePatterns.js'; /** * 形态优先级枚举 */ export var PatternPriority; (function (PatternPriority) { PatternPriority[PatternPriority["Critical"] = 5] = "Critical"; PatternPriority[PatternPriority["High"] = 4] = "High"; PatternPriority[PatternPriority["Medium"] = 3] = "Medium"; PatternPriority[PatternPriority["Low"] = 2] = "Low"; PatternPriority[PatternPriority["Minor"] = 1] = "Minor"; })(PatternPriority || (PatternPriority = {})); /** * 获取形态类型的优先级 */ export function getPatternPriority(patternType) { switch (patternType) { case PatternType.HeadAndShoulders: case PatternType.InverseHeadAndShoulders: case PatternType.DoubleTop: case PatternType.DoubleBottom: case PatternType.TripleTop: case PatternType.TripleBottom: return PatternPriority.Critical; case PatternType.AscendingTriangle: case PatternType.DescendingTriangle: case PatternType.SymmetricalTriangle: case PatternType.RisingWedge: case PatternType.FallingWedge: return PatternPriority.High; case PatternType.Flag: case PatternType.Pennant: case PatternType.Rectangle: return PatternPriority.Medium; case PatternType.RoundingBottom: case PatternType.RoundingTop: case PatternType.CupAndHandle: return PatternPriority.Low; case PatternType.BuyingClimax: case PatternType.SellingClimax: return PatternPriority.Minor; default: return PatternPriority.Medium; } } /** * 形态冲突类型 */ export var ConflictType; (function (ConflictType) { ConflictType["DirectionConflict"] = "direction_conflict"; ConflictType["OverlapConflict"] = "overlap_conflict"; ConflictType["TimingConflict"] = "timing_conflict"; ConflictType["LevelConflict"] = "level_conflict"; })(ConflictType || (ConflictType = {})); /** * 检测形态冲突 */ export function detectPatternConflicts(patterns) { const conflicts = []; // 检查所有形态对之间的冲突 for (let i = 0; i < patterns.length; i++) { for (let j = i + 1; j < patterns.length; j++) { const pattern1 = patterns[i]; const pattern2 = patterns[j]; // 检测方向冲突 if (pattern1.direction !== pattern2.direction) { const directionConflict = detectDirectionConflict(pattern1, pattern2); if (directionConflict) { conflicts.push(directionConflict); } } // 检测重叠冲突 const overlapConflict = detectOverlapConflict(pattern1, pattern2); if (overlapConflict) { conflicts.push(overlapConflict); } // 检测水平冲突 const levelConflict = detectLevelConflict(pattern1, pattern2); if (levelConflict) { conflicts.push(levelConflict); } } } return conflicts; } /** * 检测方向冲突 */ function detectDirectionConflict(pattern1, pattern2) { // 如果方向不同且可靠性都较高,则存在方向冲突 if (pattern1.direction !== pattern2.direction && pattern1.reliability > 60 && pattern2.reliability > 60) { const severity = Math.min(pattern1.reliability, pattern2.reliability) / 100; return { type: ConflictType.DirectionConflict, pattern1, pattern2, severity, description: `${pattern1.patternType}(${pattern1.direction})与${pattern2.patternType}(${pattern2.direction})方向冲突`, }; } return null; } /** * 检测重叠冲突 */ function detectOverlapConflict(pattern1, pattern2) { // 检查形态时间范围是否重叠 const overlapStart = Math.max(pattern1.component.startIndex, pattern2.component.startIndex); const overlapEnd = Math.min(pattern1.component.endIndex, pattern2.component.endIndex); if (overlapStart <= overlapEnd) { // 计算重叠程度 const pattern1Duration = pattern1.component.endIndex - pattern1.component.startIndex; const pattern2Duration = pattern2.component.endIndex - pattern2.component.startIndex; const overlapDuration = overlapEnd - overlapStart; const overlapRatio1 = overlapDuration / pattern1Duration; const overlapRatio2 = overlapDuration / pattern2Duration; const maxOverlapRatio = Math.max(overlapRatio1, overlapRatio2); // 如果重叠程度超过50%,则认为存在冲突 if (maxOverlapRatio > 0.5) { return { type: ConflictType.OverlapConflict, pattern1, pattern2, severity: maxOverlapRatio, description: `${pattern1.patternType}与${pattern2.patternType}在时间上重叠${(maxOverlapRatio * 100).toFixed(1)}%`, }; } } return null; } /** * 检测水平冲突 */ function detectLevelConflict(pattern1, pattern2) { // 检查关键价位是否冲突 const level1 = pattern1.component.breakoutLevel; const level2 = pattern2.component.breakoutLevel; if (level1 && level2) { const levelDiff = Math.abs(level1 - level2) / Math.min(level1, level2); // 如果关键价位差异小于5%,则认为存在冲突 if (levelDiff < 0.05) { return { type: ConflictType.LevelConflict, pattern1, pattern2, severity: 1 - levelDiff / 0.05, // 差异越小,冲突越严重 description: `${pattern1.patternType}与${pattern2.patternType}的关键价位接近`, }; } } return null; } /** * 解决形态冲突 */ export function resolvePatternConflicts(patterns, conflicts) { // 如果没有冲突,直接返回 if (conflicts.length === 0) { return patterns; } // 创建形态副本用于处理 const resolvedPatterns = [...patterns]; // 按冲突严重程度排序,优先处理严重冲突 conflicts.sort((a, b) => b.severity - a.severity); for (const conflict of conflicts) { const { pattern1, pattern2, type, severity } = conflict; // 根据冲突类型和严重程度采取不同策略 switch (type) { case ConflictType.DirectionConflict: resolveDirectionConflict(resolvedPatterns, pattern1, pattern2, severity); break; case ConflictType.OverlapConflict: resolveOverlapConflict(resolvedPatterns, pattern1, pattern2, severity); break; case ConflictType.LevelConflict: resolveLevelConflict(resolvedPatterns, pattern1, pattern2); break; } } return resolvedPatterns; } /** * 解决方向冲突 */ function resolveDirectionConflict(patterns, pattern1, pattern2, severity) { // 获取形态优先级 const priority1 = getPatternPriority(pattern1.patternType); const priority2 = getPatternPriority(pattern2.patternType); // 如果优先级不同,保留高优先级形态 if (priority1 !== priority2) { if (priority1 > priority2) { // 降低pattern2的可靠性 const index2 = patterns.findIndex(p => p === pattern2); if (index2 !== -1) { patterns[index2].reliability *= 1 - severity * 0.5; } } else { // 降低pattern1的可靠性 const index1 = patterns.findIndex(p => p === pattern1); if (index1 !== -1) { patterns[index1].reliability *= 1 - severity * 0.5; } } } else { // 优先级相同,根据可靠性和重要性决定 const score1 = pattern1.reliability * pattern1.significance; const score2 = pattern2.reliability * pattern2.significance; if (score1 > score2) { // 降低pattern2的可靠性 const index2 = patterns.findIndex(p => p === pattern2); if (index2 !== -1) { patterns[index2].reliability *= 1 - severity * 0.3; } } else { // 降低pattern1的可靠性 const index1 = patterns.findIndex(p => p === pattern1); if (index1 !== -1) { patterns[index1].reliability *= 1 - severity * 0.3; } } } } /** * 解决重叠冲突 */ function resolveOverlapConflict(patterns, pattern1, pattern2, severity) { // 对于重叠冲突,根据形态类型和可靠性调整 const priority1 = getPatternPriority(pattern1.patternType); const priority2 = getPatternPriority(pattern2.patternType); // 如果优先级不同,保留高优先级形态 if (priority1 !== priority2) { if (priority1 > priority2) { // 降低pattern2的重要性 const index2 = patterns.findIndex(p => p === pattern2); if (index2 !== -1) { patterns[index2].significance *= 1 - severity * 0.4; } } else { // 降低pattern1的重要性 const index1 = patterns.findIndex(p => p === pattern1); if (index1 !== -1) { patterns[index1].significance *= 1 - severity * 0.4; } } } else { // 优先级相同,根据可靠性调整 if (pattern1.reliability > pattern2.reliability) { // 降低pattern2的重要性 const index2 = patterns.findIndex(p => p === pattern2); if (index2 !== -1) { patterns[index2].significance *= 1 - severity * 0.3; } } else { // 降低pattern1的重要性 const index1 = patterns.findIndex(p => p === pattern1); if (index1 !== -1) { patterns[index1].significance *= 1 - severity * 0.3; } } } } /** * 解决水平冲突 */ function resolveLevelConflict(patterns, pattern1, pattern2) { // 对于水平冲突,根据形态类型调整 const priority1 = getPatternPriority(pattern1.patternType); const priority2 = getPatternPriority(pattern2.patternType); // 如果优先级不同,保留高优先级形态的关键价位 if (priority1 !== priority2) { if (priority1 > priority2) { // 调整pattern2的突破水平 const index2 = patterns.findIndex(p => p === pattern2); if (index2 !== -1) { // 将突破水平调整5%以避免冲突 if (pattern2.direction === PatternDirection.Bullish) { patterns[index2].component.breakoutLevel *= 1.05; } else { patterns[index2].component.breakoutLevel *= 0.95; } } } else { // 调整pattern1的突破水平 const index1 = patterns.findIndex(p => p === pattern1); if (index1 !== -1) { // 将突破水平调整5%以避免冲突 if (pattern1.direction === PatternDirection.Bullish) { patterns[index1].component.breakoutLevel *= 1.05; } else { patterns[index1].component.breakoutLevel *= 0.95; } } } } else { // 优先级相同,根据可靠性调整 if (pattern1.reliability > pattern2.reliability) { // 调整pattern2的突破水平 const index2 = patterns.findIndex(p => p === pattern2); if (index2 !== -1) { if (pattern2.direction === PatternDirection.Bullish) { patterns[index2].component.breakoutLevel *= 1.03; } else { patterns[index2].component.breakoutLevel *= 0.97; } } } else { // 调整pattern1的突破水平 const index1 = patterns.findIndex(p => p === pattern1); if (index1 !== -1) { if (pattern1.direction === PatternDirection.Bullish) { patterns[index1].component.breakoutLevel *= 1.03; } else { patterns[index1].component.breakoutLevel *= 0.97; } } } } }