azapyGUI 0.0.2__tar.gz → 0.1.1__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.
Files changed (66) hide show
  1. {azapygui-0.0.2 → azapygui-0.1.1}/PKG-INFO +6 -6
  2. {azapygui-0.0.2 → azapygui-0.1.1}/README.md +3 -3
  3. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/AppSettingsPage.py +0 -1
  4. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/AppSettingsPageMisc.py +30 -7
  5. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/GetMktData.py +4 -0
  6. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/MktDataNode.py +20 -14
  7. azapygui-0.1.1/azapyGUI/ViewTip.py +12 -0
  8. azapygui-0.1.1/azapyGUI/ViewTip_Ubuntu.py +52 -0
  9. azapygui-0.1.1/azapyGUI/ViewTip_fade.py +73 -0
  10. azapygui-0.1.1/azapyGUI/ViewTip_fast.py +55 -0
  11. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/azapyApp.py +1 -1
  12. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/config.py +1 -1
  13. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/configSettings.py +21 -2
  14. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/configTips.py +6 -0
  15. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/modelParametersValidation.py +5 -0
  16. azapygui-0.1.1/azapyGUI/serviceMasterUserConfig.py +42 -0
  17. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI.egg-info/PKG-INFO +6 -6
  18. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI.egg-info/SOURCES.txt +6 -0
  19. azapygui-0.1.1/azapyGUI.egg-info/requires.txt +7 -0
  20. {azapygui-0.0.2 → azapygui-0.1.1}/setup.py +3 -3
  21. azapygui-0.0.2/azapyGUI/ViewTip.py +0 -72
  22. azapygui-0.0.2/azapyGUI/serviceMasterUserConfig.py +0 -28
  23. azapygui-0.0.2/azapyGUI.egg-info/requires.txt +0 -5
  24. {azapygui-0.0.2 → azapygui-0.1.1}/LICENSE +0 -0
  25. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/AppSettingsWindow.py +0 -0
  26. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/BacktestComputation.py +0 -0
  27. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/BacktestEntryWindow.py +0 -0
  28. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/BacktestMenuPortfolioWindow.py +0 -0
  29. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/CloneMenuPortfolioWindow.py +0 -0
  30. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/CrossHairBCursor.py +0 -0
  31. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/DF_Window.py +0 -0
  32. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/DF_table.py +0 -0
  33. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/EditMenuPortfolioWindow.py +0 -0
  34. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/EditPortfolioWindow.py +0 -0
  35. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/EntryClonePortfolioWindow.py +0 -0
  36. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/EntryNameWindow.py +0 -0
  37. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/EntryRenamePortfolioWindow.py +0 -0
  38. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/MenuApp.py +0 -0
  39. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/MktDataFrame.py +0 -0
  40. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/ModelParamEditWindow.py +0 -0
  41. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/NrShares_table.py +0 -0
  42. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/PortAnalyseWindow.py +0 -0
  43. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/PortDataNode.py +0 -0
  44. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/PortfolioFrame.py +0 -0
  45. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/RebalanceMenuPortfolioWindow.py +0 -0
  46. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/RemoveMenuPortfolioWindow.py +0 -0
  47. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/SaveMenuPortfolioWindow.py +0 -0
  48. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/Scrollable.py +0 -0
  49. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/SelectOneWindow.py +0 -0
  50. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/SymbAnalyseWindow.py +0 -0
  51. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/SymbExtractWindow.py +0 -0
  52. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/SymbTableEntry.py +0 -0
  53. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/TimeSeriesViewWindow.py +0 -0
  54. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/WeightsWindow.py +0 -0
  55. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/__init__.py +0 -0
  56. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/azHelper.py +0 -0
  57. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/configHelps.py +0 -0
  58. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/configMSG.py +0 -0
  59. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/configModels.py +0 -0
  60. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/configPlot.py +0 -0
  61. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/mktDataValidation.py +0 -0
  62. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI/tkHelper.py +0 -0
  63. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI.egg-info/dependency_links.txt +0 -0
  64. {azapygui-0.0.2 → azapygui-0.1.1}/azapyGUI.egg-info/top_level.txt +0 -0
  65. {azapygui-0.0.2 → azapygui-0.1.1}/pyproject.toml +0 -0
  66. {azapygui-0.0.2 → azapygui-0.1.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: azapyGUI
3
- Version: 0.0.2
3
+ Version: 0.1.1
4
4
  Summary: GUI for azapy library - Financial Portfolio Optimization Algorithms
5
5
  Home-page: https://github.com/Mircea-MMXXI/azapyGUI.git
6
6
  Author: Mircea Marinescu
@@ -15,11 +15,11 @@ Classifier: Operating System :: OS Independent
15
15
  Requires-Python: >=3.11
16
16
  Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
- Requires-Dist: azapy>=1.2.4
18
+ Requires-Dist: azapy>=1.2.5
19
19
  Requires-Dist: numpy
20
20
  Requires-Dist: pandas
21
21
  Requires-Dist: matplotlib
22
- Requires-Dist: xlsxwriter
22
+ Requires-Dist: xlsxwriter; platform_system == "Windows"
23
23
 
24
24
  # azapyGUI project
25
25
 
@@ -99,7 +99,7 @@ and then run in a powershell: `python my_azapy.py`
99
99
 
100
100
  1. Kelly's portfolio (as in John Larry Kelly Jr. scientist 1923-1965) -
101
101
  maximization of portfolio log returns
102
- 2. Universal portfolio (Thomas M. Cover 1996) <span style="color:red">(alpha version)</span>
102
+ 2. Universal portfolio (Thomas M. Cover 1996) <span style="color:blue">(beta version)</span>
103
103
 
104
104
  ### D. Market Selectors
105
105
 
@@ -118,9 +118,9 @@ and then run in a powershell: `python my_azapy.py`
118
118
  ### Required packages
119
119
 
120
120
  * python 3.11.8
121
- * azapy 1.2.4
121
+ * azapy 1.2.5
122
122
  * pandas 2.2.0
123
123
  * numpy 1.26.0
124
124
  * matplotlib 3.8.0
125
- * xlsxwriter 3.1.1
125
+ * xlsxwriter 3.1.1 (for non-Linux installations)
126
126
 
@@ -76,7 +76,7 @@ and then run in a powershell: `python my_azapy.py`
76
76
 
77
77
  1. Kelly's portfolio (as in John Larry Kelly Jr. scientist 1923-1965) -
78
78
  maximization of portfolio log returns
79
- 2. Universal portfolio (Thomas M. Cover 1996) <span style="color:red">(alpha version)</span>
79
+ 2. Universal portfolio (Thomas M. Cover 1996) <span style="color:blue">(beta version)</span>
80
80
 
81
81
  ### D. Market Selectors
82
82
 
@@ -95,9 +95,9 @@ and then run in a powershell: `python my_azapy.py`
95
95
  ### Required packages
96
96
 
97
97
  * python 3.11.8
98
- * azapy 1.2.4
98
+ * azapy 1.2.5
99
99
  * pandas 2.2.0
100
100
  * numpy 1.26.0
101
101
  * matplotlib 3.8.0
102
- * xlsxwriter 3.1.1
102
+ * xlsxwriter 3.1.1 (for non-Linux installations)
103
103
 
@@ -36,7 +36,6 @@ class AppSettingsPage(tk.Frame):
36
36
 
37
37
  # on frm_set
38
38
  self._setDef = configSettings.settings_model[self._category]
39
- #self.settings = deepcopy(configSettings.MasterApplicationSettings)
40
39
  self.settings = {key: configSettings.MasterApplicationSettings[key] for key in self._setDef.keys()}
41
40
  row = 0
42
41
  self._chk_val = {}
@@ -1,5 +1,9 @@
1
1
  import tkinter as tk
2
+ import tkinter.ttk as ttk
3
+ import platform
2
4
  from copy import deepcopy
5
+ import pandas as pd
6
+ import azapy as az
3
7
 
4
8
  import azapyGUI.config as config
5
9
  import azapyGUI.configSettings as configSettings
@@ -26,7 +30,6 @@ class AppSettingsPageMisc(tk.Frame):
26
30
 
27
31
  # on frm
28
32
  self._setDef = configSettings.settings_model[self._category]
29
- #self.settings = deepcopy(configSettings.MasterApplicationSettings)
30
33
  self.settings = {key: configSettings.MasterApplicationSettings[key] for key in self._setDef.keys()}
31
34
  row = 0
32
35
  self._chk_val = {}
@@ -35,26 +38,39 @@ class AppSettingsPageMisc(tk.Frame):
35
38
  match value["type"]:
36
39
  case 'Checkbutton':
37
40
  lbl = tk.Label(master=frm_set, text=value["field"], anchor=tk.W)
38
- lbl.grid(row=row, column=0, padx=5, pady=5, sticky=tk.EW)
41
+ lbl.grid(row=row, column=0, padx=5, pady=2, sticky=tk.EW)
39
42
  chk_var = tk.BooleanVar(master=frm_set, value=self.settings[param])
40
43
  chk_btn = tk.Checkbutton(master=frm_set, variable = chk_var,
41
44
  onvalue = True, offvalue = False,
42
- height=2, width=18, anchor=tk.W)
43
- chk_btn.grid(row=row, column=1, padx=5, pady=5, sticky=tk.W)
45
+ height=1, width=1, anchor=tk.W)
46
+ chk_btn.grid(row=row, column=1, padx=5, pady=2, sticky=tk.W)
44
47
  self._chk_val[param] = chk_var
