วิธีเขียนโค้ดดึงข้อมูลหุ้นไทย ด้วยภาษา Python (แจกโค้ดฟรี)

บทความนี้จะกล่าวถึง ตัวอย่างเขียนภาษา Python 3 เพื่อดึงข้อมูลจากตลาดหุ้นไทย ซึ่งมีหลากหลายวิธีดังนี้

(ผมสรุปค่อนข้างสั้น ดังนั้นควรมีพื้นฐาน python จะดีมาก)

 

คำเตือน

  • ถ้าเปิดบนถือ อาจเห็นโค้ดเพี้ยนได้ แนะนำให้เปิดบนคอมดีกว่า
  • ถ้าจะลง Python เพื่อรันโค้ดตัวอย่าง ให้ติดตั้ง?Anaconda??ดีกว่า (มันจะติดตั้งทั้งคอมไพลเลอร์ มอดูล แพ็กเก็จ ?IDE, IPython และอื่นๆ ที่จำเป็นสำหรับเขียน Python ให้เสร็จสรรพ)

 

วิธีที่ 1 ใช้โมดูล googlefinance

 

ติดตั้งโมดูลด้วยคำสั่ง

pip install googlefinance

 

ตัวอย่างโค้ด?ดูข้อมูลหุ้น PTT

from googlefinance import getQuotes
import json
try:
    symbol = 'PTT'
    print(json.dumps(getQuotes('SET:' + symbol), indent=2))
    print()
except:
    print("Error:", sys.exc_info()[0])
    print("Description:", sys.exc_info()[1])

ได้ผลลัพธ์

[
 {
 "ID": "1079066631482057",
 "StockSymbol": "PTT",
 "Index": "BKK",
 "LastTradePrice": "382.00",
 "LastTradeWithCurrency": "THB382.00",
 "LastTradeTime": "12:29PM GMT+7",
 "LastTradeDateTime": "2017-06-19T12:29:33Z",
 "LastTradeDateTimeLong": "Jun 19, 12:29PM GMT+7"
 }
]

หมายเหตุ ชื่อย่อหุ้นไทยจะมีชื่อ “SET:” นำหน้าชื่อย่อหุ้นนั้นๆ?(ค่าอาร์กิวเมนต์ตอนเรียกใช้ฟังก์ชั่น getQuotes())

เช่น “SET:PTT”, “SET:AOT”, “SET:SCC” หรือถ้าจะดู SET ก็ระบุไปว่า “SET:SET”

 

อ่านเพิ่ม ?https://pypi.python.org/pypi/googlefinance

 

วิธีที่ 2 ใช้โมดูล quandl

 

ติดตั้งโมดูลด้วยคำสั่ง

pip install quandl

 

ไปที่เว็บ https://www.quandl.com/ แล้วสมัครเป็นสมาชิกเพื่อขอ API KEY ?แล้วจะมีเมลส่งมาให้เรายืนยัน

 

หลังจากกดยืนยันเสร็จ เมื่อไปที่หน้า https://www.quandl.com/account/api ก็จะมีหน้าบอก API KEY ว่าของเราคืออะไร ดังรูปข้างล่าง

 

 

 

ตัวอย่างโค้ด

import quandl
try:
    quandl.ApiConfig.api_key = 'YOUR_API_KEY'
    #print("THAISE index:")
    data = quandl.get("THAISE/INDEX")
    print(data.head())
except:
    print("Error:", sys.exc_info()[0])
    print("Description:", sys.exc_info()[1])

ในโค้ดข้างบนจะเห็นชื่อตัวแปร quandl.ApiConfig.api_key ก็ให้ใส่ API KEY ที่เราได้มาลงไป

 

ผลลัพธ์ที่ได้

            Value
Date 
2009-12-31 734.54
2010-12-31 1032.76
2011-12-31 1025.32
2012-12-31 1391.93
2013-12-31 1298.71

 

แต่น่าเสียดายข้อมูลมีเฉพาะดัชนี SET อย่างเดียว ข้อมูลเฉพาะหุ้นรายตัวของไทยไม่มี ?(หรือมีเปล่าหว้า ถ้าใครรู้ช่วยบอกที)

 

อ่านเพิ่ม

 

วิธีที่ 3 ใช้โมดูล pandas-datareader

 

