goldhand 11.3__py3-none-any.whl → 12.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/__init__.py CHANGED
@@ -1,4 +1,5 @@
1
1
  from .tw import *
2
2
  from .stocks import *
3
3
  from .helpers import *
4
-
4
+ from .backtest import *
5
+ from .strategy_rsi import *
goldhand/backtest.py ADDED
@@ -0,0 +1,112 @@
1
+ from IPython.display import display
2
+ import numpy as np
3
+ import pandas as pd
4
+ import plotly.graph_objects as go
5
+ import plotly.express as px
6
+
7
+ class Backtest:
8
+ def __init__(self, data, strategy_function, **kwargs):
9
+ self.data = data
10
+ self.strategy_function = strategy_function
11
+ self.additional_params = kwargs
12
+ self.add_trades()
13
+ self.summary_of_trades()
14
+
15
+
16
+ def add_trades(self):
17
+ self.trades = self.strategy_function(self.data, **self.additional_params)
18
+
19
+
20
+ def summary_of_trades(self):
21
+ self.trades_summary = {
22
+ 'number_of_trades' : self.trades.shape[0],
23
+
24
+ 'average_res(%)' : round(((self.trades['result'].mean()-1)*100),2),
25
+ 'median_res(%)': round(((self.trades['result'].median()-1)*100),2),
26
+ 'cumulative_result': list(np.cumprod(self.trades['result'], axis=0))[-1],
27
+ 'trade_results': ' # '.join([ str(round(((x-1)*100),2)) for x in self.trades['result']]),
28
+
29
+ 'profitable_trade_results': ' # '.join([ str(round(((x-1)*100),2)) for x in self.trades['result'] if x>=1]),
30
+
31
+ 'profitable_trades_mean' : round((( np.mean([x for x in self.trades['result'] if x>=1]) -1)*100),2),
32
+ 'profitable_trades_median' : round((( np.median([x for x in self.trades['result'] if x>=1])-1)*100),2),
33
+
34
+ 'looser_trade_results': ' # '.join([ str(round(((x-1)*100),2)) for x in self.trades['result'] if x<1]),
35
+
36
+ 'looser_trades_mean' : round((( np.mean([x for x in self.trades['result'] if x<1])-1)*100),2),
37
+ 'looser_trades_median' : round((( np.median([x for x in self.trades['result'] if x<1])-1)*100),2),
38
+
39
+
40
+ 'average_trade_len(days)' : self.trades['days_in_trade'].mean(),
41
+ 'median_trade_len(days)' : self.trades['days_in_trade'].median(),
42
+
43
+ 'win_ratio(%)' : round(((sum(self.trades['result'] >1) / self.trades.shape[0])*100),2),
44
+ 'number_of_win_trades': sum(self.trades['result'] >1),
45
+ 'number_of_lost_trades': (self.trades.shape[0] - sum(self.trades['result'] >1)),
46
+
47
+ 'max_gain(%)' : round(((self.trades['result'].max()-1)*100),2),
48
+ 'max_lost(%)' : round(((self.trades['result'].min()-1)*100),2),
49
+
50
+ 'first_trade_buy' : min(self.trades['buy_date'])
51
+
52
+ }
53
+ self.trades_summary.update(self.additional_params)
54
+
55
+ def show_trades(self):
56
+ tdf = self.data
57
+ fig = go.Figure(data=go.Ohlc(x=tdf['date'], open=tdf['open'], high=tdf['high'], low=tdf['low'],close=tdf['close']))
58
+ fig.add_trace( go.Scatter(x=tdf['date'], y=tdf['sma_50'], opacity =0.5, line=dict(color='lightblue', width = 2) , name = 'SMA 50') )
59
+ fig.add_trace( go.Scatter(x=tdf['date'], y=tdf['sma_200'], opacity =0.7, line=dict(color='red', width = 2.5) , name = 'SMA 200') )
60
+ fig.update_layout(showlegend=False, plot_bgcolor='white', height=800, title= f"Closed trades" )
61
+ fig.update(layout_xaxis_rangeslider_visible=False)
62
+ fig.update_xaxes( mirror=True, ticks='outside', showline=True, linecolor='black', gridcolor='lightgrey')
63
+ fig.update_yaxes( mirror=True, ticks='outside', showline=True, linecolor='black', gridcolor='lightgrey')
64
+
65
+ for index, row in self.trades.iterrows():
66
+ buy_date= row['buy_date']
67
+ sell_date= row['sell_date']
68
+ buy_price = row['buy_price']
69
+ sell_price = row['sell_price']
70
+ trade_id = row['trade_id']
71
+ status = row['status']
72
+ triangle_color = 'green' if row['result'] >1 else 'red'
73
+
74
+ rise = (row['result'] -1)*100
75
+
76
+ if rise>100:
77
+ if status =='closed':
78
+ result = f'Up:{round(((rise+100)/100), 2)}x'
79
+ else:
80
+ result = f'Up:{round(((rise+100)/100), 2)}x <br> Still open'
81
+ else:
82
+ if status =='closed':
83
+ result = f"{round(((row['result']-1)*100),2) }%"
84
+ else:
85
+ result = f"{round(((row['result']-1)*100),2) }% <br> Still open"
86
+
87
+
88
+ # add buy
89
+ buy_point=(buy_date, buy_price)
90
+ triangle_trace = go.Scatter(x=[buy_point[0]], y=[buy_point[1]], mode='markers', marker=dict(symbol='triangle-up', size=16, color=triangle_color))
91
+ fig.add_trace(triangle_trace)
92
+ fig.add_annotation( x=buy_date, y=buy_price, text=f"Buy: ${round(buy_price, 2)}<br>#{trade_id}", hovertext = f"Buy: ${round(buy_price, 2)}<br>#{trade_id}", showarrow=True, align="center", bordercolor="#c7c7c7", font=dict(family="Courier New, monospace", size=12, color= triangle_color ), borderwidth=2, borderpad=4, bgcolor="#f4fdff", opacity=0.8, arrowhead=2, arrowsize=1, arrowwidth=1, ax=30,ay=30)
93
+
94
+ # add sell
95
+ sell_point=(sell_date, sell_price)
96
+ triangle_trace = go.Scatter(x=[sell_point[0]], y=[sell_point[1]], mode='markers', marker=dict(symbol='triangle-down', size=16, color=triangle_color))
97
+ fig.add_trace(triangle_trace)
98
+ fig.add_annotation( x=sell_date, y=sell_price, text=f"Sell: ${round(sell_price, 2)}<br>#{trade_id}, {result}", hovertext = f"Sell: ${round(sell_price, 2)}<br>#{trade_id}, {result}" ,showarrow=True, align="center", bordercolor="#c7c7c7", font=dict(family="Courier New, monospace", size=12, color= triangle_color ), borderwidth=2, borderpad=4, bgcolor="#f4fdff", opacity=0.8, arrowhead=2, arrowsize=1, arrowwidth=1, ax=-30,ay=-30)
99
+
100
+ # add reactangle
101
+ fig.add_shape(type="rect", x0=buy_point[0], y0=buy_point[1], x1=sell_point[0], y1=sell_point[1],line=dict(color= triangle_color ,width=2,),fillcolor="LightSkyBlue", opacity=0.3, label=dict( text=f"{result}<br>{row['days_in_trade']} days", textposition="bottom center", font=dict(size=13, color =triangle_color, family="Times New Roman")))
102
+
103
+ # set size
104
+ fig.update_layout(showlegend=False, plot_bgcolor='white', )
105
+
106
+ return(fig)
107
+
108
+
109
+ def summarize_strategy(self):
110
+ display(pd.DataFrame(self.trades_summary, index=['Strategy summary']).T)
111
+ self.show_trades().show()
112
+ display(self.trades)
goldhand/stocks.py CHANGED
@@ -30,6 +30,17 @@ class GoldHand:
30
30
  if self.ad_ticker:
