-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 2b1de24
Showing
4 changed files
with
291 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import pandas as pd | ||
import streamlit as st | ||
from streamlit_autorefresh import st_autorefresh | ||
from raindrop import make_raindrop_chart | ||
|
||
st.set_page_config(layout="wide", page_title="Raindrop Charts") | ||
tickers = pd.read_csv("tickers.csv") | ||
st.title("Raindrop Charts using Yfinance, Streamlit, & Plotly") | ||
|
||
today = pd.Timestamp.now() | ||
date = st.sidebar.date_input(label="Date Range", value=today) | ||
company = st.sidebar.selectbox(label="Company", options=tickers["Company"]) | ||
vwap_margin = st.sidebar.number_input(label="VWAP Margin", value=0.1, step=0.01, min_value=0., format="%.2f") | ||
frequency = st.sidebar.number_input(label="Bin Size (minutes)", value=30, step=1, min_value=5, max_value=60) | ||
ticker = tickers.loc[tickers["Company"] == company, "Ticker"].values[0] | ||
if pd.Timestamp(date) >= pd.Timestamp.now().floor("d"): | ||
count = st_autorefresh(interval=5000, limit=100, key="fizzbuzzcounter") | ||
raindrop_chart, vwap_open, vwap_close, ohlc = make_raindrop_chart( | ||
ticker=ticker, | ||
start=date.strftime("%Y-%m-%d"), | ||
end=(date + pd.Timedelta(days=1)).strftime("%Y-%m-%d"), | ||
interval="1m", | ||
frequency_value=frequency, | ||
margin=vwap_margin | ||
) | ||
col1, col2, col3 = st.columns(3) | ||
col1.metric("VWAP (Current vs Previous)", f"{str(vwap_close)}$", f"{str(vwap_close - vwap_open)}$") | ||
col2.metric("Current Prices (Close vs Open)", f"{str(ohlc['Close'])}$", f"{str(ohlc['Close'] - ohlc['Open'])}$") | ||
col3.metric("Last Update", str(pd.Timestamp.now().floor("s"))) | ||
st.plotly_chart(raindrop_chart, use_container_width=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
import pandas as pd | ||
import yfinance as yf | ||
import plotly.graph_objects as go | ||
from plotly.subplots import make_subplots | ||
|
||
|
||
def make_raindrop_chart( | ||
ticker: str = "AAPL", | ||
start: str = "2022-01-10", | ||
end: str = "2022-01-11", | ||
interval: str = "5m", | ||
frequency_unit: str = "m", | ||
frequency_value: int = 30, | ||
margin: float = 0.1 | ||
) -> go.Figure: | ||
df = yf.download( | ||
tickers=ticker, | ||
start=start, | ||
end=end, | ||
interval=interval, | ||
).reset_index() | ||
df["Typical"] = df[["Open", "High", "Low", "Close"]].sum(axis=1)/4 | ||
df["QTY*PX"] = df["Volume"] * df["Typical"] | ||
|
||
grouping_frequency = pd.Timedelta(frequency_value, unit=frequency_unit) | ||
split_frequency = pd.Timedelta(grouping_frequency.total_seconds() / 2, unit="s") | ||
|
||
ohlc = df.groupby(pd.Grouper(key="Datetime", freq=grouping_frequency)).agg( | ||
Open=("Open", "first"), | ||
High=("High", "max"), | ||
Low=("Open", "min"), | ||
Close=("Open", "last"), | ||
Volume=("Volume", "sum") | ||
) | ||
ohlc = ohlc.query("Volume > 0").reset_index() | ||
df["Split"] = df.groupby(pd.Grouper(key="Datetime", freq=split_frequency)).ngroup() | ||
df["Split"] = df["Split"] % 2 | ||
df["Datetime"] = df["Datetime"].dt.floor(grouping_frequency) | ||
volume_divider = df["Volume"].max()/1000 | ||
|
||
fig = make_subplots( | ||
rows=3, | ||
cols=1, | ||
row_heights=[0.45, 0.45, 0.1], | ||
shared_xaxes=True, | ||
vertical_spacing=0.01 | ||
) | ||
showlegend = True | ||
|
||
for period, period_df in df.groupby("Datetime"): | ||
vwap_df = period_df.groupby("Split", as_index=False)[["Volume", "QTY*PX"]].sum() | ||
vwap_df = vwap_df.query("Volume > 0").reset_index() | ||
if not vwap_df.empty: | ||
vwap_df["VWAP"] = vwap_df["QTY*PX"] / vwap_df["Volume"] | ||
color = "blue" | ||
if len(vwap_df.index) > 1: | ||
vwap_open, vwap_close = vwap_df.loc[0, "VWAP"], vwap_df.loc[1, "VWAP"] | ||
if (vwap_close - vwap_open) > margin: | ||
color = "green" | ||
elif (vwap_open - vwap_close) > margin: | ||
color = "red" | ||
period_df["Volume"] = period_df["Volume"].div(volume_divider).round() | ||
for split, split_df in period_df.groupby("Split"): | ||
is_pre_split = split == 0 | ||
# We multiply each row by volume of the trade. we multiply by 10 since smallest volume is 0.1 | ||
split_df = split_df.loc[split_df.index.repeat(split_df["Volume"])] | ||
fig.add_trace( | ||
go.Violin( | ||
x=split_df["Datetime"], | ||
y=split_df["Typical"], | ||
side="negative" if is_pre_split else "positive", | ||
name="Raindrop", | ||
legendgroup="Raindrop", | ||
showlegend=showlegend, | ||
line=dict(color=color), | ||
spanmode="hard", | ||
scalegroup=str(period), | ||
scalemode="count", | ||
points=False, | ||
hoverinfo="y", | ||
hoveron="violins", | ||
meanline=dict(color="white"), | ||
), | ||
row=1, | ||
col=1 | ||
) | ||
showlegend = False | ||
|
||
fig.add_trace( | ||
go.Candlestick( | ||
x=ohlc["Datetime"], | ||
open=ohlc["Open"], | ||
high=ohlc["High"], | ||
low=ohlc["Low"], | ||
close=ohlc["Close"], | ||
name="OHLC", | ||
decreasing_line_color="red", | ||
increasing_line_color="green", | ||
), | ||
row=2, | ||
col=1 | ||
) | ||
|
||
ohlc["BarColor"] = ohlc.apply(lambda x: "green" if x["Open"] < x["Close"] else "red", axis=1) | ||
showlegend = True | ||
for color, sub_ohlc in ohlc.groupby("BarColor"): | ||
fig.add_trace( | ||
go.Bar( | ||
x=sub_ohlc["Datetime"], | ||
y=sub_ohlc["Volume"], | ||
marker=dict(color=color), | ||
legendgroup="Volume", | ||
name="Volume", | ||
showlegend=showlegend, | ||
hovertemplate=None, | ||
texttemplate="%{y:.2s}" | ||
), | ||
row=3, | ||
col=1 | ||
) | ||
showlegend = False | ||
|
||
fig.update_xaxes( | ||
rangeslider_visible=False, | ||
row=2 | ||
) | ||
fig.update_xaxes( | ||
dtick=1000 * grouping_frequency.total_seconds(), | ||
showgrid=True, | ||
title="Datetime", | ||
row=3 | ||
) | ||
fig.update_xaxes( | ||
rangebreaks=[dict(bounds=[16, 9.5], pattern="hour")], | ||
) | ||
fig.update_yaxes(title="Price", row=1) | ||
fig.update_yaxes(title="Price", row=2) | ||
fig.update_yaxes(title="Volume", row=3) | ||
fig.update_layout( | ||
title=dict(text=ticker), | ||
violingap=0, | ||
violingroupgap=0, | ||
template="plotly_dark", | ||
height=800, | ||
uirevision="uirevision" | ||
) | ||
return fig, vwap_open, vwap_close, ohlc.to_dict("records")[-1] | ||
|
||
|
||
if __name__ == "__main__": | ||
raindrop = make_raindrop_chart()[0] | ||
raindrop.show("browser") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
pandas~=1.3 | ||
plotly~=5.5 | ||
streamlit~=1.3 | ||
streamlit-autorefresh==0.0.1 | ||
yfinance~=0.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
Company,Ticker | ||
Activision Blizzard,ATVI | ||
Adobe Inc.,ADBE | ||
Advanced Micro Devices,AMD | ||
Alexion Pharmaceuticals,ALXN | ||
Align Technology,ALGN | ||
Alphabet Inc. (Class A),GOOGL | ||
Alphabet Inc. (Class C),GOOG | ||
Amazon.com,AMZN | ||
Amgen,AMGN | ||
Analog Devices,ADI | ||
ANSYS,ANSS | ||
Apple Inc.,AAPL | ||
"Applied Materials, Inc.",AMAT | ||
ASML Holding,ASML | ||
Autodesk,ADSK | ||
"Automatic Data Processing, Inc.",ADP | ||
Baidu,BIDU | ||
Biogen,BIIB | ||
BioMarin Pharmaceutical Inc.,BMRN | ||
Booking Holdings,BKNG | ||
Broadcom Inc.,AVGO | ||
Cadence Design Systems,CDNS | ||
CDW,CDW | ||
Cerner Corporation,CERN | ||
"Charter Communications, Inc.",CHTR | ||
Check Point Software Technologies Ltd.,CHKP | ||
Cintas Corporation,CTAS | ||
Cisco Systems,CSCO | ||
Citrix Systems,CTXS | ||
Cognizant Technology Solutions Corporation,CTSH | ||
Comcast Corporation,CMCSA | ||
Copart,CPRT | ||
Costco Wholesale Corporation,COST | ||
CSX Corporation,CSX | ||
DexCom,DXCM | ||
DocuSign,DOCU | ||
"Dollar Tree, Inc.",DLTR | ||
eBay Inc.,EBAY | ||
Electronic Arts,EA | ||
Exelon Corporation,EXC | ||
Expedia Group,EXPE | ||
"Facebook, Inc.",FB | ||
Fastenal Company,FAST | ||
"Fiserv, Inc.",FISV | ||
Fox Corporation (Class A),FOXA | ||
Fox Corporation (Class B),FOX | ||
"Gilead Sciences, Inc.",GILD | ||
IDEXX Laboratories,IDXX | ||
"Illumina, Inc.",ILMN | ||
Incyte Corporation,INCY | ||
Intel Corporation,INTC | ||
Intuit,INTU | ||
Intuitive Surgical,ISRG | ||
JD.com,JD | ||
Keurig Dr Pepper Inc.,KDP | ||
KLA Corporation,KLAC | ||
Kraft Heinz Co,KHC | ||
Lam Research,LRCX | ||
Liberty Global (Class A),LBTYA | ||
Liberty Global (Class C),LBTYK | ||
Lululemon Athletica,LULU | ||
Marriott International,MAR | ||
Maxim Integrated Products,MXIM | ||
MercadoLibre,MELI | ||
Microchip Technology,MCHP | ||
"Micron Technology, Inc.",MU | ||
Microsoft Corporation,MSFT | ||
Moderna,MRNA | ||
Mondelēz International,MDLZ | ||
Monster Beverage Corporation,MNST | ||
"NetEase, Inc.",NTES | ||
Netflix,NFLX | ||
Nvidia Corporation,NVDA | ||
NXP Semiconductors N.V.,NXPI | ||
"O'Reilly Automotive, Inc.",ORLY | ||
PACCAR Inc.,PCAR | ||
"Paychex, Inc.",PAYX | ||
PayPal,PYPL | ||
"PepsiCo, Inc.",PEP | ||
Pinduoduo Inc.,PDD | ||
QUALCOMM,QCOM | ||
Regeneron Pharmaceuticals,REGN | ||
Ross Stores Inc.,ROST | ||
Seagen Inc.,SGEN | ||
"Sirius XM Radio, Inc.",SIRI | ||
"Skyworks Solutions, Inc.",SWKS | ||
Splunk,SPLK | ||
Starbucks Corporation,SBUX | ||
"Synopsys, Inc.",SNPS | ||
T-Mobile US,TMUS | ||
"Take-Two Interactive, Inc.",TTWO | ||
"Tesla, Inc.",TSLA | ||
Texas Instruments,TXN | ||
Trip.com Group,TCOM | ||
Ulta Beauty,ULTA | ||
Verisign,VRSN | ||
Verisk Analytics,VRSK | ||
Vertex Pharmaceuticals,VRTX | ||
"Walgreen Boots Alliance, Inc.",WBA | ||
"Workday, Inc.",WDAY | ||
"Xcel Energy, Inc.",XEL | ||
"Xilinx, Inc.",XLNX | ||
Zoom Video Communications,ZM |