
個人對於股市沒有這麼關心,短時間內股價怎麼起起落落,市場上什麼樣的消息可能會導致怎麼樣的變動,這些我都沒什麼概念,目前的操作也僅止於把一些閒錢拿去投資ETF或金融股這樣而已。
對於股市,我會想知道我什麼時候買(賣)了什麼股票,當時購入(出售)的成本如何,什麼時間點配息以及配息之後我的總投資成本如何變化等等,但這些在APP上不容易找到,APP提供的資訊也不是我需要的,所以還是自己刻一下吧。
需求是
- 只看指定的股票,並抓取指定的時間後的資料。
- 可以隨時增加新的股票代號。
- 可以手動登記每支股票買入、賣出、稅金、手續費與股息的紀錄,可以自動計算盈虧。
- 有一個總覽頁面可以快速地知道當下的狀況。
讓python來處理這些事情,先安裝python套件
$ pip3 install twstock pandas openpyxl
寫一支名為get_stock.py的script,第一次執行前修改12~16欄的資訊,執行get_stock.py後會得到一個stock.xlsx的檔案。之後執行視情況修改12~16欄的資訊,比如說多加一支股票代碼,這個script會去更新原來的stock.xlsx檔案並存檔。
import shutil
from datetime import datetime
from time import sleep
import twstock
import pandas as pd
from openpyxl import Workbook
from openpyxl import load_workbook
from openpyxl.utils import get_column_letter
from openpyxl.utils.dataframe import dataframe_to_rows
from openpyxl.styles import Font
#輸入以下資訊############################################################################
stock_array = ['2886', '5880', '0056', '00713', '00878', '00919', '00929', '00679B']
data_year = 2023
data_month = 3
########################################################################################
#更新台股股票代碼
twstock.__update_codes()
#檢查stock.xlsx是否存在
try:
wb = load_workbook('stock.xlsx')
except FileNotFoundError:
wb = Workbook()
wb.save('stock.xlsx')
else:
#複製一份原始檔當備份
current_date = datetime.now().strftime('%Y-%m-%d')
new_filename = f'stock_{current_date}.xlsx'
shutil.copyfile('stock.xlsx', new_filename)
#更新每檔股票內容
for stock in stock_array:
stock_name = twstock.realtime.get(stock)['info']['name']
stock_data = twstock.Stock(stock)
stock_history = stock_data.fetch_from(data_year, data_month)
stock_table = pd.DataFrame(data=stock_history, columns=['日期', '總成交股數', '總成交金額', '開盤價', '最高價', '最低價', '收盤價', '漲跌價差', '成交筆數'])
stock_table['日期'] = stock_table['日期'].dt.strftime('%Y-%m-%d')
rows = dataframe_to_rows(stock_table, index=False, header=True)
#若無列表中的股票則新增對應的分頁
if stock in wb.sheetnames:
sheet = wb[stock]
else:
sheet = wb.create_sheet(title=stock)
sheet.cell(row=1, column=10, value='購入/出售')
sheet.cell(row=1, column=11, value='購入價/出售價')
sheet.cell(row=1, column=12, value='股息')
sheet.cell(row=1, column=13, value='稅金/手續費')
sheet.cell(row=1, column=14, value='成本')
sheet.cell(row=1, column=15, value='總成本')
sheet.cell(row=1, column=16, value='股票市值')
sheet.cell(row=1, column=17, value='盈虧')
#清空分頁內的原有資料
for row in sheet.iter_rows(min_row=1, max_row=sheet.max_row, min_col=1, max_col=9):
for cell in row:
cell.value = None
#更新每日股票資訊
for r_idx, row in enumerate(rows, 1):
for c_idx, value in enumerate(row, 1):
sheet.cell(row=r_idx, column=c_idx, value=value)
sheet.cell(row=1, column=1, value=stock_name)
#計算與指定格式
for row in range(3, sheet.max_row + 1):
for col in sheet.iter_cols(min_row=row, max_row=row, min_col=11, max_col=17):
for cell in col:
if col[0].column == 11:
cell.number_format = '"$"#,##0.00'
elif col[0].column == 12:
cell.number_format = '"$"#,##0'
elif col[0].column == 13:
cell.number_format = '"$"#,##0'
elif col[0].column == 14:
cell.value = f'=J{row}*K{row}+L{row}+M{row}'
cell.number_format = '"$"#,##0'
elif col[0].column == 15:
cell.value = f'=N{row}+O{row-1}'
cell.number_format = '"$"#,##0'
elif col[0].column == 16:
cell.value = f'=SUM($J$2:$J{row})*G{row}'
cell.number_format = '"$"#,##0'
elif col[0].column == 17:
cell.value = f'=P{row}-O{row}'
cell.number_format = '"$"#,##0'
#統一字體
for row in sheet.iter_rows(min_row=1, max_row=sheet.max_row, min_col=1, max_col=17):
for cell in row:
cell.font = Font(name='Arial', size = "10")
#統一列距
for col_num in range(1, 4):
col_letter = get_column_letter(col_num)
sheet.column_dimensions[col_letter].width = 15
for col_num in range(4, 10):
col_letter = get_column_letter(col_num)
sheet.column_dimensions[col_letter].width = 10
for col_num in range(10, 18):
col_letter = get_column_letter(col_num)
sheet.column_dimensions[col_letter].width = 15
sleep(3)
#確認summary分頁是否存在
if 'summary' in wb.sheetnames:
new_ws = wb['summary']
else:
new_ws = wb.create_sheet(title='summary')
new_ws['B2'] = '股票代號'
new_ws['C2'] = '股票名稱'
new_ws['D2'] = '持有股數'
new_ws['E2'] = '持有成本'
new_ws['F2'] = '股票市值'
new_ws['G2'] = '目前收益'
new_ws['H2'] = '股息收益'
#更新summary分頁內容
z = 4
for sheet in wb:
if sheet.title == 'Sheet':
wb.remove(wb['Sheet'])
if sheet.title != 'summary' and sheet.title != 'Sheet':
new_ws[f'B{z}'] = sheet.title
new_ws[f'C{z}'] = f'=\'{sheet.title}\'!A1'
new_ws[f'D{z}'] = f'=SUM(\'{sheet.title}\'!J:J)'
new_ws[f'E{z}'] = f'=OFFSET(\'{sheet.title}\'!O1,COUNT(\'{sheet.title}\'!O:O)+1,0)'
new_ws[f'F{z}'] = f'=OFFSET(\'{sheet.title}\'!P1,COUNT(\'{sheet.title}\'!P:P)+1,0)'
new_ws[f'G{z}'] = f'=F{z}-E{z}'
new_ws[f'H{z}'] = f'=-SUM(\'{sheet.title}\'!L:L)'
z += 1
#統一字體
for row in new_ws.iter_rows(min_row=1, max_row=new_ws.max_row, min_col=2, max_col=8):
for cell in row:
cell.font = Font(name='Arial', size = "10")
wb.save('stock.xlsx')
stock.xlsx裡各個股票需要手動維護的是登記買入、賣出、稅金、手續費與股息的部分,在各支股票分頁裡的J~M欄,例如我在2023-07-04購入20張00929,當時購入價為15.85元。
比如說在2023-08-14領了2190元的股息,收入以負數表示。
在summary分頁裡可以清楚地看到各支股票的狀況。