// © geenabhud · XAULearn //@version=6 // ⚑ ชื่อเวอร์ชันมีที่เดียว — v1.0→v1.1→v1.2 เคยลืมแก้หัวตาราง ทำให้เครื่องมือรายงานตัวเองผิด VER = "v1.2" indicator("VWAP Distribution Levels " + VER, "VWAP-DL " + VER, overlay = true) // ════════════════════════════════════════════════════════════════════════════ // ทำไมตัวนี้ต่างจากอินดิเคเตอร์ VWAP-SD ทั่วไป — สองจุด และทั้งคู่วัดมาแล้ว // // ① σ รู้ล่วงหน้า ไม่ใช่ σ ในเซสชัน // สูตรมาตรฐาน dev = sqrt(Σvp²/Σv − vwap²) เป็นตัวหารที่พองตามตัวเศษ // ราคาวิ่งหนีไกล σ ก็กว้างตาม แถบจึงกว้างขึ้นพอดีกับตอนที่เกิดเหตุ // ผลคือ z ไม่เคยใหญ่ โดยโครงสร้าง // วัดบนทอง M1 ปี 2015-19 (1.77 ล้านแท่ง): ส่วนเกินความโก่งของ // (close − VWAP)/σ_สะสม = −0.3 … −0.5 คือ หางบางกว่าเกาส์เซียน // เปลี่ยนเป็น σ จากพิสัยเซสชันเดียวกัน 20 ครั้งก่อน ได้ +4.0 (นิวยอร์ก) // +6.8 (ลอนดอน) +68 (เอเชีย) ซึ่งคือหางอ้วนของจริง // ผลพลอยได้: แถบมีความกว้างเต็มตั้งแต่แท่งแรกของเซสชัน // // ② ตัวคูณวัดจากข้อมูล ไม่ใช่ควอนไทล์เกาส์เซียน — และมี "สองเกณฑ์" // // ต่อแท่ง (ค่าตั้งต้น) "ราคาปิดอยู่ในกรอบกี่ % ของแท่ง" // คือคำถามที่ตามองบนจอ · NY 0.58/0.98/1.54/2.44/3.95 // ต่อเซสชัน "ทั้งเซสชันไม่แตะกรอบกี่ %" // คือคำถามขอบเขตความเสี่ยง · NY 2.20/2.85/3.73/5.28/7.17 // เกาส์เซียน 0.67/1.04/1.44/1.96/2.58 // // ⚑ v1.0 ใช้เกณฑ์ต่อเซสชันเป็นค่าตั้งต้น ซึ่งกว้างเกินกว่าจะอ่านบนจอ // (L5 ห่าง VWAP ราว 100$ ที่ความผันผวนปี 2026) · v1.1 ตั้งต้นที่ต่อแท่ง // // ⭐ ลายเซ็นหางอ้วนอ่านได้จากเกณฑ์ต่อแท่งตรง ๆ: L1 **แคบกว่า** เกาส์เซียน // (0.58 < 0.67) แต่ L5 **กว้างกว่า 1.5 เท่า** (3.95 > 2.58) // = มวลกระจุกกลางมากขึ้น และไปไกลมากขึ้น พร่องตรงกลางทาง // ช่วงไดนามิก L5/L1 = 6.8 เท่า ขณะที่เกาส์เซียนให้แค่ 3.85 เท่า // // ⚑ ตัวนี้บอกว่าราคา "ไป" ถึงไหน ไม่ได้บอกว่าราคา "ตอบสนอง" ที่นั่น // ใช้เป็นสเกลความเสี่ยงได้ทันที (SL/TP ควรห่างเท่าไร) // ใช้เป็นสัญญาณต้องผ่านการทดสอบก่อน — L5 แตะ 1% ของเซสชัน = พิสูจน์ไม่ได้ // // คู่แฝด Python: edge/vwap_dist.py · ตารางตัวคูณตรงกันทุกตัว // ════════════════════════════════════════════════════════════════════════════ // ───── ① ขอบเขตที่แสดง ───────────────────────────────────────────────────── g1 = "① ขอบเขต" i_sess_on = input.bool(true, "แถบเซสชัน (เอเชีย/ลอนดอน/นิวยอร์ก)", group = g1) i_day_on = input.bool(true, "แถบวัน (ยึด 17:00 นิวยอร์ก)", group = g1) i_day_lvls = input.bool(false, "วาดระดับของขอบเขตวันด้วย", group = g1, tooltip = "ปิดไว้ = เห็นแค่เส้น VWAP ของวัน · เปิด = เพิ่มอีก 10 เส้น") i_lvl_max = input.int(5, "วาดถึงระดับที่", minval = 1, maxval = 5, group = g1) // ───── ② เครื่องประเมิน σ ────────────────────────────────────────────────── g2 = "② σ ที่รู้ล่วงหน้า" i_lb = input.int(20, "จำนวนเซสชันย้อนหลัง", minval = 5, maxval = 60, group = g2, tooltip = "ค่ากลางของพิสัยเซสชันเดียวกัน N ครั้งก่อน · ไม่มีข้อมูลเซสชันปัจจุบัน") i_div = input.float(4.0, "พิสัย → σ หารด้วย", minval = 2.0, maxval = 6.0, step = 0.25, group = g2, tooltip = "พิสัย ≈ 4σ สำหรับการเดินสุ่ม") i_src = input.source(hl2, "ราคาที่ใช้ถ่วงน้ำหนัก", group = g2) i_gvz = input.bool(true, "ปรับ σ ด้วยความผันผวนแฝง GVZ", group = g2, tooltip = "GVZ หารด้วยค่าเฉลี่ย 20 วันของตัวเอง แล้วคูณเข้ากับ σ // วัดแล้วความเบี่ยงเบนของความคุ้มครองลดจาก 1.08 เหลือ 0.90 จุด% และดีขึ้น 14 จาก 15 ช่องปี-เซสชัน // ปิดได้ถ้าสัญลักษณ์ CBOE:GVZ ใช้ไม่ได้") i_gvzsym = input.symbol("CBOE:GVZ", "สัญลักษณ์ความผันผวนแฝง", group = g2) // ───── ③ ตัวคูณ ──────────────────────────────────────────────────────────── g3 = "③ ตัวคูณ (วัดจาก DEV 2015-19)" i_calib = input.string("ต่อแท่ง", "เกณฑ์คาลิเบรต", options = ["ต่อแท่ง", "ต่อเซสชัน"], group = g3, tooltip = "ต่อแท่ง = ราคาปิดอยู่ในกรอบกี่ % ของแท่ง คือสิ่งที่ตามองบนจอ // ต่อเซสชัน = ทั้งเซสชันไม่แตะกรอบกี่ % คือขอบเขตความเสี่ยง กว้างกว่าเกือบเท่าตัว") i_gauss = input.bool(false, "ใช้ตัวคูณเกาส์เซียนแทน (ด่านควบคุม)", group = g3, tooltip = "0.67/1.04/1.44/1.96/2.58 · เปิดเพื่อเห็นว่าเกาส์เซียนแคบแค่ไหน") i_cmp = input.bool(false, "เทียบกับ σ สะสมแบบเดิมที่ระดับ 3", group = g3, tooltip = "เส้นกากบาท = สิ่งที่อินดิเคเตอร์ VWAP-SD ทั่วไปวาด ณ ตัวคูณเดียวกัน") // ───── ④ สี ──────────────────────────────────────────────────────────────── g4 = "④ สี" c_vw = input.color(#ffffff, "VWAP เซสชัน", group = g4) c_dvw = input.color(#ffb300, "VWAP วัน", group = g4) c_up = input.color(#ef5350, "ระดับฝั่งบน", group = g4) c_dn = input.color(#26a69a, "ระดับฝั่งล่าง", group = g4) i_fill = input.int(93, "ความโปร่งของพื้นที่ระบาย", minval = 70, maxval = 100, group = g4) i_fill_to = input.int(2, "ระบายถึงระดับที่", minval = 0, maxval = 5, group = g4, tooltip = "0 = ไม่ระบายเลย · ระบายทั้ง 5 ชั้นทำให้จอทึบจนบังแท่งเทียน") g5 = "⑤ ตาราง" i_tbl = input.bool(true, "แสดงตารางสถานะ", group = g5) // ════════════════════════════════════════════════════════════════════════════ // เวลานิวยอร์ก และรหัสเซสชัน // ════════════════════════════════════════════════════════════════════════════ // ⭐ GVZ — ความผันผวนแฝงของออปชันทอง · ใช้แท่งวันที่ปิดแล้วเท่านั้น (lookahead_off) gvz_raw = request.security(i_gvzsym, "D", close[1], barmerge.gaps_off, barmerge.lookahead_off) gvz_avg = request.security(i_gvzsym, "D", ta.sma(close[1], 20), barmerge.gaps_off, barmerge.lookahead_off) gvz_r = i_gvz and not na(gvz_raw) and not na(gvz_avg) and gvz_avg > 0 ? gvz_raw / gvz_avg : 1.0 TZ = "America/New_York" hm = hour(time, TZ) * 100 + minute(time, TZ) // 0 = เอเชีย (17:00–03:00) · 1 = ลอนดอน (03:00–08:00) · 2 = นิวยอร์ก (08:00–17:00) sid = hm >= 800 and hm < 1700 ? 2 : hm >= 300 and hm < 800 ? 1 : 0 new_sess = ta.change(sid) != 0 or barstate.isfirst // วันเทรดเริ่มเมื่อเข้าเซสชันเอเชีย = 17:00 นิวยอร์ก · กันเวลาออมแสงเพราะ // อ่าน hm จากโซนเวลา ไม่ใช่จากออฟเซ็ตคงที่ · และไม่ใช้แท่ง D1 ของผู้ให้ข้อมูล // (แท่ง D1 ติดป้ายด้วยเวลาเปิด การ join แบบวันปฏิทินคืออ่านอนาคต 17 ชม.) new_day = (sid == 0 and nz(sid[1], -1) != 0) or barstate.isfirst // ════════════════════════════════════════════════════════════════════════════ // คลังพิสัยย้อนหลัง — หนึ่งคลังต่อชนิดเซสชัน บวกอีกหนึ่งของขอบเขตวัน // ════════════════════════════════════════════════════════════════════════════ var array hist_asia = array.new_float() var array hist_lon = array.new_float() var array hist_ny = array.new_float() var array hist_day = array.new_float() push(array a, float v) => if not na(v) and v > 0 array.push(a, v) if array.size(a) > i_lb array.shift(a) sigma_of(array a) => float base = array.size(a) >= i_lb ? array.median(a) / i_div : float(na) na(base) ? float(na) : base * gvz_r // ── ตัวสะสมของเซสชัน ─────────────────────────────────────────────────────── var float s_anchor = na var float s_wsum = 0.0 var float s_wdsum = 0.0 var float s_wd2 = 0.0 var float s_hi = na var float s_lo = na var float s_sig = na var int s_id = 0 // ── ตัวสะสมของวัน ────────────────────────────────────────────────────────── var float d_anchor = na var float d_wsum = 0.0 var float d_wdsum = 0.0 var float d_hi = na var float d_lo = na var float d_sig = na if new_sess // ปิดเซสชันก่อนหน้า: เก็บพิสัยเข้าคลังของชนิดนั้น แล้วค่อยรีเซ็ต if not na(s_hi) and not na(s_lo) float r = s_hi - s_lo if s_id == 0 push(hist_asia, r) else if s_id == 1 push(hist_lon, r) else push(hist_ny, r) s_id := sid s_anchor := i_src s_wsum := 0.0 s_wdsum := 0.0 s_wd2 := 0.0 s_hi := high s_lo := low // σ ของเซสชันที่กำลังเปิด — รู้ค่าทันทีตั้งแต่แท่งแรก float sg = sid == 0 ? sigma_of(hist_asia) : sid == 1 ? sigma_of(hist_lon) : sigma_of(hist_ny) s_sig := sg if new_day if not na(d_hi) and not na(d_lo) push(hist_day, d_hi - d_lo) d_anchor := i_src d_wsum := 0.0 d_wdsum := 0.0 d_hi := high d_lo := low d_sig := sigma_of(hist_day) // ── สะสม · หักจุดยึดก่อนยกกำลังสอง เลี่ยงการสูญเสียนัยสำคัญ ──────────────── // สูตร Σvp²/Σv − vwap² ลบเลขใหญ่สองตัวที่เกือบเท่ากัน (ทองราคา 4 หลัก ⇒ // p² ราว 1e7 แต่ความแปรปรวนราว 1) · max(...,0) ในสคริปต์ทั่วไปคือร่องรอย // ว่าเจ้าของเคยเห็นมันติดลบ · หักจุดยึดก่อนแล้วปัญหานี้หายไป w = math.max(nz(volume), 1e-9) ds = i_src - s_anchor s_wsum += w s_wdsum += w * ds s_wd2 += w * ds * ds s_hi := math.max(nz(s_hi, high), high) s_lo := math.min(nz(s_lo, low), low) dd = i_src - d_anchor d_wsum += w d_wdsum += w * dd d_hi := math.max(nz(d_hi, high), high) d_lo := math.min(nz(d_lo, low), low) s_mu = s_wsum > 0 ? s_wdsum / s_wsum : 0.0 s_vwap = s_anchor + s_mu d_vwap = d_anchor + (d_wsum > 0 ? d_wdsum / d_wsum : 0.0) // σ สะสมแบบเดิม — เก็บไว้เทียบเท่านั้น ไม่ได้ใช้วางระดับ s_var = s_wsum > 0 ? s_wd2 / s_wsum - s_mu * s_mu : 0.0 s_sd_live = math.sqrt(math.max(s_var, 0.0)) // ════════════════════════════════════════════════════════════════════════════ // ตัวคูณ — คาลิเบรตที่ความคุ้มครองสองฝั่ง 50/70/85/95/99% // ════════════════════════════════════════════════════════════════════════════ mult(int which, int k) => // which: 0=เอเชีย 1=ลอนดอน 2=นิวยอร์ก 3=วัน · k: 1..5 float m = na bool bar_mode = i_calib == "ต่อแท่ง" if i_gauss m := k == 1 ? 0.67 : k == 2 ? 1.04 : k == 3 ? 1.44 : k == 4 ? 1.96 : 2.58 else if bar_mode and which == 0 m := i_gvz ? (k == 1 ? 0.49 : k == 2 ? 0.84 : k == 3 ? 1.30 : k == 4 ? 2.02 : 3.22) : (k == 1 ? 0.48 : k == 2 ? 0.83 : k == 3 ? 1.29 : k == 4 ? 2.03 : 3.31) else if bar_mode and which == 1 m := i_gvz ? (k == 1 ? 0.54 : k == 2 ? 0.91 : k == 3 ? 1.41 : k == 4 ? 2.20 : 3.47) : (k == 1 ? 0.53 : k == 2 ? 0.90 : k == 3 ? 1.39 : k == 4 ? 2.21 : 3.54) else if bar_mode and which == 2 m := i_gvz ? (k == 1 ? 0.58 : k == 2 ? 0.99 : k == 3 ? 1.56 : k == 4 ? 2.46 : 3.91) : (k == 1 ? 0.58 : k == 2 ? 0.98 : k == 3 ? 1.54 : k == 4 ? 2.44 : 3.95) else if bar_mode m := i_gvz ? (k == 1 ? 0.44 : k == 2 ? 0.79 : k == 3 ? 1.31 : k == 4 ? 2.25 : 3.74) : (k == 1 ? 0.44 : k == 2 ? 0.78 : k == 3 ? 1.30 : k == 4 ? 2.25 : 3.72) else if which == 0 m := k == 1 ? 2.14 : k == 2 ? 2.77 : k == 3 ? 3.54 : k == 4 ? 5.02 : 7.44 else if which == 1 m := k == 1 ? 2.28 : k == 2 ? 2.92 : k == 3 ? 3.69 : k == 4 ? 5.00 : 7.48 else if which == 2 m := k == 1 ? 2.20 : k == 2 ? 2.85 : k == 3 ? 3.73 : k == 4 ? 5.28 : 7.17 else m := k == 1 ? 2.28 : k == 2 ? 2.92 : k == 3 ? 3.78 : k == 4 ? 5.09 : 7.36 m lvl(float base, float sig, int which, int k, bool up, bool on) => float m = mult(which, k) float r = na if on and k <= i_lvl_max and not na(sig) r := up ? base + m * sig : base - m * sig r sOK = i_sess_on dOK = i_day_on and i_day_lvls su1 = lvl(s_vwap, s_sig, s_id, 1, true, sOK) sd1 = lvl(s_vwap, s_sig, s_id, 1, false, sOK) su2 = lvl(s_vwap, s_sig, s_id, 2, true, sOK) sd2 = lvl(s_vwap, s_sig, s_id, 2, false, sOK) su3 = lvl(s_vwap, s_sig, s_id, 3, true, sOK) sd3 = lvl(s_vwap, s_sig, s_id, 3, false, sOK) su4 = lvl(s_vwap, s_sig, s_id, 4, true, sOK) sd4 = lvl(s_vwap, s_sig, s_id, 4, false, sOK) su5 = lvl(s_vwap, s_sig, s_id, 5, true, sOK) sd5 = lvl(s_vwap, s_sig, s_id, 5, false, sOK) du1 = lvl(d_vwap, d_sig, 3, 1, true, dOK) dl1 = lvl(d_vwap, d_sig, 3, 1, false, dOK) du2 = lvl(d_vwap, d_sig, 3, 2, true, dOK) dl2 = lvl(d_vwap, d_sig, 3, 2, false, dOK) du3 = lvl(d_vwap, d_sig, 3, 3, true, dOK) dl3 = lvl(d_vwap, d_sig, 3, 3, false, dOK) du4 = lvl(d_vwap, d_sig, 3, 4, true, dOK) dl4 = lvl(d_vwap, d_sig, 3, 4, false, dOK) du5 = lvl(d_vwap, d_sig, 3, 5, true, dOK) dl5 = lvl(d_vwap, d_sig, 3, 5, false, dOK) // เส้นเทียบ: σ สะสม ที่ตัวคูณระดับ 3 ตัวเดียวกัน cm3 = mult(s_id, 3) cu3 = i_cmp and i_sess_on ? s_vwap + cm3 * s_sd_live : na cl3 = i_cmp and i_sess_on ? s_vwap - cm3 * s_sd_live : na // ════════════════════════════════════════════════════════════════════════════ // วาด // ════════════════════════════════════════════════════════════════════════════ pV = plot(i_sess_on ? s_vwap : na, "VWAP เซสชัน", c_vw, 2) pU1 = plot(su1, "เซสชัน +L1 (50%)", color.new(c_up, 35), 1) pD1 = plot(sd1, "เซสชัน −L1 (50%)", color.new(c_dn, 35), 1) pU2 = plot(su2, "เซสชัน +L2 (70%)", color.new(c_up, 30), 1) pD2 = plot(sd2, "เซสชัน −L2 (70%)", color.new(c_dn, 30), 1) pU3 = plot(su3, "เซสชัน +L3 (85%)", color.new(c_up, 20), 1) pD3 = plot(sd3, "เซสชัน −L3 (85%)", color.new(c_dn, 20), 1) pU4 = plot(su4, "เซสชัน +L4 (95%)", color.new(c_up, 10), 2) pD4 = plot(sd4, "เซสชัน −L4 (95%)", color.new(c_dn, 10), 2) pU5 = plot(su5, "เซสชัน +L5 (99%)", c_up, 2) pD5 = plot(sd5, "เซสชัน −L5 (99%)", c_dn, 2) plot(i_day_on ? d_vwap : na, "VWAP วัน", c_dvw, 2) plot(du1, "วัน +L1", color.new(c_dvw, 55), 1) plot(dl1, "วัน −L1", color.new(c_dvw, 55), 1) plot(du2, "วัน +L2", color.new(c_dvw, 50), 1) plot(dl2, "วัน −L2", color.new(c_dvw, 50), 1) plot(du3, "วัน +L3", color.new(c_dvw, 40), 1) plot(dl3, "วัน −L3", color.new(c_dvw, 40), 1) plot(du4, "วัน +L4", color.new(c_dvw, 25), 1) plot(dl4, "วัน −L4", color.new(c_dvw, 25), 1) plot(du5, "วัน +L5", color.new(c_dvw, 10), 2) plot(dl5, "วัน −L5", color.new(c_dvw, 10), 2) plot(cu3, "เทียบ σ สะสม +L3", color.new(color.gray, 20), 1, plot.style_cross) plot(cl3, "เทียบ σ สะสม −L3", color.new(color.gray, 20), 1, plot.style_cross) f1 = i_fill_to >= 1 ? i_fill : 100 f2 = i_fill_to >= 2 ? i_fill : 100 f3 = i_fill_to >= 3 ? i_fill : 100 f4 = i_fill_to >= 4 ? i_fill : 100 f5 = i_fill_to >= 5 ? i_fill : 100 fill(pV, pU1, color.new(c_up, f1), "ระบาย VWAP→L1 บน") fill(pV, pD1, color.new(c_dn, f1), "ระบาย VWAP→L1 ล่าง") fill(pU1, pU2, color.new(c_up, f2), "ระบาย L1→L2 บน") fill(pD1, pD2, color.new(c_dn, f2), "ระบาย L1→L2 ล่าง") fill(pU2, pU3, color.new(c_up, f3), "ระบาย L2→L3 บน") fill(pD2, pD3, color.new(c_dn, f3), "ระบาย L2→L3 ล่าง") fill(pU3, pU4, color.new(c_up, f4), "ระบาย L3→L4 บน") fill(pD3, pD4, color.new(c_dn, f4), "ระบาย L3→L4 ล่าง") fill(pU4, pU5, color.new(c_up, f5), "ระบาย L4→L5 บน") fill(pD4, pD5, color.new(c_dn, f5), "ระบาย L4→L5 ล่าง") // ── ตารางสถานะ ───────────────────────────────────────────────────────────── sess_name = s_id == 0 ? "เอเชีย" : s_id == 1 ? "ลอนดอน" : "นิวยอร์ก" zs = na(s_sig) or s_sig <= 0 ? float(na) : (close - s_vwap) / s_sig m4 = mult(s_id, 4) var table tb = table.new(position.top_right, 2, 6, border_width = 1) if i_tbl and barstate.islast table.cell(tb, 0, 0, "VWAP-DL " + VER, text_color = color.white, bgcolor = color.new(color.black, 20), text_size = size.small) table.cell(tb, 1, 0, i_gauss ? "เกาส์เซียน" : i_calib, text_color = color.white, bgcolor = color.new(i_gauss ? color.red : color.teal, 40), text_size = size.small) table.cell(tb, 0, 1, "เซสชัน", text_color = color.gray, text_size = size.small) table.cell(tb, 1, 1, sess_name, text_color = color.white, text_size = size.small) table.cell(tb, 0, 2, "σ รู้ล่วงหน้า", text_color = color.gray, text_size = size.small) table.cell(tb, 1, 2, na(s_sig) ? "รอข้อมูล" : str.tostring(s_sig, "#.##") + " $", text_color = color.white, text_size = size.small) table.cell(tb, 0, 3, "σ สะสม (เทียบ)", text_color = color.gray, text_size = size.small) table.cell(tb, 1, 3, str.tostring(s_sd_live, "#.##") + " $", text_color = color.gray, text_size = size.small) table.cell(tb, 0, 4, "ราคาอยู่ที่", text_color = color.gray, text_size = size.small) table.cell(tb, 1, 4, na(zs) ? "—" : str.tostring(zs, "#.##") + " σ", text_color = na(zs) ? color.gray : math.abs(zs) >= m4 ? color.yellow : color.white, text_size = size.small) table.cell(tb, 0, 5, i_gvz ? "อัตราส่วน GVZ" : "σ วัน", text_color = color.gray, text_size = size.small) table.cell(tb, 1, 5, i_gvz ? str.tostring(gvz_r, "#.###") + "×" : (na(d_sig) ? "รอข้อมูล" : str.tostring(d_sig, "#.##") + " $"), text_color = i_gvz ? (gvz_r > 1.05 ? color.yellow : gvz_r < 0.95 ? color.aqua : color.white) : c_dvw, text_size = size.small)