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,341 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ FTD Detector - Report Generator
4
+
5
+ Generates JSON and Markdown reports for FTD detection analysis.
6
+ """
7
+
8
+ import json
9
+ from typing import Dict
10
+
11
+
12
+ def generate_json_report(analysis: Dict, output_file: str):
13
+ """Save full analysis as JSON."""
14
+ with open(output_file, 'w') as f:
15
+ json.dump(analysis, f, indent=2, default=str)
16
+ print(f" JSON report saved to: {output_file}")
17
+
18
+
19
+ def generate_markdown_report(analysis: Dict, output_file: str):
20
+ """Generate comprehensive Markdown report."""
21
+ lines = []
22
+ metadata = analysis.get("metadata", {})
23
+ ms = analysis.get("market_state", {})
24
+ sp500 = analysis.get("sp500", {})
25
+ nasdaq = analysis.get("nasdaq", {})
26
+ quality = analysis.get("quality_score", {})
27
+ post_dist = analysis.get("post_ftd_distribution", {})
28
+ inv = analysis.get("ftd_invalidation", {})
29
+ pt = analysis.get("power_trend", {})
30
+
31
+ combined_state = ms.get("combined_state", "UNKNOWN")
32
+ total_score = quality.get("total_score", 0)
33
+ signal = quality.get("signal", "N/A")
34
+
35
+ # Header
36
+ lines.append("# FTD Detector Report")
37
+ lines.append("")
38
+ lines.append(f"**Generated:** {metadata.get('generated_at', 'N/A')}")
39
+ prices = metadata.get("index_prices", {})
40
+ if prices.get("sp500"):
41
+ lines.append(f"**S&P 500:** ${prices['sp500']:.2f}")
42
+ if prices.get("qqq"):
43
+ lines.append(f"**QQQ:** ${prices['qqq']:.2f}")
44
+ lines.append("")
45
+
46
+ # ── Market Timing Status ─────────────────────────────────────────────
47
+ lines.append("---")
48
+ lines.append("")
49
+ lines.append("## Market Timing Status")
50
+ lines.append("")
51
+
52
+ state_emoji = _state_emoji(combined_state)
53
+ lines.append(f"| Metric | Value |")
54
+ lines.append(f"|--------|-------|")
55
+ lines.append(f"| **Current State** | {state_emoji} **{_state_label(combined_state)}** |")
56
+ lines.append(f"| **Quality Score** | **{total_score}/100** |")
57
+ lines.append(f"| **Signal** | {signal} |")
58
+ lines.append(f"| **Exposure Guidance** | {quality.get('exposure_range', 'N/A')} |")
59
+ if ms.get("dual_confirmation"):
60
+ lines.append(f"| **Dual Confirmation** | YES (S&P 500 + NASDAQ) |")
61
+ elif ms.get("ftd_index"):
62
+ lines.append(f"| **FTD Index** | {ms['ftd_index']} |")
63
+ lines.append("")
64
+
65
+ lines.append(f"> **Guidance:** {quality.get('guidance', 'N/A')}")
66
+ lines.append("")
67
+
68
+ # ── Index Status Table ────────────────────────────────────────────────
69
+ lines.append("---")
70
+ lines.append("")
71
+ lines.append("## Index Status")
72
+ lines.append("")
73
+ lines.append("| Index | State | Current | High | Correction | Swing Low |")
74
+ lines.append("|-------|-------|---------|------|------------|-----------|")
75
+
76
+ for label, data in [("S&P 500", sp500), ("NASDAQ/QQQ", nasdaq)]:
77
+ state = data.get("state", "N/A")
78
+ current = f"${data['current_price']:.2f}" if data.get("current_price") else "N/A"
79
+ high = f"${data['lookback_high']:.2f}" if data.get("lookback_high") else "N/A"
80
+ corr = f"{data['correction_depth_pct']:.1f}%" if data.get("correction_depth_pct") is not None else "N/A"
81
+ swing = data.get("swing_low", {})
82
+ sl_str = f"{swing.get('date', 'N/A')} (${swing.get('price', 0):.2f})" if swing else "None"
83
+ lines.append(f"| {label} | {state} | {current} | {high} | {corr} | {sl_str} |")
84
+
85
+ lines.append("")
86
+
87
+ # ── Rally Attempt Details ─────────────────────────────────────────────
88
+ has_rally = False
89
+ for label, data in [("S&P 500", sp500), ("NASDAQ/QQQ", nasdaq)]:
90
+ rally = data.get("rally_attempt", {})
91
+ if rally and rally.get("day1_date"):
92
+ has_rally = True
93
+
94
+ if has_rally:
95
+ lines.append("---")
96
+ lines.append("")
97
+ lines.append("## Rally Attempt Details")
98
+ lines.append("")
99
+
100
+ for label, data in [("S&P 500", sp500), ("NASDAQ/QQQ", nasdaq)]:
101
+ rally = data.get("rally_attempt", {})
102
+ swing = data.get("swing_low", {})
103
+ if not rally or not rally.get("day1_date"):
104
+ continue
105
+
106
+ lines.append(f"### {label}")
107
+ lines.append("")
108
+ lines.append(f"- **Swing Low:** {swing.get('date', 'N/A')} "
109
+ f"(${swing.get('price', 0):.2f}, {swing.get('decline_pct', 0):.1f}% decline)")
110
+ lines.append(f"- **Rally Day 1:** {rally.get('day1_date', 'N/A')}")
111
+ lines.append(f"- **Current Day Count:** {rally.get('current_day_count', 0)}")
112
+
113
+ if rally.get("invalidated"):
114
+ lines.append(f"- **INVALIDATED:** {rally.get('invalidation_reason', 'N/A')}")
115
+ lines.append("")
116
+
117
+ # ── FTD Signal ────────────────────────────────────────────────────────
118
+ sp_ftd = sp500.get("ftd", {})
119
+ nq_ftd = nasdaq.get("ftd", {})
120
+ has_ftd = (sp_ftd and sp_ftd.get("ftd_detected")) or (nq_ftd and nq_ftd.get("ftd_detected"))
121
+
122
+ if has_ftd:
123
+ lines.append("---")
124
+ lines.append("")
125
+ lines.append("## FTD Signal")
126
+ lines.append("")
127
+
128
+ for label, ftd_data in [("S&P 500", sp_ftd), ("NASDAQ/QQQ", nq_ftd)]:
129
+ if not ftd_data or not ftd_data.get("ftd_detected"):
130
+ continue
131
+
132
+ lines.append(f"### {label} FTD")
133
+ lines.append("")
134
+ lines.append(f"| Metric | Value |")
135
+ lines.append(f"|--------|-------|")
136
+ lines.append(f"| **FTD Date** | {ftd_data.get('ftd_date', 'N/A')} |")
137
+ lines.append(f"| **Day Number** | Day {ftd_data.get('ftd_day_number', 'N/A')} |")
138
+ lines.append(f"| **Price Gain** | +{ftd_data.get('gain_pct', 0):.2f}% "
139
+ f"({ftd_data.get('gain_tier', 'N/A')}) |")
140
+ vol_above = ftd_data.get("volume_above_avg")
141
+ if vol_above is not None:
142
+ vol_str = "Above 50-day avg" if vol_above else "Below 50-day avg"
143
+ else:
144
+ vol_str = "N/A"
145
+ lines.append(f"| **Volume** | {vol_str} |")
146
+ lines.append("")
147
+
148
+ # ── Quality Score Breakdown ───────────────────────────────────────────
149
+ if quality.get("breakdown"):
150
+ lines.append("---")
151
+ lines.append("")
152
+ lines.append("## Quality Score Breakdown")
153
+ lines.append("")
154
+ lines.append(f"**Total: {total_score}/100**")
155
+ lines.append("")
156
+ lines.append("| Factor | Detail |")
157
+ lines.append("|--------|--------|")
158
+
159
+ for key, detail in quality.get("breakdown", {}).items():
160
+ lines.append(f"| {key.replace('_', ' ').title()} | {detail} |")
161
+ lines.append("")
162
+
163
+ # ── Post-FTD Health ───────────────────────────────────────────────────
164
+ if post_dist or inv or pt:
165
+ lines.append("---")
166
+ lines.append("")
167
+ lines.append("## Post-FTD Health")
168
+ lines.append("")
169
+
170
+ if post_dist:
171
+ dist_count = post_dist.get("distribution_count", 0)
172
+ monitored = post_dist.get("days_monitored", 0)
173
+ lines.append(f"- **Distribution Days Since FTD:** {dist_count} "
174
+ f"(in {monitored} days monitored)")
175
+ for d in post_dist.get("details", []):
176
+ lines.append(f" - Day {d['day']}: {d['date']} "
177
+ f"({d['change_pct']:+.2f}%, vol {d['volume_change_pct']:+.1f}%)")
178
+
179
+ if inv:
180
+ if inv.get("invalidated"):
181
+ lines.append(f"- **FTD INVALIDATED** on {inv.get('invalidation_date')} "
182
+ f"(Day {inv.get('days_after_ftd')}, close ${inv.get('invalidation_close', 0):.2f} "
183
+ f"below FTD low ${inv.get('ftd_low', 0):.2f})")
184
+ else:
185
+ lines.append(f"- **FTD Valid:** {inv.get('days_since_ftd', 0)} days since FTD "
186
+ f"(FTD low: ${inv.get('ftd_low', 0):.2f})")
187
+
188
+ if pt:
189
+ pt_status = "YES" if pt.get("power_trend") else "No"
190
+ lines.append(f"- **Power Trend:** {pt_status} "
191
+ f"({pt.get('conditions_met', 0)}/3 conditions)")
192
+ if pt.get("ema_21") is not None:
193
+ lines.append(f" - 21 EMA: ${pt['ema_21']:.2f} "
194
+ f"({'>' if pt.get('ema_above_sma') else '<'} 50 SMA: ${pt.get('sma_50', 0):.2f})")
195
+ lines.append(f" - 50 SMA Rising: {'Yes' if pt.get('sma_50_rising') else 'No'}")
196
+ lines.append(f" - Price above 21 EMA: {'Yes' if pt.get('price_above_21ema') else 'No'}")
197
+
198
+ lines.append("")
199
+
200
+ # ── Action Guidance ───────────────────────────────────────────────────
201
+ lines.append("---")
202
+ lines.append("")
203
+ lines.append("## Action Guidance")
204
+ lines.append("")
205
+
206
+ exposure = quality.get("exposure_range", "N/A")
207
+ lines.append(f"**Recommended Exposure:** {exposure}")
208
+ lines.append("")
209
+
210
+ if combined_state == "FTD_CONFIRMED" and total_score >= 80:
211
+ lines.append("- Aggressively increase equity exposure")
212
+ lines.append("- Buy leading stocks breaking out of proper bases")
213
+ lines.append("- Use FTD day's low as stop-loss reference")
214
+ lines.append("- Monitor for distribution days (early distribution = caution)")
215
+ elif combined_state == "FTD_CONFIRMED" and total_score >= 60:
216
+ lines.append("- Gradually increase exposure with each successful breakout")
217
+ lines.append("- Start with half positions, add on confirmation")
218
+ lines.append("- Use FTD day's low as invalidation level")
219
+ lines.append("- Watch for distribution within 3 days (bearish)")
220
+ elif combined_state == "FTD_CONFIRMED":
221
+ lines.append("- Cautious exposure increase with tight stops")
222
+ lines.append("- Only buy highest-quality setups")
223
+ lines.append("- Small position sizes (25-50% of normal)")
224
+ lines.append("- Be prepared for FTD failure")
225
+ elif combined_state == "FTD_WINDOW":
226
+ lines.append("- WATCH MODE: FTD window is open (Day 4-10)")
227
+ lines.append("- Prepare buy lists of leading stocks in bases")
228
+ lines.append("- Do not buy ahead of FTD confirmation")
229
+ lines.append("- Monitor daily for qualifying FTD day")
230
+ elif combined_state == "RALLY_ATTEMPT":
231
+ lines.append("- Rally attempt in progress (Day 1-3)")
232
+ lines.append("- Too early to act - wait for Day 4+")
233
+ lines.append("- Prepare watchlists, research leaders")
234
+ lines.append("- Monitor for rally failure (close below swing low)")
235
+ elif combined_state == "CORRECTION":
236
+ lines.append("- Market in correction, no rally attempt yet")
237
+ lines.append("- Stay defensive, preserve capital")
238
+ lines.append("- Build watchlists of relative strength leaders")
239
+ lines.append("- Wait for first up day to start rally count")
240
+ elif combined_state == "FTD_INVALIDATED":
241
+ lines.append("- FTD has been invalidated - signal failed")
242
+ lines.append("- Reduce exposure back to defensive levels")
243
+ lines.append("- Wait for new swing low and fresh rally attempt")
244
+ lines.append("- Do not try to anticipate next FTD")
245
+ elif combined_state == "RALLY_FAILED":
246
+ lines.append("- Rally attempt failed (broke below swing low)")
247
+ lines.append("- Remain in cash/defensive")
248
+ lines.append("- New swing low may form - reset cycle")
249
+ lines.append("- Patience is key; do not force entries")
250
+ else:
251
+ lines.append("- No correction detected - normal market conditions")
252
+ lines.append("- FTD monitoring not applicable in uptrend")
253
+ lines.append("- Focus on individual stock setups")
254
+ lines.append("- Use Market Top Detector for defensive signals")
255
+
256
+ lines.append("")
257
+
258
+ # ── Key Watch Levels ──────────────────────────────────────────────────
259
+ lines.append("---")
260
+ lines.append("")
261
+ lines.append("## Key Watch Levels")
262
+ lines.append("")
263
+
264
+ for label, data in [("S&P 500", sp500), ("NASDAQ/QQQ", nasdaq)]:
265
+ swing = data.get("swing_low", {})
266
+ ftd_data = data.get("ftd", {})
267
+
268
+ if not swing and not ftd_data:
269
+ continue
270
+
271
+ lines.append(f"**{label}:**")
272
+ if swing:
273
+ lines.append(f"- Swing Low: ${swing.get('price', 0):.2f} "
274
+ f"({swing.get('date', 'N/A')})")
275
+ if ftd_data and ftd_data.get("ftd_detected"):
276
+ lines.append(f"- FTD Day: {ftd_data.get('ftd_date', 'N/A')}")
277
+ if data.get("lookback_high"):
278
+ lines.append(f"- Lookback High: ${data['lookback_high']:.2f}")
279
+ lines.append("")
280
+
281
+ # ── Methodology ───────────────────────────────────────────────────────
282
+ lines.append("---")
283
+ lines.append("")
284
+ lines.append("## Methodology")
285
+ lines.append("")
286
+ lines.append("This analysis uses William O'Neil's Follow-Through Day (FTD) methodology "
287
+ "to confirm market bottoms:")
288
+ lines.append("")
289
+ lines.append("1. **Swing Low Detection:** 3%+ decline from recent high with 3+ down days")
290
+ lines.append("2. **Rally Attempt:** Day 1 (first up close), Day 2-3 must hold Day 1 low")
291
+ lines.append("3. **FTD (Day 4-10):** 1.25%+ gain on volume higher than previous day")
292
+ lines.append("4. **Quality Score:** Multi-factor 0-100 score (day timing, gain size, "
293
+ "volume, dual-index, post-FTD health)")
294
+ lines.append("5. **Post-FTD Monitoring:** Distribution day tracking, invalidation check, "
295
+ "Power Trend confirmation")
296
+ lines.append("")
297
+ lines.append("Dual-index tracking (S&P 500 + NASDAQ) provides stronger confirmation "
298
+ "than single-index analysis.")
299
+ lines.append("")
300
+ lines.append("For detailed methodology, see `references/ftd_methodology.md`.")
301
+ lines.append("")
302
+
303
+ # ── Disclaimer ────────────────────────────────────────────────────────
304
+ lines.append("---")
305
+ lines.append("")
306
+ lines.append("**Disclaimer:** This analysis is for educational and informational purposes only. "
307
+ "Not investment advice. Follow-Through Days have approximately a 25% success rate "
308
+ "historically. Always use proper risk management and position sizing. "
309
+ "Consult a financial advisor before making investment decisions.")
310
+ lines.append("")
311
+
312
+ with open(output_file, 'w') as f:
313
+ f.write('\n'.join(lines))
314
+
315
+ print(f" Markdown report saved to: {output_file}")
316
+
317
+
318
+ def _state_emoji(state: str) -> str:
319
+ mapping = {
320
+ "NO_SIGNAL": "⚪",
321
+ "CORRECTION": "🔴",
322
+ "RALLY_ATTEMPT": "🟡",
323
+ "FTD_WINDOW": "🟡",
324
+ "FTD_CONFIRMED": "🟢",
325
+ "RALLY_FAILED": "🔴",
326
+ "FTD_INVALIDATED": "🔴",
327
+ }
328
+ return mapping.get(state, "⚪")
329
+
330
+
331
+ def _state_label(state: str) -> str:
332
+ mapping = {
333
+ "NO_SIGNAL": "No Signal (Uptrend)",
334
+ "CORRECTION": "Correction",
335
+ "RALLY_ATTEMPT": "Rally Attempt (Day 1-3)",
336
+ "FTD_WINDOW": "FTD Window (Day 4-10)",
337
+ "FTD_CONFIRMED": "FTD Confirmed",
338
+ "RALLY_FAILED": "Rally Failed",
339
+ "FTD_INVALIDATED": "FTD Invalidated",
340
+ }
341
+ return mapping.get(state, state)
@@ -0,0 +1,9 @@
1
+ """Shared fixtures for FTD Detector tests"""
2
+
3
+ import os
4
+ import sys
5
+
6
+ # Add scripts directory to path so modules can be imported
7
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
8
+ # Add tests directory to path so helpers can be imported
9
+ sys.path.insert(0, os.path.dirname(__file__))
@@ -0,0 +1,107 @@
1
+ """Importable test helpers for FTD Detector tests"""
2
+
3
+
4
+ def make_bar(close, volume=1_000_000, date="2026-01-15", open_=None, high=None, low=None):
5
+ """Create a single OHLCV bar dict."""
6
+ if open_ is None:
7
+ open_ = close
8
+ if high is None:
9
+ high = close * 1.005
10
+ if low is None:
11
+ low = close * 0.995
12
+ return {
13
+ "date": date,
14
+ "open": open_,
15
+ "high": high,
16
+ "low": low,
17
+ "close": close,
18
+ "volume": volume,
19
+ }
20
+
21
+
22
+ def make_correction_history(peak=100.0, decline_pct=5.0, down_days=5, base_volume=1_000_000):
23
+ """
24
+ Build a synthetic chronological history with a clear correction.
25
+
26
+ Returns history with: flat lead-in -> peak -> decline -> swing low.
27
+ Total length ~ 20 bars (enough for find_swing_low lookback).
28
+ """
29
+ bars = []
30
+ day = 0
31
+
32
+ # 10-day flat lead-in near peak
33
+ for i in range(10):
34
+ price = peak * (0.98 + 0.02 * (i / 10))
35
+ bars.append(make_bar(price, base_volume, date=f"day-{day:03d}"))
36
+ day += 1
37
+
38
+ # Peak day
39
+ bars.append(make_bar(peak, base_volume, date=f"day-{day:03d}"))
40
+ day += 1
41
+
42
+ # Decline phase: down_days of steady decline to reach target
43
+ low_price = peak * (1 - decline_pct / 100)
44
+ step = (peak - low_price) / down_days
45
+ for i in range(1, down_days + 1):
46
+ price = peak - step * i
47
+ bars.append(make_bar(price, base_volume, date=f"day-{day:03d}"))
48
+ day += 1
49
+
50
+ return bars, day
51
+
52
+
53
+ def make_rally_history(
54
+ peak=100.0,
55
+ decline_pct=5.0,
56
+ down_days=5,
57
+ rally_days=10,
58
+ rally_gain_per_day=0.3,
59
+ base_volume=1_000_000,
60
+ ftd_day=None,
61
+ ftd_gain_pct=1.5,
62
+ ftd_volume_mult=1.5,
63
+ ):
64
+ """
65
+ Build a full correction -> rally history with optional FTD.
66
+
67
+ Args:
68
+ ftd_day: If set, inject an FTD-qualifying day at this rally day number.
69
+ ftd_gain_pct: Gain percentage for the FTD day.
70
+ ftd_volume_mult: Volume multiplier for FTD day vs previous day.
71
+
72
+ Returns (history, swing_low_idx, day1_idx, ftd_day_idx).
73
+ """
74
+ bars, day = make_correction_history(peak, decline_pct, down_days, base_volume)
75
+ swing_low_idx = len(bars) - 1
76
+ swing_low_price = bars[-1]["close"]
77
+
78
+ day1_idx = None
79
+ ftd_day_idx = None
80
+ prev_close = swing_low_price
81
+
82
+ for rally_num in range(1, rally_days + 1):
83
+ vol = base_volume
84
+
85
+ if ftd_day is not None and rally_num == ftd_day:
86
+ # FTD day: large gain, higher volume than previous day
87
+ gain = ftd_gain_pct / 100
88
+ price = prev_close * (1 + gain)
89
+ vol = int(base_volume * ftd_volume_mult)
90
+ ftd_day_idx = len(bars)
91
+ else:
92
+ price = prev_close * (1 + rally_gain_per_day / 100)
93
+
94
+ bars.append(
95
+ make_bar(
96
+ price,
97
+ vol,
98
+ date=f"day-{day:03d}",
99
+ low=price * 0.997,
100
+ )
101
+ )
102
+ if day1_idx is None and price > prev_close:
103
+ day1_idx = len(bars) - 1
104
+ prev_close = price
105
+ day += 1
106
+
107
+ return bars, swing_low_idx, day1_idx, ftd_day_idx