How to get alternating trading signals? - python

I am trying to develop a simple RSI strategy by using this code. As you can see by plotting the code, there are too many consecutive sell signals. I'd like there were buy signals followed by a SINGLE sell signal and, after that, another buy signal in order to have, at the end, something like buy, sell, buy, sell... and not something like buy, sell, sell, sell, sell, buy, sell, sell... Here you are the code:
import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import datetime as dt
import ta
start = dt.datetime(2020, 1, 1)
df = yf.download("^GSPC", start)
portfolio = 10000
df['rsi'] = ta.momentum.rsi(df.Close, window=10)
df['200ma'] = df.Close.rolling(200).mean()
df.dropna(inplace=True)
buy, sell = [], []
for i in range(1, len(df)):
if df.Close.iloc[i] > df['200ma'].iloc[i]:
if df['rsi'].iloc[i] < 30:
buy.append(i)
elif df['rsi'].iloc[i] > 40 or ((df['rsi'].iloc[i] - df.Close.iloc[i]) > 10):
sell.append(i)
realbuys = [i+1 for i in buy]
realsells = [i+1 for i in sell]
buyprices = df.Open.iloc[realbuys]
sellprices = df.Open.iloc[realsells]
# plt.figure(figsize = (12, 6))
# plt.scatter(df.iloc[buy].index, df.iloc[buy].Close, marker = "^", color = "green" )
# plt.scatter(df.iloc[sell].index, df.iloc[sell].Close, marker = "v", color = "red" )
# plt.plot(df.Close, label = "S&P", color='k')
# plt.legend()
# plt.show()
pnl = []
for i in range(len(sellprices)):
pnl.append(((sellprices[i] - buyprices[i])/buyprices[i]))
portfolio = portfolio + (portfolio * pnl[i])
averagepnl = sum(pnl) / len(pnl)
print(portfolio, averagepnl)

So. A variable 'order' has been created, in which we record the current transaction. As you will notice, the entry into the transaction occurs only in the opposite direction. For example, if you bought it now, then the next transaction will only be a sale. Or any transaction, if it's the first one.
In the portfolio, I purposefully reduced the cycle by one element. Since buying and selling transactions are not the same. That is, the current sale is not closed.
import yfinance as yf
import matplotlib.pyplot as plt
import datetime as dt
import ta
start = dt.datetime(2020, 1, 1)
df = yf.download("^GSPC", start)
portfolio = 10000
df['rsi'] = ta.momentum.rsi(df.Close, window=10)
df['200ma'] = df.Close.rolling(200).mean()
df.dropna(inplace=True)
buy, sell = [], []
order = ''
for i in range(1, len(df)):
if df.Close.iloc[i] > df['200ma'].iloc[i]:
if df['rsi'].iloc[i] < 30:
if order == 'sell' or order == '':
buy.append(i)
order = 'buy'
elif df['rsi'].iloc[i] > 40 or ((df['rsi'].iloc[i] - df.Close.iloc[i]) > 10):
if order == 'buy' or order == '':
sell.append(i)
order = 'sell'
realbuys = [i + 1 for i in buy]
realsells = [i + 1 for i in sell]
buyprices = df.Open.iloc[realbuys]
sellprices = df.Open.iloc[realsells]
plt.figure(figsize = (12, 6))
plt.scatter(df.iloc[buy].index, df.iloc[buy].Close, marker = "^", color = "green" )
plt.scatter(df.iloc[sell].index, df.iloc[sell].Close, marker = "v", color = "red" )
plt.plot(df.Close, label = "S&P", color='k')
plt.legend()
plt.show()
pnl = []
for i in range(len(sellprices)-1):
pnl.append(((sellprices[i] - buyprices[i]) / buyprices[i]))
portfolio = portfolio + (portfolio * pnl[i])
averagepnl = sum(pnl) / len(pnl)
print(portfolio, averagepnl)

Related

how do i make 1 plotly chart consisting of different dataframes, I need help to add the right buttons as well?

Below is the starting code, dataframes and TA indicator. Using plotly to make all my graphs. The dataframes are 'df' and 'd15'. I do have others but will keep it simple for the help.
import yfinance as yf
import plotly.graph_objs as go
#Importing my data
df = yf.download(tickers='EURUSD=X', period='1d', interval='5m')
d15 = yf.download(tickers='EURUSD=X', period='3d',interval='15m')
def Supertrend(df, atr_period, multiplier):
high = df['High']
low = df['Low']
close = df['Close']
# calculate ATR
price_diffs = [high - low,
high - close.shift(),
close.shift() - low]
true_range = pd.concat(price_diffs, axis=1)
true_range = true_range.abs().max(axis=1)
# default ATR calculation in supertrend indicator
atr = true_range.ewm(alpha=1/atr_period,min_periods=atr_period).mean()
# df['atr'] = df['tr'].rolling(atr_period).mean()
# HL2 is simply the average of high and low prices
hl2 = (high + low) / 2
# upperband and lowerband calculation
# notice that final bands are set to be equal to the respective bands
final_upperband = upperband = hl2 + (multiplier * atr)
final_lowerband = lowerband = hl2 - (multiplier * atr)
# initialize Supertrend column to True
supertrend = [True] * len(df)
for i in range(1, len(df.index)):
curr, prev = i, i-1
# if current close price crosses above upperband
if close[curr] > final_upperband[prev]:
supertrend[curr] = True
# if current close price crosses below lowerband
elif close[curr] < final_lowerband[prev]:
supertrend[curr] = False
# else, the trend continues
else:
supertrend[curr] = supertrend[prev]
# adjustment to the final bands
if supertrend[curr] == True and final_lowerband[curr] < final_lowerband[prev]:
final_lowerband[curr] = final_lowerband[prev]
if supertrend[curr] == False and final_upperband[curr] > final_upperband[prev]:
final_upperband[curr] = final_upperband[prev]
# to remove bands according to the trend direction
if supertrend[curr] == True:
final_upperband[curr] = np.nan
else:
final_lowerband[curr] = np.nan
return pd.DataFrame({
'Supertrend': supertrend,
'Final Lowerband': final_lowerband,
'Final Upperband': final_upperband
}, index=df.index)
atr_period = 10
atr_multiplier = 6.0
df = yf.download(tickers='EURUSD=X', period='1d', interval='5m')
supertrend = Supertrend(df, atr_period, atr_multiplier)
df = df.join(supertrend)
#15 Minute Indicator
def Supertrend(df, atr_period, multiplier):
high = df['High']
low = df['Low']
close = df['Close']
# calculate ATR
price_diffs = [high - low,
high - close.shift(),
close.shift() - low]
true_range = pd.concat(price_diffs, axis=1)
true_range = true_range.abs().max(axis=1)
# default ATR calculation in supertrend indicator
atr = true_range.ewm(alpha=1/atr_period,min_periods=atr_period).mean()
# df['atr'] = df['tr'].rolling(atr_period).mean()
# HL2 is simply the average of high and low prices
hl2 = (high + low) / 2
# upperband and lowerband calculation
# notice that final bands are set to be equal to the respective bands
final_upperband = upperband = hl2 + (multiplier * atr)
final_lowerband = lowerband = hl2 - (multiplier * atr)
# initialize Supertrend column to True
supertrend = [True] * len(df)
for i in range(1, len(df.index)):
curr, prev = i, i-1
# if current close price crosses above upperband
if close[curr] > final_upperband[prev]:
supertrend[curr] = True
# if current close price crosses below lowerband
elif close[curr] < final_lowerband[prev]:
supertrend[curr] = False
# else, the trend continues
else:
supertrend[curr] = supertrend[prev]
# adjustment to the final bands
if supertrend[curr] == True and final_lowerband[curr] < final_lowerband[prev]:
final_lowerband[curr] = final_lowerband[prev]
if supertrend[curr] == False and final_upperband[curr] > final_upperband[prev]:
final_upperband[curr] = final_upperband[prev]
# to remove bands according to the trend direction
if supertrend[curr] == True:
final_upperband[curr] = np.nan
else:
final_lowerband[curr] = np.nan
return pd.DataFrame({
'Supertrend': supertrend,
'Final Lowerband': final_lowerband,
'Final Upperband': final_upperband
}, index=df.index)
atr_period = 10
atr_multiplier = 6.0
df = yf.download(tickers='EURUSD=X', period='1d', interval='5m')
supertrend = Supertrend(df, atr_period, atr_multiplier)
df = df.join(supertrend)
This next part is the plot which I think is where I need the help. I need to add 2 buttons and add these 2 charts to each other?
Button 1: 5m (Shows 05m TF Plot)
Button 2: 15m (Shows 15m TF Plot)
#5 Minute TF plot
fig = go.Figure()
fig.add_trace(go.Candlestick(x=df.index,
open=df['Open'],
high=df['High'],
low=df['Low'],
close=df['Close'],
increasing_line_color= '#04b29b',
decreasing_line_color= '#ff2d5d',
increasing_fillcolor = '#04b29b',
decreasing_fillcolor = '#ff2d5d',
name='EURUSD'
))
fig.add_trace(go.Scatter(x=df.index,
y=df['Final Lowerband'],
mode='lines',
line=dict(color='#04b29b'),
name='Bullish'
))
fig.add_trace(go.Scatter(x=df.index,
y=df['Final Upperband'],
mode='lines',
line=dict(color='#ff2d5d'),
name='Bearish'
))
fig.update_layout(xaxis_rangeslider_visible=False,
plot_bgcolor = 'black', showlegend = False,
margin = dict(l=10, r=10,t=10,b=10),
paper_bgcolor='black',
xaxis=dict(showgrid=False, zerolinecolor = 'white',
color='white'),
yaxis=dict(showticklabels=False, showgrid=False))
fig.update_xaxes(
rangebreaks=[
dict(bounds=["sat", "mon"]), #hide weekends
dict(values=["2015-12-25", "2016-01-01"]) # hide Christmas
and New Year's
]
)
fig.show()
This is the 15 minute tf
15 Minute TF Plot
fig15 = go.Figure()
fig15.add_trace(go.Candlestick(x=d15.index,
open=d15['Open'],
high=d15['High'],
low=d15['Low'],
close=d15['Close'],
increasing_line_color= '#04b29b',
decreasing_line_color= '#ff2d5d',
increasing_fillcolor = '#04b29b',
decreasing_fillcolor = '#ff2d5d',
name='EURUSD'
))
fig15.add_trace(go.Scatter(x=d15.index,
y=d15['Final Lowerband'],
mode='lines',
line=dict(color='#04b29b'),
name='Bullish'
))
fig15.add_trace(go.Scatter(x=d15.index,
y=d15['Final Upperband'],
mode='lines',
line=dict(color='#ff2d5d'),
name='Bearish'
))
fig15.update_layout(xaxis_rangeslider_visible=False,
plot_bgcolor = 'black', showlegend = False,
margin = dict(l=10, r=10,t=10,b=10),
paper_bgcolor='black',
xaxis=dict(showgrid=False, zerolinecolor = 'white',
color='white'),
yaxis=dict(showticklabels=False, showgrid=False))
fig15.update_xaxes(
rangebreaks=[
dict(bounds=["sat", "mon"]), #hide weekends
dict(values=["2015-12-25", "2016-01-01"]) # hide Christmas
and New Year's
]
)
fig15.show()
If you want to get an answer quickly, you will get a quicker answer if you put a more simplified code on it. Or, if you create a reproducible situation with sample data and code for graphs, you will have a better chance of getting an answer. To answer the main question of how to make each graph a button, you can use the stock price data from the official reference, draw three different stocks, and set the show/hide control for each to show For example, if you only have AAPL, set the others to False to hide them. That is simply the only setting.
import plotly.graph_objects as go
import plotly.express as px
df = px.data.stocks()
fig = go.Figure()
fig.add_trace(go.Scatter(x=df['date'], y=df['AAPL'], name='AAPL'))
fig.add_trace(go.Scatter(x=df['date'], y=df['GOOG'], name='GOOG'))
fig.add_trace(go.Scatter(x=df['date'], y=df['AMZN'], name='AMZN'))
fig.update_layout(
updatemenus=[
dict(
type="buttons",
direction="right",
active=0,
x=0.25,
y=1.2,
buttons=list([
dict(label="All",
method="update",
args=[{"visible": [True, True, True]},
{"title": "All"}
]),
dict(label="AAPL",
method="update",
args=[{"visible": [True, False, False]},
{"title": "AAPL"}
]),
dict(label="GOOG",
method="update",
args=[{"visible": [False, True, False]},
{"title": "GOOG"}
]),
dict(label="AMZN",
method="update",
args=[{"visible": [False, False, True]},
{"title": "AMZN"}
]),
]),
)
])
fig.show()

