กลยุทธ์ Day of Week ของคุณ Larry R. Williams ทำงานได้จริงไหม

สองสามวันก่อนผู้เขียนได้ อ่านหนังสือ “Long-term secrets to short-term trading” (มีเวอร์ชั่นแปลไทยโดยใช้ชื่อว่า กลยุทธ์เก็งกำไรเทรดระยะสั้น) ของคุณ Larry R. Williams ก็เลยอยากทดลองใช้กลยุทธ์ในการวิเคราะห์ข้อมูลหุ้นตามคุณ Larry ด้วยภาษา Python ดูซะหน่อย จึงถือโอกาสหยิบยกการทดลองนี้มาให้เพื่อนๆ ได้ดูกัน ถือเป็นการฝึกมือภาษา Python และทำความรู้จักกับข้อมูลหุ้นให้มากขึ้นกันไปในตัวด้วยค่ะ

Long-Term Secrets to Short-Term Trading (Wiley Trading Book 78) eBook:  Williams, Larry: Amazon.in: Kindle Store
รูปจาก Amazon.com

สมมุติฐานเริ่มต้น

คุณ Larry ได้ตั้งสมมุติฐานของกลยุทธ์นี้ไว้ว่า

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

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

บทความนี้ผู้เขียนจะขอใช้หุ้นใน Dow Jones Industrial Average (DJIA) ในการทดลองนะคะ เราจะนำหุ้นเหล่านี้วิเคราะห์ลักษณะเฉพาะ (Characteristic) ของมัน เพื่อสร้างกลยุทธการ ซื้อ-ขาย จากนั้นเราจะมาทดลอง Backtest ผลลัพธ์อย่างง่ายๆ กัน เพื่อเปรียบผลการทำงานระหว่าง กลยุทธ์ กับ การถือหุ้นตัวนั้น (Buy & Hold) ไว้เฉยๆ ว่าผลงานแตกต่างกันอย่างไร

มาเริ่มกันเลยค่ะ

Photo by Alex Jones on Unsplash
1. Import libraries ที่สำคัญ

เริ่มด้วยการเรียก Library ที่จำเป็นต้องใช้กันก่อนเลยค่ะ

import pandas as pd
import numpy as np
import yfinance as yf
import matplotlib.pyplot as plt
plt.style.use("ggplot")
%matplotlib inline
2. กำหนดช่วงเวลา และ ดึงข้อมูล

ผู้เขียนได้ ทำการเรียกข้อมูลหุ้น IBM มาจากแพคเกจดึงข้อมูลหุ้นยอดนิยมอย่าง yfinance เริ่มตั้งแต่ปี 2010 มาจนถึงปี 2020 และนำมาเก็บไว้ในตัวแปร df

start = "2010-01-01"
end = "2020-12-31"
period = "1d"

