sqa 0.0.24 → 0.0.31

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 (180) hide show
  1. checksums.yaml +4 -4
  2. data/.goose/memory/development.txt +3 -0
  3. data/.semver +6 -0
  4. data/ARCHITECTURE.md +648 -0
  5. data/CHANGELOG.md +82 -0
  6. data/CLAUDE.md +653 -0
  7. data/COMMITS.md +196 -0
  8. data/DATAFRAME_ARCHITECTURE_REVIEW.md +421 -0
  9. data/NEXT-STEPS.md +154 -0
  10. data/README.md +812 -262
  11. data/TASKS.md +358 -0
  12. data/TEST_RESULTS.md +140 -0
  13. data/TODO.md +42 -0
  14. data/_notes.txt +25 -0
  15. data/bin/sqa-console +11 -0
  16. data/data/talk_talk.json +103284 -0
  17. data/develop_summary.md +313 -0
  18. data/docs/advanced/backtesting.md +206 -0
  19. data/docs/advanced/ensemble.md +68 -0
  20. data/docs/advanced/fpop.md +153 -0
  21. data/docs/advanced/index.md +112 -0
  22. data/docs/advanced/multi-timeframe.md +67 -0
  23. data/docs/advanced/pattern-matcher.md +75 -0
  24. data/docs/advanced/portfolio-optimizer.md +79 -0
  25. data/docs/advanced/portfolio.md +166 -0
  26. data/docs/advanced/risk-management.md +210 -0
  27. data/docs/advanced/strategy-generator.md +158 -0
  28. data/docs/advanced/streaming.md +209 -0
  29. data/docs/ai_and_ml.md +80 -0
  30. data/docs/api/dataframe.md +1115 -0
  31. data/docs/api/index.md +126 -0
  32. data/docs/assets/css/custom.css +88 -0
  33. data/docs/assets/js/mathjax.js +18 -0
  34. data/docs/concepts/index.md +68 -0
  35. data/docs/contributing/index.md +60 -0
  36. data/docs/data-sources/index.md +66 -0
  37. data/docs/data_frame.md +317 -97
  38. data/docs/factors_that_impact_price.md +26 -0
  39. data/docs/finviz.md +11 -0
  40. data/docs/fx_pro_bit.md +25 -0
  41. data/docs/genetic_programming.md +104 -0
  42. data/docs/getting-started/index.md +123 -0
  43. data/docs/getting-started/installation.md +229 -0
  44. data/docs/getting-started/quick-start.md +244 -0
  45. data/docs/i_gotta_an_idea.md +22 -0
  46. data/docs/index.md +163 -0
  47. data/docs/indicators/index.md +97 -0
  48. data/docs/indicators.md +110 -24
  49. data/docs/options.md +8 -0
  50. data/docs/strategies/bollinger-bands.md +146 -0
  51. data/docs/strategies/consensus.md +64 -0
  52. data/docs/strategies/custom.md +310 -0
  53. data/docs/strategies/ema.md +53 -0
  54. data/docs/strategies/index.md +92 -0
  55. data/docs/strategies/kbs.md +164 -0
  56. data/docs/strategies/macd.md +96 -0
  57. data/docs/strategies/market-profile.md +54 -0
  58. data/docs/strategies/mean-reversion.md +58 -0
  59. data/docs/strategies/rsi.md +95 -0
  60. data/docs/strategies/sma.md +55 -0
  61. data/docs/strategies/stochastic.md +63 -0
  62. data/docs/strategies/volume-breakout.md +54 -0
  63. data/docs/tags.md +7 -0
  64. data/docs/true_strength_index.md +46 -0
  65. data/docs/weighted_moving_average.md +48 -0
  66. data/examples/README.md +354 -0
  67. data/examples/advanced_features_example.rb +350 -0
  68. data/examples/fpop_analysis_example.rb +191 -0
  69. data/examples/genetic_programming_example.rb +148 -0
  70. data/examples/kbs_strategy_example.rb +208 -0
  71. data/examples/pattern_context_example.rb +300 -0
  72. data/examples/rails_app/Gemfile +34 -0
  73. data/examples/rails_app/README.md +416 -0
  74. data/examples/rails_app/app/assets/javascripts/application.js +107 -0
  75. data/examples/rails_app/app/assets/stylesheets/application.css +659 -0
  76. data/examples/rails_app/app/controllers/analysis_controller.rb +11 -0
  77. data/examples/rails_app/app/controllers/api/v1/stocks_controller.rb +227 -0
  78. data/examples/rails_app/app/controllers/application_controller.rb +22 -0
  79. data/examples/rails_app/app/controllers/backtest_controller.rb +11 -0
  80. data/examples/rails_app/app/controllers/dashboard_controller.rb +21 -0
  81. data/examples/rails_app/app/controllers/portfolio_controller.rb +7 -0
  82. data/examples/rails_app/app/views/analysis/show.html.erb +209 -0
  83. data/examples/rails_app/app/views/backtest/show.html.erb +171 -0
  84. data/examples/rails_app/app/views/dashboard/index.html.erb +118 -0
  85. data/examples/rails_app/app/views/dashboard/show.html.erb +408 -0
  86. data/examples/rails_app/app/views/errors/show.html.erb +17 -0
  87. data/examples/rails_app/app/views/layouts/application.html.erb +60 -0
  88. data/examples/rails_app/app/views/portfolio/index.html.erb +33 -0
  89. data/examples/rails_app/bin/rails +6 -0
  90. data/examples/rails_app/config/application.rb +45 -0
  91. data/examples/rails_app/config/boot.rb +5 -0
  92. data/examples/rails_app/config/database.yml +18 -0
  93. data/examples/rails_app/config/environment.rb +11 -0
  94. data/examples/rails_app/config/routes.rb +26 -0
  95. data/examples/rails_app/config.ru +8 -0
  96. data/examples/realtime_stream_example.rb +274 -0
  97. data/examples/sinatra_app/Gemfile +22 -0
  98. data/examples/sinatra_app/QUICKSTART.md +159 -0
  99. data/examples/sinatra_app/README.md +461 -0
  100. data/examples/sinatra_app/app.rb +344 -0
  101. data/examples/sinatra_app/config.ru +5 -0
  102. data/examples/sinatra_app/public/css/style.css +659 -0
  103. data/examples/sinatra_app/public/js/app.js +107 -0
  104. data/examples/sinatra_app/views/analyze.erb +306 -0
  105. data/examples/sinatra_app/views/backtest.erb +325 -0
  106. data/examples/sinatra_app/views/dashboard.erb +419 -0
  107. data/examples/sinatra_app/views/error.erb +58 -0
  108. data/examples/sinatra_app/views/index.erb +118 -0
  109. data/examples/sinatra_app/views/layout.erb +61 -0
  110. data/examples/sinatra_app/views/portfolio.erb +43 -0
  111. data/examples/strategy_generator_example.rb +346 -0
  112. data/hsa_portfolio.csv +11 -0
  113. data/justfile +0 -0
  114. data/lib/api/alpha_vantage_api.rb +462 -0
  115. data/lib/sqa/backtest.rb +329 -0
  116. data/lib/sqa/data_frame/alpha_vantage.rb +43 -65
  117. data/lib/sqa/data_frame/data.rb +92 -0
  118. data/lib/sqa/data_frame/yahoo_finance.rb +35 -43
  119. data/lib/sqa/data_frame.rb +148 -243
  120. data/lib/sqa/ensemble.rb +359 -0
  121. data/lib/sqa/fpop.rb +199 -0
  122. data/lib/sqa/gp.rb +259 -0
  123. data/lib/sqa/indicator.rb +5 -8
  124. data/lib/sqa/init.rb +15 -8
  125. data/lib/sqa/market_regime.rb +240 -0
  126. data/lib/sqa/multi_timeframe.rb +379 -0
  127. data/lib/sqa/pattern_matcher.rb +497 -0
  128. data/lib/sqa/portfolio.rb +260 -6
  129. data/lib/sqa/portfolio_optimizer.rb +377 -0
  130. data/lib/sqa/risk_manager.rb +442 -0
  131. data/lib/sqa/seasonal_analyzer.rb +209 -0
  132. data/lib/sqa/sector_analyzer.rb +300 -0
  133. data/lib/sqa/stock.rb +67 -125
  134. data/lib/sqa/strategy/bollinger_bands.rb +42 -0
  135. data/lib/sqa/strategy/consensus.rb +5 -2
  136. data/lib/sqa/strategy/kbs_strategy.rb +470 -0
  137. data/lib/sqa/strategy/macd.rb +46 -0
  138. data/lib/sqa/strategy/mp.rb +1 -1
  139. data/lib/sqa/strategy/stochastic.rb +60 -0
  140. data/lib/sqa/strategy/volume_breakout.rb +57 -0
  141. data/lib/sqa/strategy.rb +5 -0
  142. data/lib/sqa/strategy_generator.rb +947 -0
  143. data/lib/sqa/stream.rb +361 -0
  144. data/lib/sqa/version.rb +1 -7
  145. data/lib/sqa.rb +23 -16
  146. data/main.just +81 -0
  147. data/mkdocs.yml +288 -0
  148. data/trace.log +0 -0
  149. metadata +261 -51
  150. data/bin/sqa +0 -6
  151. data/lib/patches/dry-cli.rb +0 -228
  152. data/lib/sqa/activity.rb +0 -10
  153. data/lib/sqa/cli.rb +0 -62
  154. data/lib/sqa/commands/analysis.rb +0 -309
  155. data/lib/sqa/commands/base.rb +0 -139
  156. data/lib/sqa/commands/web.rb +0 -199
  157. data/lib/sqa/commands.rb +0 -22
  158. data/lib/sqa/constants.rb +0 -23
  159. data/lib/sqa/indicator/average_true_range.rb +0 -33
  160. data/lib/sqa/indicator/bollinger_bands.rb +0 -28
  161. data/lib/sqa/indicator/candlestick_pattern_recognizer.rb +0 -60
  162. data/lib/sqa/indicator/donchian_channel.rb +0 -29
  163. data/lib/sqa/indicator/double_top_bottom_pattern.rb +0 -34
  164. data/lib/sqa/indicator/elliott_wave_theory.rb +0 -57
  165. data/lib/sqa/indicator/exponential_moving_average.rb +0 -25
  166. data/lib/sqa/indicator/exponential_moving_average_trend.rb +0 -36
  167. data/lib/sqa/indicator/fibonacci_retracement.rb +0 -23
  168. data/lib/sqa/indicator/head_and_shoulders_pattern.rb +0 -26
  169. data/lib/sqa/indicator/market_profile.rb +0 -32
  170. data/lib/sqa/indicator/mean_reversion.rb +0 -37
  171. data/lib/sqa/indicator/momentum.rb +0 -28
  172. data/lib/sqa/indicator/moving_average_convergence_divergence.rb +0 -29
  173. data/lib/sqa/indicator/peaks_and_valleys.rb +0 -29
  174. data/lib/sqa/indicator/predict_next_value.rb +0 -202
  175. data/lib/sqa/indicator/relative_strength_index.rb +0 -47
  176. data/lib/sqa/indicator/simple_moving_average.rb +0 -24
  177. data/lib/sqa/indicator/simple_moving_average_trend.rb +0 -32
  178. data/lib/sqa/indicator/stochastic_oscillator.rb +0 -68
  179. data/lib/sqa/indicator/true_range.rb +0 -39
  180. data/lib/sqa/trade.rb +0 -26
