sqa 0.0.32 → 0.0.38

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 (110) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +154 -1
  3. data/README.md +4 -0
  4. data/Rakefile +52 -10
  5. data/docs/advanced/index.md +1 -13
  6. data/docs/api/index.md +547 -61
  7. data/docs/api-reference/alphavantageapi.md +1057 -0
  8. data/docs/api-reference/apierror.md +31 -0
  9. data/docs/api-reference/index.md +221 -0
  10. data/docs/api-reference/notimplemented.md +27 -0
  11. data/docs/api-reference/sqa.md +267 -0
  12. data/docs/api-reference/sqa_backtest.md +171 -0
  13. data/docs/api-reference/sqa_backtest_results.md +530 -0
  14. data/docs/api-reference/sqa_badparametererror.md +13 -0
  15. data/docs/api-reference/sqa_config.md +538 -0
  16. data/docs/api-reference/sqa_configurationerror.md +13 -0
  17. data/docs/api-reference/sqa_datafetcherror.md +56 -0
  18. data/docs/api-reference/sqa_dataframe.md +779 -0
  19. data/docs/api-reference/sqa_dataframe_alphavantage.md +30 -0
  20. data/docs/api-reference/sqa_dataframe_data.md +325 -0
  21. data/docs/api-reference/sqa_dataframe_yahoofinance.md +25 -0
  22. data/docs/api-reference/sqa_ensemble.md +413 -0
  23. data/docs/api-reference/sqa_fpop.md +211 -0
  24. data/docs/api-reference/sqa_geneticprogram.md +325 -0
  25. data/docs/api-reference/sqa_geneticprogram_individual.md +114 -0
  26. data/docs/api-reference/sqa_marketregime.md +212 -0
  27. data/docs/api-reference/sqa_multitimeframe.md +227 -0
  28. data/docs/api-reference/sqa_patternmatcher.md +195 -0
  29. data/docs/api-reference/sqa_pluginmanager.md +55 -0
  30. data/docs/api-reference/sqa_portfolio.md +512 -0
  31. data/docs/api-reference/sqa_portfolio_position.md +220 -0
  32. data/docs/api-reference/sqa_portfolio_trade.md +332 -0
  33. data/docs/api-reference/sqa_portfoliooptimizer.md +248 -0
  34. data/docs/api-reference/sqa_riskmanager.md +388 -0
  35. data/docs/api-reference/sqa_seasonalanalyzer.md +121 -0
  36. data/docs/api-reference/sqa_sectoranalyzer.md +163 -0
  37. data/docs/api-reference/sqa_stock.md +661 -0
  38. data/docs/api-reference/sqa_strategy.md +178 -0
  39. data/docs/api-reference/sqa_strategy_bollingerbands.md +26 -0
  40. data/docs/api-reference/sqa_strategy_common.md +29 -0
  41. data/docs/api-reference/sqa_strategy_consensus.md +129 -0
  42. data/docs/api-reference/sqa_strategy_ema.md +41 -0
  43. data/docs/api-reference/sqa_strategy_kbs.md +154 -0
  44. data/docs/api-reference/sqa_strategy_macd.md +26 -0
  45. data/docs/api-reference/sqa_strategy_mp.md +41 -0
  46. data/docs/api-reference/sqa_strategy_mr.md +41 -0
  47. data/docs/api-reference/sqa_strategy_random.md +41 -0
  48. data/docs/api-reference/sqa_strategy_rsi.md +41 -0
  49. data/docs/api-reference/sqa_strategy_sma.md +41 -0
  50. data/docs/api-reference/sqa_strategy_stochastic.md +26 -0
  51. data/docs/api-reference/sqa_strategy_volumebreakout.md +26 -0
  52. data/docs/api-reference/sqa_strategygenerator.md +298 -0
  53. data/docs/api-reference/sqa_strategygenerator_pattern.md +264 -0
  54. data/docs/api-reference/sqa_strategygenerator_patterncontext.md +326 -0
  55. data/docs/api-reference/sqa_strategygenerator_profitablepoint.md +424 -0
  56. data/docs/api-reference/sqa_stream.md +256 -0
  57. data/docs/api-reference/sqa_ticker.md +175 -0
  58. data/docs/api-reference/string.md +135 -0
  59. data/docs/assets/images/advanced-workflow.svg +89 -0
  60. data/docs/assets/images/architecture.svg +107 -0
  61. data/docs/assets/images/data-flow.svg +138 -0
  62. data/docs/assets/images/getting-started-workflow.svg +88 -0
  63. data/docs/assets/images/strategy-flow.svg +78 -0
  64. data/docs/assets/images/system-architecture.svg +150 -0
  65. data/docs/concepts/index.md +292 -19
  66. data/docs/file_formats.md +250 -0
  67. data/docs/getting-started/index.md +1 -14
  68. data/docs/index.md +26 -23
  69. data/docs/llms.txt +109 -0
  70. data/docs/strategies/kbs.md +15 -14
  71. data/docs/strategy.md +381 -3
  72. data/docs/terms_of_use.md +1 -1
  73. data/examples/README.md +10 -0
  74. data/lib/api/alpha_vantage_api.rb +3 -7
  75. data/lib/sqa/backtest.rb +32 -0
  76. data/lib/sqa/config.rb +109 -28
  77. data/lib/sqa/data_frame/data.rb +13 -1
  78. data/lib/sqa/data_frame.rb +193 -26
  79. data/lib/sqa/errors.rb +79 -17
  80. data/lib/sqa/init.rb +70 -15
  81. data/lib/sqa/pattern_matcher.rb +4 -4
  82. data/lib/sqa/portfolio.rb +55 -1
  83. data/lib/sqa/sector_analyzer.rb +3 -11
  84. data/lib/sqa/stock.rb +180 -15
  85. data/lib/sqa/strategy.rb +62 -4
  86. data/lib/sqa/ticker.rb +106 -48
  87. data/lib/sqa/version.rb +1 -1
  88. data/lib/sqa.rb +4 -4
  89. data/mkdocs.yml +69 -81
  90. metadata +89 -21
  91. data/docs/README.md +0 -43
  92. data/examples/sinatra_app/Gemfile +0 -42
  93. data/examples/sinatra_app/Gemfile.lock +0 -268
  94. data/examples/sinatra_app/QUICKSTART.md +0 -169
  95. data/examples/sinatra_app/README.md +0 -471
  96. data/examples/sinatra_app/RUNNING_WITHOUT_TALIB.md +0 -90
  97. data/examples/sinatra_app/TROUBLESHOOTING.md +0 -95
  98. data/examples/sinatra_app/app.rb +0 -404
  99. data/examples/sinatra_app/config.ru +0 -5
  100. data/examples/sinatra_app/public/css/style.css +0 -723
  101. data/examples/sinatra_app/public/debug_macd.html +0 -82
  102. data/examples/sinatra_app/public/js/app.js +0 -107
  103. data/examples/sinatra_app/start.sh +0 -53
  104. data/examples/sinatra_app/views/analyze.erb +0 -306
  105. data/examples/sinatra_app/views/backtest.erb +0 -325
  106. data/examples/sinatra_app/views/dashboard.erb +0 -831
  107. data/examples/sinatra_app/views/error.erb +0 -58
  108. data/examples/sinatra_app/views/index.erb +0 -118
  109. data/examples/sinatra_app/views/layout.erb +0 -61
  110. data/examples/sinatra_app/views/portfolio.erb +0 -43
