azapyGUI 0.0.1__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.
Files changed (54) hide show
  1. azapyGUI/AppSettingsPage.py +213 -0
  2. azapyGUI/AppSettingsPageMisc.py +101 -0
  3. azapyGUI/AppSettingsWindow.py +52 -0
  4. azapyGUI/BacktestComputation.py +166 -0
  5. azapyGUI/BacktestEntryWindow.py +307 -0
  6. azapyGUI/BacktestMenuPortfolioWindow.py +20 -0
  7. azapyGUI/CloneMenuPortfolioWindow.py +93 -0
  8. azapyGUI/CrossHairBCursor.py +80 -0
  9. azapyGUI/DF_Window.py +63 -0
  10. azapyGUI/DF_table.py +282 -0
  11. azapyGUI/EditMenuPortfolioWindow.py +16 -0
  12. azapyGUI/EditPortfolioWindow.py +475 -0
  13. azapyGUI/EntryClonePortfolioWindow.py +35 -0
  14. azapyGUI/EntryNameWindow.py +55 -0
  15. azapyGUI/EntryRenamePortfolioWindow.py +33 -0
  16. azapyGUI/GetMktData.py +85 -0
  17. azapyGUI/MenuApp.py +194 -0
  18. azapyGUI/MktDataFrame.py +129 -0
  19. azapyGUI/MktDataNode.py +34 -0
  20. azapyGUI/ModelParamEditWindow.py +143 -0
  21. azapyGUI/NrShares_table.py +54 -0
  22. azapyGUI/PortAnalyseWindow.py +179 -0
  23. azapyGUI/PortDataNode.py +180 -0
  24. azapyGUI/PortfolioFrame.py +197 -0
  25. azapyGUI/RebalanceMenuPortfolioWindow.py +21 -0
  26. azapyGUI/RemoveMenuPortfolioWindow.py +33 -0
  27. azapyGUI/SaveMenuPortfolioWindow.py +36 -0
  28. azapyGUI/Scrollable.py +60 -0
  29. azapyGUI/SelectOneWindow.py +65 -0
  30. azapyGUI/SymbAnalyseWindow.py +21 -0
  31. azapyGUI/SymbExtractWindow.py +129 -0
  32. azapyGUI/SymbTableEntry.py +109 -0
  33. azapyGUI/TimeSeriesViewWindow.py +480 -0
  34. azapyGUI/ViewTip.py +72 -0
  35. azapyGUI/WeightsWindow.py +352 -0
  36. azapyGUI/__init__.py +6 -0
  37. azapyGUI/azHelper.py +27 -0
  38. azapyGUI/azapyApp.py +89 -0
  39. azapyGUI/config.py +35 -0
  40. azapyGUI/configHelps.py +84 -0
  41. azapyGUI/configMSG.py +194 -0
  42. azapyGUI/configModels.py +519 -0
  43. azapyGUI/configPlot.py +70 -0
  44. azapyGUI/configSettings.py +138 -0
  45. azapyGUI/configTips.py +240 -0
  46. azapyGUI/mktDataValidation.py +42 -0
  47. azapyGUI/modelParametersValidation.py +442 -0
  48. azapyGUI/serviceMasterUserConfig.py +28 -0
  49. azapyGUI/tkHelper.py +18 -0
  50. azapyGUI-0.0.1.dist-info/LICENSE +674 -0
  51. azapyGUI-0.0.1.dist-info/METADATA +126 -0
  52. azapyGUI-0.0.1.dist-info/RECORD +54 -0
  53. azapyGUI-0.0.1.dist-info/WHEEL +5 -0
  54. azapyGUI-0.0.1.dist-info/top_level.txt +1 -0
azapyGUI/DF_table.py ADDED
@@ -0,0 +1,282 @@
1
+ import tkinter as tk
2
+ import pandas as pd
3
+ import numpy as np
4
+ import platform
5
+ import numbers
6
+
7
+
8
+ class DF_table(tk.Frame):
9
+ def __init__(self, df, master=None, **args):
10
+ self._master = master if master is not None else tk.Toplevel()
11
+ self._df = df
12
+
13
+ self._bwidth = 2 #border width of each cell
14
+ self._relife = "raised" #cell style
15
+ self._bg = 'white' #background of regular header cells
16
+ self._bg_data = 'white' #background of data cells
17
+ self._fg = 'black' #foreground header cells
18
+ self._fg_data_normal = 'black' #foreground of positive numerical data
19
+ self._fg_data_mark = 'red' #foreground ofr negative numerical data
20
+ self._bg_select = 'gray85' #background of selectable header cells
21
+
22
+ self._index_sort_ascending = True
23
+ self._columns_sort_ascending = True
24
+
25
+ super().__init__(master=self._master, **args)
26
+ self.grid_columnconfigure(0, weight=1)
27
+ self.grid_rowconfigure(0, weight=1)
28
+
29
+ self._canvas = tk.Canvas(master=self)
30
+ self._canvas.grid(row=0, column=0, sticky=tk.NSEW)
31
+
32
+ sv = tk.Scrollbar(master=self, orient=tk.VERTICAL, command=self._canvas.yview)
33
+ sv.grid(row=0, column=1, sticky=tk.NS)
34
+ self._canvas.configure(yscrollcommand=sv.set)
35
+
36
+ sh = tk.Scrollbar(master=self, orient=tk.HORIZONTAL, command=self._canvas.xview)
37
+ sh.grid(row=1, column=0, sticky=tk.EW)
38
+ self._canvas.configure(xscrollcommand=sh.set)
39
+
40
+ self._frm = tk.Frame(master=self._canvas, borderwidth=2, bg="black")
41
+ self._frm.pack(fill=tk.BOTH, expand=True)
42
+
43
+ self._canvas_window = self._canvas.create_window(0, 0, window=self._frm, anchor=tk.NW,)
44
+
45
+ self._frm.bind("<Configure>", self._onFrameConfigure)
46
+ self._canvas.bind("<Configure>", self._onCanvasConfigure)
47
+
48
+ self._frm.bind('<Enter>', self._onEnter)
49
+ self._frm.bind('<Leave>', self._onLeave)
50
+
51
+ self._onFrameConfigure(None)
52
+
53
+ self._first_time= True
54
+ self._draw(self._df)
55
+
56
+
57
+ def _onFrameConfigure(self, event):
58
+ self._canvas.configure(scrollregion=self._canvas.bbox("all"))
59
+
60
+
61
+ def _onCanvasConfigure(self, event):
62
+ if self._first_time:
63
+ self._hh0 = self._frm.winfo_height()
64
+ self._ww0 = self._frm.winfo_width()
65
+ self._first_time = False
66
+ canvas_width = max(event.width, self._ww0)
67
+ canvas_heigth = max(event.height, self._hh0)
68
+ self._canvas.itemconfig(self._canvas_window, width=canvas_width, height=canvas_heigth)
69
+
70
+
71
+ def _onMouseWheel(self, event):
72
+ if platform.system() == 'Windows':
73
+ self._canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
74
+ elif platform.system() == 'Darwin':
75
+ self._canvas.yview_scroll(int(-1 * event.delta), "units")
76
+ else:
77
+ if event.num == 4:
78
+ self._canvas.yview_scroll(-1, "units")
79
+ elif event.num == 5:
80
+ self._canvas.yview_scroll(1, "units")
81
+
82
+
83
+ def _onEnter(self, event):
84
+ if platform.system() == 'Linux':
85
+ self._canvas.bind_all("<Button-4>", self._onMouseWheel)
86
+ self._canvas.bind_all("<Button-5>", self._onMouseWheel)
87
+ else:
88
+ self._canvas.bind_all("<MouseWheel>", self._onMouseWheel)
89
+
90
+
91
+ def _onLeave(self, event):
92
+ if platform.system() == 'Linux':
93
+ self._canvas.unbind_all("<Button-4>")
94
+ self._canvas.unbind_all("<Button-5>")
95
+ else:
96
+ self._canvas.unbind_all("<MouseWheel>")
97
+
98
+
99
+ def _draw(self, df):
100
+ tb_rows, tb_cols = df.shape
101
+ nr_cnames = len(df.columns.names)
102
+ nr_rnames = len(df.index.names)
103
+
104
+ # header corner
105
+ if (nr_cnames == 1) and (df.columns.names[0] is None):
106
+ row = 0
107
+ for col, rname in enumerate(df.index.names):
108
+ lbl = tk.Label(master=self._frm, text=rname, justify=tk.LEFT,
109
+ borderwidth=self._bwidth, relief=self._relife, anchor=tk.NW,
110
+ bg=self._bg_select, fg=self._fg)
111
+ lbl.grid(row=row, column=col, sticky=tk.EW, ipadx=2, ipady=2)
112
+ lbl.bind("<Button-1>", self._swap_rows)
113
+ col += 1
114
+ sv = tk.Frame(master=self._frm, bg="black", width=1, bd=0)
115
+ sv.grid(row = 0, column=col, rowspan=nr_cnames + 2 + tb_rows, sticky=tk.NS)
116
+ for col in range(nr_rnames, nr_rnames + tb_cols):
117
+ lbl = tk.Label(master=self._frm, text=df.columns[col - nr_rnames], justify=tk.LEFT,
118
+ borderwidth=self._bwidth, relief=self._relife, anchor=tk.NW,
119
+ bg=self._bg, fg=self._fg)
120
+ lbl.grid(row=row, column=col + 1, sticky=tk.EW)
121
+ row += 1
122
+ sh = tk.Frame(master=self._frm, bg="black", height=1, bd=0)
123
+ sh.grid(row=row, column=0, columnspan=nr_rnames + 1 + tb_cols, sticky=tk.EW)
124
+
125
+ row_data = row + 1
126
+ col_data = nr_rnames + 1
127
+ else:
128
+ columnspan = len(df.index.names)
129
+ for row, cname in enumerate(df.columns.names):
130
+ lbl = tk.Label(master=self._frm, text=cname, justify=tk.LEFT,
131
+ borderwidth=self._bwidth, relief=self._relife, anchor=tk.NW,
132
+ bg=self._bg_select, fg=self._fg)
133
+ lbl.grid(row=row, columnspan=columnspan, sticky=tk.EW, ipadx=2, ipady=2)
134
+ lbl.bind("<Button-1>", self._swap_cols)
135
+
136
+ for name in df.index.names:
137
+ if name is not None:
138
+ row += 1
139
+ for col, rname in enumerate(df.index.names):
140
+ lbl = tk.Label(master=self._frm, text=rname, justify=tk.LEFT,
141
+ borderwidth=self._bwidth, relief=self._relife,
142
+ anchor=tk.NW, bg=self._bg_select, fg=self._fg)
143
+ lbl.grid(row=row, column=col, sticky=tk.EW, ipadx=2, ipady=2)
144
+ lbl.bind("<Button-1>", self._swap_rows)
145
+ break
146
+ row += 1
147
+ sh = tk.Frame(master=self._frm, bg="black", height=1, bd=0)
148
+ sh.grid(row=row, column=0, columnspan=nr_rnames + 1 + tb_cols, sticky=tk.EW)
149
+ col = nr_rnames
150
+ sv = tk.Frame(master=self._frm, bg="black", width=1, bd=0)
151
+ sv.grid(row = 0, column=col, rowspan=nr_cnames + 2 + tb_rows, sticky=tk.NS)
152
+ row_data = row + 1
153
+ col_data = nr_rnames + 1
154
+ # pad
155
+ for col in range(row_data, row_data + tb_cols):
156
+ lbl = tk.Label(master=self._frm, text="",
157
+ borderwidth=self._bwidth, relief=self._relife, anchor=tk.NW,
158
+ bg=self._bg, fg=self._fg)
159
+ lbl.grid(row=row_data - 2, column=col, sticky=tk.EW, ipadx=2, ipady=2)
160
+
161
+ # header columns
162
+ cspan = np.ones(nr_cnames, dtype=int)
163
+ ent = [None for _ in range(nr_cnames)]
164
+ for col, cname in enumerate(df.columns):
165
+ cname = cname if isinstance(cname, tuple) else (cname, )
166
+ if col == 0:
167
+ for kk in range(nr_cnames):
168
+ ent[kk] = tk.Label(master=self._frm, text=cname[kk],
169
+ borderwidth=self._bwidth, relief=self._relife,
170
+ anchor=tk.NW, bg=self._bg, fg=self._fg)
171
+ cname_ = cname
172
+ continue
173
+ for j in range(nr_cnames):
174
+ if cname[j] == cname_[j]:
175
+ cspan[j] += 1
176
+ else:
177
+ for kk in range(j, nr_cnames):
178
+ column = col - cspan[kk] + col_data
179
+ ent[kk].grid(row=kk, column=column, columnspan=cspan[kk],
180
+ sticky=tk.EW, ipadx=2, ipady=2)
181
+ ent[kk] = tk.Label(master=self._frm, text=cname[kk],
182
+ borderwidth=self._bwidth, relief=self._relife,
183
+ anchor=tk.NW, bg=self._bg, fg=self._fg)
184
+ cspan[kk] = 1
185
+ break
186
+ cname_ = cname
187
+ for kk in range(nr_cnames):
188
+ ent[kk].grid(row=kk, column=col - cspan[kk] + col_data + 1,
189
+ columnspan=cspan[kk], sticky=tk.EW, ipadx=2, ipady=2)
190
+
191
+ # header index
192
+ rspan = np.ones(nr_rnames, dtype=int)
193
+ ent = [None for _ in range(nr_rnames)]
194
+ for row, rname in enumerate(df.index):
195
+ rname = rname if isinstance(rname, tuple) else (rname,)
196
+ if row == 0:
197
+ for kk in range(nr_rnames):
198
+ ent[kk] = tk.Label(master=self._frm, text=self._tr2str(rname[kk]),
199
+ borderwidth=self._bwidth, relief=self._relife,
200
+ anchor=tk.NW, bg=self._bg, fg=self._fg)
201
+ rname_ = rname
202
+ continue
203
+ for j in range(nr_rnames):
204
+ if rname[j] == rname_[j]:
205
+ rspan[j] += 1
206
+ else:
207
+ for kk in range(j, nr_rnames):
208
+ prow = row - rspan[kk] + row_data
209
+ ent[kk].grid(row=prow, column=kk, rowspan=rspan[kk], sticky=tk.NSEW)
210
+ ent[kk] = tk.Label(master=self._frm, text=self._tr2str(rname[kk]),
211
+ borderwidth=self._bwidth, relief=self._relife,
212
+ anchor=tk.NW, bg=self._bg, fg=self._fg)
213
+ rspan[kk] = 1
214
+ break
215
+ rname_ = rname
216
+ for kk in range(nr_rnames):
217
+ ent[kk].grid(row=row - rspan[kk] + 1 + row_data, column=kk,
218
+ rowspan=rspan[kk], sticky=tk.NSEW, ipadx=2, ipady=2)
219
+
220
+ # data
221
+ for col in range(df.shape[1]):
222
+ self._frm.columnconfigure(col + col_data, weight=1)
223
+ for row in range(df.shape[0]):
224
+ ldata = df.iloc[row, col]
225
+ if (pd.isna(ldata) or
226
+ (isinstance(ldata, numbers.Number) and ldata < 0)):
227
+ fg_data = self._fg_data_mark
228
+ else:
229
+ fg_data = self._fg_data_normal
230
+ ent = tk.Label(master=self._frm, text=self._tr2str(ldata), borderwidth=self._bwidth,
231
+ relief=self._relife, fg=fg_data, bg=self._bg_data)
232
+ ent.grid(row = row_data + row, column=col + col_data, sticky=tk.NSEW)
233
+ self._frm.rowconfigure(row_data + row, weight=1)
234
+
235
+
236
+ def _swap_rows(self, event):
237
+ wname = event.widget.cget("text")
238
+ if wname == self._df.index.names[0]:
239
+ self._index_sort_ascending = not self._index_sort_ascending
240
+ self._df.sort_index(level=wname,
241
+ ascending=self._index_sort_ascending,
242
+ inplace=True)
243
+ self._draw(self._df)
244
+ return
245
+ if isinstance(self._df.index, pd.MultiIndex):
246
+ self._index_sort_ascending = True
247
+ self._df = self._df.swaplevel(0, wname)\
248
+ .sort_index(ascending=self._index_sort_ascending)
249
+ self._draw(self._df)
250
+
251
+
252
+ def _swap_cols(self, event):
253
+ wname = event.widget.cget("text")
254
+ if wname == self._df.columns.names[0]:
255
+ self._columns_sort_ascending = not self._columns_sort_ascending
256
+ self._df.sort_index(axis=1, level=wname,
257
+ ascending=self._columns_sort_ascending,
258
+ inplace=True)
259
+ self._draw(self._df)
260
+ return
261
+ if isinstance(self._df.columns, pd.MultiIndex):
262
+ self._columns_sort_ascending = True
263
+ self._df = self._df.swaplevel(0, wname, axis=1)\
264
+ .sort_index(axis=1, ascending=self._columns_sort_ascending)
265
+ self._draw(self._df)
266
+
267
+
268
+ def get_df(self):
269
+ return self._df
270
+
271
+
272
+ def _tr2str(self, name):
273
+ if pd.isna(name):
274
+ sname = ''
275
+ elif isinstance(name, str):
276
+ sname = name
277
+ elif isinstance(name, numbers.Number):
278
+ sname = str(name)
279
+ else: #date
280
+ sname = name.strftime('%Y-%m-%d')
281
+
282
+ return sname
@@ -0,0 +1,16 @@
1
+ import azapyGUI.config as config
2
+ from azapyGUI.SelectOneWindow import SelectOneWindow
3
+
4
+ class EditMenuPortfolioWindow(SelectOneWindow):
5
+ def __init__(self, master=None):
6
+ self.selection = None
7
+ values =[kk for kk, vv in config.PortDataDict.items() if vv.status == 'Set']
8
+ if len(values) == 0: return
9
+
10
+ title = "Select Portfolio"
11
+ text = "Choose portfolio for editing"
12
+ tip_text = "Only portfolios with status=Set can be edited."
13
+ btn_text = "Edit"
14
+ super().__init__(master=master, title=title, text=text, values=values,
15
+ tip_text=tip_text, btn_text=btn_text)
16
+