เพื่อสนับสนุนวงการลงทุนด้วยระบบเทรดในเมืองไทยให้ก้าวไปข้างหน้าในระดับสากล ด้วยการให้ความรู้แก่ นลท สายควอนทฺ (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
