pkscreener 0.46.20250210.703__cp312-cp312-win_amd64.whl → 0.46.20250213.705__cp312-cp312-win_amd64.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 (60) hide show
  1. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/README.txt +9 -7
  2. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/MarketMonitor.py +80 -33
  3. pkscreener-0.46.20250213.705.data/purelib/pkscreener/classes/__init__.py +1 -0
  4. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/globals.py +6 -3
  5. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/pkscreenerbot.py +285 -210
  6. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/requirements.txt +1 -1
  7. {pkscreener-0.46.20250210.703.dist-info → pkscreener-0.46.20250213.705.dist-info}/METADATA +11 -9
  8. pkscreener-0.46.20250213.705.dist-info/RECORD +58 -0
  9. pkscreener-0.46.20250210.703.data/purelib/pkscreener/classes/__init__.py +0 -1
  10. pkscreener-0.46.20250210.703.dist-info/RECORD +0 -58
  11. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/Disclaimer.txt +0 -0
  12. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/LICENSE-Others.txt +0 -0
  13. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/LICENSE.txt +0 -0
  14. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/LogoWM.txt +0 -0
  15. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/__init__.py +0 -0
  16. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/ArtTexts.py +0 -0
  17. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/AssetsManager.py +0 -0
  18. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/Backtest.py +0 -0
  19. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/Barometer.py +0 -0
  20. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/BaseScreeningStatistics.py +0 -0
  21. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/CandlePatterns.py +0 -0
  22. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/Changelog.py +0 -0
  23. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/ConfigManager.py +0 -0
  24. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/ConsoleMenuUtility.py +0 -0
  25. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/ConsoleUtility.py +0 -0
  26. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/Fetcher.py +0 -0
  27. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/GlobalStore.py +0 -0
  28. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/ImageUtility.py +0 -0
  29. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/MarketStatus.py +0 -0
  30. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/MenuOptions.py +0 -0
  31. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/Messenger.py +0 -0
  32. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/OtaUpdater.py +0 -0
  33. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/PKAnalytics.py +0 -0
  34. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/PKDataService.py +0 -0
  35. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/PKDemoHandler.py +0 -0
  36. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/PKMarketOpenCloseAnalyser.py +0 -0
  37. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/PKPremiumHandler.py +0 -0
  38. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/PKScanRunner.py +0 -0
  39. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/PKScheduledTaskProgress.py +0 -0
  40. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/PKScheduler.py +0 -0
  41. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/PKSpreadsheets.py +0 -0
  42. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/PKTask.py +0 -0
  43. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/PKUserRegistration.py +0 -0
  44. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/Pktalib.py +0 -0
  45. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/Portfolio.py +0 -0
  46. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/PortfolioXRay.py +0 -0
  47. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/ScreeningStatistics.py +0 -0
  48. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/StockScreener.py +0 -0
  49. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/StockSentiment.py +0 -0
  50. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/UserMenuChoicesHandler.py +0 -0
  51. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/Utility.py +0 -0
  52. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/WorkflowManager.py +0 -0
  53. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/classes/keys.py +0 -0
  54. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/courbd.ttf +0 -0
  55. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/pkscreener.ini +0 -0
  56. {pkscreener-0.46.20250210.703.data → pkscreener-0.46.20250213.705.data}/purelib/pkscreener/pkscreenercli.py +0 -0
  57. {pkscreener-0.46.20250210.703.dist-info → pkscreener-0.46.20250213.705.dist-info}/LICENSE +0 -0
  58. {pkscreener-0.46.20250210.703.dist-info → pkscreener-0.46.20250213.705.dist-info}/WHEEL +0 -0
  59. {pkscreener-0.46.20250210.703.dist-info → pkscreener-0.46.20250213.705.dist-info}/entry_points.txt +0 -0
  60. {pkscreener-0.46.20250210.703.dist-info → pkscreener-0.46.20250213.705.dist-info}/top_level.txt +0 -0
@@ -4,8 +4,8 @@
4
4
  | [![MADE-IN-INDIA][MADE-IN-INDIA-badge]][MADE-IN-INDIA] | [![GitHub release (latest by date)][GitHub release (latest by date)-badge]][GitHub release (latest by date)] | [![Downloads][Downloads-badge]][Downloads] | ![latest download][Latest-Downloads-badge] | [![Docker Pulls][Docker Pulls-badge]][Docker Status] |