45
48
  self._chk_btn[param] = chk_btn
46
49
  config.tiptil.bind(chk_btn, value["tip"])
50
+ if (param == 'OpenExcel') and (platform.system() == 'Linux'):
51
+ chk_var.set(False)
52
+ chk_btn.config(state=tk.DISABLED)
47
53
  row += 1
48
54
  case 'Entry':
49
55
  lbl = tk.Label(master=frm_set, text=value["field"], anchor=tk.W)
50
- lbl.grid(row=row, column=0, padx=5, pady=5, sticky=tk.W)
56
+ lbl.grid(row=row, column=0, padx=5, pady=2, sticky=tk.W)
51
57
  ent_var = tk.StringVar(master=frm_set, value=self.settings[param])
52
58
  ent = tk.Entry(master=frm_set, textvariable=ent_var, validate='key', width=10)
53
59
  ent['validatecommand'] = (ent.register(value["validate"]),'%S','%d','%P')
54
- ent.grid(row=row, column=1, padx=5, pady=5, sticky=tk.W)
60
+ ent.grid(row=row, column=1, padx=5, pady=2, sticky=tk.W)
55
61
  self._chk_val[param] = ent_var
56
62
  config.tiptil.bind(ent, value["tip"])
57
63
  row += 1
64
+ case 'Combobox':
65
+ lbl = tk.Label(master=frm_set, text=value["field"], anchor=tk.W)
66
+ lbl.grid(row=row, column=0, padx=5, pady=2, sticky=tk.EW)
67
+ cbx_var = tk.StringVar(master=frm_set, value=self.settings[param])
68
+ cbx = ttk.Combobox(master=frm_set, textvariable=cbx_var, width=10, state='readonly')
69
+ cbx["values"] = value["values"]
70
+ cbx.grid(row=row, column=1, padx=5, pady=2, sticky=tk.W)
71
+ self._chk_val[param] = cbx_var
72
+ config.tiptil.bind(cbx, value["tip"])
73
+ row += 1
58
74
  case _:
59
75
  # you should not be here
60
76
  raise ValueError("Error: Unknown configSetting type")
@@ -88,14 +104,21 @@ class AppSettingsPageMisc(tk.Frame):
88
104
  self._chk_btn[kk].select()
89
105
  else:
90
106
  self._chk_btn[kk].deselect()
91
- case "Entry":
107
+ #case "Entry":
108
+ case _:
92
109
  self._chk_val[kk].set(self.settings[kk])
93
110
 
94
111
 
95
112
  def _btn_save_func(self):
113
+ if self.settings['calendar'] != self._chk_val['calendar'].get():
114
+ config.MktDataDict.clear()
115
+ config.appMktDataFrame.refresh()
116
+
96
117
  self.settings.update({key: self._chk_val[key].get() for key in self._chk_val.keys()})
97
118
  configSettings.MasterApplicationSettings.update(self.settings)
98
119
  _saveMasterUserConfig(configSettings.MasterApplicationSettings)
99
120
  config.tiptil.turned(on=configSettings.MasterApplicationSettings["ShowTips"])
121
+ config.calendar = az.calendarGen(configSettings.MasterApplicationSettings["calendar"])
122
+ config._bday = pd.offsets.CustomBusinessDay(calendar=config.calendar)
100
123
 
101
124
 
@@ -4,6 +4,7 @@ from copy import deepcopy
4
4
  import azapyGUI.config as config
5
5
  import azapyGUI.configSettings as configSettings
6
6
  from azapyGUI.MktDataNode import MktDataNode
7
+ from azapyGUI.modelParametersValidation import _validStr
7
8
 
8
9
 
9
10
  class GetMktData():
@@ -53,6 +54,9 @@ class GetMktData():
53
54
  # retrieve symb (not in the system)
54
55
  self._symb_req["symbol"] = symb
55
56
  mktdata = self._mktr.get(calendar=config.calendar, **self._symb_req)
57
+ imputation_method = _validStr(configSettings.MasterApplicationSettings['imputation'])
58
+ if imputation_method is not None:
59
+ mktdata = self._mktr.set_imputation(method=imputation_method)
56
60
  if len(mktdata.keys()) == 0:
57
61
  # no extraction was possible (all symb are error symbols)
58
62
  self.symbols = list(set(symbols) - set(symb))
@@ -1,4 +1,5 @@
1
1
  import azapy as az
2
+ import azapyGUI.config as config
2
3
 
3
4
  class MktDataNode:
4
5
  def __init__(self):
@@ -7,28 +8,33 @@ class MktDataNode:
7
8
  self.stats = None
8
9
  self.status = False
9
10
  self._summary = None
10
-
11
-
11
+
12
+
13
+ def _set_summary(self):
14
+ if self._summary is None:
15
+ self._summary = az.summary_MkTdata(self.mktdata, calendar=config.calendar)
16
+
17
+
12
18
  def sdate(self):
13
- if self._summary is None: self._summary = az.summary_MkTdata(self.mktdata)
19
+ self._set_summary()
14
20
  return self._summary.begin[0]
15
-
16
-
21
+
22
+
17
23
  def edate(self):
18
- if self._summary is None: self._summary = az.summary_MkTdata(self.mktdata)
24
+ self._set_summary()
19
25
  return self._summary.end[0]
20
-
21
-
26
+
27
+
22
28
  def nrow(self):
23
- if self._summary is None: self._summary = az.summary_MkTdata(self.mktdata)
29
+ self._set_summary()
24
30
  return self._summary.length[0]
25
-
26
-
31
+
32
+
27
33
  def iserror(self):
28
- if self._summary is None: self._summary = az.summary_MkTdata(self.mktdata)
34
+ self._set_summary()
29
35
  return (self._summary.na_total[0] + self._summary.cont[0]) > 0
30
-
31
-
36
+
37
+
32
38
  def get_mktdata(self, edate=None):
33
39
  return self.mktdata if edate is None else self.mktdata[self.mktdata.index <= edate]
34
40
 
@@ -0,0 +1,12 @@
1
+ import platform
2
+
3
+ from azapyGUI.ViewTip_Ubuntu import ViewTip_Ubuntu
4
+ from azapyGUI.ViewTip_fade import ViewTip_fade
5
+ from azapyGUI.ViewTip_fast import ViewTip_fast
6
+
7
+
8
+ def ViewTip(master, **kwargs):
9
+ if platform.system() == 'Windows':
10
+ return ViewTip_fade(master, **kwargs)
11
+ else:
12
+ return ViewTip_Ubuntu(master, **kwargs)
@@ -0,0 +1,52 @@
1
+ import tkinter as tk
2
+ from tkinter import ttk
3
+ from typing import Union
4
+
5
+ Widget = Union[tk.Widget, ttk.Widget]
6
+
7
+
8
+ class ViewTip_Ubuntu(tk.Toplevel):
9
+ def __init__(self, master, **kwargs):
10
+ tk.Toplevel.__init__(self, master)
11
+
12
+ self.attributes('-alpha', 0, '-topmost', True)
13
+ self.overrideredirect(True)
14
+
15
+ style = dict(bd=2, relief='raised', font='Ariel 10', bg='#D4D4D4',
16
+ anchor='w', justify='left')
17
+ self._label = tk.Label(self, **{**style, **kwargs})
18
+ self._label.grid(row=0, column=0, sticky='w')
19
+
20
+ self._view = True
21
+
22
+
23
+ def bind(self, target:Widget, text:str, **kwargs):
24
+ target.bind('<Enter>', lambda e: self._goin(text, e), add="+")
25
+ target.bind('<Leave>', lambda e: self._goout(), add="+")
26
+
27
+
28
+ def _goin(self, text:str=None, event:tk.Event=None):
29
+ if not self._view: return
30
+ self.deiconify()
31
+
32
+ self._label.configure(text=f'{text:^{len(text) + 2}}')
33
+ self.update()
34
+
35
+ offset_x = event.widget.winfo_width() + 2
36
+ offset_y = int((event.widget.winfo_height() - self._label.winfo_height()) / 2)
37
+
38
+ w = self._label.winfo_width()
39
+ h = self._label.winfo_height()
40
+ x = event.widget.winfo_rootx() + offset_x
41
+ y = event.widget.winfo_rooty() + offset_y
42
+
43
+ self.geometry(f'{w}x{h}+{x}+{y}')
44
+
45
+
46
+ def _goout(self):
47
+ if not self._view: return
48
+ self.withdraw()
49
+
50
+
51
+ def turned(self, on:bool=True):
52
+ self._view = on
@@ -0,0 +1,73 @@
1
+ import tkinter as tk
2
+ from tkinter import ttk
3
+ from typing import Union
4
+
5
+ Widget = Union[tk.Widget, ttk.Widget]
6
+
7
+
8
+ class ViewTip_fade(tk.Toplevel):
9
+ def __init__(self, master, fade_inc=0.07, fade_ms=20, **kwargs):
10
+ tk.Toplevel.__init__(self, master)
11
+ self._fade_inc = fade_inc
12
+ self._fade_ms = fade_ms
13
+
14
+ self.attributes('-alpha', 0, '-topmost', True)
15
+ self.overrideredirect(1)
16
+
17
+ style = dict(bd=2, relief='raised', font='Ariel 10', bg='#D4D4D4',
18
+ anchor='w', justify='left')
19
+ self._label = tk.Label(self, **{**style, **kwargs})
20
+ self._label.grid(row=0, column=0, sticky='w')
21
+
22
+ self._fout:bool = False
23
+
24
+
25
+ def bind(self, target:Widget, text:str, **kwargs):
26
+ target.bind('<Enter>', lambda e: self._fadein(0, text, e), add="+")
27
+ target.bind('<Leave>', lambda e: self._fadeout(1 - self._fade_inc, e), add="+")
28
+
29
+
30
+ def _fadein(self, alpha:float, text:str=None, event:tk.Event=None):
31
+ if event and text:
32
+ if self._fout:
33
+ self.attributes('-alpha', 0)
34
+ self._fout = False
35
+
36
+ self._label.configure(text=f'{text:^{len(text) + 2}}')
37
+ self.update()
38
+
39
+ offset_x = event.widget.winfo_width() + 2
40
+ offset_y = int((event.widget.winfo_height() - self._label.winfo_height()) / 2)
41
+
42
+ w = self._label.winfo_width()
43
+ h = self._label.winfo_height()
44
+ x = event.widget.winfo_rootx() + offset_x
45
+ y = event.widget.winfo_rooty() + offset_y
46
+
47
+ self.geometry(f'{w}x{h}+{x}+{y}')
48
+
49
+ if not self._fout:
50
+ self.attributes('-alpha', alpha)
51
+
52
+ if alpha < 1:
53
+ self.after(self._fade_ms,
54
+ lambda: self._fadein(min(alpha + self._fade_inc, 1)))
55
+
56
+
57
+ def _fadeout(self, alpha:float, event:tk.Event=None):
58
+ if event:
59
+ self._fout = True
60
+
61
+ if self._fout:
62
+ self.attributes('-alpha', alpha)
63
+
64
+ if alpha > 0:
65
+ self.after(self._fade_ms,
66
+ lambda: self._fadeout(max(alpha - self._fade_inc, 0)))
67
+
68
+
69
+ def turned(self, on=True):
70
+ if on:
71
+ self.deiconify()
72
+ else:
73
+ self.withdraw()
@@ -0,0 +1,55 @@
1
+ import tkinter as tk
2
+ from tkinter import ttk
3
+ from typing import Union
4
+
5
+ Widget = Union[tk.Widget, ttk.Widget]
6
+
7
+
8
+ class ViewTip_fast(tk.Toplevel):
9
+ def __init__(self, master, fade_inc=0.07, fade_ms=20, **kwargs):
10
+ tk.Toplevel.__init__(self, master)
11
+ self._fade_inc = fade_inc
12
+ self._fade_ms = fade_ms
13
+
14
+ self.attributes('-alpha', 0, '-topmost', True)
15
+ self.overrideredirect(True)
16
+
17
+ style = dict(bd=2, relief='raised', font='Ariel 10', bg='#D4D4D4',
18
+ anchor='w', justify='left')
19
+ self._label = tk.Label(self, **{**style, **kwargs})
20
+ self._label.grid(row=0, column=0, sticky='w')
21
+
22
+
23
+ def bind(self, target:Widget, text:str, **kwargs):
24
+ target.bind('<Enter>', lambda e: self._goin(text, e), add="+")
25
+ target.bind('<Leave>', lambda e: self._goout(), add="+")
26
+
27
+
28
+ def _goin(self, text:str=None, event:tk.Event=None):
29
+ if text is None: return
30
+
31
+ self._label.configure(text=f'{text:^{len(text) + 2}}')
32
+ self.update()
33
+
34
+ offset_x = event.widget.winfo_width() + 2
35
+ offset_y = int((event.widget.winfo_height() - self._label.winfo_height()) / 2)
36
+
37
+ w = self._label.winfo_width()
38
+ h = self._label.winfo_height()
39
+ x = event.widget.winfo_rootx() + offset_x
40
+ y = event.widget.winfo_rooty() + offset_y
41
+
42
+ self.geometry(f'{w}x{h}+{x}+{y}')
43
+
44
+ self.attributes('-alpha', 1)
45
+
46
+
47
+ def _goout(self):
48
+ self.attributes('-alpha', 0)
49
+
50
+
51
+ def turned(self, on=True):
52
+ if on:
53
+ self.deiconify()
54
+ else:
55
+ self.withdraw()
@@ -37,7 +37,7 @@ class app:
37
37
  config.MktDataDict = {}
