File size: 7,219 Bytes
4ee8ea3 a906ac4 4ee8ea3 6834747 4ee8ea3 7f57be2 4ee8ea3 343a02a 4ee8ea3 f732c53 343a02a f732c53 6c634e7 4ee8ea3 176e9df 802d262 176e9df 802d262 5cf0dbb f732c53 343a02a f732c53 3c1f5a2 7f57be2 3c1f5a2 4ee8ea3 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
import yfinance as yf
import numpy as np
import pandas as pd
import plotly.graph_objs as go
import gradio as gr
def plot_volatility_bands(ticker, reference_year):
# Retrieving historical data and performing some preprocessing
df = yf.download(ticker, multi_level_index=False, auto_adjust=False)
df['Returns'] = df['Adj Close'].pct_change(1)
df['Adj Low'] = df['Low'] - (df['Close'] - df['Adj Close'])
df['Adj High'] = df['High'] - (df['Close'] - df['Adj Close'])
df['Adj Open'] = df['Open'] - (df['Close'] - df['Adj Close'])
df = df.fillna(0)
# Obtaining the annualized volatility
T = 20
df['Annualized_Vol'] = np.round(df['Returns'].rolling(T).std()*np.sqrt(252), 2)
# Calculating Bands
High_Band_1std = df.loc[reference_year]["Annualized_Vol"][-1]*df.loc[reference_year]["Adj Close"][-1] + df.loc[reference_year]["Adj Close"][-1]
Low_Band_1std = df.loc[reference_year]["Adj Close"][-1] - df.loc[reference_year]["Annualized_Vol"][-1]*df.loc[reference_year]["Adj Close"][-1]
High_Band_2std = 2*df.loc[reference_year]["Annualized_Vol"][-1]*df.loc[reference_year]["Adj Close"][-1] + df.loc[reference_year]["Adj Close"][-1]
Low_Band_2std = df.loc[reference_year]["Adj Close"][-1] - 2*df.loc[reference_year]["Annualized_Vol"][-1]*df.loc[reference_year]["Adj Close"][-1]
High_Band_3std = 3*df.loc[reference_year]["Annualized_Vol"][-1]*df.loc[reference_year]["Adj Close"][-1] + df.loc[reference_year]["Adj Close"][-1]
Low_Band_3std = df.loc[reference_year]["Adj Close"][-1] - 3*df.loc[reference_year]["Annualized_Vol"][-1]*df.loc[reference_year]["Adj Close"][-1]
# Creating Candlestick chart
candlestick = go.Candlestick(x = df.loc[str(int(reference_year) + 1)].index,
open = df.loc[str(int(reference_year) + 1)]['Adj Open'],
high = df.loc[str(int(reference_year) + 1)]['Adj High'],
low = df.loc[str(int(reference_year) + 1)]['Adj Low'],
close = df.loc[str(int(reference_year) + 1)]['Adj Close'],
increasing = dict(line=dict(color = 'red')),
decreasing = dict(line=dict(color = 'black')),
name = 'Candlesticks')
# Defining layout
layout = go.Layout(title = {'text': f'<b>Volatility-Based Supply and Demand Levels ({ticker})<br><br><sup> <i>Yearly Forecast - {str(int(reference_year) + 1)}</i></sup></b>',
'x': .035, 'xanchor': 'left'},
yaxis = dict(title = '<b>Price (USD)</b>',
tickfont=dict(size=16)),
xaxis = dict(title = '<b>Date</b>'),
template = 'seaborn',
plot_bgcolor = '#F6F5F5',
paper_bgcolor = '#F6F5F5',
height = 450, width = 650,
showlegend=False,
xaxis_rangeslider_visible = False)
fig = go.Figure(data = [candlestick], layout = layout)
# Fixing the empty spaces in the X-Axis
dt_all = pd.date_range(start = df.index[0]
, end = df.index[-1]
, freq = "D")
dt_all_py = [d.to_pydatetime() for d in dt_all]
dt_obs_py = [d.to_pydatetime() for d in df.index]
dt_breaks = [d for d in dt_all_py if d not in dt_obs_py]
fig.update_xaxes(
rangebreaks = [dict(values = dt_breaks)]
)
# 1Ο
fig.add_hline(y = High_Band_1std, line_width = 2, line_dash = "dot", line_color = "green")
fig.add_hline(y = Low_Band_1std, line_width = 2, line_dash = "dot", line_color = "red")
# 2Ο
fig.add_hline(y = High_Band_2std, line_width = 4, line_dash = "dash", line_color = "green")
fig.add_hline(y = Low_Band_2std, line_width = 4, line_dash = "dash", line_color = "red")
# 3Ο
fig.add_hline(y = High_Band_3std, line_width = 6, line_dash = "dashdot", line_color = "green")
fig.add_hline(y = Low_Band_3std, line_width = 6, line_dash = "dashdot", line_color = "red")
fig.show()
# Printing Supply and Demand Levels
print(f"\nVolatility-Based Supply and Demand Levels for {ticker} in {int(reference_year) + 1}\n")
print(f"Supply Level 3Ο: {High_Band_3std.round(2)}\n")
print(f"Supply Level 2Ο: {High_Band_2std.round(2)}\n")
print(f"Supply Level 1Ο: {High_Band_1std.round(2)}\n")
print('-' * 165, '\n')
print(f"Demand Level 1Ο: {Low_Band_1std.round(2)}\n")
print(f"Demand Level 2Ο: {Low_Band_2std.round(2)}\n")
print(f"Demand Level 3Ο: {Low_Band_3std.round(2)}\n")
# Creating the text output
text_info = f"""
Volatility-Based Supply and Demand Levels for {ticker} in {int(reference_year) + 1}\n
Supply Level 3Ο: {High_Band_3std.round(2)}\n
Supply Level 2Ο: {High_Band_2std.round(2)}\n
Supply Level 1Ο: {High_Band_1std.round(2)}\n
-------------------------\n
Demand Level 1Ο: {Low_Band_1std.round(2)}\n
Demand Level 2Ο: {Low_Band_2std.round(2)}\n
Demand Level 3Ο: {Low_Band_3std.round(2)}\n
"""
return fig, text_info
def wrapper_func(ticker, reference_year):
try:
fig, text_info = plot_volatility_bands(ticker, str(int(reference_year)))
return fig, text_info
except Exception as e:
error_message = str(e)
return error_message, error_message
iface = gr.Interface(
title = 'π Volatility-Based Supply and Demand Levels π',
description="""<br> The ideas presented in this app are based on the research paper <a href = "https://www.outspokenmarket.com/uploads/8/8/2/3/88233040/supply_and_demand_levels_forecasting_based_on_returns_volatility.pdf">Supply and Demand Levels Forecasting Based on Returns Volatility</a>,authored by <a href = "https://www.outspokenmarket.com/">Leandro Guerra</a>. <br>
In the Kaggle Notebook, <a href = "https://www.kaggle.com/code/lusfernandotorres/volatility-based-supply-and-demand-levels/notebook">Volatility-Based Supply & Demand Levels Forecasting</a>, you can read further on how these supply and demand levels are calculated. <br><br>
<b>Intructions</b><br>
Enter the ticker of a security as it is displayed on Yahoo Finance. Then inform a year of reference. <br>
The supply and demand levels are forecastings for the following year. If you inform <i>2022</i> as input, the plot will contain the forecastings for <i>2023</i>. <br><br>
β’ Dot lines represent one standard deviation (68.7% probability). <br>
β’ Dash lines represent two standard deviations (95.4% probability). <br>
β’ Dash and dot lines represent three standard deviations (99.7% probability).""",
fn=wrapper_func,
inputs=[
gr.Textbox(label="Enter the Ticker as it Appears on Yahoo Finance"),
gr.Number(label="Enter the Year of Reference")
],
outputs=[
gr.Plot(label = ""),
gr.Textbox(label = "")
],
css=".gr-input {width: 60px;}"
)
iface.launch()
|