Search code examples
pythonpandasdataframeplotlyplotly-python

Plot horizontal lines between date ranges iterating through pandas dataframe


I essentially have two different data frames, one for calculating weekly data (df) and a second one (df1) that has the plot values of the stock/crypto. On df, I have created a pandas column 'pivot' ((open+high+low)/3) using the weekly data to create a set of values containing the weekly pivot values.

Now I want to plot these weekly data (as lines) onto df1 which has the daily data. Therefore the x1 would be the start of the week and x2 be the end of the week. the y values being the pivot value from the df(weekly). Here is what I would want it to look like:

My Approach & Problem:

First of all, I am a beginner in Python, this is my second month of learning. My apologies if this was asked before.

I know the pivot values can be calculated using a single data frame & pandas group-by but I want to take the issue after this is done, so both ways should be fine if you are approaching this issue. What I would like to have is those final lines with OHLC candlesticks. I would like to plot these results using Plotly OHLC and go Shapes. What I am stuck with is iterating through the pivot weekly data frame and adding the lines as traces on top of the OHLC data daily data.

Here's my code so far:

import yfinance as yf
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
from datetime import datetime, timedelta 


df = yf.download( tickers = 'BTC-USD',
                start = '2021-08-30',
                end = datetime.today().strftime('%Y-%m-%d'),
                interval = '1wk',
                group_by = 'ticker',
                auto_adjust = True).reset_index()

#daily df for plot
df2 = yf.download( tickers = 'BTC-USD',
                start = '2021-08-30',
                end = datetime.today().strftime('%Y-%m-%d'),
                interval = '1d',
                group_by = 'ticker',
                auto_adjust = True).reset_index()
#small cap everything
df = df.rename(columns={'Date':'date',
                          'Open': 'open',
                          'High': 'high',
                          'Low' : 'low',
                          'Close' : 'close'})

df['pivot'] = (df['high']+ df['low'] + df['close'])/3
result = df.copy()

fig = go.Figure(data = [go.Candlestick(x= df['date'],
                                      open = df['open'],
                                      high = df['high'],
                                      low = df['low'],
                                      close = df['close'],
                                      name = 'Price Candle')])

This would be for plotting until the candlesticks OHLC, however, the rest iteration is what is troubling me. You can plot it on a line chart or on an OHLC chart and iterate it.

fig = px.line(df, x='time', y='close')
result = df.copy()

for i, pivot in result.iterrows():
        fig.add_shape(type="line",
            x0=pivot.date, y0=pivot, x1=pivot.date, y1=pivot,
            line=dict(
                color="green",
                width=3)
            )
fig

When I print this no pivot lines appear the way I want them to show.Only the original price line graph shows Thanks in advance for taking the time to read this so far.


Solution

  • There are two ways to create a line segment: add a shape or use line mode on a scatter plot. I think the line mode of scatter plots is more advantageous because it allows for more detailed settings. For the data frame, introduce a loop process on a line-by-line basis to get the next line using the idx of the data frame. y-axis values are pivot values. I wanted to get Yokohama, so I moved the legend position up. Also, since we are looping through the scatter plot, we will have many legends for the pivot values, so we set the legend display to True for the first time only.

    import yfinance as yf
    import pandas as pd
    import numpy as np
    import plotly.express as px
    import plotly.graph_objects as go
    from datetime import datetime, timedelta 
    
    df = yf.download( tickers = 'BTC-USD',
                    start = '2021-08-30',
                    end = datetime.today().strftime('%Y-%m-%d'),
                    interval = '1wk',
                    group_by = 'ticker',
                    auto_adjust = True).reset_index()
    
    #daily df for plot
    df2 = yf.download( tickers = 'BTC-USD',
                    start = '2021-08-30',
                    end = datetime.today().strftime('%Y-%m-%d'),
                    interval = '1d',
                    group_by = 'ticker',
                    auto_adjust = True).reset_index()
    #small cap everything
    df = df.rename(columns={'Date':'date',
                              'Open': 'open',
                              'High': 'high',
                              'Low' : 'low',
                              'Close' : 'close'})
    
    df['pivot'] = (df['high']+ df['low'] + df['close'])/3
    
    fig = go.Figure()
    fig.add_trace(go.Candlestick(x= df['date'],
                                 open = df['open'],
                                 high = df['high'],
                                 low = df['low'],
                                 close = df['close'],
                                 name = 'Price Candle',
                                 legendgroup='one'
                                )
                 )
    #fig.add_trace(go.Scatter(mode='lines', x=df['date'], y=df['pivot'], line=dict(color='green'), name='pivot'))
    
    for idx, row in df.iterrows():
        #print(idx)
        if idx == len(df)-2:
            break
        fig.add_trace(go.Scatter(mode='lines',
                                 x=[row['date'], df.loc[idx+1,'date']],
                                 y=[row['pivot'], row['pivot']],
                                 line=dict(color='blue', width=1),
                                 name='pivot',
                                 showlegend=True if idx == 0 else False,
                                )
                     )
        
    fig.update_layout(
        autosize=False,
        height=600,
        width=1100,
        legend=dict(
            orientation="h",
            yanchor="bottom",
            y=1.02,
            xanchor="right",
            x=1)
    )
    fig.update_xaxes(rangeslider_visible=False)
    
    fig.show()
    

    enter image description here