trade

Repaint — คู่มือฉบับสมบูรณ์ 2026 — คู่มือฉบับสมบูรณ์ 2026

Repaint — คู่มือฉบับสมบูรณ์ 2026 — คู่มือฉบับสมบูรณ์ 2026

Repaint คืออะไร — ปัญหา Indicator Repaint ในการเทรด

Repaint — คู่มือฉบับสมบูรณ์ 2026 — คู่มือฉบับสมบูรณ์ 2026

Repaint (รีเพนท์) คือปรากฏการณ์ที่ indicator บนกราฟเทรดเปลี่ยนแปลงค่าย้อนหลังหลังจากที่ bar ปิดแล้ว ทำให้ signal ที่เห็นในอดีตไม่ตรงกับ signal ที่เกิดขึ้นจริงในขณะนั้น เป็นปัญหาสำคัญที่ทำให้ backtesting ให้ผลดีเกินจริง แต่เมื่อเทรดจริงกลับขาดทุน เพราะ indicator ที่ repaint จะแสดง signal ที่ "สมบูรณ์แบบ" ในอดีต แต่ใน real-time จะให้ signal ที่เปลี่ยนไปมา บทความนี้อธิบายปัญหา repaint วิธีตรวจสอบ และ Python tools สำหรับทดสอบ

ประเภทของ Repaint

# repaint_types.py — Types of indicator repainting
import json

class RepaintTypes:
 TYPES = {
 "future_data": {
 "name": "Future Data Repaint",
 "description": "Indicator ใช้ข้อมูลในอนาคตคำนวณ — ย้อนกลับไปแก้ค่าเก่า",
 "example": "Zigzag indicator — วาด high/low ย้อนหลังหลังจากรู้ว่า peak/trough อยู่ตรงไหน",
 "danger": "สูงมาก — backtest ดีเกินจริง 100%",
 },
 "current_bar": {
 "name": "Current Bar Repaint",
 "description": "Indicator เปลี่ยนค่าบน bar ปัจจุบันก่อนที่ bar จะปิด — ปกติ ไม่อันตราย",
 "example": "Moving Average บน bar ปัจจุบัน — ค่าเปลี่ยนตาม tick ใหม่",
 "danger": "ต่ำ — ปกติของ indicator ทุกตัว (แก้ได้โดยใช้ค่าจาก bar ก่อนหน้า)",
 },
 "historical_repaint": {
 "name": "Historical Repaint",
 "description": "Indicator เปลี่ยนค่าของ bars ที่ปิดแล้ว — อันตรายมาก",
 "example": "บาง RSI/Stochastic versions ที่คำนวณใหม่เมื่อมี data ใหม่",
 "danger": "สูง — signal ในอดีตไม่น่าเชื่อถือ",
 },
 "recalculation": {
 "name": "Recalculation Repaint",
 "description": "Indicator คำนวณใหม่ทั้ง history เมื่อ reload chart หรือเปลี่ยน timeframe",
 "example": "บาง custom indicators ที่ใช้ global variables",
 "danger": "ปานกลาง — ผลจาก backtest ไม่ consistent",
 },
 }

 COMMON_REPAINTERS = {
 "zigzag": "Zigzag — วาด highs/lows ย้อนหลัง (future data)",
 "fractal": "Williams Fractal — ต้องรอ 2 bars ยืนยัน (delayed, ไม่ repaint ถ้า code ถูก)",
 "renko": "Renko Charts — อาจ repaint ถ้า real-time calculation ต่างจาก historical",
 "heiken_ashi": "Heiken Ashi — ใช้ average ของ OHLC → ค่าเปลี่ยนบน current bar",
 "supertrend": "SuperTrend — บาง version repaint, บาง version ไม่",
 }

 NON_REPAINTERS = {
 "sma": "Simple Moving Average — ไม่ repaint (ค่า fixed หลัง bar ปิด)",
 "ema": "Exponential Moving Average — ไม่ repaint",
 "macd": "MACD — ไม่ repaint (based on EMA)",
 "rsi": "RSI (standard) — ไม่ repaint",
 "bollinger": "Bollinger Bands — ไม่ repaint",
 "atr": "ATR — ไม่ repaint",
 }

 def show_types(self):
 print("=== Types of Repaint ===\n")
 for key, t in self.TYPES.items():
 print(f"[{t['name']}]")
 print(f" {t['description']}")
 print(f" Danger: {t['danger']}")
 print()

 def show_indicators(self):
 print("=== Common Repainting Indicators ===")
 for name, desc in self.COMMON_REPAINTERS.items():
 print(f" ⚠️ {desc}")
 print(f"\n=== Non-Repainting Indicators ===")
 for name, desc in self.NON_REPAINTERS.items():
 print(f" ✅ {desc}")

