網頁

2024年3月16日 星期六

Python 計算股價 KDJ (2)

續上一篇:Python 計算股價 KDJ,這篇把它完備一點,再加上前一日收盤價格,今日收盤價格,差異和百分比:


我定義一個函數來取得最後日和前一日的收盤價格資料,並計算差異百分比,最後將結果傳回:

# 取得最後一天收盤資料
def last_day_data(name, df):
date = df.index[-1].strftime('%Y-%m-%d') # 取出最後一筆日期
price = round(df.Close[-1], 2) # 當日收盤價
pre_price = round(df.Close[-2], 2) # 前一日收盤價
diff = round(df.Close[-1] - df.Close[-2], 2) # 價格差異
percent = round(float(diff) * 100 / pre_price, 2) # 差異百分比
high = round(df.High[-1], 2) # 當日最高
low = round(df.Low[-1], 2) # 當日最低
return [date, name, pre_price, price, diff, percent, high, low]

完整程式碼如下:

import yfinance as yf
import pandas as pd
# 計算KDJ,以9日週期計算
def calc_kdj(df, n=9):
low_list = df['Low'].rolling(window=n).min()
low_list.fillna(value=df['Low'].expanding().min(), inplace=True)
high_list = df['High'].rolling(window=n).max()
high_list.fillna(value=df['High'].expanding().max(), inplace=True)
rsv = (df['Close'] - low_list) / (high_list - low_list) * 100

df['K'] = rsv.ewm(com=2).mean()
df['D'] = df['K'].ewm(com=2).mean()
df['J'] = 3 * df['K'] - 2 * df['D']

r = round(rsv.iloc[-1], 2)
k = round(df.iloc[-1].K, 2)
d = round(df.iloc[-1].D, 2)
j = round(df.iloc[-1].J, 2)

return [r, k, d, j]
 
# 取得最後一天收盤資料
def last_day_data(name, df):
date = df.index[-1].strftime('%Y-%m-%d') # 取出最後一筆日期
price = round(df.Close[-1], 2) # 當日收盤價
pre_price = round(df.Close[-2], 2) # 前一日收盤價
diff = round(df.Close[-1] - df.Close[-2], 2) # 價格差異
percent = round(float(diff) * 100 / pre_price, 2) # 差異百分比
high = round(df.High[-1], 2) # 當日最高
low = round(df.Low[-1], 2) # 當日最低
return [date, name, pre_price, price, diff, percent, high, low]
 
def list_conv_matrix(lst):
data, data_matrix = [], []
for val in lst:
data_matrix.append(val)
cols = ['Date', 'Name', '前一日', '收盤價', '差異', '%', '當日最高', '當日最低',
'RSV', 'K', 'D', 'J']
return pd.DataFrame(data_matrix, columns=cols).set_index('Date')
 
def get_ticker_data(ticker_list):
data = []
for ticker in ticker_list:
df = yf.download(ticker, period='30d')

kdj_list = calc_kdj(df) # 計算KDJ
data_list = last_day_data(ticker, df) # 取得最後一天收盤資料
date_str = data_list[0] # 取出日期
data_list.extend(kdj_list)
data.append(data_list)
return data

ticker_list = ['AAPL', 'AMZN', 'GOOGL']
df = list_conv_matrix(get_ticker_data(ticker_list))
df
 

執行結果:

 

你可以參考上一篇:

Python 計算股價 KDJ (1)


2024年3月11日 星期一

Python 計算股價 KDJ

KDJ是通過一個特定的周期(常見為9天)內出現的最高價、最低價和最後交易日的收市價,以及三者之間的比例關係,計出未成熟隨機值(Raw Stochastic Value,RSV),再根據平滑移動平均線(又名「指數移動平均線」,EMA) 的方法計出K值、D值和J值。


今天就來講解如何用python計算KDJ值。

1.首先匯入相關套件:

import yfinance as yf
import pandas as pd

2.下載特斯拉(美股代號:TSLA) 最近30天的股價資料,(列出最後5日資料查看):

 

3.計算 KDJ 值,以最後收盤日2024/03/08 與看盤軟體Tiger trade驗證:

Tiger trade的 K值是18.23,D值是33.04J值是-11.38,計算沒問題

4.將股票名稱,最後收盤價,KDJ值放入list

5.寫一個函數將list轉成 DataFrame 格式,欄位有:名稱(Name),最後收盤價格(Price),K,D,J,並且以股票名稱"Name"當作索引欄,並傳回DataFrame:

6.最後將上面的程式寫成3個函數,
(1)計算KDJ:calc_kdj()
(2)取得股價的資料:get_ticker_price()
(3)list轉換dataframe:list_conv_matrix()