31
31
  df['ticker'] = self.ticker
32
32
  return(df)
33
+
34
+ def smma(self, data, window, colname):
35
+ hl2 = data['hl2'].values
36
+ smma_values = [hl2[0]]
37
+
38
+ for i in range(1, len(hl2)):
39
+ smma_val = (smma_values[-1] * (window - 1) + hl2[i]) / window
40
+ smma_values.append(smma_val)
41
+
42
+ data[colname] = smma_values
43
+ return data
33
44
 
34
45
 
35
46
 
@@ -37,7 +48,8 @@ class GoldHand:
37
48
  # Download historical stock data for the last year
38
49
  self.df = self.get_olhc()
39
50
  self.df.columns = self.df.columns.str.lower()
40
-
51
+ self.df['hl2'] = (self.df['high'] + self.df['low'])/2
52
+
41
53
  # Rsi
42
54
  self.df['rsi'] = ta.rsi(self.df['close'], 14)
43
55
 
@@ -148,7 +160,7 @@ class GoldHand:
148
160
  if direction == 'minimum':
149
161
  fig.add_annotation( x=tdate, y=min_price, text=local_text, showarrow=True, align="center", bordercolor="#c7c7c7", font=dict(family="Courier New, monospace", size=16, color="red" ), borderwidth=2, borderpad=4, bgcolor="#f4fdff", opacity=0.8, arrowhead=2, arrowsize=1, arrowwidth=1, ax=45,ay=45)
