goldhand 14.6__tar.gz → 15.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of goldhand might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: goldhand
3
- Version: 14.6
3
+ Version: 15.3
4
4
  Summary: A package working with financial data
5
5
  Home-page: https://github.com/misrori/goldhand
6
6
  Author: Mihaly
@@ -30,8 +30,10 @@ class Backtest:
30
30
  'ticker' : self.data['ticker'].iloc[0],
31
31
  'number_of_trades' : self.trades.shape[0],
32
32
  'win_ratio(%)' : round(((sum(self.trades['result'] >1) / self.trades.shape[0])*100),2),
33
-
34
33
  'average_res(%)' : round(((self.trades['result'].mean()-1)*100),2),
34
+ 'average_trade_len(days)' : round(self.trades['days_in_trade'].mean(), 0),
35
+
36
+
35
37
  'median_res(%)': round(((self.trades['result'].median()-1)*100),2),
36
38
  'cumulative_result': list(np.cumprod(self.trades['result'], axis=0))[-1],
37
39
  'trade_results': ' # '.join([ str(round(((x-1)*100),2)) for x in self.trades['result']]),
@@ -46,8 +48,6 @@ class Backtest:
46
48
  'looser_trades_mean' : round((( np.mean([x for x in self.trades['result'] if x<1])-1)*100),2),
47
49
  'looser_trades_median' : round((( np.median([x for x in self.trades['result'] if x<1])-1)*100),2),
48
50
 
49
-
50
- 'average_trade_len(days)' : self.trades['days_in_trade'].mean(),
51
51
  'median_trade_len(days)' : self.trades['days_in_trade'].median(),
52
52
 
53
53
 
@@ -21,6 +21,9 @@ class GoldHand:
21
21
 
22
22
 
23
23
  def get_olhc(self):
24
+ """
25
+ Download historical stock data for the last year
26
+ """
24
27
  #scraper = cloudscraper.create_scraper()
25
28
  response = self.scraper.get(f"https://query1.finance.yahoo.com/v8/finance/chart/{self.ticker}?interval={self.interval}&range={self.range}")
26
29
  t= response.json()
@@ -32,6 +35,9 @@ class GoldHand:
32
35
  return(df)
33
36
 
34
37
  def smma(self, data, window, colname):
38
+ """
39
+ Calculate Smoothed Moving Average (SMMA)
40
+ """
35
41
  hl2 = data['hl2'].values
36
42
  smma_values = [hl2[0]]
37
43
 
@@ -141,7 +147,7 @@ class GoldHand:
141
147
  else:
142
148
  temj = '😭💔'
143
149
  self.df.loc[states[i], 'local_text'] = f'{temj}{fall}%<br>${round(current_low, 2)}'
144
-
150
+ self.df.reset_index(inplace=True, drop=True)
145
151
 
146
152
  def plotly_last_year(self, plot_title, plot_height=900, ndays=500, ad_local_min_max=True):
147
153
  tdf = self.df.tail(ndays)
@@ -8,7 +8,16 @@ from goldhand import *
8
8
 
9
9
 
10
10
 
11
- def goldhand_line_strategy(data):
11
+ def goldhand_line_strategy(data, buy_at='gold', sell_at='grey'):
12
+ """
13
+ This function implements the goldhand line strategy.
14
+ Parameters:
15
+ data (pandas.DataFrame): The dataframe containing the data.
16
+ buy_at (str): The color of the line to buy at. Default is 'gold'.
17
+ sell_at (str): The color of the line to sell at. Default is 'grey'.
18
+ Returns:
19
+ res_df (pandas.DataFrame): The dataframe containing the results.
20
+ """
12
21
 
13
22
  data['hl2'] = (data['high'] + data['low'])/2
14
23
 
@@ -45,23 +54,33 @@ def goldhand_line_strategy(data):
45
54
  # Check if not already in a trade
46
55
  if not in_trade:
47
56
  # Generate buy signal
48
- if (data['color'][i] =='gold') :
49
-
50
- temp_trade['buy_price'] = data['close'][i]
57
+ if (data['color'][i] ==buy_at) :
58
+
59
+ if i == (len(data) -1):
60
+ temp_trade['buy_price'] = data['close'][i]
61
+ temp_trade.update(dict(data.iloc[i].add_prefix('buy_')))
62
+ else:
63
+ temp_trade['buy_price'] = data['open'][i+1]
64
+ temp_trade.update(dict(data.iloc[i+1].add_prefix('buy_')))
65
+
66
+
51
67
  temp_trade['trade_id'] = trade_id
52
68
  temp_trade['status'] = 'open'
53
- temp_trade.update(dict(data.iloc[i].add_prefix('buy_')))
54
69
  in_trade = True # Set flag to indicate in a trade
55
70
  else:
56
71
  # Generate sell signal
57
- if (data['color'][i] =='grey') :
58
-
59
- temp_trade['sell_price'] = data['close'][i]
72
+ if (data['color'][i] ==sell_at) :
73
+
74
+ if i == (len(data) -1):
75
+ temp_trade['sell_price'] = data['close'][i]
76
+ temp_trade.update(dict(data.iloc[i].add_prefix('sell_')))
77
+ else:
78
+ temp_trade['sell_price'] = data['open'][i+1]
79
+ temp_trade.update(dict(data.iloc[i+1].add_prefix('sell_')))
80
+
60
81
  temp_trade['trade_id'] = trade_id
61
82
  temp_trade['status'] = 'closed'
62
83
 
63
- temp_trade.update(dict(data.iloc[i].add_prefix('sell_')))
64
-
65
84
  # calculate results
66
85
  temp_trade['result'] = temp_trade['sell_price'] / temp_trade['buy_price']
67
86
  temp_trade['days_in_trade'] = (temp_trade['sell_date'] - temp_trade['buy_date']).days
@@ -91,7 +110,18 @@ def goldhand_line_strategy(data):
91
110
  return(res_df)
92
111
 
93
112
 
94
- def show_indicator_goldhand_line_strategy(ticker, plot_title = '', ndays=0, plot_height=800):
113
+ def show_indicator_goldhand_line_strategy(ticker, plot_title = '', buy_at='gold', sell_at='grey', ndays=0, plot_height=1000, add_strategy_summary = True):
114
+ """
115
+ This function shows the goldhand line strategy on a plotly candlestick chart.
116
+ Parameters:
117
+ ticker (str): The ticker of the stock or ETF.
118
+ plot_title (str): The title of the plot.
119
+ ndays (int): The number of days to show. If 0, all data will be shown.
120
+ plot_height (int): The height of the plot.
121
+ add_strategy_summary (bool): If True, the strategy summary will be added to the plot.
122
+ Returns:
123
+ fig (plotly.graph_objects.Figure): The plotly figure.
124
+ """
95
125
 
96
126
  data = GoldHand(ticker).df
97
127
 