5
5
  | :-------------: | :-----------------: | :-----------------: | :-----------------: | :-----------------: |
6
6
  | Platforms | [![Windows][Windows-badge]][Windows] | [![Linux(x64)][Linux-badge_x64]][Linux_x64] [![Linux(arm64)][Linux-badge_arm64]][Linux_arm64] | [![Mac OS(x64)][Mac OS-badge_x64]][Mac OS_x64] [![Mac OS(arm64)][Mac OS-badge_arm64]][Mac OS_arm64] | [![Docker Status][Docker Status-badge]][Docker Status] |
7
- | Package / Docs | [![Documentation][Documentation-badge]][Documentation] | [![PyPI][pypi-badge]][pypi] | [![is wheel][wheel-badge]][pypi] | ![github license][github-license] |
8
- | Tests | [![CodeFactor][Codefactor-badge]][Codefactor] | [![Coverage Status][Coverage-Status-badge]][Coverage-Status] | [![codecov][codecov-badge]][codecov] | [![After Market][After Market-badge]][After Market] |
7
+ | Package / Docs | [![Documentation][Documentation-badge]][Documentation] [![OpenSSF Best Practices][OpenSSF-Badge]][OpenSSF-pkscreener] | [![PyPI][pypi-badge]][pypi] | [![is wheel][wheel-badge]][pypi] | ![github license][github-license] |
8
+ | Tests/Code-Quality | [![CodeFactor][Codefactor-badge]][Codefactor] | [![Coverage Status][Coverage-Status-badge]][Coverage-Status] | [![codecov][codecov-badge]][codecov] | [![After Market][After Market-badge]][After Market] |
9
9
 
10
10
  ## What is PKScreener?
11
11
  | Telegram Alerts | Nifty AI Prediction | Scheduling Cron Jobs | On-Demand Telegram Bot | Backtesting / Growth of 10k|
@@ -328,15 +328,15 @@ After you have finished the run, go to that copied path, zip the contents of the
328
328
  [MADE-IN-INDIA-badge]: https://img.shields.io/badge/MADE%20WITH%20%E2%9D%A4%20IN-INDIA-orange
329
329
  [MADE-IN-INDIA]: https://en.wikipedia.org/wiki/India
330
330
  [Windows-badge]: https://img.shields.io/badge/Windows-0078D6?logo=windows&logoColor=white
331
- [Windows]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250210.702/pkscreenercli.exe
331
+ [Windows]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250212.704/pkscreenercli.exe
332
332
  [Linux-badge_x64]: https://img.shields.io/badge/Linux(x64)-FCC624?logo=linux&logoColor=black
333
- [Linux_x64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250210.702/pkscreenercli_x64.bin
333
+ [Linux_x64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250212.704/pkscreenercli_x64.bin
334
334
  [Linux-badge_arm64]: https://img.shields.io/badge/Linux(arm64)-FCC624?logo=linux&logoColor=black
335
- [Linux_arm64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250210.702/pkscreenercli_arm64.bin
335
+ [Linux_arm64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250212.704/pkscreenercli_arm64.bin
336
336
  [Mac OS-badge_x64]: https://img.shields.io/badge/mac%20os(x64)-D3D3D3?logo=apple&logoColor=000000
337
- [Mac OS_x64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250210.702/pkscreenercli_x64.run
337
+ [Mac OS_x64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250212.704/pkscreenercli_x64.run
338
338
  [Mac OS-badge_arm64]: https://img.shields.io/badge/mac%20os(arm64)-D3D3D3?logo=apple&logoColor=000000
339
- [Mac OS_arm64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250210.702/pkscreenercli_arm64.run
339
+ [Mac OS_arm64]: https://github.com/pkjmesra/PKScreener/releases/download/0.46.20250212.704/pkscreenercli_arm64.run
340
340
  [GitHub release (latest by date)-badge]: https://img.shields.io/github/v/release/pkjmesra/PKScreener
341
341
  [GitHub release (latest by date)]: https://github.com/pkjmesra/PKScreener/releases/latest
342
342
  [pypi-badge]: https://img.shields.io/pypi/v/pkscreener.svg?style=flat-square
@@ -372,6 +372,8 @@ After you have finished the run, go to that copied path, zip the contents of the
372
372
  [New Release]: https://github.com/pkjmesra/PKScreener/actions/workflows/w1-workflow-build-matrix.yml
373
373
  [Docker-Build-badge]: https://github.com/pkjmesra/PKScreener/actions/workflows/w15-docker-image.yml/badge.svg
374
374
  [Docker-Build]: https://github.com/pkjmesra/PKScreener/actions/workflows/w15-docker-image.yml
375
+ [OpenSSF-Badge]:https://www.bestpractices.dev/projects/10011/badge
376
+ [OpenSSF-pkscreener]: https://www.bestpractices.dev/projects/10011
375
377
 
376
378
  <!-- [![Docker Build][Docker-Build-badge]][Docker-Build] [![PKScreener Test - New Features][New Features-badge]][New Features] [![w9. After-Market Data Gen][After Market-badge]][After Market] [![1. PKScreener Build - New Release][New Release-badge]][New Release] [![Documentation][Documentation-badge]][Documentation]
377
379
 
@@ -54,6 +54,7 @@ class MarketMonitor(SingletonMixin, metaclass=SingletonType):
54
54
  self.alertOptions = alertOptions
55
55
  self.hiddenColumns = ""
56
56
  self.alertStocks = []
57
+ self.firstAlertTriggered = False
57
58
  self.pinnedIntervalWaitSeconds = pinnedIntervalWaitSeconds
58
59
  # self.monitorNames = {}
59
60
  # We are going to present the dataframes in a 3x3 matrix with limited set of columns
@@ -127,23 +128,42 @@ class MarketMonitor(SingletonMixin, metaclass=SingletonType):
127
128
  if self.isPinnedSingleMonitorMode:
128
129
  screen_monitor_df = screen_monitor_df[screen_monitor_df.columns[:14]]
129
130
  self.monitor_df = screen_monitor_df
130
- else:
131
- screen_monitor_df.reset_index(inplace=True)
132
- screen_monitor_df = screen_monitor_df[["Stock", "LTP", "%Chng","52Wk-H","RSI/i" if "RSI/i" in screen_monitor_df.columns else "RSI","Volume"]].head(self.maxNumRowsInEachResult-1)
133
- # Import Utility here since Utility has dependency on PKScheduler which in turn has dependency on
134
- # multiprocessing, which behaves erratically if imported at the top.
135
- screen_monitor_df.loc[:, "%Chng"] = screen_monitor_df.loc[:, "%Chng"].astype(str).apply(
136
- lambda x: ImageUtility.PKImageTools.roundOff(str(x).split("% (")[0] + colorText.END,0)
131
+ if "RUNNER" in os.environ.keys():
132
+ self.monitor_df.reset_index(inplace=True)
133
+ with pd.option_context('mode.chained_assignment', None):
134
+ self.monitor_df = self.monitor_df[["Stock", "LTP", "%Chng","52Wk-H","RSI/i" if "RSI/i" in self.monitor_df.columns else "RSI","Volume"]]
135
+ # Import Utility here since Utility has dependency on PKScheduler which in turn has dependency on
136
+ # multiprocessing, which behaves erratically if imported at the top.
137
+ self.monitor_df.loc[:, "%Chng"] = self.monitor_df.loc[:, "%Chng"].astype(str).apply(
138
+ lambda x: ImageUtility.PKImageTools.roundOff(str(x).split("% (")[0] + colorText.END,0)
139
+ )
140
+ self.monitor_df.loc[:, "52Wk-H"] = self.monitor_df.loc[:, "52Wk-H"].astype(str).apply(
141
+ lambda x: ImageUtility.PKImageTools.roundOff(x,0)
137
142
  )
138
- screen_monitor_df.loc[:, "52Wk-H"] = screen_monitor_df.loc[:, "52Wk-H"].astype(str).apply(
139
- lambda x: ImageUtility.PKImageTools.roundOff(x,0)
140
- )
141
- screen_monitor_df.loc[:, "Volume"] = screen_monitor_df.loc[:, "Volume"].astype(str).apply(
142
- lambda x: ImageUtility.PKImageTools.roundOff(x,0)
143
- )
144
- screen_monitor_df.rename(columns={"%Chng": "Ch%","Volume":"Vol","52Wk-H":"52WkH", "RSI":"RSI/i"}, inplace=True)
145
- telegram_df = self.updateDataFrameForTelegramMode(telegram, screen_monitor_df)
146
-
143
+ self.monitor_df.loc[:, "Volume"] = self.monitor_df.loc[:, "Volume"].astype(str).apply(
144
+ lambda x: ImageUtility.PKImageTools.roundOff(x,0)
145
+ )
146
+ self.monitor_df.rename(columns={"%Chng": "Ch%","Volume":"Vol","52Wk-H":"52WkH", "RSI":"RSI/i"}, inplace=True)
147
+ telegram_df = self.updateDataFrameForTelegramMode(telegram or "RUNNER" in os.environ.keys(), self.monitor_df)
148
+ self.monitor_df.set_index("Stock",inplace=True)
149
+
150
+ if not self.isPinnedSingleMonitorMode:
151
+ screen_monitor_df.reset_index(inplace=True)
152
+ with pd.option_context('mode.chained_assignment', None):
153
+ screen_monitor_df = screen_monitor_df[["Stock", "LTP", "%Chng","52Wk-H","RSI/i" if "RSI/i" in screen_monitor_df.columns else "RSI","Volume"]].head(self.maxNumRowsInEachResult-1)
154
+ # Import Utility here since Utility has dependency on PKScheduler which in turn has dependency on
155
+ # multiprocessing, which behaves erratically if imported at the top.
156
+ screen_monitor_df.loc[:, "%Chng"] = screen_monitor_df.loc[:, "%Chng"].astype(str).apply(
157
+ lambda x: ImageUtility.PKImageTools.roundOff(str(x).split("% (")[0] + colorText.END,0)
158
+ )
159
+ screen_monitor_df.loc[:, "52Wk-H"] = screen_monitor_df.loc[:, "52Wk-H"].astype(str).apply(
160
+ lambda x: ImageUtility.PKImageTools.roundOff(x,0)
161
+ )
162
+ screen_monitor_df.loc[:, "Volume"] = screen_monitor_df.loc[:, "Volume"].astype(str).apply(
163
+ lambda x: ImageUtility.PKImageTools.roundOff(x,0)
164
+ )
165
+ screen_monitor_df.rename(columns={"%Chng": "Ch%","Volume":"Vol","52Wk-H":"52WkH", "RSI":"RSI/i"}, inplace=True)
166
+ telegram_df = self.updateDataFrameForTelegramMode(telegram or "RUNNER" in os.environ.keys(), screen_monitor_df)
147
167
 
148
168
  if monitorPosition is not None:
149
169
  startRowIndex, startColIndex = monitorPosition
@@ -197,7 +217,8 @@ class MarketMonitor(SingletonMixin, metaclass=SingletonType):
197
217
  stockName = (f"{colorText.BOLD}{colorText.WHITE_FG_BRED_BG}{stock}{colorText.END}") if stockName in self.alertStocks else stock
198
218
  updatedStocks.append(stockName)
199
219
  self.monitor_df.reset_index(inplace=True)
200
- self.monitor_df["Stock"] = updatedStocks
220
+ with pd.option_context('mode.chained_assignment', None):
221
+ self.monitor_df["Stock"] = updatedStocks
201
222
  self.monitor_df.set_index("Stock",inplace=True)
202
223
 
203
224
  self.monitor_df = self.monitor_df.replace(np.nan, "-", regex=True)
@@ -241,6 +262,21 @@ class MarketMonitor(SingletonMixin, metaclass=SingletonType):
241
262
  if telegram:
242
263
  self.updateIfRunningInTelegramBotMode(screenOptions, chosenMenu, dbTimestamp, telegram, telegram_df)
243
264
  else:
265
+ if ((screenOptions in self.alertOptions and numRecords > 3) or len(self.alertStocks) > 0 or not self.firstAlertTriggered): # Alert conditions met? Sound alert!
266
+ # numRecords is actually new lines. Top 3 lines are only headers
267
+ if telegram_df is not None:
268
+ telegram_df.reset_index(inplace=True)
269
+ notify_df = telegram_df[telegram_df["Stock"].isin(self.alertStocks)] if self.firstAlertTriggered else telegram_df
270
+ notify_df = notify_df[["Stock","LTP","Ch%","Vol"]].head(50)
271
+ if len(notify_df) > 0:
272
+ notify_output = self.updateIfRunningInTelegramBotMode(screenOptions, chosenMenu, dbTimestamp, False, notify_df,maxcolwidths=None)
273
+ if len(notify_output) > 0:
274
+ from PKDevTools.classes.pubsub.publisher import PKUserService
275
+ from PKDevTools.classes.pubsub.subscriber import notification_service
276
+ PKUserService().notify_user(scannerID=self.getScanOptionName(screenOptions),notification=notify_output)
277
+ self.firstAlertTriggered = True
278
+ # notify_df = self.monitor_df.reindex(self.alertStocks) # Includes missing stocks, if any. Returns NaN for such cases
279
+ Utility.tools.alertSound(beeps=5)
244
280
  sleep(self.pinnedIntervalWaitSeconds)
245
281
 
246
282
  def updateDataFrameForTelegramMode(self, telegram, screen_monitor_df):
@@ -272,34 +308,45 @@ class MarketMonitor(SingletonMixin, metaclass=SingletonType):
272
308
  pass
273
309
  return telegram_df
274
310
 
275
- def updateIfRunningInTelegramBotMode(self, screenOptions, chosenMenu, dbTimestamp, telegram, telegram_df):
276
- if telegram and telegram_df is not None:
311
+ def updateIfRunningInTelegramBotMode(self, screenOptions, chosenMenu, dbTimestamp, telegram, telegram_df,maxcolwidths=[None,None,4,3]):
312
+ result_output = ""
313
+ telegram_df_tabulated = ""
314
+ if telegram_df is not None:
277
315
  STD_ENCODING=sys.stdout.encoding if sys.stdout is not None else 'utf-8'
278
-
279
- telegram_df_tabulated = colorText.miniTabulator().tabulate(
280
- telegram_df,
281
- headers="keys",
282
- tablefmt=colorText.No_Pad_GridFormat,
283
- showindex=False,
284
- maxcolwidths=[None,None,4,3]
285
- ).encode("utf-8").decode(STD_ENCODING).replace("-K-----S-----C-----R","-K-----S----C---R").replace("% ","% ").replace("=K=====S=====C=====R","=K=====S====C===R").replace("Vol |","Vol|").replace("x ","x")
316
+ try:
317
+ telegram_df_tabulated = colorText.miniTabulator().tabulate(
318
+ telegram_df,
319
+ headers="keys",
320
+ tablefmt=colorText.No_Pad_GridFormat,
321
+ showindex=False,
322
+ maxcolwidths=maxcolwidths if maxcolwidths is not None else None
323
+ ).encode("utf-8").decode(STD_ENCODING).replace("-K-----S-----C-----R","-K-----S----C---R").replace("% ","% ").replace("=K=====S=====C=====R","=K=====S====C===R").replace("Vol |","Vol|").replace("x ","x")
324
+ except Exception as e:
325
+ default_logger().debug(e,exc_info=True)
326
+ pass
286
327
  telegram_df_tabulated = telegram_df_tabulated.replace("-E-----N-----E-----R","-E-----N----E---R").replace("=E=====N=====E=====R","=E=====N====E===R")
287
328
  choiceSegments = chosenMenu.split(">")
288
329
  optionName = self.getScanOptionName(screenOptions)
289
330
  chosenMenu = f"{choiceSegments[-2]}>{choiceSegments[-1]}" if (len(choiceSegments)>=4 or len(choiceSegments[-1]) <= 10) else f"{choiceSegments[-1]}"
290
- result_output = f"Latest data as of:{dbTimestamp}\n<b>{optionName}{chosenMenu}</b> [{screenOptions}]\n<pre>{telegram_df_tabulated}</pre>"
331
+ result_output = f"Latest data as of {dbTimestamp}\n<b>[{optionName}] {chosenMenu}</b> [{screenOptions}]\n<pre>{telegram_df_tabulated}</pre>"
291
332
  try:
292
- filePath = os.path.join(Archiver.get_user_data_dir(), f"monitor_outputs_{self.monitorIndex}.txt")
293
- f = open(filePath, "w")
294
- f.write(result_output)
295
- f.close()
333
+ if telegram:
334
+ filePath = os.path.join(Archiver.get_user_data_dir(), f"monitor_outputs_{self.monitorIndex}.txt")
335
+ f = open(filePath, "w")
336
+ f.write(result_output)
337
+ f.close()
296
338
  except: # pragma: no cover
297
339
  pass
340
+ return result_output
298
341
 
299
342
  def getScanOptionName(self, screenOptions):
300
343
  from pkscreener.classes.MenuOptions import PREDEFINED_SCAN_MENU_VALUES
301
344
  if screenOptions is None:
302
345
  return ""
346
+ baseIndex = 12
347
+ baseIndices = screenOptions.split(":")
348
+ if len(baseIndices) > 1:
349
+ baseIndex = baseIndices[1]
303
350
  choices = f"--systemlaunched -a y -e -o '{screenOptions.replace('C:','X:').replace('D:','')}'"
304
351
  indexNum = -1
305
352
  try:
@@ -308,5 +355,5 @@ class MarketMonitor(SingletonMixin, metaclass=SingletonType):
308
355
  pass
309
356
  optionName = ""
310
357
  if indexNum >= 0:
311
- optionName = f"{('P_1_'+str(indexNum +1)+':') if '>|' in choices else optionName}"
358
+ optionName = f"{('P_1_'+str(indexNum +1)+'_'+str(baseIndex)) if '>|' in choices else screenOptions.replace(':D','').replace(':','_')}"
312
359
  return optionName
@@ -0,0 +1 @@
1
+ VERSION='0.46.20250213.705'
@@ -1145,6 +1145,9 @@ def main(userArgs=None,optionalFinalOutcome_df=None):
1145
1145
  stockListParam = f" --stocklist {userPassedArgs.stocklist}" if userPassedArgs.stocklist else ""
1146
1146
  slicewindowParam = f" --slicewindow {userPassedArgs.slicewindow}" if userPassedArgs.slicewindow else ""
1147
1147
  fnameParam = f" --fname {resultsContentsEncoded}" if resultsContentsEncoded else ""
1148
+ if userPassedArgs.monitor and "-e -o" in scannerOptionQuoted:
1149
+ # We've been launched in monitor mode. Get rid of -e -o
1150
+ scannerOptionQuoted = scannerOptionQuoted.replace("-e -o","-m")
1148
1151
  OutputControls().printOutput(f"{colorText.GREEN}Launching PKScreener with piped scanners. If it does not launch, please try with the following:{colorText.END}\n{colorText.FAIL}{launcher} {scannerOptionQuoted}{requestingUser}{enableLog}{backtestParam}{enableTelegramMode}{stockListParam}{slicewindowParam}{fnameParam}{colorText.END}")
1149
1152
  sleep(2)
1150
1153
  os.system(f"{launcher} {scannerOptionQuoted}{requestingUser}{enableLog}{backtestParam}{enableTelegramMode}{stockListParam}{slicewindowParam}{fnameParam}")
@@ -3995,9 +3998,9 @@ def sendMessageToTelegramChannel(
3995
3998
  os.remove(f)
3996
3999
  except: # pragma: no cover
3997
4000
  pass
3998
- if message is None and mediagroup:
3999
- sendMessageToTelegramChannel(message=f"No scan results found for {menuChoiceHierarchy}", user=user)
4000
- return
4001
+ # if message is None and mediagroup:
4002
+ # sendMessageToTelegramChannel(message=f"No scan results found for {menuChoiceHierarchy}", user=user)
4003
+ # return
4001
4004
  handleAlertSubscriptions(user,message)
4002
4005
  if user is not None:
4003
4006
  if str(user) != str(DEV_CHANNEL_ID) and userPassedArgs is not None and not userPassedArgs.monitor: