Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Redis

สร้างแอปพลิเคชันการเงินที่ขยายได้ด้วย RedisTimeSeries

กว้างๆ ไป มีนักลงทุน 2 ประเภทในโลก Fundamental investors (นักลงทุนเชิงพื้นฐาน) มองที่ fundamental metrics เช่น โมเดลธุรกิจ บริษัท รายได้ กำไร التدفقاتเงินสด (cashflows) การประเมินมูลค่าปัจจุบัน ความเสี่ยง และโอกาสเติบโต เมื่อตัดสินใจลงทุน Warren Buffett ดังและกลายเป็นหนึ่งในคนร่ำรวยที่สุดโลก โดยการหาบริษัทที่ถูกประเมินต่ำ (undervalued) ผ่านการวิจัยเชิงพื้นฐาน

อีกฝ่ายหนึ่ง technical investors (นักลงทุนเชิงเทคนิค) ให้ความสนใจน้อยมากหรือไม่สนใจ fundamentals ของบริษัท แต่โฟกัสที่การ derive สัญญาณ buy, sell, และ hold จาก technical indicators หลายร้อยตัว ตัวนักลงทุนเชิงเทคนิค trade ทุกวัน, ทุกสัปดาห์, หรือทุกเดือน

ผมไม่ได้อยู่ที่นี่เพื่อโต้แย้งโน้มถ่วงหรือคัดค้านสไตล์การลงทุนใดๆ แต่นักลงทุนทั้ง fundamental และ technical เรียนรู้ วิเคราะห์ และตัดสินใจจากแหล่งข้อมูลหลายร้อย ถ้าหลายพัน

Fundamental investors ศึกษา balance sheets, income statements, cash flow statements, แนวโน้มประชากร แนวโน้มธีม และแนวโน้มสังคม ข้ามบริษัทหลายพันและอุตสาหกรรมหลายร้อยทั่วโลก พวกเขาสร้าง financial models หรือ analytics บนข้อมูลนั้น เพื่อเข้าใจ trajectory ของบริษัทและโอกาสเติบโตได้ดีขึ้น

Technical investors มอง technical indicators หลายร้อยตัวในแต่ละชั่วโมงหรือวัน เพื่อ derive investing signals นักลงทุนที่พึ่งพา technical indicators ต้องจัดการกับอาร์เรย์ข้อมูลมหาศาลข้าม multiple time frames เพื่อสร้าง trading strategies พวกเขาอาจต้อง query indicators จำนวนมาก และต้องการคำตอบทันทีเกือบ พวกเขาอาจต้องปรับ algorithms และ trading strategies ให้รวดเร็วตามตลาดที่เปลี่ยนแปลงเร็ว Redis Enterprise ตอบสนองทุกความท้าทายนี้ได้

เมื่อเร็วๆ นี้ ผมเขียนเกี่ยวกับทำไม Redis Enterprise จึงเป็นเครื่องมือจำเป็นสำหรับอุตสาหกรรมการเงิน ในบล็อกโพสต์นี้ ผมจะแสดงว่า RedisTimeSeries ใช้เก็บรวบรวม aggregate และ query ราคาหุ้นและ technical indicators ได้อย่างไร หลักการที่ผมจะ रूपร่าง สามารถใช้เก็บและ query ข้อมูลการเงินจากบริษัท หรือ time-series data ใดๆ ที่ fundamental investors ใช้ได้เช่นกัน

โมดูล RedisTimeSeries สามารถ ingest และ query ล้านๆ events, samples, และ pricing data RedisTimeSeries เหมาะที่สุดสำหรับเก็บคู่ของเวลาและค่าที่เกี่ยวข้อง เพื่อช่วยระบุ trends ใน use cases ตั้งแต่ IoT ไปจนถึง healthcare และ finance RedisTimeSeries ให้ aggregations เช่น average, sum, minimum, maximum, standard deviation, range ฯลฯ เพื่อช่วยคุณวิเคราะห์ข้อมูลและตัดสินใจได้ง่าย

ติดตามราคาหุ้นด้วย RedisTimeSeries

