Side Project Document
  • 如果沒能一次成功,那就叫它 1.0 版吧。
  • Stock Price for LINE Notify V1
    • 前言
    • 一、申請玉山富果 API
    • 二、申請 LINE Notify Token
    • 三、環境架設與資料表設定
    • 四、SSIS 設計
      • SSIS 流程圖
      • Move to History Table & Truncate Table
      • Foreach Loop to Get API
      • Lookup File - Chart
      • Lookup File - Quote
      • Join Table to Result Set
      • Post Result Set to LINE Notify
      • Delete Over 3 days Files
      • 事件處理常式
    • 五、安裝教學
  • Stock Price for LINE Notify V2
    • 前言
    • 一、軟體架構與流程圖
    • 二、環境架設與資料表設定
    • 三、Python 程式說明
      • 主程式:Local_Stock_Main.py
      • 取得個股基本資訊:Local_Stock_Meta.py
      • 取得個股交易資訊:Local_Stock_Quote.py
      • 將折線圖發送至 LINE Notify:Local_Stock_Line_Notify.py
      • 資料解密:Local_Encryption.py
      • 排程設定
  • Stock Price for LINE Notify V3
    • 前言
    • 一、軟體架構與流程圖
    • 二、環境架設與資料表設定
    • 三、Python 程式說明
      • Local_Stock_Main.py
      • Local_Stock_Meta.py
      • Local_Stock_Quote.py
      • Local_Stock_Line_Notify.py
      • Create_RSA_Key.py
      • Encrypt_Data.py
      • Decrypt_Data.py
      • 排程設定
      • 加碼:.py 打包成 .exe 執行檔
Powered by GitBook
On this page
  1. Stock Price for LINE Notify V3
  2. 三、Python 程式說明

Local_Stock_Line_Notify.py

資料清洗完後,透過 VIEW 取得最終結果,將開盤價、最高價、最低價、漲幅等資訊繪製成折線圖,存檔之後透過 API 發送至 LINE Notify。

Local_Stock_Line_Notify.py
from datetime import datetime, timedelta
import requests
import datetime
from datetime import datetime
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.colors as mcolors
# 以下 package 需事先使用 pip install 安裝
import pandas
import pyodbc

'''
==================================================================================================================
Author: Skylar Ma
------------------------------------------------------------------------------------------------------------------
Description: Get the stock price information and draw it into a line chart and send it through LINE Notify.
------------------------------------------------------------------------------------------------------------------
Version  Date        Note
1.0      2023-05-27  Init.
==================================================================================================================
'''

# For MS-SQL
TABLE = "vw_For_Line_Notify"


def send_line_notify(symbolId, now, line_token, pic_folder):
    url = "https://notify-api.line.me/api/notify"
    headers = {
        "Authorization": f"Bearer {line_token}"
    }
    payload = {
        "message": f"{symbolId} 當日股價資訊"
    }
    image = open(f'{pic_folder}\\{symbolId}_{now}.png', 'rb')    # 以二進位方式開啟圖片
    imageFile = {'imageFile' : image}   # 設定圖片資訊
    r = requests.post(url, headers=headers, params=payload, files=imageFile)
    return r.status_code