150
162
 
151
- fig.update_layout(showlegend=False, plot_bgcolor='white', height=plot_height, title= plot_title)
163
+ fig.update_layout(showlegend=False, plot_bgcolor='white', height=plot_height, title= plot_title)
152
164
 
153
165
  fig.update_xaxes( mirror=True, ticks='outside', showline=True, linecolor='black', gridcolor='lightgrey' )
154
166
  fig.update_yaxes( mirror=True, ticks='outside', showline=True, linecolor='black', gridcolor='lightgrey')
@@ -157,7 +169,62 @@ class GoldHand:
157
169
  fig.add_trace( go.Scatter(x=tdf['date'], y=tdf['sma_200'], opacity =0.7, line=dict(color='red', width = 2.5) , name = 'SMA 200') )
158
170
  return(fig)
159
171
 
172
+ def plot_goldhand_line(self, plot_title, plot_height=900):
173
+
174
+ data = self.df.copy()
175
+ # Apply SMMA to the dataframe
176
+ data = self.smma(data, 15, 'v1')
177
+ data = self.smma(data, 19, 'v2')
178
+ data = self.smma(data, 25, 'v3')
179
+ data = self.smma(data, 29, 'v4')
180
+
181
+ data['color'] = 'grey' # Set default color to grey
182
+
183
+ # Update color based on conditions
184
+ data.loc[(data['v4'] < data['v3']) & (data['v3'] < data['v2']) & (data['v2'] < data['v1']), 'color'] = 'gold'
185
+ data.loc[(data['v1'] < data['v2']) & (data['v2'] < data['v3']) & (data['v3'] < data['v4']), 'color'] = 'blue'
186
+
187
+ # Identify rows where color changes compared to the previous row
188
+ data['color_change'] = data['color'] != data['color'].shift(1)
189
+
190
+ # Create a 'group' column and increase the value only when there's a color change
191
+ data['group'] = (data['color_change']).cumsum()
192
+
193
+ tdf = data.tail(800)
194
+
195
+ fig = go.Figure(data=go.Ohlc(x=tdf['date'], open=tdf['open'], high=tdf['high'], low=tdf['low'],close=tdf['close']))
196
+
197
+ fig.update_xaxes( mirror=True, ticks='outside', showline=True, linecolor='black', gridcolor='lightgrey' )
198
+ fig.update_yaxes( mirror=True, ticks='outside', showline=True, linecolor='black', gridcolor='lightgrey')
199
+ fig.update(layout_xaxis_rangeslider_visible=False)
200
+
201
+ for group_id in tdf['group'].unique():
202
+ if group_id ==tdf['group'].unique().max():
203
+ indices = tdf[tdf['group'] == group_id].index.to_list()
204
+ else:
205
+ indices = tdf[tdf['group'] == group_id].index.to_list()
206
+ indices.append(indices[-1]+1)
207
+
208
+
209
+ group_df = tdf.loc[indices]
210
+
211
+ group_color = group_df['color'].iloc[0]
212
+ color_dict = {'gold' : 'rgba(255, 215, 0, 0.4)' , 'grey' : 'rgba(128, 128 ,128, 0.4)' , 'blue' : 'rgba(0, 0, 255, 0.4)' }
160
213
 