ในโพสต์นี้ ผมจะ illustrate โมเดลการใช้ RedisTimeSeries เก็บราคาหุ้นและ technical indicators ผมจะครอบคลุมการสร้าง time series ต่างๆ สำหรับราคาและ indicators แสดงวิธีสร้าง aggregations บน raw time series และสาธิตว่าการ ingest และ query bulk time series ด้วยคำสั่ง RedisTimeSeries ต่างๆ ง่ายแค่ไหน ผมยังให้ sample code ใน Python ที่คุณสามารถใช้เป็นจุดเริ่มต้นสำหรับ use case ของตัวเอง

ถูกหรือผิด หลายคนมอง Dow Jones Industrial Average (DJIA) ว่าเป็น bellwether ของเศรษฐกิจสหรัฐ ผมอยากติดตาม technical indicator ของหุ้น 30 ตัวใน DJIA พร้อมกับราคาและปริมาณการซื้อขาย ผมเริ่มต้นด้วยการติดตามราคาหุ้นของ Goldman Sachs ซึ่งเป็น component ของ Dow และ technical indicator หนึ่งตัวสำหรับหุ้นนั้น ตัว indicator โปรดของผมคือ Relative Strength Index (RSI) RSI เป็น momentum indicator ใช้วัดหุ้นที่อาจอยู่ใน overbought หรือ oversold territory เมื่อ RSI เข้าใกล้หรือต่ำกว่า 30 หุ้นอาจถือว่า oversold และอาจเป็นโอกาสซื้อ เช่นกัน เมื่อ RSI ขึ้นเกิน 70 อาจเข้าสู่ overbought territory และส่งสัญญาณว่าเป็นเวลาขายที่ดี

Relative Strength Index สำหรับ Goldman Sachs Group

สร้างแอปพลิเคชันการเงินที่ขยายได้ด้วย RedisTimeSeries

ระหว่างชั่วโมงการซื้อขาย RSI เหมือน technical indicator ตัวอื่น จะเปลี่ยนแปลงตามการทำธุรกรรมจาก demand และ supply ของหุ้น Goldman Sachs เราสามารถใช้โมดูล RedisTimeSeries ช่วยตอบคำถามสำคัญหลายข้อ:

  • ค่า minimum และ maximum ของ technical indicator สำหรับแต่ละช่วงเวลาที่กำหนดคืออะไร?
    • สิ่งนี้ช่วยให้คุณระบุ entry หรือ exit points สำหรับ trade ได้เร็ว
  • Range และ standard deviation สำหรับราคาหุ้นในช่วงเวลาที่กำหนดคืออะไร?
    • Range และ standard deviation เป็นตัวบ่งชี้ volatility ของราคาหุ้น underlying
  • ราคา entry และ exit ที่อาจให้กำไรสำหรับ trade ในหุ้นนี้คืออะไร?
  • ค่าของ technical indicator ข้ามหุ้นทั้งหมดในช่วงเวลาที่กำหนดคืออะไร?

เราสามารถใช้ RedisTimeSeries queries เพื่อระบุ minimum และ maximum RSI values และราคาหุ้นในช่วงเวลาที่กำหนดได้โดยโปรแกรม ตัวอย่างเช่น ถ้าผมอยากหา min และ max RSI numbers ในแต่ละช่วง 15 นาทีของวันซื้อขาย? เมื่อ RSI อยู่ที่หรือใกล้ 30 ผมอาจอยากสร้าง alert, วาง trade, หรือเริ่ม complex trading workflow อื่นๆ เพื่อวิเคราะห์ technical indicators อื่นๆ ก่อนซื้อหรือขาย อะไรก็ตามที่คุณอยากทำ สามารถจำลองได้ง่ายในฐานข้อมูล RedisTimeSeries

โมเดลข้อมูลสำหรับราคาหุ้นและ technical indicators

วิธีง่ายที่สุดได้ประสบการณ์ hands-on กับ RedisTimeSeries คือรัน Docker image สำหรับ RedisTimeSeries

รันคำสั่งต่อไปนี้เพื่อ pull และ run Docker image:

docker run -p 6379:6379 -it --rm redis/redistimeseries

