แนวรับแนวต้านคืออะไร
แนวรับ (Support) คือระดับราคาที่มีแรงซื้อ (Demand) มากพอจะหยุดราคาไม่ให้ลงต่อ เมื่อราคาลงมาถึงแนวรับ มักจะ Bounce กลับขึ้นไป แนวต้าน (Resistance) คือระดับราคาที่มีแรงขาย (Supply) มากพอจะหยุดราคาไม่ให้ขึ้นต่อ เมื่อราคาขึ้นไปถึงแนวต้าน มักจะ Bounce กลับลงมา
แนวรับแนวต้านเป็นพื้นฐานที่สำคัญที่สุดของ Technical Analysis ใช้ในการหาจุดเข้า (Entry), จุดออก (Exit), วาง Stop Loss และ Take Profit การเขียน Code ตรวจจับแนวรับแนวต้านอัตโนมัติช่วยให้ EA ทำงานได้อย่างมีประสิทธิภาพ
MQL4 Indicator — Support/Resistance Detection
//+------------------------------------------------------------------+
//| SupportResistance.mq4 — Custom Indicator |
//| ตรวจจับแนวรับแนวต้านด้วย Fractal Method + Clustering |
//+------------------------------------------------------------------+
#property copyright "SiamCafe Blog"
#property version "2.0"
#property strict
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 clrDodgerBlue // Support
#property indicator_color2 clrOrangeRed // Resistance
#property indicator_width1 2
#property indicator_width2 2
#property indicator_style1 STYLE_SOLID
#property indicator_style2 STYLE_SOLID
//--- Input Parameters
input int LookbackBars = 200; // จำนวนแท่งเทียนย้อนหลัง
input int FractalPeriod = 5; // Fractal Period (แท่งเทียนข้างละ)
input double ClusterRange = 0.0010; // ระยะรวม Cluster (สำหรับ 4-digit)
input int MinTouches = 2; // จำนวนครั้งที่ราคาต้อง Touch
input bool DrawZones = true; // วาด Zone บนกราฟ
//--- Indicator Buffers
double SupportBuffer[];
double ResistanceBuffer[];
//--- Global Arrays
double SupportLevels[];
double ResistanceLevels[];
int SupportStrength[];
int ResistanceStrength[];
//+------------------------------------------------------------------+
int OnInit()
{
SetIndexBuffer(0, SupportBuffer);
SetIndexBuffer(1, ResistanceBuffer);
SetIndexStyle(0, DRAW_ARROW);
SetIndexStyle(1, DRAW_ARROW);
SetIndexArrow(0, 159); // Up Arrow
SetIndexArrow(1, 159); // Down Arrow
IndicatorShortName("S/R Detector");
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[])
{
int limit = MathMin(rates_total - FractalPeriod, LookbackBars);
// Clear buffers
ArrayInitialize(SupportBuffer, EMPTY_VALUE);
ArrayInitialize(ResistanceBuffer, EMPTY_VALUE);
// Step 1: หา Fractal Highs และ Lows
double fractalHighs[];
double fractalLows[];
ArrayResize(fractalHighs, 0);
ArrayResize(fractalLows, 0);
for(int i = FractalPeriod; i < limit; i++)
{
// Fractal High
bool isHigh = true;
for(int j = 1; j <= FractalPeriod; j++)
{
if(high[i] <= high[i-j] || high[i] <= high[i+j])
{
isHigh = false;
break;
}
}
if(isHigh)
{
int size = ArraySize(fractalHighs);
ArrayResize(fractalHighs, size + 1);
fractalHighs[size] = high[i];
}
// Fractal Low
bool isLow = true;
for(int j = 1; j <= FractalPeriod; j++)
{
if(low[i] >= low[i-j] || low[i] >= low[i+j])
{
isLow = false;
break;
}
}
if(isLow)
{
int size = ArraySize(fractalLows);
ArrayResize(fractalLows, size + 1);
fractalLows[size] = low[i];
}
}
// Step 2: Cluster ระดับราคาใกล้กัน
ClusterLevels(fractalHighs, ResistanceLevels, ResistanceStrength);
ClusterLevels(fractalLows, SupportLevels, SupportStrength);
// Step 3: วาดบนกราฟ
if(DrawZones)
{
DrawSRZones();
}
return(rates_total);
}
//+------------------------------------------------------------------+
//| รวม Level ที่ใกล้กันเป็น Cluster |
//+------------------------------------------------------------------+
void ClusterLevels(double &levels[], double &clustered[],
int &strength[])
{
ArrayResize(clustered, 0);
ArrayResize(strength, 0);
if(ArraySize(levels) == 0) return;
// Sort
ArraySort(levels);
double currentCluster = levels[0];
double clusterSum = levels[0];
int clusterCount = 1;
for(int i = 1; i < ArraySize(levels); i++)
{
if(MathAbs(levels[i] - currentCluster) <= ClusterRange)
{
clusterSum += levels[i];
clusterCount++;
}
else
{
if(clusterCount >= MinTouches)
{
int size = ArraySize(clustered);
ArrayResize(clustered, size + 1);
ArrayResize(strength, size + 1);
clustered[size] = clusterSum / clusterCount;
strength[size] = clusterCount;
}
currentCluster = levels[i];
clusterSum = levels[i];
clusterCount = 1;
}
}
// Last cluster
if(clusterCount >= MinTouches)
{
int size = ArraySize(clustered);
ArrayResize(clustered, size + 1);
ArrayResize(strength, size + 1);
clustered[size] = clusterSum / clusterCount;
strength[size] = clusterCount;
}
}
//+------------------------------------------------------------------+
//| วาด S/R Zones บนกราฟ |
//+------------------------------------------------------------------+
void DrawSRZones()
{
// ลบ Objects เก่า
ObjectsDeleteAll(0, "SR_");
double zoneWidth = ClusterRange / 2;
for(int i = 0; i < ArraySize(SupportLevels); i++)
{
string name = "SR_S_" + IntegerToString(i);
ObjectCreate(0, name, OBJ_RECTANGLE, 0,
Time[LookbackBars], SupportLevels[i] - zoneWidth,
Time[0], SupportLevels[i] + zoneWidth);
ObjectSetInteger(0, name, OBJPROP_COLOR, clrDodgerBlue);
ObjectSetInteger(0, name, OBJPROP_FILL, true);
ObjectSetInteger(0, name, OBJPROP_BACK, true);
ObjectSetString(0, name, OBJPROP_TOOLTIP,
"Support: " + DoubleToString(SupportLevels[i], Digits)
+ " (Touches: " + IntegerToString(SupportStrength[i]) + ")");
}
for(int i = 0; i < ArraySize(ResistanceLevels); i++)
{
string name = "SR_R_" + IntegerToString(i);
ObjectCreate(0, name, OBJ_RECTANGLE, 0,
Time[LookbackBars], ResistanceLevels[i] - zoneWidth,
Time[0], ResistanceLevels[i] + zoneWidth);
ObjectSetInteger(0, name, OBJPROP_COLOR, clrOrangeRed);
ObjectSetInteger(0, name, OBJPROP_FILL, true);
ObjectSetInteger(0, name, OBJPROP_BACK, true);
}
}
Pivot Points Calculator
//+------------------------------------------------------------------+
//| PivotPoints.mq4 — Pivot Points Indicator |
//| คำนวณ Classic, Fibonacci และ Camarilla Pivot Points |
//+------------------------------------------------------------------+
#property strict
#property indicator_chart_window
input string PivotType = "Classic"; // Classic, Fibonacci, Camarilla
void OnInit()
{
CalculatePivots();
}
void CalculatePivots()
{
// ดึงข้อมูลจากวันก่อน
double prevHigh = iHigh(Symbol(), PERIOD_D1, 1);
double prevLow = iLow(Symbol(), PERIOD_D1, 1);
double prevClose = iClose(Symbol(), PERIOD_D1, 1);
double prevOpen = iOpen(Symbol(), PERIOD_D1, 1);
double PP, R1, R2, R3, S1, S2, S3;
if(PivotType == "Classic")
{
PP = (prevHigh + prevLow + prevClose) / 3;
R1 = 2 * PP - prevLow;
S1 = 2 * PP - prevHigh;
R2 = PP + (prevHigh - prevLow);
S2 = PP - (prevHigh - prevLow);
R3 = prevHigh + 2 * (PP - prevLow);
S3 = prevLow - 2 * (prevHigh - PP);
}
else if(PivotType == "Fibonacci")
{
PP = (prevHigh + prevLow + prevClose) / 3;
double range = prevHigh - prevLow;
R1 = PP + 0.382 * range;
R2 = PP + 0.618 * range;
R3 = PP + 1.000 * range;
S1 = PP - 0.382 * range;
S2 = PP - 0.618 * range;
S3 = PP - 1.000 * range;
}
else // Camarilla
{
double range = prevHigh - prevLow;
PP = (prevHigh + prevLow + prevClose) / 3;
R1 = prevClose + range * 1.1 / 12;
R2 = prevClose + range * 1.1 / 6;
R3 = prevClose + range * 1.1 / 4;
S1 = prevClose - range * 1.1 / 12;
S2 = prevClose - range * 1.1 / 6;
S3 = prevClose - range * 1.1 / 4;
}
// วาดเส้นบนกราฟ
DrawLevel("PP", PP, clrYellow, STYLE_SOLID);
DrawLevel("R1", R1, clrRed, STYLE_DASH);
DrawLevel("R2", R2, clrRed, STYLE_DASHDOT);
DrawLevel("R3", R3, clrRed, STYLE_SOLID);
DrawLevel("S1", S1, clrDodgerBlue, STYLE_DASH);
DrawLevel("S2", S2, clrDodgerBlue, STYLE_DASHDOT);
DrawLevel("S3", S3, clrDodgerBlue, STYLE_SOLID);
Comment(StringFormat(
"%s Pivot Points\nR3: %.5f\nR2: %.5f\nR1: %.5f\n"
"PP: %.5f\nS1: %.5f\nS2: %.5f\nS3: %.5f",
PivotType, R3, R2, R1, PP, S1, S2, S3));
}
void DrawLevel(string name, double price, color clr, int style)
{
string objName = "Pivot_" + name;
ObjectDelete(objName);
ObjectCreate(0, objName, OBJ_HLINE, 0, 0, price);
ObjectSetInteger(0, objName, OBJPROP_COLOR, clr);
ObjectSetInteger(0, objName, OBJPROP_STYLE, style);
ObjectSetInteger(0, objName, OBJPROP_WIDTH, 1);
ObjectSetString(0, objName, OBJPROP_TEXT, name + ": " +
DoubleToString(price, Digits));
}
Python Script วิเคราะห์ S/R จากข้อมูลจริง
# sr_analysis.py — วิเคราะห์ Support/Resistance ด้วย Python
import numpy as np
from collections import defaultdict
class SupportResistanceDetector:
"""ตรวจจับแนวรับแนวต้านจากข้อมูลราคา"""
def __init__(self, cluster_pct=0.1, min_touches=2):
self.cluster_pct = cluster_pct / 100 # % ของราคา
self.min_touches = min_touches
def find_fractals(self, highs, lows, period=5):
"""หา Fractal Highs/Lows"""
frac_highs, frac_lows = [], []
for i in range(period, len(highs) - period):
# Fractal High
if all(highs[i] > highs[i-j] for j in range(1, period+1)) and \
all(highs[i] > highs[i+j] for j in range(1, period+1)):
frac_highs.append(highs[i])
# Fractal Low
if all(lows[i] < lows[i-j] for j in range(1, period+1)) and \
all(lows[i] < lows[i+j] for j in range(1, period+1)):
frac_lows.append(lows[i])
return frac_highs, frac_lows
def cluster_levels(self, levels):
"""รวม Level ที่ใกล้กัน"""
if not levels:
return []
sorted_levels = sorted(levels)
clusters = []
current = [sorted_levels[0]]
for level in sorted_levels[1:]:
if abs(level - np.mean(current)) / np.mean(current) <= self.cluster_pct:
current.append(level)
else:
if len(current) >= self.min_touches:
clusters.append({
"price": round(np.mean(current), 5),
"touches": len(current),
"strength": len(current),
})
current = [level]
if len(current) >= self.min_touches:
clusters.append({
"price": round(np.mean(current), 5),
"touches": len(current),
"strength": len(current),
})
return clusters
def detect(self, highs, lows, closes):
"""ตรวจจับ Support/Resistance"""
frac_highs, frac_lows = self.find_fractals(highs, lows)
resistance = self.cluster_levels(frac_highs)
support = self.cluster_levels(frac_lows)
current_price = closes[-1]
# แยก Active Levels (ใกล้ราคาปัจจุบัน)
active_support = [s for s in support if s["price"] < current_price]
active_resistance = [r for r in resistance if r["price"] > current_price]
# Sort by distance
active_support.sort(key=lambda x: current_price - x["price"])
active_resistance.sort(key=lambda x: x["price"] - current_price)
return {
"support": active_support[:5],
"resistance": active_resistance[:5],
"current_price": current_price,
}
# ตัวอย่าง
np.random.seed(42)
n = 500
prices = 1.1000 + np.cumsum(np.random.randn(n) * 0.001)
highs = prices + np.abs(np.random.randn(n) * 0.0005)
lows = prices - np.abs(np.random.randn(n) * 0.0005)
detector = SupportResistanceDetector(cluster_pct=0.15, min_touches=2)
result = detector.detect(highs, lows, prices)
print(f"Current Price: {result['current_price']:.5f}")
print(f"\nSupport Levels:")
for s in result["support"]:
print(f" {s['price']:.5f} (touches: {s['touches']})")
print(f"\nResistance Levels:")
for r in result["resistance"]:
print(f" {r['price']:.5f} (touches: {r['touches']})")
Trading Strategies กับ S/R
- Bounce Trading: เปิด Buy ที่แนวรับ เปิด Sell ที่แนวต้าน SL อีกด้านของ Zone TP ที่ S/R ถัดไป
- Breakout Trading: เปิด Buy เมื่อราคาทะลุแนวต้าน เปิด Sell เมื่อทะลุแนวรับ รอ Confirmation ก่อนเข้า
- Retest Strategy: รอ Breakout แล้วรอราคากลับมา Retest Level เดิม จึงเข้า Trade ลด False Breakout
- Multi-timeframe: หา S/R จาก Daily แล้วเข้า Trade บน H1 หรือ S/R จาก Timeframe ใหญ่มีน้ำหนักมากกว่า
แนวรับแนวต้าน (Support/Resistance) คืออะไร
แนวรับคือระดับราคาที่มีแรงซื้อหยุดราคาไม่ให้ลงต่อ แนวต้านคือระดับที่มีแรงขายหยุดราคาไม่ให้ขึ้นต่อ เกิดจากจุดที่ราคาเคย Bounce กลับหลายครั้ง เป็นพื้นฐาน Technical Analysis
วิธีหาแนวรับแนวต้านด้วย Code ทำอย่างไร
ใช้ Fractal Method หาจุด High/Low ที่สูงหรือต่ำกว่าแท่งข้างเคียง Pivot Points คำนวณจาก OHLC วันก่อน Volume Profile หาระดับที่มี Volume สูง Clustering รวมระดับใกล้กันเป็นโซนเดียว
Pivot Points คำนวณอย่างไร
Classic: PP = (H+L+C)/3 R1 = 2*PP-L S1 = 2*PP-H R2 = PP+(H-L) S2 = PP-(H-L) มีหลายแบบ Classic Fibonacci Camarilla Woodie แต่ละแบบเหมาะกับสภาวะตลาดต่างกัน
ควรใช้ Timeframe ไหนหา Support/Resistance
Daily และ Weekly มีน้ำหนักมากที่สุด เหมาะ Intraday M30 สำหรับ Scalping ใช้หลาย Timeframe ร่วมกัน (Multi-timeframe Analysis) S/R จาก Timeframe ใหญ่สำคัญกว่า Timeframe เล็ก
สรุป
Support/Resistance เป็นพื้นฐานสำคัญของ Technical Analysis การเขียน MQL4 Indicator ตรวจจับอัตโนมัติด้วย Fractal Method และ Clustering ช่วยให้หาแนวรับแนวต้านได้แม่นยำ Pivot Points ให้ระดับราคาสำคัญจาก OHLC วันก่อน ใช้ร่วมกับ Trading Strategy เช่น Bounce, Breakout, Retest และ Multi-timeframe Analysis สิ่งสำคัญคือ S/R เป็นโซนไม่ใช่เส้น และ Timeframe ใหญ่มีน้ำหนักมากกว่า