Why are the indicators on my chart delayed by at least 1 day, making them not flush on the blue line? Is it because the time frame is too wide?

Why are the up triangles, when the program is supposed to buy, not on the line when it crosses under, or in the other scenario, the down triangle, when the program is supposed to sell, not on the line when it crosses on top? The blue line is the price and the red line is the EMA, tracking the price.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import requests
plt.style.use("fivethirtyeight")
df = pd.read_csv("TSLA.csv")
df = df.set_index(pd.DatetimeIndex(df["Date"].values))
ShortEMA = df.Close.ewm(span=5, adjust = False).mean()
MiddleEMA = df.Close.ewm(span = 21, adjust = False).mean()
LongEMA = df.Close.ewm(span = 53, adjust = False).mean()
df['Short'] = ShortEMA
df['Middle'] = MiddleEMA
df['Long'] = LongEMA
def MyStrat(data):
bought_list = []
sold_list = []
In = False
Out = True
for i in range(0, len(data)):
if data["Close"][i] > data["Short"][i] and In == False and Out == True:
bought_list.append(data["Close"][i])
sold_list.append(np.nan)
In = True
Out = False
elif data["Close"][i] < data["Short"][i] and In == True and Out == False:
sold_list.append(data["Close"][i])
bought_list.append(np.nan)
In = False
Out = True
else:
bought_list.append(np.nan)
sold_list.append(np.nan)
return(bought_list,sold_list)
df["Bought"] = MyStrat(df)[0]
df["Sold"] = MyStrat(df)[1]
print(df)
plt.figure(figsize=(16, 5))
plt.title('Buy and Sell', fontsize = 18)
plt.plot(df['Close'], label = 'Close Price', color = 'blue', alpha = 0.35)
plt.plot(ShortEMA, label = 'Short', color = 'red', alpha = 0.35)
plt.scatter(df.index, df["Bought"], color = "purple", marker = "^", alpha = 1)
plt.scatter(df.index, df["Sold"], color = "blue", marker = "v", alpha = 1)
plt.xlabel("Date", fontsize = 18)
plt.ylabel("Close", fontsize = 18)
plt.show()
You can use this data for reference:
Date,Open,High,Low,Close,Adj Close,Volume
2022-01-06,1077.000000,1088.000000,1020.500000,1064.699951,1064.699951,30112200
2022-01-07,1080.369995,1080.930054,1010.000000,1026.959961,1026.959961,28054900
2022-01-10,1000.000000,1059.099976,980.000000,1058.119995,1058.119995,30605000
2022-01-11,1053.670044,1075.849976,1038.819946,1064.400024,1064.400024,22021100
2022-01-12,1078.849976,1114.839966,1072.589966,1106.219971,1106.219971,27913000
2022-01-13,1109.069946,1115.599976,1026.540039,1031.560059,1031.560059,32403300
2022-01-14,1019.880005,1052.000000,1013.380005,1049.609985,1049.609985,24308100
2022-01-18,1026.609985,1070.790039,1016.059998,1030.510010,1030.510010,22247800
2022-01-19,1041.709961,1054.670044,995.000000,995.650024,995.650024,25147500
2022-01-20,1009.729980,1041.660034,994.000000,996.270020,996.270020,23496200
2022-01-21,996.340027,1004.549988,940.500000,943.900024,943.900024,34472000
2022-01-24,904.760010,933.510010,851.469971,930.000000,930.000000,50521900
2022-01-25,914.200012,951.260010,903.210022,918.400024,918.400024,28865300
2022-01-26,952.429993,987.690002,906.000000,937.409973,937.409973,34955800
2022-01-27,933.359985,935.390015,829.000000,829.099976,829.099976,49036500
2022-01-28,831.559998,857.500000,792.010010,846.349976,846.349976,44929700
2022-01-31,872.710022,937.989990,862.049988,936.719971,936.719971,34812000
2022-02-01,935.210022,943.700012,905.000000,931.250000,931.250000,24379400
2022-02-02,928.179993,931.500000,889.409973,905.659973,905.659973,22264300
2022-02-03,882.000000,937.000000,880.520020,891.140015,891.140015,26285200
2022-02-04,897.219971,936.500000,881.169983,923.320007,923.320007,24541800
2022-02-07,923.789978,947.770020,902.710022,907.340027,907.340027,20331500
2022-02-08,905.530029,926.289978,894.799988,922.000000,922.000000,16909700
2022-02-09,935.000000,946.270020,920.000000,932.000000,932.000000,17419800
2022-02-10,908.369995,943.809998,896.700012,904.549988,904.549988,22042300
2022-02-11,909.630005,915.960022,850.700012,860.000000,860.000000,26548600
2022-02-14,861.570007,898.880005,853.150024,875.760010,875.760010,22585500
2022-02-15,900.000000,923.000000,893.380005,922.429993,922.429993,19095400
2022-02-16,914.049988,926.429993,901.210022,923.390015,923.390015,17098100
2022-02-17,913.260010,918.500000,874.099976,876.349976,876.349976,18392800
2022-02-18,886.000000,886.869995,837.609985,856.979980,856.979980,22833900
2022-02-22,834.130005,856.729980,801.099976,821.530029,821.530029,27762700
2022-02-23,830.429993,835.299988,760.559998,764.039978,764.039978,31752300
2022-02-24,700.390015,802.479980,700.000000,800.770020,800.770020,45107400
2022-02-25,809.229980,819.500000,782.400024,809.869995,809.869995,25355900
2022-02-28,815.010010,876.859985,814.710022,870.429993,870.429993,33002300
2022-03-01,869.679993,889.880005,853.780029,864.369995,864.369995,24922300
2022-03-02,872.130005,886.479980,844.270020,879.890015,879.890015,24881100
2022-03-03,878.770020,886.440002,832.599976,839.289978,839.289978,20541200
2022-03-04,849.099976,855.650024,825.159973,838.289978,838.289978,22333200
2022-03-07,856.299988,866.140015,804.570007,804.580017,804.580017,24164700
2022-03-08,795.530029,849.989990,782.169983,824.400024,824.400024,26799700
2022-03-09,839.479980,860.559998,832.010010,858.969971,858.969971,19728000
2022-03-10,851.450012,854.450012,810.359985,838.299988,838.299988,19549500
2022-03-11,840.200012,843.799988,793.770020,795.349976,795.349976,22272800
2022-03-14,780.609985,800.700012,756.039978,766.369995,766.369995,23717400
2022-03-15,775.270020,805.570007,756.570007,801.890015,801.890015,22280400
2022-03-16,809.000000,842.000000,802.260010,840.229980,840.229980,28009600
2022-03-17,830.989990,875.000000,825.719971,871.599976,871.599976,22194300
2022-03-18,874.489990,907.849976,867.390015,905.390015,905.390015,33408500
2022-03-21,914.979980,942.849976,907.090027,921.159973,921.159973,27327200
2022-03-22,930.000000,997.859985,921.750000,993.979980,993.979980,35289500
2022-03-23,979.940002,1040.699951,976.400024,999.109985,999.109985,40225400
2022-03-24,1009.729980,1024.489990,988.799988,1013.919983,1013.919983,22973600
2022-03-25,1008.000000,1021.799988,997.320007,1010.640015,1010.640015,20642900
2022-03-28,1065.099976,1097.880005,1053.599976,1091.839966,1091.839966,34168700
2022-03-29,1107.989990,1114.770020,1073.109985,1099.569946,1099.569946,24538300
2022-03-30,1091.170044,1113.949951,1084.000000,1093.989990,1093.989990,19955000
2022-03-31,1094.569946,1103.140015,1076.640015,1077.599976,1077.599976,16265600
2022-03-31,1094.569946,1103.139893,1076.640991,1077.599976,1077.599976,16330919
The problem with this is that the point of intersection occurs between days, not on a specific day. As the data is not continuous, but rather just one point per business day, it is not possible to put the arrow on the intersection itself. I have enlarged a portion of the graph here so you can see what I mean. The change occurs between the 9th and 10th. The data is only on the 9th or the 10th, so the arrow is plotted, and the buy occurs, on the 10th.
The buy/sell is on the next possible day, causing the mis-alignment of the arrows.

