投資-軟體開發



AI 價格預測

價格預測通常結合機器學習和深度學習演算法,並運用歷史數據及市場技術指標。以下是常見的一些方法:

1. 時間序列分析

2. 機器學習演算法

3. 深度學習模型

4. 混合模型

5. 技術指標

6. 強化學習

使用強化學習的智能交易系統可以在模擬的市場環境中學習,並隨時間優化買賣決策,逐步改善交易策略。

7. 大數據與情感分析

AI 模型可以通過新聞和社交媒體的情感分析,來判斷市場情緒,並根據外部因素預測股票價格變化。

8. 注意事項

結合多種演算法和外部數據(例如經濟指標、公司基本面分析),通常能產生最有效的 AI 股票價格預測模型。



指標與操作策略

在使用 AI 進行股票價格預測時,模型會生成多種指標來幫助投資者做出決策。這些指標可以用來判斷市場走向,並根據不同的情境採取相應的交易操作。以下是一些常見的預測指標及其操作策略:

1. 預測價格

這是模型直接預測的未來股票價格數值。

2. 漲跌概率

模型可能會預測股票價格上漲或下跌的概率。

3. 趨勢信號

模型可能會基於技術指標(如移動平均線)預測股票的趨勢方向。

4. 超買/超賣信號

技術指標如 RSI(相對強弱指數)可以用來判斷股票是否處於超買或超賣狀態。

5. 波動性

模型可以預測股票未來的價格波動區間。

6. 買賣強度

基於市場買賣雙方的強度預測。

7. 止損與止盈點

模型可能會根據歷史數據建議合理的止損與止盈點。

總結

根據不同的預測指標,投資者可以做出相應的交易決策,如買入、賣出或保持觀望。綜合多種指標有助於在不同的市場情境下做出更合理的投資決策。



輪動指標程式

在眾多輪動判斷指標中,並非所有指標都具備同等的預測能力。根據近年(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失真;而散戶透過社群媒體的群體行為也讓傳統情緒指標的訊號品質降低。

跨市場比較的方法論

進行不同市場間的輪動比較時,需要建立可比較的標準化框架:

相對強弱比較法(Relative Strength)

將兩個市場或板塊的價格做比值,觀察比值的趨勢方向。例如將「MSCI新興市場指數 / MSCI已開發市場指數」繪成曲線,比值上升代表新興市場跑贏。這個方法可套用在任何兩個可比較的資產上:

Z-Score標準化法

將不同市場的指標統一轉換為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建立自動化監測系統的完整架構與程式範例。

資料來源與對應的API

資料類型 免費來源 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)

實務建議

程式化監測的核心價值不在於取代人為判斷,而在於消除情緒干擾並確保紀律性。以下幾點在建置系統時需特別注意:

  1. 單一指標的勝率大約在55%至65%之間,必須多指標交叉驗證才能提升可靠度至70%以上。
  2. FRED API每日有120次呼叫上限(免費版),建議將取得的資料存入本地SQLite或CSV,避免重複請求。
  3. yfinance並非官方API,偶爾會因Yahoo改版而失效,建議加入try-except與備用來源(如FinMind for台股)。
  4. 所有指標都有適用的時間框架,殖利率曲線適合判斷中長期(6個月以上),板塊動能適合短中期(1至3個月),混用時需注意時間尺度的一致性。
  5. 建議每週產出一次完整報告,每日僅監測異常變動(如利差單日擴大超過20bp),避免過度交易。


Python yfinance 套件

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")

回傳的 DataFrame 結構

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即可。



交易市場的資料庫設計

1. 資料庫結構