@@ -129,11 +159,10 @@ def show_indicator_goldhand_line_strategy(ticker, plot_title = '', ndays=0, plot
129
159
  # Create a 'group' column and increase the value only when there's a color change
130
160
  data['group'] = (data['color_change']).cumsum()
131
161
 
132
-
133
162
  ##### data prepar end
134
163
 
135
164
  ##### backtest
136
- backtest = Backtest( data, goldhand_line_strategy, plot_title =plot_title)
165
+ backtest = Backtest( data, goldhand_line_strategy, plot_title =plot_title, buy_at='gold', sell_at='grey')
137
166
  trades =backtest.trades
138
167
 
139
168
  if ndays!=0:
@@ -237,21 +266,21 @@ def show_indicator_goldhand_line_strategy(ticker, plot_title = '', ndays=0, plot
237
266
  fig.update_layout(showlegend=False, plot_bgcolor='white', height=plot_height, title=plot_title)
238
267
  fig.update(layout_xaxis_rangeslider_visible=False)
239
268
 
240
-
241
- t= backtest.trades_summary
242
- trade_text = f"Trades: {t['number_of_trades']}<br>"\
243
- f"Win ratio: {t['win_ratio(%)']}%<br>"\
244
- f"Average result: {t['average_res(%)']}%<br>"\
245
- f"Median result: {t['median_res(%)']}%<br>"\
246
- f"Average trade lenght: {round(t['average_trade_len(days)'], 0)} days<br>"\
247
- f"Cumulative result: {round(t['cumulative_result'], 2)}x<br>"\
248
- f"Profitable trades mean: {t['profitable_trades_mean']}%<br>"\
249
- f"Profitable trades median: {t['profitable_trades_median']}%<br>"\
250
- f"Looser trades mean: {t['looser_trades_mean']}%<br>"\
251
- f"Looser trades median: {t['looser_trades_median']}%<br>"
252
-
253
- # Add a larger textbox using annotations
254
- fig.add_annotation( go.layout.Annotation( x=tex_loc[0], y=tex_loc[1], xref='paper', yref='paper', text=trade_text, showarrow=True, arrowhead=4, ax=0, ay=0, bordercolor='black', borderwidth=2, bgcolor='white', align='left', font=dict(size=14, color='black')))
269
+ if add_strategy_summary:
270
+ t= backtest.trades_summary
271
+ trade_text = f"Trades: {t['number_of_trades']}<br>"\
272
+ f"Win ratio: {t['win_ratio(%)']}%<br>"\
273
+ f"Average result: {t['average_res(%)']}%<br>"\
274
+ f"Median result: {t['median_res(%)']}%<br>"\
275
+ f"Average trade lenght: {round(t['average_trade_len(days)'], 0)} days<br>"\
276
+ f"Cumulative result: {round(t['cumulative_result'], 2)}x<br>"\
277
+ f"Profitable trades mean: {t['profitable_trades_mean']}%<br>"\
278
+ f"Profitable trades median: {t['profitable_trades_median']}%<br>"\
279
+ f"Looser trades mean: {t['looser_trades_mean']}%<br>"\
280
+ f"Looser trades median: {t['looser_trades_median']}%<br>"
281
+
282
+ # Add a larger textbox using annotations
283
+ fig.add_annotation( go.layout.Annotation( x=tex_loc[0], y=tex_loc[1], xref='paper', yref='paper', text=trade_text, showarrow=True, arrowhead=4, ax=0, ay=0, bordercolor='black', borderwidth=2, bgcolor='white', align='left', font=dict(size=14, color='black')))
255
284
 
256
285
  # Show the plot
257
286
  return (fig)
@@ -20,33 +20,43 @@ def rsi_strategy(data, buy_threshold = 30, sell_threshold = 70):
20
20
  # Check if not already in a trade
21
21
  if not in_trade:
22
22
  # Generate buy signal
23
+ #You have to change olne the buy and sell signal
23
24
  if data['rsi'][i] < buy_threshold:
24
25
 
25
- temp_trade['buy_price'] = data['close'][i]
26
+ if i == (len(data) -1):
27
+ temp_trade['buy_price'] = data['close'][i]
28
+ temp_trade.update(dict(data.iloc[i].add_prefix('buy_')))
29
+ else:
30
+ temp_trade['buy_price'] = data['open'][i+1]
31
+ temp_trade.update(dict(data.iloc[i+1].add_prefix('buy_')))
32
+
26
33
  temp_trade['trade_id'] = trade_id
27
34
  temp_trade['status'] = 'open'
28
- temp_trade.update(dict(data.iloc[i].add_prefix('buy_')))
29
35
  in_trade = True # Set flag to indicate in a trade
30
36
  else:
31
37
  # Generate sell signal
38
+ #You have to change olne the buy and sell signal
32
39
  if data['rsi'][i] > sell_threshold:
33
-
34
- temp_trade['sell_price'] = data['close'][i]
40
+ if i == (len(data) -1):
41
+ temp_trade['sell_price'] = data['close'][i]
42
+ temp_trade.update(dict(data.iloc[i].add_prefix('sell_')))
43
+ else:
44
+ temp_trade['sell_price'] = data['open'][i+1]
45
+ temp_trade.update(dict(data.iloc[i+1].add_prefix('sell_')))
46
+
35
47
  temp_trade['trade_id'] = trade_id
36
48
  temp_trade['status'] = 'closed'
37
49
 
38
- temp_trade.update(dict(data.iloc[i].add_prefix('sell_')))
39
-
50
+
40
51
  # calculate results
41
52
  temp_trade['result'] = temp_trade['sell_price'] / temp_trade['buy_price']
42
53
  temp_trade['days_in_trade'] = (temp_trade['sell_date'] - temp_trade['buy_date']).days
43
54
 
44
-
45
-
46
55
  in_trade = False # Reset flag to indicate not in a trade
47
56
  trade_id +=1
48
57
  all_trades.append(temp_trade)
49
58
  temp_trade = {}
59
+
50
60
  if temp_trade:
51
61
  temp_trade['sell_price'] = data['close'][i]
52
62
  temp_trade['trade_id'] = trade_id
@@ -59,7 +69,6 @@ def rsi_strategy(data, buy_threshold = 30, sell_threshold = 70):
59
69
  res_df = pd.DataFrame(all_trades)
60
70
 
61
71
  # change orders
62
-
63
72
  all_col = res_df.columns.tolist()
64
73
  first = ['result', 'buy_price', 'sell_price', 'buy_date', 'sell_date', 'days_in_trade']
65
74
  first.extend([x for x in all_col if x not in first])
@@ -68,14 +77,14 @@ def rsi_strategy(data, buy_threshold = 30, sell_threshold = 70):
68
77
 
69
78
 
70
79
 
71
- def show_indicator_rsi_strategy(ticker, buy_threshold = 30, sell_threshold = 70, plot_title = '', ndays=0, plot_height=800):
80
+ def show_indicator_rsi_strategy(ticker, buy_threshold = 30, sell_threshold = 70, plot_title = '', ndays=0, plot_height=1000, add_strategy_summary = True):
72
81
 
73
82
  tdf = GoldHand(ticker).df
74
83
  backtest = Backtest( tdf, rsi_strategy, buy_threshold=buy_threshold, sell_threshold=sell_threshold)
75
84
  trades =backtest.trades
76
85
 
77
- if ndays!=0:
78
- tdf = data.tail(tdf)
86
+ if ndays > 0:
87
+ tdf = tdf.tail(ndays)
79
88
  trades = trades.loc[trades['buy_date']>tdf.date.min()]
80
89
 
81
90
  if tdf['high'].max() == max(tdf['high'][0:50]):
@@ -86,7 +95,7 @@ def show_indicator_rsi_strategy(ticker, buy_threshold = 30, sell_threshold = 70,
86
95
 
87
96
 
88
97
  # Create subplots with shared x-axis and custom heights
89
- fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1, subplot_titles=[plot_title, "RSI"], row_heights=[0.7, 0.3])
98
+ fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1, subplot_titles=['', "RSI"], row_heights=[0.7, 0.3])
90
99
 
91
100
  # Add OHLC candlestick chart
92
101
  fig.add_trace(go.Ohlc(x=tdf['date'], open=tdf['open'], high=tdf['high'], low=tdf['low'], close=tdf['close']), row=1, col=1)
@@ -151,7 +160,7 @@ def show_indicator_rsi_strategy(ticker, buy_threshold = 30, sell_threshold = 70,
151
160
  font=dict(size=13, color=triangle_color, family="Times New Roman")))
