goldhand 15.4__py3-none-any.whl → 15.7__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 CHANGED
@@ -6,6 +6,15 @@ import plotly.express as px
6
6
 
7
7
  class Backtest:
8
8
  def __init__(self, data, strategy_function, plot_title='', **kwargs):
9
+ """
10
+ Backtest class to test strategies on historical data to see how they would have performed.
11
+
12
+ Parameters:
13
+ - data: pandas DataFrame with historical data
14
+ - strategy_function: function that takes in the data and returns a DataFrame of trades
15
+ - plot_title: title for the plot
16
+ - kwargs: additional parameters to be passed to the strategy function
17
+ """
9
18
  self.data = data
10
19
  self.plot_title = plot_title
11
20
  self.strategy_function = strategy_function
@@ -15,6 +24,9 @@ class Backtest:
15
24
 
16
25
 
17
26
  def add_trades(self):
27
+ """
28
+ Calculate the trades using the strategy function and the data provided
29
+ """
18
30
  self.trades = self.strategy_function(self.data, **self.additional_params)
19
31
  self.trades['ticker'] = self.data['ticker'].iloc[0]
20
32
 
@@ -26,6 +38,9 @@ class Backtest:
26
38
 
27
39
 
28
40
  def summary_of_trades(self):
41
+ """
42
+ Calculate the summary of the trades
43
+ """
29
44
  self.trades_summary = {
30
45
  'ticker' : self.data['ticker'].iloc[0],
31
46
  'number_of_trades' : self.trades.shape[0],
@@ -57,12 +72,20 @@ class Backtest:
57
72
  'max_gain(%)' : round(((self.trades['result'].max()-1)*100),2),
58
73
  'max_lost(%)' : round(((self.trades['result'].min()-1)*100),2),
59
74
 
60
- 'first_trade_buy' : min(self.trades['buy_date'])
75
+ 'first_trade_buy' : min(self.trades['buy_date']),
76
+ 'first_close_price' : self.data['close'].iloc[0],
77
+ 'first_date' : self.data['date'].iloc[0],
78
+ 'last_price' : self.data['close'].iloc[-1],
79
+ 'hold_result' : round(((self.data['close'].iloc[-1] / self.data['close'].iloc[0])-1)*100,2)
80
+
61
81
 
62
82
  }
63
83
  self.trades_summary.update(self.additional_params)
64
84
 
65
85
  def show_trades(self):
86
+ """
87
+ Plot the trades of the strategy on the data provided
88
+ """
66
89
  tdf = self.data
67
90
  fig = go.Figure(data=go.Ohlc(x=tdf['date'], open=tdf['open'], high=tdf['high'], low=tdf['low'],close=tdf['close']))
68
91
  fig.add_trace( go.Scatter(x=tdf['date'], y=tdf['sma_50'], opacity =0.5, line=dict(color='lightblue', width = 2) , name = 'SMA 50') )
@@ -116,6 +139,12 @@ class Backtest:
116
139
 
117
140
 
118
141
  def summarize_strategy(self):
142
+ """
143
+ Display the summary of the strategy:
144
+ - Summary of trades
145
+ - Trades in interactive plot
146
+ - Trades in DataFrame
147
+ """
119
148
  display(pd.DataFrame(self.trades_summary, index=['Strategy summary']).T )
120
149
  self.show_trades().show()
121
150
  display(self.trades)
goldhand/stocks.py CHANGED
@@ -11,6 +11,15 @@ import cloudscraper
11
11
 
12
12
  class GoldHand:
13
13
  def __init__(self, ticker, ad_ticker=True, range='18y', interval='1d'):
14
+ """
15
+ GoldHand class to download and analyze stock data
16
+
17
+ Paramseters:
18
+ - ticker: str, ticker symbol of the stocks or crypto or ETF
19
+ - ad_ticker: bool, add ticker column to the DataFrame
20
+ - range: str, time range to download data for example 5y,1y, 1mo, 1d, 1h
21
+ - interval: str, interval to download data for example 1d, 1h, 5m
22
+ """
14
23
  self.scraper = cloudscraper.create_scraper()
15
24
  self.ad_ticker = ad_ticker
16
25
  self.range = range
@@ -22,7 +31,8 @@ class GoldHand:
22
31
 
23
32
  def get_olhc(self):
24
33
  """
25
- Download historical stock data for the last year
34
+ Download historical stock, crypto or ETF data from yahoo finance
35
+ API documentation location: https://cryptocointracker.com/yahoo-finance/yahoo-finance-api
26
36
  """
27
37
  #scraper = cloudscraper.create_scraper()
28
38
  response = self.scraper.get(f"https://query1.finance.yahoo.com/v8/finance/chart/{self.ticker}?interval={self.interval}&range={self.range}")
@@ -36,7 +46,13 @@ class GoldHand:
36
46
 
37
47
  def smma(self, data, window, colname):
38
48
  """
39
- Calculate Smoothed Moving Average (SMMA)
49
+ Calculate Smoothed Simple Moving Average (SMMA)
50
+ Parameters:
51
+ - data: Pandas DataFrame
52
+ - window: int, window size
53
+ - colname: str, name of the column to add to the DataFrame
54
+
55
+ Return: DataFrame with added column
40
56
  """
41
57
  hl2 = data['hl2'].values
42
58
  smma_values = [hl2[0]]
@@ -51,105 +67,119 @@ class GoldHand:
51
67
 
52
68
 
53
69
  def download_historical_data(self):
70
+ """
71
+ Download historical stock, crypto or ETF data
72
+ """
54
73
  # Download historical stock data for the last year
55
74
  self.df = self.get_olhc()
56
75
  self.df.columns = self.df.columns.str.lower()
57
76
  self.df['hl2'] = (self.df['high'] + self.df['low'])/2
58
77
 
59
- # Rsi
60
- self.df['rsi'] = ta.rsi(self.df['close'], 14)
61
-
62
- # SMAS
63
- self.df['sma_50']= ta.sma(self.df['close'], 50)
64
- self.df['diff_sma50'] = (self.df['close']/self.df['sma_50'] -1)*100
65
- self.df['sma_100']= ta.sma(self.df['close'], 100)
66
- self.df['diff_sma100'] = (self.df['close']/self.df['sma_100'] -1)*100
67
- self.df['sma_200']= ta.sma(self.df['close'], 200)
68
- self.df['diff_sma200'] = (self.df['close']/self.df['sma_200'] -1)*100
69
-
70
- #Bolinger bands
71
- bb = ta.bbands(self.df['close'])
72
- bb.columns = ['bb_lower', 'bb_mid', 'bb_upper', 'bandwidth', 'percent']
73
- self.df['bb_lower'] = bb['bb_lower']
74
- self.df['bb_upper'] = bb['bb_upper']
75
- self.df['diff_upper_bb'] = (self.df['bb_upper']/self.df['close'] -1)*100
76
- self.df['diff_lower_bb'] = (self.df['bb_lower']/self.df['close'] -1)*100
77
-
78
- #local min maxs
79
- self.df['local'] = ''
80
- self.df['local_text'] = ''
81
- max_ids = list(argrelextrema(self.df['high'].values, np.greater, order=30)[0])
82
- min_ids = list(argrelextrema(self.df['low'].values, np.less, order=30)[0])
83
- self.df.loc[min_ids, 'local'] = 'minimum'
84
- self.df.loc[max_ids, 'local'] = 'maximum'
85
-
86
-
87
- states = self.df[self.df['local']!='']['local'].index.to_list()
88
- problem = []
89
- problem_list = []
90
- for i in range(0, (len(states)-1) ):
91
-
92
- if (self.df.loc[states[i], 'local'] != self.df.loc[states[i+1], 'local']):
93
- if (len(problem)==0):
94
- continue
78
+ try:
79
+ # Rsi
80
+ self.df['rsi'] = ta.rsi(self.df['close'], 14)
81
+
82
+ # SMAS
83
+ self.df['sma_50']= ta.sma(self.df['close'], 50)
84
+ self.df['diff_sma50'] = (self.df['close']/self.df['sma_50'] -1)*100
85
+ self.df['sma_100']= ta.sma(self.df['close'], 100)
86
+ self.df['diff_sma100'] = (self.df['close']/self.df['sma_100'] -1)*100
87
+ self.df['sma_200']= ta.sma(self.df['close'], 200)
88
+ self.df['diff_sma200'] = (self.df['close']/self.df['sma_200'] -1)*100
89
+
90
+ #Bolinger bands
91
+ bb = ta.bbands(self.df['close'])
92
+ bb.columns = ['bb_lower', 'bb_mid', 'bb_upper', 'bandwidth', 'percent']
93
+ self.df['bb_lower'] = bb['bb_lower']
94
+ self.df['bb_upper'] = bb['bb_upper']
95
+ self.df['diff_upper_bb'] = (self.df['bb_upper']/self.df['close'] -1)*100
96
+ self.df['diff_lower_bb'] = (self.df['bb_lower']/self.df['close'] -1)*100
97
+
98
+ #local min maxs
99
+ self.df['local'] = ''
100
+ self.df['local_text'] = ''
101
+ max_ids = list(argrelextrema(self.df['high'].values, np.greater, order=30)[0])
102
+ min_ids = list(argrelextrema(self.df['low'].values, np.less, order=30)[0])
103
+ self.df.loc[min_ids, 'local'] = 'minimum'
104
+ self.df.loc[max_ids, 'local'] = 'maximum'
105
+
106
+
107
+ states = self.df[self.df['local']!='']['local'].index.to_list()
108
+ problem = []
109
+ for i in range(0, (len(states)-1) ):
110
+
111
+ if (self.df.loc[states[i], 'local'] != self.df.loc[states[i+1], 'local']):
112
+ if (len(problem)==0):
113
+ continue
114
+ else:
115
+ problem.append(states[i])
116
+ text = self.df.loc[states[i], 'local']
117
+ if(text=='minimum'):
118
+ real_min = self.df.loc[problem, 'low'].idxmin()
119
+ problem.remove(real_min)
120
+ self.df.loc[problem, 'local']=''
121
+ else:
122
+ real_max = self.df.loc[problem, 'high'].idxmax()
123
+ problem.remove(real_max)
124
+ self.df.loc[problem, 'local']=''
125
+
126
+ problem = []
95
127
  else:
96
128
  problem.append(states[i])
97
- text = self.df.loc[states[i], 'local']
98
- if(text=='minimum'):
99
- real_min = self.df.loc[problem, 'low'].idxmin()
100
- problem.remove(real_min)
101
- self.df.loc[problem, 'local']=''
102
- else:
103
- real_max = self.df.loc[problem, 'high'].idxmax()
104
- problem.remove(real_max)
105
- self.df.loc[problem, 'local']=''
106
-
107
- problem = []
108
- else:
109
- problem.append(states[i])
110
-
111
- states = self.df[self.df['local']!='']['local'].index.to_list()
112
129
 
113
- # if first is min ad the price
114
- if self.df.loc[states[0], 'local']== 'minimum':
115
- self.df.loc[states[0],'local_text'] = f"${round(self.df.loc[states[0], 'low'], 2)}"
116
- else:
117
- self.df.loc[states[0],'local_text'] = f"${round(self.df.loc[states[0], 'high'], 2)}"
130
+ states = self.df[self.df['local']!='']['local'].index.to_list()
118
131
 
119
- # add last fall if last local is max
120
- if list(self.df[self.df['local']!='']['local'])[-1]=='maximum':
121
- last_min_id = self.df.loc[self.df['low']==min(self.df['low'][-3:] )].index.to_list()[0]
122
- self.df.loc[last_min_id , 'local'] = 'minimum'
123
-
124
- states = self.df[self.df['local']!='']['local'].index.to_list()
125
-
126
-
127
- for i in range(1,len(states)):
128
- prev = self.df.loc[states[i-1], 'local']
129
- current= self.df.loc[states[i], 'local']
130
- prev_high = self.df.loc[states[i-1], 'high']
131
- prev_low = self.df.loc[states[i-1], 'low']
132
- current_high = self.df.loc[states[i], 'high']
133
- current_low = self.df.loc[states[i], 'low']
134
- if current == 'maximum':
135
- # rise
136
- rise = (current_high/ prev_low -1)*100
137
- if rise>100:
138
- self.df.loc[states[i], 'local_text'] = f'🚀🌌{round(((rise+100)/100), 2)}x<br>${round(current_high, 2)}'
139
- else:
140
- self.df.loc[states[i], 'local_text'] = f'🚀{round(rise, 2)}%<br>${round(current_high, 2)}'
132
+ # if first is min ad the price
133
+ if self.df.loc[states[0], 'local']== 'minimum':
134
+ self.df.loc[states[0],'local_text'] = f"${round(self.df.loc[states[0], 'low'], 2)}"
141
135
  else:
142
- fall = round((1-(current_low / prev_high))*100, 2)
143
- if fall < 30:
144
- temj = '💸'
145
- elif fall < 50:
146
- temj = '💸'
136
+ self.df.loc[states[0],'local_text'] = f"${round(self.df.loc[states[0], 'high'], 2)}"
137
+
138
+ # add last fall if last local is max
139
+ if list(self.df[self.df['local']!='']['local'])[-1]=='maximum':
140
+ last_min_id = self.df.loc[self.df['low']==min(self.df['low'][-3:] )].index.to_list()[0]
141
+ self.df.loc[last_min_id , 'local'] = 'minimum'
142
+
143
+ states = self.df[self.df['local']!='']['local'].index.to_list()
144
+
145
+
146
+ for i in range(1,len(states)):
147
+ prev = self.df.loc[states[i-1], 'local']
148
+ current= self.df.loc[states[i], 'local']
149
+ prev_high = self.df.loc[states[i-1], 'high']
150
+ prev_low = self.df.loc[states[i-1], 'low']
151
+ current_high = self.df.loc[states[i], 'high']
152
+ current_low = self.df.loc[states[i], 'low']
153
+ if current == 'maximum':
154
+ # rise
155
+ rise = (current_high/ prev_low -1)*100
156
+ if rise>100:
157
+ self.df.loc[states[i], 'local_text'] = f'🚀🌌{round(((rise+100)/100), 2)}x<br>${round(current_high, 2)}'
158
+ else:
159
+ self.df.loc[states[i], 'local_text'] = f'🚀{round(rise, 2)}%<br>${round(current_high, 2)}'
147
160
  else:
148
- temj = '😭💔'
149
- self.df.loc[states[i], 'local_text'] = f'{temj}{fall}%<br>${round(current_low, 2)}'
150
- self.df.reset_index(inplace=True, drop=True)
161
+ fall = round((1-(current_low / prev_high))*100, 2)
162
+ if fall < 30:
163
+ temj = '💸'
164
+ elif fall < 50:
165
+ temj = '💸'
166
+ else:
167
+ temj = '😭💔'
168
+ self.df.loc[states[i], 'local_text'] = f'{temj}{fall}%<br>${round(current_low, 2)}'
169
+ self.df.reset_index(inplace=True, drop=True)
170
+ except:
171
+ pass
151
172
 
152
173
  def plotly_last_year(self, plot_title, plot_height=900, ndays=500, ad_local_min_max=True):
174
+ """
175
+ Plot last year interactive plot of a stock analyzing the local minimums and maximums
176
+ Parameters:
177
+ - plot_title: str, title of the plot
178
+ - plot_height: int, height of the plot
179
+ - ndays: int, number of days to plot
180
+ - ad_local_min_max: bool, add local min max to the plot
181
+ Return: plotly figure
182
+ """
153
183
  tdf = self.df.tail(ndays)
154
184
 
155
185
  fig = go.Figure(data=go.Ohlc(x=tdf['date'], open=tdf['open'], high=tdf['high'], low=tdf['low'],close=tdf['close']))
@@ -176,6 +206,15 @@ class GoldHand:
176
206
  return(fig)
177
207
 
178
208
  def plot_goldhand_line(self, plot_title, plot_height=900, ndays=800, ad_local_min_max=True):
209
+ """
210
+ Plot last year interactive plot of a stock analyzing the local minimums and maximums using the GoldHandLine indicator
211
+ Parameters:
212
+ - plot_title: str, title of the plot
213
+ - plot_height: int, height of the plot
214
+ - ndays: int, number of days to plot
215
+ - ad_local_min_max: bool, add local min max to the plot
216
+ Return: plotly figure
217
+ """
179
218
 
180
219
  data = self.df.copy()
181
220
  # Apply SMMA to the dataframe
@@ -10,13 +10,14 @@ from goldhand import *
10
10
 
11
11
  def goldhand_line_strategy(data, buy_at='gold', sell_at='grey'):
12
12
  """
13
- This function implements the goldhand line strategy.
13
+ This function implements the GoldHandLine strategy.
14
+
14
15
  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.
16
+ - data (pandas DataFrame) : The DataFrame containing the data.
17
+ - buy_at (str): The color of the line to buy at. Default is 'gold'.
18
+ - sell_at (str): The color of the line to sell at. Default is 'grey'.
19
+
20
+ Returns: The trades of the GoldHandLine strategy.
20
21
  """
21
22
 
22
23
  data['hl2'] = (data['high'] + data['low'])/2
@@ -112,15 +113,18 @@ def goldhand_line_strategy(data, buy_at='gold', sell_at='grey'):
112
113
 
113
114
  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
  """
115
- This function shows the goldhand line strategy on a plotly candlestick chart.
116
+ This function shows the GoldHandLine strategy on a plotly chart including the price, trades, strategy summary and GoldHandLine indicator.
117
+
116
118
  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.
119
+ - ticker (str): The ticker of the stock or crypto or ETF.
120
+ - plot_title (str): The title of the plot.
121
+ - buy_at (str): The color of the line to buy at. Default is 'gold'.
122
+ - sell_at (str): The color of the line to sell at. Default is 'grey'.
123
+ - ndays (int): The number of days to show. If 0, all data will be shown.
124
+ - plot_height (int): The height of the plot.
125
+ - add_strategy_summary (bool): If True, the strategy summary will be added to the plot.
126
+
127
+ Returns: The plot including the price, trades, strategy summary and GoldHandLine indicator.
124
128
  """
125
129
 
126
130
  data = GoldHand(ticker).df
