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,330 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Market Breadth Analyzer - Report Generator
4
+
5
+ Generates JSON and Markdown reports for market breadth health analysis.
6
+ """
7
+
8
+ import json
9
+ from typing import Dict
10
+
11
+
12
+ def generate_json_report(analysis: Dict, output_file: str):
13
+ """Save full analysis as JSON."""
14
+ with open(output_file, "w") as f:
15
+ json.dump(analysis, f, indent=2, default=str)
16
+ print(f" JSON report saved to: {output_file}")
17
+
18
+
19
+ def generate_markdown_report(analysis: Dict, output_file: str):
20
+ """Generate comprehensive Markdown report."""
21
+ lines = []
22
+ composite = analysis.get("composite", {})
23
+ components = analysis.get("components", {})
24
+ metadata = analysis.get("metadata", {})
25
+ freshness = metadata.get("data_freshness", {})
26
+
27
+ score = composite.get("composite_score", 0)
28
+ zone = composite.get("zone", "Unknown")
29
+ exposure = composite.get("exposure_guidance", "N/A")
30
+
31
+ # Header
32
+ lines.append("# Market Breadth Analyzer Report")
33
+ lines.append("")
34
+ lines.append(f"**Generated:** {metadata.get('generated_at', 'N/A')}")
35
+ lines.append(f"**Data Source:** TraderMonty Market Breadth CSV (no API key required)")
36
+ latest = freshness.get("latest_date", "N/A")
37
+ days_old = freshness.get("days_old", "?")
38
+ last_modified = freshness.get("last_modified")
39
+ lm_str = f" | CSV last modified: {last_modified}" if last_modified else ""
40
+ lines.append(f"**Latest Data:** {latest} ({days_old} days old{lm_str})")
41
+ lines.append(
42
+ f"**Live Dashboard:** [Interactive Chart]"
43
+ f"(https://tradermonty.github.io/market-breadth-analysis/)"
44
+ )
45
+ lines.append("")
46
+
47
+ # Freshness warning
48
+ warning = freshness.get("warning")
49
+ if warning:
50
+ lines.append(f"> **WARNING:** {warning}")
51
+ lines.append("")
52
+
53
+ # Overall Assessment
54
+ lines.append("---")
55
+ lines.append("")
56
+ lines.append("## Overall Assessment")
57
+ lines.append("")
58
+ zone_emoji = _zone_emoji(composite.get("zone_color", ""))
59
+ lines.append("| Metric | Value |")
60
+ lines.append("|--------|-------|")
61
+ lines.append(f"| **Composite Score** | **{score}/100** |")
62
+ lines.append(f"| **Health Zone** | {zone_emoji} {zone} |")
63
+ lines.append(f"| **Equity Exposure** | {exposure} |")
64
+ lines.append(
65
+ f"| **Strongest** | {composite.get('strongest_health', {}).get('label', 'N/A')} "
66
+ f"({composite.get('strongest_health', {}).get('score', 0)}/100) |"
67
+ )
68
+ lines.append(
69
+ f"| **Weakest** | {composite.get('weakest_health', {}).get('label', 'N/A')} "
70
+ f"({composite.get('weakest_health', {}).get('score', 0)}/100) |"
71
+ )
72
+ dq = composite.get("data_quality", {})
73
+ if dq:
74
+ lines.append(f"| **Data Quality** | {dq.get('label', 'N/A')} |")
75
+ lines.append("")
76
+
77
+ # Guidance
78
+ lines.append(f"> **Guidance:** {composite.get('guidance', '')}")
79
+ lines.append("")
80
+
81
+ # Component Scores Table
82
+ lines.append("---")
83
+ lines.append("")
84
+ lines.append("## Component Scores")
85
+ lines.append("")
86
+ lines.append("| # | Component | Weight | Score | Contribution | Signal |")
87
+ lines.append("|---|-----------|--------|-------|--------------|--------|")
88
+
89
+ component_order = [
90
+ "breadth_level_trend",
91
+ "ma_crossover",
92
+ "cycle_position",
93
+ "bearish_signal",
94
+ "historical_percentile",
95
+ "divergence",
96
+ ]
97
+
98
+ for i, key in enumerate(component_order, 1):
99
+ comp = composite.get("component_scores", {}).get(key, {})
100
+ detail = components.get(key, {})
101
+ signal = detail.get("signal", "N/A")
102
+ score_val = comp.get("score", 0)
103
+ weight_pct = f"{comp.get('weight', 0) * 100:.0f}%"
104
+ contribution = comp.get("weighted_contribution", 0)
105
+ bar = _score_bar(score_val)
106
+
107
+ lines.append(
108
+ f"| {i} | **{comp.get('label', key)}** | {weight_pct} | "
109
+ f"{bar} {score_val} | {contribution:.1f} | {signal} |"
110
+ )
111
+
112
+ lines.append("")
113
+
114
+ # Component Details
115
+ lines.append("---")
116
+ lines.append("")
117
+ lines.append("## Component Details")
118
+ lines.append("")
119
+
120
+ # C1: Breadth Level & Trend
121
+ c1 = components.get("breadth_level_trend", {})
122
+ lines.append("### 1. Current Breadth Level & Trend")
123
+ lines.append("")
124
+ if c1:
125
+ lines.append(f"- **8MA Level:** {c1.get('current_8ma', 0):.4f}")
126
+ lines.append(f"- **200MA Level:** {c1.get('current_200ma', 0):.4f}")
127
+ lines.append(
128
+ f"- **200MA Trend:** {'Uptrend' if c1.get('trend') == 1 else 'Downtrend'}"
129
+ )
130
+ lines.append(f"- **Level Score:** {c1.get('level_score', 'N/A')}")
131
+ lines.append(f"- **Trend Score:** {c1.get('trend_score', 'N/A')}")
132
+ lines.append("")
133
+
134
+ # C2: MA Crossover
135
+ c2 = components.get("ma_crossover", {})
136
+ lines.append("### 2. 8MA vs 200MA Crossover Dynamics")
137
+ lines.append("")
138
+ if c2:
139
+ lines.append(f"- **Gap (8MA - 200MA):** {c2.get('gap', 0):+.4f}")
140
+ lines.append(f"- **Gap Score:** {c2.get('gap_score', 'N/A')}")
141
+ lines.append(
142
+ f"- **8MA Direction (5d):** {c2.get('ma8_direction', 'N/A')}"
143
+ )
144
+ lines.append(
145
+ f"- **Direction Modifier:** {c2.get('direction_modifier', 0):+d}"
146
+ )
147
+ lines.append("")
148
+
149
+ # C3: Cycle Position
150
+ c3 = components.get("cycle_position", {})
151
+ lines.append("### 3. Peak/Trough Cycle Position")
152
+ lines.append("")
153
+ if c3:
154
+ lines.append(f"- **Latest Marker:** {c3.get('latest_marker_type', 'None')}")
155
+ lines.append(f"- **Days Since Marker:** {c3.get('days_since_marker', 'N/A')}")
156
+ lines.append(f"- **8MA Trend:** {c3.get('ma8_trend', 'N/A')}")
157
+ if c3.get("extreme_trough"):
158
+ lines.append("- **Extreme Trough (8MA < 0.4):** Yes (+10 bonus)")
159
+ lines.append("")
160
+
161
+ # C4: Bearish Signal
162
+ c4 = components.get("bearish_signal", {})
163
+ lines.append("### 4. Bearish Signal Status")
164
+ lines.append("")
165
+ if c4:
166
+ lines.append(
167
+ f"- **Bearish Signal Active:** {'YES' if c4.get('signal_active') else 'No'}"
168
+ )
169
+ lines.append(
170
+ f"- **200MA Trend:** {'Uptrend' if c4.get('trend') == 1 else 'Downtrend'}"
171
+ )
172
+ lines.append(f"- **Current 8MA:** {c4.get('current_8ma', 0):.4f}")
173
+ in_pink = c4.get("in_pink_zone", False)
174
+ pink_days = c4.get("pink_zone_days", 0)
175
+ if in_pink:
176
+ lines.append(
177
+ f"- **Pink Zone:** YES ({pink_days} consecutive days) "
178
+ f"- 200MA downtrend + 8MA below 200MA"
179
+ )
180
+ else:
181
+ lines.append("- **Pink Zone:** No (outside bearish region)")
182
+ lines.append(f"- **Base Score:** {c4.get('base_score', 'N/A')}")
183
+ lines.append(
184
+ f"- **Context Adjustment:** {c4.get('context_adjustment', 0):+d}"
185
+ )
186
+ pink_adj = c4.get("pink_zone_adjustment", 0)
187
+ if pink_adj != 0:
188
+ lines.append(f"- **Pink Zone Adjustment:** {pink_adj:+d}")
189
+ lines.append("")
190
+
191
+ # C5: Historical Percentile
192
+ c5 = components.get("historical_percentile", {})
193
+ lines.append("### 5. Historical Percentile")
194
+ lines.append("")
195
+ if c5:
196
+ lines.append(f"- **Current 8MA:** {c5.get('current_8ma', 0):.4f}")
197
+ lines.append(
198
+ f"- **Percentile Rank:** {c5.get('percentile_rank', 'N/A'):.1f}%"
199
+ )
200
+ lines.append(f"- **Avg Peak (200MA):** {c5.get('avg_peak', 'N/A')}")
201
+ lines.append(f"- **Avg Trough (8MA<0.4):** {c5.get('avg_trough', 'N/A')}")
202
+ adj = c5.get("adjustment", 0)
203
+ if adj != 0:
204
+ label = "Overheated (-10)" if adj < 0 else "Oversold (+10)"
205
+ lines.append(f"- **Adjustment:** {label}")
206
+ lines.append("")
207
+
208
+ # C6: Divergence
209
+ c6 = components.get("divergence", {})
210
+ lines.append("### 6. S&P 500 vs Breadth Divergence")
211
+ lines.append("")
212
+ if c6:
213
+ lines.append(
214
+ f"- **S&P 500 60d Change:** {c6.get('sp500_pct_change', 0):+.2f}%"
215
+ )
216
+ lines.append(
217
+ f"- **Breadth 8MA 60d Change:** {c6.get('breadth_change', 0):+.4f}"
218
+ )
219
+ lines.append(f"- **Divergence Type:** {c6.get('divergence_type', 'N/A')}")
220
+ lines.append("")
221
+
222
+ # Key Levels to Watch
223
+ lines.append("---")
224
+ lines.append("")
225
+ lines.append("## Key Levels to Watch")
226
+ lines.append("")
227
+ key_levels = analysis.get("key_levels", {})
228
+ if key_levels:
229
+ lines.append("| Level | Value | Significance |")
230
+ lines.append("|-------|-------|-------------|")
231
+ for level_name, level_info in key_levels.items():
232
+ lines.append(
233
+ f"| {level_name} | {level_info.get('value', 'N/A')} | "
234
+ f"{level_info.get('significance', '')} |"
235
+ )
236
+ else:
237
+ lines.append("*No key levels computed.*")
238
+ lines.append("")
239
+
240
+ # Recommended Actions
241
+ lines.append("---")
242
+ lines.append("")
243
+ lines.append("## Recommended Actions")
244
+ lines.append("")
245
+ lines.append(f"**Health Zone:** {zone}")
246
+ lines.append(f"**Equity Exposure:** {exposure}")
247
+ lines.append("")
248
+ for action in composite.get("actions", []):
249
+ lines.append(f"- {action}")
250
+ lines.append("")
251
+
252
+ # Methodology
253
+ lines.append("---")
254
+ lines.append("")
255
+ lines.append("## Methodology")
256
+ lines.append("")
257
+ lines.append(
258
+ "This analysis uses TraderMonty's market breadth dataset to quantify "
259
+ "market participation health across 6 dimensions:"
260
+ )
261
+ lines.append("")
262
+ lines.append(
263
+ "1. **Breadth Level & Trend (25%):** Current 8MA level and 200MA trend direction"
264
+ )
265
+ lines.append(
266
+ "2. **MA Crossover (20%):** Gap between 8MA and 200MA with momentum detection"
267
+ )
268
+ lines.append(
269
+ "3. **Cycle Position (20%):** Position relative to recent peaks/troughs"
270
+ )
271
+ lines.append(
272
+ "4. **Bearish Signal (15%):** Backtested bearish signal flag from dataset"
273
+ )
274
+ lines.append(
275
+ "5. **Historical Percentile (10%):** Current level vs full history distribution"
276
+ )
277
+ lines.append(
278
+ "6. **Divergence (10%):** S&P 500 price vs breadth directional agreement"
279
+ )
280
+ lines.append("")
281
+ lines.append(
282
+ "Composite score: 0-100 (100 = maximum health). "
283
+ "No API key required - uses freely available CSV data."
284
+ )
285
+ lines.append("")
286
+ lines.append(
287
+ "For detailed methodology, see `references/breadth_analysis_methodology.md`."
288
+ )
289
+ lines.append("")
290
+
291
+ # Disclaimer
292
+ lines.append("---")
293
+ lines.append("")
294
+ lines.append(
295
+ "**Disclaimer:** This analysis is for educational and informational purposes only. "
296
+ "Not investment advice. Past patterns may not predict future outcomes. "
297
+ "Conduct your own research and consult a financial advisor before making "
298
+ "investment decisions."
299
+ )
300
+ lines.append("")
301
+
302
+ with open(output_file, "w") as f:
303
+ f.write("\n".join(lines))
304
+
305
+ print(f" Markdown report saved to: {output_file}")
306
+
307
+
308
+ def _zone_emoji(color: str) -> str:
309
+ mapping = {
310
+ "green": "🟢",
311
+ "blue": "🔵",
312
+ "yellow": "🟡",
313
+ "orange": "🟠",
314
+ "red": "🔴",
315
+ }
316
+ return mapping.get(color, "⚪")
317
+
318
+
319
+ def _score_bar(score: int) -> str:
320
+ """Text bar for score visualization (100 = full/healthy)."""
321
+ if score >= 80:
322
+ return "████"
323
+ elif score >= 60:
324
+ return "███░"
325
+ elif score >= 40:
326
+ return "██░░"
327
+ elif score >= 20:
328
+ return "█░░░"
329
+ else:
330
+ return "░░░░"
@@ -0,0 +1,271 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Market Breadth Analyzer - Composite Scoring Engine
4
+
5
+ Combines 6 component scores into a weighted composite (0-100).
6
+ Score direction: 100 = Healthy, 0 = Critical (breadth is a health indicator).
7
+
8
+ Component Weights:
9
+ 1. Current Breadth Level & Trend: 25%
10
+ 2. 8MA vs 200MA Crossover: 20%
11
+ 3. Peak/Trough Cycle Position: 20%
12
+ 4. Bearish Signal Status: 15%
13
+ 5. Historical Percentile: 10%
14
+ 6. S&P 500 vs Breadth Divergence: 10%
15
+ Total: 100%
16
+
17
+ Health Zone Mapping (100 = Healthy):
18
+ 80-100: Strong - Full equity exposure
19
+ 60-79: Healthy - Normal operations
20
+ 40-59: Neutral - Selective positioning
21
+ 20-39: Weakening - Profit-taking, raise cash
22
+ 0-19: Critical - Capital preservation
23
+ """
24
+
25
+ from typing import Dict, List, Optional
26
+
27
+
28
+ COMPONENT_WEIGHTS = {
29
+ "breadth_level_trend": 0.25,
30
+ "ma_crossover": 0.20,
31
+ "cycle_position": 0.20,
32
+ "bearish_signal": 0.15,
33
+ "historical_percentile": 0.10,
34
+ "divergence": 0.10,
35
+ }
36
+
37
+ COMPONENT_LABELS = {
38
+ "breadth_level_trend": "Current Breadth Level & Trend",
39
+ "ma_crossover": "8MA vs 200MA Crossover",
40
+ "cycle_position": "Peak/Trough Cycle Position",
41
+ "bearish_signal": "Bearish Signal Status",
42
+ "historical_percentile": "Historical Percentile",
43
+ "divergence": "S&P 500 vs Breadth Divergence",
44
+ }
45
+
46
+
47
+ def calculate_composite_score(
48
+ component_scores: Dict[str, float],
49
+ data_availability: Optional[Dict[str, bool]] = None,
50
+ ) -> Dict:
51
+ """
52
+ Calculate weighted composite market breadth health score.
53
+
54
+ Args:
55
+ component_scores: Dict with keys matching COMPONENT_WEIGHTS, each 0-100.
56
+ data_availability: Optional dict mapping component key -> bool.
57
+
58
+ Returns:
59
+ Dict with composite_score, zone, exposure_guidance, guidance,
60
+ strongest/weakest components, component breakdown, and data_quality.
61
+ """
62
+ if data_availability is None:
63
+ data_availability = {}
64
+
65
+ # Weighted composite
66
+ composite = 0.0
67
+ for key, weight in COMPONENT_WEIGHTS.items():
68
+ score = component_scores.get(key, 50)
69
+ composite += score * weight
70
+
71
+ composite = round(composite, 1)
72
+
73
+ # Identify strongest and weakest health signals
74
+ valid_scores = {
75
+ k: v for k, v in component_scores.items() if k in COMPONENT_WEIGHTS
76
+ }
77
+
78
+ if valid_scores:
79
+ strongest_health = max(valid_scores, key=valid_scores.get)
80
+ weakest_health = min(valid_scores, key=valid_scores.get)
81
+ else:
82
+ strongest_health = "N/A"
83
+ weakest_health = "N/A"
84
+
85
+ # Zone interpretation
86
+ zone_info = _interpret_zone(composite)
87
+
88
+ # Data quality
89
+ available_count = sum(
90
+ 1 for k in COMPONENT_WEIGHTS if data_availability.get(k, True)
91
+ )
92
+ total_components = len(COMPONENT_WEIGHTS)
93
+ missing_components = [
94
+ COMPONENT_LABELS[k]
95
+ for k in COMPONENT_WEIGHTS
96
+ if not data_availability.get(k, True)
97
+ ]
98
+
99
+ if available_count == total_components:
100
+ quality_label = f"Complete ({available_count}/{total_components} components)"
101
+ elif available_count >= total_components - 2:
102
+ quality_label = (
103
+ f"Partial ({available_count}/{total_components} components)"
104
+ " - interpret with caution"
105
+ )
106
+ else:
107
+ quality_label = (
108
+ f"Limited ({available_count}/{total_components} components)"
109
+ " - low confidence"
110
+ )
111
+
112
+ data_quality = {
113
+ "available_count": available_count,
114
+ "total_components": total_components,
115
+ "label": quality_label,
116
+ "missing_components": missing_components,
117
+ }
118
+
119
+ return {
120
+ "composite_score": composite,
121
+ "zone": zone_info["zone"],
122
+ "zone_color": zone_info["color"],
123
+ "exposure_guidance": zone_info["exposure_guidance"],
124
+ "guidance": zone_info["guidance"],
125
+ "actions": zone_info["actions"],
126
+ "strongest_health": {
127
+ "component": strongest_health,
128
+ "label": COMPONENT_LABELS.get(strongest_health, strongest_health),
129
+ "score": valid_scores.get(strongest_health, 0),
130
+ },
131
+ "weakest_health": {
132
+ "component": weakest_health,
133
+ "label": COMPONENT_LABELS.get(weakest_health, weakest_health),
134
+ "score": valid_scores.get(weakest_health, 0),
135
+ },
136
+ "data_quality": data_quality,
137
+ "component_scores": {
138
+ k: {
139
+ "score": component_scores.get(k, 50),
140
+ "weight": w,
141
+ "weighted_contribution": round(component_scores.get(k, 50) * w, 1),
142
+ "label": COMPONENT_LABELS[k],
143
+ }
144
+ for k, w in COMPONENT_WEIGHTS.items()
145
+ },
146
+ }
147
+
148
+
149
+ def _interpret_zone(composite: float) -> Dict:
150
+ """Map composite score to health zone (100 = healthy)."""
151
+ if composite >= 80:
152
+ return {
153
+ "zone": "Strong",
154
+ "color": "green",
155
+ "exposure_guidance": "90-100%",
156
+ "guidance": (
157
+ "Broad market participation. Maintain full equity exposure."
158
+ ),
159
+ "actions": [
160
+ "Full position sizing allowed",
161
+ "New entries on pullbacks encouraged",
162
+ "Wide stop-losses acceptable",
163
+ "Growth and momentum strategies favored",
164
+ ],
165
+ }
166
+ elif composite >= 60:
167
+ return {
168
+ "zone": "Healthy",
169
+ "color": "blue",
170
+ "exposure_guidance": "75-90%",
171
+ "guidance": (
172
+ "Above-average breadth. Normal operations with standard risk management."
173
+ ),
174
+ "actions": [
175
+ "Normal position sizing",
176
+ "Standard stop-loss levels",
177
+ "New position entries allowed",
178
+ "Monitor for deterioration in leading indicators",
179
+ ],
180
+ }
181
+ elif composite >= 40:
182
+ return {
183
+ "zone": "Neutral",
184
+ "color": "yellow",
185
+ "exposure_guidance": "60-75%",
186
+ "guidance": (
187
+ "Mixed signals. Be selective with new positions and tighten risk controls."
188
+ ),
189
+ "actions": [
190
+ "Reduce new position sizes by 25-50%",
191
+ "Tighten stop-losses",
192
+ "Focus on stocks with strong relative strength",
193
+ "Avoid lagging sectors and speculative names",
194
+ ],
195
+ }
196
+ elif composite >= 20:
197
+ return {
198
+ "zone": "Weakening",
199
+ "color": "orange",
200
+ "exposure_guidance": "40-60%",
201
+ "guidance": (
202
+ "Breadth deteriorating. Begin profit-taking and raise cash allocation."
203
+ ),
204
+ "actions": [
205
+ "Take profits on weakest 25-40% of positions",
206
+ "No new momentum entries",
207
+ "Raise cash allocation significantly",
208
+ "Consider defensive sector rotation (XLU, XLP, XLV)",
209
+ "Watch for cycle trough signal for re-entry",
210
+ ],
211
+ }
212
+ else:
213
+ return {
214
+ "zone": "Critical",
215
+ "color": "red",
216
+ "exposure_guidance": "25-40%",
217
+ "guidance": (
218
+ "Severe breadth weakness. Capital preservation is the priority. "
219
+ "Watch for trough formation as re-entry signal."
220
+ ),
221
+ "actions": [
222
+ "Maximum cash allocation (60-75%)",
223
+ "Only hold strongest relative strength leaders",
224
+ "Consider hedges (put options, inverse ETFs)",
225
+ "Monitor for extreme trough (8MA < 0.4) as contrarian buy signal",
226
+ "Prepare watchlist for recovery: quality stocks near support",
227
+ ],
228
+ }
229
+
230
+
231
+ # Testing
232
+ if __name__ == "__main__":
233
+ print("Testing Market Breadth Scorer...\n")
234
+
235
+ # Test 1: Strong market
236
+ strong = {
237
+ "breadth_level_trend": 85,
238
+ "ma_crossover": 80,
239
+ "cycle_position": 75,
240
+ "bearish_signal": 85,
241
+ "historical_percentile": 70,
242
+ "divergence": 70,
243
+ }
244
+ r1 = calculate_composite_score(strong)
245
+ print(f"Test 1 - Strong: {r1['composite_score']}/100 -> {r1['zone']}")
246
+
247
+ # Test 2: Neutral
248
+ neutral = {
249
+ "breadth_level_trend": 50,
250
+ "ma_crossover": 50,
251
+ "cycle_position": 50,
252
+ "bearish_signal": 50,
253
+ "historical_percentile": 50,
254
+ "divergence": 50,
255
+ }
256
+ r2 = calculate_composite_score(neutral)
257
+ print(f"Test 2 - Neutral: {r2['composite_score']}/100 -> {r2['zone']}")
258
+
259
+ # Test 3: Critical
260
+ crisis = {
261
+ "breadth_level_trend": 10,
262
+ "ma_crossover": 5,
263
+ "cycle_position": 15,
264
+ "bearish_signal": 10,
265
+ "historical_percentile": 10,
266
+ "divergence": 30,
267
+ }
268
+ r3 = calculate_composite_score(crisis)
269
+ print(f"Test 3 - Critical: {r3['composite_score']}/100 -> {r3['zone']}")
270
+
271
+ print("\nAll tests completed.")