152
161
 
153
162
  # Update layout
154
- fig.update_layout(showlegend=False, plot_bgcolor='white', height=800, title=plot_title)
163
+ fig.update_layout(showlegend=False, plot_bgcolor='white', height=plot_height, title=plot_title)
155
164
  fig.update(layout_xaxis_rangeslider_visible=False)
156
165
 
157
166
  # Update x-axes and y-axes for the main chart
@@ -162,22 +171,21 @@ def show_indicator_rsi_strategy(ticker, buy_threshold = 30, sell_threshold = 70,
162
171
  fig.update_xaxes(mirror=True, ticks='outside', showline=True, linecolor='black', gridcolor='lightgrey', row=2, col=1)
163
172
  fig.update_yaxes(mirror=True, ticks='outside', showline=True, linecolor='black', gridcolor='lightgrey', row=2, col=1)
164
173
 
165
-
166
- t= backtest.trades_summary
167
- trade_text = f"Trades: {t['number_of_trades']}<br>"\
168
- f"Win ratio: {t['win_ratio(%)']}%<br>"\
169
- f"Average result: {t['average_res(%)']}%<br>"\
170
- f"Median result: {t['median_res(%)']}%<br>"\
171
- f"Average trade length: {round(t['average_trade_len(days)'], 0)} days<br>"\
172
- f"Cumulative result: {round(t['cumulative_result'], 2)}x<br>"\
173
- f"Profitable trades mean: {t['profitable_trades_mean']}%<br>"\
174
- f"Profitable trades median: {t['profitable_trades_median']}%<br>"\
175
- f"Looser trades mean: {t['looser_trades_mean']}%<br>"\
176
- f"Looser trades median: {t['looser_trades_median']}%<br>"
177
-
178
- # Add a larger textbox using annotations
179
- fig.add_annotation( go.layout.Annotation( x=tex_loc[0], y=tex_loc[1], xref='paper', yref='paper', text=trade_text, showarrow=True, arrowhead=4, ax=0, ay=0, bordercolor='black', borderwidth=2, bgcolor='white', align='left', font=dict(size=14, color='black')))
180
-
174
+ if add_strategy_summary:
175
+ t= backtest.trades_summary
176
+ trade_text = f"Trades: {t['number_of_trades']}<br>"\
177
+ f"Win ratio: {t['win_ratio(%)']}%<br>"\
178
+ f"Average result: {t['average_res(%)']}%<br>"\
179
+ f"Median result: {t['median_res(%)']}%<br>"\
180
+ f"Average trade length: {round(t['average_trade_len(days)'], 0)} days<br>"\
181
+ f"Cumulative result: {round(t['cumulative_result'], 2)}x<br>"\
182
+ f"Profitable trades mean: {t['profitable_trades_mean']}%<br>"\
183
+ f"Profitable trades median: {t['profitable_trades_median']}%<br>"\
184
+ f"Looser trades mean: {t['looser_trades_mean']}%<br>"\
185
+ f"Looser trades median: {t['looser_trades_median']}%<br>"
186
+
187
+ # Add a larger textbox using annotations
188
+ fig.add_annotation( go.layout.Annotation( x=tex_loc[0], y=tex_loc[1], xref='paper', yref='paper', text=trade_text, showarrow=True, arrowhead=4, ax=0, ay=0, bordercolor='black', borderwidth=2, bgcolor='white', align='left', font=dict(size=14, color='black')))
181
189
 
182
190
 
183
191
  # Add RSI line
@@ -92,7 +92,9 @@ class Tw:
92
92
 
93
93
  secdf.rename(columns = {'description': 'Company'}, inplace=True)
94
94
 
95
- fig = px.bar(secdf, x='name', y='market_cap_basic', title = f"{row_df['Company'].iloc[0]} ({row_df['name'].iloc[0]})<br>{row_df['sector'].iloc[0]} | {row_df['industry'].iloc[0]}", labels={'market_cap_basic':'Market kapitalization'}, text='Company')
95
+ #fig = px.bar(secdf, x='name', y='market_cap_basic', title = f"{row_df['Company'].iloc[0]} ({row_df['name'].iloc[0]})<br>{row_df['sector'].iloc[0]} | {row_df['industry'].iloc[0]}", labels={'market_cap_basic':'Market kapitalization'}, text='Company')
96
+
97
+ fig = px.bar(secdf, x='name', y='market_cap_basic', title = self.get_plotly_title(ticker), labels={'market_cap_basic':'Market kapitalization'}, text='Company')
96
98
 
97
99
  fig.add_annotation( x=row_df['name'].iloc[0], y=row_df['market_cap_basic'].iloc[0], text= f"{market_cap}", showarrow=True, align="center", bordercolor="#c7c7c7", font=dict(family="Courier New, monospace", size=16, color="#214e34" ), borderwidth=2, borderpad=4, bgcolor="#f4fdff", opacity=0.8, arrowhead=2, arrowsize=1, arrowwidth=1, ax=65,ay=-45)
98
100
  fig.update_layout(showlegend=False, plot_bgcolor='white', height=600)
@@ -110,7 +112,7 @@ class Tw:
110
112
 
111
113
  inddf.rename(columns = {'description': 'Company'}, inplace=True)
112
114
 
113
- fig = px.bar(inddf, x='name', y='market_cap_basic', title = f"{row_df['Company'].iloc[0]} ({row_df['name'].iloc[0]})<br>{row_df['sector'].iloc[0]} | {row_df['industry'].iloc[0]}", labels={'market_cap_basic':'Market kapitalization'}, text='Company')
115
+ fig = px.bar(inddf, x='name', y='market_cap_basic', title = self.get_plotly_title(ticker), labels={'market_cap_basic':'Market kapitalization'}, text='Company')
114
116
 
115
117
 
116
118
  fig.add_annotation( x=row_df['name'].iloc[0], y=row_df['market_cap_basic'].iloc[0], text= f"{market_cap}", showarrow=True, align="center", bordercolor="#c7c7c7", font=dict(family="Courier New, monospace", size=16, color="#214e34" ), borderwidth=2, borderpad=4, bgcolor="#f4fdff", opacity=0.8, arrowhead=2, arrowsize=1, arrowwidth=1, ax=65,ay=-45)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: goldhand
3
- Version: 14.6
3
+ Version: 15.3
4
4
  Summary: A package working with financial data
5
5
  Home-page: https://github.com/misrori/goldhand
6
6
  Author: Mihaly
@@ -8,7 +8,7 @@ long_description = (this_directory / "README.md").read_text()
8
8
 
9
9
  setup(
10
10
  name="goldhand",
11
- version="14.6",
11
+ version="15.3",
12
12
  author="Mihaly",
13
13
  author_email="ormraat.pte@gmail.com",
14
14
  description="A package working with financial data",
File without changes
File without changes
File without changes
File without changes