types = RepaintTypes()
types.show_types()
types.show_indicators()

วิธีตรวจสอบ Repaint

# detect_repaint.py — How to detect repainting
import json

class DetectRepaint:
 METHODS = {
 "visual_test": {
 "name": "1. Visual Test (ทดสอบด้วยตา)",
 "steps": [
 "เปิด indicator บน chart real-time",
 "สังเกต signal ล่าสุด — จด position ของ arrow/line",
 "รอ bar ใหม่เปิด — ดูว่า signal เก่าเปลี่ยนหรือไม่",
 "ถ้า signal เก่าเปลี่ยน/หายไป = REPAINT",
 "ทำซ้ำหลายครั้งเพื่อยืนยัน",
 ],
 },
 "bar_replay": {
 "name": "2. Bar Replay Test",
 "steps": [
 "ใช้ Bar Replay ใน TradingView หรือ MT4 Strategy Tester",
 "เล่น bar ทีละ bar — ดู signal ที่เกิดขึ้น",
 "เปรียบเทียบกับ signal ที่เห็นบน historical chart",
 "ถ้าต่างกัน = REPAINT",
 ],
 },
 "code_review": {
 "name": "3. Code Review",
 "steps": [
 "ดู source code ของ indicator",
 "ตรวจสอบว่าใช้ bar[0] (current bar) หรือ bar[1] (previous bar)",
 "ตรวจว่ามีการ reference future bars หรือไม่",
 "ตรวจว่าคำนวณบน closed bars เท่านั้นหรือไม่",
 ],
 "red_flags": [
 "ใช้ iHighest/iLowest แล้ว plot ย้อนหลัง",
 "ใช้ bar index ที่เปลี่ยนตาม data ใหม่",
 "ใช้ future data (lookahead bias)",
 ],
 },
 "dual_chart": {
 "name": "4. Dual Chart Test",
 "steps": [
 "เปิด 2 charts เดียวกัน — chart 1 เปิด indicator, chart 2 ไม่เปิด",
 "Screenshot indicator signals ทุก 1 ชั่วโมง",
 "เปรียบเทียบ screenshots — signal เปลี่ยนหรือไม่",
 ],
 },
 }

 def show_methods(self):
 print("=== วิธีตรวจสอบ Repaint ===\n")
 for key, method in self.METHODS.items():
 print(f"[{method['name']}]")
 for step in method['steps'][:3]:
 print(f" • {step}")
 print()

detect = DetectRepaint()
detect.show_methods()

MQL4 Non-Repaint Indicator

Repaint — คู่มือฉบับสมบูรณ์ 2026 — คู่มือฉบับสมบูรณ์ 2026
// non_repaint.mq4 — Non-repainting indicator example

// === วิธีเขียน indicator ที่ไม่ repaint ===

// Rule 1: คำนวณเฉพาะ closed bars (bar[1] ขึ้นไป)
// Rule 2: ไม่เปลี่ยนค่าที่ plot แล้วบน closed bars
// Rule 3: ไม่ใช้ future data

// ตัวอย่าง: Non-Repaint Moving Average Crossover Signal
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 clrGreen // Buy signal
#property indicator_color2 clrRed // Sell signal