214
+ # Create v1 and v4 traces
215
+ trace_v1 = go.Scatter(x=group_df['date'], y=group_df['v1'], mode='lines', name='v1', line=dict(color=color_dict[group_color]) )
216
+ trace_v4 = go.Scatter(x=group_df['date'], y=group_df['v4'], mode='lines', name='v4', line=dict(color=color_dict[group_color]), fill='tonexty', fillcolor =color_dict[group_color])
217
+
218
+ # Add candlestick trace and additional lines to the figure
219
+ fig.add_trace(trace_v1)
220
+ fig.add_trace(trace_v4)
221
+
222
+ fig.update_layout(showlegend=False, plot_bgcolor='white', height=plot_height, title= plot_title)
223
+ return(fig)
224
+
225
+
226
+
227
+
161
228
  # https://stackoverflow.com/questions/71411995/pandas-plotly-secondary-graph-needs-to-be-to-rsi
162
229
 
163
230
  #https://wire.insiderfinance.io/plot-candlestick-rsi-bollinger-bands-and-macd-charts-using-yfinance-python-api-1c2cb182d147
@@ -0,0 +1,166 @@
1
+ from IPython.display import display
2
+ import numpy as np
3
+ import pandas as pd
4
+ import plotly.graph_objects as go
5
+ from plotly.subplots import make_subplots
6
+ import plotly.express as px
7
+ from goldhand import *
8
+
9
+
10
+ def rsi_strategy(data, buy_threshold = 30, sell_threshold = 70):
11
+
12
+ in_trade = False # Flag to track if already in a trade
13
+ trade_id = 1
14
+ all_trades = []
15
+
16
+ temp_trade = {}
17
+
18
+ for i in range(1, len(data)):
19
+ # Check if not already in a trade
20
+ if not in_trade:
21
+ # Generate buy signal
22
+ if data['rsi'][i] < buy_threshold:
23
+
24
+ temp_trade['buy_price'] = data['close'][i]
25
+ temp_trade['trade_id'] = trade_id
26
+ temp_trade['status'] = 'open'
27
+ temp_trade.update(dict(data.iloc[i].add_prefix('buy_')))
28
+ in_trade = True # Set flag to indicate in a trade
29
+ else:
30
+ # Generate sell signal
31
+ if data['rsi'][i] > sell_threshold:
32
+
33
+ temp_trade['sell_price'] = data['close'][i]
34
+ temp_trade['trade_id'] = trade_id
35
+ temp_trade['status'] = 'closed'
36
+
37
+ temp_trade.update(dict(data.iloc[i].add_prefix('sell_')))
38
+
39
+ # calculate results
40
+ temp_trade['result'] = temp_trade['sell_price'] / temp_trade['buy_price']
41
+ temp_trade['days_in_trade'] = (temp_trade['sell_date'] - temp_trade['buy_date']).days
42
+
43
+
44
+
45
+ in_trade = False # Reset flag to indicate not in a trade
46
+ trade_id +=1
47
+ all_trades.append(temp_trade)
48
+ temp_trade = {}
49
+ if temp_trade:
50
+ temp_trade['sell_price'] = data['close'][i]
51
+ temp_trade['trade_id'] = trade_id
52
+ temp_trade['sell_date'] = data['date'][i]
53
+
54
+ temp_trade['result'] = temp_trade['sell_price'] / temp_trade['buy_price']
55
+ temp_trade['days_in_trade'] = (temp_trade['sell_date'] - temp_trade['buy_date']).days
56
+ all_trades.append(temp_trade)
57
+
58
+ res_df = pd.DataFrame(all_trades)
59
+ # change orders
60
+
61
+ all_col = res_df.columns.tolist()
62
+ first = ['result', 'buy_price', 'sell_price', 'buy_date', 'sell_date', 'days_in_trade']
63
+ first.extend([x for x in all_col if x not in first])
64
+ res_df = res_df[first]
65
+ return(res_df)
66
+
67
+
68
+
69
+ def show_indicator_rsi_strategy(ticker, buy_threshold = 30, sell_threshold = 70):
70
+
71
+ tdf = GoldHand(ticker).df
72
+ backtest = Backtest( tdf, rsi_strategy, buy_threshold=buy_threshold, sell_threshold=sell_threshold)
73
+ trades =backtest.trades
74
+
75
+ # Create subplots with shared x-axis and custom heights
76
+ fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1, subplot_titles=["Price Chart", "RSI"], row_heights=[0.7, 0.3])
77
+
78
+ # Add OHLC candlestick chart
79
+ fig.add_trace(go.Ohlc(x=tdf['date'], open=tdf['open'], high=tdf['high'], low=tdf['low'], close=tdf['close']), row=1, col=1)
80
+
81
+ # Add SMA lines
82
+ fig.add_trace(go.Scatter(x=tdf['date'], y=tdf['sma_50'], opacity=0.5, line=dict(color='lightblue', width=2), name='SMA 50'), row=1, col=1)
83
+ fig.add_trace(go.Scatter(x=tdf['date'], y=tdf['sma_200'], opacity=0.7, line=dict(color='red', width=2.5), name='SMA 200'), row=1, col=1)
84
+
85
+ # Add trade points and annotations
86
+ for index, row in trades.iterrows():
87
+ buy_date = row['buy_date']
88
+ sell_date = row['sell_date']
89
+ buy_price = row['buy_price']
90
+ sell_price = row['sell_price']
91
+ trade_id = row['trade_id']
92
+ status = row['status']
93
+ triangle_color = 'green' if row['result'] > 1 else 'red'
94
+
95
+ rise = (row['result'] - 1) * 100
96
+
97
+ if rise > 100:
98
+ if status == 'closed':
99
+ result = f'Up:{round(((rise + 100) / 100), 2)}x'
100
+ else:
101
+ result = f'Up:{round(((rise + 100) / 100), 2)}x <br> Still open'
102
+ else:
103
+ if status == 'closed':
104
+ result = f"{round(((row['result'] - 1) * 100), 2)}%"
105
+ else:
106
+ result = f"{round(((row['result'] - 1) * 100), 2)}% <br> Still open"
107
+
108
+ # add buy
109
+ buy_point = (buy_date, buy_price)
110
+ triangle_trace = go.Scatter(x=[buy_point[0]], y=[buy_point[1]], mode='markers',
111
+ marker=dict(symbol='triangle-up', size=16, color=triangle_color))
112
+ fig.add_trace(triangle_trace)
113
+ fig.add_annotation(x=buy_date, y=buy_price, text=f"Buy: ${round(buy_price, 2)}<br>#{trade_id}",
114
+ showarrow=True, align="center", bordercolor="#c7c7c7",
115
+ font=dict(family="Courier New, monospace", size=12, color=triangle_color),
116
+ borderwidth=2, borderpad=4, bgcolor="#f4fdff", opacity=0.8,
117
+ arrowhead=2, arrowsize=1, arrowwidth=1, ax=30, ay=30,
118
+ hovertext= f"Buy: ${round(buy_price, 2)}")
119
+
120
+ # add sell
121
+ sell_point = (sell_date, sell_price)
122
+ triangle_trace = go.Scatter(x=[sell_point[0]], y=[sell_point[1]], mode='markers',
123
+ marker=dict(symbol='triangle-down', size=16, color=triangle_color))
124
+ fig.add_trace(triangle_trace)
125
+ fig.add_annotation(x=sell_date, y=sell_price,
126
+ text=f"Sell: ${round(sell_price, 2)}<br>#{trade_id}, {result}",
127
+ showarrow=True, align="center", bordercolor="#c7c7c7",
128
+ font=dict(family="Courier New, monospace", size=12, color=triangle_color),
129
+ borderwidth=2, borderpad=4, bgcolor="#f4fdff", opacity=0.8,
130
+ arrowhead=2, arrowsize=1, arrowwidth=1, ax=-30, ay=-30,
131
+ hovertext = f"Sell: ${round(sell_price, 2)}<br>#{trade_id}, {result}")
132
+
133
+ # add rectangle
134
+ fig.add_shape(type="rect", x0=buy_point[0], y0=buy_point[1], x1=sell_point[0], y1=sell_point[1],
135
+ line=dict(color=triangle_color, width=2,), fillcolor="LightSkyBlue", opacity=0.3,
136
+ label=dict(text=f"{result}<br>{row['days_in_trade']} days",
137
+ textposition="bottom center",
138
+ font=dict(size=13, color=triangle_color, family="Times New Roman")))
139
+
140
+ # Update layout
141
+ fig.update_layout(showlegend=False, plot_bgcolor='white', height=800, title=f"Closed trades")
142
+ fig.update(layout_xaxis_rangeslider_visible=False)
143
+
144
+ # Update x-axes and y-axes for the main chart
145
+ fig.update_xaxes(mirror=True, ticks='outside', showline=True, linecolor='black', gridcolor='lightgrey', row=1, col=1)
146
+ fig.update_yaxes(mirror=True, ticks='outside', showline=True, linecolor='black', gridcolor='lightgrey', row=1, col=1)
147
+
148
+ # Update x-axes and y-axes for the RSI subplot
149
+ fig.update_xaxes(mirror=True, ticks='outside', showline=True, linecolor='black', gridcolor='lightgrey', row=2, col=1)
150
+ fig.update_yaxes(mirror=True, ticks='outside', showline=True, linecolor='black', gridcolor='lightgrey', row=2, col=1)
151
+
152
+
153
+
154
+
155
+ # Add RSI line
156
+ fig.add_trace(go.Scatter(x=tdf['date'], y=tdf['rsi'], line=dict(color='green', width=2), name='RSI'), row=2, col=1)
157
+ fig.add_shape(type="line", x0=tdf['date'].min(), x1=tdf['date'].max(), y0=buy_threshold, y1=buy_threshold, line=dict(color="black", width=2, dash="dash"), row=2, col=1)
158
+ fig.add_shape(type="line", x0=tdf['date'].min(), x1=tdf['date'].max(), y0=sell_threshold, y1=sell_threshold, line=dict(color="black", width=2, dash="dash"), row=2, col=1)
159
+
160
+
161
+ # Show the plot
162
+ fig.show()
163
+
164
+
165
+ # Test
166
+ # show_indicator_rsi_strategy('TSLA', 30,80)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: goldhand
3
- Version: 11.3
3
+ Version: 12.7
4
4
  Summary: A package working with financial data
5
5
  Home-page: https://github.com/misrori/goldhand
6
6
  Author: Mihaly
@@ -0,0 +1,10 @@
1
+ goldhand/__init__.py,sha256=PYVuqK8lz7FmiWuiBngkqB1SBTUxA002In9d4z1OESA,115
2
+ goldhand/backtest.py,sha256=3TTN98Yt_CIgCdt3vSLx-fmDieJZvWr2K_HvFAqgPJg,6124
3
+ goldhand/helpers.py,sha256=l9yn0kVTiwfUR8sI5nH1QFx6dYikaUQgRA227Ox7hs0,6130
4
+ goldhand/stocks.py,sha256=0MnjAex2A2c06JHinToKHBAvUJvYtDFXxtGudqBux6o,10521
5
+ goldhand/strategy_rsi.py,sha256=X38rjkjcph_D7U1CSh8Ismc8CFwhfr3rTWc7VinLIv8,7567
6
+ goldhand/tw.py,sha256=K8MwMDkW5JtBFBG0qcPzj8OVx2OhDjrOH2UGo6nwtSs,8375
7
+ goldhand-12.7.dist-info/METADATA,sha256=RYqbk7_AKvGicD-vqX6GycP9SWQ2C6PJZbyhmJDO4Mo,1952
8
+ goldhand-12.7.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
9
+ goldhand-12.7.dist-info/top_level.txt,sha256=siEJ2_a_Fx_7hqRI4Ms6SzCelbXrK_1H_eOF8KAaMdA,9
10
+ goldhand-12.7.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- goldhand/__init__.py,sha256=ihEkhO-z6MG_h27u4Mf6dAldHfhFpz55Zc3b8l96baE,64
2
- goldhand/helpers.py,sha256=l9yn0kVTiwfUR8sI5nH1QFx6dYikaUQgRA227Ox7hs0,6130
3
- goldhand/stocks.py,sha256=O3h0ifn_bIwTfGOK9PpOOIlqjsYZHRRhG9THqUzW5I0,7547
4
- goldhand/tw.py,sha256=K8MwMDkW5JtBFBG0qcPzj8OVx2OhDjrOH2UGo6nwtSs,8375
5
- goldhand-11.3.dist-info/METADATA,sha256=Zfr9ei3Tthr9FvilaMTFQ4CySHFVx34K0RcWt1mTBJw,1952
6
- goldhand-11.3.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
7
- goldhand-11.3.dist-info/top_level.txt,sha256=siEJ2_a_Fx_7hqRI4Ms6SzCelbXrK_1H_eOF8KAaMdA,9
8
- goldhand-11.3.dist-info/RECORD,,