บทความนี้จะกล่าวถึง ตัวอย่างเขียนภาษา 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 อย่างเดียว ข้อมูลเฉพาะหุ้นรายตัวของไทยไม่มี ?(หรือมีเปล่าหว้า ถ้าใครรู้ช่วยบอกที)
อ่านเพิ่ม
- https://github.com/quandl/quandl-python
- https://docs.quandl.com/docs/installation-1
วิธีที่ 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 ฉบับเต็มได้ที่
- https://github.com/adminho/trading-stock-thailand/blob/master/datasets/web_set_price.py
- ในโค้ดจะมีการเซฟข้อมูลเก็บไว้เป็นไฟล์ .csv ที่โฟลเดอร์ DIR_SEC_CSV = “sec_set_price“
แต่มีข้อควรระวัง วิธีที่ 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
ตรง getFileName, getStockData นี่ใช้ function อะไรครับ
ขออภัยที่ไม่แสดงโค้ดให้ดูอย่างละเอียด
ลองเข้าไปดูโค้ดเต็มๆ ได้ครับ
https://github.com/adminho/trading-stock-thailand/blob/master/dataset_siamchart.py
เข้าไปที่ https://github.com/adminho/trading-stock-thailand/blob/master/dataset_siamchart.py แล้วไม่มีไฟล์ รบกวนด้วยครับ
https://github.com/adminho/trading-stock-thailand/blob/master/datasets/siamchart.py
โทษทีครับ
บทความดีมากครับ
ปล. ต้องใช้คำว่า “ไส้แห้ง” นะครับ ?
ขอบคุณครับ