7.我用蘋果(AAPL),輝達(NVDA),特斯拉(TSLA) 這3支股票來計算 KDJ,執行結果如下:

8.最後如果要將 dataframe 存成 csv 檔可以用下面的指令:

kdj_df.to_csv(file_name, sep=',')  # 用逗點分隔的csv檔

完整程式碼如下:

import yfinance as yf
import pandas as pd
 
def calc_kdj(df, n=9):
low_list = df['Low'].rolling(window=n).min()
low_list.fillna(value=df['Low'].expanding().min(), inplace=True)
high_list = df['High'].rolling(window=n).max()
high_list.fillna(value=df['High'].expanding().max(), inplace=True)
rsv = (df['Close'] - low_list) / (high_list - low_list) * 100
df['K'] = rsv.ewm(com=2).mean()
df['D'] = df['K'].ewm(com=2).mean()
df['J'] = 3 * df['K'] - 2 * df['D']
r = round(rsv[-1], 2)
k = round(df[-1:]['K'][0], 2)
d = round(df[-1:]['D'][0], 2)
j = round(df[-1:]['J'][0], 2)
price = round(df[-1:]['Close'][0], 2) # 最後一日收盤價
return price, r, k, d, j

def get_ticker_price(ticker_list):
price_data = []
for ticker in ticker_list:
df = yf.download(ticker, period='30d')
price, r, k, d, j = calc_kdj(df)
date = df.index[-1].strftime('%Y-%m-%d')
data_list = [date, ticker, price, r, k, d, j]
price_data.append(data_list)
return price_data, date

def list_conv_matrix(lst):
data, data_matrix = [], []
for val in lst:
data_matrix.append(val)
cols = ['Date', 'NAME', 'Price', 'RSV', 'K', 'D', 'J']
return pd.DataFrame(data_matrix, columns=cols).set_index('Date')
 
ticker_list = ['AAPL', 'NVDA', 'TSLA']
data, date = get_ticker_price(ticker_list)
kdj_df = list_conv_matrix(data)
print(kdj_df)
 


你可以參考下一篇:

Python 計算股價 KDJ

 

2024年1月18日 星期四

LangChain實作:用ChatPDF找出文件重點

本篇是利用LangChain框架的ChatPDF工具,讀入pdf file,然後透過提問的方式,快速進行文件摘要總結,甚至請它提供建議。

1.首先 import 相關套件:

! pip install -U langchain-openai
from langchain_openai import OpenAIEmbeddings
!pip install kaleido
!pip install langchain pypdf sentence_transformers chromadb tiktoken openai
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.document_loaders import TextLoader, PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import Chroma
from langchain.chat_models import ChatOpenAI
from langchain.chains import ConversationalRetrievalChain
 

2.準備你的openAI API key (或是去申請):

import os
os.environ["OPENAI_API_KEY"] = 'sk-kxz......'

3.因為我是用 Colab線上編輯器,所以先掛載雲端硬碟,然後才能讀取雲端硬碟的檔案:

from google.colab import drive
drive.mount('/content/drive')

3.使用LangChain提供的讀檔方式讀取PDF檔案:
檔案是 索甲仁波切的 "西藏生死書",第六章演化業與輪迴

# 讀取檔案
file_path = "/content/drive/My Drive/Colab Notebooks/openai/西藏生死書_第六章演化業與輪迴.pdf"
loader = file_path.endswith(".pdf") and \
        PyPDFLoader(file_path) or \
        TextLoader(file_path)

如果是 txt 文字檔,可以這樣:

# txt文字檔的讀取方式
loader = TextLoader("/content/drive/My Drive/Colab Notebooks/openai/臨終的恐懼.txt")

4.由於語言模型一次能讀取的文字數量有限,因此需要將文件切分成數個小區塊:
每個區塊(chunk) 200個字元

# 利用 splitter 將文字切分成多個 chunk
splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=0)
texts = loader.load_and_split(splitter)

5.透過Chroma (一個專門為LLM embedding database設計的工具)
將剛剛的文字轉換成向量,最後儲存成一個本地的vector store。

# 建立本地 db
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(texts, embeddings)

6.最後建立對話chain,使用LangChain的ConversationalRetrievalChain:

# 對話 chain
qa = ConversationalRetrievalChain.from_llm(ChatOpenAI(temperature=0), 
        vectorstore.as_retriever()
    )
chat_history = []
while True:
query = input('\nQ: ')
if not query:
break
result = qa({"question": query + ' (用繁體中文回答)', "chat_history": chat_history})
print('A:', result['answer'])
chat_history.append((query, result['answer']))

7.結果:

Q: 意識來自何方?