ติดตั้งโมดูลด้วยคำสั่ง

pip install pandas-datareader

 

ตัวอย่างโค้ด

from pandas_datareader import data as pdr
try:
    ptt = pdr.get_data_yahoo("PTT.BK", start="2017-01-01", end="2017-04-30")
    print(ptt.tail())
    print()
except:
    print("Error:", sys.exc_info()[0])
    print("Description:", sys.exc_info()[1])

 

หมายเหตุ ชื่อย่อหุ้นไทยจะมีชื่อ ?.BK? ตามหลังชื่อย่อหุ้นนั้นๆ

เช่น ?PTT.BK?, ? AOT.BK?, ?SCC.BK? (แต่ผมลองแล้ว ถ้าระบุ “SET.BK” ยังไม่ได้นะครับ)

 

ได้ผลลัพธ์

           High      Low       Open      Close     Volume   Adj Close
Date
2017-04-24 39.299999 38.900002 39.299999 38.900002 29944000.0 24.505602
2017-04-25 39.099998 38.799999 38.900002 39.000000 31018000.0 24.568596
2017-04-26 39.200001 38.599998 39.099998 38.799999 48800000.0 24.442604
2017-04-27 39.099998 38.599998 38.700001 38.799999 21043000.0 24.442604
2017-04-28 39.200001 38.900002 39.099998 38.900002 24511000.0 24.505602

สังเกตวิธีนี้ให้ดีๆ ผลลัพธ์ที่แสดงออกมา จะมีราคาปิดของหุ้นอยู่ 2 ค่าได้แก่ Close (ราคาปิดธรรมดา) กับ Adj Close (Adjusted Closing Price)

 

อ่านเพิ่มเติม

 

สำหรับวิธีที่ 1-3 ก็ดูโค้ดฉบับเต็มได้ที่

*** ถ้าลองรันแล้วเห็น error ไม่ต้องตกใจ ?เพราะวิธีที่ 2 ใช้โมดูล quandl ซึ่งต้องการค่า API KEY ของจริงครับ? ส่วนวิธีที่ 1 ตอนเขียนบทความนี้ใหม่ๆ ก็ใช้ได้นะครับ แต่พอกลับมาลองรันใหม่ ปรากฏว่าเกิด error เลยยังไม่ได้แก้ไขครับ (ค้างไว้ก่อน)

 

วิธีที่ 4

ดาวน์โหลดไฟล์ EOD จาก http://siamchart.com/stock/

เมื่อไปที่เว็บ เราก็ต้องสมัครเป็นสมาชิกเว็บเขาก่อน ถึงจะโหลดได้

(เป็นวิธีลูกครึ่งนะ ครึ่งหนึ่งใช้มือดาวน์โหลด อีกครึ่งเขียนโปรแกรมเพื่อเตรียมข้อมูล)

 

 

จากรูปภาพข้างบน ต้องดาวน์โหลด 2 อย่าง ได้แก่

  • ข้อมูล EOD ปี 1970 ถึงปีที่แล้ว (.csv)
  • ข้อมูล EOD ต้นปีถึงปัจจุบัน (.csv)

 

จากนั้นให้แตกไฟล์ .csv ออกมาจาก 2 แหล่งข้อมูลดังกล่าว แล้วมากองรวมกันที่โฟลเดอร์

อย่างของผมแตกไฟล์ แล้วมารวมไว้ที่โฟลเดอร์ set-archive_EOD_UPDATE

ทั้งนี้ชื่อไฟล์ .csv ?จะเรียงตามวันที่ซื้อขาย (เริ่มตั้งแต่ซื้อขายวันแรก 30 เมษายน พ.ศ. 2518 )

ซึ่งข้างในไฟล์จะเก็บข้อมูลหลักทรัพย์ทุกตัว ที่ซื้อขายในวันนั้นๆ

 

ตัวอย่างไฟล์ set-history_EOD_2017-05-23.csv เป็นข้อมูลหลักทรัพย์ที่ซื้อขายเฉพาะในวันที่ 2017-05-23

 

 

เนื่องจากข้อมูลที่ได้มา มันเอาไปใช้ลำบากนิดดดดหนึ่ง

 

