Technical Analysis คืออะไร
Technical Analysis เป็นการวิเคราะห์การเคลื่อนไหวของราคาและปริมาณการซื้อขาย (volume) เพื่อคาดการณ์ทิศทางราคาในอนาคต ใช้ chart patterns, indicators และ statistical methods แทนการวิเคราะห์ปัจจัยพื้นฐาน (fundamental analysis)
หลักการสำคัญของ Technical Analysis ได้แก่ Price discounts everything ราคาสะท้อนข้อมูลทั้งหมดแล้ว, Prices move in trends ราคาเคลื่อนไหวเป็นแนวโน้ม, History tends to repeat itself รูปแบบราคาในอดีตมักเกิดซ้ำ เครื่องมือหลัก ได้แก่ Trend lines และ channels, Support และ Resistance levels, Moving Averages (SMA, EMA), Oscillators (RSI, MACD, Stochastic), Volume analysis, Chart patterns (Head and Shoulders, Double Top/Bottom, Triangles) และ Candlestick patterns
สำหรับ developers การเข้าใจ Technical Analysis ช่วยในการสร้าง automated trading systems, backtesting frameworks, charting libraries, signal generation engines และ risk management tools
หนังสือ Technical Analysis ที่ดีที่สุด
รายชื่อหนังสือที่แนะนำสำหรับเรียน Technical Analysis ตั้งแต่พื้นฐานจนถึงขั้นสูง โดยแบ่งตามระดับ
สำหรับผู้เริ่มต้น Technical Analysis of the Financial Markets โดย John J. Murphy เป็นหนังสือ classic ที่ครอบคลุมทุกด้านของ TA ตั้งแต่ chart patterns, indicators, intermarket analysis เหมาะเป็นหนังสือเล่มแรก Japanese Candlestick Charting Techniques โดย Steve Nison เป็นหนังสือที่แนะนำ candlestick patterns อย่างละเอียด เป็นคนแรกที่นำ candlestick จากญี่ปุ่นมาเผยแพร่ในตะวันตก
สำหรับระดับกลาง Trading for a Living โดย Dr. Alexander Elder ครอบคลุมทั้ง psychology, trading methods และ money management ใช้ Triple Screen Trading System Encyclopedia of Chart Patterns โดย Thomas Bulkowski รวม chart patterns ทั้งหมดพร้อมสถิติ success rate จากข้อมูลจริง
สำหรับระดับสูง Technical Analysis Using Multiple Timeframes โดย Brian Shannon วิเคราะห์หลาย timeframes พร้อมกัน Quantitative Technical Analysis โดย Howard Bandy ใช้ statistics และ programming สำหรับ systematic trading Evidence-Based Technical Analysis โดย David Aronson ใช้ scientific method ทดสอบ TA methods
สร้าง Technical Analysis Tools ด้วย Python
เครื่องมือวิเคราะห์ทางเทคนิค
#!/usr/bin/env python3
# technical_analysis.py — Technical Analysis Library
import json
import math
import logging
from typing import List, Dict, Optional, Tuple
from dataclasses import dataclass
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("ta")
@dataclass
class OHLCV:
timestamp: str
open: float
high: float
low: float
close: float
volume: float
class TechnicalIndicators:
@staticmethod
def sma(prices: List[float], period: int) -> List[Optional[float]]:
"""Simple Moving Average"""
result = [None] * (period - 1)
for i in range(period - 1, len(prices)):
window = prices[i - period + 1:i + 1]
result.append(round(sum(window) / period, 4))
return result
@staticmethod
def ema(prices: List[float], period: int) -> List[Optional[float]]:
"""Exponential Moving Average"""
multiplier = 2 / (period + 1)
result = [None] * (period - 1)
# First EMA = SMA
first_sma = sum(prices[:period]) / period
result.append(round(first_sma, 4))
for i in range(period, len(prices)):
ema_val = (prices[i] - result[-1]) * multiplier + result[-1]
result.append(round(ema_val, 4))
return result
@staticmethod
def rsi(prices: List[float], period: int = 14) -> List[Optional[float]]:
"""Relative Strength Index"""
if len(prices) < period + 1:
return [None] * len(prices)
changes = [prices[i] - prices[i-1] for i in range(1, len(prices))]
gains = [max(c, 0) for c in changes]
losses = [abs(min(c, 0)) for c in changes]
result = [None] * period
avg_gain = sum(gains[:period]) / period
avg_loss = sum(losses[:period]) / period
if avg_loss == 0:
result.append(100.0)
else:
rs = avg_gain / avg_loss
result.append(round(100 - (100 / (1 + rs)), 2))
for i in range(period, len(changes)):
avg_gain = (avg_gain * (period - 1) + gains[i]) / period
avg_loss = (avg_loss * (period - 1) + losses[i]) / period
if avg_loss == 0:
result.append(100.0)
else:
rs = avg_gain / avg_loss
result.append(round(100 - (100 / (1 + rs)), 2))
return result
@staticmethod
def macd(prices: List[float], fast=12, slow=26, signal=9):
"""MACD (Moving Average Convergence Divergence)"""
ema_fast = TechnicalIndicators.ema(prices, fast)
ema_slow = TechnicalIndicators.ema(prices, slow)
macd_line = []
for f, s in zip(ema_fast, ema_slow):
if f is not None and s is not None:
macd_line.append(round(f - s, 4))
else:
macd_line.append(None)
valid_macd = [v for v in macd_line if v is not None]
signal_line_raw = TechnicalIndicators.ema(valid_macd, signal)
signal_line = [None] * (len(macd_line) - len(signal_line_raw)) + signal_line_raw
histogram = []
for m, s in zip(macd_line, signal_line):
if m is not None and s is not None:
histogram.append(round(m - s, 4))
else:
histogram.append(None)
return {
"macd": macd_line,
"signal": signal_line,
"histogram": histogram,
}
@staticmethod
def bollinger_bands(prices: List[float], period=20, std_dev=2):
"""Bollinger Bands"""
sma = TechnicalIndicators.sma(prices, period)
upper = []
lower = []
for i in range(len(prices)):
if sma[i] is None:
upper.append(None)
lower.append(None)
else:
window = prices[max(0, i - period + 1):i + 1]
mean = sum(window) / len(window)
variance = sum((x - mean) ** 2 for x in window) / len(window)
std = math.sqrt(variance)
upper.append(round(sma[i] + std_dev * std, 4))
lower.append(round(sma[i] - std_dev * std, 4))
return {"upper": upper, "middle": sma, "lower": lower}
@staticmethod
def support_resistance(prices: List[float], window=20):
"""Find support and resistance levels"""
levels = []
for i in range(window, len(prices) - window):
# Local maximum (resistance)
if prices[i] == max(prices[i-window:i+window+1]):
levels.append({"type": "resistance", "price": prices[i], "index": i})
# Local minimum (support)
if prices[i] == min(prices[i-window:i+window+1]):
levels.append({"type": "support", "price": prices[i], "index": i})
return levels
# Example usage
import random
random.seed(42)
prices = [100]
for _ in range(99):
prices.append(round(prices[-1] * (1 + random.gauss(0.0005, 0.02)), 2))
ta = TechnicalIndicators()
print("SMA(20):", ta.sma(prices, 20)[-5:])
print("EMA(12):", ta.ema(prices, 12)[-5:])
print("RSI(14):", ta.rsi(prices, 14)[-5:])
print("MACD:", {k: [v for v in vals[-3:] if v] for k, vals in ta.macd(prices).items()})
print("Bollinger:", {k: [v for v in vals[-3:] if v] for k, vals in ta.bollinger_bands(prices).items()})
Backtesting Strategies จากหนังสือ
ทดสอบกลยุทธ์จากหนังสือ
#!/usr/bin/env python3
# backtest_strategies.py — Backtest Classic TA Strategies
import json
import math
import random
import logging
from typing import List, Dict
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("backtest")
class SimpleBacktester:
def __init__(self, initial_capital=100000):
self.initial_capital = initial_capital
self.capital = initial_capital
self.position = 0
self.trades = []
self.equity_curve = [initial_capital]
def buy(self, price, size=None):
if self.position > 0:
return
if size is None:
size = int(self.capital * 0.95 / price)
cost = size * price
if cost > self.capital:
return
self.position = size
self.capital -= cost
self.trades.append({"type": "buy", "price": price, "size": size})
def sell(self, price):
if self.position <= 0:
return
revenue = self.position * price
self.capital += revenue
self.trades.append({"type": "sell", "price": price, "size": self.position, "pnl": revenue - self.trades[-1]["price"] * self.position})
self.position = 0
def get_equity(self, current_price):
return self.capital + self.position * current_price
def get_results(self, final_price):
if self.position > 0:
self.sell(final_price)
total_return = (self.capital - self.initial_capital) / self.initial_capital * 100
wins = [t for t in self.trades if t.get("pnl", 0) > 0]
losses = [t for t in self.trades if t.get("pnl", 0) < 0]
# Max drawdown
peak = self.equity_curve[0]
max_dd = 0
for eq in self.equity_curve:
if eq > peak:
peak = eq
dd = (peak - eq) / peak * 100
max_dd = max(max_dd, dd)
sell_trades = [t for t in self.trades if t["type"] == "sell"]
return {
"initial_capital": self.initial_capital,
"final_capital": round(self.capital, 2),
"total_return_pct": round(total_return, 2),
"total_trades": len(sell_trades),
"winning_trades": len(wins),
"losing_trades": len(losses),
"win_rate_pct": round(len(wins) / max(len(sell_trades), 1) * 100, 1),
"max_drawdown_pct": round(max_dd, 2),
}
def generate_prices(start=100, days=500, seed=42):
random.seed(seed)
prices = [start]
for _ in range(days - 1):
change = random.gauss(0.0003, 0.015)
prices.append(round(prices[-1] * (1 + change), 2))
return prices
def sma_crossover_strategy(prices, fast=10, slow=30):
"""Golden Cross / Death Cross strategy from Murphy's book"""
bt = SimpleBacktester()
for i in range(slow, len(prices)):
fast_sma = sum(prices[i-fast:i]) / fast
slow_sma = sum(prices[i-slow:i]) / slow
prev_fast = sum(prices[i-fast-1:i-1]) / fast
prev_slow = sum(prices[i-slow-1:i-1]) / slow
# Golden Cross: fast crosses above slow
if prev_fast <= prev_slow and fast_sma > slow_sma:
bt.buy(prices[i])
# Death Cross: fast crosses below slow
elif prev_fast >= prev_slow and fast_sma < slow_sma:
bt.sell(prices[i])
bt.equity_curve.append(bt.get_equity(prices[i]))
return bt.get_results(prices[-1])
def rsi_strategy(prices, period=14, oversold=30, overbought=70):
"""RSI strategy from Elder's book"""
bt = SimpleBacktester()
changes = [prices[i] - prices[i-1] for i in range(1, len(prices))]
for i in range(period + 1, len(prices)):
window = changes[i-period:i]
gains = [max(c, 0) for c in window]
losses_ = [abs(min(c, 0)) for c in window]
avg_gain = sum(gains) / period
avg_loss = sum(losses_) / period
if avg_loss == 0:
rsi = 100
else:
rs = avg_gain / avg_loss
rsi = 100 - (100 / (1 + rs))
if rsi < oversold:
bt.buy(prices[i])
elif rsi > overbought:
bt.sell(prices[i])
bt.equity_curve.append(bt.get_equity(prices[i]))
return bt.get_results(prices[-1])
def bollinger_bounce_strategy(prices, period=20, std_dev=2):
"""Bollinger Bands bounce strategy"""
bt = SimpleBacktester()
for i in range(period, len(prices)):
window = prices[i-period:i]
sma = sum(window) / period
std = math.sqrt(sum((x - sma) ** 2 for x in window) / period)
upper = sma + std_dev * std
lower = sma - std_dev * std
if prices[i] <= lower:
bt.buy(prices[i])
elif prices[i] >= upper:
bt.sell(prices[i])
bt.equity_curve.append(bt.get_equity(prices[i]))
return bt.get_results(prices[-1])
# Run backtests
prices = generate_prices(100, 500)
strategies = {
"SMA Crossover (10/30)": sma_crossover_strategy(prices, 10, 30),
"RSI (14, 30/70)": rsi_strategy(prices),
"Bollinger Bounce (20, 2)": bollinger_bounce_strategy(prices),
}
print("=== Backtest Results ===")
for name, result in strategies.items():
print(f"\n{name}:")
print(json.dumps(result, indent=2))
Automated Chart Pattern Recognition
ระบบตรวจจับ chart patterns อัตโนมัติ
#!/usr/bin/env python3
# pattern_recognition.py — Chart Pattern Detection
import json
import logging
from typing import List, Dict, Tuple, Optional
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("patterns")
class ChartPatternDetector:
def __init__(self, prices: List[float]):
self.prices = prices
self.pivots = self._find_pivots()
def _find_pivots(self, window=5):
pivots = []
for i in range(window, len(self.prices) - window):
if self.prices[i] == max(self.prices[i-window:i+window+1]):
pivots.append({"type": "high", "index": i, "price": self.prices[i]})
elif self.prices[i] == min(self.prices[i-window:i+window+1]):
pivots.append({"type": "low", "index": i, "price": self.prices[i]})
return pivots
def detect_double_top(self, tolerance=0.02):
"""Detect Double Top pattern (bearish reversal)"""
patterns = []
highs = [p for p in self.pivots if p["type"] == "high"]
for i in range(len(highs) - 1):
h1, h2 = highs[i], highs[i + 1]
price_diff = abs(h1["price"] - h2["price"]) / h1["price"]
if price_diff < tolerance and h2["index"] - h1["index"] > 10:
# Find neckline (lowest point between the two tops)
between = self.prices[h1["index"]:h2["index"]+1]
neckline = min(between)
patterns.append({
"pattern": "double_top",
"signal": "bearish",
"top1": {"index": h1["index"], "price": h1["price"]},
"top2": {"index": h2["index"], "price": h2["price"]},
"neckline": round(neckline, 2),
"target": round(neckline - (h1["price"] - neckline), 2),
})
return patterns
def detect_double_bottom(self, tolerance=0.02):
"""Detect Double Bottom pattern (bullish reversal)"""
patterns = []
lows = [p for p in self.pivots if p["type"] == "low"]
for i in range(len(lows) - 1):
l1, l2 = lows[i], lows[i + 1]
price_diff = abs(l1["price"] - l2["price"]) / l1["price"]
if price_diff < tolerance and l2["index"] - l1["index"] > 10:
between = self.prices[l1["index"]:l2["index"]+1]
neckline = max(between)
patterns.append({
"pattern": "double_bottom",
"signal": "bullish",
"bottom1": {"index": l1["index"], "price": l1["price"]},
"bottom2": {"index": l2["index"], "price": l2["price"]},
"neckline": round(neckline, 2),
"target": round(neckline + (neckline - l1["price"]), 2),
})
return patterns
def detect_head_shoulders(self, tolerance=0.03):
"""Detect Head and Shoulders pattern (bearish reversal)"""
patterns = []
highs = [p for p in self.pivots if p["type"] == "high"]
for i in range(len(highs) - 2):
left, head, right = highs[i], highs[i+1], highs[i+2]
# Head must be highest
if head["price"] <= left["price"] or head["price"] <= right["price"]:
continue
# Shoulders should be roughly equal
shoulder_diff = abs(left["price"] - right["price"]) / left["price"]
if shoulder_diff > tolerance:
continue
# Find neckline
lows_between = [p for p in self.pivots
if p["type"] == "low"
and left["index"] < p["index"] < right["index"]]
if len(lows_between) >= 2:
neckline = (lows_between[0]["price"] + lows_between[-1]["price"]) / 2
patterns.append({
"pattern": "head_and_shoulders",
"signal": "bearish",
"left_shoulder": {"index": left["index"], "price": left["price"]},
"head": {"index": head["index"], "price": head["price"]},
"right_shoulder": {"index": right["index"], "price": right["price"]},
"neckline": round(neckline, 2),
"target": round(neckline - (head["price"] - neckline), 2),
})
return patterns
def detect_trend(self, period=50):
"""Detect current trend using moving average"""
if len(self.prices) < period:
return "unknown"
current = self.prices[-1]
sma = sum(self.prices[-period:]) / period
slope_prices = self.prices[-period:]
first_half = sum(slope_prices[:period//2]) / (period//2)
second_half = sum(slope_prices[period//2:]) / (period//2)
if current > sma and second_half > first_half:
return "uptrend"
elif current < sma and second_half < first_half:
return "downtrend"
else:
return "sideways"
def scan_all_patterns(self):
results = {
"trend": self.detect_trend(),
"double_tops": self.detect_double_top(),
"double_bottoms": self.detect_double_bottom(),
"head_shoulders": self.detect_head_shoulders(),
"pivots_found": len(self.pivots),
}
total_patterns = (
len(results["double_tops"]) +
len(results["double_bottoms"]) +
len(results["head_shoulders"])
)
results["total_patterns"] = total_patterns
return results
# Generate sample data and scan
import random
random.seed(123)
prices = [100]
for _ in range(299):
prices.append(round(prices[-1] * (1 + random.gauss(0, 0.02)), 2))
detector = ChartPatternDetector(prices)
patterns = detector.scan_all_patterns()
print(json.dumps(patterns, indent=2))
สร้าง Trading Dashboard
Dashboard สำหรับ Technical Analysis
# === Trading Dashboard Architecture ===
# 1. Data Pipeline
# ===================================
# Real-time price data -> Technical indicators -> Signal generation -> Dashboard
# Data sources:
# - Yahoo Finance API (free, delayed)
# - Alpha Vantage API (free tier: 5 calls/min)
# - Binance API (free, real-time crypto)
# - Interactive Brokers API (requires account)
# pip install yfinance pandas ta-lib plotly dash
# 2. Quick Data Fetch Script
# ===================================
#!/usr/bin/env python3
# fetch_data.py
import json
from datetime import datetime
# Using yfinance (pip install yfinance)
# import yfinance as yf
#
# ticker = yf.Ticker("AAPL")
# df = ticker.history(period="1y")
#
# # Calculate indicators
# df['SMA_20'] = df['Close'].rolling(20).mean()
# df['SMA_50'] = df['Close'].rolling(50).mean()
# df['RSI'] = calculate_rsi(df['Close'], 14)
#
# # Generate signals
# df['Signal'] = 'hold'
# df.loc[df['SMA_20'] > df['SMA_50'], 'Signal'] = 'buy'
# df.loc[df['SMA_20'] < df['SMA_50'], 'Signal'] = 'sell'
# 3. Dashboard with Plotly Dash
# ===================================
# app.py
#
# import dash
# from dash import dcc, html
# import plotly.graph_objects as go
# from plotly.subplots import make_subplots
#
# app = dash.Dash(__name__)
#
# fig = make_subplots(
# rows=3, cols=1,
# shared_xaxes=True,
# vertical_spacing=0.03,
# row_heights=[0.6, 0.2, 0.2],
# subplot_titles=('Price + MA', 'Volume', 'RSI'),
# )
#
# # Candlestick chart
# fig.add_trace(go.Candlestick(
# x=df.index, open=df['Open'], high=df['High'],
# low=df['Low'], close=df['Close'], name='Price',
# ), row=1, col=1)
#
# # Moving averages
# fig.add_trace(go.Scatter(
# x=df.index, y=df['SMA_20'], name='SMA 20',
# line=dict(color='orange', width=1),
# ), row=1, col=1)
#
# fig.add_trace(go.Scatter(
# x=df.index, y=df['SMA_50'], name='SMA 50',
# line=dict(color='blue', width=1),
# ), row=1, col=1)
#
# # Volume
# fig.add_trace(go.Bar(
# x=df.index, y=df['Volume'], name='Volume',
# ), row=2, col=1)
#
# # RSI
# fig.add_trace(go.Scatter(
# x=df.index, y=df['RSI'], name='RSI',
# line=dict(color='purple'),
# ), row=3, col=1)
#
# fig.add_hline(y=70, line_dash="dash", row=3, col=1)
# fig.add_hline(y=30, line_dash="dash", row=3, col=1)
#
# fig.update_layout(
# height=800, template='plotly_dark',
# xaxis_rangeslider_visible=False,
# )
#
# app.layout = html.Div([
# html.H1('Technical Analysis Dashboard'),
# dcc.Graph(figure=fig),
# ])
#
# app.run_server(debug=True, port=8050)
# 4. Alert System
# ===================================
# Send alerts when signals trigger
#
# def check_signals(df):
# latest = df.iloc[-1]
# alerts = []
#
# if latest['RSI'] < 30:
# alerts.append(f"RSI oversold: {latest['RSI']:.1f}")
# elif latest['RSI'] > 70:
# alerts.append(f"RSI overbought: {latest['RSI']:.1f}")
#
# if latest['Close'] < latest['BB_Lower']:
# alerts.append("Price below lower Bollinger Band")
# elif latest['Close'] > latest['BB_Upper']:
# alerts.append("Price above upper Bollinger Band")
#
# return alerts
echo "Trading dashboard documented"
FAQ คำถามที่พบบ่อย
Q: Technical Analysis ใช้ได้จริงไหม?
A: มีงานวิจัยทั้งสนับสนุนและคัดค้าน TA ไม่ได้ predict อนาคตได้ 100% แต่ช่วยระบุ probabilities และ manage risk TA ทำงานได้ดีใน trending markets แต่อาจให้ false signals ใน sideways markets ที่สำคัญคือ money management และ risk management ไม่ใช่แค่ entry signals นักเทรดที่ประสบความสำเร็จใช้ TA ร่วมกับ risk management ที่เข้มงวด ไม่ใช่ใช้ TA อย่างเดียว
Q: ควรเริ่มอ่านหนังสือเล่มไหนัก่อน?
A: เริ่มจาก Technical Analysis of the Financial Markets โดย John Murphy เป็นเล่มแรก เพราะครอบคลุมทุกพื้นฐาน อ่านง่าย มีภาพประกอบมาก จากนั้นอ่าน Japanese Candlestick Charting Techniques เพื่อเรียน candlestick patterns จากนั้น Trading for a Living เพื่อเรียน psychology และ money management สำหรับ developers ที่ต้องการ quantitative approach อ่าน Quantitative Technical Analysis โดย Howard Bandy
Q: Indicator ไหนสำคัญที่สุด?
A: ไม่มี indicator ที่ดีที่สุดสำหรับทุกสถานการณ์ แนะนำใช้ combination Moving Averages (SMA/EMA) สำหรับ trend identification, RSI หรือ Stochastic สำหรับ overbought/oversold, MACD สำหรับ momentum และ trend changes, Volume สำหรับ confirm signals, Bollinger Bands สำหรับ volatility อย่าใช้ indicators มากเกินไป (indicator overload) 3-4 indicators ที่ complement กันเพียงพอ
Q: Backtesting สำคัญแค่ไหน?
A: สำคัญมากก่อน trade ด้วยเงินจริง backtesting ช่วยให้เห็นว่ากลยุทธ์ทำงานอย่างไรในอดีต ข้อควรระวัง overfitting (optimize จนดีกับข้อมูลอดีตแต่แย่กับอนาคต), survivorship bias, look-ahead bias (ใช้ข้อมูลอนาคตใน backtesting) ใช้ out-of-sample testing (แบ่งข้อมูลเป็น training/testing) และ walk-forward analysis เสมอ backtesting ที่ดีไม่ได้รับประกันผลในอนาคต แต่กลยุทธ์ที่ fail ใน backtest มักจะ fail ในจริงด้วย
