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)
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.
I am trying to create a dashboard in bokeh. I am fairly new to bokeh. The plots work alright but when I try to update it using bokeh server, it gets very slow, it takes more than a minute to update the plots.
I don't know if I'm doing anything wrong. Below is the code I'm using:
import pandas as pd
from bokeh.io import curdoc
from bokeh.plotting import figure
from bokeh.models import (
Div, SingleIntervalTicker, DatetimeTickFormatter, NumeralTickFormatter, DateRangeSlider, ColumnDataSource
)
from bokeh.layouts import layout
def _get_data(path, name):
df = pd.read_csv(path)
df.drop(columns='Province/State', inplace=True)
df.rename(columns={'Country/Region': 'country', 'Lat': 'lat', 'Long': 'long'}, inplace=True)
df = df.melt(var_name='date', value_name=name, id_vars=['country', 'lat', 'long'])
df = df.groupby(by=['country', 'date'], as_index=False, sort=False, dropna=False).sum()
df['id'] = df.country + df.date
df['date'] = pd.to_datetime(df['date'], format='%m/%d/%y', infer_datetime_format=True)
return df
def _merged_data():
confirmed = _get_data('data/time_series_covid19_confirmed_global.csv', 'confirmed')
deaths = _get_data('data/time_series_covid19_deaths_global.csv', 'deaths')
recovered = _get_data('data/time_series_covid19_recovered_global.csv', 'recovered')
merged = pd.merge(confirmed, deaths[['id', 'deaths']], on='id', validate='1:1')
merged = merged.merge(recovered[['id', 'recovered']], on='id', validate='1:1')
merged.drop(columns='id', inplace=True)
return merged
def line_fig(label, interval, **kwargs):
fig = figure(
plot_width=400,
plot_height=250,
background_fill_color='#222222',
y_axis_label=label,
border_fill_color='#222222',
outline_line_color='#222222',
**kwargs
)
# Fig
fig.toolbar_location = None
fig.tools = []
# Axis
fig.axis.major_label_text_color = '#bdbdbd'
fig.axis.major_tick_line_color = '#5c5c5c'
fig.axis.major_tick_in = 0
fig.axis.minor_tick_line_color = None
fig.axis.axis_label_text_color = '#bdbdbd'
fig.axis.axis_line_color = "#5c5c5c"
# X-Axis
fig.xgrid.grid_line_color = "#5c5c5c"
fig.xgrid.grid_line_width = 1
fig.xgrid.grid_line_alpha = 0.4
fig.xgrid.grid_line_dash = [3, 9]
fig.xaxis.formatter = DatetimeTickFormatter(months="%b %Y")
# Y-Axis
fig.ygrid.grid_line_color = "#5c5c5c"
fig.ygrid.grid_line_width = 1
fig.ygrid.grid_line_alpha = 0.4
fig.ygrid.grid_line_dash = [3, 9]
fig.yaxis.ticker = SingleIntervalTicker(interval=interval)
fig.yaxis.formatter = NumeralTickFormatter(format='0a')
return fig
source = _merged_data()
datacache = ColumnDataSource(source)
date = datacache.data['date']
start_date = date.min()
end_date = date.max()
date_slider = DateRangeSlider(start=start_date,
end=end_date,
value=(start_date, end_date),
step=1,
show_value=False,
default_size=400)
del date
def date_slider_callback(attr, old, new):
old = pd.to_datetime(date_slider.value_as_date[0], infer_datetime_format=True)
new = pd.to_datetime(date_slider.value_as_date[1], infer_datetime_format=True)
temp_data = source[(source['date'] >= old) & (source['date'] <= new)]
datacache.data = ColumnDataSource.from_df(temp_data)
date_slider.on_change('value', date_slider_callback)
confirmed_chart = make_chart('Confirmed Cases', 'date', 'confirmed', interval=10000000.00, color='#D83020')
death_chart = make_chart('Confirmed Deaths', 'date', 'deaths', interval=300000.00, color='#eaeaea')
recovery_chart = make_chart('Confirmed Recovery', 'date', 'recovered', interval=10000000.00, color='#35ac46')
lay_out = layout(
children=[
[date_slider],
[confirmed_chart],
[death_chart],
[recovery_chart]
]
)
document = curdoc()
document.add_root(lay_out)
Right now, I don't know what I'm doing wrong, maybe there's some kind of best practice I should follow, I don't really know what's making the plot so slow.
My question is very similar to this one, but I still cannot find how to adapt the answers to my problem.
I have a dataframe with 100 columns. I want to use two sliders in Bokeh to select one column to show in the plot. I want to do this with CDSView.
Say the columns are named as such: ["11", "12", .."99"]. Plus I have one column, "x", which is the x axis and does not change. The first slider, range [0-9], should select the first digit of the column name. The second slider should select the last two digits in the same way.
This would mean that if the user selects 2, 5 on the first and second sliders, Bokeh would show a plot using the column "25" from my dataframe.
How can I do this?
So I've found a solution, using some snippets from other questions.
Here is a working example (Bokeh 2+), I hope somebody will find it useful in the future.
import pandas as pd
from bokeh.plotting import figure, show, ColumnDataSource
from bokeh.layouts import column
from bokeh.models import CustomJS, Slider
df = pd.DataFrame([[1,2,3,4,5],[2,20,3,10,20]], columns = ['1','21','22','31','32'])
source_available = ColumnDataSource(df)
source_visible = ColumnDataSource(data = dict(x = df['1'], y = df['21']))
p = figure(title = 'SLIMe')
p.circle('x', 'y', source = source_visible)
slider1 = Slider(title = "SlideME", value = 2, start = 2, end = 3, step = 1)
slider2 = Slider(title = "SlideME2", value = 1, start = 1, end = 2, step = 1)
slider1.js_on_change('value', CustomJS(
args=dict(source_visible=source_visible,
source_available=source_available,
slider1 = slider1,
slider2 = slider2), code="""
var sli1 = slider1.value;
var sli2 = slider2.value;
var data_visible = source_visible.data;
var data_available = source_available.data;
data_visible.y = data_available[sli1.toString() + sli2.toString()];
source_visible.change.emit();
""") )
slider2.js_on_change('value', CustomJS(
args=dict(source_visible=source_visible,
source_available=source_available,
slider1 = slider1,
slider2 = slider2), code="""
var sli1 = slider1.value;
var sli2 = slider2.value;
var data_visible = source_visible.data;
var data_available = source_available.data;
data_visible.y = data_available[sli1.toString() + sli2.toString()];
source_visible.change.emit();
""") )
show(column(p, slider1, slider2))