1st working commit. TODO - fix SettingWithCopyWarning
This commit is contained in:
parent
37b6fdb145
commit
456bfc38d2
492
indicators.py
492
indicators.py
@ -37,6 +37,7 @@ import json
|
|||||||
import io
|
import io
|
||||||
from flask_caching import Cache
|
from flask_caching import Cache
|
||||||
from dash.exceptions import PreventUpdate
|
from dash.exceptions import PreventUpdate
|
||||||
|
import yahoo_fin.stock_info as si
|
||||||
|
|
||||||
# def fill_missing_data(df):
|
# def fill_missing_data(df):
|
||||||
# df.ffill(inplace=True)
|
# df.ffill(inplace=True)
|
||||||
@ -95,7 +96,7 @@ class security:
|
|||||||
This can be a list of stocks, bonds, or otherinvestment vehicles.
|
This can be a list of stocks, bonds, or otherinvestment vehicles.
|
||||||
price - Pandas DataFrame with datetime as index sorted to chronical order
|
price - Pandas DataFrame with datetime as index sorted to chronical order
|
||||||
"""
|
"""
|
||||||
def __init__(self, price, volume=None, rfr: float = 0.01, sf: float = 252.0):
|
def __init__(self, sym, price, volume=None, rfr: float = 0.01, sf: float = 252.0):
|
||||||
"""
|
"""
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -111,9 +112,10 @@ class security:
|
|||||||
days in a year. Monthly sampling frequency would be 12. And
|
days in a year. Monthly sampling frequency would be 12. And
|
||||||
weekly sampling frequenc is 52.
|
weekly sampling frequenc is 52.
|
||||||
"""
|
"""
|
||||||
|
self._symbol = sym
|
||||||
self._price = price
|
self._price = price
|
||||||
self._volume = volume
|
self._volume = volume
|
||||||
self._symbol = price.columns.values
|
# self._symbol = price.columns.values
|
||||||
self._rfr = rfr
|
self._rfr = rfr
|
||||||
self._sf = sf
|
self._sf = sf
|
||||||
|
|
||||||
@ -607,7 +609,7 @@ def plot_macd(macd, macd_sig, macd_hist, axs):
|
|||||||
axs.grid()
|
axs.grid()
|
||||||
|
|
||||||
|
|
||||||
def intelligent_loop_plots():
|
def intelligent_loop_plots(sym):
|
||||||
# Only plot ones that are standing out meaning:
|
# Only plot ones that are standing out meaning:
|
||||||
# 1. outside of bollinger bands or recently crossed over (within 9 days)
|
# 1. outside of bollinger bands or recently crossed over (within 9 days)
|
||||||
# 2. RSI above 70 or below 30
|
# 2. RSI above 70 or below 30
|
||||||
@ -631,238 +633,168 @@ def intelligent_loop_plots():
|
|||||||
plot_sd = ed - dt.timedelta(days = 365 * plt_year)
|
plot_sd = ed - dt.timedelta(days = 365 * plt_year)
|
||||||
plot_ed = ed
|
plot_ed = ed
|
||||||
|
|
||||||
watchlist = get_watchlist()
|
tmp = si.get_data(sym, start_date=sd)[["adjclose", "volume"]]
|
||||||
symbols = watchlist.index.values.tolist()
|
price = tmp["adjclose"]
|
||||||
|
vol = tmp["volume"]
|
||||||
|
stk = security(sym, price, vol)
|
||||||
|
|
||||||
prices, volumes = get_price_volume(symbols, pd.date_range(sd, ed), addSPY=True)
|
rsi = stk.rsi()
|
||||||
|
vorsi = stk.volume_rsi()
|
||||||
|
macd, macd_sig, macd_hist, norm_hist = stk.macd()
|
||||||
|
sma50 = stk.sma(50)
|
||||||
|
vwma50 = stk.vwma(50)
|
||||||
|
sma200 = stk.sma(200)
|
||||||
|
bol_low, bol_up = stk.bollinger(200)
|
||||||
|
|
||||||
# plt.ion()
|
# init
|
||||||
num_of_plots = 2
|
plot_indicator = "["
|
||||||
all_plot_sym = []
|
# print('{:5}: '.format(sym), end = '')
|
||||||
all_plot_ind = {}
|
|
||||||
all_data = pd.DataFrame([])
|
|
||||||
all_vol = pd.DataFrame([])
|
|
||||||
all_macd = pd.DataFrame([])
|
|
||||||
all_rsi = pd.DataFrame([])
|
|
||||||
|
|
||||||
for sym in symbols:
|
# RSI outside window (over bought / over sold)
|
||||||
price = prices[sym].to_frame()
|
rsi_tail = rsi.tail(lb_trigger)
|
||||||
vol = volumes[sym].to_frame()
|
if (rsi_tail >= 70).any() or (rsi_tail <= 30).any():
|
||||||
all_vol = all_vol.join(vol, how='outer')
|
# print('--RSI', end = '')
|
||||||
stk = security(price, vol)
|
plot_indicator += 'RSI, '
|
||||||
|
|
||||||
rsi = stk.rsi()
|
# VoRSI outside window (over bought / over sold)
|
||||||
vorsi = stk.volume_rsi()
|
vorsi_tail = vorsi.tail(lb_trigger)
|
||||||
macd, macd_sig, macd_hist, norm_hist = stk.macd()
|
if (vorsi_tail >= 70).any() or (vorsi_tail <= 30).any():
|
||||||
sma50 = stk.sma(50)
|
# print('--VoRSI', end = '')
|
||||||
vwma50 = stk.vwma(50)
|
plot_indicator += 'VoRSI, '
|
||||||
sma200 = stk.sma(200)
|
|
||||||
bol_low, bol_up = stk.bollinger(200)
|
|
||||||
|
|
||||||
# init
|
# Normalized MACD histogram out of 3% range
|
||||||
plot_indicator = "["
|
norm_hist_tail = abs(norm_hist.tail(lb_trigger))
|
||||||
# print('{:5}: '.format(sym), end = '')
|
if (abs(norm_hist_tail) >= 0.02).any():
|
||||||
|
# print('--MACD/R', end = '') # outside normal range
|
||||||
|
plot_indicator += 'MACD/R, '
|
||||||
|
|
||||||
# RSI outside window (over bought / over sold)
|
# MACD histogram zero crossing
|
||||||
rsi_tail = rsi.tail(lb_trigger)
|
macd_hist_tail = macd_hist.tail(lb_trigger)
|
||||||
if (rsi_tail[sym] >= 70).any() or (rsi_tail[sym] <= 30).any():
|
macd_hist_sign = np.sign(macd_hist_tail)
|
||||||
# print('--RSI', end = '')
|
macd_hist_diff = macd_hist_sign.diff()
|
||||||
plot_indicator += 'RSI, '
|
if (abs(macd_hist_diff) > 1).any():
|
||||||
|
# print('--MACD', end = '') # zero crossing
|
||||||
|
plot_indicator += 'MACD, '
|
||||||
|
|
||||||
# VoRSI outside window (over bought / over sold)
|
# Stock price crosses SMA50
|
||||||
vorsi_tail = vorsi.tail(lb_trigger)
|
sma50_cross_tail = sma50.tail(lb_trigger) - price.tail(lb_trigger)
|
||||||
if (vorsi_tail[sym] >= 70).any() or (vorsi_tail[sym] <= 30).any():
|
sma50_cross_sign = np.sign(sma50_cross_tail)
|
||||||
# print('--VoRSI', end = '')
|
sma50_cross_diff = sma50_cross_sign.diff()
|
||||||
plot_indicator += 'VoRSI, '
|
if (abs(sma50_cross_diff) > 1).any():
|
||||||
|
# print('--SMA50', end = '')
|
||||||
|
plot_indicator += 'SMA50, '
|
||||||
|
|
||||||
# Normalized MACD histogram out of 3% range
|
# Death cross or golden cross - SMA50 vs SMA200
|
||||||
norm_hist_tail = abs(norm_hist.tail(lb_trigger))
|
sma_cross_tail = sma50.tail(lb_trigger) - sma200.tail(lb_trigger).values
|
||||||
if (abs(norm_hist_tail[sym]) >= 0.02).any():
|
sma_cross_sign = np.sign(sma_cross_tail)
|
||||||
# print('--MACD/R', end = '') # outside normal range
|
sma_cross_diff = sma_cross_sign.diff()
|
||||||
plot_indicator += 'MACD/R, '
|
if (abs(sma_cross_diff) > 1).any():
|
||||||
|
# print('--Golden/Death', end = '')
|
||||||
|
plot_indicator += 'Golden/Death, '
|
||||||
|
|
||||||
# MACD histogram zero crossing
|
# Price outside bollinger band or crossing
|
||||||
macd_hist_tail = macd_hist.tail(lb_trigger)
|
price_tail = price.tail(lb_trigger)
|
||||||
macd_hist_sign = np.sign(macd_hist_tail)
|
bol_low_tail = bol_low.tail(lb_trigger)
|
||||||
macd_hist_diff = macd_hist_sign.diff()
|
bol_up_tail = bol_up.tail(lb_trigger)
|
||||||
if (abs(macd_hist_diff[sym]) > 1).any():
|
price_high = price_tail - bol_up_tail.values
|
||||||
# print('--MACD', end = '') # zero crossing
|
price_low = price_tail - bol_low_tail.values
|
||||||
plot_indicator += 'MACD, '
|
if (price_high >= 0).any() or (price_low <= 0).any():
|
||||||
|
# print('--Bollinger', end ='')
|
||||||
|
plot_indicator += 'Bollinger, '
|
||||||
|
|
||||||
# Stock price crosses SMA50
|
# Price cross 200 day moving average
|
||||||
sma50_cross_tail = sma50.tail(lb_trigger) - price.tail(lb_trigger)
|
sma200_tail = sma200.tail(lb_trigger)
|
||||||
sma50_cross_sign = np.sign(sma50_cross_tail)
|
sma200_cross = price_tail - sma200_tail.values
|
||||||
sma50_cross_diff = sma50_cross_sign.diff()
|
sma200_cross_sign = np.sign(sma200_cross)
|
||||||
if (abs(sma50_cross_diff[sym]) > 1).any():
|
sma200_cross_diff = sma200_cross_sign.diff()
|
||||||
# print('--SMA50', end = '')
|
if (abs(sma200_cross_diff) > 1).any():
|
||||||
plot_indicator += 'SMA50, '
|
# print('--SMA200', end = '')
|
||||||
|
plot_indicator += 'SMA200, '
|
||||||
|
|
||||||
# Death cross or golden cross - SMA50 vs SMA200
|
# Large trading volume trigger
|
||||||
sma_cross_tail = sma50.tail(lb_trigger) - sma200.tail(lb_trigger).values
|
volume_tail = vol.tail(lb_trigger)
|
||||||
sma_cross_sign = np.sign(sma_cross_tail)
|
vol_mean = vol.tail(50).mean()
|
||||||
sma_cross_diff = sma_cross_sign.diff()
|
vol_std = vol.tail(50).std()
|
||||||
if (abs(sma_cross_diff[sym]) > 1).any():
|
if ((volume_tail[1] - vol_mean - 2*vol_std) > 0).any():
|
||||||
# print('--Golden/Death', end = '')
|
# print('--HiVol', end = '')
|
||||||
plot_indicator += 'Golden/Death, '
|
plot_indicator += "HiVol, "
|
||||||
|
|
||||||
# Price outside bollinger band or crossing
|
# print(f"-- {watchlist.loc[sym, 'Notes']}") # carriage return
|
||||||
price_tail = price.tail(lb_trigger)
|
plot_indicator += ']'
|
||||||
bol_low_tail = bol_low.tail(lb_trigger)
|
# note_field = watchlist.loc[sym, 'Notes'].strip().lower()
|
||||||
bol_up_tail = bol_up.tail(lb_trigger)
|
# if note_field != "watch" and ( note_field == "skip" or \
|
||||||
price_high = price_tail - bol_up_tail.values
|
# plot_indicator =="[]" ):
|
||||||
price_low = price_tail - bol_low_tail.values
|
# continue # skipping plotting to save memory and time
|
||||||
if (price_high[sym] >= 0).any() or (price_low[sym] <= 0).any():
|
|
||||||
# print('--Bollinger', end ='')
|
|
||||||
plot_indicator += 'Bollinger, '
|
|
||||||
|
|
||||||
# Price cross 200 day moving average
|
# Plotting
|
||||||
sma200_tail = sma200.tail(lb_trigger)
|
|
||||||
sma200_cross = price_tail - sma200_tail.values
|
|
||||||
sma200_cross_sign = np.sign(sma200_cross)
|
|
||||||
sma200_cross_diff = sma200_cross_sign.diff()
|
|
||||||
if (abs(sma200_cross_diff[sym]) > 1).any():
|
|
||||||
# print('--SMA200', end = '')
|
|
||||||
plot_indicator += 'SMA200, '
|
|
||||||
|
|
||||||
# Large trading volume trigger
|
# fig, (axs0, axs1, axs2, axs3) = plt.subplots(4, sharex=True,
|
||||||
volume_tail = vol.tail(lb_trigger)
|
# gridspec_kw={'hspace': 0, 'height_ratios': [3, 1, 1, 1]},
|
||||||
vol_mean = vol.tail(50).mean()
|
# figsize=(16, 12))
|
||||||
vol_std = vol.tail(50).std()
|
# # fig.suptitle('{} - {} - {} - {}'.format(sym,\
|
||||||
if ((volume_tail[sym] - vol_mean[sym] - 2*vol_std[sym]) > 0).any():
|
# # watchlist.loc[sym, 'Segment'], watchlist.loc[sym, 'Sub Segment']))
|
||||||
# print('--HiVol', end = '')
|
# axs0.set_title('{} - {} - {} - {} - {}'.format(sym,\
|
||||||
plot_indicator += "HiVol, "
|
# watchlist.loc[sym, 'Segment'], watchlist.loc[sym, 'Sub Segment'],\
|
||||||
|
# watchlist.loc[sym, 'Notes'], plot_indicator))
|
||||||
|
# axs0.set_xlim([plot_sd, plot_ed])
|
||||||
|
|
||||||
# print(f"-- {watchlist.loc[sym, 'Notes']}") # carriage return
|
# plot basic price info
|
||||||
plot_indicator += ']'
|
data = price.copy().to_frame(sym)
|
||||||
note_field = watchlist.loc[sym, 'Notes'].strip().lower()
|
# to limit low bound when plotting in log scale
|
||||||
if note_field != "watch" and ( note_field == "skip" or \
|
bol_low.loc[sma200.divide(bol_low) > bol_up.divide(sma200).mul(3)] = np.nan
|
||||||
plot_indicator =="[]" ):
|
data = data.join(bol_low.rename('_BOL200L'))
|
||||||
continue # skipping plotting to save memory and time
|
data = data.join(bol_up.rename('_BOL200U'))
|
||||||
|
data = data.join(sma200.rename('_SMA200'))
|
||||||
|
data = data.join(sma50.rename('_SMA50'))
|
||||||
|
data = data.join(vwma50.rename('_WVMA50'))
|
||||||
|
|
||||||
# Plotting
|
macd = macd.to_frame('_MACD').join(macd_sig.rename('_SIG'))
|
||||||
all_plot_sym.append(sym)
|
macd = macd.join(macd_hist.rename('_HIST'))
|
||||||
all_plot_ind[sym] = sym + ' - ' + watchlist.loc[sym, 'Segment'] + ' - ' +\
|
# macd.rename(columns={sym: sym+'_MACD'}, inplace=True)
|
||||||
watchlist.loc[sym, 'Sub Segment'] +\
|
|
||||||
' - ' + watchlist.loc[sym, 'Notes'] + ' - ' + plot_indicator
|
|
||||||
|
|
||||||
# fig, (axs0, axs1, axs2, axs3) = plt.subplots(4, sharex=True,
|
rsi = rsi.to_frame('_RSI').join(vorsi.rename('_VoRSI'))
|
||||||
# gridspec_kw={'hspace': 0, 'height_ratios': [3, 1, 1, 1]},
|
# rsi.rename(columns={sym: sym+'_RSI'}, inplace=True)
|
||||||
# figsize=(16, 12))
|
|
||||||
# # fig.suptitle('{} - {} - {} - {}'.format(sym,\
|
|
||||||
# # watchlist.loc[sym, 'Segment'], watchlist.loc[sym, 'Sub Segment']))
|
|
||||||
# axs0.set_title('{} - {} - {} - {} - {}'.format(sym,\
|
|
||||||
# watchlist.loc[sym, 'Segment'], watchlist.loc[sym, 'Sub Segment'],\
|
|
||||||
# watchlist.loc[sym, 'Notes'], plot_indicator))
|
|
||||||
# axs0.set_xlim([plot_sd, plot_ed])
|
|
||||||
|
|
||||||
# plot basic price info
|
return data, vol.to_frame('_VOL'), macd, rsi, plot_indicator
|
||||||
data = price.copy()
|
|
||||||
# to limit low bound when plotting in log scale
|
|
||||||
bol_low.loc[sma200[sym].divide(bol_low[sym]) >\
|
|
||||||
bol_up[sym].divide(sma200[sym]).mul(3), sym] = np.nan
|
|
||||||
data = data.join(bol_low, rsuffix = '_BOL200L')
|
|
||||||
data = data.join(bol_up, rsuffix = '_BOL200U')
|
|
||||||
data = data.join(sma200, rsuffix = '_SMA200')
|
|
||||||
data = data.join(sma50, rsuffix = '_SMA50')
|
|
||||||
data = data.join(vwma50, rsuffix = '_WVMA50')
|
|
||||||
|
|
||||||
all_data = all_data.join(data, how='outer')
|
|
||||||
|
|
||||||
macd = macd.join(macd_sig, rsuffix = '_SIG')
|
|
||||||
macd = macd.join(macd_hist, rsuffix = '_HIST')
|
|
||||||
macd.rename(columns={sym: sym+'_MACD'}, inplace=True)
|
|
||||||
all_macd = all_macd.join(macd, how='outer')
|
|
||||||
|
|
||||||
rsi = rsi.join(vorsi, rsuffix = '_VoRSI')
|
|
||||||
rsi.rename(columns={sym: sym+'_RSI'}, inplace=True)
|
|
||||||
all_rsi = all_rsi.join(rsi, how='outer')
|
|
||||||
|
|
||||||
# # plot stk price in log scale
|
|
||||||
# axs0.set_yscale('log')
|
|
||||||
# plot_data(data, axs0, ylabel='Price ($)')
|
|
||||||
# axs0.plot(data.index[-1], data.iloc[-1][sym], marker=5, color='C0',\
|
|
||||||
# markersize=10)
|
|
||||||
|
|
||||||
# # plot volume
|
|
||||||
# axs0t = axs0.twinx()
|
|
||||||
# vol.plot(kind='area', ax=axs0t, color='red', alpha=0.1, legend=False)
|
|
||||||
# axs0t.plot(vol.index[-1], vol.iloc[-1][sym], marker=5, color='red',\
|
|
||||||
# markersize=10)
|
|
||||||
|
|
||||||
# # plot RSI
|
|
||||||
# plot_rsi(rsi, axs1)
|
|
||||||
# # plot Volume RSI
|
|
||||||
# plot_volume_rsi(vorsi, axs2)
|
|
||||||
# # plot MCAD
|
|
||||||
# plot_macd(macd, macd_sig, macd_hist, axs3)
|
|
||||||
|
|
||||||
# for debug only
|
|
||||||
# num_of_plots -= 1
|
|
||||||
# if num_of_plots < 0:
|
|
||||||
# break
|
|
||||||
|
|
||||||
all_data = all_data[all_data.index >= plot_sd]
|
|
||||||
all_vol = all_vol[all_vol.index >= plot_sd]
|
|
||||||
all_macd = all_macd[all_macd.index >= plot_sd]
|
|
||||||
all_rsi = all_rsi[all_rsi.index >= plot_sd]
|
|
||||||
|
|
||||||
# pack into one json obj
|
|
||||||
j_dict = {"all_plot_sym": all_plot_sym, "all_plot_ind": all_plot_ind,
|
|
||||||
"all_data": all_data.to_json(orient='columns', index=True),
|
|
||||||
"all_vol": all_vol.to_json(orient='columns', index=True),
|
|
||||||
"all_macd": all_macd.to_json(orient='columns', index=True),
|
|
||||||
"all_rsi": all_rsi.to_json(orient='columns', index=True)}
|
|
||||||
|
|
||||||
j_obj = json.dumps(j_dict)
|
|
||||||
|
|
||||||
# return all_plot_sym, all_plot_ind, all_data, all_vol, all_macd, all_rsi
|
|
||||||
return j_obj
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# test_sec_class()
|
# test_sec_class()
|
||||||
# test_smooth()
|
# test_smooth()
|
||||||
# test_bollinger_sell()
|
# test_bollinger_sell()
|
||||||
# test_get_orders()
|
# test_get_orders()
|
||||||
# all_plot_sym, all_plot_ind, all_data, all_vol, all_macd, all_rsi = intelligent_loop_plots()
|
|
||||||
|
|
||||||
# j_obj = intelligent_loop_plots()
|
|
||||||
# # unpacking
|
|
||||||
# json_data = json.loads(j_obj)
|
|
||||||
# all_plot_sym = json_data["all_plot_sym"]
|
|
||||||
# all_plot_ind = json_data["all_plot_ind"]
|
|
||||||
# all_data = pd.read_json(io.StringIO(json_data['all_data']))
|
|
||||||
# all_vol = pd.read_json(io.StringIO(json_data['all_vol']))
|
|
||||||
# all_macd = pd.read_json(io.StringIO(json_data['all_macd']))
|
|
||||||
# all_rsi = pd.read_json(io.StringIO(json_data['all_rsi']))
|
|
||||||
|
|
||||||
# Initialize the app
|
# Initialize the app
|
||||||
app = Dash()
|
app = Dash()
|
||||||
|
|
||||||
CACHE_CONFIG = {'CACHE_TYPE': 'SimpleCache'}
|
# CACHE_CONFIG = {'CACHE_TYPE': 'SimpleCache'}
|
||||||
cache = Cache()
|
# cache = Cache()
|
||||||
cache.init_app(app.server, config=CACHE_CONFIG)
|
# cache.init_app(app.server, config=CACHE_CONFIG)
|
||||||
|
|
||||||
|
watchlist = get_watchlist()
|
||||||
|
symbols = watchlist.index.values.tolist()
|
||||||
|
|
||||||
# App layout
|
# App layout
|
||||||
app.layout = [
|
app.layout = [
|
||||||
html.Button('Refresh Data', id='button', n_clicks=0),
|
# html.Button('Refresh Data', id='button', n_clicks=0),
|
||||||
html.Button('Auto Play', id="start-button", n_clicks=0, disabled=True),
|
html.Button('Auto Play', id="start-button", n_clicks=0),
|
||||||
# html.Div(children='Pick A Symbol from Dropdown List: '),
|
# html.Div(children='Pick A Symbol from Dropdown List: '),
|
||||||
# html.Hr(),
|
# html.Hr(),
|
||||||
# dcc.RadioItems(options=['pop', 'lifeExp', 'gdpPercap'], value='lifeExp', id='controls-and-radio-item'),
|
# dcc.RadioItems(options=['pop', 'lifeExp', 'gdpPercap'], value='lifeExp', id='symbols_dropdown_list'),
|
||||||
# dcc.Dropdown(['pop', 'lifeExp', 'gdpPercap'], 'lifeExp', id='controls-and-radio-item'),
|
# dcc.Dropdown(['pop', 'lifeExp', 'gdpPercap'], 'lifeExp', id='symbols_dropdown_list'),
|
||||||
dcc.Dropdown(id='controls-and-radio-item'),
|
dcc.Dropdown(symbols, symbols[0], id='symbols_dropdown_list'),
|
||||||
# dash_table.DataTable(data=df.to_dict('records'), page_size=6),
|
# dash_table.DataTable(data=df.to_dict('records'), page_size=6),
|
||||||
dcc.Graph(
|
dcc.Graph(
|
||||||
figure={},
|
figure={},
|
||||||
id='controls-and-graph',
|
id='controls-and-graph',
|
||||||
style={'height':'85vh'}
|
style={'height':'85vh'}
|
||||||
),
|
),
|
||||||
dcc.Store(id="signal"),
|
# dcc.Store(id="signal"),
|
||||||
# dcc.Store(id="dropdown-index"),
|
dcc.Store(id="dropdown_index", data='0'),
|
||||||
dcc.Interval(
|
dcc.Interval(
|
||||||
id='interval-component',
|
id='interval-component',
|
||||||
interval=3*1000, # in milliseconds
|
interval=3*1000, # in milliseconds
|
||||||
n_intervals=0,
|
n_intervals=len(symbols),
|
||||||
disabled=True,
|
disabled=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
@ -886,7 +818,7 @@ if __name__ == "__main__":
|
|||||||
# start / stop button callback
|
# start / stop button callback
|
||||||
@callback(Output('interval-component', 'disabled'),
|
@callback(Output('interval-component', 'disabled'),
|
||||||
Output("start-button", "children"),
|
Output("start-button", "children"),
|
||||||
Output('controls-and-radio-item', 'disabled'),
|
Output('symbols_dropdown_list', 'disabled'),
|
||||||
Input("start-button", "n_clicks"),
|
Input("start-button", "n_clicks"),
|
||||||
State("start-button", "children"),)
|
State("start-button", "children"),)
|
||||||
|
|
||||||
@ -900,9 +832,9 @@ if __name__ == "__main__":
|
|||||||
return no_update
|
return no_update
|
||||||
|
|
||||||
# interval callback
|
# interval callback
|
||||||
@callback(Output('controls-and-radio-item', 'value'),
|
@callback(Output('symbols_dropdown_list', 'value'),
|
||||||
Input("interval-component", "n_intervals"),
|
Input("interval-component", "n_intervals"),
|
||||||
State('controls-and-radio-item', 'options'),
|
State('symbols_dropdown_list', 'options'),
|
||||||
# State('dropdown-index', 'data'),
|
# State('dropdown-index', 'data'),
|
||||||
)
|
)
|
||||||
def cycle_syms(n, syms):
|
def cycle_syms(n, syms):
|
||||||
@ -911,77 +843,77 @@ if __name__ == "__main__":
|
|||||||
else:
|
else:
|
||||||
return no_update
|
return no_update
|
||||||
|
|
||||||
@cache.memoize(timeout=14400) # cache timeout set to 4 hours
|
# @cache.memoize(timeout=14400) # cache timeout set to 4 hours
|
||||||
def global_store():
|
# def global_store():
|
||||||
j_obj = intelligent_loop_plots()
|
# j_obj = intelligent_loop_plots()
|
||||||
return j_obj
|
# return j_obj
|
||||||
|
|
||||||
# retrieve data button callbacks
|
# retrieve data button callbacks
|
||||||
@callback(
|
# @callback(
|
||||||
Output("button", "disabled", allow_duplicate=True),
|
# Output("button", "disabled", allow_duplicate=True),
|
||||||
Input("button", "n_clicks"),
|
# Input("button", "n_clicks"),
|
||||||
prevent_initial_call=True,
|
# prevent_initial_call=True,
|
||||||
)
|
# )
|
||||||
def disable_btn(n):
|
# def disable_btn(n):
|
||||||
if n:
|
# if n:
|
||||||
return True
|
# return True
|
||||||
return no_update
|
# return no_update
|
||||||
|
|
||||||
@callback(
|
# @callback(
|
||||||
Output(component_id='signal', component_property='data'),
|
# Output(component_id='signal', component_property='data'),
|
||||||
# Output(component_id='button', component_property='disabled'),
|
# # Output(component_id='button', component_property='disabled'),
|
||||||
Input(component_id='button', component_property='n_clicks'),
|
# Input(component_id='button', component_property='n_clicks'),
|
||||||
prevent_initial_call=True,
|
# prevent_initial_call=True,
|
||||||
)
|
# )
|
||||||
def get_data_cb(clicks):
|
# def get_data_cb(clicks):
|
||||||
# global all_plot_sym, all_plot_ind, all_data, all_vol, all_macd, all_rsi
|
# # global all_plot_sym, all_plot_ind, all_data, all_vol, all_macd, all_rsi
|
||||||
# if clicks == 0:
|
# # if clicks == 0:
|
||||||
# return # no update
|
# # return # no update
|
||||||
if not clicks or clicks == 0:
|
# if not clicks or clicks == 0:
|
||||||
raise PreventUpdate
|
# raise PreventUpdate
|
||||||
|
|
||||||
print("get data")
|
# print("get data")
|
||||||
global_store()
|
# global_store()
|
||||||
print("data retrieved")
|
# print("data retrieved")
|
||||||
# unpacking
|
# # unpacking
|
||||||
# json_data = json.loads(j_obj)
|
# # json_data = json.loads(j_obj)
|
||||||
# all_plot_sym = json_data["all_plot_sym"]
|
# # all_plot_sym = json_data["all_plot_sym"]
|
||||||
# all_plot_ind = json_data["all_plot_ind"]
|
# # all_plot_ind = json_data["all_plot_ind"]
|
||||||
# all_data = pd.read_json(io.StringIO(json_data['all_data']))
|
# # all_data = pd.read_json(io.StringIO(json_data['all_data']))
|
||||||
# all_vol = pd.read_json(io.StringIO(json_data['all_vol']))
|
# # all_vol = pd.read_json(io.StringIO(json_data['all_vol']))
|
||||||
# all_macd = pd.read_json(io.StringIO(json_data['all_macd']))
|
# # all_macd = pd.read_json(io.StringIO(json_data['all_macd']))
|
||||||
# all_rsi = pd.read_json(io.StringIO(json_data['all_rsi']))
|
# # all_rsi = pd.read_json(io.StringIO(json_data['all_rsi']))
|
||||||
return clicks
|
# return clicks
|
||||||
|
|
||||||
# Add controls to build the interaction
|
# Add controls to build the interaction
|
||||||
|
|
||||||
# callback when data retrieve finishes triggered by signal
|
# callback when data retrieve finishes triggered by signal
|
||||||
@callback(
|
# @callback(
|
||||||
Output(component_id='controls-and-radio-item', component_property='options'),
|
# Output(component_id='symbols_dropdown_list', component_property='options'),
|
||||||
Output(component_id='button', component_property='disabled'),
|
# Output(component_id='button', component_property='disabled'),
|
||||||
Output(component_id='start-button', component_property='disabled'),
|
# Output(component_id='start-button', component_property='disabled'),
|
||||||
Input(component_id='signal', component_property='data'),
|
# Input(component_id='signal', component_property='data'),
|
||||||
)
|
# )
|
||||||
def update_dropdown(in_data):
|
# def update_dropdown(in_data):
|
||||||
if not in_data or in_data == 0:
|
# if not in_data or in_data == 0:
|
||||||
raise PreventUpdate
|
# raise PreventUpdate
|
||||||
# return no_update
|
# # return no_update
|
||||||
print(f"input: {in_data}")
|
# print(f"input: {in_data}")
|
||||||
j_obj = global_store()
|
# j_obj = global_store()
|
||||||
# unpacking
|
# # unpacking
|
||||||
json_data = json.loads(j_obj)
|
# json_data = json.loads(j_obj)
|
||||||
all_plot_sym = json_data["all_plot_sym"]
|
# all_plot_sym = json_data["all_plot_sym"]
|
||||||
print("dropdown menu options updated")
|
# print("dropdown menu options updated")
|
||||||
# all_plot_sym = ["SPY", "AMZN"]
|
# # all_plot_sym = ["SPY", "AMZN"]
|
||||||
|
|
||||||
return sorted(all_plot_sym), False, False
|
# return sorted(all_plot_sym), False, False
|
||||||
|
|
||||||
# dropdown callback
|
# dropdown callback
|
||||||
@callback(
|
@callback(
|
||||||
Output(component_id='controls-and-graph', component_property='figure'),
|
Output(component_id='controls-and-graph', component_property='figure'),
|
||||||
# Output("dropdown-index", "data"),
|
# Output("dropdown-index", "data"),
|
||||||
Input(component_id='controls-and-radio-item', component_property='value'),
|
Input(component_id='symbols_dropdown_list', component_property='value'),
|
||||||
# State('controls-and-radio-item', 'options')
|
# State('symbols_dropdown_list', 'options')
|
||||||
# Input(component_id='signal', component_property='data'),
|
# Input(component_id='signal', component_property='data'),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -991,15 +923,18 @@ if __name__ == "__main__":
|
|||||||
raise PreventUpdate
|
raise PreventUpdate
|
||||||
# return no_update
|
# return no_update
|
||||||
# col_chosen = "SPY"
|
# col_chosen = "SPY"
|
||||||
j_obj = global_store()
|
# j_obj = global_store()
|
||||||
# unpacking
|
# # unpacking
|
||||||
json_data = json.loads(j_obj)
|
# json_data = json.loads(j_obj)
|
||||||
# all_plot_sym = json_data["all_plot_sym"]
|
# # all_plot_sym = json_data["all_plot_sym"]
|
||||||
all_plot_ind = json_data["all_plot_ind"]
|
# all_plot_ind = json_data["all_plot_ind"]
|
||||||
all_data = pd.read_json(io.StringIO(json_data['all_data']))
|
# all_data = pd.read_json(io.StringIO(json_data['all_data']))
|
||||||
all_vol = pd.read_json(io.StringIO(json_data['all_vol']))
|
# all_vol = pd.read_json(io.StringIO(json_data['all_vol']))
|
||||||
all_macd = pd.read_json(io.StringIO(json_data['all_macd']))
|
# all_macd = pd.read_json(io.StringIO(json_data['all_macd']))
|
||||||
all_rsi = pd.read_json(io.StringIO(json_data['all_rsi']))
|
# all_rsi = pd.read_json(io.StringIO(json_data['all_rsi']))
|
||||||
|
|
||||||
|
# get data
|
||||||
|
data, vol, macd, rsi, plot_ind = intelligent_loop_plots(col_chosen)
|
||||||
|
|
||||||
fig = make_subplots(
|
fig = make_subplots(
|
||||||
rows=3,
|
rows=3,
|
||||||
@ -1011,48 +946,47 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
|
|
||||||
price_line = px.line(
|
price_line = px.line(
|
||||||
all_data,
|
data,
|
||||||
x=all_data.index,
|
x=data.index,
|
||||||
y=[col_chosen, col_chosen+'_BOL200L', col_chosen+'_BOL200U', col_chosen+'_SMA200', col_chosen+'_SMA50', col_chosen+'_WVMA50'],
|
y=data.columns.to_list(),
|
||||||
# y=[sym, sym+'_BOL200L', sym+'_BOL200U', sym+'_SMA200', sym+'_SMA50', sym+'_WVMA50'],
|
# y=[sym, sym+'_BOL200L', sym+'_BOL200U', sym+'_SMA200', sym+'_SMA50', sym+'_WVMA50'],
|
||||||
)
|
)
|
||||||
|
|
||||||
volume_line = px.bar(
|
volume_line = px.bar(
|
||||||
all_vol,
|
vol,
|
||||||
x=all_vol.index,
|
x=vol.index,
|
||||||
# y=sym,
|
y=vol.columns.to_list(),
|
||||||
y=col_chosen,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
macd_line = px.line(
|
macd_line = px.line(
|
||||||
all_macd,
|
macd,
|
||||||
x=all_macd.index,
|
x=macd.index,
|
||||||
y=[col_chosen+'_MACD', col_chosen+'_SIG'],
|
y=['_MACD', '_SIG'],
|
||||||
)
|
)
|
||||||
|
|
||||||
macd_neg = all_macd.copy()
|
macd_neg = macd.copy()
|
||||||
macd_pos = all_macd.copy()
|
macd_pos = macd.copy()
|
||||||
macd_neg[macd_neg>0] = 0
|
macd_neg[macd_neg>0] = 0
|
||||||
macd_pos[macd_pos<0] = 0
|
macd_pos[macd_pos<0] = 0
|
||||||
|
|
||||||
macd_hist_pos = px.line(
|
macd_hist_pos = px.line(
|
||||||
macd_pos,
|
macd_pos,
|
||||||
x=macd_pos.index,
|
x=macd_pos.index,
|
||||||
y=[col_chosen+'_HIST'],
|
y=['_HIST'],
|
||||||
)
|
)
|
||||||
macd_hist_pos.update_traces(fill='tozeroy', line_color='rgba(0,100,0,0.5)', showlegend=False)
|
macd_hist_pos.update_traces(fill='tozeroy', line_color='rgba(0,100,0,0.5)', showlegend=False)
|
||||||
|
|
||||||
macd_hist_neg = px.line(
|
macd_hist_neg = px.line(
|
||||||
macd_neg,
|
macd_neg,
|
||||||
x=macd_neg.index,
|
x=macd_neg.index,
|
||||||
y=[col_chosen+'_HIST'],
|
y=['_HIST'],
|
||||||
)
|
)
|
||||||
macd_hist_neg.update_traces(fill='tozeroy', line_color='rgba(100,0,0,0.5)', showlegend=False)
|
macd_hist_neg.update_traces(fill='tozeroy', line_color='rgba(100,0,0,0.5)', showlegend=False)
|
||||||
|
|
||||||
rsi_line = px.line(
|
rsi_line = px.line(
|
||||||
all_rsi,
|
rsi,
|
||||||
x=all_rsi.index,
|
x=rsi.index,
|
||||||
y=[col_chosen+'_RSI', col_chosen+'_VoRSI'],
|
y=['_RSI', '_VoRSI'],
|
||||||
)
|
)
|
||||||
fig.add_traces(price_line.data + volume_line.data, rows=1, cols=1, secondary_ys=[False, False, False, False, False, False, True])
|
fig.add_traces(price_line.data + volume_line.data, rows=1, cols=1, secondary_ys=[False, False, False, False, False, False, True])
|
||||||
fig.add_traces(macd_line.data + macd_hist_pos.data + macd_hist_neg.data, rows=2, cols=1)
|
fig.add_traces(macd_line.data + macd_hist_pos.data + macd_hist_neg.data, rows=2, cols=1)
|
||||||
@ -1072,7 +1006,7 @@ if __name__ == "__main__":
|
|||||||
fig.layout.yaxis3.title="MACD"
|
fig.layout.yaxis3.title="MACD"
|
||||||
fig.layout.yaxis4.title="RSI/VoRSI"
|
fig.layout.yaxis4.title="RSI/VoRSI"
|
||||||
|
|
||||||
fig.update_layout(title_text=all_plot_ind[col_chosen])
|
fig.update_layout(title_text=plot_ind)
|
||||||
# fig.update_layout(showlegend=False)
|
# fig.update_layout(showlegend=False)
|
||||||
fig.update_layout(margin=dict(l=30, r=20, t=50, b=20))
|
fig.update_layout(margin=dict(l=30, r=20, t=50, b=20))
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user