goldhand 16.0__py3-none-any.whl → 17.2__py3-none-any.whl
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.
- goldhand/backtest.py +21 -7
- goldhand/stocks.py +14 -6
- goldhand/strategy_goldhand_line.py +2 -12
- goldhand/strategy_rsi.py +2 -13
- goldhand/tw.py +20 -15
- {goldhand-16.0.dist-info → goldhand-17.2.dist-info}/METADATA +15 -6
- goldhand-17.2.dist-info/RECORD +11 -0
- {goldhand-16.0.dist-info → goldhand-17.2.dist-info}/WHEEL +1 -1
- goldhand-16.0.dist-info/RECORD +0 -11
- {goldhand-16.0.dist-info → goldhand-17.2.dist-info}/top_level.txt +0 -0
goldhand/backtest.py
CHANGED
|
@@ -50,7 +50,7 @@ class Backtest:
|
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
'median_res(%)': round(((self.trades['result'].median()-1)*100),2),
|
|
53
|
-
'cumulative_result': list(np.cumprod(self.trades['result'], axis=0))[-1],
|
|
53
|
+
'cumulative_result': f"{round(list(np.cumprod(self.trades['result'], axis=0))[-1], 2)} x",
|
|
54
54
|
'trade_results': ' # '.join([ str(round(((x-1)*100),2)) for x in self.trades['result']]),
|
|
55
55
|
|
|
56
56
|
'profitable_trade_results': ' # '.join([ str(round(((x-1)*100),2)) for x in self.trades['result'] if x>=1]),
|
|
@@ -75,17 +75,31 @@ class Backtest:
|
|
|
75
75
|
'first_trade_buy' : min(self.trades['buy_date']),
|
|
76
76
|
|
|
77
77
|
|
|
78
|
-
'first_data_date' : self.data['date'].iloc[0],
|
|
79
|
-
'first_open_price' : self.data['open'].iloc[0],
|
|
78
|
+
'first_data_date' : self.data['date'].iloc[0].strftime('%Y-%m-%d'),
|
|
79
|
+
'first_open_price' : round(self.data['open'].iloc[0], 2),
|
|
80
80
|
|
|
81
|
-
'last_data_date' : self.data['date'].iloc[-1],
|
|
82
|
-
'last_close_price' :
|
|
81
|
+
'last_data_date' : self.data['date'].iloc[-1].strftime('%Y-%m-%d'),
|
|
82
|
+
'last_close_price' :round(self.data['close'].iloc[-1], 2),
|
|
83
83
|
|
|
84
84
|
'hold_result' : f"{round(self.data['close'].iloc[-1] / self.data['open'].iloc[0],2)} x",
|
|
85
|
-
|
|
86
|
-
|
|
87
85
|
}
|
|
88
86
|
self.trades_summary.update(self.additional_params)
|
|
87
|
+
self.trade_summary_plot_text = f"Trades: { self.trades_summary['number_of_trades']}<br>"\
|
|
88
|
+
f"Win ratio: { self.trades_summary['win_ratio(%)']}%<br>"\
|
|
89
|
+
f"Average result: { self.trades_summary['average_res(%)']}%<br>"\
|
|
90
|
+
f"Median result: { self.trades_summary['median_res(%)']}%<br>"\
|
|
91
|
+
f"Average trade length: { self.trades_summary['average_trade_len(days)']} days<br>"\
|
|
92
|
+
f"Cumulative result: { self.trades_summary['cumulative_result']}<br>"\
|
|
93
|
+
f"Profitable trades mean: { self.trades_summary['profitable_trades_mean']}%<br>"\
|
|
94
|
+
f"Profitable trades median: { self.trades_summary['profitable_trades_median']}%<br>"\
|
|
95
|
+
f"Looser trades mean: { self.trades_summary['looser_trades_mean']}%<br>"\
|
|
96
|
+
f"Looser trades median: { self.trades_summary['looser_trades_median']}%<br>"\
|
|
97
|
+
f"Hold result: {self.trades_summary['hold_result'] }<br>"\
|
|
98
|
+
f"First data date: { self.trades_summary['first_data_date']}<br>"\
|
|
99
|
+
f"First open price: ${self.trades_summary['first_open_price']}<br>"
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
89
103
|
|
|
90
104
|
def show_trades(self):
|
|
91
105
|
"""
|
goldhand/stocks.py
CHANGED
|
@@ -135,14 +135,22 @@ class GoldHand:
|
|
|
135
135
|
else:
|
|
136
136
|
self.df.loc[states[0],'local_text'] = f"${round(self.df.loc[states[0], 'high'], 2)}"
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
self.df
|
|
138
|
+
|
|
139
|
+
# add one local min max after the last one
|
|
140
|
+
if self.df.loc[states[-1], 'local']== 'maximum':
|
|
141
|
+
lowest_index_after_last_max = self.df['low'][states[-1]+1:].idxmin()
|
|
142
|
+
self.df.loc[lowest_index_after_last_max, 'local'] = 'minimum'
|
|
143
|
+
else:
|
|
144
|
+
high_index_after_last_min = self.df['high'][states[-1]+1:].idxmax()
|
|
145
|
+
self.df.loc[high_index_after_last_min, 'local'] = 'maximum'
|
|
142
146
|
|
|
143
147
|
states = self.df[self.df['local']!='']['local'].index.to_list()
|
|
144
|
-
|
|
145
|
-
|
|
148
|
+
|
|
149
|
+
except:
|
|
150
|
+
pass
|
|
151
|
+
|
|
152
|
+
try:
|
|
153
|
+
|
|
146
154
|
for i in range(1,len(states)):
|
|
147
155
|
prev = self.df.loc[states[i-1], 'local']
|
|
148
156
|
current= self.df.loc[states[i], 'local']
|
|
@@ -271,20 +271,10 @@ def show_indicator_goldhand_line_strategy(ticker, plot_title = '', buy_at='gold'
|
|
|
271
271
|
fig.update(layout_xaxis_rangeslider_visible=False)
|
|
272
272
|
|
|
273
273
|
if add_strategy_summary:
|
|
274
|
-
|
|
275
|
-
trade_text = f"Trades: {t['number_of_trades']}<br>"\
|
|
276
|
-
f"Win ratio: {t['win_ratio(%)']}%<br>"\
|
|
277
|
-
f"Average result: {t['average_res(%)']}%<br>"\
|
|
278
|
-
f"Median result: {t['median_res(%)']}%<br>"\
|
|
279
|
-
f"Average trade lenght: {round(t['average_trade_len(days)'], 0)} days<br>"\
|
|
280
|
-
f"Cumulative result: {round(t['cumulative_result'], 2)}x<br>"\
|
|
281
|
-
f"Profitable trades mean: {t['profitable_trades_mean']}%<br>"\
|
|
282
|
-
f"Profitable trades median: {t['profitable_trades_median']}%<br>"\
|
|
283
|
-
f"Looser trades mean: {t['looser_trades_mean']}%<br>"\
|
|
284
|
-
f"Looser trades median: {t['looser_trades_median']}%<br>"
|
|
274
|
+
|
|
285
275
|
|
|
286
276
|
# Add a larger textbox using annotations
|
|
287
|
-
fig.add_annotation( go.layout.Annotation( x=tex_loc[0], y=tex_loc[1], xref='paper', yref='paper', text=
|
|
277
|
+
fig.add_annotation( go.layout.Annotation( x=tex_loc[0], y=tex_loc[1], xref='paper', yref='paper', text=backtest.trade_summary_plot_text, showarrow=True, arrowhead=4, ax=0, ay=0, bordercolor='black', borderwidth=2, bgcolor='white', align='left', font=dict(size=14, color='black')))
|
|
288
278
|
|
|
289
279
|
# Show the plot
|
|
290
280
|
return (fig)
|
goldhand/strategy_rsi.py
CHANGED
|
@@ -191,20 +191,9 @@ def show_indicator_rsi_strategy(ticker, buy_threshold = 30, sell_threshold = 70,
|
|
|
191
191
|
fig.update_yaxes(mirror=True, ticks='outside', showline=True, linecolor='black', gridcolor='lightgrey', row=2, col=1)
|
|
192
192
|
|
|
193
193
|
if add_strategy_summary:
|
|
194
|
-
|
|
195
|
-
trade_text = f"Trades: {t['number_of_trades']}<br>"\
|
|
196
|
-
f"Win ratio: {t['win_ratio(%)']}%<br>"\
|
|
197
|
-
f"Average result: {t['average_res(%)']}%<br>"\
|
|
198
|
-
f"Median result: {t['median_res(%)']}%<br>"\
|
|
199
|
-
f"Average trade length: {round(t['average_trade_len(days)'], 0)} days<br>"\
|
|
200
|
-
f"Cumulative result: {round(t['cumulative_result'], 2)}x<br>"\
|
|
201
|
-
f"Profitable trades mean: {t['profitable_trades_mean']}%<br>"\
|
|
202
|
-
f"Profitable trades median: {t['profitable_trades_median']}%<br>"\
|
|
203
|
-
f"Looser trades mean: {t['looser_trades_mean']}%<br>"\
|
|
204
|
-
f"Looser trades median: {t['looser_trades_median']}%<br>"
|
|
205
|
-
|
|
194
|
+
|
|
206
195
|
# Add a larger textbox using annotations
|
|
207
|
-
fig.add_annotation( go.layout.Annotation( x=tex_loc[0], y=tex_loc[1], xref='paper', yref='paper', text=
|
|
196
|
+
fig.add_annotation( go.layout.Annotation( x=tex_loc[0], y=tex_loc[1], xref='paper', yref='paper', text=backtest.trade_summary_plot_text, showarrow=True, arrowhead=4, ax=0, ay=0, bordercolor='black', borderwidth=2, bgcolor='white', align='left', font=dict(size=14, color='black')))
|
|
208
197
|
|
|
209
198
|
|
|
210
199
|
# Add RSI line
|
goldhand/tw.py
CHANGED
|
@@ -32,6 +32,7 @@ class Tw:
|
|
|
32
32
|
self.stock = pd.DataFrame(list_elements)
|
|
33
33
|
self.stock.columns = json.loads(data_query)['columns']
|
|
34
34
|
self.stock = self.stock[self.stock['name'].str.contains('\\.')!=True]
|
|
35
|
+
self.stock.reset_index(inplace=True, drop=True)
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
def get_all_crypto(self):
|
|
@@ -48,6 +49,7 @@ class Tw:
|
|
|
48
49
|
filter = list(map(lambda x: 'stablecoins' not in x, self.crypto['crypto_common_categories'].fillna('-') ))
|
|
49
50
|
self.crypto = self.crypto.loc[filter, ]
|
|
50
51
|
self.crypto['ticker'] = self.crypto['base_currency'] + '-USD'
|
|
52
|
+
self.crypto.reset_index(inplace=True, drop=True)
|
|
51
53
|
|
|
52
54
|
def get_all_etf(self):
|
|
53
55
|
"""
|
|
@@ -60,6 +62,7 @@ class Tw:
|
|
|
60
62
|
self.etf = pd.DataFrame(list_elements)
|
|
61
63
|
self.etf.columns = json.loads(data_query)['columns']
|
|
62
64
|
self.etf = self.etf[self.etf['name'].str.contains('\\.')!=True]
|
|
65
|
+
self.etf.reset_index(inplace=True, drop=True)
|
|
63
66
|
|
|
64
67
|
|
|
65
68
|
def moneystring( self, money):
|
|
@@ -128,21 +131,23 @@ class Tw:
|
|
|
128
131
|
- ticker: ticker of the stock
|
|
129
132
|
Return: Summary of the stock or crypto to be used as plotly title
|
|
130
133
|
"""
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
134
|
+
try:
|
|
135
|
+
if '-USD' in ticker:
|
|
136
|
+
# crypto
|
|
137
|
+
coin = self.crypto.loc[self.crypto['ticker']==ticker].iloc[0]
|
|
138
|
+
plotly_title = f"{coin['base_currency_desc']} ({coin['base_currency']})<br>💲{self.moneystring(coin['market_cap_calc'])} | {', '.join(coin['crypto_common_categories'])}"
|
|
139
|
+
|
|
140
|
+
elif ticker in self.etf['name'].tolist() :
|
|
141
|
+
# ETF
|
|
142
|
+
t = self.etf.loc[self.etf['name']==ticker].iloc[0]
|
|
143
|
+
plotly_title = f"{t['description']} ({t['name']}) | 💲{round(t['close'], 2)} <br>AUM:💲{self.moneystring(t['aum'])} | {t['focus.tr']} | Expense ratio {t['expense_ratio']}"
|
|
144
|
+
else:
|
|
145
|
+
# stock
|
|
146
|
+
t = self.get_one_stock_info(ticker)
|
|
147
|
+
plotly_title = f"{t['name']} ({t['ticker']}) | 💲{round(t['price'], 2)} | {t['sector']} | {t['industry']} <br>💲{t['market_cap_text']} | 👨💼 {round(t['n_emp']):,} <br>Sector location: {t['sec_loc']} | Industry location: {t['ind_loc']}"
|
|
148
|
+
return(plotly_title)
|
|
149
|
+
except:
|
|
150
|
+
return(f"{ticker}")
|
|
146
151
|
|
|
147
152
|
|
|
148
153
|
def get_sec_plot(self, ticker):
|
|
@@ -1,24 +1,33 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: goldhand
|
|
3
|
-
Version:
|
|
3
|
+
Version: 17.2
|
|
4
4
|
Summary: A package working with financial data
|
|
5
5
|
Home-page: https://github.com/misrori/goldhand
|
|
6
6
|
Author: Mihaly
|
|
7
7
|
Author-email: ormraat.pte@gmail.com
|
|
8
8
|
License: MIT
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
10
|
-
Requires-Dist:
|
|
10
|
+
Requires-Dist: pandas_datareader
|
|
11
11
|
Requires-Dist: pandas
|
|
12
|
-
Requires-Dist:
|
|
12
|
+
Requires-Dist: pandas_ta
|
|
13
13
|
Requires-Dist: plotly
|
|
14
14
|
Requires-Dist: scipy
|
|
15
|
+
Requires-Dist: numpy==1.26.4
|
|
15
16
|
Requires-Dist: numpy
|
|
16
17
|
Requires-Dist: requests
|
|
17
18
|
Requires-Dist: cloudscraper
|
|
18
19
|
Requires-Dist: tqdm
|
|
20
|
+
Dynamic: author
|
|
21
|
+
Dynamic: author-email
|
|
22
|
+
Dynamic: description
|
|
23
|
+
Dynamic: description-content-type
|
|
24
|
+
Dynamic: home-page
|
|
25
|
+
Dynamic: license
|
|
26
|
+
Dynamic: requires-dist
|
|
27
|
+
Dynamic: summary
|
|
19
28
|
|
|
20
29
|
|
|
21
|
-
# Goldhand
|
|
30
|
+
# [Goldhand](https://github.com/misrori/goldhand)
|
|
22
31
|
The ultimate python package to work with stock and crypto data
|
|
23
32
|
|
|
24
33
|
```bash
|
|
@@ -63,7 +72,7 @@ tw.get_sec_plot('AMD').show()
|
|
|
63
72
|
|
|
64
73
|
|
|
65
74
|
|
|
66
|
-
# [Goldhand class](
|
|
75
|
+
# [Goldhand class](https://github.com/misrori/goldhand/stock.py)
|
|
67
76
|
|
|
68
77
|
The `GoldHand` class is a part of the `goldhand` Python package, which provides functionality for working with stock and crypto data. This class allows users to retrieve detailed information and charts for a specific stock.
|
|
69
78
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
goldhand/__init__.py,sha256=2D68nqSZuv6sqyLJbOXnWIeeFpNgpYc90rHa2Fo70lk,152
|
|
2
|
+
goldhand/backtest.py,sha256=hxSyFEDNvGg8P2eQKHG6fEzr0pOuG3Mgk2-lGnyz2RU,8825
|
|
3
|
+
goldhand/helpers.py,sha256=l9yn0kVTiwfUR8sI5nH1QFx6dYikaUQgRA227Ox7hs0,6130
|
|
4
|
+
goldhand/stocks.py,sha256=3RWj1LI276o4VLIzwQUooXfZ2BcsZCfWJnQEcPMzzqU,14017
|
|
5
|
+
goldhand/strategy_goldhand_line.py,sha256=VopjGsufi1Dg367ys_8xWgYSSF1cw96lHgxJx2bPUNA,11656
|
|
6
|
+
goldhand/strategy_rsi.py,sha256=TWZyT2uzQ1zCfevM2sMZAD6p_vSY_rTZ0qnJiMDN02Y,9831
|
|
7
|
+
goldhand/tw.py,sha256=jT6DL2PyJxoPojNHL39pkk0PsuZajTQBbRStipnbq9w,12840
|
|
8
|
+
goldhand-17.2.dist-info/METADATA,sha256=3QdwhInlyPZhL4xbzOHr6sUrbB4PedLF_MdzqyLqvu8,5608
|
|
9
|
+
goldhand-17.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
10
|
+
goldhand-17.2.dist-info/top_level.txt,sha256=siEJ2_a_Fx_7hqRI4Ms6SzCelbXrK_1H_eOF8KAaMdA,9
|
|
11
|
+
goldhand-17.2.dist-info/RECORD,,
|
goldhand-16.0.dist-info/RECORD
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
goldhand/__init__.py,sha256=2D68nqSZuv6sqyLJbOXnWIeeFpNgpYc90rHa2Fo70lk,152
|
|
2
|
-
goldhand/backtest.py,sha256=0AiN29QVco9sibOb_qffnCpg1Jp9OifCKtaGI0xSmTY,7683
|
|
3
|
-
goldhand/helpers.py,sha256=l9yn0kVTiwfUR8sI5nH1QFx6dYikaUQgRA227Ox7hs0,6130
|
|
4
|
-
goldhand/stocks.py,sha256=knYaAD0pkQepPfDMqHSXZvx4oWhVdts57WRaJQYqF18,13792
|
|
5
|
-
goldhand/strategy_goldhand_line.py,sha256=h2yAA4XGTxQ1qaN1EPVwCpKDEDiWVy2DMZ0ssFVXN88,12315
|
|
6
|
-
goldhand/strategy_rsi.py,sha256=yS6YZ1zeKURvy9wELWXX6clcr0AM-ptPgILgM8hXgPA,10485
|
|
7
|
-
goldhand/tw.py,sha256=4W8xmCbDkI4UGRVxgA7aNtyddXOLTprNgUihwSh0-lI,12557
|
|
8
|
-
goldhand-16.0.dist-info/METADATA,sha256=qzCP_PyE9qfKjVpuTB86C9XFbNEJCm9b_KrqDDMLSp0,5373
|
|
9
|
-
goldhand-16.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
10
|
-
goldhand-16.0.dist-info/top_level.txt,sha256=siEJ2_a_Fx_7hqRI4Ms6SzCelbXrK_1H_eOF8KAaMdA,9
|
|
11
|
-
goldhand-16.0.dist-info/RECORD,,
|
|
File without changes
|