How to display Resampling of candles / time series data in plotly?

How can I merge the two functions given below to achieve something like the histogram example. Any button or drop down would do fine.
If you run the function, you get a nice Candlesticks chart with the functionality of removing non trading day gaps.
def plot_candlesticks(df, names = ('DATE','OPEN','CLOSE','LOW','HIGH'), mv:list = [200], slider:bool = False, fig_size:bool = (1400,700), plot:bool = True):
'''
Plot a candlestick on a given dataframe
args:
df: DataFrame
names: Tuple of column names showing ('DATE','OPEN','CLOSE','LOW','HIGH')
mv: Moving Averages
slider: Whether to have below zoom slider or not
fig_size: Size of Figure as (Width, Height)
plotting: Whether to plot the figure or just return the figure for firther modifications
'''
freq = 5 # 5 min candle
candle_text = f"{str(freq)} Min"
stocks = df.copy()
stocks.sort_index(ascending=False, inplace = True) # Without reverse, recent rolling mean will be either NaN or equal to the exact value
Date, Open, Close, Low, High = names
mv = [] if not mv else mv # just in case you don't want to have any moving averages
colors = sample(['black','magenta','teal','brown','violet'],len(mv))
# To remove, non-trading days, grab first and last observations from df.date and make a continuous date range from that
start = stocks['DATE'].iloc[0] - timedelta(days=1)
end = stocks['DATE'].iloc[-1] + timedelta(days=1)
dt_all = pd.date_range(start=start,end=end, freq = f'{str(freq)}min')
# check which dates from your source that also accur in the continuous date range
dt_obs = [d.strftime("%Y-%m-%d %H:%M:%S") for d in stocks['DATE']]
# isolate missing timestamps
dt_breaks = [d for d in dt_all.strftime("%Y-%m-%d %H:%M:%S").tolist() if not d in dt_obs]
rangebreaks=[dict(dvalue = freq*60*1000, values=dt_breaks)]
range_selector = dict(buttons = list([dict(step = 'all', label = 'All')]))
candle = go.Figure(data = [go.Candlestick(opacity = 0.9, x = stocks[Date], name = 'X',
open = stocks[Open], high = stocks[High], low = stocks[Low], close = stocks[Close]),])
for i in range(len(mv)):
stocks[f'{str(mv[i])}-SMA'] = stocks[Close].rolling(mv[i], min_periods = 1).mean()
candle.add_trace(go.Scatter(name=f'{str(mv[i])} MA',x=stocks[Date], y=stocks[f'{str(mv[i])}-SMA'],
line=dict(color=colors[i], width=1.7)))
candle.update_xaxes(title_text = 'Date', rangeslider_visible = slider, rangeselector = range_selector, rangebreaks=rangebreaks)
candle.update_layout(autosize = False, width = fig_size[0], height = fig_size[1],
title = {'text': f"{stocks['SYMBOL'][0]} : {str(candle_text)} Candles",'y':0.97,'x':0.5,
'xanchor': 'center','yanchor': 'top'},
margin=dict(l=30,r=30,b=30,t=30,pad=2),
paper_bgcolor="lightsteelblue")
candle.update_yaxes(title_text = 'Price in Rupees', tickprefix = u"\u20B9" ) # Rupee symbol
if plot:
candle.show()
return candle
and running the below code resamples your data.
def resample_data(self,to:str = '15min', names:tuple = ('OPEN','CLOSE','LOW','HIGH','DATE')):
'''
Resample the data from 5 Minutes to 15 or 75 Minutes
args:
data: Dataframe of Daily data
to: One of [15M, 75M]
'''
Open, Close, Low, High, Date = names
data = data.resample(to,on=Date).agg({Open:'first', High:'max', Low: 'min', Close:'last'})
return data.sort_index(ascending = False).reset_index()
Is there a functionality when I click 15M / 75M button in my chart, it shows me exactly the same data but resampled? Just like there is functionality in online trading softwares.
no sample data so I have used https://plotly.com/python/candlestick-charts/ sample
at core use https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.resample.html and change trace contents with resampled data
plus using https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20Events.html for events from widgets
import pandas as pd
import numpy as np
import plotly.graph_objects as go
import ipywidgets as widgets
df = pd.read_csv(
"https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv",
parse_dates=["Date"],
)
fig = go.FigureWidget(
data=[
go.Candlestick(
x=df["Date"],
open=df["AAPL.Open"],
high=df["AAPL.High"],
low=df["AAPL.Low"],
close=df["AAPL.Close"],
)
]
).update_layout(margin={"t": 30, "b": 0, "l": 0, "r": 0})
out = widgets.Output(layout={"border": "1px solid black"})
out.append_stdout("Output appended with append_stdout\n")
reset = widgets.Button(description="Reset")
slider = widgets.IntSlider(
value=1,
min=1,
max=10,
step=1,
description='Days:',
disabled=False,
continuous_update=False,
orientation='horizontal',
readout=True,
readout_format='d'
)
#out.capture()
def on_slider_change(v):
print(f"slider: {v['new']}")
dfr = df.resample(f"{v['new']}B", on="Date").mean().reset_index()
t = fig.data[0]
t.update(
x=dfr["Date"],
open=dfr["AAPL.Open"],
high=dfr["AAPL.High"],
low=dfr["AAPL.Low"],
close=dfr["AAPL.Close"],
)
#out.capture()
def on_reset_clicked(b):
print("reset")
t = fig.data[0]
t.update(
x=df["Date"],
open=df["AAPL.Open"],
high=df["AAPL.High"],
low=df["AAPL.Low"],
close=df["AAPL.Close"],
)
out.clear_output()
reset.on_click(on_reset_clicked)
slider.observe(on_slider_change, names='value')
widgets.VBox([widgets.HBox([reset, slider]), widgets.VBox([fig, out])])