def query_table(server_name, database, account, pwd, line_token, pic_folder):
    # 開啟 SQL Server 連線
    cnxn = pyodbc.connect('DRIVER={SQL Server};SERVER='+server_name+';DATABASE='+database+';UID='+account+';PWD='+ pwd)
    cursor = cnxn.cursor()

    # 查詢現在關注哪些標的
    query = "SELECT [stock_id] FROM [Stock_API].[dbo].[Stock_Get] WHERE isGet = 'TRUE';"
    df = pandas.read_sql(query, cnxn)

    for index, item in df.iterrows():
        symbolId = item['stock_id']
        # 設定前後七天
        to_date = datetime.today()
        from_date = to_date - timedelta(days=7)
        to_date_str = to_date.strftime("%Y-%m-%d")
        from_date_str = from_date.strftime("%Y-%m-%d")
        # 設定 Query 語法
        query_status_1 = f"SELECT * FROM [Stock_API].[dbo].[vw_For_Line_Notify] WHERE FullDate BETWEEN '{from_date_str}' AND '{to_date_str}' AND symbolId = '{symbolId}' AND SRC = 'Today';"
        # 讀取資料並寫入 Dataframe 中
        df1 = pandas.read_sql(query_status_1, cnxn)

        # 建立一個圖形,裡面包含四個子圖表,並設定大小為 8*6
        fig, (ax1, ax2, ax3, ax4) = plt.subplots(4, constrained_layout=True, figsize=(8, 6))

        # 【第一個子圖表:開盤價】
        ax1.plot(df1['date'], df1['priceOpen'], color = 'lightcoral', marker='o', markersize=4, label='Opening')
        # 取得最後一個資料點的座標
        last_date = df1['date'].iloc[-1]
        last_price = df1['priceOpen'].iloc[-1]
        # 在最後一個資料點上標上資料文字
        ax1.text(last_date, last_price, f'{last_price}', ha='right')

        # 【第二個子圖表:當日最高價】
        ax2.plot(df1['date'], df1['priceHigh'], color = 'sandybrown', marker='o', markersize=4, label='High')
        # 取得最後一個資料點的座標
        last_date = df1['date'].iloc[-1]
        last_price = df1['priceHigh'].iloc[-1]
        # 在最後一個資料點上標上資料文字
        ax2.text(last_date, last_price, f'{last_price}', ha='right')

        # 【第三個子圖表:當日最低價】
        ax3.plot(df1['date'], df1['priceLow'], color = 'mediumaquamarine', marker='o', markersize=4, label='Low')
        # 取得最後一個資料點的座標
        last_date = df1['date'].iloc[-1]
        last_price = df1['priceLow'].iloc[-1]
        # 在最後一個資料點上標上資料文字
        ax3.text(last_date, last_price, f'{last_price}', ha='right')

        # 【第四個子圖表:漲跌幅】
        ax4.plot(df1['date'], df1['changePercent'], color = 'steelblue', marker='o', markersize=4, label='Change\nPercent')
        # 取得最後一個資料點的座標
        last_date = df1['date'].iloc[-1]
        last_price = df1['changePercent'].iloc[-1]
        # 在最後一個資料點上標上資料文字
        ax4.text(last_date, last_price, f'{last_price}', ha='right')

        # 加上標題與座標名稱
        ax1.set_title(f"{symbolId} Opening")
        ax1.set_xlabel("Date")
        ax1.set_ylabel("Price")

        ax2.set_title(f"{symbolId} High")
        ax2.set_xlabel("Date")
        ax2.set_ylabel("Price")

        ax3.set_title(f"{symbolId} Low")
        ax3.set_xlabel("Date")
        ax3.set_ylabel("Price")

        ax4.set_title(f"{symbolId} Change Percent")
        ax4.set_xlabel("Date")
        ax4.set_ylabel("%")

        # 加上圖例與位置調整
        ax1.legend(bbox_to_anchor=(1.05, 1.0), loc='upper left')
        ax2.legend(bbox_to_anchor=(1.05, 1.0), loc='upper left')
        ax3.legend(bbox_to_anchor=(1.05, 1.0), loc='upper left')
        ax4.legend(bbox_to_anchor=(1.05, 1.0), loc='upper left')

        # 調整子圖間距
        fig.tight_layout()

        # 儲存圖表
        now = datetime.today().strftime('%Y%m%d%H%M%S%f')[:-3]
        plt.savefig(f'{pic_folder}\\{symbolId}_{now}.png',
                transparent=False,
                bbox_inches='tight',
                pad_inches=1)

        # 顯示圖形(測試用)
        #plt.show()

        status_code = send_line_notify(symbolId, now, line_token, pic_folder)
        if status_code == 200:
            print("訊息傳送成功!")
        else:
            print("訊息傳送失敗,錯誤碼:", status_code)
            
    cursor.close()
    cnxn.close()



def convertDatetime(time_string):
    # 解析時間字符串
    datetime_obj = datetime.fromisoformat(time_string)
    date_str = datetime_obj.strftime('%H:%M:%S')

    return date_str

# 測試用
#query_table(server_name, database, account, pwd, line_token, pic_folder)

Last updated 1 year ago