input int FastMA = 10;
input int SlowMA = 20;

double BuyBuffer[];
double SellBuffer[];

int OnInit()
{
 SetIndexBuffer(0, BuyBuffer);
 SetIndexBuffer(1, SellBuffer);
 SetIndexStyle(0, DRAW_ARROW);
 SetIndexStyle(1, DRAW_ARROW);
 SetIndexArrow(0, 233); // Up arrow
 SetIndexArrow(1, 234); // Down arrow
 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 = rates_total - prev_calculated;
 if (limit > rates_total - SlowMA - 2) 
 limit = rates_total - SlowMA - 2;
 
 // IMPORTANT: เริ่มจาก bar 1 (closed bar) — ไม่ใช่ bar 0
 for (int i = limit; i >= 1; i--)
 {
 double fastMA_current = iMA(NULL, 0, FastMA, 0, MODE_EMA, PRICE_CLOSE, i);
 double slowMA_current = iMA(NULL, 0, SlowMA, 0, MODE_EMA, PRICE_CLOSE, i);
 double fastMA_prev = iMA(NULL, 0, FastMA, 0, MODE_EMA, PRICE_CLOSE, i + 1);
 double slowMA_prev = iMA(NULL, 0, SlowMA, 0, MODE_EMA, PRICE_CLOSE, i + 1);
 
 BuyBuffer[i] = EMPTY_VALUE;
 SellBuffer[i] = EMPTY_VALUE;
 
 // Buy: Fast MA crosses above Slow MA (on CLOSED bar)
 if (fastMA_prev <= slowMA_prev && fastMA_current > slowMA_current)
 {
 BuyBuffer[i] = Low[i] - 10 * Point;
 }
 
 // Sell: Fast MA crosses below Slow MA (on CLOSED bar)
 if (fastMA_prev >= slowMA_prev && fastMA_current < slowMA_current)
 {
 SellBuffer[i] = High[i] + 10 * Point;
 }
 }
 
 return rates_total;
}

Python Repaint Detector

# repaint_detector.py — Python tool to detect repainting
import json

class RepaintDetector:
 CODE = """
# repaint_test.py — Test indicator for repainting
import pandas as pd
import numpy as np

class RepaintTester:
 def __init__(self, data):
 '''data: DataFrame with OHLCV'''
 self.data = data.copy()
 
 def test_indicator(self, indicator_func, lookback=0):
 '''Test if indicator repaints by comparing incremental vs full calculation'''
 full_result = indicator_func(self.data)
 
 repaints = 0
 total_checks = 0
 repaint_bars = []
 
 # Simulate bar-by-bar calculation
 for i in range(lookback + 10, len(self.data)):
 # Calculate with data up to bar i
 partial_data = self.data.iloc[:i+1].copy()
 partial_result = indicator_func(partial_data)
 
 # Check if previous bars changed
 for j in range(max(0, i-5), i):
 if j < len(partial_result) and j < len(full_result):
 partial_val = partial_result.iloc[j]
 full_val = full_result.iloc[j]
 
 if not np.isnan(partial_val) and not np.isnan(full_val):
 total_checks += 1
 if abs(partial_val - full_val) > 1e-10:
 repaints += 1
 repaint_bars.append({
 'bar': j,
 'calculated_at': i,
 'partial_value': round(partial_val, 5),
 'full_value': round(full_val, 5),
 })
 
 repaint_pct = (repaints / max(total_checks, 1)) * 100
 
 return {
 'repaints': repaints > 0,
 'repaint_count': repaints,
 'total_checks': total_checks,
 'repaint_pct': round(repaint_pct, 2),
 'verdict': 'REPAINTS' if repaints > 0 else 'SAFE (no repaint)',
 'repaint_bars': repaint_bars[:10],
 }
 
 def test_sma(self, period=20):
 '''Test SMA for repainting (should not repaint)'''
 def sma_indicator(data):
 return data['close'].rolling(period).mean()
 
 return self.test_indicator(sma_indicator, lookback=period)
 
 def test_zigzag(self, depth=12, deviation=5):
 '''Test Zigzag (known to repaint)'''
 def zigzag_indicator(data):
 # Simplified zigzag — will repaint
 result = pd.Series(np.nan, index=data.index)
 high_idx = data['high'].rolling(depth).apply(lambda x: x.argmax())
 low_idx = data['low'].rolling(depth).apply(lambda x: x.argmin())
 return result # Placeholder
 
 return {'verdict': 'KNOWN REPAINTER — Zigzag uses future data by design'}
 
 def backtest_comparison(self, indicator_func, signal_func):
 '''Compare backtest results: full data vs incremental'''
 # Full data signals (potentially with repaint)
 full_signals = signal_func(self.data, indicator_func(self.data))
 
 # Incremental signals (real-time simulation)
 incremental_signals = pd.Series(0, index=self.data.index)
 for i in range(50, len(self.data)):
 partial = self.data.iloc[:i+1]
 indicator = indicator_func(partial)
 signal = signal_func(partial, indicator)
 incremental_signals.iloc[i] = signal.iloc[-1] if len(signal) > 0 else 0
 
 # Compare
 matches = (full_signals == incremental_signals).sum()
 total = len(self.data) - 50
 
 return {
 'match_pct': round(matches / max(total, 1) * 100, 1),
 'mismatches': total - matches,
 'reliable': matches / max(total, 1) > 0.99,
 }

# tester = RepaintTester(data)
# sma_test = tester.test_sma(20)
# print(sma_test['verdict']) # SAFE (no repaint)
"""

 def show_code(self):
 print("=== Repaint Detector ===")
 print(self.CODE[:600])

