กลยุทธ์สร้างผลลัพธ์ที่ดีเกินจริงด้วยการมองไปสู่อนาคต

เป้าหมายหลักประการหนึ่งของเราในการพัฒนาภาษา Pine คือการจัดหาเครื่องมือที่มีประโยชน์ให้ผู้ใช้มากที่สุด เครื่องมือเหล่านี้อาจมีการใช้งานที่แตกต่างกัน และด้วยการปรับเปลี่ยนบางอย่าง อินดิเคเตอร์และประเภทชาร์ตบางประเภททำให้คุณสามารถดึงข้อมูลจากบาร์หรือการซื้อขายในอนาคต (เทียบกับบาร์ที่ประมวลผลในปัจจุบัน) เนื่องจากเทรดเดอร์ไม่สามารถรับข้อมูลนี้ในการซื้อขายจริง กลยุทธ์ที่สร้างขึ้นจากข้อมูลนั้นสามารถสร้างผลกำไรที่ไม่สมจริงเมื่อทำการทดสอบย้อนหลัง ในขณะที่การซื้อขายแบบเรียลไทม์จะขาดทุน ความผิดพลาดในการใช้ข้อมูลจากอนาคตในกลยุทธ์เรียกอีกอย่างว่าความลำเอียงมองไปข้างหน้า

ผู้ใช้งาน TradingView บางราย ด้วยความไม่รู้หรือมีเจตนามุ่งร้าย มีแนวโน้มที่จะสร้างแนวคิดและการเผยแพร่สคริปต์ที่ใช้ประโยชน์จากคุณลักษณะนี้ TradingView ไม่สามารถลบคุณลักษณะนี้ออกได้ เนื่องจากอาจมีประโยชน์ในบางกรณี แต่ในขณะเดียวกัน เรามุ่งมั่นที่จะเตือนผู้ใช้ถึงพฤติกรรมนี้

กลยุทธ์การใช้แท่งเทียนสไตล์ญี่ปุ่น

สาเหตุที่พบบ่อยมากสำหรับพฤติกรรมนี้คือการทำ backtesting ของกลยุทธ์ในชาร์ตสไตล์ญี่ปุ่น (Renko, Kagi ฯลฯ) ปัญหาเกิดขึ้นจากการที่ Strategy Backtesting Engine พิจารณาแต่ละแท่งเป็น 4 ธุรกรรม โดยมีราคาเปิด, สูง, ต่ำ และปิด (เช่นเดียวกับชาร์ตแท่งเทียนปกติ) ด้วยเหตุนี้ บนชาร์ต Renko เครื่องมือ Backtesting ของกลยุทธ์จึงสามารถเข้า/ออกจากโพสิชั่นในราคาที่ไม่มีอยู่จริง นอกจากนี้ หากคุณตั้งค่า Box Size ให้เล็กกว่า mintick คุณสามารถตรวจสอบได้ว่าราคาถัดไปจะสูงหรือต่ำกว่าราคาปัจจุบันและเข้า/ออกจากโพสิชั่นล่วงหน้า ก่อนที่ Backtesting Engine จะประมวลผล ราคาจริง.

//@version=5
strategy("My Strategy", overlay=true)
if close < close[1]
    strategy.entry("ShortEntryId", strategy.short)
strategy.close("ShortEntryId", when = close > close[1])

if close > close[1]
    strategy.entry("LongEntryId", strategy.long)
strategy.close("LongEntryId", when = close < close[1])

ดังที่คุณเห็นในภาพหน้าจอ กลยุทธ์ง่ายๆ นี้สามารถสร้างข้อตกลงในราคาที่ใกล้เคียงกับราคาสูงสุด/ต่ำสุด

กลยุทธ์ที่ใช้พารามิเตอร์ calc_on_order_fills = true

เมื่อพารามิเตอร์ calc_on_order_fills = true ถูกระบุในฟังก์ชันกลยุทธ์ Backtesting Engine จะทำการคำนวณเพิ่มเติมภายในบาร์หลังจากดำเนินการตามออร์เดอร์ (ตรงกันข้ามกับสถานการณ์ปกติเมื่อคำนวณกลยุทธ์เมื่อปิดบาร์ เท่านั้น) ในขณะเดียวกัน ในระหว่างการคำนวณ กลยุทธ์จะเข้าถึงพารามิเตอร์แท่งเพิ่มเติมมากมาย เช่น ค่าสูงและค่าต่ำ วิธีนี้ช่วยให้คุณเขียนกลยุทธ์ที่จะแสดงประสิทธิภาพที่ยอดเยี่ยมขณะทำการทดสอบย้อนหลังได้:

//@version=5
strategy("CalcOnOrderFillsStrategy", overlay=true, calc_on_order_fills=true)

// a variable is used to prevent double entry on the same bar
var lastTimeEntry = 0

