Scan หุ้นไทย ตามสูตร พี่ Mark Vinervini ด้วย python

Tanakorn Taweepoka
2 min readJun 22, 2021

--

โดยผมจะแบ่งเป็น 2 พาร์ทนะครับ เป็น 1.data collection 2.signal calculation

1.Data Collection

ก่อนอื่นเราต้องมี data หุ้นไทยก่อนนะครับโดยผมจะใช้จาก library pandas_datareader ครับ โดย set_stock_list.csv ได้มาจากเวปไซต์ www.siamchart.com ตรง data eod ครับ

import pandas as pd
from pandas_datareader import data as pdr
import datetime as dt
stock_list_df = pd.read_csv('set_stock_list.csv')
stock_list = stock_list_df['<TICKER>'].to_list()
stock_list1=[]
for i in range(len(stock_list)):
stock_list1.append(stock_list[i]+'.BK')

del_list = ['M-PAT.BK','S&J.BK','TU-PF.BK']
for element in stock_list1:
if element in del_list:
stock_list1.remove(element)
start = dt.datetime(2020,1,1)
now = dt.datetime.now()
stock_data_df = {}
for x in stock_list1:
stock_data_df[x[:-3].format(x)] = pdr.get_data_yahoo(x, start, now)

หมายเหตุ ตรง del_list เป็น หุ้นที่ api ไปหามาไม่เจอนะครับ เลยเอาออก

2.Signal Calculation

หลังจากที่เราได้ data ก็มาเริ่มสร้าง column ตามพี่ Mark ได้เลยครับ โดยก่อนอื่นผมขออธิบายสูตรของเขาก่อนนะครับ โดยจะมีอยู่ 8 เงื่อนไข ตามรูปข้างล่างครับ

ภาพจาก หนังสือ Trade Like a Stock Market Wizard

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

https://www.youtube.com/watch?v=CdFmuCRq2tM

for key,value in stock_data_df.items():
o=stock_data_df[key]['Open']
h=stock_data_df[key]['High']
l=stock_data_df[key]['Low']
c=stock_data_df[key]['Close']
v=stock_data_df[key]['Volume']

stock_data_df[key]['Date']=stock_data_df[key].index
stock_data_df[key]['MA_50'] = c.rolling(window=50).mean()
stock_data_df[key]['MA_150'] = c.rolling(window=150).mean()
stock_data_df[key]['MA_200'] = c.rolling(window=200).mean()

ma200=stock_data_df[key]['MA_200']
stock_data_df[key]['is_increasing']=ma200.diff().lt(0).cumsum()
stock_data_df[key]['MA_200_consec_increase']=stock_data_df[key].groupby(['is_increasing'])['Date'].rank(ascending=True)
stock_data_df[key]['MA_200_growth_22d_flag'] = np.where( stock_data_df[key]['MA_200_consec_increase']>=22,1,0 )
stock_data_df[key]['High_1y'] = c.rolling('365D').max()
stock_data_df[key]['Low_1y'] = c.rolling('365D').min()
stock_data_df[key]['IBD_Value'] = 2*c/c.shift(63)+c/c.shift(126)+c/c.shift(189)+c/c.shift(252)

โดยหลังจากที่เราได้คอลัมที่เราต้องการแล้วผมก็จะมาทำตัว relative strenth ranking ครับ

for key,value in stock_data_df.items():
stock_data_df[key]['Symbol'] = key

df2=pd.concat(stock_data_df[frame] for frame in stock_data_df.keys())
#df2['Date']=df2.index
df2['IBD_pct_rank']=df2.groupby(['Date'])['IBD_Value'].rank(pct=True)
df2['IBD_rank']=df2.groupby(['Date'])['IBD_Value'].rank(ascending=False)
c = df2['Close']
ma50 = df2['MA_50']
ma150 = df2['MA_150']
ma200 = df2['MA_200']
ma200_22d_consec = df2['MA_200_growth_22d_flag']
h_1y = df2['High_1y']
l_1y = df2['Low_1y']
df2['Mark_flag'] = np.where((c > ma50) & (c > ma150) & (c > ma200) & (ma50 > ma150) & (ma50 > ma200) & (ma150 > ma200) & (ma150 > ma200) & (ma200_22d_consec == 1) & (c/l_1y>1.3) & (h_1y/c > 1.25), 1, 0)

พวกเงื่อนไขที่ไม่ได้ให้มาแบบมีทั้ง atleast กับ prefer ผมให้เป็นแบบ atleast ไป ส่วนถ้าใครอยากได้แบบที่เค้าแนะนำเลยก็ไปปรับค่าเองได้เลยครับ

และจากตามของสูตร mark เขาต้องให้ได้อย่างน้อย 70 ผมไม่แน่ใจว่าคือค่าอะไรแต่ทำตัว IBD_pct_rank เพื่อบอกค่า percentile และ IBD_rank เพื่อบอก rank ของ ค่า IBD อันนี้แล้วแต่คนเลยว่าจะคิด threshold ที่เท่าไร แต่ส่วนตัวผมจะ sort จากมากมาน้อยหลังจากกรองเงื่อนไขทั้ง 7 ข้อมาแล้วชอบหุ้นตัวไหนก็เตรียมเข้าซื้อได้เลยครับ

ถ้าหากมีรายละเอียดตรงไหนที่ผิดพลาดประการใดขออภัยด้วยครับ

--

--

Tanakorn Taweepoka
Tanakorn Taweepoka

No responses yet