File size: 5,797 Bytes
4ee8ea3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
343a02a
4ee8ea3
 
f732c53
343a02a
 
f732c53
6c634e7
 
4ee8ea3
 
f732c53
 
343a02a
 
f732c53
 
343a02a
 
f732c53
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
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)
    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>&nbsp;&nbsp;&nbsp;&nbsp;<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 = 850, width = 1000,
                       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('-' * 65, '\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(
    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.Plotly(label="Candlestick Chart"),
        gr.Textbox(label="Supply and Demand Levels")
    ]
)

iface.launch()