df = yf.download("IBM", start, end, interval=period)
df.head(
3. วิเคราะห์ข้อมูลเบื้องต้นกัน

ก่อนจะเริ่มต้นการทำงาน เรามาวิเคราะห์ข้อมูลเบื้อต้นของข้อมูลกันหน่อย ด้วยคำสั่ง info() เพื่อดูความเรียบร้อยของข้อมูล

df.info()
ผลลัพธ์

จากผลลัพธ์ที่ได้ จะเห็นว่า ข้อมูลมีทั้งหมด 2769 แถว (rows) และ ไม่มีข้อมูลเป็น Null (non-null) เลยค่ะ ซึ่งก็แปลว่า ข้อมูลที่เก็บได้นั้นครบถ้วนเรียบร้อยดี ประเภทข้อมูลเก็บในรูปแบบ ทศนิยม (floast64) ทั้งหมดยกเว้น Volume ที่เก็บเป็นจำนวนเต็ม (int64)

ดูจำนวนและรูปแบบของข้อมูลเบื้องต้นแล้วเรามาลองภาพรวมข้อมูลทางสถิติกันบ้างค่ะ ด้วยคำสั่ง describe()

df.describe()
ผลลัพธ์

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

มาถึงตรงนี้ เราอาจจะรู้สึกว่า ข้อมูลทางสถิติมันไม่ค่อยบอกอะไรเรามากนัก ลองมาวิเคราะห์กันต่ออีกนิดค่ะ ด้วยคำสั่ง .pct_change().describe()

df.pct_change().describe()
ผลลัพธ์

เนื่องจากผู้เขียนได้ทำการเปลี่ยนข้อมูลเป็นเปอร์เซ็นต์การเปลี่ยนแปลงของค่า หรือ Percentage Change ด้วยคำสั่ง pct_change() เพื่อทำให้ข้อมูลสามารถเข้าใจได้ง่ายขึ้น ทำให้เห็นว่าข้อมูลเบื้องต้นเริ่มบอกอะไรเราได้บ้างแล้วค่ะ เช่น

  • –> โดยปรกติแล้วหุ้นตัวนี้ จะเทรดอยู่ในช่วงระหว่าง ราคาลงไปที่ -12.8% และ ขึ้นมาไม่เกิน 11.3%
  • –> มีโอกาสน้อยกว่า 25% ที่ราคาของหุ้นตัวนี้ขยับขึ้นถึง 0.68% ต่อวัน (ที่ Percentile 75) หรือ ทางฝั่งลด ก็มีโอกาสน้อยกว่า 25% ที่มันจะลดลงมากกว่า -0.63% ต่อวัน (ที่ Percentile 25) (หุ้นใหญ่ๆคลื่อนไหวต่อวันไม่มากนัก)

มาถึงตอนนี้ เราก็ได้เห็นกันคร่าวๆ แล้วนะคะ ว่าหุ้นตัวนี้มันเป็นอย่างไร แต่มันก็ยังไม่ใช่ประเด็นที่เราจะสื่อในวันนี้นะคะ ประเด็นที่เราจะดูกันในวันนี้คือเรื่อง “วันเทรดในสัปดาห์” หรือ “Day of week trading” ค่ะ มาเริ่มกันเลยดีกว่าค่ะ

4. เริ่มต้นจัดการกับข้อมูลวันในการเทรด

ในส่วนนี้เราจะมาทำงานกับ “วันและเวลา” กันค่ะ ฉะนั้นเราต้องดึง Library มาเพิ่ม

import datetime
import dateutil
from datetime import datetime
from dateutil import parser

Libraries เหล่านี้คือฟังก์ชั่นในการทำงานกับวันและเวลาค่ะ จากนั้นเราก็จะทำการสำรองข้อมูลหุ้นทั้งหมดไว้ในตัวแปรที่ชื่อ df_date ที่ใช้ .copy() เพราะไม่อยากให้ข้อมูลต้นฉบับ (Original data) ของเราเกิดการเปลี่ยนแปลงใดๆ ค่ะ

df_date = df.copy()

สิ่งที่ต่อไปอยากรู้คือ แต่ละวันในการเทรด เป็นวันอะไรในอาทิตย์นั้นๆ โดยใช้ 2 index.weekday ค่ะ

df_date['Day'] = df.index.weekday
df_date[['Day']].head()
ผลลัพธ์

ด้วยวิธีนี้เราจะได้ว่า ณ index นั้นๆ เป็นวันที่เท่าไหร่ของสัปดาห์ โดยวันแต่ละสัปดาห์จะเริ่มต้นที่ 0 ซึ่งคือ วันจันทร์ และ ไปจบที่ 4 คือ วันศุกร์ ตัวอย่างเช่น วันที่ 4 เดือนมกราคม ปี 2010 เป็นวันที่ 0 ของสัปดาห์ ซึ่งก็คือวันจันทร์นั่นเอง

เมื่อได้ดังนี้แล้วเรายังอยากได้เพิ่มอีกคือ ชื่อของวัน เพื่อให้ง่ายต่อการดูข้อมูล ซึ่งสามารถทำได้ด้วยคำสั่ง .index.day_name()

df_date['Day_name'] = df_date.index.day_name()
df_date[['Day_name','Day']].head()
ผลลัพธ์

ด้วยคำสั่ง .day_name เราจะแปลความหมาย ของตัวเลขออกมาเป็นวัน และเก็บชื่อของวันนั้นๆ ไว้ในตัวแปร Day_name ใน DataFrame

Photo by Clay Banks on Unsplash
5. คำนวณ Return

ก่อนจะไปวิเคราะห์อะไรต่อไป ผู้เขียนจะขอแบ่งข้อมูลเป็นสองชุดก่อนนะคะ ข้อมูล 2 ชุดนี้ ประกอบด้วย Train set (ใช้ในการวิเคราะห์เพื่อสร้างกลยุทธ์) และ Test set (ข้อมูลที่ใช้ในการทดสอบกลยุทธ์) ค่ะ แต่ก่อนจะแบ่งข้อมูล ผู้เขียนขอจะหา Return ของข้อมูลก่อนค่ะ เพื่อความสะดวกต่อการคำนวณ (แต่ในความเป็นจริง ควรแบ่งข้อมูลก่อนนะคะ)

bnh = df_date.copy()
bnh["Ret"] = bnh["Close"].pct_change()
df_date["Ret"] = (df_date["Close"]/df_date["Open"])-1
df_date.dropna(inplace=True)
bnh.dropna(inplace=True)

เราจะทำการดึงข้อมูล df_date ดั้งเดิมมาเก็บไว้ในตัวแปร bnh ซึ่งเป็นตัวแปรที่ใช้เก็บข้อมูลที่จะใช้เพื่อใช้วัดผลเปรียบเทียบภายหลัง จากนั้นทำการหา Return ของข้อมูลแบบ Buy & Hold เป็น Percentage change เก็บไว้ใน bnh[“Ret”]

ต่อมา เราจะมาคำนวณ return ของข้อมูลชุด df_date ซึ่งจะแตกต่างจากการคำนวณ Return ของ Buy & Hold เพราะเราจะไม่หา Percentage change แบบวันต่อวันอีกต่อไปแล้ว แต่จะหาเฉพาะ Return ที่คิดจากราคาเปิด (Open) กับ ราคาปิด (Close) เปรียบเหมือน เนื่องจากในกลยุธ์ที่เราจะทดลองนี้ เราจะซื้อที่ราคาเปิด และ ขายที่ราคาปิดค่ะ เช่น ถ้าเราซื้อในวันจันทร์ เราก็จะซื้อที่ราคาเปิด และไปขายที่ราคาปิดของวันเท่านั้นค่ะ เพื่อที่เราจะได้ดูลักษณะนิสัยของเจ้าหุ้นตัวนี้ของวันต่อวันนั้นๆจริงๆ

จากนั้นผู้เขียนจะทำการลบข้อมูลที่เป็น Na ทิ้งทั้งหมดด้วยคำสั่ง .dropna(inplace=True) กับทั้งสองตัวแปรค่ะ

6. แบ่งข้อมูล TRAIN SET และ TEST SET

.ในขั้นตอนนี้ เราจะทำการแบ่งข้อมูล df_date ออกเป็น Training set และทำการแบ่งข้อมูลชุดที่แบ่งไว้ทำ Buy and Hold คือ bnh เป็นแบบเดียวกันด้วย เพื่อเอาไว้เปรียบเทียบในภายหลัง

Training Set เริ่มตั้งแต่ปี 2010 ไปจนถึงปลายปี 2015

train_date = "2015"
test_date = "2016"
df_train = df_date[:train_date].copy()
bnh_train = bnh[:train_date].copy()
df_train.head(), bnh.head()

ต่อมา เราก็จะทำการแบ่ง Test set ในทำนองเดียวกันกับ Train set คือ แบ่งทั้งตัวชุดข้อมูล df_date และ ตัวชุดข้อมูล bnh สำหรับทำเปรียบเทียบกับ Buy & Hold ในภายหลัง โดยข้อมูลชุด Test set นี้จะเริ่มตั้งแต่จุดเริ่มต้นปี 2016 ไปจนถึงสิ้นปี 2020

df_test = df_date[test_date:].copy()
bnh_test = bnh[test_date:].copy()
del bnh_test["Ret"]
df_test.head(), bnh_test.head()
ผลลัพธ์

จากนั้น เพื่อความสมจริง เราจึงจะลบ Return ของตัว Testing Set ของ df_date ออกค่ะ เพราะเราจะเอามาเริ่มคิดคำนวณจริงๆ ตอนเทสไปเลย ไม่อยากให้มันรู้อนาคต (จริงๆมันไม่ได้รู้หรอก แต่ผู้เขียนก็ไม่อยากให้ข้อมูลในอนาคตมาเกี่ยวอยู่ดีเลยขอลบไปก่อนค่ะ)

เมื่อได้ดังนี้แล้ว เรามาเริ่มเข้าเรื่องกลยุทธ์สนุกๆ ของคุณ Larry กันดีกว่าค่ะ

7. วิเคราะห์กลยุทธ์ของคุณ Larry

ในการวิเคราะห์ข้อมุลนี้ผู้เขียนจะทำการวิเคราะห์เฉพาะข้อมูลใน Traning Set เท่านั้นนะคะ เพื่อกำหนดกลยุทธ์ เนื่องจากในระหว่างการคิดวิเคราะห์กลยุทธ์นั้น ตามหลักความเป็นจริงแล้ว เราจะยังไม่มีข้อมูล Test set ค่ะ ทำให้ Test Set ห้ามเข้ามีส่วนเกี่ยวข้องกับกระบวนการนี้อย่างเด็ดขาด

ก่อนอื่นผู้เขียนจะมาดูเบื้องต้นกันก่อน ว่าในแต่ละวันมีจำนวนเท่ากันหรือเปล่า

day = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
total_trade = 0

for idx, d in enumerate(day):
    print('*'*10 , d,'*'*10)
    print('Number of Trade: ' + str(len(df_train[df_train["Day"]== idx])))
    total_trade = total_trade + len(df_train[df_train["Day"]== idx])

    
print('*'*30)
print('Total Trades: ' + str(total_trade) )
print('Total Trades recheck: ' + str(len(df_train)))
ผลลัพธ์

นี่คือจำนวนวันเทรดในชุดข้อมูลทั้ง 6 ปีของ Train set จะเห็นว่า จำนวนวันที่เทรดจะอยู่ที่ประมาณ 300 – 310 วัน โดยวันจันทร์จะเป็นวันที่มีจำนวนวันเทรดน้อยสุดเลย (284 วัน) ทั้งนี้ทั้งนั้นอาจจะเป็นเพราะวันจันทร์จะตรงกับวันหยุดของตลาดมากกว่าวันอื่นๆนั่นเอง

7.1 สร้าง DataFrame เพื่อเก็บข้อมูล Profit ของแต่ละวัน

ในขั้นตอนนี้เราจะเริ่มคำนวณ ผลการทำงานของแต่ละวันกันค่ะ ก่อนอื่นผู้เขียนจะสร้าง DataFrame ขึันมา 1 ตัวก่อน ให้ชื่อว่า df_profit เพื่อใช้เก็บผลกำไรโดยเฉพาะ

df_profit = pd.DataFrame(day, columns=["Name"])
df_profit["Day_name"] = (0,1,2,3,4)
df_profit["Profit"] = 0
ผลลัพธ์

เราจะได้ DataFrame 1 ตัว ประกอบไปด้วย 3 คอลัมน์ คือ ชื่อวัน หมายเลขวัน และ ผลกำไร ของวันนั้นๆ

7.2 คำนวณ Profit ของแต่ละวัน

ในขั้นตอนนี้เราจะทำการคำนวน Profit ของแต่ละวัน พร้อมๆ กับพล็อตกราฟเพื่อเปรียบเทียบความแตกต่างของกำไร ในแต่ละวัน เพื่อที่จะดูลักษณะนิสัยของแต่ละวันทำการของหุ้น IBM

plt.figure(figsize = (15,10))
ax1 = plt.subplot2grid((4,1), (0,0), rowspan = 4, colspan = 1)
for idx, d in enumerate(day):
    df_profit.loc[ idx,"Profit"]  = (1+df_train.loc[df_train["Day"] == idx, 'Ret']).cumprod().iloc[-1] * 100
    print(d,"Profit: ",df_profit.loc[ idx,"Profit"] )
    ax1.plot((1+df_train.loc[df_train["Day"] == idx, 'Ret']).cumprod(), label=d)
    
h1, l1 = ax1.get_legend_handles_labels()

ax1.set_xlabel('Trading day')
ax1.set_ylabel('Return')
ax1.legend(h1, l1, loc='best')
ax1.grid(True, zorder=0)   

plt.title('Comparison of weekday returns');
ผลลัพธ์

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

7.3 นำผลลัพธ์กำไรของแต่ละวันมาจัดเรียงจากมากไปน้อย

ในส่วนนี้ผู้เขียนใช้คำสั่ง .sort_values() มาจัดเรียงผลกำไรที่คำนวณได้จากมากไปน้อย เพื่อประโยชน์ในการสร้างกลยุทธ์ ตามวิธีการของคุณ Larry นั่นเองค่ะ

df_profit.sort_values(by="Profit", inplace= True,ascending=False)
df_profit
ผลลัพธ์

นอกจากข้อมูลผลกำไรที่เราเรียงไว้ข้างต้น เรามาดูกันดีกว่าค่ะ ว่านอกจากผลกำไรแล้วเราสามารถดูอะไรได้อีกบ้าง

CAGR

Compound Annual Growth Rate หรือ กำไรต่อปี นั้นก็เหมือน Profit นั่นแหละค่ะ ค่อนข้างเคลียร์ว่าวันจันทร์ เป็นวันที่ทำกำไรได้ดีสุด แต่ถ้าเราจะสร้างกลยุทธ์ซื้อขายแค่นี้ก็ยังไงๆอยู่นะคะ ลองมาดูตัวชี้วัดตัวอื่นๆ กันอีกหน่อยดีกว่าค่ะ

Volatility

Volatility จะเห็นว่าไม่ใช่แค่ วันจันทร์จะทำผลงานได้ดีสุดอย่างเดียว แต่เราจะได้รู้ด้วยว่า วันจันทร์มีการเหวี่ยงของการทำกำไรน้อยที่สุดอีกด้วย

โดยในที่นี้ผู้เขียนได้วัด Volatility จากข้อมูลทั้งปีของหุ้น และวัดผลเฉพาะวันที่มีสัญญาณเท่านั้น เช่น ใน 1 ปี มีวันจันทร์ แค่50 กว่าวัน เราก็นับการเหวี่ยงเปรียบเสมือนว่าเราถือหุ้นเฉพาะวันจันทร์เท่านั้น วันอื่นๆ ไม่ได้ถือหุ้น ค่า Volatility มันเลยดูไม่สูงมากนักนั่นเอง ต่อไปมาดูเรื่องของ Drawdown กันดูบ้างนะคะ

Drawdown

Drawdown ของวันจันทร์ก็ดูสมเหตุสมผลนะคะที่ประมาณ -7% ขณะที่ของวันอังคาร ที่แม้จะมีกำไรสูงตามมาเป็นอันดับ 2 ที่ 3.79% ต่อปี แต่กลับมี Drawdown สูงมากถึง -16% ดังนั้น ถ้าจะมองหาวันที่ดีที่สุดสำหรับการเข้าซื้อ ก็จะเป็นวันจันทร์นั่นเอง

ในส่วนของวันที่ดีที่สุดในการขายนั้น (ขายในที่นี้หมายถึง Short Selling นะคะ ไม่ได้หมายถึงซื้อวันจันทร์แล้วจะไปขายในวันขาย) เพราะอย่างที่บอกไปแล้วข้างต้นว่า ในการทดลองนี้ เราจะซื้อที่ราคาเปิด และขายที่ราคาปิดของวันเดียวกันเท่านั้น เช่นเดียวกับการ Short เราจะ Short ที่ราคาเปิด และทำการปิดสัญญาที่ราคาปิดของวันนั้นเช่นกัน

เมื่อวิเคราะห์จากผลลัพธ์แล้ว จะเห็นว่าวันศุกร์เป็นวันที่มีกำไรน้อยสุด ตามแผนของคุณ Larry ก็คือเอาวันที่ได้กำไรน้อยสุดไป Short นั้นก็พอจะเหมาะสมอยู่ (ถ้าใครอยากจะทดลองต่อไป ก็อาจจะไม่ Short แต่เลือกวัน ซื้อ เพิ่มเป็น 2 วันก็ได้ อันนี้แล้วแต่ผู้ทดลองนะคะ) แต่สำหรับบทความนี้ ผู้เขียนจะขอทดลองตามที่คุณ Larry แนะนำมาก่อนค่ะ นั่นก็คือ หาวันที่ดีที่สุดสำหรับการ Long และ Short ซึ่งในที่นี้ก็คือ วันจันทร์ และ วันศุกร์นั่นเองค่ะ

จากนั้นผู้เขียนได้ทำการเก็บ index ของวันที่ผลงานดีสุด และแย่สุดไว้ทำสัญญาณสำหรับซื้อขายต่อไป

buy = df_profit["Day_name"].iloc[0]
sell =df_profit["Day_name"].iloc[-1]

เมื่อเลือกวันที่เราสนใจจะทำการซื้อและขายได้แล้ว มาลองพล็อตการแจกแจงของผลกำไรของทั้งสองวันนี้กันดูหน่อยดีกว่าค่ะ

plt.figure(figsize=(15,8))
plt.title('Histogram of Day return', fontsize=18)
plt.xlabel('Return', fontsize=18)
plt.ylabel('Density', fontsize=18)

sns.distplot(df_train.loc[df_train["Day"] == buy, 'Ret'], label=day[buy]+" Maximum Return", bins=10, 
             hist=False, kde_kws={'linewidth': 3, 'shade':True})
sns.distplot(df_train.loc[df_train["Day"] == sell, 'Ret'], label=day[sell] +" Minimum Return", bins=10, 
             hist=False, kde_kws={'linewidth': 3, 'shade':True});
ผลลัพธ์ การแจกแจงเปรียบเทียบละระหว่าง วันจันทร์ (วันซื้อ) และ วันศุกร์ (วันขาย)

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

ถือว่าผลที่ได้จากการพล็อตการแจกแจงนี้ มีประโยชน์มากทีเดียวค่ะ

8. TESTing (backtest กลยุทธ์ใน Testing Set)

มาถึงส่วนของการทดสอบว่ากลยุทธ์ที่เราทดลองตามคุณ Larray นั้นทำงานได้จริงมั้ยกันแล้วค่ะ โดยในส่วนนี้เราจะทำงานกับชุดข้อมูล Testing Set เท่านั้น เนื่องจากในการทดสอบกลยุทธ์เราจะต้องทดสอบกับชุดข้อมูลใหม่ ที่ไม่เคยเห็นมาก่อน ซึ่งในที่นี้ก็คือ ชุดข้อมูล Test set ที่เราได้ทำการแบ่งไว้ตั้งแต่ขั้นตอนแรกๆ นั่นเองค่ะ ชุดข้อมูลนี้จะเริ่มต้นตั้งแต่ปี 2016 ไปจนถึงปลายปี 2020

8.1 กำหนดสัญญาณเทรด

ก่อนอื่นเรามากำหนดสัญญาณเทรดกันก่อนค่ะ ส่วนนี้ผู้เขียน ได้ทำการสร้างคอลัมน์ Signal ขึ้น สำหรับเก็บสัญญาณในการซื้อขายตามกลยุทธ์ คือ สัญญาณซื้อ (1) สำหรับวันจันทร์ และ สัญญาณขาย (Short) ในวันศุกร์(-1)

# put signals on Monday and Friday
df_test['Signal'] = 0


# insert signals for buy and sell
df_test.loc[df_test.Day == buy, 'Signal'] = 1
df_test.loc[df_test.Day == sell, 'Signal'] = -1
df_test.head()
ผลลัพธ์

8.2 คิด Simulation ผลกำไรขาดทุนจากกลยุทธ์

df_test['Ret_1'] = 0
df_test.loc[df_test.Day == buy, 'Ret_1'] = (df_date["Close"]/df_date["Open"])-1
df_test.loc[df_test.Day == sell, 'Ret_1'] = (df_date["Close"]/df_date["Open"])-1
df_test['Ret'] = df_test['Signal'] * df_test['Ret_1']

ก่อนอื่นคำนวณผลกำไรระหว่างของ วันจันทร์และวันศุกร์ ด้วย ราคาเปิดและราคาปิด เฉพาะวันที่มีการซื้อขายเก็บใส่ Column Ret_1 จากนั้นนำมัน * กับสัญญาณซื้อขายของเราเก็บใส่ Column Ret

8.3 ดูผลงาน

ในส่วนนี้ ผู้เขียนทำการเปรียบเทียบผลงานระหว่างการถือหุ้น IBM ไว้เฉยๆ กับการใช้กลยุทธ์ของคุณ Larry และทำการพล็อตเปรียบเทียบกัน

plt.figure(figsize = (15,8))
ax1 = plt.subplot2grid((4,1), (0,0), rowspan = 4, colspan = 1)

ax1.plot((1+df_test['Ret']).cumprod(), label = 'Profit')
ax1.plot((1+bnh_test['Ret']).cumprod(), label = 'Buy And Hold')
plt.title("Strategy Return vs Buy and hold on IBM stock")

h1, l1 = ax1.get_legend_handles_labels()
ax1.legend(h1, l1, loc='best')
ax1.grid(True, zorder=0)
print("Strategy return: ",round(((1+df_test['Ret']).cumprod()[-1]-1),4) *100,"%" )
print("Buy and Hold return: ",round(((1+bnh_test['Ret']).cumprod()[-1]-1),4) *100,"%" )
ผลลัพธ์เปรียบเทียบกำไรจากกลยุทธ์ของคุณ Larry กับ Buy & Hold

จะเห็นว่ากลยุทธ์ของคุณ Larry (กราฟสีแดง) ทำผลงานได้ดีกว่าการถือหุ้นไว้เฉยๆ (กราฟสีฟ้า) อยู่พอสมควรเหมือนกันค่ะ โดยกลยุทธ์ของคุณ Larry ทำกำไรได้ประมาณ 54.05% ส่วน Buy & Hold นั้นไม่สามารถทำกำไรได้ และ จบลงที่การขาดทุนประมาณ -9.65% นั่นเองค่ะ

เมื่อสังเกตุ การวัดผลอื่นๆ ก็ดูเหมือนกับว่ากลยุทธ์ของคุณ Larry ก็ยังคงดีกว่า คงมาถึงคำถามที่สำคัญทีุ่สดแล้วก็ คือ ….

9. กลยุทธ์นี้ดีจริงหรือไม่?

คำตอบก็คือ ผู้เขียนเองก็ตอบไม่ได้ค่ะ สิ่งที่เราต้องทำต่อไปก็คือ เราต้องลองกับข้อมูลหุ้นจำนวนมากกว่านี้ค่ะ ถึงจะสามารถสรุปได้ ซึ่งผู้เขียนได้ลองทดลองดูผลงานของหุ้นเพิ่มไว้อีก ดังนี้ (จริงๆ แล้วต้องทดลองเยอะกว่านี้อีกมากนะคะ ยังไงก็ฝากผู้อ่านไปทดลองกันเองต่อนะคะ ถ้าสนใจแนวคิดนี้)

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

คำถามที่สำคัญสำหรับการทดลองเพื่อหากลยุทธ์ ก็คือ ถ้ากลยุทธ์ที่เราคิดออกมายังทำงานได้ไม่ดีเท่าที่ควรอยู่ เราจะปรับแต่งอะไรเพิ่มเติมอีกมั้ย? เช่น เราจะเลือกวันที่ดีใหม่ทุกๆ ปี หรือ ทุก 6 เดือน หรือ จะใช้กลยุทธ์ ซื้อในวันที่ทำผลงานดีที่สุด 2 วัน และ ขาย 1 วัน เป็นต้น ถ้าคิดกันดีๆ แม้แต่ในกลยุทธ์ที่ดูไม่ได้ซับซ้อนอย่างกลยุทธ์นี้ ยังมีอะไรๆ ให้ทดลองได้อีกเยอะค่ะ ดังนั้น สิ่งที่สำคัญไม่แพ้การเริ่มต้นคิดกลยุทธ์ ก็คือ การปรับแต่งกลยุทธ์นั่นเองค่ะ และ กลยุทธ์ที่ยกมาจากในหนังสือของคุณ Larry นี้ ก็ถือเป็นตัวอย่าง Old School แบบหนึ่งให้เราได้ศึกษากันค่ะ

Photo by Ben White on Unsplash

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

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s