Support and Resistance for Stocks — คู่มือฉบับสมบูรณ์
Support และ Resistance เป็นแนวคิดพื้นฐานที่สำคัญที่สุดใน Technical Analysis สำหรับการเทรดหุ้นและตลาดการเงิน Support คือระดับราคาที่แรงซื้อมากพอจะหยุดการลดลงของราคา Resistance คือระดับราคาที่แรงขายมากพอจะหยุดการเพิ่มขึ้นของราคา การเข้าใจ support/resistance ช่วยในการตัดสินใจ entry/exit, ตั้ง stop loss และ take profit บทความนี้อธิบายทฤษฎี วิธีหาแนวรับแนวต้าน และ Python tools สำหรับวิเคราะห์อัตโนมัติ
Support & Resistance Basics
# sr_basics.py — Support and Resistance fundamentals
import json
class SRBasics:
CONCEPTS = {
"support": {
"name": "Support (แนวรับ)",
"description": "ระดับราคาที่ demand มากกว่า supply — ราคามักจะเด้งกลับขึ้น",
"psychology": "Buyers มองว่าราคาถูก → เข้าซื้อ → ราคาหยุดลง",
"strength": "ยิ่งทดสอบหลายครั้ง + volume สูง = แนวรับแข็งแรง",
},
"resistance": {
"name": "Resistance (แนวต้าน)",
"description": "ระดับราคาที่ supply มากกว่า demand — ราคามักจะลงกลับ",
"psychology": "Sellers มองว่าราคาแพง → ขาย → ราคาหยุดขึ้น",
"strength": "ยิ่งทดสอบหลายครั้ง + volume สูง = แนวต้านแข็งแรง",
},
"role_reversal": {
"name": "Role Reversal (เปลี่ยนบทบาท)",
"description": "เมื่อ support ถูกทะลุ → กลายเป็น resistance (และกลับกัน)",
"example": "หุ้นลงทะลุแนวรับ 100 บาท → 100 บาทกลายเป็นแนวต้านใหม่",
},
"breakout": {
"name": "Breakout (ทะลุแนว)",
"description": "ราคาทะลุแนวรับ/ต้าน + volume สูง = สัญญาณ strong move",
"caution": "False breakout: ทะลุแล้วกลับมา — ต้อง confirm ด้วย volume + candle close",
},
}
TYPES = {
"horizontal": "แนวนอน — ระดับราคาคงที่ (เช่น 100, 200, 500 บาท)",
"trendline": "เส้น trend — ลาก highs/lows ต่อกัน ได้แนวรับ/ต้านแบบเอียง",
"moving_average": "Moving Average — MA50, MA200 ทำหน้าที่เป็น dynamic support/resistance",
"fibonacci": "Fibonacci Retracement — 23.6%, 38.2%, 50%, 61.8% เป็นแนวรับ/ต้าน",
"round_numbers": "ตัวเลขกลม — 100, 500, 1000 บาท มักเป็นแนวรับ/ต้านทางจิตวิทยา",
"pivot_points": "Pivot Points — คำนวณจาก OHLC ของวันก่อน",
}
def show_concepts(self):
print("=== S/R Concepts ===\n")
for key, concept in self.CONCEPTS.items():
print(f"[{concept['name']}]")
print(f" {concept['description']}")
print()
def show_types(self):
print("=== Types of S/R ===")
for stype, desc in self.TYPES.items():
print(f" [{stype}] {desc}")
sr = SRBasics()
sr.show_concepts()
sr.show_types()
Python Support/Resistance Finder
# sr_finder.py — Automated support/resistance detection
import json
class SRFinder:
CODE = """
# find_sr.py — Find support and resistance levels
import numpy as np
import pandas as pd
from scipy.signal import argrelextrema
class SupportResistanceFinder:
def __init__(self, df, window=20):
'''
df: DataFrame with 'close', 'high', 'low', 'volume' columns
window: lookback window for local extrema
'''
self.df = df.copy()
self.window = window
def find_pivot_points(self):
'''Find local highs and lows (pivot points)'''
highs = argrelextrema(self.df['high'].values, np.greater, order=self.window)[0]
lows = argrelextrema(self.df['low'].values, np.less, order=self.window)[0]
pivot_highs = self.df.iloc[highs][['high', 'volume']].copy()
pivot_highs.columns = ['price', 'volume']
pivot_highs['type'] = 'resistance'
pivot_lows = self.df.iloc[lows][['low', 'volume']].copy()
pivot_lows.columns = ['price', 'volume']
pivot_lows['type'] = 'support'
return pd.concat([pivot_highs, pivot_lows]).sort_index()
def cluster_levels(self, pivots, tolerance=0.02):
'''Cluster nearby price levels together'''
prices = pivots['price'].values
clusters = []
used = set()
for i, price in enumerate(prices):
if i in used:
continue
cluster = [price]
for j, other in enumerate(prices):
if j != i and j not in used:
if abs(price - other) / price < tolerance:
cluster.append(other)
used.add(j)
used.add(i)
clusters.append({
'price': np.mean(cluster),
'touches': len(cluster),
'strength': len(cluster),
})
return sorted(clusters, key=lambda x: x['strength'], reverse=True)
def find_levels(self, n_levels=5, tolerance=0.02):
'''Find top N support/resistance levels'''
pivots = self.find_pivot_points()
# Separate support and resistance
supports = pivots[pivots['type'] == 'support']
resistances = pivots[pivots['type'] == 'resistance']
support_levels = self.cluster_levels(supports, tolerance)[:n_levels]
resistance_levels = self.cluster_levels(resistances, tolerance)[:n_levels]
current_price = self.df['close'].iloc[-1]
return {
'current_price': current_price,
'support': [l for l in support_levels if l['price'] < current_price],
'resistance': [l for l in resistance_levels if l['price'] > current_price],
}
def fibonacci_levels(self, high=None, low=None):
'''Calculate Fibonacci retracement levels'''
if high is None:
high = self.df['high'].max()
if low is None:
low = self.df['low'].min()
diff = high - low
levels = {
'0%': high,
'23.6%': high - diff * 0.236,
'38.2%': high - diff * 0.382,
'50%': high - diff * 0.5,
'61.8%': high - diff * 0.618,
'78.6%': high - diff * 0.786,
'100%': low,
}
return levels
# Usage with yfinance
# import yfinance as yf
# df = yf.download("PTT.BK", period="1y")
# finder = SupportResistanceFinder(df, window=10)
# levels = finder.find_levels(n_levels=3)
# fib = finder.fibonacci_levels()
"""
def show_code(self):
print("=== S/R Finder ===")
print(self.CODE[:600])
finder = SRFinder()
finder.show_code()
Trading Strategies
# strategies.py — Trading strategies using S/R
import json
import random
class SRStrategies:
STRATEGIES = {
"bounce": {
"name": "Bounce Trading (เทรดเด้ง)",
"description": "ซื้อที่แนวรับ / ขายที่แนวต้าน",
"entry": "ราคาลงมาแตะ support + candle reversal (hammer, engulfing)",
"stop_loss": "ต่ำกว่า support 1-2%",
"take_profit": "ที่ resistance ถัดไป หรือ Risk:Reward 1:2+",
"win_rate": "55-65%",
},
"breakout": {
"name": "Breakout Trading (เทรดทะลุ)",
"description": "ซื้อเมื่อทะลุ resistance / ขายเมื่อทะลุ support",
"entry": "ราคา close เหนือ resistance + volume สูงกว่า average 1.5x",
"stop_loss": "กลับมาต่ำกว่า breakout level",
"take_profit": "วัด range ของ consolidation → project เป้าหมาย",
"win_rate": "40-55%",
},
"pullback": {
"name": "Pullback Trading (เทรดย่อ)",
"description": "รอราคาทะลุ → ย่อกลับมา retest → เข้าซื้อ",
"entry": "ราคาทะลุ resistance → ย่อมาทดสอบ (resistance เป็น support ใหม่)",
"stop_loss": "ต่ำกว่า retest level",
"take_profit": "Fibonacci extension หรือ next resistance",
"win_rate": "50-60%",
},
"range": {
"name": "Range Trading",
"description": "เทรดไปมาระหว่าง support-resistance ในช่วง sideway",
"entry": "ซื้อที่ support + ขายที่ resistance (ทั้งสองทาง)",
"stop_loss": "นอก range 1-2%",
"take_profit": "ฝั่งตรงข้ามของ range",
"win_rate": "60-70% (เฉพาะช่วง sideway)",
},
}
def show_strategies(self):
print("=== S/R Trading Strategies ===\n")
for key, strat in self.STRATEGIES.items():
print(f"[{strat['name']}]")
print(f" {strat['description']}")
print(f" Entry: {strat['entry']}")
print(f" Stop Loss: {strat['stop_loss']}")
print(f" Win Rate: {strat['win_rate']}")
print()
strat = SRStrategies()
strat.show_strategies()
Confirmation Indicators
# confirmation.py — Indicators to confirm S/R levels
import json
import random
class ConfirmationIndicators:
CODE = """
# sr_confirm.py — Confirm S/R levels with indicators
import pandas as pd
import numpy as np
class SRConfirmation:
def __init__(self, df):
self.df = df
def volume_confirmation(self, level, tolerance=0.01):
'''Check if high volume occurs near S/R level'''
near_level = self.df[
abs(self.df['close'] - level) / level < tolerance
]
avg_volume = self.df['volume'].mean()
if len(near_level) == 0:
return False
high_vol_touches = near_level[near_level['volume'] > avg_volume * 1.5]
return len(high_vol_touches) / len(near_level) > 0.5
def rsi_confirmation(self, period=14):
'''RSI confirmation at S/R levels'''
delta = self.df['close'].diff()
gain = delta.clip(lower=0).rolling(period).mean()
loss = (-delta.clip(upper=0)).rolling(period).mean()
rs = gain / loss
rsi = 100 - (100 / (1 + rs))
return {
'current_rsi': rsi.iloc[-1],
'oversold': rsi.iloc[-1] < 30, # Near support?
'overbought': rsi.iloc[-1] > 70, # Near resistance?
}
def ma_support_resistance(self, periods=[20, 50, 200]):
'''Moving averages as dynamic S/R'''
current_price = self.df['close'].iloc[-1]
levels = {}
for period in periods:
ma = self.df['close'].rolling(period).mean().iloc[-1]
if ma < current_price:
levels[f'MA{period}'] = {'price': ma, 'type': 'support'}
else:
levels[f'MA{period}'] = {'price': ma, 'type': 'resistance'}
return levels
def candlestick_pattern(self):
'''Detect reversal patterns near S/R'''
last = self.df.iloc[-1]
prev = self.df.iloc[-2]
# Hammer (bullish reversal at support)
body = abs(last['close'] - last['open'])
lower_shadow = min(last['open'], last['close']) - last['low']
upper_shadow = last['high'] - max(last['open'], last['close'])
is_hammer = lower_shadow > body * 2 and upper_shadow < body * 0.5
# Engulfing
is_bullish_engulfing = (prev['close'] < prev['open'] and # prev bearish
last['close'] > last['open'] and # curr bullish
last['close'] > prev['open'] and
last['open'] < prev['close'])
return {
'hammer': is_hammer,
'bullish_engulfing': is_bullish_engulfing,
}
# confirm = SRConfirmation(df)
# vol_ok = confirm.volume_confirmation(level=100.0)
# rsi = confirm.rsi_confirmation()
# ma_levels = confirm.ma_support_resistance()
"""
def show_code(self):
print("=== Confirmation Indicators ===")
print(self.CODE[:600])
def checklist(self):
print(f"\n=== S/R Confirmation Checklist ===")
checks = [
("Volume สูงกว่า average 1.5x", random.choice([True, False])),
("RSI oversold/overbought", random.choice([True, False])),
("Candlestick reversal pattern", random.choice([True, False])),
("MA support/resistance align", random.choice([True, False])),
("Multiple timeframe confirm", random.choice([True, False])),
]
score = sum(1 for _, v in checks if v)
for check, passed in checks:
status = "✓" if passed else "✗"
print(f" [{status}] {check}")
print(f"\n Score: {score}/5 — {'Strong signal' if score >= 3 else 'Weak signal'}")
confirm = ConfirmationIndicators()
confirm.show_code()
confirm.checklist()
Thai Stock Examples
# thai_stocks.py — S/R analysis for Thai stocks
import json
import random
class ThaiStockSR:
EXAMPLES = {
"PTT": {
"name": "PTT (SET)",
"support": [f"{random.uniform(30, 33):.2f}", f"{random.uniform(28, 30):.2f}"],
"resistance": [f"{random.uniform(35, 38):.2f}", f"{random.uniform(38, 42):.2f}"],
},
"ADVANC": {
"name": "ADVANC (SET)",
"support": [f"{random.uniform(195, 205):.2f}", f"{random.uniform(185, 195):.2f}"],
"resistance": [f"{random.uniform(215, 225):.2f}", f"{random.uniform(225, 240):.2f}"],
},
"SCB": {
"name": "SCB (SET)",
"support": [f"{random.uniform(95, 100):.2f}", f"{random.uniform(88, 95):.2f}"],
"resistance": [f"{random.uniform(105, 115):.2f}", f"{random.uniform(115, 125):.2f}"],
},
}
PYTHON_EXAMPLE = """
# thai_sr.py — Analyze Thai stocks with yfinance
import yfinance as yf
import pandas as pd
# Download data
ptt = yf.download("PTT.BK", period="1y")
advanc = yf.download("ADVANC.BK", period="1y")
# Find S/R levels
from sr_finder import SupportResistanceFinder
finder = SupportResistanceFinder(ptt, window=10)
levels = finder.find_levels(n_levels=3)
print(f"PTT Current: {levels['current_price']:.2f}")
print("Support levels:")
for s in levels['support']:
print(f" {s['price']:.2f} (touches: {s['touches']})")
print("Resistance levels:")
for r in levels['resistance']:
print(f" {r['price']:.2f} (touches: {r['touches']})")
# Fibonacci
fib = finder.fibonacci_levels()
print("\\nFibonacci levels:")
for level, price in fib.items():
print(f" {level}: {price:.2f}")
"""
def show_examples(self):
print("=== Thai Stock S/R Examples ===\n")
for key, stock in self.EXAMPLES.items():
print(f"[{stock['name']}]")
print(f" Support: {', '.join(stock['support'])}")
print(f" Resistance: {', '.join(stock['resistance'])}")
print()
def show_python(self):
print("=== Python Example ===")
print(self.PYTHON_EXAMPLE[:500])
thai = ThaiStockSR()
thai.show_examples()
thai.show_python()
FAQ - คำถามที่พบบ่อย
Q: แนวรับแนวต้านแม่นยำแค่ไหน?
A: ไม่ใช่เส้นตรง แต่เป็น zone — ราคาอาจทะลุเล็กน้อยแล้วกลับมา ยิ่ง timeframe ใหญ่ (Daily, Weekly) ยิ่งแม่นยำกว่า timeframe เล็ก (, H1) ยิ่งทดสอบหลายครั้ง + volume สูง ยิ่งเชื่อถือได้ ใช้เป็น probability ไม่ใช่ certainty — ต้องมี risk management เสมอ
Q: ใช้ timeframe ไหนดี?
A: Multiple timeframe analysis ดีที่สุด: Weekly/Monthly: หา major S/R levels (strong zones) Daily: หา intermediate levels + confirm direction H4/H1: หา entry/exit points Rule: S/R จาก timeframe ใหญ่ > timeframe เล็ก เมื่อ levels จากหลาย timeframes ตรงกัน = confluence zone (แข็งแรงมาก)
Q: Fibonacci levels เชื่อถือได้ไหม?
A: เป็น self-fulfilling prophecy — เพราะคนเยอะใช้ จึง work ระดับที่สำคัญที่สุด: 38.2%, 50%, 61.8% ใช้ร่วมกับ horizontal S/R = powerful (confluence) ไม่ควรใช้ Fibonacci อย่างเดียว — ต้อง confirm ด้วย price action + volume
Q: Stop loss ควรตั้งห่างจาก S/R เท่าไหร่?
A: ขึ้นกับ volatility ของหุ้น: หุ้น volatility ต่ำ: 1-2% ต่ำกว่า support หุ้น volatility สูง: 2-5% ต่ำกว่า support ใช้ ATR (Average True Range): SL = support - 1.5 * ATR สำคัญ: stop loss ต้องอยู่ "นอก" S/R zone ไม่ใช่ที่ขอบ zone อย่าตั้ง stop loss ที่ตัวเลขกลม (ถูก hunt ง่าย)