ผมเลยต้องจัดเตรียมข้อมูลใหม่ เพื่อให้ 1 ไฟล์เก็บเฉพาะข้อมูล 1 หลักทรัพย์ เช่น ไฟล์ PTT.csv ก็ให้มีเฉพาะข้อมูลหุ้น PTT ดังรูปข้างล่าง

 

 

แถมผมยังจะเปลี่ยนชื่อหัวคอลัมน์ เป็น Open, High, Low, Close, Volume ( ไม่ใช่ “<OPEN>”, “<HIGH>”, “<LOW>”, “<CLOSE>”, “<VOL>”)

 

…ด้วยเหตุนี้ผมเลยต้องเขียนโค้ดขึ้นเพิ่มเติม

แต่ก่อนอื่นจะขอติดตั้งโมดูลเพิ่มเติม ได้แก่ tqdm ด้วยคำสั่งตามนี้

pip install tqdm

ถ้าถามว่าโมดูลนี้มีไว้ทำอะไร ก็ต้องบอกว่าเอาไว้แสดงสถานะแบบ progress bar บนคอมมานไลน์ ก็เวลาที่โค้ดมันทำงานจะนานสักนิดหนึ่ง เพราะข้อมูลมันเยอะ เลยต้องให้เห็นสถานะความคืบหน้าสักหน่อย

…คราวนี้จะมาดูโครงสร้างโปรเจคก่อนเขียนโค้ด

 

root_folder\
    |-- datasets\
           |-- sec_csv\
           |-- set-archive_EOD_UPDATE\
?? ???     |-- siamchart_csv.py
  • sec_csv เป็นโฟลเดอร์ เอาไว้เก็บไฟล์ .csv (เอาท์พุต)
  • set-archive_EOD_UPDATE เป็นโฟลเดอร์ เก็บไฟล์ .csv ที่ได้จาก http://siamchart.com/stock/ (ที่เราดาวน์โหลดมา)
  • siamchart_csv.py คือโค้ดที่จะเขียนขึ้นมา

 

ตัวอย่างโค้ด

EOD_file = "set-archive_EOD_UPDATE"
def createSymbolCSV(start_idex, outputPath=DIR_SEC_CSV):
?   eodFiles = getFileNameInDir(EOD_file)?
??? eodFiles = eodFiles[-1 * start_idex:]

??? outputPath = join(DIR_CURRENT,outputPath)
??? clearDir(outputPath)

??? eodFiles = [ join(DIR_CURRENT,file)? for file in eodFiles]
??? dataStock? = getStockData(eodFiles)??????
??? headers = getHeaderFile(eodFiles)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
??? columnNames = { index:changeName(value)? for index, value in enumerate(headers)}
????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
??? itemList = list(dataStock.items())
??? allItem = len(itemList)
??? assert allItem == len(dataStock.items())???????????????
??? for i in tqdm(range(allItem), ascii=True, desc='Writing CSV files'):
    ??? key, allRow = itemList[i]
??????? df = pd.DataFrame(allRow)
??????? df.rename(columns=columnNames, inplace=True)?
??????? df.drop('<TICKER>', axis=1, inplace=True) # remove column
??????? fileName = "{}.csv".format(join(outputPath, key))??????????????????????????
??????? df.to_csv(fileName, index = False)

 

วิธีใช้งานฟังก์ชั่น

createSymbolCSV(2000)

โค้ดข้างบนจะสร้างไฟล์ .csv โดยใช้ข้อมูลของวันที่ปัจจุบัน นับย้อนหลังไป 2,000 วัน??(ทำการ)

(ขออภัยผมไม่ได้นำโค้ดทั้งหมดมาแสดงให้ดู ถ้าจะดูโค้ดทั้งหมด ผมแปะไว้ในท้ายข้อที่ 4 นี้แล้วนะครับ)

 

เวลารันก็ใช้คำสั่ง

python siamchart_csv.py

 

เมื่อโค้ดรันเสร็จ จะได้ไฟล์ .csv เป็นชื่อย่อของหลักทรัพย์นั้นๆ ดังรูปข้างล่าง

 

 

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

 

โค้ดวิธีที่ 4 เวอร์ชั่นเต็มทั้งหมด ก็ดาวน์โหลดได้ที่

หมายเหตุ ผมยังเพิ่มโค้ดสำหรับแปลง csv ที่ได้ในวิธีที่ 4 นี้ ให้เขียนลงฐานข้อมูล (เป็น sqlite) สนใจก็ลองดูตัวอย่างที่ลิงค์นี้? หรือจะดูตัวอย่างโค้ดที่แปลง csv ให้กลายเป็น json ก็ได้ที่ลิงค์นี้

วิธีที่ 5?Web scraping

 

ยกตัวอย่างหุ้น PTT เมื่อใช้ URL เป็น

https://www.set.or.th/set/historicaltrading.do?symbol=PTT&page=2&language=en&country=US&type=trading

 

(ถ้าหุ้นตัวอื่นก็เปลี่ยนใน URL เช่น BBL ก็แก้ไขเป็น symbol=BBL)

 

ก็จะเห็นหน้าตาเว็บดังนี้ (ราคาหุ้น PTT)

 

 

 

เมื่อมองเป็นภาษา HTML

 

 

Web scraping คือการดึงข้อมูลจากหน้าเว็บ โดยในทางโปรแกรมมิ่ง เนื้อหา HTML เราจะมองเป็นโครงสร้าง DOM แล้วก็สามารถเข้าถึงทีละ element ได้

 

ด้วยเหตุนี้เราจึงสามารถเขียนโค้ดดึงข้อมูลราคาหุ้น PTT ได้ในภาษา Python ดังตัวอย่าง

 

def getTableData(symbol, page=1):
??? if page > 3:
??????? page = 3 # limit at 3
?????
??? url_string = "https://www.set.or.th/set/historicaltrading.do?symbol={0}".format(symbol)
??? url_string += '&page={0}&language=en&country=US&type=trading'.format(page-1)???????
??? page = urllib.request.urlopen(url_string).read()??????????
??? soup = BeautifulSoup(page, 'lxml')???
??? table_element =soup.find('table', class_='table table-hover table-info')
??? return table_element, url_string

 

ลองทดสอบรันฟังก์ชั่น

table_element, url_string = getTableData("PTT")
tr_list = table_element.findAll('tr')
print(tr_list[0:2])

 

ได้ผลลัพธ์ (โชว์ข้อมูลแค่ส่วน header ของตาราง กับ ข้อมูลหุ้น PTT แถวแรก ถ้าโชว์หมดไม่ไหว มันเยอะไป)

[<tr align="center" class="bggrey1">
 <th height="35" width="10%"><strong>Date</strong></th>
 <th width="10%"><strong>Open</strong></th>
 <th width="10%"><strong>High</strong></th>
 <th width="10%"><strong>Low</strong></th>
 <th width="10%"><strong>Close</strong></th>
 <th width="10%"><strong>Change</strong></th>
 <th width="10%"><strong>%Change</strong></th>
 <th width="13%"><strong>Total Volume<br/>(Shares)</strong></th>
 <th width="17%"><strong>Total Value<br/>('000 Baht)</strong></th>
 </tr>, <tr align="right">
 <td align="center">16/06/2017</td>
 <td>380.00</td>
 <td>382.00</td>
 <td>377.00</td>
 <td>379.00</td>
 <td><font color="#FF0000"> -1.00</font></td>
 <td><font color="#FF0000"> -0.26</font></td>
 <td>4,051,989</td>
 <td>1,537,504.20</td>
 </tr>]

 

ดูโค้ดวิธีที่ 5 ฉบับเต็มได้ที่

 

แต่มีข้อควรระวัง วิธีที่ 5 ด้วย Web scraping เหมือนดาบสองคม ถ้าเรียกใช้ติดต่อกันถี่ๆ ก็จะเหมือนเราส่ง request ไปโจมตี Server ….เดี่ยวเจอเพ่งเล็งจากตลาดหลักทรัพย์ได้ว่า เป็นการโจมตีแบบ DOS? บทความนี้ไม่แนะนำ?เอาไปใช้ดูหุ้นแบบ real time นะครับ

 

วิธีที่ 6 สุดท้าย (ไม่รู้จะนับรวมดีไหม)

 

ยังมีวิธีเรียกดูข้อมูลด้วยโมดูล yahoo_finance

ติดตั้งโมดูลด้วยคำสั่ง

pip install yahoo_finance

 

ตัวอย่างโค้ด ดูหุ้นฝรั่ง YHOO และค่าเงิน EURPLN

from yahoo_finance import Share
try:
? ? yahoo = Share("YHOO")
? ? print("\n++++YHOO stock++++")
? ? print (yahoo.get_open())
? ? print (yahoo.get_price())
? ? print (yahoo.get_trade_datetime())
except:
? ? print("Error:", sys.exc_info()[0])
? ? print("Description:", sys.exc_info()[1])

from yahoo_finance import Currency
try:
? ? eur_pln = Currency('EURPLN')
? ? print("\n++++Currency of EURPLN++++")
? ? print (eur_pln.get_bid())
? ? print (eur_pln.get_ask())
? ? print (eur_pln.get_rate())
? ? print (eur_pln.get_trade_datetime())
except:
? ?print("Error:", sys.exc_info()[0])
? ?print("Description:", sys.exc_info()[1])

 

ได้ผลลัพธ์

++++YHOO stock++++
None
52.58
2017-06-16 20:00:00 UTC+0000

++++Currency of EURPLN++++
4.2100
4.2110
4.2100
2017-06-19 16:10:00 UTC+0000

 

แต่อนิจจัง วัฏสังขารา? เมื่อก่อนตอนเขียนบทความก็ทำงานนะคับ

…แต่มาลองทำใหม่อีกที ทำไมทำไม่ได้ก็ไม่รู้ เกิด error อีกตั้งหาก

?อีกทั้งผมไม่รู้วิธีเรียกดูข้อมูลหุ้นไทยอะนะ ใครทำเป็นบอกที

ถ้าไงลองอ่านเพิ่มเติมได้ที่ https://pypi.python.org/pypi/yahoo-finance

 

 

ดูโค้ดตัวอย่างได้ที่ (โค้ดจะกองรวมกันอยู่กับวิธีในข้อ 1-3)

 

วิธีนำข้อมูลมาใช้

 

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

 

ตัวอย่างอ่านข้อมูลเฉพาะหุ้น PTT มาแสดงผล

def load_OHLCV(symbol, dates,
               column_names=['OPEN', 'HIGH', 'LOW', 'CLOSE', 'VOLUME'],?
? ? ? ? ? ? ? ?base_dir=DIR_SEC_CSV):????????????
    if 'DATE' not in column_names:?
    ??? column_names = np.append(['DATE'],column_names)?? ? ? ? ? ? ? ? ?

??? base_dir = join(DIR_CURRENT,base_dir)
??? csv_file = os.path.join(base_dir, "{}.csv".format(symbol))

??? df_csv = pd.read_csv(csv_file, index_col='DATE',
 ? ? ? ?                 parse_dates=True, usecols=column_names, 
                         na_values=['nan'])

 ? ?if dates is None:
    ??? dates = df_csv.index
????df_main = pd.DataFrame(index=dates)?

??? df_main = df_main.join(df_csv)
??? df_main = df_main.dropna(0)???
??? return df_main

เรียกฟังก์ชั่นให้ทำงาน โดยข้อมูลเริ่มต้นคือวันที่ ‘2017-03-01’ ถึงวันที่ปัจจุบัน (ตอนที่เขียนบทความคือวันที่ 2017-06-16)

 

startDate = '2017-03-01'
endDate = strftime("%Y-%m-%d", gmtime())
dates = pd.date_range(startDate, endDate)
#print("Load data: PTT") 
df = load_OHLCV("PTT", dates)
print(df.tail())

 

ได้ผลลัพธ์

             OPEN   HIGH    LOW  CLOSE     VOLUME
2017-07-17  376.0  377.0  374.0  376.0  2032500.0
2017-07-18  376.0  380.0  375.0  380.0  3194500.0
2017-07-19  380.0  381.0  379.0  380.0  1777400.0
2017-07-20  382.0  382.0  378.0  378.0  2236700.0
2017-07-21  378.0  380.0  378.0  378.0  1261800.0

ผลลัพธ์จะแสดงค่าข้อมูลหุ้น PPT ได้แก่ ราคาเปิด (Open) ราคาสูงสุด (High) ราคาต่ำสุด (Low) ราคาปิด (Close) และปริมาณการซื้อขาย (Volume) ของ 5 วันล่าสุด

 

ตัวอย่างพล็อตกราฟแท่งเทียนของหุ้น PTT

# Borrowed code from : http://matplotlib.org/examples/pylab_examples/finance_demo.
def plotCandlestick(symbol, dates, title="Selected data"):??????????
    quotes = loadStockQuotes(symbol, dates)?????
?????????????????????
????mondays = WeekdayLocator(MONDAY)?
??? alldays = DayLocator()
??? weekFormatter = DateFormatter('%b %d')
??? dayFormatter = DateFormatter('%d')

??? fig, ax = plt.subplots()
??? fig.subplots_adjust(bottom=0.2)
??? ax.xaxis.set_major_locator(mondays)
??? ax.xaxis.set_minor_locator(alldays)
??? ax.xaxis.set_major_formatter(weekFormatter)

??? candlestick_ohlc(ax, quotes, width=0.6)

??? ax.xaxis_date()
??? ax.autoscale_view()
??? ax.set_title(title)
??? plt.setp(plt.gca().get_xticklabels(), rotation=45, horizontalalignment='right')

??? plt.show()

เรียกใช้ฟังก์ชั่น

plotCandlestick("PTT", dates, title ="PTT symbol")

 

ได้ผลลัพธ์

 

 

ตัวอย่าง หุ้น PTT, AOT, SCC, CPALL จะเอาเฉพาะราคาปิด (Close) มาแสดงพร้อมกันทั้ง 5 ตัว (รวม SET ด้วย)

def loadManySymbols(symbols, dates, column_name, base_dir):
    df = pd.DataFrame(index=dates)
??? if 'SET' not in symbols:
    ??? symbols = np.append(['SET'],symbols)
???????
??? base_dir = join(DIR_CURRENT,base_dir)
??? for symbol in symbols:
    ??? csv_file = os.path.join(base_dir, symbol + '.csv')

????????df_temp = pd.read_csv(csv_file, index_col='DATE',
????????????????????????????? parse_dates=True, usecols=['DATE', column_name], 
                              na_values=['nan'])

????????df_temp = df_temp.rename(columns={column_name: symbol})
??????? df = df.join(df_temp)

        if symbol == 'SET':
    ??????? df = df.dropna(subset=["SET"])

 

def loadPriceData(symbols, dates,? base_dir=DIR_SEC_CSV):
    return loadManySymbols(symbols, dates, 'Close', base_dir)

 

เรียกใช้ฟังก์ชั่น

symbols = ["PTT", "AOT", "SCC", "CPALL"]
#print("\nLoad close prices of:", symbols) 
df = loadPriceData(symbols, dates)
print(df.tail())

 

ได้ผลลัพธ์ ?(เอาข้อมูล 5 วันล่าสุด มาแสดง)

?               SET    PTT    AOT    SCC  CPALL
2017-07-17  1574.09  376.0  47.50  506.0  61.00
2017-07-18  1571.52  380.0  48.25  510.0  61.00
2017-07-19  1575.85  380.0  49.00  508.0  61.00
2017-07-20  1575.28  378.0  50.50  504.0  61.00
2017-07-21  1573.51  378.0  51.25  500.0  60.75

หมายเหตุ ฟังก์ชั่น loadManySymbols() จะแอบโหลดข้อมูล SET มาแปะไว้เป็นคอลัมน์แรกเสมอ

 

หรือจะพล็อตกราฟรวม

df = df/df.iloc[0,:]
df.plot()
plt.show()

 

ในโค้ดบรรทัดที่เขียน df = df/df.iloc[0,:] จะเป็นการทำ normalized ?อย่างง่ายๆ โดยหุ้นแต่ละตัวจะเอาข้อมูล ณ วันที่เริ่มต้นมาหารวันอื่นที่เหลือทั้งหมด (บทความนี้ วันที่เริ่มต้นคือ ‘2017-03-01? )

 

ที่ทำแบบนี้จะได้เห็นภาพหุ้นแต่ละตัวในกราฟเดียวกันง่ายขึ้น (มีเสกลเดียวกัน) ดังรูปข้างล่าง

สำหรับโค้ดส่วนนี้ เวอร์ชั่นเต็มทั้งหมด ก็ดาวน์โหลดที่

 

หมายเหตุ เนื่องจากการดาวน์โหลดไฟล์ EOD จากเว็บ http://www.siamchart.com/ อาจดูยุ่งยากไป

จึงอาจใช้วิธีที่ 3 (โมดูล pandas-datareader) ซึ่งจะดาวน์โหลดข้อมูลแบบออนไลน์ได้โดยตรง ?(แต่ยังมีปัญหาตรงที่ดาวน์โหลดข้อมูล SET ไม่ได้)

 

และผมก็ทำตัวอย่างซอร์สโค้ดไว้ที่

 

โดยมีชื่อฟังก์ชั่นและใช้งานได้เหมือนกันดังนี้ (พารามิเตอร์ต่างกันนิดหน่อย)

  • load_OHLCV
  • plotCandlestick
  • loadPriceData (ไม่ได้แปะข้อมูล SET ที่คอลัมน์แรก)

 

คำนวณ Indicator อย่างง่าย

 

จะกำหนดโครงสร้างโปรเจคใหม่

root_folder\
    |-- datasets\
           |-- sec_csv\
           |-- set-archive_EOD_UPDATE\
           |-- siamchart_csv.py
    |-- indicator_example.py

ไฟล์ indicator_example.py เอาไว้ใช้คำนวณ Indicator อย่างง่าย โดยข้างในจะอิมพอร์ต siamchart_csv.py เข้ามาอีกที ดังนี้

import datasets.siamchart_csv as ds

 

ตัวอย่างคำนวณค่า EMA ของหุ้น PTT, AOT, SCC, CPALL (รวม SET ด้วย)

 

EMA?(Exponential Moving Average)??หรือก็คือ เส้นค่าเฉลี่ยเคลื่อนที่แบบเอกซ์โพเนนเชียล สำหรับนักลงทุนสายเทคนิคคงรู้จักกันดีอยู่แล้ว ใครไม่ทราบลองอ่านดูที่นี้แล้วกันครับ

 

ส่วนที่มาสูตรคงไม่ลงลึกนะครับ ลองหาอ่านดูที่นี้

?

วิธีคำนวณ สามารถเขียนโค้ดได้ดังนี้

def ema(df, periods=12):??????????
????? return df.ewm(span=periods, adjust=True, min_periods=0, ignore_na=False).mean()

 

ลองทดสอบฟังก์ชั่น ด้วยการหา EMA (15 วัน) ของหุ้นทั้ง 5 ตัว (รวม SET ด้วย)

startDate = '2017-03-01'
endDate = strftime("%Y-%m-%d", gmtime())
dates = pd.date_range(startDate, endDate)
symbols = ["PTT", "AOT", "SCC", "CPALL"]
df = ds.loadPriceData(symbols, dates)
ema15 = ema(df, 15)
print(ema15.tail())

 

ได้ผลลัพธ์?(แสดงเฉพาะข้อมูลล่าสุด 5 ตัว)

?                   SET         PTT        AOT         SCC      CPALL
2017-07-17  1575.326784  375.146532  47.787416  505.832947  61.579550
2017-07-18  1574.850934  375.753218  47.845239  506.353830  61.507106
2017-07-19  1574.975818  376.284067  47.989585  506.559602  61.443717
2017-07-20  1575.013841  376.498559  48.303387  506.239651  61.388253
2017-07-21  1574.825860  376.686240  48.671715  505.459693  61.308471

 

ตัวอย่างคำนวณค่า MACD ของหุ้น PTT, AOT, SCC, CPALL (รวม SET ด้วย)

 

ตัวเลข MACD (Moving Average Convergence Divergence) ?อ่านว่า ?Mac-Dee? หรือจะได้เรียกว่า ? M-A-C-D? ก็ได้ ซึ่งนักลงทุนสายเทคนิคคงรู้จักดีอยู่แล้ว ใครไม่ทราบลองอ่านดูที่นี้แล้วกันครับ

 

ส่วนที่มาสูตรคงไม่ลงลึกนะครับ ลองหาอ่านดูได้ที่นี้

 

วิธีคำนวณ สามารถเขียนโค้ดได้ดังนี้

def average_convergence(df, period_low=26, period_fast=12):
??? """
??? compute the MACD (Moving Average Convergence/Divergence)
??????????? using a fast and slow exponential moving average'???
??? """
??? emaslow = ema(df, period_low)
??? emafast = ema(df, period_fast)
??? return (emaslow, emafast, emafast - emaslow)

 

ลองทดสอบฟังก์ชั่น ด้วยการหา MACD ของหุ้นทั้ง 5 ตัว (รวม SET ด้วย) โดยใช้ตัวแปร df จากตัวอย่างก่อน

_, _, macd = average_convergence(df)
print(macd.tail())

 

ได้ผลลัพธ์ (แสดงเฉพาะข้อมูลล่าสุด 5 ตัว)

?                SET        PTT       AOT        SCC      CPALL
2017-07-17  0.928926  -2.678597  1.151917  -3.607406  -0.383129
2017-07-18  0.555025  -2.054254  1.083894  -2.954415  -0.390908
2017-07-19  0.600958  -1.541689  1.078039  -2.568589  -0.392547
2017-07-20  0.584652  -1.281990  1.180755  -2.555936  -0.389358
2017-07-21  0.424091  -1.063914  1.307569  -2.835812  -0.402354

 

ตัวอย่างพล็อตกราฟของหลักทรัพย์ทั้งหมด พร้อมค่า EMA 15 วัน, EMA 45 วัน และ EMA 100 วัน

ตัวอย่างโค้ดฟังก์ชั่นเอาไว้พล็อตกราฟ

def plot_graph(values):
    style = ['b-', 'r-', 'g-', 'k-', 'y-']
??? column_list = values[0].columns
??? num_stock = len(column_list)
??? date = values[0].index
??????????
??? if num_stock > 6:
   ???  num_stock = 6??????????????????????

??? for pos in range(0, num_stock):
    ??  column = column_list[pos]
    ??? plt.subplot(2, 3, pos+1)????????????????????????????

    ??????? for i? in range(0, len(values)):
    ??????????? plt.plot(date, values[i][column], style[i])
??????????????? plt.title(column)??????????????????????????????
??????????????? plt.xticks([])?

??? plt.show()

 

นำตัวแปร df และ ema15 จากหัวข้อก่อนหน้านี้มาเรียกใช้ พร้อมทั้งเพิ่มตัวแปร ema45 และ ema100 เอาไว้เก็บค่า EMA 45 วัน และ EMA 100 ตามลำดับ

ema45 = ema(df, 45)
ema100 = ema(df, 100)?
values = [df, ema15, ema45, ema100]
plot_graph(values)

 

ได้ผลลัพธ์

ในกราฟแต่ละรูป เส้นสีน้ำเงินคือราคาของหลักทรัพย์แต่ละตัว

ส่วนเส้นสีแดง เขียว และดำ ในแต่ละกราฟ มันคือเส้น EMA 15 วัน , EMA 45 วัน และ 100 วันตามลำดับ

 

สำหรับโค้ดส่วนนี้ เวอร์ชั่นเต็มทั้งหมด ก็ดาวน์โหลดที่

 

อ่ออีกอย่าง ผมก็ทำตัวอย่างการคำนวณ Indicator ตัวอื่นไว้ด้วย โค้ดรกๆ หน่อย ไม่เป็นระเบียบ และยังไม่เสร็จดีด้วยครับ ตัวอย่าง เช่น

ROC, Bollinger Band (BBANDS), daily returns, SMA, EMA, MACD, RSI, Sharpe ratio,True Range (TR), ATR, Beta, OBV และอื่นๆ

 

เผื่อใครสนใจโค้ดก็ดูได้ที่นี้

 

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

 


เพิ่มเติมให้ สำหรับใครที่อยากเอาโค้ดไปพัฒนาต่อ

 

สำหรับการนำ Python ไปใช้จัดการข้อมูล อย่างในบทความนี้คือหุ้นเป็นหลัก
ก็จะใช้ไลบรารี่ 4 อย่าง ที่เป็นพระเอกดังนี้

 

1 Panda

จะใช้สร้างโครงสร้างข้อมูลแบบตาราง จะช่วยให้เราสามารถประมวลผลทั้งตารางได้สะดวกมากขึ้น รวมทั้ง export ออกมาเป็น exel, csv, หรือ text ไฟล์ก็สะดวก

2 Numpy

เอาไว้คำนวณด้านตัวเลข จัดการพวกแอเรย์ ทำได้อย่างสะดวก

3 Scipy

เอาไว้คำนวณด้านเลข วิทยาศาสตร์ วิศวกรรม

4 Matplotlib

เอาไว้พล็อตกราฟ

 

เขียนโดย แอดมินโฮ โอน้อยออก

Please like Fanpage

 

ความเห็น