VPN Indicator ThinkScript to Python

Taking a stab at converting a ThinkScript to Python for the first time, and I think my logic is right, but I am missing something as the two plots for the indicator don't match.
Trying to convert the ThinkScript for the VPNIndicator to a Python implementation. Looking for someone knowledgeable in both languages to contribute here.
To start, the indicator plot in ThinkorSwim looks like this (bottom):
So I'm trying to replicate that plot using matplotlib finance, but first I need to translate from ThinkScript to Python, which I've attempted here:
import mplfinance as mpf
import pandas as pd
import numpy as np
import talib
def VPN_Indicator(df, params):
# def atr = WildersAverage(TrueRange(high, close, low), length);
df['H-L'] = df['High'] - df['Low']
df['H-C1'] = df['High'] - df['Close'].shift()
df['C1-L'] = df['Close'].shift() - df['Low']
df['TrueRange'] = df[['H-L','H-C1','C1-L']].max(axis=1)
df['WildersATR'] = df['TrueRange'].ewm(alpha=1.0 / params['length'], adjust=False).mean()
# def diff = hlc3 - hlc3[1];
df['Diff'] = ((df['High'] + df['Low'] + df['Close']) / 3) - ((df['High'].shift() + df['Low'].shift() + df['Close'].shift()) / 3) # Forward peak here?
# def vp = Sum(if diff > factor * atr then volume else 0, length);
df['VP_Helper'] = np.where(df['Diff'] > params['factor'] * df['WildersATR'], df['Volume'], 0)
df['VP'] = df['VP_Helper'].rolling(params['length']).sum()
# def vn = Sum(if diff < -factor * atr then volume else 0, length);
df['VN_Helper'] = np.where(df['Diff'] < -params['factor'] * df['WildersATR'], df['Volume'], 0)
df['VN'] = df['VN_Helper'].rolling(params['length']).sum()
# plot VPN = ExpAverage(100 * (vp - vn) / Sum(volume, length), emaLength);
df['RollingVol'] = df['Volume'].rolling(params['length']).sum()
df['VPN'] = talib.EMA(100 * (df['VP'] - df['VN']) / df['RollingVol'], timeperiod=params['emaLength'])
# plot VPNAvg = MovingAverage(averageType, VPN, averageLength);
if params['averageType'] in ['simple','sma','SMA','SIMPLE']:
df['VPNAvg'] = talib.SMA(df['VPN'], timeperiod=params['averageLength'])
# plot CriticalLevel = criticalValue;
df['CriticalLevel'] = params['criticalValue']
# VPN.DefineColor("Above", Color.UPTICK);
# VPN.DefineColor("Below", Color.DOWNTICK);
# VPN.AssignValueColor(if VPN > CriticalLevel then VPN.Color("Above") else VPN.Color("Below"));
# VPNAvg.SetDefaultColor(GetColor(7));
# CriticalLevel.SetDefaultColor(GetColor(1));
# Gimicks, don't need the top bit for now
return df
params = {
"length": 30,
"emaLength": 3,
"averageLength": 30,
"factor": 0.1,
"criticalValue": 10,
"averageType": "simple"
}
# Import a 1min dataset and rename columns as necessary
df = pd.read_csv("SPY.csv").iloc[-2000:,:]
df['time'] = pd.to_datetime(df['time'])
df = df.set_index('time')
df = df.rename(columns={'open':'Open', 'high':'High', 'low':"Low", "close": "Close", "volume": "Volume"})
df = VPN_Indicator(df, params)
# Plot the results
apds = [ mpf.make_addplot((df['CriticalLevel']), panel=2, color='g'),
mpf.make_addplot((df['VPN']), panel=2, color='g'),
mpf.make_addplot((df['VPNAvg']), panel=2, color='g'),
]
mpf.plot(df[['Open', 'High', 'Low', 'Close', 'Volume']], addplot=apds, figscale=1.2, volume=True)
... which results in a plot that looks like this:
... which is close, but the peaks don't line up with the ThinkOrSwim plot. So I'm wanting to know from someone who knows these languages where I might be off? Thanks!
Try using this to calculate ATR. This gives the same output as TOS.
import numpy as np
def ema(arr, periods=14, weight=1, init=None):
leading_na = np.where(~np.isnan(arr))[0][0]
arr = arr[leading_na:]
alpha = weight / (periods + (weight-1))
alpha_rev = 1 - alpha
n = arr.shape[0]
pows = alpha_rev**(np.arange(n+1))
out1 = np.array([])
if 0 in pows:
out1 = ema(arr[:int(len(arr)/2)], periods)
arr = arr[int(len(arr)/2) - 1:]
init = out1[-1]
n = arr.shape[0]
pows = alpha_rev**(np.arange(n+1))
scale_arr = 1/pows[:-1]
if init:
offset = init * pows[1:]
else:
offset = arr[0]*pows[1:]
pw0 = alpha*alpha_rev**(n-1)
mult = arr*pw0*scale_arr
cumsums = mult.cumsum()
out = offset + cumsums*scale_arr[::-1]
out = out[1:] if len(out1) > 0 else out
out = np.concatenate([out1, out])
out[:periods] = np.nan
out = np.concatenate(([np.nan]*leading_na, out))
return out
def atr(highs, lows, closes, periods=14, ema_weight=1):
hi = np.array(highs)
lo = np.array(lows)
c = np.array(closes)
tr = np.vstack([np.abs(hi[1:]-c[:-1]),
np.abs(lo[1:]-c[:-1]),
(hi-lo)[1:]]).max(axis=0)
atr = ema(tr, periods=periods, weight=ema_weight)
atr = np.concatenate([[np.nan], atr])
return atr

