UNPKG

@gabriel3615/ta_analysis

Version:

stock ta analysis

123 lines (122 loc) 6.06 kB
export class NarrativeBuilder { buildSummary(signalResult) { const dirText = signalResult.direction === 'long' ? '做多' : signalResult.direction === 'short' ? '做空' : '中性'; return `综合信号 ${dirText}|强度:${signalResult.signalStrength}|置信度:${signalResult.confidenceScore?.toFixed?.(1) ?? signalResult.confidenceScore}%`; } buildPrimaryRationale(signalResult, analyses) { const ws = signalResult.weightedScores; const entries = Object.entries(ws).sort((a, b) => Math.abs(b[1]) - Math.abs(a[1])); const top = entries .slice(0, 3) .map(([k]) => k) .join('/'); const patternDir = analyses.pattern?.combinedSignal ?? '-'; const chip = analyses.chip; return `主要由${top} 驱动;形态:${patternDir};筹码买:${chip.combinedBuySignalStrength}/卖:${chip.combinedShortSignalStrength}`; } buildSecondaryRationale(analyses) { const structure = analyses.structure; const sd = analyses.supplyDemand; const range = analyses.range; const tl = analyses.trendline; const parts = []; if (structure?.trend) parts.push(`结构:${structure.trend}`); if (sd?.premiumDiscount?.position != null) parts.push(`估值位:${Math.round(sd.premiumDiscount.position)}%`); if (range?.breakout) parts.push(`区间突破:${range.breakout.direction}/质量${range.breakout.qualityScore}`); if (tl?.breakoutRetest) parts.push(`趋势线突破回踩:${tl.breakoutRetest.direction}/质量${tl.breakoutRetest.qualityScore}`); return parts.length ? parts.join(';') : '—'; } buildSummariesFromPlugins(plugins, analysisData, context) { const get = (id, fallback) => { const plugin = plugins.find(p => p.id === id); if (plugin?.summarize) { try { return plugin.summarize(analysisData, context); } catch { return 'Error in summarize()'; } } return fallback(); }; return { chipSummary: get('chip', () => { const chip = analysisData.analyses.chip; return `买入强度:${chip.combinedBuySignalStrength} 做空强度:${chip.combinedShortSignalStrength} 主周期:${chip.primaryTimeframe}`; }), patternSummary: get('pattern', () => { const p = analysisData.analyses.pattern; return `形态综合方向:${p.combinedSignal} 强度:${p.signalStrength?.toFixed?.(1) ?? p.signalStrength}`; }), bbsrSummary: get('bbsr', () => { const b = analysisData.analyses.bbsr; const d = b.dailyBBSRResult?.strength; const w = b.weeklyBBSRResult?.strength; return `BBSR(日/周) 强度:${d ?? '-'} / ${w ?? '-'}`; }), vvSummary: get('volume', () => { const vv = analysisData.analyses.volatility; const regime = vv.volatilityAnalysis?.volatilityAnalysis?.volatilityRegime ?? 'low'; const atrp = vv.volatilityAnalysis?.volatilityAnalysis?.atrPercent ?? 0; const volConfirm = vv.volumeAnalysis?.volumeAnalysis ?.volumePriceConfirmation ? '确认' : '未确认'; return `波动率:${regime} ATR%:${atrp.toFixed?.(2) ?? atrp} 成交量确认:${volConfirm}`; }), structureSummary: get('structure', () => { const s = analysisData.analyses.structure; return `结构趋势:${s.trend} 关键位数:${s.keyLevels?.length ?? 0}`; }), supplyDemandSummary: get('supplyDemand', () => { const sd = analysisData.analyses.supplyDemand; const pos = sd.premiumDiscount?.position ?? 50; const zones = sd.recentEffectiveZones?.length ?? 0; return `供需位置:${pos.toFixed?.(1) ?? pos} 有效区域:${zones}`; }), rangeSummary: get('range', () => { const r = analysisData.analyses.range; const comp = r.compressionScore; const br = r.breakout ? `${r.breakout.direction}/${r.breakout.qualityScore}` : '无突破'; return `压缩:${comp} 突破:${br}`; }), trendlineSummary: get('trendline', () => { const tl = analysisData.analyses.trendline; const slope = tl.channel?.slope ?? 0; return tl.summary || `通道斜率:${slope.toFixed?.(4) ?? slope}`; }), }; } buildShortTermOutlook(analyses) { const pattern = analyses.pattern; const vv = analyses.volatility; const tl = analyses.trendline; const dir = pattern?.combinedSignal ?? '-'; const regime = vv?.volatilityAnalysis?.volatilityAnalysis?.volatilityRegime ?? 'low'; const slope = tl?.channel?.slope ?? 0; return `短期(${dir}),波动率${regime},通道斜率${typeof slope?.toFixed === 'function' ? slope.toFixed(3) : slope}`; } buildMediumTermOutlook(analyses) { const chip = analyses.chip; const sd = analyses.supplyDemand; const pos = sd?.premiumDiscount?.position ?? 50; return `中期(筹码买:${chip.combinedBuySignalStrength}/卖:${chip.combinedShortSignalStrength}),估值位置${typeof pos?.toFixed === 'function' ? pos.toFixed(1) : pos}`; } buildLongTermOutlook(analyses) { const structure = analyses.structure; const range = analyses.range; const trend = structure?.trend ?? '-'; const comp = range?.compressionScore ?? '-'; return `长期(${trend}),压缩度${comp}`; } }