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,103 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Component 1: Current Breadth Level & Trend (Weight: 25%)
4
+
5
+ The most direct indicator of market health.
6
+
7
+ Input: Breadth_Index_8MA, Breadth_200MA_Trend (latest row)
8
+
9
+ Scoring (100 = healthy):
10
+ 8MA Level (70% of component):
11
+ >= 0.70 -> 95 >= 0.60 -> 80 >= 0.50 -> 65
12
+ >= 0.40 -> 50 >= 0.30 -> 35 >= 0.20 -> 20
13
+ < 0.20 -> 5
14
+
15
+ 200MA Trend (30% of component):
16
+ Trend == 1 -> 80 (uptrend)
17
+ Trend == -1 -> 20 (downtrend)
18
+
19
+ Score = 0.70 * level_score + 0.30 * trend_score
20
+ """
21
+
22
+ from typing import Dict, List
23
+
24
+
25
+ def calculate_breadth_level_trend(rows: List[Dict]) -> Dict:
26
+ """
27
+ Calculate current breadth level and trend score.
28
+
29
+ Args:
30
+ rows: All detail rows sorted by date ascending.
31
+
32
+ Returns:
33
+ Dict with score, signal, and component details.
34
+ """
35
+ if not rows:
36
+ return {
37
+ "score": 50,
38
+ "signal": "NO DATA: No breadth data available",
39
+ "data_available": False,
40
+ }
41
+
42
+ latest = rows[-1]
43
+ ma8 = latest["Breadth_Index_8MA"]
44
+ trend = latest["Breadth_200MA_Trend"]
45
+
46
+ # 8MA level score
47
+ level_score = _score_8ma_level(ma8)
48
+
49
+ # Trend score
50
+ trend_score = 80 if trend == 1 else 20
51
+
52
+ # Combined
53
+ score = round(0.70 * level_score + 0.30 * trend_score)
54
+ score = max(0, min(100, score))
55
+
56
+ # Signal
57
+ signal = _generate_signal(ma8, trend, score)
58
+
59
+ return {
60
+ "score": score,
61
+ "signal": signal,
62
+ "data_available": True,
63
+ "current_8ma": ma8,
64
+ "current_200ma": latest["Breadth_Index_200MA"],
65
+ "trend": trend,
66
+ "level_score": level_score,
67
+ "trend_score": trend_score,
68
+ "date": latest["Date"],
69
+ }
70
+
71
+
72
+ def _score_8ma_level(ma8: float) -> int:
73
+ """Score based on 8MA level."""
74
+ if ma8 >= 0.70:
75
+ return 95
76
+ elif ma8 >= 0.60:
77
+ return 80
78
+ elif ma8 >= 0.50:
79
+ return 65
80
+ elif ma8 >= 0.40:
81
+ return 50
82
+ elif ma8 >= 0.30:
83
+ return 35
84
+ elif ma8 >= 0.20:
85
+ return 20
86
+ else:
87
+ return 5
88
+
89
+
90
+ def _generate_signal(ma8: float, trend: int, score: int) -> str:
91
+ """Generate human-readable signal."""
92
+ trend_str = "uptrend" if trend == 1 else "downtrend"
93
+
94
+ if score >= 80:
95
+ return f"STRONG: 8MA={ma8:.3f} in {trend_str} - broad participation"
96
+ elif score >= 60:
97
+ return f"HEALTHY: 8MA={ma8:.3f} in {trend_str} - above average"
98
+ elif score >= 40:
99
+ return f"NEUTRAL: 8MA={ma8:.3f} in {trend_str} - mixed signals"
100
+ elif score >= 20:
101
+ return f"WEAK: 8MA={ma8:.3f} in {trend_str} - deteriorating breadth"
102
+ else:
103
+ return f"CRITICAL: 8MA={ma8:.3f} in {trend_str} - severe weakness"
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Market Breadth Analyzer - CSV Data Client
4
+
5
+ Fetches and parses market breadth CSV data from TraderMonty's public GitHub Pages.
6
+ No API key required.
7
+
8
+ Data sources:
9
+ Detail: https://tradermonty.github.io/market-breadth-analysis/market_breadth_data.csv
10
+ Summary: https://tradermonty.github.io/market-breadth-analysis/market_breadth_summary.csv
11
+ """
12
+
13
+ import csv
14
+ import io
15
+ import sys
16
+ from datetime import datetime, timedelta
17
+ from typing import Dict, List, Optional, Tuple
18
+
19
+ import requests
20
+
21
+ DEFAULT_DETAIL_URL = (
22
+ "https://tradermonty.github.io/market-breadth-analysis/market_breadth_data.csv"
23
+ )
24
+ DEFAULT_SUMMARY_URL = (
25
+ "https://tradermonty.github.io/market-breadth-analysis/market_breadth_summary.csv"
26
+ )
27
+
28
+ DETAIL_COLUMNS = {
29
+ "Date": str,
30
+ "S&P500_Price": float,
31
+ "Breadth_Index_Raw": float,
32
+ "Breadth_Index_200MA": float,
33
+ "Breadth_Index_8MA": float,
34
+ "Breadth_200MA_Trend": int,
35
+ "Bearish_Signal": bool,
36
+ "Is_Peak": bool,
37
+ "Is_Trough": bool,
38
+ "Is_Trough_8MA_Below_04": bool,
39
+ }
40
+
41
+ TIMEOUT = 30
42
+
43
+
44
+ def fetch_detail_csv(url: str = DEFAULT_DETAIL_URL) -> List[Dict]:
45
+ """
46
+ Fetch and parse the detail CSV (market_breadth_data.csv).
47
+
48
+ Returns list of dicts sorted by date ascending (oldest first).
49
+ """
50
+ print(f" Fetching detail CSV from {url}...", end=" ", flush=True)
51
+ try:
52
+ resp = requests.get(url, timeout=TIMEOUT)
53
+ resp.raise_for_status()
54
+ except requests.RequestException as e:
55
+ print("FAILED")
56
+ print(f"ERROR: Failed to fetch detail CSV: {e}", file=sys.stderr)
57
+ return []
58
+
59
+ reader = csv.DictReader(io.StringIO(resp.text))
60
+ rows = []
61
+
62
+ for line_num, raw_row in enumerate(reader, start=2):
63
+ try:
64
+ row = _parse_detail_row(raw_row)
65
+ rows.append(row)
66
+ except (ValueError, KeyError) as e:
67
+ print(f"\n WARN: Skipping line {line_num}: {e}", file=sys.stderr)
68
+
69
+ # Validate columns
70
+ if rows:
71
+ missing = set(DETAIL_COLUMNS.keys()) - set(rows[0].keys())
72
+ if missing:
73
+ print(f"\n WARN: Missing columns: {missing}", file=sys.stderr)
74
+
75
+ # Sort by date ascending
76
+ rows.sort(key=lambda r: r["Date"])
77
+
78
+ print(f"OK ({len(rows)} rows, {rows[0]['Date']} to {rows[-1]['Date']})")
79
+ return rows
80
+
81
+
82
+ def fetch_summary_csv(url: str = DEFAULT_SUMMARY_URL) -> Dict[str, str]:
83
+ """
84
+ Fetch and parse the summary CSV (market_breadth_summary.csv).
85
+
86
+ Returns dict mapping Metric -> Value.
87
+ """
88
+ print(f" Fetching summary CSV from {url}...", end=" ", flush=True)
89
+ try:
90
+ resp = requests.get(url, timeout=TIMEOUT)
91
+ resp.raise_for_status()
92
+ except requests.RequestException as e:
93
+ print("FAILED")
94
+ print(f"ERROR: Failed to fetch summary CSV: {e}", file=sys.stderr)
95
+ return {}
96
+
97
+ reader = csv.DictReader(io.StringIO(resp.text))
98
+ summary = {}
99
+ for raw_row in reader:
100
+ metric = raw_row.get("Metric", "").strip()
101
+ value = raw_row.get("Value", "").strip()
102
+ if metric:
103
+ summary[metric] = value
104
+
105
+ print(f"OK ({len(summary)} metrics)")
106
+ return summary
107
+
108
+
109
+ def check_data_freshness(rows: List[Dict], max_stale_days: int = 5,
110
+ detail_url: str = DEFAULT_DETAIL_URL) -> Dict:
111
+ """
112
+ Check whether the latest data is reasonably fresh.
113
+ Uses both CSV date and HTTP Last-Modified header for accuracy.
114
+
115
+ Args:
116
+ rows: Parsed detail rows (sorted by date ascending).
117
+ max_stale_days: Calendar days before data is considered stale.
118
+ detail_url: URL to check Last-Modified header against.
119
+
120
+ Returns:
121
+ Dict with is_fresh, latest_date, days_old, last_modified, warning.
122
+ """
123
+ if not rows:
124
+ return {
125
+ "is_fresh": False,
126
+ "latest_date": None,
127
+ "days_old": None,
128
+ "last_modified": None,
129
+ "warning": "No data available",
130
+ }
131
+
132
+ latest_date_str = rows[-1]["Date"]
133
+ try:
134
+ latest_date = datetime.strptime(latest_date_str, "%Y-%m-%d")
135
+ except ValueError:
136
+ return {
137
+ "is_fresh": False,
138
+ "latest_date": latest_date_str,
139
+ "days_old": None,
140
+ "last_modified": None,
141
+ "warning": f"Cannot parse latest date: {latest_date_str}",
142
+ }
143
+
144
+ days_old = (datetime.now() - latest_date).days
145
+ is_fresh = days_old <= max_stale_days
146
+
147
+ # Check HTTP Last-Modified header for additional freshness info
148
+ last_modified = _check_last_modified(detail_url)
149
+
150
+ warning = None
151
+ if not is_fresh:
152
+ warning = (
153
+ f"Data is {days_old} days old (latest: {latest_date_str}). "
154
+ f"Threshold: {max_stale_days} days. Results may not reflect current conditions."
155
+ )
156
+
157
+ return {
158
+ "is_fresh": is_fresh,
159
+ "latest_date": latest_date_str,
160
+ "days_old": days_old,
161
+ "last_modified": last_modified,
162
+ "warning": warning,
163
+ }
164
+
165
+
166
+ def _check_last_modified(url: str) -> Optional[str]:
167
+ """Check HTTP Last-Modified header via HEAD request."""
168
+ try:
169
+ resp = requests.head(url, timeout=10, allow_redirects=True)
170
+ resp.raise_for_status()
171
+ lm = resp.headers.get("Last-Modified")
172
+ if lm:
173
+ from email.utils import parsedate_to_datetime
174
+ dt = parsedate_to_datetime(lm)
175
+ return dt.strftime("%Y-%m-%d %H:%M UTC")
176
+ except Exception:
177
+ pass
178
+ return None
179
+
180
+
181
+ def get_latest_n_rows(rows: List[Dict], n: int) -> List[Dict]:
182
+ """Return the last n rows (most recent)."""
183
+ return rows[-n:] if len(rows) >= n else rows[:]
184
+
185
+
186
+ def _parse_detail_row(raw: Dict) -> Dict:
187
+ """Convert a raw CSV row dict to properly typed values."""
188
+ row = {}
189
+ row["Date"] = raw["Date"].strip()
190
+ row["S&P500_Price"] = float(raw["S&P500_Price"])
191
+ row["Breadth_Index_Raw"] = float(raw["Breadth_Index_Raw"])
192
+ row["Breadth_Index_200MA"] = float(raw["Breadth_Index_200MA"])
193
+ row["Breadth_Index_8MA"] = float(raw["Breadth_Index_8MA"])
194
+ row["Breadth_200MA_Trend"] = int(raw["Breadth_200MA_Trend"])
195
+ row["Bearish_Signal"] = _parse_bool(raw["Bearish_Signal"])
196
+ row["Is_Peak"] = _parse_bool(raw["Is_Peak"])
197
+ row["Is_Trough"] = _parse_bool(raw["Is_Trough"])
198
+ row["Is_Trough_8MA_Below_04"] = _parse_bool(raw["Is_Trough_8MA_Below_04"])
199
+ return row
200
+
201
+
202
+ def _parse_bool(val: str) -> bool:
203
+ """Parse boolean from CSV string."""
204
+ return val.strip().lower() in ("true", "1", "yes")
205
+
206
+
207
+ # Testing
208
+ if __name__ == "__main__":
209
+ print("Testing CSV Client...\n")
210
+
211
+ detail = fetch_detail_csv()
212
+ print(f" Detail rows: {len(detail)}")
213
+ if detail:
214
+ print(f" First row: {detail[0]}")
215
+ print(f" Last row: {detail[-1]}")
216
+
217
+ print()
218
+ summary = fetch_summary_csv()
219
+ print(f" Summary metrics: {summary}")
220
+
221
+ print()
222
+ freshness = check_data_freshness(detail)
223
+ print(f" Freshness: {freshness}")
224
+
225
+ print("\nAll tests completed.")
@@ -0,0 +1,307 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Market Breadth Analyzer - Main Orchestrator
4
+
5
+ Quantifies market breadth health using TraderMonty's public CSV data.
6
+ Generates a 0-100 composite score across 6 components.
7
+ No API key required.
8
+
9
+ Usage:
10
+ # Default (uses public CSV URLs):
11
+ python3 market_breadth_analyzer.py
12
+
13
+ # Custom URLs:
14
+ python3 market_breadth_analyzer.py \\
15
+ --detail-url "https://example.com/data.csv" \\
16
+ --summary-url "https://example.com/summary.csv"
17
+
18
+ # Custom output directory:
19
+ python3 market_breadth_analyzer.py --output-dir ./reports
20
+
21
+ Output:
22
+ - JSON: market_breadth_YYYY-MM-DD_HHMMSS.json
23
+ - Markdown: market_breadth_YYYY-MM-DD_HHMMSS.md
24
+ """
25
+
26
+ import argparse
27
+ import os
28
+ import sys
29
+ from datetime import datetime
30
+
31
+ # Add parent directory to path for imports
32
+ sys.path.insert(0, os.path.dirname(__file__))
33
+
34
+ from csv_client import (
35
+ fetch_detail_csv,
36
+ fetch_summary_csv,
37
+ check_data_freshness,
38
+ DEFAULT_DETAIL_URL,
39
+ DEFAULT_SUMMARY_URL,
40
+ )
41
+ from calculators.trend_level_calculator import calculate_breadth_level_trend
42
+ from calculators.ma_crossover_calculator import calculate_ma_crossover
43
+ from calculators.cycle_calculator import calculate_cycle_position
44
+ from calculators.bearish_signal_calculator import calculate_bearish_signal
45
+ from calculators.historical_context_calculator import calculate_historical_percentile
46
+ from calculators.divergence_calculator import calculate_divergence
47
+ from scorer import calculate_composite_score
48
+ from report_generator import generate_json_report, generate_markdown_report
49
+
50
+
51
+ def parse_arguments():
52
+ parser = argparse.ArgumentParser(
53
+ description="Market Breadth Analyzer - 6-Component Health Scoring"
54
+ )
55
+
56
+ parser.add_argument(
57
+ "--detail-url",
58
+ default=DEFAULT_DETAIL_URL,
59
+ help="URL for detail CSV (market_breadth_data.csv)",
60
+ )
61
+ parser.add_argument(
62
+ "--summary-url",
63
+ default=DEFAULT_SUMMARY_URL,
64
+ help="URL for summary CSV (market_breadth_summary.csv)",
65
+ )
66
+ parser.add_argument(
67
+ "--output-dir",
68
+ default=".",
69
+ help="Output directory for reports (default: current directory)",
70
+ )
71
+
72
+ return parser.parse_args()
73
+
74
+
75
+ def main():
76
+ args = parse_arguments()
77
+
78
+ print("=" * 70)
79
+ print("Market Breadth Analyzer")
80
+ print("6-Component Health Scoring (No API Key Required)")
81
+ print("=" * 70)
82
+ print()
83
+
84
+ # ========================================================================
85
+ # Step 1: Fetch CSV Data
86
+ # ========================================================================
87
+ print("Step 1: Fetching CSV Data")
88
+ print("-" * 70)
89
+
90
+ detail_rows = fetch_detail_csv(args.detail_url)
91
+ if not detail_rows:
92
+ print("ERROR: Cannot proceed without detail CSV data", file=sys.stderr)
93
+ sys.exit(1)
94
+
95
+ summary = fetch_summary_csv(args.summary_url)
96
+
97
+ freshness = check_data_freshness(detail_rows)
98
+ if freshness.get("warning"):
99
+ print(f" WARNING: {freshness['warning']}")
100
+ else:
101
+ print(
102
+ f" Data freshness: OK "
103
+ f"(latest: {freshness['latest_date']}, {freshness['days_old']} days old)"
104
+ )
105
+
106
+ print()
107
+
108
+ # ========================================================================
109
+ # Step 2: Calculate Components
110
+ # ========================================================================
111
+ print("Step 2: Calculating Components")
112
+ print("-" * 70)
113
+
114
+ # Component 1: Current Breadth Level & Trend (25%)
115
+ print(" [1/6] Current Breadth Level & Trend...", end=" ", flush=True)
116
+ comp1 = calculate_breadth_level_trend(detail_rows)
117
+ print(f"Score: {comp1['score']} ({comp1['signal']})")
118
+
119
+ # Component 2: 8MA vs 200MA Crossover (20%)
120
+ print(" [2/6] 8MA vs 200MA Crossover...", end=" ", flush=True)
121
+ comp2 = calculate_ma_crossover(detail_rows)
122
+ print(f"Score: {comp2['score']} ({comp2['signal']})")
123
+
124
+ # Component 3: Peak/Trough Cycle Position (20%)
125
+ print(" [3/6] Peak/Trough Cycle Position...", end=" ", flush=True)
126
+ comp3 = calculate_cycle_position(detail_rows)
127
+ print(f"Score: {comp3['score']} ({comp3['signal']})")
128
+
129
+ # Component 4: Bearish Signal Status (15%)
130
+ print(" [4/6] Bearish Signal Status...", end=" ", flush=True)
131
+ comp4 = calculate_bearish_signal(detail_rows)
132
+ print(f"Score: {comp4['score']} ({comp4['signal']})")
133
+
134
+ # Component 5: Historical Percentile (10%)
135
+ print(" [5/6] Historical Percentile...", end=" ", flush=True)
136
+ comp5 = calculate_historical_percentile(detail_rows, summary)
137
+ print(f"Score: {comp5['score']} ({comp5['signal']})")
138
+
139
+ # Component 6: S&P 500 vs Breadth Divergence (10%)
140
+ print(" [6/6] S&P 500 vs Breadth Divergence...", end=" ", flush=True)
141
+ comp6 = calculate_divergence(detail_rows)
142
+ print(f"Score: {comp6['score']} ({comp6['signal']})")
143
+
144
+ print()
145
+
146
+ # ========================================================================
147
+ # Step 3: Composite Score
148
+ # ========================================================================
149
+ print("Step 3: Calculating Composite Score")
150
+ print("-" * 70)
151
+
152
+ component_scores = {
153
+ "breadth_level_trend": comp1["score"],
154
+ "ma_crossover": comp2["score"],
155
+ "cycle_position": comp3["score"],
156
+ "bearish_signal": comp4["score"],
157
+ "historical_percentile": comp5["score"],
158
+ "divergence": comp6["score"],
159
+ }
160
+
161
+ data_availability = {
162
+ "breadth_level_trend": comp1.get("data_available", True),
163
+ "ma_crossover": comp2.get("data_available", True),
164
+ "cycle_position": comp3.get("data_available", True),
165
+ "bearish_signal": comp4.get("data_available", True),
166
+ "historical_percentile": comp5.get("data_available", True),
167
+ "divergence": comp6.get("data_available", True),
168
+ }
169
+
170
+ composite = calculate_composite_score(component_scores, data_availability)
171
+
172
+ print(f" Composite Score: {composite['composite_score']}/100")
173
+ print(f" Health Zone: {composite['zone']}")
174
+ print(f" Equity Exposure: {composite['exposure_guidance']}")
175
+ print(
176
+ f" Strongest: {composite['strongest_health']['label']} "
177
+ f"({composite['strongest_health']['score']})"
178
+ )
179
+ print(
180
+ f" Weakest: {composite['weakest_health']['label']} "
181
+ f"({composite['weakest_health']['score']})"
182
+ )
183
+ print()
184
+
185
+ # ========================================================================
186
+ # Step 4: Key Levels
187
+ # ========================================================================
188
+ key_levels = _compute_key_levels(detail_rows, summary)
189
+
190
+ # ========================================================================
191
+ # Step 5: Generate Reports
192
+ # ========================================================================
193
+ print("Step 4: Generating Reports")
194
+ print("-" * 70)
195
+
196
+ analysis = {
197
+ "metadata": {
198
+ "generated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
199
+ "data_source": "TraderMonty Market Breadth CSV",
200
+ "detail_url": args.detail_url,
201
+ "summary_url": args.summary_url,
202
+ "total_rows": len(detail_rows),
203
+ "data_freshness": freshness,
204
+ },
205
+ "composite": composite,
206
+ "components": {
207
+ "breadth_level_trend": comp1,
208
+ "ma_crossover": comp2,
209
+ "cycle_position": comp3,
210
+ "bearish_signal": comp4,
211
+ "historical_percentile": comp5,
212
+ "divergence": comp6,
213
+ },
214
+ "key_levels": key_levels,
215
+ }
216
+
217
+ timestamp = datetime.now().strftime("%Y-%m-%d_%H%M%S")
218
+ json_file = os.path.join(args.output_dir, f"market_breadth_{timestamp}.json")
219
+ md_file = os.path.join(args.output_dir, f"market_breadth_{timestamp}.md")
220
+
221
+ generate_json_report(analysis, json_file)
222
+ generate_markdown_report(analysis, md_file)
223
+
224
+ print()
225
+ print("=" * 70)
226
+ print("Market Breadth Analysis Complete")
227
+ print("=" * 70)
228
+ print(f" Composite Score: {composite['composite_score']}/100")
229
+ print(f" Health Zone: {composite['zone']}")
230
+ print(f" Equity Exposure: {composite['exposure_guidance']}")
231
+ print(f" JSON Report: {json_file}")
232
+ print(f" Markdown Report: {md_file}")
233
+ print()
234
+
235
+
236
+ def _compute_key_levels(rows, summary):
237
+ """Compute key breadth levels to watch."""
238
+ if not rows:
239
+ return {}
240
+
241
+ latest = rows[-1]
242
+ ma8 = latest["Breadth_Index_8MA"]
243
+ ma200 = latest["Breadth_Index_200MA"]
244
+
245
+ levels = {}
246
+
247
+ # 200MA crossover level
248
+ levels["200MA Level"] = {
249
+ "value": f"{ma200:.4f}",
250
+ "significance": (
251
+ "Key support/resistance for 8MA. "
252
+ "8MA crossing below is an early warning of deterioration, "
253
+ "not a standalone bearish signal."
254
+ ),
255
+ }
256
+
257
+ # 0.40 extreme weakness threshold
258
+ levels["Extreme Weakness (0.40)"] = {
259
+ "value": "0.4000",
260
+ "significance": (
261
+ "8MA below 0.40 marks extreme weakness. "
262
+ "Historically, troughs at this level precede significant rallies."
263
+ ),
264
+ }
265
+
266
+ # 0.60 healthy threshold
267
+ levels["Healthy Threshold (0.60)"] = {
268
+ "value": "0.6000",
269
+ "significance": (
270
+ "8MA above 0.60 indicates broad participation. "
271
+ "Below 0.60 = selective market, above = inclusive rally."
272
+ ),
273
+ }
274
+
275
+ # Average peak from summary
276
+ avg_peak_str = summary.get("Average Peaks (200MA)", "")
277
+ try:
278
+ avg_peak = float(avg_peak_str)
279
+ levels["Historical Avg Peak"] = {
280
+ "value": f"{avg_peak:.3f}",
281
+ "significance": (
282
+ "Average peak level. Approaching this level suggests "
283
+ "breadth may be near a cyclical high."
284
+ ),
285
+ }
286
+ except (ValueError, TypeError):
287
+ pass
288
+
289
+ # Average trough from summary
290
+ avg_trough_str = summary.get("Average Troughs (8MA < 0.4)", "")
291
+ try:
292
+ avg_trough = float(avg_trough_str)
293
+ levels["Historical Avg Trough"] = {
294
+ "value": f"{avg_trough:.3f}",
295
+ "significance": (
296
+ "Average extreme trough level. Reaching this level "
297
+ "is a potential contrarian buy signal."
298
+ ),
299
+ }
300
+ except (ValueError, TypeError):
301
+ pass
302
+
303
+ return levels
304
+
305
+
306
+ if __name__ == "__main__":
307
+ main()