@@ -0,0 +1,388 @@
1
+ # 📦 SQA::RiskManager
2
+
3
+ !!! note "Description"
4
+ RiskManager - Comprehensive risk management and position sizing
5
+
6
+ Provides methods for:
7
+ - Value at Risk (VaR): Historical, Parametric, Monte Carlo
8
+ - Conditional VaR (CVaR / Expected Shortfall)
9
+ - Position sizing: Kelly Criterion, Fixed Fractional, Percent Volatility
10
+ - Risk metrics: Sharpe, Sortino, Calmar, Maximum Drawdown
11
+ - Stop loss calculations
12
+
13
+ !!! abstract "Source Information"
14
+ **Defined in:** [`lib/sqa/risk_manager.rb:29`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L29)
15
+
16
+ **Inherits from:** `Object`
17
+
18
+ ## 🏭 Class Methods
19
+
20
+ ### `.var(returns, confidence: = 0.95, method: = :historical, simulations: = 10_000)`
21
+
22
+ Calculate Value at Risk (VaR) using historical method
23
+
24
+ VaR represents the maximum expected loss over a given time period
25
+ at a specified confidence level.
26
+
27
+ !!! info "Parameters"
28
+
29
+ | Name | Type | Description |
30
+ |------|------|-------------|
31
+ | `returns` | `Array<Float>` | Array of period returns (e.g., daily returns) |
32
+ | `confidence` | `Float` | Confidence level (default: 0.95 for 95%) |
33
+ | `method` | `Symbol` | Method to use (:historical, :parametric, :monte_carlo) |
34
+ | `simulations` | `Integer` | Number of Monte Carlo simulations (if method is :monte_carlo) |
35
+ !!! success "Returns"
36
+
37
+ **Type:** `Float`
38
+
39
+
40
+
41
+ Value at Risk as a percentage
42
+ !!! example "Usage Examples"
43
+
44
+ ```ruby
45
+ returns = [0.01, -0.02, 0.015, -0.01, 0.005]
46
+ var = SQA::RiskManager.var(returns, confidence: 0.95)
47
+ # => -0.02 (2% maximum expected loss at 95% confidence)
48
+ ```
49
+ ??? info "Source Location"
50
+ [`lib/sqa/risk_manager.rb:48`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L48)
51
+
52
+ ---
53
+
54
+ ### `.cvar(returns, confidence: = 0.95)`
55
+
56
+ Calculate Conditional Value at Risk (CVaR / Expected Shortfall)
57
+
58
+ CVaR is the expected loss given that the loss exceeds the VaR threshold.
59
+ It provides a more conservative risk measure than VaR.
60
+
61
+ !!! info "Parameters"
62
+
63
+ | Name | Type | Description |
64
+ |------|------|-------------|
65
+ | `returns` | `Array<Float>` | Array of period returns |
66
+ | `confidence` | `Float` | Confidence level (default: 0.95) |
67
+ !!! success "Returns"
68
+
69
+ **Type:** `Float`
70
+
71
+
72
+
73
+ CVaR as a percentage
74
+ !!! example "Usage Examples"
75
+
76
+ ```ruby
77
+ cvar = SQA::RiskManager.cvar(returns, confidence: 0.95)
78
+ # => -0.025 (2.5% expected loss in worst 5% of cases)
79
+ ```
80
+ ??? info "Source Location"
81
+ [`lib/sqa/risk_manager.rb:77`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L77)
82
+
83
+ ---
84
+
85
+ ### `.kelly_criterion(win_rate:, avg_win:, avg_loss:, capital:, max_fraction: = 0.25)`
86
+
87
+ Calculate position size using Kelly Criterion
88
+
89
+ Kelly Criterion calculates the optimal fraction of capital to risk
90
+ based on win rate and win/loss ratio.
91
+
92
+ Formula: f = (p * b - q) / b
93
+ where:
94
+ f = fraction of capital to bet
95
+ p = probability of winning
96
+ q = probability of losing (1 - p)
97
+ b = win/loss ratio (avg_win / avg_loss)
98
+
99
+ !!! info "Parameters"
100
+
101
+ | Name | Type | Description |
102
+ |------|------|-------------|
103
+ | `win_rate` | `Float` | Win rate (0.0 to 1.0) |
104
+ | `avg_win` | `Float` | Average win size (as percentage) |
105
+ | `avg_loss` | `Float` | Average loss size (as percentage) |
106
+ | `capital` | `Float` | Total capital available |
107
+ | `max_fraction` | `Float` | Maximum fraction to risk (default: 0.25 for 25%) |
108
+ !!! success "Returns"
109
+
110
+ **Type:** `Float`
111
+
112
+
113
+
114
+ Dollar amount to risk
115
+ !!! example "Usage Examples"
116
+
117
+ ```ruby
118
+ position = SQA::RiskManager.kelly_criterion(
119
+ win_rate: 0.60,
120
+ avg_win: 0.10,
121
+ avg_loss: 0.05,
122
+ capital: 10_000,
123
+ max_fraction: 0.25
124
+ )
125
+ ```
126
+ ??? info "Source Location"
127
+ [`lib/sqa/risk_manager.rb:116`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L116)
128
+
129
+ ---
130
+
131
+ ### `.fixed_fractional(capital:, risk_fraction: = 0.02)`
132
+
133
+ Calculate position size using Fixed Fractional method
134
+
135
+ Risk a fixed percentage of capital on each trade.
136
+ Simple and conservative approach.
137
+
138
+ !!! info "Parameters"
139
+
140
+ | Name | Type | Description |
141
+ |------|------|-------------|
142
+ | `capital` | `Float` | Total capital |
143
+ | `risk_fraction` | `Float` | Fraction to risk (e.g., 0.02 for 2%) |
144
+ !!! success "Returns"
145
+
146
+ **Type:** `Float`
147
+
148
+
149
+
150
+ Dollar amount to risk
151
+ !!! example "Usage Examples"
152
+
153
+ ```ruby
154
+ position = SQA::RiskManager.fixed_fractional(capital: 10_000, risk_fraction: 0.02)
155
+ # => 200.0 (risk $200 per trade)
156
+ ```
157
+ ??? info "Source Location"
158
+ [`lib/sqa/risk_manager.rb:146`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L146)
159
+
160
+ ---
161
+
162
+ ### `.percent_volatility(capital:, returns:, target_volatility: = 0.15, current_price:)`
163
+
164
+ Calculate position size using Percent Volatility method
165
+
166
+ Adjust position size based on recent volatility.
167
+ Higher volatility = smaller position size.
168
+
169
+ !!! info "Parameters"
170
+
171
+ | Name | Type | Description |
172
+ |------|------|-------------|
173
+ | `capital` | `Float` | Total capital |
174
+ | `returns` | `Array<Float>` | Recent returns |
175
+ | `target_volatility` | `Float` | Target portfolio volatility (annualized) |
176
+ | `current_price` | `Float` | Current asset price |
177
+ !!! success "Returns"
178
+
179
+ **Type:** `Integer`
180
+
181
+
182
+
183
+ Number of shares to buy
184
+ !!! example "Usage Examples"
185
+
186
+ ```ruby
187
+ shares = SQA::RiskManager.percent_volatility(
188
+ capital: 10_000,
189
+ returns: recent_returns,
190
+ target_volatility: 0.15,
191
+ current_price: 150.0
192
+ )
193
+ ```
194
+ ??? info "Source Location"
195
+ [`lib/sqa/risk_manager.rb:170`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L170)
196
+
197
+ ---
198
+
199
+ ### `.atr_stop_loss(current_price:, atr:, multiplier: = 2.0, direction: = :long)`
200
+
201
+ Calculate stop loss price based on ATR (Average True Range)
202
+
203
+ !!! info "Parameters"
204
+
205
+ | Name | Type | Description |
206
+ |------|------|-------------|
207
+ | `current_price` | `Float` | Current asset price |
208
+ | `atr` | `Float` | Average True Range |
209
+ | `multiplier` | `Float` | ATR multiplier (default: 2.0) |
210
+ | `direction` | `Symbol` | :long or :short |
211
+ !!! success "Returns"
212
+
213
+ **Type:** `Float`
214
+
215
+
216
+
217
+ Stop loss price
218
+ !!! example "Usage Examples"
219
+
220
+ ```ruby
221
+ stop = SQA::RiskManager.atr_stop_loss(
222
+ current_price: 150.0,
223
+ atr: 3.5,
224
+ multiplier: 2.0,
225
+ direction: :long
226
+ )
227
+ # => 143.0 (stop at current - 2*ATR)
228
+ ```
229
+ ??? info "Source Location"
230
+ [`lib/sqa/risk_manager.rb:204`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L204)
231
+
232
+ ---
233
+
234
+ ### `.max_drawdown(prices)`
235
+
236
+ Calculate maximum drawdown from price series
237
+
238
+ Drawdown is the peak-to-trough decline in portfolio value.
239
+
240
+ !!! info "Parameters"
241
+
242
+ | Name | Type | Description |
243
+ |------|------|-------------|
244
+ | `prices` | `Array<Float>` | Array of prices or portfolio values |
245
+ !!! success "Returns"
246
+
247
+ **Type:** `Hash`
248
+
249
+
250
+
251
+ { max_drawdown: Float, peak_idx: Integer, trough_idx: Integer }
252
+ !!! example "Usage Examples"
253
+
254
+ ```ruby
255
+ dd = SQA::RiskManager.max_drawdown([100, 110, 105, 95, 100])
256
+ # => { max_drawdown: -0.136, peak_idx: 1, trough_idx: 3 }
257
+ ```
258
+ ??? info "Source Location"
259
+ [`lib/sqa/risk_manager.rb:224`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L224)
260
+
261
+ ---
262
+
263
+ ### `.sharpe_ratio(returns, risk_free_rate: = 0.02, periods_per_year: = 252)`
264
+
265
+ Calculate Sharpe Ratio
266
+
267
+ Measures risk-adjusted return (excess return per unit of risk).
268
+
269
+ !!! info "Parameters"
270
+
271
+ | Name | Type | Description |
272
+ |------|------|-------------|
273
+ | `returns` | `Array<Float>` | Array of period returns |
274
+ | `risk_free_rate` | `Float` | Risk-free rate (annualized, default: 0.02) |
275
+ | `periods_per_year` | `Integer` | Number of periods per year (default: 252 for daily) |
276
+ !!! success "Returns"
277
+
278
+ **Type:** `Float`
279
+
280
+
281
+
282
+ Sharpe ratio
283
+ !!! example "Usage Examples"
284
+
285
+ ```ruby
286
+ sharpe = SQA::RiskManager.sharpe_ratio(returns, risk_free_rate: 0.02)
287
+ ```
288
+ ??? info "Source Location"
289
+ [`lib/sqa/risk_manager.rb:269`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L269)
290
+
291
+ ---
292
+
293
+ ### `.sortino_ratio(returns, target_return: = 0.0, periods_per_year: = 252)`
294
+
295
+ Calculate Sortino Ratio
296
+
297
+ Like Sharpe ratio but only penalizes downside volatility.
298
+
299
+ !!! info "Parameters"
300
+
301
+ | Name | Type | Description |
302
+ |------|------|-------------|
303
+ | `returns` | `Array<Float>` | Array of period returns |
304
+ | `target_return` | `Float` | Target return (default: 0.0) |
305
+ | `periods_per_year` | `Integer` | Number of periods per year (default: 252) |
306
+ !!! success "Returns"
307
+
308
+ **Type:** `Float`
309
+
310
+
311
+
312
+ Sortino ratio
313
+ !!! example "Usage Examples"
314
+
315
+ ```ruby
316
+ sortino = SQA::RiskManager.sortino_ratio(returns)
317
+ ```
318
+ ??? info "Source Location"
319
+ [`lib/sqa/risk_manager.rb:294`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L294)
320
+
321
+ ---
322
+
323
+ ### `.calmar_ratio(returns, periods_per_year: = 252)`
324
+
325
+ Calculate Calmar Ratio
326
+
327
+ Ratio of annualized return to maximum drawdown.
328
+
329
+ !!! info "Parameters"
330
+
331
+ | Name | Type | Description |
332
+ |------|------|-------------|
333
+ | `returns` | `Array<Float>` | Array of period returns |
334
+ | `periods_per_year` | `Integer` | Number of periods per year (default: 252) |
335
+ !!! success "Returns"
336
+
337
+ **Type:** `Float`
338
+
339
+
340
+
341
+ Calmar ratio
342
+ !!! example "Usage Examples"
343
+
344
+ ```ruby
345
+ calmar = SQA::RiskManager.calmar_ratio(returns)
346
+ ```
347
+ ??? info "Source Location"
348
+ [`lib/sqa/risk_manager.rb:325`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L325)
349
+
350
+ ---
351
+
352
+ ### `.monte_carlo_simulation(initial_capital:, returns:, periods:, simulations: = 1000)`
353
+
354
+ Monte Carlo simulation for portfolio value
355
+
356
+ !!! info "Parameters"
357
+
358
+ | Name | Type | Description |
359
+ |------|------|-------------|
360
+ | `initial_capital` | `Float` | Starting capital |
361
+ | `returns` | `Array<Float>` | Historical returns to sample from |
362
+ | `periods` | `Integer` | Number of periods to simulate |
363
+ | `simulations` | `Integer` | Number of simulation paths |
364
+ !!! success "Returns"
365
+
366
+ **Type:** `Hash`
367
+
368
+
369
+
370
+ Simulation results with percentiles
371
+ !!! example "Usage Examples"
372
+
373
+ ```ruby
374
+ results = SQA::RiskManager.monte_carlo_simulation(
375
+ initial_capital: 10_000,
376
+ returns: historical_returns,
377
+ periods: 252,
378
+ simulations: 1000
379
+ )
380
+ puts "95th percentile: $#{results[:percentile_95]}"
381
+ ```
382
+ ??? info "Source Location"
383
+ [`lib/sqa/risk_manager.rb:360`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L360)
384
+
385
+ ---
386
+
387
+ ## 📝 Attributes
388
+
@@ -0,0 +1,121 @@
1
+ # 🔧 SQA::SeasonalAnalyzer
2
+
3
+ !!! abstract "Source Information"
4
+ **Defined in:** [`lib/sqa/seasonal_analyzer.rb:18`](https://github.com/madbomber/sqa/blob/main/lib/sqa/seasonal_analyzer.rb#L18)
5
+
6
+ ## 🏭 Class Methods
7
+
8
+ ### `.analyze(stock)`
9
+
10
+ Analyze seasonal performance patterns
11
+
12
+ !!! info "Parameters"
13
+
14
+ | Name | Type | Description |
15
+ |------|------|-------------|
16
+ | `stock` | `SQA::Stock` | Stock to analyze |
17
+ !!! success "Returns"
18
+
19
+ **Type:** `Hash`
20
+
21
+
22
+
23
+ Seasonal performance metadata
24
+
25
+ ??? info "Source Location"
26
+ [`lib/sqa/seasonal_analyzer.rb:25`](https://github.com/madbomber/sqa/blob/main/lib/sqa/seasonal_analyzer.rb#L25)
27
+
28
+ ---
29
+
30
+ ### `.filter_by_months(stock, months)`
31
+
32
+ Filter data by calendar months
33
+
34
+ !!! info "Parameters"
35
+
36
+ | Name | Type | Description |
37
+ |------|------|-------------|
38
+ | `stock` | `SQA::Stock` | Stock to analyze |
39
+ | `months` | `Array<Integer>` | Months to include (1-12) |
40
+ !!! success "Returns"
41
+
42
+ **Type:** `Hash`
43
+
44
+
45
+
46
+ Filtered data
47
+
48
+ ??? info "Source Location"
49
+ [`lib/sqa/seasonal_analyzer.rb:56`](https://github.com/madbomber/sqa/blob/main/lib/sqa/seasonal_analyzer.rb#L56)
50
+
51
+ ---
52
+
53
+ ### `.filter_by_quarters(stock, quarters)`
54
+
55
+ Filter data by quarters
56
+
57
+ !!! info "Parameters"
58
+
59
+ | Name | Type | Description |
60
+ |------|------|-------------|
61
+ | `stock` | `SQA::Stock` | Stock to analyze |
62
+ | `quarters` | `Array<Integer>` | Quarters to include (1-4) |
63
+ !!! success "Returns"
64
+
65
+ **Type:** `Hash`
66
+
67
+
68
+
69
+ Filtered data
70
+
71
+ ??? info "Source Location"
72
+ [`lib/sqa/seasonal_analyzer.rb:82`](https://github.com/madbomber/sqa/blob/main/lib/sqa/seasonal_analyzer.rb#L82)
73
+
74
+ ---
75
+
76
+ ### `.detect_seasonality(monthly_returns)`
77
+
78
+ Detect if stock has seasonal pattern
79
+
80
+ !!! info "Parameters"
81
+
82
+ | Name | Type | Description |
83
+ |------|------|-------------|
84
+ | `monthly_returns` | `Hash` | Monthly return statistics |
85
+ !!! success "Returns"
86
+
87
+ **Type:** `Boolean`
88
+
89
+
90
+
91
+ True if significant seasonal pattern exists
92
+
93
+ ??? info "Source Location"
94
+ [`lib/sqa/seasonal_analyzer.rb:99`](https://github.com/madbomber/sqa/blob/main/lib/sqa/seasonal_analyzer.rb#L99)
95
+
96
+ ---
97
+
98
+ ### `.context_for_date(date)`
99
+
100
+ Get seasonal context for a specific date
101
+
102
+ !!! info "Parameters"
103
+
104
+ | Name | Type | Description |
105
+ |------|------|-------------|
106
+ | `date` | `Date` | Date to check |
107
+ !!! success "Returns"
108
+
109
+ **Type:** `Hash`
110
+
111
+
112
+
113
+ Seasonal context
114
+
115
+ ??? info "Source Location"
116
+ [`lib/sqa/seasonal_analyzer.rb:116`](https://github.com/madbomber/sqa/blob/main/lib/sqa/seasonal_analyzer.rb#L116)
117
+
118
+ ---
119
+
120
+ ## 📝 Attributes
121
+
@@ -0,0 +1,163 @@
1
+ # 📦 SQA::SectorAnalyzer
2
+
3
+ !!! abstract "Source Information"
4
+ **Defined in:** [`lib/sqa/sector_analyzer.rb:26`](https://github.com/madbomber/sqa/blob/main/lib/sqa/sector_analyzer.rb#L26)
5
+
6
+ **Inherits from:** `Object`
7
+
8
+ ## 🔨 Instance Methods
9
+
10
+ ### `#blackboards()`
11
+
12
+ Returns the value of attribute blackboards.
13
+
14
+
15
+
16
+
17
+ ??? info "Source Location"
18
+ [`lib/sqa/sector_analyzer.rb:40`](https://github.com/madbomber/sqa/blob/main/lib/sqa/sector_analyzer.rb#L40)
19
+
20
+ ---
21
+
22
+ ### `#stocks_by_sector()`
23
+
24
+ Returns the value of attribute stocks_by_sector.
25
+
26
+
27
+
28
+
29
+ ??? info "Source Location"
30
+ [`lib/sqa/sector_analyzer.rb:40`](https://github.com/madbomber/sqa/blob/main/lib/sqa/sector_analyzer.rb#L40)
31
+
32
+ ---
33
+
34
+ ### `#initialize(db_dir: = '/tmp/sqa_sectors')`
35
+
36
+
37
+ !!! success "Returns"
38
+
39
+ **Type:** `SectorAnalyzer`
40
+
41
+
42
+
43
+ a new instance of SectorAnalyzer
44
+
45
+ ??? info "Source Location"
46
+ [`lib/sqa/sector_analyzer.rb:42`](https://github.com/madbomber/sqa/blob/main/lib/sqa/sector_analyzer.rb#L42)
47
+
48
+ ---
49
+
50
+ ### `#add_stock(stock, sector:)`
51
+
52
+ Add a stock to sector analysis
53
+
54
+ !!! info "Parameters"
55
+
56
+ | Name | Type | Description |
57
+ |------|------|-------------|
58
+ | `stock` | `SQA::Stock, String` | Stock object or ticker |
59
+ | `sector` | `Symbol` | Sector classification |
60
+
61
+
62
+ ??? info "Source Location"
63
+ [`lib/sqa/sector_analyzer.rb:62`](https://github.com/madbomber/sqa/blob/main/lib/sqa/sector_analyzer.rb#L62)
64
+
65
+ ---
66
+
67
+ ### `#discover_sector_patterns(sector, stocks, **options)`
68
+
69
+ Discover patterns for an entire sector
70
+
71
+ !!! info "Parameters"
72
+
73
+ | Name | Type | Description |
74
+ |------|------|-------------|
75
+ | `sector` | `Symbol` | Sector to analyze |
76
+ | `stocks` | `Array<SQA::Stock>` | Stock objects to analyze |
77
+ | `options` | `Hash` | Pattern discovery options |
78
+ !!! success "Returns"
79
+
80
+ **Type:** `Array<Hash>`
81
+
82
+
83
+
84
+ Sector-wide patterns
85
+
86
+ ??? info "Source Location"
87
+ [`lib/sqa/sector_analyzer.rb:86`](https://github.com/madbomber/sqa/blob/main/lib/sqa/sector_analyzer.rb#L86)
88
+
89
+ ---
90
+
91
+ ### `#detect_sector_regime(sector, stocks)`
92
+
93
+ Detect sector regime
94
+
95
+ !!! info "Parameters"
96
+
97
+ | Name | Type | Description |
98
+ |------|------|-------------|
99
+ | `sector` | `Symbol` | Sector to analyze |
100
+ | `stocks` | `Array<SQA::Stock>` | Stock objects |
101
+ !!! success "Returns"
102
+
103
+ **Type:** `Hash`
104
+
105
+
106
+
107
+ Sector regime information
108
+
109
+ ??? info "Source Location"
110
+ [`lib/sqa/sector_analyzer.rb:146`](https://github.com/madbomber/sqa/blob/main/lib/sqa/sector_analyzer.rb#L146)
111
+
112
+ ---
113
+
114
+ ### `#query_sector(sector, fact_type, pattern = {})`
115
+
116
+ Query sector blackboard
117
+
118
+ !!! info "Parameters"
119
+
120
+ | Name | Type | Description |
121
+ |------|------|-------------|
122
+ | `sector` | `Symbol` | Sector to query |
123
+ | `fact_type` | `Symbol` | Type of fact to query |
124
+ | `pattern` | `Hash` | Pattern to match |
125
+ !!! success "Returns"
126
+
127
+ **Type:** `Array<KBS::Fact>`
128
+
129
+
130
+
131
+ Matching facts
132
+
133
+ ??? info "Source Location"
134
+ [`lib/sqa/sector_analyzer.rb:190`](https://github.com/madbomber/sqa/blob/main/lib/sqa/sector_analyzer.rb#L190)
135
+
136
+ ---
137
+
138
+ ### `#print_sector_summary(sector)`
139
+
140
+ Print sector summary
141
+
142
+ !!! info "Parameters"
143
+
144
+ | Name | Type | Description |
145
+ |------|------|-------------|
146
+ | `sector` | `Symbol` | Sector to summarize |
147
+
148
+
149
+ ??? info "Source Location"
150
+ [`lib/sqa/sector_analyzer.rb:202`](https://github.com/madbomber/sqa/blob/main/lib/sqa/sector_analyzer.rb#L202)
151
+
152
+ ---
153
+
154
+ ## 📝 Attributes
155
+
156
+ ### 👁️ `blackboards` <small>read-only</small>
157
+
158
+ Returns the value of attribute blackboards.
159
+
160
+ ### 👁️ `stocks_by_sector` <small>read-only</small>
161
+
162
+ Returns the value of attribute stocks_by_sector.
163
+