38
38
  config.PortDataDict = {}
39
39
  config.count_SymbTableEntry = -1
40
- config.calendar = az.NYSEgen()
40
+ config.calendar = az.calendarGen(configSettings.MasterApplicationSettings["calendar"])
41
41
  config._bday = pd.offsets.CustomBusinessDay(calendar=config.calendar)
42
42
  img = base64.b64decode(config.iconimgdata)
43
43
  config.photo = tk.PhotoImage(data=img, master=self._root)
@@ -1,4 +1,4 @@
1
- __version__ = '0.0.2'
1
+ __version__ = '0.1.1'
2
2
 
3
3
  MktDataDict = {}
4
4
  PortDataDict = {}
@@ -2,7 +2,15 @@ import os
2
2
  import azapyGUI.configTips as configTips
3
3
  from azapyGUI.modelParametersValidation import _validDateMMDDYYYY, _validInt, _validIntNegative, _validIntPositive
4
4
 
5
- Version = '0.0.1'
5
+ Version = '0.1.0'
6
+
7
+ _exchange_calendar_values = ('NYSE', 'XBUE', 'XASX', 'XWBO', 'XBRU', 'BVMF', 'XTSE', 'XSGO', 'XSHG', 'XBOG',
8
+ 'XPRA', 'XCSE', 'XLON', 'XHEL', 'XPAR', 'XFRA', 'ASEX', 'XHKG', 'XBUD', 'XICE',
9
+ 'XBOM', 'XIDX', 'XDUB', 'XMIL', 'XTKS', 'XKLS', 'XMEX', 'XAMS', 'XNZE', 'XOSL',
10
+ 'XKAR', 'XLIM', 'XPHS', 'XWAR', 'XLIS', 'XMOS', 'XSES', 'XJSE', 'XKRX', 'XMAD',
11
+ 'XSTO', 'XSWX', 'XTAI', 'XBKK', 'XIST', 'XNYS')
12
+
13
+ _imputation_method_values = ('None', 'linear')
6
14
 
