เพื่อสนับสนุนวงการลงทุนด้วยระบบเทรดในเมืองไทยให้ก้าวไปข้างหน้าในระดับสากล ด้วยการให้ความรู้แก่ นลท สายควอนทฺ (Quants) ในการเขียน AmiBroker AFL CODE ให้โค้ดถูกต้อง โค้ดครบถ้วน และโค้ดเป็นระเบียบ (ลำดับโค้ดสำคัญมาก) ซึ่งจะช่วยให้สามารถพัฒนากลยุทธ์/ระบบเทรด (Strategies และ Trading System) อย่างมีประสิทธิภาพและต่อยอดได้ง่ายขึ้น อีกทั้งยังทำให้ เรา นลท สายควอนทฺ พูดจาภาษาเดียวกัน ใช้โครงสร้างโค้ดคล้ายๆกัน ด้วยเทมเพลต (template) ที่ได้ถูกออกแบบสำหรับการสร้าง Trading Platform โดยเฉพาะ
หมายเหตุ: No Copyright or Any Rights Reserved ไม่สงวนลิขสิทธิ์ใดๆทั้งสิ้น ผู้ที่สนใจสามารถนำไปใช้ได้เลย ไม่ต้องขออนุญาติ ไม่ต้องอ้างอิงถึงก็ได้ ถ้าไม่สะดวก
Template จะแบ่งออกได้เป็น 7 ส่วน (สีเข้ม คือ ส่วนที่ต้องใช้แน่นอน)
- OPTIONS ตั้งค่าสำคัญต่างๆที่ต้องใช้ในการทดสอบ Backtest ซึ่งส่วนใหญ่อยู่ในรูปแบบของตัวเลข
- MARKET ANALYSIS ใช้สำหรับวิเคราะห์หาสภาพตลาดที่เอื้ออำนวนต่อการลงทุน
- SIGNALS สัญญาณซื้อขาย Buy และ Sell ซึ่งจะถูกเขียนในรูปแบบเงื่อนไข Conditions
- POSITIONS เป็นส่วนของการบริหารหน้าตัก รวมถึงเรียงลำดับความสำคัญของสัญญาณเข้าซื้อ
- STOPS เป็นส่วนของการขายหุ้นในพอร์ต ที่ไม่ได้มาจาก Sell Signals เช่น การคัทลอส และการขายล๊อคกำไร
- SIMULATION & RISK เป็นการผนวกความผันผวน ความเสี่ยงเข้าไปในการทดสอบ และ/หรือจำลองการเทรด
- CUSTOM BACKTEST เป็นการเขียนโค้ด AmiBroker ขั้นกลาง-สูง เพื่อให้ได้การวิเคราะห์ที่ละเอียดขึ้น
และใน template ยังมีโค้ดจิ๋วสั้นๆ (code snippets) ที่มีหน้าที่เฉพาะเจาะจง มักจำเป็นต้องใช้ในทุกกลยุทธ์
- โค้ดจิ๋วเลี่ยงหุ้นแตกพาร์ Avoid stock split
- โค้ดจิ๋วเลี่ยงหุ้นเพิกถอนและหุ้นที่ถูกเปลี่ยนชื่อ Avoid stock delisted and renamed
- โค้ดจิ๋วปรับ tick size ตามช่วงระดับราคาหุ้น
- โค้ดจิ๋วจำลองการพลาดการเข้าซื้อหุ้น (Missing Trades)
- โค้ดจิ๋วจำลองการ slippage ด้วย Random ฟังก์ชั่น
CONCISE TEMPLATE แบบกระชับ
เหมาะสำหรับผู้เริ่มต้น และ/หรือผู้ที่ได้เรียน ABEC ซึ่ง template ตัวนี้จะละเว้นในส่วนของ Market Analysis และ Simulation รวมถึงโค้ดจิ๋วปรับ tick size (ที่มีผลกระทบเพียงเล็กน้อย)
/** CONCISE TEMPLATE with #required info No Copyright or Any Rights Reserved @link https://bit.ly/tq-template */ {//1. OPTIONS MOP = #required; SetOption("MaxOpenPositions", MOP); SetOption("InitialEquity", #required); SetOption("CommissionMode", 1); SetOption("CommissionAmount", 0.2); SetOption("AllowPositionShrinking", 1); RoundLotSize = 100; BuyPrice = SellPrice = Open; signalDelay = #required; SetTradeDelays(signalDelay, signalDelay, 0, 0); } {//2. MARKET ANALYSIS (empty) } {//3. SIGNALS buyCon1 = #required; buyCon2 = #required; Buy = buyCon1 AND buyCon2; sellCon1 = #required; sellCon2 = #required; Sell = sellCon1 AND sellCon2; Short = 0; Cover = 0; {//Avoid stock split (Don't change) C0 = Ref(C, 0); C1 = Ref(C, 1); C2 = Ref(C, 2); difC1C0 = abs( (C1 - C0)/C0 ) * 100; difC2C1 = abs( (C2 - C1)/C1 ) * 100; detectSplit = 0.35 * 100; buyConAvoidSplit = !(difC1C0 > detectSplit) AND !(difC2C1 > detectSplit); sellConAvoidSplit = (difC1C0 > detectSplit) OR (difC2C1 > detectSplit); Buy &= buyConAvoidSplit; Sell |= sellConAvoidSplit; } {//Avoid stock delisted and renamed (Don't change) buyConAvoidDelisted = BarIndex() < (LastValue(BarIndex()) - signalDelay - 1); sellConAvoidDelisted = BarIndex() >= (LastValue(BarIndex()) - signalDelay - 1); Buy &= buyConAvoidDelisted; Sell |= sellConAvoidDelisted; } } {//4. POSITIONS PositionScore = #required; SetPositionSize(100/MOP, spsPercentOfEquity); } {//5. STOPS stopLoss = #required; ApplyStop(stopTypeLoss, stopModePercent, stopLoss); } {//6. SIMULATION AND RISK slippage = #required; BuyPrice = BuyPrice*(1 + slippage/100); SellPrice = SellPrice*(1 - slippage/100); } {//7. CUSTOM BACKTEST (empty) }
FULL TEMPLATE แบบเต็ม สำหรับคนทั่วไป
เหมาะสำหรับผู้ที่มีประสบการณ์ในระดับหนึ่ง หรือผู้ที่ได้เรียน ABQC ซึ่งมีความรู้ในการทำ Market Analysis และการทำ Simulation ใน AmiBroker แล้ววิเคราะห์ผลลัพธ์ที่ได้ด้วย Excel เพื่อหาค่าสำคัญที่ Confidence Level ระดับต่างๆ
/** FULL TEMPLATE with #required info No Copyright or Any Rights Reserved @link https://bit.ly/tq-template */ {//1. OPTIONS MOP = #required; SetOption("MaxOpenPositions", MOP); SetOption("InitialEquity", #required); SetOption("CommissionMode", 1); SetOption("CommissionAmount", 0.2); SetOption("AllowPositionShrinking", 1); //SetOption("UsePrevBarEquityForPosSizing", 1); //SetOption("MinPosValue", 10000); //SetOption("MinShares", 100); RoundLotSize = 100; BuyPrice = SellPrice = Open; signalDelay = #required; SetTradeDelays(signalDelay, signalDelay, 0, 0); } {//2. MARKET ANALYSIS SetForeign("SET"); buyConMK = #required; RestorePriceArrays(); } {//3. SIGNALS buyCon1 = #required; buyCon2 = #required; Buy = buyConMK AND buyCon1 AND buyCon2; sellCon1 = #required; sellCon2 = #required; Sell = sellCon1 AND sellCon2; Short = 0; Cover = 0; {//Avoid stock split (Don't change) C0 = Ref(C, 0); C1 = Ref(C, 1); C2 = Ref(C, 2); difC1C0 = abs( (C1 - C0)/C0 ) * 100; difC2C1 = abs( (C2 - C1)/C1 ) * 100; detectSplit = 0.35 * 100; buyConAvoidSplit = !(difC1C0 > detectSplit) AND !(difC2C1 > detectSplit); sellConAvoidSplit = (difC1C0 > detectSplit) OR (difC2C1 > detectSplit); Buy &= buyConAvoidSplit; Sell |= sellConAvoidSplit; } {//Avoid stock delisted and renamed (Don't change) buyConAvoidDelisted = BarIndex() < (LastValue(BarIndex()) - signalDelay - 1); sellConAvoidDelisted = BarIndex() >= (LastValue(BarIndex()) - signalDelay - 1); Buy &= buyConAvoidDelisted; Sell |= sellConAvoidDelisted; } } {//4. POSITIONS PositionScore = #required; SetPositionSize(100/MOP, spsPercentOfEquity); } {//5. STOPS stopLoss = #required; ApplyStop(stopTypeLoss, stopModePercent, stopLoss); //ApplyStop(stopTypeTrailing, stopModePercent, #required); //ApplyStop(stopTypeProfit, stopModePercent, #required); //ApplyStop(stopTypeNBar, stopModeBars, #required); } {//6. SIMULATION AND RISK missingTrades = #required; Buy &= IIf(Random() < 1 - missingTrades/100, 1, 0); Sell &= IIf(Random() < 1 - missingTrades/100, 1, 0); slippage = #required; BuyPrice = BuyPrice*(1 + slippage*Random()/100); SellPrice = SellPrice*(1 - slippage*Random()/100); {//Correct tick size (Don't change) //avgPrice = (Open + Close)/2; //avgPrice = (Low + High)/2; avgPrice = Open; TickSize = IIf(avgPrice < 2, 0.01, IIf(avgPrice < 5, 0.02, IIf(avgPrice < 10, 0.05, IIf(avgPrice < 25, 0.10, IIf(avgPrice < 100, 0.25, IIf(avgPrice < 200, 0.50, IIf(avgPrice < 400, 1.00, 2.00 ))))))); BuyPrice = Prec(ceil(BuyPrice/TickSize)*TickSize,2); SellPrice = Prec(floor(SellPrice/TickSize)*TickSize,2); } } {//7. CUSTOM BACKTEST (empty) }
FINAL TEMPLATE with Simulation Runs
/** FINAL TEMPLATE with Simulation Runs and #required info No Copyright or Any Rights Reserved @link https://bit.ly/tq-template */ {//1. OPTIONS MOP = #required; SetOption("MaxOpenPositions", MOP); SetOption("InitialEquity", #required); SetOption("CommissionMode", 1); SetOption("CommissionAmount", 0.2); SetOption("AllowPositionShrinking", 1); //SetOption("UsePrevBarEquityForPosSizing", 1); //SetOption("MinPosValue", 10000); //SetOption("MinShares", 100); RoundLotSize = 100; BuyPrice = SellPrice = Open; signalDelay = #required; SetTradeDelays(signalDelay, signalDelay, 0, 0); } {//2. MARKET ANALYSIS SetForeign("SET"); buyConMK = #required; RestorePriceArrays(); } {//3. SIGNALS buyCon1 = #required; buyCon2 = #required; Buy = buyConMK AND buyCon1 AND buyCon2; sellCon1 = #required; sellCon2 = #required; Sell = sellCon1 AND sellCon2; Short = 0; Cover = 0; {//Avoid stock split (Don't change) C0 = Ref(C, 0); C1 = Ref(C, 1); C2 = Ref(C, 2); difC1C0 = abs( (C1 - C0)/C0 ) * 100; difC2C1 = abs( (C2 - C1)/C1 ) * 100; detectSplit = 0.35 * 100; buyConAvoidSplit = !(difC1C0 > detectSplit) AND !(difC2C1 > detectSplit); sellConAvoidSplit = (difC1C0 > detectSplit) OR (difC2C1 > detectSplit); Buy &= buyConAvoidSplit; Sell |= sellConAvoidSplit; } {//Avoid stock delisted and renamed (Don't change) buyConAvoidDelisted = BarIndex() < (LastValue(BarIndex()) - signalDelay - 1); sellConAvoidDelisted = BarIndex() >= (LastValue(BarIndex()) - signalDelay - 1); Buy &= buyConAvoidDelisted; Sell |= sellConAvoidDelisted; } } {//4. POSITIONS PositionScore = #required; SetPositionSize(100/MOP, spsPercentOfEquity); } {//5. STOPS stopLoss = #required; ApplyStop(stopTypeLoss, stopModePercent, stopLoss); //ApplyStop(stopTypeTrailing, stopModePercent, #required); //ApplyStop(stopTypeProfit, stopModePercent, #required); //ApplyStop(stopTypeNBar, stopModeBars, #required); } {//6. SIMULATION AND RISK simRuns = #required; missingTrades = #required; slippage = #required; if(simRuns){//Simulation runs (Don't change) simRuns = Optimize("simRuns", 1, 1, simRuns, 1); {//Missing Trades Buy &= IIf(Random() < 1 - missingTrades/100, 1, 0); Sell &= IIf(Random() < 1 - missingTrades/100, 1, 0); } {//Slippage BuyPrice = BuyPrice*(1 + slippage*Random()/100); SellPrice = SellPrice*(1 - slippage*Random()/100); } } {//Correct tick size (Don't change) //avgPrice = (Open + Close)/2; //avgPrice = (Low + High)/2; avgPrice = Open; TickSize = IIf(avgPrice < 2, 0.01, IIf(avgPrice < 5, 0.02, IIf(avgPrice < 10, 0.05, IIf(avgPrice < 25, 0.10, IIf(avgPrice < 100, 0.25, IIf(avgPrice < 200, 0.50, IIf(avgPrice < 400, 1.00, 2.00 ))))))); BuyPrice = Prec(ceil(BuyPrice/TickSize)*TickSize,2); SellPrice = Prec(floor(SellPrice/TickSize)*TickSize,2); } } {//7. CUSTOM BACKTEST (empty) }
ตัวอย่าง Win 62%; CAR 24%; MDD -15% (ต้น 2010 ถึงสิ้น 2019)
เหมาะสำหรับนำไปศึกษาองค์ประกอบโค้ดต่างๆใน Template รวมถึงศึกษารูปแบบกลยุทธ์ที่ใช้ Market Analysis เป็นหลัก (มิใช่การใช้ indicators) ในการซื้อขายหุ้นทุกๆต้นเดือน ซึ่งถือว่าเป็นท่าไม้ตาย
/** EXAMPLE from FULL TEMPLATE No Copyright or Any Rights Reserved @link https://bit.ly/tq-template */ {//1. OPTIONS MOP = 10; SetOption("MaxOpenPositions", MOP); SetOption("InitialEquity", 100000); SetOption("CommissionMode", 1); SetOption("CommissionAmount", 0.2); SetOption("AllowPositionShrinking", 1); //SetOption("UsePrevBarEquityForPosSizing", 1); //SetOption("MinPosValue", 10000); //SetOption("MinShares", 100); RoundLotSize = 100; BuyPrice = SellPrice = Open; signalDelay = 1; SetTradeDelays(signalDelay, signalDelay, 0, 0); } {//2. MARKET ANALYSIS periodMK = 60; SetForeign("SET"); buyConMK = High > Ref(HHV(Close, periodMK),-1); RestorePriceArrays(); } {//3. SIGNALS firstDayOfMonth = Month() != Ref(Month(),-1); buyCon1 = firstDayOfMonth; buyCon2 = MA(V*C, periodMK) >= 10*1000000; Buy = buyConMK AND buyCon1 AND buyCon2;// AND C < 50; sellCon1 = !buyConMK; sellCon2 = firstDayOfMonth; Sell = sellCon1 AND sellCon2;// AND diffCloseToMaSET > 1; Short = 0; Cover = 0; {//Avoid stock split (Don't change) C0 = Ref(C, 0); C1 = Ref(C, 1); C2 = Ref(C, 2); difC1C0 = abs( (C1 - C0)/C0 ) * 100; difC2C1 = abs( (C2 - C1)/C1 ) * 100; detectSplit = 0.35 * 100; buyConAvoidSplit = !(difC1C0 > detectSplit) AND !(difC2C1 > detectSplit); sellConAvoidSplit = (difC1C0 > detectSplit) OR (difC2C1 > detectSplit); Buy &= buyConAvoidSplit; Sell |= sellConAvoidSplit; } {//Avoid stock delisted and renamed (Don't change) buyConAvoidDelisted = BarIndex() < (LastValue(BarIndex()) - signalDelay - 1); sellConAvoidDelisted = BarIndex() >= (LastValue(BarIndex()) - signalDelay - 1); Buy &= buyConAvoidDelisted; Sell |= sellConAvoidDelisted; } } {//4. POSITIONS PositionScore = H/Ref(Highest(C),-1); SetPositionSize(100/MOP, spsPercentOfEquity); } {//5. STOPS stopLoss = 15; ApplyStop(stopTypeLoss, stopModePercent, stopLoss); //ApplyStop(stopTypeTrailing, stopModePercent, #required); //ApplyStop(stopTypeProfit, stopModePercent, #required); //ApplyStop(stopTypeNBar, stopModeBars, #required); } {//6. SIMULATION AND RISK //missingTrades = 10; //Buy &= IIf(Random() < 1 - missingTrades/100, 1, 0); //Sell &= IIf(Random() < missingTrades/100, 1, 0); //slippage = 2; //BuyPrice = BuyPrice*(1 + slippage*Random()/100); //SellPrice = SellPrice*(1 - slippage*Random()/100); {//Correct tick size (Don't change) //avgPrice = (Open + Close)/2; //avgPrice = (Low + High)/2; avgPrice = Open; TickSize = IIf(avgPrice < 2, 0.01, IIf(avgPrice < 5, 0.02, IIf(avgPrice < 10, 0.05, IIf(avgPrice < 25, 0.10, IIf(avgPrice < 100, 0.25, IIf(avgPrice < 200, 0.50, IIf(avgPrice < 400, 1.00, 2.00 ))))))); BuyPrice = Prec(ceil(BuyPrice/TickSize)*TickSize,2); SellPrice = Prec(floor(SellPrice/TickSize)*TickSize,2); } } {//7. CUSTOM BACKTEST (empty) }
One for All & All for One