ทีม Redis ตัดสินใจออกแบบโดยเจตนา (deliberate design decision) ให้โมดูล RedisTimeSeries เก็บ metric เดียวในแต่ละ time series ความเรียบง่ายใน data model นี้ทำให้ insertion และ retrieval ของข้อมูล super fast คุณสามารถเพิ่ม time series ใหม่ได้ตามต้องการโดยไม่ต้องกังวลว่าจะทำลายแอปพลิเคชันเดิม นั่นหมายความว่าคุณเพิ่มแหล่งข้อมูลใหม่ได้ง่ายโดยไม่กังวลเรื่อง database schema หรือแอปพลิเคชัน

เมื่อคุณมี RedisTimeSeries container เริ่มทำงานแล้ว คุณสามารถเชื่อมต่อกับ server (ตรวจสอบให้แน่ใจว่ามี IP address หรือ hostname ถูกต้อง) โดยใช้ Python ดังนี้:

from redistimeseries.client import Client rts = Client(host='127.0.0.1', port=6379)

ด้วยหลักการออกแบบที่เก็บ metric เดียวในแต่ละ time series เราสามารถเก็บ intraday stock price และ RSI สำหรับหุ้น DJIA แต่ละตัวใน time series ของตัวเอง ด้านล่าง ผมสร้าง time series สำหรับ Goldman Sachs Group, Inc. (NYSE: GS) ผมตั้งชื่อ intraday RSI สำหรับ Goldman Sachs ว่า ‘DAILYRSI:GS’ และผม attach labels ต่างๆ ให้แต่ละ time series—การติด label ให้ time series ให้คุณ query ข้าม keys ทั้งหมดโดยใช้ label

rts.create('DAILYRSI:GS', labels={ 'SYMBOL': 'GS' , 'DESC':'RELATIVE_STRENGTH_INDEX' , 'INDEX' :'DJIA' , 'TIMEFRAME': '1_DAY' , 'INDICATOR':'RSI' , 'COMPANYNAME': 'GOLDMAN_SACHS_GROUP'})

ที่นี่ ผมสร้าง time series สำหรับราคาหุ้น intraday ของ Goldman Sachs ชื่อ ‘INTRADAYPRICES:GS’:

rts.create('INTRADAYPRICES:GS', labels={ 'SYMBOL': 'GS' , 'DESC':'SHARE_PRICE' , 'INDEX' :'DJIA' , 'PRICETYPE':'INTRADAY' , 'COMPANYNAME': 'GOLDMAN_SACHS_GROUP'})

ต่อไป ผมสร้าง aggregations ต่างๆ บนข้อมูล RSI ภายในช่วงเวลา 15 นาทีบางช่วง (เราอาจสร้าง aggregations ที่ time frames ยาวหรือสั้นกว่านี้เพื่อตอบสนองความต้องการ trading) Aggregations นี้จะให้เราดู first, last, min, max, และ range values สำหรับ RSI เพื่อสร้าง aggregation เราสร้าง time series เพื่อเก็บ aggregation ก่อน แล้วสร้าง rule เพื่อ populate time series ด้วย aggregated value ในกรณีนี้ เราสร้าง time series ชื่อ ‘DAILYRSI15MINRNG:GS’ เพื่อเก็บ range สำหรับ RSI ภายในช่วง 15 นาที ‘createrule’ ใช้ range function บน raw data (‘DAILYRSI:GS’) ในแต่ละช่วง 15 นาที และ aggregate เข้าไปใน ‘DAILYRSI15MINRNG:GS’

rts.create('DAILYRSI15MINRNG:GS', labels={ 'SYMBOL': 'GS' , 'DESC':'RELATIVE_STRENGTH_INDEX' , 'INDEX' :'DJIA' , 'TIMEFRAME': '15_MINUTES' , 'AGGREGATION': 'RANGE' , 'INDICATOR':'RSI' , 'COMPANYNAME': 'GOLDMAN_SACHS_GROUP'}) rts.createrule('DAILYRSI:GS', 'DAILYRSI15MINRNG:GS', 'range', 900)

ที่นี่ ผมสร้าง rules คู่หนึ่ง เพื่อคำนวณ range และ standard deviation สำหรับราคาหุ้น Goldman Sachs ในแต่ละช่วง 15 นาทีระหว่างวันซื้อขาย:

rts.create('INTRADAYPRICES15MINRNG:GS' , labels={ 'SYMBOL': 'GS' , 'DESC':'SHARE_PRICE' , 'INDEX' :'DJIA' , 'PRICETYPE':'RANGE' , 'AGGREGATION': 'RANGE' , 'DURATION':'15_MINUTES' , 'COMPANYNAME': 'GOLDMAN_SACHS_GROUP'}) rts.createrule('INTRADAYPRICES:GS’ ,'INTRADAYPRICES15MINRNG:GS' ,'range', 900) rts.create('INTRADAYPRICES15MINSTDP:GS' , labels={ 'SYMBOL': 'GS' , 'DESC':'SHARE_PRICE' , 'INDEX' :'DJIA' , 'PRICETYPE':'STDDEV' , 'AGGREGATION': 'STDDEV' , 'DURATION':'15_MINUTES' , 'COMPANYNAME': 'GOLDMAN_SACHS_GROUP'}) rts.createrule( 'INTRADAYPRICES:GS' , 'INTRADAYPRICES15MINSTDP:GS' , 'std.p', 900)

คุณสามารถสร้าง time series สำหรับหุ้นทั้ง 30 ตัวใน Dow Jones Industrial Average (DJIA) แบบเดียวกันได้

วิธีการ ingest ข้อมูล (Data ingestion methods)

มี 2 วิธี ingest ข้อมูลเข้า RedisTimeSeries คำสั่ง TS.ADD ให้คุณเพิ่มราคาหุ้นหรือ technical indicator แต่ละตัวเข้า time series แต่เพราะข้อมูลจากตลาดการเงินผลิตขึ้นเกือบต่อเนื่อง และคุณต้องเพิ่ม multiple samples เข้า RedisTimeSeries จึงควรใช้ method TS.MADD ฟังก์ชัน MADD รับ list of tuples เป็น argument แต่ละ tuple รับชื่อ time-series key, timestamp, และ value:

สร้างแอปพลิเคชันการเงินที่ขยายได้ด้วย RedisTimeSeries

คุณสามารถใช้คำสั่ง Python ต่อไปนี้เพื่อ insert ข้อมูลเข้า time-series key:

rts.madd(<RSIIndicatorList>)

Query RedisTimeSeries

เหมือนกับสิ่งส่วนใหญ่ใน RedisTimeSeries การ query ฐานข้อมูลง่ายมาก Range และ standard deviation สำหรับราคาหุ้นหรือ technical indicator เป็นการบ่งชี้ volatility คำ query ต่อไปนี้จะให้คุณเห็น price range และ standard deviation สำหรับราคาหุ้น Goldman Sachs ภายในทุกช่วง 15 นาที:

rts.range( 'INTRADAYPRICES15MINRNG:GS' , from_time = 1603704600 , to_time = 1603713600)

คำ query aggregation range นี้ให้ result set ดังนี้:

[(1603704600, 1.75999999999999), (1603705500, 0.775000000000006), (1603706400, 0.730000000000018), (1603707300, 0.449999999999989), (1603708200, 0.370000000000005), (1603709100, 1.01000000000002), (1603710000, 0.490000000000009), (1603710900, 0.89500000000001), (1603711800, 0.629999999999995), (1603712700, 0.490000000000009), (1603713600, 0.27000000000001)]

ตามผลลัพธ์ query นี้ ตอนเปิดตลาด 9:30 น. ET วันที่ 26 ตุลาคม 2020 (integer timestamp = 1603704600) หุ้น Goldman Sachs เล่น volatile ด้วย range $1.75 เปรียบเทียบกับ 15 นาทีถัดไป เริ่ม 9:45 น. วันที่ 26 ตุลาคม (integer timestamp = 1603705500) volatility ลดลง range $0.77 Range ของราคาหุ้น Goldman Sachs ลดลงต่อในช่วง 15 นาทีถัดไป และ volatility ไม่กลับสู่ระดับที่ถึงในช่วง 15 นาทีแรก

ข้อมูลจาก RedisTimeSeries นี้ visualize ได้ง่ายใน dashboards และ charts แผนภาพด้านล่างแสดง price range ของ Goldman Sachs ในช่วง 15 นาที:

สร้างแอปพลิเคชันการเงินที่ขยายได้ด้วย RedisTimeSeries

แผนภาพด้านล่างแสดงข้อมูลเดียวกันในรูปแบบ line chart บ่งชี้ว่า price range ที่ Goldman Sachs trade กลายแคบลงมากเมื่อเวลาผ่านไปในวัน (แผนภาพนี้แสดง integer timestamps บนแกน x):

สร้างแอปพลิเคชันการเงินที่ขยายได้ด้วย RedisTimeSeries

คุณสามารถ query แบบเดียวกันกับอีก measure ของ volatility—standard deviation—เป็น aggregation function:

rts.range( 'INTRADAYPRICES15MINSTDP:GS' , from_time = 1603704600 , to_time = 1603713600)
[(1603704600, 0.54657783830434), (1603705500, 0.23201149395202), (1603706400, 0.196072381345986), (1603707300, 0.160267138157647), (1603708200, 0.116990621700049), (1603709100, 0.28043101744222), (1603710000, 0.144379900126934), (1603710900, 0.327611558618967), (1603711800, 0.163118915546951), (1603712700, 0.151417199675549), (1603713600, 0.0963889432843203)]

สิ่งนี้เปิดโอกาสน่าสนใจมาก สมมติคุณอยากรู้ราคาหุ้น Goldman Sachs เมื่อ intraday RSI value อยู่ระหว่าง 30 และ 40 คุณสามารถ query time series สำหรับ RSI และ time series ของราคาหุ้น เพื่อระบุ entry points ที่ให้กำไรสำหรับ trade

ที่นี่ ผม query ค่า RSI สำหรับ Goldman Sachs ใน time frame ระหว่าง 1605260100 (9:35 น. ET วันที่ 13 พฤศจิกายน 2020) และ 1605260940 (9:49 น. ET วันเดียวกัน)

dailyGSRSIValue = rts.range( 'DAILYRSI:GS' , from_time = 1605260100 , to_time = 1605260940)

คำ query พบว่า RSI value คือ 34.2996427544861 ที่ 1605260820 (9:47 น. ET)

[(1605260100, 75.0305441024708), (1605260160, 81.6673948350152), (1605260220, 83.8852225932517), (1605260280, 85.9469082344746), (1605260340, 94.3803586011592), (1605260400, 92.2412262502652), (1605260460, 85.6867329371465), (1605260520, 87.9557361513823), (1605260580, 89.9407873066781), (1605260640, 57.1512452602676), (1605260700, 50.5638232111769), (1605260760, 35.2804436894564), (1605260820, 34.2996427544861), (1605260880, 54.5486275202972), (1605260940, 64.7593307385219)]

ตอนนี้ผมสามารถ query ราคาหุ้น Goldman Sachs intraday สำหรับ interval เดียวกับที่ใช้ query RSI หรือเปลี่ยน query โดยโปรแกรมเพื่อสะท้อนเวลาที่ RSI value อยู่ที่ 34.29 ตัวอย่างใช้ time frame เดียวกับ RSI query

dailyGSPrice = rts.range( 'INTRADAYPRICES:GS' , from_time = 1605260100 , to_time = 1605260940)

คำ query คืนค่าราคาหุ้น Goldman Sachs สำหรับ range ที่ระบุ: ที่ 1605260820 (9:47 น. ET วันที่ 13 พฤศจิกายน 2020) ราคาคือ $217.18

[(1605260100, 216.57), (1605260160, 216.73), (1605260220, 217.08), (1605260280, 217.17), (1605260340, 217.87), (1605260400, 218.05), (1605260460, 217.91), (1605260520, 218.0), (1605260580, 218.11), (1605260640, 218.02), (1605260700, 217.72), (1605260760, 217.22), (1605260820, 217.18), (1605260880, 217.46), (1605260940, 217.61)]

RedisTimeSeries ให้วิธี query ข้าม multiple time series พร้อมกันอย่างทรงพลัง คำสั่ง TS.MGET ให้คุณ query ข้าม multiple time series โดยใช้ filters เราสร้าง time series ต่างๆ และ attach labels ไปแล้ว ตอนนี้ labels นั้นทำหน้าที่เป็น filters เพื่อ query ข้าม time series

โค้ด Python ต่อไปนี้ใช้ filters 2 ตัว บน labels "DESC" และ "TIMEFRAME" พารามิเตอร์ “with_labels=False” ให้ result set คืนมาโดยไม่มี labels สำหรับแต่ละค่า:

allRSIValues = rts.mget(filters=['DESC=RELATIVE_STRENGTH_INDEX','TIMEFRAME=1_DAY'], with_labels=False)

คำ query นี้จะนำเสนอผลลัพธ์คล้ายกับที่แสดงที่นี่ ซึ่งคืนค่า RSI ล่าสุดข้ามหุ้นหลายตัว:

[{'DAILYRSI:BA': [{}, 1605261060, 62.2048922111768]}, {'DAILYRSI:CAT': [{}, 1605261060, 68.3834400302296]}, {'DAILYRSI:CRM': [{}, 1605261060, 59.2107333830133]}, {'DAILYRSI:CSCO': [{}, 1605261060, 52.7011052724688]}, {'DAILYRSI:CVX': [{}, 1605261060, 62.9890368832232]}, {'DAILYRSI:DOW': [{}, 1605261060, 73.597680480764]}, {'DAILYRSI:GS': [{}, 1605283140, 41.182852552541]}, {'DAILYRSI:IBM': [{}, 1605261060, 65.3742140862697]}, {'DAILYRSI:JPM': [{}, 1605261060, 77.7760292843745]}, {'DAILYRSI:KO': [{}, 1605261060, 26.8638381005608]}, {'DAILYRSI:MMM': [{}, 1605261060, 65.7852833683174]}, {'DAILYRSI:MRK': [{}, 1605261060, 38.9991886598036]}, {'DAILYRSI:UNH': [{}, 1605261060, 74.2672428885775]}, {'DAILYRSI:VZ': [{}, 1605261060, 33.177554436462]}, {'DAILYRSI:WBA': [{}, 1605261060, 47.3877762365391]}]

หากผมตั้ง “with_labels=True” ผลลัพธ์จะรวม labels ทั้งหมดบนแต่ละ time series ตามที่แสดงที่นี่:

[{'DAILYRSI:BA': [{'SYMBOL': 'BA', 'DESC': 'RELATIVE_STRENGTH_INDEX', 'INDEX': 'DJIA', 'TIMEFRAME': '1_DAY', 'INDICATOR': 'RSI', 'COMPANYNAME': 'BOEING'}, 1605261060, 62.2048922111768]}, {'DAILYRSI:CAT': [{'SYMBOL': 'CAT', 'DESC': 'RELATIVE_STRENGTH_INDEX', 'INDEX': 'DJIA', 'TIMEFRAME': '1_DAY', 'INDICATOR': 'RSI', 'COMPANYNAME': 'CATERPILLAR'}, 1605261060, 68.3834400302296]}, {'DAILYRSI:CRM': [{'SYMBOL': 'CRM', 'DESC': 'RELATIVE_STRENGTH_INDEX', 'INDEX': 'DJIA', 'TIMEFRAME': '1_DAY', 'INDICATOR': 'RSI', 'COMPANYNAME': 'SALESFORCE'}, 1605261060, 59.2107333830133]}]

สรุป

บล็อกโพสต์นี้ illustrate คำสั่ง RedisTimeSeries หลายคำสั่ง เพื่อสร้างแอปพลิเคชันการเงินที่ยืดหยุ่นซึ่งพึ่งพา time-series data นักซื้อขายหุ้น ตัวอย่าง ต้องตัดสินใจเดิมพันสูงใน real time บนโดหลายสิบตัวแปร RedisTimeSeries เป็น schemaless หมายความว่าคุณโหลดข้อมูลได้โดยไม่ต้อง define schema เพิ่ม fields ใหม่ on the fly หรือเปลี่ยน data model หากสภาพแวดล้อมธุรกิจเปลี่ยนไป Real-time performance และ developer experience ที่เรียบง่าย ทำให้การทำงานกับ time-series data สนุกสนาน!

คุณหา sample code สำหรับบล็อกโพสต์นี้ได้ที่ GitHub ที่นี่ และเรียนรู้เพิ่มเติมเกี่ยวกับ RedisTimeSeries ที่นี่