Skip to content

Commit b974812

Browse files
committed
various changes
1 parent 5e2ae68 commit b974812

File tree

7 files changed

+94
-47
lines changed

7 files changed

+94
-47
lines changed

assets/favicon.ico

15 KB
Binary file not shown.

assets/s1.css

-1
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,6 @@ li {
436436
/* Tables
437437
–––––––––––––––––––––––––––––––––––––––––––––––––– */
438438
table {
439-
border-collapse: collapse;
440439
}
441440
th,
442441
td {

dash_app.py

+64-10
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import dash_core_components as dcc
22
import dash_html_components as html
3+
import dash_table
34
from dash import Dash
45
from dash.dependencies import Input, Output
56

6-
from dash_app_functions import get_search_window_sizes, visualize_graph, get_symbols
7+
import stock_pattern_analyzer as spa
8+
from dash_app_functions import get_search_window_sizes, get_symbols, search_most_recent
79

810
app = Dash(__name__, meta_tags=[{"name": "viewport", "content": "width=device-width"}])
11+
app.title = "Stock Patterns"
912
server = app.server
1013

1114
##### Header #####
@@ -60,34 +63,85 @@
6063
##### Stats & Graph #####
6164

6265
graph_id = "id-graph"
63-
6466
stats_and_graph_div = html.Div([html.Div(id="id-stats-container", className="row container-display"),
6567
html.Div([dcc.Graph(id=graph_id)], id="id-graph-div", className="pretty_container")],
6668
id="id-graph-container", className="nine columns")
6769

70+
##### Matched Stocks List #####
71+
72+
matched_table_id = "id-matched-list"
73+
table_columns = ["Index", "Match distance", "Symbol", "Start date", "End Date", "Start Close Value ($)",
74+
"End Close Value ($)"]
75+
table = dash_table.DataTable(id=matched_table_id, columns=[{"id": c, "name": c} for c in table_columns], page_size=5)
76+
matched_div = html.Div([html.Div([html.H6("Matched patterns"), table],
77+
className="pretty_container")],
78+
id="id-matched-list-container",
79+
className="eleven columns")
80+
81+
##### Reference Links #####
82+
83+
css_link = dcc.Link("[1] Style of the page (css)",
84+
href="https://github.com/plotly/dash-sample-apps/tree/master/apps/dash-oil-and-gas")
85+
yahoo_data_link = dcc.Link("[2] Yahoo data", href="https://finance.yahoo.com")
86+
reference_links_div = html.Div([html.Div([html.H6("References"),
87+
css_link,
88+
html.Br(),
89+
yahoo_data_link],
90+
className="pretty_container")],
91+
className="four columns")
92+
6893
##### Layout #####
6994

7095
app.layout = html.Div([header_div,
7196
html.Div([settings_div,
7297
stats_and_graph_div],
73-
className="row flex-display")],
98+
className="row flex-display"),
99+
html.Div([matched_div], className="row flex-display"),
100+
reference_links_div],
74101
id="mainContainer",
75102
style={"display": "flex", "flex-direction": "column"})
76103

77104

78105
##### Callbacks #####
79106

80-
@app.callback(Output(graph_id, "figure"),
107+
@app.callback([Output(graph_id, "figure"),
108+
Output(matched_table_id, "data")],
81109
[Input(symbol_dropdown_id, "value"),
82110
Input(window_size_dropdown_id, "value"),
83111
Input(future_size_input_id, "value"),
84112
Input(top_k_input_id, "value")])
85-
def update_plot(symbol_value, window_size_value, future_size_value, top_k_value):
86-
fig = visualize_graph(symbol=symbol_value,
87-
window_size=window_size_value,
88-
future_size=future_size_value,
89-
top_k=top_k_value)
90-
return fig
113+
def update_plot_and_table(symbol_value, window_size_value, future_size_value, top_k_value):
114+
# RetAPI search
115+
ret = search_most_recent(symbol=symbol_value,
116+
window_size=window_size_value,
117+
top_k=top_k_value,
118+
future_size=future_size_value)
119+
120+
# Parse response and build the HTML table rows
121+
table_rows = []
122+
values = []
123+
symbols = []
124+
start_end_dates = []
125+
for i, match in enumerate(ret.matches):
126+
values.append(match.values)
127+
symbols.append(match.symbol)
128+
start_end_dates.append((match.start_date, match.end_date))
129+
row_values = [i + 1, match.distance, match.symbol, match.start_date, match.end_date, match.values[0],
130+
match.values[-1]]
131+
row_dict = {c: v for c, v in zip(table_columns, row_values)}
132+
table_rows.append(row_dict)
133+
134+
# Visualize the data on a graph
135+
fig = spa.visualize_graph(match_values_list=values,
136+
match_symbols=symbols,
137+
match_str_dates=start_end_dates,
138+
window_size=window_size_value,
139+
future_size=future_size_value,
140+
anchor_symbol=ret.anchor_symbol,
141+
anchor_values=ret.anchor_values,
142+
show_legend=False)
143+
144+
return fig, table_rows
91145

92146

93147
if __name__ == "__main__":

dash_app_functions.py

+2-28
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import requests
21
import os
32

4-
import stock_pattern_analyzer as spa
3+
import requests
4+
55
from rest_api_models import (TopKSearchResponse, SearchWindowSizeResponse, DataRefreshResponse,
66
AvailableSymbolsResponse)
77

@@ -33,29 +33,3 @@ def get_last_refresh_date() -> str:
3333
res = DataRefreshResponse.parse_obj(res)
3434
date_str = res.date.strftime("%Y/%m/%d, %H:%M:%S")
3535
return date_str
36-
37-
38-
def visualize_graph(symbol: str, window_size: int, future_size: int, top_k: int):
39-
try:
40-
ret = search_most_recent(symbol=symbol,
41-
window_size=window_size,
42-
top_k=top_k,
43-
future_size=future_size)
44-
values = []
45-
symbols = []
46-
dates = []
47-
for m in ret.matches:
48-
values.append(m.values)
49-
symbols.append(m.symbol)
50-
dates.append((m.start_date, m.end_date))
51-
52-
fig = spa.visualize_graph(match_values_list=values,
53-
match_symbols=symbols,
54-
match_str_dates=dates,
55-
window_size=window_size,
56-
future_size=future_size,
57-
anchor_symbol=ret.anchor_symbol,
58-
anchor_values=ret.anchor_values)
59-
return fig
60-
except Exception:
61-
return None

rest_api.py

+15-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from pathlib import Path
33

44
import numpy as np
5+
import pandas as pd
56
import uvicorn
67
from apscheduler.schedulers.asyncio import AsyncIOScheduler
78
from fastapi import FastAPI, HTTPException, Response
@@ -16,8 +17,20 @@
1617
app.scheduler = AsyncIOScheduler()
1718
app.last_refreshed = None
1819

19-
AVAILABLE_SEARCH_WINDOW_SIZES = [5, 10, 15, 20]
20-
TICKER_LIST = ["AAPL", "GME", "AMC", "TSLA"]
20+
21+
def get_sp500_ticker_list() -> set:
22+
table = pd.read_html('https://en.wikipedia.org/wiki/List_of_S%26P_500_companies')
23+
df = table[0]
24+
return set(df["Symbol"].values)
25+
26+
27+
AVAILABLE_SEARCH_WINDOW_SIZES = list(range(5, 16, 1)) + [20, 25, 30, 45]
28+
TICKER_LIST = ["AAPL", "GME", "AMC", "TSLA", "hff"]
29+
# TICKER_LIST = {"AAPL", "MSFT", "AMZN", "BABA", "ROKU", "TDOC", "CRSP", "SQ", "NVTA", "Z", "BIDU", "SPOT", "PRLB",
30+
# "TSLA", "GME", "BB", "AMC", "LI", "NIO"}
31+
# # TODO: handle if symbol is missing + parallell download
32+
# TICKER_LIST = TICKER_LIST.union(get_sp500_ticker_list())
33+
TICKER_LIST = sorted(TICKER_LIST)
2134
PERIOD_YEARS = 2
2235

2336

stock_pattern_analyzer/data.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@ def __init__(self, ticker_symbols: list, period_years: int = 5, interval: int =
2828
def fill(self) -> None:
2929
for symbol in tqdm(self.ticker_symbols):
3030
ticker = yfinance.Ticker(symbol)
31-
ticker_df = ticker.history(period=f"{self.period_years}y", interval=f"{self.interval}d")[::-1]
31+
period_str = f"{self.period_years}y"
32+
interval_str = f"{self.interval}d"
33+
ticker_df = ticker.history(period=period_str, interval=interval_str, rounding=True)[::-1]
34+
if ticker_df.empty or len(ticker_df) == 0:
35+
self.ticker_symbols.remove(symbol)
36+
continue
3237

3338
close_values = ticker_df["Close"].values
3439
dates = ticker_df.index.values

stock_pattern_analyzer/visualization.py

+7-5
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ def visualize_graph(match_values_list: List[np.ndarray],
1515
window_size: int,
1616
future_size: int,
1717
anchor_symbol: str,
18-
anchor_values: np.ndarray):
18+
anchor_values: np.ndarray,
19+
show_legend: bool = True) -> graph_objs.Figure:
1920
fig = graph_objs.Figure()
2021

2122
assert len(match_values_list) == len(match_symbols), "Something is fishy"
@@ -30,7 +31,7 @@ def visualize_graph(match_values_list: List[np.ndarray],
3031
minmax_values = minmax_scale(original_values)
3132
trace = graph_objs.Scatter(x=x,
3233
y=minmax_values,
33-
name=f"{i}) {match_symbol} ({match_start_date}-{match_end_date})",
34+
name=f"{i}) {match_symbol} ({match_start_date} - {match_end_date})",
3435
mode="lines",
3536
line=dict(color=VALUES_COLOR),
3637
opacity=1 / (i + 1),
@@ -52,8 +53,8 @@ def visualize_graph(match_values_list: List[np.ndarray],
5253

5354
fig.add_vline(x=window_size, line_dash="dash", line_color="black", annotation_text="Last market close")
5455

55-
fig.update_xaxes(showspikes=True, spikecolor="black", spikesnap="cursor", spikemode="across")
56-
fig.update_yaxes(showspikes=True, spikecolor="black", spikethickness=1)
56+
# fig.update_xaxes(showspikes=True, spikecolor="black", spikesnap="cursor", spikemode="across")
57+
# fig.update_yaxes(showspikes=True, spikecolor="black", spikethickness=1)
5758

5859
x_axis_ticker_labels = list(range(-window_size, future_size + 1))
5960
fig.update_layout(title=f"Similar patters for {anchor_symbol} based on historical market close data",
@@ -66,6 +67,7 @@ def visualize_graph(match_values_list: List[np.ndarray],
6667
autosize=True,
6768
plot_bgcolor=FIG_BG_COLOR,
6869
paper_bgcolor=FIG_BG_COLOR,
69-
legend=dict(font=dict(size=9), orientation="h"))
70+
legend=dict(font=dict(size=9), orientation="h", yanchor="bottom", y=-0.5),
71+
showlegend=show_legend)
7072

7173
return fig

0 commit comments

Comments
 (0)