PyAlgoEngine 0.7.7a1__tar.gz → 0.7.7a2__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 (53) hide show
  1. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/PKG-INFO +1 -1
  2. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/PyAlgoEngine.egg-info/PKG-INFO +1 -1
  3. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/__init__.py +1 -1
  4. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/apps/sim_input/client.py +133 -41
  5. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/LICENSE +0 -0
  6. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/PyAlgoEngine.egg-info/SOURCES.txt +0 -0
  7. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/PyAlgoEngine.egg-info/dependency_links.txt +0 -0
  8. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/PyAlgoEngine.egg-info/requires.txt +0 -0
  9. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/PyAlgoEngine.egg-info/top_level.txt +0 -0
  10. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/README.md +0 -0
  11. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/apps/__init__.py +0 -0
  12. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/apps/backtest/__init__.py +0 -0
  13. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/apps/backtest/doc_server.py +0 -0
  14. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/apps/backtest/tester.py +0 -0
  15. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/apps/backtest/web_app.py +0 -0
  16. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/apps/bokeh_server.py +0 -0
  17. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/apps/demo/__init__.py +0 -0
  18. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/apps/demo/test.py +0 -0
  19. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/apps/sim_input/__init__.py +0 -0
  20. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/apps/sim_input/sim_keyboard.py +0 -0
  21. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/apps/sim_input/sim_mouse.py +0 -0
  22. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/apps/sim_input/window.py +0 -0
  23. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/backtest/__init__.py +0 -0
  24. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/backtest/__main__.py +0 -0
  25. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/backtest/metrics.py +0 -0
  26. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/backtest/replay.py +0 -0
  27. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/backtest/sim_match.py +0 -0
  28. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/base/__init__.py +0 -0
  29. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/base/console_utils.py +0 -0
  30. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/base/finance_decimal.py +0 -0
  31. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/base/market_buffer.py +0 -0
  32. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/base/market_utils.py +0 -0
  33. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/base/market_utils_nt.py +0 -0
  34. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/base/market_utils_posix.py +0 -0
  35. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/base/technical_analysis.py +0 -0
  36. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/base/telemetrics.py +0 -0
  37. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/base/trade_utils.py +0 -0
  38. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/engine/__init__.py +0 -0
  39. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/engine/algo_engine.py +0 -0
  40. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/engine/event_engine.py +0 -0
  41. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/engine/market_engine.py +0 -0
  42. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/engine/trade_engine.py +0 -0
  43. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/monitor/__init__.py +0 -0
  44. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/monitor/advanced_data_interface.py +0 -0
  45. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/profile/__init__.py +0 -0
  46. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/profile/cn.py +0 -0
  47. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/strategy/__init__.py +0 -0
  48. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/strategy/strategy_engine.py +0 -0
  49. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/utils/__init__.py +0 -0
  50. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/utils/commit_regularizer.py +0 -0
  51. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/algo_engine/utils/data_utils.py +0 -0
  52. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/setup.cfg +0 -0
  53. {pyalgoengine-0.7.7a1 → pyalgoengine-0.7.7a2}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyAlgoEngine
3
- Version: 0.7.7a1
3
+ Version: 0.7.7a2
4
4
  Summary: Basic algo engine
5
5
  Home-page: https://github.com/BolunHan/PyAlgoEngine
6
6
  Author: Bolun.Han
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyAlgoEngine
3
- Version: 0.7.7a1
3
+ Version: 0.7.7a2
4
4
  Summary: Basic algo engine
5
5
  Home-page: https://github.com/BolunHan/PyAlgoEngine
6
6
  Author: Bolun.Han
@@ -1,4 +1,4 @@
1
- __version__ = "0.7.7.alpha1"
1
+ __version__ = "0.7.7.alpha2"
2
2
 
3
3
  import logging
4
4
  import os
@@ -1,7 +1,7 @@
1
1
  __package__ = 'algo_engine.apps.sim_input'
2
2
 
3
3
  import abc
4
- import threading
4
+ from threading import Thread
5
5
  import time
6
6
  import tkinter
7
7
  from collections.abc import Callable, Iterable
@@ -63,53 +63,143 @@ class Action(object):
63
63
 
64
64
 
65
65
  class AutoWorkClient(object, metaclass=abc.ABCMeta):
66
- def __init__(self, root=None):
66
+ def __init__(self, root=None, **kwargs):
67
67
  self.root = root if root is not None else tkinter.Tk()
68
- self.root.title("Structured GUI Client")
69
- self.root.geometry("600x500")
68
+ self.root.title(kwargs.get('title', "Structured GUI Client"))
69
+
70
+ self.actions: dict[int, list[Action]] = {}
71
+ self.layout = {}
70
72
 
71
73
  # State variables
72
74
  self.worker_thread = None
73
75
  self.running = False
74
76
 
75
- # Create button
76
- self.button = ttk.Button(root, text="Takeover Input", command=self.toggle_auto_work)
77
- self.button.pack(pady=10)
78
-
79
- # Create table
80
- self.table = ttk.Treeview(
81
- root,
82
- columns=("Action", "Status", "Comments"),
83
- show="tree headings",
84
- height=20
85
- )
86
- self.table.heading("Action", text="Action")
87
- self.table.heading("Status", text="Status")
88
- self.table.heading("Comments", text="Comments")
89
- self.table.pack(padx=10, pady=10, fill="both", expand=True)
77
+ self.render_layout()
90
78
 
91
- self.actions: dict[int, list[Action]] = {}
79
+ def render_layout(self):
80
+ # No fixed geometry, letting it resize
81
+ # self.root.geometry("600x500")
82
+
83
+ # Grid(0, 0): Create button
84
+ button_takeover = self.layout['button_takeover'] = ttk.Button(self.root, text="Takeover Input", command=self.toggle_auto_work)
85
+ button_takeover.grid(row=0, column=0, columnspan=2, pady=10, sticky="ew")
86
+
87
+ # Grid(1, 0): Mock button
88
+ button_mock = self.layout['button_mock'] = ttk.Button(self.root, text="Mock Action", command=self.toggle_mock)
89
+ button_mock.grid(row=1, column=0, padx=10, pady=10, sticky="ew")
90
+
91
+ # Grid(1, 1): Dropdown for action selection
92
+ action_selected = self.layout['action_selected'] = tkinter.StringVar()
93
+ action_dropdown = self.layout['action_dropdown'] = ttk.Combobox(self.root, textvariable=action_selected, state="readonly")
94
+ action_dropdown.grid(row=1, column=1, padx=10, pady=10, sticky="ew")
95
+
96
+ # Grid(2, 0): Create table
97
+ action_table = self.layout['action_table'] = ttk.Treeview(self.root, columns=("Action", "Status", "Comments"), show="tree headings")
98
+ action_table.heading("Action", text="Action")
99
+ action_table.heading("Status", text="Status")
100
+ action_table.heading("Comments", text="Comments")
101
+ action_table.grid(row=2, column=0, columnspan=2, padx=10, pady=10, sticky="nsew")
102
+
103
+ # Make the window resize properly by configuring grid weights
104
+ self.root.grid_columnconfigure(0, weight=1, minsize=200) # Adjust minsize for column 0
105
+ self.root.grid_columnconfigure(1, weight=1, minsize=200) # Adjust minsize for column 1
106
+ self.root.grid_rowconfigure(2, weight=1) # Make row 2 expand with the window
92
107
 
93
108
  @abc.abstractmethod
94
109
  def listen_signal(self) -> int:
95
110
  ...
96
111
 
97
112
  def register_action(self, action: Action, signal: int):
98
- if signal in self.actions:
99
- self.actions[signal].append(action)
100
- else:
101
- self.actions[signal] = [action]
113
+ self.actions.setdefault(signal, []).append(action)
114
+
115
+ # Update the dropdown with all registered actions.
116
+ all_actions = [f"Signal {signal} - {action.name}" for signal, actions in self.actions.items() for action in actions]
117
+ action_dropdown = self.layout['action_dropdown']
118
+ action_dropdown["values"] = all_actions
119
+
120
+ def mock_action(self, action: Action, timeout: float = 3.):
121
+ """Mock the execution of an action on a transparent test ground."""
122
+ self.root.iconify()
123
+
124
+ # Create a borderless, transparent test ground window
125
+ testground = tkinter.Toplevel(self.root)
126
+ # testground.overrideredirect(True) # Remove all window borders and decorations
127
+
128
+ # Get screen dimensions and set the testground window to cover the entire screen
129
+ # screen_width = self.root.winfo_screenwidth()
130
+ # screen_height = self.root.winfo_screenheight()
131
+ # testground.geometry(f"{screen_width}x{screen_height}+0+0")
132
+
133
+ # Make the window semi-transparent and ensure it stays on top
134
+ testground.attributes("-alpha", 0.5) # Set transparency to 50%
135
+ testground.attributes("-fullscreen", True)
136
+ testground.attributes("-topmost", True) # Ensure it stays above other windows
137
+
138
+ # Force the window manager to render the window completely
139
+ testground.lift() # Bring it to the front
140
+ testground.focus_force() # Force focus to this window
141
+
142
+ # Add a label to display input history
143
+ input_history = tkinter.Listbox(testground, font=("Courier", 14))
144
+ input_history.pack(fill="both", expand=True, padx=20, pady=20)
145
+ input_history.insert("active", f"Mocking {action.name}")
146
+ testground.update_idletasks()
147
+
148
+ # Simulate action execution
149
+ for step in action.steps:
150
+ # Display the step name in the input history
151
+ input_history.insert("end", f"Executing Step: {step['name']}")
152
+ input_history.insert("end", f"Comments: {step.get('comments', 'No comments')}")
153
+ input_history.insert("end", "-" * 50)
154
+ input_history.see("end")
155
+ testground.update_idletasks()
156
+
157
+ # Simulate mouse and keyboard inputs
158
+ procedure = step['procedure']
159
+ args = step.get('args', [])
160
+ kwargs = step.get('kwargs', {})
161
+ try:
162
+ procedure(*args, **kwargs)
163
+ except Exception as e:
164
+ input_history.insert("end", f"Error: {str(e)}")
165
+ input_history.see("end")
166
+
167
+ # Simulate delay between steps
168
+
169
+ # Wait 3 seconds, then close the test ground and restore the client window
170
+ time.sleep(timeout)
171
+ testground.destroy()
102
172
 
103
173
  def toggle_auto_work(self):
104
174
  """Toggle the daemon thread to start or stop auto work."""
105
175
  if not self.running:
106
176
  self.running = True
107
- self.button.config(text="Release Control")
108
- self.worker_thread = threading.Thread(target=self.auto_work, daemon=True)
177
+ self.layout['button_takeover'].config(text="Release Control")
178
+ self.worker_thread = Thread(target=self.auto_work, daemon=True)
109
179
  self.worker_thread.start()
110
180
  else:
111
181
  self.running = False
112
- self.button.config(text="Takeover Input")
182
+ self.layout['button_takeover'].config(text="Takeover Input")
183
+
184
+ def toggle_mock(self):
185
+ """Mock the action selected in the dropdown."""
186
+ selected_name = self.layout['action_selected'].get()
187
+ if not selected_name:
188
+ LOGGER.warning("No action selected to mock!")
189
+ return
190
+
191
+ selected_action = None
192
+ for signal, actions in self.actions.items():
193
+ for action in actions:
194
+ if f"Signal {signal} - {action.name}" == selected_name:
195
+ selected_action = action
196
+ break
197
+
198
+ if selected_action is None:
199
+ LOGGER.warning(f"Action '{selected_name}' not found!")
200
+ return
201
+
202
+ self.mock_action(action=selected_action)
113
203
 