detector = RepaintDetector()
detector.show_code()

วิธีป้องกัน Repaint

# prevention.py — How to avoid repaint issues
import json

class RepaintPrevention:
 RULES = {
 "use_closed_bars": {
 "name": "ใช้เฉพาะ Closed Bars",
 "description": "คำนวณ signal จาก bar[1] ขึ้นไป — ไม่ใช่ bar[0] (current)",
 "mql4": "ใช้ Close[1] แทน Close[0], iMA(..., 1) แทน iMA(..., 0)",
 },
 "no_future_data": {
 "name": "ไม่ใช้ Future Data",
 "description": "ไม่ reference bars ที่ยังไม่เกิดขึ้น — ไม่ใช้ lookahead",
 "mql4": "หลีกเลี่ยง Zigzag, Fractal ที่ไม่ confirm, บาง pivot indicators",
 },
 "confirm_signals": {
 "name": "ยืนยัน Signal",
 "description": "รอ bar ปิดก่อน act — ไม่เทรดจาก signal ที่ยังไม่ confirm",
 "mql4": "if (Volume[0] > 1) return; // รอ bar ใหม่เริ่ม",
 },
 "test_thoroughly": {
 "name": "ทดสอบอย่างละเอียด",
 "description": "ใช้ Bar Replay, forward test, และ Python repaint detector",
 "tools": "TradingView Bar Replay, MT4 Strategy Tester (visual mode)",
 },
 }

 SAFE_INDICATORS = [
 "SMA, EMA, WMA — Moving Averages ทุกแบบ (ไม่ repaint)",
 "RSI, Stochastic, CCI — Oscillators มาตรฐาน",
 "MACD — based on EMA, ไม่ repaint",
 "Bollinger Bands — based on SMA + StdDev",
 "ATR — Average True Range",
 "ADX — Average Directional Index",
 "Ichimoku — ไม่ repaint (แต่มี displacement ที่ดูเหมือน repaint)",
 ]

 def show_rules(self):
 print("=== Prevention Rules ===\n")
 for key, rule in self.RULES.items():
 print(f"[{rule['name']}]")
 print(f" {rule['description']}")
 print()

 def show_safe(self):
 print("=== Safe (Non-Repaint) Indicators ===")
 for ind in self.SAFE_INDICATORS:
 print(f" ✅ {ind}")