A: 從佛教的觀點來看,意識來自於前一刻意識的連續。意識是一個持續不斷的過程,
每一刻的意識都是由前一刻的意識所產生。因此,意識沒有一個特定的來源,而是由無窮盡
的過去意識所連續形成的。

Q: 用300字總結這文件的重點
A: 這份文件的重點是,瀕死經驗中的人會經歷全景式的生命回顧,看到自己的行為對他人產生的影響,
並感受到業的真理。他們意識到每一個思想、語言和行為都對周圍的人和環境產生影響,
並且認識到負責任的重要性。他們也明白逃脫不了業的自然律,並意識到未來世的存在。
最終,他們希望通過觀察業的法則、淨化心靈和喚醒智慧,成為真正的人並證悟。 
 
另外,我再用 索甲仁波切的 "西藏生死書"的 臨終的恐懼篇 來測試一下:
# 讀取檔案
file_path = "/content/drive/My Drive/Colab Notebooks/openai/臨終的恐懼.pdf"
loader = file_path.endswith(".pdf") and PyPDFLoader(file_path) or TextLoader(file_path)
結果:

Q: 如何面對臨終前未完成的事
A: 面對臨終前未完成的事,可以遵循以下方法:

1. 深入思考:花時間反思自己的生活,找出那些未完成的事情。這可能包括個人目標、夢想、
關係或者其他重要的事情。

2. 優先排序:將這些未完成的事情按照重要性和緊迫性進行排序。確定哪些事情是最重要的,
並優先處理它們。

3. 與親友溝通:與親友分享自己的未完成事項,並尋求他們的理解和支持。他們可能能夠提供幫助、
建議或者陪伴你完成這些事情。

4. 接受現實:有些事情可能無法在臨終前完成,這是現實。學會接受這些無法改變的情況,
並尋找其他方式來處理或者放下這些事情。

5. 尋求心理支持:如果你感到壓力、焦慮或者情緒困擾,尋求心理專業人士的幫助是很重要的。
他們可以提供情緒支持和指導,幫助你處理這些未完成的事情。

6. 尋找內心寧靜:在臨終前,尋找內心的寧靜和平靜是非常重要的。這可以通過冥想、呼吸練習、
寫日記或者其他自我反省的方式來實現。

7. 培養感恩之心:感恩自己所擁有的一切,並將注意力轉移到當下的幸福和滿足感上。
這有助於減輕對未完成事情的焦慮和壓力。

重要的是要記住,每個人的情況和處理方式都不同。找到適合自己的方法,並尋求支持和幫助,
以幫助你面對臨終前的未完成事情。
Q: 用200字總結這文件的重點
A: 這份文件的重點是關於如何在臨終關懷中放下過去的困難,並與臨終者進行對話和溝通。
文件提到了寫下自己的感覺和對話,直到沒有保留的話為止。同時,文件呼籲醫界人士以善意和關懷,
讓臨終者能夠在寧靜和安詳中離世。此外,文件還提到了保留愛和美好回憶的重要性,
以及家人也應該學習如何放下並面對悲痛和未來的不安全感。

2024年1月3日 星期三

用 Python 製作股票績效比較圖表

程式碼如下:

 
import yfinance as yf
import pandas as pd
import matplotlib.pyplot as plt
 
# 製作美股代碼與名稱的字典
tickers_dict = {'NVDA':'Nvidia', 'META':'Meta', 'TSLA':'Tesla',
'AMZN':'Amazon', 'AAPL':'Apple', 'MSFT':'MicroSoft',
'GOOGL':'Google'}
 
tickers_list = list(tickers_dict.keys())
legend_text = []
list(map(lambda x:legend_text.append(tickers_dict[x]), tickers_list))
 
# 下載股價收盤價格,區間從2023/01/01~2023/12/31 
df = yf.download(tickers_list, start="2023-01-01", end="2023-12-31")['Close']
print(df.tail())
 
# 利用cumprod函數畫出回報率圖表
((df.pct_change() + 1).cumprod()-1).plot(figsize=(10, 7))
# 圖表名稱
plt.title('1 Years Returns', fontsize=16)
 
# 定義 X軸 Y軸 的名稱
plt.ylabel('Cumulative Returns', fontsize=14)
plt.xlabel('Year', fontsize=14)

# 圖表要呈現格線
plt.grid(which="major", color='k', linestyle='-.', linewidth=0.5)
plt.show()
 

 輸出結果:

看起來2023年度績效最好的是Nvidia,最差的是Apple。

如果Y軸要以百分比來表示可以將:

 
 (df.pct_change() + 1).cumprod()-1).plot(figsize=(10, 7))
 

改成:

 
data = ((df.pct_change() + 1).cumprod() -1 )
ax = data.plot(figsize=(10, 7))
vals = ax.get_yticks()
ax.set_yticklabels(['{:.0%}'.format(x) for x in vals])
 

輸出結果:

以Nvidia (美股代號:NVDA) 2023/01/03收盤價143.15,到2023/12/29收盤價495.22來算

回報率為245.94%


2023年4月30日 星期日

使用 Python 製作台股代碼與股票名稱對應字典(二)

上一篇提到將台股上市上櫃公司名稱從證交所網頁抓下來,並存成 dataframe 的格式,如下:

如果要用 yfinance 來取得股價寫法是:

import yfinance as yf
hist = yf.Ticker('1101.TW') # 台泥
price_df = hist.history(period='1d', auto_adjust=False)

因此我們要有一個 '1101.TW' 可以對應到 '台泥' 的一個 table,我們可以這樣做,

將上一篇得到的 df 的有價證券代號及名稱欄位的值切開,例如上圖,索引0台泥的 '有價證券代號及名稱' 欄位的值是 '1101  台泥',我們要切開成為 '1101.TW' 和 '台泥'

code, name = df['有價證券代號及名稱'][0].split()
print(code, name)

結果:1101 台泥 
將變數code+'.TW',就是股票代碼,股票名稱就是'台泥',然後使用 code 當作字典的key,
name當作字典的value,我們可以用一個迴圈跑完整個 df,順便將產業別也放上去
stock_dict = {}
for index, item in enumerate(df['有價證券代號及名稱']):
name_list = item.split()
code = name_list[0] + '.TW'
name = name_list[1]
key = code
value = [name, df['產業別'][index]]
stock_dict[key] = value
print(index, code, value)

 
 
 
 
 
然後將上面的程式寫成 function: 
# 製作股票代碼與股票名稱dict
def make_stock_dict(df):
stock_dict = {}
for index, item in enumerate(df['有價證券代號及名稱']):
name_list = item.split()
code = name_list[0] + '.TW'
name = name_list[1]
key = code
value = [name, df['產業別'][index]]
stock_dict[key] = value
return stock_dict
要呼叫的時候就這樣寫:
stock_dict = make_stock_dict(df)

返回的變數 stock_dict 是字典型態,
鍵(key)是股票代碼;值(value)是一個list,包含公司名稱和產業別。
這樣就製作了一個台股代碼和公司,名產業別的一個對照清單。

 
你可以參考上一篇:
1. 用 Python 取得台股上市上櫃清單(一)
 
 



2023年4月29日 星期六

用 Python 取得台股上市上櫃清單(一)

各位知道目前台股上市上櫃的公司有多少嗎?
今天用 Python 來抓取台灣證券交易所上市上櫃的公司清單。

台灣證券交易所公佈的上市證券國際證券辨識號碼一覽表網頁在:
https://isin.twse.com.tw/isin/C_public.jsp?strMode=2

 Mode=2是上市資料,Mode=4是上櫃資料,現在先用上市資料來說明。

1.首先先載入相關套件:

import requests
import pandas as pd

2. 將html 網頁資料抓下來存成 dataframe資料格式:

res = requests.get("http://isin.twse.com.tw/isin/C_public.jsp?strMode=2")
df = pd.read_html(res.text)[0]
df

3. 接著設定欄位(column)名稱:

df.columns = df.iloc[0]
df


4.  刪除第一行(Row):

df = df.iloc[2:]
df 


5. 接著要找出CFI code 是 ESVUFR 的資料,其中CFI代碼CBCIXU是不動產投資信託,CEOGEU是ETF . . .

df = df[df['CFICode'] == 'ESVUFR']
df

6. 現在資料有977筆,就是上市公司資料,接著我們要將索引序號重新編排一下:

df = df.reset_index(drop=True)
df

7. 最後我們把這寫成一個 function:

def crawler_stock_name(req_code):
# req_code:2 上市,
# req_code:4 上櫃
res = requests.get("http://isin.twse.com.tw/isin/C_public.jsp?strMode=" + str(req_code))
df = pd.read_html(res.text)[0]
# 設定column名稱
df.columns = df.iloc[0]
# 刪除第一行
df = df.iloc[2:]
# 篩選資料
df = df[df['CFICode'] == 'ESVUFR']
# index 序號重新編號
df = df.reset_index(drop=True)
return df

要取得上市公司的資料就執行:

df = crawler_stock_name(2)
df

要取得上櫃公司的資料就執行:

df = crawler_stock_name(4)
df
上櫃公司809家

下篇再來講一下如何將股票代碼和公司名稱做一個索引。

你可以參考:

1.  使用 Python 製作台股代碼與股票名稱對應字典(二)