@kamuira/stock-analyzer 1.2.3 → 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.html +68 -41
  2. package/package.json +1 -1
package/index.html CHANGED
@@ -72,31 +72,42 @@
72
72
  .result { display: none; }
73
73
  .result.active { display: block; }
74
74
 
75
- /* 信号卡片 */
75
+ /* 信号卡片 — 中性底色 + 顶部强调条 + 微渐变 */
76
76
  .signal-card {
77
- text-align: center; padding: 30px; border-radius: 12px;
78
- margin-bottom: 20px; position: relative; overflow: hidden;
79
- }
80
- .signal-card::before {
81
- content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0;
82
- opacity: 0.1; z-index: 0;
83
- }
84
- .signal-card.strong-buy { background: #1a2e1a; border: 1px solid #2d5a2d; }
85
- .signal-card.strong-buy::before { background: #00ff00; }
86
- .signal-card.buy { background: #1a2e1a; border: 1px solid #2d5a2d; }
87
- .signal-card.weak-buy { background: #1a2a1a; border: 1px solid #2a4a2a; }
88
- .signal-card.neutral { background: #2a2a1a; border: 1px solid #4a4a2a; }
89
- .signal-card.sell { background: #2e1a1a; border: 1px solid #5a2d2d; }
90
- .signal-card.strong-sell { background: #2e1a1a; border: 1px solid #5a2d2d; }
91
-
92
- .signal-card .stock-info { margin-bottom: 15px; position: relative; z-index: 1; }
77
+ text-align: center; padding: 28px 30px 26px; border-radius: 12px;
78
+ margin-bottom: 20px; position: relative;
79
+ background: #141e28; border: 1px solid #1f2d3a; border-top: 4px solid #555;
80
+ }
81
+ .signal-card.strong-buy {
82
+ border-top-color: #ff4444;
83
+ background: linear-gradient(180deg, rgba(255,68,68,0.10), rgba(255,68,68,0) 55%), #141e28;
84
+ }
85
+ .signal-card.buy {
86
+ border-top-color: #ff7043;
87
+ background: linear-gradient(180deg, rgba(255,112,67,0.07), rgba(255,112,67,0) 55%), #141e28;
88
+ }
89
+ .signal-card.weak-buy {
90
+ border-top-color: #ff9800;
91
+ background: linear-gradient(180deg, rgba(255,152,0,0.06), rgba(255,152,0,0) 55%), #141e28;
92
+ }
93
+ .signal-card.neutral { border-top-color: #888; }
94
+ .signal-card.sell {
95
+ border-top-color: #26c281;
96
+ background: linear-gradient(180deg, rgba(38,194,129,0.06), rgba(38,194,129,0) 55%), #141e28;
97
+ }
98
+ .signal-card.strong-sell {
99
+ border-top-color: #00cc66;
100
+ background: linear-gradient(180deg, rgba(0,204,102,0.10), rgba(0,204,102,0) 55%), #141e28;
101
+ }
102
+
103
+ .signal-card .stock-info { margin-bottom: 14px; }
93
104
  .signal-card .stock-name { font-size: 22px; font-weight: bold; color: #fff; }
94
105
  .signal-card .stock-code { font-size: 13px; color: #888; margin-left: 8px; }
95
- .signal-card .stock-price { font-size: 28px; font-weight: bold; margin: 8px 0; }
106
+ .signal-card .stock-price { font-size: 30px; font-weight: bold; margin: 6px 0 2px; letter-spacing: 0.5px; }
96
107
  .signal-card .stock-change { font-size: 14px; }
97
- .signal-card .signal-text { font-size: 24px; font-weight: bold; margin: 15px 0 5px; position: relative; z-index: 1; }
98
- .signal-card .signal-score { font-size: 13px; color: #aaa; position: relative; z-index: 1; }
99
- .signal-card .signal-advice { font-size: 14px; color: #ccc; margin-top: 10px; position: relative; z-index: 1; }
108
+ .signal-card .signal-text { font-size: 24px; font-weight: bold; margin: 16px 0 4px; letter-spacing: 1px; }
109
+ .signal-card .signal-score { font-size: 13px; color: #8a9aa8; }
110
+ .signal-card .signal-advice { font-size: 14px; color: #c4d0db; margin-top: 10px; }
100
111
 
101
112
  .up { color: #ff4444; }
102
113
  .down { color: #00cc66; }
@@ -218,9 +229,6 @@
218
229
  <button onclick="quickAnalyze('sh600111')">北方稀土</button>
219
230
  <button onclick="quickAnalyze('sh601318')">中国平安</button>
220
231
  <button onclick="quickAnalyze('sh601066')">中信建投</button>
221
- <button onclick="quickAnalyze('2330')">台积电</button>
222
- <button onclick="quickAnalyze('2317')">鸿海</button>
223
- <button onclick="quickAnalyze('2454')">联发科</button>
224
232
  </div>
225
233
  <div class="shortcuts" id="customShortcuts"></div>
226
234
 
@@ -354,8 +362,8 @@
354
362
  </div>
355
363
  <div style="text-align:center;padding:8px;background:#141e28;border-radius:6px">
356
364
  <div style="font-size:11px;color:#888">盈亏比</div>
357
- <div style="font-size:18px;font-weight:bold;color:#fff">${long.avgWin || 0} / ${long.avgLoss || 0}</div>
358
- <div style="font-size:11px;color:#888">均盈 / 均亏</div>
365
+ <div style="font-size:18px;font-weight:bold;color:#fff">${long.avgWin || 0} : ${Math.abs(long.avgLoss || 0)}</div>
366
+ <div style="font-size:11px;color:#888">均盈 : 均亏</div>
359
367
  </div>
360
368
  </div>` : `<div style="padding:12px;text-align:center;color:#888;font-size:13px;background:#141e28;border-radius:6px;margin-bottom:12px">回测周期内无做多入场信号</div>`}
361
369
  <button onclick="saveToShortcuts('${bt.code}','${safeName}','${long.winRate}','${bt.grade}')" style="padding:8px 16px;border:1px solid ${gradeColor};border-radius:6px;background:transparent;color:${gradeColor};cursor:pointer;font-size:13px">+ 加入快捷列表</button>
@@ -363,8 +371,18 @@
363
371
  </div>`;
364
372
  }
365
373
 
366
- // 信号卡片
367
- html += `<div class="signal-card ${summary.signalClass}">
374
+ // 信号卡片 - 按 totalScore 派生 class(后端不返回 signalClass)
375
+ const ts = summary.totalScore;
376
+ const signalClass = summary.signalClass
377
+ || (ts >= 10 ? 'strong-buy'
378
+ : ts >= 5 ? 'buy'
379
+ : ts >= 1 ? 'weak-buy'
380
+ : ts >= -4 ? 'neutral'
381
+ : ts >= -9 ? 'sell'
382
+ : 'strong-sell');
383
+ const signalIsBullish = ts >= 1;
384
+ const signalIsBearish = ts < -4;
385
+ html += `<div class="signal-card ${signalClass}">
368
386
  <div class="stock-info">
369
387
  <span class="stock-name">${rt.name}</span>
370
388
  <span class="stock-code">${rt.code}</span>
@@ -374,13 +392,22 @@
374
392
  <div class="stock-change ${direction}">
375
393
  ${rt.change > 0 ? '+' : ''}${rt.change.toFixed(2)} (${rt.changePct > 0 ? '+' : ''}${rt.changePct.toFixed(2)}%)
376
394
  </div>
377
- <div class="signal-text ${direction === 'up' ? 'up' : direction === 'down' ? 'down' : ''}">${summary.signal}</div>
378
- <div class="signal-score">综合评分: ${summary.totalScore} | ${summary.positionAdvice || ''}</div>
395
+ <div class="signal-text ${signalIsBullish ? 'up' : signalIsBearish ? 'down' : 'flat'}">${summary.signal}</div>
396
+ <div class="signal-score">综合评分: ${summary.totalScore} 分${rr && rr.positionAdvice ? ' | ' + rr.positionAdvice : ''}</div>
379
397
  <div class="signal-advice">${summary.advice}</div>
380
398
  </div>`;
381
399
 
400
+ // 评分条(紧贴信号卡片下方,可视化综合评分)
401
+ const barColor = summary.totalScore >= 5 ? '#4caf50' : summary.totalScore >= 0 ? '#ff9800' : '#f44336';
402
+ html += `<div class="score-bar-container">
403
+ <div class="score-bar">
404
+ <div class="score-bar-fill" style="width:${summary.normalizedScore}%; background:${barColor}"></div>
405
+ </div>
406
+ <div class="score-labels"><span>强烈卖出</span><span>观望</span><span>强烈买入</span></div>
407
+ </div>`;
408
+
382
409
  // 操作建议大卡片(最显眼)
383
- const posAdvice = summary.positionAdvice || '';
410
+ const posAdvice = (rr && rr.positionAdvice) || '';
384
411
  const holdAdvice = summary.totalScore >= 10 ? '建议持仓5-10天,趋势跟踪' : summary.totalScore >= 5 ? '建议持仓3-5天,短线波段' : summary.totalScore >= 1 ? '建议持仓1-3天,快进快出' : '不建议开仓';
385
412
  const signalColor = summary.totalScore >= 5 ? '#4caf50' : summary.totalScore >= 1 ? '#ff9800' : summary.totalScore >= -4 ? '#888' : '#f44336';
386
413
 
@@ -432,15 +459,6 @@
432
459
  </div>` : ''}
433
460
  </div>`;
434
461
 
435
- // 评分条
436
- const barColor = summary.totalScore >= 5 ? '#4caf50' : summary.totalScore >= 0 ? '#ff9800' : '#f44336';
437
- html += `<div class="score-bar-container">
438
- <div class="score-bar">
439
- <div class="score-bar-fill" style="width:${summary.normalizedScore}%; background:${barColor}"></div>
440
- </div>
441
- <div class="score-labels"><span>强烈卖出</span><span>观望</span><span>强烈买入</span></div>
442
- </div>`;
443
-
444
462
  // 大盘环境
445
463
  if (marketEnv && marketEnv.signals) {
446
464
  html += `<div style="background:#1a2530;border:1px solid #2a3a4a;border-radius:8px;padding:12px 16px;margin-bottom:16px;font-size:13px;color:#aaa">
@@ -492,7 +510,16 @@
492
510
  ${scoreText}
493
511
  </div>
494
512
  <div class="section-body">
495
- ${d.signals.map(s => `<div class="signal-item">${s}</div>`).join('')}
513
+ ${d.signals.map(s => {
514
+ const m = (typeof s === 'string' ? s : '').match(/^\[([^\]]+)\]\s*(.*)$/);
515
+ if (!m) return `<div class="signal-item">${s}</div>`;
516
+ const tag = m[1], rest = m[2];
517
+ const bullish = /多|涨|强|底/.test(tag);
518
+ const bearish = /空|跌|弱|顶/.test(tag);
519
+ const bg = bullish ? '#1a3a1a' : bearish ? '#3a1a1a' : '#1a2a3a';
520
+ const fg = bullish ? '#8bc34a' : bearish ? '#ff8a80' : '#7fa9d4';
521
+ return `<div class="signal-item"><span style="display:inline-block;padding:1px 7px;border-radius:4px;font-size:11px;margin-right:6px;background:${bg};color:${fg}">${tag}</span>${rest}</div>`;
522
+ }).join('')}
496
523
  </div>
497
524
  </div>`;
498
525
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kamuira/stock-analyzer",
3
- "version": "1.2.3",
3
+ "version": "1.2.5",
4
4
  "preferGlobal": true,
5
5
  "description": "A股/台股综合技术分析工具 - 支持实时分析、回测验证、买卖建议",
6
6
  "main": "server.js",