@@ -0,0 +1,153 @@
1
+ # FPOP - Future Period of Performance
2
+
3
+ ## Overview
4
+
5
+ Calculate future returns, risk metrics, and direction classification to evaluate trading opportunities.
6
+
7
+ ## Quick Start
8
+
9
+ ```ruby
10
+ require 'sqa'
11
+
12
+ stock = SQA::Stock.new(ticker: 'AAPL')
13
+ prices = stock.df["adj_close_price"].to_a
14
+
15
+ # Calculate FPL (Future Period Loss/Profit)
16
+ fpl_data = SQA::FPOP.fpl(prices, fpop: 10)
17
+ # => [[min_delta, max_delta], ...]
18
+
19
+ # Comprehensive analysis
20
+ analysis = SQA::FPOP.fpl_analysis(prices, fpop: 10)
21
+ puts "Risk: #{analysis[:risk]}%"
22
+ puts "Direction: #{analysis[:direction]}" # :UP, :DOWN, :FLAT
23
+ ```
24
+
25
+ ## Methods
26
+
27
+ ### Basic FPL Calculation
28
+
29
+ ```ruby
30
+ prices = [100, 102, 105, 103, 107, 110]
31
+ fpl = SQA::FPOP.fpl(prices, fpop: 3)
32
+
33
+ # For each point, calculates min/max change over next 3 periods
34
+ # fpl[0] = [min(102,105,103) - 100, max(102,105,103) - 100]
35
+ # = [100-100, 105-100] = [0, 5]
36
+ ```
37
+
38
+ ### Comprehensive Analysis
39
+
40
+ ```ruby
41
+ analysis = SQA::FPOP.fpl_analysis(prices, fpop: 10)
42
+
43
+ # Returns hash with:
44
+ # {
45
+ # fpl: [[min_delta, max_delta], ...],
46
+ # risk: 15.5, # Max downside %
47
+ # reward: 25.2, # Max upside %
48
+ # direction: :UP, # Overall trend
49
+ # magnitude: 10.3, # Average move size
50
+ # quality_score: 0.75 # Risk/reward ratio
51
+ # }
52
+ ```
53
+
54
+ ### Quality Filtering
55
+
56
+ ```ruby
57
+ filtered = SQA::FPOP.filter_by_quality(
58
+ analysis,
59
+ min_magnitude: 5.0, # Minimum 5% move
60
+ max_risk: 25.0, # Maximum 25% downside
61
+ directions: [:UP] # Only upward moves
62
+ )
63
+
64
+ # Returns only high-quality opportunities
65
+ ```
66
+
67
+ ## Integration with Strategy Generator
68
+
69
+ ```ruby
70
+ generator = SQA::StrategyGenerator.new(
71
+ stock: stock,
72
+ min_gain_percent: 10.0,
73
+ fpop: 10, # Use 10-period lookahead
74
+ max_fpl_risk: 20.0 # Filter by max acceptable risk
75
+ )
76
+
77
+ patterns = generator.discover_patterns
78
+ # Only includes patterns with acceptable risk/reward
79
+ ```
80
+
81
+ ## DataFrame Methods
82
+
83
+ ```ruby
84
+ # Convenient DataFrame extensions
85
+ df = stock.df
86
+
87
+ # Add FPL columns
88
+ df_with_fpl = df.fpl(fpop: 10)
89
+
90
+ # Add full analysis
91
+ df_with_analysis = df.fpl_analysis(fpop: 10)
92
+
93
+ # Now has columns: fpl_min, fpl_max, fpl_risk, fpl_direction, etc.
94
+ ```
95
+
96
+ ## Use Cases
97
+
98
+ ### 1. Opportunity Screening
99
+
100
+ ```ruby
101
+ stocks = ['AAPL', 'GOOGL', 'MSFT']
102
+
103
+ stocks.each do |ticker|
104
+ stock = SQA::Stock.new(ticker: ticker)
105
+ prices = stock.df["adj_close_price"].to_a
106
+
107
+ analysis = SQA::FPOP.fpl_analysis(prices, fpop: 10)
108
+
109
+ if analysis[:reward] > 15.0 && analysis[:risk] < 10.0
110
+ puts "#{ticker}: Good risk/reward (#{analysis[:reward]}/#{analysis[:risk]})"
111
+ end
112
+ end
113
+ ```
114
+
115
+ ### 2. Entry Point Validation
116
+
117
+ ```ruby
118
+ # Check if current point offers good risk/reward
119
+ current_analysis = SQA::FPOP.fpl_analysis(prices, fpop: 10)
120
+
121
+ if current_analysis[:direction] == :UP &&
122
+ current_analysis[:quality_score] > 0.7
123
+ puts "Strong buy opportunity"
124
+ end
125
+ ```
126
+
127
+ ### 3. Stop Loss Calculation
128
+
129
+ ```ruby
130
+ analysis = SQA::FPOP.fpl_analysis(prices, fpop: 10)
131
+
132
+ # Set stop loss based on expected risk
133
+ entry_price = prices.last
134
+ stop_loss = entry_price * (1 - analysis[:risk] / 100)
135
+
136
+ puts "Entry: $#{entry_price}"
137
+ puts "Stop Loss: $#{stop_loss}"
138
+ puts "Target: $#{entry_price * (1 + analysis[:reward] / 100)}"
139
+ ```
140
+
141
+ ## Parameters
142
+
143
+ - `fpop`: Future periods to analyze (default: 10)
144
+ - `min_magnitude`: Minimum move size to consider (%)
145
+ - `max_risk`: Maximum acceptable downside (%)
146
+ - `directions`: Filter by `:UP`, `:DOWN`, or `:FLAT`
147
+
148
+ ## Related
149
+
150
+ - [Strategy Generator](strategy-generator.md) - Uses FPOP for pattern quality
151
+ - [Risk Management](risk-management.md) - Position sizing based on risk
152
+ - [Backtesting](backtesting.md) - Validate FPOP predictions
153
+
@@ -0,0 +1,112 @@
1
+ # Advanced Features
2
+
3
+ Explore SQA's advanced capabilities for professional-grade analysis.
4
+
5
+ ## Power Tools for Serious Analysis
6
+
7
+ SQA goes beyond basic technical analysis with powerful features for portfolio management, strategy optimization, and real-time trading.
8
+
9
+ ## Available Features
10
+
11
+ ### Portfolio Management
12
+ Track positions, calculate P&L, manage commissions, and monitor portfolio performance.
13
+
14
+ **Key Capabilities:**
15
+ - Position tracking with share quantities
16
+ - Commission and fee calculations
17
+ - Realized and unrealized P&L
18
+ - Portfolio value over time
19
+
20
+ [Learn more →](portfolio.md)
21
+
22
+ ### Backtesting Framework
23
+ Simulate trading strategies on historical data with comprehensive performance metrics.
24
+
25
+ **Performance Metrics:**
26
+ - Total return and annualized return
27
+ - Sharpe ratio and Sortino ratio
28
+ - Maximum drawdown
29
+ - Win rate and profit factor
30
+
31
+ [Learn more →](backtesting.md)
32
+
33
+ ### Strategy Generator
34
+ Reverse-engineer profitable trades to discover patterns and generate new strategies.
35
+
36
+ **Workflow:**
37
+ 1. Identify profitable entry/exit points
38
+ 2. Capture indicator states at those points
39
+ 3. Mine patterns from indicator combinations
40
+ 4. Generate executable strategies
41
+
42
+ [Learn more →](strategy-generator.md)
43
+
44
+ ### Genetic Programming
45
+ Evolve optimal strategy parameters using genetic algorithms.
46
+
47
+ **Process:**
48
+ - Define parameter space (genes)
49
+ - Create random population
50
+ - Evaluate fitness via backtesting
51
+ - Evolve through selection, crossover, mutation
52
+
53
+ [Learn more →](../genetic_programming.md)
54
+
55
+ ### Real-Time Streaming
56
+ Process live price data with event callbacks and parallel strategy execution.
57
+
58
+ **Features:**
59
+ - Rolling window of recent data
60
+ - On-the-fly indicator calculations
61
+ - Multiple strategies in parallel
62
+ - Customizable callbacks
63
+
64
+ [Learn more →](streaming.md)
65
+
66
+ ### FPOP Analysis
67
+ Future Period of Performance analysis for risk/reward calculations.
68
+
69
+ **Capabilities:**
70
+ - Calculate future returns
71
+ - Direction classification
72
+ - Risk/reward metrics
73
+ - Performance attribution
74
+
75
+ [Learn more →](fpop.md)
76
+
77
+ ## Example Workflow
78
+
79
+ ```mermaid
80
+ graph LR
81
+ A[Historical Data] --> B[Strategy Generator]
82
+ B --> C[Discovered Patterns]
83
+ C --> D[Generated Strategies]
84
+ D --> E[Genetic Programming]
85
+ E --> F[Optimized Parameters]
86
+ F --> G[Backtest]
87
+ G --> H{Results Good?}
88
+ H -->|Yes| I[Live Stream]
89
+ H -->|No| D
90
+ I --> J[Portfolio Management]
91
+ ```
92
+
93
+ ## Use Cases
94
+
95
+ ### Quantitative Research
96
+ - Pattern discovery in historical data
97
+ - Parameter optimization
98
+ - Strategy validation
99
+
100
+ ### Algorithmic Trading (Educational)
101
+ - Real-time signal generation
102
+ - Portfolio tracking
103
+ - Performance monitoring
104
+
105
+ ### Risk Management
106
+ - Drawdown analysis
107
+ - Volatility tracking
108
+ - Position sizing
109
+
110
+ ---
111
+
112
+ **Remember**: These are powerful tools for education and research. Always test thoroughly before considering any real trading applications.
@@ -0,0 +1,67 @@
1
+ # Multi-Timeframe Analysis
2
+
3
+ Analyze multiple timeframes simultaneously for better trade timing.
4
+
5
+ ## Setup
6
+
7
+ ```ruby
8
+ mta = SQA::MultiTimeframe.new(stock: stock)
9
+ ```
10
+
11
+ ## Trend Alignment
12
+
13
+ ```ruby
14
+ alignment = mta.trend_alignment
15
+
16
+ # {
17
+ # daily: :up,
18
+ # weekly: :up,
19
+ # monthly: :up,
20
+ # aligned: true,
21
+ # direction: :bullish
22
+ # }
23
+
24
+ if alignment[:aligned] && alignment[:direction] == :bullish
25
+ puts "Strong uptrend across all timeframes"
26
+ end
27
+ ```
28
+
29
+ ## Multi-Timeframe Signal
30
+
31
+ ```ruby
32
+ # Higher timeframe = trend, lower timeframe = timing
33
+ signal = mta.signal(
34
+ strategy_class: SQA::Strategy::RSI,
35
+ higher_timeframe: :weekly, # Trend filter
36
+ lower_timeframe: :daily # Entry timing
37
+ )
38
+
39
+ # Only takes trades aligned with higher timeframe trend
40
+ ```
41
+
42
+ ## Support/Resistance
43
+
44
+ ```ruby
45
+ # Find levels that appear across multiple timeframes
46
+ levels = mta.support_resistance(tolerance: 0.02)
47
+
48
+ levels.each do |level|
49
+ puts "Strong level at #{level[:price]}"
50
+ puts " Appears in: #{level[:timeframes].join(', ')}"
51
+ end
52
+ ```
53
+
54
+ ## Divergence Detection
55
+
56
+ ```ruby
57
+ # Price makes new high but indicator doesn't (bearish)
58
+ divergence = mta.detect_divergence(
59
+ indicator: :rsi,
60
+ lookback: 20
61
+ )
62
+
63
+ if divergence[:type] == :bearish
64
+ puts "Bearish divergence detected - potential reversal"
65
+ end
66
+ ```
67
+
@@ -0,0 +1,75 @@
1
+ # Pattern Matcher
2
+
3
+ Pattern recognition and similarity search for forecasting.
4
+
5
+ ## Find Similar Patterns
6
+
7
+ ```ruby
8
+ matcher = SQA::PatternMatcher.new(stock: stock)
9
+
10
+ # Find historical patterns similar to current
11
+ similar = matcher.find_similar(
12
+ lookback: 10, # 10-period pattern
13
+ num_matches: 5, # Find 5 best matches
14
+ method: :euclidean # Distance metric
15
+ )
16
+
17
+ similar.each do |match|
18
+ puts "Distance: #{match[:distance]}"
19
+ puts "Future return: #{match[:future_return]}%"
20
+ end
21
+ ```
22
+
23
+ ## Distance Methods
24
+
25
+ - `:euclidean` - Standard distance
26
+ - `:dtw` - Dynamic Time Warping (handles compression/stretching)
27
+ - `:correlation` - Correlation-based similarity
28
+
29
+ ## Forecasting
30
+
31
+ ```ruby
32
+ forecast = matcher.forecast(
33
+ lookback: 10,
34
+ forecast_periods: 5,
35
+ method: :dtw
36
+ )
37
+
38
+ puts "Forecast price: #{forecast[:forecast_price]}"
39
+ puts "Expected return: #{forecast[:forecast_return]}%"
40
+ puts "95% CI: #{forecast[:confidence_interval_95]}"
41
+ ```
42
+
43
+ ## Chart Pattern Detection
44
+
45
+ ```ruby
46
+ # Detect double top/bottom
47
+ patterns = matcher.detect_chart_pattern(:double_top)
48
+
49
+ # Detect head & shoulders
50
+ patterns = matcher.detect_chart_pattern(:head_and_shoulders)
51
+
52
+ # Detect triangles
53
+ patterns = matcher.detect_chart_pattern(:triangle)
54
+
55
+ patterns.each do |pattern|
56
+ puts "#{pattern[:type]} at index #{pattern[:index]}"
57
+ puts "Confidence: #{pattern[:confidence]}"
58
+ end
59
+ ```
60
+
61
+ ## Pattern Clustering
62
+
63
+ ```ruby
64
+ # Group similar patterns
65
+ clusters = matcher.cluster_patterns(
66
+ num_clusters: 5,
67
+ lookback: 10
68
+ )
69
+
70
+ clusters.each_with_index do |cluster, i|
71
+ puts "Cluster #{i}: #{cluster.size} patterns"
72
+ puts " Avg future return: #{cluster[:avg_return]}%"
73
+ end
74
+ ```
75
+
@@ -0,0 +1,79 @@
1
+ # Portfolio Optimizer
2
+
3
+ Multi-objective portfolio optimization for optimal asset allocation and rebalancing.
4
+
5
+ ## Maximum Sharpe Portfolio
6
+
7
+ ```ruby
8
+ # Get returns for multiple stocks
9
+ returns_matrix = ['AAPL', 'GOOGL', 'MSFT'].map do |ticker|
10
+ stock = SQA::Stock.new(ticker: ticker)
11
+ prices = stock.df["adj_close_price"].to_a
12
+ prices.each_cons(2).map { |a, b| (b - a) / a }
13
+ end
14
+
15
+ # Find optimal weights
16
+ result = SQA::PortfolioOptimizer.maximum_sharpe(returns_matrix)
17
+
18
+ puts "Optimal Weights:"
19
+ puts " AAPL: #{(result[:weights][0] * 100).round(2)}%"
20
+ puts " GOOGL: #{(result[:weights][1] * 100).round(2)}%"
21
+ puts " MSFT: #{(result[:weights][2] * 100).round(2)}%"
22
+ puts "\nExpected Sharpe: #{result[:sharpe].round(2)}"
23
+ ```
24
+
25
+ ## Minimum Variance Portfolio
26
+
27
+ ```ruby
28
+ result = SQA::PortfolioOptimizer.minimum_variance(returns_matrix)
29
+ # Lowest risk allocation
30
+ ```
31
+
32
+ ## Risk Parity
33
+
34
+ ```ruby
35
+ result = SQA::PortfolioOptimizer.risk_parity(returns_matrix)
36
+ # Equal risk contribution from each asset
37
+ ```
38
+
39
+ ## Efficient Frontier
40
+
41
+ ```ruby
42
+ frontier = SQA::PortfolioOptimizer.efficient_frontier(
43
+ returns_matrix,
44
+ num_portfolios: 50
45
+ )
46
+
47
+ frontier.each do |portfolio|
48
+ puts "Return: #{portfolio[:return]}, Risk: #{portfolio[:volatility]}"
49
+ end
50
+ ```
51
+
52
+ ## Multi-Objective Optimization
53
+
54
+ ```ruby
55
+ result = SQA::PortfolioOptimizer.multi_objective(
56
+ returns_matrix,
57
+ objectives: {
58
+ maximize_return: 0.4,
59
+ minimize_volatility: 0.3,
60
+ minimize_drawdown: 0.3
61
+ }
62
+ )
63
+ ```
64
+
65
+ ## Rebalancing
66
+
67
+ ```ruby
68
+ current_weights = [0.5, 0.3, 0.2]
69
+ target_weights = [0.4, 0.4, 0.2]
70
+
71
+ trades = SQA::PortfolioOptimizer.rebalance(
72
+ current_weights: current_weights,
73
+ target_weights: target_weights,
74
+ portfolio_value: 10_000
75
+ )
76
+
77
+ # trades => [{ ticker: 'AAPL', shares: -5, value: -750 }, ...]
78
+ ```
79
+
@@ -0,0 +1,166 @@
1
+ # Portfolio Management
2
+
3
+ ## Overview
4
+
5
+ The Portfolio class tracks positions, calculates P&L, manages commissions, and monitors portfolio performance over time.
6
+
7
+ ## Creating a Portfolio
8
+
9
+ ```ruby
10
+ require 'sqa'
11
+
12
+ portfolio = SQA::Portfolio.new(
13
+ initial_cash: 10_000, # Starting capital
14
+ commission: 1.0 # Commission per trade
15
+ )
16
+ ```
17
+
18
+ ## Basic Operations
19
+
20
+ ### Buy Stock
21
+
22
+ ```ruby
23
+ portfolio.buy('AAPL', shares: 10, price: 150.0)
24
+ # Deducts: (10 × $150) + $1 commission = $1,501
25
+
26
+ puts portfolio.cash # => 8,499.0
27
+ puts portfolio.positions['AAPL'] # => 10 shares
28
+ ```
29
+
30
+ ### Sell Stock
31
+
32
+ ```ruby
33
+ portfolio.sell('AAPL', shares: 5, price: 160.0)
34
+ # Adds: (5 × $160) - $1 commission = $799
35
+
36
+ puts portfolio.cash # => 9,298.0
37
+ puts portfolio.positions['AAPL'] # => 5 shares
38
+ ```
39
+
40
+ ### Calculate Portfolio Value
41
+
42
+ ```ruby
43
+ current_prices = {
44
+ 'AAPL' => 165.0,
45
+ 'GOOGL' => 2800.0
46
+ }
47
+
48
+ total_value = portfolio.value(current_prices)
49
+ # Cash + (positions × current prices)
50
+ ```
51
+
52
+ ## Complete Example
53
+
54
+ ```ruby
55
+ # Initialize
56
+ portfolio = SQA::Portfolio.new(initial_cash: 10_000)
57
+
58
+ # Buy multiple stocks
59
+ portfolio.buy('AAPL', shares: 10, price: 150.0)
60
+ portfolio.buy('GOOGL', shares: 2, price: 2750.0)
61
+
62
+ # Check positions
63
+ puts "Positions: #{portfolio.positions}"
64
+ # => {"AAPL"=>10, "GOOGL"=>2}
65
+
66
+ # Calculate current value
67
+ prices = { 'AAPL' => 160.0, 'GOOGL' => 2800.0 }
68
+ puts "Portfolio Value: $#{portfolio.value(prices)}"
69
+
70
+ # Sell some shares
71
+ portfolio.sell('AAPL', shares: 5, price: 160.0)
72
+
73
+ # View trade history
74
+ portfolio.trades.each do |trade|
75
+ puts "#{trade.action} #{trade.shares} #{trade.ticker} @ $#{trade.price}"
76
+ end
77
+ ```
78
+
79
+ ## P&L Tracking
80
+
81
+ ### Realized P&L
82
+ Profit/loss from closed positions (sold shares).
83
+
84
+ ```ruby
85
+ # Buy 10 shares @ $150
86
+ portfolio.buy('AAPL', shares: 10, price: 150.0)
87
+
88
+ # Sell 5 shares @ $160
89
+ portfolio.sell('AAPL', shares: 5, price: 160.0)
90
+
91
+ # Realized P&L: (160 - 150) × 5 = $50
92
+ # (minus 2 × $1 commission = $48)
93
+ ```
94
+
95
+ ### Unrealized P&L
96
+ Paper profit/loss on open positions.
97
+
98
+ ```ruby
99
+ # Still holding 5 shares bought @ $150
100
+ # Current price: $165
101
+
102
+ unrealized_pnl = (165.0 - 150.0) * 5 # => $75
103
+ ```
104
+
105
+ ## Portfolio Methods
106
+
107
+ | Method | Description |
108
+ |--------|-------------|
109
+ | `buy(ticker, shares:, price:)` | Purchase shares |
110
+ | `sell(ticker, shares:, price:)` | Sell shares |
111
+ | `value(current_prices)` | Calculate total portfolio value |
112
+ | `positions` | Hash of ticker → share count |
113
+ | `trades` | Array of all trades |
114
+ | `cash` | Available cash balance |
115
+
116
+ ## Usage with Backtesting
117
+
118
+ ```ruby
119
+ backtest = SQA::Backtest.new(
120
+ stock: stock,
121
+ strategy: SQA::Strategy::RSI,
122
+ initial_cash: 10_000,
123
+ commission: 1.0
124
+ )
125
+
126
+ results = backtest.run
127
+
128
+ puts "Final Value: $#{results.portfolio_value}"
129
+ puts "Total Return: #{results.total_return}%"
130
+ puts "Total Trades: #{results.num_trades}"
131
+ ```
132
+
133
+ ## Advanced Features
134
+
135
+ ### Position Sizing
136
+
137
+ ```ruby
138
+ # Risk-based position sizing
139
+ risk_per_trade = portfolio.cash * 0.02 # 2% risk
140
+ shares = (risk_per_trade / stop_loss_distance).to_i
141
+
142
+ portfolio.buy('AAPL', shares: shares, price: current_price)
143
+ ```
144
+
145
+ ### Diversification Check
146
+
147
+ ```ruby
148
+ def check_diversification(portfolio, prices)
149
+ total_value = portfolio.value(prices)
150
+
151
+ portfolio.positions.each do |ticker, shares|
152
+ position_value = shares * prices[ticker]
153
+ percentage = (position_value / total_value) * 100
154
+
155
+ puts "#{ticker}: #{percentage.round(2)}%"
156
+ warn "⚠️ #{ticker} exceeds 20%" if percentage > 20
157
+ end
158
+ end
159
+ ```
160
+
161
+ ## Related
162
+
163
+ - [Backtesting](backtesting.md) - Test strategies with portfolio tracking
164
+ - [Risk Management](risk-management.md) - Position sizing and risk metrics
165
+ - [Portfolio Optimizer](portfolio-optimizer.md) - Optimal asset allocation
166
+