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
@@ -0,0 +1,213 @@
1
+ import tkinter as tk
2
+ from tkinter import ttk
3
+ from tkinter import filedialog
4
+
5
+ from copy import deepcopy
6
+
7
+ import azapyGUI.configSettings as configSettings
8
+ import azapyGUI.config as config
9
+ import azapyGUI.configMSG as configMSG
10
+ from azapyGUI.serviceMasterUserConfig import _saveMasterUserConfig
11
+
12
+ class AppSettingsPage(tk.Frame):
13
+ def __init__(self, master, category, title):
14
+ self._master = master
15
+ self._category = category
16
+ super().__init__(self._master)
17
+
18
+ self._window = self
19
+
20
+ frm = tk.LabelFrame(master=self._window, text=title, font=("Forte", 10))
21
+ frm.grid(row=0, column=0, padx=5, pady=5, sticky=tk.NSEW)
22
+ self._window.rowconfigure(0, weight=1)
23
+ self._window.columnconfigure(0, weight=1)
24
+
25
+ frm_btn = tk.Frame(master=self._window)
26
+ frm_btn.grid(row=1, column=0, padx=5, pady=5, sticky=tk.EW)
27
+
28
+ # on frm
29
+ frm_set = tk.Frame(master=frm)
30
+ frm_set.grid(row=0, column=0, padx=5, pady=5, sticky=tk.NS)
31
+ frm.rowconfigure(0, weight=1)
32
+
33
+ frm_view = tk.Frame(master=frm, width=150)
34
+ frm_view.grid(row=0, column=1, padx=5, pady=5, sticky=tk.NSEW)
35
+ frm.columnconfigure(1, weight=1)
36
+
37
+ # on frm_set
38
+ self._setDef = configSettings.settings_model[self._category]
39
+ self.settings = deepcopy(configSettings.MasterApplicationSettings)
40
+ row = 0
41
+ self._chk_val = {}
42
+ self._chk_btn = {}
43
+ for param, value in self._setDef.items():
44
+ match value["type"]:
45
+ case 'ButtonDir':
46
+ btn = tk.Button(master=frm_set, text=value['field'], width=18,
47
+ command=lambda pp=param: self._get_directory_func(pp))
48
+ btn.grid(row=row, column=0, padx=5, pady=5, sticky=tk.W)
49
+ config.tiptil.bind(btn, value["tip"])
50
+ row += 1
51
+ case 'Checkbutton':
52
+ chk_var = tk.BooleanVar(master=frm_set, value=self.settings[param])
53
+ chk_btn = tk.Checkbutton(master=frm_set, text=value["field"],
54
+ variable = chk_var,
55
+ onvalue = True, offvalue = False,
56
+ height=2, width=18,
57
+ command=lambda pp=param: self._chk_btn_func(pp),
58
+ anchor=tk.W)
59
+ chk_btn.grid(row=row, column=0, padx=5, pady=5, sticky=tk.W)
60
+ self._chk_val[param] = chk_var
61
+ self._chk_btn[param] = chk_btn
62
+ config.tiptil.bind(chk_btn, value["tip"])
63
+ row += 1
64
+ case 'MCheckbutton':
65
+ frm_chk = tk.LabelFrame(master=frm_set, text=value["field"])
66
+ frm_chk.grid(row=row, column=0, padx=5, pady=5, sticky=tk.W)
67
+ row += 1
68
+ row_chk = 0
69
+ self._chk_val[param] = {}
70
+ self._chk_btn[param] = {}
71
+ for param_chk, value_chk in value["values"].items():
72
+ chk_var = tk.BooleanVar(master=frm_chk,
73
+ value=True if param_chk in self.settings[param].keys() else False)
74
+ chk_btn = tk.Checkbutton(master=frm_chk, text=param_chk,
75
+ variable = chk_var,
76
+ onvalue = True, offvalue = False,
77
+ height=2, width=18,
78
+ command=lambda param=param, pp=param_chk: self._mchk_btn_func(param, pp),
79
+ anchor=tk.W)
80
+ chk_btn.grid(row=row_chk, column=0, padx=5, pady=0, sticky=tk.W)
81
+ self._chk_val[param][param_chk] = chk_var
82
+ self._chk_btn[param][param_chk] = chk_btn
83
+ row_chk += 1
84
+ case _:
85
+ # you should not be here
86
+ raise ValueError("Error: Unknown configSetting type")
87
+
88
+ # on frm_view
89
+ self._stv = ttk.Treeview(master=frm_view, selectmode="browse", show="tree")
90
+ self._stv.pack(padx=0, pady=0, expand=True, side=tk.LEFT, fill=tk.BOTH)
91
+ self._stv_write()
92
+
93
+ vscrlb = ttk.Scrollbar(master=frm_view,
94
+ orient ="vertical",
95
+ command = self._stv.yview)
96
+ vscrlb.pack(padx=0, pady=2, side=tk.RIGHT, fill=tk.Y)
97
+ self._stv.configure(yscrollcommand = vscrlb.set)
98
+
99
+ # on frm_btn
100
+ btn_cancel = tk.Button(master=frm_btn, text="Cancel/Exit", width=12,
101
+ command=self._btn_cancel_func)
102
+ btn_cancel.pack(padx=5, pady=5, side=tk.LEFT)
103
+
104
+ btn_save = tk.Button(master=frm_btn, text="Save", width=12,
105
+ command=self._btn_save_func)
106
+ btn_save.pack(padx=5, pady=5, side=tk.RIGHT)
107
+
108
+ btn_reset = tk.Button(master=frm_btn, text="Default Values", width=12,
109
+ command=self._btn_reset_func)
110
+ btn_reset.pack(padx=5, pady=5, side=tk.LEFT)
111
+
112
+
113
+ def _stv_write(self):
114
+ for kk in self._setDef.keys():
115
+ val = self.settings[kk]
116
+ item = self._stv.insert("", tk.END, text=self._setDef[kk]["field"] + ":", open=True)
117
+ if isinstance(val, dict):
118
+ for subkk, subval in val.items():
119
+ subitem = self._stv.insert(item, tk.END, text=subkk, open=True)
120
+ for subsubkk, subsubval in subval.items():
121
+ self._stv.insert(subitem, tk.END, text=subsubkk +" = "+ str(subsubval))
122
+ else:
123
+ self._stv.insert(item, tk.END, text=str(val))
124
+
125
+
126
+ def _stv_refresh(self):
127
+ for item in self._stv.get_children():
128
+ self._stv.delete(item)
129
+ self._stv_write()
130
+
131
+
132
+ def _get_directory_func(self, param=None):
133
+ title = self._setDef[param]["title"]
134
+ folder_selected = filedialog.askdirectory(parent=self._window, title=title)
135
+ if folder_selected:
136
+ self.settings[param] = folder_selected
137
+ self._stv_refresh()
138
+
139
+
140
+ def _chk_btn_func(self, param):
141
+ self.settings[param] = self._chk_val[param].get()
142
+ self._stv_refresh()
143
+
144
+
145
+ def _mchk_btn_func(self, param, pp):
146
+ if self._chk_val[param][pp].get():
147
+ self.settings[param][pp] = {}
148
+ for kk, vv in self._setDef[param]["values"][pp].items():
149
+ match vv['type']:
150
+ case 'str':
151
+ vpar = tk.simpledialog.askstring(pp, vv["field"],
152
+ parent=self._window,
153
+ initialvalue=vv["default"])
154
+ if vpar == '':
155
+ vpar = configSettings.get_envkey(pp)
156
+ if vpar is None:
157
+ msg = (configMSG._validate_provider_key_msg
158
+ +'\n'
159
+ + configSettings.get_envkey_valriable_name(pp))
160
+ tk.messagebox.showwarning(title="Warning", message=msg, parent=self._window)
161
+ del self.settings[param][pp]
162
+ self._chk_btn[param][pp].deselect()
163
+ return
164
+ self.settings[param][pp][kk] = vpar
165
+ case 'int':
166
+ vpar = tk.simpledialog.askinteger(pp, vv["field"],
167
+ parent=self._window,
168
+ initialvalue=vv["default"],
169
+ minvalue=1)
170
+ self.settings[param][pp][kk] = vpar
171
+ case 'float':
172
+ vpar = tk.simpledialog.askfloat(pp, vv["field"],
173
+ parent=self._window,
174
+ initialvalue=vv["default"],
175
+ minvalue=1)
176
+ self.settings[param][pp][kk] = vpar
177
+ case _:
178
+ # you should not be here
179
+ raise ValueError("Error: in AppSettingWindow::_chk_bth_func wrong type")
180
+ else:
181
+ del self.settings[param][pp]
182
+ self._stv_refresh()
183
+
184
+
185
+ def _btn_cancel_func(self):
186
+ if self._master.winfo_exists():
187
+ self._master.grab_release()
188
+ self._master.destroy()
189
+
190
+
191
+ def _btn_save_func(self):
192
+ configSettings.MasterApplicationSettings = deepcopy(self.settings)
193
+ _saveMasterUserConfig(configSettings.MasterApplicationSettings)
194
+ #self._btn_cancel_func()
195
+
196
+
197
+ def _btn_reset_func(self):
198
+ for kk, vv in self._setDef.items():
199
+ self.settings[kk] = deepcopy(vv["default"])
200
+ match vv["type"]:
201
+ case "Checkbutton":
202
+ if self.settings[kk]:
203
+ self._chk_btn[kk].select()
204
+ else:
205
+ self._chk_btn[kk].deselect()
206
+ case "MCheckbutton":
207
+ for ll in self._setDef[kk]["values"].keys():
208
+ if ll in self.settings[kk].keys():
209
+ self._chk_btn[kk][ll].select()
210
+ else:
211
+ self._chk_btn[kk][ll].deselect()
212
+ self._stv_refresh()
213
+
@@ -0,0 +1,101 @@
1
+ import tkinter as tk
2
+ from copy import deepcopy
3
+
4
+ import azapyGUI.config as config
5
+ import azapyGUI.configSettings as configSettings
6
+ from azapyGUI.serviceMasterUserConfig import _saveMasterUserConfig
7
+
8
+ class AppSettingsPageMisc(tk.Frame):
9
+ def __init__(self, master):
10
+ self._master = master
11
+ super().__init__(self._master)
12
+
13
+ self._window = self
14
+ self._category = "Miscellaneous"
15
+
16
+ title = "Miscellaneous"
17
+ frm_set = tk.LabelFrame(master=self._window, text=title, font=("Forte", 10))
18
+ frm_set.grid(row=0, column=0, padx=5, pady=5, sticky=tk.NSEW)
19
+ self._window.rowconfigure(0, weight=1)
20
+ self._window.columnconfigure(0, weight=1)
21
+ frm_set.columnconfigure(0, weight=1)
22
+ frm_set.columnconfigure(1, weight=1)
23
+
24
+ frm_btn = tk.Frame(master=self._window)
25
+ frm_btn.grid(row=1, column=0, padx=5, pady=5, sticky=tk.EW)
26
+
27
+ # on frm
28
+ self._setDef = configSettings.settings_model[self._category]
29
+ self.settings = deepcopy(configSettings.MasterApplicationSettings)
30
+ row = 0
31
+ self._chk_val = {}
32
+ self._chk_btn = {}
33
+ for param, value in self._setDef.items():
34
+ match value["type"]:
35
+ case 'Checkbutton':
36
+ lbl = tk.Label(master=frm_set, text=value["field"], anchor=tk.W)
37
+ lbl.grid(row=row, column=0, padx=5, pady=5, sticky=tk.EW)
38
+ chk_var = tk.BooleanVar(master=frm_set, value=self.settings[param])
39
+ chk_btn = tk.Checkbutton(master=frm_set, variable = chk_var,
40
+ onvalue = True, offvalue = False,
41
+ height=2, width=18, anchor=tk.W)
42
+ chk_btn.grid(row=row, column=1, padx=5, pady=5, sticky=tk.W)
43
+ self._chk_val[param] = chk_var
44
+ self._chk_btn[param] = chk_btn
45
+ config.tiptil.bind(chk_btn, value["tip"])
46
+ row += 1
47
+ case 'Entry':
48
+ lbl = tk.Label(master=frm_set, text=value["field"], anchor=tk.W)
49
+ lbl.grid(row=row, column=0, padx=5, pady=5, sticky=tk.W)
50
+ ent_var = tk.StringVar(master=frm_set, value=self.settings[param])
51
+ ent = tk.Entry(master=frm_set, textvariable=ent_var, validate='key', width=10)
52
+ ent['validatecommand'] = (ent.register(value["validate"]),'%S','%d','%P')
53
+ ent.grid(row=row, column=1, padx=5, pady=5, sticky=tk.W)
54
+ self._chk_val[param] = ent_var
55
+ config.tiptil.bind(ent, value["tip"])
56
+ row += 1
57
+ case _:
58
+ # you should not be here
59
+ raise ValueError("Error: Unknown configSetting type")
60
+
61
+ # on frm_btn
62
+ btn_cancel = tk.Button(master=frm_btn, text="Cancel/Exit", width=12,
63
+ command=self._btn_cancel_func)
64
+ btn_cancel.pack(padx=5, pady=5, side=tk.LEFT)
65
+
66
+ btn_save = tk.Button(master=frm_btn, text="Save", width=12,
67
+ command=self._btn_save_func)
68
+ btn_save.pack(padx=5, pady=5, side=tk.RIGHT)
69
+
70
+ btn_reset = tk.Button(master=frm_btn, text="Default Values", width=12,
71
+ command=self._btn_reset_func)
72
+ btn_reset.pack(padx=5, pady=5, side=tk.LEFT)
73
+
74
+
75
+ def _btn_cancel_func(self):
76
+ if self._master.winfo_exists():
77
+ self._master.grab_release()
78
+ self._master.destroy()
79
+
80
+
81
+ def _btn_reset_func(self):
82
+ for kk, vv in self._setDef.items():
83
+ self.settings[kk] = deepcopy(vv["default"])
84
+ match vv["type"]:
85
+ case "Checkbutton":
86
+ if self.settings[kk]:
87
+ self._chk_btn[kk].select()
88
+ else:
89
+ self._chk_btn[kk].deselect()
90
+ case "Entry":
91
+ self._chk_val[kk].set(self.settings[kk])
92
+
93
+
94
+ def _btn_save_func(self):
95
+ for param in self._chk_val.keys():
96
+ self.settings[param] = self._chk_val[param].get()
97
+ configSettings.MasterApplicationSettings = deepcopy(self.settings)
98
+ _saveMasterUserConfig(configSettings.MasterApplicationSettings)
99
+ config.tiptil.turned(on=configSettings.MasterApplicationSettings["ShowTips"])
100
+
101
+
@@ -0,0 +1,52 @@
1
+ import tkinter as tk
2
+ from tkinter import ttk
3
+ import webbrowser
4
+
5
+ import azapyGUI.configSettings as configSettings
6
+ import azapyGUI.configHelps as configHelps
7
+ from azapyGUI.AppSettingsPage import AppSettingsPage
8
+ from azapyGUI.AppSettingsPageMisc import AppSettingsPageMisc
9
+
10
+ class AppSettingsWindow:
11
+ def __init__(self, master):
12
+ self._master = master
13
+
14
+ self._window = tk.Toplevel()
15
+ title = f"User Default Settings v.{configSettings.Version}"
16
+ self._window.title(title)
17
+ self._window.focus_set()
18
+ self._window.grab_set()
19
+ self._window.protocol("WM_DELETE_WINDOW", self._on_exit)
20
+
21
+ menubar = tk.Menu(self._window)
22
+ filemenu = tk.Menu(menubar, tearoff=0)
23
+ filemenu.add_command(label='Help', command=self._menu_help_func)
24
+ menubar.add_cascade(label='Help', menu=filemenu)
25
+ self._window.config(menu=menubar)
26
+
27
+ ntb = ttk.Notebook(master=self._window)
28
+ ntb.pack(expand=True, fill=tk.BOTH)
29
+
30
+ category = "Directors"
31
+ title = "Default Directories"
32
+ pg_dirctor = AppSettingsPage(master=self._window, category=category, title=title)
33
+ ntb.add(pg_dirctor, text="Directories")
34
+
35
+ category = "MkTData"
36
+ title = "Market Data"
37
+ pg_mktdata = AppSettingsPage(master=self._window, category=category, title=title)
38
+ ntb.add(pg_mktdata, text="Market Data")
39
+
40
+ pg_misc = AppSettingsPageMisc(master=self._window)
41
+ ntb.add(pg_misc, text="Miscellaneous")
42
+
43
+
44
+ def _on_exit(self):
45
+ self._window.grab_release()
46
+ if self._master.winfo_exists():
47
+ self._master.focus_set()
48
+ self._window.destroy()
49
+
50
+
51
+ def _menu_help_func(self):
52
+ webbrowser.open_new_tab(configHelps._Settings_panel_help)
@@ -0,0 +1,166 @@
1
+ import tkinter as tk
2
+ import time
3
+ import azapy as az
4
+
5
+ import azapyGUI.config as config
6
+ import azapyGUI.configModels as configModels
7
+ from azapyGUI.GetMktData import GetMktData
8
+
9
+
10
+ class BacktestComputation:
11
+ def __init__(self, master, pnames, sdate, edate, noffset, fixoffset,
12
+ capital, nsh_round, provider, force):
13
+ self._master = master
14
+ self._pnames = pnames
15
+ self._sdate = sdate
16
+ self._edate = edate
17
+ self._noffset = noffset
18
+ self._fixoffset = fixoffset
19
+ self._capital = capital
20
+ self._nsh_round = nsh_round
21
+ self._provider = provider
22
+ self._force = force
23
+
24
+ self.backtest = {}
25
+ self.backtest_error = []
26
+
27
+ def collectMktData(self):
28
+ symbols = set()
29
+ for pname in self._pnames:
30
+ port = config.PortDataDict[pname]
31
+ symbols.update(port.symbols)
32
+
33
+ gmd = GetMktData(self._provider, self._force)
34
+ gmd.getMkTDataSymb(list(symbols), self._sdate, self._edate)
35
+ self.symbols = gmd.symbols
36
+ errorsymb = set(gmd.errorsymb)
37
+
38
+ if len(errorsymb) == 0: return True
39
+ porterror = []
40
+ for pname in self._pnames:
41
+ port = config.PortDataDict[pname]
42
+ res = errorsymb.intersection(port.symbols)
43
+ if len(res) > 0:
44
+ porterror.append(pname)
45
+ config.PortDataDict[pname].status = 'Unset'
46
+ port = set(self._pnames).intersection(porterror)
47
+ msg = (f"The following symbols, {errorsymb},\n"
48
+ f"cannot be retrieved from the provider {self._provider}\n"
49
+ f"Abort the backtesting for portfolios {porterror}.")
50
+ if len(port) == 0:
51
+ msg += "Abort backtesting!"
52
+ tk.messagebox.showwarning("Warning", message=msg, parent=self._master)
53
+ return False
54
+
55
+ msg += ("Do you want to continue with the \n"
56
+ f"backtesting for {port}?")
57
+ ask = tk.messagebox.askyesno("Warning", message=msg)
58
+ if ask == 'yes':
59
+ self._pnames = list[port]
60
+ return True
61
+
62
+ return False
63
+
64
+
65
+ def compute(self, time_port):
66
+ for pname in self._pnames:
67
+
68
+ tic = time.perf_counter()
69
+ res = self._computePort(pname)
70
+ toc = time.perf_counter()
71
+
72
+ msg = str(round(toc - tic, 4)) + 's' if res else 'error'
73
+ time_port[pname].set(msg)
74
+ self._master.update()
75
+
76
+ if not res:
77
+ self.backtest_error.append(pname)
78
+ else:
79
+ self.backtest[pname] = self._btest
80
+
81
+ return len(self.backtest_error) == 0
82
+
83
+
84
+ def _computePort(self, pname):
85
+ optname = list(config.PortDataDict[pname].optimizer.keys())[0]
86
+ if configModels.get_comptype(optname) == 'pipe':
87
+ return self._computePort_pipe(pname)
88
+ else:
89
+ return self._computePort_standalone(pname)
90
+
91
+
92
+ def _computePort_standalone(self, pname):
93
+ portdata = config.PortDataDict[pname]
94
+ mktdata = {symb: config.MktDataDict[symb].get_mktdata().copy() for symb in portdata.symbols}
95
+
96
+ optname = list(config.PortDataDict[pname].optimizer.keys())[0]
97
+ fmname = configModels.get_model_family(optname)
98
+ mname = configModels.portfolio_model_family[fmname][optname]['azapy'][1]
99
+ param = portdata.optimizer[optname]['param']
100
+ freq = param['freq']
101
+ hlength = 0
102
+ pp = getattr(az, mname)(mktdata=mktdata,
103
+ sdate=self._sdate,
104
+ edate=self._edate,
105
+ pname=pname,
106
+ pcolname='close',
107
+ capital=self._capital,
108
+ freq=freq,
109
+ noffset=self._noffset,
110
+ fixoffset=self._fixoffset,
111
+ histoffset=hlength,
112
+ calendar=config.calendar,
113
+ nsh_round=self._nsh_round,
114
+ )
115
+ pp.set_model(**param)
116
+ self._btest = pp
117
+ return (pp.status == 0)
118
+
119
+
120
+ def _computePort_pipe(self, pname):
121
+ portdata = config.PortDataDict[pname]
122
+ mktdata = {symb: config.MktDataDict[symb].mktdata.copy() for symb in portdata.symbols}
123
+ model = []
124
+ hlength = 0
125
+
126
+ sel_list = [None] * len(portdata.selectors.keys())
127
+ for name, vv in portdata.selectors.items():
128
+ sel_list[vv['index']] = vv
129
+ for vv in sel_list:
130
+ mname = configModels.selector_models[vv['name']]['azapy']
131
+ oo = getattr(az, mname)
132
+ moo = oo(**vv['param'])
133
+ model.append(moo)
134
+ if 'hlength' in vv['param'].keys():
135
+ hlength = max(hlength, vv['param']['hlength'])
136
+
137
+ for mopt, vv in portdata.optimizer.items():
138
+ fmname = configModels.get_model_family(vv['name'])
139
+ mname = configModels.portfolio_model_family[fmname][vv['name']]['azapy']
140
+ if mname == 'EWPEngine':
141
+ model.append('EWP')
142
+ else:
143
+ oo = getattr(az, mname)
144
+ moo = oo(**vv['param'])
145
+ model.append(moo)
146
+ hlength = max(hlength, vv['param']['hlength'])
147
+ freq = vv['param']['freq']
148
+
149
+ pipe = az.ModelPipeline(model)
150
+
151
+ pp = az.Port_Generator(mktdata=mktdata,
152
+ sdate=self._sdate,
153
+ edate=self._edate,
154
+ pname=pname,
155
+ pcolname='close',
156
+ capital=self._capital,
157
+ freq=freq,
158
+ noffset=self._noffset,
159
+ fixoffset=self._fixoffset,
160
+ histoffset=hlength,
161
+ calendar=config.calendar,
162
+ nsh_round=self._nsh_round,
163
+ )
164
+ pp.set_model(pipe)
165
+ self._btest = pp
166
+ return (pp.status == 0)