quantwise 1.2.0 → 1.2.2

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 (362) hide show
  1. package/.claude/skills/README.md +80 -0
  2. package/.claude/skills/backtest-expert/SKILL.md +206 -0
  3. package/.claude/skills/backtest-expert/references/failed_tests.md +236 -0
  4. package/.claude/skills/backtest-expert/references/methodology.md +227 -0
  5. package/.claude/skills/breadth-chart-analyst/SKILL.md +583 -0
  6. package/.claude/skills/breadth-chart-analyst/assets/SP500_Breadth_Index_200MA_8MA.jpeg +0 -0
  7. package/.claude/skills/breadth-chart-analyst/assets/US_Stock_Market_Uptrend_Ratio.jpeg +0 -0
  8. package/.claude/skills/breadth-chart-analyst/assets/breadth_analysis_template.md +558 -0
  9. package/.claude/skills/breadth-chart-analyst/references/breadth_chart_methodology.md +590 -0
  10. package/.claude/skills/canslim-screener/SKILL.md +599 -0
  11. package/.claude/skills/canslim-screener/references/canslim_methodology.md +606 -0
  12. package/.claude/skills/canslim-screener/references/fmp_api_endpoints.md +707 -0
  13. package/.claude/skills/canslim-screener/references/interpretation_guide.md +516 -0
  14. package/.claude/skills/canslim-screener/references/scoring_system.md +597 -0
  15. package/.claude/skills/canslim-screener/scripts/calculators/earnings_calculator.py +343 -0
  16. package/.claude/skills/canslim-screener/scripts/calculators/growth_calculator.py +334 -0
  17. package/.claude/skills/canslim-screener/scripts/calculators/institutional_calculator.py +347 -0
  18. package/.claude/skills/canslim-screener/scripts/calculators/leadership_calculator.py +380 -0
  19. package/.claude/skills/canslim-screener/scripts/calculators/market_calculator.py +244 -0
  20. package/.claude/skills/canslim-screener/scripts/calculators/new_highs_calculator.py +194 -0
  21. package/.claude/skills/canslim-screener/scripts/calculators/supply_demand_calculator.py +221 -0
  22. package/.claude/skills/canslim-screener/scripts/finviz_stock_client.py +227 -0
  23. package/.claude/skills/canslim-screener/scripts/fmp_client.py +393 -0
  24. package/.claude/skills/canslim-screener/scripts/report_generator.py +405 -0
  25. package/.claude/skills/canslim-screener/scripts/scorer.py +625 -0
  26. package/.claude/skills/canslim-screener/scripts/screen_canslim.py +361 -0
  27. package/.claude/skills/canslim-screener/scripts/test_institutional_endpoint.py +109 -0
  28. package/.claude/skills/chart/SKILL.md +20 -0
  29. package/.claude/skills/dividend-growth-pullback-screener/SKILL.md +322 -0
  30. package/.claude/skills/dividend-growth-pullback-screener/references/dividend_growth_compounding.md +400 -0
  31. package/.claude/skills/dividend-growth-pullback-screener/references/fmp_api_guide.md +642 -0
  32. package/.claude/skills/dividend-growth-pullback-screener/references/rsi_oversold_strategy.md +333 -0
  33. package/.claude/skills/dividend-growth-pullback-screener/scripts/screen_dividend_growth_rsi.py +1155 -0
  34. package/.claude/skills/earnings-calendar/SKILL.md +721 -0
  35. package/.claude/skills/earnings-calendar/assets/earnings_report_template.md +102 -0
  36. package/.claude/skills/earnings-calendar/references/fmp_api_guide.md +590 -0
  37. package/.claude/skills/earnings-calendar/scripts/fetch_earnings_fmp.py +443 -0
  38. package/.claude/skills/earnings-calendar/scripts/generate_report.py +366 -0
  39. package/.claude/skills/economic-calendar-fetcher/SKILL.md +365 -0
  40. package/.claude/skills/economic-calendar-fetcher/references/fmp_api_documentation.md +345 -0
  41. package/.claude/skills/economic-calendar-fetcher/scripts/get_economic_calendar.py +267 -0
  42. package/.claude/skills/ftd-detector/SKILL.md +147 -0
  43. package/.claude/skills/ftd-detector/references/ftd_methodology.md +188 -0
  44. package/.claude/skills/ftd-detector/references/post_ftd_guide.md +185 -0
  45. package/.claude/skills/ftd-detector/scripts/fmp_client.py +158 -0
  46. package/.claude/skills/ftd-detector/scripts/ftd_detector.py +280 -0
  47. package/.claude/skills/ftd-detector/scripts/post_ftd_monitor.py +404 -0
  48. package/.claude/skills/ftd-detector/scripts/rally_tracker.py +508 -0
  49. package/.claude/skills/ftd-detector/scripts/report_generator.py +341 -0
  50. package/.claude/skills/ftd-detector/scripts/tests/conftest.py +9 -0
  51. package/.claude/skills/ftd-detector/scripts/tests/helpers.py +107 -0
  52. package/.claude/skills/ftd-detector/scripts/tests/test_post_ftd_monitor.py +311 -0
  53. package/.claude/skills/ftd-detector/scripts/tests/test_rally_tracker.py +302 -0
  54. package/.claude/skills/institutional-flow-tracker/README.md +362 -0
  55. package/.claude/skills/institutional-flow-tracker/SKILL.md +357 -0
  56. package/.claude/skills/institutional-flow-tracker/references/13f_filings_guide.md +383 -0
  57. package/.claude/skills/institutional-flow-tracker/references/institutional_investor_types.md +580 -0
  58. package/.claude/skills/institutional-flow-tracker/references/interpretation_framework.md +573 -0
  59. package/.claude/skills/institutional-flow-tracker/scripts/analyze_single_stock.py +457 -0
  60. package/.claude/skills/institutional-flow-tracker/scripts/track_institution_portfolio.py +108 -0
  61. package/.claude/skills/institutional-flow-tracker/scripts/track_institutional_flow.py +450 -0
  62. package/.claude/skills/macro-regime-detector/SKILL.md +86 -0
  63. package/.claude/skills/macro-regime-detector/references/historical_regimes.md +124 -0
  64. package/.claude/skills/macro-regime-detector/references/indicator_interpretation_guide.md +144 -0
  65. package/.claude/skills/macro-regime-detector/references/regime_detection_methodology.md +138 -0
  66. package/.claude/skills/macro-regime-detector/scripts/calculators/__init__.py +1 -0
  67. package/.claude/skills/macro-regime-detector/scripts/calculators/concentration_calculator.py +165 -0
  68. package/.claude/skills/macro-regime-detector/scripts/calculators/credit_conditions_calculator.py +124 -0
  69. package/.claude/skills/macro-regime-detector/scripts/calculators/equity_bond_calculator.py +198 -0
  70. package/.claude/skills/macro-regime-detector/scripts/calculators/sector_rotation_calculator.py +123 -0
  71. package/.claude/skills/macro-regime-detector/scripts/calculators/size_factor_calculator.py +131 -0
  72. package/.claude/skills/macro-regime-detector/scripts/calculators/utils.py +347 -0
  73. package/.claude/skills/macro-regime-detector/scripts/calculators/yield_curve_calculator.py +279 -0
  74. package/.claude/skills/macro-regime-detector/scripts/fmp_client.py +134 -0
  75. package/.claude/skills/macro-regime-detector/scripts/macro_regime_detector.py +278 -0
  76. package/.claude/skills/macro-regime-detector/scripts/report_generator.py +327 -0
  77. package/.claude/skills/macro-regime-detector/scripts/scorer.py +574 -0
  78. package/.claude/skills/macro-regime-detector/scripts/tests/conftest.py +9 -0
  79. package/.claude/skills/macro-regime-detector/scripts/tests/test_concentration.py +78 -0
  80. package/.claude/skills/macro-regime-detector/scripts/tests/test_credit_conditions.py +59 -0
  81. package/.claude/skills/macro-regime-detector/scripts/tests/test_equity_bond.py +74 -0
  82. package/.claude/skills/macro-regime-detector/scripts/tests/test_helpers.py +90 -0
  83. package/.claude/skills/macro-regime-detector/scripts/tests/test_scorer.py +439 -0
  84. package/.claude/skills/macro-regime-detector/scripts/tests/test_sector_rotation.py +78 -0
  85. package/.claude/skills/macro-regime-detector/scripts/tests/test_size_factor.py +59 -0
  86. package/.claude/skills/macro-regime-detector/scripts/tests/test_utils.py +126 -0
  87. package/.claude/skills/macro-regime-detector/scripts/tests/test_yield_curve.py +64 -0
  88. package/.claude/skills/market-breadth-analyzer/SKILL.md +121 -0
  89. package/.claude/skills/market-breadth-analyzer/references/breadth_analysis_methodology.md +168 -0
  90. package/.claude/skills/market-breadth-analyzer/scripts/calculators/__init__.py +1 -0
  91. package/.claude/skills/market-breadth-analyzer/scripts/calculators/bearish_signal_calculator.py +150 -0
  92. package/.claude/skills/market-breadth-analyzer/scripts/calculators/cycle_calculator.py +168 -0
  93. package/.claude/skills/market-breadth-analyzer/scripts/calculators/divergence_calculator.py +119 -0
  94. package/.claude/skills/market-breadth-analyzer/scripts/calculators/historical_context_calculator.py +120 -0
  95. package/.claude/skills/market-breadth-analyzer/scripts/calculators/ma_crossover_calculator.py +115 -0
  96. package/.claude/skills/market-breadth-analyzer/scripts/calculators/trend_level_calculator.py +103 -0
  97. package/.claude/skills/market-breadth-analyzer/scripts/csv_client.py +225 -0
  98. package/.claude/skills/market-breadth-analyzer/scripts/market_breadth_analyzer.py +307 -0
  99. package/.claude/skills/market-breadth-analyzer/scripts/report_generator.py +330 -0
  100. package/.claude/skills/market-breadth-analyzer/scripts/scorer.py +271 -0
  101. package/.claude/skills/market-environment-analysis/SKILL.md +139 -0
  102. package/.claude/skills/market-environment-analysis/references/analysis_patterns.md +124 -0
  103. package/.claude/skills/market-environment-analysis/references/indicators.md +99 -0
  104. package/.claude/skills/market-environment-analysis/scripts/market_utils.py +127 -0
  105. package/.claude/skills/market-news-analyst/SKILL.md +714 -0
  106. package/.claude/skills/market-news-analyst/references/corporate_news_impact.md +446 -0
  107. package/.claude/skills/market-news-analyst/references/geopolitical_commodity_correlations.md +499 -0
  108. package/.claude/skills/market-news-analyst/references/market_event_patterns.md +393 -0
  109. package/.claude/skills/market-news-analyst/references/trusted_news_sources.md +510 -0
  110. package/.claude/skills/market-top-detector/SKILL.md +159 -0
  111. package/.claude/skills/market-top-detector/references/distribution_day_guide.md +100 -0
  112. package/.claude/skills/market-top-detector/references/historical_tops.md +142 -0
  113. package/.claude/skills/market-top-detector/references/market_top_methodology.md +167 -0
  114. package/.claude/skills/market-top-detector/scripts/calculators/__init__.py +17 -0
  115. package/.claude/skills/market-top-detector/scripts/calculators/breadth_calculator.py +116 -0
  116. package/.claude/skills/market-top-detector/scripts/calculators/defensive_rotation_calculator.py +127 -0
  117. package/.claude/skills/market-top-detector/scripts/calculators/distribution_day_calculator.py +161 -0
  118. package/.claude/skills/market-top-detector/scripts/calculators/index_technical_calculator.py +254 -0
  119. package/.claude/skills/market-top-detector/scripts/calculators/leading_stock_calculator.py +198 -0
  120. package/.claude/skills/market-top-detector/scripts/calculators/sentiment_calculator.py +213 -0
  121. package/.claude/skills/market-top-detector/scripts/fmp_client.py +158 -0
  122. package/.claude/skills/market-top-detector/scripts/market_top_detector.py +349 -0
  123. package/.claude/skills/market-top-detector/scripts/report_generator.py +314 -0
  124. package/.claude/skills/market-top-detector/scripts/scorer.py +473 -0
  125. package/.claude/skills/market-top-detector/scripts/tests/conftest.py +9 -0
  126. package/.claude/skills/market-top-detector/scripts/tests/helpers.py +49 -0
  127. package/.claude/skills/market-top-detector/scripts/tests/test_breadth.py +62 -0
  128. package/.claude/skills/market-top-detector/scripts/tests/test_defensive_rotation.py +56 -0
  129. package/.claude/skills/market-top-detector/scripts/tests/test_distribution_day.py +92 -0
  130. package/.claude/skills/market-top-detector/scripts/tests/test_index_technical.py +73 -0
  131. package/.claude/skills/market-top-detector/scripts/tests/test_leading_stock.py +57 -0
  132. package/.claude/skills/market-top-detector/scripts/tests/test_scorer.py +180 -0
  133. package/.claude/skills/market-top-detector/scripts/tests/test_sentiment.py +64 -0
  134. package/.claude/skills/options-strategy-advisor/README.md +469 -0
  135. package/.claude/skills/options-strategy-advisor/SKILL.md +959 -0
  136. package/.claude/skills/options-strategy-advisor/scripts/black_scholes.py +495 -0
  137. package/.claude/skills/pair-trade-screener/README.md +389 -0
  138. package/.claude/skills/pair-trade-screener/SKILL.md +622 -0
  139. package/.claude/skills/pair-trade-screener/references/cointegration_guide.md +745 -0
  140. package/.claude/skills/pair-trade-screener/references/methodology.md +853 -0
  141. package/.claude/skills/pair-trade-screener/scripts/analyze_spread.py +394 -0
  142. package/.claude/skills/pair-trade-screener/scripts/find_pairs.py +535 -0
  143. package/.claude/skills/portfolio-manager/README.md +394 -0
  144. package/.claude/skills/portfolio-manager/SKILL.md +750 -0
  145. package/.claude/skills/portfolio-manager/references/alpaca-mcp-setup.md +367 -0
  146. package/.claude/skills/portfolio-manager/references/asset-allocation.md +502 -0
  147. package/.claude/skills/portfolio-manager/references/diversification-principles.md +553 -0
  148. package/.claude/skills/portfolio-manager/references/portfolio-risk-metrics.md +603 -0
  149. package/.claude/skills/portfolio-manager/references/position-evaluation.md +477 -0
  150. package/.claude/skills/portfolio-manager/references/rebalancing-strategies.md +715 -0
  151. package/.claude/skills/portfolio-manager/references/risk-profile-questionnaire.md +608 -0
  152. package/.claude/skills/portfolio-manager/references/target-allocations.md +558 -0
  153. package/.claude/skills/portfolio-manager/scripts/test_alpaca_connection.py +286 -0
  154. package/.claude/skills/scenario-analyzer/SKILL.md +317 -0
  155. package/.claude/skills/scenario-analyzer/references/headline_event_patterns.md +264 -0
  156. package/.claude/skills/scenario-analyzer/references/scenario_playbooks.md +320 -0
  157. package/.claude/skills/scenario-analyzer/references/sector_sensitivity_matrix.md +217 -0
  158. package/.claude/skills/sector-analyst/SKILL.md +206 -0
  159. package/.claude/skills/sector-analyst/assets/industory_performance_1.jpeg +0 -0
  160. package/.claude/skills/sector-analyst/assets/industory_performance_2.jpeg +0 -0
  161. package/.claude/skills/sector-analyst/assets/sector_performance.jpeg +0 -0
  162. package/.claude/skills/sector-analyst/references/sector_rotation.md +170 -0
  163. package/.claude/skills/stanley-druckenmiller-investment/SKILL.md +84 -0
  164. package/.claude/skills/stanley-druckenmiller-investment/references/case-studies.md +148 -0
  165. package/.claude/skills/stanley-druckenmiller-investment/references/investment-philosophy.md +80 -0
  166. package/.claude/skills/stanley-druckenmiller-investment/references/market-analysis-guide.md +146 -0
  167. package/.claude/skills/stock/NOTION_SETUP.md +33 -0
  168. package/.claude/skills/stock/SKILL.md +38 -0
  169. package/.claude/skills/technical-analyst/SKILL.md +238 -0
  170. package/.claude/skills/technical-analyst/assets/analysis_template.md +183 -0
  171. package/.claude/skills/technical-analyst/references/technical_analysis_framework.md +282 -0
  172. package/.claude/skills/theme-detector/SKILL.md +320 -0
  173. package/.claude/skills/theme-detector/assets/report_template.md +155 -0
  174. package/.claude/skills/theme-detector/references/cross_sector_themes.md +252 -0
  175. package/.claude/skills/theme-detector/references/finviz_industry_codes.md +403 -0
  176. package/.claude/skills/theme-detector/references/thematic_etf_catalog.md +333 -0
  177. package/.claude/skills/theme-detector/references/theme_detection_methodology.md +430 -0
  178. package/.claude/skills/theme-detector/scripts/calculators/__init__.py +1 -0
  179. package/.claude/skills/theme-detector/scripts/calculators/heat_calculator.py +123 -0
  180. package/.claude/skills/theme-detector/scripts/calculators/industry_ranker.py +98 -0
  181. package/.claude/skills/theme-detector/scripts/calculators/lifecycle_calculator.py +172 -0
  182. package/.claude/skills/theme-detector/scripts/calculators/theme_classifier.py +195 -0
  183. package/.claude/skills/theme-detector/scripts/calculators/theme_discoverer.py +280 -0
  184. package/.claude/skills/theme-detector/scripts/config_loader.py +142 -0
  185. package/.claude/skills/theme-detector/scripts/default_theme_config.py +254 -0
  186. package/.claude/skills/theme-detector/scripts/etf_scanner.py +609 -0
  187. package/.claude/skills/theme-detector/scripts/finviz_performance_client.py +131 -0
  188. package/.claude/skills/theme-detector/scripts/report_generator.py +490 -0
  189. package/.claude/skills/theme-detector/scripts/representative_stock_selector.py +673 -0
  190. package/.claude/skills/theme-detector/scripts/scorer.py +87 -0
  191. package/.claude/skills/theme-detector/scripts/tests/README.md +21 -0
  192. package/.claude/skills/theme-detector/scripts/tests/conftest.py +9 -0
  193. package/.claude/skills/theme-detector/scripts/tests/test_config_loader.py +239 -0
  194. package/.claude/skills/theme-detector/scripts/tests/test_etf_scanner.py +810 -0
  195. package/.claude/skills/theme-detector/scripts/tests/test_heat_calculator.py +245 -0
  196. package/.claude/skills/theme-detector/scripts/tests/test_industry_ranker.py +256 -0
  197. package/.claude/skills/theme-detector/scripts/tests/test_lifecycle_calculator.py +301 -0
  198. package/.claude/skills/theme-detector/scripts/tests/test_report_generator.py +624 -0
  199. package/.claude/skills/theme-detector/scripts/tests/test_representative_stock_selector.py +898 -0
  200. package/.claude/skills/theme-detector/scripts/tests/test_scorer.py +185 -0
  201. package/.claude/skills/theme-detector/scripts/tests/test_theme_classifier.py +534 -0
  202. package/.claude/skills/theme-detector/scripts/tests/test_theme_detector_e2e.py +467 -0
  203. package/.claude/skills/theme-detector/scripts/tests/test_theme_discoverer.py +458 -0
  204. package/.claude/skills/theme-detector/scripts/tests/test_uptrend_client.py +76 -0
  205. package/.claude/skills/theme-detector/scripts/theme_detector.py +815 -0
  206. package/.claude/skills/theme-detector/scripts/themes.yaml +168 -0
  207. package/.claude/skills/theme-detector/scripts/uptrend_client.py +241 -0
  208. package/.claude/skills/uptrend-analyzer/SKILL.md +108 -0
  209. package/.claude/skills/uptrend-analyzer/references/uptrend_methodology.md +215 -0
  210. package/.claude/skills/uptrend-analyzer/scripts/calculators/__init__.py +1 -0
  211. package/.claude/skills/uptrend-analyzer/scripts/calculators/historical_context_calculator.py +122 -0
  212. package/.claude/skills/uptrend-analyzer/scripts/calculators/market_breadth_calculator.py +145 -0
  213. package/.claude/skills/uptrend-analyzer/scripts/calculators/momentum_calculator.py +183 -0
  214. package/.claude/skills/uptrend-analyzer/scripts/calculators/sector_participation_calculator.py +204 -0
  215. package/.claude/skills/uptrend-analyzer/scripts/calculators/sector_rotation_calculator.py +218 -0
  216. package/.claude/skills/uptrend-analyzer/scripts/data_fetcher.py +236 -0
  217. package/.claude/skills/uptrend-analyzer/scripts/report_generator.py +329 -0
  218. package/.claude/skills/uptrend-analyzer/scripts/scorer.py +276 -0
  219. package/.claude/skills/uptrend-analyzer/scripts/uptrend_analyzer.py +219 -0
  220. package/.claude/skills/us-market-bubble-detector/CHANGELOG.md +118 -0
  221. package/.claude/skills/us-market-bubble-detector/SKILL.md +545 -0
  222. package/.claude/skills/us-market-bubble-detector/references/bubble_framework.md +335 -0
  223. package/.claude/skills/us-market-bubble-detector/references/historical_cases.md +327 -0
  224. package/.claude/skills/us-market-bubble-detector/references/implementation_guide.md +473 -0
  225. package/.claude/skills/us-market-bubble-detector/references/quick_reference.md +354 -0
  226. package/.claude/skills/us-market-bubble-detector/references/quick_reference_en.md +342 -0
  227. package/.claude/skills/us-market-bubble-detector/scripts/bubble_scorer.py +309 -0
  228. package/.claude/skills/us-stock-analysis/SKILL.md +294 -0
  229. package/.claude/skills/us-stock-analysis/references/financial-metrics.md +172 -0
  230. package/.claude/skills/us-stock-analysis/references/fundamental-analysis.md +129 -0
  231. package/.claude/skills/us-stock-analysis/references/report-template.md +207 -0
  232. package/.claude/skills/us-stock-analysis/references/technical-analysis.md +93 -0
  233. package/.claude/skills/value-dividend-screener/SKILL.md +562 -0
  234. package/.claude/skills/value-dividend-screener/references/fmp_api_guide.md +348 -0
  235. package/.claude/skills/value-dividend-screener/references/screening_methodology.md +315 -0
  236. package/.claude/skills/value-dividend-screener/scripts/screen_dividend_stocks.py +1138 -0
  237. package/.claude/skills/vcp-screener/SKILL.md +79 -0
  238. package/.claude/skills/vcp-screener/references/fmp_api_endpoints.md +45 -0
  239. package/.claude/skills/vcp-screener/references/scoring_system.md +154 -0
  240. package/.claude/skills/vcp-screener/references/vcp_methodology.md +124 -0
  241. package/.claude/skills/vcp-screener/scripts/calculators/__init__.py +1 -0
  242. package/.claude/skills/vcp-screener/scripts/calculators/pivot_proximity_calculator.py +139 -0
  243. package/.claude/skills/vcp-screener/scripts/calculators/relative_strength_calculator.py +161 -0
  244. package/.claude/skills/vcp-screener/scripts/calculators/trend_template_calculator.py +228 -0
  245. package/.claude/skills/vcp-screener/scripts/calculators/vcp_pattern_calculator.py +322 -0
  246. package/.claude/skills/vcp-screener/scripts/calculators/volume_pattern_calculator.py +121 -0
  247. package/.claude/skills/vcp-screener/scripts/fmp_client.py +162 -0
  248. package/.claude/skills/vcp-screener/scripts/report_generator.py +317 -0
  249. package/.claude/skills/vcp-screener/scripts/scorer.py +155 -0
  250. package/.claude/skills/vcp-screener/scripts/screen_vcp.py +536 -0
  251. package/.claude/skills/vcp-screener/scripts/tests/__init__.py +0 -0
  252. package/.claude/skills/vcp-screener/scripts/tests/conftest.py +9 -0
  253. package/.claude/skills/vcp-screener/scripts/tests/test_vcp_screener.py +834 -0
  254. package/.claude/skills/weekly-trade-strategy/.claude/agents/druckenmiller-strategy-planner.md +300 -0
  255. package/.claude/skills/weekly-trade-strategy/.claude/agents/market-news-analyzer.md +239 -0
  256. package/.claude/skills/weekly-trade-strategy/.claude/agents/technical-market-analyst.md +187 -0
  257. package/.claude/skills/weekly-trade-strategy/.claude/agents/us-market-analyst.md +218 -0
  258. package/.claude/skills/weekly-trade-strategy/.claude/agents/weekly-trade-blog-writer.md +318 -0
  259. package/.claude/skills/weekly-trade-strategy/.claude/skills/breadth-chart-analyst/SKILL.md +662 -0
  260. package/.claude/skills/weekly-trade-strategy/.claude/skills/breadth-chart-analyst/assets/SP500_Breadth_Index_200MA_8MA.jpeg +0 -0
  261. package/.claude/skills/weekly-trade-strategy/.claude/skills/breadth-chart-analyst/assets/US_Stock_Market_Uptrend_Ratio.jpeg +0 -0
  262. package/.claude/skills/weekly-trade-strategy/.claude/skills/breadth-chart-analyst/assets/breadth_analysis_template.md +558 -0
  263. package/.claude/skills/weekly-trade-strategy/.claude/skills/breadth-chart-analyst/references/breadth_chart_methodology.md +590 -0
  264. package/.claude/skills/weekly-trade-strategy/.claude/skills/earnings-calendar/SKILL.md +721 -0
  265. package/.claude/skills/weekly-trade-strategy/.claude/skills/earnings-calendar/assets/earnings_report_template.md +102 -0
  266. package/.claude/skills/weekly-trade-strategy/.claude/skills/earnings-calendar/earnings_calendar_2025-11-02.md +447 -0
  267. package/.claude/skills/weekly-trade-strategy/.claude/skills/earnings-calendar/references/fmp_api_guide.md +590 -0
  268. package/.claude/skills/weekly-trade-strategy/.claude/skills/earnings-calendar/scripts/fetch_earnings_fmp.py +443 -0
  269. package/.claude/skills/weekly-trade-strategy/.claude/skills/earnings-calendar/scripts/generate_report.py +366 -0
  270. package/.claude/skills/weekly-trade-strategy/.claude/skills/economic-calendar-fetcher/SKILL.md +365 -0
  271. package/.claude/skills/weekly-trade-strategy/.claude/skills/economic-calendar-fetcher/references/fmp_api_documentation.md +345 -0
  272. package/.claude/skills/weekly-trade-strategy/.claude/skills/economic-calendar-fetcher/scripts/get_economic_calendar.py +267 -0
  273. package/.claude/skills/weekly-trade-strategy/.claude/skills/market-environment-analysis/SKILL.md +139 -0
  274. package/.claude/skills/weekly-trade-strategy/.claude/skills/market-environment-analysis/references/analysis_patterns.md +124 -0
  275. package/.claude/skills/weekly-trade-strategy/.claude/skills/market-environment-analysis/references/indicators.md +99 -0
  276. package/.claude/skills/weekly-trade-strategy/.claude/skills/market-environment-analysis/scripts/market_utils.py +127 -0
  277. package/.claude/skills/weekly-trade-strategy/.claude/skills/market-news-analyst/SKILL.md +714 -0
  278. package/.claude/skills/weekly-trade-strategy/.claude/skills/market-news-analyst/references/corporate_news_impact.md +446 -0
  279. package/.claude/skills/weekly-trade-strategy/.claude/skills/market-news-analyst/references/geopolitical_commodity_correlations.md +499 -0
  280. package/.claude/skills/weekly-trade-strategy/.claude/skills/market-news-analyst/references/market_event_patterns.md +393 -0
  281. package/.claude/skills/weekly-trade-strategy/.claude/skills/market-news-analyst/references/trusted_news_sources.md +510 -0
  282. package/.claude/skills/weekly-trade-strategy/.claude/skills/sector-analyst/SKILL.md +206 -0
  283. package/.claude/skills/weekly-trade-strategy/.claude/skills/sector-analyst/assets/industory_performance_1.jpeg +0 -0
  284. package/.claude/skills/weekly-trade-strategy/.claude/skills/sector-analyst/assets/industory_performance_2.jpeg +0 -0
  285. package/.claude/skills/weekly-trade-strategy/.claude/skills/sector-analyst/assets/sector_performance.jpeg +0 -0
  286. package/.claude/skills/weekly-trade-strategy/.claude/skills/sector-analyst/references/sector_rotation.md +170 -0
  287. package/.claude/skills/weekly-trade-strategy/.claude/skills/stanley-druckenmiller-investment/SKILL.md +84 -0
  288. package/.claude/skills/weekly-trade-strategy/.claude/skills/stanley-druckenmiller-investment/references/case-studies.md +148 -0
  289. package/.claude/skills/weekly-trade-strategy/.claude/skills/stanley-druckenmiller-investment/references/investment-philosophy.md +80 -0
  290. package/.claude/skills/weekly-trade-strategy/.claude/skills/stanley-druckenmiller-investment/references/market-analysis-guide.md +146 -0
  291. package/.claude/skills/weekly-trade-strategy/.claude/skills/technical-analyst/SKILL.md +238 -0
  292. package/.claude/skills/weekly-trade-strategy/.claude/skills/technical-analyst/assets/analysis_template.md +183 -0
  293. package/.claude/skills/weekly-trade-strategy/.claude/skills/technical-analyst/references/technical_analysis_framework.md +282 -0
  294. package/.claude/skills/weekly-trade-strategy/.claude/skills/us-market-bubble-detector/CHANGELOG.md +118 -0
  295. package/.claude/skills/weekly-trade-strategy/.claude/skills/us-market-bubble-detector/SKILL.md +545 -0
  296. package/.claude/skills/weekly-trade-strategy/.claude/skills/us-market-bubble-detector/references/bubble_framework.md +335 -0
  297. package/.claude/skills/weekly-trade-strategy/.claude/skills/us-market-bubble-detector/references/historical_cases.md +327 -0
  298. package/.claude/skills/weekly-trade-strategy/.claude/skills/us-market-bubble-detector/references/implementation_guide.md +473 -0
  299. package/.claude/skills/weekly-trade-strategy/.claude/skills/us-market-bubble-detector/references/quick_reference.md +354 -0
  300. package/.claude/skills/weekly-trade-strategy/.claude/skills/us-market-bubble-detector/references/quick_reference_en.md +342 -0
  301. package/.claude/skills/weekly-trade-strategy/.claude/skills/us-market-bubble-detector/scripts/bubble_scorer.py +309 -0
  302. package/.claude/skills/weekly-trade-strategy/.claude/skills/us-stock-analysis/SKILL.md +294 -0
  303. package/.claude/skills/weekly-trade-strategy/.claude/skills/us-stock-analysis/references/financial-metrics.md +172 -0
  304. package/.claude/skills/weekly-trade-strategy/.claude/skills/us-stock-analysis/references/fundamental-analysis.md +129 -0
  305. package/.claude/skills/weekly-trade-strategy/.claude/skills/us-stock-analysis/references/report-template.md +207 -0
  306. package/.claude/skills/weekly-trade-strategy/.claude/skills/us-stock-analysis/references/technical-analysis.md +93 -0
  307. package/.claude/skills/weekly-trade-strategy/CLAUDE.md +454 -0
  308. package/.claude/skills/weekly-trade-strategy/README.md +287 -0
  309. package/.claude/skills/weekly-trade-strategy/blogs/.gitkeep +0 -0
  310. package/.claude/skills/weekly-trade-strategy/charts/.gitkeep +0 -0
  311. package/.claude/skills/weekly-trade-strategy/earnings_data.json +10054 -0
  312. package/.claude/skills/weekly-trade-strategy/skills/breadth-chart-analyst/SKILL.md +662 -0
  313. package/.claude/skills/weekly-trade-strategy/skills/breadth-chart-analyst/assets/SP500_Breadth_Index_200MA_8MA.jpeg +0 -0
  314. package/.claude/skills/weekly-trade-strategy/skills/breadth-chart-analyst/assets/US_Stock_Market_Uptrend_Ratio.jpeg +0 -0
  315. package/.claude/skills/weekly-trade-strategy/skills/breadth-chart-analyst/assets/breadth_analysis_template.md +558 -0
  316. package/.claude/skills/weekly-trade-strategy/skills/breadth-chart-analyst/references/breadth_chart_methodology.md +590 -0
  317. package/.claude/skills/weekly-trade-strategy/skills/earnings-calendar/SKILL.md +721 -0
  318. package/.claude/skills/weekly-trade-strategy/skills/earnings-calendar/assets/earnings_report_template.md +102 -0
  319. package/.claude/skills/weekly-trade-strategy/skills/earnings-calendar/earnings_calendar_2025-11-02.md +447 -0
  320. package/.claude/skills/weekly-trade-strategy/skills/earnings-calendar/references/fmp_api_guide.md +590 -0
  321. package/.claude/skills/weekly-trade-strategy/skills/earnings-calendar/scripts/fetch_earnings_fmp.py +443 -0
  322. package/.claude/skills/weekly-trade-strategy/skills/earnings-calendar/scripts/generate_report.py +366 -0
  323. package/.claude/skills/weekly-trade-strategy/skills/economic-calendar-fetcher/SKILL.md +365 -0
  324. package/.claude/skills/weekly-trade-strategy/skills/economic-calendar-fetcher/references/fmp_api_documentation.md +345 -0
  325. package/.claude/skills/weekly-trade-strategy/skills/economic-calendar-fetcher/scripts/get_economic_calendar.py +267 -0
  326. package/.claude/skills/weekly-trade-strategy/skills/market-environment-analysis/SKILL.md +139 -0
  327. package/.claude/skills/weekly-trade-strategy/skills/market-environment-analysis/references/analysis_patterns.md +124 -0
  328. package/.claude/skills/weekly-trade-strategy/skills/market-environment-analysis/references/indicators.md +99 -0
  329. package/.claude/skills/weekly-trade-strategy/skills/market-environment-analysis/scripts/market_utils.py +127 -0
  330. package/.claude/skills/weekly-trade-strategy/skills/market-news-analyst/SKILL.md +714 -0
  331. package/.claude/skills/weekly-trade-strategy/skills/market-news-analyst/references/corporate_news_impact.md +446 -0
  332. package/.claude/skills/weekly-trade-strategy/skills/market-news-analyst/references/geopolitical_commodity_correlations.md +499 -0
  333. package/.claude/skills/weekly-trade-strategy/skills/market-news-analyst/references/market_event_patterns.md +393 -0
  334. package/.claude/skills/weekly-trade-strategy/skills/market-news-analyst/references/trusted_news_sources.md +510 -0
  335. package/.claude/skills/weekly-trade-strategy/skills/sector-analyst/SKILL.md +206 -0
  336. package/.claude/skills/weekly-trade-strategy/skills/sector-analyst/assets/industory_performance_1.jpeg +0 -0
  337. package/.claude/skills/weekly-trade-strategy/skills/sector-analyst/assets/industory_performance_2.jpeg +0 -0
  338. package/.claude/skills/weekly-trade-strategy/skills/sector-analyst/assets/sector_performance.jpeg +0 -0
  339. package/.claude/skills/weekly-trade-strategy/skills/sector-analyst/references/sector_rotation.md +170 -0
  340. package/.claude/skills/weekly-trade-strategy/skills/stanley-druckenmiller-investment/SKILL.md +84 -0
  341. package/.claude/skills/weekly-trade-strategy/skills/stanley-druckenmiller-investment/references/case-studies.md +148 -0
  342. package/.claude/skills/weekly-trade-strategy/skills/stanley-druckenmiller-investment/references/investment-philosophy.md +80 -0
  343. package/.claude/skills/weekly-trade-strategy/skills/stanley-druckenmiller-investment/references/market-analysis-guide.md +146 -0
  344. package/.claude/skills/weekly-trade-strategy/skills/technical-analyst/SKILL.md +238 -0
  345. package/.claude/skills/weekly-trade-strategy/skills/technical-analyst/assets/analysis_template.md +183 -0
  346. package/.claude/skills/weekly-trade-strategy/skills/technical-analyst/references/technical_analysis_framework.md +282 -0
  347. package/.claude/skills/weekly-trade-strategy/skills/us-market-bubble-detector/CHANGELOG.md +118 -0
  348. package/.claude/skills/weekly-trade-strategy/skills/us-market-bubble-detector/SKILL.md +545 -0
  349. package/.claude/skills/weekly-trade-strategy/skills/us-market-bubble-detector/references/bubble_framework.md +335 -0
  350. package/.claude/skills/weekly-trade-strategy/skills/us-market-bubble-detector/references/historical_cases.md +327 -0
  351. package/.claude/skills/weekly-trade-strategy/skills/us-market-bubble-detector/references/implementation_guide.md +473 -0
  352. package/.claude/skills/weekly-trade-strategy/skills/us-market-bubble-detector/references/quick_reference.md +354 -0
  353. package/.claude/skills/weekly-trade-strategy/skills/us-market-bubble-detector/references/quick_reference_en.md +342 -0
  354. package/.claude/skills/weekly-trade-strategy/skills/us-market-bubble-detector/scripts/bubble_scorer.py +309 -0
  355. package/.claude/skills/weekly-trade-strategy/skills/us-stock-analysis/SKILL.md +294 -0
  356. package/.claude/skills/weekly-trade-strategy/skills/us-stock-analysis/references/financial-metrics.md +172 -0
  357. package/.claude/skills/weekly-trade-strategy/skills/us-stock-analysis/references/fundamental-analysis.md +129 -0
  358. package/.claude/skills/weekly-trade-strategy/skills/us-stock-analysis/references/report-template.md +207 -0
  359. package/.claude/skills/weekly-trade-strategy/skills/us-stock-analysis/references/technical-analysis.md +93 -0
  360. package/.mcp.json +3 -0
  361. package/cli.mjs +16 -16
  362. package/package.json +4 -2
@@ -0,0 +1,215 @@
1
+ # Uptrend Analyzer Methodology
2
+
3
+ ## Data Source: Monty's Uptrend Ratio Dashboard
4
+
5
+ Monty's Uptrend Ratio Dashboard tracks approximately 2,800 US stocks across 11 GICS sectors. For each stock, it determines whether the stock is in an "uptrend" based on the criteria below. The dashboard publishes daily CSV data on GitHub.
6
+
7
+ **GitHub Repository:** `tradermonty/uptrend-dashboard`
8
+ **Live Dashboard:** https://uptrend-dashboard.streamlit.app/
9
+
10
+ ### Uptrend Definition (Finviz Elite Screener)
11
+
12
+ A stock is classified as "uptrend" when it meets **all** of the following conditions:
13
+
14
+ | Condition | Description |
15
+ |-----------|-------------|
16
+ | Price > $10 | Penny stocks excluded |
17
+ | Avg Volume > 100K | Sufficient liquidity |
18
+ | Market Cap > $50M | Micro-cap and above |
19
+ | Price > SMA20 | Short-term uptrend |
20
+ | Price > SMA200 | Long-term uptrend |
21
+ | SMA50 > SMA200 | Golden cross (bullish structure) |
22
+ | 52W High/Low > 30% above Low | Recovering from bottom |
23
+ | 4-Week Performance: Up | Recent momentum positive |
24
+
25
+ The **uptrend ratio** = (stocks meeting all conditions) / (stocks meeting base filters: price, volume, market cap).
26
+
27
+ ### CSV Files
28
+
29
+ | File | Description | Update Frequency |
30
+ |------|-------------|------------------|
31
+ | `uptrend_ratio_timeseries.csv` | Daily ratios for "all" + 11 sectors | Daily |
32
+ | `sector_summary.csv` | Latest snapshot of all sectors | Daily |
33
+
34
+ **Data availability:**
35
+ - "all" (full market): Since 2023-08-11
36
+ - Sector-level data: Since 2024-07-21
37
+
38
+ ### Timeseries Columns
39
+
40
+ | Column | Type | Description |
41
+ |--------|------|-------------|
42
+ | worksheet | string | "all" or sector slug (e.g., "sec_technology") |
43
+ | date | string | YYYY-MM-DD format |
44
+ | count | int | Number of stocks in uptrend |
45
+ | total | int | Total stocks tracked |
46
+ | ratio | float | count/total (0-1 scale, raw decimal) |
47
+ | ma_10 | float | 10-day simple moving average of ratio |
48
+ | slope | float | 1-day difference of ma_10 (`ma_10.diff()`) |
49
+ | trend | string | "up" (slope > 0) or "down" (slope <= 0) |
50
+
51
+ ### Sector Summary Columns
52
+
53
+ | Column | Type | Description |
54
+ |--------|------|-------------|
55
+ | Sector | string | Display name (e.g., "Technology") |
56
+ | Ratio | float | Current uptrend ratio (0-1) |
57
+ | 10MA | float | 10-day MA of ratio |
58
+ | Trend | string | "Up" or "Down" |
59
+ | Slope | float | 1-day difference of MA |
60
+ | Status | string | "Overbought", "Oversold", or "Normal" |
61
+
62
+ ### Indicator Calculations (from source code)
63
+
64
+ All indicators are computed on-the-fly from raw count/total data:
65
+
66
+ ```
67
+ ratio = count / total
68
+ ma_10 = ratio.rolling(10).mean() # 10-day simple MA
69
+ slope = ma_10.diff() # 1-day change of MA
70
+ trend = "up" if slope > 0 else "down"
71
+ ```
72
+
73
+ **Peak/Trough Detection:** The dashboard uses `scipy.signal.find_peaks` with parameters `distance=20, prominence=0.015` to identify local tops and bottoms in the 10MA series.
74
+
75
+ ---
76
+
77
+ ## Official Dashboard Thresholds
78
+
79
+ These thresholds are defined in `src/constants.py` of the source repository:
80
+
81
+ | Threshold | Value | Meaning |
82
+ |-----------|-------|---------|
83
+ | **Upper (Overbought)** | **37%** | Ratio above this = overbought conditions |
84
+ | **Lower (Oversold)** | **9.7%** | Ratio below this = oversold / crisis |
85
+ | MA Period | 10 | Simple moving average window |
86
+
87
+ ### Status Determination
88
+
89
+ ```
90
+ ratio > 0.37 -> "Overbought"
91
+ ratio < 0.097 -> "Oversold"
92
+ otherwise -> "Normal"
93
+ ```
94
+
95
+ ### Practical Interpretation
96
+
97
+ | Ratio | Interpretation | Market Environment |
98
+ |-------|---------------|-------------------|
99
+ | 50%+ | Strong breadth | Broad bull market, most stocks participating |
100
+ | 37-50% | Overbought / Healthy | Above upper threshold, strong but extended |
101
+ | 25-37% | Normal / Recovering | Between thresholds, typical trading range |
102
+ | 9.7-25% | Weak | Below normal, breadth deteriorating |
103
+ | < 9.7% | Oversold / Crisis | Below lower threshold, extreme selling |
104
+
105
+ ---
106
+
107
+ ## 5-Component Scoring System
108
+
109
+ ### Component 1: Market Breadth (Overall) - Weight: 30%
110
+
111
+ **Rationale:** The overall uptrend ratio is the single most important measure of market health. A high ratio means broad participation; a low ratio means a narrow, fragile market.
112
+
113
+ **Scoring Bands (aligned with dashboard thresholds):**
114
+
115
+ | Ratio | Score Range | Signal |
116
+ |-------|-------------|--------|
117
+ | >= 50% | 90-100 | Strong Bull |
118
+ | 37-50% | 70-89 | Bullish (above overbought threshold) |
119
+ | 25-37% | 40-69 | Neutral/Recovering |
120
+ | 9.7-25% | 10-39 | Weak (between thresholds) |
121
+ | < 9.7% | 0-9 | Crisis (below oversold threshold) |
122
+
123
+ **Trend Adjustment:** +5 when trend="up" and slope>0, -5 when trend="down" and slope<0.
124
+
125
+ ### Component 2: Sector Participation - Weight: 25%
126
+
127
+ **Rationale:** A healthy market has most sectors participating. When only 2-3 sectors lead, the market is fragile and vulnerable to sector rotation shocks.
128
+
129
+ **Sub-scores:**
130
+ - **Uptrend Count (60%):** Number of sectors in uptrend mapped to 0-100
131
+ - **Spread (40%):** Max-min ratio spread. Narrow spread = uniform participation (good). Wide spread = selective market (risky).
132
+
133
+ **Overbought/Oversold classification uses dashboard thresholds:** >37% = Overbought, <9.7% = Oversold.
134
+
135
+ ### Component 3: Sector Rotation - Weight: 15%
136
+
137
+ **Rationale:** In a healthy bull market, cyclical sectors (Technology, Consumer Cyclical) lead defensive sectors (Utilities, Consumer Defensive). When defensives lead, it signals risk-off behavior.
138
+
139
+ **Sector Classification:**
140
+
141
+ | Group | Sectors |
142
+ |-------|---------|
143
+ | Cyclical | Technology, Consumer Cyclical, Communication Services, Financial, Industrials |
144
+ | Defensive | Utilities, Consumer Defensive, Healthcare, Real Estate |
145
+ | Commodity | Energy, Basic Materials |
146
+
147
+ **Scoring:** Based on cyclical_avg - defensive_avg difference.
148
+ - Cyclical lead > +15pp = Strong risk-on (90-100)
149
+ - Balanced within +/-5pp = Neutral (45-69)
150
+ - Defensive lead > +15pp = Strong risk-off (0-19)
151
+
152
+ **Commodity Adjustment:** When commodity sectors outperform both cyclical and defensive groups, it may signal late-cycle dynamics. A penalty of -5 to -10 is applied.
153
+
154
+ ### Component 4: Momentum - Weight: 20%
155
+
156
+ **Rationale:** The direction and rate of change in breadth matters as much as the level. Improving breadth (positive slope, accelerating) suggests the environment is getting better; deteriorating breadth suggests caution.
157
+
158
+ **Sub-scores:**
159
+ - **Slope Score (50%):** Current slope mapped to 0-100 (typical range: -0.02 to +0.02)
160
+ - **Acceleration (30%):** Recent 5-point slope average vs prior 5-point average
161
+ - **Sector Slope Breadth (20%):** Count of sectors with positive slope
162
+
163
+ ### Component 5: Historical Context - Weight: 10%
164
+
165
+ **Rationale:** Knowing where the current ratio falls in historical distribution provides perspective. A ratio that seems "low" might be historically average, or vice versa.
166
+
167
+ **Scoring:** Percentile rank of current ratio in the full historical distribution (Aug 2023 to present).
168
+
169
+ **Note:** The "all" dataset starts from 2023-08-11 (~650+ data points), while sector data starts from 2024-07-21 (~370+ data points each).
170
+
171
+ ---
172
+
173
+ ## Scoring Zones and Exposure Guidance
174
+
175
+ | Score | Zone | Exposure | Description |
176
+ |-------|------|----------|-------------|
177
+ | 80-100 | Strong Bull | Full (100%) | Broad participation, strong momentum. Ideal for aggressive positioning. |
178
+ | 60-79 | Bull | Normal (80-100%) | Healthy breadth. Standard position management. |
179
+ | 40-59 | Neutral | Reduced (60-80%) | Mixed signals. Participate selectively. |
180
+ | 20-39 | Cautious | Defensive (30-60%) | Weak breadth. Prioritize capital preservation. |
181
+ | 0-19 | Bear | Preservation (0-30%) | Severe deterioration. Maximum defense. |
182
+
183
+ ---
184
+
185
+ ## Weight Rationale
186
+
187
+ | Component | Weight | Rationale |
188
+ |-----------|--------|-----------|
189
+ | Market Breadth | 30% | Most direct measure of market health |
190
+ | Sector Participation | 25% | Breadth of sector-level participation is critical for sustainability |
191
+ | Momentum | 20% | Direction matters as much as level |
192
+ | Sector Rotation | 15% | Rotation signals provide important risk-on/off context |
193
+ | Historical Context | 10% | Provides perspective but less actionable than real-time signals |
194
+
195
+ ---
196
+
197
+ ## Limitations
198
+
199
+ 1. **Data History:** "all" data starts from Aug 2023; sector data from Jul 2024. Long-term percentile analysis is limited.
200
+ 2. **Single Source:** Relies entirely on Monty's dashboard (Finviz Elite data); no cross-validation with other breadth measures.
201
+ 3. **No Volume Data:** Uptrend ratio is price-based only; no volume confirmation.
202
+ 4. **Lagging Indicator:** 10-day moving average and slope introduce inherent lag.
203
+ 5. **US Only:** Covers US stocks only; no international market breadth.
204
+ 6. **Sector Classification:** Uses fixed GICS sectors which may not capture all rotation dynamics.
205
+ 7. **Finviz Dependency:** Upstream data depends on Finviz Elite availability and screener accuracy.
206
+
207
+ ---
208
+
209
+ ## Complementary Analysis
210
+
211
+ This skill works best when combined with:
212
+ - **Market Top Detector:** For distribution day and leadership deterioration signals
213
+ - **Technical Analyst:** For index-level chart confirmation
214
+ - **Sector Analyst:** For detailed sector rotation analysis
215
+ - **Market News Analyst:** For fundamental catalyst context
@@ -0,0 +1 @@
1
+ # Uptrend Analyzer - Calculator modules
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Component 5: Historical Context - Weight: 10%
4
+
5
+ Evaluates the current uptrend ratio relative to its full historical
6
+ distribution (2023/08~present) using percentile rank.
7
+
8
+ Data Source: Timeseries "all" worksheet
9
+
10
+ Score = percentile rank of current ratio in historical distribution
11
+ Additional context: min, max, median, 30d avg, 90d avg
12
+ """
13
+
14
+ from typing import Dict, List, Optional
15
+
16
+
17
+ def calculate_historical_context(all_timeseries: List[Dict]) -> Dict:
18
+ """
19
+ Calculate historical context score via percentile rank.
20
+
21
+ Args:
22
+ all_timeseries: Full "all" timeseries sorted by date ascending
23
+
24
+ Returns:
25
+ Dict with score (0-100), signal, and context fields
26
+ """
27
+ if not all_timeseries:
28
+ return {
29
+ "score": 50,
30
+ "signal": "NO DATA: Historical timeseries unavailable (neutral default)",
31
+ "data_available": False,
32
+ "percentile": None,
33
+ "current_ratio": None,
34
+ "historical_min": None,
35
+ "historical_max": None,
36
+ "historical_median": None,
37
+ }
38
+
39
+ # Extract all valid ratios
40
+ ratios = [r["ratio"] for r in all_timeseries if r.get("ratio") is not None]
41
+
42
+ if len(ratios) < 2:
43
+ return {
44
+ "score": 50,
45
+ "signal": "INSUFFICIENT DATA: Need at least 2 data points",
46
+ "data_available": False,
47
+ "percentile": None,
48
+ "current_ratio": None,
49
+ "data_points": len(ratios),
50
+ }
51
+
52
+ current_ratio = ratios[-1]
53
+
54
+ # Calculate percentile rank
55
+ below_count = sum(1 for r in ratios if r < current_ratio)
56
+ equal_count = sum(1 for r in ratios if r == current_ratio)
57
+ percentile = (below_count + equal_count * 0.5) / len(ratios) * 100
58
+ percentile = round(percentile, 1)
59
+
60
+ # Score = percentile rank (direct mapping)
61
+ score = round(min(100, max(0, percentile)))
62
+
63
+ # Historical statistics
64
+ sorted_ratios = sorted(ratios)
65
+ hist_min = sorted_ratios[0]
66
+ hist_max = sorted_ratios[-1]
67
+ n = len(sorted_ratios)
68
+ if n % 2 == 0:
69
+ hist_median = (sorted_ratios[n // 2 - 1] + sorted_ratios[n // 2]) / 2
70
+ else:
71
+ hist_median = sorted_ratios[n // 2]
72
+
73
+ # Recent averages
74
+ avg_30d = _avg_last_n(ratios, 30)
75
+ avg_90d = _avg_last_n(ratios, 90)
76
+
77
+ signal = _build_signal(score, percentile, current_ratio)
78
+
79
+ return {
80
+ "score": score,
81
+ "signal": signal,
82
+ "data_available": True,
83
+ "percentile": percentile,
84
+ "current_ratio": current_ratio,
85
+ "current_ratio_pct": round(current_ratio * 100, 1),
86
+ "historical_min": round(hist_min, 4),
87
+ "historical_min_pct": round(hist_min * 100, 1),
88
+ "historical_max": round(hist_max, 4),
89
+ "historical_max_pct": round(hist_max * 100, 1),
90
+ "historical_median": round(hist_median, 4),
91
+ "historical_median_pct": round(hist_median * 100, 1),
92
+ "avg_30d": round(avg_30d, 4) if avg_30d is not None else None,
93
+ "avg_30d_pct": round(avg_30d * 100, 1) if avg_30d is not None else None,
94
+ "avg_90d": round(avg_90d, 4) if avg_90d is not None else None,
95
+ "avg_90d_pct": round(avg_90d * 100, 1) if avg_90d is not None else None,
96
+ "data_points": len(ratios),
97
+ "date_range": f"{all_timeseries[0].get('date', '?')} to {all_timeseries[-1].get('date', '?')}",
98
+ }
99
+
100
+
101
+ def _avg_last_n(values: List[float], n: int) -> Optional[float]:
102
+ """Average of the last n values, or all if fewer than n."""
103
+ if not values:
104
+ return None
105
+ subset = values[-n:]
106
+ return sum(subset) / len(subset)
107
+
108
+
109
+ def _build_signal(score: int, percentile: float, current_ratio: float) -> str:
110
+ """Build human-readable signal."""
111
+ ratio_pct = round(current_ratio * 100, 1)
112
+
113
+ if score >= 80:
114
+ return f"ABOVE AVERAGE: {ratio_pct}% at {percentile}th percentile historically"
115
+ elif score >= 60:
116
+ return f"SLIGHTLY ABOVE: {ratio_pct}% at {percentile}th percentile historically"
117
+ elif score >= 40:
118
+ return f"NEAR MEDIAN: {ratio_pct}% at {percentile}th percentile historically"
119
+ elif score >= 20:
120
+ return f"BELOW AVERAGE: {ratio_pct}% at {percentile}th percentile historically"
121
+ else:
122
+ return f"HISTORICALLY LOW: {ratio_pct}% at {percentile}th percentile historically"
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Component 1: Market Breadth (Overall) - Weight: 30%
4
+
5
+ Evaluates the overall market uptrend ratio level and trend direction.
6
+ Primary signal: ratio level mapped to scoring bands with trend adjustment.
7
+
8
+ Data Source: Timeseries "all" worksheet
9
+
10
+ Thresholds aligned with Monty's dashboard:
11
+ - Overbought: 37% (upper threshold)
12
+ - Oversold: 9.7% (lower threshold)
13
+
14
+ Scoring Bands (linear interpolation within each band):
15
+ >= 50% -> 90-100 (Strong Bull)
16
+ 37-50% -> 70-89 (Bullish / above overbought threshold)
17
+ 25-37% -> 40-69 (Neutral/Recovering)
18
+ 9.7-25% -> 10-39 (Weak / between thresholds)
19
+ < 9.7% -> 0-9 (Crisis / below oversold threshold)
20
+
21
+ Trend adjustment: trend="up" & slope>0 -> +5, trend="down" & slope<0 -> -5
22
+ """
23
+
24
+ from typing import Dict, List, Optional
25
+
26
+ # Monty's official dashboard thresholds
27
+ UPPER_THRESHOLD = 0.37 # Overbought
28
+ LOWER_THRESHOLD = 0.097 # Oversold
29
+
30
+
31
+ def calculate_market_breadth(latest_all: Optional[Dict],
32
+ all_timeseries: List[Dict]) -> Dict:
33
+ """
34
+ Calculate market breadth score from overall uptrend ratio.
35
+
36
+ Args:
37
+ latest_all: Most recent "all" timeseries row
38
+ all_timeseries: Full "all" timeseries sorted by date ascending
39
+
40
+ Returns:
41
+ Dict with score (0-100), signal, and detail fields
42
+ """
43
+ if not latest_all or latest_all.get("ratio") is None:
44
+ return {
45
+ "score": 50,
46
+ "signal": "NO DATA: Overall uptrend ratio unavailable (neutral default)",
47
+ "data_available": False,
48
+ "ratio": None,
49
+ "ma_10": None,
50
+ "trend": None,
51
+ "slope": None,
52
+ "distance_from_upper": None,
53
+ "distance_from_lower": None,
54
+ }
55
+
56
+ ratio = latest_all["ratio"]
57
+ ma_10 = latest_all.get("ma_10")
58
+ trend = latest_all.get("trend", "")
59
+ slope = latest_all.get("slope")
60
+
61
+ # Map ratio to base score via linear interpolation
62
+ base_score = _ratio_to_score(ratio)
63
+
64
+ # Trend adjustment
65
+ trend_adj = 0
66
+ if trend.lower() == "up" and slope is not None and slope > 0:
67
+ trend_adj = 5
68
+ elif trend.lower() == "down" and slope is not None and slope < 0:
69
+ trend_adj = -5
70
+
71
+ score = round(min(100, max(0, base_score + trend_adj)))
72
+
73
+ # Signal label
74
+ signal = _score_to_signal(score, ratio, trend)
75
+
76
+ # Key distances from Monty's official thresholds
77
+ distance_from_upper = round(ratio - UPPER_THRESHOLD, 4) if ratio is not None else None
78
+ distance_from_lower = round(ratio - LOWER_THRESHOLD, 4) if ratio is not None else None
79
+
80
+ return {
81
+ "score": score,
82
+ "signal": signal,
83
+ "data_available": True,
84
+ "ratio": ratio,
85
+ "ratio_pct": round(ratio * 100, 1) if ratio is not None else None,
86
+ "ma_10": ma_10,
87
+ "ma_10_pct": round(ma_10 * 100, 1) if ma_10 is not None else None,
88
+ "trend": trend,
89
+ "slope": slope,
90
+ "trend_adjustment": trend_adj,
91
+ "distance_from_upper": distance_from_upper,
92
+ "distance_from_lower": distance_from_lower,
93
+ "upper_threshold": UPPER_THRESHOLD,
94
+ "lower_threshold": LOWER_THRESHOLD,
95
+ "date": latest_all.get("date", "N/A"),
96
+ }
97
+
98
+
99
+ def _ratio_to_score(ratio: float) -> float:
100
+ """Map uptrend ratio (0-1 scale) to base score (0-100).
101
+
102
+ Aligned with Monty's dashboard thresholds:
103
+ Upper (Overbought) = 0.37, Lower (Oversold) = 0.097
104
+
105
+ Scoring bands with linear interpolation:
106
+ >= 0.50 -> 90-100 (Strong Bull)
107
+ 0.37-0.50 -> 70-89 (Bullish, above overbought)
108
+ 0.25-0.37 -> 40-69 (Neutral/Recovering)
109
+ 0.097-0.25 -> 10-39 (Weak, between thresholds)
110
+ < 0.097 -> 0-9 (Crisis, below oversold)
111
+ """
112
+ if ratio >= 0.50:
113
+ # 0.50 -> 90, 0.60+ -> 100
114
+ return min(100, 90 + (ratio - 0.50) / 0.10 * 10)
115
+ elif ratio >= UPPER_THRESHOLD:
116
+ # 0.37 -> 70, 0.50 -> 89
117
+ return 70 + (ratio - UPPER_THRESHOLD) / (0.50 - UPPER_THRESHOLD) * 19
118
+ elif ratio >= 0.25:
119
+ # 0.25 -> 40, 0.37 -> 69
120
+ return 40 + (ratio - 0.25) / (UPPER_THRESHOLD - 0.25) * 29
121
+ elif ratio >= LOWER_THRESHOLD:
122
+ # 0.097 -> 10, 0.25 -> 39
123
+ return 10 + (ratio - LOWER_THRESHOLD) / (0.25 - LOWER_THRESHOLD) * 29
124
+ else:
125
+ # 0 -> 0, 0.097 -> 9
126
+ return max(0, ratio / LOWER_THRESHOLD * 9)
127
+
128
+
129
+ def _score_to_signal(score: int, ratio: float, trend: str) -> str:
130
+ """Map score to human-readable signal."""
131
+ ratio_pct = round(ratio * 100, 1)
132
+ trend_label = f", trend {trend}" if trend else ""
133
+
134
+ if score >= 90:
135
+ return f"STRONG BULL: {ratio_pct}% uptrend ratio{trend_label}"
136
+ elif score >= 70:
137
+ return f"BULLISH: {ratio_pct}% uptrend ratio{trend_label}"
138
+ elif score >= 45:
139
+ return f"NEUTRAL: {ratio_pct}% uptrend ratio{trend_label}"
140
+ elif score >= 30:
141
+ return f"WEAK: {ratio_pct}% uptrend ratio{trend_label}"
142
+ elif score >= 10:
143
+ return f"VERY WEAK: {ratio_pct}% uptrend ratio{trend_label}"
144
+ else:
145
+ return f"CRISIS: {ratio_pct}% uptrend ratio{trend_label}"
@@ -0,0 +1,183 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Component 4: Momentum - Weight: 20%
4
+
5
+ Evaluates the rate of change (slope) and acceleration of the overall
6
+ uptrend ratio, plus sector-level slope breadth.
7
+
8
+ Data Source: Timeseries "all" + Sector Summary
9
+
10
+ Sub-scores:
11
+ - Slope Score (50%): Current slope mapped to 0-100 (typical range: -0.02~+0.02)
12
+ - Acceleration (30%): Recent 5-point slope avg vs prior 5-point
13
+ - Sector Slope Breadth (20%): Count of sectors with positive slope
14
+ """
15
+
16
+ from typing import Dict, List, Optional
17
+
18
+
19
+ def calculate_momentum(all_timeseries: List[Dict],
20
+ sector_summary: List[Dict]) -> Dict:
21
+ """
22
+ Calculate momentum score from slope, acceleration, and sector breadth.
23
+
24
+ Args:
25
+ all_timeseries: Full "all" timeseries sorted by date ascending
26
+ sector_summary: Latest sector summary rows
27
+
28
+ Returns:
29
+ Dict with score (0-100), signal, and detail fields
30
+ """
31
+ if not all_timeseries:
32
+ return {
33
+ "score": 50,
34
+ "signal": "NO DATA: Timeseries unavailable (neutral default)",
35
+ "data_available": False,
36
+ "slope": None,
37
+ "acceleration": None,
38
+ "sector_slope_breadth": None,
39
+ }
40
+
41
+ latest = all_timeseries[-1]
42
+ current_slope = latest.get("slope")
43
+
44
+ # Sub-score 1: Slope Score (50%)
45
+ slope_score = _score_slope(current_slope) if current_slope is not None else 50
46
+
47
+ # Sub-score 2: Acceleration (30%)
48
+ accel_score, accel_value, accel_label = _score_acceleration(all_timeseries)
49
+
50
+ # Sub-score 3: Sector Slope Breadth (20%)
51
+ breadth_score, positive_slope_count, total_sectors = _score_sector_slope_breadth(
52
+ sector_summary
53
+ )
54
+
55
+ # Composite
56
+ raw_score = slope_score * 0.50 + accel_score * 0.30 + breadth_score * 0.20
57
+ score = round(min(100, max(0, raw_score)))
58
+
59
+ signal = _build_signal(score, current_slope, accel_label)
60
+
61
+ return {
62
+ "score": score,
63
+ "signal": signal,
64
+ "data_available": True,
65
+ "slope": current_slope,
66
+ "slope_score": round(slope_score),
67
+ "acceleration": accel_value,
68
+ "acceleration_label": accel_label,
69
+ "acceleration_score": round(accel_score),
70
+ "sector_positive_slope_count": positive_slope_count,
71
+ "sector_total": total_sectors,
72
+ "sector_slope_breadth_score": round(breadth_score),
73
+ "date": latest.get("date", "N/A"),
74
+ }
75
+
76
+
77
+ def _score_slope(slope: float) -> float:
78
+ """Map current slope to 0-100 score.
79
+
80
+ Typical slope range: -0.02 to +0.02
81
+ Extreme range: -0.03 to +0.03
82
+
83
+ >= +0.02 -> 95-100 (strong bullish momentum)
84
+ +0.01~+0.02 -> 75-94
85
+ 0~+0.01 -> 55-74 (mild positive)
86
+ -0.01~0 -> 35-54 (mild negative)
87
+ -0.02~-0.01 -> 10-34
88
+ < -0.02 -> 0-9 (strong bearish momentum)
89
+ """
90
+ if slope >= 0.02:
91
+ return min(100, 95 + (slope - 0.02) / 0.01 * 5)
92
+ elif slope >= 0.01:
93
+ return 75 + (slope - 0.01) / 0.01 * 19
94
+ elif slope >= 0:
95
+ return 55 + slope / 0.01 * 19
96
+ elif slope >= -0.01:
97
+ return 35 + (slope + 0.01) / 0.01 * 19
98
+ elif slope >= -0.02:
99
+ return 10 + (slope + 0.02) / 0.01 * 24
100
+ else:
101
+ return max(0, 9 + (slope + 0.02) / 0.01 * 9)
102
+
103
+
104
+ def _score_acceleration(timeseries: List[Dict]) -> tuple:
105
+ """Calculate acceleration: recent vs prior slope average.
106
+
107
+ Returns: (score, acceleration_value, label)
108
+ """
109
+ if len(timeseries) < 10:
110
+ return 50, None, "insufficient_data"
111
+
112
+ # Get slopes for recent 10 data points
113
+ recent_slopes = []
114
+ for row in timeseries[-10:]:
115
+ s = row.get("slope")
116
+ if s is not None:
117
+ recent_slopes.append(s)
118
+
119
+ if len(recent_slopes) < 10:
120
+ return 50, None, "insufficient_data"
121
+
122
+ recent_5_avg = sum(recent_slopes[-5:]) / 5
123
+ prior_5_avg = sum(recent_slopes[:5]) / 5
124
+
125
+ acceleration = recent_5_avg - prior_5_avg
126
+
127
+ if acceleration > 0.005:
128
+ label = "strong_accelerating"
129
+ score = 90
130
+ elif acceleration > 0.001:
131
+ label = "accelerating"
132
+ score = 75
133
+ elif acceleration > -0.001:
134
+ label = "steady"
135
+ score = 50
136
+ elif acceleration > -0.005:
137
+ label = "decelerating"
138
+ score = 25
139
+ else:
140
+ label = "strong_decelerating"
141
+ score = 10
142
+
143
+ return score, round(acceleration, 6), label
144
+
145
+
146
+ def _score_sector_slope_breadth(sector_summary: List[Dict]) -> tuple:
147
+ """Score based on count of sectors with positive slope.
148
+
149
+ Returns: (score, positive_count, total_count)
150
+ """
151
+ if not sector_summary:
152
+ return 50, 0, 0
153
+
154
+ total = len(sector_summary)
155
+ positive = sum(
156
+ 1 for s in sector_summary
157
+ if s.get("Slope") is not None and s["Slope"] > 0
158
+ )
159
+
160
+ if total == 0:
161
+ return 50, 0, 0
162
+
163
+ # Linear mapping: 0 sectors -> 0, all sectors -> 100
164
+ score = (positive / total) * 100
165
+
166
+ return score, positive, total
167
+
168
+
169
+ def _build_signal(score: int, slope: Optional[float], accel_label: str) -> str:
170
+ """Build human-readable signal."""
171
+ slope_str = f"slope={slope:.4f}" if slope is not None else "slope=N/A"
172
+ accel_str = accel_label.replace("_", " ")
173
+
174
+ if score >= 80:
175
+ return f"STRONG MOMENTUM: {slope_str}, {accel_str}"
176
+ elif score >= 60:
177
+ return f"POSITIVE MOMENTUM: {slope_str}, {accel_str}"
178
+ elif score >= 40:
179
+ return f"NEUTRAL MOMENTUM: {slope_str}, {accel_str}"
180
+ elif score >= 20:
181
+ return f"WEAK MOMENTUM: {slope_str}, {accel_str}"
182
+ else:
183
+ return f"NEGATIVE MOMENTUM: {slope_str}, {accel_str}"