@@ -159,10 +163,10 @@ def show_indicator_goldhand_line_strategy(ticker, plot_title = '', buy_at='gold'
159
163
  # Create a 'group' column and increase the value only when there's a color change
160
164
  data['group'] = (data['color_change']).cumsum()
161
165
 
162
- ##### data prepar end
166
+ ##### data preparation end
163
167
 
164
168
  ##### backtest
165
- backtest = Backtest( data, goldhand_line_strategy, plot_title =plot_title, buy_at='gold', sell_at='grey')
169
+ backtest = Backtest( data, goldhand_line_strategy, plot_title =plot_title, buy_at= buy_at, sell_at=sell_at)
166
170
  trades =backtest.trades
167
171
 
168
172
  if ndays!=0:
goldhand/strategy_rsi.py CHANGED
@@ -9,6 +9,14 @@ from goldhand import *
9
9
 
10
10
 
11
11
  def rsi_strategy(data, buy_threshold = 30, sell_threshold = 70):
12
+ """
13
+ RSI strategy for backtesting with Backtest class
14
+
15
+ Parameters:
16
+ - data: pandas DataFrame with columns: date, open, high, low, close, volume and rsi
17
+ - buy_threshold: int, default 30, buy when RSI is below this value
18
+ - sell_threshold: int, default 70, sell when RSI is above this value
19
+ """
12
20
 
13
21
  in_trade = False # Flag to track if already in a trade
14
22
  trade_id = 1
@@ -78,6 +86,17 @@ def rsi_strategy(data, buy_threshold = 30, sell_threshold = 70):
78
86
 
79
87
 
80
88
  def show_indicator_rsi_strategy(ticker, buy_threshold = 30, sell_threshold = 70, plot_title = '', ndays=0, plot_height=1000, add_strategy_summary = True):
89
+ """
90
+ Show RSI strategy result in one plot: candlestick chart, SMA lines, trades, RSI indicator, summary of the strategy on the left side of the plot
91
+ Parameters:
92
+ - ticker: str, ticker symbol
93
+ - buy_threshold: int, default 30, buy when RSI is below this value
94
+ - sell_threshold: int, default 70, sell when RSI is above this value
95
+ - plot_title: str, default '', title of the plot
96
+ - ndays: int, default 0, number of days to show, if 0, show all data
97
+ - plot_height: int, default 1000, height of the plot
98
+ - add_strategy_summary: bool, default True, add strategy summary to the plot
99
+ """
81
100
 
82
101
  tdf = GoldHand(ticker).df
83
102
  backtest = Backtest( tdf, rsi_strategy, buy_threshold=buy_threshold, sell_threshold=sell_threshold)
goldhand/tw.py CHANGED
@@ -9,13 +9,22 @@ import json
9
9
 
10
10
  class Tw:
11
11
  def __init__(self):
12
+ """
13
+ Get all stock, crypto and ETF data from TradingView
14
+ """
12
15
  self.stock = pd.DataFrame()
13
16
  self.crypto = pd.DataFrame()
17
+ self.etf = pd.DataFrame()
14
18
 
15
19
  self.get_all_stock()
16
20
  self.get_all_crypto()
21
+ self.get_all_etf()
17
22
 
18
23
  def get_all_stock(self):
24
+ """
25
+ Get all stocks data from TradingView
26
+ """
27
+
19
28
  data_query = '{"filter":[{"left":"type","operation":"in_range","right":["stock","dr","fund"]},{"left":"subtype","operation":"in_range","right":["common","foreign-issuer","","etf","etf,odd","etf,otc","etf,cfd"]},{"left":"exchange","operation":"in_range","right":["AMEX","NASDAQ","NYSE"]},{"left":"is_primary","operation":"equal","right":true},{"left":"active_symbol","operation":"equal","right":true}],"options":{"lang":"en"},"markets":["america"],"symbols":{"query":{"types":[]},"tickers":[]},"columns":["logoid","name","close","change","change_abs","Recommend.All","volume","Value.Traded","market_cap_basic","price_earnings_ttm","earnings_per_share_basic_ttm","number_of_employees","sector","High.3M","Low.3M","Perf.3M","Perf.5Y","High.1M","Low.1M","High.6M","Low.6M","Perf.6M","beta_1_year","price_52_week_high","price_52_week_low","High.All","Low.All","BB.lower","BB.upper","change|1M","change_abs|1M","change|1W","change_abs|1W","change|240","country","EMA50","EMA100","EMA200","MACD.macd","MACD.signal","Mom","Perf.1M","RSI7","SMA50","SMA100","SMA200","Stoch.RSI.K","Stoch.RSI.D","Perf.W","Perf.Y","Perf.YTD","industry","Perf.All","description","type","subtype","update_mode","pricescale","minmov","fractional","minmove2","Mom[1]","RSI7[1]","Rec.Stoch.RSI","currency","fundamental_currency_code"],"sort":{"sortBy":"market_cap_basic","sortOrder":"desc"},"range":[0,8000]}'
20
29
  response = requests.post('https://scanner.tradingview.com/america/scan', data=data_query)
21
30
  data = response.json()
@@ -26,6 +35,10 @@ class Tw:
26
35
 
27
36
 
28
37
  def get_all_crypto(self):
38
+ """
39
+ Get all crypto data from TradingView
40
+ """
41
+
29
42
  data_query = '{"columns":["base_currency","base_currency_desc","base_currency_logoid","update_mode","type","typespecs","exchange","crypto_total_rank","close","pricescale","minmov","fractional","minmove2","currency","24h_close_change|5","market_cap_calc","fundamental_currency_code","24h_vol_cmc","circulating_supply","crypto_common_categories","crypto_blockchain_ecosystems"],"ignore_unknown_fields":false,"options":{"lang":"en"},"range":[0,300],"sort":{"sortBy":"crypto_total_rank","sortOrder":"asc"},"markets":["coin"]}'
30
43
  response = requests.post('https://scanner.tradingview.com/coin/scan', data=data_query)
31
44
  data = response.json()
@@ -36,21 +49,53 @@ class Tw:
36
49
  self.crypto = self.crypto.loc[filter, ]
37
50
  self.crypto['ticker'] = self.crypto['base_currency'] + '-USD'
38
51
 
52
+ def get_all_etf(self):
53
+ """
54
+ Get all ETFs from TradingView
55
+ """
56
+ data_query = '{"columns":["name","description","logoid","update_mode","type","typespecs","close","pricescale","minmov","fractional","minmove2","currency","change","Value.Traded","relative_volume_10d_calc","aum","fundamental_currency_code","nav_total_return.5Y","expense_ratio","asset_class.tr","focus.tr","nav_discount_premium","category.tr","brand.tr","niche.tr"],"ignore_unknown_fields":false,"options":{"lang":"en"},"price_conversion":{"to_symbol":true},"range":[0,3000],"sort":{"sortBy":"aum","sortOrder":"desc"},"markets":["america"],"filter2":{"operator":"and","operands":[{"operation":{"operator":"or","operands":[{"operation":{"operator":"and","operands":[{"expression":{"left":"typespecs","operation":"has","right":["etn"]}}]}},{"operation":{"operator":"and","operands":[{"expression":{"left":"typespecs","operation":"has","right":["etf"]}}]}}]}}]}}'
57
+ response = requests.post('https://scanner.tradingview.com/america/scan', data=data_query)
58
+ data = response.json()
59
+ list_elements = list(map(lambda x:x['d'], data['data'] ))
60
+ self.etf = pd.DataFrame(list_elements)
61
+ self.etf.columns = json.loads(data_query)['columns']
62
+ self.etf = self.etf[self.etf['name'].str.contains('\\.')!=True]
63
+
64
+
65
+ def moneystring( self, money):
66
+ """
67
+ Convert money to string with unit
68
+ Parameters:
69
+ - money: money to convert
70
+ Return: string with unit
71
+ """
72
+
73
+ if money > 1_000_000_000_000:
74
+ money_str = f"{round(money / 1_000_000_000_000, 2)} Trillion"
75
+ elif money>1_000_000_000:
76
+ money_str = f"{round(money / 1_000_000_000, 2)} Billion"
77
+ else:
78
+ money_str = f"{round(money / 1_000_000, 2)} Million"
79
+ return money_str
80
+
39
81
 
40
82
  def get_one_stock_info(self, ticker):
83
+ """
84
+ Get info about one stock
85
+ Parameters:
86
+ - ticker: ticker of the stock
87
+ Return: type dictioanry
88
+ """
89
+
41
90
  ticker = ticker.upper()
42
91
  one_row = self.stock.loc[self.stock['name']==ticker,].iloc[0]
43
92
  tsec = self.stock.loc[self.stock['sector']==one_row['sector']].reset_index(drop=True)
44
93
  tind = self.stock.loc[self.stock['industry']== one_row['industry']].reset_index(drop=True)
45
- if one_row['market_cap_basic'] <100_000_000:
46
- market_cap = f"💲{round(one_row['market_cap_basic']/1_000_000, 2):,} Million"
47
- else:
48
- market_cap = f"💲{round(one_row['market_cap_basic']/1_000_000):,} Million"
49
94
  return({'ticker': one_row['name'],
50
95
  'price': one_row['close'],
51
96
  'market_cap': one_row['market_cap_basic'] ,
52
97
  'n_emp': one_row['number_of_employees'],
53
- 'market_cap_text': market_cap,
98
+ 'market_cap_text': self.moneystring(one_row['market_cap_basic']),
54
99
  'name': one_row['description'],
55
100
  'sector': one_row['sector'],
56
101
  'industry': one_row['industry'],
@@ -61,66 +106,104 @@ class Tw:
61
106
 
62
107
 
63
108
  def get_top_n_stocks_by_sector(self,percent=10):
64
- return(
65
- (
109
+ """
110
+ Get top n % stocks by sector
111
+ Parameters:
112
+ - percent: percent of stocks to return
113
+ Return: Pandas DataFrame
114
+ """
115
+
116
+ return (
66
117
  self.stock.groupby('sector')
67
118
  .apply(lambda x: x.nlargest(int(len(x) * round((percent/100),2) ), 'market_cap_basic'))
68
119
  .reset_index(drop=True)
69
- )
120
+
70
121
  )
71
-
122
+
72
123
 
73
124
  def get_plotly_title(self, ticker):
125
+ """
126
+ Get plotly title for stock or crypto
127
+ Parameters:
128
+ - ticker: ticker of the stock
129
+ Return: Summary of the stock or crypto to be used as plotly title
130
+ """
74
131
 
75
132
  if '-USD' in ticker:
133
+ # crypto
76
134
  coin = self.crypto.loc[self.crypto['ticker']==ticker].iloc[0]
77
- plotly_title = f"{coin['base_currency_desc']} ({coin['base_currency']})<br>💲{round(coin['market_cap_calc']/1_000_000):,} Million | {', '.join(coin['crypto_common_categories'])}"
135
+ plotly_title = f"{coin['base_currency_desc']} ({coin['base_currency']})<br>💲{self.moneystring(coin['market_cap_calc'])} | {', '.join(coin['crypto_common_categories'])}"
136
+
137
+ elif ticker in self.etf['name'].tolist() :
138
+ # ETF
139
+ t = self.etf.loc[self.etf['name']==ticker].iloc[0]
140
+ 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']}"
78
141
  else:
142
+ # stock
79
143
  t = self.get_one_stock_info(ticker)
80
- 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']}"
144
+ 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']}"
81
145
  return(plotly_title)
82
146
 
147
+
83
148
  def get_sec_plot(self, ticker):
149
+ """
150
+ Get plotly figure for a ticker showing the sector location of the stock
151
+ Parameters:
152
+ - ticker: ticker of the stock
153
+ Return: plotly figure showing the sector location of the stock
154
+ """
155
+
156
+ if ticker in self.etf['name'].tolist():
157
+ return f"{ticker} is ETF use get_etf_plot"
84
158
  row_df = self.stock.loc[self.stock['name']==ticker]
85
159
  row_df.rename(columns = {'description': 'Company'}, inplace=True)
86
160
  secdf = self.stock.loc[ (self.stock['sector'] ==row_df['sector'].iloc[0] ) ].reset_index(drop=True)
87
- if row_df['market_cap_basic'].iloc[0] <100_000_000:
88
- market_cap = f"💲{round(row_df['market_cap_basic'].iloc[0]/1_000_000, 2):,} Million"
89
- else:
90
- market_cap = f"💲{round(row_df['market_cap_basic'].iloc[0]/1_000_000):,} Million"
91
-
92
-
93
161
  secdf.rename(columns = {'description': 'Company'}, inplace=True)
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')
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')
98
-
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)
162
+ 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')
163
+ fig = px.bar(secdf, x='name', y='market_cap_basic', title = self.get_plotly_title(ticker), labels={'market_cap_basic':'Market Capitalization'}, text='Company')
164
+ fig.add_annotation( x=row_df['name'].iloc[0], y=row_df['market_cap_basic'].iloc[0], text= f"{self.moneystring(row_df['market_cap_basic'].iloc[0])}", 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)
100
165
  fig.update_layout(showlegend=False, plot_bgcolor='white', height=600)
101
166
  return (fig)
102
167
 
168
+
103
169
  def get_ind_plot(self, ticker):
170
+ """
171
+ Get plotly figure for a ticker showing the industry location of the stock
172
+ Parameters:
173
+ - ticker: ticker of the stock
174
+ Return: plotly figure showing the industry location of the stock
175
+ """
176
+
177
+ if ticker in self.etf['name'].tolist():
178
+ return f"{ticker} is ETF use get_etf_plot"
104
179
  row_df = self.stock.loc[self.stock['name']==ticker]
105
180
  inddf = self.stock.loc[ (self.stock['industry'] ==row_df['industry'].iloc[0] ) ].reset_index(drop=True)
106
181
  row_df.rename(columns = {'description': 'Company'}, inplace=True)
107
-
108
- if row_df['market_cap_basic'].iloc[0] <100_000_000:
109
- market_cap = f"💲{round(row_df['market_cap_basic'].iloc[0]/1_000_000, 2):,} Million"
110
- else:
111
- market_cap = f"💲{round(row_df['market_cap_basic'].iloc[0]/1_000_000):,} Million"
112
-
113
182
  inddf.rename(columns = {'description': 'Company'}, inplace=True)
114
-
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')
183
+ fig = px.bar(inddf, x='name', y='market_cap_basic', title = self.get_plotly_title(ticker), labels={'market_cap_basic':'Market Capitalization'}, text='Company')
184
+ fig.add_annotation( x=row_df['name'].iloc[0], y=row_df['market_cap_basic'].iloc[0], text= f"{self.moneystring(row_df['market_cap_basic'].iloc[0])}", 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)
185
+ fig.update_layout(showlegend=False, plot_bgcolor='white', height=600)
186
+ return (fig)
116
187
 
117
188
 
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)
189
+ def get_etf_plot(self, ticker):
190
+ """
191
+ Get plotly figure for a ETF showing the ETF location with the same focus
192
+ Parameters:
193
+ - ticker: ticker of the ETF
194
+ Return: plotly figure showing the ETF location with the same focus
195
+
196
+ """
197
+ row_df = self.etf.loc[self.etf['name']==ticker]
198
+ focdf = self.etf.loc[ (self.etf['focus.tr'] ==row_df['focus.tr'].iloc[0] ) ].reset_index(drop=True)
199
+ fig = px.bar(focdf, x='name', y='aum', title = self.get_plotly_title(ticker), labels={'aum':'Assets Under Management'}, text='description')
200
+ fig.add_annotation( x=row_df['name'].iloc[0], y=row_df['aum'].iloc[0], text= f"{self.moneystring(row_df['aum'].iloc[0])}", 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)
119
201
  fig.update_layout(showlegend=False, plot_bgcolor='white', height=600)
120
202
  return (fig)
121
203
 
122
204
 
123
205
 
206
+
124
207
  #tw = Tw()
125
208
  #print(tw.stock.head(1).T)
126
209
  #print(tw.crypto.head(1).T)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: goldhand
3
- Version: 15.4
3
+ Version: 15.7
4
4
  Summary: A package working with financial data
5
5
  Home-page: https://github.com/misrori/goldhand
6
6
  Author: Mihaly
@@ -25,7 +25,6 @@ pip install goldhand
25
25
  ```
26
26
 
27
27
 
28
-
29
28
  # TradingView
30
29
 
31
30
 
@@ -40,11 +39,15 @@ tw.stock
40
39
 
41
40
  # data frame of the top 300 crypto currency
42
41
  tw.crypto
42
+
43
+ # data frame of the top 3000 etf
44
+ tw.etf
45
+
43
46
  ```
44
47
 
45
48
  ```python
46
49
  # Get a plot of the stock to see the location in the sector
47
- tw.get_sec_plot('AMD')
50
+ tw.get_sec_plot('AMD').show()
48
51
 
49
52
  ```
50
53
  ![Sector plot](https://github.com/misrori/goldhand/blob/main/img/sec_plot.png?raw=true "Sector location of FDS")
@@ -52,7 +55,7 @@ tw.get_sec_plot('AMD')
52
55
 
53
56
  ```python
54
57
  # Get a plot of the stock to see the location in the industry
55
- tw.get_sec_plot('AMD')
58
+ tw.get_sec_plot('AMD').show()
56
59
 
57
60
  ```
58
61
  ![Sector plot](https://github.com/misrori/goldhand/blob/main/img/ind_plot.png?raw=true "Sector location of FDS")
@@ -0,0 +1,11 @@
1
+ goldhand/__init__.py,sha256=2D68nqSZuv6sqyLJbOXnWIeeFpNgpYc90rHa2Fo70lk,152
2
+ goldhand/backtest.py,sha256=dfrm2Mntp-qUCXsmayExuQgLur5U30QZ6wYJLt7Wq68,7576
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-15.7.dist-info/METADATA,sha256=4o42aSMO8TNT5AzuilA7sWAQ0SQFncDpSq6zpNUuiwI,2007
9
+ goldhand-15.7.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
10
+ goldhand-15.7.dist-info/top_level.txt,sha256=siEJ2_a_Fx_7hqRI4Ms6SzCelbXrK_1H_eOF8KAaMdA,9
11
+ goldhand-15.7.dist-info/RECORD,,
@@ -1,11 +0,0 @@
1
- goldhand/__init__.py,sha256=2D68nqSZuv6sqyLJbOXnWIeeFpNgpYc90rHa2Fo70lk,152
2
- goldhand/backtest.py,sha256=haK0c7wbUv02DUU5LcrvDSC1i0h1nDX7HHYzD9abhb8,6456
3
- goldhand/helpers.py,sha256=l9yn0kVTiwfUR8sI5nH1QFx6dYikaUQgRA227Ox7hs0,6130
4
- goldhand/stocks.py,sha256=rQmcBo6cwu8mXmVSqT9PJhHCHJ9X1laPwhqX5sDHS6E,11886
5
- goldhand/strategy_goldhand_line.py,sha256=TEb16PvaoX07bjtTRVMYlz2ilJ_YlQ2Q6_o-sAC60QQ,12056
6
- goldhand/strategy_rsi.py,sha256=JhmefDm-PXmIT2tQNeLFjaDb0SpR1yln33wuDPt1Zp4,9540
7
- goldhand/tw.py,sha256=Rv0oy9QjX3FC_7Rxiv_oUftQhkvrq65LUgbrhwXhWDE,8460
8
- goldhand-15.4.dist-info/METADATA,sha256=OAiDn38e4u0l9lorFyMv1yali-oDlvdXL1upFholHRE,1952
9
- goldhand-15.4.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
10
- goldhand-15.4.dist-info/top_level.txt,sha256=siEJ2_a_Fx_7hqRI4Ms6SzCelbXrK_1H_eOF8KAaMdA,9
11
- goldhand-15.4.dist-info/RECORD,,