prevention = RepaintPrevention()
prevention.show_rules()
prevention.show_safe()

FAQ - คำถามที่พบบ่อย

Q: Indicator ที่ repaint ใช้ไม่ได้เลยหรือ?

อ่านเพิ่ม: Rust คืออะไร? สอน Rust Programming ภาษาที่เร็วและปลอดภัยที่ส · อ่านเพิ่ม: PostgreSQL ขั้นสูง สอน Indexing, Query Optimization, Replica · อ่านเพิ่ม: Event-Driven Architecture คืออะไร? สอนออกแบบระบบ Event Sourc

เนื้อหาเกี่ยวข้อง — support and resistance for stocks

A: ใช้ได้ — แต่ต้องเข้าใจข้อจำกัด: ใช้เป็น reference (ดูภาพรวม) ไม่ใช่ signal ตรง Zigzag: ใช้ดู structure ของ market, ไม่ใช้เป็น entry signal Fractal: ใช้ได้ถ้ารอ confirm (2 bars หลัง fractal) สำคัญ: อย่า backtest ด้วย repainting indicator — ผลจะดีเกินจริง

แนะนำเพิ่มเติม — คอร์สเทรด Forex ที่ iCafeForex

Q: ทำไม backtest ดีแต่เทรดจริงขาดทุน?

เนื้อหาเกี่ยวข้อง — อ่านต่อ: Trend Following Books — หนังสือแนะนำเกี่ยวกับ

A: สาเหตุหลัก 3 ข้อ: 1) Indicator repaint — signal ในอดีตดูดีเพราะใช้ future data 2) Curve fitting — optimize parameters ให้ fit historical data เกินไป 3) Slippage + spread — backtest ไม่รวมค่า execution จริง วิธีแก้: ใช้ non-repaint indicators, forward test 3+ เดือน, รวม realistic costs ใน backtest

Q: TradingView indicators repaint ไหม?

แนะนำเพิ่มเติม — XM Signal

เนื้อหาเกี่ยวข้อง — แนะนำให้อ่าน technical analysis of stocks

A: ขึ้นกับ indicator: Built-in (SMA, EMA, RSI): ไม่ repaint Community scripts: ต้องตรวจสอบเอง — อ่าน description + comments วิธีตรวจ: ใช้ Bar Replay ใน TradingView — เล่นทีละ bar ดู signal เปลี่ยนไหม Pine Script: ดูว่าใช้ barstate.isrealtime, security() ที่ lookahead=true หรือไม่

Q: Non-repaint indicator ดีกว่า repaint indicator เสมอไหม?

เนื้อหาเกี่ยวข้อง — แนะนำให้อ่าน CDK Construct Edge Deployment — คู่มือฉบับสมบูรณ์ 2026

A: ไม่เสมอไป — non-repaint มี lag มากกว่า (สัญญาณช้ากว่า) Tradeoff: Non-repaint = reliable แต่ late signal, Repaint = early signal แต่ไม่ reliable วิธีที่ดี: ใช้ non-repaint เป็น primary signal + repaint เป็น context (ดูภาพรวม) สำหรับ backtest: ต้องใช้ non-repaint เท่านั้น — ไม่งั้นผลไม่น่าเชื่อถือ

เปิดพอร์ต XM วันนี้ — โบรกที่ อ.บอม ใช้เทรดจริง (พาร์ทเนอร์ XM)

XM Legend · เทรดเดอร์ & ผู้สอน Forex 13 ปี

ผู้ก่อตั้ง SiamCafe ตั้งแต่ปี 1997 · เทรดเดอร์สาย Forex มากกว่า 13 ปี ได้รับการยกย่องเป็น XM Legend · แบ่งปันความรู้ Forex, ไอที, AI และการเทรด จากประสบการณ์จริงในตลาดจริง