114
204
  def auto_work(self):
115
205
  """Generate data for the table in a loop."""
@@ -150,19 +240,20 @@ class AutoWorkClient(object, metaclass=abc.ABCMeta):
150
240
 
151
241
  def update_table(self, actions: list[Action]):
152
242
  """Render the table based on the provided actions."""
153
- self.table.delete(*self.table.get_children()) # Clear existing rows
243
+ action_table = self.layout['action_table']
244
+ action_table.delete(*action_table.get_children()) # Clear existing rows
154
245
 
155
246
  for action_idx, action in enumerate(actions):
156
247
  prefix = chr(0x250C)
157
248
  # Insert the parent row
158
- parent_id = self.table.insert(
249
+ parent_id = action_table.insert(
159
250
  "", "end", iid=action_idx, values=(f"{prefix} {action.name}", "Pending", "")
160
251
  )
161
252
 
162
253
  # Insert child rows for steps
163
254
  for step_idx, step in enumerate(action.steps):
164
255
  prefix = f'{chr(0x251C) if step_idx < len(action.steps) - 1 else chr(0x2514)}{chr(0x2500)}'
165
- self.table.insert(
256
+ action_table.insert(
166
257
  parent_id,
167
258
  "end",
168
259
  iid=f"{action_idx}-{step_idx}",
@@ -171,7 +262,7 @@ class AutoWorkClient(object, metaclass=abc.ABCMeta):
171
262
  )
172
263
 
173
264
  # Expand parent row by default
174
- self.table.item(parent_id, open=True)
265
+ action_table.item(parent_id, open=True)
175
266
 
176
267
  # Auto-adjust column widths
177
268
  self.adjust_column_widths()
@@ -179,26 +270,27 @@ class AutoWorkClient(object, metaclass=abc.ABCMeta):
179
270
  def update_status(self, parent_id: int, child_id: int = None, status: str = "Pending"):
180
271
  """Update the status of the specified row."""
181
272
  row_id = f"{parent_id}" if child_id is None else f"{parent_id}-{child_id}"
182
- values = self.table.item(row_id, "values")
273
+ action_table = self.layout['action_table']
274
+ values = action_table.item(row_id, "values")
183
275
 
184
276
  # Select the row if the status is "Executing"
185
277
  match status:
186
278
  case "Executing":
187
- self.table.selection_set(row_id)
188
- self.table.see(row_id) # Ensure the row is visible
279
+ action_table.selection_set(row_id)
280
+ action_table.see(row_id) # Ensure the row is visible
189
281
 
190
- self.table.item(row_id, values=(values[0], status, values[2]))
282
+ action_table.item(row_id, values=(values[0], status, values[2]))
191
283
 
192
284
  def adjust_column_widths(self):
193
285
  """Automatically adjust column widths based on content."""
286
+ action_table = self.layout['action_table']
287
+ action_table.column("#0", width=30, minwidth=30, stretch=False)
194
288
 
195
- self.table.column("#0", width=30, minwidth=30, stretch=False)
196
-
197
- for col in self.table["columns"]:
289
+ for col in action_table["columns"]:
198
290
  max_width = max(
199
- [len(str(self.table.set(item, col))) for item in self.table.get_children()] + [len(col)]
291
+ [len(str(action_table.set(item, col))) for item in action_table.get_children()] + [len(col)]
200
292
  )
201
- self.table.column(col, width=max_width * 10, minwidth=30, stretch=True) # Scale width for readability
293
+ action_table.column(col, width=max_width * 10, minwidth=30, stretch=True) # Scale width for readability
202
294
 
203
295
 
204
296
  class ExampleClient(AutoWorkClient):
@@ -249,5 +341,5 @@ def main():
249
341
 
250
342
 
251
343
  if __name__ == "__main__":
252
- t = threading.Thread(target=main, daemon=False)
344
+ t = Thread(target=main, daemon=False)
253
345
  t.start()
File without changes
File without changes
File without changes
File without changes