7
15
  settings_model = {"Directors": {"UserPortfolioDirectory": {"default": None,
8
16
  "type": 'ButtonDir',
@@ -93,6 +101,18 @@ settings_model = {"Directors": {"UserPortfolioDirectory": {"default": None,
93
101
  "tip": configTips._settings_capital_default_tip,
94
102
  "validate": _validIntPositive,
95
103
  },
104
+ "calendar": {"default": 'NYSE',
105
+ "type": 'Combobox',
106
+ "field": 'Exchange calendar',
107
+ "tip": configTips._exchange_calendar_tip,
108
+ "values": _exchange_calendar_values,
109
+ },
110
+ "imputation": {"default": 'linear',
111
+ "type": 'Combobox',
112
+ "field": 'Imputation method',
113
+ "tip": configTips._imputation_method_tip,
114
+ "values": _imputation_method_values,
115
+ },
96
116
  "nsh_round": {"default": True,
97
117
  "type": 'Checkbutton',
98
118
  "field": 'Int. nr. shares',
@@ -113,7 +133,6 @@ settings_model = {"Directors": {"UserPortfolioDirectory": {"default": None,
113
133
  }
114
134
 
115
135
 
116
-
117
136
  def get_settings_default(category):
118
137
  rout = {kk: vv["default"] for kk, vv in settings_model[category].items()}
119
138
  return rout
@@ -238,3 +238,9 @@ _sew_provider_tip = \
238
238
 
239
239
  _sew_force_tip = \
240
240
  "Check to force market data reding from provider (slower)."
241
+
242
+ _exchange_calendar_tip = \
243
+ "Exchange business calendar."
244
+
245
+ _imputation_method_tip = \
246
+ "Method to imputing missing data."
@@ -440,3 +440,8 @@ def _validDateMMDDYYYY(inp, acttype, val):
440
440
 
441
441
  def _list2string(lnames, bk=10):
442
442
  return '\n'.join([', '.join(lnames[k : (k + bk)]) for k in range(0, len(lnames), bk)])
443
+
444
+
445
+ def _validStr(name):
446
+ rout = str(name)
447
+ return rout if rout.upper() not in ('NULL', 'NAN', 'NA', 'NONE') else None
@@ -0,0 +1,42 @@
1
+ import pathlib
2
+ import json
3
+ import tkinter as tk
4
+
5
+ import azapyGUI.configSettings as configSettings
6
+
7
+
8
+ def _fileMasterUserConfig():
9
+ return pathlib.Path.home().joinpath(".azapyGUI/MasterUserConfig.json")
10
+
11
+
12
+ def _readMasterUserConfig():
13
+ try:
14
+ out_file = _fileMasterUserConfig()
15
+ with open(out_file, 'r') as fp:
16
+ data = json.load(fp)
17
+ _update_version(data)
18
+ except FileNotFoundError:
19
+ data = configSettings.get_settings_default_all()
20
+ _saveMasterUserConfig(data)
21
+
22
+ return data
23
+
24
+
25
+ def _saveMasterUserConfig(data):
26
+ out_file = _fileMasterUserConfig()
27
+ out_file.parent.mkdir(exist_ok=True, parents=True)
28
+ with open(out_file, 'w') as fp:
29
+ json.dump(data, fp)
30
+
31
+
32
+ def _update_version(data):
33
+ d_data = configSettings.get_settings_default_all()
34
+ if data['Version'] == d_data['Version']:
35
+ return
36
+
37
+ msg = f"The setting version was updated from {data['Version']} to {d_data['Version']}." + \
38
+ "Please check the Settings for new updated values."
39
+ tk.messagebox.showinfo(title='Setting Version Update', message=msg)
40
+ data = {kk: data.get(kk, vv) for kk, vv in d_data.items()}
41
+ data['Version'] = d_data['Version']
42
+ _saveMasterUserConfig(data)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: azapyGUI
3
- Version: 0.0.2
3
+ Version: 0.1.1
4
4
  Summary: GUI for azapy library - Financial Portfolio Optimization Algorithms
5
5
  Home-page: https://github.com/Mircea-MMXXI/azapyGUI.git
6
6
  Author: Mircea Marinescu
@@ -15,11 +15,11 @@ Classifier: Operating System :: OS Independent
15
15
  Requires-Python: >=3.11
16
16
  Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
- Requires-Dist: azapy>=1.2.4
18
+ Requires-Dist: azapy>=1.2.5
19
19
  Requires-Dist: numpy
20
20
  Requires-Dist: pandas
21
21
  Requires-Dist: matplotlib
22
- Requires-Dist: xlsxwriter
22
+ Requires-Dist: xlsxwriter; platform_system == "Windows"
23
23
 
24
24
  # azapyGUI project
25
25
 
@@ -99,7 +99,7 @@ and then run in a powershell: `python my_azapy.py`
99
99
 
100
100
  1. Kelly's portfolio (as in John Larry Kelly Jr. scientist 1923-1965) -
101
101
  maximization of portfolio log returns
102
- 2. Universal portfolio (Thomas M. Cover 1996) <span style="color:red">(alpha version)</span>
102
+ 2. Universal portfolio (Thomas M. Cover 1996) <span style="color:blue">(beta version)</span>
103
103
 
104
104
  ### D. Market Selectors
105
105
 
@@ -118,9 +118,9 @@ and then run in a powershell: `python my_azapy.py`
118
118
  ### Required packages
119
119
 
120
120
  * python 3.11.8
121
- * azapy 1.2.4
121
+ * azapy 1.2.5
122
122
  * pandas 2.2.0
123
123
  * numpy 1.26.0
124
124
  * matplotlib 3.8.0
125
- * xlsxwriter 3.1.1
125
+ * xlsxwriter 3.1.1 (for non-Linux installations)
126
126
 
@@ -36,6 +36,9 @@ setup.py
36
36
  ./azapyGUI/SymbTableEntry.py
37
37
  ./azapyGUI/TimeSeriesViewWindow.py
38
38
  ./azapyGUI/ViewTip.py
39
+ ./azapyGUI/ViewTip_Ubuntu.py
40
+ ./azapyGUI/ViewTip_fade.py
41
+ ./azapyGUI/ViewTip_fast.py
39
42
  ./azapyGUI/WeightsWindow.py
40
43
  ./azapyGUI/__init__.py
41
44
  ./azapyGUI/azHelper.py
@@ -85,6 +88,9 @@ azapyGUI/SymbExtractWindow.py
85
88
  azapyGUI/SymbTableEntry.py
86
89
  azapyGUI/TimeSeriesViewWindow.py
87
90
  azapyGUI/ViewTip.py
91
+ azapyGUI/ViewTip_Ubuntu.py
92
+ azapyGUI/ViewTip_fade.py
93
+ azapyGUI/ViewTip_fast.py
88
94
  azapyGUI/WeightsWindow.py
89
95
  azapyGUI/__init__.py
90
96
  azapyGUI/azHelper.py
@@ -0,0 +1,7 @@
1
+ azapy>=1.2.5
2
+ numpy
3
+ pandas
4
+ matplotlib
5
+
6
+ [:platform_system == "Windows"]
7
+ xlsxwriter
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as readme:
5
5
 
6
6
  setuptools.setup(
7
7
  name="azapyGUI",
8
- version="0.0.2",
8
+ version="0.1.1",
9
9
  author="Mircea Marinescu",
10
10
  author_email="mircea.marinescu@outlook.com",
11
11
  description="GUI for azapy library - Financial Portfolio Optimization Algorithms",
@@ -27,10 +27,10 @@ setuptools.setup(
27
27
  packages=setuptools.find_packages(),
28
28
  python_requires=">=3.11",
29
29
  install_requires=[
30
- 'azapy>=1.2.4',
30
+ 'azapy>=1.2.5',
31
31
  'numpy',
32
32
  'pandas',
33
33
  'matplotlib',
34
- 'xlsxwriter'
34
+ 'xlsxwriter; platform_system=="Windows"'
35
35
  ],
36
36
  )
@@ -1,72 +0,0 @@
1
- import tkinter as tk
2
- from tkinter import ttk
3
- from typing import Union
4
-
5
- Widget = Union[tk.Widget, ttk.Widget]
6
-
7
- class ViewTip(tk.Toplevel):
8
- _FADE_INC:float = .07
9
- _FADE_MS :int = 20
10
-
11
- def __init__(self, master, **kwargs):
12
- tk.Toplevel.__init__(self, master)
13
-
14
- self.attributes('-alpha', 0, '-topmost', True)
15
- self.overrideredirect(1)
16
-
17
- style = dict(bd=2, relief='raised', font='Ariel 10', bg='#D4D4D4',
18
- anchor='w', justify='left')
19
- self.label = tk.Label(self, **{**style, **kwargs})
20
- self.label.grid(row=0, column=0, sticky='w')
21
-
22
- self.fout:bool = False
23
-
24
-
25
- def bind(self, target:Widget, text:str, **kwargs):
26
- target.bind('<Enter>', lambda e: self._fadein(0, text, e))
27
- target.bind('<Leave>', lambda e: self._fadeout(1 - ViewTip._FADE_INC, e))
28
-
29
-
30
- def _fadein(self, alpha:float, text:str=None, event:tk.Event=None):
31
- if event and text:
32
- if self.fout:
33
- self.attributes('-alpha', 0)
34
- self.fout = False
35
- self.label.configure(text=f'{text:^{len(text)+2}}')
36
- self.update()
37
-
38
- offset_x = event.widget.winfo_width()+2
39
- offset_y = int((event.widget.winfo_height() - self.label.winfo_height()) / 2)
40
-
41
- w = self.label.winfo_width()
42
- h = self.label.winfo_height()
43
- x = event.widget.winfo_rootx()+offset_x
44
- y = event.widget.winfo_rooty()+offset_y
45
-
46
- self.geometry(f'{w}x{h}+{x}+{y}')
47
-
48
- if not self.fout:
49
- self.attributes('-alpha', alpha)
50
-
51
- if alpha < 1:
52
- self.after(ViewTip._FADE_MS,
53
- lambda: self._fadein(min(alpha + ViewTip._FADE_INC, 1)))
54
-
55
-
56
- def _fadeout(self, alpha:float, event:tk.Event=None):
57
- if event:
58
- self.fout = True
59
-
60
- if self.fout:
61
- self.attributes('-alpha', alpha)
62
-
63
- if alpha > 0:
64
- self.after(ViewTip._FADE_MS,
65
- lambda: self._fadeout(max(alpha - ViewTip._FADE_INC, 0)))
66
-
67
-
68
- def turned(self, on=True):
69
- if on:
70
- self.deiconify()
71
- else:
72
- self.withdraw()
@@ -1,28 +0,0 @@
1
- import pathlib
2
- import json
3
-
4
- import azapyGUI.configSettings as configSettings
5
-
6
-
7
- def _fileMasterUserConfig():
8
- return pathlib.Path.home().joinpath(".azapyGUI/MasterUserConfig.json")
9
-
10
-
11
- def _readMasterUserConfig():
12
- out_file = _fileMasterUserConfig()
13
- try:
14
- with open(out_file, 'r') as fp:
15
- data = json.load(fp)
16
- except FileNotFoundError:
17
- data = configSettings.get_settings_default_all()
18
- out_file.parent.mkdir(exist_ok=True, parents=True)
19
- with open(out_file, 'w') as fp:
20
- json.dump(data, fp)
21
- return data
22
-
23
-
24
- def _saveMasterUserConfig(data):
25
- out_file = _fileMasterUserConfig()
26
- out_file.parent.mkdir(exist_ok=True, parents=True)
27
- with open(out_file, 'w') as fp:
28
- json.dump(data, fp)
@@ -1,5 +0,0 @@
1
- azapy>=1.2.4
2
- numpy
3
- pandas
4
- matplotlib
5
- xlsxwriter
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes