價格預測通常結合機器學習和深度學習演算法,並運用歷史數據及市場技術指標。以下是常見的一些方法:
使用強化學習的智能交易系統可以在模擬的市場環境中學習,並隨時間優化買賣決策,逐步改善交易策略。
AI 模型可以通過新聞和社交媒體的情感分析,來判斷市場情緒,並根據外部因素預測股票價格變化。
結合多種演算法和外部數據(例如經濟指標、公司基本面分析),通常能產生最有效的 AI 股票價格預測模型。
在使用 AI 進行股票價格預測時,模型會生成多種指標來幫助投資者做出決策。這些指標可以用來判斷市場走向,並根據不同的情境採取相應的交易操作。以下是一些常見的預測指標及其操作策略:
這是模型直接預測的未來股票價格數值。
模型可能會預測股票價格上漲或下跌的概率。
模型可能會基於技術指標(如移動平均線)預測股票的趨勢方向。
技術指標如 RSI(相對強弱指數)可以用來判斷股票是否處於超買或超賣狀態。
模型可以預測股票未來的價格波動區間。
基於市場買賣雙方的強度預測。
模型可能會根據歷史數據建議合理的止損與止盈點。
根據不同的預測指標,投資者可以做出相應的交易決策,如買入、賣出或保持觀望。綜合多種指標有助於在不同的市場情境下做出更合理的投資決策。
在眾多輪動判斷指標中,並非所有指標都具備同等的預測能力。根據近年(2020至2025年)的市場經驗,以下依準度與實用性進行分級,並說明如何跨市場比較以及透過程式自動化取得與計算。
| 指標 | 準度評級 | 領先時間 | 近年驗證案例 |
|---|---|---|---|
| 殖利率曲線(2Y-10Y利差) | 極高 | 6~18個月 | 2022年7月倒掛,準確預警2023年區域銀行危機與經濟放緩 |
| ISM製造業新訂單指數 | 極高 | 3~6個月 | 2022Q4跌破42後,工業與原物料股於2023Q1觸底反彈 |
| 高收益債利差(HY Spread) | 極高 | 2~4個月 | 2022年利差擴大至500bp以上,精確對應風險資產低點 |
| 銅金比(Copper/Gold Ratio) | 高 | 2~5個月 | 2020年3月銅金比觸底後,全球景氣循環股啟動長達一年的漲勢 |
| 全球資金流向(EPFR Fund Flows) | 高 | 1~3個月 | 2023年底資金大舉流入新興市場ETF,領先EM指數反彈約兩個月 |
| 聯準會點陣圖與期貨隱含利率 | 高 | 3~6個月 | 2023年底市場定價2024年降息,成長股提前啟動 |
| PMI跨國差異 | 高 | 1~3個月 | 2024年美國PMI持續擴張而歐洲收縮,美股持續跑贏歐股 |
| VIX恐慌指數 | 中等 | 即時~1個月 | 作為反向指標有效,但2021年多次假突破降低實用性 |
| 融資餘額與散戶情緒調查 | 中等 | 即時~2週 | 極端值有用,但中間區間雜訊太多,需配合其他指標 |
殖利率曲線之所以維持高準度,是因為它反映的是債券市場對未來經濟的集體定價,而債市參與者以機構法人為主,資訊效率遠高於散戶主導的市場。ISM新訂單則直接反映企業端的實際需求變化,不受市場情緒干擾。高收益債利差則是信用市場的「壓力計」,當企業違約風險上升時,資金會率先從高風險資產撤離,這個訊號通常早於股市反應。
相對而言,VIX和融資餘額在近年的準度下降,主要原因是零日到期選擇權(0DTE)大幅改變了選擇權市場結構,使VIX失真;而散戶透過社群媒體的群體行為也讓傳統情緒指標的訊號品質降低。
進行不同市場間的輪動比較時,需要建立可比較的標準化框架:
將兩個市場或板塊的價格做比值,觀察比值的趨勢方向。例如將「MSCI新興市場指數 / MSCI已開發市場指數」繪成曲線,比值上升代表新興市場跑贏。這個方法可套用在任何兩個可比較的資產上:
將不同市場的指標統一轉換為Z-Score(距離均值的標準差倍數),消除量綱差異後才能橫向比較。公式為:Z = (目前值 - 過去N期均值) / 過去N期標準差。例如美國PMI為52、歐元區PMI為47,表面看差距不大,但若美國PMI歷史均值為53、標準差為3,Z-Score為-0.33;歐元區歷史均值為51、標準差為4,Z-Score為-1.0,則歐元區的惡化程度其實遠超美國。
花旗經濟驚奇指數(Citi Economic Surprise Index)衡量實際經濟數據相對於市場預期的偏離程度。跨國比較此指數可以判斷哪個地區的基本面正在超預期改善或惡化,資金往往流向驚奇指數改善的市場。
以下為使用Python建立自動化監測系統的完整架構與程式範例。
| 資料類型 | 免費來源 | Python套件/API | 更新頻率 |
|---|---|---|---|
| 股價、ETF價格 | Yahoo Finance | yfinance | 即時/日線 |
| 美國公債殖利率 | FRED(聯準會資料庫) | fredapi | 每日 |
| PMI、GDP、CPI | FRED / OECD | fredapi / pandas-datareader | 月/季 |
| 高收益債利差 | FRED(BAMLH0A0HYM2) | fredapi | 每日 |
| 銅、黃金價格 | Yahoo Finance | yfinance(HG=F, GC=F) | 即時/日線 |
| VIX指數 | Yahoo Finance / CBOE | yfinance(^VIX) | 即時 |
| 資金流向 | ETF持倉變化估算 | yfinance(成交量+淨值變化) | 每日 |
| 期貨隱含利率 | CME FedWatch(需爬蟲) | requests + BeautifulSoup | 即時 |
# === 安裝所需套件 === # pip install yfinance fredapi pandas numpy schedule import yfinance as yf import pandas as pd import numpy as np from fredapi import Fred from datetime import datetime, timedelta # FRED API Key(至 https://fred.stlouisfed.org/docs/api/api_key.html 免費申請) fred = Fred(api_key='YOUR_FRED_API_KEY') # ========================================== # 1. 殖利率曲線:2年-10年利差 # ========================================== def get_yield_curve_spread(): gs10 = fred.get_series('DGS10') # 10年期公債殖利率 gs2 = fred.get_series('DGS2') # 2年期公債殖利率 spread = gs10 - gs2 spread = spread.dropna() latest = spread.iloc[-1] status = "倒掛(衰退警訊)" if latest < 0 else "正常" return { 'spread': round(latest, 3), 'status': status, 'series': spread.tail(252) # 近一年資料 } # ========================================== # 2. 高收益債利差 # ========================================== def get_hy_spread(): hy = fred.get_series('BAMLH0A0HYM2') hy = hy.dropna() latest = hy.iloc[-1] avg_1y = hy.tail(252).mean() z_score = (latest - hy.tail(756).mean()) / hy.tail(756).std() return { 'spread_bp': round(latest * 100, 0), 'z_score': round(z_score, 2), 'risk_level': "高風險" if z_score > 1.5 else "中性" if z_score > -0.5 else "低風險" } # ========================================== # 3. 銅金比 # ========================================== def get_copper_gold_ratio(): copper = yf.download('HG=F', period='2y')['Close'] gold = yf.download('GC=F', period='2y')['Close'] ratio = copper / gold ratio = ratio.dropna() current = ratio.iloc[-1] ma_200 = ratio.rolling(200).mean().iloc[-1] trend = "景氣擴張訊號" if current > ma_200 else "景氣收縮訊號" return {'ratio': round(current, 5), 'ma200': round(ma_200, 5), 'trend': trend} # ========================================== # 4. 跨市場相對強弱比較 # ========================================== def relative_strength(ticker_a, ticker_b, period='1y'): """計算兩個資產的相對強弱比值與趨勢""" a = yf.download(ticker_a, period=period)['Close'] b = yf.download(ticker_b, period=period)['Close'] ratio = a / b ratio = ratio.dropna() ma_50 = ratio.rolling(50).mean() latest_ratio = ratio.iloc[-1] latest_ma = ma_50.iloc[-1] outperformer = ticker_a if latest_ratio > latest_ma else ticker_b return { 'ratio': round(latest_ratio, 4), 'ma50': round(latest_ma, 4), 'outperformer': outperformer, 'series': ratio } # 使用範例: # relative_strength('IWF', 'IWD') # 成長 vs 價值 # relative_strength('EEM', 'SPY') # 新興市場 vs 美股 # relative_strength('^TWII', '000300.SS') # 台股 vs 滬深300 # ========================================== # 5. Z-Score標準化跨市場比較 # ========================================== def zscore_compare(series_dict, lookback=756): """ 接收多個市場的時間序列,計算Z-Score後橫向比較 series_dict: {'美國': pd.Series, '歐洲': pd.Series, ...} """ results = {} for name, series in series_dict.items(): s = series.dropna().tail(lookback) current = s.iloc[-1] z = (current - s.mean()) / s.std() results[name] = { 'current': round(current, 3), 'z_score': round(z, 2), 'percentile': round((s < current).mean() * 100, 1) } return pd.DataFrame(results).T.sort_values('z_score', ascending=False) # ========================================== # 6. 板塊動能排名(Sector Momentum) # ========================================== def sector_momentum_ranking(): """取得美股11大板塊ETF的多期動能並排名""" sectors = { '科技': 'XLK', '金融': 'XLF', '醫療': 'XLV', '非必需消費': 'XLY', '必需消費': 'XLP', '工業': 'XLI', '能源': 'XLE', '原物料': 'XLB', '公用事業': 'XLU', '不動產': 'XLRE', '通訊': 'XLC' } results = [] for name, ticker in sectors.items(): data = yf.download(ticker, period='1y')['Close'] ret_1m = (data.iloc[-1] / data.iloc[-21] - 1) * 100 ret_3m = (data.iloc[-1] / data.iloc[-63] - 1) * 100 ret_6m = (data.iloc[-1] / data.iloc[-126] - 1) * 100 # 綜合動能分數:近期權重較高 score = ret_1m * 0.4 + ret_3m * 0.35 + ret_6m * 0.25 results.append({ '板塊': name, '1個月%': round(ret_1m, 2), '3個月%': round(ret_3m, 2), '6個月%': round(ret_6m, 2), '綜合動能': round(score, 2) }) df = pd.DataFrame(results).sort_values('綜合動能', ascending=False) return df.reset_index(drop=True)
import schedule import time import requests def send_line_notify(token, msg): """透過LINE Notify發送訊息""" headers = {'Authorization': f'Bearer {token}'} requests.post('https://notify-api.line.me/api/notify', headers=headers, data={'message': msg}) def daily_rotation_report(): """每日輪動監測報告""" yc = get_yield_curve_spread() hy = get_hy_spread() cg = get_copper_gold_ratio() sectors = sector_momentum_ranking() report = f""" === 每日輪動監測 === 日期:{datetime.now().strftime('%Y-%m-%d')} 殖利率曲線(2Y-10Y):{yc['spread']}% {yc['status']} 高收益債利差 Z-Score:{hy['z_score']}({hy['risk_level']}) 銅金比趨勢:{cg['trend']} 板塊動能排名前三: {sectors.head(3).to_string(index=False)} 板塊動能排名末三: {sectors.tail(3).to_string(index=False)} """ print(report) # send_line_notify('YOUR_LINE_TOKEN', report) return report # 每個交易日下午6點執行 schedule.every().monday.at("18:00").do(daily_rotation_report) schedule.every().tuesday.at("18:00").do(daily_rotation_report) schedule.every().wednesday.at("18:00").do(daily_rotation_report) schedule.every().thursday.at("18:00").do(daily_rotation_report) schedule.every().friday.at("18:00").do(daily_rotation_report) while True: schedule.run_pending() time.sleep(60)
def rotation_dashboard(): """ 綜合多項指標,輸出目前經濟週期階段判斷 回傳:復甦/擴張/過熱/衰退 的機率估計 """ scores = {'復甦': 0, '擴張': 0, '過熱': 0, '衰退': 0} # 殖利率曲線訊號 yc = get_yield_curve_spread() if yc['spread'] < -0.5: scores['衰退'] += 3 elif yc['spread'] < 0: scores['過熱'] += 2; scores['衰退'] += 1 elif yc['spread'] < 1.0: scores['擴張'] += 2 else: scores['復甦'] += 3 # 高收益債利差訊號 hy = get_hy_spread() if hy['z_score'] > 1.5: scores['衰退'] += 3 elif hy['z_score'] > 0.5: scores['過熱'] += 2 elif hy['z_score'] > -0.5: scores['擴張'] += 2 else: scores['復甦'] += 2 # 銅金比訊號 cg = get_copper_gold_ratio() if cg['ratio'] > cg['ma200']: scores['擴張'] += 2 else: scores['衰退'] += 1; scores['復甦'] += 1 # 轉為機率分布 total = sum(scores.values()) probs = {k: round(v/total*100, 1) for k, v in scores.items()} phase = max(probs, key=probs.get) return { '判斷週期': phase, '各階段機率': probs, '建議配置': { '復甦': '加碼科技、金融;減碼防禦型', '擴張': '加碼原物料、能源;維持股票高水位', '過熱': '減碼成長股;增加商品與抗通膨資產', '衰退': '增加公債與現金;加碼防禦型板塊' }[phase] }
def tw_sector_rotation(): """台股主要類股ETF動能追蹤""" tw_sectors = { '台灣半導體': '00891.TW', '台灣ESG永續': '00850.TW', '台灣金融': '0055.TW', '台灣高股息': '0056.TW', '台灣50': '0050.TW', '台灣中型100': '0051.TW', } results = [] for name, ticker in tw_sectors.items(): try: data = yf.download(ticker, period='6mo')['Close'].dropna() if len(data) < 63: continue ret_1m = (data.iloc[-1] / data.iloc[-21] - 1) * 100 ret_3m = (data.iloc[-1] / data.iloc[-63] - 1) * 100 results.append({ '類股': name, '1個月報酬%': round(ret_1m, 2), '3個月報酬%': round(ret_3m, 2), '動能分數': round(ret_1m * 0.5 + ret_3m * 0.5, 2) }) except Exception as e: print(f"{name} 取得失敗:{e}") return pd.DataFrame(results).sort_values('動能分數', ascending=False)
程式化監測的核心價值不在於取代人為判斷,而在於消除情緒干擾並確保紀律性。以下幾點在建置系統時需特別注意:
yfinance 是由 Ran Aroussi 開發的開源 Python 套件,用於從 Yahoo Finance 取得金融市場資料。Yahoo Finance 在2017年關閉了官方API後,yfinance 成為存取其公開資料的最主流工具。目前最新版本為 1.2.0(2026年2月發布),採用 Apache 授權,完全免費,適用於研究與教育用途。
# 安裝 pip install yfinance # 升級到最新版 pip install yfinance --upgrade # 基本匯入 import yfinance as yf
yfinance 的相依套件包括 pandas、numpy、requests 和 lxml,如果使用 Anaconda 環境則全部已預裝。
| 類別/函式 | 用途 | 使用範例 |
|---|---|---|
| Ticker | 存取單一標的的所有資料(價格、財報、股息等) | yf.Ticker("AAPL") |
| Tickers | 同時處理多個標的 | yf.Tickers("AAPL MSFT GOOG") |
| download() | 批次下載多個標的的歷史價格(最常用的函式) | yf.download("SPY QQQ", period="1y") |
| Search | 搜尋代碼 | yf.Search("台積電") |
| Market | 存取市場摘要資料 | yf.Market("us_market") |
| Sector / Industry | 存取產業與板塊資訊 | yf.Sector("technology") |
| WebSocket | 即時串流市場資料(v1.0+新功能) | yf.WebSocket(on_message=callback) |
yfinance 能取得的資料遠超過單純的股價,涵蓋以下類別:
| 資料類別 | 具體內容 | 對應屬性/方法 |
|---|---|---|
| 歷史價格 | OHLCV(開高低收量)、調整後收盤價 | .history() 或 yf.download() |
| 公司基本資訊 | 市值、本益比、52週高低、產業分類、員工數等 | .info |
| 財務報表 | 損益表、資產負債表、現金流量表(年度與季度) | .income_stmt / .balance_sheet / .cashflow / .quarterly_income_stmt |
| 股息與分割 | 歷史股息發放、股票分割紀錄 | .dividends / .splits / .actions |
| 分析師資料 | 目標價、評等、盈餘預估 | .analyst_price_targets / .recommendations |
| 選擇權 | 到期日、買權/賣權鏈 | .options / .option_chain() |
| 法人持股 | 主要機構持股、內部人交易 | .institutional_holders / .insider_transactions |
| 行事曆 | 財報日、除息日等 | .calendar |
| 市場類型 | 代碼格式 | 範例 |
|---|---|---|
| 美股 | 直接輸入代碼 | AAPL, MSFT, TSLA, SPY |
| 台股 | 代碼.TW(上市)/ 代碼.TWO(上櫃) | 2330.TW(台積電), 0050.TW, 0056.TW |
| 日股 | 代碼.T | 7203.T(Toyota), 6758.T(Sony) |
| 港股 | 代碼.HK | 0700.HK(騰訊), 9988.HK(阿里巴巴) |
| 陸股 | 代碼.SS(上海)/ 代碼.SZ(深圳) | 600519.SS(茅台), 000001.SZ |
| 歐股 | 代碼.交易所後綴 | SAP.DE(德國), MC.PA(法國LVMH), AZN.L(倫敦) |
| 指數 | ^開頭 | ^GSPC(S&P 500), ^DJI(道瓊), ^IXIC(Nasdaq), ^TWII(加權指數), ^N225(日經) |
| 期貨 | 代碼=F | GC=F(黃金), SI=F(白銀), CL=F(原油), HG=F(銅), NG=F(天然氣) |
| 加密貨幣 | 代碼-USD | BTC-USD, ETH-USD, SOL-USD, ADA-USD |
| 外匯 | 代碼1代碼2=X | EURUSD=X, JPYUSD=X, TWDUSD=X |
| ETF | 直接輸入代碼 | SPY, QQQ, EEM, VGK, EWT, EWJ |
import yfinance as yf # ======================================== # 方法一:使用 Ticker 物件(適合單一標的深度分析) # ======================================== tsmc = yf.Ticker("2330.TW") # 取得歷史價格 hist = tsmc.history(period="1y") # 近一年 hist = tsmc.history(period="6mo") # 近6個月 hist = tsmc.history(period="5d") # 近5天 hist = tsmc.history(period="max") # 全部歷史 hist = tsmc.history(start="2024-01-01", end="2025-12-31") # 指定日期範圍 # period參數選項: # 1d, 5d, 1mo, 3mo, 6mo, 1y, 2y, 5y, 10y, ytd, max # ======================================== # 方法二:使用 download()(適合批次下載多標的) # ======================================== data = yf.download( tickers="SPY QQQ EEM GC=F BTC-USD", period="1y", interval="1d", # 日線 group_by="ticker", # 按標的分組 auto_adjust=True, # 自動調整除權息 threads=True # 多執行緒加速下載 ) # 存取特定標的:data['SPY']['Close'] # ======================================== # 時間粒度(interval參數) # ======================================== # 分鐘級:1m, 2m, 5m, 15m, 30m, 60m, 90m # 小時級:1h # 日級以上:1d, 5d, 1wk, 1mo, 3mo # # 注意限制: # 1m 資料只能取最近 7 天 # 日內資料(interval < 1d)只能取最近 60 天 # 日線以上則可取數十年歷史 # 取得5分鐘K線(近5天) intraday = yf.download("AAPL", period="5d", interval="5m")
history() 和 download() 回傳的都是 pandas DataFrame,包含以下欄位:
| 欄位 | 說明 |
|---|---|
| Open | 開盤價 |
| High | 最高價 |
| Low | 最低價 |
| Close | 收盤價(預設已調整除權息) |
| Volume | 成交量 |
| Dividends | 股息(僅 .history() 有) |
| Stock Splits | 股票分割(僅 .history() 有) |
msft = yf.Ticker("MSFT") # === 公司基本資訊(回傳 dict)=== info = msft.info print(info['marketCap']) # 市值 print(info['trailingPE']) # 本益比 print(info['dividendYield']) # 股息殖利率 print(info['fiftyTwoWeekHigh']) # 52週最高 print(info['sector']) # 產業 print(info['longBusinessSummary'])# 公司簡介 # === 財務報表(回傳 DataFrame)=== msft.income_stmt # 年度損益表 msft.quarterly_income_stmt # 季度損益表 msft.balance_sheet # 年度資產負債表 msft.quarterly_balance_sheet # 季度資產負債表 msft.cashflow # 年度現金流量表 msft.quarterly_cashflow # 季度現金流量表 # === 股息與分割 === msft.dividends # 歷史股息 msft.splits # 歷史股票分割 msft.actions # 股息+分割合併 # === 分析師資訊 === msft.analyst_price_targets # 目標價(高/低/平均/中位數) msft.recommendations # 分析師評等 msft.calendar # 行事曆(財報日等) # === 法人持股 === msft.institutional_holders # 機構持股 msft.major_holders # 主要持股者 msft.insider_transactions # 內部人交易 # === 選擇權 === msft.options # 可用到期日列表 chain = msft.option_chain(msft.options[0]) chain.calls # 買權資料 chain.puts # 賣權資料
# ======================================== # 1. 批次下載後取得單一標的的收盤價 # ======================================== data = yf.download(["SPY", "GC=F", "BTC-USD"], period="1y") spy_close = data['Close']['SPY'] # 多標的時是 MultiIndex # 單一標的下載時直接取用 spy = yf.download("SPY", period="1y") spy_close = spy['Close'] # ======================================== # 2. 處理 MultiIndex 的 .squeeze() 技巧 # ======================================== # 單一標的下載時,Close欄位可能是DataFrame而非Series # 使用 .squeeze() 確保轉為 Series close = yf.download("AAPL", period="1y")['Close'].squeeze() # ======================================== # 3. 錯誤處理(yfinance偶爾會失敗) # ======================================== def safe_download(ticker, **kwargs): """安全下載,失敗時回傳空DataFrame""" try: data = yf.download(ticker, progress=False, **kwargs) if data.empty: print(f"{ticker}: 無資料") return data except Exception as e: print(f"{ticker} 下載失敗: {e}") return pd.DataFrame() # ======================================== # 4. 台股常用代碼速查 # ======================================== tw_tickers = { '台積電': '2330.TW', '鴻海': '2317.TW', '聯發科': '2454.TW', '台灣50': '0050.TW', '高股息': '0056.TW', '金融': '0055.TW', '半導體': '00891.TW', '加權指數': '^TWII', } # ======================================== # 5. 計算技術指標的完整範例 # ======================================== import pandas as pd ticker = yf.Ticker("2330.TW") df = ticker.history(period="1y") # 移動平均線 df['MA20'] = df['Close'].rolling(20).mean() df['MA60'] = df['Close'].rolling(60).mean() df['EMA12'] = df['Close'].ewm(span=12).mean() # RSI delta = df['Close'].diff() gain = delta.where(delta > 0, 0).rolling(14).mean() loss = (-delta.where(delta < 0, 0)).rolling(14).mean() df['RSI'] = 100 - (100 / (1 + gain / loss)) # 布林通道 df['BB_mid'] = df['Close'].rolling(20).mean() df['BB_std'] = df['Close'].rolling(20).std() df['BB_upper'] = df['BB_mid'] + 2 * df['BB_std'] df['BB_lower'] = df['BB_mid'] - 2 * df['BB_std'] print(df[['Close','MA20','RSI','BB_upper','BB_lower']].tail()) # ======================================== # 6. 匯出為CSV # ======================================== df.to_csv("tsmc_data.csv", encoding="utf-8-sig") # utf-8-sig讓Excel正確顯示中文
| 限制 | 詳細說明 | 應對策略 |
|---|---|---|
| 非官方API | yfinance不隸屬於Yahoo,使用Yahoo的公開API,可能因Yahoo端改版而暫時失效 | 保持更新到最新版本;準備備用資料來源(如台股可用FinMind) |
| 頻率限制 | 短時間大量請求可能被Yahoo暫時封鎖IP | 在迴圈中加入 time.sleep(1);使用 progress=False 減少請求;將資料本地快取 |
| 日內資料期限 | 1分鐘資料僅保留7天;日內資料最多60天 | 需要長期日內資料應定期下載並存入本地資料庫 |
| 資料品質 | 偶有缺值或異常值;部分冷門標的資料不完整 | 下載後務必用 .dropna() 清理;重要分析用多來源交叉驗證 |
| 僅供個人/研究用 | Yahoo Finance的使用條款限定資料為個人用途,不得用於商業轉售 | 商業用途應使用付費API(如Bloomberg、Refinitiv、Polygon.io) |
| 部分方法使用網頁爬蟲 | 少數功能(如部分 .info 欄位)透過爬取Yahoo網頁取得,較不穩定 | 核心的 .history() 和 download() 使用正式API,穩定度高 |
| 套件/服務 | 費用 | 優勢 | 劣勢 |
|---|---|---|---|
| yfinance | 免費 | 簡單易用、資料範圍廣、社群活躍 | 非官方、偶爾失效、不適合高頻交易 |
| Alpha Vantage | 免費(有限額)/ 付費 | 內建技術指標計算、正式API Key | 免費版每分鐘5次請求限制 |
| FRED API(fredapi) | 免費 | 總經數據最權威(殖利率、PMI、GDP等) | 僅有總經數據,無個股價格 |
| FinMind | 免費(有限額) | 台股資料最完整,含法人籌碼、融資券等 | 僅覆蓋台灣市場 |
| Polygon.io | 免費(延遲)/ 付費(即時) | 極低延遲(1ms)、適合即時交易 | 免費版資料延遲15分鐘 |
對於個人研究與學習、策略原型開發以及中長期投資分析而言,yfinance 是最佳的起點選擇。它的簡潔設計讓初學者可以用兩三行程式碼就取得全球市場資料,配合 pandas 進行分析。當需求升級至即時交易或商業應用時,再轉向付費API即可。
MetaQuotes Language(簡稱 MQL)是一種專為金融市場交易開發的程式語言,用於在 MetaTrader 平台(如 MT4 和 MT5)中創建自動交易策略(Expert Advisors)、自定指標、腳本及函數庫。
// 每次新 K 棒開始時進行操作
int start() {
if (OrdersTotal() == 0 && Volume[0] == 1) {
OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, 0, 0, "Buy Order", 0, 0, clrGreen);
}
return 0;
}
#property indicator_separate_window
#property indicator_buffers 1
double Buffer[];
int OnInit() {
SetIndexBuffer(0, Buffer);
return(INIT_SUCCEEDED);
}
int OnCalculate(const int rates_total, const int prev_calculated,
const datetime &time[], const double &open[],
const double &high[], const double &low[],
const double &close[], const long &tick_volume[],
const long &volume[], const int &spread[]) {
for (int i = 0; i < rates_total; i++) {
Buffer[i] = close[i] - open[i];
}
return(rates_total);
}
MQL 程式碼可透過 MetaTrader 內建的 MetaEditor 編輯與編譯,並在策略測試器中回測與優化。
MetaQuotes Language 是為交易自動化而生的專業語言,無論是初學者還是專業量化交易者,都能利用其強大功能實現精細交易策略。
這是功能最完整的版本,包含多種指標、畫圖工具及完整交易介面(如果連接經紀商)。
<!-- 進階圖表容器 -->
<div class="tradingview-widget-container">
<div id="tradingview_adv"></div>
<script type="text/javascript" src="https://s3.tradingview.com/tv.js"></script>
<script type="text/javascript">
new TradingView.widget({
"autosize": true,
"symbol": "BINANCE:BTCUSDT",
"interval": "H",
"timezone": "Etc/UTC",
"theme": "dark",
"style": "1",
"locale": "zh_TW",
"container_id": "tradingview_adv"
});
</script>
</div>
此工具以儀表板形式呈現,根據多種技術指標(如移動平均線、振盪指標)自動計算並顯示買入或賣出的建議。
<!-- 技術分析小工具 -->
<div class="tradingview-widget-container">
<div class="tradingview-widget-container__widget"></div>
<script type="text/javascript" src="https://s3.tradingview.com/external-embedding/embed-widget-technical-analysis.js" async>
{
"interval": "1m",
"width": 425,
"isTransparent": false,
"height": 450,
"symbol": "NASDAQ:TSLA",
"showIntervalTabs": true,
"locale": "zh_TW",
"colorTheme": "light"
}
</script>
</div>
適用於顯示多個商品的即時價格對比,常見於財經網站的首頁側邊欄。
<!-- 市場概覽 -->
<div class="tradingview-widget-container">
<script type="text/javascript" src="https://s3.tradingview.com/external-embedding/embed-widget-market-overview.js" async>
{
"colorTheme": "dark",
"dateRange": "12M",
"showChart": true,
"locale": "zh_TW",
"width": "100%",
"height": "400",
"tabs": [
{
"title": "指數",
"symbols": [
{"s": "FOREXCOM:SPX500", "d": "S&P 500"},
{"s": "FOREXCOM:NSXUSD", "d": "Nasdaq 100"}
]
}
]
}
</script>
</div>
雖然可以手動撰寫 JavaScript,但 TradingView 提供了官方的圖形化生成器,建議優先使用以避免語法錯誤:
| 問題 | 解決方法 |
|---|---|
| 圖表無法載入 | 檢查 container_id 是否與 HTML ID 完全匹配。 |
| 寬度跑版 | 將 width 設為 "100%" 並確保外層 div 有固定寬度。 |
| 數據延遲 | 免費版小工具數據通常有 15-20 分鐘延遲,取決於交易所。 |
Binance 是一個全球領先的加密貨幣交易所,為開發者提供豐富的 API 支援,包括 Spot API 和 Client API,方便使用者進行自動交易和數據獲取。
Binance Spot API 是 Binance 為現貨市場交易者設計的 API,可用於查詢市場資訊、下單、取消訂單等操作。此 API 常用於設計交易機器人、自動交易策略和監控市場波動。
Binance Client API 提供一個便捷的方式來存取 Binance 的各種 API 方法。開發者可以使用 binance.client 庫進行 API
認證和管理,並便捷地調用各種現貨和合約市場的功能。
pip install binancebinance.client 進行 API 連接,並調用 binance.spot 方法。
from binance.client import Client
# 初始化客戶端
client = Client(api_key='your_api_key', api_secret='your_secret_key')
# 取得當前的價格
price = client.get_symbol_ticker(symbol="BTCUSDT")
print(price)
Bybit 提供 REST 與 WebSocket API,可用於查詢行情、下單、查資金費率、管理帳戶等。以下展示如何使用 Python requests 套件呼叫 Bybit 公開 API。
pip install requests
import requests
BASE_URL = "https://api.bybit.com"
def get_symbols():
url = f"{BASE_URL}/v5/market/instruments-info?category=linear"
res = requests.get(url)
res.raise_for_status()
data = res.json()
symbols = [s["symbol"] for s in data["result"]["list"]]
print(f"共取得 {len(symbols)} 個交易對:")
print(symbols[:10]) # 顯示前 10 筆
if __name__ == "__main__":
get_symbols()
import requests
def get_klines(symbol="BTCUSDT", interval="60", limit=5):
url = f"{BASE_URL}/v5/market/kline?category=linear&symbol={symbol}&interval={interval}&limit={limit}"
res = requests.get(url)
res.raise_for_status()
data = res.json()
for k in data["result"]["list"]:
print(k)
if __name__ == "__main__":
get_klines()
Bybit 的下單、資產查詢等私有端點需要 API Key 與簽名。
import requests, time, hmac, hashlib
API_KEY = "your_api_key"
API_SECRET = "your_api_secret"
def sign_request(params, secret):
"""Bybit 簽名生成"""
query = "&".join([f"{k}={v}" for k, v in sorted(params.items())])
return hmac.new(secret.encode(), query.encode(), hashlib.sha256).hexdigest()
def get_wallet_balance():
endpoint = "/v5/account/wallet-balance"
url = BASE_URL + endpoint
timestamp = str(int(time.time() * 1000))
params = {
"accountType": "UNIFIED",
"timestamp": timestamp,
"api_key": API_KEY,
}
params["sign"] = sign_request(params, API_SECRET)
res = requests.get(url, params=params)
print(res.json())
if __name__ == "__main__":
get_wallet_balance()
Pionex 使用 /api/v1/common/symbols?type=PERP 來取得「永續合約」交易對;在 Bybit,可使用 /v5/market/instruments-info 並指定 category=linear(USDT 永續)或 inverse(反向合約)達到同樣效果。
import requests
class BybitAPI:
BASE_URL = "https://api.bybit.com"
@classmethod
def get_symbols(cls, category="linear"):
"""
取得特定類型交易對
category 可為:
- linear → USDT 永續 (PERP)
- inverse → 反向永續/交割合約
- spot → 現貨
"""
endpoint = "/v5/market/instruments-info"
url = f"{cls.BASE_URL}{endpoint}"
params = {"category": category}
res = requests.get(url, params=params)
res.raise_for_status()
data = res.json()
if data.get("retCode") == 0:
symbols = [s["symbol"] for s in data["result"]["list"]]
print(f"共取得 {len(symbols)} 個 {category} 類型交易對")
for s in symbols[:10]:
print(s)
else:
print("取得失敗:", data)
if __name__ == "__main__":
BybitAPI.get_symbols("linear")
| Pionex | Bybit | 說明 |
|---|---|---|
type=PERP | category=linear | USDT 永續合約 |
type=SPOT | category=spot | 現貨市場 |
| — | category=inverse | 反向永續或交割合約 |
{
"retCode": 0,
"result": {
"list": [
{
"symbol": "BTCUSDT",
"contractType": "LinearPerpetual",
"status": "Trading",
"lotSizeFilter": {
"minOrderQty": "0.001",
"maxOrderQty": "100",
"qtyStep": "0.001"
},
"priceFilter": {
"tickSize": "0.5"
}
}
]
}
}
category=linear 即對應到 Pionex 的「PERP」交易對。priceFilter、lotSizeFilter 等限制。在 Pionex 中可使用 /api/v1/market/klines 查行情;Bybit 對應的端點是 /v5/market/kline。透過 category 指定市場類型(例如 linear 表示 USDT 永續合約),並可傳入 symbol、interval、limit、endTime 等參數。
import requests
import time
class BybitAPI:
BASE_URL = "https://api.bybit.com"
@classmethod
def get_klines(cls, symbol: str, interval: str, end_time: int = None, limit: int = 100):
"""
查詢 Bybit K線資料
:param symbol: 交易對,例如 "BTCUSDT"
:param interval: 時間區間 (1, 3, 5, 15, 30, 60, 120, 240, 360, 720, D, W, M)
:param end_time: 結束時間 (Unix 毫秒),預設為現在
:param limit: 回傳筆數,最大 1000
"""
endpoint = "/v5/market/kline"
url = f"{cls.BASE_URL}{endpoint}"
params = {
"category": "linear", # USDT 永續
"symbol": symbol,
"interval": interval,
"limit": limit
}
if end_time:
params["end"] = end_time
else:
params["end"] = int(time.time() * 1000)
res = requests.get(url, params=params)
res.raise_for_status()
data = res.json()
if data.get("retCode") == 0:
klines = data["result"]["list"]
print(f"{symbol} 共取得 {len(klines)} 根 K 線")
# 顯示前 3 根資料
for k in klines[:3]:
open_time, open_price, high, low, close, volume, turnover = k
print(f"開:{open_price} 收:{close} 高:{high} 低:{low} 量:{volume}")
else:
print("取得失敗:", data)
if __name__ == "__main__":
BybitAPI.get_klines(symbol="BTCUSDT", interval="60", limit=5)
{
"retCode": 0,
"result": {
"symbol": "BTCUSDT",
"category": "linear",
"list": [
[
"1735119600000", // 開始時間 (毫秒)
"98342.5", // 開盤價
"98350.0", // 最高價
"98285.0", // 最低價
"98290.5", // 收盤價
"12.304", // 交易量
"1210000.5" // 成交額 (USDT)
]
]
}
}
category 可改為 spot 或 inverse 對應不同市場。end 參數為毫秒時間戳(Unix epoch × 1000)。下面是一個可直接複製的 Python 範例,採用 ThreadPoolExecutor 並內建重試、速率限制與快取(cache)。流程:先從快取載入已抓到的 K 線(若有),只對缺少或不足的交易對發出請求;使用 thread pool 同時執行多請求並以 semaphore 控制並發數避免被限流;遇到失敗會 exponential backoff 重試。
# 需求: pip install requests
import requests
import time
import json
import os
from concurrent.futures import ThreadPoolExecutor, as_completed
from threading import Semaphore
BASE_URL = "https://api.bybit.com/v5/market/kline"
CACHE_FILE = "klines_cache.json"
# 可調參數
MAX_WORKERS = 20 # thread pool 大小(視 API 速率限制調整)
MAX_CONCURRENT = 10 # 真正並發的請求數(用 semaphore 控制)
RETRY = 3 # 每個請求的重試次數
INITIAL_BACKOFF = 0.5 # 首次重試等待秒數
CATEGORY = "linear" # linear -> USDT 永續;spot/inverse 可改
LIMIT_PER_CALL = 200 # 每次 kline API limit(視 API 上限設定)
DATASET_ALLDAYS = 24 * 6 # 範例:判定需要至少多少根 K 線(可改)
# 載入/存取快取
def load_cache():
if os.path.exists(CACHE_FILE):
try:
return json.load(open(CACHE_FILE, "r", encoding="utf-8"))
except Exception:
return {}
return {}
def save_cache(cache):
json.dump(cache, open(CACHE_FILE, "w", encoding="utf-8"), ensure_ascii=False, indent=2)
# 單一 symbol 的 API 抓取,含重試與速率控制(由 semaphore 控制同時執行數)
def fetch_klines_for_symbol(symbol, interval="60", end_time=None, limit=LIMIT_PER_CALL, sem: Semaphore = None):
params = {
"category": CATEGORY,
"symbol": symbol,
"interval": interval,
"limit": limit
}
if end_time:
params["end"] = int(end_time)
backoff = INITIAL_BACKOFF
last_exc = None
# 取得 semaphore(若提供)
if sem:
sem.acquire()
try:
for attempt in range(1, RETRY + 1):
try:
resp = requests.get(BASE_URL, params=params, timeout=10)
resp.raise_for_status()
data = resp.json()
# Bybit v5 回傳 retCode == 0 才表示成功
if data.get("retCode", 0) == 0 and "result" in data:
klines = data["result"].get("list", [])
return klines
else:
last_exc = Exception(f"API error: {data}")
except requests.exceptions.RequestException as e:
last_exc = e
# backoff
time.sleep(backoff)
backoff *= 2
finally:
if sem:
sem.release()
# 若失敗,拋出最後一個錯誤或回傳 None
raise last_exc
# 批次處理:傳入 pairs(list of symbols),回傳 dict {symbol: klines}
def get_klines_batch(pairs, interval="60", dataset_alldays=DATASET_ALLDAYS, limit=LIMIT_PER_CALL, max_workers=MAX_WORKERS, max_concurrent=MAX_CONCURRENT):
cache = load_cache() # cache 格式: { symbol: [kline_list] }
results = {}
to_fetch = []
# 判斷哪些 symbol 需要抓(cache 中不存在或長度不足)
for s in pairs:
cached = cache.get(s)
if cached and len(cached) >= dataset_alldays:
results[s] = cached
else:
to_fetch.append(s)
# 如果沒有需要抓取的就直接回傳
if not to_fetch:
return results
sem = Semaphore(max_concurrent)
with ThreadPoolExecutor(max_workers=max_workers) as exe:
futures = {exe.submit(fetch_klines_for_symbol, sym, interval, None, limit, sem): sym for sym in to_fetch}
for fut in as_completed(futures):
sym = futures[fut]
try:
kl = fut.result()
# 若 API 回傳以列表格式儲存(依 Bybit 範例 [time,open,high,low,close,vol,turnover])
cache[sym] = kl
results[sym] = kl
except Exception as e:
# 記錄失敗,但不阻斷整體程序
print(f"[錯誤] {sym} 取得失敗: {e}")
results[sym] = None
# 將 cache 存檔(可選:只存成功的)
save_cache(cache)
return results
# 範例使用
if __name__ == "__main__":
# 假設有 500 個 pairs(示意)
pairs = ["BTCUSDT", "ETHUSDT", "SOLUSDT"] # ... 500 個
# 執行批次抓取
all_klines = get_klines_batch(pairs, interval="60", dataset_alldays=100, limit=200)
# 篩選符合長度需求的 symbols
good = [s for s, kl in all_klines.items() if kl and len(kl) >= 100]
print(f"符合 100 根以上的交易對數量: {len(good)}")
print(good[:20])
MAX_WORKERS 與 MAX_CONCURRENT。若有 API key,通常能提高速率配額。Pionex 提供官方 API,讓開發者能透過程式自動化交易、查詢市場數據、管理帳戶資產。API 支援 REST 與 WebSocket 兩種方式。
API Key 與 Secret,僅顯示一次
// 使用 Node.js axios 請求 Pionex API
const axios = require("axios");
const crypto = require("crypto");
const apiKey = "你的API_KEY";
const secret = "你的API_SECRET";
const baseUrl = "https://api.pionex.com";
// 簽名產生
function sign(query) {
return crypto.createHmac("sha256", secret).update(query).digest("hex");
}
// 查詢帳戶餘額
async function getBalances() {
const timestamp = Date.now();
const query = `timestamp=${timestamp}`;
const signature = sign(query);
const res = await axios.get(`${baseUrl}/api/v1/account?${query}&signature=${signature}`, {
headers: { "X-MBX-APIKEY": apiKey }
});
console.log(res.data);
}
getBalances();
import time
import hmac
import hashlib
import requests
API_KEY = "你的API_KEY"
SECRET = "你的API_SECRET"
BASE_URL = "https://api.pionex.com"
def sign(query: str) -> str:
return hmac.new(SECRET.encode(), query.encode(), hashlib.sha256).hexdigest()
def get_balances():
timestamp = str(int(time.time() * 1000))
query = f"timestamp={timestamp}"
signature = sign(query)
url = f"{BASE_URL}/api/v1/account?{query}&signature={signature}"
headers = {"X-MBX-APIKEY": API_KEY}
res = requests.get(url, headers=headers)
print(res.json())
get_balances()
const WebSocket = require("ws");
const ws = new WebSocket("wss://ws.pionex.com/ws");
ws.on("open", () => {
console.log("已連線至 Pionex WebSocket");
// 訂閱 BTC/USDT 行情
ws.send(JSON.stringify({
event: "subscribe",
channel: "market",
market: "BTC_USDT"
}));
});
ws.on("message", (msg) => {
console.log("接收訊息:", msg.toString());
});
import websocket
import json
def on_open(ws):
print("已連線至 Pionex WebSocket")
sub_msg = {
"event": "subscribe",
"channel": "market",
"market": "BTC_USDT"
}
ws.send(json.dumps(sub_msg))
def on_message(ws, message):
print("接收訊息:", message)
ws = websocket.WebSocketApp(
"wss://ws.pionex.com/ws",
on_open=on_open,
on_message=on_message
)
ws.run_forever()
可使用 GET /api/v1/common/symbols 來取得 Pionex 所有支援的交易對與詳細屬性,例如最小下單量、價格精度、交易類型(現貨或合約)等。
GET https://api.pionex.com/api/v1/common/symbols
{
"code": 0,
"data": [
{
"symbol": "BTC_USDT",
"quoteCurrency": "USDT",
"baseCurrency": "BTC",
"minQty": "0.0001",
"minNotional": "5",
"pricePrecision": 2,
"quantityPrecision": 6,
"tradeEnable": true
},
{
"symbol": "ETH_USDT",
"quoteCurrency": "USDT",
"baseCurrency": "ETH",
"minQty": "0.001",
"pricePrecision": 2,
"quantityPrecision": 6,
"tradeEnable": true
}
]
}
import requests
BASE_URL = "https://api.pionex.com"
def get_symbols():
url = f"{BASE_URL}/api/v1/common/symbols"
res = requests.get(url)
data = res.json()
if data.get("code") == 0:
symbols = data.get("data", [])
print(f"共取得 {len(symbols)} 個交易對")
for s in symbols[:10]: # 只顯示前10個
print(f"{s['symbol']} ({s['baseCurrency']}/{s['quoteCurrency']})")
else:
print("取得失敗:", data)
if __name__ == "__main__":
get_symbols()
若要只取出支援永續合約的交易對,可使用下列簡單篩選邏輯:
perp_symbols = [s for s in data["data"] if ".PERP" in s["symbol"]]
/api/v1/market/tickers 取得即時價格。以下程式會呼叫 https://api.pionex.com/api/v1/common/symbols,自動印出回傳 JSON 的結構(key 與資料型態),方便了解實際格式。
import requests
import json
def print_json_structure(data, indent=0):
"""遞迴印出 JSON 結構"""
space = " " * indent
if isinstance(data, dict):
for k, v in data.items():
if isinstance(v, (dict, list)):
print(f"{space}{k}: {type(v).__name__}")
print_json_structure(v, indent + 1)
else:
print(f"{space}{k}: {type(v).__name__}")
elif isinstance(data, list) and data:
print(f"{space}[list] item type: {type(data[0]).__name__}")
print_json_structure(data[0], indent + 1)
def get_pionex_symbols_format():
url = "https://api.pionex.com/api/v1/common/symbols"
res = requests.get(url)
res.raise_for_status()
data = res.json()
print("根層結構:")
print_json_structure(data)
if __name__ == "__main__":
get_pionex_symbols_format()
根層結構:
code: int
data: list
[list] item type: dict
symbol: str
baseCurrency: str
quoteCurrency: str
pricePrecision: int
quantityPrecision: int
minQty: str
minNotional: str
tradeEnable: bool
json.dumps(data, indent=2) 可檢視完整內容。取得指定交易對的 K 線(Candlestick / OHLCV)數據,來源來自 Pionex 公開市場資料。
| 參數 | 型別 | 是否必需 | 說明 |
|---|---|---|---|
| symbol | string | 是 | 交易對 (例:BTC_USDT 或 BTC_USDT.PERP) |
| interval | string | 是 | 時間間隔,例如 1M、5M、15M、30M、60M、4H、8H、12H、1D |
| endTime | number (毫秒) | 否 | 結束時間(毫秒時間戳) |
| limit | number | 否 | 取得資料數量,預設 100,範圍 1-500 |
{
"result": true,
"data": {
"klines": [
{
"time": 1691649240000,
"open": "1851.27",
"close": "1851.32",
"high": "1851.32",
"low": "1851.27",
"volume": "0.542"
}
]
},
"timestamp": 1691649271544
}
import requests
BASE_URL = "https://api.pionex.com"
def get_klines(symbol: str, interval: str, end_time: int = None, limit: int = 100):
params = {
"symbol": symbol,
"interval": interval,
"limit": limit
}
if end_time is not None:
params["endTime"] = end_time
response = requests.get(f"{BASE_URL}/api/v1/market/klines", params=params)
result = response.json()
if result.get("result") and "data" in result:
return result["data"]["klines"]
else:
raise Exception(f"取得 K 線失敗: {result}")
if __name__ == "__main__":
# 範例:取得 BTC_USDT 永續合約最近 50 根 15 分鐘 K 線
symbol = "BTC_USDT.PERP"
interval = "15M"
klines = get_klines(symbol, interval, limit=50)
for k in klines:
print(k)
Pionex 並沒有單獨一個 「取得支援網格交易對」 的專用 API,但可以透過 GET /api/v1/market/tickers 取得所有交易對,再從中篩選出 .PERP 類型(USDT 永續合約),即可得到 Futures Grid 支援的交易對清單。
import requests
BASE_URL = "https://api.pionex.com"
def get_perp_pairs():
url = f"{BASE_URL}/api/v1/market/tickers"
res = requests.get(url)
data = res.json()
perp_pairs = []
if "data" in data:
for item in data["data"]:
market = item.get("symbol", "")
# 永續合約交易對通常以 .PERP 結尾
if ".PERP" in market:
perp_pairs.append(market)
return perp_pairs
if __name__ == "__main__":
pairs = get_perp_pairs()
print("支援的永續合約網格交易對:")
for p in pairs:
print(p)
支援的永續合約網格交易對:
BTC_USDT.PERP
ETH_USDT.PERP
SOL_USDT.PERP
LINK_USDT.PERP
...
.PERP)可直接用於 Futures Grid Bot。Max Coin API 是由 Max Exchange 提供的一套應用程式介面,允許開發者程式化地訪問其加密貨幣交易功能。開發者可以透過 API 自動化執行交易、檢索市場數據以及管理資產。
以下是一個透過 API 獲取市場數據的範例:
GET https://max-api.maicoin.com/api/v1/ticker?market=btctwd
該請求將返回 BTC/TWD 的即時市場數據,包括價格、成交量等。
以下是一個使用 Python 語言調用 Max API 的簡單範例:
import requests
BASE_URL = "https://max-api.maicoin.com"
def get_ticker(pair):
endpoint = "/api/v1/ticker"
params = {"market": pair}
response = requests.get(BASE_URL + endpoint, params=params)
return response.json()
# 獲取 BTC/TWD 市場數據
ticker_data = get_ticker("btctwd")
print(ticker_data)
比特幣使用 工作量證明(Proof of Work, PoW) 作為共識機制,以實現去中心化的記帳系統。PoW 的核心目標是讓節點透過競爭解數學難題來決定誰擁有記帳權,確保資料無法被任意竄改。
礦工會根據以下條件優先挑選交易,以提高成功打包區塊並賺取手續費的機會:
當交易量過大時,出現擁堵與手續費上升的情況。為改善此問題,提出多種擴展解決方案:
| 欄位名稱 | 大小(位元組) | 說明 |
|---|---|---|
| block size | 4 | 整個區塊(含 header 與所有交易資料)的總大小(以 byte 為單位) |
| block header | 80 | 區塊的標頭資訊,用來做驗證與連結前後區塊 |
| transaction counter | 1 ~ 9 | 交易數量,以變長整數(VarInt)表示本區塊內有幾筆交易 |
| transactions | 可變 | 所有實際的交易資料,每一筆交易包含輸入與輸出 |
長度固定為 80 個位元組,內容如下:
| 欄位名稱 | 資料型別 | 長度 | 說明 |
|---|---|---|---|
| version | int32 | 4 | 區塊版本,代表可接受的區塊驗證規則 |
| previous block hash | char[32] | 32 | 前一個區塊的哈希值 |
| merkle root | char[32] | 32 | 所有交易哈希值的 Merkle Tree 根 |
| timestamp | uint32 | 4 | 區塊建立時間(UNIX 時間戳) |
| bits | uint32 | 4 | 目標難度的壓縮表示 |
| nonce | uint32 | 4 | 為了找到合法區塊哈希的變動值 |
使用 VarInt(變長整數)格式,表示區塊中有多少筆交易:
每一筆交易資料包含以下主要部分(長度可變):
第一筆交易通常是 coinbase 交易,也就是礦工領取區塊獎勵的特殊交易,不包含輸入。
import time
class Transaction:
def __init__(self, sender, receiver, amount, fee):
self.sender = sender
self.receiver = receiver
self.amount = amount
self.fee = fee
self.timestamp = time.time()
def __repr__(self):
return f"[Tx: {self.sender} → {self.receiver}, ${self.amount}, fee: {self.fee}]"
class Node:
def __init__(self, name):
self.name = name
self.peers = []
self.transaction_pool = []
def connect(self, peer):
if peer not in self.peers:
self.peers.append(peer)
peer.connect(self) # 雙向連線
def receive_transaction(self, tx):
if tx not in self.transaction_pool:
self.transaction_pool.append(tx)
print(f"{self.name} 收到交易:{tx}")
self.broadcast(tx)
def broadcast(self, tx):
for peer in self.peers:
peer.receive_transaction(tx)
class Miner(Node):
def mine_block(self):
print(f"\n⛏️ {self.name} 開始打包區塊")
# 按手續費高排序,取最多 5 筆交易
sorted_txs = sorted(self.transaction_pool, key=lambda tx: tx.fee, reverse=True)
selected = sorted_txs[:5]
print(f"{self.name} 打包交易:")
for tx in selected:
print(f" - {tx}")
# 清空已處理的交易
self.transaction_pool = [tx for tx in self.transaction_pool if tx not in selected]
# 建立節點與礦工
A = Node("節點 A")
B = Node("節點 B")
C = Miner("礦工 C")
# 連接節點網路
A.connect(B)
B.connect(C)
# 用戶發出交易
tx_list = [
Transaction("Alice", "Bob", 2.0, 0.0005),
Transaction("Eve", "Tom", 1.2, 0.0009),
Transaction("Joe", "Mary", 3.5, 0.0002),
Transaction("Rick", "Sam", 0.8, 0.0015),
Transaction("Ann", "Lily", 1.7, 0.0001)
]
for tx in tx_list:
print(f"\n用戶送出交易:{tx}")
A.receive_transaction(tx)
time.sleep(0.2)
# 礦工開始打包
C.mine_block()
Ethereum 虛擬機(Ethereum Virtual Machine,簡稱 EVM)是以太坊的核心組件,負責執行智能合約。EVM 提供了一個沙箱環境,允許開發者在上面運行代碼,而不需要擔心會影響到以太坊網絡的其他部分。
智能合約是自動執行、不可更改的合約,執行時由 EVM 處理。開發者通常使用 Solidity 等高級編程語言來撰寫智能合約,然後將其編譯成 EVM 可理解的字節碼。
Solidity 是 Ethereum 上最常用的編程語言,語法類似於 JavaScript。以下是一個簡單的 Solidity 智能合約示例:
pragma solidity ^0.8.0;
contract SimpleStorage {
uint public storedData;
function set(uint x) public {
storedData = x;
}
function get() public view returns (uint) {
return storedData;
}
}
上述合約包含一個用來儲存整數數據的變量 storedData,以及設置和獲取該數據的函數。
當用戶在以太坊網絡上執行一個智能合約時,以下步驟會發生:
EVM 的運算資源是有限的,為了防止網絡濫用,EVM 使用 Gas 機制來計算和收取交易費用。每個操作都有其相應的 Gas 成本,用戶在提交交易時需要提供足夠的 Gas
來支付執行智能合約所需的計算資源。
EVM 是以太坊網絡的核心,提供了一個強大的環境來運行智能合約。通過使用 Solidity 等編程語言,開發者可以創建各種去中心化應用(dApps),並利用 EVM 的功能來實現複雜的邏輯運算和交易處理。
Node.js 和 npmHardhat:npm install --save-dev hardhatnpx hardhat,選擇「Create a basic sample project」在 contracts 資料夾中新增 LendingProtocol.sol 並貼上你的 Solidity 合約。
於 scripts 資料夾建立 deploy.js,內容如下:
async function main() {
const [deployer] = await ethers.getSigners();
console.log("部署帳號:", deployer.address);
const TokenAddress = "0xYourTokenAddressHere";
const LendingProtocol = await ethers.getContractFactory("LendingProtocol");
const lending = await LendingProtocol.deploy(TokenAddress);
await lending.deployed();
console.log("LendingProtocol 部署成功:", lending.address);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
啟動 Hardhat 測試鏈:
npx hardhat node
另開一個 terminal 部署:
npx hardhat run scripts/deploy.js --network localhost
hardhat.config.js 中加入:
require("@nomiclabs/hardhat-ethers");
module.exports = {
networks: {
goerli: {
url: "https://goerli.infura.io/v3/你的API金鑰",
accounts: ["0x你的私鑰"]
}
},
solidity: "0.8.20"
};
然後部署:
npx hardhat run scripts/deploy.js --network goerli
部署後會輸出合約地址,可用於前端整合與互動。
本借貸協議為以太坊虛擬機(EVM)上運行的智慧合約,用戶可以透過本合約存入資產賺取利息或借出資產支付利息。此協議支援ERC-20代幣,具備借貸、儲蓄、清算等核心功能。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC20 {
function transferFrom(address sender, address recipient, uint amount) external returns (bool);
function transfer(address recipient, uint amount) external returns (bool);
function balanceOf(address account) external view returns (uint);
function approve(address spender, uint amount) external returns (bool);
}
contract LendingProtocol {
IERC20 public token;
address public owner;
uint public interestRate = 5; // 年利率5%
mapping(address => uint) public deposits;
mapping(address => uint) public borrows;
constructor(address _token) {
token = IERC20(_token);
owner = msg.sender;
}
function deposit(uint amount) external {
require(amount > 0, "金額需大於0");
token.transferFrom(msg.sender, address(this), amount);
deposits[msg.sender] += amount;
}
function borrow(uint amount) external {
require(amount > 0, "金額需大於0");
uint collateral = deposits[msg.sender];
require(collateral >= amount * 2, "抵押不足");
borrows[msg.sender] += amount;
token.transfer(msg.sender, amount);
}
function repay(uint amount) external {
require(amount > 0, "金額需大於0");
require(borrows[msg.sender] >= amount, "借款不足");
borrows[msg.sender] -= amount;
token.transferFrom(msg.sender, address(this), amount);
}
function withdraw(uint amount) external {
require(deposits[msg.sender] >= amount, "餘額不足");
require(borrows[msg.sender] == 0, "有未還借款");
deposits[msg.sender] -= amount;
token.transfer(msg.sender, amount);
}
}
BSC (Binance Smart Chain) 是一條相容於 EVM (Ethereum Virtual Machine) 的公鏈,因此在以太坊上編寫的 Solidity 智能合約幾乎可以直接部署到 BSC。主要差異在於部署時連接的網路與 Gas 費以 BNB 計價。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SimpleStorage {
uint private value;
function setValue(uint _value) public {
value = _value;
}
function getValue() public view returns (uint) {
return value;
}
}
使用 Hardhat 進行部署,在 hardhat.config.js 中設定 BSC 網路:
require("@nomiclabs/hardhat-ethers");
module.exports = {
solidity: "0.8.20",
networks: {
bscTestnet: {
url: "https://data-seed-prebsc-1-s1.binance.org:8545/",
chainId: 97,
gasPrice: 20000000000,
accounts: ["0x你的私鑰"]
},
bscMainnet: {
url: "https://bsc-dataseed.binance.org/",
chainId: 56,
gasPrice: 20000000000,
accounts: ["0x你的私鑰"]
}
}
};
async function main() {
const [deployer] = await ethers.getSigners();
console.log("部署帳號:", deployer.address);
const SimpleStorage = await ethers.getContractFactory("SimpleStorage");
const storage = await SimpleStorage.deploy();
await storage.deployed();
console.log("合約已部署:", storage.address);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
npm install --save-dev hardhat @nomiclabs/hardhat-ethers ethersnpx hardhat run scripts/deploy.js --network bscTestnet使用 Python 和隨機森林模型來預測股票的漲跌概率。此範例利用 Yahoo 財經的股票數據,並通過技術指標來訓練模型,最後輸出股票上漲和下跌的概率。
首先,我們需要安裝並匯入 Python 的一些套件:
pip install yfinance scikit-learn pandas numpy
接著匯入這些必要的庫:
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
import yfinance as yf
接下來,我們從 Yahoo 財經下載股票的歷史數據,並計算簡單移動平均線 (SMA) 作為技術指標。
# 從 Yahoo 財經下載蘋果公司的股票數據
symbol = 'AAPL'
data = yf.download(symbol, start='2020-01-01', end='2023-01-01')
# 計算 10 日和 50 日簡單移動平均線 (SMA)
data['SMA_10'] = data['Close'].rolling(window=10).mean()
data['SMA_50'] = data['Close'].rolling(window=50).mean()
# 設置漲跌目標,若次日收盤價高於當日收盤價,則為1 (表示上漲),否則為0 (表示下跌)
data['Target'] = np.where(data['Close'].shift(-1) > data['Close'], 1, 0)
# 移除缺失值
data.dropna(inplace=True)
我們將使用移動平均線 (SMA) 和收盤價作為特徵,並將數據分為訓練集和測試集。
# 選擇特徵
features = ['SMA_10', 'SMA_50', 'Close']
X = data[features]
y = data['Target']
# 分割訓練集與測試集 (80%訓練,20%測試)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False)
我們使用隨機森林模型來訓練數據,並預測測試集中股票的漲跌概率。
# 初始化隨機森林分類器
model = RandomForestClassifier(n_estimators=100, random_state=42)
# 訓練模型
model.fit(X_train, y_train)
# 預測測試集中的漲跌
y_pred = model.predict(X_test)
y_prob = model.predict_proba(X_test) # 獲取漲跌的概率
我們可以計算模型的準確率,並顯示每一天的漲跌概率。
# 計算模型準確率
accuracy = accuracy_score(y_test, y_pred)
print(f"模型準確率: {accuracy:.2f}")
# 顯示測試集中前 5 天的漲跌概率
for i in range(5):
print(f"第{i+1}天:上漲概率={y_prob[i][1]:.2f}, 下跌概率={y_prob[i][0]:.2f}")
根據上漲的概率,您可以設定一個閾值來決定是否進行買入操作。例如,如果上漲概率超過 70%,則買入。
# 設定上漲概率的閾值
threshold = 0.7
# 根據概率進行買入決策
for i in range(len(y_prob)):
if y_prob[i][1] > threshold:
print(f"第{i+1}天建議買入,預測上漲概率={y_prob[i][1]:.2f}")
else:
print(f"第{i+1}天不建議買入,預測上漲概率={y_prob[i][1]:.2f}")
這個範例展示了如何使用隨機森林模型來預測股票的漲跌概率,並根據預測結果進行交易決策。這是一種簡單但有效的方式來提高交易決策的準確性。
可以透過以下網址訪問台灣證券交易所的公開申購公告頁面:
使用 Python 搭配 requests 和 BeautifulSoup,即可抓取頁面上的公開申購資料。
import requests
from bs4 import BeautifulSoup
import pandas as pd
# 抓取公開申購公告頁面
url = "https://www.twse.com.tw/zh/announcement/public.html"
headers = {"User-Agent": "Mozilla/5.0"}
response = requests.get(url, headers=headers)
if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')
tables = pd.read_html(response.text)
if tables:
df = tables[0] # 取第一個表格
print(df)
else:
print("未找到表格資料")
else:
print("無法連接到公開申購公告頁面")
Selenium 模擬瀏覽器操作。CurrencyAPI 提供即時匯率資訊。以下是範例程式碼:
import requests
url = 'https://api.currencyapi.com/v3/latest'
params = {
'apikey': '您的API金鑰',
'base_currency': 'USD',
'currencies': 'TWD'
}
response = requests.get(url, params=params)
data = response.json()
usd_to_twd = data['data']['TWD']['value']
print(f"1 美元等於 {usd_to_twd} 新台幣")
注意:需至 CurrencyAPI 註冊並取得 API 金鑰後才能使用。
ExchangeRatesAPI 同樣提供即時匯率查詢服務:
import requests
url = 'https://api.exchangeratesapi.io/latest'
params = {
'access_key': '您的API金鑰',
'base': 'USD',
'symbols': 'TWD'
}
response = requests.get(url, params=params)
data = response.json()
usd_to_twd = data['rates']['TWD']
print(f"1 美元等於 {usd_to_twd} 新台幣")
請先至 ExchangeRatesAPI 註冊取得 API 金鑰並替換程式碼中的 '您的API金鑰'。
若不想直接調用 API,可使用第三方 Python 套件 forex-python:
from forex_python.converter import CurrencyRates
cr = CurrencyRates()
usd_to_twd = cr.get_rate('USD', 'TWD')
print(f"1 美元等於 {usd_to_twd} 新台幣")
安裝套件命令:
pip install forex-python
若不使用 API,可以透過網頁爬蟲技術直接從 Currency.Wiki 網站擷取美元對台幣的即時匯率。
需要安裝以下 Python 套件:
pip install requests pip install beautifulsoup4
import requests
from bs4 import BeautifulSoup
# 設定目標網址
url = "https://currency.wiki/usd_twd"
# 發送 GET 請求取得網頁內容
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
# 查找特定標籤和類別
span_tag = soup.find('span', class_='unit_secondary_value')
rate = span_tag.text
print(f"1 美元等於 {rate} 新台幣")
透過 Python 爬蟲技術可直接取得即時匯率資訊,但需注意網頁結構變動和合規性問題,適合小規模應用或學習用途。
email: [email protected]