longCondition = close > sma(close, 14)  and lastTimeEntry != time
if longCondition
    strategy.entry("LongEntryId", strategy.long)

strategy.exit("exitId", "LongEntryId", limit=high)
lastTimeEntry := time

ในภาพหน้าจอ คุณจะเห็นว่ารายการอยู่ที่ราคาเปิดของบาร์ และทางออกจะเกิดขึ้นที่จุดสูงสุดของบาร์เดียวกัน นั่นคือ ระหว่างการคำนวณ หลังจากดำเนินการตามออร์เดอร์ เรากำหนดราคาลิมิตของ Strategy.exit ให้เท่ากับระดับสูงของบาร์ปัจจุบัน ซึ่งเราไม่สามารถทำในการซื้อขายจริงได้

พารามิเตอร์ lookahead = barmerge.lookahead_on ในความปลอดภัยและการรักษาความปลอดภัยใดๆ ก่อน Pine v3

ฟังก์ชันความปลอดภัยใน Pine ช่วยให้คุณสามารถขอข้อมูลจากสัญลักษณ์และ/หรือไทม์เฟรมอื่นๆ ขึ้นอยู่กับการใช้งาน วิธีนี้อาจทำให้กลยุทธ์ได้รับข้อมูลจากอนาคต: ตัวอย่างเช่น หากมีคำขอปิดหรือสูงของแท่งรายวัน ในขณะที่การทดสอบย้อนหลังของกลยุทธ์สามารถทราบค่าเหล่านี้ได้ทันทีที่เปิดของวัน

ก่อนเวอร์ชัน 3 ฟังก์ชันความปลอดภัยจะคืนค่าจากไทม์เฟรมที่สูงกว่า ก่อนที่มันจะสามารถเข้าถึงได้ ในเวอร์ชัน 3 ลักษณะการทำงานนี้ได้รับการแก้ไขแล้ว แต่สำหรับความเข้ากันได้ พารามิเตอร์ lookahead ถูกเพิ่มในฟังก์ชันความปลอดภัย โดยค่าเริ่มต้นจะเป็นเท็จ (เช่น ปิดการมองเห็นในอนาคต) แต่คุณสามารถเปิดใช้งานได้โดยการตั้งค่าพารามิเตอร์ lookahead เป็น barmerge.lookahead_on

ตัวอย่างของกลยุทธ์ที่สร้างผลกำไรโดยใช้คุณลักษณะนี้:

//@version=5
strategy("My Strategy", overlay=true)
dayStart = request.security(syminfo.tickerid, "1D", time, lookahead=barmerge.lookahead_on)
dayHigh = request.security(syminfo.tickerid, "1D", high, lookahead=barmerge.lookahead_on)
dayLow = request.security(syminfo.tickerid, "1D", low, lookahead=barmerge.lookahead_on)

// entry at first bar of a day
if time == dayStart
    // distance to daily high is further, so we can earn more
    if math.abs(open - dayHigh) > math.abs(open - dayLow)
        strategy.entry("LongEntryId", strategy.long)
        strategy.exit("exitLongId", "LongEntryId", limit=dayHigh)
    else
        strategy.entry("ShortEntryId", strategy.short)
        strategy.exit("exitShortId", "ShortEntryId", limit=dayLow)
        
plot(dayHigh)
plot(dayLow)

ในบาร์แรก เราวิเคราะห์ว่าราคาจะขยับขึ้นหรือลงมากขึ้นเมื่อเทียบกับราคาเปิด และจากข้อมูลนี้ เราจะเข้าสู่โพสิชั่น Long หรือ Short จากนั้นออกที่ราคาสูงสุดหรือต่ำสุดของวันตามลำดับ

โปรดทราบว่าไม่ใช่ทุกกรณีที่ request.security() มีอาร์กิวเมนต์ barmerge.lookahead_on มองไปในอนาคต ตัวอย่างเช่น หากเราต้องเปลี่ยนโค้ดด้านบนโดยแทนที่ time/high/low ภายใน request.security() เป็น time[1 ]/high[1]/low[1] ตามลำดับ เราจะได้รับค่าสำหรับแท่งที่ปิดไปแล้ว มักใช้โดยโค๊ดเดอร์ผู้มีประสบการณ์เพื่อรับข้อมูลจาก request.security() โดยไม่ต้องเสี่ยงกับการมองไปข้างหน้า

ในขณะนี้ สิ่งเหล่านี้เป็นวิธีที่ทราบกันดีสำหรับกลยุทธ์ในการมองไปสู่อนาคต เราหวังว่าคำอธิบายนี้จะช่วยให้คุณสร้างกลยุทธ์ที่ไม่มีข้อบกพร่องเหล่านี้ ตลอดจนหลีกเลี่ยงกลยุทธ์ที่เผยแพร่ซึ่งผู้เขียนใช้ประโยชน์จากคุณลักษณะเหล่านี้ในแนวคิดของตน