-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path6442_DEEPSEEK.py
More file actions
899 lines (767 loc) · 36.5 KB
/
Copy path6442_DEEPSEEK.py
File metadata and controls
899 lines (767 loc) · 36.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
"""
台股 6442 (台積電) AI 交易信号生成器
======================================
信号: 卖出 (SELL) 20251222
强度: 1.00 / 1.00
建议卖出比例: 100%
建议卖出价格区间: NT$180.00 - NT$180.90
📌 卖出理由:
1. RSI 偏高,有回调风险
2. 价格高于短期均线,可能回调
💡 操作建议:
• 分批卖出,避免一次性清仓
• 保留部分仓位应对反弹
================================================================================
⚠️ 风险提示
================================================================================
• 本信号由 AI 模型生成,仅供参考,不构成投资建议
• 股市有风险,投资需谨慎
• 请根据自身风险承受能力做出投资决策
• 建议结合其他分析方法综合判断
================================================================================
✅ 信号生成成功!
📱 快速摘要:
股票: 6442.TW (台積電)
日期: 2025-12-22
价格: NT$180.00
信号: 卖出 (SELL)
强度: 1.00
使用训练好的 PPO 模型生成今日交易策略
输出: 买入/卖出/持有 信号 + 建议价格
"""
import os
# 抑制 TensorFlow 警告
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0'
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
import numpy as np
import pandas as pd
import gymnasium as gym
from gymnasium import spaces
from stable_baselines3 import PPO
from datetime import datetime
import warnings
warnings.filterwarnings('ignore')
# 导入动态权重计算器
from dynamic_signal_weights import DynamicWeightCalculator
# 导入增强评分模块
# 导入增强评分模块(含FinBERT情绪分析)
from finbert_enhanced_scoring import calculate_enhanced_buy_score_with_sentiment, format_sentiment_output
from candlestick_patterns import analyze_candlestick_patterns, format_pattern_output, get_pattern_score_adjustment
# 导入MA50斜率分析模块
from ma50_slope_analysis import calculate_ma50_slope, format_ma50_slope_output, get_ma50_slope_score_adjustment
# 导入模型准确度追踪器
from model_accuracy_tracker import ModelAccuracyTracker, get_model_accuracy_display
# ==========================================
# 交易环境 (必须与训练时一致)
# ==========================================
class ImprovedTradingEnv(gym.Env):
def __init__(self, df, initial_balance=10000):
super(ImprovedTradingEnv, self).__init__()
self.df = df.reset_index(drop=True)
self.initial_balance = initial_balance
self.current_step = 0
self.action_space = spaces.Box(low=-1.0, high=1.0, shape=(1,), dtype=np.float32)
self.observation_space = spaces.Box(low=-np.inf, high=np.inf, shape=(15,), dtype=np.float32)
self.reset()
def reset(self, seed=None, options=None):
super().reset(seed=seed)
self.current_step = 0
self.balance = self.initial_balance
self.shares_held = 0
self.total_profit = 0
self.total_trades = 0
self.last_action = 0
return self._get_observation(), {}
def _get_observation(self):
row = self.df.iloc[self.current_step]
current_price = float(row['close'])
total_value = self.balance + self.shares_held * current_price
stock_ratio = (self.shares_held * current_price) / total_value if total_value > 0 else 0
cash_ratio = self.balance / total_value if total_value > 0 else 1
obs = np.array([
float(self.shares_held),
float(self.balance),
float(row['close']),
float(row.get('sma_10', 0)),
float(row.get('sma_30', 0)),
float(row.get('sma_50', 0)),
float(row.get('rsi', 50)),
float(row.get('macd', 0)),
float(row.get('macd_signal', 0)),
float(row.get('bb_upper', 0)),
float(row.get('bb_lower', 0)),
float(row.get('volume', 0)),
float(self.total_profit),
float(stock_ratio),
float(cash_ratio),
], dtype=np.float32)
return obs
def step(self, action):
if isinstance(action, np.ndarray):
action = float(action[0])
else:
action = float(action)
action = np.clip(action, -1.0, 1.0)
current_price = float(self.df.iloc[self.current_step]['close'])
if action < -0.1:
sell_ratio = abs(action)
shares_to_sell = int(self.shares_held * sell_ratio)
if shares_to_sell > 0:
self.balance += shares_to_sell * current_price
self.shares_held -= shares_to_sell
self.total_trades += 1
elif action > 0.1:
buy_ratio = action
max_can_buy = int(self.balance // current_price)
shares_to_buy = int(max_can_buy * buy_ratio)
if shares_to_buy > 0:
cost = shares_to_buy * current_price
self.balance -= cost
self.shares_held += shares_to_buy
self.total_trades += 1
new_total_value = self.balance + self.shares_held * current_price
self.total_profit = new_total_value - self.initial_balance
reward = self.total_profit / self.initial_balance
self.current_step += 1
done = self.current_step >= len(self.df) - 1
obs = self._get_observation()
return obs, float(reward), done, False, {}
# ==========================================
# 技术指标计算
# ==========================================
def add_technical_indicators(df):
"""添加技术指标"""
df['sma_10'] = df['close'].rolling(10).mean()
df['sma_30'] = df['close'].rolling(30).mean()
df['sma_50'] = df['close'].rolling(50).mean()
df['sma_200'] = df['close'].rolling(200).mean() # 添加200日均线
df['ema_12'] = df['close'].ewm(span=12).mean()
df['ema_26'] = df['close'].ewm(span=26).mean()
delta = df['close'].diff()
gain = (delta.where(delta > 0, 0)).rolling(14).mean()
loss = (-delta.where(delta < 0, 0)).rolling(14).mean()
rs = gain / (loss + 1e-10)
df['rsi'] = 100 - (100 / (1 + rs))
df['macd'] = df['ema_12'] - df['ema_26']
df['macd_signal'] = df['macd'].ewm(span=9).mean()
df['bb_middle'] = df['close'].rolling(20).mean()
df['bb_std'] = df['close'].rolling(20).std()
df['bb_upper'] = df['bb_middle'] + (df['bb_std'] * 2)
df['bb_lower'] = df['bb_middle'] - (df['bb_std'] * 2)
# 计算OBV (能量潮指标)
df = calculate_obv(df)
df = df.bfill().ffill()
return df
# ==========================================
# 新增:资金流向分析函数
# ==========================================
def calculate_obv(df):
"""计算OBV (能量潮指标)"""
obv = [0]
for i in range(1, len(df)):
if df['close'].iloc[i] > df['close'].iloc[i-1]:
obv.append(obv[-1] + df['volume'].iloc[i])
elif df['close'].iloc[i] < df['close'].iloc[i-1]:
obv.append(obv[-1] - df['volume'].iloc[i])
else:
obv.append(obv[-1])
df['obv'] = obv
df['obv_ma20'] = pd.Series(obv).rolling(20).mean()
return df
def money_flow_strength(df):
"""分析资金流向强度"""
if len(df) < 20:
return False, 1.0
obv_now = df['obv'].iloc[-1]
obv_ma = df['obv_ma20'].iloc[-1]
volume_ratio = df['volume'].iloc[-1] / df['volume'].rolling(20).mean().iloc[-1]
strong_money = (
obv_now > obv_ma and
volume_ratio > 1.3
)
return strong_money, volume_ratio
def detect_memory_cycle_phase(df):
"""检测内存周期阶段(适用于芯片股)"""
if len(df) < 200:
return "NEUTRAL"
ma50 = df['sma_50']
ma200 = df['sma_200']
price = df['close'].iloc[-1]
# 週期初升段
early_upcycle = (
price > ma50.iloc[-1] and
ma50.iloc[-1] > ma200.iloc[-1] and
ma50.diff().iloc[-1] > 0
)
# 高檔末升段
late_cycle = (
price > ma50.iloc[-1] * 1.25 and
ma50.diff().iloc[-1] < ma50.diff().iloc[-5] if len(df) >= 5 else False
)
if early_upcycle:
return "EARLY_UPCYCLE" # 🔥最會噴的階段
elif late_cycle:
return "LATE_CYCLE"
else:
return "NEUTRAL"
def trend_acceleration(df):
"""检测趋势加速"""
if len(df) < 30:
return False
sma10 = df['sma_10']
sma30 = df['sma_30']
slope10 = sma10.diff().iloc[-1]
slope30 = sma30.diff().iloc[-1]
price = df['close'].iloc[-1]
accelerating = (
slope10 > slope30 and
slope10 > 0 and
price > sma10.iloc[-1]
)
return accelerating
def explosive_trend_filter(df):
"""爆发行情过滤器"""
strong_money, vol_ratio = money_flow_strength(df)
cycle_phase = detect_memory_cycle_phase(df)
accelerating = trend_acceleration(df)
explosive = (
strong_money and
accelerating and
cycle_phase == "EARLY_UPCYCLE"
)
return {
"explosive": explosive,
"volume_ratio": vol_ratio,
"cycle_phase": cycle_phase,
"money_inflow": strong_money,
"trend_accelerating": accelerating
}
# ==========================================
# 交易信号生成
# ==========================================
def get_trading_signal():
"""生成今日交易信号"""
print("=" * 80)
print("🤖 台股 6442 (EZCONN) AI 交易信号生成器")
print("=" * 80)
print(f"生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
# 顯示AI模型準確度
accuracy_display = get_model_accuracy_display('6442.TW')
print(f"模型準確度: {accuracy_display}")
print("=" * 80)
# 1. 加载模型
import os
# 使用相对路径或当前目录查找模型
model_filename = "ppo_6442_tw_improved"
possible_paths = [
os.path.join(os.getcwd(), model_filename), # 当前目录
model_filename # 相对路径
]
model_path = None
for path in possible_paths:
if os.path.exists(f"{path}.zip") or os.path.exists(path):
model_path = path
break
if not model_path:
print(f"\n❌ 无法找到模型文件: {model_filename}")
print(f" 搜索位置: {possible_paths}")
return None
print(f"\n📦 加载 AI 模型: {model_path}")
try:
model = PPO.load(model_path)
print("✅ 模型加载成功!")
except Exception as e:
print(f"❌ 模型加载失败: {e}")
return None
# 2. 下载最新数据 (使用 period 方式获取更新的数据)
print("\n📊 下载最新市场数据...")
try:
import yfinance as yf
# 使用 period 方式下载,auto_adjust=True 确保价格是最新的
df = yf.download('6442.TW', period='300d', progress=False, auto_adjust=True) # 改为300天以计算200日均线
if df.empty:
print("❌ 无法获取数据")
return None
# 处理可能的 MultiIndex 列
if isinstance(df.columns, pd.MultiIndex):
df.columns = df.columns.droplevel(1)
df = df.rename(columns={
'Close': 'close', 'Volume': 'volume',
'Open': 'open', 'High': 'high', 'Low': 'low'
})
df = df.reset_index()
print(f"✅ 成功下载 {len(df)} 天数据")
# 獲取分析師目標價和評級
target_price = None
target_high = None
recommendation_mean = None
try:
ticker_info = yf.Ticker('6442.TW').info
target_price = ticker_info.get('targetMeanPrice')
target_high = ticker_info.get('targetHighPrice')
target_low = ticker_info.get('targetLowPrice')
num_analysts = ticker_info.get('numberOfAnalystOpinions', 0)
recommendation_mean = ticker_info.get('recommendationMean') # 1=Strong Buy, 5=Sell
recommendation_key = ticker_info.get('recommendationKey', '')
if target_price and num_analysts > 0:
print(f" 📊 分析師目標價: NT${target_price:.2f} (平均) / NT${target_high:.2f} (最高)")
print(f" 📊 分析師評級: {recommendation_key} ({recommendation_mean:.1f}/5, {num_analysts}位分析師)")
except:
pass
except Exception as e:
print(f"❌ 数据下载失败: {e}")
return None
# 3. 添加技术指标
print("\n🔧 计算技术指标...")
df = add_technical_indicators(df)
# 获取今日数据 (最后一行)
latest_data = df.iloc[-1]
try:
latest_date = str(pd.to_datetime(df.iloc[-1]['Date']).date())
except:
latest_date = datetime.now().strftime('%Y-%m-%d')
print(f"✅ 最新数据日期: {latest_date}")
print(f" 当前价格: NT${float(latest_data['close']):.2f}")
print(f" 今日成交量: {int(latest_data['volume']):,}")
# 4. 创建环境并获取观察值
env = ImprovedTradingEnv(df)
env.current_step = len(df) - 1 # 移到最后一天
obs = env._get_observation()
# 5. 使用模型预测
print("\n🧠 AI 模型分析中...")
action, _ = model.predict(obs, deterministic=True)
action_value = float(action[0]) if isinstance(action, np.ndarray) else float(action)
# 6. 解析交易信号
current_price = float(latest_data['close'])
rsi = float(latest_data['rsi'])
macd = float(latest_data['macd'])
macd_signal = float(latest_data['macd_signal'])
sma_10 = float(latest_data['sma_10'])
sma_30 = float(latest_data['sma_30'])
sma_50 = float(latest_data['sma_50'])
sma_200 = float(latest_data['sma_200'])
bb_upper = float(latest_data['bb_upper'])
bb_lower = float(latest_data['bb_lower'])
current_volume = float(latest_data['volume'])
obv_now = float(latest_data['obv'])
obv_ma20 = float(latest_data['obv_ma20'])
# 计算平均成交量(过去20天)
avg_volume_20 = float(df['volume'].tail(20).mean())
# 计算成交量比率
volume_ratio = (current_volume / avg_volume_20) if avg_volume_20 > 0 else 1.0
print("\n" + "=" * 80)
print("📊 技术指标分析")
print("=" * 80)
print(f"RSI (14): {rsi:.2f} {'[超买]' if rsi > 70 else '[超卖]' if rsi < 30 else '[中性]'}")
print(f"MACD: {macd:.4f}")
print(f"MACD Signal: {macd_signal:.4f} {'[金叉]' if macd > macd_signal else '[死叉]'}")
print(f"SMA 10: NT${sma_10:.2f}")
print(f"SMA 30: NT${sma_30:.2f} {'[多头]' if sma_10 > sma_30 else '[空头]'}")
print(f"SMA 50: NT${sma_50:.2f}")
print(f"SMA 200: NT${sma_200:.2f} {'[多头]' if sma_50 > sma_200 else '[空头]'}")
print(f"布林带上轨: NT${bb_upper:.2f}")
print(f"布林带下轨: NT${bb_lower:.2f}")
print(f"当前价格位置: {((current_price - bb_lower) / (bb_upper - bb_lower) * 100):.1f}% (布林带内)")
print(f"成交量: {int(current_volume):,}")
print(f"20日平均量: {int(avg_volume_20):,} {'[放量]' if volume_ratio > 1.5 else '[缩量]' if volume_ratio < 0.7 else '[正常]'}")
print(f"量比: {volume_ratio:.2f}x")
print(f"OBV: {int(obv_now):,}")
print(f"OBV 20日均线: {int(obv_ma20):,} {'[资金流入]' if obv_now > obv_ma20 else '[资金流出]'}")
# 7.1 計算MA50斜率
print("\n" + "=" * 80)
print("📈 MA50趨勢分析")
print("=" * 80)
ma50_slope_info = calculate_ma50_slope(df['close'], window=50, slope_period=5)
print(f"當前MA50: NT${ma50_slope_info['ma50_current']:.2f}")
print(f"MA50斜率: {ma50_slope_info['slope']:+.6f}")
print(f"斜率百分比: {ma50_slope_info['slope_pct']:+.4f}%")
print(f"趨勢判斷: {ma50_slope_info['color']} {ma50_slope_info['trend']}")
print(f"交易信號: {ma50_slope_info['signal']}")
print(f"\n💡 說明: {ma50_slope_info['description']}")
# 7. 初始化动态权重计算器
weight_calc = DynamicWeightCalculator('6442.TW')
buy_weights = weight_calc.get_buy_weights()
sell_weights = weight_calc.get_sell_weights()
# 7.5 获取市场情绪分析(FinBERT + VADER)
print("\n" + "=" * 80)
print("📰 市场情绪分析 (FinBERT NLP Engine)")
print("=" * 80)
from finbert_enhanced_scoring import calculate_sentiment_score, format_sentiment_output
sentiment_result = calculate_sentiment_score('6442.TW', verbose=True)
if sentiment_result and sentiment_result['news_count'] > 0:
print(format_sentiment_output(sentiment_result))
else:
print("⚠️ 未找到相关新闻,情绪分析不可用")
sentiment_result = {'sentiment_score': 0.0, 'news_count': 0, 'sentiment_label': '中性'}
# 蠟燭圖型態分析
print("\n" + "=" * 80)
print("📊 蠟燭圖型態分析")
print("=" * 80)
try:
patterns = analyze_candlestick_patterns(df, days=5)
print(format_pattern_output(patterns))
# 獲取型態評分調整
pattern_adjustment = get_pattern_score_adjustment(patterns)
print(f"\n型態評分調整: {pattern_adjustment:+.1f} 分")
except Exception as e:
print(f" ⚠️ 型態分析失敗: {e}")
pattern_adjustment = 0
# 8. 爆发行情检测(主升段分析)
print("\n" + "=" * 80)
print("🚀 爆发行情检测 (主升段分析)")
print("=" * 80)
explosion = explosive_trend_filter(df)
print(f"资金流入状态: {'✅ 强势' if explosion['money_inflow'] else '❌ 弱势'}")
print(f"趋势加速状态: {'✅ 加速中' if explosion['trend_accelerating'] else '❌ 减速中'}")
print(f"周期阶段: {explosion['cycle_phase']}")
print(f"量比: {explosion['volume_ratio']:.2f}x")
if explosion["explosive"]:
print("\n🚀 主升段爆发行情侦测!")
print("📌 爆发行情特征:")
print(" • 资金强势流入 (OBV > 20日均线)")
print(" • 趋势加速 (10日均线斜率 > 30日均线斜率)")
print(" • 处于周期初升段 (EARLY_UPCYCLE)")
print(" • 量能放大 (量比 > 1.3x)")
# 9. 生成交易建议
print("\n" + "=" * 80)
print("🎯 AI 交易信号")
print("=" * 80)
print(f"模型输出动作值: {action_value:+.4f}")
if action_value > 0.1:
signal = "买入 (BUY)"
signal_emoji = "🟢"
strength = action_value
suggested_price_low = current_price * 0.995
suggested_price_high = current_price * 1.000
# 🔥 买入信号评分系统(加入成交量判断)
# 🔥 增强版买入信号评分系统
buy_score, signal_override, buy_reasons, buy_warnings, buy_metadata, sentiment_result = calculate_enhanced_buy_score_with_sentiment(
rsi=rsi,
macd=macd,
macd_signal=macd_signal,
sma_10=sma_10,
sma_30=sma_30,
current_price=current_price,
bb_upper=bb_upper,
bb_lower=bb_lower,
volume_ratio=volume_ratio,
ai_action=action_value,
buy_weights=buy_weights,
symbol='6442.TW'
)
# 加入MA50斜率評分調整
ma50_slope_adjustment = get_ma50_slope_score_adjustment(ma50_slope_info)
buy_score += ma50_slope_adjustment
# 加入爆发行情评分调整
if explosion["explosive"]:
buy_score += 25 # 爆发行情额外加分
buy_reasons.append(f"🚀 爆发行情确认: 主升段初期")
buy_reasons.append(f"资金强势流入 (OBV > MA20)")
buy_reasons.append(f"趋势加速 (10日斜率 > 30日斜率)")
buy_score = max(0, min(100, buy_score)) # 限制在0-100之間
if ma50_slope_adjustment > 0:
buy_reasons.append(f"MA50趨勢向上 (+{ma50_slope_adjustment}分)")
elif ma50_slope_adjustment < 0:
buy_warnings.append(f"MA50趨勢向下 ({ma50_slope_adjustment}分)")
# 使用增强评分结果
reasons = buy_reasons
warnings = buy_warnings
# 🔥 调整买入强度
adjusted_buy_strength = max(min((buy_score / 100) * strength, 1.0), 0)
suggested_buy_ratio = int(adjusted_buy_strength * 100)
# 如果评分过低,改为观望
if buy_score < 20:
signal = "观望 (WAIT)"
signal_emoji = "🟡"
print(f"\n{signal_emoji} 信号: {signal}")
print(f" AI 模型强度: {strength:.2f} / 1.00")
print(f" 技术指标评分: {buy_score} / 100")
print(f" 综合建议强度: {adjusted_buy_strength:.2f}")
if buy_score >= 20:
print(f" 建议买入比例: {suggested_buy_ratio}%")
print(f" 建议买入价格区间: NT${suggested_price_low:.2f} - NT${suggested_price_high:.2f}")
if warnings:
print(f"\n ⚠️ 警告:")
for warning in warnings:
print(f" • {warning}")
if reasons:
print(f"\n 📌 买入理由:")
for i, reason in enumerate(reasons, 1):
print(f" {i}. {reason}")
print(f"\n 💡 操作建议:")
if buy_score < 20:
print(f" • AI建议买入,但技术面支持度不足")
print(f" • 建议观望,等待成交量放大")
print(f" • 关注支撑位: NT${bb_lower:.2f}")
elif buy_score >= 60:
print(f" • 多个买入信号确认,可以买入")
print(f" • 分批买入,建议买入 {suggested_buy_ratio}%")
print(f" • 设置止损: NT${current_price * 0.95:.2f} (-5%)")
else:
print(f" • 谨慎买入 {suggested_buy_ratio}%")
print(f" • 等待量能确认后再加仓")
print(f" • 设置止损: NT${current_price * 0.95:.2f} (-5%)")
elif action_value < -0.1:
# 先检查是否为爆发行情,如果是则覆盖卖出信号
if explosion["explosive"]:
signal = "强势持有 (HOLD - TREND EXPLOSION)"
signal_emoji = "🚀"
strength = abs(action_value)
suggested_price_low = current_price
suggested_price_high = current_price
print("\n🚀 主升段爆发行情侦测!")
print(f"资金流入: {explosion['money_inflow']}")
print(f"趋势加速: {explosion['trend_accelerating']}")
print(f"周期位置: {explosion['cycle_phase']}")
print(f"量比: {explosion['volume_ratio']:.2f}x")
print("\n📌 操作策略:")
print(" • 不卖出 (主升段爆发行情)")
print(" • 回调不破均线继续抱")
print(" • 使用追踪止损代替固定止损")
print(" • 关注 OBV 资金流向指标")
print(" • 设置移动止盈: 跌破 10 日均线减半仓")
# 跳过卖出评分逻辑
skip_sell_scoring = True
else:
skip_sell_scoring = False
if not skip_sell_scoring:
signal = "卖出 (SELL)"
signal_emoji = "🔴"
strength = abs(action_value)
suggested_price_low = current_price * 1.000
suggested_price_high = current_price * 1.005
# 🔥 改进的卖出判断逻辑
# 计算更多技术指标
bb_position = (current_price - bb_lower) / (bb_upper - bb_lower) * 100 if (bb_upper - bb_lower) > 0 else 50
is_macd_bearish = macd < macd_signal
is_trending_down = sma_10 < sma_30
# 卖出信号评分系统(0-100分)
sell_score = 0
reasons = []
# 加入MA50斜率評分調整 (負斜率增加賣出分數)
ma50_slope_adjustment = get_ma50_slope_score_adjustment(ma50_slope_info)
if ma50_slope_adjustment < 0:
sell_score += abs(ma50_slope_adjustment)
reasons.append(f"MA50趨勢向下 ({ma50_slope_info['slope_pct']:.2f}%)")
elif ma50_slope_adjustment > 0:
# MA50向上趨勢,降低賣出評分
sell_score -= abs(ma50_slope_adjustment) * 0.5 # 使用0.5係數減少影響
if sell_score < 0:
sell_score = 0
# 1. 分析師目標價判斷 (使用动态权重)
# 投資官邏輯:修復數據盲點
if target_price is not None and current_price > 0:
target_upside_mean = ((target_price - current_price) / current_price) * 100
target_upside_high = ((target_high - current_price) / current_price) * 100 if target_high else None
# 狀況1: 股價衝破平均目標價,但評級還是 Buy (1.0-2.5) = 動能突破
if current_price > target_price and recommendation_mean and recommendation_mean <= 2.5:
# 這是動能股!分析師目標價滯後,不應賣出
if target_upside_high and target_upside_high > 0:
reasons.append(f"🔥 動能突破! 股價已超越平均目標價,但分析師仍看好")
reasons.append(f" 最高目標價 NT${target_high:.2f} (上漲空間 {target_upside_high:.1f}%)")
else:
reasons.append(f"🔥 動能突破! 分析師目標價滯後 (評級: {recommendation_mean:.1f}/5)")
# 狀況2: 股價高於目標價,且評級差 (>3.0) = 危險
elif current_price > target_price and recommendation_mean and recommendation_mean > 3.0:
sell_score += sell_weights['target_below']
reasons.append(f"⚠️ 股價過高! 超越目標價且評級差 ({recommendation_mean:.1f}/5)")
# 狀況3: 股價低於目標價,正常的低估值判斷
elif target_upside_mean < -10:
sell_score += sell_weights['target_below']
reasons.append(f"📉 目標價低於現價 {target_upside_mean:.1f}%")
elif target_upside_mean < 5:
sell_score += sell_weights['target_near']
reasons.append(f"⚠️ 上漲空間有限 (僅{target_upside_mean:.1f}%)")
# 2. MACD 死叉 (使用动态权重)
if is_macd_bearish:
sell_score += sell_weights['macd_bearish']
reasons.append("MACD 死叉,趋势转弱")
# 3. 均线排列 (使用动态权重)
if is_trending_down:
sell_score += sell_weights['ma_bearish']
reasons.append("短期均线下穿长期均线")
# 4. 布林带位置 (使用动态权重)
if bb_position > 90:
sell_score += sell_weights['bb_upper']
reasons.append(f"价格接近布林带上轨 ({bb_position:.1f}%)")
elif bb_position > 80:
sell_score += sell_weights['bb_high']
reasons.append(f"价格偏高,接近布林带上轨")
# 6. 成交量分析(量价配合)- 基于回测数据优化
is_strong_trend = (not is_macd_bearish) and (not is_trending_down) and (volume_ratio > 1.2)
# 🔥 情景A: 极度放量 + RSI<80 + 多头趋势 = 超强势股
# 回测2317: 66.7%继续涨, 0%回调 → 应该100%持有!
if volume_ratio > 2.5 and rsi < 80 and is_strong_trend:
sell_score = 0 # 评分归零 = 不卖出
reasons.clear()
reasons.append(f"🚀 超强势突破信号!")
reasons.append(f"极度放量({volume_ratio:.1f}x) + MACD金叉 + 均线多头")
reasons.append(f"RSI {rsi:.1f} (未达极端超买)")
reasons.append(f"回测数据: 此情景66.7%继续大涨")
reasons.append(f"💡 建议: 继续持有100%, 设置追踪止损")
# 🔥 情景B: 普通强势股 (量比1.2-2.5)
# 回测: 39.3%继续涨 vs 28.6%回调
elif is_strong_trend and rsi > 70:
sell_score = int(sell_score * 0.2) # 评分打2折(更激进)
reasons.clear()
reasons.append(f"⚠️ RSI超买但符合强势股特征")
reasons.append(f"MACD金叉 + 均线多头 + 放量({volume_ratio:.1f}x)")
reasons.append(f"回测: 继续涨39.3% vs 回调28.6%")
reasons.append(f"💡 建议: 持有或小幅减仓10-20%")
# 🔥 情景C: 超级放量(>3.0x) + RSI>80 = 可能出货
elif volume_ratio > 3.0 and rsi > 80:
sell_score += 30
reasons.append(f"⚠️ 超级放量({volume_ratio:.1f}x) + RSI严重超买({rsi:.1f})")
reasons.append(f"可能是主力出货高峰")
# 🔥 情景D: 高位放量但趋势转弱
elif volume_ratio > 2.0 and rsi > 70 and (not is_strong_trend):
sell_score += 20
reasons.append(f"高位放量({volume_ratio:.1f}x)但趋势转弱")
reasons.append(f"疑似出货信号")
# 🔥 情景E: 价涨量缩
elif volume_ratio < 0.5 and current_price > sma_10:
sell_score += 15
reasons.append(f"价涨量缩(量比{volume_ratio:.1f}x),上涨乏力")
# 🛡️ 超跌保护(接近布林带下轨 = 不应追杀!)- 加入基本面判断
# 使用 < 35 来捕捉超跌股票(布林带下1/3区域)
if bb_position < 35 and sell_score > 0:
# 获取公司基本面(超跌时才检查)
fundamentals_good_sell = False
fundamentals_bad_sell = False
profit_margin_sell = 0
try:
ticker_obj = yf.Ticker('6442.TW')
info = ticker_obj.info
net_income_sell = info.get('netIncome', None)
profit_margin_sell = info.get('profitMargins', None)
# 优先使用利润率判断(更可靠)
if profit_margin_sell is not None and profit_margin_sell > 0.10:
fundamentals_good_sell = True
elif profit_margin_sell is not None and profit_margin_sell < 0:
fundamentals_bad_sell = True
elif net_income_sell is not None and net_income_sell > 0:
fundamentals_good_sell = True
elif net_income_sell is not None and net_income_sell < 0:
fundamentals_bad_sell = True
except:
pass
original_score = sell_score
if fundamentals_good_sell:
# 优质公司超跌 = 不要卖!可能是买入机会
sell_score = 0 # 评分归零
reasons.clear()
reasons.append(f"🎯 优质公司超跌! 布林带{bb_position:.1f}%")
if profit_margin_sell is not None and profit_margin_sell > 0:
reasons.append(f"淨利率{profit_margin_sell*100:.1f}% (健康)")
else:
reasons.append(f"公司盈利良好")
reasons.append(f"💎 建议: 不要追杀,这是价值投资机会!")
reasons.append(f"可考虑加仓或持有,等待反弹")
elif fundamentals_bad_sell:
# 亏损公司超跌 = 合理下跌,可以卖出
sell_score = original_score # 保持原评分
reasons.clear()
reasons.append(f"⚠️ 公司亏损,超跌合理")
reasons.append(f"淨利为负,下跌可能持续")
reasons.append(f"💡 建议: 可以卖出止损")
else:
# 无法获取基本面,使用原保护逻辑
sell_score = int(sell_score * 0.3) # 评分打3折
reasons.clear()
reasons.append(f"⚠️ 股价接近支撑位(布林带{bb_position:.1f}%)")
reasons.append(f"虽然技术指标转弱(原评分{original_score}),但已超跌")
reasons.append(f"💡 建议: 暂不追杀,等待反弹或进一步确认")
# 调整卖出强度和建议比例
adjusted_strength = min(sell_score / 100, 1.0) # 根据评分调整强度
suggested_sell_ratio = int(adjusted_strength * 100)
# 🔥 如果评分=0,覆盖为持有信号
if sell_score == 0:
signal = "持有 (HOLD - 强势突破)"
signal_emoji = "🟢"
print(f"\n{signal_emoji} 信号: {signal}")
print(f" AI 模型强度: {strength:.2f} / 1.00")
print(f" 技术指标评分: {sell_score} / 100")
print(f" 综合建议强度: {adjusted_strength:.2f}")
if sell_score > 0:
print(f" 建议卖出比例: {suggested_sell_ratio}%")
print(f" 建议卖出价格区间: NT${suggested_price_low:.2f} - NT${suggested_price_high:.2f}")
if reasons:
if sell_score == 0:
print(f"\n 📌 持有理由:")
else:
print(f"\n 📌 卖出理由:")
for i, reason in enumerate(reasons, 1):
print(f" {i}. {reason}")
# 根据评分给出不同的操作建议
print(f"\n 💡 操作建议:")
if sell_score == 0:
# 已经在reasons里输出了
pass
elif sell_score >= 70:
print(f" • ⚠️ 多个卖出信号确认,建议尽快卖出")
print(f" • 可分2-3批卖出,保留少量仓位")
print(f" • 设置止损: NT${current_price * 0.97:.2f} (-3%)")
elif sell_score >= 50:
print(f" • 适度卖出,建议卖出 {suggested_sell_ratio}% 仓位")
print(f" • 保留部分仓位观察后续走势")
print(f" • 如果 RSI 继续上升,再卖出剩余仓位")
else:
print(f" • AI 建议卖出,但技术指标支持度较弱")
print(f" • 可考虑小幅减仓 10-20%")
print(f" • 密切关注 MACD 和 RSI 变化")
else:
signal = "持有 (HOLD)"
signal_emoji = "🟡"
print(f"\n{signal_emoji} 信号: {signal}")
print(f" 市场观望,暂不操作")
print(f"\n 💡 操作建议:")
print(f" • 继续观察市场走势")
print(f" • 关注支撑位: NT${bb_lower:.2f}")
print(f" • 关注压力位: NT${bb_upper:.2f}")
# 8. 风险提示
print("\n" + "=" * 80)
print("⚠️ 风险提示")
print("=" * 80)
print(" • 本信号由 AI 模型生成,仅供参考,不构成投资建议")
print(" • 股市有风险,投资需谨慎")
print(" • 请根据自身风险承受能力做出投资决策")
print(" • 建议结合其他分析方法综合判断")
print("=" * 80)
return {
'date': latest_date,
'symbol': '6442.TW',
'current_price': current_price,
'signal': signal,
'action_value': action_value,
'strength': abs(action_value) if abs(action_value) > 0.1 else 0,
'rsi': rsi,
'macd': macd,
'sma_10': sma_10,
'sma_30': sma_30,
'suggested_price_low': suggested_price_low if abs(action_value) > 0.1 else current_price,
'suggested_price_high': suggested_price_high if abs(action_value) > 0.1 else current_price,
'explosion_detected': explosion["explosive"] if 'explosion' in locals() else False
}
# ==========================================
# 主程序
# ==========================================
if __name__ == "__main__":
result = get_trading_signal()
if result:
print(f"\n✅ 信号生成成功!")
print(f"\n📱 快速摘要:")
print(f" 股票: {result['symbol']} (台積電)")
print(f" 日期: {result['date']}")
print(f" 价格: NT${result['current_price']:.2f}")
print(f" 信号: {result['signal']}")
if result['strength'] > 0:
print(f" 强度: {result['strength']:.2f}")
if result.get('explosion_detected', False):
print(f" 🚀 爆发行情侦测: 主升段确认!")
# 顯示AI模型準確度摘要
print(f" {get_model_accuracy_display('6442.TW')}")
else:
print("\n❌ 信号生成失败")