Slight challenge. Need to optimize code. Original one takes too long :(

So i'm trying to read 3 different csv files and plotting the information in an img with four graphs.
One with the average delay by airline, expressed in minutes
Another with the ratio of delayed flights, by airline
Another with the average delay by destination airport, expressed in minutes
And finally another with the ratio of flights delayed to arrival, by destination airport
All the information is correct and i got it from the files. The problem is that the program below takes too long to produce the graphs and that they're all being separately plotted and not all together in one image. Is there a way to optimize my code to run faster? And how do i use subplots without changing everything?
import pandas as pd
import matplotlib.pyplot as plt
path_main = '850566403_T_ONTIME.csv'
path_airline = 'L_AIRLINE_ID.csv'
path_airport = 'L_AIRPORT_ID.csv'
df1 = pd.read_csv(path_main)
al = pd.read_csv(path_airline)
ap = pd.read_csv(path_airport)
#remove columns and rows with nan
df1.dropna(axis=1, how='all', inplace=True)
df = df1.dropna(subset=['ARR_DELAY_NEW'])
#------------------------------------------------------------------------------
#Airlines:
#dict with {ID: Name}
d_al = {}
for i in range(len(al)):
d_al[al['Code'][i]] = al['Description'][i]
# array with ID's of airlines and delays
arr_al = df.loc[:, ('AIRLINE_ID', 'ARR_DELAY_NEW')].to_numpy()
# list with ID's of airlines
list_al = []
for i in arr_al:
if i[0] not in list_al:
list_al.append(int(i[0]))
def airline_avg_ratio(ID):
'''
function that requires an airline ID
and returns a tuple with name (first 10
characters), average delay and
delayed flight ratios
'''
nr_voos = 0
soma = 0
nr_atrasos = 0
for i in arr_al:
if i[0] == ID:
soma += i[1]
nr_voos += 1
if i[1] != 0:
nr_atrasos += 1
for k,v in d_al.items():
if k == ID:
nome = v[0:10]
media = round((soma / nr_atrasos), 3)
racio = round((nr_atrasos / nr_voos), 3)
return (nome, media, racio)
dados_al = []
for i in list_al:
dados_al.append(airline_avg_ratio(i))
df_al = pd.DataFrame(dados_al, columns=['Airlines', 'Average', 'Ratio'])
graph1 = df_al.drop(columns='Ratio').sort_values(by='Average').iloc[-10:]
graph1.plot(x='Airlines', y='Average', kind='bar')
plt.title("Atraso Médio por Companhia (top 10)")
plt.xlabel('Companhia Aérea', fontsize=12)
plt.ylabel('Minutos', fontsize=12)
plt.show()
graph2 = df_al.drop(columns='Average').sort_values(by='Ratio').iloc[-10:]
graph2.plot(x='Airlines', y='Ratio', kind='bar')
plt.title("Vôos Atrasados por Companhia (top 10)")
plt.xlabel('Companhia Aérea', fontsize=12)
plt.ylabel('Rácio', fontsize=12)
plt.show()
#------------------------------------------------------------------------------
# Airports:
#dict with {ID: Name}
d_ap = {}
for i in range(len(ap)):
d_ap[ap['Code'][i]] = ap['Description'][i]
#array with ID's of Airports and delays
arr_ap = df.loc[:, ('DEST_AIRPORT_ID', 'ARR_DELAY_NEW')].to_numpy()
#list with ID's of Airports
list_ap = []
for i in arr_ap:
if i[0] not in list_ap:
list_ap.append(int(i[0]))
def airport_avg_ratio(ID):
'''
function that requires an airport
and returns a tuple with name (first 10
characters), average delay and
delayed flight ratios
'''
nr_chegadas = 0
soma = 0
nr_atrasos = 0
for i in arr_ap:
if i[0] == ID:
soma += i[1]
nr_chegadas += 1
if i[1] != 0:
nr_atrasos += 1
for k,v in d_ap.items():
if k == ID:
nome = v[0:10]
media = round((soma / nr_atrasos), 3)
racio = round((nr_atrasos / nr_chegadas), 3)
return (nome, media, racio)
dados_ap = []
for i in list_ap:
dados_ap.append(airport_avg_ratio(i))
df_ap = pd.DataFrame(dados_ap, columns=['Airports', 'Average', 'Ratio'])
graph3 = df_ap.drop(columns='Ratio').sort_values(by='Average').iloc[-10:]
graph3.plot(x='Airports', y='Average', kind='bar')
plt.title("Atraso Médio por Aeroporto (top 10)")
plt.xlabel('Aeroporto', fontsize=12)
plt.ylabel('Minutos', fontsize=12)
plt.show()
graph4 = df_ap.drop(columns='Average').sort_values(by='Ratio').iloc[-10:]
graph4.plot(x='Airports', y='Ratio', kind='bar')
plt.title("Vôos Atrasados por Aeroporto (top 10)")
plt.xlabel('Aeroporto', fontsize=12)
plt.ylabel('Rácio', fontsize=12)
plt.show()

Categories