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,443 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ FMP Earnings Calendar Fetcher
4
+
5
+ Retrieves upcoming earnings announcements from Financial Modeling Prep API,
6
+ filters by market cap (>$2B), and outputs structured JSON data.
7
+
8
+ Usage:
9
+ # With environment variable
10
+ export FMP_API_KEY="your-key"
11
+ python fetch_earnings_fmp.py 2025-11-03 2025-11-09
12
+
13
+ # With API key as argument
14
+ python fetch_earnings_fmp.py 2025-11-03 2025-11-09 YOUR_API_KEY
15
+
16
+ # Help
17
+ python fetch_earnings_fmp.py --help
18
+ """
19
+
20
+ import sys
21
+ import os
22
+ import json
23
+ import requests
24
+ from datetime import datetime, timedelta
25
+ from typing import List, Dict, Optional
26
+
27
+
28
+ class FMPEarningsCalendar:
29
+ """FMP Earnings Calendar API client"""
30
+
31
+ BASE_URL = "https://financialmodelingprep.com/api/v3"
32
+ MIN_MARKET_CAP = 2_000_000_000 # $2B
33
+ US_EXCHANGES = ['NYSE', 'NASDAQ', 'AMEX', 'NYSEArca', 'BATS', 'NMS', 'NGM', 'NCM']
34
+
35
+ def __init__(self, api_key: str, us_only: bool = True):
36
+ """
37
+ Initialize FMP client
38
+
39
+ Args:
40
+ api_key: FMP API key
41
+ us_only: If True, filter for US stocks only (default: True)
42
+ """
43
+ self.api_key = api_key
44
+ self.us_only = us_only
45
+
46
+ def fetch_earnings_calendar(self, start_date: str, end_date: str) -> Optional[List[Dict]]:
47
+ """
48
+ Fetch earnings calendar from FMP API
49
+
50
+ Args:
51
+ start_date: Start date (YYYY-MM-DD)
52
+ end_date: End date (YYYY-MM-DD)
53
+
54
+ Returns:
55
+ List of earnings announcements or None on error
56
+ """
57
+ url = f"{self.BASE_URL}/earning_calendar"
58
+ params = {
59
+ "apikey": self.api_key,
60
+ "from": start_date,
61
+ "to": end_date
62
+ }
63
+
64
+ try:
65
+ response = requests.get(url, params=params, timeout=30)
66
+
67
+ if response.status_code == 401:
68
+ print("❌ ERROR: Invalid API key", file=sys.stderr)
69
+ print("Get free API key: https://site.financialmodelingprep.com/developer/docs", file=sys.stderr)
70
+ return None
71
+
72
+ if response.status_code == 429:
73
+ print("❌ ERROR: Rate limit exceeded", file=sys.stderr)
74
+ print("Free tier: 250 calls/day. Consider upgrading.", file=sys.stderr)
75
+ return None
76
+
77
+ response.raise_for_status()
78
+ data = response.json()
79
+
80
+ # Check if response is error message
81
+ if isinstance(data, dict) and "Error Message" in data:
82
+ print(f"❌ API Error: {data['Error Message']}", file=sys.stderr)
83
+ return None
84
+
85
+ print(f"✓ Retrieved {len(data)} earnings announcements", file=sys.stderr)
86
+ return data
87
+
88
+ except requests.exceptions.Timeout:
89
+ print("❌ ERROR: Request timeout. Please try again.", file=sys.stderr)
90
+ return None
91
+
92
+ except requests.exceptions.ConnectionError:
93
+ print("❌ ERROR: Connection error. Check your internet connection.", file=sys.stderr)
94
+ return None
95
+
96
+ except Exception as e:
97
+ print(f"❌ ERROR: Unexpected error: {str(e)}", file=sys.stderr)
98
+ return None
99
+
100
+ def fetch_company_profiles(self, symbols: List[str]) -> Dict[str, Dict]:
101
+ """
102
+ Fetch company profiles for multiple symbols (batch)
103
+
104
+ Args:
105
+ symbols: List of ticker symbols
106
+
107
+ Returns:
108
+ Dictionary mapping symbol to profile data
109
+ """
110
+ profiles = {}
111
+ batch_size = 100 # FMP allows batch requests
112
+
113
+ print(f"✓ Fetching profiles for {len(symbols)} companies...", file=sys.stderr)
114
+
115
+ for i in range(0, len(symbols), batch_size):
116
+ batch = symbols[i:i+batch_size]
117
+ symbols_str = ",".join(batch)
118
+
119
+ url = f"{self.BASE_URL}/profile/{symbols_str}"
120
+ params = {"apikey": self.api_key}
121
+
122
+ try:
123
+ response = requests.get(url, params=params, timeout=30)
124
+ response.raise_for_status()
125
+
126
+ for profile in response.json():
127
+ if isinstance(profile, dict):
128
+ profiles[profile.get("symbol")] = profile
129
+
130
+ print(f" ✓ Batch {i//batch_size + 1}: {len(batch)} profiles", file=sys.stderr)
131
+
132
+ except Exception as e:
133
+ print(f" ⚠️ Warning: Failed to fetch batch {i//batch_size + 1}: {str(e)}", file=sys.stderr)
134
+ continue
135
+
136
+ print(f"✓ Retrieved {len(profiles)} company profiles", file=sys.stderr)
137
+ return profiles
138
+
139
+ def filter_by_market_cap(self, earnings: List[Dict], profiles: Dict[str, Dict]) -> List[Dict]:
140
+ """
141
+ Filter earnings by minimum market cap and enrich with company data
142
+
143
+ Args:
144
+ earnings: List of earnings announcements
145
+ profiles: Dictionary of company profiles
146
+
147
+ Returns:
148
+ Filtered and enriched list of earnings
149
+ """
150
+ filtered = []
151
+
152
+ for earning in earnings:
153
+ symbol = earning.get("symbol")
154
+ if not symbol:
155
+ continue
156
+
157
+ profile = profiles.get(symbol)
158
+
159
+ # Filter by market cap and exchange
160
+ if profile:
161
+ market_cap = profile.get("mktCap", 0)
162
+ if market_cap < self.MIN_MARKET_CAP:
163
+ continue
164
+
165
+ exchange = profile.get("exchangeShortName", "N/A")
166
+
167
+ # Filter by US exchanges if us_only is True
168
+ if self.us_only and exchange not in self.US_EXCHANGES:
169
+ continue
170
+
171
+ # Enrich with profile data
172
+ earning["marketCap"] = market_cap
173
+ earning["companyName"] = profile.get("companyName", symbol)
174
+ earning["sector"] = profile.get("sector", "N/A")
175
+ earning["industry"] = profile.get("industry", "N/A")
176
+ earning["exchange"] = exchange
177
+
178
+ filtered.append(earning)
179
+
180
+ if self.us_only:
181
+ print(f"✓ Filtered to {len(filtered)} US mid-cap+ companies (>${self.MIN_MARKET_CAP/1e9:.0f}B)", file=sys.stderr)
182
+ else:
183
+ print(f"✓ Filtered to {len(filtered)} mid-cap+ companies (>${self.MIN_MARKET_CAP/1e9:.0f}B)", file=sys.stderr)
184
+
185
+ return filtered
186
+
187
+ def normalize_timing(self, time_value: Optional[str]) -> str:
188
+ """
189
+ Normalize timing values to BMO/AMC/TAS
190
+
191
+ Args:
192
+ time_value: Raw time value from API
193
+
194
+ Returns:
195
+ Normalized timing: BMO, AMC, or TAS
196
+ """
197
+ if not time_value:
198
+ return "TAS"
199
+
200
+ time_lower = time_value.lower()
201
+
202
+ if time_lower in ["bmo", "pre-market", "before market open"]:
203
+ return "BMO"
204
+ elif time_lower in ["amc", "after-market", "after market close"]:
205
+ return "AMC"
206
+ else:
207
+ return "TAS"
208
+
209
+ def format_market_cap(self, market_cap: float) -> str:
210
+ """
211
+ Format market cap in human-readable format
212
+
213
+ Args:
214
+ market_cap: Market cap in dollars
215
+
216
+ Returns:
217
+ Formatted string (e.g., "$3.0T", "$150B")
218
+ """
219
+ if market_cap >= 1e12:
220
+ return f"${market_cap/1e12:.1f}T"
221
+ elif market_cap >= 1e9:
222
+ return f"${market_cap/1e9:.1f}B"
223
+ elif market_cap >= 1e6:
224
+ return f"${market_cap/1e6:.0f}M"
225
+ else:
226
+ return f"${market_cap:,.0f}"
227
+
228
+ def process_earnings(self, earnings: List[Dict]) -> List[Dict]:
229
+ """
230
+ Process and standardize earnings data
231
+
232
+ Args:
233
+ earnings: Raw earnings data
234
+
235
+ Returns:
236
+ Processed earnings data
237
+ """
238
+ processed = []
239
+
240
+ for earning in earnings:
241
+ # Normalize timing
242
+ timing = self.normalize_timing(earning.get("time"))
243
+
244
+ # Format market cap
245
+ market_cap = earning.get("marketCap", 0)
246
+ market_cap_formatted = self.format_market_cap(market_cap)
247
+
248
+ processed_earning = {
249
+ "symbol": earning.get("symbol"),
250
+ "companyName": earning.get("companyName", earning.get("symbol")),
251
+ "date": earning.get("date"),
252
+ "timing": timing,
253
+ "marketCap": market_cap,
254
+ "marketCapFormatted": market_cap_formatted,
255
+ "sector": earning.get("sector", "N/A"),
256
+ "industry": earning.get("industry", "N/A"),
257
+ "epsEstimated": earning.get("epsEstimated"),
258
+ "revenueEstimated": earning.get("revenueEstimated"),
259
+ "fiscalDateEnding": earning.get("fiscalDateEnding"),
260
+ "exchange": earning.get("exchange", "N/A")
261
+ }
262
+
263
+ processed.append(processed_earning)
264
+
265
+ return processed
266
+
267
+ def sort_earnings(self, earnings: List[Dict]) -> List[Dict]:
268
+ """
269
+ Sort earnings by date, timing, and market cap
270
+
271
+ Args:
272
+ earnings: Processed earnings data
273
+
274
+ Returns:
275
+ Sorted earnings data
276
+ """
277
+ # Define timing order
278
+ timing_order = {"BMO": 1, "AMC": 2, "TAS": 3}
279
+
280
+ return sorted(
281
+ earnings,
282
+ key=lambda x: (
283
+ x.get("date", ""),
284
+ timing_order.get(x.get("timing", "TAS"), 3),
285
+ -x.get("marketCap", 0) # Descending market cap
286
+ )
287
+ )
288
+
289
+
290
+ def get_api_key() -> Optional[str]:
291
+ """
292
+ Get API key from environment or command line
293
+
294
+ Returns:
295
+ API key or None
296
+ """
297
+ # Method 1: Command line argument (position 3)
298
+ if len(sys.argv) >= 4:
299
+ api_key = sys.argv[3]
300
+ print("✓ API key provided via command line argument", file=sys.stderr)
301
+ return api_key
302
+
303
+ # Method 2: Environment variable
304
+ api_key = os.environ.get('FMP_API_KEY')
305
+ if api_key:
306
+ print("✓ API key loaded from FMP_API_KEY environment variable", file=sys.stderr)
307
+ return api_key
308
+
309
+ # Not found
310
+ print("❌ ERROR: No API key found", file=sys.stderr)
311
+ print("", file=sys.stderr)
312
+ print("Options:", file=sys.stderr)
313
+ print("1. Set environment variable: export FMP_API_KEY='your-key'", file=sys.stderr)
314
+ print("2. Pass as argument: python fetch_earnings_fmp.py START END YOUR_KEY", file=sys.stderr)
315
+ print("3. Get free API key: https://site.financialmodelingprep.com/developer/docs", file=sys.stderr)
316
+ return None
317
+
318
+
319
+ def validate_date(date_str: str) -> bool:
320
+ """
321
+ Validate date format (YYYY-MM-DD)
322
+
323
+ Args:
324
+ date_str: Date string
325
+
326
+ Returns:
327
+ True if valid, False otherwise
328
+ """
329
+ try:
330
+ datetime.strptime(date_str, "%Y-%m-%d")
331
+ return True
332
+ except ValueError:
333
+ return False
334
+
335
+
336
+ def print_usage():
337
+ """Print usage instructions"""
338
+ print("Usage:", file=sys.stderr)
339
+ print(" python fetch_earnings_fmp.py START_DATE END_DATE [API_KEY]", file=sys.stderr)
340
+ print("", file=sys.stderr)
341
+ print("Arguments:", file=sys.stderr)
342
+ print(" START_DATE Start date in YYYY-MM-DD format", file=sys.stderr)
343
+ print(" END_DATE End date in YYYY-MM-DD format", file=sys.stderr)
344
+ print(" API_KEY (Optional) FMP API key (or use FMP_API_KEY env var)", file=sys.stderr)
345
+ print("", file=sys.stderr)
346
+ print("Examples:", file=sys.stderr)
347
+ print(" export FMP_API_KEY='your-key'", file=sys.stderr)
348
+ print(" python fetch_earnings_fmp.py 2025-11-03 2025-11-09", file=sys.stderr)
349
+ print("", file=sys.stderr)
350
+ print(" python fetch_earnings_fmp.py 2025-11-03 2025-11-09 your-key", file=sys.stderr)
351
+ print("", file=sys.stderr)
352
+ print("Output:", file=sys.stderr)
353
+ print(" JSON data is written to stdout", file=sys.stderr)
354
+ print(" Progress messages are written to stderr", file=sys.stderr)
355
+
356
+
357
+ def main():
358
+ """Main execution"""
359
+ # Check for help flag
360
+ if len(sys.argv) > 1 and sys.argv[1] in ["-h", "--help", "help"]:
361
+ print_usage()
362
+ sys.exit(0)
363
+
364
+ # Validate arguments
365
+ if len(sys.argv) < 3:
366
+ print("❌ ERROR: Missing required arguments", file=sys.stderr)
367
+ print("", file=sys.stderr)
368
+ print_usage()
369
+ sys.exit(1)
370
+
371
+ start_date = sys.argv[1]
372
+ end_date = sys.argv[2]
373
+
374
+ # Validate dates
375
+ if not validate_date(start_date):
376
+ print(f"❌ ERROR: Invalid start date format: {start_date}", file=sys.stderr)
377
+ print("Expected format: YYYY-MM-DD", file=sys.stderr)
378
+ sys.exit(1)
379
+
380
+ if not validate_date(end_date):
381
+ print(f"❌ ERROR: Invalid end date format: {end_date}", file=sys.stderr)
382
+ print("Expected format: YYYY-MM-DD", file=sys.stderr)
383
+ sys.exit(1)
384
+
385
+ # Get API key
386
+ api_key = get_api_key()
387
+ if not api_key:
388
+ sys.exit(1)
389
+
390
+ print(f"", file=sys.stderr)
391
+ print(f"📅 Fetching earnings calendar: {start_date} to {end_date}", file=sys.stderr)
392
+ print(f"", file=sys.stderr)
393
+
394
+ # Initialize client
395
+ client = FMPEarningsCalendar(api_key)
396
+
397
+ # Step 1: Fetch earnings calendar
398
+ print("Step 1: Fetching earnings calendar...", file=sys.stderr)
399
+ earnings = client.fetch_earnings_calendar(start_date, end_date)
400
+ if earnings is None:
401
+ sys.exit(1)
402
+
403
+ if len(earnings) == 0:
404
+ print("⚠️ Warning: No earnings announcements found for date range", file=sys.stderr)
405
+ print(json.dumps([], indent=2))
406
+ sys.exit(0)
407
+
408
+ # Step 2: Fetch company profiles
409
+ print("", file=sys.stderr)
410
+ print("Step 2: Fetching company profiles...", file=sys.stderr)
411
+ symbols = list(set([e.get("symbol") for e in earnings if e.get("symbol")]))
412
+ profiles = client.fetch_company_profiles(symbols)
413
+
414
+ # Step 3: Filter by market cap
415
+ print("", file=sys.stderr)
416
+ print("Step 3: Filtering by market cap...", file=sys.stderr)
417
+ filtered_earnings = client.filter_by_market_cap(earnings, profiles)
418
+
419
+ if len(filtered_earnings) == 0:
420
+ print("⚠️ Warning: No companies with market cap >$2B found", file=sys.stderr)
421
+ print(json.dumps([], indent=2))
422
+ sys.exit(0)
423
+
424
+ # Step 4: Process earnings data
425
+ print("", file=sys.stderr)
426
+ print("Step 4: Processing earnings data...", file=sys.stderr)
427
+ processed_earnings = client.process_earnings(filtered_earnings)
428
+
429
+ # Step 5: Sort earnings
430
+ print("", file=sys.stderr)
431
+ print("Step 5: Sorting by date, timing, and market cap...", file=sys.stderr)
432
+ sorted_earnings = client.sort_earnings(processed_earnings)
433
+
434
+ print(f"✓ Final dataset: {len(sorted_earnings)} companies", file=sys.stderr)
435
+
436
+ # Output JSON to stdout
437
+ print("", file=sys.stderr)
438
+ print("✓ Complete! Writing JSON output...", file=sys.stderr)
439
+ print(json.dumps(sorted_earnings, indent=2))
440
+
441
+
442
+ if __name__ == "__main__":
443
+ main()