erDiagram User { int UserID string Username string Password string Email datetime CreatedAt } Product { int ProductID string ProductName decimal Price int StockQuantity int SellerID } Order { int OrderID int BuyerID datetime OrderDate decimal TotalAmount } OrderItem { int OrderItemID int OrderID int ProductID int Quantity decimal Subtotal } Payment { int PaymentID int OrderID datetime PaymentDate decimal Amount string PaymentMethod } User ||--o{ Product : sells User ||--o{ Order : places Product ||--o{ OrderItem : is_included_in Order ||--o{ OrderItem : contains Order ||--o| Payment : is_paid_by

2. 關係說明



公開交易市場的資料庫設計

1. 資料庫結構

erDiagram Asset { int AssetID string AssetName string AssetType string BaseAsset string QuoteAsset decimal CurrentPrice datetime LastUpdated } MarketData { int MarketDataID int AssetID decimal OpeningPrice decimal ClosingPrice decimal HighPrice decimal LowPrice bigint Volume datetime DataDate } OrderBook { int OrderBookID int AssetID decimal PriceLevel int BuyVolume int SellVolume datetime SnapshotTime } HistoricalTrade { int TradeID int AssetID decimal TradePrice int TradeVolume datetime TradeTime } Asset ||--o{ MarketData : "has" Asset ||--o{ OrderBook : "has" Asset ||--o{ HistoricalTrade : "has"

2. 關係說明

3. 關鍵功能



MetaQuotes Language (MQL)

語言概述

MetaQuotes Language(簡稱 MQL)是一種專為金融市場交易開發的程式語言,用於在 MetaTrader 平台(如 MT4 和 MT5)中創建自動交易策略(Expert Advisors)、自定指標、腳本及函數庫。

MQL4 與 MQL5

應用類型

語法特色

簡單範例:MQL4 的 EA

// 每次新 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;
}

簡單範例:MQL5 的指標

#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 是為交易自動化而生的專業語言,無論是初學者還是專業量化交易者,都能利用其強大功能實現精細交易策略。



TradingView 小工具

進階圖表小工具 (Advanced Real-Time Chart)

這是功能最完整的版本,包含多種指標、畫圖工具及完整交易介面(如果連接經紀商)。

<!-- 進階圖表容器 -->
<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>

技術分析小工具 (Technical Analysis)

此工具以儀表板形式呈現,根據多種技術指標(如移動平均線、振盪指標)自動計算並顯示買入或賣出的建議。

<!-- 技術分析小工具 -->
<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>

市場概覽小工具 (Market Overview)

適用於顯示多個商品的即時價格對比,常見於財經網站的首頁側邊欄。

<!-- 市場概覽 -->
<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 與 Client 介紹

Binance 是一個全球領先的加密貨幣交易所,為開發者提供豐富的 API 支援,包括 Spot APIClient API,方便使用者進行自動交易和數據獲取。

Binance Spot API

Binance Spot API 是 Binance 為現貨市場交易者設計的 API,可用於查詢市場資訊、下單、取消訂單等操作。此 API 常用於設計交易機器人、自動交易策略和監控市場波動。

主要功能

Binance Client API

Binance Client API 提供一個便捷的方式來存取 Binance 的各種 API 方法。開發者可以使用 binance.client 庫進行 API 認證和管理,並便捷地調用各種現貨和合約市場的功能。

Client API 的主要功能

如何使用 Binance Spot 與 Client API

  1. 首先,需在 Binance 申請 API Key 和 Secret Key,並妥善保管。
  2. 安裝 Binance API 的 Python SDK:pip install binance
  3. 使用 binance.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 API

說明

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()

查詢 K 線資料


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()

需要簽名的私有 API

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()

補充



Bybit 取得特定類型交易對

說明

Pionex 使用 /api/v1/common/symbols?type=PERP 來取得「永續合約」交易對;在 Bybit,可使用 /v5/market/instruments-info 並指定 category=linear(USDT 永續)或 inverse(反向合約)達到同樣效果。

Python 範例


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")

參數對照表

PionexBybit說明
type=PERPcategory=linearUSDT 永續合約
type=SPOTcategory=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"
        }
      }
    ]
  }
}

補充



Bybit REST API 查詢 K 線資料

說明

在 Pionex 中可使用 /api/v1/market/klines 查行情;Bybit 對應的端點是 /v5/market/kline。透過 category 指定市場類型(例如 linear 表示 USDT 永續合約),並可傳入 symbolintervallimitendTime 等參數。

Python 範例函式


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)
      ]
    ]
  }
}

補充



加速批量取得 K 線

說明

下面是一個可直接複製的 Python 範例,採用 ThreadPoolExecutor 並內建重試、速率限制與快取(cache)。流程:先從快取載入已抓到的 K 線(若有),只對缺少或不足的交易對發出請求;使用 thread pool 同時執行多請求並以 semaphore 控制並發數避免被限流;遇到失敗會 exponential backoff 重試。

程式碼(Bybit /v5/market/kline 範例)


# 需求: 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])

注意事項與最佳實務



Pionex API

簡介

Pionex 提供官方 API,讓開發者能透過程式自動化交易、查詢市場數據、管理帳戶資產。API 支援 REST 與 WebSocket 兩種方式。

申請 API Key

  1. 登入 Pionex 帳號
  2. 進入 API 管理 頁面
  3. 建立新的 API Key,設定權限(讀取、交易、提幣等)
  4. 記下 API KeySecret,僅顯示一次

REST API 範例 (Node.js)


// 使用 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();

REST API 範例 (Python)


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()

WebSocket 範例 (Node.js)


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());
});

WebSocket 範例 (Python)


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()

常用功能

注意事項



Pionex REST API 取得交易對清單

API 說明

可使用 GET /api/v1/common/symbols 來取得 Pionex 所有支援的交易對與詳細屬性,例如最小下單量、價格精度、交易類型(現貨或合約)等。

HTTP 請求


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
    }
  ]
}

Python 範例


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"]]

用途



解析 Pionex 回傳格式

說明

以下程式會呼叫 https://api.pionex.com/api/v1/common/symbols,自動印出回傳 JSON 的結構(key 與資料型態),方便了解實際格式。

Python 範例


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

補充



Pionex REST API Get Klines

API 說明

取得指定交易對的 K 線(Candlestick / OHLCV)數據,來源來自 Pionex 公開市場資料。

GET /api/v1/market/klines

請求參數

參數型別是否必需說明
symbolstring交易對 (例:BTC_USDT 或 BTC_USDT.PERP)
intervalstring時間間隔,例如 1M、5M、15M、30M、60M、4H、8H、12H、1D
endTimenumber (毫秒)結束時間(毫秒時間戳)
limitnumber取得資料數量,預設 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
}

Python 範例


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 REST API 查詢支援合約網格交易對

說明

Pionex 並沒有單獨一個 「取得支援網格交易對」 的專用 API,但可以透過 GET /api/v1/market/tickers 取得所有交易對,再從中篩選出 .PERP 類型(USDT 永續合約),即可得到 Futures Grid 支援的交易對清單。

Python 範例程式


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
...

補充



Max Coin API

什麼是 Max Coin API?

Max Coin API 是由 Max Exchange 提供的一套應用程式介面,允許開發者程式化地訪問其加密貨幣交易功能。開發者可以透過 API 自動化執行交易、檢索市場數據以及管理資產。

如何使用 Max Coin API?

  1. 註冊 Max 帳戶:訪問 Max 官方網站 並註冊帳戶。
  2. 取得 API 密鑰:登入後,前往帳戶設置,生成新的 API 密鑰並設定所需的權限。
  3. 參考 API 文件:閱讀官方提供的 API 文件,瞭解每個端點的功能和用法。

API 支援的主要功能

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)
    

使用 Max Coin API 的注意事項

相關資源



比特幣 PoW 記帳流程

分散式記帳的核心

比特幣使用 工作量證明(Proof of Work, PoW) 作為共識機制,以實現去中心化的記帳系統。PoW 的核心目標是讓節點透過競爭解數學難題來決定誰擁有記帳權,確保資料無法被任意竄改。

交易需求的產生與傳播

交易的選擇優先順序

礦工會根據以下條件優先挑選交易,以提高成功打包區塊並賺取手續費的機會:

打包區塊與競爭記帳權

驗證與鏈的選擇

區塊限制與產生頻率

記帳擁堵與解決方案

當交易量過大時,出現擁堵與手續費上升的情況。為改善此問題,提出多種擴展解決方案:



BTC 區塊的資料結構

區塊主要結構

欄位名稱 大小(位元組) 說明
block size 4 整個區塊(含 header 與所有交易資料)的總大小(以 byte 為單位)
block header 80 區塊的標頭資訊,用來做驗證與連結前後區塊
transaction counter 1 ~ 9 交易數量,以變長整數(VarInt)表示本區塊內有幾筆交易
transactions 可變 所有實際的交易資料,每一筆交易包含輸入與輸出

區塊頭(Block Header)

長度固定為 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 為了找到合法區塊哈希的變動值

交易數量(transaction counter)

使用 VarInt(變長整數)格式,表示區塊中有多少筆交易:

交易資料(transactions)

每一筆交易資料包含以下主要部分(長度可變):

第一筆交易通常是 coinbase 交易,也就是礦工領取區塊獎勵的特殊交易,不包含輸入。



交易需求的產生與傳播流程實作

程式簡介

以下範例以 Python 模擬用戶發送交易、節點進行廣播,以及礦工挑選交易並打包至區塊的簡化流程。此模擬未涵蓋密碼學簽章與完整區塊鏈實作,僅針對「交易→廣播→打包」的邏輯操作。

主要流程

Python 程式碼

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 VM 寫程式

1. 什麼是 Ethereum VM

Ethereum 虛擬機(Ethereum Virtual Machine,簡稱 EVM)是以太坊的核心組件,負責執行智能合約。EVM 提供了一個沙箱環境,允許開發者在上面運行代碼,而不需要擔心會影響到以太坊網絡的其他部分。

2. 智能合約與 EVM

智能合約是自動執行、不可更改的合約,執行時由 EVM 處理。開發者通常使用 Solidity 等高級編程語言來撰寫智能合約,然後將其編譯成 EVM 可理解的字節碼。

3. EVM 編程語言:Solidity

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,以及設置和獲取該數據的函數。

4. EVM 的運作原理

當用戶在以太坊網絡上執行一個智能合約時,以下步驟會發生:

5. EVM 的計算資源與 Gas

EVM 的運算資源是有限的,為了防止網絡濫用,EVM 使用 Gas 機制來計算和收取交易費用。每個操作都有其相應的 Gas 成本,用戶在提交交易時需要提供足夠的 Gas 來支付執行智能合約所需的計算資源。

6. 總結

EVM 是以太坊網絡的核心,提供了一個強大的環境來運行智能合約。通過使用 Solidity 等編程語言,開發者可以創建各種去中心化應用(dApps),並利用 EVM 的功能來實現複雜的邏輯運算和交易處理。



EVM部署流程

準備工作

編寫合約

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

部署到測試網(例如 Goerli)


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代幣,具備借貸、儲蓄、清算等核心功能。

主要功能

智能合約範例(Solidity)


// 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 Contract

簡介

BSC (Binance Smart Chain) 是一條相容於 EVM (Ethereum Virtual Machine) 的公鏈,因此在以太坊上編寫的 Solidity 智能合約幾乎可以直接部署到 BSC。主要差異在於部署時連接的網路與 Gas 費以 BNB 計價。

合約範例 (Solidity)


// 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;
});

部署方法

  1. 安裝相依套件:
    npm install --save-dev hardhat @nomiclabs/hardhat-ethers ethers
  2. 啟動部署:
    npx hardhat run scripts/deploy.js --network bscTestnet
  3. 確認合約地址後,可以到 BscScan 測試網BscScan 主網 查詢合約。

注意事項



股市程式開發

股票漲跌概率的實作

使用 Python 和隨機森林模型來預測股票的漲跌概率。此範例利用 Yahoo 財經的股票數據,並通過技術指標來訓練模型,最後輸出股票上漲和下跌的概率。

步驟 1: 安裝與匯入必要的套件

首先,我們需要安裝並匯入 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
    

步驟 2: 下載股票數據並生成技術指標

接下來,我們從 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)
    

步驟 3: 準備訓練和測試數據集

我們將使用移動平均線 (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)

步驟 4: 使用隨機森林模型進行訓練與預測

我們使用隨機森林模型來訓練數據,並預測測試集中股票的漲跌概率。

# 初始化隨機森林分類器 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) # 獲取漲跌的概率

步驟 5: 計算模型準確率與顯示漲跌概率

我們可以計算模型的準確率,並顯示每一天的漲跌概率。

# 計算模型準確率 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}")

步驟 6: 根據漲跌概率進行交易決策

根據上漲的概率,您可以設定一個閾值來決定是否進行買入操作。例如,如果上漲概率超過 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 搭配 requestsBeautifulSoup,即可抓取頁面上的公開申購資料。

範例程式碼

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("無法連接到公開申購公告頁面")

注意事項



外匯程式開發

取得美元對台幣匯率

方法一:使用 CurrencyAPI

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

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金鑰'。

方法三:使用 forex-python 套件

若不想直接調用 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

注意事項



使用爬蟲從 Currency.Wiki 取得美元對台幣匯率

前言

若不使用 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]
T:0000
資訊與搜尋 | 回dev首頁
email: Yan Sa [email protected] Line: 阿央
電話: 02-27566655 ,03-5924828
阿央
泱泱科技
捷昱科技泱泱企業