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,343 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ C Component - Current Quarterly Earnings Calculator
4
+
5
+ Calculates CANSLIM 'C' component score based on quarterly EPS and revenue growth.
6
+
7
+ O'Neil's Rule: "Look for companies whose current quarterly earnings per share
8
+ are up at least 18-20% compared to the same quarter the prior year."
9
+
10
+ Scoring:
11
+ - 100 points: EPS +50%+ YoY AND Revenue +25%+ YoY (explosive growth)
12
+ - 80 points: EPS +30-49% AND Revenue +15%+ (strong growth)
13
+ - 60 points: EPS +18-29% AND Revenue +10%+ (meets CANSLIM minimum)
14
+ - 40 points: EPS +10-17% (below threshold)
15
+ - 0 points: EPS <10% or negative
16
+ """
17
+
18
+ from typing import Dict, List, Optional
19
+
20
+
21
+ def calculate_quarterly_growth(income_statements: List[Dict]) -> Dict:
22
+ """
23
+ Calculate quarterly EPS and revenue growth (year-over-year)
24
+
25
+ Args:
26
+ income_statements: List of quarterly income statements from FMP API
27
+ (most recent quarter first, needs at least 5 quarters)
28
+
29
+ Returns:
30
+ Dict with:
31
+ - score: 0-100 points
32
+ - latest_qtr_eps_growth: YoY EPS growth percentage
33
+ - latest_qtr_revenue_growth: YoY revenue growth percentage
34
+ - latest_eps: Most recent quarterly EPS
35
+ - year_ago_eps: EPS from same quarter last year
36
+ - latest_revenue: Most recent quarterly revenue
37
+ - year_ago_revenue: Revenue from same quarter last year
38
+ - interpretation: Human-readable interpretation
39
+ - error: Error message if calculation failed
40
+
41
+ Example:
42
+ >>> income_stmts = client.get_income_statement("NVDA", period="quarter", limit=8)
43
+ >>> result = calculate_quarterly_growth(income_stmts)
44
+ >>> print(f"C Score: {result['score']}, EPS Growth: {result['latest_qtr_eps_growth']:.1f}%")
45
+ """
46
+ # Validate input
47
+ if not income_statements or len(income_statements) < 5:
48
+ return {
49
+ "score": 0,
50
+ "error": "Insufficient quarterly data (need at least 5 quarters for YoY comparison)",
51
+ "latest_qtr_eps_growth": None,
52
+ "latest_qtr_revenue_growth": None,
53
+ "latest_eps": None,
54
+ "year_ago_eps": None,
55
+ "latest_revenue": None,
56
+ "year_ago_revenue": None,
57
+ "interpretation": "Data unavailable"
58
+ }
59
+
60
+ # Extract most recent quarter (index 0) and year-ago quarter (index 4)
61
+ latest = income_statements[0]
62
+ year_ago = income_statements[4]
63
+
64
+ # Extract EPS (try multiple field names for compatibility)
65
+ latest_eps = latest.get("eps") or latest.get("epsdiluted") or latest.get("netIncomePerShare")
66
+ year_ago_eps = year_ago.get("eps") or year_ago.get("epsdiluted") or year_ago.get("netIncomePerShare")
67
+
68
+ # Extract revenue
69
+ latest_revenue = latest.get("revenue")
70
+ year_ago_revenue = year_ago.get("revenue")
71
+
72
+ # Validate extracted data
73
+ if latest_eps is None or year_ago_eps is None:
74
+ return {
75
+ "score": 0,
76
+ "error": "EPS data missing or invalid",
77
+ "latest_qtr_eps_growth": None,
78
+ "latest_qtr_revenue_growth": None,
79
+ "latest_eps": latest_eps,
80
+ "year_ago_eps": year_ago_eps,
81
+ "latest_revenue": latest_revenue,
82
+ "year_ago_revenue": year_ago_revenue,
83
+ "interpretation": "EPS data unavailable"
84
+ }
85
+
86
+ if latest_revenue is None or year_ago_revenue is None or year_ago_revenue == 0:
87
+ return {
88
+ "score": 0,
89
+ "error": "Revenue data missing or invalid",
90
+ "latest_qtr_eps_growth": None,
91
+ "latest_qtr_revenue_growth": None,
92
+ "latest_eps": latest_eps,
93
+ "year_ago_eps": year_ago_eps,
94
+ "latest_revenue": latest_revenue,
95
+ "year_ago_revenue": year_ago_revenue,
96
+ "interpretation": "Revenue data unavailable"
97
+ }
98
+
99
+ # Calculate year-over-year growth
100
+ # Use abs() for denominator to handle negative EPS (turnaround situations)
101
+ if year_ago_eps == 0:
102
+ # Handle zero/negative EPS edge case
103
+ if latest_eps > 0 and year_ago_eps <= 0:
104
+ # Turnaround situation (negative to positive)
105
+ eps_growth = 999.9 # Cap at very high growth
106
+ else:
107
+ eps_growth = 0
108
+ else:
109
+ eps_growth = ((latest_eps - year_ago_eps) / abs(year_ago_eps)) * 100
110
+
111
+ revenue_growth = ((latest_revenue - year_ago_revenue) / year_ago_revenue) * 100
112
+
113
+ # Calculate score
114
+ score = score_current_earnings(eps_growth, revenue_growth)
115
+
116
+ # Generate interpretation
117
+ interpretation = interpret_earnings_score(score, eps_growth, revenue_growth)
118
+
119
+ # Quality check: flag if revenue growth significantly lags EPS growth
120
+ quality_warning = None
121
+ if revenue_growth < (eps_growth * 0.5) and eps_growth > 20:
122
+ quality_warning = ("Revenue growth significantly lags EPS growth - "
123
+ "investigate earnings quality (potential buyback-driven)")
124
+
125
+ return {
126
+ "score": score,
127
+ "latest_qtr_eps_growth": round(eps_growth, 1),
128
+ "latest_qtr_revenue_growth": round(revenue_growth, 1),
129
+ "latest_eps": latest_eps,
130
+ "year_ago_eps": year_ago_eps,
131
+ "latest_revenue": latest_revenue,
132
+ "year_ago_revenue": year_ago_revenue,
133
+ "latest_qtr_date": latest.get("date"),
134
+ "year_ago_qtr_date": year_ago.get("date"),
135
+ "interpretation": interpretation,
136
+ "quality_warning": quality_warning,
137
+ "error": None
138
+ }
139
+
140
+
141
+ def score_current_earnings(eps_growth: float, revenue_growth: float) -> int:
142
+ """
143
+ Score C component based on quarterly EPS and revenue growth
144
+
145
+ Args:
146
+ eps_growth: Year-over-year EPS growth percentage
147
+ revenue_growth: Year-over-year revenue growth percentage
148
+
149
+ Returns:
150
+ Score (0-100)
151
+
152
+ Scoring Logic (from scoring_system.md):
153
+ - 100: EPS >=50% AND Revenue >=25% (explosive)
154
+ - 80: EPS 30-49% AND Revenue >=15% (strong)
155
+ - 60: EPS 18-29% AND Revenue >=10% (meets CANSLIM minimum)
156
+ - 40: EPS 10-17% (below threshold)
157
+ - 0: EPS <10% (weak/negative)
158
+ """
159
+ # Exceptional growth
160
+ if eps_growth >= 50 and revenue_growth >= 25:
161
+ return 100
162
+
163
+ # Strong growth
164
+ if eps_growth >= 30 and revenue_growth >= 15:
165
+ return 80
166
+
167
+ # Meets CANSLIM minimum (18%+ EPS growth)
168
+ if eps_growth >= 18 and revenue_growth >= 10:
169
+ return 60
170
+
171
+ # Below threshold but positive
172
+ if eps_growth >= 10:
173
+ return 40
174
+
175
+ # Weak or negative growth
176
+ return 0
177
+
178
+
179
+ def interpret_earnings_score(score: int, eps_growth: float, revenue_growth: float) -> str:
180
+ """
181
+ Generate human-readable interpretation of C component score
182
+
183
+ Args:
184
+ score: Component score (0-100)
185
+ eps_growth: YoY EPS growth percentage
186
+ revenue_growth: YoY revenue growth percentage
187
+
188
+ Returns:
189
+ Interpretation string
190
+ """
191
+ if score >= 90:
192
+ return (f"Exceptional - Explosive earnings acceleration "
193
+ f"(EPS +{eps_growth:.1f}%, Revenue +{revenue_growth:.1f}%)")
194
+
195
+ elif score >= 70:
196
+ return (f"Strong - Well above CANSLIM threshold "
197
+ f"(EPS +{eps_growth:.1f}%, Revenue +{revenue_growth:.1f}%)")
198
+
199
+ elif score >= 50:
200
+ return (f"Acceptable - Meets CANSLIM minimum 18% threshold "
201
+ f"(EPS +{eps_growth:.1f}%, Revenue +{revenue_growth:.1f}%)")
202
+
203
+ elif score >= 30:
204
+ return (f"Below threshold - Insufficient growth "
205
+ f"(EPS +{eps_growth:.1f}%, Revenue +{revenue_growth:.1f}%)")
206
+
207
+ else:
208
+ return (f"Weak - Does not meet CANSLIM criteria "
209
+ f"(EPS {eps_growth:+.1f}%, Revenue {revenue_growth:+.1f}%)")
210
+
211
+
212
+ def detect_earnings_acceleration(income_statements: List[Dict]) -> Dict:
213
+ """
214
+ Detect if earnings are accelerating or decelerating (trend analysis)
215
+
216
+ Args:
217
+ income_statements: List of quarterly income statements (recent first)
218
+
219
+ Returns:
220
+ Dict with:
221
+ - trend: "accelerating", "stable", or "decelerating"
222
+ - recent_growth: Most recent quarter YoY growth
223
+ - prior_growth: Prior quarter YoY growth
224
+ - interpretation: Trend description
225
+
226
+ Note:
227
+ Earnings acceleration (recent > prior) is bullish signal per O'Neil.
228
+ Deceleration is early warning of potential weakness.
229
+ """
230
+ if len(income_statements) < 6:
231
+ return {
232
+ "trend": "unknown",
233
+ "recent_growth": None,
234
+ "prior_growth": None,
235
+ "interpretation": "Insufficient data for trend analysis"
236
+ }
237
+
238
+ # Most recent quarter vs year-ago
239
+ recent_eps = income_statements[0].get("eps", 0)
240
+ recent_year_ago_eps = income_statements[4].get("eps", 0.01)
241
+ recent_growth = ((recent_eps - recent_year_ago_eps) / abs(recent_year_ago_eps)) * 100 if recent_year_ago_eps else 0
242
+
243
+ # Prior quarter vs its year-ago
244
+ prior_eps = income_statements[1].get("eps", 0)
245
+ prior_year_ago_eps = income_statements[5].get("eps", 0.01)
246
+ prior_growth = ((prior_eps - prior_year_ago_eps) / abs(prior_year_ago_eps)) * 100 if prior_year_ago_eps else 0
247
+
248
+ # Determine trend
249
+ if recent_growth > prior_growth + 5: # 5% threshold for significance
250
+ trend = "accelerating"
251
+ interpretation = f"Earnings accelerating ({recent_growth:.1f}% vs {prior_growth:.1f}% prior quarter)"
252
+ elif recent_growth < prior_growth - 5:
253
+ trend = "decelerating"
254
+ interpretation = f"Earnings decelerating ({recent_growth:.1f}% vs {prior_growth:.1f}% prior quarter) - Warning sign"
255
+ else:
256
+ trend = "stable"
257
+ interpretation = f"Earnings stable ({recent_growth:.1f}% vs {prior_growth:.1f}% prior quarter)"
258
+
259
+ return {
260
+ "trend": trend,
261
+ "recent_growth": round(recent_growth, 1),
262
+ "prior_growth": round(prior_growth, 1),
263
+ "interpretation": interpretation
264
+ }
265
+
266
+
267
+ # Example usage and testing
268
+ if __name__ == "__main__":
269
+ print("Testing Earnings Calculator (C Component)...\n")
270
+
271
+ # Test case 1: Exceptional growth (should score 100)
272
+ test_data_exceptional = [
273
+ {"date": "2023-06-30", "eps": 2.70, "revenue": 13507000000}, # Q2 2023
274
+ {"date": "2023-03-31", "eps": 1.09, "revenue": 7192000000},
275
+ {"date": "2022-12-31", "eps": 0.88, "revenue": 6051000000},
276
+ {"date": "2022-09-30", "eps": 0.58, "revenue": 5931000000},
277
+ {"date": "2022-06-30", "eps": 0.51, "revenue": 6704000000}, # Q2 2022 (year-ago)
278
+ ]
279
+
280
+ result1 = calculate_quarterly_growth(test_data_exceptional)
281
+ print("Test 1: Exceptional Growth (NVDA-like)")
282
+ print(f" Score: {result1['score']}/100")
283
+ print(f" EPS Growth: {result1['latest_qtr_eps_growth']}%")
284
+ print(f" Revenue Growth: {result1['latest_qtr_revenue_growth']}%")
285
+ print(f" Interpretation: {result1['interpretation']}\n")
286
+
287
+ # Test case 2: Meets minimum (should score 60)
288
+ test_data_minimum = [
289
+ {"date": "2023-06-30", "eps": 1.20, "revenue": 10500000000},
290
+ {"date": "2023-03-31", "eps": 1.15, "revenue": 10200000000},
291
+ {"date": "2022-12-31", "eps": 1.10, "revenue": 10000000000},
292
+ {"date": "2022-09-30", "eps": 1.05, "revenue": 9800000000},
293
+ {"date": "2022-06-30", "eps": 1.00, "revenue": 9500000000}, # +20% EPS, +10.5% revenue
294
+ ]
295
+
296
+ result2 = calculate_quarterly_growth(test_data_minimum)
297
+ print("Test 2: Meets CANSLIM Minimum")
298
+ print(f" Score: {result2['score']}/100")
299
+ print(f" EPS Growth: {result2['latest_qtr_eps_growth']}%")
300
+ print(f" Revenue Growth: {result2['latest_qtr_revenue_growth']}%")
301
+ print(f" Interpretation: {result2['interpretation']}\n")
302
+
303
+ # Test case 3: Below threshold (should score 40)
304
+ test_data_weak = [
305
+ {"date": "2023-06-30", "eps": 1.12, "revenue": 10200000000},
306
+ {"date": "2023-03-31", "eps": 1.08, "revenue": 10100000000},
307
+ {"date": "2022-12-31", "eps": 1.05, "revenue": 10000000000},
308
+ {"date": "2022-09-30", "eps": 1.02, "revenue": 9900000000},
309
+ {"date": "2022-06-30", "eps": 1.00, "revenue": 9800000000}, # +12% EPS, +4% revenue
310
+ ]
311
+
312
+ result3 = calculate_quarterly_growth(test_data_weak)
313
+ print("Test 3: Below Threshold")
314
+ print(f" Score: {result3['score']}/100")
315
+ print(f" EPS Growth: {result3['latest_qtr_eps_growth']}%")
316
+ print(f" Revenue Growth: {result3['latest_qtr_revenue_growth']}%")
317
+ print(f" Interpretation: {result3['interpretation']}\n")
318
+
319
+ # Test case 4: Turnaround (negative to positive EPS)
320
+ test_data_turnaround = [
321
+ {"date": "2023-06-30", "eps": 0.50, "revenue": 10000000000},
322
+ {"date": "2023-03-31", "eps": 0.20, "revenue": 9500000000},
323
+ {"date": "2022-12-31", "eps": -0.10, "revenue": 9000000000},
324
+ {"date": "2022-09-30", "eps": -0.30, "revenue": 8500000000},
325
+ {"date": "2022-06-30", "eps": -0.40, "revenue": 8000000000}, # Turnaround situation
326
+ ]
327
+
328
+ result4 = calculate_quarterly_growth(test_data_turnaround)
329
+ print("Test 4: Turnaround (Negative to Positive)")
330
+ print(f" Score: {result4['score']}/100")
331
+ print(f" EPS Growth: {result4['latest_qtr_eps_growth']}%")
332
+ print(f" Revenue Growth: {result4['latest_qtr_revenue_growth']}%")
333
+ print(f" Interpretation: {result4['interpretation']}\n")
334
+
335
+ # Test acceleration detection
336
+ print("Test 5: Acceleration Detection")
337
+ accel = detect_earnings_acceleration(test_data_exceptional)
338
+ print(f" Trend: {accel['trend']}")
339
+ print(f" Recent growth: {accel['recent_growth']}%")
340
+ print(f" Prior growth: {accel['prior_growth']}%")
341
+ print(f" Interpretation: {accel['interpretation']}")
342
+
343
+ print("\n✓ All tests completed")
@@ -0,0 +1,334 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ A Component - Annual EPS Growth Calculator
4
+
5
+ Calculates CANSLIM 'A' component score based on multi-year EPS CAGR and growth stability.
6
+
7
+ O'Neil's Rule: "Annual earnings per share should be up 25% or more in each
8
+ of the last three years."
9
+
10
+ Scoring:
11
+ - 90-100: CAGR 40%+, stable growth (no down years)
12
+ - 70-89: CAGR 30-39%, stable
13
+ - 50-69: CAGR 25-29% (meets CANSLIM minimum)
14
+ - 30-49: CAGR 15-24% (below threshold)
15
+ - 0-29: CAGR <15% or erratic growth
16
+
17
+ Bonus: +10 points for stability (no down years)
18
+ Penalty: -20% if revenue CAGR significantly lags EPS CAGR (buyback-driven growth)
19
+ """
20
+
21
+ from typing import Dict, List, Optional
22
+
23
+
24
+ def calculate_annual_growth(income_statements: List[Dict]) -> Dict:
25
+ """
26
+ Calculate 3-year EPS CAGR and growth stability
27
+
28
+ Args:
29
+ income_statements: List of annual income statements from FMP API
30
+ (most recent year first, needs at least 4 years for 3-year CAGR)
31
+
32
+ Returns:
33
+ Dict with:
34
+ - score: 0-100 points
35
+ - eps_cagr_3yr: 3-year EPS compound annual growth rate (%)
36
+ - revenue_cagr_3yr: 3-year revenue CAGR (%) for validation
37
+ - stability: "stable" or "erratic"
38
+ - eps_values: List of EPS values (chronological)
39
+ - interpretation: Human-readable interpretation
40
+ - error: Error message if calculation failed
41
+ """
42
+ # Validate input
43
+ if not income_statements or len(income_statements) < 4:
44
+ return {
45
+ "score": 50, # Default for insufficient data (neutral)
46
+ "error": "Insufficient annual data (need at least 4 years for 3-year CAGR)",
47
+ "eps_cagr_3yr": None,
48
+ "revenue_cagr_3yr": None,
49
+ "stability": "unknown",
50
+ "eps_values": None,
51
+ "interpretation": "Data unavailable"
52
+ }
53
+
54
+ # Extract EPS for last 4 years (most recent first in API response)
55
+ eps_values = []
56
+ revenue_values = []
57
+
58
+ for i in range(4):
59
+ stmt = income_statements[i]
60
+ eps = stmt.get("eps") or stmt.get("epsdiluted")
61
+ revenue = stmt.get("revenue")
62
+
63
+ if eps is None:
64
+ return {
65
+ "score": 0,
66
+ "error": f"Missing EPS data for year {stmt.get('date', 'unknown')}",
67
+ "eps_cagr_3yr": None,
68
+ "revenue_cagr_3yr": None,
69
+ "stability": "unknown",
70
+ "eps_values": None,
71
+ "interpretation": "EPS data incomplete"
72
+ }
73
+
74
+ if eps <= 0:
75
+ return {
76
+ "score": 0,
77
+ "error": f"Negative or zero EPS in year {stmt.get('date', 'unknown')} - cannot calculate CAGR",
78
+ "eps_cagr_3yr": None,
79
+ "revenue_cagr_3yr": None,
80
+ "stability": "unknown",
81
+ "eps_values": None,
82
+ "interpretation": "Negative EPS - not a CANSLIM candidate"
83
+ }
84
+
85
+ eps_values.append(eps)
86
+ revenue_values.append(revenue if revenue else 0)
87
+
88
+ # Reverse to chronological order (oldest first)
89
+ eps_values_chrono = eps_values[::-1]
90
+ revenue_values_chrono = revenue_values[::-1]
91
+
92
+ # Calculate 3-year CAGR
93
+ # CAGR = ((Ending Value / Beginning Value) ^ (1 / Number of Years)) - 1
94
+ eps_start = eps_values_chrono[0] # 3 years ago
95
+ eps_end = eps_values_chrono[3] # Current year
96
+ years = 3
97
+
98
+ eps_cagr = (((eps_end / eps_start) ** (1 / years)) - 1) * 100
99
+
100
+ # Calculate revenue CAGR for validation
101
+ revenue_start = revenue_values_chrono[0]
102
+ revenue_end = revenue_values_chrono[3]
103
+
104
+ if revenue_start > 0:
105
+ revenue_cagr = (((revenue_end / revenue_start) ** (1 / years)) - 1) * 100
106
+ else:
107
+ revenue_cagr = 0
108
+
109
+ # Check growth stability (no down years)
110
+ stable = all(eps_values_chrono[i] >= eps_values_chrono[i - 1]
111
+ for i in range(1, len(eps_values_chrono)))
112
+
113
+ # Calculate score
114
+ score = score_annual_growth(eps_cagr, revenue_cagr, stable)
115
+
116
+ # Generate interpretation
117
+ interpretation = interpret_growth_score(score, eps_cagr, stable)
118
+
119
+ # Quality warning
120
+ quality_warning = None
121
+ if revenue_cagr < (eps_cagr * 0.5) and eps_cagr > 20:
122
+ quality_warning = ("Revenue CAGR significantly lags EPS CAGR - "
123
+ "growth may be buyback-driven rather than organic")
124
+
125
+ return {
126
+ "score": score,
127
+ "eps_cagr_3yr": round(eps_cagr, 1),
128
+ "revenue_cagr_3yr": round(revenue_cagr, 1),
129
+ "stability": "stable" if stable else "erratic",
130
+ "eps_values": [round(eps, 2) for eps in eps_values_chrono],
131
+ "revenue_values": [int(rev) for rev in revenue_values_chrono],
132
+ "years_analyzed": len(eps_values_chrono),
133
+ "interpretation": interpretation,
134
+ "quality_warning": quality_warning,
135
+ "error": None
136
+ }
137
+
138
+
139
+ def score_annual_growth(eps_cagr: float, revenue_cagr: float, stable: bool) -> int:
140
+ """
141
+ Score A component based on EPS CAGR, revenue validation, and stability
142
+
143
+ Args:
144
+ eps_cagr: 3-year EPS compound annual growth rate (%)
145
+ revenue_cagr: 3-year revenue CAGR (%)
146
+ stable: True if no down years, False if erratic
147
+
148
+ Returns:
149
+ Score (0-100)
150
+
151
+ Scoring Logic:
152
+ - Base score from EPS CAGR:
153
+ - 40%+: 90 points
154
+ - 30-39%: 70 points
155
+ - 25-29%: 50 points (meets CANSLIM minimum)
156
+ - 15-24%: 30 points
157
+ - <15%: 0 points
158
+ - Penalty: -20% if revenue CAGR < 50% of EPS CAGR (buyback concern)
159
+ - Bonus: +10 points if stable growth (no down years)
160
+ """
161
+ # Base score from EPS CAGR
162
+ if eps_cagr >= 40:
163
+ base_score = 90
164
+ elif eps_cagr >= 30:
165
+ base_score = 70
166
+ elif eps_cagr >= 25:
167
+ base_score = 50 # Meets CANSLIM minimum
168
+ elif eps_cagr >= 15:
169
+ base_score = 30
170
+ else:
171
+ base_score = 0
172
+
173
+ # Revenue growth validation penalty
174
+ if revenue_cagr < (eps_cagr * 0.5):
175
+ base_score = int(base_score * 0.8) # 20% penalty
176
+
177
+ # Stability bonus
178
+ if stable:
179
+ base_score += 10
180
+
181
+ # Cap at 100
182
+ return min(base_score, 100)
183
+
184
+
185
+ def interpret_growth_score(score: int, eps_cagr: float, stable: bool) -> str:
186
+ """
187
+ Generate human-readable interpretation of A component score
188
+
189
+ Args:
190
+ score: Component score (0-100)
191
+ eps_cagr: 3-year EPS CAGR (%)
192
+ stable: Growth stability flag
193
+
194
+ Returns:
195
+ Interpretation string
196
+ """
197
+ stability_text = "stable" if stable else "erratic"
198
+
199
+ if score >= 90:
200
+ return (f"Exceptional - {eps_cagr:.1f}% CAGR, {stability_text} growth trajectory")
201
+
202
+ elif score >= 70:
203
+ return (f"Strong - {eps_cagr:.1f}% CAGR, well above CANSLIM 25% threshold ({stability_text})")
204
+
205
+ elif score >= 50:
206
+ return (f"Acceptable - {eps_cagr:.1f}% CAGR meets CANSLIM minimum ({stability_text})")
207
+
208
+ elif score >= 30:
209
+ return (f"Below threshold - {eps_cagr:.1f}% CAGR insufficient (<25% required)")
210
+
211
+ else:
212
+ return (f"Weak - {eps_cagr:.1f}% CAGR does not meet CANSLIM criteria")
213
+
214
+
215
+ def check_consistency(income_statements: List[Dict]) -> Dict:
216
+ """
217
+ Check year-over-year growth consistency (no down years is ideal)
218
+
219
+ Args:
220
+ income_statements: List of annual income statements (recent first)
221
+
222
+ Returns:
223
+ Dict with:
224
+ - down_years: Count of years with YoY decline
225
+ - consecutive_growth_years: Max consecutive years of growth
226
+ - growth_pattern: List of YoY growth rates
227
+ """
228
+ if len(income_statements) < 2:
229
+ return {
230
+ "down_years": None,
231
+ "consecutive_growth_years": None,
232
+ "growth_pattern": None,
233
+ "interpretation": "Insufficient data"
234
+ }
235
+
236
+ eps_values = []
237
+ for stmt in income_statements:
238
+ eps = stmt.get("eps") or stmt.get("epsdiluted")
239
+ if eps:
240
+ eps_values.append(eps)
241
+
242
+ # Reverse to chronological order
243
+ eps_values = eps_values[::-1]
244
+
245
+ # Calculate YoY growth rates
246
+ growth_pattern = []
247
+ for i in range(1, len(eps_values)):
248
+ if eps_values[i - 1] > 0:
249
+ yoy_growth = ((eps_values[i] - eps_values[i - 1]) / eps_values[i - 1]) * 100
250
+ growth_pattern.append(round(yoy_growth, 1))
251
+
252
+ # Count down years
253
+ down_years = sum(1 for g in growth_pattern if g < 0)
254
+
255
+ # Find max consecutive growth years
256
+ consecutive = 0
257
+ max_consecutive = 0
258
+ for g in growth_pattern:
259
+ if g >= 0:
260
+ consecutive += 1
261
+ max_consecutive = max(max_consecutive, consecutive)
262
+ else:
263
+ consecutive = 0
264
+
265
+ interpretation = f"{max_consecutive} consecutive years of growth, {down_years} down years"
266
+
267
+ return {
268
+ "down_years": down_years,
269
+ "consecutive_growth_years": max_consecutive,
270
+ "growth_pattern": growth_pattern,
271
+ "interpretation": interpretation
272
+ }
273
+
274
+
275
+ # Example usage and testing
276
+ if __name__ == "__main__":
277
+ print("Testing Growth Calculator (A Component)...\n")
278
+
279
+ # Test case 1: Exceptional growth (NVDA-like, 40%+ CAGR, stable)
280
+ test_data_exceptional = [
281
+ {"date": "2023-01-31", "eps": 4.02, "revenue": 26974000000}, # FY2023
282
+ {"date": "2022-01-31", "eps": 4.44, "revenue": 26914000000}, # FY2022
283
+ {"date": "2021-01-31", "eps": 1.93, "revenue": 16675000000}, # FY2021
284
+ {"date": "2020-01-31", "eps": 1.67, "revenue": 10918000000}, # FY2020
285
+ ]
286
+
287
+ result1 = calculate_annual_growth(test_data_exceptional)
288
+ print("Test 1: Exceptional Growth (40%+ CAGR)")
289
+ print(f" Score: {result1['score']}/100")
290
+ print(f" EPS CAGR: {result1['eps_cagr_3yr']}%")
291
+ print(f" Revenue CAGR: {result1['revenue_cagr_3yr']}%")
292
+ print(f" Stability: {result1['stability']}")
293
+ print(f" Interpretation: {result1['interpretation']}\n")
294
+
295
+ # Test case 2: Meets minimum (25-29% CAGR, stable)
296
+ test_data_minimum = [
297
+ {"date": "2023-12-31", "eps": 2.00, "revenue": 50000000000},
298
+ {"date": "2022-12-31", "eps": 1.60, "revenue": 45000000000},
299
+ {"date": "2021-12-31", "eps": 1.28, "revenue": 40000000000},
300
+ {"date": "2020-12-31", "eps": 1.02, "revenue": 36000000000}, # ~25% CAGR
301
+ ]
302
+
303
+ result2 = calculate_annual_growth(test_data_minimum)
304
+ print("Test 2: Meets CANSLIM Minimum (25% CAGR)")
305
+ print(f" Score: {result2['score']}/100")
306
+ print(f" EPS CAGR: {result2['eps_cagr_3yr']}%")
307
+ print(f" Revenue CAGR: {result2['revenue_cagr_3yr']}%")
308
+ print(f" Stability: {result2['stability']}")
309
+ print(f" Interpretation: {result2['interpretation']}\n")
310
+
311
+ # Test case 3: Erratic growth (one down year)
312
+ test_data_erratic = [
313
+ {"date": "2023-12-31", "eps": 2.50, "revenue": 50000000000},
314
+ {"date": "2022-12-31", "eps": 1.80, "revenue": 45000000000}, # Down year
315
+ {"date": "2021-12-31", "eps": 2.00, "revenue": 48000000000},
316
+ {"date": "2020-12-31", "eps": 1.60, "revenue": 42000000000},
317
+ ]
318
+
319
+ result3 = calculate_annual_growth(test_data_erratic)
320
+ print("Test 3: Erratic Growth (One Down Year)")
321
+ print(f" Score: {result3['score']}/100")
322
+ print(f" EPS CAGR: {result3['eps_cagr_3yr']}%")
323
+ print(f" Stability: {result3['stability']}")
324
+ print(f" Interpretation: {result3['interpretation']}\n")
325
+
326
+ # Test consistency check
327
+ print("Test 4: Consistency Check")
328
+ consistency = check_consistency(test_data_exceptional)
329
+ print(f" Down years: {consistency['down_years']}")
330
+ print(f" Consecutive growth: {consistency['consecutive_growth_years']} years")
331
+ print(f" Growth pattern: {consistency['growth_pattern']}")
332
+ print(f" Interpretation: {consistency['interpretation']}")
333
+
334
+ print("\n✓ All tests completed")