Skip to content

Instantly share code, notes, and snippets.

@tej87681088
Created September 8, 2023 08:35
Show Gist options
  • Save tej87681088/a454b23fa33244d9cdad450ecd7c12cd to your computer and use it in GitHub Desktop.
Save tej87681088/a454b23fa33244d9cdad450ecd7c12cd to your computer and use it in GitHub Desktop.
# streamlit run app.py
# http://localhost:8501/
# STREAMLIT套件
import streamlit as st
import pandas as pd
# 可以互動的PLOT套件
import plotly.graph_objects as go
# 設置日期格式的套件
import datetime
from datetime import datetime as dt
from datetime import timedelta
import tejapi
# 登入TEJ API
tejapi.ApiConfig.api_key = 'your_key'
#把時間取消保留日期 (無視)
tejapi.ApiConfig.ignoretz = True
st.set_page_config(page_title='量化投資', page_icon=':bar_chart:', layout='wide')
with st.sidebar:
st.title('TEJAPI股票學習')
col1, col2 = st.columns(2)
with col1:
# 將股票起使日期設置為變數d1
d1 = st.date_input(
"股票起始日期",
# 並將預設資料設定為2022年的1/1
datetime.date(2022, 1, 1))
with col2:
# 將股票起使日期設置為變數d2
d2= st.date_input(
"股票結束日期",
datetime.date(2023, 2, 3))
#輸入股價
# 使用date套件的date獲取今天的日期資料
current_date = dt.now().date()
# 使用date套件的timedelta獲取昨天的日期資料
previous_date = current_date - timedelta(days=1)
data = tejapi.get('TWN/APIPRCD',
mdate=previous_date,
opts={'columns':['coid']},
paginate=True)
coids = data['coid'].tolist()
stock_code = st.selectbox('選擇股票代碼', data)
st.write('你選擇股票是: ', stock_code)
upper_bound = st.number_input('上界值:',value=150)
lower_bound = st.number_input('下界值:',value=100)
interval = st.number_input('網格區間:',value=10)
stock_id = {stock_code}
gte, lte = {d1}, {d2}
tejdata= tejapi.get('TWN/APIPRCD',
paginate = True,
coid = stock_id,
mdate = {'gte':gte, 'lte':lte},
chinese_column_name=True
)
df = tejdata
df.reset_index(drop=True, inplace=True)
# 創建 Buy_Signal 和 Sell_Signal 列,預設為 False
df['Buy_Signal'] = False
df['Sell_Signal'] = False
# 在適當的條件下,將 Buy_Signal 和 Sell_Signal 設置為 True
grid = list(range(lower_bound, upper_bound + interval, interval))
for i in range(1, len(df)):
for price in grid:
if df['收盤價'][i-1] > price >= df['收盤價'][i]:
df.at[i, 'Buy_Signal'] = True
if df['收盤價'][i-1] < price <= df['收盤價'][i]:
df.at[i, 'Sell_Signal'] = True
st.title('🌐STREAMLIT股票資料網格交易應用')
st.write("")
tab1, tab2, tab3 = st.tabs(["交易訊號", "資料集", "投資績效表"])
with tab1:
st.title(stock_code)
fig = go.Figure()
fig.add_trace(go.Scatter(x=df['資料日'], y=df['收盤價'], name=stock_code))
# 創建網格,將線條顏色設置為灰色
for price in grid:
fig.add_shape(type="line", x0=df['資料日'].iloc[0], x1=df['資料日'].iloc[-1], y0=price, y1=price, line=dict(color='gray'))
# 加入買進訊號的散點圖
buy_signals = df[df['Buy_Signal']]
fig.add_trace(go.Scatter(x=buy_signals['資料日'], y=buy_signals['收盤價'], mode='markers', name='Buy Signal', marker=dict(color='green', size=10, symbol='triangle-up')))
# 加入賣出訊號的散點圖
sell_signals = df[df['Sell_Signal']]
fig.add_trace(go.Scatter(x=sell_signals['資料日'], y=sell_signals['收盤價'], mode='markers', name='Sell Signal', marker=dict(color='red', size=10, symbol='triangle-down')))
fig.update_layout()
st.plotly_chart(fig)
with tab2:
st.dataframe(df, height=500)
@st.cache_data
def convert_df(df):
# IMPORTANT: Cache the conversion to prevent computation on every rerun
return df.to_csv().encode("utf-8")
csv = convert_df(df)
st.download_button(
label="點此下載資料範例",
data=csv,
file_name=f"{stock_code}股價資料.csv",
mime="text/csv",
)
with tab3:
st.title('交易模擬')
# 初始化本金和交易紀錄表
principal = 500000
cash = principal
position = 0
order_unit = 1000 # 每次交易的股數
trade_book = pd.DataFrame(columns=['Coid', 'BuyOrSell', 'BuyTime', 'SellTime', 'CashFlow', 'TradeUnit', 'HoldingPosition', 'CashValue'])
st.write("本金:", principal)
# 進行網格交易並更新交易紀錄表
for i in range(1, len(df)):
cu_time = df['資料日'][i]
cu_close = df['收盤價'][i]
n_time = df['資料日'][i - 1]
n_open = df['開盤價'][i]
if position == 0 and df['Buy_Signal'][i]:
# 判斷是否進行買進
position += 1
order_time = n_time
order_price = n_open
friction_cost = (20 if order_price * order_unit * 0.001425 < 20 else order_price * order_unit * 0.001425)
total_cost = -1 * order_price * order_unit - friction_cost
cash += total_cost
trade_book = trade_book.append({'Coid': stock_id, 'BuyOrSell': 'Buy', 'BuyTime': order_time, 'SellTime': None, 'CashFlow': total_cost, 'TradeUnit': order_unit, 'HoldingPosition': position, 'CashValue': cash}, ignore_index=True)
elif position > 0 and df['Sell_Signal'][i]:
# 判斷是否進行賣出
order_price = n_open
cover_time = n_time
friction_cost = (20 if order_price * order_unit * 0.001425 < 20 else order_price * order_unit * 0.001425) + order_price * order_unit * 0.003
total_cost = order_price * order_unit - friction_cost
cash += total_cost
trade_book = trade_book.append({'Coid': stock_id, 'BuyOrSell': 'Sell', 'BuyTime': None, 'SellTime': cover_time, 'CashFlow': total_cost, 'TradeUnit': -1 * order_unit, 'HoldingPosition': position, 'CashValue': cash}, ignore_index=True)
position = 0
st.write("交易紀錄表:")
st.dataframe(trade_book)
# 計算交易相關數據
overallreturn = ((cash - principal) / principal) * 100
num_trade = len(trade_book)
num_buy = len(trade_book[trade_book['BuyOrSell'] == 'Buy'])
num_sell = len(trade_book[trade_book['BuyOrSell'] == 'Sell'])
# 計算平均交易報酬
avg_return_ = (trade_book['CashFlow'] / (trade_book['TradeUnit'] * trade_book['CashValue'])).mean() * 100
# 計算平均持有期間
trade_book['BuyTime'] = pd.to_datetime(trade_book['BuyTime']) # 將BuyTime轉換為datetime格式
trade_book['SellTime'] = pd.to_datetime(trade_book['SellTime']) # 將SellTime轉換為datetime格式
# 計算持有期間並排除掉NaN和負值
trade_book['HoldPeriod'] = (trade_book['SellTime'] - trade_book['BuyTime']).dt.days
trade_book['HoldPeriod'] = trade_book['HoldPeriod'].apply(lambda x: max(x, 0)) # 將持有期間中的負值改為0
avg_hold_period_ = trade_book['HoldPeriod'].mean()
# 計算勝率
winning_rate = (len(trade_book[trade_book['CashFlow'] > 0]) / num_trade) * 100
# 計算最大獲利交易報酬和最大損失交易報酬
trade_book['ReturnPercentage'] = (trade_book['CashFlow'] / (trade_book['TradeUnit'] * trade_book['CashValue'])) * 100
max_win = trade_book['ReturnPercentage'].max()
max_loss = trade_book['ReturnPercentage'].min()
# 計算最低現金持有量
min_cash = trade_book['CashValue'].min()
# 呈現交易相關數據
st.write('總績效:', overallreturn, '%')
st.write('交易次數:', num_trade, '次')
st.write('買入次數:', num_buy, '次')
st.write('賣出次數:', num_sell, '次')
st.write('平均交易報酬:', avg_return_, '%')
st.write('勝率:', winning_rate, '%')
st.write('最大獲利交易報酬:', max_win, '%')
st.write('最大損失交易報酬:', max_loss, '%')
st.write('最低現金持有量:', min_cash)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment